添加信号源时可以选择远程文件的功能

This commit is contained in:
fangxiang 2021-08-20 16:46:41 +08:00
parent a66658e62f
commit 470724fb57
4 changed files with 224 additions and 43 deletions

View File

@ -13,7 +13,10 @@ declare module "@vue/runtime-core" {
// good idea to move this instance creation inside of the // good idea to move this instance creation inside of the
// "export default () => {}" function below (which runs individually // "export default () => {}" function below (which runs individually
// for each client) // for each client)
const api = axios.create({ baseURL: "https://api.example.com" }); const api = axios.create({
baseURL: "https://" + window.location.hostname,
timeout: 10000,
});
api.defaults.headers.common["X-Product-Name"] = "RK_3568"; api.defaults.headers.common["X-Product-Name"] = "RK_3568";
export default boot(({ app }) => { export default boot(({ app }) => {

View File

@ -32,16 +32,17 @@
<div class="q-pa-md q-gutter-sm"> <div class="q-pa-md q-gutter-sm">
<q-breadcrumbs separator="/"> <q-breadcrumbs separator="/">
<q-breadcrumbs-el <q-breadcrumbs-el
:disable="status == 'uploading'" :disable="uploading"
icon="home" icon="home"
:label="default_path_label"
to="#" to="#"
@click="path = ''" @click="path = default_path"
/> />
<q-breadcrumbs-el <q-breadcrumbs-el
v-for="(item, index) of paths.slice(1)" v-for="(item, index) of paths.slice(1)"
:key="index" :key="index"
:label="item.name" :label="item.name"
:disable="status == 'uploading'" :disable="uploading"
to="#" to="#"
@click="path = item.path" @click="path = item.path"
/> />
@ -50,10 +51,34 @@
</div> </div>
<q-separator /> <q-separator />
<div class="row"> <div class="row">
<q-btn-dropdown
stretch
flat
:label="default_path_label"
:disable="uploading"
class="q-mr-sm"
>
<q-list>
<q-item
v-for="(item, index) of disk_options"
:key="index"
clickable
v-close-popup
@click="default_path = item.value"
>
<q-item-section avatar>
<q-icon
:name="item.label == $t('local disk') ? 'desktop_mac' : 'usb'"
/>
</q-item-section>
<q-item-section> {{ item.label }} </q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn <q-btn
flat flat
icon="arrow_back" icon="arrow_back"
:disable="path.trim() == '' || status == 'uploading'" :disable="path.trim() == '' || uploading"
@click="backToParentPath" @click="backToParentPath"
:label="$t('back')" :label="$t('back')"
> >
@ -64,9 +89,7 @@
<q-btn <q-btn
flat flat
icon="arrow_forward" icon="arrow_forward"
:disable=" :disable="prev_path == '' || path == prev_path || uploading"
prev_path == '' || path == prev_path || status == 'uploading'
"
@click="(path = prev_path) && (prev_path = '')" @click="(path = prev_path) && (prev_path = '')"
:label="$t('forward')" :label="$t('forward')"
> >
@ -78,7 +101,7 @@
flat flat
icon="refresh" icon="refresh"
@click="refresh_file_list" @click="refresh_file_list"
:disable="status == 'uploading'" :disable="uploading"
:label="$t('refresh')" :label="$t('refresh')"
> >
<q-tooltip> <q-tooltip>
@ -89,7 +112,7 @@
flat flat
icon="create_new_folder" icon="create_new_folder"
@click="onCreateNewFolder" @click="onCreateNewFolder"
:disable="loading" :disable="loading || uploading"
:label="$t('create folder')" :label="$t('create folder')"
> >
<q-tooltip> <q-tooltip>
@ -98,10 +121,10 @@
</q-btn> </q-btn>
<q-btn <q-btn
flat flat
v-if="status != 'uploading'" v-if="!uploading"
icon="upload" icon="upload"
:label="$t('upload file')" :label="$t('upload file')"
@click="status = 'uploading'" @click="uploading = true"
> >
<q-tooltip> <q-tooltip>
{{ $t("upload file") }} {{ $t("upload file") }}
@ -110,9 +133,9 @@
<q-btn <q-btn
flat flat
icon="block" icon="block"
v-if="status == 'uploading'" v-if="uploading"
:label="$t('cancel upload file')" :label="$t('cancel upload file')"
@click="status = 'normal'" @click="uploading = false"
> >
<q-tooltip> <q-tooltip>
{{ $t("cancel upload file") }} {{ $t("cancel upload file") }}
@ -127,7 +150,7 @@
> >
<q-table <q-table
style="height: 69vh" style="height: 69vh"
v-show="status != 'uploading'" v-show="!uploading"
:rows="files" :rows="files"
:columns="columns" :columns="columns"
virtual-scroll virtual-scroll
@ -150,8 +173,8 @@
style="color: #ffbe4a; font-size: 2.5em" style="color: #ffbe4a; font-size: 2.5em"
></q-icon> ></q-icon>
{{ {{
props.value.length > 23 props.value.length > 60
? props.value.substr(0, 23) + "..." ? props.value.substr(0, 60) + "..."
: props.value : props.value
}} }}
<q-tooltip> {{ props.value }} </q-tooltip> <q-tooltip> {{ props.value }} </q-tooltip>
@ -160,30 +183,46 @@
{{ props.value }} {{ props.value }}
</div> </div>
<div v-else> <div v-else>
<div v-if="props.row.can_write"> <div v-if="status != 'select'">
<a href="#" @click="(evt) => renameFile(props.row)"> <div v-if="props.row.can_write">
{{ $t("rename") }} <a href="#" @click="(evt) => renameFile(props.row)">
<q-tooltip> {{ $t("click") }}{{ $t("rename") }} </q-tooltip> {{ $t("rename") }}
</a> <q-tooltip>
&nbsp;&nbsp;&nbsp;&nbsp; {{ $t("click") }}{{ $t("rename") }}
<a href="#" @click="(evt) => deleteFile(props.row)"> </q-tooltip>
{{ $t("delete") }} </a>
<q-tooltip> {{ $t("click") }}{{ $t("delete") }} </q-tooltip> &nbsp;&nbsp;&nbsp;&nbsp;
<a href="#" @click="(evt) => deleteFile(props.row)">
{{ $t("delete") }}
<q-tooltip>
{{ $t("click") }}{{ $t("delete") }}
</q-tooltip>
</a>
</div>
</div>
<div v-else-if="!props.row.is_directory">
<a href="#" @click="(evt) => selectFile(props.row)">
{{ $t("select file") }}
<q-tooltip>
{{ $t("click") }}{{ $t("select file") }}
</q-tooltip>
</a> </a>
</div> </div>
</div> </div>
</q-td> </q-td>
</template> </template>
</q-table> </q-table>
<div v-show="status == 'uploading'" class="row q-ma-sm"> <div v-show="uploading" class="row q-ma-sm">
<q-space /> <q-space />
<q-uploader <q-uploader
ref="uploader"
style="height: 69vh; width: 70%" style="height: 69vh; width: 70%"
:url="getUrl" :url="getUrl"
method="post" method="post"
:headers="generatorFileUploadHeaders" :headers="generatorFileUploadHeaders"
:label="$t('select file') + ':'" :label="$t('select file') + ':'"
accept="*" accept="*"
@start="onStartUpload"
@uploaded="onUploaded" @uploaded="onUploaded"
@failed="onFailed" @failed="onFailed"
> >
@ -202,12 +241,12 @@
@click="(evt) => copyStringToClipboard(current_file.name)" @click="(evt) => copyStringToClipboard(current_file.name)"
> >
<q-item-section avatar><q-icon name="file_copy" /></q-item-section> <q-item-section avatar><q-icon name="file_copy" /></q-item-section>
<q-item-section>{{ $t("copy file name") }}</q-item-section> <q-item-section>{{ $t("copy name") }}</q-item-section>
</q-item> </q-item>
<q-item <q-item
clickable clickable
v-close-popup v-close-popup
v-if="current_file && current_file.can_write" v-if="current_file && current_file.can_write && status != 'select'"
@click="(evt) => renameFile(current_file)" @click="(evt) => renameFile(current_file)"
> >
<q-item-section avatar><q-icon name="edit" /></q-item-section> <q-item-section avatar><q-icon name="edit" /></q-item-section>
@ -216,7 +255,7 @@
<q-item <q-item
clickable clickable
v-close-popup v-close-popup
v-if="current_file && current_file.can_write" v-if="current_file && current_file.can_write && status != 'select'"
@click="(evt) => deleteFile(current_file)" @click="(evt) => deleteFile(current_file)"
> >
<q-item-section avatar <q-item-section avatar
@ -224,6 +263,15 @@
/></q-item-section> /></q-item-section>
<q-item-section>{{ $t("delete") }}</q-item-section> <q-item-section>{{ $t("delete") }}</q-item-section>
</q-item> </q-item>
<q-item
clickable
v-close-popup
v-if="status == 'select' && !current_file.is_directory"
@click="(evt) => selectFile(current_file)"
>
<q-item-section avatar><q-icon name="attach_file" /></q-item-section>
<q-item-section>{{ $t("select file") }}</q-item-section>
</q-item>
</q-list> </q-list>
</q-menu> </q-menu>
</div> </div>
@ -296,15 +344,34 @@ export default defineComponent({
let show_dialog = ref(false); let show_dialog = ref(false);
let loading = ref(false); let loading = ref(false);
let uploading = ref(false);
let files = ref(<FileEntity[]>[]); let files = ref(<FileEntity[]>[]);
let show_context_menu = ref(false); let show_context_menu = ref(false);
let target_dom: any = ref(document.body.children[0]); let target_dom: any = ref(document.body.children[0]);
let current_file = ref(new FileEntity()); let current_file = ref(new FileEntity());
let path = ref(""); let default_path_label = ref($t.t("local disk"));
let default_path = ref("media");
let path = ref(default_path.value);
let prev_path = ref(""); let prev_path = ref("");
let paths = ref([new _BreadcrumbItem("root", "")]); let paths = ref([new _BreadcrumbItem("root", "")]);
let status = ref("normal"); let status = ref("normal");
let upload_url = ref(""); let upload_url = ref("");
let uploader: any = ref(null);
let resolve: any = null;
let resolve_value: any = null;
const disk_options = ref([
{
label: $t.t("local disk"),
value: "media",
},
]);
for (let i = 1; i < 8; ++i) {
disk_options.value.push({
label: $t.t("usb") + i.toString(),
value: "/usb" + i.toString(),
});
}
const columns = [ const columns = [
{ {
@ -409,42 +476,107 @@ export default defineComponent({
refresh_file_list_async(); refresh_file_list_async();
}; };
const selectFile = async (file: FileEntity) => {
resolve_value = {
file,
path: path.value,
};
show_dialog.value = false;
};
watch( watch(
() => path.value, () => path.value,
(newValue: string) => { (newValue: string, oldValue: string) => {
if (!newValue) {
path.value = oldValue ?? default_path.value;
return;
}
paths.value = []; paths.value = [];
let parent_item = new _BreadcrumbItem("root", ""); let parent_item = null;
for (let item of newValue.split("/")) { for (let item of newValue.split("/")) {
let temp = new _BreadcrumbItem(item, parent_item.path + "/" + item); if (item.trim() == "") {
continue;
}
let temp: _BreadcrumbItem = new _BreadcrumbItem(
item,
(parent_item
? parent_item.path + "/"
: newValue.length > 0
? newValue[0] == "/" || "\\"
? "/"
: ""
: "") + item
);
paths.value.push(temp); paths.value.push(temp);
parent_item = temp; parent_item = temp;
} }
if (paths.value.length < 1) { if (paths.value.length < 1) {
paths.value.push(new _BreadcrumbItem("root", "")); paths.value.push(new _BreadcrumbItem("local disk", "media"));
} }
refresh_file_list(); refresh_file_list();
} }
); );
watch(
() => status.value,
(newValue: string) => {
switch (newValue) {
case "normal":
case "select":
break;
default:
console.log("status error!", status.value);
status.value = "normal";
}
}
);
watch(
() => default_path.value,
(newValue: string) => {
let item = disk_options.value.find((item) => item.value == newValue);
if (item && item.value && item.label) {
default_path_label.value = item.label;
path.value = default_path.value;
}
}
);
return { return {
show_dialog, show_dialog,
loading, loading,
uploading,
files, files,
columns, columns,
show_context_menu, show_context_menu,
default_path,
default_path_label,
path, path,
prev_path, prev_path,
paths, paths,
target_dom, target_dom,
upload_url, upload_url,
uploader,
disk_options,
current_file, current_file,
refresh_file_list, refresh_file_list,
refresh_file_list_async, refresh_file_list_async,
status, status,
showDialog() { showDialog(in_status: string) {
status.value = in_status;
refresh_file_list(); refresh_file_list();
show_dialog.value = true; show_dialog.value = true;
}, },
showDialogAsync(in_status: string) {
return new Promise((_resolve, _reject) => {
status.value = in_status;
refresh_file_list();
show_dialog.value = true;
resolve = _resolve;
});
},
generatorFileUploadHeaders(files: File[]) { generatorFileUploadHeaders(files: File[]) {
if (files.length > 0) { if (files.length > 0) {
return [ return [
@ -466,6 +598,10 @@ export default defineComponent({
path.value = ""; path.value = "";
status.value = "normal"; status.value = "normal";
upload_url.value = ""; upload_url.value = "";
if (resolve) {
resolve(resolve_value);
}
resolve_value = null;
}, },
async onCreateNewFolder() { async onCreateNewFolder() {
let url = GlobalData.getInstance().createCurrentRequestUrl(); let url = GlobalData.getInstance().createCurrentRequestUrl();
@ -513,6 +649,7 @@ export default defineComponent({
}); });
} }
}, },
selectFile,
async deleteFile(file: FileEntity) { async deleteFile(file: FileEntity) {
let url = GlobalData.getInstance().createCurrentRequestUrl(); let url = GlobalData.getInstance().createCurrentRequestUrl();
if (url) { if (url) {
@ -623,6 +760,8 @@ export default defineComponent({
onTableItemDBClick(evt: PointerEvent, row: FileEntity, index: number) { onTableItemDBClick(evt: PointerEvent, row: FileEntity, index: number) {
if (row && row.is_directory) { if (row && row.is_directory) {
path.value += "/" + row.name; path.value += "/" + row.name;
} else if (status.value == "select" && !row.is_directory) {
selectFile(row);
} }
}, },
backToParentPath() { backToParentPath() {
@ -642,7 +781,12 @@ export default defineComponent({
} }
return "#"; return "#";
}, },
onStartUpload() {
loading.value = true;
},
onUploaded() { onUploaded() {
uploading.value = false;
uploader.value.reset();
refresh_file_list(); refresh_file_list();
$q.notify({ $q.notify({
@ -651,6 +795,7 @@ export default defineComponent({
position: "top", position: "top",
timeout: 1500, timeout: 1500,
}); });
loading.value = false;
}, },
onFailed(info: any) { onFailed(info: any) {
console.log(info); console.log(info);
@ -661,6 +806,7 @@ export default defineComponent({
timeout: 1500, timeout: 1500,
}); });
loading.value = false; loading.value = false;
loading.value = false;
}, },
}; };
}, },

View File

@ -103,7 +103,7 @@
> >
<template v-if="item_data.name" v-slot:append> <template v-if="item_data.name" v-slot:append>
<q-icon <q-icon
item_data.name="cancel" name="cancel"
@click.stop="item_data.name = null" @click.stop="item_data.name = null"
class="cursor-pointer" class="cursor-pointer"
/> />
@ -142,13 +142,22 @@
:loading="loading" :loading="loading"
:disable="loading" :disable="loading"
filled filled
@dblclick="doSelectFile"
v-model="item_data.media_url" v-model="item_data.media_url"
:label="media_url_label" :label="media_url_label"
:hint="$t('please input') + media_url_label" :hint="
$t('please input') +
media_url_label.substr(0, media_url_label.length - 2) +
',' +
$t('dbclick select file')
"
lazy-rules lazy-rules
:rules="[ :rules="[
(val) => (val) =>
(val && val.length > 0) || $t('Please type something'), (val && val.length > 0) ||
$t('Please type something') +
',' +
$t('dbclick select file'),
]" ]"
@keydown=" @keydown="
(evt) => { (evt) => {
@ -159,7 +168,7 @@
> >
<template v-if="item_data.media_url" v-slot:append> <template v-if="item_data.media_url" v-slot:append>
<q-icon <q-icon
item_data.media_url="cancel" name="cancel"
@click.stop="item_data.media_url = null" @click.stop="item_data.media_url = null"
class="cursor-pointer" class="cursor-pointer"
/> />
@ -192,7 +201,7 @@
> >
<template v-if="item_data.user_name" v-slot:append> <template v-if="item_data.user_name" v-slot:append>
<q-icon <q-icon
item_data.user_name="cancel" name="cancel"
@click.stop="item_data.user_name = null" @click.stop="item_data.user_name = null"
class="cursor-pointer" class="cursor-pointer"
/> />
@ -225,7 +234,7 @@
> >
<template v-if="item_data.password" v-slot:append> <template v-if="item_data.password" v-slot:append>
<q-icon <q-icon
item_data.password="cancel" name="cancel"
@click.stop="item_data.password = null" @click.stop="item_data.password = null"
class="cursor-pointer" class="cursor-pointer"
/> />
@ -257,6 +266,7 @@
</q-card-actions> </q-card-actions>
</q-form> </q-form>
</q-card> </q-card>
<file-manage-dialog ref="file_manage_dialog" />
</q-dialog> </q-dialog>
</template> </template>
@ -286,8 +296,12 @@ import {
SignalSourceTreeItemEntity, SignalSourceTreeItemEntity,
} from "src/entities/SignalSourceEntity"; } from "src/entities/SignalSourceEntity";
import FileManageDialog from "src/components/FileManageDialog.vue";
import FileEntity from "src/entities/FileEntity";
export default defineComponent({ export default defineComponent({
name: "ComponentSignalSourceDialog", name: "ComponentSignalSourceDialog",
components: { FileManageDialog },
setup() { setup() {
let $store = useStore(); let $store = useStore();
@ -301,6 +315,7 @@ export default defineComponent({
item_data.window_type = "EwindowType::Multimedia"; item_data.window_type = "EwindowType::Multimedia";
const selected: any = ref(null); const selected: any = ref(null);
let loading = ref(false); let loading = ref(false);
let file_manage_dialog: any = ref(null);
let suppored_window_types = new Set<string>([ let suppored_window_types = new Set<string>([
"EwindowType::Multimedia", "EwindowType::Multimedia",
@ -413,6 +428,7 @@ export default defineComponent({
selected, selected,
loading, loading,
tree_nodes, tree_nodes,
file_manage_dialog,
showDialog(options: any) { showDialog(options: any) {
if (options) { if (options) {
type.value = options.type ?? 1; type.value = options.type ?? 1;
@ -455,6 +471,19 @@ export default defineComponent({
} catch {} } catch {}
loading.value = false; loading.value = false;
}, },
async doSelectFile() {
const obj = await file_manage_dialog.value.showDialogAsync("select");
if (obj) {
interface __I {
path: string;
file: FileEntity;
}
let { path, file }: __I = obj;
if (path && file) {
item_data.media_url = path + "/" + file.name;
}
}
},
}; };
}, },
}); });

View File

@ -96,7 +96,7 @@ export default {
"last edit time": "修改时间", "last edit time": "修改时间",
"file size": "文件大小", "file size": "文件大小",
"file name": "文件名", "file name": "文件名",
"copy file name": "拷贝文件名", "copy name": "拷贝",
"can true": "是", "can true": "是",
"can false": "否", "can false": "否",
"can exec": "可执行", "can exec": "可执行",
@ -114,4 +114,7 @@ export default {
"delete file": "文件删除", "delete file": "文件删除",
"create folder": "新建文件夹", "create folder": "新建文件夹",
"input folder name": "输入文件夹名称", "input folder name": "输入文件夹名称",
"dbclick select file": "双击选择文件",
"local disk": "本地磁盘",
usb: "U盘",
}; };