diff --git a/frontend/package.json b/frontend/package.json
index f70143d4..062964a5 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -17,6 +17,7 @@
"@popperjs/core": "^2.6.0",
"@types/codemirror": "^0.0.103",
"@types/echarts": "^4.9.8",
+ "@types/getos": "^3.0.1",
"@types/humanize-duration": "^3.25.0",
"@types/javascript-time-ago": "^2.0.2",
"@types/md5": "^2.2.1",
@@ -31,6 +32,7 @@
"echarts": "^5.1.2",
"element-plus": "1.0.2-beta.40",
"font-awesome": "^4.7.0",
+ "getos": "^3.2.1",
"humanize-duration": "^3.26.0",
"javascript-time-ago": "^2.3.6",
"md5": "^2.3.0",
diff --git a/frontend/src/components/file/FileUpload.vue b/frontend/src/components/file/FileUpload.vue
index 8e796365..5116945a 100644
--- a/frontend/src/components/file/FileUpload.vue
+++ b/frontend/src/components/file/FileUpload.vue
@@ -19,15 +19,16 @@
:http-request="() => {}"
drag
multiple
+ :show-file-list="false"
>
Drag files here, or click to upload
-
+
-
-
+
+
@@ -85,14 +94,14 @@ export default defineComponent({
],
setup(props: FileUploadProps, {emit}) {
const modeOptions: FileUploadModeOption[] = [
- {
- label: 'Files',
- value: FILE_UPLOAD_MODE_FILES,
- },
{
label: 'Folder',
value: FILE_UPLOAD_MODE_DIR,
},
+ {
+ label: 'Files',
+ value: FILE_UPLOAD_MODE_FILES,
+ },
];
const internalMode = ref();
@@ -122,11 +131,14 @@ export default defineComponent({
internalMode.value = mode;
});
- const dirInfo = ref();
+ const dirInfo = ref();
- const setDirInfo = (info: FileUploadDirInfo) => {
- console.debug(info);
+ const setInfo = (info: FileUploadInfo) => {
dirInfo.value = plainClone(info);
+ }
+
+ const resetInfo = (info: FileUploadInfo) => {
+ dirInfo.value = undefined;
};
return {
@@ -140,13 +152,16 @@ export default defineComponent({
clearFiles,
onModeChange,
dirInfo,
- setDirInfo,
+ setInfo,
+ resetInfo,
};
},
});
diff --git a/frontend/src/constants/os.ts b/frontend/src/constants/os.ts
new file mode 100644
index 00000000..e6d80d9f
--- /dev/null
+++ b/frontend/src/constants/os.ts
@@ -0,0 +1,3 @@
+export const OS_WINDOWS = 'windows';
+export const OS_MAC = 'mac';
+export const OS_LINUX = 'linux';
diff --git a/frontend/src/interfaces/common/os.d.ts b/frontend/src/interfaces/common/os.d.ts
new file mode 100644
index 00000000..dc83139c
--- /dev/null
+++ b/frontend/src/interfaces/common/os.d.ts
@@ -0,0 +1,9 @@
+import {
+ OS_WINDOWS,
+ OS_MAC,
+ OS_LINUX,
+} from '@/constants/os';
+
+declare global {
+ type OS = OS_WINDOWS | OS_MAC | OS_LINUX;
+}
diff --git a/frontend/src/interfaces/components/file/FileUpload.d.ts b/frontend/src/interfaces/components/file/FileUpload.d.ts
index 2b0e7eac..a154536d 100644
--- a/frontend/src/interfaces/components/file/FileUpload.d.ts
+++ b/frontend/src/interfaces/components/file/FileUpload.d.ts
@@ -9,7 +9,8 @@ interface FileUploadModeOption {
value: string;
}
-interface FileUploadDirInfo {
- dirName: string;
- fileCount: number;
+interface FileUploadInfo {
+ dirName?: string;
+ fileCount?: number;
+ filePaths?: string[];
}
diff --git a/frontend/src/utils/os.ts b/frontend/src/utils/os.ts
new file mode 100644
index 00000000..3122e7f7
--- /dev/null
+++ b/frontend/src/utils/os.ts
@@ -0,0 +1,32 @@
+import getos from 'getos';
+import {OS_LINUX, OS_MAC, OS_WINDOWS} from '@/constants/os';
+
+let os: OS;
+
+getos((e, _os) => {
+ if (e) {
+ console.error(e);
+ return;
+ }
+
+ switch (_os.os) {
+ case 'win32':
+ return OS_WINDOWS;
+ case 'darwin':
+ return OS_MAC;
+ default:
+ return OS_LINUX;
+ }
+});
+
+export const getOS = (): OS => {
+ return os;
+};
+
+export const isWindows = (): boolean => {
+ return getOS() === OS_WINDOWS;
+};
+
+export const getOSPathSeparator = () => {
+ return isWindows() ? '\\' : '/';
+};
diff --git a/frontend/src/views/spider/detail/actions/SpiderDetailActionsFiles.vue b/frontend/src/views/spider/detail/actions/SpiderDetailActionsFiles.vue
index 94d6239b..de94ff17 100644
--- a/frontend/src/views/spider/detail/actions/SpiderDetailActionsFiles.vue
+++ b/frontend/src/views/spider/detail/actions/SpiderDetailActionsFiles.vue
@@ -40,6 +40,8 @@ import FileUpload from '@/components/file/FileUpload.vue';
import Dialog from '@/components/dialog/Dialog.vue';
import {ElMessage} from 'element-plus';
import {FILE_UPLOAD_MODE_DIR, FILE_UPLOAD_MODE_FILES} from '@/constants/file';
+import {FileWithPath} from 'file-selector';
+import {getOSPathSeparator} from '@/utils/os';
export default defineComponent({
name: 'SpiderDetailActionsFiles',
@@ -64,8 +66,8 @@ export default defineComponent({
saveFileBinary,
} = useSpiderService(store);
- const mode = ref(FILE_UPLOAD_MODE_FILES);
- const files = ref();
+ const mode = ref(FILE_UPLOAD_MODE_DIR);
+ const files = ref([]);
const id = computed(() => route.params.id as string);
@@ -74,14 +76,50 @@ export default defineComponent({
const confirmLoading = ref(false);
const confirmDisabled = computed(() => !files.value?.length);
+ const hasMultiDir = computed(() => {
+ if (!files.value) return false;
+ const set = new Set();
+ for (const f of files.value) {
+ const lv1 = f.path?.split(getOSPathSeparator())[0] as string;
+ if (!set.has(lv1)) {
+ set.add(lv1);
+ }
+ if (set.size > 1) {
+ return true;
+ }
+ }
+ return false;
+ });
+
+ const getFilePath = (path: string) => {
+ if (hasMultiDir.value) {
+ return path;
+ } else {
+ return path.split(getOSPathSeparator()).filter((_, i) => i > 0).join(getOSPathSeparator());
+ }
+ };
+
+ const setInfo = () => {
+ // set file upload info
+ const info = {
+ fileCount: files.value.length,
+ filePaths: files.value.map(f => f.path || f.name),
+ } as FileUploadInfo;
+ if (mode.value === FILE_UPLOAD_MODE_DIR) {
+ const f = files.value[0];
+ info.dirName = f.path?.split(getOSPathSeparator())[0];
+ }
+ fileUploadRef.value?.setInfo(info);
+ };
+
const onOpenFilesSettings = () => {
store.commit(`${storeNamespace}/setEditorSettingsDialogVisible`, true);
};
const uploadFiles = async () => {
if (!files.value) return;
- await Promise.all(files.value.map(f => {
- return saveFileBinary(id.value, f.name, f as File);
+ await Promise.all(files.value.map((f: FileWithPath) => {
+ return saveFileBinary(id.value, getFilePath(f.path as string), f as File);
}));
await listRootDir(id.value);
};
@@ -90,20 +128,11 @@ export default defineComponent({
getInputProps,
open,
} = useDropzone({
- onDrop: async (fileList: InputFile[]) => {
- if (mode.value === FILE_UPLOAD_MODE_DIR) {
- if (!fileList.length) return;
- const f = fileList[0];
- const dirName = f.path?.split('/')[0];
- const fileCount = fileList.length;
- const dirInfo = {
- dirName,
- fileCount,
- } as FileUploadDirInfo;
- console.debug(fileList, dirInfo);
- fileUploadRef.value?.setDirInfo(dirInfo);
- }
- files.value = fileList as File[];
+ onDrop: (fileList: InputFile[]) => {
+ files.value = fileList.map(f => f as FileWithPath);
+
+ // set file upload info
+ setInfo();
},
});
@@ -115,10 +144,19 @@ export default defineComponent({
const onModeChange = (value: string) => {
mode.value = value;
+
+ // reset file upload info
+ fileUploadRef.value?.resetInfo();
};
- const onFilesChange = (fileList: File[]) => {
- files.value = fileList;
+ const onFilesChange = (fileList: FileWithPath[]) => {
+ if (!fileList.length) return;
+
+ // set files
+ files.value = fileList as FileWithPath[];
+
+ // set file upload info
+ setInfo();
};
const onUploadConfirm = async () => {
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index a8dfdd34..228d869e 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1137,6 +1137,11 @@
"@types/qs" "*"
"@types/serve-static" "*"
+"@types/getos@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.nlark.com/@types/getos/download/@types/getos-3.0.1.tgz#6812bfdca81aaeba7ac2d0f4ad002b7e6566fc3b"
+ integrity sha1-aBK/3Kgarrp6wtD0rQArfmVm/Ds=
+
"@types/glob@^7.1.1":
version "7.1.3"
resolved "https://registry.npm.taobao.org/@types/glob/download/@types/glob-7.1.3.tgz?cache=0&sync_timestamp=1605053412496&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fglob%2Fdownload%2F%40types%2Fglob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
@@ -2268,6 +2273,11 @@ async@^2.6.2:
dependencies:
lodash "^4.17.14"
+async@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.npm.taobao.org/async/download/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
+ integrity sha1-s6JoXF67ZB094C0WEALGD8n4VyA=
+
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -4890,6 +4900,13 @@ get-value@^2.0.3, get-value@^2.0.6:
resolved "https://registry.npm.taobao.org/get-value/download/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+getos@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.npm.taobao.org/getos/download/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5"
+ integrity sha1-ATTR9OAOtGFExanArE3Ah8uyfcU=
+ dependencies:
+ async "^3.2.0"
+
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"