s-uploader.js 16 KB

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