s-uploader.js 16 KB

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