wd-upload.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. "use strict";
  2. const common_vendor = require("../../../../common/vendor.js");
  3. if (!Math) {
  4. (wdIcon + wdLoading + wdVideoPreview)();
  5. }
  6. const wdIcon = () => "../wd-icon/wd-icon.js";
  7. const wdVideoPreview = () => "../wd-video-preview/wd-video-preview.js";
  8. const wdLoading = () => "../wd-loading/wd-loading.js";
  9. const __default__ = {
  10. name: "wd-upload",
  11. options: {
  12. addGlobalClass: true,
  13. virtualHost: true,
  14. styleIsolation: "shared"
  15. }
  16. };
  17. const _sfc_main = /* @__PURE__ */ common_vendor.defineComponent({
  18. ...__default__,
  19. props: common_vendor.uploadProps,
  20. emits: ["fail", "change", "success", "progress", "oversize", "chooseerror", "remove", "update:fileList"],
  21. setup(__props, { expose: __expose, emit: __emit }) {
  22. const props = __props;
  23. const emit = __emit;
  24. __expose({
  25. submit: () => startUploadFiles(),
  26. abort: () => abort()
  27. });
  28. const { translate } = common_vendor.useTranslate("upload");
  29. const uploadFiles = common_vendor.ref([]);
  30. const showUpload = common_vendor.computed(() => !props.limit || uploadFiles.value.length < props.limit);
  31. const videoPreview = common_vendor.ref();
  32. const { startUpload, abort, chooseFile, UPLOAD_STATUS } = common_vendor.useUpload();
  33. common_vendor.watch(
  34. () => props.fileList,
  35. (val) => {
  36. const { statusKey } = props;
  37. if (common_vendor.isEqual(val, uploadFiles.value))
  38. return;
  39. const uploadFileList = val.map((item) => {
  40. item[statusKey] = item[statusKey] || "success";
  41. item.response = item.response || "";
  42. return { ...item, uid: common_vendor.context.id++ };
  43. });
  44. uploadFiles.value = uploadFileList;
  45. },
  46. {
  47. deep: true,
  48. immediate: true
  49. }
  50. );
  51. common_vendor.watch(
  52. () => props.limit,
  53. (val) => {
  54. if (val && val < uploadFiles.value.length) {
  55. console.error("[wot-design]Error: props limit must less than fileList.length");
  56. }
  57. },
  58. {
  59. deep: true,
  60. immediate: true
  61. }
  62. );
  63. common_vendor.watch(
  64. () => props.beforePreview,
  65. (fn) => {
  66. if (fn && !common_vendor.isFunction(fn)) {
  67. console.error("The type of beforePreview must be Function");
  68. }
  69. },
  70. {
  71. deep: true,
  72. immediate: true
  73. }
  74. );
  75. common_vendor.watch(
  76. () => props.onPreviewFail,
  77. (fn) => {
  78. if (fn && !common_vendor.isFunction(fn)) {
  79. console.error("The type of onPreviewFail must be Function");
  80. }
  81. },
  82. {
  83. deep: true,
  84. immediate: true
  85. }
  86. );
  87. common_vendor.watch(
  88. () => props.beforeRemove,
  89. (fn) => {
  90. if (fn && !common_vendor.isFunction(fn)) {
  91. console.error("The type of beforeRemove must be Function");
  92. }
  93. },
  94. {
  95. deep: true,
  96. immediate: true
  97. }
  98. );
  99. common_vendor.watch(
  100. () => props.beforeUpload,
  101. (fn) => {
  102. if (fn && !common_vendor.isFunction(fn)) {
  103. console.error("The type of beforeUpload must be Function");
  104. }
  105. },
  106. {
  107. deep: true,
  108. immediate: true
  109. }
  110. );
  111. common_vendor.watch(
  112. () => props.beforeChoose,
  113. (fn) => {
  114. if (fn && !common_vendor.isFunction(fn)) {
  115. console.error("The type of beforeChoose must be Function");
  116. }
  117. },
  118. {
  119. deep: true,
  120. immediate: true
  121. }
  122. );
  123. common_vendor.watch(
  124. () => props.buildFormData,
  125. (fn) => {
  126. if (fn && !common_vendor.isFunction(fn)) {
  127. console.error("The type of buildFormData must be Function");
  128. }
  129. },
  130. {
  131. deep: true,
  132. immediate: true
  133. }
  134. );
  135. function emitFileList() {
  136. emit("update:fileList", uploadFiles.value);
  137. }
  138. function startUploadFiles() {
  139. const { buildFormData, formData = {}, statusKey } = props;
  140. const { action, name, header = {}, accept, successStatus, uploadMethod } = props;
  141. const statusCode = common_vendor.isDef(successStatus) ? successStatus : 200;
  142. for (const uploadFile of uploadFiles.value) {
  143. if (uploadFile[statusKey] === UPLOAD_STATUS.PENDING) {
  144. if (buildFormData) {
  145. buildFormData({
  146. file: uploadFile,
  147. formData,
  148. resolve: (formData2) => {
  149. formData2 && startUpload(uploadFile, {
  150. action,
  151. header,
  152. name,
  153. formData: formData2,
  154. fileType: accept,
  155. statusCode,
  156. statusKey,
  157. uploadMethod,
  158. onSuccess: handleSuccess,
  159. onError: handleError,
  160. onProgress: handleProgress
  161. });
  162. }
  163. });
  164. } else {
  165. startUpload(uploadFile, {
  166. action,
  167. header,
  168. name,
  169. formData,
  170. fileType: accept,
  171. statusCode,
  172. statusKey,
  173. uploadMethod,
  174. onSuccess: handleSuccess,
  175. onError: handleError,
  176. onProgress: handleProgress
  177. });
  178. }
  179. }
  180. }
  181. }
  182. function getImageInfo(img) {
  183. return new Promise((resolve, reject) => {
  184. common_vendor.index.getImageInfo({
  185. src: img,
  186. success: (res) => {
  187. resolve(res);
  188. },
  189. fail: (error) => {
  190. reject(error);
  191. }
  192. });
  193. });
  194. }
  195. function initFile(file, currentIndex) {
  196. const { statusKey } = props;
  197. const initState = {
  198. uid: common_vendor.context.id++,
  199. // 仅h5支持 name
  200. name: file.name || "",
  201. thumb: file.thumb || "",
  202. [statusKey]: "pending",
  203. size: file.size || 0,
  204. url: file.path,
  205. percent: 0
  206. };
  207. if (typeof currentIndex === "number") {
  208. uploadFiles.value.splice(currentIndex, 1, initState);
  209. } else {
  210. uploadFiles.value.push(initState);
  211. }
  212. if (props.autoUpload) {
  213. startUploadFiles();
  214. }
  215. }
  216. function handleError(err, file, formData) {
  217. const { statusKey } = props;
  218. const index = uploadFiles.value.findIndex((item) => item.uid === file.uid);
  219. if (index > -1) {
  220. uploadFiles.value[index][statusKey] = "fail";
  221. uploadFiles.value[index].error = err.message;
  222. uploadFiles.value[index].response = err;
  223. emit("fail", { error: err, file, formData });
  224. emitFileList();
  225. }
  226. }
  227. function handleSuccess(res, file, formData) {
  228. const { statusKey } = props;
  229. const index = uploadFiles.value.findIndex((item) => item.uid === file.uid);
  230. if (index > -1) {
  231. uploadFiles.value[index][statusKey] = "success";
  232. uploadFiles.value[index].response = res.data;
  233. emit("change", { fileList: uploadFiles.value });
  234. emit("success", { file, fileList: uploadFiles.value, formData });
  235. emitFileList();
  236. }
  237. }
  238. function handleProgress(res, file) {
  239. const index = uploadFiles.value.findIndex((item) => item.uid === file.uid);
  240. if (index > -1) {
  241. uploadFiles.value[index].percent = res.progress;
  242. emit("progress", { response: res, file });
  243. }
  244. }
  245. function onChooseFile(currentIndex) {
  246. const { multiple, maxSize, accept, sizeType, limit, sourceType, compressed, maxDuration, camera, beforeUpload, extension } = props;
  247. chooseFile({
  248. multiple,
  249. sizeType,
  250. sourceType,
  251. maxCount: limit ? limit - uploadFiles.value.length : 9,
  252. accept,
  253. compressed,
  254. maxDuration,
  255. camera,
  256. extension
  257. }).then((res) => {
  258. let files = res;
  259. if (!multiple) {
  260. files = files.slice(0, 1);
  261. }
  262. const mapFiles = async (files2) => {
  263. for (let index = 0; index < files2.length; index++) {
  264. const file = files2[index];
  265. if (file.type === "image" && !file.size) {
  266. const imageInfo = await getImageInfo(file.path);
  267. file.size = imageInfo.width * imageInfo.height;
  268. }
  269. Number(file.size) <= maxSize ? initFile(file, currentIndex) : emit("oversize", { file });
  270. }
  271. };
  272. if (beforeUpload) {
  273. beforeUpload({
  274. files,
  275. fileList: uploadFiles.value,
  276. resolve: (isPass) => {
  277. isPass && mapFiles(files);
  278. }
  279. });
  280. } else {
  281. mapFiles(files);
  282. }
  283. }).catch((error) => {
  284. emit("chooseerror", { error });
  285. });
  286. }
  287. function handleChoose(index) {
  288. if (props.disabled)
  289. return;
  290. const { beforeChoose } = props;
  291. if (beforeChoose) {
  292. beforeChoose({
  293. fileList: uploadFiles.value,
  294. resolve: (isPass) => {
  295. isPass && onChooseFile(index);
  296. }
  297. });
  298. } else {
  299. onChooseFile(index);
  300. }
  301. }
  302. function handleRemove(file) {
  303. uploadFiles.value.splice(
  304. uploadFiles.value.findIndex((item) => item.uid === file.uid),
  305. 1
  306. );
  307. emit("change", {
  308. fileList: uploadFiles.value
  309. });
  310. emit("remove", { file });
  311. emitFileList();
  312. }
  313. function removeFile(index) {
  314. const { beforeRemove } = props;
  315. const intIndex = index;
  316. const file = uploadFiles.value[intIndex];
  317. if (beforeRemove) {
  318. beforeRemove({
  319. file,
  320. index: intIndex,
  321. fileList: uploadFiles.value,
  322. resolve: (isPass) => {
  323. isPass && handleRemove(file);
  324. }
  325. });
  326. } else {
  327. handleRemove(file);
  328. }
  329. }
  330. function handlePreviewFile(file) {
  331. common_vendor.index.openDocument({
  332. filePath: file.url,
  333. showMenu: true
  334. });
  335. }
  336. function handlePreviewImage(index, lists) {
  337. const { onPreviewFail } = props;
  338. common_vendor.index.previewImage({
  339. urls: lists,
  340. current: lists[index],
  341. fail() {
  342. if (onPreviewFail) {
  343. onPreviewFail({
  344. index,
  345. imgList: lists
  346. });
  347. } else {
  348. common_vendor.index.showToast({ title: "预览图片失败", icon: "none" });
  349. }
  350. }
  351. });
  352. }
  353. function handlePreviewVieo(index, lists) {
  354. const { onPreviewFail } = props;
  355. common_vendor.index.previewMedia({
  356. current: index,
  357. sources: lists.map((file) => {
  358. return {
  359. url: file.url,
  360. type: "video",
  361. poster: file.thumb
  362. };
  363. }),
  364. fail() {
  365. if (onPreviewFail) {
  366. onPreviewFail({
  367. index,
  368. imgList: []
  369. });
  370. } else {
  371. common_vendor.index.showToast({ title: "预览视频失败", icon: "none" });
  372. }
  373. }
  374. });
  375. }
  376. function onPreviewImage(file) {
  377. const { beforePreview, reupload } = props;
  378. const fileList = common_vendor.deepClone(uploadFiles.value);
  379. const index = fileList.findIndex((item) => item.url === file.url);
  380. const imgList = fileList.filter((file2) => isImage(file2)).map((file2) => file2.url);
  381. const imgIndex = imgList.findIndex((item) => item === file.url);
  382. if (reupload) {
  383. handleChoose(index);
  384. } else {
  385. if (beforePreview) {
  386. beforePreview({
  387. file,
  388. index,
  389. fileList,
  390. imgList,
  391. resolve: (isPass) => {
  392. isPass && handlePreviewImage(imgIndex, imgList);
  393. }
  394. });
  395. } else {
  396. handlePreviewImage(imgIndex, imgList);
  397. }
  398. }
  399. }
  400. function onPreviewVideo(file) {
  401. const { beforePreview, reupload } = props;
  402. const fileList = common_vendor.deepClone(uploadFiles.value);
  403. const index = fileList.findIndex((item) => item.url === file.url);
  404. const videoList = fileList.filter((file2) => isVideo(file2));
  405. const videoIndex = videoList.findIndex((item) => item.url === file.url);
  406. if (reupload) {
  407. handleChoose(index);
  408. } else {
  409. if (beforePreview) {
  410. beforePreview({
  411. file,
  412. index,
  413. imgList: [],
  414. fileList,
  415. resolve: (isPass) => {
  416. isPass && handlePreviewVieo(videoIndex, videoList);
  417. }
  418. });
  419. } else {
  420. handlePreviewVieo(videoIndex, videoList);
  421. }
  422. }
  423. }
  424. function onPreviewFile(file) {
  425. const { beforePreview, reupload } = props;
  426. const fileList = common_vendor.deepClone(uploadFiles.value);
  427. const index = fileList.findIndex((item) => item.url === file.url);
  428. if (reupload) {
  429. handleChoose(index);
  430. } else {
  431. if (beforePreview) {
  432. beforePreview({
  433. file,
  434. index,
  435. imgList: [],
  436. fileList,
  437. resolve: (isPass) => {
  438. isPass && handlePreviewFile(file);
  439. }
  440. });
  441. } else {
  442. handlePreviewFile(file);
  443. }
  444. }
  445. }
  446. function isVideo(file) {
  447. return file.name && common_vendor.isVideoUrl(file.name) || common_vendor.isVideoUrl(file.url);
  448. }
  449. function isImage(file) {
  450. return file.name && common_vendor.isImageUrl(file.name) || common_vendor.isImageUrl(file.url);
  451. }
  452. return (_ctx, _cache) => {
  453. return common_vendor.e({
  454. a: common_vendor.f(uploadFiles.value, (file, index, i0) => {
  455. return common_vendor.e({
  456. a: isImage(file)
  457. }, isImage(file) ? {
  458. b: file.url,
  459. c: _ctx.imageMode,
  460. d: common_vendor.o(($event) => onPreviewImage(file), index)
  461. } : isVideo(file) ? common_vendor.e({
  462. f: file.thumb
  463. }, file.thumb ? {
  464. g: file.thumb,
  465. h: _ctx.imageMode,
  466. i: "7c014dc0-0-" + i0,
  467. j: common_vendor.p({
  468. name: "play-circle-filled",
  469. ["custom-class"]: "wd-upload__video-paly"
  470. }),
  471. k: common_vendor.o(($event) => onPreviewVideo(file), index)
  472. } : {
  473. l: file.url,
  474. m: file.name || "视频" + index,
  475. n: file.thumb,
  476. o: "7c014dc0-1-" + i0,
  477. p: common_vendor.p({
  478. name: "play-circle-filled",
  479. ["custom-class"]: "wd-upload__video-paly"
  480. }),
  481. q: common_vendor.o(($event) => onPreviewVideo(file), index)
  482. }) : {
  483. r: "7c014dc0-2-" + i0,
  484. s: common_vendor.p({
  485. name: "file",
  486. ["custom-class"]: "wd-upload__file-icon"
  487. }),
  488. t: common_vendor.t(file.name || file.url),
  489. v: common_vendor.o(($event) => onPreviewFile(file), index)
  490. }, {
  491. e: isVideo(file),
  492. w: file[props.statusKey] !== "success"
  493. }, file[props.statusKey] !== "success" ? common_vendor.e({
  494. x: file[props.statusKey] === "loading"
  495. }, file[props.statusKey] === "loading" ? {
  496. y: "7c014dc0-3-" + i0,
  497. z: common_vendor.p({
  498. type: _ctx.loadingType,
  499. size: _ctx.loadingSize,
  500. color: _ctx.loadingColor
  501. }),
  502. A: common_vendor.t(file.percent)
  503. } : {}, {
  504. B: file[props.statusKey] === "fail"
  505. }, file[props.statusKey] === "fail" ? {
  506. C: "7c014dc0-4-" + i0,
  507. D: common_vendor.p({
  508. name: "close-outline",
  509. ["custom-class"]: "wd-upload__icon"
  510. }),
  511. E: common_vendor.t(file.error || common_vendor.unref(translate)("error"))
  512. } : {}) : {}, {
  513. F: file[props.statusKey] !== "loading" && !_ctx.disabled
  514. }, file[props.statusKey] !== "loading" && !_ctx.disabled ? {
  515. G: common_vendor.o(($event) => removeFile(index), index),
  516. H: "7c014dc0-5-" + i0,
  517. I: common_vendor.p({
  518. name: "error-fill",
  519. ["custom-class"]: "wd-upload__close"
  520. })
  521. } : {}, _ctx.$slots["preview-cover"] ? {
  522. J: "preview-cover-" + i0,
  523. K: common_vendor.r("preview-cover", {
  524. file,
  525. index
  526. }, i0)
  527. } : {}, {
  528. L: index
  529. });
  530. }),
  531. b: _ctx.$slots["preview-cover"],
  532. c: common_vendor.n(_ctx.customPreviewClass),
  533. d: showUpload.value
  534. }, showUpload.value ? common_vendor.e({
  535. e: _ctx.$slots.default
  536. }, _ctx.$slots.default ? {
  537. f: common_vendor.n(_ctx.customEvokeClass),
  538. g: common_vendor.o(handleChoose)
  539. } : common_vendor.e({
  540. h: common_vendor.p({
  541. name: "fill-camera"
  542. }),
  543. i: _ctx.limit && _ctx.showLimitNum
  544. }, _ctx.limit && _ctx.showLimitNum ? {
  545. j: common_vendor.t(uploadFiles.value.length),
  546. k: common_vendor.t(_ctx.limit)
  547. } : {}, {
  548. l: common_vendor.o(handleChoose),
  549. m: common_vendor.n(_ctx.disabled ? "is-disabled" : ""),
  550. n: common_vendor.n(_ctx.customEvokeClass)
  551. })) : {}, {
  552. o: common_vendor.n(_ctx.customClass),
  553. p: common_vendor.s(_ctx.customStyle),
  554. q: common_vendor.sr(videoPreview, "7c014dc0-7", {
  555. "k": "videoPreview"
  556. })
  557. });
  558. };
  559. }
  560. });
  561. const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-7c014dc0"]]);
  562. wx.createComponent(Component);