feat: Optimize file selection component (#9983)

This commit is contained in:
ssongliu 2025-08-13 17:56:51 +08:00 committed by GitHub
parent b173e808c7
commit 58ca377418
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 287 additions and 170 deletions

View file

@ -10,7 +10,7 @@
type="textarea"
:placeholder="$t('setting.ignoreHelper1')"
/>
<FileList @choose="loadDir" :path="baseDir" :isAll="true"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ path: baseDir, isAll: true })" />
</div>
<span class="input-help">{{ $t('cronjob.exclusionRulesHelper') }}</span>
</el-form-item>
@ -31,6 +31,7 @@
</el-table-column>
</el-table>
</div>
<FileList ref="fileRef" @choose="loadDir" />
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
@ -40,6 +41,7 @@ import { FormInstance } from 'element-plus';
import { loadBaseDir } from '@/api/modules/setting';
const loading = ref();
const fileRef = ref();
const baseDir = ref();
const tableList = ref();
const em = defineEmits(['update:files']);

View file

@ -1,37 +1,43 @@
<template>
<el-popover
placement="right"
:width="400"
trigger="click"
:title="$t('file.list')"
:visible="popoverVisible"
popper-class="file-list"
>
<template #reference>
<el-button icon="Folder" :disabled="disabled" @click="openPage()"></el-button>
</template>
<DialogPro :title="$t('file.list')" size="w-60" v-model="open" @close="handleClose">
<div>
<el-button class="close" link @click="closePage" icon="Close"></el-button>
<div>
<el-button link icon="HomeFilled" @click="jump(-1)"></el-button>
<el-button v-if="paths.length > 0" link @click="jump(0)">/{{ paths[0] }}</el-button>
<el-popover v-if="paths.length > 2" placement="bottom" trigger="hover">
<template #reference>
<el-button link>...</el-button>
</template>
<div class="hidden-paths">
<div v-for="(item, index) in paths.slice(1, -1)" :key="index">
<svg-icon :class="'table-icon'" iconName="p-file-folder"></svg-icon>
<el-link underline="never" @click="jump(index + 1)">{{ item }}</el-link>
</div>
</div>
</el-popover>
<el-button v-if="paths.length > 1" link @click="jump(paths.length - 1)">
/{{ paths[paths.length - 1] }}
</el-button>
<div
v-show="!searchableStatus"
@click="searchableStatus = true"
class="address-bar shadow-md rounded-md px-4 py-2 flex items-center flex-grow"
>
<span class="root mr-1">
<el-link @click.stop="jump(-1)">
<el-icon :size="20"><HomeFilled /></el-icon>
</el-link>
</span>
<span v-if="paths.length > 0">
<span v-for="(_, index) in paths" class="inline-flex items-center" :key="index">
<span class="ml-1 mr-1 arrow">></span>
<el-tooltip effect="dark" :content="paths[index]" placement="top">
<el-link class="path-segment cursor-pointer mr-1 pathname" @click.stop="jump(index)">
{{ paths[index].length > 25 ? paths[index].substring(0, 22) + '...' : paths[index] }}
</el-link>
</el-tooltip>
</span>
</span>
</div>
<el-input
ref="searchableInputRef"
v-show="searchableStatus"
v-model="searchablePath"
@blur="searchableInputBlur"
class="px-4 py-2 border rounded-md shadow-md"
@keyup.enter="
jumpPath();
searchableStatus = false;
"
/>
</div>
<div class="mt-4">
<el-button class="mt-4 float-left" link @click="jump(paths.length - 2)" type="primary" size="small">
{{ $t('file.top') }}
</el-button>
<div class="mt-4 float-right">
<el-button link @click="onAddItem(true)" type="primary" size="small">
{{ $t('commons.button.createNewFolder') }}
</el-button>
@ -41,16 +47,6 @@
</div>
<div>
<el-table :data="data" highlight-current-row height="40vh">
<el-table-column width="40" fix>
<template #default="{ row }">
<el-checkbox
v-model="rowName"
:true-value="row.name"
:disabled="disabledDir(row)"
@change="checkFile(row)"
/>
</template>
</el-table-column>
<el-table-column show-overflow-tooltip fix>
<template #default="{ row }">
<div>
@ -60,7 +56,7 @@
></svg-icon>
<template v-if="!row.isCreate">
<el-link underline="never" @click="open(row)">
<el-link underline="never" @click="openDir(row)">
{{ row.name }}
</el-link>
</template>
@ -96,93 +92,85 @@
</el-tag>
</el-tooltip>
</div>
<div class="button">
<el-button @click="closePage">{{ $t('commons.button.cancel') }}</el-button>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="selectFile" :disabled="disBtn">
{{ $t('commons.button.confirm') }}
</el-button>
</div>
</div>
</el-popover>
</span>
</template>
</DialogPro>
</template>
<script lang="ts" setup>
import { File } from '@/api/interface/file';
import { createFile, getFilesList } from '@/api/modules/files';
import { onMounted, onUpdated, reactive, ref, nextTick } from 'vue';
import { onUpdated, reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess, MsgWarning } from '@/utils/message';
import { useSearchable } from '@/views/host/file-management/hooks/searchable';
const rowName = ref('');
const data = ref([]);
const loading = ref(false);
const paths = ref<string[]>([]);
const req = reactive({ path: '/', expand: true, page: 1, pageSize: 300, showHidden: true });
const selectRow = ref({ path: '', name: '' });
const rowRefs = ref();
const popoverVisible = ref(false);
const open = ref(false);
const newFolder = ref();
const disBtn = ref(false);
const props = defineProps({
path: {
type: String,
default: '/',
},
dir: {
type: Boolean,
default: false,
},
isAll: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
});
const { searchableStatus, searchablePath, searchableInputRef, searchableInputBlur } = useSearchable(paths);
const oldUrl = ref<string>('');
const em = defineEmits(['choose']);
const checkFile = (row: any) => {
disBtn.value = row.isCreate;
selectRow.value = row;
rowName.value = selectRow.value.name;
const form = reactive({
path: '/',
dir: false,
isAll: false,
disabled: false,
});
interface DialogProps {
path: string;
dir: boolean;
isAll: boolean;
disabled: boolean;
}
const acceptParams = (props: DialogProps): void => {
form.path = props.path || '/';
form.dir = props.dir;
form.isAll = props.isAll;
form.disabled = props.disabled;
openPage();
req.path = form.path;
oldUrl.value = form.path;
search(req);
open.value = true;
};
const selectFile = () => {
if (selectRow.value) {
em('choose', selectRow.value.path);
}
closePage();
handleClose();
};
const closePage = () => {
popoverVisible.value = false;
const handleClose = () => {
open.value = false;
selectRow.value = { path: '', name: '' };
};
const openPage = () => {
popoverVisible.value = true;
selectRow.value.path = props.dir ? props.path || '/' : '';
rowName.value = '';
open.value = true;
selectRow.value.path = form.dir ? form.path || '/' : '';
};
const disabledDir = (row: File.File) => {
if (props.isAll) {
return false;
}
if (props.dir !== row.isDir) {
return true;
}
if (!props.dir) {
return row.isDir;
}
return false;
};
const open = async (row: File.File) => {
const openDir = async (row: File.File) => {
if (row.isDir) {
const name = row.name;
paths.value.push(name);
@ -192,12 +180,22 @@ const open = async (row: File.File) => {
req.path = req.path + '/' + name;
}
await search(req);
if (form.isAll || form.dir) {
selectRow.value.path = req.path;
} else {
selectRow.value.path = '';
}
return;
}
selectRow.value.path = props.dir ? req.path : '';
rowName.value = '';
if (!form.isAll && !form.dir) {
selectRow.value.path = (req.path === '/' ? req.path : req.path + '/') + row.name;
return;
}
selectRow.value.path = '';
};
const jump = async (index: number) => {
oldUrl.value = req.path;
let path = '';
if (index != -1) {
if (index !== -1) {
@ -207,17 +205,50 @@ const jump = async (index: number) => {
}
path = path || '/';
req.path = path;
selectRow.value.path = props.dir ? req.path : '';
rowName.value = '';
selectRow.value.path = form.dir ? req.path : '';
await search(req);
popoverVisible.value = true;
open.value = true;
};
const jumpPath = async () => {
loading.value = true;
try {
oldUrl.value = req.path;
getPaths(searchablePath.value);
req.path = searchablePath.value || '/';
search(req);
} finally {
loading.value = false;
}
};
const getPaths = (reqPath: string) => {
const pathArray = reqPath.split('/');
paths.value = [];
let base = '/';
for (const p of pathArray) {
if (p != '') {
if (base.endsWith('/')) {
base = base + p;
} else {
base = base + '/' + p;
}
paths.value.push(p);
}
}
};
const search = async (req: File.ReqFile) => {
req.dir = props.dir;
req.dir = form.dir;
loading.value = true;
await getFilesList(req)
.then((res) => {
if (!res.data.path) {
req.path = oldUrl.value;
getPaths(oldUrl.value);
MsgWarning(i18n.global.t('commons.res.notFound'));
return;
}
data.value = res.data.items || [];
req.path = res.data.path;
const pathArray = req.path.split('/');
@ -242,8 +273,7 @@ const onAddItem = async (isDir: boolean) => {
return;
}
newFolder.value = isDir ? i18n.global.t('file.noNameFolder') : i18n.global.t('file.noNameFile');
if (props.dir === isDir) {
rowName.value = newFolder.value;
if (form.dir === isDir) {
selectRow.value.name = newFolder.value;
const basePath = req.path === '/' ? req.path : `${req.path}/`;
selectRow.value.path = `${basePath}${newFolder.value}`;
@ -263,19 +293,27 @@ const cancelFolder = (row: any) => {
data.value.shift();
row.isCreate = false;
disBtn.value = false;
selectRow.value.path = props.dir ? req.path : '';
rowName.value = '';
selectRow.value.path = form.dir ? req.path : '';
newFolder.value = '';
};
const handleChange = (value: string, row: any) => {
if (rowName.value === row.name) {
selectRow.value.name = value;
rowName.value = value;
row.name = value;
const basePath = req.path === '/' ? req.path : `${req.path}/`;
selectRow.value.path = `${basePath}${value}`;
row.name = value;
const basePath = req.path === '/' ? req.path : `${req.path}/`;
selectRow.value.path = `${basePath}${value}`;
if (row.isDir) {
if (form.isAll || form.dir) {
selectRow.value.path = `${basePath}${value}`;
} else {
selectRow.value.path = '';
}
return;
}
if (form.isAll || !form.dir) {
selectRow.value.path = `${basePath}${value}`;
return;
}
selectRow.value.path = '';
};
const createFolder = async (row: any) => {
@ -301,47 +339,37 @@ const createFolder = async (row: any) => {
});
};
onMounted(() => {
if (props.path != '') {
req.path = props.path;
onUpdated(() => {
if (form.path != '') {
req.path = form.path;
}
rowName.value = '';
search(req);
});
onUpdated(() => {
if (props.path != '') {
req.path = props.path;
}
search(req);
defineExpose({
acceptParams,
});
</script>
<style lang="scss" scoped>
.file-list {
position: relative;
.close {
position: absolute;
right: 10px;
top: 10px;
<style scoped lang="scss">
.file-row {
display: flex;
align-items: center;
width: 100%;
}
.address-bar {
border: var(--el-border);
.arrow {
color: #726e6e;
}
}
.file-list-bottom {
margin-top: 10px;
.path {
width: 250px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.button {
margin-top: 10px;
float: right;
}
}
.hidden-paths {
display: flex;
flex-direction: column;
}
</style>

View file

@ -21,7 +21,7 @@
v-model="form.path"
>
<template #prepend>
<FileList @choose="loadDir" :dir="false"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ dir: false })" />
</template>
</el-input>
</el-form-item>
@ -69,6 +69,7 @@
</template>
</DrawerPro>
<TaskLog ref="taskLogRef" width="70%" />
<FileList ref="fileRef" @choose="loadDir" />
</template>
<script lang="ts" setup>
@ -91,6 +92,7 @@ const templateOptions = ref();
const baseDir = ref();
const composeFile = ref();
const taskLogRef = ref();
const fileRef = ref();
const form = reactive({
taskID: '',
@ -227,5 +229,3 @@ defineExpose({
acceptParams,
});
</script>
<style scoped lang="scss"></style>

View file

@ -26,7 +26,7 @@
<el-form-item v-else :rules="Rules.requiredSelect" prop="dockerfile">
<el-input clearable v-model="form.dockerfile">
<template #prepend>
<FileList @choose="loadBuildDir"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({})" />
</template>
</el-input>
</el-form-item>
@ -45,6 +45,7 @@
</template>
</DrawerPro>
<TaskLog ref="taskLogRef" width="70%" />
<FileList ref="fileRef" @choose="loadBuildDir" />
</template>
<script lang="ts" setup>
@ -60,6 +61,7 @@ import { MsgSuccess } from '@/utils/message';
const drawerVisible = ref(false);
const taskLogRef = ref();
const fileRef = ref();
const form = reactive({
taskID: '',

View file

@ -4,7 +4,7 @@
<el-form-item :label="$t('container.path')" :rules="Rules.requiredInput" prop="path">
<el-input v-model="form.path">
<template #prepend>
<FileList @choose="loadLoadDir" :dir="false"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ dir: false })" />
</template>
</el-input>
</el-form-item>
@ -20,6 +20,7 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="loadLoadDir" />
</template>
<script lang="ts" setup>
@ -32,6 +33,7 @@ import { imageLoad } from '@/api/modules/container';
import { MsgSuccess } from '@/utils/message';
const loading = ref(false);
const fileRef = ref();
const loadVisible = ref(false);
const form = reactive({

View file

@ -15,7 +15,7 @@
<el-form-item :label="$t('container.path')" :rules="Rules.requiredInput" prop="path">
<el-input v-model="form.path">
<template #prepend>
<FileList @choose="loadSaveDir" :dir="true"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ dir: true })" />
</template>
</el-input>
</el-form-item>
@ -34,6 +34,7 @@
</el-button>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="loadSaveDir" />
</template>
<script lang="ts" setup>
@ -47,6 +48,7 @@ import { Container } from '@/api/interface/container';
import { MsgSuccess } from '@/utils/message';
const loading = ref(false);
const fileRef = ref();
const drawerVisible = ref(false);
const form = reactive({

View file

@ -13,7 +13,7 @@
<el-input v-model="form.dockerSockPath">
<template #prepend>unix://</template>
<template #append>
<FileList @choose="loadBuildDir"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({})" />
</template>
</el-input>
<span class="input-help">{{ $t('container.sockPathHelper1') }}</span>
@ -26,12 +26,14 @@
</el-button>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="loadBuildDir" />
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import FileList from '@/components/file-list/index.vue';
import { updateAgentSetting } from '@/api/modules/setting';
import { ElMessageBox, FormInstance } from 'element-plus';
@ -42,6 +44,7 @@ interface DialogProps {
}
const drawerVisible = ref();
const loading = ref();
const fileRef = ref();
const form = reactive({
dockerSockPath: '',

View file

@ -485,7 +485,10 @@
v-model="form.script"
>
<template #prepend>
<FileList @choose="loadScriptDir" :dir="false"></FileList>
<el-button
icon="Folder"
@click="scriptFileRef.acceptParams({ dir: false })"
/>
</template>
</el-input>
</el-form-item>
@ -497,7 +500,10 @@
<el-form-item :label="$t('cronjob.backupContent')" prop="sourceDir">
<el-input v-model="form.sourceDir">
<template #prepend>
<FileList @choose="loadDir" :dir="true" :path="form.sourceDir" />
<el-button
icon="Folder"
@click="dirRef.acceptParams({ dir: true, path: form.sourceDir })"
/>
</template>
</el-input>
</el-form-item>
@ -506,7 +512,10 @@
<el-form-item :label="$t('cronjob.backupContent')" prop="files">
<el-input>
<template #prepend>
<FileList @choose="loadFile" :dir="false" />
<el-button
icon="Folder"
@click="fileRef.acceptParams({ dir: false })"
/>
</template>
</el-input>
<div class="w-full">
@ -744,6 +753,9 @@
</template>
</LayoutContent>
<FileList ref="scriptFileRef" @choose="loadScriptDir" />
<FileList ref="dirRef" @choose="loadDir" />
<FileList ref="fileRef" @choose="loadFile" />
<LicenseImport ref="licenseRef" />
</template>
@ -786,6 +798,9 @@ const router = useRouter();
const globalStore = GlobalStore();
const licenseRef = ref();
const scriptFileRef = ref();
const dirRef = ref();
const fileRef = ref();
const { isProductPro } = storeToRefs(globalStore);
const loading = ref();
const nextTimes = ref([]);

View file

@ -21,7 +21,7 @@
<el-form-item :label="$t('file.compressDst')" prop="dst">
<el-input v-model="form.dst">
<template #prepend>
<FileList :path="form.dst" @choose="getLinkPath" :dir="true"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ dir: true, path: form.dst })" />
</template>
</el-input>
</el-form-item>
@ -39,6 +39,7 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="getLinkPath" />
</template>
<script setup lang="ts">
@ -72,6 +73,7 @@ const options = ref<string[]>([]);
const open = ref(false);
const title = ref('');
const operate = ref('compress');
const fileRef = ref();
const em = defineEmits(['close']);

View file

@ -24,7 +24,7 @@
<el-form-item v-if="addForm.isLink" :label="$t('file.linkPath')" prop="linkPath">
<el-input v-model="addForm.linkPath">
<template #prepend>
<FileList @choose="getLinkPath"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({})" />
</template>
</el-input>
</el-form-item>
@ -40,6 +40,7 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="getLinkPath" />
</template>
<script setup lang="ts">
@ -56,6 +57,7 @@ import { MsgSuccess, MsgWarning } from '@/utils/message';
const fileForm = ref<FormInstance>();
let loading = ref(false);
let setRole = ref(false);
const fileRef = ref();
interface CreateProps {
file: Object;

View file

@ -14,7 +14,7 @@
<el-form-item :label="$t('file.deCompressDst')" prop="dst">
<el-input v-model="form.dst">
<template #prepend>
<FileList :path="form.dst" @choose="getLinkPath" :dir="true"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ path: form.dst, dir: true })" />
</template>
</el-input>
</el-form-item>
@ -29,6 +29,7 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="getLinkPath" />
</template>
<script setup lang="ts">
@ -59,6 +60,7 @@ let loading = ref(false);
let form = ref<File.FileDeCompress>({ type: 'zip', dst: '', path: '', secret: '' });
let open = ref(false);
let name = ref('');
const fileRef = ref();
const em = defineEmits(['close']);

View file

@ -20,7 +20,9 @@
</el-alert>
<el-form-item :label="$t('file.path')" prop="newPath">
<el-input v-model="addForm.newPath">
<template #prepend><FileList @choose="getPath" :dir="true"></FileList></template>
<template #prepend>
<el-button icon="Folder" @click="fileRef.acceptParams({ dir: true })" />
</template>
</el-input>
</el-form-item>
<div v-if="changeName">
@ -61,6 +63,7 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="getPath" />
</template>
<script lang="ts" setup>
@ -92,6 +95,7 @@ const oldName = ref('');
const existFiles = ref<File.ExistFileInfo[]>([]);
const skipFiles = ref([]);
const transferData = ref([]);
const fileRef = ref();
const title = computed(() => {
if (type.value === 'cut') {

View file

@ -13,7 +13,9 @@
</el-form-item>
<el-form-item :label="$t('file.path')" prop="path">
<el-input v-model="addForm.path">
<template #prepend><FileList :path="addForm.path" @choose="getPath"></FileList></template>
<template #prepend>
<el-button icon="Folder" @click="fileRef.acceptParams({ path: addForm.path })" />
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('commons.table.name')" prop="name">
@ -35,6 +37,7 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="getPath" />
</template>
<script lang="ts" setup>
@ -54,6 +57,7 @@ const fileForm = ref<FormInstance>();
const loading = ref(false);
let open = ref(false);
let submitData = ref(false);
const fileRef = ref();
const rules = reactive<FormRules>({
name: [Rules.requiredInput],

View file

@ -381,7 +381,7 @@
>
<el-input v-model="dialogData.rowData!.backupPath">
<template #prepend>
<FileList @choose="loadDir" :dir="true"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ dir: true })" />
</template>
</el-input>
</el-form-item>
@ -395,6 +395,7 @@
</el-button>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="loadDir" />
</template>
<script lang="ts" setup>
@ -403,6 +404,7 @@ import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { Backup } from '@/api/interface/backup';
import FileList from '@/components/file-list/index.vue';
import { addBackup, editBackup, getClientInfo, listBucket } from '@/api/modules/backup';
import { cities } from './../helper';
import { deepCopy, spliceHttp, splitHttp } from '@/utils/util';
@ -416,6 +418,7 @@ type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
const buckets = ref();
const clientInfo = ref();
const fileRef = ref();
const regionInput = ref();

View file

@ -53,14 +53,14 @@
<el-form-item :label="$t('website.privateKey')" prop="key">
<el-input v-model="form.key">
<template #prepend>
<FileList @choose="getKeyPath" :dir="false"></FileList>
<el-button icon="Folder" @click="keyFileRef.acceptParams({ dir: false })" />
</template>
</el-input>
</el-form-item>
<el-form-item class="marginTop" :label="$t('website.certificate')" prop="cert">
<el-input v-model="form.cert">
<template #prepend>
<FileList @choose="getCertPath" :dir="false"></FileList>
<el-button icon="Folder" @click="certFileRef.acceptParams({ dir: false })" />
</template>
</el-input>
</el-form-item>
@ -112,6 +112,8 @@
</el-button>
</template>
</DrawerPro>
<FileList ref="keyFileRef" @choose="getKeyPath" />
<FileList ref="certFileRef" @choose="getCertPath" />
</template>
<script lang="ts" setup>
import { Website } from '@/api/interface/website';
@ -129,6 +131,8 @@ const globalStore = GlobalStore();
const loading = ref();
const drawerVisible = ref();
const keyFileRef = ref();
const certFileRef = ref();
const form = reactive({
ssl: 'Enable',

View file

@ -19,7 +19,7 @@
<el-form-item :label="$t('toolbox.clam.scanDir')" prop="path">
<el-input v-model="dialogData.rowData!.path">
<template #prepend>
<FileList @choose="loadDir" :dir="true"></FileList>
<el-button icon="Folder" @click="scanDirRef.acceptParams({ dir: true })" />
</template>
</el-input>
</el-form-item>
@ -38,7 +38,7 @@
<el-form-item v-if="hasInfectedDir()" :label="$t('toolbox.clam.infectedDir')" prop="infectedDir">
<el-input v-model="dialogData.rowData!.infectedDir">
<template #prepend>
<FileList @choose="loadInfectedDir" :dir="true"></FileList>
<el-button icon="Folder" @click="infectedDirRef.acceptParams({ dir: true })" />
</template>
</el-input>
</el-form-item>
@ -189,6 +189,8 @@
</template>
<LicenseImport ref="licenseRef" />
</DrawerPro>
<FileList ref="scanDirRef" @choose="loadDir" />
<FileList ref="infectedDirRef" @choose="loadInfectedDir" />
</template>
<script lang="ts" setup>
@ -207,6 +209,8 @@ import { specOptions, transObjToSpec, transSpecToObj, weekOptions } from '@/view
const globalStore = GlobalStore();
const licenseRef = ref();
const scanDirRef = ref();
const infectedDirRef = ref();
const { isProductPro } = storeToRefs(globalStore);
interface DialogProps {
title: string;

View file

@ -4,7 +4,7 @@
<el-form-item :label="$t('toolbox.fail2ban.logPath')" prop="logPath" :rules="Rules.requiredInput">
<el-input v-model="form.logPath">
<template #prepend>
<FileList @choose="loadLogPath"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({})" />
</template>
</el-input>
<span class="input-help">{{ $t('toolbox.fail2ban.logPathHelper') }}</span>
@ -19,11 +19,13 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="loadLogPath" />
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import FileList from '@/components/file-list/index.vue';
import { updateFail2ban } from '@/api/modules/toolbox';
import { ElMessageBox, FormInstance } from 'element-plus';
import { Rules } from '@/global/form-rules';
@ -35,6 +37,7 @@ interface DialogProps {
}
const drawerVisible = ref();
const loading = ref();
const fileRef = ref();
const form = reactive({
logPath: '',

View file

@ -20,7 +20,7 @@
<el-form-item :label="$t('file.root')" prop="path">
<el-input v-model="dialogData.rowData!.path">
<template #prepend>
<FileList @choose="loadDir" :dir="true"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ dir: true })" />
</template>
</el-input>
<span class="input-help">{{ $t('toolbox.ftp.dirHelper') }}</span>
@ -38,6 +38,7 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="loadDir" />
</template>
<script lang="ts" setup>
@ -59,6 +60,7 @@ interface DialogProps {
const loading = ref();
const title = ref<string>('');
const drawerVisible = ref(false);
const fileRef = ref();
const dialogData = ref<DialogProps>({
title: '',
});

View file

@ -21,7 +21,9 @@
</el-form-item>
<el-form-item :label="$t('tool.supervisor.dir')" prop="dir">
<el-input v-model.trim="process.dir">
<template #prepend><FileList @choose="getPath" :dir="true"></FileList></template>
<template #prepend>
<el-button icon="Folder" @click="fileRef.acceptParams({ dir: true })" />
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('tool.supervisor.command')" prop="command">
@ -48,6 +50,7 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="getPath" />
</template>
<script lang="ts" setup>
@ -62,6 +65,7 @@ import { HostTool } from '@/api/interface/host-tool';
const open = ref(false);
const loading = ref(false);
const fileRef = ref();
const processForm = ref<FormInstance>();
const rules = ref({
name: [Rules.requiredInput, Rules.supervisorName],

View file

@ -2,7 +2,10 @@
<el-form-item :label="$t('runtime.codeDir')" prop="codeDir">
<el-input v-model.trim="runtime.codeDir" :disabled="mode === 'edit'" @blur="changeDir">
<template #prepend>
<FileList :disabled="mode === 'edit'" :path="runtime.codeDir" @choose="getPath" :dir="true"></FileList>
<el-button
icon="Folder"
@click="fileRef.acceptParams({ path: runtime.codeDir, dir: true, disabled: mode === 'edit' })"
/>
</template>
</el-input>
<span class="input-help">
@ -55,13 +58,17 @@
</span>
</el-form-item>
</div>
<FileList ref="fileRef" @choose="getPath" />
</template>
<script setup lang="ts">
import { Runtime } from '@/api/interface/runtime';
import FileList from '@/components/file-list/index.vue';
import { GetNodeScripts } from '@/api/modules/runtime';
import { useVModel } from '@vueuse/core';
const fileRef = ref();
const props = defineProps({
mode: {
type: String,

View file

@ -22,12 +22,12 @@
<el-form-item :label="$t('tool.supervisor.dir')" prop="codeDir">
<el-input v-model.trim="runtime.codeDir" :disabled="mode === 'edit'">
<template #prepend>
<FileList
:disabled="mode === 'edit'"
:path="runtime.codeDir"
@choose="getPath"
:dir="true"
></FileList>
<el-button
icon="Folder"
@click="
fileRef.acceptParams({ disabled: mode === 'edit', path: runtime.codeDir, dir: true })
"
/>
</template>
</el-input>
<span class="input-help">
@ -64,6 +64,7 @@
</el-button>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="getPath" />
</template>
<script lang="ts" setup>
@ -71,6 +72,7 @@ import { App } from '@/api/interface/app';
import { Runtime } from '@/api/interface/runtime';
import { CreateRuntime, GetRuntime, UpdateRuntime } from '@/api/modules/runtime';
import { Rules, checkNumberRange } from '@/global/form-rules';
import FileList from '@/components/file-list/index.vue';
import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
@ -87,6 +89,7 @@ interface OperateRrops {
}
const open = ref(false);
const fileRef = ref();
const runtimeForm = ref<FormInstance>();
const loading = ref(false);
const mode = ref('create');

View file

@ -43,7 +43,10 @@
<el-form-item :label="$t('ssl.dir')" prop="dir" v-if="obtain.pushDir">
<el-input v-model.trim="obtain.dir">
<template #prepend>
<FileList :path="obtain.dir" @choose="getPath" :dir="true"></FileList>
<el-button
icon="Folder"
@click="fileRef.acceptParams({ path: obtain.dir, dir: true })"
/>
</template>
</el-input>
<span class="input-help">
@ -71,18 +74,21 @@
</span>
</template>
</DialogPro>
<FileList ref="fileRef" @choose="getPath" />
</template>
<script lang="ts" setup>
import { obtainSSLByCA } from '@/api/modules/website';
import { Rules, checkNumberRange, checkMaxLength } from '@/global/form-rules';
import i18n from '@/lang';
import FileList from '@/components/file-list/index.vue';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { ref } from 'vue';
import { KeyTypes } from '@/global/mimetype';
const open = ref(false);
const fileRef = ref();
const loading = ref(false);
const obtainForm = ref<FormInstance>();
const em = defineEmits(['close']);

View file

@ -100,7 +100,7 @@
<el-form-item :label="$t('ssl.dir')" prop="dir" v-if="ssl.pushDir">
<el-input v-model.trim="ssl.dir">
<template #prepend>
<FileList :path="ssl.dir" @choose="getPath" :dir="true"></FileList>
<el-button icon="Folder" @click="fileRef.acceptParams({ path: ssl.dir, dir: true })" />
</template>
</el-input>
<span class="input-help">
@ -152,12 +152,14 @@
</span>
</template>
</DrawerPro>
<FileList ref="fileRef" @choose="getPath" />
</template>
<script lang="ts" setup>
import { Website } from '@/api/interface/website';
import { createSSL, listWebsites, searchAcmeAccount, searchDnsAccount, updateSSL } from '@/api/modules/website';
import { Rules, checkMaxLength } from '@/global/form-rules';
import FileList from '@/components/file-list/index.vue';
import i18n from '@/lang';
import { FormInstance } from 'element-plus';
import { computed, reactive, ref } from 'vue';
@ -177,6 +179,7 @@ const id = computed(() => {
});
const open = ref(false);
const fileRef = ref();
const loading = ref(false);
const dnsReq = reactive({
page: 1,

View file

@ -19,14 +19,14 @@
<el-form-item :label="$t('website.privateKeyPath')" prop="privateKeyPath">
<el-input v-model="ssl.privateKeyPath">
<template #prepend>
<FileList @choose="getPrivateKeyPath" :dir="false"></FileList>
<el-button icon="Folder" @click="keyFileRef.acceptParams({ dir: false })" />
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('website.certificatePath')" prop="certificatePath">
<el-input v-model="ssl.certificatePath">
<template #prepend>
<FileList @choose="getCertificatePath" :dir="false"></FileList>
<el-button icon="Folder" @click="certFileRef.acceptParams({ dir: false })" />
</template>
</el-input>
</el-form-item>
@ -44,6 +44,8 @@
</span>
</template>
</DrawerPro>
<FileList ref="keyFileRef" @choose="getPrivateKeyPath" />
<FileList ref="certFileRef" @choose="getCertificatePath" />
</template>
<script lang="ts" setup>
@ -51,11 +53,14 @@ import { uploadSSL } from '@/api/modules/website';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { FormInstance } from 'element-plus';
import FileList from '@/components/file-list/index.vue';
import { ref } from 'vue';
import { MsgSuccess } from '@/utils/message';
import { Website } from '@/api/interface/website';
const open = ref(false);
const keyFileRef = ref();
const certFileRef = ref();
const loading = ref(false);
const sslForm = ref<FormInstance>();

View file

@ -109,14 +109,14 @@
<el-form-item :label="$t('website.privateKeyPath')" prop="privateKeyPath">
<el-input v-model="form.privateKeyPath">
<template #prepend>
<FileList @choose="getPrivateKeyPath" :dir="false"></FileList>
<el-button icon="Folder" @click="keyFileRef.acceptParams({ dir: false })" />
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('website.certificatePath')" prop="certificatePath">
<el-input v-model="form.certificatePath">
<template #prepend>
<FileList @choose="getCertificatePath" :dir="false"></FileList>
<el-button icon="Folder" @click="certFileRef.acceptParams({ dir: false })" />
</template>
</el-input>
</el-form-item>
@ -182,6 +182,9 @@
</el-form>
</el-col>
</el-row>
<FileList ref="keyFileRef" @choose="getPrivateKeyPath" />
<FileList ref="certFileRef" @choose="getCertificatePath" />
</template>
<script lang="ts" setup>
import { Website } from '@/api/interface/website';
@ -194,6 +197,8 @@ import { dateFormatSimple, getProvider, getAccountName } from '@/utils/util';
import { MsgSuccess } from '@/utils/message';
import FileList from '@/components/file-list/index.vue';
const keyFileRef = ref();
const certFileRef = ref();
const props = defineProps({
id: {
type: Number,