@fengzhongwen/kukan-ui 1.0.21 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["webpack://kukan-ui/webpack/bootstrap","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue?458d","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue?ee3c","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue?655f","webpack://kukan-ui/./node_modules/spark-md5/spark-md5.js","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue?1015","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue?1c0d","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue?e4c3","webpack://kukan-ui/./src/components/FileUpload/index.vue?3c8f","webpack://kukan-ui/./src/components/FileUpload/index.vue?59bd","webpack://kukan-ui/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://kukan-ui/./src/components/FileUpload/api.js","webpack://kukan-ui/./src/components/FileUpload/index.vue?05cf","webpack://kukan-ui/./src/components/FileUpload/util.js","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue?9223","webpack://kukan-ui/src/components/FileUpload/components/UploadCard_Ver_Second/index.vue","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue?e145","webpack://kukan-ui/./node_modules/vue-loader/lib/runtime/componentNormalizer.js","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue?069c","webpack://kukan-ui/src/components/FileUpload/components/Upload_table/index.vue","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue?cf02","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue","webpack://kukan-ui/./src/components/FileUpload/upload.js","webpack://kukan-ui/src/components/FileUpload/index.vue","webpack://kukan-ui/./src/components/FileUpload/index.vue?02c5","webpack://kukan-ui/./src/components/FileUpload/index.vue","webpack://kukan-ui/./src/components/FileUpload/index.js","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue?f739","webpack://kukan-ui/src/components/VideoPreviewDialog/index.vue","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue?333e","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue","webpack://kukan-ui/./src/index.js","webpack://kukan-ui/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js"],"names":[],"mappings":";;QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA,0CAA0C,gCAAgC;QAC1E;QACA;;QAEA;QACA;QACA;QACA,wDAAwD,kBAAkB;QAC1E;QACA,iDAAiD,cAAc;QAC/D;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,iCAAiC;QAC1E,gHAAgH,mBAAmB,EAAE;QACrI;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;;QAGA;QACA;;;;;;;;AClFA,uC;;;;;;;ACAA,uC;;;;;;;;ACAA;AAAA;AAAA;;;;;;;;ACAA;AACA,QAAQ,IAA2B;AACnC;AACA;AACA,KAAK,MAAM,aAcN;AACL,CAAC;;AAED;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;;AAGA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,cAAc;;AAEd,mBAAmB,QAAQ;AAC3B;AACA;AACA;AACA;;AAEA;AACA;AACA,cAAc;;AAEd,mBAAmB,QAAQ;AAC3B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,QAAQ;AAC5B;AACA;AACA;AACA;AACA;AACA,mBAAmB,YAAY;AAC/B;AACA;AACA;AACA;AACA;AACA,uBAAuB,QAAQ;AAC/B;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,IAAI;AAClD;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,QAAQ;AAC5B;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;AACA;AACA;AACA,uBAAuB,QAAQ;AAC/B;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,IAAI;AAClD;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA;AACA;AACA;;AAEA;AACA;AACA,mBAAmB,cAAc;AACjC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,SAAS;AACT;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,mBAAmB,gBAAgB;AACnC;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,OAAO;AACtB;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,eAAe,OAAO;AACtB;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;;AAEA;AACA;;AAEA,oBAAoB,aAAa;AACjC;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,OAAO;AACtB;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,MAAM;AACrB,eAAe,OAAO;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,uBAAuB,QAAQ;AAC/B;AACA;AACA;;AAEA;AACA;AACA;AACA,8CAA8C,IAAI;AAClD;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,OAAO;AACtB,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,OAAO;AACtB,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,YAAY;AAC3B;AACA,gBAAgB,qBAAqB;AACrC;AACA;AACA;AACA;AACA;;AAEA;;AAEA,oBAAoB,aAAa;AACjC;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,qBAAqB;AACrC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,eAAe,OAAO;AACtB;AACA,gBAAgB,qBAAqB;AACrC;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,eAAe,YAAY;AAC3B,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;;;;;;;;AC9uBD;AAAA;AAAA;;;;;;;;;ACAA;AAAA;AAAA;;;;;;;;ACAA,uC;;;;;;;;ACAA;AAAA;AAAA;;;;;;;;ACAA,uC;;;;;;;;;;;;;;;ACAA;;AAEA;AACA;AACA,MAAM,KAAuC,EAAE,yBAQ5C;;AAEH;AACA;AACA,IAAI,qBAAuB;AAC3B;AACA;;AAEA;AACe,sDAAI;;;ACrBnB;;AAEA;;AAEA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;;AC1JA,0BAA0B,aAAa,0BAA0B,wBAAwB,iBAAiB,8BAA8B,cAAc,sCAAsC,iBAAiB,QAAQ,iEAAiE,KAAK,0CAA0C,YAAY,kCAAkC,YAAY,6FAA6F,kEAAkE,wBAAwB,8BAA8B,8BAA8B,wBAAwB,+BAA+B,yBAAyB,wBAAwB,4BAA4B,8BAA8B,6EAA6E,+CAA+C,6BAA6B,6IAA6I,wCAAwC,YAAY,4CAA4C,yBAAyB,yBAAyB,kCAAkC,UAAU,4BAA4B,cAAc,OAAO,6DAA6D,2DAA2D,mCAAmC,mFAAmF,KAAK,sCAAsC,oEAAoE,oCAAoC,qBAAqB,OAAO,uJAAuJ,KAAK,0KAA0K,gDAAgD,mCAAmC,aAAa,wBAAwB,aAAa,oBAAoB,8CAA8C,OAAO,wCAAwC,gDAAgD,6BAA6B,YAAY,mBAAmB,uFAAuF,OAAO,mCAAmC,sEAAsE,OAAO,yBAAyB,sEAAsE,OAAO,yBAAyB,kHAAkH,OAAO,0FAA0F,KAAK,iCAAiC,qCAAqC,OAAO,gGAAgG,KAAK,+BAA+B,qCAAqC,iCAAiC,gDAAgD,4BAA4B,sDAAsD,oBAAoB,iBAAiB,iCAAiC,KAAK,6HAA6H,EAAE,eAAe,sBAAsB,UAAU,+BAA+B;AACpkH;;;;;;ACDA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,E;;ACvEA,IAAI,qEAAM,gBAAgB,aAAa,0BAA0B,wBAAwB,iBAAiB;AAC1G;AACA;AACA,GAAG,KAAK,yBAAyB,iDAAiD,YAAY,4BAA4B,YAAY,wBAAwB,2EAA2E,wBAAwB,oDAAoD,+BAA+B,YAAY,qBAAqB,YAAY,0BAA0B,aAAa,iDAAiD;AACzd;AACA,oBAAoB,8BAA8B,yBAAyB,yBAAyB,8CAA8C,eAAe,OAAO,+BAA+B;AACvM;AACA;AACA;AACA,oBAAoB,8BAA8B,yBAAyB,yBAAyB,6CAA6C,eAAe,OAAO,yBAAyB,wPAAwP,4BAA4B,oBAAoB,qCAAqC,iFAAiF;AAC9lB,IAAI,8EAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC0DJ;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;ACzI6L,CAAgB,wIAAG,EAAC,C;;;;;ACAnN;;AAEA;AACA;AACA;;AAEe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;AC/F+F;AACvC;AACL;AAC2C;;;AAG9F;AACmG;AACnG,gBAAgB,kBAAU;AAC1B,EAAE,uDAAM;AACR,EAAE,qEAAM;AACR,EAAE,8EAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,2E;;ACnBf,IAAI,4DAAM,gBAAgB,aAAa,0BAA0B,wBAAwB,iBAAiB,2BAA2B,YAAY,qBAAqB,YAAY,oBAAoB,sHAAsH,OAAO,yBAAyB,iEAAiE,sBAAsB,kBAAkB,OAAO,gGAAgG,KAAK,yBAAyB,mCAAmC,wCAAwC,aAAa,eAAe,QAAQ,8CAA8C,wCAAwC,8BAA8B,KAAK,iFAAiF,wBAAwB,OAAO,iCAAiC,wBAAwB,OAAO,6BAA6B,wBAAwB,OAAO,4BAA4B,sBAAsB,iCAAiC,kBAAkB,wBAAwB,YAAY,wBAAwB,uEAAuE,6BAA6B,uCAAuC,GAAG,wBAAwB,OAAO,2BAA2B,sBAAsB,iCAAiC,kBAAkB,wBAAwB,aAAa,6BAA6B,uEAAuE,GAAG,wBAAwB,OAAO,2BAA2B,sBAAsB,iCAAiC,kBAAkB,0BAA0B,aAAa,4CAA4C,sCAAsC,GAAG,wBAAwB,OAAO,4BAA4B,sBAAsB,iCAAiC,kBAAkB,4BAA4B,oBAAoB,qCAAqC,2EAA2E,QAAQ,GAAG,wBAAwB,OAAO,4BAA4B,sBAAsB,iCAAiC,4CAA4C,8BAA8B,yBAAyB,yBAAyB,yCAAyC,aAAa,aAAa,sCAAsC;AACj+E;AACA;AACA;AACA,sBAAsB,8BAA8B,yBAAyB,yBAAyB,wCAAwC,aAAa,aAAa,sCAAsC,8BAA8B,GAAG;AAC/O,IAAI,qEAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC4FJ;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,CAAC,EAAC;;;AClL6L,CAAgB,sHAAG,EAAC,C;;;;;ACApH;AACvC;AACL;AAC2C;;;AAG9F;AACmG;AACnG,IAAI,sBAAS,GAAG,kBAAU;AAC1B,EAAE,8CAAM;AACR,EAAE,4DAAM;AACR,EAAE,qEAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,uEAAS,Q;;;;;;ACnBS;AACO;;AAExC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA,KAAK;AACL;AACe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,eAAe;;AAEvB;;AAEA,iBAAiB,qBAAqB;AACtC;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,yBAAyB,4BAA4B;AACrD;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,iBAAiB;AACjB,uBAAuB;AACvB,sBAAsB;AACtB,sBAAsB;AACtB,uBAAuB;AACvB,0BAA0B;;AAE1B,oBAAoB;AACpB,yBAAyB;AACzB,qBAAqB;;AAErB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA,8DAA8D;;AAE9D;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA,OAAO;AACP;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,oBAAoB,qDAAqD;AACzE;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC;AACpC;AACA,aAAa;AACb;AACA;AACA;AACA,aAAa;AACb,SAAS;AACT,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA,aAAa,4BAA4B;;AAEzC;;AAEA,UAAU,+BAA+B;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,WAAW;AACX;AACA,0BAA0B;AAC1B;;AAEA,6BAA6B,4BAA4B,EAAE;;AAE3D;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,8BAA8B;AAC9B;AACA;;AAEA;AACA,SAAS;AACT;AACA;AACA;AACA,wBAAwB;AACxB;AACA,2BAA2B,4BAA4B,EAAE;;AAEzD;AACA;AACA,SAAS;AACT;AACA;AACA,4BAA4B;AAC5B,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,oBAAoB,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO;;AAElE;AACA;AACA;;AAEA;AACA;AACA,SAAS,yCAAyC;AAClD;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA,8BAA8B,2BAAoB;AAClD,cAAc;AACd,KAAK;AACL,cAAc;AACd;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA,sBAAsB,mBAAmB;AACzC;AACA;;AAEA;AACA;AACA,OAAO,yCAAyC;AAChD;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,sBAAsB,mBAAmB;AACzC;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA,oBAAoB,mBAAQ;AAC5B;AACA;;AAEA,iBAAiB,YAAY;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd,gBAAgB;;AAEhB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA,qBAAqB;AACrB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,sBAAsB,mBAAQ;;AAE9B;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,mCAAmC,4BAAqB;AACxD;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA,WAAW;AACX;AACA,SAAS;AACT,OAAO;;AAEP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,wCAAwC,uBAAuB;AAC/D;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB,cAAc;AACd;;AAEA;AACA;AACA;AACA,gBAAgB;AAChB;AACA,YAAY;AACZ;AACA;AACA;AACA,cAAc;AACd;AACA,UAAU;;AAEV;;AAEA;;AAEA;AACA;;AAEA,YAAY;AACZ,GAAG;;AAEH;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA,eAAe,4BAAqB;AACpC;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,2BAA2B,sBAAe;AAC1C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,eAAe,sBAAe;AAC9B;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA,eAAe,2BAAoB;AACnC;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA,aAAa;AACb;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACn4B+C;AACmB;AACH;AACV;;AAEtC;AACf;AACA;AACA,IAAI,6BAAM;AACV,IAAI,0BAAY;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,0BAA0B,gDAAW;;AAErC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,6BAA6B,0BAA0B;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,kCAAkC,gDAAW;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;ACt7BiL,CAAgB,kHAAG,EAAC,C;;;;;ACAxG;AACvC;AACL;AAC2C;;;AAG9F;AAC6F;AAC7F,IAAI,oBAAS,GAAG,kBAAU;AAC1B,EAAE,4CAAM;AACR,EAAE,MAAM;AACR,EAAE,eAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,mEAAS,Q;;ACnBS;;AAEjC;AACA,UAAM;AACN,gBAAgB,UAAM,OAAO,UAAM;AACnC;;AAEe,oEAAM,E;;ACPrB,IAAI,kEAAM,gBAAgB,aAAa,0BAA0B,wBAAwB,uBAAuB,OAAO,kMAAkM,KAAK,kCAAkC,yBAAyB,wBAAwB,YAAY,6CAA6C,qBAAqB,MAAM,yEAAyE,YAAY,kCAAkC,YAAY,wBAAwB,aAAa,+BAA+B,sBAAsB,yGAAyG,wBAAwB,4HAA4H,oCAAoC,eAAe,sCAAsC,qCAAqC,KAAK,qBAAqB,UAAU,+BAA+B,eAAe,2BAA2B,iEAAiE,sCAAsC,qCAAqC,KAAK,oBAAoB,UAAU,8BAA8B,cAAc,8BAA8B,eAAe,sCAAsC,oBAAoB,KAAK,uBAAuB,UAAU,oCAAoC,iBAAiB,6CAA6C,0BAA0B,UAAU,4BAA4B,kBAAkB,uCAAuC,yBAAyB,wBAAwB,+BAA+B,8BAA8B,2CAA2C,aAAa,EAAE,6BAA6B,2BAA2B,wCAAwC,mBAAmB,OAAO,eAAe,4CAA4C,6BAA6B,UAAU,8BAA8B,sEAAsE,mCAAmC,UAAU,mCAAmC,kDAAkD,aAAa,wGAAwG,mEAAmE,2BAA2B,6BAA6B,2EAA2E,qFAAqF,WAAW,aAAa,KAAK,sFAAsF,2BAA2B,gCAAgC;AACr5F,IAAI,2EAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACyGJ;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;AC3QiL,CAAgB,kIAAG,EAAC,C;;;;;ACAxG;AACvC;AACL;AAC2C;;;AAG9F;AAC6F;AAC7F,IAAI,4BAAS,GAAG,kBAAU;AAC1B,EAAE,oDAAM;AACR,EAAE,kEAAM;AACR,EAAE,2EAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,mFAAS,Q;;ACnBuC;;AAElB;AACmB;;AAEhE;;AAEA;AACA,EAAE,qBAAM;AACR,EAAE,kBAAiB;AACnB;;AAEA;AACA,2CAA2C;AAC3C;AACA;AACA;AACA,GAAG;;AAEH;AACA,EAAE,gBAAgB;AAClB;;AAEA;AACA;AACA;AACA;;AAEA;AACe,2CAAC,UAAU,EAAC;AAC3B;;;AC9BwB;AACA;AACT,oFAAG;AACI","file":"kukan-ui.common.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"fb15\");\n","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","export * from \"-!../../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=style&index=0&id=419a04c7&prod&lang=scss&scoped=true\"","(function (factory) {\n if (typeof exports === 'object') {\n // Node/CommonJS\n module.exports = factory();\n } else if (typeof define === 'function' && define.amd) {\n // AMD\n define(factory);\n } else {\n // Browser globals (with support for web workers)\n var glob;\n\n try {\n glob = window;\n } catch (e) {\n glob = self;\n }\n\n glob.SparkMD5 = factory();\n }\n}(function (undefined) {\n\n 'use strict';\n\n /*\n * Fastest md5 implementation around (JKM md5).\n * Credits: Joseph Myers\n *\n * @see http://www.myersdaily.org/joseph/javascript/md5-text.html\n * @see http://jsperf.com/md5-shootout/7\n */\n\n /* this function is much faster,\n so if possible we use it. Some IEs\n are the only ones I know of that\n need the idiotic second function,\n generated by an if clause. */\n var add32 = function (a, b) {\n return (a + b) & 0xFFFFFFFF;\n },\n hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];\n\n\n function cmn(q, a, b, x, s, t) {\n a = add32(add32(a, q), add32(x, t));\n return add32((a << s) | (a >>> (32 - s)), b);\n }\n\n function md5cycle(x, k) {\n var a = x[0],\n b = x[1],\n c = x[2],\n d = x[3];\n\n a += (b & c | ~b & d) + k[0] - 680876936 | 0;\n a = (a << 7 | a >>> 25) + b | 0;\n d += (a & b | ~a & c) + k[1] - 389564586 | 0;\n d = (d << 12 | d >>> 20) + a | 0;\n c += (d & a | ~d & b) + k[2] + 606105819 | 0;\n c = (c << 17 | c >>> 15) + d | 0;\n b += (c & d | ~c & a) + k[3] - 1044525330 | 0;\n b = (b << 22 | b >>> 10) + c | 0;\n a += (b & c | ~b & d) + k[4] - 176418897 | 0;\n a = (a << 7 | a >>> 25) + b | 0;\n d += (a & b | ~a & c) + k[5] + 1200080426 | 0;\n d = (d << 12 | d >>> 20) + a | 0;\n c += (d & a | ~d & b) + k[6] - 1473231341 | 0;\n c = (c << 17 | c >>> 15) + d | 0;\n b += (c & d | ~c & a) + k[7] - 45705983 | 0;\n b = (b << 22 | b >>> 10) + c | 0;\n a += (b & c | ~b & d) + k[8] + 1770035416 | 0;\n a = (a << 7 | a >>> 25) + b | 0;\n d += (a & b | ~a & c) + k[9] - 1958414417 | 0;\n d = (d << 12 | d >>> 20) + a | 0;\n c += (d & a | ~d & b) + k[10] - 42063 | 0;\n c = (c << 17 | c >>> 15) + d | 0;\n b += (c & d | ~c & a) + k[11] - 1990404162 | 0;\n b = (b << 22 | b >>> 10) + c | 0;\n a += (b & c | ~b & d) + k[12] + 1804603682 | 0;\n a = (a << 7 | a >>> 25) + b | 0;\n d += (a & b | ~a & c) + k[13] - 40341101 | 0;\n d = (d << 12 | d >>> 20) + a | 0;\n c += (d & a | ~d & b) + k[14] - 1502002290 | 0;\n c = (c << 17 | c >>> 15) + d | 0;\n b += (c & d | ~c & a) + k[15] + 1236535329 | 0;\n b = (b << 22 | b >>> 10) + c | 0;\n\n a += (b & d | c & ~d) + k[1] - 165796510 | 0;\n a = (a << 5 | a >>> 27) + b | 0;\n d += (a & c | b & ~c) + k[6] - 1069501632 | 0;\n d = (d << 9 | d >>> 23) + a | 0;\n c += (d & b | a & ~b) + k[11] + 643717713 | 0;\n c = (c << 14 | c >>> 18) + d | 0;\n b += (c & a | d & ~a) + k[0] - 373897302 | 0;\n b = (b << 20 | b >>> 12) + c | 0;\n a += (b & d | c & ~d) + k[5] - 701558691 | 0;\n a = (a << 5 | a >>> 27) + b | 0;\n d += (a & c | b & ~c) + k[10] + 38016083 | 0;\n d = (d << 9 | d >>> 23) + a | 0;\n c += (d & b | a & ~b) + k[15] - 660478335 | 0;\n c = (c << 14 | c >>> 18) + d | 0;\n b += (c & a | d & ~a) + k[4] - 405537848 | 0;\n b = (b << 20 | b >>> 12) + c | 0;\n a += (b & d | c & ~d) + k[9] + 568446438 | 0;\n a = (a << 5 | a >>> 27) + b | 0;\n d += (a & c | b & ~c) + k[14] - 1019803690 | 0;\n d = (d << 9 | d >>> 23) + a | 0;\n c += (d & b | a & ~b) + k[3] - 187363961 | 0;\n c = (c << 14 | c >>> 18) + d | 0;\n b += (c & a | d & ~a) + k[8] + 1163531501 | 0;\n b = (b << 20 | b >>> 12) + c | 0;\n a += (b & d | c & ~d) + k[13] - 1444681467 | 0;\n a = (a << 5 | a >>> 27) + b | 0;\n d += (a & c | b & ~c) + k[2] - 51403784 | 0;\n d = (d << 9 | d >>> 23) + a | 0;\n c += (d & b | a & ~b) + k[7] + 1735328473 | 0;\n c = (c << 14 | c >>> 18) + d | 0;\n b += (c & a | d & ~a) + k[12] - 1926607734 | 0;\n b = (b << 20 | b >>> 12) + c | 0;\n\n a += (b ^ c ^ d) + k[5] - 378558 | 0;\n a = (a << 4 | a >>> 28) + b | 0;\n d += (a ^ b ^ c) + k[8] - 2022574463 | 0;\n d = (d << 11 | d >>> 21) + a | 0;\n c += (d ^ a ^ b) + k[11] + 1839030562 | 0;\n c = (c << 16 | c >>> 16) + d | 0;\n b += (c ^ d ^ a) + k[14] - 35309556 | 0;\n b = (b << 23 | b >>> 9) + c | 0;\n a += (b ^ c ^ d) + k[1] - 1530992060 | 0;\n a = (a << 4 | a >>> 28) + b | 0;\n d += (a ^ b ^ c) + k[4] + 1272893353 | 0;\n d = (d << 11 | d >>> 21) + a | 0;\n c += (d ^ a ^ b) + k[7] - 155497632 | 0;\n c = (c << 16 | c >>> 16) + d | 0;\n b += (c ^ d ^ a) + k[10] - 1094730640 | 0;\n b = (b << 23 | b >>> 9) + c | 0;\n a += (b ^ c ^ d) + k[13] + 681279174 | 0;\n a = (a << 4 | a >>> 28) + b | 0;\n d += (a ^ b ^ c) + k[0] - 358537222 | 0;\n d = (d << 11 | d >>> 21) + a | 0;\n c += (d ^ a ^ b) + k[3] - 722521979 | 0;\n c = (c << 16 | c >>> 16) + d | 0;\n b += (c ^ d ^ a) + k[6] + 76029189 | 0;\n b = (b << 23 | b >>> 9) + c | 0;\n a += (b ^ c ^ d) + k[9] - 640364487 | 0;\n a = (a << 4 | a >>> 28) + b | 0;\n d += (a ^ b ^ c) + k[12] - 421815835 | 0;\n d = (d << 11 | d >>> 21) + a | 0;\n c += (d ^ a ^ b) + k[15] + 530742520 | 0;\n c = (c << 16 | c >>> 16) + d | 0;\n b += (c ^ d ^ a) + k[2] - 995338651 | 0;\n b = (b << 23 | b >>> 9) + c | 0;\n\n a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;\n a = (a << 6 | a >>> 26) + b | 0;\n d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;\n d = (d << 10 | d >>> 22) + a | 0;\n c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;\n c = (c << 15 | c >>> 17) + d | 0;\n b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;\n b = (b << 21 |b >>> 11) + c | 0;\n a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;\n a = (a << 6 | a >>> 26) + b | 0;\n d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;\n d = (d << 10 | d >>> 22) + a | 0;\n c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;\n c = (c << 15 | c >>> 17) + d | 0;\n b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;\n b = (b << 21 |b >>> 11) + c | 0;\n a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;\n a = (a << 6 | a >>> 26) + b | 0;\n d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;\n d = (d << 10 | d >>> 22) + a | 0;\n c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;\n c = (c << 15 | c >>> 17) + d | 0;\n b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;\n b = (b << 21 |b >>> 11) + c | 0;\n a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;\n a = (a << 6 | a >>> 26) + b | 0;\n d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;\n d = (d << 10 | d >>> 22) + a | 0;\n c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;\n c = (c << 15 | c >>> 17) + d | 0;\n b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;\n b = (b << 21 | b >>> 11) + c | 0;\n\n x[0] = a + x[0] | 0;\n x[1] = b + x[1] | 0;\n x[2] = c + x[2] | 0;\n x[3] = d + x[3] | 0;\n }\n\n function md5blk(s) {\n var md5blks = [],\n i; /* Andy King said do it this way. */\n\n for (i = 0; i < 64; i += 4) {\n md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);\n }\n return md5blks;\n }\n\n function md5blk_array(a) {\n var md5blks = [],\n i; /* Andy King said do it this way. */\n\n for (i = 0; i < 64; i += 4) {\n md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);\n }\n return md5blks;\n }\n\n function md51(s) {\n var n = s.length,\n state = [1732584193, -271733879, -1732584194, 271733878],\n i,\n length,\n tail,\n tmp,\n lo,\n hi;\n\n for (i = 64; i <= n; i += 64) {\n md5cycle(state, md5blk(s.substring(i - 64, i)));\n }\n s = s.substring(i - 64);\n length = s.length;\n tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n for (i = 0; i < length; i += 1) {\n tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);\n }\n tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n if (i > 55) {\n md5cycle(state, tail);\n for (i = 0; i < 16; i += 1) {\n tail[i] = 0;\n }\n }\n\n // Beware that the final length might not fit in 32 bits so we take care of that\n tmp = n * 8;\n tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n lo = parseInt(tmp[2], 16);\n hi = parseInt(tmp[1], 16) || 0;\n\n tail[14] = lo;\n tail[15] = hi;\n\n md5cycle(state, tail);\n return state;\n }\n\n function md51_array(a) {\n var n = a.length,\n state = [1732584193, -271733879, -1732584194, 271733878],\n i,\n length,\n tail,\n tmp,\n lo,\n hi;\n\n for (i = 64; i <= n; i += 64) {\n md5cycle(state, md5blk_array(a.subarray(i - 64, i)));\n }\n\n // Not sure if it is a bug, however IE10 will always produce a sub array of length 1\n // containing the last element of the parent array if the sub array specified starts\n // beyond the length of the parent array - weird.\n // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue\n a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);\n\n length = a.length;\n tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n for (i = 0; i < length; i += 1) {\n tail[i >> 2] |= a[i] << ((i % 4) << 3);\n }\n\n tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n if (i > 55) {\n md5cycle(state, tail);\n for (i = 0; i < 16; i += 1) {\n tail[i] = 0;\n }\n }\n\n // Beware that the final length might not fit in 32 bits so we take care of that\n tmp = n * 8;\n tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n lo = parseInt(tmp[2], 16);\n hi = parseInt(tmp[1], 16) || 0;\n\n tail[14] = lo;\n tail[15] = hi;\n\n md5cycle(state, tail);\n\n return state;\n }\n\n function rhex(n) {\n var s = '',\n j;\n for (j = 0; j < 4; j += 1) {\n s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];\n }\n return s;\n }\n\n function hex(x) {\n var i;\n for (i = 0; i < x.length; i += 1) {\n x[i] = rhex(x[i]);\n }\n return x.join('');\n }\n\n // In some cases the fast add32 function cannot be used..\n if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592') {\n add32 = function (x, y) {\n var lsw = (x & 0xFFFF) + (y & 0xFFFF),\n msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n return (msw << 16) | (lsw & 0xFFFF);\n };\n }\n\n // ---------------------------------------------------\n\n /**\n * ArrayBuffer slice polyfill.\n *\n * @see https://github.com/ttaubert/node-arraybuffer-slice\n */\n\n if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {\n (function () {\n function clamp(val, length) {\n val = (val | 0) || 0;\n\n if (val < 0) {\n return Math.max(val + length, 0);\n }\n\n return Math.min(val, length);\n }\n\n ArrayBuffer.prototype.slice = function (from, to) {\n var length = this.byteLength,\n begin = clamp(from, length),\n end = length,\n num,\n target,\n targetArray,\n sourceArray;\n\n if (to !== undefined) {\n end = clamp(to, length);\n }\n\n if (begin > end) {\n return new ArrayBuffer(0);\n }\n\n num = end - begin;\n target = new ArrayBuffer(num);\n targetArray = new Uint8Array(target);\n\n sourceArray = new Uint8Array(this, begin, num);\n targetArray.set(sourceArray);\n\n return target;\n };\n })();\n }\n\n // ---------------------------------------------------\n\n /**\n * Helpers.\n */\n\n function toUtf8(str) {\n if (/[\\u0080-\\uFFFF]/.test(str)) {\n str = unescape(encodeURIComponent(str));\n }\n\n return str;\n }\n\n function utf8Str2ArrayBuffer(str, returnUInt8Array) {\n var length = str.length,\n buff = new ArrayBuffer(length),\n arr = new Uint8Array(buff),\n i;\n\n for (i = 0; i < length; i += 1) {\n arr[i] = str.charCodeAt(i);\n }\n\n return returnUInt8Array ? arr : buff;\n }\n\n function arrayBuffer2Utf8Str(buff) {\n return String.fromCharCode.apply(null, new Uint8Array(buff));\n }\n\n function concatenateArrayBuffers(first, second, returnUInt8Array) {\n var result = new Uint8Array(first.byteLength + second.byteLength);\n\n result.set(new Uint8Array(first));\n result.set(new Uint8Array(second), first.byteLength);\n\n return returnUInt8Array ? result : result.buffer;\n }\n\n function hexToBinaryString(hex) {\n var bytes = [],\n length = hex.length,\n x;\n\n for (x = 0; x < length - 1; x += 2) {\n bytes.push(parseInt(hex.substr(x, 2), 16));\n }\n\n return String.fromCharCode.apply(String, bytes);\n }\n\n // ---------------------------------------------------\n\n /**\n * SparkMD5 OOP implementation.\n *\n * Use this class to perform an incremental md5, otherwise use the\n * static methods instead.\n */\n\n function SparkMD5() {\n // call reset to init the instance\n this.reset();\n }\n\n /**\n * Appends a string.\n * A conversion will be applied if an utf8 string is detected.\n *\n * @param {String} str The string to be appended\n *\n * @return {SparkMD5} The instance itself\n */\n SparkMD5.prototype.append = function (str) {\n // Converts the string to utf8 bytes if necessary\n // Then append as binary\n this.appendBinary(toUtf8(str));\n\n return this;\n };\n\n /**\n * Appends a binary string.\n *\n * @param {String} contents The binary string to be appended\n *\n * @return {SparkMD5} The instance itself\n */\n SparkMD5.prototype.appendBinary = function (contents) {\n this._buff += contents;\n this._length += contents.length;\n\n var length = this._buff.length,\n i;\n\n for (i = 64; i <= length; i += 64) {\n md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));\n }\n\n this._buff = this._buff.substring(i - 64);\n\n return this;\n };\n\n /**\n * Finishes the incremental computation, reseting the internal state and\n * returning the result.\n *\n * @param {Boolean} raw True to get the raw string, false to get the hex string\n *\n * @return {String} The result\n */\n SparkMD5.prototype.end = function (raw) {\n var buff = this._buff,\n length = buff.length,\n i,\n tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n ret;\n\n for (i = 0; i < length; i += 1) {\n tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);\n }\n\n this._finish(tail, length);\n ret = hex(this._hash);\n\n if (raw) {\n ret = hexToBinaryString(ret);\n }\n\n this.reset();\n\n return ret;\n };\n\n /**\n * Resets the internal state of the computation.\n *\n * @return {SparkMD5} The instance itself\n */\n SparkMD5.prototype.reset = function () {\n this._buff = '';\n this._length = 0;\n this._hash = [1732584193, -271733879, -1732584194, 271733878];\n\n return this;\n };\n\n /**\n * Gets the internal state of the computation.\n *\n * @return {Object} The state\n */\n SparkMD5.prototype.getState = function () {\n return {\n buff: this._buff,\n length: this._length,\n hash: this._hash.slice()\n };\n };\n\n /**\n * Gets the internal state of the computation.\n *\n * @param {Object} state The state\n *\n * @return {SparkMD5} The instance itself\n */\n SparkMD5.prototype.setState = function (state) {\n this._buff = state.buff;\n this._length = state.length;\n this._hash = state.hash;\n\n return this;\n };\n\n /**\n * Releases memory used by the incremental buffer and other additional\n * resources. If you plan to use the instance again, use reset instead.\n */\n SparkMD5.prototype.destroy = function () {\n delete this._hash;\n delete this._buff;\n delete this._length;\n };\n\n /**\n * Finish the final calculation based on the tail.\n *\n * @param {Array} tail The tail (will be modified)\n * @param {Number} length The length of the remaining buffer\n */\n SparkMD5.prototype._finish = function (tail, length) {\n var i = length,\n tmp,\n lo,\n hi;\n\n tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n if (i > 55) {\n md5cycle(this._hash, tail);\n for (i = 0; i < 16; i += 1) {\n tail[i] = 0;\n }\n }\n\n // Do the final computation based on the tail and length\n // Beware that the final length may not fit in 32 bits so we take care of that\n tmp = this._length * 8;\n tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n lo = parseInt(tmp[2], 16);\n hi = parseInt(tmp[1], 16) || 0;\n\n tail[14] = lo;\n tail[15] = hi;\n md5cycle(this._hash, tail);\n };\n\n /**\n * Performs the md5 hash on a string.\n * A conversion will be applied if utf8 string is detected.\n *\n * @param {String} str The string\n * @param {Boolean} [raw] True to get the raw string, false to get the hex string\n *\n * @return {String} The result\n */\n SparkMD5.hash = function (str, raw) {\n // Converts the string to utf8 bytes if necessary\n // Then compute it using the binary function\n return SparkMD5.hashBinary(toUtf8(str), raw);\n };\n\n /**\n * Performs the md5 hash on a binary string.\n *\n * @param {String} content The binary string\n * @param {Boolean} [raw] True to get the raw string, false to get the hex string\n *\n * @return {String} The result\n */\n SparkMD5.hashBinary = function (content, raw) {\n var hash = md51(content),\n ret = hex(hash);\n\n return raw ? hexToBinaryString(ret) : ret;\n };\n\n // ---------------------------------------------------\n\n /**\n * SparkMD5 OOP implementation for array buffers.\n *\n * Use this class to perform an incremental md5 ONLY for array buffers.\n */\n SparkMD5.ArrayBuffer = function () {\n // call reset to init the instance\n this.reset();\n };\n\n /**\n * Appends an array buffer.\n *\n * @param {ArrayBuffer} arr The array to be appended\n *\n * @return {SparkMD5.ArrayBuffer} The instance itself\n */\n SparkMD5.ArrayBuffer.prototype.append = function (arr) {\n var buff = concatenateArrayBuffers(this._buff.buffer, arr, true),\n length = buff.length,\n i;\n\n this._length += arr.byteLength;\n\n for (i = 64; i <= length; i += 64) {\n md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));\n }\n\n this._buff = (i - 64) < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);\n\n return this;\n };\n\n /**\n * Finishes the incremental computation, reseting the internal state and\n * returning the result.\n *\n * @param {Boolean} raw True to get the raw string, false to get the hex string\n *\n * @return {String} The result\n */\n SparkMD5.ArrayBuffer.prototype.end = function (raw) {\n var buff = this._buff,\n length = buff.length,\n tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n i,\n ret;\n\n for (i = 0; i < length; i += 1) {\n tail[i >> 2] |= buff[i] << ((i % 4) << 3);\n }\n\n this._finish(tail, length);\n ret = hex(this._hash);\n\n if (raw) {\n ret = hexToBinaryString(ret);\n }\n\n this.reset();\n\n return ret;\n };\n\n /**\n * Resets the internal state of the computation.\n *\n * @return {SparkMD5.ArrayBuffer} The instance itself\n */\n SparkMD5.ArrayBuffer.prototype.reset = function () {\n this._buff = new Uint8Array(0);\n this._length = 0;\n this._hash = [1732584193, -271733879, -1732584194, 271733878];\n\n return this;\n };\n\n /**\n * Gets the internal state of the computation.\n *\n * @return {Object} The state\n */\n SparkMD5.ArrayBuffer.prototype.getState = function () {\n var state = SparkMD5.prototype.getState.call(this);\n\n // Convert buffer to a string\n state.buff = arrayBuffer2Utf8Str(state.buff);\n\n return state;\n };\n\n /**\n * Gets the internal state of the computation.\n *\n * @param {Object} state The state\n *\n * @return {SparkMD5.ArrayBuffer} The instance itself\n */\n SparkMD5.ArrayBuffer.prototype.setState = function (state) {\n // Convert string to buffer\n state.buff = utf8Str2ArrayBuffer(state.buff, true);\n\n return SparkMD5.prototype.setState.call(this, state);\n };\n\n SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;\n\n SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;\n\n /**\n * Performs the md5 hash on an array buffer.\n *\n * @param {ArrayBuffer} arr The array buffer\n * @param {Boolean} [raw] True to get the raw string, false to get the hex one\n *\n * @return {String} The result\n */\n SparkMD5.ArrayBuffer.hash = function (arr, raw) {\n var hash = md51_array(new Uint8Array(arr)),\n ret = hex(hash);\n\n return raw ? hexToBinaryString(ret) : ret;\n };\n\n return SparkMD5;\n}));\n","export * from \"-!../../../../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../../../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../../../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=style&index=0&id=61052c10&prod&lang=scss&scoped=true\"","export * from \"-!../../../../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../../../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../../../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=style&index=0&id=cdec1cec&prod&lang=scss&scoped=true\"","// extracted by mini-css-extract-plugin","export * from \"-!../../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=style&index=0&id=4f005bbc&prod&scoped=true&lang=scss\"","// extracted by mini-css-extract-plugin","// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","// import request from \"@/utils/request\";\r\n\r\nlet request = null\r\n\r\n// 将vue.use传入的axios实例赋值给request\r\nexport function setAxiosInstance(axiosInstance) {\r\n if (axiosInstance) {\r\n request = axiosInstance;\r\n }\r\n}\r\n\r\n// 执行一个方法,返回n个请求方法\r\n/**\r\n * \r\n * @param {Object} apiObj 包含所有接口地址的对象 {\r\n checkfileStatusUrl: \"/zt-api/resources/check\",\r\n filesAllUoloadedUrl: \"/zt-api/resources/chunk/merge\",\r\n searchFileIsUploadedUrl: \"/zt-api/resources/check\",\r\n searchChunkIsUploadedUrl: \"/zt-api/resources/check/chunk\",\r\n uploadFileChunkUrl: \"/zt-api/resources/chunk/upload\",\r\n addNewFileOfTxtUrl: \"/api/v1/program/create-doc\",\r\n addNewFileOfVideoUrl: \"/api/v1/program/create-video\",\r\n addNewFileOfAudioUrl: \"/api/v1/program/create-audio\",\r\n addNewFileOfPicUrl: \"/api/v1/program/create-pic\",\r\n addNewFileOfSubTitleUrl: \"/api/v1/program/create-srt\",\r\n }\r\n * @returns \r\n */\r\nexport function mapApiToRequest(apiObj) {\r\n return {\r\n checkfileStatus: data => \r\n checkfileStatus(data, apiObj.checkfileStatusUrl),\r\n\r\n filesAllUoloaded: data =>\r\n filesAllUoloaded(data, apiObj.filesAllUoloadedUrl),\r\n\r\n searchFileIsUploaded: data =>\r\n searchFileIsUploaded(data, apiObj.searchFileIsUploadedUrl),\r\n\r\n searchChunkIsUploaded: data =>\r\n searchChunkIsUploaded(data, apiObj.searchChunkIsUploadedUrl),\r\n\r\n uploadFileChunk: data => \r\n uploadFileChunk(data, apiObj.uploadFileChunkUrl),\r\n\r\n addNewFileOfTxt: data => \r\n addNewFileOfTxt(data, apiObj.addNewFileOfTxtUrl),\r\n\r\n addNewFileOfVideo: data =>\r\n addNewFileOfVideo(data, apiObj.addNewFileOfVideoUrl),\r\n\r\n addNewFileOfAudio: data =>\r\n addNewFileOfAudio(data, apiObj.addNewFileOfAudioUrl),\r\n\r\n addNewFileOfPic: data => \r\n addNewFileOfPic(data, apiObj.addNewFileOfPicUrl),\r\n \r\n addNewFileOfSubTitle: data =>\r\n addNewFileOfSubTitle(data, apiObj.addNewFileOfSubTitleUrl),\r\n };\r\n}\r\n\r\n// 检查文件状态\r\nfunction checkfileStatus(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n\r\n// 合并块文件\r\nfunction filesAllUoloaded(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n\r\n// 检查文件是否已上传过\r\nfunction searchFileIsUploaded(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n\r\n// 检查文件块是否已上传过\r\nfunction searchChunkIsUploaded(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n\r\n// 上传文件块\r\nfunction uploadFileChunk(data, url) {\r\n const formData = data instanceof FormData ? data : new FormData();\r\n\r\n if (!(data instanceof FormData) && data && typeof data === \"object\") {\r\n Object.keys(data).forEach(key => {\r\n formData.append(key, data[key]);\r\n });\r\n }\r\n\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data: formData,\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n timeout: 1000 * 60 * 10,\r\n });\r\n}\r\n\r\n// 创建新文件\r\nfunction addNewFileOfTxt(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\nfunction addNewFileOfVideo(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\nfunction addNewFileOfAudio(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\nfunction addNewFileOfPic(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\nfunction addNewFileOfSubTitle(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"upload-multiple\"},[_c('input',{ref:\"multiplePloadInput\",staticStyle:{\"display\":\"none\"},attrs:{\"type\":\"file\",\"multiple\":_vm.multiple,\"accept\":_vm.limitFileType},on:{\"change\":_vm.handleSelectedMultipleFiles}}),_c('div',{staticClass:\"upload-multiple-box\"},[_c('div',{ref:\"upLoded_box\",staticClass:\"multiple_upload_area\",class:_vm.multipleUploadAreaClass(),on:{\"click\":_vm.reviewUploadMultipleFiles,\"dragover\":function($event){$event.preventDefault();return _vm.onDragOver($event)},\"dragleave\":function($event){$event.preventDefault();return _vm.onDragLeave($event)},\"drop\":function($event){$event.preventDefault();return _vm.onDrop($event)}}},[(_vm.isUploading)?_c('div',{staticClass:\"upload-loading-mask\",style:(_vm.setUploadingLoadingMaskStyle())}):_vm._e(),(_vm.showIconTip)?_c('div',[_c('i',{staticClass:\"el-icon-upload\"})]):_vm._e(),_c('div',[_vm._v(_vm._s(_vm.startButtonText))]),_vm._t(\"tips\")],2),(_vm.pictureConfig.show && _vm.showSuccessPicture)?_c('div',{staticClass:\"upload-multiple-box-right\"},[_c('div',{staticClass:\"upload-multiple-box-close\",on:{\"click\":function($event){$event.stopPropagation();return _vm.clearPicture($event)}}},[_c('i',{staticClass:\"el-icon-close\"})]),_c('img',{attrs:{\"src\":_vm.pictureConfig.url,\"alt\":_vm.pictureConfig.altText}})]):_vm._e()]),(_vm.isShowAllUploadButton)?_c('el-button',{staticClass:\"upload_button\",attrs:{\"type\":\"primary\",\"disabled\":_vm.isUploading || _vm.needUploadFilesArr.length === 0},on:{\"click\":_vm.startUploadMultipleFiles}},[_vm._v(\" 全部文件开始上传 \")]):_vm._e(),(_vm.model === 'table')?_c('div',{staticClass:\"upload-multiple-table\"},[_c('Upload_table',{attrs:{\"needUploadFilesArr\":_vm.needUploadFilesArr,\"fileConfig\":_vm.fileConfig,\"fileType\":_vm.addDataBaseLinkConfig.addFileType,\"isUploading\":_vm.isUploading},on:{\"delteSelectedFile\":_vm.delteSelectedFile,\"cancelFileUpload\":_vm.cancelFileUpload,\"resetFileUpload\":_vm.resetFileUpload,\"handleSelectionChange\":_vm.tableSelectionChange}})],1):_vm._e(),(_vm.model === 'info')?_c('div',{staticClass:\"multiple_upload_list\"},[_c('span',{staticClass:\"tip_title\"},[_c('span',{staticClass:\"title\"},[_c('div',[_vm._v(\"文件列表\")]),_c('transition',{attrs:{\"name\":\"totalProgress\",\"mode\":\"out-in\"}},[(_vm.needUploadFilesArr.length > 0)?_c('div',{staticClass:\"total_progress\"},[_c('div',{staticClass:\"logo\"}),_c('span',[_vm._v(\"总进度:\")]),(_vm.fileConfig.uploadController)?_c('div',[_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":_vm.isDanger}},[_vm._v(\"上传错误:\"+_vm._s(_vm.fileConfig.skipError_num))]),_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":\"\"}},[_vm._v(\"上传成功:\"+_vm._s(_vm.fileConfig.completed_num))]),_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":\"\"}},[_vm._v(\"文件总数:\"+_vm._s(_vm.fileConfig.filetotal_num))])],1):_vm._e()]):_vm._e()])],1),_c('span',[_c('el-button',{attrs:{\"size\":\"mini\",\"type\":\"\",\"disabled\":_vm.isUploading || _vm.needUploadFilesArr.length === 0},on:{\"click\":_vm.handleSelectAllFile}},[_vm._v(\"全选所有文件\")]),_c('el-button',{attrs:{\"size\":\"mini\",\"type\":\"danger\",\"disabled\":_vm.isUploading || _vm.needUploadFilesArr.length === 0},on:{\"click\":_vm.delteSelectedFile}},[_vm._v(\"移除所选文件\")])],1)]),_c('div',{staticClass:\"selected_list_area\"},[(_vm.needUploadFilesArr.length > 0)?_c('div',{staticClass:\"selected_list\"},_vm._l((_vm.needUploadFilesArr),function(item,index){return _c('Card_2',{key:index,attrs:{\"index\":index,\"file-config\":item},on:{\"cancelFileUpload\":_vm.cancelFileUpload,\"resetFileUpload\":_vm.resetFileUpload,\"handleClickOnlyFile\":_vm.handleClickOnlyFile}})}),1):_c('div',{staticClass:\"no_file\"},[_c('i',{staticClass:\"el-icon-document\"}),_c('div',[_vm._v(\"暂无文件,请点击或拖拽文件到上传区域\")])])])]):_vm._e()],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","// 辅助函数:获取MIME类型\r\nfunction getMimeType(fileOrType) {\r\n if (!fileOrType) return \"\";\r\n\r\n if (typeof fileOrType === \"string\") {\r\n return fileOrType;\r\n }\r\n\r\n if (fileOrType instanceof File || fileOrType instanceof Blob) {\r\n return fileOrType.type;\r\n }\r\n\r\n if (fileOrType.type && typeof fileOrType.type === \"string\") {\r\n return fileOrType.type;\r\n }\r\n return \"\";\r\n}\r\n\r\nexport const fileTypeValidators = {\r\n /**\r\n * 验证图片类型\r\n * 支持: jpg, jpeg, png, gif, webp, bmp, svg, tiff, ico\r\n */\r\n isImage: (fileOrType) => {\r\n const mime = getMimeType(fileOrType);\r\n return /(jpg|jpeg|png|gif|webp|bmp|svg|tiff|ico)$/i.test(mime);\r\n },\r\n\r\n /**\r\n * 验证视频类型\r\n * 支持: mp4, avi, webm, mov, wmv, flv, mkv, mpeg, 3gp\r\n */\r\n isVideo: (fileOrType) => {\r\n const mime = getMimeType(fileOrType);\r\n return /(mp4|avi|webm|mov|wmv|flv|mkv|mpeg|3gp)$/i.test(mime);\r\n },\r\n\r\n /**\r\n * 验证音频类型\r\n * 支持: mp3, wav, ogg, aac, flac, m4a, mid, opus\r\n */\r\n isAudio: (fileOrType) => {\r\n const mime = getMimeType(fileOrType);\r\n return (\r\n /^audio\\/(mpeg|mp3|mp4|x-m4a|wav|ogg|aac|flac|mid|x-midi|opus|webm)$/i.test(\r\n mime\r\n ) ||\r\n /\\.(mp3|wav|ogg|aac|flac|m4a|mid|opus)$/i.test(mime) ||\r\n /^(mp3|wav|ogg|aac|flac|m4a|mid|opus)$/i.test(mime)\r\n );\r\n },\r\n\r\n /**\r\n * 验证字幕类型\r\n * 支持: srt, vtt, ass, ssa, sub\r\n */\r\n isSubtitle: (fileOrType) => {\r\n const mime = getMimeType(fileOrType);\r\n console.log(mime);\r\n return /(vtt|ass|srt)$/i.test(mime);\r\n },\r\n\r\n /**\r\n * 验证文档类型\r\n * 支持: pdf, doc, docx, xls, xlsx, ppt, pptx, txt, rtf, zip, rar, 7z\r\n */\r\n isDocument: (fileOrType) => {\r\n return true;\r\n // const mime = getMimeType(fileOrType);\r\n // return /^(presentation))|text\\/(plain|html|csv|xml|css|javascript|markdown))$/i.test(mime);\r\n },\r\n};","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{key:_vm.fileConfig.name + '_' + _vm.index,staticClass:\"only_file_area\",class:{\n only_file_area_isActive: _vm.fileConfig.isSelected,\n 'fade-in-element': true,\n },on:{\"click\":function($event){return _vm.handleClickOnlyFile(_vm.fileConfig)}}},[_c('div',{staticClass:\"file_card_top\"},[_c('div',{staticClass:\"file_type\"},[_vm._v(\" \"+_vm._s(_vm.getFileType(_vm.fileConfig.name))+\" \")]),_c('div',{staticClass:\"file_name\"},[_vm._v(_vm._s(_vm.fileConfig.name))])]),_c('div',{staticClass:\"file_card_bottom\"},[_c('div',{staticClass:\"option\"},[_c('div',{staticClass:\"status_text\"},[_c('span',{class:_vm.uploadingTextStyle(_vm.fileConfig.tip)},[_vm._v(_vm._s(_vm.fileConfig.tip))])]),(\n _vm.fileConfig.tip === '上传中'\n )?_c('div',{staticClass:\"option_text\",on:{\"click\":function($event){$event.stopPropagation();return _vm.cancelFileUpload(_vm.fileConfig)}}},[_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":\"danger\"}},[_vm._v(\"取消\")])],1):_vm._e(),(\n _vm.fileConfig.tip === '已取消' ||\n _vm.fileConfig.tip === '上传出错' ||\n _vm.fileConfig.tip === '未知出错'\n )?_c('div',{staticClass:\"option_text\",on:{\"click\":function($event){$event.stopPropagation();return _vm.resetFileUpload(_vm.fileConfig)}}},[_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":\"\"}},[_vm._v(\"重试\")])],1):_vm._e()]),_c('div',[_c('span',[_vm._v(_vm._s(_vm.uploadingNumber( _vm.fileFormatValid(_vm.fileConfig.file.size), _vm.fileConfig.uploadProgress ))+\"/\"+_vm._s(_vm.fileFormatValid(_vm.fileConfig.file.size))+\"mb\")])])]),_c('div',{staticClass:\"progress_area\"},[_c('el-progress',{staticClass:\"custom-progress\",attrs:{\"color\":_vm.colors,\"show-text\":false,\"percentage\":_vm.fileConfig.uploadProgress}})],1)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","<template>\r\n <div\r\n :key=\"fileConfig.name + '_' + index\"\r\n class=\"only_file_area\"\r\n :class=\"{\r\n only_file_area_isActive: fileConfig.isSelected,\r\n 'fade-in-element': true,\r\n }\"\r\n @click=\"handleClickOnlyFile(fileConfig)\"\r\n >\r\n <div class=\"file_card_top\">\r\n <div class=\"file_type\">\r\n {{ getFileType(fileConfig.name) }}\r\n </div>\r\n <div class=\"file_name\">{{ fileConfig.name }}</div>\r\n </div>\r\n\r\n <div class=\"file_card_bottom\">\r\n <div class=\"option\">\r\n <div class=\"status_text\">\r\n <span :class=\"uploadingTextStyle(fileConfig.tip)\">{{\r\n fileConfig.tip\r\n }}</span>\r\n </div>\r\n <div\r\n v-if=\"\r\n fileConfig.tip === '上传中'\r\n \"\r\n class=\"option_text\"\r\n @click.stop=\"cancelFileUpload(fileConfig)\"\r\n >\r\n <!-- 只有上传中,在排队的人物可以进行取消 -->\r\n <el-tag size=\"mini\" type=\"danger\">取消</el-tag>\r\n </div>\r\n <div\r\n v-if=\"\r\n fileConfig.tip === '已取消' ||\r\n fileConfig.tip === '上传出错' ||\r\n fileConfig.tip === '未知出错'\r\n \"\r\n class=\"option_text\"\r\n @click.stop=\"resetFileUpload(fileConfig)\"\r\n >\r\n <el-tag size=\"mini\" type=\"\">重试</el-tag>\r\n </div>\r\n </div>\r\n <div>\r\n <span>{{\r\n uploadingNumber(\r\n fileFormatValid(fileConfig.file.size),\r\n fileConfig.uploadProgress\r\n )\r\n }}/{{ fileFormatValid(fileConfig.file.size) }}mb</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"progress_area\">\r\n <el-progress\r\n :color=\"colors\"\r\n :show-text=\"false\"\r\n :percentage=\"fileConfig.uploadProgress\"\r\n class=\"custom-progress\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script>\r\nexport default {\r\n name: \"UploadCardVerFirst\",\r\n props: {\r\n fileConfig: {\r\n required: true,\r\n type: Object,\r\n default: () => {\r\n return {};\r\n },\r\n },\r\n index: {\r\n required: false,\r\n type: Number,\r\n default: 0,\r\n },\r\n },\r\n data() {\r\n return {\r\n colors: [\r\n { color: \"#bae6fd\", percentage: 20 }, // 浅天蓝:刚刚启动,轻快感\r\n { color: \"#7dd3fc\", percentage: 40 }, // 天蓝:平稳进行\r\n { color: \"#38bdf8\", percentage: 60 }, // 亮蓝:进入核心处理\r\n { color: \"#2563eb\", percentage: 80 }, // 宝蓝:即将完成的厚重感\r\n { color: \"#6366f1\", percentage: 100 }, // 靛紫:完成时的精致感\r\n ],\r\n };\r\n },\r\n methods: {\r\n handleClickOnlyFile(fileConfig) {\r\n this.$emit(\"handleClickOnlyFile\", this.fileConfig);\r\n },\r\n getFileType(name) {\r\n return name.split(\".\")[1];\r\n },\r\n uploadingTextStyle(text) {\r\n // 第一个未知,第二个stauts超时,第三个上传块超时\r\n if (\r\n text === \"出错\" ||\r\n text === \"查询文件地址超时\" ||\r\n text === \"上传出错\"\r\n ) {\r\n return \"uploading_error\";\r\n } else if (text === \"已完成\") {\r\n return \"uploading_success\";\r\n } else if (text === \"等待上传\") {\r\n return \"uploading_wait\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n // 更新上传数字\r\n uploadingNumber(total, completed) {\r\n if (!completed) return 0;\r\n\r\n return (total * (completed / 100)).toFixed(2);\r\n },\r\n // 数字验证\r\n fileFormatValid(val) {\r\n const number = (val / (1024 * 1024)).toFixed(2);\r\n\r\n return number;\r\n },\r\n resetFileUpload(item) {\r\n this.$emit(\"resetFileUpload\", item);\r\n },\r\n cancelFileUpload(item) {\r\n this.$emit(\"cancelFileUpload\", item);\r\n },\r\n },\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.only_file_area {\r\n width: 13.5rem;\r\n min-height: 6rem;\r\n padding: 1rem;\r\n border-radius: 15px;\r\n // background: linear-gradient(135deg, #dae5f5 0%, #ffffff 100%);\r\n border: 1px solid rgb(226, 232, 239);\r\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);\r\n transition: all 0.3s ease;\r\n cursor: pointer;\r\n position: relative;\r\n overflow: hidden;\r\n\r\n &:hover {\r\n transform: translateY(-3px);\r\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n &::before {\r\n content: \"\";\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n width: 3px;\r\n height: 100%;\r\n background: #1890ff;\r\n transform: scaleY(0);\r\n transition: transform 0.3s ease;\r\n }\r\n\r\n &:hover::before {\r\n transform: scaleY(1);\r\n }\r\n\r\n .file_icon {\r\n font-size: 2rem;\r\n color: #909399;\r\n margin-right: 1rem;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n .file_card_top {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.4rem;\r\n\r\n .file_type {\r\n width: 2.5rem;\r\n height: 2rem;\r\n // padding: 0.2rem;\r\n text-align: center;\r\n line-height: 2rem;\r\n background-color: #e2e8ef;\r\n font-weight: 600;\r\n border-radius: 5px;\r\n text-transform: uppercase;\r\n font-size: 12px;\r\n white-space: nowrap;\r\n }\r\n\r\n .file_name {\r\n white-space: nowrap;\r\n overflow-x: auto; /* 水平滚动 */\r\n text-overflow: ellipsis;\r\n overflow: hidden;\r\n width: 12rem;\r\n height: 1.5rem;\r\n min-height: 0.5rem;\r\n font-size: 0.9rem;\r\n font-weight: 600;\r\n color: #1f283a;\r\n // margin-bottom: 0.5rem;\r\n word-break: break-all;\r\n line-height: 1.3;\r\n }\r\n }\r\n\r\n .progress_area {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n width: 100%;\r\n\r\n .el-progress {\r\n width: 100%;\r\n // height: 1.5rem;\r\n // min-height: 0.5rem;\r\n // padding-top: 0.2rem;\r\n\r\n ::v-deep .el-progress-bar__outer {\r\n background-color: #b3c3e8;\r\n }\r\n\r\n ::v-deep .el-progress-bar__inner {\r\n transition: width 0.4s ease;\r\n }\r\n }\r\n }\r\n\r\n .file_card_bottom {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n font-size: 12px;\r\n\r\n .option {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.3rem;\r\n\r\n height: 1.5rem;\r\n min-height: 0.5rem;\r\n // font-size: 0.85rem;\r\n\r\n .option_text {\r\n color: red;\r\n }\r\n .option_text:hover {\r\n text-decoration: underline;\r\n cursor: pointer;\r\n }\r\n .status_text {\r\n .uploading_error {\r\n color: red;\r\n font-weight: 500;\r\n }\r\n\r\n .uploading_wait {\r\n color: #909399;\r\n }\r\n\r\n .uploading_success {\r\n color: #67c23a;\r\n font-weight: 500;\r\n }\r\n }\r\n }\r\n }\r\n\r\n &.only_file_area_isActive {\r\n border: 1px solid #1890ff;\r\n background-color: rgba(24, 144, 255, 0.05);\r\n\r\n .file_icon {\r\n color: #1890ff;\r\n transform: scale(1.1);\r\n }\r\n\r\n &::after {\r\n content: \"\";\r\n position: absolute;\r\n top: 0.5rem;\r\n right: 0.5rem;\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 50%;\r\n background: #1890ff;\r\n box-shadow: 0 0 0 2px white;\r\n }\r\n }\r\n}\r\n</style>\r\n","import mod from \"-!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"","/* globals __VUE_SSR_CONTEXT__ */\n\n// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).\n// This module is a runtime utility for cleaner component module output and will\n// be included in the final webpack user bundle.\n\nexport default function normalizeComponent(\n scriptExports,\n render,\n staticRenderFns,\n functionalTemplate,\n injectStyles,\n scopeId,\n moduleIdentifier /* server only */,\n shadowMode /* vue-cli only */\n) {\n // Vue.extend constructor export interop\n var options =\n typeof scriptExports === 'function' ? scriptExports.options : scriptExports\n\n // render functions\n if (render) {\n options.render = render\n options.staticRenderFns = staticRenderFns\n options._compiled = true\n }\n\n // functional template\n if (functionalTemplate) {\n options.functional = true\n }\n\n // scopedId\n if (scopeId) {\n options._scopeId = 'data-v-' + scopeId\n }\n\n var hook\n if (moduleIdentifier) {\n // server build\n hook = function (context) {\n // 2.3 injection\n context =\n context || // cached call\n (this.$vnode && this.$vnode.ssrContext) || // stateful\n (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional\n // 2.2 with runInNewContext: true\n if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\n context = __VUE_SSR_CONTEXT__\n }\n // inject component styles\n if (injectStyles) {\n injectStyles.call(this, context)\n }\n // register component module identifier for async chunk inferrence\n if (context && context._registeredComponents) {\n context._registeredComponents.add(moduleIdentifier)\n }\n }\n // used by ssr in case component is cached and beforeCreate\n // never gets called\n options._ssrRegister = hook\n } else if (injectStyles) {\n hook = shadowMode\n ? function () {\n injectStyles.call(\n this,\n (options.functional ? this.parent : this).$root.$options.shadowRoot\n )\n }\n : injectStyles\n }\n\n if (hook) {\n if (options.functional) {\n // for template-only hot-reload because in that case the render fn doesn't\n // go through the normalizer\n options._injectStyles = hook\n // register for functional component in vue file\n var originalRender = options.render\n options.render = function renderWithStyleInjection(h, context) {\n hook.call(context)\n return originalRender(h, context)\n }\n } else {\n // inject component registration as beforeCreate hook\n var existing = options.beforeCreate\n options.beforeCreate = existing ? [].concat(existing, hook) : [hook]\n }\n }\n\n return {\n exports: scriptExports,\n options: options\n }\n}\n","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=cdec1cec&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=js\"\nexport * from \"./index.vue?vue&type=script&lang=js\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=cdec1cec&prod&lang=scss&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"cdec1cec\",\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"upload_table\"},[_c('div',{staticClass:\"header\"},[_c('div',{staticClass:\"total\"},[_c('span',[_vm._v(\"已选择\"+_vm._s(_vm.needUploadFilesArr.length)+\"个文件\")]),(_vm.needUploadFilesArr.length)?_c('el-tag',{attrs:{\"type\":\"\",\"size\":\"mini\"}},[_vm._v(\"上传中\"+_vm._s(_vm.totalNumber))]):_vm._e()],1),_c('div',{staticClass:\"options\"},[_c('el-button',{attrs:{\"type\":\"danger\",\"size\":\"mini\",\"disabled\":_vm.isUploading || _vm.needUploadFilesArr.length === 0},on:{\"click\":function($event){return _vm.handleClickOnlyFile()}}},[_vm._v(\"清除已选\")])],1)]),_c('el-table',{staticStyle:{\"width\":\"100%\"},attrs:{\"data\":_vm.needUploadFilesArr,\"default-sort\":{ prop: 'fileName', order: 'descending' },\"border\":\"\",\"height\":\"400px\"},on:{\"sort-change\":_vm.handleSortChange,\"selection-change\":_vm.handleSelectionChange}},[_c('el-table-column',{attrs:{\"type\":\"selection\",\"width\":\"40\"}}),_c('el-table-column',{attrs:{\"type\":\"index\",\"width\":\"40\"}}),_c('el-table-column',{attrs:{\"label\":\"文件名\",\"width\":\"300\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [_c('div',{staticClass:\"file_name\"},[_c('div',{staticClass:\"file_type\"},[_vm._v(\" \"+_vm._s(_vm.getFileType(scope.row.name))+\" \")]),_c('span',{staticClass:\"file_name_text\"},[_vm._v(_vm._s(scope.row.name))])])]}}])}),_c('el-table-column',{attrs:{\"label\":\"大小\",\"width\":\"100\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [_c('div',{staticClass:\"file_size\"},[_c('span',{staticClass:\"file_size_text\"},[_vm._v(_vm._s(_vm.fileFormatValid(scope.row.file.size))+\" mb\")])])]}}])}),_c('el-table-column',{attrs:{\"label\":\"状态\",\"width\":\"100\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [_c('div',{staticClass:\"status_text\"},[_c('span',{class:_vm.uploadingTextStyle(scope.row.tip)},[_vm._v(_vm._s(scope.row.tip))])])]}}])}),_c('el-table-column',{attrs:{\"label\":\"进度\",\"width\":\"auto\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [_c('div',{staticClass:\"progress_area\"},[_c('el-progress',{staticClass:\"custom-progress\",attrs:{\"color\":_vm.colors,\"show-text\":true,\"percentage\":scope.row.uploadProgress}})],1)]}}])}),_c('el-table-column',{attrs:{\"label\":\"操作\",\"width\":\"auto\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [(scope.row.tip === '上传中')?_c('div',{staticClass:\"option_text\",on:{\"click\":function($event){$event.stopPropagation();return _vm.cancelFileUpload(scope.row)}}},[_c('span',{staticStyle:{\"color\":\"#f74444\",\"cursor\":\"pointer\"}},[_vm._v(\"取消上传\")])]):_vm._e(),(\n scope.row.tip === '已取消' ||\n scope.row.tip === '上传出错' ||\n scope.row.tip === '未知出错'\n )?_c('div',{staticClass:\"option_text\",on:{\"click\":function($event){$event.stopPropagation();return _vm.resetFileUpload(scope.row)}}},[_c('span',{staticStyle:{\"color\":\"#f74444\",\"cursor\":\"pointer\"}},[_vm._v(\"重试\")])]):_vm._e()]}}])})],1)],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","<template>\r\n <div class=\"upload_table\">\r\n <div class=\"header\">\r\n <div class=\"total\">\r\n <span>已选择{{ needUploadFilesArr.length }}个文件</span>\r\n <el-tag v-if=\"needUploadFilesArr.length\" type=\"\" size=\"mini\"\r\n >上传中{{ totalNumber }}</el-tag\r\n >\r\n </div>\r\n <div class=\"options\">\r\n <el-button\r\n type=\"danger\"\r\n size=\"mini\"\r\n @click=\"handleClickOnlyFile()\"\r\n :disabled=\"isUploading || needUploadFilesArr.length === 0\"\r\n >清除已选</el-button\r\n >\r\n </div>\r\n </div>\r\n <el-table\r\n :data=\"needUploadFilesArr\"\r\n style=\"width: 100%\"\r\n :default-sort=\"{ prop: 'fileName', order: 'descending' }\"\r\n border\r\n height=\"400px\"\r\n @sort-change=\"handleSortChange\"\r\n @selection-change=\"handleSelectionChange\"\r\n >\r\n <el-table-column type=\"selection\" width=\"40\"> </el-table-column>\r\n <el-table-column type=\"index\" width=\"40\"> </el-table-column>\r\n <el-table-column label=\"文件名\" width=\"300\">\r\n <template slot-scope=\"scope\">\r\n <div class=\"file_name\">\r\n <div class=\"file_type\">\r\n {{ getFileType(scope.row.name) }}\r\n </div>\r\n <span class=\"file_name_text\">{{ scope.row.name }}</span>\r\n </div>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"大小\" width=\"100\">\r\n <template slot-scope=\"scope\">\r\n <div class=\"file_size\">\r\n <span class=\"file_size_text\"\r\n >{{ fileFormatValid(scope.row.file.size) }} mb</span\r\n >\r\n </div>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"状态\" width=\"100\">\r\n <template slot-scope=\"scope\">\r\n <div class=\"status_text\">\r\n <span :class=\"uploadingTextStyle(scope.row.tip)\">{{\r\n scope.row.tip\r\n }}</span>\r\n </div>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"进度\" width=\"auto\">\r\n <template slot-scope=\"scope\">\r\n <div class=\"progress_area\">\r\n <el-progress\r\n :color=\"colors\"\r\n :show-text=\"true\"\r\n :percentage=\"scope.row.uploadProgress\"\r\n class=\"custom-progress\"\r\n />\r\n </div>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"操作\" width=\"auto\">\r\n <template slot-scope=\"scope\">\r\n <div\r\n v-if=\"scope.row.tip === '上传中'\"\r\n class=\"option_text\"\r\n @click.stop=\"cancelFileUpload(scope.row)\"\r\n >\r\n <!-- 只有上传中,在排队的任务可以进行取消 -->\r\n <span style=\"color: #f74444; cursor: pointer\">取消上传</span>\r\n </div>\r\n <div\r\n v-if=\"\r\n scope.row.tip === '已取消' ||\r\n scope.row.tip === '上传出错' ||\r\n scope.row.tip === '未知出错'\r\n \"\r\n class=\"option_text\"\r\n @click.stop=\"resetFileUpload(scope.row)\"\r\n >\r\n <span style=\"color: #f74444; cursor: pointer\">重试</span>\r\n </div>\r\n </template>\r\n </el-table-column>\r\n </el-table>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n name: \"Upload_Table\",\r\n props: {\r\n needUploadFilesArr: {\r\n type: Array,\r\n default: () => [],\r\n },\r\n fileConfig: {\r\n type: Object,\r\n default: () => {},\r\n },\r\n fileType: {\r\n type: String,\r\n default: \"\",\r\n },\r\n isUploading: {\r\n type: Boolean,\r\n },\r\n },\r\n data() {\r\n return {\r\n colors: [\r\n { color: \"#bae6fd\", percentage: 20 }, // 浅天蓝:刚刚启动,轻快感\r\n { color: \"#7dd3fc\", percentage: 40 }, // 天蓝:平稳进行\r\n { color: \"#38bdf8\", percentage: 60 }, // 亮蓝:进入核心处理\r\n { color: \"#2563eb\", percentage: 80 }, // 宝蓝:即将完成的厚重感\r\n { color: \"#6366f1\", percentage: 100 }, // 靛紫:完成时的精致感\r\n ],\r\n };\r\n },\r\n computed: {\r\n totalNumber() {\r\n return (\r\n this.fileConfig.completed_num + \"/\" + this.needUploadFilesArr.length\r\n );\r\n },\r\n },\r\n methods: {\r\n handleSortChange(val) {\r\n this.$emit(\"sortChange\", val);\r\n },\r\n uploadingTextStyle(text) {\r\n // 第一个未知,第二个stauts超时,第三个上传块超时\r\n if (\r\n text === \"出错\" ||\r\n text === \"查询文件地址超时\" ||\r\n text === \"上传出错\"\r\n ) {\r\n return \"uploading_error\";\r\n } else if (text === \"已完成\") {\r\n return \"uploading_success\";\r\n } else if (text === \"等待上传\") {\r\n return \"uploading_wait\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n resetFileUpload(item) {\r\n this.$emit(\"resetFileUpload\", item);\r\n },\r\n cancelFileUpload(item) {\r\n this.$emit(\"cancelFileUpload\", item);\r\n },\r\n handleClickOnlyFile() {\r\n this.$emit(\"delteSelectedFile\");\r\n },\r\n // 数字验证\r\n fileFormatValid(val) {\r\n const number = (val / (1024 * 1024)).toFixed(2);\r\n\r\n return number;\r\n },\r\n getFileType(name) {\r\n return name.split(\".\")[1];\r\n },\r\n handleSelectionChange(selection) {\r\n const selecId = selection.map(item => item.index);\r\n\r\n this.$emit(\"handleSelectionChange\", selecId);\r\n },\r\n },\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.upload_table {\r\n height: 100%;\r\n width: 100%;\r\n\r\n ::v-deep {\r\n .el-table__cell {\r\n padding: 6px 0;\r\n }\r\n }\r\n\r\n .header {\r\n height: 3rem;\r\n padding: 0.5rem;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n border: 1px solid #dfe6ec;\r\n border-bottom: 0px;\r\n\r\n .total {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.25rem;\r\n }\r\n }\r\n\r\n .file_name {\r\n display: flex;\r\n gap: 0.25rem;\r\n\r\n overflow: hidden;\r\n min-height: 0.5rem;\r\n font-size: 0.9rem;\r\n font-weight: 400;\r\n color: #1f283a;\r\n\r\n .file_type {\r\n width: 1.5rem;\r\n height: 1.5rem;\r\n // padding: 0.2rem;\r\n text-align: center;\r\n line-height: 1.5rem;\r\n background-color: #e2e8ef;\r\n font-weight: 600;\r\n border-radius: 5px;\r\n text-transform: uppercase;\r\n font-size: 10px;\r\n color: #1392e8;\r\n white-space: nowrap;\r\n }\r\n }\r\n\r\n .option_text {\r\n color: red;\r\n }\r\n .option_text:hover {\r\n text-decoration: underline;\r\n cursor: pointer;\r\n }\r\n .status_text {\r\n .uploading_error {\r\n color: red;\r\n font-weight: 500;\r\n }\r\n\r\n .uploading_wait {\r\n color: #909399;\r\n }\r\n\r\n .uploading_success {\r\n color: #67c23a;\r\n font-weight: 500;\r\n }\r\n }\r\n\r\n .progress_area {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n width: 100%;\r\n\r\n .el-progress {\r\n width: 100%;\r\n // height: 1.5rem;\r\n // min-height: 0.5rem;\r\n // padding-top: 0.2rem;\r\n\r\n ::v-deep .el-progress-bar__outer {\r\n background-color: #b3c3e8;\r\n }\r\n\r\n ::v-deep .el-progress-bar__inner {\r\n transition: width 0.4s ease;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","import mod from \"-!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=61052c10&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=js\"\nexport * from \"./index.vue?vue&type=script&lang=js\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=61052c10&prod&lang=scss&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"61052c10\",\n null\n \n)\n\nexport default component.exports","import SparkMD5 from \"spark-md5\";\r\nimport { mapApiToRequest } from \"./api\";\r\n\r\n// 超时控制\r\nconst timer = {\r\n entranceTime: 120000,\r\n uploadChunkTime: 1000 * 60 * 10,\r\n dropStateOverTime: 1000 * 60 * 10,\r\n dropStatePollTime: 2000,\r\n};\r\n// 文件分块大小\r\nconst chunkSegmentationSize = 1024 * 1024 * 5;\r\n\r\n// 文件上传接口\r\nlet api = {};\r\n// 默认配置内容管理api\r\nconst contentManagement = {\r\n checkfileStatusUrl: \"/zt-api/resources/check\",\r\n filesAllUoloadedUrl: \"/zt-api/resources/chunk/merge\",\r\n searchFileIsUploadedUrl: \"/zt-api/resources/check\",\r\n searchChunkIsUploadedUrl: \"/zt-api/resources/check/chunk\",\r\n uploadFileChunkUrl: \"/zt-api/resources/chunk/upload\",\r\n addNewFileOfTxtUrl: \"/api/v1/program/create-doc\",\r\n addNewFileOfVideoUrl: \"/api/v1/program/create-video\",\r\n addNewFileOfAudioUrl: \"/api/v1/program/create-audio\",\r\n addNewFileOfPicUrl: \"/api/v1/program/create-pic\",\r\n addNewFileOfSubTitleUrl: \"/api/v1/program/create-srt\",\r\n};\r\n\r\n/**\r\n * 上传入口:此文件用于处理文件上传的核心逻辑。处去文件自身声明变量,必须得有uploadFilesConfig_AndStart的所有参数。以及各个接口调用函数\r\n * @param {Array} fileList 文件列表\r\n * @param {number} maxConcurrent 文件块最大并发数\r\n * @param {number} maxFileConcurrent 文件最大并发数\r\n * @param {Object} addDataBaseLinkConfig 文件上传成功之后或者检索文件已存在时是否创建数据库链接的配置项\r\n * @param {Function} createFileQueues 创建文件队列的回调函数\r\n * @param {Function} createUploadQueues 创建上传任务的回调函数\r\n * @param {Function} total_progress_function 全局进度更新函数\r\n * @param {Function} setTotalStatus 全局进度条状态\r\n * @param {Object} apiObj 外界传来的上传api\r\n * @returns {Array} [{\r\n status: true,\r\n uploadId: number,\r\n uuid: check_result.fileCheck,\r\n fileName: fileName,\r\n }, ...] 每个文件的上传结果组成的数组\r\n */\r\nexport default async function uploadFilesConfig_AndStart(\r\n fileList,\r\n maxConcurrent,\r\n maxFileConcurrent,\r\n addDataBaseLinkConfig,\r\n createFileQueues,\r\n createUploadQueues,\r\n total_progress_function,\r\n setTotalStatus,\r\n apiObj = contentManagement,\r\n) {\r\n // 1.准备上传接口\r\n api = mapApiToRequest(apiObj);\r\n\r\n const uploadPromises = [];\r\n\r\n for (let i = 0; i < fileList.length; i++) {\r\n const item = fileList[i];\r\n const uploadId = generateUploadId(item.file);\r\n\r\n // 创建并发控制器\r\n const controller = createConcurrentController(\r\n maxConcurrent,\r\n item.updateProgress,\r\n );\r\n\r\n // 通过uploadId查看每一个文件的uploadId\r\n createFileQueues(item.index, controller);\r\n\r\n // controller保证每一个文件有单独的并发控制\r\n const taskFn = () => {\r\n const task = uploadSingleFile(\r\n item.file,\r\n uploadId,\r\n controller,\r\n item.updateProgress,\r\n item.progress_error,\r\n addDataBaseLinkConfig,\r\n );\r\n // 通过uploadId可知文件是否已经上传完成\r\n createUploadQueues(uploadId, task);\r\n return task;\r\n };\r\n\r\n uploadPromises.push({ index: item.index, taskFn });\r\n }\r\n\r\n const controller = createConcurrentController(\r\n maxFileConcurrent,\r\n total_progress_function,\r\n );\r\n\r\n setTotalStatus(controller, \"上传中\");\r\n\r\n // 文件可以允许上传失败\r\n return controller.runTasks(uploadPromises);\r\n}\r\n\r\n// 分块并发控制器,后续集成文件并发控制器\r\nfunction createConcurrentController(maxConcurrent, onProgress) {\r\n let queue = []; // 等待队列\r\n let cancleTasks = []; // 被取消暂存的数组\r\n let errorTasks = []; // 出错暂存的数组,用于重新上传\r\n let activeCount = 0; // 当前正在执行的任务数\r\n let isPaused = false; // 是否暂停\r\n let pauseResolve = null; // 暂停时的resolve函数\r\n\r\n let skipError = 0; // 跳过错误的任务个数\r\n let completedCount = 0; // 已完成的任务数\r\n let totalTasks = 0; // 总任务数\r\n\r\n // 进度计算函数,此处故意设计为最多99左右,后面给创建文件路径,合并块,落盘等等\r\n const calculateProgress = () => {\r\n if (totalTasks === 0) return 0;\r\n return Math.round((completedCount / totalTasks) * 100);\r\n };\r\n\r\n // 进度更新函数\r\n const updateProgress = preventUpdate => {\r\n if (onProgress && typeof onProgress === \"function\") {\r\n const progress = calculateProgress();\r\n\r\n // 如果存在错误任务或控制器被暂停,不要被后续成功任务覆盖状态,保持错误提示\r\n if (\r\n preventUpdate &&\r\n ((Array.isArray(errorTasks) && errorTasks.length > 0) || isPaused)\r\n ) {\r\n console.log(\"重要:进度条强制不更新\", errorTasks.length);\r\n } else {\r\n // console.log(\r\n // \"2.进度条为成功状态(异步工具内部更新),错误个数\",\r\n // errorTasks.length,\r\n // );\r\n\r\n onProgress({\r\n percentage: progress,\r\n notShowTip: true,\r\n tip: progress === 100 ? \"上传完成\" : \"上传中\",\r\n completed: completedCount,\r\n total: totalTasks,\r\n active: activeCount,\r\n queued: queue.length,\r\n skipError,\r\n });\r\n }\r\n }\r\n };\r\n // 进度更新出错\r\n const updateProgress_error = () => {\r\n if (onProgress && typeof onProgress === \"function\") {\r\n const progress = calculateProgress();\r\n console.log(\"异步工具内部更新进度条为错误状态\");\r\n onProgress({\r\n percentage: progress,\r\n notShowTip: false,\r\n tip: \"上传出错\",\r\n completed: completedCount,\r\n total: totalTasks,\r\n active: activeCount,\r\n queued: queue.length,\r\n skipError,\r\n });\r\n }\r\n };\r\n\r\n return {\r\n async errorActiveIsFull(index) {\r\n const queueArr = errorTasks.filter(it => it.id === index);\r\n if (queueArr.length > 0) {\r\n cancleTasks = errorTasks.filter(it => it.id !== index);\r\n\r\n const item = queueArr[0];\r\n const result = await this.add(true, {\r\n taskFn: item.task,\r\n index: item.id,\r\n });\r\n console.log(\"重新尝试的结果\", result, queue);\r\n }\r\n },\r\n\r\n // 只适配文件上传出错,块上传直接暂停,不使用此函数\r\n async startResetErrorTask(index) {\r\n // 重尝试失败的任务\r\n const queueArr = errorTasks.filter(item => item.id === index);\r\n\r\n if (queueArr.length > 0) {\r\n errorTasks = errorTasks.filter(it => it.id !== index); // 无论重试成功失败都需要清理原来的数据\r\n\r\n const item = queueArr[0];\r\n // 通过 add 创建新的入队条目(会创建新的 resolve/reject)\r\n const result = await this.add(true, {\r\n taskFn: item.task,\r\n index: item.id,\r\n });\r\n\r\n console.log(\"重新尝试的结果\", result, queue);\r\n }\r\n },\r\n\r\n errorFilehandled(index) {\r\n errorTasks = [...errorTasks, ...queue.filter(item => item.id === index)];\r\n\r\n queue = queue.filter(item => item.id !== index);\r\n },\r\n\r\n startResetCanceledyTask(index) {\r\n // 重置单个任务\r\n const queueArr = cancleTasks.filter(item => item.id === index);\r\n if (queueArr.length > 0) {\r\n queue.push(queueArr[0]);\r\n cancleTasks = cancleTasks.filter(item => item.id !== index);\r\n }\r\n run();\r\n },\r\n\r\n cancelFileUpload(index) {\r\n const _arr = queue.filter(item => item.id === index);\r\n\r\n if (_arr.length > 0) {\r\n cancleTasks = [...cancleTasks, ..._arr];\r\n queue = queue.filter(item => item.id !== index);\r\n\r\n return true;\r\n } else {\r\n // 说明此文件已被队列消耗\r\n return false;\r\n }\r\n },\r\n // 添加单个任务\r\n add(isErrorReset, item) {\r\n return new Promise((resolve, reject) => {\r\n queue.push({ task: item.taskFn, id: item.index, resolve, reject });\r\n run(isErrorReset);\r\n });\r\n },\r\n\r\n // 批量添加任务\r\n runTasks(taskOption) {\r\n return new Promise((resolve, reject) => {\r\n const allResults = [];\r\n let hasError = false;\r\n totalTasks = taskOption.length;\r\n\r\n // 全部任务添加到队列,没添加一次就会进行试运行\r\n taskOption.forEach((item, index) => {\r\n this.add(false, item)\r\n .then(result => {\r\n allResults[index] = result;\r\n // 有结果出错是否停止所有任务,暂时采取停止所有任务\r\n if (\r\n (completedCount + cancleTasks.length === taskOption.length &&\r\n !hasError) ||\r\n (result.status === false && !result.skip)\r\n ) {\r\n resolve(allResults); // 当队列结束或者块队列出现文件错误(且结果为不跳过任务时)则立马返回数据!\r\n }\r\n })\r\n .catch(error => {\r\n hasError = true;\r\n reject(error);\r\n });\r\n });\r\n });\r\n },\r\n\r\n // 暂停所有任务\r\n pause() {\r\n isPaused = true;\r\n },\r\n\r\n // 恢复执行\r\n resume() {\r\n isPaused = false;\r\n },\r\n\r\n // 清空队列\r\n clear() {\r\n queue = [];\r\n errorTasks = [];\r\n completedCount = 0;\r\n totalTasks = 0;\r\n },\r\n\r\n // 获取状态\r\n getStatus() {\r\n return {\r\n queue: queue,\r\n completed: completedCount,\r\n activeCount,\r\n isPaused,\r\n totalTasks,\r\n skipError,\r\n };\r\n },\r\n\r\n // 获取当前进度\r\n getProgress() {\r\n return {\r\n percentage: calculateProgress(),\r\n completed: completedCount,\r\n total: totalTasks,\r\n active: activeCount,\r\n queued: queue.length,\r\n };\r\n },\r\n };\r\n\r\n // 内部执行函数\r\n async function run(isErrorReset = false) {\r\n // 如果暂停了,就等待\r\n if (isPaused) {\r\n if (!pauseResolve) {\r\n await new Promise(resolve => {\r\n pauseResolve = resolve;\r\n });\r\n }\r\n }\r\n\r\n // 执行队列中的任务\r\n while (queue.length > 0 && activeCount < maxConcurrent && !isPaused) {\r\n // 老代码\r\n const { task, id, resolve, reject } = queue.shift();\r\n\r\n activeCount++;\r\n\r\n // {result: boolean, error: string} msg???\r\n // 需要处理块任务和文件任务的结果\r\n task()\r\n .then(result => {\r\n // console.log(\r\n // \"1.任务执行完成的返回结果(异步工具函数队列中一个)\",\r\n // result,\r\n // isErrorReset,\r\n // );\r\n if (result.status) {\r\n if (isErrorReset) {\r\n completedCount++;\r\n skipError--;\r\n updateProgress(false);\r\n } else {\r\n completedCount++;\r\n updateProgress(true);\r\n }\r\n } else {\r\n if (!isErrorReset) {\r\n skipError++; // 不能随便加加,有的时重试的\r\n }\r\n\r\n errorTasks.push({ task, id, resolve, reject }); // resolve和reject无用,已经被使用\r\n\r\n updateProgress_error();\r\n // 块上传并不返回skip,只能停止所有任务\r\n\r\n if (result.skip) {\r\n console.error(\"已经出错的统计的错误任务数组\", errorTasks);\r\n\r\n console.error(\r\n \"===============跳过错误的文件上传================,错误的原因:\",\r\n result.error,\r\n result,\r\n );\r\n } else {\r\n isPaused = true; // 块并发任务停止后续任务,文件应该由结果决定\r\n }\r\n }\r\n\r\n resolve(result);\r\n })\r\n .catch(error => {\r\n console.log(\"上传时候失败\", error);\r\n if (!isErrorReset) {\r\n skipError++; // 不能随便加加,有的时重试的\r\n }\r\n errorTasks.push({ task, id, resolve, reject }); // resolve和reject无用,已经被使用\r\n\r\n updateProgress_error();\r\n reject(error);\r\n })\r\n .finally(() => {\r\n activeCount--;\r\n run(isErrorReset); // 尝试执行下一个任务\r\n });\r\n }\r\n }\r\n}\r\n\r\n// 生成唯一上传编号\r\nfunction generateUploadId(file) {\r\n // 使用文件名+文件大小+时间戳+随机数生成唯一ID\r\n const timestamp = Date.now();\r\n const random = Math.random().toString(36).substr(2, 9);\r\n const fileId = `${file.name}_${file.size}_${timestamp}_${random}`;\r\n\r\n // 清理文件名中的特殊字符\r\n return fileId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\r\n}\r\n\r\n// 文件存无处理\r\nasync function handleFileExistOrNo(fileConfig, addDataBaseLinkConfig) {\r\n const { uploadId, fileHash, fileSize, fileName } = fileConfig;\r\n const {\r\n addProgramVersion: programVersion,\r\n addFileType: fileType,\r\n addDataBaseLink: createLink,\r\n } = addDataBaseLinkConfig;\r\n\r\n // 此处用于网络超时对UI界面的影响,此处是函数入口最适合判断的地方\r\n const timerPromise = new Promise(resolve => {\r\n const timer_upload_file = setTimeout(() => {\r\n resolve({\r\n status: false,\r\n error: \"文件检查超时\",\r\n uploadId,\r\n skip: true,\r\n });\r\n clearTimeout(timer_upload_file);\r\n }, timer.entranceTime);\r\n });\r\n\r\n const fileCheckPromise = (async () => {\r\n try {\r\n const fileCheck = await searchFileIsUploaded(fileHash, fileSize);\r\n return { status: true, fileCheck };\r\n } catch (error) {\r\n return { status: false, error, uploadId };\r\n }\r\n })();\r\n\r\n const check_result = await Promise.race([fileCheckPromise, timerPromise]);\r\n if (!check_result.status) {\r\n // 如若第一波就网络错误,此处需要通知其文件的子进度条出错并且进行统计\r\n // progress_error();\r\n\r\n console.debug(\r\n \"=============网络超时或者网络错误================,以下为check_result的错误结果\",\r\n );\r\n console.debug(check_result);\r\n console.debug(\"=============网络超时或者网络错误================\");\r\n // 网络超时不应该跳过错误文件,而是停止所有任务,暂不处理\r\n // 此处的错误返回只能控制总进度条的值。文件进度条是由块上传控制的\r\n return {\r\n fileIsExist: false,\r\n status: false,\r\n error: \"网络超时或者网络错误\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n\r\n if (check_result.fileCheck) {\r\n if (!createLink) {\r\n return {\r\n fileIsExist: true,\r\n status: true,\r\n uploadId,\r\n uuid: check_result.fileCheck,\r\n fileName: fileName,\r\n };\r\n }\r\n\r\n // 文件存在。直接走新建流程,此处也可能会出错,后续处理\r\n const add_result = await addNewFileId(\r\n check_result.fileCheck,\r\n programVersion,\r\n fileType,\r\n );\r\n\r\n if (add_result.status) {\r\n // 步骤2:文件存在,直接新增文件链接\r\n console.log(\"文件已经存在,直接创建新链接\");\r\n\r\n return {\r\n fileIsExist: true,\r\n status: true,\r\n uploadId,\r\n uuid: check_result.fileCheck,\r\n fileName: fileName,\r\n };\r\n } else {\r\n return {\r\n fileIsExist: true,\r\n status: false,\r\n error: \"文件路径创建失败\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n } else {\r\n return {\r\n fileIsExist: false,\r\n status: true,\r\n uploadId,\r\n uuid: check_result.fileCheck,\r\n fileName: fileName,\r\n };\r\n }\r\n}\r\n\r\n// 核心:上传单个文件。 返回值设置skip可实现是否进行跳过错误的文件上传\r\nasync function uploadSingleFile(\r\n file,\r\n uploadId,\r\n controller,\r\n updateProgress,\r\n progress_error,\r\n addDataBaseLinkConfig,\r\n) {\r\n const {\r\n addProgramVersion: programVersion,\r\n addFileType: fileType,\r\n addDataBaseLink: createLink,\r\n } = addDataBaseLinkConfig;\r\n\r\n const fileHash = await getFileMd5Safe(file);\r\n const fileSize = file.size;\r\n const fileName = file.name;\r\n\r\n const setStep = (percentage, notShowTip, tip) => {\r\n updateProgress({\r\n percentage: percentage,\r\n notShowTip: notShowTip,\r\n tip: tip,\r\n });\r\n };\r\n\r\n try {\r\n setStep(0, false, \"解析中\");\r\n\r\n console.log(\r\n \"%c 文件上传中:\",\r\n \"color: #2196F3; font-weight: bold;\",\r\n fileName,\r\n );\r\n\r\n // 步骤1:检查文件是否存在\r\n const fileStorageResult = await handleFileExistOrNo(\r\n { uploadId, fileHash, fileSize, fileName },\r\n addDataBaseLinkConfig,\r\n );\r\n\r\n console.log(\"是否分块上传?\", !fileStorageResult.fileIsExist);\r\n\r\n // 文件存在或者内部错误时返回\r\n if (fileStorageResult.fileIsExist || fileStorageResult.error) {\r\n if (fileStorageResult.status) {\r\n setStep(100, false, \"已完成\");\r\n return fileStorageResult;\r\n } else {\r\n progress_error();\r\n return fileStorageResult;\r\n }\r\n }\r\n\r\n setStep(0, false, \"准备中\");\r\n\r\n // 步骤2:上传所有切片\r\n // 准备切片\r\n const chunks = await createChunks(file, [], chunkSegmentationSize);\r\n console.groupCollapsed(\r\n \"%c 分片上传流程\",\r\n \"color: #2196F3; font-weight: bold;\",\r\n );\r\n console.log(\"切片列表\", chunks);\r\n\r\n // 上传切片\r\n // 1:此处错误处理一部分在并发控制器里面进行(控制自己本身),逻辑:直接改变文件的进度条,进行错误状态,数字文字等回显\r\n // 2:此处错误处理(用于文件并发控制检查所有切片是否已经完成),目前两片逻辑不可合并\r\n const chunk_AllUploded_error_esult = await uploadChunks(\r\n chunks,\r\n fileHash,\r\n file.name,\r\n uploadId,\r\n controller,\r\n );\r\n\r\n // 检查切片上传结果\r\n if (chunk_AllUploded_error_esult.length > 0) {\r\n console.debug(\r\n \"=============文件分片上传失败================,以下为分片的错误列表:\",\r\n chunk_AllUploded_error_esult,\r\n );\r\n\r\n return {\r\n status: false,\r\n error: \"文件块上传失败\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n\r\n setStep(99, true, \"上传中\");\r\n\r\n // 步骤3:请求后端合并切片\r\n const uploadedFileIsMerge = await informServeUploaded(fileHash, fileSize);\r\n console.log(\"合并切片,结果:\", uploadedFileIsMerge);\r\n\r\n if (!uploadedFileIsMerge) {\r\n setStep(0, false, \"文件合并失败\");\r\n\r\n return {\r\n status: false,\r\n // skip: false,\r\n error: \"文件合并失败\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n\r\n console.groupEnd();\r\n\r\n // 步骤4:轮询检查文件落盘状态\r\n const resultFile = await startCheckfileStatus(\r\n fileHash,\r\n timer.dropStatePollTime,\r\n timer.dropStateOverTime,\r\n );\r\n\r\n if (!resultFile.result) {\r\n // 落盘失败\r\n setStep(0, false, resultFile.Message);\r\n\r\n return {\r\n status: false,\r\n error: resultFile.Message,\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n\r\n // 步骤5:是否自动创建数据库路径\r\n if (!createLink) {\r\n setStep(100, false, \"已完成\");\r\n\r\n return {\r\n status: true,\r\n uploadId,\r\n uuid: resultFile.fileId,\r\n fileName: fileName,\r\n };\r\n }\r\n\r\n // 步骤6:请求数据库创建新的文件路径\r\n const add_result = await addNewFileId(\r\n resultFile.fileId,\r\n programVersion,\r\n fileType,\r\n );\r\n\r\n if (add_result.status) {\r\n // 创建成功\r\n setStep(100, false, \"已完成\");\r\n return {\r\n status: true,\r\n uploadId,\r\n uuid: resultFile.fileId,\r\n fileName: fileName,\r\n };\r\n } else {\r\n // 创建失败\r\n setStep(0, false, \"内部错误\");\r\n\r\n return {\r\n status: false,\r\n error: \"内部错误\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n } catch (error) {\r\n // 总错误处理\r\n console.debug(\r\n \"=============单个文件上传出错(意料之外的出错)================,未知出错:\",\r\n error,\r\n );\r\n setStep(0, false, \"未知出错\");\r\n return { status: false, error, uploadId, skip: true };\r\n }\r\n}\r\n\r\n// 获取文件的md5\r\nasync function getFileMd5Safe(file_blob) {\r\n const spark = new SparkMD5.ArrayBuffer();\r\n const chunkSize = 5 * 1024 * 1024;\r\n const chunks = Math.ceil(file_blob.size / chunkSize);\r\n\r\n for (let i = 0; i < chunks; i++) {\r\n const start = i * chunkSize;\r\n const end = Math.min(start + chunkSize, file_blob.size);\r\n const chunk = file_blob.slice(start, end);\r\n // 使用arrayBuffer()替代FileReader(更简洁,自动管理内存)\r\n const arrayBuffer = await chunk.arrayBuffer();\r\n spark.append(arrayBuffer);\r\n if (i % 100 === 0) {\r\n await new Promise(resolve => setTimeout(resolve, 0));\r\n }\r\n }\r\n\r\n return spark.end();\r\n}\r\n\r\n// 生成分块数组\r\nasync function createChunks(\r\n file,\r\n uploadedChunks = [],\r\n chunkSize = 5 * 1024 * 1024,\r\n) {\r\n const chunks = [];\r\n let cur = 0; // 当前读取位置\r\n let index = 0; // 分片索引\r\n\r\n // 循环创建分片,直到文件读取完\r\n while (cur < file.size) {\r\n const chunk = file.slice(cur, cur + chunkSize);\r\n const chunkMd5 = await getChunkMD5(chunk);\r\n\r\n // 如果这个分片还没有上传过\r\n if (!uploadedChunks.includes(index)) {\r\n chunks.push({\r\n chunk: chunk, // 实际的分片数据\r\n index: index, // 分片索引\r\n start: cur, // 分片在文件中的起始位置\r\n end: Math.min(cur + chunkSize, file.size), // 分片结束位置\r\n hash: chunkMd5, // 分片哈希(可后续计算)\r\n size: Math.min(chunkSize, file.size - cur), // 分片实际大小\r\n });\r\n }\r\n\r\n cur += chunkSize; // 移动到下一个分片的起始位置\r\n index++; // 分片索引增加\r\n }\r\n return chunks;\r\n}\r\n\r\n// 获取文件块的md5\r\nfunction getChunkMD5(chunkBlob) {\r\n return new Promise(resolve => {\r\n const reader = new FileReader();\r\n const spark = new SparkMD5.ArrayBuffer();\r\n\r\n reader.onload = function (e) {\r\n spark.append(e.target.result);\r\n resolve(spark.end());\r\n };\r\n\r\n reader.readAsArrayBuffer(chunkBlob);\r\n });\r\n}\r\n\r\n// 上传切片(文件块)文件块增加上传块失败是否停止的配置项。\r\nasync function uploadChunks(chunks, fileHash, fileName, uploadId, controller) {\r\n const total = chunks.length;\r\n\r\n const uploadPromises = chunks.map((chunk, index) => {\r\n const fn = async () => {\r\n const requstData = {\r\n filename: fileName,\r\n index: chunk.index,\r\n total: total,\r\n identifier: fileHash,\r\n chunkIdentifier: chunk.hash,\r\n file: chunk.chunk,\r\n };\r\n\r\n // 测试块上传失败的代码\r\n // return {\r\n // status: false,\r\n // msg: \"文件块上传失败\",\r\n // };\r\n\r\n try {\r\n const chunkIsExist = await searchChunkIsUploaded(fileHash, chunk.hash);\r\n if (chunkIsExist) {\r\n return {\r\n status: true,\r\n msg: \"文件块已经存在了\",\r\n };\r\n }\r\n } catch (error) {\r\n return {\r\n status: false,\r\n msg: error,\r\n };\r\n }\r\n\r\n const timerPromise = new Promise(resolve => {\r\n const timer_upload_chunk = setTimeout(() => {\r\n // 重复,进度条status回显+1,最大90\r\n // updateProgress({\r\n // percentage: 0,\r\n // notShowTip: false,\r\n // tip: \"文件错误\",\r\n // });\r\n resolve({\r\n status: false,\r\n msg: \"文件错误\",\r\n });\r\n clearTimeout(timer_upload_chunk);\r\n }, timer.uploadChunkTime);\r\n });\r\n\r\n const uplodChunkPromise = (async () => {\r\n try {\r\n const result = await api.uploadFileChunk(requstData);\r\n\r\n if (result.code === \"Success\") {\r\n return {\r\n status: true,\r\n msg: \"文件块上传成功\",\r\n };\r\n } else {\r\n return {\r\n status: false,\r\n msg: \"文件块上传失败\",\r\n };\r\n }\r\n } catch (error) {\r\n return {\r\n status: false,\r\n msg: \"文件块上传失败\",\r\n };\r\n // throw new Error(`上传过程异常: ${error.message || error}`);\r\n }\r\n })();\r\n\r\n // const uplodChunkPromise = new Promise(async(resolve, reject) => {\r\n // try {\r\n // const result = await _this.$store.dispatch(\r\n // \"app/uploadFileChunk\",\r\n // requstData,\r\n // );\r\n\r\n // // const test_boolean = Math.random() > 0.9 ? false : true;\r\n\r\n // if (result.code === \"Success\") {\r\n // // console.log(\"文件块内部上传成功\", test_boolean);\r\n // resolve({\r\n // status: true,\r\n // msg: \"文件块上传成功\",\r\n // });\r\n // } else {\r\n // // console.error(\"文件块内部上传失败\", test_boolean);\r\n\r\n // resolve({\r\n // status: false,\r\n // msg: \"文件块上传失败\",\r\n // });\r\n // }\r\n // } catch (error) {\r\n // resolve({\r\n // status: false,\r\n // msg: error,\r\n // });\r\n // }\r\n // });\r\n\r\n const result = await Promise.race([uplodChunkPromise, timerPromise]);\r\n\r\n console.log(\"块上传,序号:\", index, result);\r\n\r\n return result;\r\n };\r\n\r\n return { taskFn: fn, index: index };\r\n });\r\n\r\n const result = await controller.runTasks(uploadPromises);\r\n\r\n // 通过并发控制器执行\r\n return result.filter(item => item.status !== true);\r\n}\r\n\r\n// 通知文件块需要合并\r\nasync function informServeUploaded(fileMd, FileSize) {\r\n const result = await api.filesAllUoloaded({\r\n size: FileSize,\r\n identifier: fileMd,\r\n });\r\n\r\n return result.code === \"Success\";\r\n}\r\n\r\n// 检查文件块是否已经存在\r\nasync function searchChunkIsUploaded(fileMd5, chunkMd5) {\r\n const result = await api.searchChunkIsUploaded({\r\n identifier: fileMd5,\r\n chunkIdentifier: chunkMd5,\r\n });\r\n\r\n return result.data;\r\n}\r\n\r\n// 检查文件合并后的落盘状态\r\nasync function startCheckfileStatus(fileMd5, poll = 4000, overTime = 10000) {\r\n let timer1 = 0;\r\n let timer2 = 0;\r\n\r\n const request = new Promise((resolve, reject) => {\r\n timer1 = setInterval(async () => {\r\n const result = await checkfileStatus(fileMd5);\r\n // console.log(\"请求一次文件状态:\", result.data.status)\r\n\r\n if (result.code === \"Success\" && result.data.status === \"STORAGE\") {\r\n // console.log(\"文件已经存储\", result.data.status)\r\n resolve({\r\n result: true,\r\n Message: \"文件状态成功\",\r\n fileId: result.data.uuid,\r\n version_id: result.version,\r\n });\r\n } else if (result.code === \"Success\" && result.data.status === \"ERROR\") {\r\n // console.log(\"文件正在上传\", result.data.status)\r\n resolve({\r\n result: false,\r\n Message: \"文件状态错误\",\r\n fileId: result.data.uuid,\r\n version_id: result.version,\r\n });\r\n }\r\n }, poll);\r\n });\r\n\r\n const timeout = new Promise((resolve, reject) => {\r\n timer2 = setTimeout(() => {\r\n console.log(\"文件上传超时了\");\r\n resolve({\r\n result: false,\r\n Message: \"文件合并超时\",\r\n });\r\n }, overTime);\r\n });\r\n\r\n return Promise.race([request, timeout])\r\n .then(res => {\r\n if (timer1) {\r\n clearInterval(timer1);\r\n timer1 = null;\r\n }\r\n if (timer2) {\r\n clearTimeout(timer2);\r\n timer2 = null;\r\n }\r\n\r\n if (res.result) {\r\n return {\r\n result: true,\r\n fileId: res.fileId,\r\n version_id: res.version_id,\r\n Message: res.Message,\r\n };\r\n } else {\r\n return {\r\n result: false,\r\n Message: res.Message,\r\n };\r\n }\r\n })\r\n .catch(err => {\r\n return err;\r\n });\r\n}\r\n// 检查文件落盘状态的工具函数-检查落盘状态\r\nasync function checkfileStatus(fileMd5) {\r\n const result = await api.checkfileStatus({\r\n identifier: fileMd5,\r\n });\r\n\r\n return result;\r\n}\r\n\r\n// 检查文件是否已经存在\r\nasync function searchFileIsUploaded(md5, filesize) {\r\n const result = await api.searchFileIsUploaded({\r\n identifier: md5,\r\n size: filesize,\r\n });\r\n\r\n // 文件存在值为有长度的字符串,不存在值为null\r\n if (result) {\r\n return result.data;\r\n } else {\r\n return \"\";\r\n }\r\n}\r\n\r\n// 增加新的数据库路径;直接走此方法所有的图片都是全局图片\r\nasync function addNewFileId(id, version_id, fileType) {\r\n let result = null;\r\n\r\n if (fileType === \"txt\") {\r\n // txt表示所有文件都可以上传。\r\n // version_id为0说明不在媒资管理中上传。走的是系统总上传。基本与txt绑定使用\r\n if (version_id === 0) {\r\n result = await api.addNewFileOfTxt({\r\n uuid: id,\r\n });\r\n } else {\r\n result = await api.addNewFileOfTxt({\r\n version_id: version_id,\r\n uuid: id,\r\n });\r\n }\r\n } else if (fileType === \"video\") {\r\n result = await api.addNewFileOfVideo({\r\n version_id: version_id,\r\n uuid: id,\r\n });\r\n } else if (fileType === \"audio\") {\r\n result = await api.addNewFileOfAudio({\r\n version_id: version_id,\r\n uuid: id,\r\n });\r\n } else if (fileType === \"subTitle\") {\r\n result = await api.addNewFileOfSubTitle({\r\n version_id: version_id,\r\n uuid: id,\r\n });\r\n } else if (fileType === \"pictrue\") {\r\n result = await api.addNewFileOfPic({\r\n version_id: version_id,\r\n video_id: 0,\r\n uuid: id,\r\n });\r\n }\r\n\r\n if (result.code === 0) {\r\n if (result.data.length < 1) {\r\n return {\r\n status: false,\r\n message: \"文件路径创建失败\",\r\n };\r\n } else {\r\n return {\r\n status: true,\r\n message: \"文件路径创建成功\",\r\n };\r\n }\r\n } else {\r\n return {\r\n status: false,\r\n message: \"文件路径创建失败\",\r\n };\r\n }\r\n}\r\n","<template>\r\n <div class=\"upload-multiple\">\r\n <!-- input核心 -->\r\n <input\r\n ref=\"multiplePloadInput\"\r\n type=\"file\"\r\n style=\"display: none\"\r\n :multiple=\"multiple\"\r\n :accept=\"limitFileType\"\r\n @change=\"handleSelectedMultipleFiles\"\r\n />\r\n\r\n <div class=\"upload-multiple-box\">\r\n <!-- 上传组件本身 -->\r\n <div\r\n ref=\"upLoded_box\"\r\n class=\"multiple_upload_area\"\r\n :class=\"multipleUploadAreaClass()\"\r\n @click=\"reviewUploadMultipleFiles\"\r\n @dragover.prevent=\"onDragOver\"\r\n @dragleave.prevent=\"onDragLeave\"\r\n @drop.prevent=\"onDrop\"\r\n >\r\n <!-- 自定义loading遮罩,只作用于当前组件 -->\r\n <div\r\n v-if=\"isUploading\"\r\n class=\"upload-loading-mask\"\r\n :style=\"setUploadingLoadingMaskStyle()\"\r\n />\r\n <!-- 上传图标 -->\r\n <div v-if=\"showIconTip\"><i class=\"el-icon-upload\" /></div>\r\n <div>{{ startButtonText }}</div>\r\n <!-- 具名插槽 -->\r\n <slot name=\"tips\" />\r\n </div>\r\n\r\n <!-- 上传成功显示的图片 -->\r\n <div\r\n v-if=\"pictureConfig.show && showSuccessPicture\"\r\n class=\"upload-multiple-box-right\"\r\n >\r\n <!-- 清除图片按钮 -->\r\n <div class=\"upload-multiple-box-close\" @click.stop=\"clearPicture\">\r\n <i class=\"el-icon-close\" />\r\n </div>\r\n <img :src=\"pictureConfig.url\" :alt=\"pictureConfig.altText\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 全部上传按钮 -->\r\n <el-button\r\n v-if=\"isShowAllUploadButton\"\r\n type=\"primary\"\r\n class=\"upload_button\"\r\n :disabled=\"isUploading || needUploadFilesArr.length === 0\"\r\n @click=\"startUploadMultipleFiles\"\r\n >\r\n 全部文件开始上传\r\n </el-button>\r\n\r\n <!-- 底部区域 -->\r\n <div v-if=\"model === 'table'\" class=\"upload-multiple-table\">\r\n <Upload_table\r\n :needUploadFilesArr=\"needUploadFilesArr\"\r\n :fileConfig=\"fileConfig\"\r\n :fileType=\"addDataBaseLinkConfig.addFileType\"\r\n :isUploading=\"isUploading\"\r\n @delteSelectedFile=\"delteSelectedFile\"\r\n @cancelFileUpload=\"cancelFileUpload\"\r\n @resetFileUpload=\"resetFileUpload\"\r\n @handleSelectionChange=\"tableSelectionChange\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"model === 'info'\" class=\"multiple_upload_list\">\r\n <span class=\"tip_title\">\r\n <!-- 标题-显示栏 -->\r\n <span class=\"title\">\r\n <div>文件列表</div>\r\n <transition name=\"totalProgress\" mode=\"out-in\">\r\n <div v-if=\"needUploadFilesArr.length > 0\" class=\"total_progress\">\r\n <div class=\"logo\" />\r\n <!-- 暂时关闭总进度条的错误处理 -->\r\n <!-- <span>总进度({{ fileConfig.tip }}):</span> -->\r\n <!-- <el-progress\r\n :percentage=\"fileConfig.overallProgress\"\r\n :color=\"colors\"\r\n :stroke-width=\"8\"\r\n ></el-progress> -->\r\n <span>总进度:</span>\r\n <div v-if=\"fileConfig.uploadController\">\r\n <el-tag size=\"mini\" :type=\"isDanger\"\r\n >上传错误:{{ fileConfig.skipError_num }}</el-tag\r\n >\r\n <el-tag size=\"mini\" type=\"\"\r\n >上传成功:{{ fileConfig.completed_num }}</el-tag\r\n >\r\n <el-tag size=\"mini\" type=\"\"\r\n >文件总数:{{ fileConfig.filetotal_num }}</el-tag\r\n >\r\n </div>\r\n </div>\r\n </transition>\r\n </span>\r\n <!-- 标题-操作栏 -->\r\n <span>\r\n <el-button\r\n size=\"mini\"\r\n type=\"\"\r\n :disabled=\"isUploading || needUploadFilesArr.length === 0\"\r\n @click=\"handleSelectAllFile\"\r\n >全选所有文件</el-button\r\n >\r\n <el-button\r\n size=\"mini\"\r\n type=\"danger\"\r\n :disabled=\"isUploading || needUploadFilesArr.length === 0\"\r\n @click=\"delteSelectedFile\"\r\n >移除所选文件</el-button\r\n >\r\n </span>\r\n </span>\r\n\r\n <!-- 上传队列 -->\r\n <div class=\"selected_list_area\">\r\n <div v-if=\"needUploadFilesArr.length > 0\" class=\"selected_list\">\r\n <Card_2\r\n v-for=\"(item, index) in needUploadFilesArr\"\r\n :key=\"index\"\r\n :index=\"index\"\r\n :file-config=\"item\"\r\n @cancelFileUpload=\"cancelFileUpload\"\r\n @resetFileUpload=\"resetFileUpload\"\r\n @handleClickOnlyFile=\"handleClickOnlyFile\"\r\n />\r\n </div>\r\n <div v-else class=\"no_file\">\r\n <i class=\"el-icon-document\" />\r\n <div>暂无文件,请点击或拖拽文件到上传区域</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<!-- 需要给这个组件的网络请求重构\r\n 1.目标:外界可传入自己的axios,内部直接使用外部的axios发请求.这样可以解决token的问题.缺点是必须在vu.use时候传入axios实例\r\n 2. -->\r\n\r\n<script>\r\nimport { fileTypeValidators } from \"./util.js\";\r\nimport Card_2 from \"./components/UploadCard_Ver_Second/index.vue\";\r\nimport Upload_table from \"./components/Upload_table/index.vue\";\r\nimport uploadFilesConfig_AndStart from \"./upload.js\";\r\n\r\nexport default {\r\n name: \"KukanUpload\",\r\n components: {\r\n Card_2,\r\n Upload_table,\r\n },\r\n props: {\r\n // 秒传(文件已存在则跳过上传);待做\r\n // 分片队列最大长度;待做\r\n // 上传文件限制;待做\r\n // 回调函数。待做\r\n // 断网自动重连开关(重试策略);待做\r\n // 断点续传开关;尚不支持\r\n // 文件上传时是否允许取消\r\n\r\n // 添加数据库链接配置\r\n addDataBaseLinkConfig: {\r\n required: false,\r\n type: Object,\r\n default: () => {\r\n return {\r\n // 文件上传成功之后或者检索文件已存在时是否创建数据库链接\r\n addDataBaseLink: false,\r\n // 文件类型,用于检查文件类型是否正确以及增加数据库链接\r\n addFileType: \"\",\r\n // 节目版本,用于检查文件是否存在以及创建数据库的路径\r\n addProgramVersion: 0,\r\n };\r\n },\r\n },\r\n // 选择完文件是否开启自动传输\r\n autoUpload: {\r\n required: false,\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 多选\r\n multiple: {\r\n required: false,\r\n type: Boolean,\r\n },\r\n // 开始按钮的提示文字\r\n startButtonText: {\r\n required: false,\r\n type: String,\r\n default: \"\",\r\n },\r\n // 是否显示上传成功的图片?当前只支持small模式。后续应当拓冲\r\n showSuccessPicture: {\r\n required: false,\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 上传区域的UI样式。small/mill/info\r\n model: {\r\n required: true,\r\n type: String,\r\n default: \"small\",\r\n },\r\n // 是否显示提示文字上方的logo\r\n showIconTip: {\r\n required: false,\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 不显示上传区域边框\r\n noneBoder: {\r\n required: false,\r\n type: Boolean,\r\n default: false,\r\n },\r\n // 配置内部的请求api\r\n apiObj: {\r\n required: false,\r\n type: Object,\r\n default: () => {\r\n return {};\r\n },\r\n },\r\n maxFileConcurrent: {\r\n required: false,\r\n type: Number,\r\n default: 2,\r\n },\r\n maxFileChunkConcurrent: {\r\n required: false,\r\n type: Number,\r\n default: 2,\r\n },\r\n },\r\n data() {\r\n return {\r\n // showSuccessPicture属性显示图片的配置\r\n pictureConfig: {\r\n show: false,\r\n url: \"\",\r\n altText: \"封面图片\",\r\n },\r\n // 总文件队列上传的配置\r\n fileConfig: {\r\n overallProgress: 0,\r\n notShowTip: true,\r\n tip: \"等待上传\",\r\n uploadController: null,\r\n skipError_num: 0,\r\n filetotal_num: 0,\r\n completed_num: 0,\r\n maxFileConcurrent: this.maxFileConcurrent,\r\n },\r\n // 创建路径需要知道节目id\r\n program_id: 0,\r\n // 上传收集的文件数组\r\n needUploadFilesArr: [],\r\n // 单文件分块队列上传配置\r\n multipleChunkConfig: {\r\n fileQueues: new Map(), // 文件队列映射\r\n progressCallbacks: new Map(), // 进度回调映射\r\n uploadTasks: new Map(), // 上传任务映射\r\n chunkSize: 1 * 1024 * 1024,\r\n maxConcurrent: this.maxFileChunkConcurrent,\r\n },\r\n };\r\n },\r\n computed: {\r\n limitFileType() {\r\n if (this.addDataBaseLinkConfig.addFileType === \"txt\") {\r\n return \"\";\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"video\") {\r\n return \"video/*\";\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"pictrue\") {\r\n return \"image/*\";\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"audio\") {\r\n return \"audio/*\";\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"subTitle\") {\r\n return \".srt, .vtt, .ass, .ssa, .smi, .webvtt, .ttml, .dfxp, .lrc, .vtt, .srt, .txt\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n // 是否显示全部上传按钮\r\n isShowAllUploadButton() {\r\n if (this.model === \"info\" && this.autoUpload !== true) {\r\n return true;\r\n }\r\n },\r\n // 是否显示批量上传的列表\r\n isDanger() {\r\n if (this.fileConfig.skipError_num > 0) {\r\n return \"danger\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n currentFileUploadedArr() {\r\n return this.fileConfig.uploadController.getStatus();\r\n },\r\n // 判断是否正在上传(单个或批量)\r\n isUploading() {\r\n // 批量上传状态:检查是否有文件正在上传中\r\n if (this.needUploadFilesArr && this.needUploadFilesArr.length > 0) {\r\n const hasUploading = this.needUploadFilesArr.some(\r\n item =>\r\n item.tip === \"上传中\" ||\r\n (item.notShowTip &&\r\n item.uploadProgress >= 0 &&\r\n item.uploadProgress < 100),\r\n );\r\n return hasUploading;\r\n }\r\n\r\n return false;\r\n },\r\n },\r\n mounted() {},\r\n methods: {\r\n // 父组件事件集合\r\n // 文件删除后的回调\r\n removeFileInform(removeArr) {\r\n this.$emit(\"removeFile\", removeArr);\r\n },\r\n // 通知父组件刷新数据,已经上传完成了\r\n informUploadedOfRefresh() {\r\n this.$emit(\"informTableOfRefresh\");\r\n },\r\n // 上传完成的回调,返回上传结果\r\n uploadedResult(result) {\r\n this.$emit(\"handelResult\", result);\r\n },\r\n // 获取上传成功的文件id列表\r\n uploadedUUIDs(_arr) {\r\n this.$emit(\"getUUID\", _arr);\r\n },\r\n // 上传开始\r\n uploadStart() {\r\n this.$emit(\"uploadStart\");\r\n },\r\n\r\n tableSelectionChange(selectIds) {\r\n this.needUploadFilesArr.forEach(item => {\r\n item.isSelected = selectIds.includes(item.index);\r\n });\r\n },\r\n\r\n // 上传开始后制定其他的文件筛选逻辑\r\n // 返回 Promise,父组件通过回调在需要时调用 `done(filterFiles)` 来决议\r\n uploadingOtherFilterFun(needUploadFilesArr) {\r\n return new Promise(resolve => {\r\n let resolved = false;\r\n\r\n const done = filterFiles => {\r\n if (Array.isArray(filterFiles)) {\r\n this.needUploadFilesArr = filterFiles;\r\n }\r\n console.log(\r\n \"上传开始后指定其他的文件筛选逻辑\",\r\n this.needUploadFilesArr,\r\n );\r\n if (!resolved) {\r\n resolved = true;\r\n resolve();\r\n }\r\n };\r\n\r\n // 发出事件并传入回调,监听方应在合适时机调用该回调\r\n this.$emit(\"otherFilterFiles\", needUploadFilesArr, done);\r\n\r\n // 如果没有任何监听器或监听器没有调用回调,保证不会永远等待\r\n // 在短时间内自动继续(例如 0ms 微任务后),以便保持向后兼容\r\n setTimeout(() => {\r\n if (!resolved) {\r\n resolved = true;\r\n resolve();\r\n }\r\n }, 500);\r\n });\r\n },\r\n\r\n // 还原配置\r\n resetConfig() {\r\n // 清理控制器与缓存,恢复 UI 状态\r\n if (this.fileConfig && this.fileConfig.uploadController) {\r\n try {\r\n this.pauseAllQueue();\r\n this.fileConfig.uploadController.clear();\r\n } catch (error) {\r\n console.error(error);\r\n }\r\n }\r\n this.fileConfig.uploadController = null;\r\n this.multipleChunkConfig.uploadTasks = new Map();\r\n this.multipleChunkConfig.fileQueues = new Map();\r\n this.needUploadFilesArr = [];\r\n // 根据 skipError 或 completed 设置提示\r\n if (this.fileConfig.skipError_num > 0) {\r\n this.fileConfig.tip = \"上传出错\";\r\n this.fileConfig.notShowTip = false;\r\n } else {\r\n this.fileConfig.tip = \"等待上传\";\r\n this.fileConfig.notShowTip = true;\r\n this.fileConfig.overallProgress = 0;\r\n }\r\n },\r\n // 设置上传loading遮罩的style样式\r\n setUploadingLoadingMaskStyle() {\r\n return { \"--spinner-size\": this.model === \"mini\" ? \"20px\" : \"40px\" };\r\n },\r\n // 设置上传区域的class样式\r\n multipleUploadAreaClass() {\r\n return {\r\n multiple_upload_area_disabled: this.isUploading,\r\n small_model: this.model === \"small\",\r\n mini_model: this.model === \"mini\",\r\n };\r\n },\r\n // 每个列表的上传状态的样式\r\n uploadingTextStyle(text) {\r\n // 第一个未知,第二个stauts超时,第三个上传块超时\r\n if (\r\n text === \"出错\" ||\r\n text === \"查询文件地址超时\" ||\r\n text === \"上传出错\"\r\n ) {\r\n return \"uploading_error\";\r\n } else if (text === \"已完成\") {\r\n return \"uploading_success\";\r\n } else if (text === \"等待上传\") {\r\n return \"uploading_wait\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n // 设置图片的url\r\n setPictureConfig(uuid) {\r\n if (!uuid) {\r\n return;\r\n }\r\n\r\n const serveUrl = `${process.env.VUE_APP_ZT_BASE_API}/resources/open/view/image?`;\r\n\r\n this.pictureConfig.show = true;\r\n this.pictureConfig.url = serveUrl + `uuid=${uuid}`;\r\n this.pictureConfig.altText = \"读取成功\";\r\n },\r\n // 清理图片\r\n clearPicture() {\r\n this.pictureConfig.show = false;\r\n this.pictureConfig.url = \"\";\r\n this.pictureConfig.altText = \"封面图片\";\r\n },\r\n // 总进度条的状态\r\n totalProgressStatus(fileConfig) {\r\n if (!fileConfig.notShowTip) {\r\n if (fileConfig.overallProgress < 100) {\r\n return \"exception\";\r\n } else {\r\n return null;\r\n }\r\n } else {\r\n if (fileConfig.overallProgress > 99) {\r\n return \"success\";\r\n }\r\n return null;\r\n }\r\n },\r\n // 文件进度条\r\n progressStatus(progress) {\r\n if (progress < 100) {\r\n return \"active\";\r\n } else {\r\n return \"success\";\r\n }\r\n },\r\n // 暂停所有队列\r\n pauseAllQueue() {\r\n // 暂停所有任务\r\n this.fileConfig.uploadController.pause(); // 成功取消\r\n this.multipleChunkConfig.fileQueues.forEach((value, key, map) => {\r\n value.pause();\r\n }); // 成功取消\r\n },\r\n // 检查文件名称是否已经存在。应当使用id,此处逻辑有错误,此函数暂时无用,暂不处理。2025/12/17\r\n async searchFilePathIsExist(name) {\r\n let arr = [];\r\n\r\n const result = await this.$store.dispatch(\"app/getMediaList\", {\r\n currentFileType: this.addDataBaseLinkConfig.addFileType,\r\n version_id: this.addDataBaseLinkConfig.programVersion,\r\n page_num: 1,\r\n page_sizet: 10,\r\n file_id: \"\",\r\n file_name: name,\r\n imageIsOnlyImg: this.imageIsOnlyImgOfButton === 1,\r\n });\r\n\r\n if (result.code === 0) {\r\n if (this.addDataBaseLinkConfig.addFileType === \"txt\") {\r\n arr = result.data.doc_list;\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"video\") {\r\n arr = result.data.video_list;\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"audio\") {\r\n arr = result.data.audio_list;\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"subTitle\") {\r\n arr = result.data.srt_list;\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"pictrue\") {\r\n arr = result.data.pic_list;\r\n }\r\n }\r\n\r\n if (arr.length > 1) {\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n },\r\n // 全选列表所有文件\r\n handleSelectAllFile() {\r\n this.needUploadFilesArr.forEach(item => {\r\n item.isSelected = true;\r\n });\r\n },\r\n // 重试取消的文件\r\n resetFileUpload(item) {\r\n if (item.tip === \"上传出错\") {\r\n // 目前已知流程错误可以重试\r\n // 清除小块的队列\r\n const id = item.index;\r\n const fileQueue = this.multipleChunkConfig.fileQueues;\r\n const controller =\r\n fileQueue && typeof fileQueue.get === \"function\"\r\n ? fileQueue.get(id)\r\n : fileQueue[id];\r\n\r\n if (controller && typeof controller.resume === \"function\") {\r\n controller.resume();\r\n controller.clear();\r\n }\r\n\r\n // 如果已经有两个重试的在执行,应该直接放进队列或者显示队列已满,稍后再试\r\n const status =\r\n this.fileConfig &&\r\n this.fileConfig.uploadController &&\r\n typeof this.fileConfig.uploadController.getStatus === \"function\"\r\n ? this.fileConfig.uploadController.getStatus()\r\n : { activeCount: 0 };\r\n\r\n if (status.activeCount >= this.fileConfig.maxFileConcurrent) {\r\n console.debug(\"队列已满\", this.fileConfig.uploadController);\r\n if (\r\n this.fileConfig &&\r\n this.fileConfig.uploadController &&\r\n typeof this.fileConfig.uploadController.errorActiveIsFull ===\r\n \"function\"\r\n ) {\r\n this.fileConfig.uploadController.errorActiveIsFull(item.index);\r\n item.tip = \"上传中\";\r\n console.log(\"item是否修改成功\", item.tip);\r\n }\r\n } else {\r\n console.debug(\"队列未满\", this.fileConfig.uploadController);\r\n this.fileConfig.uploadController.startResetErrorTask(item.index);\r\n }\r\n } else if (item.tip === \"已取消\") {\r\n // 如果已经有两个重试的在执行,应该直接放进队列或者显示队列已满,稍后再试\r\n const status =\r\n this.fileConfig &&\r\n this.fileConfig.uploadController &&\r\n typeof this.fileConfig.uploadController.getStatus === \"function\"\r\n ? this.fileConfig.uploadController.getStatus()\r\n : { activeCount: 0 };\r\n\r\n if (status.activeCount >= this.fileConfig.maxFileConcurrent) {\r\n if (\r\n this.fileConfig &&\r\n this.fileConfig.uploadController &&\r\n typeof this.fileConfig.uploadController.errorActiveIsFull ===\r\n \"function\"\r\n ) {\r\n item.tip = \"上传中\";\r\n\r\n this.fileConfig.uploadController.startResetCanceledyTask(\r\n item.index,\r\n );\r\n\r\n console.log(\"item是否修改成功\", item.tip);\r\n }\r\n } else {\r\n this.fileConfig.uploadController.startResetCanceledyTask(item.index);\r\n }\r\n }\r\n },\r\n // 取消上传的文件\r\n cancelFileUpload(item) {\r\n if (!this.fileConfig.uploadController) {\r\n this.needUploadFilesArr = this.needUploadFilesArr.filter(file => {\r\n return file.index !== item.index;\r\n });\r\n\r\n return;\r\n }\r\n\r\n const result = this.fileConfig.uploadController.cancelFileUpload(\r\n item.index,\r\n );\r\n\r\n if (result) {\r\n this.$set(item, \"notShowTip\", false);\r\n this.$set(item, \"tip\", \"已取消\");\r\n } else {\r\n this.$message.error(\"正在上传,不可取消\");\r\n }\r\n },\r\n // 点击列表中选择的文件\r\n handleClickOnlyFile(item) {\r\n item.isSelected = !item.isSelected;\r\n },\r\n // 移除待上传文件的\r\n delteSelectedFile() {\r\n const _neerUploadFilesArr = [];\r\n const _noNeerUploadFilesArr = [];\r\n\r\n this.needUploadFilesArr.forEach(item => {\r\n if (!item.isSelected) {\r\n _neerUploadFilesArr.push(item);\r\n } else {\r\n item.isSelected = false;\r\n _noNeerUploadFilesArr.push(item);\r\n }\r\n });\r\n\r\n if (this.needUploadFilesArr.length === _neerUploadFilesArr.length) {\r\n this.$message(\"没有需要移除的文件\");\r\n return\r\n }\r\n\r\n // 需要添加移除文件的钩子函数\r\n this.removeFileInform(_noNeerUploadFilesArr);\r\n\r\n this.needUploadFilesArr = _neerUploadFilesArr;\r\n },\r\n // 开始上传按钮的点击事件:上传已经准备好的文件\r\n async startUploadMultipleFiles() {\r\n // 避免重复上传\r\n const handleUploadFileArr = this.needUploadFilesArr.filter(\r\n item => item.tip !== \"已完成\",\r\n );\r\n\r\n if (handleUploadFileArr.length === 0) {\r\n this.$message.error(\"没有需要上传的文件\");\r\n return;\r\n }\r\n\r\n try {\r\n this.$message.success(\"开始上传\");\r\n\r\n this.fileConfig.filetotal_num = handleUploadFileArr.length;\r\n\r\n handleUploadFileArr.forEach(item => {\r\n item.notShowTip = false;\r\n item.tip = \"上传中\";\r\n item.uploadProgress = 0;\r\n\r\n item.updateProgress = progress => {\r\n this.$set(item, \"notShowTip\", progress.notShowTip);\r\n this.$set(item, \"tip\", progress.tip);\r\n this.$set(item, \"uploadProgress\", progress.percentage);\r\n this.uploadingTextStyle(item.tip);\r\n };\r\n item.progress_error = () => {\r\n this.$set(item, \"notShowTip\", false);\r\n this.$set(item, \"tip\", \"上传出错\");\r\n this.$set(item, \"uploadProgress\", 0);\r\n this.uploadingTextStyle(item.tip);\r\n };\r\n });\r\n\r\n const total_progress_function = ({\r\n percentage,\r\n notShowTip,\r\n tip,\r\n completed,\r\n total,\r\n active,\r\n queued,\r\n skipError,\r\n }) => {\r\n console.log(\r\n \"%c 文件总进度:\", \"color: #2196F3; font-weight: bold;\", `已完成 ${completed}/${total},正在上传 ${active},排队中 ${queued}, 出错数量 ${skipError} 个`\r\n );\r\n this.fileConfig.overallProgress = percentage;\r\n this.fileConfig.notShowTip = notShowTip;\r\n this.fileConfig.tip = tip;\r\n this.fileConfig.skipError_num = skipError;\r\n this.fileConfig.completed_num = completed;\r\n this.fileConfig.filetotal_num = total;\r\n };\r\n\r\n const createFileQueues = (index, controller) => {\r\n this.multipleChunkConfig.fileQueues.set(index, controller);\r\n };\r\n const createUploadQueues = (uploadId, task) => {\r\n this.multipleChunkConfig.uploadTasks.set(uploadId, task);\r\n };\r\n\r\n const setTotalStatus = (controller, text) => {\r\n this.fileConfig.uploadController = controller;\r\n this.fileConfig.tip = \"上传中\";\r\n };\r\n\r\n const result = await uploadFilesConfig_AndStart(\r\n handleUploadFileArr,\r\n this.multipleChunkConfig.maxConcurrent,\r\n this.fileConfig.maxFileConcurrent,\r\n this.addDataBaseLinkConfig,\r\n createFileQueues,\r\n createUploadQueues,\r\n total_progress_function,\r\n setTotalStatus,\r\n this.apiObj,\r\n );\r\n if (result) {\r\n // 这三个事件考虑合并\r\n this.informUploadedOfRefresh();\r\n this.uploadedResult(result);\r\n\r\n // 检查是否有成功的上传(至少有一个文件上传成功)\r\n const hasSuccess = result.some(item => item.status === true);\r\n if (hasSuccess) {\r\n const _arr = result.map(item => item.uuid);\r\n this.uploadedUUIDs(_arr);\r\n\r\n // 只有单选模式下才会执行\r\n if (_arr.length <= 1 && !this.multiple) {\r\n const serveUrl = `${process.env.VUE_APP_ZT_BASE_API}/resources/open/view/image?`;\r\n this.pictureConfig = {\r\n alt: \"上传成功\",\r\n url: serveUrl + `uuid=${_arr[0]}`,\r\n show: true,\r\n };\r\n }\r\n }\r\n } else {\r\n this.$message.error(\"上传出错!\");\r\n }\r\n } catch (err) {\r\n console.error(\"批量上传失败\", err);\r\n this.$message.error(\"上传出错!\");\r\n }\r\n },\r\n // 这三个时间处理文件拖拽逻辑\r\n onDrop(event) {\r\n this.handleSelectedMultipleFiles(event);\r\n },\r\n onDragOver() {\r\n this.$refs.upLoded_box.classList.add(\"uploading_box_hover\");\r\n },\r\n onDragLeave() {\r\n this.$refs.upLoded_box.classList.remove(\"uploading_box_hover\");\r\n },\r\n // 文件框的点击事件\r\n reviewUploadMultipleFiles(e) {\r\n if (this.isUploading) {\r\n this.$message.error(\"后台上传中\");\r\n return;\r\n }\r\n if (!this.$refs.multiplePloadInput) {\r\n return;\r\n }\r\n this.$refs.multiplePloadInput.click();\r\n },\r\n // input传入文件的回调\r\n async handleSelectedMultipleFiles(e) {\r\n let _needUploadFilesArr = [];\r\n\r\n let error = 0;\r\n\r\n const _arr = e.target.files || e.dataTransfer.files;\r\n\r\n // 防止出错\r\n // e.target.value = \"\"\r\n\r\n // 校验文件格式\r\n Array.from(_arr).forEach((item, index) => {\r\n if (this.addDataBaseLinkConfig.addFileType === \"video\") {\r\n if (\r\n fileTypeValidators.isVideo(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"txt\") {\r\n if (\r\n fileTypeValidators.isDocument(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"subTitle\") {\r\n if (\r\n fileTypeValidators.isSubtitle(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"audio\") {\r\n if (\r\n fileTypeValidators.isAudio(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"pictrue\") {\r\n if (\r\n fileTypeValidators.isImage(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n }\r\n });\r\n\r\n if (error > 0) {\r\n this.$message.error(`${error}个文件格式不支持,已跳过`);\r\n }\r\n\r\n error = 0;\r\n\r\n // 校验文件大小\r\n _needUploadFilesArr = _needUploadFilesArr.filter(item => {\r\n // 兼容不同浏览器/环境的字段名,优先使用标准的 `file.size`\r\n const rawSize =\r\n (item &&\r\n item.file &&\r\n (item.file.size || item.fileSize || item.size)) ||\r\n 0;\r\n const fileSize = Number(rawSize) || 0;\r\n\r\n const max = 2 * 1024 * 1024 * 1024; // 2GB\r\n const allowed = fileSize > 0 && fileSize < max;\r\n if (!allowed) {\r\n error++;\r\n }\r\n return allowed;\r\n });\r\n if (error) {\r\n this.$message.error(`${error}个文件大小超出2Gb,已跳过`);\r\n error = 0;\r\n }\r\n\r\n // 选择文件时,若前一个进度条已经满了,则清空总进度条\r\n if (this.fileConfig.uploadController) {\r\n this.fileConfig.uploadController.clear();\r\n this.fileConfig.overallProgress = 0;\r\n this.fileConfig.notShowTip = true;\r\n this.fileConfig.tip = \"等待上传\";\r\n this.fileConfig.skipError_num = 0;\r\n this.fileConfig.completed_num = 0;\r\n this.fileConfig.filetotal_num = 0;\r\n }\r\n\r\n // 移除已完成的(选完文件移除)\r\n // const _needUploadFilesArr2 = this.needUploadFilesArr.filter(\r\n // item => item.tip !== \"已完成\",\r\n // );\r\n\r\n this.needUploadFilesArr = [\r\n ...this.needUploadFilesArr,\r\n ..._needUploadFilesArr,\r\n ];\r\n this.uploadStart();\r\n\r\n // 此处需要额外的处理逻辑,而这个额外的逻辑需要父组件提供\r\n // 等待父组件通过回调处理筛选逻辑(若父组件未提供回调则立即继续)\r\n await this.uploadingOtherFilterFun(this.needUploadFilesArr);\r\n\r\n // 上传分为:1.列表模式点击按钮开始上传。2.选择完文件自动上传。3.通过xxx方法可以选择改变已选文件,然后调用xxx方法实现上传,这几种方法暂时是互斥的\r\n if (this.needUploadFilesArr.length > 0 && this.autoUpload) {\r\n this.startUploadMultipleFiles();\r\n }\r\n },\r\n },\r\n};\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.upload-multiple {\r\n margin-top: 0.15rem;\r\n animation: slideDown 0.3s ease-out;\r\n\r\n .upload-loading-mask {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background-color: rgba(255, 255, 255, 0.9);\r\n z-index: 100;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: 0.5rem;\r\n\r\n &::after {\r\n content: \"\";\r\n width: var(--spinner-size, 40px);\r\n height: var(--spinner-size, 40px);\r\n border: 4px solid #f3f3f3;\r\n border-top: 4px solid #1890ff;\r\n border-radius: 50%;\r\n animation: spin 1s linear infinite;\r\n }\r\n }\r\n\r\n @keyframes spin {\r\n 0% {\r\n transform: rotate(0deg);\r\n }\r\n 100% {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n\r\n .upload-multiple-box {\r\n display: flex;\r\n\r\n .upload-multiple-box-right {\r\n // width: 8rem;\r\n height: 9rem;\r\n margin-left: 1rem;\r\n position: relative;\r\n\r\n img {\r\n max-width: 21vw;\r\n height: 100%;\r\n border-radius: 8px;\r\n }\r\n\r\n .upload-multiple-box-close {\r\n position: absolute;\r\n top: -8px;\r\n left: -8px;\r\n width: 20px;\r\n height: 20px;\r\n border-radius: 50%;\r\n background-color: #f56c6c;\r\n color: #fff;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n font-size: 12px;\r\n z-index: 10;\r\n\r\n &:hover {\r\n background-color: #e64949;\r\n }\r\n }\r\n }\r\n }\r\n\r\n .upload_button {\r\n border-radius: 5px;\r\n margin-top: 0.5rem;\r\n width: 100%;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n .upload_button:hover {\r\n transform: translateY(-2px);\r\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n .multiple_upload_area {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n transition: all 0.3s ease;\r\n\r\n position: relative;\r\n\r\n padding: 1.2rem;\r\n border: 2px dashed #c0c4cc;\r\n border-radius: 0.5rem;\r\n width: 100%;\r\n height: 9rem;\r\n // margin-bottom: 1rem;\r\n cursor: pointer;\r\n\r\n .el-icon-upload {\r\n font-size: 2.5rem;\r\n color: #909399;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n div:nth-child(2) {\r\n font-size: 1rem;\r\n color: #606266;\r\n transition: all 0.3s ease;\r\n }\r\n }\r\n .uploading_box_hover {\r\n border: 2px dashed #1890ff;\r\n background-color: rgba(24, 144, 255, 0.05);\r\n\r\n .el-icon-upload {\r\n color: #1890ff;\r\n transform: scale(1.1);\r\n }\r\n\r\n div:nth-child(2) {\r\n color: #1890ff;\r\n }\r\n }\r\n .multiple_upload_area_disabled {\r\n cursor: not-allowed;\r\n }\r\n .small_model {\r\n width: 9rem;\r\n height: 9rem;\r\n }\r\n .mini_model {\r\n width: 5rem;\r\n height: 1.5rem;\r\n padding: 0.75rem 0.25rem;\r\n }\r\n\r\n .multiple_upload_area:hover {\r\n border: 2px dashed #1890ff;\r\n background-color: rgba(24, 144, 255, 0.05);\r\n\r\n .el-icon-upload {\r\n color: #1890ff;\r\n transform: scale(1.1);\r\n }\r\n\r\n div:nth-child(2) {\r\n color: #1890ff;\r\n }\r\n }\r\n\r\n .upload-multiple-table {\r\n margin-top: 1rem;\r\n }\r\n\r\n .multiple_upload_list {\r\n position: relative;\r\n // height: 24rem;\r\n overflow: auto;\r\n padding: 0.5rem;\r\n border-radius: 4px;\r\n background-color: #f6f6f7;\r\n margin-top: 1rem;\r\n\r\n .tip_title {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.5rem 0;\r\n padding-top: 0;\r\n\r\n .title {\r\n display: flex;\r\n\r\n .total_progress {\r\n display: flex;\r\n align-items: center;\r\n margin-left: 0.5rem;\r\n\r\n .logo {\r\n border-left: 8px solid #1890ff;\r\n border-radius: 2px;\r\n width: 0.1px;\r\n height: 1rem;\r\n margin-bottom: 0.2rem;\r\n }\r\n\r\n .el-progress {\r\n width: 12rem;\r\n\r\n ::v-deep .el-progress-bar__outer {\r\n background-color: #b3c3e8;\r\n }\r\n\r\n ::v-deep .el-progress-bar__inner {\r\n transition: width 0.4s ease;\r\n }\r\n }\r\n\r\n .uploading_error {\r\n color: #f56c6c;\r\n font-weight: 500;\r\n }\r\n\r\n .uploading_wait {\r\n color: #909399;\r\n }\r\n\r\n .uploading_success {\r\n color: #67c23a;\r\n font-weight: 500;\r\n }\r\n }\r\n }\r\n\r\n .el-button {\r\n padding: 0.5rem 1rem;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n .el-button:hover {\r\n transform: translateY(-1px);\r\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);\r\n }\r\n }\r\n\r\n .selected_list_area {\r\n overflow: auto;\r\n\r\n .selected_list {\r\n margin-top: 0.2rem;\r\n padding: 0;\r\n width: 100%;\r\n display: flex;\r\n gap: 0.75rem;\r\n flex-wrap: wrap;\r\n justify-content: flex-start;\r\n }\r\n }\r\n\r\n .no_file {\r\n position: absolute;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n text-align: center;\r\n }\r\n\r\n @media screen and (max-width: 2200px) {\r\n .selected_list_area {\r\n height: 22rem;\r\n }\r\n }\r\n @media screen and (max-width: 1600px) {\r\n .selected_list_area {\r\n height: 15rem;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","import mod from \"-!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=4f005bbc&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=js\"\nexport * from \"./index.vue?vue&type=script&lang=js\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=4f005bbc&prod&scoped=true&lang=scss\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"4f005bbc\",\n null\n \n)\n\nexport default component.exports","import Upload from './index.vue';\r\n\r\n// 为单个组件也提供 install 方法\r\nUpload.install = function(Vue) {\r\n Vue.component(Upload.name, Upload);\r\n};\r\n\r\nexport default Upload;","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('el-dialog',{attrs:{\"visible\":_vm.dialogVisible,\"show-close\":false,\"modal\":true,\"width\":_vm.width,\"top\":_vm.topMargin,\"custom-class\":\"modern-video-review-dialog\",\"append-to-body\":\"\",\"before-close\":_vm.closePreview},on:{\"update:visible\":function($event){_vm.dialogVisible=$event},\"opened\":_vm.onOpened}},[_c('div',{staticClass:\"video-review-container\",style:({ height: _vm.height }),on:{\"mousemove\":_vm.onDrag,\"mouseup\":_vm.stopDrag,\"mouseleave\":_vm.stopDrag}},[_c('div',{staticClass:\"video-review-header\"},[_c('div',{staticClass:\"file-info\"},[_c('span',{staticClass:\"file-name\",attrs:{\"title\":_vm.fileName}},[_vm._v(_vm._s(_vm.fileName || \"视频预览\"))]),(!_vm.loading && !_vm.loadError && _vm.videoWidth)?_c('span',{staticClass:\"file-size\"},[_vm._v(\" \"+_vm._s(_vm.videoWidth)+\" × \"+_vm._s(_vm.videoHeight)+\" px | \"+_vm._s(_vm.duration)+\" \")]):_vm._e()]),_c('div',{staticClass:\"video-review-controls\"},[_c('button',{staticClass:\"control-icon-btn\",attrs:{\"disabled\":_vm.scale <= _vm.minScale},on:{\"click\":_vm.zoomOut}},[_c('i',{staticClass:\"el-icon-zoom-out\"})]),_c('span',{staticClass:\"zoom-display\"},[_vm._v(_vm._s(Math.round(_vm.scale * 100))+\"%\")]),_c('button',{staticClass:\"control-icon-btn\",attrs:{\"disabled\":_vm.scale >= _vm.maxScale},on:{\"click\":_vm.zoomIn}},[_c('i',{staticClass:\"el-icon-zoom-in\"})]),_c('div',{staticClass:\"control-divider\"}),_c('button',{staticClass:\"control-icon-btn\",attrs:{\"title\":\"原始尺寸/重置位置\"},on:{\"click\":_vm.resetZoom}},[_c('i',{staticClass:\"el-icon-refresh-right\"})]),_c('button',{staticClass:\"control-icon-btn close-btn\",on:{\"click\":_vm.closePreview}},[_c('i',{staticClass:\"el-icon-close\"})])])]),_c('div',{staticClass:\"video-review-content\",on:{\"wheel\":function($event){$event.preventDefault();return _vm.handleWheel($event)},\"mousedown\":function($event){if($event.target !== $event.currentTarget){ return null; }return _vm.startDrag($event)},\"!click\":function($event){return _vm.handleCaptureClick($event)}}},[_c('transition',{attrs:{\"name\":\"fade\"}},[(_vm.loading && !_vm.loadError)?_c('div',{staticClass:\"status-overlay\"},[_c('i',{staticClass:\"el-icon-loading\"}),_c('p',[_vm._v(\"视频加载中...\")])]):_vm._e()]),(_vm.loadError)?_c('div',{staticClass:\"status-overlay error\"},[_c('i',{staticClass:\"el-icon-video-camera\"}),_c('p',[_vm._v(\"视频加载失败\")])]):_vm._e(),_c('div',{directives:[{name:\"show\",rawName:\"v-show\",value:(!_vm.loading && !_vm.loadError),expression:\"!loading && !loadError\"}],staticClass:\"video-transform-wrapper\",style:(_vm.videoStyle),on:{\"mousedown\":_vm.startDrag}},[(_vm.videoUrl)?_c('video',{key:_vm.videoUrl,ref:\"videoPlayer\",staticClass:\"main-preview-video\",attrs:{\"src\":_vm.videoUrl,\"autoplay\":\"\",\"muted\":\"\",\"loop\":\"\",\"playsinline\":\"\",\"controls\":\"\"},domProps:{\"muted\":true},on:{\"loadedmetadata\":_vm.onMetadataLoad,\"error\":_vm.onVideoError,\"canplay\":_vm.onCanPlay}}):_vm._e()])],1),_c('div',{staticClass:\"video-review-hint\"},[_c('span',[_vm._v(\"鼠标拖拽背景移动,滚轮缩放查看细节\")])])])])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","<template>\r\n <el-dialog\r\n :visible.sync=\"dialogVisible\"\r\n :show-close=\"false\"\r\n :modal=\"true\"\r\n :width=\"width\"\r\n :top=\"topMargin\"\r\n custom-class=\"modern-video-review-dialog\"\r\n append-to-body\r\n :before-close=\"closePreview\"\r\n @opened=\"onOpened\"\r\n >\r\n <div\r\n class=\"video-review-container\"\r\n :style=\"{ height: height }\"\r\n @mousemove=\"onDrag\"\r\n @mouseup=\"stopDrag\"\r\n @mouseleave=\"stopDrag\"\r\n >\r\n <!-- 头部:控制栏 (保持不变) -->\r\n <div class=\"video-review-header\">\r\n <div class=\"file-info\">\r\n <span class=\"file-name\" :title=\"fileName\">{{\r\n fileName || \"视频预览\"\r\n }}</span>\r\n <span v-if=\"!loading && !loadError && videoWidth\" class=\"file-size\">\r\n {{ videoWidth }} × {{ videoHeight }} px | {{ duration }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"video-review-controls\">\r\n <button class=\"control-icon-btn\" :disabled=\"scale <= minScale\" @click=\"zoomOut\">\r\n <i class=\"el-icon-zoom-out\" />\r\n </button>\r\n <span class=\"zoom-display\">{{ Math.round(scale * 100) }}%</span>\r\n <button class=\"control-icon-btn\" :disabled=\"scale >= maxScale\" @click=\"zoomIn\">\r\n <i class=\"el-icon-zoom-in\" />\r\n </button>\r\n <div class=\"control-divider\" />\r\n <button class=\"control-icon-btn\" title=\"原始尺寸/重置位置\" @click=\"resetZoom\">\r\n <i class=\"el-icon-refresh-right\" />\r\n </button>\r\n <button class=\"control-icon-btn close-btn\" @click=\"closePreview\">\r\n <i class=\"el-icon-close\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- 内容展示区 -->\r\n <div\r\n class=\"video-review-content\"\r\n @wheel.prevent=\"handleWheel\"\r\n @mousedown.self=\"startDrag\"\r\n @click.capture=\"handleCaptureClick\"\r\n >\r\n <!-- 加载状态 -->\r\n <transition name=\"fade\">\r\n <div v-if=\"loading && !loadError\" class=\"status-overlay\">\r\n <i class=\"el-icon-loading\" />\r\n <p>视频加载中...</p>\r\n </div>\r\n </transition>\r\n\r\n <!-- 错误状态 -->\r\n <div v-if=\"loadError\" class=\"status-overlay error\">\r\n <i class=\"el-icon-video-camera\" />\r\n <p>视频加载失败</p>\r\n </div>\r\n\r\n <!-- 视频包裹层 -->\r\n <div\r\n v-show=\"!loading && !loadError\"\r\n class=\"video-transform-wrapper\"\r\n :style=\"videoStyle\"\r\n @mousedown=\"startDrag\"\r\n >\r\n <!-- \r\n 【重要改动】:key=\"videoUrl\" \r\n 当视频地址变化时,强制重新渲染 video 标签,清除之前的错误或播放状态\r\n -->\r\n <video\r\n v-if=\"videoUrl\"\r\n :key=\"videoUrl\"\r\n ref=\"videoPlayer\"\r\n :src=\"videoUrl\"\r\n class=\"main-preview-video\"\r\n autoplay\r\n muted\r\n loop\r\n playsinline\r\n controls\r\n @loadedmetadata=\"onMetadataLoad\"\r\n @error=\"onVideoError\"\r\n @canplay=\"onCanPlay\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"video-review-hint\">\r\n <span>鼠标拖拽背景移动,滚轮缩放查看细节</span>\r\n </div>\r\n </div>\r\n </el-dialog>\r\n</template>\r\n\r\n<script>\r\nexport default {\r\n name: \"KukanDialogVideoReview\",\r\n props: {\r\n visible: { type: Boolean, default: false },\r\n videoUrl: { type: String, required: true },\r\n fileName: { type: String, default: \"\" },\r\n width: { type: String, default: \"40%\" },\r\n height: { type: String, default: \"80vh\" },\r\n topMargin: { type: String, default: \"7vh\" },\r\n initialScale: { type: Number, default: 1 },\r\n },\r\n data() {\r\n return {\r\n scale: 1,\r\n minScale: 0.5,\r\n maxScale: 3,\r\n loading: true,\r\n loadError: false, // 错误标记\r\n videoWidth: 0,\r\n videoHeight: 0,\r\n duration: \"00:00\",\r\n translateX: 0,\r\n translateY: 0,\r\n isDragging: false,\r\n hasMoved: false,\r\n startMousePos: { x: 0, y: 0 },\r\n mouseStartPos: { x: 0, y: 0 },\r\n };\r\n },\r\n computed: {\r\n dialogVisible: {\r\n get() { return this.visible; },\r\n set(val) { this.$emit(\"update:visible\", val); },\r\n },\r\n videoStyle() {\r\n return {\r\n transform: `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`,\r\n transition: this.isDragging ? \"none\" : \"transform 0.25s cubic-bezier(0.2, 0, 0, 1)\",\r\n };\r\n },\r\n },\r\n watch: {\r\n visible(val) {\r\n if (val) {\r\n this.initStates(); // 每次打开弹窗,初始化状态\r\n window.addEventListener(\"keydown\", this.handleKeyDown);\r\n } else {\r\n this.pauseVideo();\r\n window.removeEventListener(\"keydown\", this.handleKeyDown);\r\n }\r\n },\r\n // 监听 URL 变化:如果弹窗没关闭但切换了视频源,也要重置状态\r\n videoUrl() {\r\n if (this.visible) {\r\n this.initStates();\r\n }\r\n }\r\n },\r\n methods: {\r\n // 初始化/重置状态的方法\r\n initStates() {\r\n this.loading = true;\r\n this.loadError = false; // 【核心修复】重置错误状态\r\n this.videoWidth = 0;\r\n this.videoHeight = 0;\r\n this.duration = \"00:00\";\r\n this.resetZoom();\r\n },\r\n onOpened() {\r\n this.resetZoom();\r\n },\r\n onMetadataLoad(e) {\r\n const video = e.target;\r\n this.videoWidth = video.videoWidth;\r\n this.videoHeight = video.videoHeight;\r\n this.duration = this.formatDuration(video.duration);\r\n },\r\n onCanPlay() {\r\n this.loading = false;\r\n this.loadError = false; // 成功能播放时确保错误关闭\r\n },\r\n onVideoError() {\r\n console.error(\"Video preview failed to load.\");\r\n this.loading = false;\r\n this.loadError = true; // 触发错误展示\r\n },\r\n formatDuration(seconds) {\r\n if (!seconds) return \"00:00\";\r\n const min = Math.floor(seconds / 60);\r\n const sec = Math.floor(seconds % 60);\r\n return `${min.toString().padStart(2, \"0\")}:${sec.toString().padStart(2, \"0\")}`;\r\n },\r\n // ... 其他方法 (zoomIn, zoomOut, handleWheel, startDrag 等保持不变) ...\r\n zoomIn() {\r\n if (this.scale < this.maxScale)\r\n this.scale = parseFloat((this.scale + 0.2).toFixed(1));\r\n },\r\n zoomOut() {\r\n if (this.scale > this.minScale)\r\n this.scale = parseFloat((this.scale - 0.2).toFixed(1));\r\n },\r\n resetZoom() {\r\n this.scale = this.initialScale;\r\n this.translateX = 0;\r\n this.translateY = 0;\r\n },\r\n handleWheel(e) {\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1;\r\n const newScale = parseFloat((this.scale + delta).toFixed(1));\r\n if (newScale >= this.minScale && newScale <= this.maxScale) {\r\n this.scale = newScale;\r\n }\r\n },\r\n startDrag(e) {\r\n if (e.target.tagName === \"VIDEO\" && e.offsetY > e.target.offsetHeight - 50) return;\r\n if (e.button !== 0 || this.loading) return;\r\n this.isDragging = true;\r\n this.hasMoved = false;\r\n this.startMousePos = { x: e.clientX, y: e.clientY };\r\n this.mouseStartPos = {\r\n x: e.clientX - this.translateX,\r\n y: e.clientY - this.translateY,\r\n };\r\n },\r\n onDrag(e) {\r\n if (!this.isDragging) return;\r\n const dx = Math.abs(e.clientX - this.startMousePos.x);\r\n const dy = Math.abs(e.clientY - this.startMousePos.y);\r\n if (dx > 5 || dy > 5) this.hasMoved = true;\r\n this.translateX = e.clientX - this.mouseStartPos.x;\r\n this.translateY = e.clientY - this.mouseStartPos.y;\r\n },\r\n stopDrag() {\r\n this.isDragging = false;\r\n },\r\n handleCaptureClick(e) {\r\n if (this.hasMoved) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.hasMoved = false;\r\n }\r\n },\r\n pauseVideo() {\r\n if (this.$refs.videoPlayer) {\r\n this.$refs.videoPlayer.pause();\r\n }\r\n },\r\n handleKeyDown(e) {\r\n if (e.key === \"Escape\") this.closePreview();\r\n if (e.key === \" \") {\r\n e.preventDefault();\r\n const v = this.$refs.videoPlayer;\r\n if (v) v.paused ? v.play() : v.pause();\r\n }\r\n },\r\n closePreview() {\r\n this.pauseVideo();\r\n this.dialogVisible = false;\r\n this.$emit(\"close\");\r\n },\r\n },\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n::v-deep .modern-video-review-dialog {\r\n background: transparent !important;\r\n box-shadow: none !important;\r\n .el-dialog__header {\r\n display: none !important;\r\n }\r\n .el-dialog__body {\r\n padding: 0 !important;\r\n }\r\n}\r\n\r\n.video-review-container {\r\n display: flex;\r\n flex-direction: column;\r\n background-color: #000; // 视频预览通常用黑色背景,更沉浸\r\n position: relative;\r\n overflow: hidden;\r\n border-radius: 12px;\r\n\r\n .video-review-header {\r\n flex-shrink: 0;\r\n z-index: 100;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0 24px;\r\n height: 64px;\r\n background: rgba(255, 255, 255, 0.9);\r\n backdrop-filter: blur(10px);\r\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\r\n }\r\n\r\n .file-info {\r\n display: flex;\r\n flex-direction: column;\r\n .file-name {\r\n font-size: 15px;\r\n font-weight: 600;\r\n color: #1a1a1a;\r\n }\r\n .file-size {\r\n font-size: 11px;\r\n color: #909399;\r\n margin-top: 2px;\r\n }\r\n }\r\n\r\n .video-review-controls {\r\n display: flex;\r\n align-items: center;\r\n background: #fff;\r\n padding: 4px;\r\n border-radius: 50px;\r\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);\r\n border: 1px solid #ebeef5;\r\n\r\n .zoom-display {\r\n font-size: 13px;\r\n font-weight: 600;\r\n width: 50px;\r\n text-align: center;\r\n color: #303133;\r\n font-variant-numeric: tabular-nums;\r\n }\r\n\r\n .control-divider {\r\n width: 1px;\r\n height: 16px;\r\n background: #eee;\r\n margin: 0 8px;\r\n }\r\n }\r\n\r\n .control-icon-btn {\r\n width: 34px;\r\n height: 34px;\r\n border: none;\r\n background: transparent;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n font-size: 18px;\r\n color: #606266;\r\n transition: all 0.2s;\r\n &:hover:not(:disabled) {\r\n background-color: #f2f6fc;\r\n color: #409eff;\r\n }\r\n &:disabled {\r\n color: #dcdfe6;\r\n cursor: not-allowed;\r\n }\r\n &.close-btn:hover {\r\n background-color: #fef0f0;\r\n color: #f56c6c;\r\n }\r\n }\r\n\r\n .video-review-content {\r\n flex: 1;\r\n position: relative;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n overflow: hidden;\r\n height: 0;\r\n // position: relative;\r\n cursor: grab;\r\n &:active {\r\n cursor: grabbing;\r\n }\r\n }\r\n\r\n .video-transform-wrapper {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n will-change: transform;\r\n width: 100%;\r\n height: 100%;\r\n }\r\n\r\n .main-preview-video {\r\n max-width: 100%;\r\n height: 100%;\r\n object-fit: contain; /* 确保比例正确,不裁剪 */\r\n outline: none;\r\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);\r\n background: #000;\r\n }\r\n\r\n .status-overlay {\r\n position: absolute;\r\n z-index: 10;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n i {\r\n font-size: 40px;\r\n color: #409eff;\r\n margin-bottom: 8px;\r\n }\r\n p {\r\n font-size: 14px;\r\n color: #eee;\r\n margin: 0;\r\n }\r\n &.error {\r\n i,\r\n p {\r\n color: #f56c6c;\r\n }\r\n }\r\n }\r\n\r\n .video-review-hint {\r\n position: absolute;\r\n bottom: 80px; // 避开视频控制条\r\n left: 50%;\r\n transform: translateX(-50%);\r\n background: rgba(0, 0, 0, 0.5);\r\n color: #fff;\r\n padding: 6px 16px;\r\n border-radius: 20px;\r\n font-size: 12px;\r\n pointer-events: none;\r\n opacity: 0;\r\n transition: opacity 0.3s;\r\n z-index: 10;\r\n }\r\n &:hover .video-review-hint {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n/* 渐变过渡动画 */\r\n.fade-enter-active,\r\n.fade-leave-active {\r\n transition: opacity 0.3s;\r\n}\r\n.fade-enter,\r\n.fade-leave-to {\r\n opacity: 0;\r\n}\r\n</style>\r\n","import mod from \"-!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=419a04c7&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=js\"\nexport * from \"./index.vue?vue&type=script&lang=js\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=419a04c7&prod&lang=scss&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"419a04c7\",\n null\n \n)\n\nexport default component.exports","import { setAxiosInstance } from './components/FileUpload/api';\r\n\r\nimport Upload from './components/FileUpload';\r\nimport DialogVideoReview from './components/VideoPreviewDialog';\r\n\r\n// import MyButton from './components/Button';\r\n\r\nconst components = [\r\n Upload,\r\n DialogVideoReview\r\n];\r\n\r\n// 整个库的 install\r\nconst install = function (Vue, options = {}) {\r\n components.forEach(component => {\r\n // 自动读取组件里的 name 属性作为组件名\r\n Vue.component(component.name, component);\r\n });\r\n\r\n // 将 axios 实例传入 api 模块\r\n setAxiosInstance(options.axios);\r\n};\r\n\r\n// 支持用 <script> 引入\r\nif (typeof window !== 'undefined' && window.Vue) {\r\n install(window.Vue);\r\n}\r\n\r\n// 全量导出,也可以解构导出\r\nexport default { install };\r\n// 按需引入\r\nexport {\r\n Upload,\r\n // MyButton\r\n};","import './setPublicPath'\nimport mod from '~entry'\nexport default mod\nexport * from '~entry'\n"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"sources":["webpack://kukan-ui/webpack/bootstrap","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue?458d","webpack://kukan-ui/./src/components/FileUpload/index.vue?4c4b","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue?ee3c","webpack://kukan-ui/./node_modules/spark-md5/spark-md5.js","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue?1015","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue?1c0d","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue?bfe0","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue?a4e4","webpack://kukan-ui/./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js","webpack://kukan-ui/./src/components/FileUpload/api.js","webpack://kukan-ui/./src/components/FileUpload/index.vue?31d7","webpack://kukan-ui/./src/components/FileUpload/util.js","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue?d355","webpack://kukan-ui/src/components/FileUpload/components/UploadCard_Ver_Second/index.vue","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue?e145","webpack://kukan-ui/./node_modules/vue-loader/lib/runtime/componentNormalizer.js","webpack://kukan-ui/./src/components/FileUpload/components/UploadCard_Ver_Second/index.vue","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue?10f6","webpack://kukan-ui/src/components/FileUpload/components/Upload_table/index.vue","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue?cf02","webpack://kukan-ui/./src/components/FileUpload/components/Upload_table/index.vue","webpack://kukan-ui/./src/components/FileUpload/upload.js","webpack://kukan-ui/src/components/FileUpload/index.vue","webpack://kukan-ui/./src/components/FileUpload/index.vue?02c5","webpack://kukan-ui/./src/components/FileUpload/index.vue","webpack://kukan-ui/./src/components/FileUpload/index.js","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue?197f","webpack://kukan-ui/src/components/VideoPreviewDialog/index.vue","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue?333e","webpack://kukan-ui/./src/components/VideoPreviewDialog/index.vue","webpack://kukan-ui/./src/index.js","webpack://kukan-ui/./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js","webpack://kukan-ui/./src/components/FileUpload/index.vue?8720"],"names":[],"mappings":";;QAAA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;;QAEA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;;;QAGA;QACA;;QAEA;QACA;;QAEA;QACA;QACA;QACA,0CAA0C,gCAAgC;QAC1E;QACA;;QAEA;QACA;QACA;QACA,wDAAwD,kBAAkB;QAC1E;QACA,iDAAiD,cAAc;QAC/D;;QAEA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA,yCAAyC,iCAAiC;QAC1E,gHAAgH,mBAAmB,EAAE;QACrI;QACA;;QAEA;QACA;QACA;QACA,2BAA2B,0BAA0B,EAAE;QACvD,iCAAiC,eAAe;QAChD;QACA;QACA;;QAEA;QACA,sDAAsD,+DAA+D;;QAErH;QACA;;;QAGA;QACA;;;;;;;;AClFA,uC;;;;;;;ACAA,uC;;;;;;;ACAA,uC;;;;;;;ACAA;AACA,QAAQ,IAA2B;AACnC;AACA;AACA,KAAK,MAAM,aAcN;AACL,CAAC;;AAED;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;;AAGA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,cAAc;;AAEd,mBAAmB,QAAQ;AAC3B;AACA;AACA;AACA;;AAEA;AACA;AACA,cAAc;;AAEd,mBAAmB,QAAQ;AAC3B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,QAAQ;AAC5B;AACA;AACA;AACA;AACA;AACA,mBAAmB,YAAY;AAC/B;AACA;AACA;AACA;AACA;AACA,uBAAuB,QAAQ;AAC/B;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,IAAI;AAClD;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,QAAQ;AAC5B;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;AACA;AACA;AACA,uBAAuB,QAAQ;AAC/B;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,IAAI;AAClD;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,mBAAmB,OAAO;AAC1B;AACA;AACA;AACA;;AAEA;AACA;AACA,mBAAmB,cAAc;AACjC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,SAAS;AACT;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,mBAAmB,gBAAgB;AACnC;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,OAAO;AACtB;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,eAAe,OAAO;AACtB;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;;AAEA;AACA;;AAEA,oBAAoB,aAAa;AACjC;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,OAAO;AACtB;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,MAAM;AACrB,eAAe,OAAO;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,uBAAuB,QAAQ;AAC/B;AACA;AACA;;AAEA;AACA;AACA;AACA,8CAA8C,IAAI;AAClD;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,OAAO;AACtB,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,OAAO;AACtB,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,YAAY;AAC3B;AACA,gBAAgB,qBAAqB;AACrC;AACA;AACA;AACA;AACA;;AAEA;;AAEA,oBAAoB,aAAa;AACjC;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,qBAAqB;AACrC;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,eAAe,OAAO;AACtB;AACA,gBAAgB,qBAAqB;AACrC;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,eAAe,YAAY;AAC3B,eAAe,QAAQ;AACvB;AACA,gBAAgB,OAAO;AACvB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;;;;;;;;AC9uBD;AAAA;AAAA;;;;;;;;;ACAA;AAAA;AAAA;;;;;;;;ACAA,uC;;;;;;;;ACAA;AAAA;AAAA;;;;;;;;;;;;;;;;ACAA;;AAEA;AACA;AACA,MAAM,KAAuC,EAAE,yBAQ5C;;AAEH;AACA;AACA,IAAI,qBAAuB;AAC3B;AACA;;AAEA;AACe,sDAAI;;;ACrBnB;;AAEA;;AAEA;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;;AC1JA,0BAA0B,aAAa,0BAA0B,wBAAwB,iBAAiB,8BAA8B,cAAc,sCAAsC,iBAAiB,QAAQ,iEAAiE,KAAK,0CAA0C,YAAY,kCAAkC,YAAY,6FAA6F,kEAAkE,wBAAwB,8BAA8B,8BAA8B,wBAAwB,+BAA+B,yBAAyB,wBAAwB,4BAA4B,8BAA8B,6EAA6E,+CAA+C,6BAA6B,6IAA6I,wCAAwC,YAAY,4CAA4C,yBAAyB,yBAAyB,kCAAkC,UAAU,4BAA4B,cAAc,OAAO,6DAA6D,2DAA2D,mCAAmC,mFAAmF,KAAK,sCAAsC,oEAAoE,oCAAoC,qBAAqB,OAAO,uJAAuJ,KAAK,0KAA0K,gDAAgD,mCAAmC,aAAa,wBAAwB,aAAa,oBAAoB,8CAA8C,OAAO,wCAAwC,gDAAgD,6BAA6B,YAAY,mBAAmB,uFAAuF,OAAO,mCAAmC,sEAAsE,OAAO,yBAAyB,sEAAsE,OAAO,yBAAyB,kHAAkH,OAAO,0FAA0F,KAAK,iCAAiC,qCAAqC,OAAO,gGAAgG,KAAK,+BAA+B,qCAAqC,iCAAiC,gDAAgD,4BAA4B,sDAAsD,oBAAoB,iBAAiB,iCAAiC,KAAK,6HAA6H,EAAE,eAAe,sBAAsB,UAAU,+BAA+B;AACpkH;;;;;;ACDA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,E;;ACvEA,IAAI,qEAAM,gBAAgB,aAAa,0BAA0B,wBAAwB,iBAAiB;AAC1G;AACA;AACA,GAAG,KAAK,yBAAyB,iDAAiD,YAAY,4BAA4B,YAAY,wBAAwB,2EAA2E,wBAAwB,oDAAoD,+BAA+B,YAAY,qBAAqB,YAAY,0BAA0B,aAAa,iDAAiD;AACzd;AACA,oBAAoB,8BAA8B,yBAAyB,yBAAyB,8CAA8C,eAAe,OAAO,+BAA+B;AACvM;AACA;AACA;AACA,oBAAoB,8BAA8B,yBAAyB,yBAAyB,6CAA6C,eAAe,OAAO,yBAAyB,wPAAwP,4BAA4B,oBAAoB,qCAAqC,iFAAiF;AAC9lB,IAAI,8EAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC0DJ;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;ACzI6L,CAAgB,wIAAG,EAAC,C;;;;;ACAnN;;AAEA;AACA;AACA;;AAEe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;AC/F+F;AACvC;AACL;AAC2C;;;AAG9F;AACmG;AACnG,gBAAgB,kBAAU;AAC1B,EAAE,uDAAM;AACR,EAAE,qEAAM;AACR,EAAE,8EAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,2E;;ACnBf,IAAI,4DAAM,gBAAgB,aAAa,0BAA0B,wBAAwB,iBAAiB,2BAA2B,YAAY,qBAAqB,YAAY,oBAAoB,sHAAsH,OAAO,yBAAyB,iEAAiE,sBAAsB,kBAAkB,OAAO,gGAAgG,KAAK,yBAAyB,mCAAmC,wCAAwC,aAAa,eAAe,QAAQ,8CAA8C,wCAAwC,8BAA8B,KAAK,iFAAiF,wBAAwB,OAAO,iCAAiC,wBAAwB,OAAO,6BAA6B,wBAAwB,OAAO,4BAA4B,sBAAsB,iCAAiC,kBAAkB,wBAAwB,YAAY,wBAAwB,uEAAuE,6BAA6B,uCAAuC,GAAG,wBAAwB,OAAO,2BAA2B,sBAAsB,iCAAiC,kBAAkB,wBAAwB,aAAa,6BAA6B,uEAAuE,GAAG,wBAAwB,OAAO,2BAA2B,sBAAsB,iCAAiC,kBAAkB,0BAA0B,aAAa,4CAA4C,sCAAsC,GAAG,wBAAwB,OAAO,4BAA4B,sBAAsB,iCAAiC,kBAAkB,4BAA4B,oBAAoB,qCAAqC,2EAA2E,QAAQ,GAAG,wBAAwB,OAAO,4BAA4B,sBAAsB,iCAAiC,4CAA4C,8BAA8B,yBAAyB,yBAAyB,yCAAyC,aAAa,aAAa,sCAAsC;AACj+E;AACA;AACA;AACA,sBAAsB,8BAA8B,yBAAyB,yBAAyB,wCAAwC,aAAa,aAAa,sCAAsC,8BAA8B,GAAG;AAC/O,IAAI,qEAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC4FJ;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,CAAC,EAAC;;;AClL6L,CAAgB,sHAAG,EAAC,C;;;;;ACApH;AACvC;AACL;AAC2C;;;AAG9F;AACmG;AACnG,IAAI,sBAAS,GAAG,kBAAU;AAC1B,EAAE,8CAAM;AACR,EAAE,4DAAM;AACR,EAAE,qEAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,uEAAS,Q;;;;;;ACnBS;AACO;;AAExC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,MAAM;AACjB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA,KAAK;AACL;AACe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,eAAe;;AAEvB;;AAEA,iBAAiB,qBAAqB;AACtC;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,yBAAyB,4BAA4B;AACrD;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,iBAAiB;AACjB,uBAAuB;AACvB,sBAAsB;AACtB,sBAAsB;AACtB,uBAAuB;AACvB,0BAA0B;;AAE1B,oBAAoB;AACpB,yBAAyB;AACzB,qBAAqB;;AAErB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA,8DAA8D;;AAE9D;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA,OAAO;AACP;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,oBAAoB,qDAAqD;AACzE;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC;AACpC;AACA,aAAa;AACb;AACA;AACA;AACA,aAAa;AACb,SAAS;AACT,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA,aAAa,4BAA4B;;AAEzC;;AAEA,UAAU,+BAA+B;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,WAAW;AACX;AACA,0BAA0B;AAC1B;;AAEA,6BAA6B,4BAA4B,EAAE;;AAE3D;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,8BAA8B;AAC9B;AACA;;AAEA;AACA,SAAS;AACT;AACA;AACA;AACA,wBAAwB;AACxB;AACA,2BAA2B,4BAA4B,EAAE;;AAEzD;AACA;AACA,SAAS;AACT;AACA;AACA,4BAA4B;AAC5B,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,oBAAoB,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO;;AAElE;AACA;AACA;;AAEA;AACA;AACA,SAAS,yCAAyC;AAClD;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA,8BAA8B,2BAAoB;AAClD,cAAc;AACd,KAAK;AACL,cAAc;AACd;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA,sBAAsB,mBAAmB;AACzC;AACA;;AAEA;AACA;AACA,OAAO,yCAAyC;AAChD;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,sBAAsB,mBAAmB;AACzC;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA,oBAAoB,mBAAQ;AAC5B;AACA;;AAEA,iBAAiB,YAAY;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd,gBAAgB;;AAEhB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA,qBAAqB;AACrB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,sBAAsB,mBAAQ;;AAE9B;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,mCAAmC,4BAAqB;AACxD;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA,WAAW;AACX;AACA,SAAS;AACT,OAAO;;AAEP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,wCAAwC,uBAAuB;AAC/D;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB,cAAc;AACd;;AAEA;AACA;AACA;AACA,gBAAgB;AAChB;AACA,YAAY;AACZ;AACA;AACA;AACA,cAAc;AACd;AACA,UAAU;;AAEV;;AAEA;;AAEA;AACA;;AAEA,YAAY;AACZ,GAAG;;AAEH;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA,eAAe,4BAAqB;AACpC;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,2BAA2B,sBAAe;AAC1C;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,eAAe,sBAAe;AAC9B;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA,eAAe,2BAAoB;AACnC;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA,aAAa;AACb;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACn4B+C;AACmB;AACH;AACV;;AAEtC;AACf;AACA;AACA,IAAI,6BAAM;AACV,IAAI,0BAAY;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,0BAA0B,gDAAW;;AAErC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,6BAA6B,0BAA0B;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,kCAAkC,gDAAW;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;ACz7BiL,CAAgB,kHAAG,EAAC,C;;;;;ACAxG;AACvC;AACL;AAC2C;;;AAG9F;AAC6F;AAC7F,IAAI,oBAAS,GAAG,kBAAU;AAC1B,EAAE,4CAAM;AACR,EAAE,MAAM;AACR,EAAE,eAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,mEAAS,Q;;ACnBS;;AAEjC;AACA,UAAM;AACN,gBAAgB,UAAM,OAAO,UAAM;AACnC;;AAEe,oEAAM,E;;ACPrB,IAAI,kEAAM,gBAAgB,aAAa,0BAA0B,wBAAwB,uBAAuB,OAAO,kMAAkM,KAAK,kCAAkC,yBAAyB,wBAAwB,YAAY,6CAA6C,qBAAqB,MAAM,yEAAyE,YAAY,kCAAkC,YAAY,wBAAwB,aAAa,+BAA+B,sBAAsB,iHAAiH,wBAAwB,4HAA4H,oCAAoC,eAAe,sCAAsC,6EAA6E,KAAK,qBAAqB,UAAU,+BAA+B,eAAe,2BAA2B,iEAAiE,sCAAsC,6EAA6E,KAAK,oBAAoB,UAAU,8BAA8B,cAAc,8BAA8B,eAAe,sCAAsC,mDAAmD,KAAK,uBAAuB,UAAU,oCAAoC,iBAAiB,6CAA6C,0BAA0B,UAAU,4BAA4B,kBAAkB,uCAAuC,yBAAyB,wBAAwB,+BAA+B,8BAA8B,2CAA2C,aAAa,EAAE,6BAA6B,2BAA2B,wCAAwC,mBAAmB,OAAO,eAAe,oDAAoD,6BAA6B,UAAU,8BAA8B,sEAAsE,mCAAmC,UAAU,mCAAmC,kDAAkD,aAAa,wHAAwH,mEAAmE,2BAA2B,4CAA4C,2EAA2E,0EAA0E,KAAK,gHAAgH,0BAA0B,2BAA2B,gCAAgC;AACpkG,IAAI,2EAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC0GJ;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;AC5RiL,CAAgB,kIAAG,EAAC,C;;;;;ACAxG;AACvC;AACL;AAC2C;;;AAG9F;AAC6F;AAC7F,IAAI,4BAAS,GAAG,kBAAU;AAC1B,EAAE,oDAAM;AACR,EAAE,kEAAM;AACR,EAAE,2EAAe;AACjB;AACA;AACA;AACA;;AAEA;;AAEe,mFAAS,Q;;ACnBuC;;AAElB;AACmB;;AAEhE;;AAEA;AACA,EAAE,qBAAM;AACR,EAAE,kBAAiB;AACnB;;AAEA;AACA,2CAA2C;AAC3C;AACA;AACA;AACA,GAAG;;AAEH;AACA,EAAE,gBAAgB;AAClB;;AAEA;AACA;AACA;AACA;;AAEA;AACe,2CAAC,UAAU,EAAC;AAC3B;;;AC9BwB;AACA;AACT,oFAAG;AACI;;;;;;;;;ACHtB;AAAA;AAAA","file":"kukan-ui.common.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"fb15\");\n","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","(function (factory) {\n if (typeof exports === 'object') {\n // Node/CommonJS\n module.exports = factory();\n } else if (typeof define === 'function' && define.amd) {\n // AMD\n define(factory);\n } else {\n // Browser globals (with support for web workers)\n var glob;\n\n try {\n glob = window;\n } catch (e) {\n glob = self;\n }\n\n glob.SparkMD5 = factory();\n }\n}(function (undefined) {\n\n 'use strict';\n\n /*\n * Fastest md5 implementation around (JKM md5).\n * Credits: Joseph Myers\n *\n * @see http://www.myersdaily.org/joseph/javascript/md5-text.html\n * @see http://jsperf.com/md5-shootout/7\n */\n\n /* this function is much faster,\n so if possible we use it. Some IEs\n are the only ones I know of that\n need the idiotic second function,\n generated by an if clause. */\n var add32 = function (a, b) {\n return (a + b) & 0xFFFFFFFF;\n },\n hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];\n\n\n function cmn(q, a, b, x, s, t) {\n a = add32(add32(a, q), add32(x, t));\n return add32((a << s) | (a >>> (32 - s)), b);\n }\n\n function md5cycle(x, k) {\n var a = x[0],\n b = x[1],\n c = x[2],\n d = x[3];\n\n a += (b & c | ~b & d) + k[0] - 680876936 | 0;\n a = (a << 7 | a >>> 25) + b | 0;\n d += (a & b | ~a & c) + k[1] - 389564586 | 0;\n d = (d << 12 | d >>> 20) + a | 0;\n c += (d & a | ~d & b) + k[2] + 606105819 | 0;\n c = (c << 17 | c >>> 15) + d | 0;\n b += (c & d | ~c & a) + k[3] - 1044525330 | 0;\n b = (b << 22 | b >>> 10) + c | 0;\n a += (b & c | ~b & d) + k[4] - 176418897 | 0;\n a = (a << 7 | a >>> 25) + b | 0;\n d += (a & b | ~a & c) + k[5] + 1200080426 | 0;\n d = (d << 12 | d >>> 20) + a | 0;\n c += (d & a | ~d & b) + k[6] - 1473231341 | 0;\n c = (c << 17 | c >>> 15) + d | 0;\n b += (c & d | ~c & a) + k[7] - 45705983 | 0;\n b = (b << 22 | b >>> 10) + c | 0;\n a += (b & c | ~b & d) + k[8] + 1770035416 | 0;\n a = (a << 7 | a >>> 25) + b | 0;\n d += (a & b | ~a & c) + k[9] - 1958414417 | 0;\n d = (d << 12 | d >>> 20) + a | 0;\n c += (d & a | ~d & b) + k[10] - 42063 | 0;\n c = (c << 17 | c >>> 15) + d | 0;\n b += (c & d | ~c & a) + k[11] - 1990404162 | 0;\n b = (b << 22 | b >>> 10) + c | 0;\n a += (b & c | ~b & d) + k[12] + 1804603682 | 0;\n a = (a << 7 | a >>> 25) + b | 0;\n d += (a & b | ~a & c) + k[13] - 40341101 | 0;\n d = (d << 12 | d >>> 20) + a | 0;\n c += (d & a | ~d & b) + k[14] - 1502002290 | 0;\n c = (c << 17 | c >>> 15) + d | 0;\n b += (c & d | ~c & a) + k[15] + 1236535329 | 0;\n b = (b << 22 | b >>> 10) + c | 0;\n\n a += (b & d | c & ~d) + k[1] - 165796510 | 0;\n a = (a << 5 | a >>> 27) + b | 0;\n d += (a & c | b & ~c) + k[6] - 1069501632 | 0;\n d = (d << 9 | d >>> 23) + a | 0;\n c += (d & b | a & ~b) + k[11] + 643717713 | 0;\n c = (c << 14 | c >>> 18) + d | 0;\n b += (c & a | d & ~a) + k[0] - 373897302 | 0;\n b = (b << 20 | b >>> 12) + c | 0;\n a += (b & d | c & ~d) + k[5] - 701558691 | 0;\n a = (a << 5 | a >>> 27) + b | 0;\n d += (a & c | b & ~c) + k[10] + 38016083 | 0;\n d = (d << 9 | d >>> 23) + a | 0;\n c += (d & b | a & ~b) + k[15] - 660478335 | 0;\n c = (c << 14 | c >>> 18) + d | 0;\n b += (c & a | d & ~a) + k[4] - 405537848 | 0;\n b = (b << 20 | b >>> 12) + c | 0;\n a += (b & d | c & ~d) + k[9] + 568446438 | 0;\n a = (a << 5 | a >>> 27) + b | 0;\n d += (a & c | b & ~c) + k[14] - 1019803690 | 0;\n d = (d << 9 | d >>> 23) + a | 0;\n c += (d & b | a & ~b) + k[3] - 187363961 | 0;\n c = (c << 14 | c >>> 18) + d | 0;\n b += (c & a | d & ~a) + k[8] + 1163531501 | 0;\n b = (b << 20 | b >>> 12) + c | 0;\n a += (b & d | c & ~d) + k[13] - 1444681467 | 0;\n a = (a << 5 | a >>> 27) + b | 0;\n d += (a & c | b & ~c) + k[2] - 51403784 | 0;\n d = (d << 9 | d >>> 23) + a | 0;\n c += (d & b | a & ~b) + k[7] + 1735328473 | 0;\n c = (c << 14 | c >>> 18) + d | 0;\n b += (c & a | d & ~a) + k[12] - 1926607734 | 0;\n b = (b << 20 | b >>> 12) + c | 0;\n\n a += (b ^ c ^ d) + k[5] - 378558 | 0;\n a = (a << 4 | a >>> 28) + b | 0;\n d += (a ^ b ^ c) + k[8] - 2022574463 | 0;\n d = (d << 11 | d >>> 21) + a | 0;\n c += (d ^ a ^ b) + k[11] + 1839030562 | 0;\n c = (c << 16 | c >>> 16) + d | 0;\n b += (c ^ d ^ a) + k[14] - 35309556 | 0;\n b = (b << 23 | b >>> 9) + c | 0;\n a += (b ^ c ^ d) + k[1] - 1530992060 | 0;\n a = (a << 4 | a >>> 28) + b | 0;\n d += (a ^ b ^ c) + k[4] + 1272893353 | 0;\n d = (d << 11 | d >>> 21) + a | 0;\n c += (d ^ a ^ b) + k[7] - 155497632 | 0;\n c = (c << 16 | c >>> 16) + d | 0;\n b += (c ^ d ^ a) + k[10] - 1094730640 | 0;\n b = (b << 23 | b >>> 9) + c | 0;\n a += (b ^ c ^ d) + k[13] + 681279174 | 0;\n a = (a << 4 | a >>> 28) + b | 0;\n d += (a ^ b ^ c) + k[0] - 358537222 | 0;\n d = (d << 11 | d >>> 21) + a | 0;\n c += (d ^ a ^ b) + k[3] - 722521979 | 0;\n c = (c << 16 | c >>> 16) + d | 0;\n b += (c ^ d ^ a) + k[6] + 76029189 | 0;\n b = (b << 23 | b >>> 9) + c | 0;\n a += (b ^ c ^ d) + k[9] - 640364487 | 0;\n a = (a << 4 | a >>> 28) + b | 0;\n d += (a ^ b ^ c) + k[12] - 421815835 | 0;\n d = (d << 11 | d >>> 21) + a | 0;\n c += (d ^ a ^ b) + k[15] + 530742520 | 0;\n c = (c << 16 | c >>> 16) + d | 0;\n b += (c ^ d ^ a) + k[2] - 995338651 | 0;\n b = (b << 23 | b >>> 9) + c | 0;\n\n a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;\n a = (a << 6 | a >>> 26) + b | 0;\n d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;\n d = (d << 10 | d >>> 22) + a | 0;\n c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;\n c = (c << 15 | c >>> 17) + d | 0;\n b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;\n b = (b << 21 |b >>> 11) + c | 0;\n a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;\n a = (a << 6 | a >>> 26) + b | 0;\n d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;\n d = (d << 10 | d >>> 22) + a | 0;\n c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;\n c = (c << 15 | c >>> 17) + d | 0;\n b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;\n b = (b << 21 |b >>> 11) + c | 0;\n a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;\n a = (a << 6 | a >>> 26) + b | 0;\n d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;\n d = (d << 10 | d >>> 22) + a | 0;\n c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;\n c = (c << 15 | c >>> 17) + d | 0;\n b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;\n b = (b << 21 |b >>> 11) + c | 0;\n a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;\n a = (a << 6 | a >>> 26) + b | 0;\n d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;\n d = (d << 10 | d >>> 22) + a | 0;\n c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;\n c = (c << 15 | c >>> 17) + d | 0;\n b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;\n b = (b << 21 | b >>> 11) + c | 0;\n\n x[0] = a + x[0] | 0;\n x[1] = b + x[1] | 0;\n x[2] = c + x[2] | 0;\n x[3] = d + x[3] | 0;\n }\n\n function md5blk(s) {\n var md5blks = [],\n i; /* Andy King said do it this way. */\n\n for (i = 0; i < 64; i += 4) {\n md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);\n }\n return md5blks;\n }\n\n function md5blk_array(a) {\n var md5blks = [],\n i; /* Andy King said do it this way. */\n\n for (i = 0; i < 64; i += 4) {\n md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);\n }\n return md5blks;\n }\n\n function md51(s) {\n var n = s.length,\n state = [1732584193, -271733879, -1732584194, 271733878],\n i,\n length,\n tail,\n tmp,\n lo,\n hi;\n\n for (i = 64; i <= n; i += 64) {\n md5cycle(state, md5blk(s.substring(i - 64, i)));\n }\n s = s.substring(i - 64);\n length = s.length;\n tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n for (i = 0; i < length; i += 1) {\n tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);\n }\n tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n if (i > 55) {\n md5cycle(state, tail);\n for (i = 0; i < 16; i += 1) {\n tail[i] = 0;\n }\n }\n\n // Beware that the final length might not fit in 32 bits so we take care of that\n tmp = n * 8;\n tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n lo = parseInt(tmp[2], 16);\n hi = parseInt(tmp[1], 16) || 0;\n\n tail[14] = lo;\n tail[15] = hi;\n\n md5cycle(state, tail);\n return state;\n }\n\n function md51_array(a) {\n var n = a.length,\n state = [1732584193, -271733879, -1732584194, 271733878],\n i,\n length,\n tail,\n tmp,\n lo,\n hi;\n\n for (i = 64; i <= n; i += 64) {\n md5cycle(state, md5blk_array(a.subarray(i - 64, i)));\n }\n\n // Not sure if it is a bug, however IE10 will always produce a sub array of length 1\n // containing the last element of the parent array if the sub array specified starts\n // beyond the length of the parent array - weird.\n // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue\n a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);\n\n length = a.length;\n tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n for (i = 0; i < length; i += 1) {\n tail[i >> 2] |= a[i] << ((i % 4) << 3);\n }\n\n tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n if (i > 55) {\n md5cycle(state, tail);\n for (i = 0; i < 16; i += 1) {\n tail[i] = 0;\n }\n }\n\n // Beware that the final length might not fit in 32 bits so we take care of that\n tmp = n * 8;\n tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n lo = parseInt(tmp[2], 16);\n hi = parseInt(tmp[1], 16) || 0;\n\n tail[14] = lo;\n tail[15] = hi;\n\n md5cycle(state, tail);\n\n return state;\n }\n\n function rhex(n) {\n var s = '',\n j;\n for (j = 0; j < 4; j += 1) {\n s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];\n }\n return s;\n }\n\n function hex(x) {\n var i;\n for (i = 0; i < x.length; i += 1) {\n x[i] = rhex(x[i]);\n }\n return x.join('');\n }\n\n // In some cases the fast add32 function cannot be used..\n if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592') {\n add32 = function (x, y) {\n var lsw = (x & 0xFFFF) + (y & 0xFFFF),\n msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n return (msw << 16) | (lsw & 0xFFFF);\n };\n }\n\n // ---------------------------------------------------\n\n /**\n * ArrayBuffer slice polyfill.\n *\n * @see https://github.com/ttaubert/node-arraybuffer-slice\n */\n\n if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {\n (function () {\n function clamp(val, length) {\n val = (val | 0) || 0;\n\n if (val < 0) {\n return Math.max(val + length, 0);\n }\n\n return Math.min(val, length);\n }\n\n ArrayBuffer.prototype.slice = function (from, to) {\n var length = this.byteLength,\n begin = clamp(from, length),\n end = length,\n num,\n target,\n targetArray,\n sourceArray;\n\n if (to !== undefined) {\n end = clamp(to, length);\n }\n\n if (begin > end) {\n return new ArrayBuffer(0);\n }\n\n num = end - begin;\n target = new ArrayBuffer(num);\n targetArray = new Uint8Array(target);\n\n sourceArray = new Uint8Array(this, begin, num);\n targetArray.set(sourceArray);\n\n return target;\n };\n })();\n }\n\n // ---------------------------------------------------\n\n /**\n * Helpers.\n */\n\n function toUtf8(str) {\n if (/[\\u0080-\\uFFFF]/.test(str)) {\n str = unescape(encodeURIComponent(str));\n }\n\n return str;\n }\n\n function utf8Str2ArrayBuffer(str, returnUInt8Array) {\n var length = str.length,\n buff = new ArrayBuffer(length),\n arr = new Uint8Array(buff),\n i;\n\n for (i = 0; i < length; i += 1) {\n arr[i] = str.charCodeAt(i);\n }\n\n return returnUInt8Array ? arr : buff;\n }\n\n function arrayBuffer2Utf8Str(buff) {\n return String.fromCharCode.apply(null, new Uint8Array(buff));\n }\n\n function concatenateArrayBuffers(first, second, returnUInt8Array) {\n var result = new Uint8Array(first.byteLength + second.byteLength);\n\n result.set(new Uint8Array(first));\n result.set(new Uint8Array(second), first.byteLength);\n\n return returnUInt8Array ? result : result.buffer;\n }\n\n function hexToBinaryString(hex) {\n var bytes = [],\n length = hex.length,\n x;\n\n for (x = 0; x < length - 1; x += 2) {\n bytes.push(parseInt(hex.substr(x, 2), 16));\n }\n\n return String.fromCharCode.apply(String, bytes);\n }\n\n // ---------------------------------------------------\n\n /**\n * SparkMD5 OOP implementation.\n *\n * Use this class to perform an incremental md5, otherwise use the\n * static methods instead.\n */\n\n function SparkMD5() {\n // call reset to init the instance\n this.reset();\n }\n\n /**\n * Appends a string.\n * A conversion will be applied if an utf8 string is detected.\n *\n * @param {String} str The string to be appended\n *\n * @return {SparkMD5} The instance itself\n */\n SparkMD5.prototype.append = function (str) {\n // Converts the string to utf8 bytes if necessary\n // Then append as binary\n this.appendBinary(toUtf8(str));\n\n return this;\n };\n\n /**\n * Appends a binary string.\n *\n * @param {String} contents The binary string to be appended\n *\n * @return {SparkMD5} The instance itself\n */\n SparkMD5.prototype.appendBinary = function (contents) {\n this._buff += contents;\n this._length += contents.length;\n\n var length = this._buff.length,\n i;\n\n for (i = 64; i <= length; i += 64) {\n md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));\n }\n\n this._buff = this._buff.substring(i - 64);\n\n return this;\n };\n\n /**\n * Finishes the incremental computation, reseting the internal state and\n * returning the result.\n *\n * @param {Boolean} raw True to get the raw string, false to get the hex string\n *\n * @return {String} The result\n */\n SparkMD5.prototype.end = function (raw) {\n var buff = this._buff,\n length = buff.length,\n i,\n tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n ret;\n\n for (i = 0; i < length; i += 1) {\n tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);\n }\n\n this._finish(tail, length);\n ret = hex(this._hash);\n\n if (raw) {\n ret = hexToBinaryString(ret);\n }\n\n this.reset();\n\n return ret;\n };\n\n /**\n * Resets the internal state of the computation.\n *\n * @return {SparkMD5} The instance itself\n */\n SparkMD5.prototype.reset = function () {\n this._buff = '';\n this._length = 0;\n this._hash = [1732584193, -271733879, -1732584194, 271733878];\n\n return this;\n };\n\n /**\n * Gets the internal state of the computation.\n *\n * @return {Object} The state\n */\n SparkMD5.prototype.getState = function () {\n return {\n buff: this._buff,\n length: this._length,\n hash: this._hash.slice()\n };\n };\n\n /**\n * Gets the internal state of the computation.\n *\n * @param {Object} state The state\n *\n * @return {SparkMD5} The instance itself\n */\n SparkMD5.prototype.setState = function (state) {\n this._buff = state.buff;\n this._length = state.length;\n this._hash = state.hash;\n\n return this;\n };\n\n /**\n * Releases memory used by the incremental buffer and other additional\n * resources. If you plan to use the instance again, use reset instead.\n */\n SparkMD5.prototype.destroy = function () {\n delete this._hash;\n delete this._buff;\n delete this._length;\n };\n\n /**\n * Finish the final calculation based on the tail.\n *\n * @param {Array} tail The tail (will be modified)\n * @param {Number} length The length of the remaining buffer\n */\n SparkMD5.prototype._finish = function (tail, length) {\n var i = length,\n tmp,\n lo,\n hi;\n\n tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n if (i > 55) {\n md5cycle(this._hash, tail);\n for (i = 0; i < 16; i += 1) {\n tail[i] = 0;\n }\n }\n\n // Do the final computation based on the tail and length\n // Beware that the final length may not fit in 32 bits so we take care of that\n tmp = this._length * 8;\n tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n lo = parseInt(tmp[2], 16);\n hi = parseInt(tmp[1], 16) || 0;\n\n tail[14] = lo;\n tail[15] = hi;\n md5cycle(this._hash, tail);\n };\n\n /**\n * Performs the md5 hash on a string.\n * A conversion will be applied if utf8 string is detected.\n *\n * @param {String} str The string\n * @param {Boolean} [raw] True to get the raw string, false to get the hex string\n *\n * @return {String} The result\n */\n SparkMD5.hash = function (str, raw) {\n // Converts the string to utf8 bytes if necessary\n // Then compute it using the binary function\n return SparkMD5.hashBinary(toUtf8(str), raw);\n };\n\n /**\n * Performs the md5 hash on a binary string.\n *\n * @param {String} content The binary string\n * @param {Boolean} [raw] True to get the raw string, false to get the hex string\n *\n * @return {String} The result\n */\n SparkMD5.hashBinary = function (content, raw) {\n var hash = md51(content),\n ret = hex(hash);\n\n return raw ? hexToBinaryString(ret) : ret;\n };\n\n // ---------------------------------------------------\n\n /**\n * SparkMD5 OOP implementation for array buffers.\n *\n * Use this class to perform an incremental md5 ONLY for array buffers.\n */\n SparkMD5.ArrayBuffer = function () {\n // call reset to init the instance\n this.reset();\n };\n\n /**\n * Appends an array buffer.\n *\n * @param {ArrayBuffer} arr The array to be appended\n *\n * @return {SparkMD5.ArrayBuffer} The instance itself\n */\n SparkMD5.ArrayBuffer.prototype.append = function (arr) {\n var buff = concatenateArrayBuffers(this._buff.buffer, arr, true),\n length = buff.length,\n i;\n\n this._length += arr.byteLength;\n\n for (i = 64; i <= length; i += 64) {\n md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));\n }\n\n this._buff = (i - 64) < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);\n\n return this;\n };\n\n /**\n * Finishes the incremental computation, reseting the internal state and\n * returning the result.\n *\n * @param {Boolean} raw True to get the raw string, false to get the hex string\n *\n * @return {String} The result\n */\n SparkMD5.ArrayBuffer.prototype.end = function (raw) {\n var buff = this._buff,\n length = buff.length,\n tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n i,\n ret;\n\n for (i = 0; i < length; i += 1) {\n tail[i >> 2] |= buff[i] << ((i % 4) << 3);\n }\n\n this._finish(tail, length);\n ret = hex(this._hash);\n\n if (raw) {\n ret = hexToBinaryString(ret);\n }\n\n this.reset();\n\n return ret;\n };\n\n /**\n * Resets the internal state of the computation.\n *\n * @return {SparkMD5.ArrayBuffer} The instance itself\n */\n SparkMD5.ArrayBuffer.prototype.reset = function () {\n this._buff = new Uint8Array(0);\n this._length = 0;\n this._hash = [1732584193, -271733879, -1732584194, 271733878];\n\n return this;\n };\n\n /**\n * Gets the internal state of the computation.\n *\n * @return {Object} The state\n */\n SparkMD5.ArrayBuffer.prototype.getState = function () {\n var state = SparkMD5.prototype.getState.call(this);\n\n // Convert buffer to a string\n state.buff = arrayBuffer2Utf8Str(state.buff);\n\n return state;\n };\n\n /**\n * Gets the internal state of the computation.\n *\n * @param {Object} state The state\n *\n * @return {SparkMD5.ArrayBuffer} The instance itself\n */\n SparkMD5.ArrayBuffer.prototype.setState = function (state) {\n // Convert string to buffer\n state.buff = utf8Str2ArrayBuffer(state.buff, true);\n\n return SparkMD5.prototype.setState.call(this, state);\n };\n\n SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;\n\n SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;\n\n /**\n * Performs the md5 hash on an array buffer.\n *\n * @param {ArrayBuffer} arr The array buffer\n * @param {Boolean} [raw] True to get the raw string, false to get the hex one\n *\n * @return {String} The result\n */\n SparkMD5.ArrayBuffer.hash = function (arr, raw) {\n var hash = md51_array(new Uint8Array(arr)),\n ret = hex(hash);\n\n return raw ? hexToBinaryString(ret) : ret;\n };\n\n return SparkMD5;\n}));\n","export * from \"-!../../../../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../../../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../../../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=style&index=0&id=61052c10&prod&lang=scss&scoped=true\"","export * from \"-!../../../../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../../../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../../../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=style&index=0&id=cdec1cec&prod&lang=scss&scoped=true\"","// extracted by mini-css-extract-plugin","export * from \"-!../../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=style&index=0&id=3f692c5e&prod&lang=scss&scoped=true\"","// This file is imported into lib/wc client bundles.\n\nif (typeof window !== 'undefined') {\n var currentScript = window.document.currentScript\n if (process.env.NEED_CURRENTSCRIPT_POLYFILL) {\n var getCurrentScript = require('@soda/get-current-script')\n currentScript = getCurrentScript()\n\n // for backward compatibility, because previously we directly included the polyfill\n if (!('currentScript' in document)) {\n Object.defineProperty(document, 'currentScript', { get: getCurrentScript })\n }\n }\n\n var src = currentScript && currentScript.src.match(/(.+\\/)[^/]+\\.js(\\?.*)?$/)\n if (src) {\n __webpack_public_path__ = src[1] // eslint-disable-line\n }\n}\n\n// Indicate to webpack that this file can be concatenated\nexport default null\n","// import request from \"@/utils/request\";\r\n\r\nlet request = null\r\n\r\n// 将vue.use传入的axios实例赋值给request\r\nexport function setAxiosInstance(axiosInstance) {\r\n if (axiosInstance) {\r\n request = axiosInstance;\r\n }\r\n}\r\n\r\n// 执行一个方法,返回n个请求方法\r\n/**\r\n * \r\n * @param {Object} apiObj 包含所有接口地址的对象 {\r\n checkfileStatusUrl: \"/zt-api/resources/check\",\r\n filesAllUoloadedUrl: \"/zt-api/resources/chunk/merge\",\r\n searchFileIsUploadedUrl: \"/zt-api/resources/check\",\r\n searchChunkIsUploadedUrl: \"/zt-api/resources/check/chunk\",\r\n uploadFileChunkUrl: \"/zt-api/resources/chunk/upload\",\r\n addNewFileOfTxtUrl: \"/api/v1/program/create-doc\",\r\n addNewFileOfVideoUrl: \"/api/v1/program/create-video\",\r\n addNewFileOfAudioUrl: \"/api/v1/program/create-audio\",\r\n addNewFileOfPicUrl: \"/api/v1/program/create-pic\",\r\n addNewFileOfSubTitleUrl: \"/api/v1/program/create-srt\",\r\n }\r\n * @returns \r\n */\r\nexport function mapApiToRequest(apiObj) {\r\n return {\r\n checkfileStatus: data => \r\n checkfileStatus(data, apiObj.checkfileStatusUrl),\r\n\r\n filesAllUoloaded: data =>\r\n filesAllUoloaded(data, apiObj.filesAllUoloadedUrl),\r\n\r\n searchFileIsUploaded: data =>\r\n searchFileIsUploaded(data, apiObj.searchFileIsUploadedUrl),\r\n\r\n searchChunkIsUploaded: data =>\r\n searchChunkIsUploaded(data, apiObj.searchChunkIsUploadedUrl),\r\n\r\n uploadFileChunk: data => \r\n uploadFileChunk(data, apiObj.uploadFileChunkUrl),\r\n\r\n addNewFileOfTxt: data => \r\n addNewFileOfTxt(data, apiObj.addNewFileOfTxtUrl),\r\n\r\n addNewFileOfVideo: data =>\r\n addNewFileOfVideo(data, apiObj.addNewFileOfVideoUrl),\r\n\r\n addNewFileOfAudio: data =>\r\n addNewFileOfAudio(data, apiObj.addNewFileOfAudioUrl),\r\n\r\n addNewFileOfPic: data => \r\n addNewFileOfPic(data, apiObj.addNewFileOfPicUrl),\r\n \r\n addNewFileOfSubTitle: data =>\r\n addNewFileOfSubTitle(data, apiObj.addNewFileOfSubTitleUrl),\r\n };\r\n}\r\n\r\n// 检查文件状态\r\nfunction checkfileStatus(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n\r\n// 合并块文件\r\nfunction filesAllUoloaded(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n\r\n// 检查文件是否已上传过\r\nfunction searchFileIsUploaded(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n\r\n// 检查文件块是否已上传过\r\nfunction searchChunkIsUploaded(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n\r\n// 上传文件块\r\nfunction uploadFileChunk(data, url) {\r\n const formData = data instanceof FormData ? data : new FormData();\r\n\r\n if (!(data instanceof FormData) && data && typeof data === \"object\") {\r\n Object.keys(data).forEach(key => {\r\n formData.append(key, data[key]);\r\n });\r\n }\r\n\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data: formData,\r\n headers: {\r\n \"Content-Type\": \"multipart/form-data\",\r\n },\r\n timeout: 1000 * 60 * 10,\r\n });\r\n}\r\n\r\n// 创建新文件\r\nfunction addNewFileOfTxt(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\nfunction addNewFileOfVideo(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\nfunction addNewFileOfAudio(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\nfunction addNewFileOfPic(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\nfunction addNewFileOfSubTitle(data, url) {\r\n return request({\r\n url: url,\r\n method: \"post\",\r\n data,\r\n });\r\n}\r\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"upload-multiple\"},[_c('input',{ref:\"multiplePloadInput\",staticStyle:{\"display\":\"none\"},attrs:{\"type\":\"file\",\"multiple\":_vm.multiple,\"accept\":_vm.limitFileType},on:{\"change\":_vm.handleSelectedMultipleFiles}}),_c('div',{staticClass:\"upload-multiple-box\"},[_c('div',{ref:\"upLoded_box\",staticClass:\"multiple_upload_area\",class:_vm.multipleUploadAreaClass(),on:{\"click\":_vm.reviewUploadMultipleFiles,\"dragover\":function($event){$event.preventDefault();return _vm.onDragOver($event)},\"dragleave\":function($event){$event.preventDefault();return _vm.onDragLeave($event)},\"drop\":function($event){$event.preventDefault();return _vm.onDrop($event)}}},[(_vm.isUploading)?_c('div',{staticClass:\"upload-loading-mask\",style:(_vm.setUploadingLoadingMaskStyle())}):_vm._e(),(_vm.showIconTip)?_c('div',[_c('i',{staticClass:\"el-icon-upload\"})]):_vm._e(),_c('div',[_vm._v(_vm._s(_vm.startButtonText))]),_vm._t(\"tips\")],2),(_vm.pictureConfig.show && _vm.showSuccessPicture)?_c('div',{staticClass:\"upload-multiple-box-right\"},[_c('div',{staticClass:\"upload-multiple-box-close\",on:{\"click\":function($event){$event.stopPropagation();return _vm.clearPicture($event)}}},[_c('i',{staticClass:\"el-icon-close\"})]),_c('img',{attrs:{\"src\":_vm.pictureConfig.url,\"alt\":_vm.pictureConfig.altText}})]):_vm._e()]),(_vm.isShowAllUploadButton)?_c('el-button',{staticClass:\"upload_button\",attrs:{\"type\":\"primary\",\"disabled\":_vm.isUploading || _vm.needUploadFilesArr.length === 0},on:{\"click\":_vm.startUploadMultipleFiles}},[_vm._v(\" 全部文件开始上传 \")]):_vm._e(),(_vm.model === 'table')?_c('div',{staticClass:\"upload-multiple-table\"},[_c('Upload_table',{attrs:{\"needUploadFilesArr\":_vm.needUploadFilesArr,\"fileConfig\":_vm.fileConfig,\"fileType\":_vm.addDataBaseLinkConfig.addFileType,\"isUploading\":_vm.isUploading},on:{\"delteSelectedFile\":_vm.delteSelectedFile,\"cancelFileUpload\":_vm.cancelFileUpload,\"resetFileUpload\":_vm.resetFileUpload,\"handleSelectionChange\":_vm.tableSelectionChange}})],1):_vm._e(),(_vm.model === 'info')?_c('div',{staticClass:\"multiple_upload_list\"},[_c('span',{staticClass:\"tip_title\"},[_c('span',{staticClass:\"title\"},[_c('div',[_vm._v(\"文件列表\")]),_c('transition',{attrs:{\"name\":\"totalProgress\",\"mode\":\"out-in\"}},[(_vm.needUploadFilesArr.length > 0)?_c('div',{staticClass:\"total_progress\"},[_c('div',{staticClass:\"logo\"}),_c('span',[_vm._v(\"总进度:\")]),(_vm.fileConfig.uploadController)?_c('div',[_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":_vm.isDanger}},[_vm._v(\"上传错误:\"+_vm._s(_vm.fileConfig.skipError_num))]),_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":\"\"}},[_vm._v(\"上传成功:\"+_vm._s(_vm.fileConfig.completed_num))]),_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":\"\"}},[_vm._v(\"文件总数:\"+_vm._s(_vm.fileConfig.filetotal_num))])],1):_vm._e()]):_vm._e()])],1),_c('span',[_c('el-button',{attrs:{\"size\":\"mini\",\"type\":\"\",\"disabled\":_vm.isUploading || _vm.needUploadFilesArr.length === 0},on:{\"click\":_vm.handleSelectAllFile}},[_vm._v(\"全选所有文件\")]),_c('el-button',{attrs:{\"size\":\"mini\",\"type\":\"danger\",\"disabled\":_vm.isUploading || _vm.needUploadFilesArr.length === 0},on:{\"click\":_vm.delteSelectedFile}},[_vm._v(\"移除所选文件\")])],1)]),_c('div',{staticClass:\"selected_list_area\"},[(_vm.needUploadFilesArr.length > 0)?_c('div',{staticClass:\"selected_list\"},_vm._l((_vm.needUploadFilesArr),function(item,index){return _c('Card_2',{key:index,attrs:{\"index\":index,\"file-config\":item},on:{\"cancelFileUpload\":_vm.cancelFileUpload,\"resetFileUpload\":_vm.resetFileUpload,\"handleClickOnlyFile\":_vm.handleClickOnlyFile}})}),1):_c('div',{staticClass:\"no_file\"},[_c('i',{staticClass:\"el-icon-document\"}),_c('div',[_vm._v(\"暂无文件,请点击或拖拽文件到上传区域\")])])])]):_vm._e()],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","// 辅助函数:获取MIME类型\r\nfunction getMimeType(fileOrType) {\r\n if (!fileOrType) return \"\";\r\n\r\n if (typeof fileOrType === \"string\") {\r\n return fileOrType;\r\n }\r\n\r\n if (fileOrType instanceof File || fileOrType instanceof Blob) {\r\n return fileOrType.type;\r\n }\r\n\r\n if (fileOrType.type && typeof fileOrType.type === \"string\") {\r\n return fileOrType.type;\r\n }\r\n return \"\";\r\n}\r\n\r\nexport const fileTypeValidators = {\r\n /**\r\n * 验证图片类型\r\n * 支持: jpg, jpeg, png, gif, webp, bmp, svg, tiff, ico\r\n */\r\n isImage: (fileOrType) => {\r\n const mime = getMimeType(fileOrType);\r\n return /(jpg|jpeg|png|gif|webp|bmp|svg|tiff|ico)$/i.test(mime);\r\n },\r\n\r\n /**\r\n * 验证视频类型\r\n * 支持: mp4, avi, webm, mov, wmv, flv, mkv, mpeg, 3gp\r\n */\r\n isVideo: (fileOrType) => {\r\n const mime = getMimeType(fileOrType);\r\n return /(mp4|avi|webm|mov|wmv|flv|mkv|mpeg|3gp)$/i.test(mime);\r\n },\r\n\r\n /**\r\n * 验证音频类型\r\n * 支持: mp3, wav, ogg, aac, flac, m4a, mid, opus\r\n */\r\n isAudio: (fileOrType) => {\r\n const mime = getMimeType(fileOrType);\r\n return (\r\n /^audio\\/(mpeg|mp3|mp4|x-m4a|wav|ogg|aac|flac|mid|x-midi|opus|webm)$/i.test(\r\n mime\r\n ) ||\r\n /\\.(mp3|wav|ogg|aac|flac|m4a|mid|opus)$/i.test(mime) ||\r\n /^(mp3|wav|ogg|aac|flac|m4a|mid|opus)$/i.test(mime)\r\n );\r\n },\r\n\r\n /**\r\n * 验证字幕类型\r\n * 支持: srt, vtt, ass, ssa, sub\r\n */\r\n isSubtitle: (fileOrType) => {\r\n const mime = getMimeType(fileOrType);\r\n console.log(mime);\r\n return /(vtt|ass|srt)$/i.test(mime);\r\n },\r\n\r\n /**\r\n * 验证文档类型\r\n * 支持: pdf, doc, docx, xls, xlsx, ppt, pptx, txt, rtf, zip, rar, 7z\r\n */\r\n isDocument: (fileOrType) => {\r\n return true;\r\n // const mime = getMimeType(fileOrType);\r\n // return /^(presentation))|text\\/(plain|html|csv|xml|css|javascript|markdown))$/i.test(mime);\r\n },\r\n};","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{key:_vm.fileConfig.name + '_' + _vm.index,staticClass:\"only_file_area\",class:{\n only_file_area_isActive: _vm.fileConfig.isSelected,\n 'fade-in-element': true,\n },on:{\"click\":function($event){return _vm.handleClickOnlyFile(_vm.fileConfig)}}},[_c('div',{staticClass:\"file_card_top\"},[_c('div',{staticClass:\"file_type\"},[_vm._v(\" \"+_vm._s(_vm.getFileType(_vm.fileConfig.name))+\" \")]),_c('div',{staticClass:\"file_name\"},[_vm._v(_vm._s(_vm.fileConfig.name))])]),_c('div',{staticClass:\"file_card_bottom\"},[_c('div',{staticClass:\"option\"},[_c('div',{staticClass:\"status_text\"},[_c('span',{class:_vm.uploadingTextStyle(_vm.fileConfig.tip)},[_vm._v(_vm._s(_vm.fileConfig.tip))])]),(\n _vm.fileConfig.tip === '上传中'\n )?_c('div',{staticClass:\"option_text\",on:{\"click\":function($event){$event.stopPropagation();return _vm.cancelFileUpload(_vm.fileConfig)}}},[_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":\"danger\"}},[_vm._v(\"取消\")])],1):_vm._e(),(\n _vm.fileConfig.tip === '已取消' ||\n _vm.fileConfig.tip === '上传出错' ||\n _vm.fileConfig.tip === '未知出错'\n )?_c('div',{staticClass:\"option_text\",on:{\"click\":function($event){$event.stopPropagation();return _vm.resetFileUpload(_vm.fileConfig)}}},[_c('el-tag',{attrs:{\"size\":\"mini\",\"type\":\"\"}},[_vm._v(\"重试\")])],1):_vm._e()]),_c('div',[_c('span',[_vm._v(_vm._s(_vm.uploadingNumber( _vm.fileFormatValid(_vm.fileConfig.file.size), _vm.fileConfig.uploadProgress ))+\"/\"+_vm._s(_vm.fileFormatValid(_vm.fileConfig.file.size))+\"mb\")])])]),_c('div',{staticClass:\"progress_area\"},[_c('el-progress',{staticClass:\"custom-progress\",attrs:{\"color\":_vm.colors,\"show-text\":false,\"percentage\":_vm.fileConfig.uploadProgress}})],1)])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","<template>\r\n <div\r\n :key=\"fileConfig.name + '_' + index\"\r\n class=\"only_file_area\"\r\n :class=\"{\r\n only_file_area_isActive: fileConfig.isSelected,\r\n 'fade-in-element': true,\r\n }\"\r\n @click=\"handleClickOnlyFile(fileConfig)\"\r\n >\r\n <div class=\"file_card_top\">\r\n <div class=\"file_type\">\r\n {{ getFileType(fileConfig.name) }}\r\n </div>\r\n <div class=\"file_name\">{{ fileConfig.name }}</div>\r\n </div>\r\n\r\n <div class=\"file_card_bottom\">\r\n <div class=\"option\">\r\n <div class=\"status_text\">\r\n <span :class=\"uploadingTextStyle(fileConfig.tip)\">{{\r\n fileConfig.tip\r\n }}</span>\r\n </div>\r\n <div\r\n v-if=\"\r\n fileConfig.tip === '上传中'\r\n \"\r\n class=\"option_text\"\r\n @click.stop=\"cancelFileUpload(fileConfig)\"\r\n >\r\n <!-- 只有上传中,在排队的人物可以进行取消 -->\r\n <el-tag size=\"mini\" type=\"danger\">取消</el-tag>\r\n </div>\r\n <div\r\n v-if=\"\r\n fileConfig.tip === '已取消' ||\r\n fileConfig.tip === '上传出错' ||\r\n fileConfig.tip === '未知出错'\r\n \"\r\n class=\"option_text\"\r\n @click.stop=\"resetFileUpload(fileConfig)\"\r\n >\r\n <el-tag size=\"mini\" type=\"\">重试</el-tag>\r\n </div>\r\n </div>\r\n <div>\r\n <span>{{\r\n uploadingNumber(\r\n fileFormatValid(fileConfig.file.size),\r\n fileConfig.uploadProgress\r\n )\r\n }}/{{ fileFormatValid(fileConfig.file.size) }}mb</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"progress_area\">\r\n <el-progress\r\n :color=\"colors\"\r\n :show-text=\"false\"\r\n :percentage=\"fileConfig.uploadProgress\"\r\n class=\"custom-progress\"\r\n />\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script>\r\nexport default {\r\n name: \"UploadCardVerFirst\",\r\n props: {\r\n fileConfig: {\r\n required: true,\r\n type: Object,\r\n default: () => {\r\n return {};\r\n },\r\n },\r\n index: {\r\n required: false,\r\n type: Number,\r\n default: 0,\r\n },\r\n },\r\n data() {\r\n return {\r\n colors: [\r\n { color: \"#bae6fd\", percentage: 20 }, // 浅天蓝:刚刚启动,轻快感\r\n { color: \"#7dd3fc\", percentage: 40 }, // 天蓝:平稳进行\r\n { color: \"#38bdf8\", percentage: 60 }, // 亮蓝:进入核心处理\r\n { color: \"#2563eb\", percentage: 80 }, // 宝蓝:即将完成的厚重感\r\n { color: \"#6366f1\", percentage: 100 }, // 靛紫:完成时的精致感\r\n ],\r\n };\r\n },\r\n methods: {\r\n handleClickOnlyFile(fileConfig) {\r\n this.$emit(\"handleClickOnlyFile\", this.fileConfig);\r\n },\r\n getFileType(name) {\r\n return name.split(\".\")[1];\r\n },\r\n uploadingTextStyle(text) {\r\n // 第一个未知,第二个stauts超时,第三个上传块超时\r\n if (\r\n text === \"出错\" ||\r\n text === \"查询文件地址超时\" ||\r\n text === \"上传出错\"\r\n ) {\r\n return \"uploading_error\";\r\n } else if (text === \"已完成\") {\r\n return \"uploading_success\";\r\n } else if (text === \"等待上传\") {\r\n return \"uploading_wait\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n // 更新上传数字\r\n uploadingNumber(total, completed) {\r\n if (!completed) return 0;\r\n\r\n return (total * (completed / 100)).toFixed(2);\r\n },\r\n // 数字验证\r\n fileFormatValid(val) {\r\n const number = (val / (1024 * 1024)).toFixed(2);\r\n\r\n return number;\r\n },\r\n resetFileUpload(item) {\r\n this.$emit(\"resetFileUpload\", item);\r\n },\r\n cancelFileUpload(item) {\r\n this.$emit(\"cancelFileUpload\", item);\r\n },\r\n },\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.only_file_area {\r\n width: 13.5rem;\r\n min-height: 6rem;\r\n padding: 1rem;\r\n border-radius: 15px;\r\n // background: linear-gradient(135deg, #dae5f5 0%, #ffffff 100%);\r\n border: 1px solid rgb(226, 232, 239);\r\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);\r\n transition: all 0.3s ease;\r\n cursor: pointer;\r\n position: relative;\r\n overflow: hidden;\r\n\r\n &:hover {\r\n transform: translateY(-3px);\r\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n &::before {\r\n content: \"\";\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n width: 3px;\r\n height: 100%;\r\n background: #1890ff;\r\n transform: scaleY(0);\r\n transition: transform 0.3s ease;\r\n }\r\n\r\n &:hover::before {\r\n transform: scaleY(1);\r\n }\r\n\r\n .file_icon {\r\n font-size: 2rem;\r\n color: #909399;\r\n margin-right: 1rem;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n .file_card_top {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.4rem;\r\n\r\n .file_type {\r\n width: 2.5rem;\r\n height: 2rem;\r\n // padding: 0.2rem;\r\n text-align: center;\r\n line-height: 2rem;\r\n background-color: #e2e8ef;\r\n font-weight: 600;\r\n border-radius: 5px;\r\n text-transform: uppercase;\r\n font-size: 12px;\r\n white-space: nowrap;\r\n }\r\n\r\n .file_name {\r\n white-space: nowrap;\r\n overflow-x: auto; /* 水平滚动 */\r\n text-overflow: ellipsis;\r\n overflow: hidden;\r\n width: 12rem;\r\n height: 1.5rem;\r\n min-height: 0.5rem;\r\n font-size: 0.9rem;\r\n font-weight: 600;\r\n color: #1f283a;\r\n // margin-bottom: 0.5rem;\r\n word-break: break-all;\r\n line-height: 1.3;\r\n }\r\n }\r\n\r\n .progress_area {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n width: 100%;\r\n\r\n .el-progress {\r\n width: 100%;\r\n // height: 1.5rem;\r\n // min-height: 0.5rem;\r\n // padding-top: 0.2rem;\r\n\r\n ::v-deep .el-progress-bar__outer {\r\n background-color: #b3c3e8;\r\n }\r\n\r\n ::v-deep .el-progress-bar__inner {\r\n transition: width 0.4s ease;\r\n }\r\n }\r\n }\r\n\r\n .file_card_bottom {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n font-size: 12px;\r\n\r\n .option {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.3rem;\r\n\r\n height: 1.5rem;\r\n min-height: 0.5rem;\r\n // font-size: 0.85rem;\r\n\r\n .option_text {\r\n color: red;\r\n }\r\n .option_text:hover {\r\n text-decoration: underline;\r\n cursor: pointer;\r\n }\r\n .status_text {\r\n .uploading_error {\r\n color: red;\r\n font-weight: 500;\r\n }\r\n\r\n .uploading_wait {\r\n color: #909399;\r\n }\r\n\r\n .uploading_success {\r\n color: #67c23a;\r\n font-weight: 500;\r\n }\r\n }\r\n }\r\n }\r\n\r\n &.only_file_area_isActive {\r\n border: 1px solid #1890ff;\r\n background-color: rgba(24, 144, 255, 0.05);\r\n\r\n .file_icon {\r\n color: #1890ff;\r\n transform: scale(1.1);\r\n }\r\n\r\n &::after {\r\n content: \"\";\r\n position: absolute;\r\n top: 0.5rem;\r\n right: 0.5rem;\r\n width: 16px;\r\n height: 16px;\r\n border-radius: 50%;\r\n background: #1890ff;\r\n box-shadow: 0 0 0 2px white;\r\n }\r\n }\r\n}\r\n</style>\r\n","import mod from \"-!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"","/* globals __VUE_SSR_CONTEXT__ */\n\n// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).\n// This module is a runtime utility for cleaner component module output and will\n// be included in the final webpack user bundle.\n\nexport default function normalizeComponent(\n scriptExports,\n render,\n staticRenderFns,\n functionalTemplate,\n injectStyles,\n scopeId,\n moduleIdentifier /* server only */,\n shadowMode /* vue-cli only */\n) {\n // Vue.extend constructor export interop\n var options =\n typeof scriptExports === 'function' ? scriptExports.options : scriptExports\n\n // render functions\n if (render) {\n options.render = render\n options.staticRenderFns = staticRenderFns\n options._compiled = true\n }\n\n // functional template\n if (functionalTemplate) {\n options.functional = true\n }\n\n // scopedId\n if (scopeId) {\n options._scopeId = 'data-v-' + scopeId\n }\n\n var hook\n if (moduleIdentifier) {\n // server build\n hook = function (context) {\n // 2.3 injection\n context =\n context || // cached call\n (this.$vnode && this.$vnode.ssrContext) || // stateful\n (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional\n // 2.2 with runInNewContext: true\n if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\n context = __VUE_SSR_CONTEXT__\n }\n // inject component styles\n if (injectStyles) {\n injectStyles.call(this, context)\n }\n // register component module identifier for async chunk inferrence\n if (context && context._registeredComponents) {\n context._registeredComponents.add(moduleIdentifier)\n }\n }\n // used by ssr in case component is cached and beforeCreate\n // never gets called\n options._ssrRegister = hook\n } else if (injectStyles) {\n hook = shadowMode\n ? function () {\n injectStyles.call(\n this,\n (options.functional ? this.parent : this).$root.$options.shadowRoot\n )\n }\n : injectStyles\n }\n\n if (hook) {\n if (options.functional) {\n // for template-only hot-reload because in that case the render fn doesn't\n // go through the normalizer\n options._injectStyles = hook\n // register for functional component in vue file\n var originalRender = options.render\n options.render = function renderWithStyleInjection(h, context) {\n hook.call(context)\n return originalRender(h, context)\n }\n } else {\n // inject component registration as beforeCreate hook\n var existing = options.beforeCreate\n options.beforeCreate = existing ? [].concat(existing, hook) : [hook]\n }\n }\n\n return {\n exports: scriptExports,\n options: options\n }\n}\n","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=cdec1cec&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=js\"\nexport * from \"./index.vue?vue&type=script&lang=js\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=cdec1cec&prod&lang=scss&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"cdec1cec\",\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"upload_table\"},[_c('div',{staticClass:\"header\"},[_c('div',{staticClass:\"total\"},[_c('span',[_vm._v(\"已选择\"+_vm._s(_vm.needUploadFilesArr.length)+\"个文件\")]),(_vm.needUploadFilesArr.length)?_c('el-tag',{attrs:{\"type\":\"\",\"size\":\"mini\"}},[_vm._v(\"上传中\"+_vm._s(_vm.totalNumber))]):_vm._e()],1),_c('div',{staticClass:\"options\"},[_c('el-button',{attrs:{\"type\":\"danger\",\"size\":\"mini\",\"disabled\":_vm.isUploading || _vm.needUploadFilesArr.length === 0},on:{\"click\":function($event){return _vm.handleClickOnlyFile()}}},[_vm._v(\"清除已选\")])],1)]),_c('el-table',{staticStyle:{\"width\":\"100%\"},attrs:{\"data\":_vm.needUploadFilesArr,\"default-sort\":{ prop: 'fileName', order: 'descending' },\"border\":\"\",\"height\":\"400px\"},on:{\"sort-change\":_vm.handleSortChange,\"selection-change\":_vm.handleSelectionChange}},[_c('el-table-column',{attrs:{\"type\":\"selection\",\"width\":\"40\"}}),_c('el-table-column',{attrs:{\"type\":\"index\",\"width\":\"40\"}}),_c('el-table-column',{attrs:{\"label\":\"文件名\",\"width\":\"300\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [_c('div',{staticClass:\"file_name\"},[_c('div',{staticClass:\"file_type\"},[_vm._v(\" \"+_vm._s(_vm.getFileType(scope.row.name))+\" \")]),_c('span',{staticClass:\"file_name_text\"},[_vm._v(_vm._s(scope.row.name))])])]}}])}),_c('el-table-column',{attrs:{\"label\":\"大小\",\"width\":\"100\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [_c('div',{staticClass:\"file_size\"},[_c('span',{staticClass:\"file_size_text\"},[_vm._v(_vm._s(_vm.fileFormatValid(scope.row.file.size))+\" mb\")])])]}}])}),_c('el-table-column',{attrs:{\"label\":\"状态\",\"width\":\"100\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [_c('div',{staticClass:\"status_text\"},[_c('span',{class:_vm.uploadingTextStyle(scope.row.tip)},[_vm._v(_vm._s(scope.row.tip))])])]}}])}),_c('el-table-column',{attrs:{\"label\":\"进度\",\"width\":\"auto\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [_c('div',{staticClass:\"progress_area\"},[_c('el-progress',{staticClass:\"custom-progress\",attrs:{\"color\":_vm.colors,\"show-text\":true,\"percentage\":scope.row.uploadProgress}})],1)]}}])}),_c('el-table-column',{attrs:{\"label\":\"操作\",\"width\":\"auto\"},scopedSlots:_vm._u([{key:\"default\",fn:function(scope){return [(scope.row.tip === '上传中')?_c('div',{staticClass:\"option_text\",on:{\"click\":function($event){$event.stopPropagation();return _vm.cancelFileUpload(scope.row)}}},[_c('span',{staticStyle:{\"color\":\"#f74444\",\"cursor\":\"pointer\"}},[_vm._v(\"取消上传\")])]):_vm._e(),(\n scope.row.tip === '已取消' ||\n scope.row.tip === '上传出错' ||\n scope.row.tip === '未知出错'\n )?_c('div',{staticClass:\"option_text\",on:{\"click\":function($event){$event.stopPropagation();return _vm.resetFileUpload(scope.row)}}},[_c('span',{staticStyle:{\"color\":\"#f74444\",\"cursor\":\"pointer\"}},[_vm._v(\"重试\")])]):_vm._e()]}}])})],1)],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","<template>\r\n <div class=\"upload_table\">\r\n <div class=\"header\">\r\n <div class=\"total\">\r\n <span>已选择{{ needUploadFilesArr.length }}个文件</span>\r\n <el-tag v-if=\"needUploadFilesArr.length\" type=\"\" size=\"mini\"\r\n >上传中{{ totalNumber }}</el-tag\r\n >\r\n </div>\r\n <div class=\"options\">\r\n <el-button\r\n type=\"danger\"\r\n size=\"mini\"\r\n @click=\"handleClickOnlyFile()\"\r\n :disabled=\"isUploading || needUploadFilesArr.length === 0\"\r\n >清除已选</el-button\r\n >\r\n </div>\r\n </div>\r\n <el-table\r\n :data=\"needUploadFilesArr\"\r\n style=\"width: 100%\"\r\n :default-sort=\"{ prop: 'fileName', order: 'descending' }\"\r\n border\r\n height=\"400px\"\r\n @sort-change=\"handleSortChange\"\r\n @selection-change=\"handleSelectionChange\"\r\n >\r\n <el-table-column type=\"selection\" width=\"40\"> </el-table-column>\r\n <el-table-column type=\"index\" width=\"40\"> </el-table-column>\r\n <el-table-column label=\"文件名\" width=\"300\">\r\n <template slot-scope=\"scope\">\r\n <div class=\"file_name\">\r\n <div class=\"file_type\">\r\n {{ getFileType(scope.row.name) }}\r\n </div>\r\n <span class=\"file_name_text\">{{ scope.row.name }}</span>\r\n </div>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"大小\" width=\"100\">\r\n <template slot-scope=\"scope\">\r\n <div class=\"file_size\">\r\n <span class=\"file_size_text\"\r\n >{{ fileFormatValid(scope.row.file.size) }} mb</span\r\n >\r\n </div>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"状态\" width=\"100\">\r\n <template slot-scope=\"scope\">\r\n <div class=\"status_text\">\r\n <span :class=\"uploadingTextStyle(scope.row.tip)\">{{\r\n scope.row.tip\r\n }}</span>\r\n </div>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"进度\" width=\"auto\">\r\n <template slot-scope=\"scope\">\r\n <div class=\"progress_area\">\r\n <el-progress\r\n :color=\"colors\"\r\n :show-text=\"true\"\r\n :percentage=\"scope.row.uploadProgress\"\r\n class=\"custom-progress\"\r\n />\r\n </div>\r\n </template>\r\n </el-table-column>\r\n <el-table-column label=\"操作\" width=\"auto\">\r\n <template slot-scope=\"scope\">\r\n <div\r\n v-if=\"scope.row.tip === '上传中'\"\r\n class=\"option_text\"\r\n @click.stop=\"cancelFileUpload(scope.row)\"\r\n >\r\n <!-- 只有上传中,在排队的任务可以进行取消 -->\r\n <span style=\"color: #f74444; cursor: pointer\">取消上传</span>\r\n </div>\r\n <div\r\n v-if=\"\r\n scope.row.tip === '已取消' ||\r\n scope.row.tip === '上传出错' ||\r\n scope.row.tip === '未知出错'\r\n \"\r\n class=\"option_text\"\r\n @click.stop=\"resetFileUpload(scope.row)\"\r\n >\r\n <span style=\"color: #f74444; cursor: pointer\">重试</span>\r\n </div>\r\n </template>\r\n </el-table-column>\r\n </el-table>\r\n </div>\r\n</template>\r\n<script>\r\nexport default {\r\n name: \"Upload_Table\",\r\n props: {\r\n needUploadFilesArr: {\r\n type: Array,\r\n default: () => [],\r\n },\r\n fileConfig: {\r\n type: Object,\r\n default: () => {},\r\n },\r\n fileType: {\r\n type: String,\r\n default: \"\",\r\n },\r\n isUploading: {\r\n type: Boolean,\r\n },\r\n },\r\n data() {\r\n return {\r\n colors: [\r\n { color: \"#bae6fd\", percentage: 20 }, // 浅天蓝:刚刚启动,轻快感\r\n { color: \"#7dd3fc\", percentage: 40 }, // 天蓝:平稳进行\r\n { color: \"#38bdf8\", percentage: 60 }, // 亮蓝:进入核心处理\r\n { color: \"#2563eb\", percentage: 80 }, // 宝蓝:即将完成的厚重感\r\n { color: \"#6366f1\", percentage: 100 }, // 靛紫:完成时的精致感\r\n ],\r\n };\r\n },\r\n computed: {\r\n totalNumber() {\r\n return (\r\n this.fileConfig.completed_num + \"/\" + this.needUploadFilesArr.length\r\n );\r\n },\r\n },\r\n methods: {\r\n handleSortChange(val) {\r\n this.$emit(\"sortChange\", val);\r\n },\r\n uploadingTextStyle(text) {\r\n // 第一个未知,第二个stauts超时,第三个上传块超时\r\n if (\r\n text === \"出错\" ||\r\n text === \"查询文件地址超时\" ||\r\n text === \"上传出错\"\r\n ) {\r\n return \"uploading_error\";\r\n } else if (text === \"已完成\") {\r\n return \"uploading_success\";\r\n } else if (text === \"等待上传\") {\r\n return \"uploading_wait\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n resetFileUpload(item) {\r\n this.$emit(\"resetFileUpload\", item);\r\n },\r\n cancelFileUpload(item) {\r\n this.$emit(\"cancelFileUpload\", item);\r\n },\r\n handleClickOnlyFile() {\r\n this.$emit(\"delteSelectedFile\");\r\n },\r\n // 数字验证\r\n fileFormatValid(val) {\r\n const number = (val / (1024 * 1024)).toFixed(2);\r\n\r\n return number;\r\n },\r\n getFileType(name) {\r\n return name.split(\".\")[1];\r\n },\r\n handleSelectionChange(selection) {\r\n const selecId = selection.map(item => item.index);\r\n\r\n this.$emit(\"handleSelectionChange\", selecId);\r\n },\r\n },\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.upload_table {\r\n height: 100%;\r\n width: 100%;\r\n\r\n ::v-deep {\r\n .el-table__cell {\r\n padding: 6px 0;\r\n }\r\n }\r\n\r\n .header {\r\n height: 3rem;\r\n padding: 0.5rem;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n border: 1px solid #dfe6ec;\r\n border-bottom: 0px;\r\n\r\n .total {\r\n display: flex;\r\n align-items: center;\r\n gap: 0.25rem;\r\n }\r\n }\r\n\r\n .file_name {\r\n display: flex;\r\n gap: 0.25rem;\r\n\r\n overflow: hidden;\r\n min-height: 0.5rem;\r\n font-size: 0.9rem;\r\n font-weight: 400;\r\n color: #1f283a;\r\n\r\n .file_type {\r\n width: 1.5rem;\r\n height: 1.5rem;\r\n // padding: 0.2rem;\r\n text-align: center;\r\n line-height: 1.5rem;\r\n background-color: #e2e8ef;\r\n font-weight: 600;\r\n border-radius: 5px;\r\n text-transform: uppercase;\r\n font-size: 10px;\r\n color: #1392e8;\r\n white-space: nowrap;\r\n }\r\n }\r\n\r\n .option_text {\r\n color: red;\r\n }\r\n .option_text:hover {\r\n text-decoration: underline;\r\n cursor: pointer;\r\n }\r\n .status_text {\r\n .uploading_error {\r\n color: red;\r\n font-weight: 500;\r\n }\r\n\r\n .uploading_wait {\r\n color: #909399;\r\n }\r\n\r\n .uploading_success {\r\n color: #67c23a;\r\n font-weight: 500;\r\n }\r\n }\r\n\r\n .progress_area {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n width: 100%;\r\n\r\n .el-progress {\r\n width: 100%;\r\n // height: 1.5rem;\r\n // min-height: 0.5rem;\r\n // padding-top: 0.2rem;\r\n\r\n ::v-deep .el-progress-bar__outer {\r\n background-color: #b3c3e8;\r\n }\r\n\r\n ::v-deep .el-progress-bar__inner {\r\n transition: width 0.4s ease;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","import mod from \"-!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=61052c10&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=js\"\nexport * from \"./index.vue?vue&type=script&lang=js\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=61052c10&prod&lang=scss&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"61052c10\",\n null\n \n)\n\nexport default component.exports","import SparkMD5 from \"spark-md5\";\r\nimport { mapApiToRequest } from \"./api\";\r\n\r\n// 超时控制\r\nconst timer = {\r\n entranceTime: 120000,\r\n uploadChunkTime: 1000 * 60 * 10,\r\n dropStateOverTime: 1000 * 60 * 10,\r\n dropStatePollTime: 2000,\r\n};\r\n// 文件分块大小\r\nconst chunkSegmentationSize = 1024 * 1024 * 5;\r\n\r\n// 文件上传接口\r\nlet api = {};\r\n// 默认配置内容管理api\r\nconst contentManagement = {\r\n checkfileStatusUrl: \"/zt-api/resources/check\",\r\n filesAllUoloadedUrl: \"/zt-api/resources/chunk/merge\",\r\n searchFileIsUploadedUrl: \"/zt-api/resources/check\",\r\n searchChunkIsUploadedUrl: \"/zt-api/resources/check/chunk\",\r\n uploadFileChunkUrl: \"/zt-api/resources/chunk/upload\",\r\n addNewFileOfTxtUrl: \"/api/v1/program/create-doc\",\r\n addNewFileOfVideoUrl: \"/api/v1/program/create-video\",\r\n addNewFileOfAudioUrl: \"/api/v1/program/create-audio\",\r\n addNewFileOfPicUrl: \"/api/v1/program/create-pic\",\r\n addNewFileOfSubTitleUrl: \"/api/v1/program/create-srt\",\r\n};\r\n\r\n/**\r\n * 上传入口:此文件用于处理文件上传的核心逻辑。处去文件自身声明变量,必须得有uploadFilesConfig_AndStart的所有参数。以及各个接口调用函数\r\n * @param {Array} fileList 文件列表\r\n * @param {number} maxConcurrent 文件块最大并发数\r\n * @param {number} maxFileConcurrent 文件最大并发数\r\n * @param {Object} addDataBaseLinkConfig 文件上传成功之后或者检索文件已存在时是否创建数据库链接的配置项\r\n * @param {Function} createFileQueues 创建文件队列的回调函数\r\n * @param {Function} createUploadQueues 创建上传任务的回调函数\r\n * @param {Function} total_progress_function 全局进度更新函数\r\n * @param {Function} setTotalStatus 全局进度条状态\r\n * @param {Object} apiObj 外界传来的上传api\r\n * @returns {Array} [{\r\n status: true,\r\n uploadId: number,\r\n uuid: check_result.fileCheck,\r\n fileName: fileName,\r\n }, ...] 每个文件的上传结果组成的数组\r\n */\r\nexport default async function uploadFilesConfig_AndStart(\r\n fileList,\r\n maxConcurrent,\r\n maxFileConcurrent,\r\n addDataBaseLinkConfig,\r\n createFileQueues,\r\n createUploadQueues,\r\n total_progress_function,\r\n setTotalStatus,\r\n apiObj = contentManagement,\r\n) {\r\n // 1.准备上传接口\r\n api = mapApiToRequest(apiObj);\r\n\r\n const uploadPromises = [];\r\n\r\n for (let i = 0; i < fileList.length; i++) {\r\n const item = fileList[i];\r\n const uploadId = generateUploadId(item.file);\r\n\r\n // 创建并发控制器\r\n const controller = createConcurrentController(\r\n maxConcurrent,\r\n item.updateProgress,\r\n );\r\n\r\n // 通过uploadId查看每一个文件的uploadId\r\n createFileQueues(item.index, controller);\r\n\r\n // controller保证每一个文件有单独的并发控制\r\n const taskFn = () => {\r\n const task = uploadSingleFile(\r\n item.file,\r\n uploadId,\r\n controller,\r\n item.updateProgress,\r\n item.progress_error,\r\n addDataBaseLinkConfig,\r\n );\r\n // 通过uploadId可知文件是否已经上传完成\r\n createUploadQueues(uploadId, task);\r\n return task;\r\n };\r\n\r\n uploadPromises.push({ index: item.index, taskFn });\r\n }\r\n\r\n const controller = createConcurrentController(\r\n maxFileConcurrent,\r\n total_progress_function,\r\n );\r\n\r\n setTotalStatus(controller, \"上传中\");\r\n\r\n // 文件可以允许上传失败\r\n return controller.runTasks(uploadPromises);\r\n}\r\n\r\n// 分块并发控制器,后续集成文件并发控制器\r\nfunction createConcurrentController(maxConcurrent, onProgress) {\r\n let queue = []; // 等待队列\r\n let cancleTasks = []; // 被取消暂存的数组\r\n let errorTasks = []; // 出错暂存的数组,用于重新上传\r\n let activeCount = 0; // 当前正在执行的任务数\r\n let isPaused = false; // 是否暂停\r\n let pauseResolve = null; // 暂停时的resolve函数\r\n\r\n let skipError = 0; // 跳过错误的任务个数\r\n let completedCount = 0; // 已完成的任务数\r\n let totalTasks = 0; // 总任务数\r\n\r\n // 进度计算函数,此处故意设计为最多99左右,后面给创建文件路径,合并块,落盘等等\r\n const calculateProgress = () => {\r\n if (totalTasks === 0) return 0;\r\n return Math.round((completedCount / totalTasks) * 100);\r\n };\r\n\r\n // 进度更新函数\r\n const updateProgress = preventUpdate => {\r\n if (onProgress && typeof onProgress === \"function\") {\r\n const progress = calculateProgress();\r\n\r\n // 如果存在错误任务或控制器被暂停,不要被后续成功任务覆盖状态,保持错误提示\r\n if (\r\n preventUpdate &&\r\n ((Array.isArray(errorTasks) && errorTasks.length > 0) || isPaused)\r\n ) {\r\n console.log(\"重要:进度条强制不更新\", errorTasks.length);\r\n } else {\r\n // console.log(\r\n // \"2.进度条为成功状态(异步工具内部更新),错误个数\",\r\n // errorTasks.length,\r\n // );\r\n\r\n onProgress({\r\n percentage: progress,\r\n notShowTip: true,\r\n tip: progress === 100 ? \"上传完成\" : \"上传中\",\r\n completed: completedCount,\r\n total: totalTasks,\r\n active: activeCount,\r\n queued: queue.length,\r\n skipError,\r\n });\r\n }\r\n }\r\n };\r\n // 进度更新出错\r\n const updateProgress_error = () => {\r\n if (onProgress && typeof onProgress === \"function\") {\r\n const progress = calculateProgress();\r\n console.log(\"异步工具内部更新进度条为错误状态\");\r\n onProgress({\r\n percentage: progress,\r\n notShowTip: false,\r\n tip: \"上传出错\",\r\n completed: completedCount,\r\n total: totalTasks,\r\n active: activeCount,\r\n queued: queue.length,\r\n skipError,\r\n });\r\n }\r\n };\r\n\r\n return {\r\n async errorActiveIsFull(index) {\r\n const queueArr = errorTasks.filter(it => it.id === index);\r\n if (queueArr.length > 0) {\r\n cancleTasks = errorTasks.filter(it => it.id !== index);\r\n\r\n const item = queueArr[0];\r\n const result = await this.add(true, {\r\n taskFn: item.task,\r\n index: item.id,\r\n });\r\n console.log(\"重新尝试的结果\", result, queue);\r\n }\r\n },\r\n\r\n // 只适配文件上传出错,块上传直接暂停,不使用此函数\r\n async startResetErrorTask(index) {\r\n // 重尝试失败的任务\r\n const queueArr = errorTasks.filter(item => item.id === index);\r\n\r\n if (queueArr.length > 0) {\r\n errorTasks = errorTasks.filter(it => it.id !== index); // 无论重试成功失败都需要清理原来的数据\r\n\r\n const item = queueArr[0];\r\n // 通过 add 创建新的入队条目(会创建新的 resolve/reject)\r\n const result = await this.add(true, {\r\n taskFn: item.task,\r\n index: item.id,\r\n });\r\n\r\n console.log(\"重新尝试的结果\", result, queue);\r\n }\r\n },\r\n\r\n errorFilehandled(index) {\r\n errorTasks = [...errorTasks, ...queue.filter(item => item.id === index)];\r\n\r\n queue = queue.filter(item => item.id !== index);\r\n },\r\n\r\n startResetCanceledyTask(index) {\r\n // 重置单个任务\r\n const queueArr = cancleTasks.filter(item => item.id === index);\r\n if (queueArr.length > 0) {\r\n queue.push(queueArr[0]);\r\n cancleTasks = cancleTasks.filter(item => item.id !== index);\r\n }\r\n run();\r\n },\r\n\r\n cancelFileUpload(index) {\r\n const _arr = queue.filter(item => item.id === index);\r\n\r\n if (_arr.length > 0) {\r\n cancleTasks = [...cancleTasks, ..._arr];\r\n queue = queue.filter(item => item.id !== index);\r\n\r\n return true;\r\n } else {\r\n // 说明此文件已被队列消耗\r\n return false;\r\n }\r\n },\r\n // 添加单个任务\r\n add(isErrorReset, item) {\r\n return new Promise((resolve, reject) => {\r\n queue.push({ task: item.taskFn, id: item.index, resolve, reject });\r\n run(isErrorReset);\r\n });\r\n },\r\n\r\n // 批量添加任务\r\n runTasks(taskOption) {\r\n return new Promise((resolve, reject) => {\r\n const allResults = [];\r\n let hasError = false;\r\n totalTasks = taskOption.length;\r\n\r\n // 全部任务添加到队列,没添加一次就会进行试运行\r\n taskOption.forEach((item, index) => {\r\n this.add(false, item)\r\n .then(result => {\r\n allResults[index] = result;\r\n // 有结果出错是否停止所有任务,暂时采取停止所有任务\r\n if (\r\n (completedCount + cancleTasks.length === taskOption.length &&\r\n !hasError) ||\r\n (result.status === false && !result.skip)\r\n ) {\r\n resolve(allResults); // 当队列结束或者块队列出现文件错误(且结果为不跳过任务时)则立马返回数据!\r\n }\r\n })\r\n .catch(error => {\r\n hasError = true;\r\n reject(error);\r\n });\r\n });\r\n });\r\n },\r\n\r\n // 暂停所有任务\r\n pause() {\r\n isPaused = true;\r\n },\r\n\r\n // 恢复执行\r\n resume() {\r\n isPaused = false;\r\n },\r\n\r\n // 清空队列\r\n clear() {\r\n queue = [];\r\n errorTasks = [];\r\n completedCount = 0;\r\n totalTasks = 0;\r\n },\r\n\r\n // 获取状态\r\n getStatus() {\r\n return {\r\n queue: queue,\r\n completed: completedCount,\r\n activeCount,\r\n isPaused,\r\n totalTasks,\r\n skipError,\r\n };\r\n },\r\n\r\n // 获取当前进度\r\n getProgress() {\r\n return {\r\n percentage: calculateProgress(),\r\n completed: completedCount,\r\n total: totalTasks,\r\n active: activeCount,\r\n queued: queue.length,\r\n };\r\n },\r\n };\r\n\r\n // 内部执行函数\r\n async function run(isErrorReset = false) {\r\n // 如果暂停了,就等待\r\n if (isPaused) {\r\n if (!pauseResolve) {\r\n await new Promise(resolve => {\r\n pauseResolve = resolve;\r\n });\r\n }\r\n }\r\n\r\n // 执行队列中的任务\r\n while (queue.length > 0 && activeCount < maxConcurrent && !isPaused) {\r\n // 老代码\r\n const { task, id, resolve, reject } = queue.shift();\r\n\r\n activeCount++;\r\n\r\n // {result: boolean, error: string} msg???\r\n // 需要处理块任务和文件任务的结果\r\n task()\r\n .then(result => {\r\n // console.log(\r\n // \"1.任务执行完成的返回结果(异步工具函数队列中一个)\",\r\n // result,\r\n // isErrorReset,\r\n // );\r\n if (result.status) {\r\n if (isErrorReset) {\r\n completedCount++;\r\n skipError--;\r\n updateProgress(false);\r\n } else {\r\n completedCount++;\r\n updateProgress(true);\r\n }\r\n } else {\r\n if (!isErrorReset) {\r\n skipError++; // 不能随便加加,有的时重试的\r\n }\r\n\r\n errorTasks.push({ task, id, resolve, reject }); // resolve和reject无用,已经被使用\r\n\r\n updateProgress_error();\r\n // 块上传并不返回skip,只能停止所有任务\r\n\r\n if (result.skip) {\r\n console.error(\"已经出错的统计的错误任务数组\", errorTasks);\r\n\r\n console.error(\r\n \"===============跳过错误的文件上传================,错误的原因:\",\r\n result.error,\r\n result,\r\n );\r\n } else {\r\n isPaused = true; // 块并发任务停止后续任务,文件应该由结果决定\r\n }\r\n }\r\n\r\n resolve(result);\r\n })\r\n .catch(error => {\r\n console.log(\"上传时候失败\", error);\r\n if (!isErrorReset) {\r\n skipError++; // 不能随便加加,有的时重试的\r\n }\r\n errorTasks.push({ task, id, resolve, reject }); // resolve和reject无用,已经被使用\r\n\r\n updateProgress_error();\r\n reject(error);\r\n })\r\n .finally(() => {\r\n activeCount--;\r\n run(isErrorReset); // 尝试执行下一个任务\r\n });\r\n }\r\n }\r\n}\r\n\r\n// 生成唯一上传编号\r\nfunction generateUploadId(file) {\r\n // 使用文件名+文件大小+时间戳+随机数生成唯一ID\r\n const timestamp = Date.now();\r\n const random = Math.random().toString(36).substr(2, 9);\r\n const fileId = `${file.name}_${file.size}_${timestamp}_${random}`;\r\n\r\n // 清理文件名中的特殊字符\r\n return fileId.replace(/[^a-zA-Z0-9_-]/g, \"_\");\r\n}\r\n\r\n// 文件存无处理\r\nasync function handleFileExistOrNo(fileConfig, addDataBaseLinkConfig) {\r\n const { uploadId, fileHash, fileSize, fileName } = fileConfig;\r\n const {\r\n addProgramVersion: programVersion,\r\n addFileType: fileType,\r\n addDataBaseLink: createLink,\r\n } = addDataBaseLinkConfig;\r\n\r\n // 此处用于网络超时对UI界面的影响,此处是函数入口最适合判断的地方\r\n const timerPromise = new Promise(resolve => {\r\n const timer_upload_file = setTimeout(() => {\r\n resolve({\r\n status: false,\r\n error: \"文件检查超时\",\r\n uploadId,\r\n skip: true,\r\n });\r\n clearTimeout(timer_upload_file);\r\n }, timer.entranceTime);\r\n });\r\n\r\n const fileCheckPromise = (async () => {\r\n try {\r\n const fileCheck = await searchFileIsUploaded(fileHash, fileSize);\r\n return { status: true, fileCheck };\r\n } catch (error) {\r\n return { status: false, error, uploadId };\r\n }\r\n })();\r\n\r\n const check_result = await Promise.race([fileCheckPromise, timerPromise]);\r\n if (!check_result.status) {\r\n // 如若第一波就网络错误,此处需要通知其文件的子进度条出错并且进行统计\r\n // progress_error();\r\n\r\n console.debug(\r\n \"=============网络超时或者网络错误================,以下为check_result的错误结果\",\r\n );\r\n console.debug(check_result);\r\n console.debug(\"=============网络超时或者网络错误================\");\r\n // 网络超时不应该跳过错误文件,而是停止所有任务,暂不处理\r\n // 此处的错误返回只能控制总进度条的值。文件进度条是由块上传控制的\r\n return {\r\n fileIsExist: false,\r\n status: false,\r\n error: \"网络超时或者网络错误\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n\r\n if (check_result.fileCheck) {\r\n if (!createLink) {\r\n return {\r\n fileIsExist: true,\r\n status: true,\r\n uploadId,\r\n uuid: check_result.fileCheck,\r\n fileName: fileName,\r\n };\r\n }\r\n\r\n // 文件存在。直接走新建流程,此处也可能会出错,后续处理\r\n const add_result = await addNewFileId(\r\n check_result.fileCheck,\r\n programVersion,\r\n fileType,\r\n );\r\n\r\n if (add_result.status) {\r\n // 步骤2:文件存在,直接新增文件链接\r\n console.log(\"文件已经存在,直接创建新链接\");\r\n\r\n return {\r\n fileIsExist: true,\r\n status: true,\r\n uploadId,\r\n uuid: check_result.fileCheck,\r\n fileName: fileName,\r\n };\r\n } else {\r\n return {\r\n fileIsExist: true,\r\n status: false,\r\n error: \"文件路径创建失败\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n } else {\r\n return {\r\n fileIsExist: false,\r\n status: true,\r\n uploadId,\r\n uuid: check_result.fileCheck,\r\n fileName: fileName,\r\n };\r\n }\r\n}\r\n\r\n// 核心:上传单个文件。 返回值设置skip可实现是否进行跳过错误的文件上传\r\nasync function uploadSingleFile(\r\n file,\r\n uploadId,\r\n controller,\r\n updateProgress,\r\n progress_error,\r\n addDataBaseLinkConfig,\r\n) {\r\n const {\r\n addProgramVersion: programVersion,\r\n addFileType: fileType,\r\n addDataBaseLink: createLink,\r\n } = addDataBaseLinkConfig;\r\n\r\n const fileHash = await getFileMd5Safe(file);\r\n const fileSize = file.size;\r\n const fileName = file.name;\r\n\r\n const setStep = (percentage, notShowTip, tip) => {\r\n updateProgress({\r\n percentage: percentage,\r\n notShowTip: notShowTip,\r\n tip: tip,\r\n });\r\n };\r\n\r\n try {\r\n setStep(0, false, \"解析中\");\r\n\r\n console.log(\r\n \"%c 文件上传中:\",\r\n \"color: #2196F3; font-weight: bold;\",\r\n fileName,\r\n );\r\n\r\n // 步骤1:检查文件是否存在\r\n const fileStorageResult = await handleFileExistOrNo(\r\n { uploadId, fileHash, fileSize, fileName },\r\n addDataBaseLinkConfig,\r\n );\r\n\r\n console.log(\"是否分块上传?\", !fileStorageResult.fileIsExist);\r\n\r\n // 文件存在或者内部错误时返回\r\n if (fileStorageResult.fileIsExist || fileStorageResult.error) {\r\n if (fileStorageResult.status) {\r\n setStep(100, false, \"已完成\");\r\n return fileStorageResult;\r\n } else {\r\n progress_error();\r\n return fileStorageResult;\r\n }\r\n }\r\n\r\n setStep(0, false, \"准备中\");\r\n\r\n // 步骤2:上传所有切片\r\n // 准备切片\r\n const chunks = await createChunks(file, [], chunkSegmentationSize);\r\n console.groupCollapsed(\r\n \"%c 分片上传流程\",\r\n \"color: #2196F3; font-weight: bold;\",\r\n );\r\n console.log(\"切片列表\", chunks);\r\n\r\n // 上传切片\r\n // 1:此处错误处理一部分在并发控制器里面进行(控制自己本身),逻辑:直接改变文件的进度条,进行错误状态,数字文字等回显\r\n // 2:此处错误处理(用于文件并发控制检查所有切片是否已经完成),目前两片逻辑不可合并\r\n const chunk_AllUploded_error_esult = await uploadChunks(\r\n chunks,\r\n fileHash,\r\n file.name,\r\n uploadId,\r\n controller,\r\n );\r\n\r\n // 检查切片上传结果\r\n if (chunk_AllUploded_error_esult.length > 0) {\r\n console.debug(\r\n \"=============文件分片上传失败================,以下为分片的错误列表:\",\r\n chunk_AllUploded_error_esult,\r\n );\r\n\r\n return {\r\n status: false,\r\n error: \"文件块上传失败\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n\r\n setStep(99, true, \"上传中\");\r\n\r\n // 步骤3:请求后端合并切片\r\n const uploadedFileIsMerge = await informServeUploaded(fileHash, fileSize);\r\n console.log(\"合并切片,结果:\", uploadedFileIsMerge);\r\n\r\n if (!uploadedFileIsMerge) {\r\n setStep(0, false, \"文件合并失败\");\r\n\r\n return {\r\n status: false,\r\n // skip: false,\r\n error: \"文件合并失败\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n\r\n console.groupEnd();\r\n\r\n // 步骤4:轮询检查文件落盘状态\r\n const resultFile = await startCheckfileStatus(\r\n fileHash,\r\n timer.dropStatePollTime,\r\n timer.dropStateOverTime,\r\n );\r\n\r\n if (!resultFile.result) {\r\n // 落盘失败\r\n setStep(0, false, resultFile.Message);\r\n\r\n return {\r\n status: false,\r\n error: resultFile.Message,\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n\r\n // 步骤5:是否自动创建数据库路径\r\n if (!createLink) {\r\n setStep(100, false, \"已完成\");\r\n\r\n return {\r\n status: true,\r\n uploadId,\r\n uuid: resultFile.fileId,\r\n fileName: fileName,\r\n };\r\n }\r\n\r\n // 步骤6:请求数据库创建新的文件路径\r\n const add_result = await addNewFileId(\r\n resultFile.fileId,\r\n programVersion,\r\n fileType,\r\n );\r\n\r\n if (add_result.status) {\r\n // 创建成功\r\n setStep(100, false, \"已完成\");\r\n return {\r\n status: true,\r\n uploadId,\r\n uuid: resultFile.fileId,\r\n fileName: fileName,\r\n };\r\n } else {\r\n // 创建失败\r\n setStep(0, false, \"内部错误\");\r\n\r\n return {\r\n status: false,\r\n error: \"内部错误\",\r\n uploadId,\r\n skip: true,\r\n };\r\n }\r\n } catch (error) {\r\n // 总错误处理\r\n console.debug(\r\n \"=============单个文件上传出错(意料之外的出错)================,未知出错:\",\r\n error,\r\n );\r\n setStep(0, false, \"未知出错\");\r\n return { status: false, error, uploadId, skip: true };\r\n }\r\n}\r\n\r\n// 获取文件的md5\r\nasync function getFileMd5Safe(file_blob) {\r\n const spark = new SparkMD5.ArrayBuffer();\r\n const chunkSize = 5 * 1024 * 1024;\r\n const chunks = Math.ceil(file_blob.size / chunkSize);\r\n\r\n for (let i = 0; i < chunks; i++) {\r\n const start = i * chunkSize;\r\n const end = Math.min(start + chunkSize, file_blob.size);\r\n const chunk = file_blob.slice(start, end);\r\n // 使用arrayBuffer()替代FileReader(更简洁,自动管理内存)\r\n const arrayBuffer = await chunk.arrayBuffer();\r\n spark.append(arrayBuffer);\r\n if (i % 100 === 0) {\r\n await new Promise(resolve => setTimeout(resolve, 0));\r\n }\r\n }\r\n\r\n return spark.end();\r\n}\r\n\r\n// 生成分块数组\r\nasync function createChunks(\r\n file,\r\n uploadedChunks = [],\r\n chunkSize = 5 * 1024 * 1024,\r\n) {\r\n const chunks = [];\r\n let cur = 0; // 当前读取位置\r\n let index = 0; // 分片索引\r\n\r\n // 循环创建分片,直到文件读取完\r\n while (cur < file.size) {\r\n const chunk = file.slice(cur, cur + chunkSize);\r\n const chunkMd5 = await getChunkMD5(chunk);\r\n\r\n // 如果这个分片还没有上传过\r\n if (!uploadedChunks.includes(index)) {\r\n chunks.push({\r\n chunk: chunk, // 实际的分片数据\r\n index: index, // 分片索引\r\n start: cur, // 分片在文件中的起始位置\r\n end: Math.min(cur + chunkSize, file.size), // 分片结束位置\r\n hash: chunkMd5, // 分片哈希(可后续计算)\r\n size: Math.min(chunkSize, file.size - cur), // 分片实际大小\r\n });\r\n }\r\n\r\n cur += chunkSize; // 移动到下一个分片的起始位置\r\n index++; // 分片索引增加\r\n }\r\n return chunks;\r\n}\r\n\r\n// 获取文件块的md5\r\nfunction getChunkMD5(chunkBlob) {\r\n return new Promise(resolve => {\r\n const reader = new FileReader();\r\n const spark = new SparkMD5.ArrayBuffer();\r\n\r\n reader.onload = function (e) {\r\n spark.append(e.target.result);\r\n resolve(spark.end());\r\n };\r\n\r\n reader.readAsArrayBuffer(chunkBlob);\r\n });\r\n}\r\n\r\n// 上传切片(文件块)文件块增加上传块失败是否停止的配置项。\r\nasync function uploadChunks(chunks, fileHash, fileName, uploadId, controller) {\r\n const total = chunks.length;\r\n\r\n const uploadPromises = chunks.map((chunk, index) => {\r\n const fn = async () => {\r\n const requstData = {\r\n filename: fileName,\r\n index: chunk.index,\r\n total: total,\r\n identifier: fileHash,\r\n chunkIdentifier: chunk.hash,\r\n file: chunk.chunk,\r\n };\r\n\r\n // 测试块上传失败的代码\r\n // return {\r\n // status: false,\r\n // msg: \"文件块上传失败\",\r\n // };\r\n\r\n try {\r\n const chunkIsExist = await searchChunkIsUploaded(fileHash, chunk.hash);\r\n if (chunkIsExist) {\r\n return {\r\n status: true,\r\n msg: \"文件块已经存在了\",\r\n };\r\n }\r\n } catch (error) {\r\n return {\r\n status: false,\r\n msg: error,\r\n };\r\n }\r\n\r\n const timerPromise = new Promise(resolve => {\r\n const timer_upload_chunk = setTimeout(() => {\r\n // 重复,进度条status回显+1,最大90\r\n // updateProgress({\r\n // percentage: 0,\r\n // notShowTip: false,\r\n // tip: \"文件错误\",\r\n // });\r\n resolve({\r\n status: false,\r\n msg: \"文件错误\",\r\n });\r\n clearTimeout(timer_upload_chunk);\r\n }, timer.uploadChunkTime);\r\n });\r\n\r\n const uplodChunkPromise = (async () => {\r\n try {\r\n const result = await api.uploadFileChunk(requstData);\r\n\r\n if (result.code === \"Success\") {\r\n return {\r\n status: true,\r\n msg: \"文件块上传成功\",\r\n };\r\n } else {\r\n return {\r\n status: false,\r\n msg: \"文件块上传失败\",\r\n };\r\n }\r\n } catch (error) {\r\n return {\r\n status: false,\r\n msg: \"文件块上传失败\",\r\n };\r\n // throw new Error(`上传过程异常: ${error.message || error}`);\r\n }\r\n })();\r\n\r\n // const uplodChunkPromise = new Promise(async(resolve, reject) => {\r\n // try {\r\n // const result = await _this.$store.dispatch(\r\n // \"app/uploadFileChunk\",\r\n // requstData,\r\n // );\r\n\r\n // // const test_boolean = Math.random() > 0.9 ? false : true;\r\n\r\n // if (result.code === \"Success\") {\r\n // // console.log(\"文件块内部上传成功\", test_boolean);\r\n // resolve({\r\n // status: true,\r\n // msg: \"文件块上传成功\",\r\n // });\r\n // } else {\r\n // // console.error(\"文件块内部上传失败\", test_boolean);\r\n\r\n // resolve({\r\n // status: false,\r\n // msg: \"文件块上传失败\",\r\n // });\r\n // }\r\n // } catch (error) {\r\n // resolve({\r\n // status: false,\r\n // msg: error,\r\n // });\r\n // }\r\n // });\r\n\r\n const result = await Promise.race([uplodChunkPromise, timerPromise]);\r\n\r\n console.log(\"块上传,序号:\", index, result);\r\n\r\n return result;\r\n };\r\n\r\n return { taskFn: fn, index: index };\r\n });\r\n\r\n const result = await controller.runTasks(uploadPromises);\r\n\r\n // 通过并发控制器执行\r\n return result.filter(item => item.status !== true);\r\n}\r\n\r\n// 通知文件块需要合并\r\nasync function informServeUploaded(fileMd, FileSize) {\r\n const result = await api.filesAllUoloaded({\r\n size: FileSize,\r\n identifier: fileMd,\r\n });\r\n\r\n return result.code === \"Success\";\r\n}\r\n\r\n// 检查文件块是否已经存在\r\nasync function searchChunkIsUploaded(fileMd5, chunkMd5) {\r\n const result = await api.searchChunkIsUploaded({\r\n identifier: fileMd5,\r\n chunkIdentifier: chunkMd5,\r\n });\r\n\r\n return result.data;\r\n}\r\n\r\n// 检查文件合并后的落盘状态\r\nasync function startCheckfileStatus(fileMd5, poll = 4000, overTime = 10000) {\r\n let timer1 = 0;\r\n let timer2 = 0;\r\n\r\n const request = new Promise((resolve, reject) => {\r\n timer1 = setInterval(async () => {\r\n const result = await checkfileStatus(fileMd5);\r\n // console.log(\"请求一次文件状态:\", result.data.status)\r\n\r\n if (result.code === \"Success\" && result.data.status === \"STORAGE\") {\r\n // console.log(\"文件已经存储\", result.data.status)\r\n resolve({\r\n result: true,\r\n Message: \"文件状态成功\",\r\n fileId: result.data.uuid,\r\n version_id: result.version,\r\n });\r\n } else if (result.code === \"Success\" && result.data.status === \"ERROR\") {\r\n // console.log(\"文件正在上传\", result.data.status)\r\n resolve({\r\n result: false,\r\n Message: \"文件状态错误\",\r\n fileId: result.data.uuid,\r\n version_id: result.version,\r\n });\r\n }\r\n }, poll);\r\n });\r\n\r\n const timeout = new Promise((resolve, reject) => {\r\n timer2 = setTimeout(() => {\r\n console.log(\"文件上传超时了\");\r\n resolve({\r\n result: false,\r\n Message: \"文件合并超时\",\r\n });\r\n }, overTime);\r\n });\r\n\r\n return Promise.race([request, timeout])\r\n .then(res => {\r\n if (timer1) {\r\n clearInterval(timer1);\r\n timer1 = null;\r\n }\r\n if (timer2) {\r\n clearTimeout(timer2);\r\n timer2 = null;\r\n }\r\n\r\n if (res.result) {\r\n return {\r\n result: true,\r\n fileId: res.fileId,\r\n version_id: res.version_id,\r\n Message: res.Message,\r\n };\r\n } else {\r\n return {\r\n result: false,\r\n Message: res.Message,\r\n };\r\n }\r\n })\r\n .catch(err => {\r\n return err;\r\n });\r\n}\r\n// 检查文件落盘状态的工具函数-检查落盘状态\r\nasync function checkfileStatus(fileMd5) {\r\n const result = await api.checkfileStatus({\r\n identifier: fileMd5,\r\n });\r\n\r\n return result;\r\n}\r\n\r\n// 检查文件是否已经存在\r\nasync function searchFileIsUploaded(md5, filesize) {\r\n const result = await api.searchFileIsUploaded({\r\n identifier: md5,\r\n size: filesize,\r\n });\r\n\r\n // 文件存在值为有长度的字符串,不存在值为null\r\n if (result) {\r\n return result.data;\r\n } else {\r\n return \"\";\r\n }\r\n}\r\n\r\n// 增加新的数据库路径;直接走此方法所有的图片都是全局图片\r\nasync function addNewFileId(id, version_id, fileType) {\r\n let result = null;\r\n\r\n if (fileType === \"txt\") {\r\n // txt表示所有文件都可以上传。\r\n // version_id为0说明不在媒资管理中上传。走的是系统总上传。基本与txt绑定使用\r\n if (version_id === 0) {\r\n result = await api.addNewFileOfTxt({\r\n uuid: id,\r\n });\r\n } else {\r\n result = await api.addNewFileOfTxt({\r\n version_id: version_id,\r\n uuid: id,\r\n });\r\n }\r\n } else if (fileType === \"video\") {\r\n result = await api.addNewFileOfVideo({\r\n version_id: version_id,\r\n uuid: id,\r\n });\r\n } else if (fileType === \"audio\") {\r\n result = await api.addNewFileOfAudio({\r\n version_id: version_id,\r\n uuid: id,\r\n });\r\n } else if (fileType === \"subTitle\") {\r\n result = await api.addNewFileOfSubTitle({\r\n version_id: version_id,\r\n uuid: id,\r\n });\r\n } else if (fileType === \"pictrue\") {\r\n result = await api.addNewFileOfPic({\r\n version_id: version_id,\r\n video_id: 0,\r\n uuid: id,\r\n });\r\n }\r\n\r\n if (result.code === 0) {\r\n if (result.data.length < 1) {\r\n return {\r\n status: false,\r\n message: \"文件路径创建失败\",\r\n };\r\n } else {\r\n return {\r\n status: true,\r\n message: \"文件路径创建成功\",\r\n };\r\n }\r\n } else {\r\n return {\r\n status: false,\r\n message: \"文件路径创建失败\",\r\n };\r\n }\r\n}\r\n","<template>\r\n <div class=\"upload-multiple\">\r\n <!-- input核心 -->\r\n <input\r\n ref=\"multiplePloadInput\"\r\n type=\"file\"\r\n style=\"display: none\"\r\n :multiple=\"multiple\"\r\n :accept=\"limitFileType\"\r\n @change=\"handleSelectedMultipleFiles\"\r\n />\r\n\r\n <div class=\"upload-multiple-box\">\r\n <!-- 上传组件本身 -->\r\n <div\r\n ref=\"upLoded_box\"\r\n class=\"multiple_upload_area\"\r\n :class=\"multipleUploadAreaClass()\"\r\n @click=\"reviewUploadMultipleFiles\"\r\n @dragover.prevent=\"onDragOver\"\r\n @dragleave.prevent=\"onDragLeave\"\r\n @drop.prevent=\"onDrop\"\r\n >\r\n <!-- 自定义loading遮罩,只作用于当前组件 -->\r\n <div\r\n v-if=\"isUploading\"\r\n class=\"upload-loading-mask\"\r\n :style=\"setUploadingLoadingMaskStyle()\"\r\n />\r\n <!-- 上传图标 -->\r\n <div v-if=\"showIconTip\"><i class=\"el-icon-upload\" /></div>\r\n <div>{{ startButtonText }}</div>\r\n <!-- 具名插槽 -->\r\n <slot name=\"tips\" />\r\n </div>\r\n\r\n <!-- 上传成功显示的图片 -->\r\n <div\r\n v-if=\"pictureConfig.show && showSuccessPicture\"\r\n class=\"upload-multiple-box-right\"\r\n >\r\n <!-- 清除图片按钮 -->\r\n <div class=\"upload-multiple-box-close\" @click.stop=\"clearPicture\">\r\n <i class=\"el-icon-close\" />\r\n </div>\r\n <img :src=\"pictureConfig.url\" :alt=\"pictureConfig.altText\" />\r\n </div>\r\n </div>\r\n\r\n <!-- 全部上传按钮 -->\r\n <el-button\r\n v-if=\"isShowAllUploadButton\"\r\n type=\"primary\"\r\n class=\"upload_button\"\r\n :disabled=\"isUploading || needUploadFilesArr.length === 0\"\r\n @click=\"startUploadMultipleFiles\"\r\n >\r\n 全部文件开始上传\r\n </el-button>\r\n\r\n <!-- 底部区域 -->\r\n <div v-if=\"model === 'table'\" class=\"upload-multiple-table\">\r\n <Upload_table\r\n :needUploadFilesArr=\"needUploadFilesArr\"\r\n :fileConfig=\"fileConfig\"\r\n :fileType=\"addDataBaseLinkConfig.addFileType\"\r\n :isUploading=\"isUploading\"\r\n @delteSelectedFile=\"delteSelectedFile\"\r\n @cancelFileUpload=\"cancelFileUpload\"\r\n @resetFileUpload=\"resetFileUpload\"\r\n @handleSelectionChange=\"tableSelectionChange\"\r\n />\r\n </div>\r\n\r\n <div v-if=\"model === 'info'\" class=\"multiple_upload_list\">\r\n <span class=\"tip_title\">\r\n <!-- 标题-显示栏 -->\r\n <span class=\"title\">\r\n <div>文件列表</div>\r\n <transition name=\"totalProgress\" mode=\"out-in\">\r\n <div v-if=\"needUploadFilesArr.length > 0\" class=\"total_progress\">\r\n <div class=\"logo\" />\r\n <!-- 暂时关闭总进度条的错误处理 -->\r\n <!-- <span>总进度({{ fileConfig.tip }}):</span> -->\r\n <!-- <el-progress\r\n :percentage=\"fileConfig.overallProgress\"\r\n :color=\"colors\"\r\n :stroke-width=\"8\"\r\n ></el-progress> -->\r\n <span>总进度:</span>\r\n <div v-if=\"fileConfig.uploadController\">\r\n <el-tag size=\"mini\" :type=\"isDanger\"\r\n >上传错误:{{ fileConfig.skipError_num }}</el-tag\r\n >\r\n <el-tag size=\"mini\" type=\"\"\r\n >上传成功:{{ fileConfig.completed_num }}</el-tag\r\n >\r\n <el-tag size=\"mini\" type=\"\"\r\n >文件总数:{{ fileConfig.filetotal_num }}</el-tag\r\n >\r\n </div>\r\n </div>\r\n </transition>\r\n </span>\r\n <!-- 标题-操作栏 -->\r\n <span>\r\n <el-button\r\n size=\"mini\"\r\n type=\"\"\r\n :disabled=\"isUploading || needUploadFilesArr.length === 0\"\r\n @click=\"handleSelectAllFile\"\r\n >全选所有文件</el-button\r\n >\r\n <el-button\r\n size=\"mini\"\r\n type=\"danger\"\r\n :disabled=\"isUploading || needUploadFilesArr.length === 0\"\r\n @click=\"delteSelectedFile\"\r\n >移除所选文件</el-button\r\n >\r\n </span>\r\n </span>\r\n\r\n <!-- 上传队列 -->\r\n <div class=\"selected_list_area\">\r\n <div v-if=\"needUploadFilesArr.length > 0\" class=\"selected_list\">\r\n <Card_2\r\n v-for=\"(item, index) in needUploadFilesArr\"\r\n :key=\"index\"\r\n :index=\"index\"\r\n :file-config=\"item\"\r\n @cancelFileUpload=\"cancelFileUpload\"\r\n @resetFileUpload=\"resetFileUpload\"\r\n @handleClickOnlyFile=\"handleClickOnlyFile\"\r\n />\r\n </div>\r\n <div v-else class=\"no_file\">\r\n <i class=\"el-icon-document\" />\r\n <div>暂无文件,请点击或拖拽文件到上传区域</div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<!-- 需要给这个组件的网络请求重构\r\n 1.目标:外界可传入自己的axios,内部直接使用外部的axios发请求.这样可以解决token的问题.缺点是必须在vu.use时候传入axios实例\r\n 2. -->\r\n\r\n<script>\r\nimport { fileTypeValidators } from \"./util.js\";\r\nimport Card_2 from \"./components/UploadCard_Ver_Second/index.vue\";\r\nimport Upload_table from \"./components/Upload_table/index.vue\";\r\nimport uploadFilesConfig_AndStart from \"./upload.js\";\r\n\r\nexport default {\r\n name: \"KukanUpload\",\r\n components: {\r\n Card_2,\r\n Upload_table,\r\n },\r\n props: {\r\n // 秒传(文件已存在则跳过上传);待做\r\n // 分片队列最大长度;待做\r\n // 上传文件限制;待做\r\n // 回调函数。待做\r\n // 断网自动重连开关(重试策略);待做\r\n // 断点续传开关;尚不支持\r\n // 文件上传时是否允许取消\r\n\r\n // 添加数据库链接配置\r\n addDataBaseLinkConfig: {\r\n required: false,\r\n type: Object,\r\n default: () => {\r\n return {\r\n // 文件上传成功之后或者检索文件已存在时是否创建数据库链接\r\n addDataBaseLink: false,\r\n // 文件类型,用于检查文件类型是否正确以及增加数据库链接\r\n addFileType: \"\",\r\n // 节目版本,用于检查文件是否存在以及创建数据库的路径\r\n addProgramVersion: 0,\r\n };\r\n },\r\n },\r\n // 选择完文件是否开启自动传输\r\n autoUpload: {\r\n required: false,\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 多选\r\n multiple: {\r\n required: false,\r\n type: Boolean,\r\n },\r\n // 开始按钮的提示文字\r\n startButtonText: {\r\n required: false,\r\n type: String,\r\n default: \"\",\r\n },\r\n // 是否显示上传成功的图片?当前只支持small模式。后续应当拓冲\r\n showSuccessPicture: {\r\n required: false,\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 上传区域的UI样式。small/mill/info\r\n model: {\r\n required: true,\r\n type: String,\r\n default: \"small\",\r\n },\r\n // 是否显示提示文字上方的logo\r\n showIconTip: {\r\n required: false,\r\n type: Boolean,\r\n default: true,\r\n },\r\n // 不显示上传区域边框\r\n noneBoder: {\r\n required: false,\r\n type: Boolean,\r\n default: false,\r\n },\r\n // 配置内部的请求api\r\n apiObj: {\r\n required: false,\r\n type: Object,\r\n default: () => {\r\n return {};\r\n },\r\n },\r\n maxFileConcurrent: {\r\n required: false,\r\n type: Number,\r\n default: 2,\r\n },\r\n maxFileChunkConcurrent: {\r\n required: false,\r\n type: Number,\r\n default: 2,\r\n },\r\n },\r\n data() {\r\n return {\r\n // showSuccessPicture属性显示图片的配置\r\n pictureConfig: {\r\n show: false,\r\n url: \"\",\r\n altText: \"封面图片\",\r\n },\r\n // 总文件队列上传的配置\r\n fileConfig: {\r\n overallProgress: 0,\r\n notShowTip: true,\r\n tip: \"等待上传\",\r\n uploadController: null,\r\n skipError_num: 0,\r\n filetotal_num: 0,\r\n completed_num: 0,\r\n maxFileConcurrent: this.maxFileConcurrent,\r\n },\r\n // 创建路径需要知道节目id\r\n program_id: 0,\r\n // 上传收集的文件数组\r\n needUploadFilesArr: [],\r\n // 单文件分块队列上传配置\r\n multipleChunkConfig: {\r\n fileQueues: new Map(), // 文件队列映射\r\n progressCallbacks: new Map(), // 进度回调映射\r\n uploadTasks: new Map(), // 上传任务映射\r\n chunkSize: 1 * 1024 * 1024,\r\n maxConcurrent: this.maxFileChunkConcurrent,\r\n },\r\n };\r\n },\r\n computed: {\r\n limitFileType() {\r\n if (this.addDataBaseLinkConfig.addFileType === \"txt\") {\r\n return \"\";\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"video\") {\r\n return \"video/*\";\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"pictrue\") {\r\n return \"image/*\";\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"audio\") {\r\n return \"audio/*\";\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"subTitle\") {\r\n return \".srt, .vtt, .ass, .ssa, .smi, .webvtt, .ttml, .dfxp, .lrc, .vtt, .srt, .txt\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n // 是否显示全部上传按钮\r\n isShowAllUploadButton() {\r\n if (this.model === \"info\" && this.autoUpload !== true) {\r\n return true;\r\n }\r\n },\r\n // 是否显示批量上传的列表\r\n isDanger() {\r\n if (this.fileConfig.skipError_num > 0) {\r\n return \"danger\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n currentFileUploadedArr() {\r\n return this.fileConfig.uploadController.getStatus();\r\n },\r\n // 判断是否正在上传(单个或批量)\r\n isUploading() {\r\n // 批量上传状态:检查是否有文件正在上传中\r\n if (this.needUploadFilesArr && this.needUploadFilesArr.length > 0) {\r\n const hasUploading = this.needUploadFilesArr.some(\r\n item =>\r\n item.tip === \"上传中\" ||\r\n (item.notShowTip &&\r\n item.uploadProgress >= 0 &&\r\n item.uploadProgress < 100),\r\n );\r\n return hasUploading;\r\n }\r\n\r\n return false;\r\n },\r\n },\r\n mounted() {},\r\n methods: {\r\n // 父组件事件集合\r\n // 文件删除后的回调\r\n removeFileInform(removeArr) {\r\n this.$emit(\"removeFile\", removeArr);\r\n },\r\n // 通知父组件刷新数据,已经上传完成了\r\n informUploadedOfRefresh() {\r\n this.$emit(\"informTableOfRefresh\");\r\n },\r\n // 上传完成的回调,返回上传结果\r\n uploadedResult(result) {\r\n this.$emit(\"handelResult\", result);\r\n },\r\n // 获取上传成功的文件id列表\r\n uploadedUUIDs(_arr) {\r\n this.$emit(\"getUUID\", _arr);\r\n },\r\n // 上传开始\r\n uploadStart() {\r\n this.$emit(\"uploadStart\");\r\n },\r\n\r\n tableSelectionChange(selectIds) {\r\n this.needUploadFilesArr.forEach(item => {\r\n item.isSelected = selectIds.includes(item.index);\r\n });\r\n },\r\n\r\n // 上传开始后制定其他的文件筛选逻辑\r\n // 返回 Promise,父组件通过回调在需要时调用 `done(filterFiles)` 来决议\r\n uploadingOtherFilterFun(needUploadFilesArr) {\r\n return new Promise(resolve => {\r\n let resolved = false;\r\n\r\n const done = filterFiles => {\r\n if (Array.isArray(filterFiles)) {\r\n this.needUploadFilesArr = filterFiles;\r\n }\r\n console.log(\r\n \"上传开始后指定其他的文件筛选逻辑\",\r\n this.needUploadFilesArr,\r\n );\r\n if (!resolved) {\r\n resolved = true;\r\n resolve();\r\n }\r\n };\r\n\r\n // 发出事件并传入回调,监听方应在合适时机调用该回调\r\n this.$emit(\"otherFilterFiles\", needUploadFilesArr, done);\r\n\r\n // 如果没有任何监听器或监听器没有调用回调,保证不会永远等待\r\n // 在短时间内自动继续(例如 0ms 微任务后),以便保持向后兼容\r\n setTimeout(() => {\r\n if (!resolved) {\r\n resolved = true;\r\n resolve();\r\n }\r\n }, 500);\r\n });\r\n },\r\n\r\n // 还原配置\r\n resetConfig() {\r\n // 清理控制器与缓存,恢复 UI 状态\r\n if (this.fileConfig && this.fileConfig.uploadController) {\r\n try {\r\n this.pauseAllQueue();\r\n this.fileConfig.uploadController.clear();\r\n } catch (error) {\r\n console.error(error);\r\n }\r\n }\r\n this.fileConfig.uploadController = null;\r\n this.multipleChunkConfig.uploadTasks = new Map();\r\n this.multipleChunkConfig.fileQueues = new Map();\r\n this.needUploadFilesArr = [];\r\n // 根据 skipError 或 completed 设置提示\r\n if (this.fileConfig.skipError_num > 0) {\r\n this.fileConfig.tip = \"上传出错\";\r\n this.fileConfig.notShowTip = false;\r\n } else {\r\n this.fileConfig.tip = \"等待上传\";\r\n this.fileConfig.notShowTip = true;\r\n this.fileConfig.overallProgress = 0;\r\n }\r\n },\r\n // 设置上传loading遮罩的style样式\r\n setUploadingLoadingMaskStyle() {\r\n return { \"--spinner-size\": this.model === \"mini\" ? \"20px\" : \"40px\" };\r\n },\r\n // 设置上传区域的class样式\r\n multipleUploadAreaClass() {\r\n return {\r\n multiple_upload_area_disabled: this.isUploading,\r\n small_model: this.model === \"small\",\r\n mini_model: this.model === \"mini\",\r\n };\r\n },\r\n // 每个列表的上传状态的样式\r\n uploadingTextStyle(text) {\r\n // 第一个未知,第二个stauts超时,第三个上传块超时\r\n if (\r\n text === \"出错\" ||\r\n text === \"查询文件地址超时\" ||\r\n text === \"上传出错\"\r\n ) {\r\n return \"uploading_error\";\r\n } else if (text === \"已完成\") {\r\n return \"uploading_success\";\r\n } else if (text === \"等待上传\") {\r\n return \"uploading_wait\";\r\n } else {\r\n return \"\";\r\n }\r\n },\r\n // 设置图片的url\r\n setPictureConfig(uuid) {\r\n if (!uuid) {\r\n return;\r\n }\r\n\r\n const serveUrl = `${process.env.VUE_APP_ZT_BASE_API}/resources/open/view/image?`;\r\n\r\n this.pictureConfig.show = true;\r\n this.pictureConfig.url = serveUrl + `uuid=${uuid}`;\r\n this.pictureConfig.altText = \"读取成功\";\r\n },\r\n // 清理图片\r\n clearPicture() {\r\n this.pictureConfig.show = false;\r\n this.pictureConfig.url = \"\";\r\n this.pictureConfig.altText = \"封面图片\";\r\n },\r\n // 总进度条的状态\r\n totalProgressStatus(fileConfig) {\r\n if (!fileConfig.notShowTip) {\r\n if (fileConfig.overallProgress < 100) {\r\n return \"exception\";\r\n } else {\r\n return null;\r\n }\r\n } else {\r\n if (fileConfig.overallProgress > 99) {\r\n return \"success\";\r\n }\r\n return null;\r\n }\r\n },\r\n // 文件进度条\r\n progressStatus(progress) {\r\n if (progress < 100) {\r\n return \"active\";\r\n } else {\r\n return \"success\";\r\n }\r\n },\r\n // 暂停所有队列\r\n pauseAllQueue() {\r\n // 暂停所有任务\r\n this.fileConfig.uploadController.pause(); // 成功取消\r\n this.multipleChunkConfig.fileQueues.forEach((value, key, map) => {\r\n value.pause();\r\n }); // 成功取消\r\n },\r\n // 检查文件名称是否已经存在。应当使用id,此处逻辑有错误,此函数暂时无用,暂不处理。2025/12/17\r\n async searchFilePathIsExist(name) {\r\n let arr = [];\r\n\r\n const result = await this.$store.dispatch(\"app/getMediaList\", {\r\n currentFileType: this.addDataBaseLinkConfig.addFileType,\r\n version_id: this.addDataBaseLinkConfig.programVersion,\r\n page_num: 1,\r\n page_sizet: 10,\r\n file_id: \"\",\r\n file_name: name,\r\n imageIsOnlyImg: this.imageIsOnlyImgOfButton === 1,\r\n });\r\n\r\n if (result.code === 0) {\r\n if (this.addDataBaseLinkConfig.addFileType === \"txt\") {\r\n arr = result.data.doc_list;\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"video\") {\r\n arr = result.data.video_list;\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"audio\") {\r\n arr = result.data.audio_list;\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"subTitle\") {\r\n arr = result.data.srt_list;\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"pictrue\") {\r\n arr = result.data.pic_list;\r\n }\r\n }\r\n\r\n if (arr.length > 1) {\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n },\r\n // 全选列表所有文件\r\n handleSelectAllFile() {\r\n this.needUploadFilesArr.forEach(item => {\r\n item.isSelected = true;\r\n });\r\n },\r\n // 重试取消的文件\r\n resetFileUpload(item) {\r\n if (item.tip === \"上传出错\") {\r\n // 目前已知流程错误可以重试\r\n // 清除小块的队列\r\n const id = item.index;\r\n const fileQueue = this.multipleChunkConfig.fileQueues;\r\n const controller =\r\n fileQueue && typeof fileQueue.get === \"function\"\r\n ? fileQueue.get(id)\r\n : fileQueue[id];\r\n\r\n if (controller && typeof controller.resume === \"function\") {\r\n controller.resume();\r\n controller.clear();\r\n }\r\n\r\n // 如果已经有两个重试的在执行,应该直接放进队列或者显示队列已满,稍后再试\r\n const status =\r\n this.fileConfig &&\r\n this.fileConfig.uploadController &&\r\n typeof this.fileConfig.uploadController.getStatus === \"function\"\r\n ? this.fileConfig.uploadController.getStatus()\r\n : { activeCount: 0 };\r\n\r\n if (status.activeCount >= this.fileConfig.maxFileConcurrent) {\r\n console.debug(\"队列已满\", this.fileConfig.uploadController);\r\n if (\r\n this.fileConfig &&\r\n this.fileConfig.uploadController &&\r\n typeof this.fileConfig.uploadController.errorActiveIsFull ===\r\n \"function\"\r\n ) {\r\n this.fileConfig.uploadController.errorActiveIsFull(item.index);\r\n item.tip = \"上传中\";\r\n console.log(\"item是否修改成功\", item.tip);\r\n }\r\n } else {\r\n console.debug(\"队列未满\", this.fileConfig.uploadController);\r\n this.fileConfig.uploadController.startResetErrorTask(item.index);\r\n }\r\n } else if (item.tip === \"已取消\") {\r\n // 如果已经有两个重试的在执行,应该直接放进队列或者显示队列已满,稍后再试\r\n const status =\r\n this.fileConfig &&\r\n this.fileConfig.uploadController &&\r\n typeof this.fileConfig.uploadController.getStatus === \"function\"\r\n ? this.fileConfig.uploadController.getStatus()\r\n : { activeCount: 0 };\r\n\r\n if (status.activeCount >= this.fileConfig.maxFileConcurrent) {\r\n if (\r\n this.fileConfig &&\r\n this.fileConfig.uploadController &&\r\n typeof this.fileConfig.uploadController.errorActiveIsFull ===\r\n \"function\"\r\n ) {\r\n item.tip = \"上传中\";\r\n\r\n this.fileConfig.uploadController.startResetCanceledyTask(\r\n item.index,\r\n );\r\n\r\n console.log(\"item是否修改成功\", item.tip);\r\n }\r\n } else {\r\n this.fileConfig.uploadController.startResetCanceledyTask(item.index);\r\n }\r\n }\r\n },\r\n // 取消上传的文件\r\n cancelFileUpload(item) {\r\n if (!this.fileConfig.uploadController) {\r\n this.needUploadFilesArr = this.needUploadFilesArr.filter(file => {\r\n return file.index !== item.index;\r\n });\r\n\r\n return;\r\n }\r\n\r\n const result = this.fileConfig.uploadController.cancelFileUpload(\r\n item.index,\r\n );\r\n\r\n if (result) {\r\n this.$set(item, \"notShowTip\", false);\r\n this.$set(item, \"tip\", \"已取消\");\r\n } else {\r\n this.$message.error(\"正在上传,不可取消\");\r\n }\r\n },\r\n // 点击列表中选择的文件\r\n handleClickOnlyFile(item) {\r\n item.isSelected = !item.isSelected;\r\n },\r\n // 移除待上传文件的\r\n delteSelectedFile() {\r\n const _neerUploadFilesArr = [];\r\n const _noNeerUploadFilesArr = [];\r\n\r\n this.needUploadFilesArr.forEach(item => {\r\n if (!item.isSelected) {\r\n _neerUploadFilesArr.push(item);\r\n } else {\r\n item.isSelected = false;\r\n _noNeerUploadFilesArr.push(item);\r\n }\r\n });\r\n\r\n if (this.needUploadFilesArr.length === _neerUploadFilesArr.length) {\r\n this.$message(\"没有需要移除的文件\");\r\n return;\r\n }\r\n\r\n // 需要添加移除文件的钩子函数\r\n this.removeFileInform(_noNeerUploadFilesArr);\r\n\r\n this.needUploadFilesArr = _neerUploadFilesArr;\r\n },\r\n // 开始上传按钮的点击事件:上传已经准备好的文件\r\n async startUploadMultipleFiles() {\r\n // 避免重复上传\r\n const handleUploadFileArr = this.needUploadFilesArr.filter(\r\n item => item.tip !== \"已完成\",\r\n );\r\n\r\n if (handleUploadFileArr.length === 0) {\r\n this.$message.error(\"没有需要上传的文件\");\r\n return;\r\n }\r\n\r\n try {\r\n this.uploadStart();\r\n\r\n this.$message.success(\"开始上传\");\r\n\r\n this.fileConfig.filetotal_num = handleUploadFileArr.length;\r\n\r\n handleUploadFileArr.forEach(item => {\r\n item.notShowTip = false;\r\n item.tip = \"上传中\";\r\n item.uploadProgress = 0;\r\n\r\n item.updateProgress = progress => {\r\n this.$set(item, \"notShowTip\", progress.notShowTip);\r\n this.$set(item, \"tip\", progress.tip);\r\n this.$set(item, \"uploadProgress\", progress.percentage);\r\n this.uploadingTextStyle(item.tip);\r\n };\r\n item.progress_error = () => {\r\n this.$set(item, \"notShowTip\", false);\r\n this.$set(item, \"tip\", \"上传出错\");\r\n this.$set(item, \"uploadProgress\", 0);\r\n this.uploadingTextStyle(item.tip);\r\n };\r\n });\r\n\r\n const total_progress_function = ({\r\n percentage,\r\n notShowTip,\r\n tip,\r\n completed,\r\n total,\r\n active,\r\n queued,\r\n skipError,\r\n }) => {\r\n console.log(\r\n \"%c 文件总进度:\",\r\n \"color: #2196F3; font-weight: bold;\",\r\n `已完成 ${completed}/${total},正在上传 ${active},排队中 ${queued}, 出错数量 ${skipError} 个`,\r\n );\r\n this.fileConfig.overallProgress = percentage;\r\n this.fileConfig.notShowTip = notShowTip;\r\n this.fileConfig.tip = tip;\r\n this.fileConfig.skipError_num = skipError;\r\n this.fileConfig.completed_num = completed;\r\n this.fileConfig.filetotal_num = total;\r\n };\r\n\r\n const createFileQueues = (index, controller) => {\r\n this.multipleChunkConfig.fileQueues.set(index, controller);\r\n };\r\n const createUploadQueues = (uploadId, task) => {\r\n this.multipleChunkConfig.uploadTasks.set(uploadId, task);\r\n };\r\n\r\n const setTotalStatus = (controller, text) => {\r\n this.fileConfig.uploadController = controller;\r\n this.fileConfig.tip = \"上传中\";\r\n };\r\n\r\n const result = await uploadFilesConfig_AndStart(\r\n handleUploadFileArr,\r\n this.multipleChunkConfig.maxConcurrent,\r\n this.fileConfig.maxFileConcurrent,\r\n this.addDataBaseLinkConfig,\r\n createFileQueues,\r\n createUploadQueues,\r\n total_progress_function,\r\n setTotalStatus,\r\n this.apiObj,\r\n );\r\n if (result) {\r\n // 这三个事件考虑合并\r\n this.informUploadedOfRefresh();\r\n this.uploadedResult(result);\r\n\r\n // 检查是否有成功的上传(至少有一个文件上传成功)\r\n const hasSuccess = result.some(item => item.status === true);\r\n if (hasSuccess) {\r\n const _arr = result.map(item => item.uuid);\r\n this.uploadedUUIDs(_arr);\r\n\r\n // 只有单选模式下才会执行\r\n if (_arr.length <= 1 && !this.multiple) {\r\n const serveUrl = `${process.env.VUE_APP_ZT_BASE_API}/resources/open/view/image?`;\r\n this.pictureConfig = {\r\n alt: \"上传成功\",\r\n url: serveUrl + `uuid=${_arr[0]}`,\r\n show: true,\r\n };\r\n }\r\n }\r\n } else {\r\n this.uploadedResult([]);\r\n this.$message.error(\"上传出错!\");\r\n }\r\n } catch (err) {\r\n console.error(\"批量上传失败\", err);\r\n this.$message.error(\"上传出错!\");\r\n }\r\n },\r\n // 这三个时间处理文件拖拽逻辑\r\n onDrop(event) {\r\n this.handleSelectedMultipleFiles(event);\r\n },\r\n onDragOver() {\r\n this.$refs.upLoded_box.classList.add(\"uploading_box_hover\");\r\n },\r\n onDragLeave() {\r\n this.$refs.upLoded_box.classList.remove(\"uploading_box_hover\");\r\n },\r\n // 文件框的点击事件\r\n reviewUploadMultipleFiles(e) {\r\n if (this.isUploading) {\r\n this.$message.error(\"后台上传中\");\r\n return;\r\n }\r\n if (!this.$refs.multiplePloadInput) {\r\n return;\r\n }\r\n this.$refs.multiplePloadInput.click();\r\n },\r\n // input传入文件的回调\r\n async handleSelectedMultipleFiles(e) {\r\n let _needUploadFilesArr = [];\r\n\r\n let error = 0;\r\n\r\n const _arr = e.target.files || e.dataTransfer.files;\r\n\r\n // 校验文件格式\r\n Array.from(_arr).forEach((item, index) => {\r\n if (this.addDataBaseLinkConfig.addFileType === \"video\") {\r\n if (\r\n fileTypeValidators.isVideo(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"txt\") {\r\n if (\r\n fileTypeValidators.isDocument(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"subTitle\") {\r\n if (\r\n fileTypeValidators.isSubtitle(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"audio\") {\r\n if (\r\n fileTypeValidators.isAudio(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n } else if (this.addDataBaseLinkConfig.addFileType === \"pictrue\") {\r\n if (\r\n fileTypeValidators.isImage(item.type || item.name.split(\".\")[1])\r\n ) {\r\n _needUploadFilesArr.push({\r\n isSelected: false,\r\n name: item.name,\r\n file: item,\r\n index: index,\r\n notShowTip: false,\r\n tip: \"等待上传\",\r\n uploadProgress: 0,\r\n updateProgress: null,\r\n progress_error: null,\r\n });\r\n } else {\r\n error++;\r\n }\r\n }\r\n });\r\n\r\n if (error > 0) {\r\n this.$message.error(`${error}个文件格式不支持,已跳过`);\r\n }\r\n\r\n error = 0;\r\n\r\n // 校验文件大小\r\n _needUploadFilesArr = _needUploadFilesArr.filter(item => {\r\n // 兼容不同浏览器/环境的字段名,优先使用标准的 `file.size`\r\n const rawSize =\r\n (item &&\r\n item.file &&\r\n (item.file.size || item.fileSize || item.size)) ||\r\n 0;\r\n const fileSize = Number(rawSize) || 0;\r\n\r\n const max = 1 * 1024 * 1024 * 1024; // 2GB\r\n const allowed = fileSize > 0 && fileSize < max;\r\n if (!allowed) {\r\n error++;\r\n }\r\n return allowed;\r\n });\r\n if (error) {\r\n this.$message.error(`${error}个文件大小超出2Gb,已跳过`);\r\n error = 0;\r\n }\r\n\r\n // 选择文件时,若前一个进度条已经满了,则清空总进度条\r\n if (this.fileConfig.uploadController) {\r\n this.fileConfig.uploadController.clear();\r\n this.fileConfig.overallProgress = 0;\r\n this.fileConfig.notShowTip = true;\r\n this.fileConfig.tip = \"等待上传\";\r\n this.fileConfig.skipError_num = 0;\r\n this.fileConfig.completed_num = 0;\r\n this.fileConfig.filetotal_num = 0;\r\n }\r\n\r\n // 移除已完成的(选完文件移除)\r\n // const _needUploadFilesArr2 = this.needUploadFilesArr.filter(\r\n // item => item.tip !== \"已完成\",\r\n // );\r\n\r\n this.needUploadFilesArr = [\r\n ...this.needUploadFilesArr,\r\n ..._needUploadFilesArr,\r\n ];\r\n // 此处需要额外的处理逻辑,而这个额外的逻辑需要父组件提供\r\n // 等待父组件通过回调处理筛选逻辑(若父组件未提供回调则立即继续)\r\n await this.uploadingOtherFilterFun(this.needUploadFilesArr);\r\n\r\n // 防止不能重复上传\r\n e.target.value = \"\"\r\n\r\n // 上传分为:1.列表模式点击按钮开始上传。2.选择完文件自动上传。3.通过xxx方法可以选择改变已选文件,然后调用xxx方法实现上传,这几种方法暂时是互斥的\r\n if (this.needUploadFilesArr.length > 0 && this.autoUpload) {\r\n this.startUploadMultipleFiles();\r\n }\r\n },\r\n },\r\n};\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n.upload-multiple {\r\n margin-top: 0.15rem;\r\n animation: slideDown 0.3s ease-out;\r\n\r\n .upload-loading-mask {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background-color: rgba(255, 255, 255, 0.9);\r\n z-index: 100;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: 0.5rem;\r\n\r\n &::after {\r\n content: \"\";\r\n width: var(--spinner-size, 40px);\r\n height: var(--spinner-size, 40px);\r\n border: 4px solid #f3f3f3;\r\n border-top: 4px solid #1890ff;\r\n border-radius: 50%;\r\n animation: spin 1s linear infinite;\r\n }\r\n }\r\n\r\n @keyframes spin {\r\n 0% {\r\n transform: rotate(0deg);\r\n }\r\n 100% {\r\n transform: rotate(360deg);\r\n }\r\n }\r\n\r\n .upload-multiple-box {\r\n display: flex;\r\n\r\n .upload-multiple-box-right {\r\n // width: 8rem;\r\n height: 9rem;\r\n margin-left: 1rem;\r\n position: relative;\r\n\r\n img {\r\n max-width: 21vw;\r\n height: 100%;\r\n border-radius: 8px;\r\n }\r\n\r\n .upload-multiple-box-close {\r\n position: absolute;\r\n top: -8px;\r\n left: -8px;\r\n width: 20px;\r\n height: 20px;\r\n border-radius: 50%;\r\n background-color: #f56c6c;\r\n color: #fff;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n font-size: 12px;\r\n z-index: 10;\r\n\r\n &:hover {\r\n background-color: #e64949;\r\n }\r\n }\r\n }\r\n }\r\n\r\n .upload_button {\r\n border-radius: 5px;\r\n margin-top: 0.5rem;\r\n width: 100%;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n .upload_button:hover {\r\n transform: translateY(-2px);\r\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n .multiple_upload_area {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n transition: all 0.3s ease;\r\n\r\n position: relative;\r\n\r\n padding: 1.2rem;\r\n border: 2px dashed #c0c4cc;\r\n border-radius: 0.5rem;\r\n width: 100%;\r\n height: 9rem;\r\n // margin-bottom: 1rem;\r\n cursor: pointer;\r\n\r\n .el-icon-upload {\r\n font-size: 2.5rem;\r\n color: #909399;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n div:nth-child(2) {\r\n font-size: 1rem;\r\n color: #606266;\r\n transition: all 0.3s ease;\r\n }\r\n }\r\n .uploading_box_hover {\r\n border: 2px dashed #1890ff;\r\n background-color: rgba(24, 144, 255, 0.05);\r\n\r\n .el-icon-upload {\r\n color: #1890ff;\r\n transform: scale(1.1);\r\n }\r\n\r\n div:nth-child(2) {\r\n color: #1890ff;\r\n }\r\n }\r\n .multiple_upload_area_disabled {\r\n cursor: not-allowed;\r\n }\r\n .small_model {\r\n width: 9rem;\r\n height: 9rem;\r\n }\r\n .mini_model {\r\n width: 5rem;\r\n height: 1.5rem;\r\n padding: 0.75rem 0.25rem;\r\n }\r\n\r\n .multiple_upload_area:hover {\r\n border: 2px dashed #1890ff;\r\n background-color: rgba(24, 144, 255, 0.05);\r\n\r\n .el-icon-upload {\r\n color: #1890ff;\r\n transform: scale(1.1);\r\n }\r\n\r\n div:nth-child(2) {\r\n color: #1890ff;\r\n }\r\n }\r\n\r\n .upload-multiple-table {\r\n margin-top: 1rem;\r\n }\r\n\r\n .multiple_upload_list {\r\n position: relative;\r\n // height: 24rem;\r\n overflow: auto;\r\n padding: 0.5rem;\r\n border-radius: 4px;\r\n background-color: #f6f6f7;\r\n margin-top: 1rem;\r\n\r\n .tip_title {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0.5rem 0;\r\n padding-top: 0;\r\n\r\n .title {\r\n display: flex;\r\n\r\n .total_progress {\r\n display: flex;\r\n align-items: center;\r\n margin-left: 0.5rem;\r\n\r\n .logo {\r\n border-left: 8px solid #1890ff;\r\n border-radius: 2px;\r\n width: 0.1px;\r\n height: 1rem;\r\n margin-bottom: 0.2rem;\r\n }\r\n\r\n .el-progress {\r\n width: 12rem;\r\n\r\n ::v-deep .el-progress-bar__outer {\r\n background-color: #b3c3e8;\r\n }\r\n\r\n ::v-deep .el-progress-bar__inner {\r\n transition: width 0.4s ease;\r\n }\r\n }\r\n\r\n .uploading_error {\r\n color: #f56c6c;\r\n font-weight: 500;\r\n }\r\n\r\n .uploading_wait {\r\n color: #909399;\r\n }\r\n\r\n .uploading_success {\r\n color: #67c23a;\r\n font-weight: 500;\r\n }\r\n }\r\n }\r\n\r\n .el-button {\r\n padding: 0.5rem 1rem;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n .el-button:hover {\r\n transform: translateY(-1px);\r\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);\r\n }\r\n }\r\n\r\n .selected_list_area {\r\n overflow: auto;\r\n\r\n .selected_list {\r\n margin-top: 0.2rem;\r\n padding: 0;\r\n width: 100%;\r\n display: flex;\r\n gap: 0.75rem;\r\n flex-wrap: wrap;\r\n justify-content: flex-start;\r\n }\r\n }\r\n\r\n .no_file {\r\n position: absolute;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n text-align: center;\r\n }\r\n\r\n @media screen and (max-width: 2200px) {\r\n .selected_list_area {\r\n height: 22rem;\r\n }\r\n }\r\n @media screen and (max-width: 1600px) {\r\n .selected_list_area {\r\n height: 15rem;\r\n }\r\n }\r\n }\r\n}\r\n</style>\r\n","import mod from \"-!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=7af8297e&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=js\"\nexport * from \"./index.vue?vue&type=script&lang=js\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=7af8297e&prod&scoped=true&lang=scss\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"7af8297e\",\n null\n \n)\n\nexport default component.exports","import Upload from './index.vue';\r\n\r\n// 为单个组件也提供 install 方法\r\nUpload.install = function(Vue) {\r\n Vue.component(Upload.name, Upload);\r\n};\r\n\r\nexport default Upload;","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('el-dialog',{attrs:{\"visible\":_vm.dialogVisible,\"show-close\":false,\"modal\":true,\"width\":_vm.width,\"top\":_vm.topMargin,\"custom-class\":\"modern-video-review-dialog\",\"append-to-body\":\"\",\"before-close\":_vm.closePreview},on:{\"update:visible\":function($event){_vm.dialogVisible=$event},\"opened\":_vm.onOpened}},[_c('div',{staticClass:\"video-review-container\",style:({ height: _vm.height }),on:{\"mousemove\":_vm.onDrag,\"mouseup\":_vm.stopDrag,\"mouseleave\":_vm.stopDrag}},[_c('div',{staticClass:\"video-review-header\"},[_c('div',{staticClass:\"file-info\"},[_c('span',{staticClass:\"file-name\",attrs:{\"title\":_vm.fileName}},[_vm._v(_vm._s(_vm.fileName || \"视频预览\"))]),(!_vm.combinedLoading && !_vm.loadError && _vm.videoWidth)?_c('span',{staticClass:\"file-size\"},[_vm._v(\" \"+_vm._s(_vm.videoWidth)+\" × \"+_vm._s(_vm.videoHeight)+\" px | \"+_vm._s(_vm.duration)+\" \")]):_vm._e()]),_c('div',{staticClass:\"video-review-controls\"},[_c('button',{staticClass:\"control-icon-btn\",attrs:{\"disabled\":_vm.combinedLoading || _vm.loadError || _vm.scale <= _vm.minScale},on:{\"click\":_vm.zoomOut}},[_c('i',{staticClass:\"el-icon-zoom-out\"})]),_c('span',{staticClass:\"zoom-display\"},[_vm._v(_vm._s(Math.round(_vm.scale * 100))+\"%\")]),_c('button',{staticClass:\"control-icon-btn\",attrs:{\"disabled\":_vm.combinedLoading || _vm.loadError || _vm.scale >= _vm.maxScale},on:{\"click\":_vm.zoomIn}},[_c('i',{staticClass:\"el-icon-zoom-in\"})]),_c('div',{staticClass:\"control-divider\"}),_c('button',{staticClass:\"control-icon-btn\",attrs:{\"disabled\":_vm.combinedLoading,\"title\":\"原始尺寸/重置位置\"},on:{\"click\":_vm.resetZoom}},[_c('i',{staticClass:\"el-icon-refresh-right\"})]),_c('button',{staticClass:\"control-icon-btn close-btn\",on:{\"click\":_vm.closePreview}},[_c('i',{staticClass:\"el-icon-close\"})])])]),_c('div',{staticClass:\"video-review-content\",on:{\"wheel\":function($event){$event.preventDefault();return _vm.handleWheel($event)},\"mousedown\":function($event){if($event.target !== $event.currentTarget){ return null; }return _vm.startDrag($event)},\"!click\":function($event){return _vm.handleCaptureClick($event)}}},[_c('transition',{attrs:{\"name\":\"fade\"}},[(_vm.combinedLoading && !_vm.loadError)?_c('div',{staticClass:\"status-overlay\"},[_c('i',{staticClass:\"el-icon-loading\"}),_c('p',[_vm._v(\"视频加载中...\")])]):_vm._e()]),(_vm.loadError)?_c('div',{staticClass:\"status-overlay error\"},[_c('i',{staticClass:\"el-icon-video-camera\"}),_c('p',[_vm._v(\"视频加载失败\")])]):_vm._e(),_c('div',{directives:[{name:\"show\",rawName:\"v-show\",value:(!_vm.combinedLoading && !_vm.loadError),expression:\"!combinedLoading && !loadError\"}],staticClass:\"video-transform-wrapper\",style:(_vm.videoStyle),on:{\"mousedown\":_vm.startDrag}},[(_vm.visible && _vm.videoUrl)?_c('video',{key:_vm.videoKey,ref:\"videoPlayer\",staticClass:\"main-preview-video\",attrs:{\"src\":_vm.videoUrl,\"autoplay\":\"\",\"loop\":\"\",\"playsinline\":\"\",\"controls\":\"\"},on:{\"loadedmetadata\":_vm.onMetadataLoad,\"error\":_vm.onVideoError,\"canplay\":_vm.onCanPlay,\"waiting\":function($event){_vm.innerLoading = true}}}):_vm._e()])],1),_c('div',{staticClass:\"video-review-hint\"},[_c('span',[_vm._v(\"鼠标拖拽背景移动,滚轮缩放查看细节\")])])])])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","<template>\r\n <el-dialog\r\n :visible.sync=\"dialogVisible\"\r\n :show-close=\"false\"\r\n :modal=\"true\"\r\n :width=\"width\"\r\n :top=\"topMargin\"\r\n custom-class=\"modern-video-review-dialog\"\r\n append-to-body\r\n :before-close=\"closePreview\"\r\n @opened=\"onOpened\"\r\n >\r\n <div\r\n class=\"video-review-container\"\r\n :style=\"{ height: height }\"\r\n @mousemove=\"onDrag\"\r\n @mouseup=\"stopDrag\"\r\n @mouseleave=\"stopDrag\"\r\n >\r\n <!-- 头部:控制栏 -->\r\n <div class=\"video-review-header\">\r\n <div class=\"file-info\">\r\n <span class=\"file-name\" :title=\"fileName\">{{\r\n fileName || \"视频预览\"\r\n }}</span>\r\n <span v-if=\"!combinedLoading && !loadError && videoWidth\" class=\"file-size\">\r\n {{ videoWidth }} × {{ videoHeight }} px | {{ duration }}\r\n </span>\r\n </div>\r\n\r\n <div class=\"video-review-controls\">\r\n <!-- 逻辑修改:增加 combinedLoading 判断来禁用按钮 -->\r\n <button class=\"control-icon-btn\" :disabled=\"combinedLoading || loadError || scale <= minScale\" @click=\"zoomOut\">\r\n <i class=\"el-icon-zoom-out\" />\r\n </button>\r\n <span class=\"zoom-display\">{{ Math.round(scale * 100) }}%</span>\r\n <button class=\"control-icon-btn\" :disabled=\"combinedLoading || loadError || scale >= maxScale\" @click=\"zoomIn\">\r\n <i class=\"el-icon-zoom-in\" />\r\n </button>\r\n <div class=\"control-divider\" />\r\n <!-- 逻辑修改:加载中禁用重置 -->\r\n <button class=\"control-icon-btn\" :disabled=\"combinedLoading\" title=\"原始尺寸/重置位置\" @click=\"resetZoom\">\r\n <i class=\"el-icon-refresh-right\" />\r\n </button>\r\n <button class=\"control-icon-btn close-btn\" @click=\"closePreview\">\r\n <i class=\"el-icon-close\" />\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- 内容展示区 -->\r\n <div\r\n class=\"video-review-content\"\r\n @wheel.prevent=\"handleWheel\"\r\n @mousedown.self=\"startDrag\"\r\n @click.capture=\"handleCaptureClick\"\r\n >\r\n <!-- 加载状态:逻辑修改,使用 combinedLoading -->\r\n <transition name=\"fade\">\r\n <div v-if=\"combinedLoading && !loadError\" class=\"status-overlay\">\r\n <i class=\"el-icon-loading\" />\r\n <p>视频加载中...</p>\r\n </div>\r\n </transition>\r\n\r\n <!-- 错误状态 -->\r\n <div v-if=\"loadError\" class=\"status-overlay error\">\r\n <i class=\"el-icon-video-camera\" />\r\n <p>视频加载失败</p>\r\n </div>\r\n\r\n <!-- 视频包裹层 -->\r\n <div\r\n v-show=\"!combinedLoading && !loadError\"\r\n class=\"video-transform-wrapper\"\r\n :style=\"videoStyle\"\r\n @mousedown=\"startDrag\"\r\n >\r\n <!-- \r\n 核心修复:增加 :key=\"videoKey\",并配合 v-if 确保可见时才渲染 \r\n -->\r\n <video\r\n v-if=\"visible && videoUrl\"\r\n :key=\"videoKey\"\r\n ref=\"videoPlayer\"\r\n :src=\"videoUrl\"\r\n class=\"main-preview-video\"\r\n autoplay\r\n loop\r\n playsinline\r\n controls\r\n @loadedmetadata=\"onMetadataLoad\"\r\n @error=\"onVideoError\"\r\n @canplay=\"onCanPlay\"\r\n @waiting=\"innerLoading = true\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"video-review-hint\">\r\n <span>鼠标拖拽背景移动,滚轮缩放查看细节</span>\r\n </div>\r\n </div>\r\n </el-dialog>\r\n</template>\r\n\r\n<script>\r\nexport default {\r\n name: \"VideoReview\",\r\n props: {\r\n visible: { type: Boolean, default: false },\r\n videoUrl: { type: String, required: true },\r\n fileName: { type: String, default: \"\" },\r\n width: { type: String, default: \"40%\" },\r\n height: { type: String, default: \"80vh\" },\r\n topMargin: { type: String, default: \"7vh\" },\r\n initialScale: { type: Number, default: 1 },\r\n // 新增逻辑:允许手动控制加载状态\r\n loading: { type: Boolean, default: false }\r\n },\r\n data() {\r\n return {\r\n scale: 1,\r\n minScale: 0.5,\r\n maxScale: 3,\r\n innerLoading: true, // 组件内部加载状态\r\n loadError: false,\r\n videoWidth: 0,\r\n videoHeight: 0,\r\n duration: \"00:00\",\r\n translateX: 0,\r\n translateY: 0,\r\n isDragging: false,\r\n hasMoved: false,\r\n videoKey: Date.now(), // 核心修复:用于强制刷新 video 标签\r\n startMousePos: { x: 0, y: 0 },\r\n mouseStartPos: { x: 0, y: 0 },\r\n };\r\n },\r\n computed: {\r\n dialogVisible: {\r\n get() { return this.visible; },\r\n set(val) { this.$emit(\"update:visible\", val); },\r\n },\r\n // 逻辑合并:外部 prop 或内部加载状态只要有一个在转,就显示 loading\r\n combinedLoading() {\r\n return this.loading || this.innerLoading;\r\n },\r\n videoStyle() {\r\n return {\r\n transform: `translate(${this.translateX}px, ${this.translateY}px) scale(${this.scale})`,\r\n transition: this.isDragging ? \"none\" : \"transform 0.25s cubic-bezier(0.2, 0, 0, 1)\",\r\n };\r\n },\r\n },\r\n watch: {\r\n visible(val) {\r\n if (val) {\r\n this.videoKey = Date.now(); // 每次开启弹窗,赋予新 key 强制重载\r\n this.initStates();\r\n window.addEventListener(\"keydown\", this.handleKeyDown);\r\n } else {\r\n this.pauseVideo();\r\n window.removeEventListener(\"keydown\", this.handleKeyDown);\r\n }\r\n },\r\n videoUrl() {\r\n if (this.visible) {\r\n this.videoKey = Date.now();\r\n this.initStates();\r\n }\r\n }\r\n },\r\n methods: {\r\n initStates() {\r\n this.innerLoading = true;\r\n this.loadError = false;\r\n this.videoWidth = 0;\r\n this.videoHeight = 0;\r\n this.duration = \"00:00\";\r\n this.resetZoom();\r\n \r\n // 显式调用 load() 确保浏览器触发资源请求\r\n this.$nextTick(() => {\r\n if (this.$refs.videoPlayer) {\r\n this.$refs.videoPlayer.load();\r\n }\r\n });\r\n },\r\n onOpened() {\r\n this.resetZoom();\r\n },\r\n onMetadataLoad(e) {\r\n const video = e.target;\r\n this.videoWidth = video.videoWidth;\r\n this.videoHeight = video.videoHeight;\r\n this.duration = this.formatDuration(video.duration);\r\n },\r\n onCanPlay() {\r\n this.innerLoading = false;\r\n this.loadError = false;\r\n },\r\n onVideoError() {\r\n this.innerLoading = false;\r\n this.loadError = true;\r\n },\r\n formatDuration(seconds) {\r\n if (!seconds) return \"00:00\";\r\n const min = Math.floor(seconds / 60);\r\n const sec = Math.floor(seconds % 60);\r\n return `${min.toString().padStart(2, \"0\")}:${sec.toString().padStart(2, \"0\")}`;\r\n },\r\n zoomIn() {\r\n if (this.combinedLoading) return; // 加载中禁止缩放\r\n if (this.scale < this.maxScale)\r\n this.scale = parseFloat((this.scale + 0.2).toFixed(1));\r\n },\r\n zoomOut() {\r\n if (this.combinedLoading) return; // 加载中禁止缩放\r\n if (this.scale > this.minScale)\r\n this.scale = parseFloat((this.scale - 0.2).toFixed(1));\r\n },\r\n resetZoom() {\r\n this.scale = this.initialScale;\r\n this.translateX = 0;\r\n this.translateY = 0;\r\n },\r\n handleWheel(e) {\r\n if (this.combinedLoading) return;\r\n const delta = e.deltaY > 0 ? -0.1 : 0.1;\r\n const newScale = parseFloat((this.scale + delta).toFixed(1));\r\n if (newScale >= this.minScale && newScale <= this.maxScale) {\r\n this.scale = newScale;\r\n }\r\n },\r\n startDrag(e) {\r\n if (this.combinedLoading) return; // 加载中禁止拖拽\r\n if (e.target.tagName === \"VIDEO\" && e.offsetY > e.target.offsetHeight - 50) return;\r\n if (e.button !== 0) return;\r\n this.isDragging = true;\r\n this.hasMoved = false;\r\n this.startMousePos = { x: e.clientX, y: e.clientY };\r\n this.mouseStartPos = {\r\n x: e.clientX - this.translateX,\r\n y: e.clientY - this.translateY,\r\n };\r\n },\r\n onDrag(e) {\r\n if (!this.isDragging) return;\r\n const dx = Math.abs(e.clientX - this.startMousePos.x);\r\n const dy = Math.abs(e.clientY - this.startMousePos.y);\r\n if (dx > 5 || dy > 5) this.hasMoved = true;\r\n this.translateX = e.clientX - this.mouseStartPos.x;\r\n this.translateY = e.clientY - this.mouseStartPos.y;\r\n },\r\n stopDrag() {\r\n this.isDragging = false;\r\n },\r\n handleCaptureClick(e) {\r\n if (this.hasMoved) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n this.hasMoved = false;\r\n }\r\n },\r\n pauseVideo() {\r\n if (this.$refs.videoPlayer) {\r\n this.$refs.videoPlayer.pause();\r\n }\r\n },\r\n handleKeyDown(e) {\r\n if (e.key === \"Escape\") this.closePreview();\r\n if (e.key === \" \" && !this.combinedLoading) {\r\n e.preventDefault();\r\n const v = this.$refs.videoPlayer;\r\n if (v) v.paused ? v.play() : v.pause();\r\n }\r\n },\r\n closePreview() {\r\n this.pauseVideo();\r\n this.dialogVisible = false;\r\n this.$emit(\"close\");\r\n },\r\n },\r\n};\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n::v-deep .modern-video-review-dialog {\r\n background: transparent !important;\r\n box-shadow: none !important;\r\n .el-dialog__header {\r\n display: none !important;\r\n }\r\n .el-dialog__body {\r\n padding: 0 !important;\r\n }\r\n}\r\n\r\n.video-review-container {\r\n display: flex;\r\n flex-direction: column;\r\n background-color: #000; // 视频预览通常用黑色背景,更沉浸\r\n position: relative;\r\n overflow: hidden;\r\n border-radius: 12px;\r\n\r\n .video-review-header {\r\n flex-shrink: 0;\r\n z-index: 100;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 0 24px;\r\n height: 64px;\r\n background: rgba(255, 255, 255, 0.9);\r\n backdrop-filter: blur(10px);\r\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\r\n }\r\n\r\n .file-info {\r\n display: flex;\r\n flex-direction: column;\r\n .file-name {\r\n font-size: 15px;\r\n font-weight: 600;\r\n color: #1a1a1a;\r\n }\r\n .file-size {\r\n font-size: 11px;\r\n color: #909399;\r\n margin-top: 2px;\r\n }\r\n }\r\n\r\n .video-review-controls {\r\n display: flex;\r\n align-items: center;\r\n background: #fff;\r\n padding: 4px;\r\n border-radius: 50px;\r\n box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);\r\n border: 1px solid #ebeef5;\r\n\r\n .zoom-display {\r\n font-size: 13px;\r\n font-weight: 600;\r\n width: 50px;\r\n text-align: center;\r\n color: #303133;\r\n font-variant-numeric: tabular-nums;\r\n }\r\n\r\n .control-divider {\r\n width: 1px;\r\n height: 16px;\r\n background: #eee;\r\n margin: 0 8px;\r\n }\r\n }\r\n\r\n .control-icon-btn {\r\n width: 34px;\r\n height: 34px;\r\n border: none;\r\n background: transparent;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n font-size: 18px;\r\n color: #606266;\r\n transition: all 0.2s;\r\n &:hover:not(:disabled) {\r\n background-color: #f2f6fc;\r\n color: #409eff;\r\n }\r\n &:disabled {\r\n color: #dcdfe6;\r\n cursor: not-allowed;\r\n }\r\n &.close-btn:hover {\r\n background-color: #fef0f0;\r\n color: #f56c6c;\r\n }\r\n }\r\n\r\n .video-review-content {\r\n flex: 1;\r\n position: relative;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n overflow: hidden;\r\n height: 0;\r\n // position: relative;\r\n cursor: grab;\r\n &:active {\r\n cursor: grabbing;\r\n }\r\n }\r\n\r\n .video-transform-wrapper {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n will-change: transform;\r\n width: 100%;\r\n height: 100%;\r\n }\r\n\r\n .main-preview-video {\r\n max-width: 100%;\r\n height: 100%;\r\n object-fit: contain; /* 确保比例正确,不裁剪 */\r\n outline: none;\r\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);\r\n background: #000;\r\n }\r\n\r\n .status-overlay {\r\n position: absolute;\r\n z-index: 10;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n i {\r\n font-size: 40px;\r\n color: #409eff;\r\n margin-bottom: 8px;\r\n }\r\n p {\r\n font-size: 14px;\r\n color: #eee;\r\n margin: 0;\r\n }\r\n &.error {\r\n i,\r\n p {\r\n color: #f56c6c;\r\n }\r\n }\r\n }\r\n\r\n .video-review-hint {\r\n position: absolute;\r\n bottom: 80px; // 避开视频控制条\r\n left: 50%;\r\n transform: translateX(-50%);\r\n background: rgba(0, 0, 0, 0.5);\r\n color: #fff;\r\n padding: 6px 16px;\r\n border-radius: 20px;\r\n font-size: 12px;\r\n pointer-events: none;\r\n opacity: 0;\r\n transition: opacity 0.3s;\r\n z-index: 10;\r\n }\r\n &:hover .video-review-hint {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n/* 渐变过渡动画 */\r\n.fade-enter-active,\r\n.fade-leave-active {\r\n transition: opacity 0.3s;\r\n}\r\n.fade-enter,\r\n.fade-leave-to {\r\n opacity: 0;\r\n}\r\n</style>\r\n","import mod from \"-!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"; export default mod; export * from \"-!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=script&lang=js\"","import { render, staticRenderFns } from \"./index.vue?vue&type=template&id=3f692c5e&scoped=true\"\nimport script from \"./index.vue?vue&type=script&lang=js\"\nexport * from \"./index.vue?vue&type=script&lang=js\"\nimport style0 from \"./index.vue?vue&type=style&index=0&id=3f692c5e&prod&lang=scss&scoped=true\"\n\n\n/* normalize component */\nimport normalizer from \"!../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"3f692c5e\",\n null\n \n)\n\nexport default component.exports","import { setAxiosInstance } from './components/FileUpload/api';\r\n\r\nimport Upload from './components/FileUpload';\r\nimport DialogVideoReview from './components/VideoPreviewDialog';\r\n\r\n// import MyButton from './components/Button';\r\n\r\nconst components = [\r\n Upload,\r\n DialogVideoReview\r\n];\r\n\r\n// 整个库的 install\r\nconst install = function (Vue, options = {}) {\r\n components.forEach(component => {\r\n // 自动读取组件里的 name 属性作为组件名\r\n Vue.component(component.name, component);\r\n });\r\n\r\n // 将 axios 实例传入 api 模块\r\n setAxiosInstance(options.axios);\r\n};\r\n\r\n// 支持用 <script> 引入\r\nif (typeof window !== 'undefined' && window.Vue) {\r\n install(window.Vue);\r\n}\r\n\r\n// 全量导出,也可以解构导出\r\nexport default { install };\r\n// 按需引入\r\nexport {\r\n Upload,\r\n // MyButton\r\n};","import './setPublicPath'\nimport mod from '~entry'\nexport default mod\nexport * from '~entry'\n","export * from \"-!../../../node_modules/mini-css-extract-plugin/dist/loader.js??ref--8-oneOf-1-0!../../../node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../node_modules/postcss-loader/src/index.js??ref--8-oneOf-1-2!../../../node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../node_modules/vue-loader/lib/index.js??vue-loader-options!./index.vue?vue&type=style&index=0&id=7af8297e&prod&scoped=true&lang=scss\""],"sourceRoot":""}
|