naive-upload
Version:
<p align="left"> <a href="https://www.npmjs.org/package/naive-upload"> <img src="https://img.shields.io/npm/v/naive-upload.svg"> </a> <a href="https://bundlephobia.com/package/naive-upload@latest"> <img src="https://img.shields.io/bundl
1 lines • 295 kB
Source Map (JSON)
{"version":3,"file":"naive-upload.min.cjs","sources":["../../../src/Model/RunMode.ts","../../../src/Model/Layout.ts","../../../src/Model/RGBAColor.ts","../../../src/Model/Settings.ts","../../../src/Piece/FileInput.vue3.vue","../../../src/Model/FileType.ts","../../../src/Piece/SelectedFileInfo.vue3.vue","../../../src/Layout/Card/index.vue3.vue","../../../src/Layout/Detailedly/index.vue3.vue","../../../src/Layout/index.vue3.vue","../../../src/Layout/Card/info.vue3.vue","../../../src/Layout/Detailedly/info.vue3.vue","../../../src/Layout/info.vue3.vue","../../../src/Piece/SingleUpload.vue3.vue","../../../src/Piece/DropFileInput.vue3.vue","../../../src/Extention/DraggingHelper.ts","../../../src/Piece/MultipleUpload.vue3.vue","../../../src/Extention/UploadError.ts","../../../src/Model/RawFile.ts","../../../src/Extention/FileTypeHelper.ts","../../../src/Model/SelectedFile.ts","../../../src/Extention/SimpleGuid.ts","../../../src/Extention/FileSizeHelper.ts","../../../src/Model/ChunkFile.ts","../../../src/Extention/HashWorkerScript.js","../../../src/Extention/FileReadHelper.ts","../../../src/Model/HashWorkerMessageType.ts","../../../src/Extention/HashHelper.ts","../../../src/Model/UploadWorkerMessageType.ts","../../../src/Model/PreUploadChunkFileState.ts","../../../src/Extention/UploadWorkerScript.ts","../../../src/Extention/UploadHelper.ts","../../../src/Core/NaiveUpload.ts","../../../src/index.vue3.vue","../../../src/Extention/DefaultApiService.ts","../../../src/export.vue3.ts"],"sourcesContent":["/**\r\n * 上传组件运行模式\r\n *\r\n * @author LCTR\r\n * @date 2022-06-24\r\n */\r\nexport enum RunMode {\r\n /**\r\n * 添加文件后会自动校验,自动上传\r\n */\r\n 全自动 = 'AT',\r\n\r\n /**\r\n * 添加文件后需要主动调用校验方法以及上传方法\r\n */\r\n 手动挡 = 'MT',\r\n\r\n /**\r\n * 添加文件后会自动校验,但需要主动调用上传方法\r\n */\r\n 半自动 = 'AMT'\r\n}","/**\r\n * 上传组件布局\r\n *\r\n * @author LCTR\r\n * @date 2022-06-24\r\n */\r\nexport enum Layout {\r\n 卡片 = 'Card',\r\n 清单 = 'Detailedly'\r\n}","/**\r\n * 有透明度的RGB颜色值\r\n *\r\n * @author LCTR\r\n * @date 2022-12-05\r\n */\r\nexport default class RGBAColor {\r\n /**\r\n * @param r 红色值\r\n * @param g 绿色值\r\n * @param b 蓝色值\r\n * @param a 色彩空间\r\n */\r\n constructor(r: number, g: number, b: number, a: number) {\r\n this.r = r;\r\n this.g = g;\r\n this.b = b;\r\n this.a = a;\r\n }\r\n\r\n /**\r\n * 红色值\r\n */\r\n r: number;\r\n\r\n /**\r\n * 绿色值\r\n */\r\n g: number;\r\n\r\n /**\r\n * 蓝色值\r\n */\r\n b: number;\r\n\r\n /**\r\n * 色彩空间\r\n */\r\n a: number;\r\n\r\n /**\r\n * 序列化\r\n */\r\n toString: (this: RGBAColor) => string = () => `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a})`;\r\n\r\n /**\r\n * @param rgba {r 红色值, g 绿色值, b 蓝色值, a 色彩空间}\r\n */\r\n public static convertFrom(rgba: { r: number, g: number, b: number, a: number }): RGBAColor {\r\n return new RGBAColor(rgba.r, rgba.g, rgba.b, rgba.a);\r\n }\r\n}","import { RunMode } from \"../Model/RunMode\";\r\nimport { Layout } from \"../Model/Layout\";\r\nimport RGBAColor from \"./RGBAColor\";\r\n\r\n\r\n/**\r\n * 文件上传组件设置\r\n *\r\n * @author LCTR\r\n * @date 2022-06-24\r\n */\r\nexport default class Settings {\r\n /**\r\n * 设置\r\n *\r\n * @param action 此方法的参数为当前示例\r\n */\r\n public readonly build: (action: (model: Settings) => void) => Settings = (action) => {\r\n action(this);\r\n return this;\r\n };\r\n\r\n /**\r\n * 设置\r\n *\r\n * @param action 此方法的参数为当前示例\r\n */\r\n public readonly setup: (this: Settings, action: (model: Settings) => void) => Settings = (action) => {\r\n action(this);\r\n return this;\r\n };\r\n\r\n /**\r\n * 默认设置\r\n */\r\n public static default: () => Settings = () => new Settings();\r\n\r\n /**\r\n * 默认设置\r\n */\r\n public static defaultWithConfigCode: (configCode: string) => Settings = (configCode: string) => {\r\n return new Settings().setup(x => x.configCode = configCode);\r\n }\r\n\r\n /**\r\n * 文件上传配置编码\r\n *\r\n * @默认值 default\r\n */\r\n configCode: string = 'default';\r\n\r\n /**\r\n * 文件上传并发数\r\n *\r\n * @默认值 3\r\n */\r\n concurrentFile: number = 3;\r\n\r\n /**\r\n * 分片文件上传并发数\r\n *\r\n * @默认值 3\r\n */\r\n concurrentChunkFile: number = 3;\r\n\r\n /**\r\n * 小贴士\r\n *\r\n * @默认值 单击或拖动文件到此区域即可上传\r\n */\r\n tip: string = '单击或拖动文件到此区域即可上传';\r\n\r\n /**\r\n * 布局\r\n *\r\n * @默认值 Layout.卡片\r\n */\r\n layout: Layout = Layout.卡片;\r\n\r\n /**\r\n * 运行模式\r\n *\r\n * @默认值 RunMode.全自动\r\n */\r\n runMode: RunMode = RunMode.全自动;\r\n\r\n /**\r\n * 是否启用文件切片\r\n *\r\n * @默认值 true\r\n */\r\n enableChunk: boolean = true;\r\n\r\n /**\r\n * 切片规格(文件字节数)\r\n *\r\n * @默认值 2097152(即为2 * 1024 * 1024 = 2MB)\r\n */\r\n chunkSize: number = 2097152;\r\n\r\n /**\r\n * 发生错误时的重试次数\r\n *\r\n * @默认值 3\r\n */\r\n retry: number = 3;\r\n\r\n /**\r\n * 是否启用Web Worker\r\n * <p>在浏览器不支持时此设置不会生效</P>\r\n *\r\n * @默认值 true\r\n */\r\n enableWorker: boolean = true;\r\n\r\n /**\r\n * 只读模式\r\n *\r\n * @默认值 false\r\n */\r\n readonly: boolean = false;\r\n\r\n /**\r\n * 调试模式\r\n */\r\n debug: boolean = false;\r\n\r\n /**\r\n * 显示错误信息\r\n */\r\n alertErrorInfo: boolean = false;\r\n\r\n /**\r\n * 启用拖动排序功能\r\n *\r\n * @默认值 true\r\n */\r\n enableDrag: boolean = true;\r\n\r\n /**\r\n * 校验状态的颜色\r\n * \r\n * @默认值 new RGBAColor(255, 235, 59, 0.5)\r\n */\r\n statusCheckingColor: RGBAColor = new RGBAColor(255, 235, 59, 0.5);\r\n\r\n /**\r\n * 上传状态的颜色\r\n * \r\n * @默认值 new RGBAColor(144, 206, 255, 0.5)\r\n */\r\n statusUploadingColor: RGBAColor = new RGBAColor(144, 206, 255, 0.5);\r\n\r\n /**\r\n * 暂停状态的颜色\r\n * \r\n * @默认值 new RGBAColor(158, 158, 158, 0.5)\r\n */\r\n statusPausedColor: RGBAColor = new RGBAColor(158, 158, 158, 0.5);\r\n\r\n /**\r\n * 暂停状态副标题的颜色\r\n * \r\n * @默认值 new RGBAColor(244, 154, 3, 0.5)\r\n */\r\n statusPausedSubColor: RGBAColor = new RGBAColor(244, 154, 3, 0.5);\r\n\r\n /**\r\n * 完成状态的颜色\r\n * \r\n * @默认值 new RGBAColor(76, 175, 80, 0.1)\r\n */\r\n statusDoneColor: RGBAColor = new RGBAColor(76, 175, 80, 0.1);\r\n\r\n /**\r\n * 完成状态副标题的颜色\r\n * \r\n * @默认值 new RGBAColor(3, 169, 244, 0.5)\r\n */\r\n statusDoneSubColor: RGBAColor = new RGBAColor(3, 169, 244, 0.5);\r\n\r\n /**\r\n * 错误状态的颜色\r\n * \r\n * @默认值 new RGBAColor(255, 0, 30, 0.35)\r\n */\r\n statusErrorColor: RGBAColor = new RGBAColor(255, 0, 30, 0.35);\r\n\r\n /**\r\n * 错误状态副标题的颜色\r\n * \r\n * @默认值 new RGBAColor(232, 31, 31, 0.5)\r\n */\r\n statusErrorSubColor: RGBAColor = new RGBAColor(232, 31, 31, 0.5);\r\n\r\n /**\r\n * 准备拖动时的动画颜色\r\n * \r\n * @默认值 new RGBAColor(255, 152, 0, 0.8)\r\n */\r\n dragReadyColor: RGBAColor = new RGBAColor(255, 152, 0, 0.8);\r\n\r\n /**\r\n * 拖动时的动画颜色\r\n * \r\n * @默认值 new RGBAColor(255, 152, 0, 0.5)\r\n */\r\n dragMovingColor: RGBAColor = new RGBAColor(255, 152, 0, 0.5);\r\n\r\n /**\r\n * 结束拖动时的动画颜色\r\n * \r\n * @默认值 new RGBAColor(255, 87, 34, 0.8)\r\n */\r\n dragOverColor: RGBAColor = new RGBAColor(255, 87, 34, 0.8);\r\n\r\n /**\r\n * 准备开始拖动的时间(单位ms)\r\n * \r\n * @默认值 1500\r\n */\r\n dragPreparationTime: number = 800;\r\n\r\n /**\r\n * 拖动时变换位置的等待时间(单位ms)\r\n * \r\n * @默认值 1300\r\n */\r\n dragChangePositionTime: number = 1000;\r\n\r\n /**\r\n * 是否为移动端\r\n * \r\n * @默认值 自动根据浏览器信息判断\r\n */\r\n isMobile: boolean = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i.test(\r\n navigator.userAgent\r\n );\r\n}","<template>\r\n <div\r\n class=\"upload-btn\"\r\n v-on:click=\"chosingFile\"\r\n :title=\"upload.getSettings().tip\"\r\n >\r\n <div @click.stop=\"() => {}\">\r\n <input\r\n type=\"file\"\r\n :multiple=\"upload.getConfig().upperLimit > 1\"\r\n :ref=\"setFileInputRef\"\r\n :accept=\"upload.getAllowedTypes()\"\r\n v-on:change=\"choseFile\"\r\n />\r\n </div>\r\n <div class=\"upload-box-content\">\r\n <slot></slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ComponentPublicInstance, inject, reactive } from \"vue-demi\";\r\nimport NaiveUpload from \"../Core/NaiveUpload\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 渲染数据\r\n */\r\nlet renderData = reactive({});\r\n\r\n// 文件选择框引用对象\r\nlet fileInputRef: HTMLInputElement;\r\n\r\n/**\r\n * 设置文件选择框引用对象\r\n *\r\n * @param el 引用对象\r\n */\r\nconst setFileInputRef = (el: Element | ComponentPublicInstance | null) => {\r\n if (el) fileInputRef = el as HTMLInputElement;\r\n};\r\n\r\n/**\r\n * 选择文件\r\n *\r\n * @param e\r\n */\r\nconst chosingFile = (e: MouseEvent) => {\r\n if (upload.limited()) return;\r\n\r\n //隐式触发文件选择事件\r\n fileInputRef?.click();\r\n};\r\n\r\n/**\r\n * 已选择文件\r\n *\r\n * @param {any} e\r\n */\r\nconst choseFile = (e: Event) => {\r\n if (fileInputRef && fileInputRef.files)\r\n for (let i = 0; i < fileInputRef.files.length; i++) {\r\n upload.append(fileInputRef.files[i]);\r\n }\r\n\r\n //清空\r\n if (fileInputRef) fileInputRef.value = \"\";\r\n};\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n upload.getSettings().debug\r\n ? console.debug(\"Piece: File Input Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>","/**\r\n * 文件类型\r\n *\r\n * @author LCTR\r\n * @date 2022-09-21\r\n */\r\nexport enum FileType {\r\n 电子文档 = '电子文档',\r\n 电子表格 = '电子表格',\r\n 文本文件 = '文本文件',\r\n 图片 = '图片',\r\n 音频 = '音频',\r\n 视频 = '视频',\r\n 压缩包 = '压缩包',\r\n 未知 = '未知',\r\n 外链资源 = '外链资源'\r\n}","<template>\r\n <div :class=\"renderData.container.style()\" :style=\"renderData.container.styleVar()\"\r\n :title=\"renderData.container.info()\" v-on:mouseenter=\"mouseEnter\" v-on:mouseleave=\"mouseLeave\"\r\n v-on:mousedown=\"mouseDown\" v-on:mouseup=\"mouseUp\" v-on:touchstart=\"mouseDown\" v-on:touchend=\"mouseUp\"\r\n v-on:touchcancel=\"mouseUp\" :ref=\"setContainerRef\">\r\n <div v-if=\"!props.selectedFile.canceled\" class=\"item-body\">\r\n <div class=\"item-image\">\r\n <img :src=\"props.selectedFile.thumbnail\" loading=\"lazy\" :alt=\"props.selectedFile.fullname()\" />\r\n </div>\r\n\r\n <span class=\"item-tools\" v-if=\"renderData.tools.show()\">\r\n <span class=\"upload-icon icon-rename\" title=\"重命名\" v-on:click=\"rename()\"\r\n v-if=\"renderData.rename.enable() && !upload.getSettings().readonly\"></span>\r\n <span class=\"upload-icon icon-view\" title=\"查看\" v-if=\"renderData.view.enable()\" v-on:click=\"view()\"></span>\r\n <span class=\"upload-icon icon-download\" title=\"保存\" v-if=\"renderData.save.enable()\" v-on:click=\"save()\"></span>\r\n <span class=\"upload-icon icon-remove\" title=\"删除\" v-on:click=\"remove()\"\r\n v-if=\"!upload.getSettings().readonly\"></span>\r\n </span>\r\n\r\n <slot :selectedFile=\"props.selectedFile\" :rename=\"renderData.rename\" :funs=\"{\r\n setRenameInputRef: setRenameInputRef,\r\n renameKeydown: renameKeydown,\r\n renameDone: renameDone,\r\n }\" :loading=\"renderData.loading\"></slot>\r\n\r\n <div v-if=\"props.selectedFile.paused\" class=\"item-sub sub-paused\">\r\n 暂停\r\n </div>\r\n <div v-if=\"props.selectedFile.done && !upload.getSettings().readonly\" class=\"item-sub sub-done\">\r\n 完成\r\n </div>\r\n <div v-if=\"props.selectedFile.error\" class=\"item-sub sub-error\">错误</div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ComponentPublicInstance,\r\n getCurrentInstance,\r\n inject,\r\n reactive,\r\n} from \"vue-demi\";\r\nimport NaiveUpload from \"../Core/NaiveUpload\";\r\nimport SelectedFile from \"../Model/SelectedFile\";\r\nimport { FileType } from \"../Model/FileType\";\r\n\r\n// 获取vue实例\r\nconst { proxy } = getCurrentInstance() as any;\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 渲染数据\r\n */\r\nlet renderData = reactive({\r\n /**\r\n * 鼠标悬浮\r\n */\r\n hover: false,\r\n\r\n /**\r\n * 容器\r\n */\r\n container: {\r\n /**\r\n * 样式\r\n */\r\n style: (): string =>\r\n `item-container ${props.selectedFile.done && !upload.getSettings().readonly\r\n ? \" item-done\"\r\n : \"\"\r\n } ${props.selectedFile.error ? \" item-error\" : \"\"} ${renderData.hover &&\r\n !renderData.rename.active &&\r\n !props.selectedFile.checking &&\r\n !props.selectedFile.uploading &&\r\n !props.readyDrag &&\r\n !props.startDrag\r\n ? \" item-hover\"\r\n : \"\"\r\n } ${props.selectedFile.checking ? \" item-checking\" : \"\"} ${props.selectedFile.uploading ? \" item-uploading\" : \"\"\r\n } ${props.selectedFile.canceled ? \" item-canceled\" : \"\"} ${props.selectedFile.paused ? \" item-paused\" : \"\"\r\n } ${props.readyDrag ? \" item-ready-drag\" : \"\"} ${props.dragging ? \" item-dragging\" : \"\"\r\n } ${props.dragover ? \" item-drag-over\" : \"\"}`,\r\n /**\r\n * 容器样式中的变量\r\n */\r\n styleVar: (): Record<string, string> => {\r\n return {\r\n \"--statusCheckingColor\": upload\r\n .getSettings()\r\n .statusCheckingColor.toString(),\r\n \"--statusUploadingColor\": upload\r\n .getSettings()\r\n .statusUploadingColor.toString(),\r\n \"--statusPausedColor\": upload\r\n .getSettings()\r\n .statusPausedColor.toString(),\r\n \"--statusPausedSubColor\": upload\r\n .getSettings()\r\n .statusPausedSubColor.toString(),\r\n \"--statusDoneColor\": upload.getSettings().statusDoneColor.toString(),\r\n \"--statusDoneSubColor\": upload\r\n .getSettings()\r\n .statusDoneSubColor.toString(),\r\n \"--statusErrorColor\": upload.getSettings().statusErrorColor.toString(),\r\n \"--statusErrorSubColor\": upload\r\n .getSettings()\r\n .statusErrorSubColor.toString(),\r\n\r\n \"--dragPreparationTime\": `${(\r\n upload.getSettings().dragPreparationTime / 1000\r\n ).toFixed(2)}s`,\r\n \"--dragChangePositionTime\": `${(\r\n upload.getSettings().dragChangePositionTime / 1000\r\n ).toFixed(2)}s`,\r\n \"--dragReadyColor\": upload.getSettings().dragReadyColor.toString(),\r\n \"--dragMovingColor\": upload.getSettings().dragMovingColor.toString(),\r\n \"--dragOverColor\": upload.getSettings().dragOverColor.toString(),\r\n };\r\n },\r\n\r\n /**\r\n * 信息\r\n */\r\n info: () =>\r\n `${props.selectedFile.done ? \"上传成功\" : \"\"} ${props.selectedFile.error ? props.selectedFile.errorMessage : \"\"\r\n } ${props.selectedFile.paused ? \"已暂停\" : \"\"}`,\r\n },\r\n\r\n /**\r\n * 加载层\r\n */\r\n loading: {\r\n /**\r\n * 显示/隐藏\r\n */\r\n show: () =>\r\n !renderData.rename.active &&\r\n (props.selectedFile.checking || props.selectedFile.uploading),\r\n\r\n /**\r\n * 信息\r\n */\r\n info: () =>\r\n `${props.selectedFile.checking\r\n ? \"扫描中...\" + props.selectedFile.percent + \"%\"\r\n : \"\"\r\n } ${props.selectedFile.uploading\r\n ? \"上传中...\" + props.selectedFile.percent + \"%\"\r\n : \"\"\r\n }`,\r\n },\r\n\r\n /**\r\n * 工具栏\r\n */\r\n tools: {\r\n /**\r\n * 显示/隐藏\r\n */\r\n show: () =>\r\n renderData.hover &&\r\n props.dragging === false &&\r\n !renderData.rename.active &&\r\n !props.selectedFile.checking &&\r\n !props.selectedFile.uploading,\r\n },\r\n\r\n /**\r\n * 重命名\r\n */\r\n rename: {\r\n /**\r\n * 启用/禁用\r\n */\r\n enable: () => !props.selectedFile.uploading,\r\n\r\n /**\r\n * 正在重命名\r\n */\r\n active: false,\r\n\r\n /**\r\n * 值\r\n */\r\n value: \"\",\r\n },\r\n\r\n /**\r\n * 浏览\r\n */\r\n view: {\r\n /**\r\n * 启用/禁用\r\n */\r\n enable: () => {\r\n switch (props.selectedFile.fileType) {\r\n case FileType.图片:\r\n case FileType.音频:\r\n return props.selectedFile.extensionLower !== \".flac\";\r\n case FileType.视频:\r\n return true;\r\n case FileType.文本文件:\r\n return true;\r\n case FileType.电子文档:\r\n return (\r\n props.selectedFile.extensionLower === \".pdf\" ||\r\n props.selectedFile.extensionLower === \".doc\" ||\r\n props.selectedFile.extensionLower === \".docx\"\r\n );\r\n default:\r\n return false;\r\n }\r\n },\r\n },\r\n\r\n /**\r\n * 保存\r\n */\r\n save: {\r\n /**\r\n * 启用/禁用\r\n */\r\n enable: () => {\r\n return true;\r\n },\r\n },\r\n});\r\n\r\n/**\r\n * 组件属性\r\n */\r\nconst props = defineProps<{\r\n key?: number;\r\n\r\n /**\r\n * 选择的文件\r\n */\r\n selectedFile: SelectedFile;\r\n\r\n /**\r\n * 准备拖动\r\n */\r\n readyDrag?: boolean;\r\n\r\n /**\r\n * 拖动操作已开始\r\n */\r\n startDrag?: boolean;\r\n\r\n /**\r\n * 正在拖动\r\n */\r\n dragging?: boolean;\r\n\r\n /**\r\n * 和拖动元素重叠\r\n */\r\n dragover?: boolean;\r\n}>();\r\n\r\n/**\r\n * 组件自定义事件\r\n */\r\nconst emit = defineEmits<{\r\n /**\r\n * 设置容器引用对象\r\n *\r\n * @param e\r\n * @param el 容器引用对象\r\n */\r\n (e: \"setContainerRef\", el: HTMLDivElement): void;\r\n\r\n /**\r\n * 按下鼠标的事件\r\n *\r\n * @param e\r\n * @param event\r\n */\r\n (e: \"mouseDown\", event: MouseEvent): void;\r\n\r\n /**\r\n * 松开鼠标的事件\r\n *\r\n * @param e\r\n * @param event\r\n */\r\n (e: \"mouseUp\", event: MouseEvent): void;\r\n\r\n /**\r\n * 鼠标进入的事件\r\n *\r\n * @param e\r\n * @param event\r\n */\r\n (e: \"mouseEnter\", event: MouseEvent): boolean;\r\n\r\n /**\r\n * 鼠标离开的事件\r\n *\r\n * @param e\r\n * @param event\r\n */\r\n (e: \"mouseLeave\", event: MouseEvent): void;\r\n}>();\r\n\r\n/**\r\n * 文件重命名输入框\r\n */\r\nlet renameInputRef: HTMLInputElement;\r\n\r\n/**\r\n * 设置文件选择框引用对象\r\n *\r\n * @param el 引用对象\r\n */\r\nconst setContainerRef = (el: Element | ComponentPublicInstance | null) => {\r\n el ? emit(\"setContainerRef\", el as HTMLDivElement) : !1;\r\n};\r\n\r\n/**\r\n * 设置重命名输入框引用对象\r\n *\r\n * @param el 引用对象\r\n */\r\nconst setRenameInputRef = (el: Element | ComponentPublicInstance | null) => {\r\n if (el) renameInputRef = el as HTMLInputElement;\r\n};\r\n\r\n/**\r\n * 鼠标进入的事件\r\n *\r\n * @param event\r\n */\r\nconst mouseEnter = (event: MouseEvent) => {\r\n if (props.readyDrag || props.startDrag) {\r\n emit(\"mouseEnter\", event);\r\n renderData.hover = false;\r\n } else renderData.hover = true;\r\n};\r\n\r\n/**\r\n * 鼠标离开的事件\r\n *\r\n * @param event\r\n */\r\nconst mouseLeave = (event: MouseEvent) => {\r\n if (props.readyDrag || props.startDrag) emit(\"mouseLeave\", event);\r\n\r\n renderData.hover = false;\r\n};\r\n\r\n/**\r\n * 按下鼠标的事件\r\n *\r\n * @param event\r\n */\r\nconst mouseDown = (event: MouseEvent) => {\r\n emit(\"mouseDown\", event);\r\n};\r\n\r\n/**\r\n * 松开鼠标的事件\r\n *\r\n * @param event\r\n */\r\nconst mouseUp = (event: MouseEvent) => {\r\n emit(\"mouseUp\", event);\r\n};\r\n\r\n/**\r\n * 重命名\r\n */\r\nconst rename = () => {\r\n renderData.rename.active = true;\r\n\r\n proxy.$nextTick(() => {\r\n if (renameInputRef) renameInputRef.focus();\r\n });\r\n};\r\n\r\n/**\r\n * 确认重命名\r\n *\r\n * @param {any} event\r\n */\r\nconst renameKeydown = (event: KeyboardEvent) => {\r\n if (event.key == \"Enter\") {\r\n renameDone();\r\n }\r\n};\r\n\r\n/**\r\n * 重命名结束\r\n */\r\nconst renameDone = () => {\r\n upload\r\n .rename(props.selectedFile.token!, renderData.rename.value)\r\n .then(() => {\r\n renderData.rename.active = false;\r\n })\r\n .catch(() => {\r\n renderData.rename.active = false;\r\n });\r\n};\r\n\r\n/**\r\n * 查看\r\n */\r\nconst view = () => {\r\n const file = upload.getRawFile(props.selectedFile);\r\n const bodyStyle =\r\n \"margin:0px;text-align: center;display: flex;flex-direction: row;justify-content: center;align-items: center\";\r\n\r\n switch (props.selectedFile.fileType) {\r\n case FileType.图片:\r\n let winImage = window.open();\r\n winImage?.document.write(\r\n `<head><title>${props.selectedFile.fullname()}</title></head><body style=\"${bodyStyle};background-color: black;\"><img style=\"max-width: 100%;max-height: 100%;\" src=\"${file.objectURL\r\n }\" alt=\"${props.selectedFile.fullname()}\"></body>`\r\n );\r\n break;\r\n case FileType.音频:\r\n if (props.selectedFile.extensionLower === \".flac\") return;\r\n\r\n let winAudio = window.open();\r\n winAudio?.document.write(\r\n `<head><title>${props.selectedFile.fullname()}</title></head><body style=\"${bodyStyle};background-color: black;\"><audio style=\"max-width: 100%;max-height: 100%;\" src=\"${file.objectURL\r\n }\" controls=\"controls\">抱歉, 暂不支持</audio></body>`\r\n );\r\n break;\r\n case FileType.视频:\r\n let winVideo = window.open();\r\n winVideo?.document.write(\r\n `<head><title>${props.selectedFile.fullname()}</title></head><body style=\"${bodyStyle};background-color: black;\"><video style=\"max-width: 100%;max-height: 100%;\" src=\"${file.objectURL\r\n }\" controls=\"controls\">抱歉, 暂不支持</video></body>`\r\n );\r\n break;\r\n default:\r\n let win = window.open();\r\n win?.document.write(\r\n `<head><title>${props.selectedFile.fullname()}</title></head><body style=\"${bodyStyle};\"><object style=\"max-width: 100%;max-height: 100%;\" data=\"${file.objectURL\r\n }\" type=\"${props.selectedFile.extensionLower === \".txt\"\r\n ? \"text/plain\"\r\n : props.selectedFile.extensionLower === \".pdf\"\r\n ? \"application/pdf\"\r\n : \"application/octet-stream\"\r\n }\" width=\"100%\" height=\"100%\"><iframe src=\"${file.objectURL\r\n }\" width=\"100%\" height=\"100%\" ></iframe></object></body>`\r\n );\r\n break;\r\n }\r\n};\r\n\r\n/**\r\n * 保存\r\n */\r\nconst save = () => {\r\n const file = upload.getRawFile(props.selectedFile);\r\n\r\n const a = document.createElement(\"a\");\r\n a.style.display = \"none\";\r\n a.href = upload.getDownloadUrl(props.selectedFile)!;\r\n if (file.file) a.download = props.selectedFile.fullname();\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n};\r\n\r\n/**\r\n * 删除\r\n */\r\nconst remove = () => {\r\n upload.remove(props.selectedFile.token!);\r\n};\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n upload.getSettings().debug\r\n ? console.debug(\"Piece: Selected File Info Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>\r\n","<template>\r\n <div class=\"upload-container independent\">\r\n <slot name=\"uploadContainer\"></slot>\r\n\r\n <div class=\"upload-list\">\r\n <slot name=\"listContainer\"></slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from \"vue-demi\";\r\nimport NaiveUpload from \"../../Core/NaiveUpload\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n upload.getSettings().debug\r\n ? console.debug(\"Layout: Card Index Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>\r\n\r\n<style scoped lang=\"scss\" type=\"text/scss\">\r\n@import \"index.vue3.scss\";\r\n</style>","<template>\r\n <div class=\"upload-container independent\">\r\n <slot name=\"uploadContainer\"></slot>\r\n\r\n <div class=\"upload-list\">\r\n <slot name=\"listContainer\"></slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from \"vue-demi\";\r\nimport NaiveUpload from \"../../Core/NaiveUpload\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n upload.getSettings().debug\r\n ? console.debug(\"Layout: Detailedly Index Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>\r\n\r\n<style scoped lang=\"scss\" type=\"text/scss\">\r\n@import \"index.vue3.scss\";\r\n</style>","<template>\r\n <div v-if=\"!renderData.loading\">\r\n <component :is=\"renderData.currentThemeIndex\">\r\n <template #uploadContainer>\r\n <slot name=\"uploadContainer\"></slot>\r\n </template>\r\n\r\n <template #listContainer>\r\n <slot name=\"listContainer\"></slot>\r\n </template>\r\n </component>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject, reactive, ShallowRef, shallowRef } from \"vue-demi\";\r\nimport NaiveUpload from \"../Core/NaiveUpload\";\r\nimport Card from \"../Layout/Card/index.vue3.vue\";\r\nimport Detailedly from \"../Layout/Detailedly/index.vue3.vue\";\r\nimport { Layout } from \"../Model/Layout\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 渲染数据\r\n */\r\nlet renderData = reactive({\r\n /**\r\n * 加载状态\r\n */\r\n loading: true,\r\n\r\n /**\r\n * 当前的主题组件\r\n */\r\n currentThemeIndex: null as ShallowRef<any> | null,\r\n});\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n const changLayout = (layout?: Layout) => {\r\n renderData.loading = true;\r\n switch (layout) {\r\n case Layout.卡片:\r\n renderData.currentThemeIndex = shallowRef(Card);\r\n break;\r\n case Layout.清单:\r\n renderData.currentThemeIndex = shallowRef(Detailedly);\r\n break;\r\n }\r\n renderData.loading = false;\r\n\r\n upload.getSettings().debug\r\n ? console.debug(\"Layout: Index Component(vue3) 已变更\")\r\n : !1;\r\n };\r\n\r\n //注册布局变更事件\r\n upload.registerLayoutChanged(changLayout);\r\n\r\n //初始化布局\r\n changLayout(upload.getSettings().layout);\r\n\r\n upload.getSettings().debug\r\n ? console.debug(\"Layout: Index Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>\r\n","<template>\r\n <div class=\"item-info\">\r\n <span\r\n class=\"single-text-omitted item-name\"\r\n :title=\"\r\n props.slotProps.selectedFile.fileType +\r\n '\\r\\n' +\r\n props.slotProps.selectedFile.size +\r\n '\\r\\n' +\r\n props.slotProps.selectedFile.fullname()\r\n \"\r\n v-html=\"props.slotProps.selectedFile.fullname()\"\r\n v-if=\"!props.slotProps.rename.active\"\r\n ></span>\r\n <input\r\n class=\"item-rename-input\"\r\n type=\"text\"\r\n v-if=\"props.slotProps.rename.active\"\r\n v-model=\"props.slotProps.rename.value\"\r\n :ref=\"props.slotProps.funs.setRenameInputRef\"\r\n v-on:keydown=\"props.slotProps.funs.renameKeydown($event)\"\r\n v-on:blur=\"props.slotProps.funs.renameDone()\"\r\n />\r\n </div>\r\n\r\n <div\r\n class=\"item-loading\"\r\n v-if=\"props.slotProps.loading.show()\"\r\n :style=\"renderData.lodingStyle()\"\r\n :title=\"props.slotProps.loading.info()\"\r\n ></div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ComponentPublicInstance, inject, reactive } from \"vue-demi\";\r\nimport NaiveUpload from \"../../Core/NaiveUpload\";\r\nimport SelectedFile from \"../../Model/SelectedFile\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 渲染数据\r\n */\r\nlet renderData = reactive({\r\n /**\r\n * 选择的文件排序值映射表\r\n */\r\n selectedFileSortMap: upload.getSelectedFileSortMap() as Map<number, number>,\r\n\r\n /**\r\n *加载层样式\r\n */\r\n lodingStyle: (): string => {\r\n return `${\r\n props.slotProps.selectedFile.checking\r\n ? upload.getGradientStyle(\r\n \"conic\",\r\n \"rgba(255, 236, 201, 0.5)\",\r\n props.slotProps.selectedFile.percent,\r\n props.slotProps.selectedFile.virtualPercent\r\n )\r\n : \"\"\r\n } ${\r\n props.slotProps.selectedFile.uploading\r\n ? upload.getGradientStyle(\r\n \"conic\",\r\n \"rgba(144, 206, 255, 0.5)\",\r\n props.slotProps.selectedFile.percent,\r\n props.slotProps.selectedFile.virtualPercent\r\n )\r\n : \"\"\r\n } ${\r\n props.slotProps.selectedFile.paused\r\n ? upload.getGradientStyle(\r\n \"conic\",\r\n \"rgba(158, 158, 158, 0.5)\",\r\n props.slotProps.selectedFile.percent,\r\n props.slotProps.selectedFile.virtualPercent\r\n )\r\n : \"\"\r\n }`;\r\n },\r\n});\r\n\r\n/**\r\n * 组件属性\r\n */\r\nconst props = defineProps<{\r\n /**\r\n * 插槽属性\r\n */\r\n slotProps: {\r\n /**\r\n * 选择的文件\r\n */\r\n selectedFile: SelectedFile;\r\n\r\n /**\r\n * 重命名\r\n */\r\n rename: {\r\n /**\r\n * 启用/禁用\r\n */\r\n enable: () => boolean;\r\n\r\n /**\r\n * 正在重命名\r\n */\r\n active: boolean;\r\n\r\n /**\r\n * 值\r\n */\r\n value: string;\r\n };\r\n\r\n /**\r\n * 方法\r\n */\r\n funs: {\r\n /**\r\n * 设置重命名输入框引用对象\r\n *\r\n * @param el 引用对象\r\n */\r\n setRenameInputRef: (el: Element | ComponentPublicInstance | null) => void;\r\n\r\n /**\r\n * 确认重命名\r\n *\r\n * @param {any} event\r\n */\r\n renameKeydown: (event: KeyboardEvent) => void;\r\n\r\n /**\r\n * 重命名结束\r\n */\r\n renameDone: () => void;\r\n };\r\n\r\n /**\r\n * 加载层\r\n */\r\n loading: {\r\n /**\r\n * 显示/隐藏\r\n */\r\n show: () => boolean;\r\n\r\n /**\r\n * 信息\r\n */\r\n info: () => string;\r\n };\r\n };\r\n}>();\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n upload.getSettings().debug\r\n ? console.debug(\"Layout: Card Info Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>","<template>\r\n <div class=\"item-info\">\r\n <span class=\"single-text-omitted item-name\">\r\n 名称:<span\r\n :title=\"props.slotProps.selectedFile.fullname()\"\r\n v-html=\"props.slotProps.selectedFile.fullname()\"\r\n v-if=\"!props.slotProps.rename.active\"\r\n ></span>\r\n <input\r\n class=\"item-rename-input\"\r\n type=\"text\"\r\n v-if=\"props.slotProps.rename.value\"\r\n v-model=\"props.slotProps.selectedFile.newName\"\r\n :ref=\"props.slotProps.funs.setRenameInputRef\"\r\n v-on:keydown=\"props.slotProps.funs.renameKeydown($event)\"\r\n v-on:blur=\"props.slotProps.funs.renameDone()\"\r\n />\r\n </span>\r\n\r\n <span class=\"single-text-omitted item-size\">\r\n 大小:<span\r\n :title=\"props.slotProps.selectedFile.size\"\r\n v-html=\"props.slotProps.selectedFile.size\"\r\n ></span>\r\n </span>\r\n\r\n <span class=\"single-text-omitted item-filetype\">\r\n 类型:<span\r\n :title=\"props.slotProps.selectedFile.fileType\"\r\n v-html=\"props.slotProps.selectedFile.fileType\"\r\n ></span>\r\n </span>\r\n </div>\r\n\r\n <div\r\n class=\"item-loading\"\r\n v-if=\"props.slotProps.loading.show()\"\r\n :style=\"renderData.lodingStyle()\"\r\n :title=\"props.slotProps.loading.info()\"\r\n ></div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ComponentPublicInstance, inject, reactive } from \"vue-demi\";\r\nimport NaiveUpload from \"../../Core/NaiveUpload\";\r\nimport SelectedFile from \"../../Model/SelectedFile\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 渲染数据\r\n */\r\nlet renderData = reactive({\r\n /**\r\n * 选择的文件排序值映射表\r\n */\r\n selectedFileSortMap: upload.getSelectedFileSortMap() as Map<number, number>,\r\n\r\n /**\r\n *加载层样式\r\n */\r\n lodingStyle: (): string => {\r\n return `${\r\n props.slotProps.selectedFile.checking\r\n ? upload.getGradientStyle(\r\n \"linear\",\r\n \"rgba(255, 236, 201, 0.5)\",\r\n props.slotProps.selectedFile.percent,\r\n props.slotProps.selectedFile.virtualPercent\r\n )\r\n : \"\"\r\n } ${\r\n props.slotProps.selectedFile.uploading\r\n ? upload.getGradientStyle(\r\n \"linear\",\r\n \"rgba(144, 206, 255, 0.5)\",\r\n props.slotProps.selectedFile.percent,\r\n props.slotProps.selectedFile.virtualPercent\r\n )\r\n : \"\"\r\n } ${\r\n props.slotProps.selectedFile.paused\r\n ? upload.getGradientStyle(\r\n \"linear\",\r\n \"rgba(158, 158, 158, 0.5)\",\r\n props.slotProps.selectedFile.percent,\r\n props.slotProps.selectedFile.virtualPercent\r\n )\r\n : \"\"\r\n }`;\r\n },\r\n});\r\n\r\n/**\r\n * 组件属性\r\n */\r\nconst props = defineProps<{\r\n /**\r\n * 插槽属性\r\n */\r\n slotProps: {\r\n /**\r\n * 选择的文件\r\n */\r\n selectedFile: SelectedFile;\r\n\r\n /**\r\n * 重命名\r\n */\r\n rename: {\r\n /**\r\n * 启用/禁用\r\n */\r\n enable: () => boolean;\r\n\r\n /**\r\n * 正在重命名\r\n */\r\n active: boolean;\r\n\r\n /**\r\n * 值\r\n */\r\n value: string;\r\n };\r\n\r\n /**\r\n * 方法\r\n */\r\n funs: {\r\n /**\r\n * 设置重命名输入框引用对象\r\n *\r\n * @param el 引用对象\r\n */\r\n setRenameInputRef: (el: Element | ComponentPublicInstance | null) => void;\r\n\r\n /**\r\n * 确认重命名\r\n *\r\n * @param {any} event\r\n */\r\n renameKeydown: (event: KeyboardEvent) => void;\r\n\r\n /**\r\n * 重命名结束\r\n */\r\n renameDone: () => void;\r\n };\r\n\r\n /**\r\n * 加载层\r\n */\r\n loading: {\r\n /**\r\n * 显示/隐藏\r\n */\r\n show: () => boolean;\r\n\r\n /**\r\n * 信息\r\n */\r\n info: () => string;\r\n };\r\n };\r\n}>();\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n upload.getSettings().debug\r\n ? console.debug(\"Layout: Detailedly Info Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>","<template>\r\n <div v-if=\"!renderData.loading\">\r\n <component :is=\"renderData.currentThemeInfo\" :slotProps=\"props.slotProps\">\r\n </component>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport {\r\n ComponentPublicInstance,\r\n inject,\r\n reactive,\r\n ShallowRef,\r\n shallowRef,\r\n} from \"vue-demi\";\r\nimport NaiveUpload from \"../Core/NaiveUpload\";\r\nimport Card from \"../Layout/Card/info.vue3.vue\";\r\nimport Detailedly from \"../Layout/Detailedly/info.vue3.vue\";\r\nimport SelectedFile from \"../Model/SelectedFile\";\r\nimport { Layout } from \"../Model/Layout\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 渲染数据\r\n */\r\nlet renderData = reactive({\r\n /**\r\n * 加载状态\r\n */\r\n loading: true,\r\n\r\n /**\r\n * 当前的主题组件\r\n */\r\n currentThemeInfo: null as ShallowRef<any> | null,\r\n});\r\n\r\n/**\r\n * 组件属性\r\n */\r\nconst props = defineProps<{\r\n /**\r\n * 插槽属性\r\n */\r\n slotProps: {\r\n /**\r\n * 选择的文件\r\n */\r\n selectedFile: SelectedFile;\r\n\r\n /**\r\n * 重命名\r\n */\r\n rename: {\r\n /**\r\n * 启用/禁用\r\n */\r\n enable: () => boolean;\r\n\r\n /**\r\n * 正在重命名\r\n */\r\n active: boolean;\r\n\r\n /**\r\n * 值\r\n */\r\n value: string;\r\n };\r\n\r\n /**\r\n * 方法\r\n */\r\n funs: {\r\n /**\r\n * 设置重命名输入框引用对象\r\n *\r\n * @param el 引用对象\r\n */\r\n setRenameInputRef: (el: Element | ComponentPublicInstance | null) => void;\r\n\r\n /**\r\n * 确认重命名\r\n *\r\n * @param {any} event\r\n */\r\n renameKeydown: (event: KeyboardEvent) => void;\r\n\r\n /**\r\n * 重命名结束\r\n */\r\n renameDone: () => void;\r\n };\r\n\r\n /**\r\n * 加载层\r\n */\r\n loading: {\r\n /**\r\n * 显示/隐藏\r\n */\r\n show: () => boolean;\r\n\r\n /**\r\n * 信息\r\n */\r\n info: () => string;\r\n };\r\n };\r\n}>();\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n const changLayout = (layout?: Layout) => {\r\n renderData.loading = true;\r\n switch (upload.getSettings().layout) {\r\n case Layout.卡片:\r\n renderData.currentThemeInfo = shallowRef(Card);\r\n break;\r\n case Layout.清单:\r\n renderData.currentThemeInfo = shallowRef(Detailedly);\r\n break;\r\n }\r\n renderData.loading = false;\r\n\r\n upload.getSettings().debug\r\n ? console.debug(\"Layout: Info Component(vue3) 已变更\")\r\n : !1;\r\n };\r\n\r\n //注册布局变更事件(index中已进行监听)\r\n // upload.registerLayoutChanged(changLayout);\r\n\r\n //初始化布局\r\n changLayout();\r\n\r\n upload.getSettings().debug\r\n ? console.debug(\"Layout: Info Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>\r\n","<template>\r\n <layout-index>\r\n <template v-if=\"!upload.getSettings().readonly\" v-slot:uploadContainer>\r\n <file-input\r\n v-if=\"!upload.anyFile()\"\r\n class=\"upload-box-container single\"\r\n :title=\"upload.getConfig().explain\"\r\n >\r\n <p class=\"upload-icon icon-select-file\"></p>\r\n </file-input>\r\n </template>\r\n\r\n <template v-slot:listContainer>\r\n <selected-file-info\r\n v-for=\"sortKey in upload.getSelectedFileSortMap().size\"\r\n :key=\"sortKey\"\r\n :selectedFile=\"upload.getSelectedFile(sortKey)\"\r\n v-slot=\"slotProps\"\r\n >\r\n <layout-info\r\n class=\"item-info-container\"\r\n :slotProps=\"slotProps\"\r\n ></layout-info>\r\n </selected-file-info>\r\n </template>\r\n </layout-index>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from \"vue-demi\";\r\nimport NaiveUpload from \"../Core/NaiveUpload\";\r\nimport FileInput from \"../Piece/FileInput.vue3.vue\";\r\nimport SelectedFileInfo from \"../Piece/SelectedFileInfo.vue3.vue\";\r\nimport LayoutIndex from \"../Layout/index.vue3.vue\";\r\nimport LayoutInfo from \"../Layout/info.vue3.vue\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n upload.getSettings().debug\r\n ? console.debug(\"Piece: Single Upload Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>\r\n","<template>\r\n <div\r\n :class=\"upload.getSelectCLass()\"\r\n v-on:drop=\"dropFile\"\r\n v-on:dragover=\"allowDrop\"\r\n :title=\"upload.getSelectFileAlarmInfo()\"\r\n >\r\n <file-input>\r\n <slot></slot>\r\n </file-input>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject } from \"vue-demi\";\r\nimport NaiveUpload from \"../Core/NaiveUpload\";\r\nimport FileInput from \"../Piece/FileInput.vue3.vue\";\r\n\r\n//注入文件上传工具实例\r\nconst upload = (inject(\"upload\") as () => NaiveUpload)();\r\n\r\n/**\r\n * 允许拖动/阻止冒泡事件\r\n *\r\n * @param {any} e\r\n */\r\nconst allowDrop = (e: DragEvent) => {\r\n e.preventDefault();\r\n};\r\n\r\n/**\r\n * 拖动文件\r\n *\r\n * @param {any} e\r\n */\r\nconst dropFile = (e: DragEvent) => {\r\n e.preventDefault();\r\n if (e.dataTransfer)\r\n for (let i = 0; i < e.dataTransfer.files.length; i++) {\r\n upload.append(e.dataTransfer.files[i]);\r\n }\r\n};\r\n\r\n/**\r\n * 初始化方法\r\n */\r\n(async () => {\r\n upload.getSettings().debug\r\n ? console.debug(\"Piece: Drop File Input Component(vue3) 已加载\")\r\n : !1;\r\n})();\r\n</script>\r\n","/**\r\n * 拖动!\r\n *\r\n * @author LCTR\r\n * @date 2022-10-14\r\n */\r\nexport default class DraggingHelper {\r\n /**\r\n * 容器元素\r\n */\r\n private containerEl?: HTMLElement;\r\n\r\n /**\r\n * 目标元素\r\n */\r\n private el?: HTMLElement;\r\n\r\n /**\r\n * 当前元素\r\n */\r\n private key: number = -1;\r\n\r\n /**\r\n * 元素集合\r\n */\r\n private els?: Map<number, HTMLDivElement>;\r\n\r\n /**\r\n * 是否为移动端\r\n */\r\n private isMobile: boolean = false;\r\n\r\n /**\r\n * 拖动标识\r\n */\r\n private flag: boolean = false;\r\n\r\n /**\r\n * X轴原坐标\r\n */\r\n private x: number = 0;\r\n\r\n /**\r\n * Y轴原坐标\r\n */\r\n private y: number = 0;\r\n\r\n /**\r\n * 当前X轴坐标\r\n */\r\n private currentX: number = 0;\r\n\r\n /**\r\n * 当前Y轴坐标\r\n */\r\n private currentY: number = 0;\r\n\r\n /**\r\n * 当前X轴偏移量\r\n */\r\n private offsetX: number = 0;\r\n\r\n /**\r\n * 当前Y轴偏移量\r\n */\r\n private offsetY: number = 0;\r\n\r\n /**\r\n * X轴滚动量\r\n */\r\n private scrollX: number = 0;\r\n\r\n /**\r\n * Y轴滚动量\r\n */\r\n private scrollY: number = 0;\r\n\r\n /**\r\n * X轴当前位移距离\r\n */\r\n private transX: number = 0;\r\n\r\n /**\r\n * Y轴当前位移距离\r\n */\r\n private transY: number = 0;\r\n\r\n /**\r\n * X轴上次位移距离\r\n */\r\n private lastTransX: number = 0;\r\n\r\n /**\r\n * Y轴上次位移时间\r\n */\r\n private lastTransY: number = 0;\r\n\r\n /**\r\n * 堆叠顺序\r\n */\r\n private zIndex: string = '';\r\n\r\n /**\r\n * 位置\r\n */\r\n private position: string = '';\r\n\r\n /**\r\n * 位移\r\n */\r\n private transform: string = '';\r\n\r\n /**\r\n * 更改位移属性的最小位移量\r\n */\r\n private transLate: number = 1;\r\n\r\n /**\r\n * 判断是否回归原位时的误差值\r\n */\r\n private readonly restoreError: number[] = [20, 10];\r\n\r\n /**\r\n * 移动鼠标\r\n *\r\n * @param event 事件\r\n */\r\n private mouseMove?: (event: MouseEvent & TouchEvent) => void;\r\n\r\n /**\r\n * 移动鼠标\r\n *\r\n * @param event 事件\r\n */\r\n private scroll?: (event: Event) => void;\r\n\r\n /**\r\n * 改变位置\r\n *\r\n * @param clientX\r\n * @param clientY\r\n */\r\n private moving(this: DraggingHelper, clientX: number, clientY: number) {\r\n this.currentX = clientX;\r\n this.currentY = clientY;\r\n\r\n if (this.checkRestore()) {\r\n this.transX = 0;\r\n this.transY = 0;\r\n\r\n this.el!.style.transform = this.transform;\r\n } else {\r\n this.transX = this.currentX - this.x + this.scrollX + this.offsetX;\r\n this.transY = this.currentY - this.y + this.scrollY + this.offsetY;\r\n\r\n if (Math.abs(this.transX - this.lastTransX) >= this.transLate\r\n || Math.abs(this.transY - this.lastTransY) >= this.transLate) {\r\n this.el!.style.transform = `translate(${this.transX}px, ${this.transY}px)`;\r\n }\r\n }\r\n\r\n this.lastTransX = this.transX;\r\n this.lastTransY = this.transY;\r\n }\r\n\r\n /**\r\n * 检查是否拖动到了原本的位置\r\n */\r\n private checkRestore(): boolean {\r\n return DraggingHelper.equalError(this.x, this.currentX, this.restoreError[0])\r\n && DraggingHelper.equalError(this.y, this.currentY, this.restoreError[1]);\r\n }\r\n\r\n /**\r\n * 是否相等\r\n *\r\n * @param current 当前值\r\n * @param target 要比较的值\r\n * @param error 误差范围(如error=5,则为±5)\r\n */\r\n private static equalError(current: number, target: number, error: number): boolean {\r\n return target + error >= current && target - error <= current;\r\n }\r\n\r\n /**\r\n * 获取实例\r\n *\r\n * @param containerEl 容器元素\r\n * @param els 元素集合\r\n * @param currenKey 当前元素的键\r\n * @param isMobile 是否为移动端\r\n */\r\n public static getInstance(containerEl: HTMLElement, els: Map<number, HTMLDivElement>, currenKey: number, isMobile: boolean): DraggingHelper {\r\n let helper = new DraggingHelper();\r\n helper.els = els;\r\n helper.el = els.get(currenKey);\r\n helper.key = currenKey;\r\n helper.containerEl = containerEl;\r\n helper.isMobile = isMobile;\r\n return helper;\r\n }\r\n\r\n /**\r\n * 开始拖动\r\n *\r\n * @param clientX X轴坐标\r\n * @param clientY Y轴坐标\r\n * @param handlerMoving 处理鼠标移动事件\r\n */\r\n public start(this: DraggingHelper, clientX: number, clientY: number, handlerMoving?: ((targetKey: number, clientX: number, clientY: number) => void)) {\r\n this.flag = true;\r\n //开始拖动时记录原始属性\r\n this.currentX = clientX;\r\n this.currentY = clientY;\r\n this.save();\r\n\r\n this.el.style.zIndex = '999';\r\n // this.el.style.position = 'relative';\r\n\r\n let handlerMovingFlag = false;\r\n\r\n this.mouseMove = (event: MouseEvent | TouchEvent) => {\r\n if (!this.flag || handlerMovingFlag)\r\n return;\r\n\r\n const clientX = this.isMobile ? (<TouchEvent>event).targetTouches[0].clientX : (<MouseEvent>event).clientX;\r\n const clientY = this.isMobile ? (<TouchEvent>event).targetTouches[0].clientY : (<MouseEvent>event).clientY;\r\n\r\n event.preventDefault();\r\n\r\n handlerMovingFlag = true;\r\n\r\n this.moving(clientX, clientY);\r\n\r\n if (handlerMoving && this.els) {\r\n let flag = false;\r\n\r\n this.els.forEach((el, key) => {\r\n if (key == this.key)\r\n return;\r\n\r\n const currentOffsetTop = this.el.offsetTop + this.transY;\r\n const currentOffsetLeft = this.el.offsetLeft + this.transX;\r\n\r\n if (currentOffsetTop > el.offsetTop\r\n && currentOffsetTop < el.offsetTop + el.offsetHeight\r\n && currentOffsetLeft > el.offsetLeft\r\n && currentOffsetLeft < el.offsetLeft + el.offsetWidth\r\n ) {\r\n handlerMoving(key, clientX, clientY);\r\n flag = true;\r\n }\r\n });\r\n\r\n flag || handlerMoving(-1, clientX, clientY);\r\n }\r\n\r\n handlerMovingFlag = false;\r\n };\r\n\r\n if (this.isMobile)\r\n this.containerEl!.addEventListener('touchmove', this.mouseMove);\r\n else\r\n this.containerEl!.addEventListener('mousemove', this.mouseMove);\r\n\r\n this.scroll = (event: Event) => {\r\n this.scrollX = this.containerEl!.scrollLeft;\r\n this.scrollY = this.containerEl!.scrollTop;\r\n };\r\n\r\n this.containerEl!.addEventListener('scroll', this.scroll);\r\n }\r\n\r\n /**\r\n * 设置偏移量\r\n *\r\n * @param x X轴偏移量\r\n * @param y Y轴偏移量\r\n */\r\n public offset(this: DraggingHelper, x: number, y: number) {\r\n this.offsetX = x;\r\n this.offsetY = y;\r\n }\r\n\r\n /**\r\n * 保存当前的位置\r\n */\r\n public save(this: DraggingHelper) {\r\n this.x = this.currentX;\r\n this.y = this.currentY;\r\n this.zIndex = this.el!.style.zIndex;\r\n this.position = this.el!.style.position;\r\n this.transform = this.el!.style.transform;\r\n }\r\n\r\n /**\r\n * 复原\r\n */\r\n public restore(this: DraggingHelper) {\r\n this.flag = false;\r\n this.x = this.currentX;\r\n this.y = this.currentY;\r\n this.el!.style.zIndex = this.zIndex;\r\n this.el!.style.position = this.position;\r\n this.el!.style.transform = this.transform;\r\n };\r\n\r\n /**\r\n * 结束拖动\r\n *\r\n * @param restore 是否还原\r\n */\r\n public end(this: DraggingHelper, restore: boolean) {\r\n if (restore)\r\n this.restore();\r\n if (this.isMobile)\r\n this.containerEl!.removeEventListener('touchmove', this.mouseMove!);\r\n else\r\n this.containerEl!.removeEventListener('mousemove', this.mouseMove!);\r\n this.containerEl!.removeEventListener('scroll', this.scroll!);\r\n }\r\n}","<template>\r\n <layout-index>\r\n <template v-if=\"!upload.getSettings().readonly\" v-slot:uploadContainer>\r\n <drop-file-input class=\"upload-box-container\">\r\n <p class=\"upload-icon icon-inbox\"></p>\r\n <p class=\"upload-text\" v-html=\"upload.getConfig().explain\"></p>\r\n <p class=\"upload-hint\" v-html=\"upload.getSettings().tip\"></p>\r\n <div class=\"upload-error-list pretty-scrollbar\">\r\n <p class=\"error-info\" v-for=\"(error, index) in renderData.errors\" :key=\"index\">\r\n {{ error }}\r\n </p>\r\n </div>\r\n </drop-file-input>\r\n </template>\r\n\r\n <template v-slot:listContainer>\r\n <div class=\"scroll-container pretty-scrollbar\" :ref=\"setListRef\" v-on:mouseenter=\"renderData.scrollLock = true\"\r\n v-on:mouseleave=\"renderData.scrollLock = false\">\r\n <TransitionGroup name=\"fade\">\r\n <selected-file-info v-for=\"sortKey in upload.getSelectedFileSortMap().size\"\r\n :ke