s-uploader.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. "use strict";
  2. const common_vendor = require("../../../common/vendor.js");
  3. const sheep_components_sUploader_chooseAndUploadFile = require("./choose-and-upload-file.js");
  4. const sheep_components_sUploader_utils = require("./utils.js");
  5. const sheep_index = require("../../index.js");
  6. require("../../api/infra/file.js");
  7. require("../../config/index.js");
  8. require("../../request/index.js");
  9. require("../../store/index.js");
  10. require("../../store/app.js");
  11. require("../../api/promotion/diy.js");
  12. require("../../platform/index.js");
  13. require("../../platform/provider/wechat/index.js");
  14. require("../../platform/provider/wechat/miniProgram.js");
  15. require("../../api/member/auth.js");
  16. require("../../api/member/social.js");
  17. require("../../api/member/user.js");
  18. require("../../platform/provider/apple/index.js");
  19. require("../../platform/share.js");
  20. require("../../router/index.js");
  21. require("../../hooks/useModal.js");
  22. require("../../helper/index.js");
  23. require("../../helper/test.js");
  24. require("../../helper/digit.js");
  25. require("../../api/member/signin.js");
  26. require("../../helper/throttle.js");
  27. require("../../url/index.js");
  28. require("../../platform/pay.js");
  29. require("../../api/pay/order.js");
  30. require("../../store/user.js");
  31. require("../../store/cart.js");
  32. require("../../api/trade/cart.js");
  33. require("../../api/pay/wallet.js");
  34. require("../../api/trade/order.js");
  35. require("../../api/promotion/coupon.js");
  36. require("../../store/sys.js");
  37. require("../../store/modal.js");
  38. require("../../api/index.js");
  39. require("../../api/distri/score.js");
  40. require("../../api/distri/share.js");
  41. require("../../api/distri/team.js");
  42. require("../../api/member/address.js");
  43. require("../../api/member/point.js");
  44. require("../../api/migration/app.js");
  45. require("../../api/migration/chat.js");
  46. require("../../api/migration/index.js");
  47. require("../../api/migration/third.js");
  48. require("../../api/pay/channel.js");
  49. require("../../api/product/category.js");
  50. require("../../api/product/comment.js");
  51. require("../../api/product/favorite.js");
  52. require("../../api/product/history.js");
  53. require("../../api/product/spu.js");
  54. require("../../api/promotion/activity.js");
  55. require("../../api/promotion/article.js");
  56. require("../../api/promotion/bargain.js");
  57. require("../../api/promotion/combination.js");
  58. require("../../api/promotion/rewardActivity.js");
  59. require("../../api/promotion/seckill.js");
  60. require("../../api/system/area.js");
  61. require("../../api/system/voice.js");
  62. require("../../api/trade/afterSale.js");
  63. require("../../api/trade/brokerage.js");
  64. require("../../api/trade/config.js");
  65. require("../../api/trade/delivery.js");
  66. require("../../config/zIndex.js");
  67. const uploadImage = () => "./upload-image.js";
  68. const uploadFile = () => "./upload-file.js";
  69. const _sfc_main = {
  70. name: "sUploader",
  71. components: {
  72. uploadImage,
  73. uploadFile
  74. },
  75. options: {
  76. virtualHost: true
  77. },
  78. emits: ["select", "success", "fail", "progress", "delete", "update:modelValue", "update:url"],
  79. props: {
  80. modelValue: {
  81. type: [Array, Object],
  82. default() {
  83. return [];
  84. }
  85. },
  86. url: {
  87. type: [Array, String],
  88. default() {
  89. return [];
  90. }
  91. },
  92. disabled: {
  93. type: Boolean,
  94. default: false
  95. },
  96. disablePreview: {
  97. type: Boolean,
  98. default: false
  99. },
  100. delIcon: {
  101. type: Boolean,
  102. default: true
  103. },
  104. // 自动上传
  105. autoUpload: {
  106. type: Boolean,
  107. default: true
  108. },
  109. // 最大选择个数 ,h5只能限制单选或是多选
  110. limit: {
  111. type: [Number, String],
  112. default: 9
  113. },
  114. // 列表样式 grid | list | list-card
  115. mode: {
  116. type: String,
  117. default: "grid"
  118. },
  119. // 选择文件类型 image/video/all
  120. fileMediatype: {
  121. type: String,
  122. default: "image"
  123. },
  124. // 文件类型筛选
  125. fileExtname: {
  126. type: [Array, String],
  127. default() {
  128. return [];
  129. }
  130. },
  131. title: {
  132. type: String,
  133. default: ""
  134. },
  135. listStyles: {
  136. type: Object,
  137. default() {
  138. return {
  139. // 是否显示边框
  140. border: true,
  141. // 是否显示分隔线
  142. dividline: true,
  143. // 线条样式
  144. borderStyle: {}
  145. };
  146. }
  147. },
  148. imageStyles: {
  149. type: Object,
  150. default() {
  151. return {
  152. width: "auto",
  153. height: "auto"
  154. };
  155. }
  156. },
  157. readonly: {
  158. type: Boolean,
  159. default: false
  160. },
  161. sizeType: {
  162. type: Array,
  163. default() {
  164. return ["original", "compressed"];
  165. }
  166. },
  167. driver: {
  168. type: String,
  169. default: "local"
  170. // local=本地 | oss | unicloud
  171. },
  172. subtitle: {
  173. type: String,
  174. default: ""
  175. }
  176. },
  177. data() {
  178. return {
  179. files: [],
  180. localValue: [],
  181. imgsrc: sheep_index.sheep.$url.static("/static/images/upload-camera.png")
  182. };
  183. },
  184. watch: {
  185. modelValue: {
  186. handler(newVal, oldVal) {
  187. this.setValue(newVal, oldVal);
  188. },
  189. immediate: true
  190. }
  191. },
  192. computed: {
  193. returnType() {
  194. if (this.limit > 1) {
  195. return "array";
  196. }
  197. return "object";
  198. },
  199. filesList() {
  200. let files = [];
  201. this.files.forEach((v) => {
  202. files.push(v);
  203. });
  204. return files;
  205. },
  206. showType() {
  207. if (this.fileMediatype === "image") {
  208. return this.mode;
  209. }
  210. return "list";
  211. },
  212. limitLength() {
  213. if (this.returnType === "object") {
  214. return 1;
  215. }
  216. if (!this.limit) {
  217. return 1;
  218. }
  219. if (this.limit >= 9) {
  220. return 9;
  221. }
  222. return this.limit;
  223. }
  224. },
  225. created() {
  226. if (this.driver === "local") {
  227. common_vendor.Ws.chooseAndUploadFile = sheep_components_sUploader_chooseAndUploadFile.chooseAndUploadFile;
  228. }
  229. this.form = this.getForm("uniForms");
  230. this.formItem = this.getForm("uniFormsItem");
  231. if (this.form && this.formItem) {
  232. if (this.formItem.name) {
  233. this.rename = this.formItem.name;
  234. this.form.inputChildrens.push(this);
  235. }
  236. }
  237. },
  238. methods: {
  239. /**
  240. * 公开用户使用,清空文件
  241. * @param {Object} index
  242. */
  243. clearFiles(index) {
  244. if (index !== 0 && !index) {
  245. this.files = [];
  246. this.$nextTick(() => {
  247. this.setEmit();
  248. });
  249. } else {
  250. this.files.splice(index, 1);
  251. }
  252. this.$nextTick(() => {
  253. this.setEmit();
  254. });
  255. },
  256. /**
  257. * 公开用户使用,继续上传
  258. */
  259. upload() {
  260. let files = [];
  261. this.files.forEach((v, index) => {
  262. if (v.status === "ready" || v.status === "error") {
  263. files.push(Object.assign({}, v));
  264. }
  265. });
  266. return this.uploadFiles(files);
  267. },
  268. async setValue(newVal, oldVal) {
  269. const newData = async (v) => {
  270. const reg = /cloud:\/\/([\w.]+\/?)\S*/;
  271. let url = "";
  272. if (v.fileID) {
  273. url = v.fileID;
  274. } else {
  275. url = v.url;
  276. }
  277. if (reg.test(url)) {
  278. v.fileID = url;
  279. v.url = await this.getTempFileURL(url);
  280. }
  281. if (v.url)
  282. v.path = v.url;
  283. return v;
  284. };
  285. if (this.returnType === "object") {
  286. if (newVal) {
  287. await newData(newVal);
  288. } else {
  289. newVal = {};
  290. }
  291. } else {
  292. if (!newVal)
  293. newVal = [];
  294. for (let i = 0; i < newVal.length; i++) {
  295. let v = newVal[i];
  296. await newData(v);
  297. }
  298. }
  299. this.localValue = newVal;
  300. if (this.form && this.formItem && !this.is_reset) {
  301. this.is_reset = false;
  302. this.formItem.setValue(this.localValue);
  303. }
  304. let filesData = Object.keys(newVal).length > 0 ? newVal : [];
  305. this.files = [].concat(filesData);
  306. },
  307. /**
  308. * 选择文件
  309. */
  310. choose() {
  311. if (this.disabled)
  312. return;
  313. if (this.files.length >= Number(this.limitLength) && this.showType !== "grid" && this.returnType === "array") {
  314. common_vendor.index.showToast({
  315. title: `您最多选择 ${this.limitLength} 个文件`,
  316. icon: "none"
  317. });
  318. return;
  319. }
  320. this.chooseFiles();
  321. },
  322. /**
  323. * 选择文件并上传
  324. */
  325. chooseFiles() {
  326. const _extname = sheep_components_sUploader_utils.get_extname(this.fileExtname);
  327. common_vendor.Ws.chooseAndUploadFile({
  328. type: this.fileMediatype,
  329. compressed: false,
  330. sizeType: this.sizeType,
  331. // TODO 如果为空,video 有问题
  332. extension: _extname.length > 0 ? _extname : void 0,
  333. count: this.limitLength - this.files.length,
  334. //默认9
  335. onChooseFile: this.chooseFileCallback,
  336. onUploadProgress: (progressEvent) => {
  337. this.setProgress(progressEvent, progressEvent.index);
  338. }
  339. }).then((result) => {
  340. this.setSuccessAndError(result.tempFiles);
  341. }).catch((err) => {
  342. console.log("选择失败", err);
  343. });
  344. },
  345. /**
  346. * 选择文件回调
  347. * @param {Object} res
  348. */
  349. async chooseFileCallback(res) {
  350. const _extname = sheep_components_sUploader_utils.get_extname(this.fileExtname);
  351. const is_one = Number(this.limitLength) === 1 && this.disablePreview && !this.disabled || this.returnType === "object";
  352. if (is_one) {
  353. this.files = [];
  354. }
  355. let { filePaths, files } = sheep_components_sUploader_utils.get_files_and_is_max(res, _extname);
  356. if (!(_extname && _extname.length > 0)) {
  357. filePaths = res.tempFilePaths;
  358. files = res.tempFiles;
  359. }
  360. let currentData = [];
  361. for (let i = 0; i < files.length; i++) {
  362. if (this.limitLength - this.files.length <= 0)
  363. break;
  364. files[i].uuid = Date.now();
  365. let filedata = await sheep_components_sUploader_utils.get_file_data(files[i], this.fileMediatype);
  366. filedata.progress = 0;
  367. filedata.status = "ready";
  368. this.files.push(filedata);
  369. currentData.push({
  370. ...filedata,
  371. file: files[i]
  372. });
  373. }
  374. this.$emit("select", {
  375. tempFiles: currentData,
  376. tempFilePaths: filePaths
  377. });
  378. res.tempFiles = files;
  379. if (!this.autoUpload) {
  380. res.tempFiles = [];
  381. }
  382. },
  383. /**
  384. * 批传
  385. * @param {Object} e
  386. */
  387. uploadFiles(files) {
  388. files = [].concat(files);
  389. return sheep_components_sUploader_chooseAndUploadFile.uploadCloudFiles.call(this, files, 5, (res) => {
  390. this.setProgress(res, res.index, true);
  391. }).then((result) => {
  392. this.setSuccessAndError(result);
  393. return result;
  394. }).catch((err) => {
  395. console.log(err);
  396. });
  397. },
  398. /**
  399. * 成功或失败
  400. */
  401. async setSuccessAndError(res, fn) {
  402. let successData = [];
  403. let errorData = [];
  404. let tempFilePath = [];
  405. let errorTempFilePath = [];
  406. for (let i = 0; i < res.length; i++) {
  407. const item = res[i];
  408. const index = item.uuid ? this.files.findIndex((p) => p.uuid === item.uuid) : item.index;
  409. if (index === -1 || !this.files)
  410. break;
  411. if (item.errMsg === "request:fail") {
  412. this.files[index].url = item.path;
  413. this.files[index].status = "error";
  414. this.files[index].errMsg = item.errMsg;
  415. errorData.push(this.files[index]);
  416. errorTempFilePath.push(this.files[index].url);
  417. } else {
  418. this.files[index].errMsg = "";
  419. this.files[index].fileID = item.url;
  420. const reg = /cloud:\/\/([\w.]+\/?)\S*/;
  421. if (reg.test(item.url)) {
  422. this.files[index].url = await this.getTempFileURL(item.url);
  423. } else {
  424. this.files[index].url = item.url;
  425. }
  426. this.files[index].status = "success";
  427. this.files[index].progress += 1;
  428. successData.push(this.files[index]);
  429. tempFilePath.push(this.files[index].fileID);
  430. }
  431. }
  432. if (successData.length > 0) {
  433. this.setEmit();
  434. this.$emit("success", {
  435. tempFiles: this.backObject(successData),
  436. tempFilePaths: tempFilePath
  437. });
  438. }
  439. if (errorData.length > 0) {
  440. this.$emit("fail", {
  441. tempFiles: this.backObject(errorData),
  442. tempFilePaths: errorTempFilePath
  443. });
  444. }
  445. },
  446. /**
  447. * 获取进度
  448. * @param {Object} progressEvent
  449. * @param {Object} index
  450. * @param {Object} type
  451. */
  452. setProgress(progressEvent, index, type) {
  453. this.files.length;
  454. const percentCompleted = Math.round(progressEvent.loaded * 100 / progressEvent.total);
  455. let idx = index;
  456. if (!type) {
  457. idx = this.files.findIndex((p) => p.uuid === progressEvent.tempFile.uuid);
  458. }
  459. if (idx === -1 || !this.files[idx])
  460. return;
  461. this.files[idx].progress = percentCompleted - 1;
  462. this.$emit("progress", {
  463. index: idx,
  464. progress: parseInt(percentCompleted),
  465. tempFile: this.files[idx]
  466. });
  467. },
  468. /**
  469. * 删除文件
  470. * @param {Object} index
  471. */
  472. delFile(index) {
  473. this.$emit("delete", {
  474. tempFile: this.files[index],
  475. tempFilePath: this.files[index].url
  476. });
  477. this.files.splice(index, 1);
  478. this.$nextTick(() => {
  479. this.setEmit();
  480. });
  481. },
  482. /**
  483. * 获取文件名和后缀
  484. * @param {Object} name
  485. */
  486. getFileExt(name) {
  487. const last_len = name.lastIndexOf(".");
  488. const len = name.length;
  489. return {
  490. name: name.substring(0, last_len),
  491. ext: name.substring(last_len + 1, len)
  492. };
  493. },
  494. /**
  495. * 处理返回事件
  496. */
  497. setEmit() {
  498. let data = [];
  499. let updateUrl = [];
  500. if (this.returnType === "object") {
  501. data = this.backObject(this.files)[0];
  502. this.localValue = data ? data : null;
  503. updateUrl = data ? data.url : "";
  504. } else {
  505. data = this.backObject(this.files);
  506. if (!this.localValue) {
  507. this.localValue = [];
  508. }
  509. this.localValue = [...data];
  510. if (this.localValue.length > 0) {
  511. this.localValue.forEach((item) => {
  512. updateUrl.push(item.url);
  513. });
  514. }
  515. }
  516. this.$emit("update:modelValue", this.localValue);
  517. this.$emit("update:url", updateUrl);
  518. },
  519. /**
  520. * 处理返回参数
  521. * @param {Object} files
  522. */
  523. backObject(files) {
  524. let newFilesData = [];
  525. files.forEach((v) => {
  526. newFilesData.push({
  527. extname: v.extname,
  528. fileType: v.fileType,
  529. image: v.image,
  530. name: v.name,
  531. path: v.path,
  532. size: v.size,
  533. fileID: v.fileID,
  534. url: v.url
  535. });
  536. });
  537. return newFilesData;
  538. },
  539. async getTempFileURL(fileList) {
  540. fileList = {
  541. fileList: [].concat(fileList)
  542. };
  543. const urls = await common_vendor.Ws.getTempFileURL(fileList);
  544. return urls.fileList[0].tempFileURL || "";
  545. },
  546. /**
  547. * 获取父元素实例
  548. */
  549. getForm(name = "uniForms") {
  550. let parent = this.$parent;
  551. let parentName = parent.$options.name;
  552. while (parentName !== name) {
  553. parent = parent.$parent;
  554. if (!parent)
  555. return false;
  556. parentName = parent.$options.name;
  557. }
  558. return parent;
  559. }
  560. }
  561. };
  562. if (!Array) {
  563. const _component_upload_image = common_vendor.resolveComponent("upload-image");
  564. const _component_upload_file = common_vendor.resolveComponent("upload-file");
  565. (_component_upload_image + _component_upload_file)();
  566. }
  567. function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  568. return common_vendor.e({
  569. a: $props.title
  570. }, $props.title ? {
  571. b: common_vendor.t($props.title),
  572. c: common_vendor.t($options.filesList.length),
  573. d: common_vendor.t($options.limitLength)
  574. } : {}, {
  575. e: $props.subtitle
  576. }, $props.subtitle ? {
  577. f: common_vendor.t($props.subtitle)
  578. } : {}, {
  579. g: $props.fileMediatype === "image" && $options.showType === "grid"
  580. }, $props.fileMediatype === "image" && $options.showType === "grid" ? {
  581. h: $data.imgsrc,
  582. i: common_vendor.o($options.uploadFiles),
  583. j: common_vendor.o($options.choose),
  584. k: common_vendor.o($options.delFile),
  585. l: common_vendor.p({
  586. readonly: $props.readonly,
  587. ["image-styles"]: $props.imageStyles,
  588. ["files-list"]: $props.url,
  589. limit: $options.limitLength,
  590. disablePreview: $props.disablePreview,
  591. delIcon: $props.delIcon
  592. })
  593. } : {}, {
  594. m: $props.fileMediatype !== "image" || $options.showType !== "grid"
  595. }, $props.fileMediatype !== "image" || $options.showType !== "grid" ? {
  596. n: common_vendor.o($options.uploadFiles),
  597. o: common_vendor.o($options.choose),
  598. p: common_vendor.o($options.delFile),
  599. q: common_vendor.p({
  600. readonly: $props.readonly,
  601. ["list-styles"]: $props.listStyles,
  602. ["files-list"]: $options.filesList,
  603. showType: $options.showType,
  604. delIcon: $props.delIcon
  605. })
  606. } : {});
  607. }
  608. const Component = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-82f430bc"], ["__file", "D:/zx/mall-front-app/sheep/components/s-uploader/s-uploader.vue"]]);
  609. wx.createComponent(Component);