添加文件复制功能,修复所有对话框在等待时可以使用ESC中断的BUG

This commit is contained in:
fangxiang 2022-03-19 16:29:53 +08:00
parent d7376ca2fb
commit 027e31f192
27 changed files with 285 additions and 31 deletions

View File

@ -1,6 +1,6 @@
{
"name": "media_player_client",
"version": "1.2.6",
"version": "1.3.1",
"description": "A Quasar Framework app",
"productName": "MediaPlayerClient",
"author": "fangxiang <fangxiang@cloudview.work>",

View File

@ -852,6 +852,26 @@ export default class ClientConnection {
}
}
public async fileOperator(
from_path: string,
to_path: string,
operator_type: string,
force_operator: boolean = true
) {
try {
return await this.doRpc<Protocol.FileOperatorResponseEntity>(
new Protocol.FileOperatorRequestEntity(
from_path,
to_path,
operator_type,
force_operator
)
);
} catch (e) {
console.error(e);
}
}
public async getEdgeBlendingInfo() {
return await this.doRpc<Protocol.GetEdgeBlendingInfoResponseEntity>(
new Protocol.GetEdgeBlendingInfoRequestEntity(0)

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -1,9 +1,8 @@
<template>
<q-dialog
v-model="show_dialog"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}
@ -13,7 +13,7 @@
>
<q-card
class="overflow-hidden"
style="overflow-y: scroll; max-width: 60vw; max-height: 80vh"
style="overflow-y: scroll; max-width: 70vw; max-height: 80vh"
>
<q-card-section class="q-ma-none q-pa-sm">
<div class="row">
@ -27,6 +27,7 @@
<div>
<q-btn
:loading="loading"
:disable="loading"
flat
round
icon="close"
@ -122,6 +123,20 @@
{{ $t("refresh") }}
</q-tooltip>
</q-btn>
<q-btn
flat
icon="content_paste"
@click="pasteFile"
:disable="
!(clipboard && clipboard.type && clipboard.type != 'NONE') ||
path == clipboard.path
"
:label="$t('paste')"
>
<q-tooltip>
{{ $t("paste") }}
</q-tooltip>
</q-btn>
<q-btn
flat
icon="create_new_folder"
@ -159,7 +174,7 @@
<q-separator />
<q-card-section
style="max-height: 50vh; width: 60vw; max-height: 80vh"
style="max-height: 50vh; width: 70vw; max-height: 80vh"
class="scroll q-pa-none q-ma-none"
>
<q-table
@ -182,6 +197,12 @@
<template v-slot:body-cell="props">
<q-td :props="props">
<div v-if="props.col.name == 'name'">
<q-icon
v-if="false && clipboard.name == props.value"
:name="clipboard.type == 'COPY' ? 'file_copy' : 'content_cut'"
style="color: #ffbe4a; font-size: 2.5em"
>
</q-icon>
<q-icon
:name="props.row.is_directory ? 'folder' : 'description'"
style="color: #ffbe4a; font-size: 2.5em"
@ -206,6 +227,13 @@
</q-tooltip>
</a>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="#" @click="(evt) => copyFile(props.row)">
{{ $t("_copy2") }}
<q-tooltip>
{{ $t("click") }}{{ $t("_copy2") }}
</q-tooltip>
</a>
&nbsp;&nbsp;&nbsp;&nbsp;
<a href="#" @click="(evt) => deleteFile(props.row)">
{{ $t("delete") }}
<q-tooltip>
@ -250,6 +278,7 @@
<q-menu :target="target_dom" v-model="show_context_menu">
<q-list>
<q-item
v-if="false"
clickable
v-close-popup
@click="(evt) => copyStringToClipboard(current_file.name)"
@ -257,6 +286,38 @@
<q-item-section avatar><q-icon name="file_copy" /></q-item-section>
<q-item-section>{{ $t("copy name") }}</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="(evt) => copyFile(current_file)"
>
<q-item-section avatar><q-icon name="file_copy" /></q-item-section>
<q-item-section>{{ $t("_copy2") }}</q-item-section>
</q-item>
<q-item
v-if="false"
clickable
v-close-popup
@click="(evt) => cutFile(current_file)"
>
<q-item-section avatar><q-icon name="content_cut" /></q-item-section>
<q-item-section>{{ $t("cut") }}</q-item-section>
</q-item>
<q-item
v-if="false"
:disable="
!(clipboard && clipboard.type && clipboard.type != 'NONE') ||
path == clipboard.path
"
clickable
v-close-popup
@click="(evt) => pasteFile()"
>
<q-item-section avatar
><q-icon name="content_paste"
/></q-item-section>
<q-item-section>{{ $t("paste") }}</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@ -324,7 +385,7 @@ a:hover {
</style>
<script lang="ts">
import { defineComponent, ref, Ref, watch, computed } from "vue";
import { defineComponent, ref, Ref, reactive, watch, computed } from "vue";
import { useStore } from "src/store";
import { useQuasar, date, copyToClipboard } from "quasar";
import { useI18n } from "vue-i18n";
@ -333,6 +394,7 @@ import GlobalData from "src/common/GlobalData";
import FileEntity from "src/entities/FileEntity";
import { HttpProtocol } from "src/entities/HttpProtocol";
import NormalResult from "src/entities/NormalResult";
import { Protocol } from "src/entities/WSProtocol";
class _BreadcrumbItem {
name: string = "";
@ -348,6 +410,27 @@ class _BreadcrumbItem {
}
}
class _ClipboardType {
static kTypeNone = "NONE";
static kTypeCopy = "COPY";
static kTypeCut = "CUT";
name: string = "";
path: string = "";
type: string = _ClipboardType.kTypeNone;
is_directory = false;
get full_path() {
return this.path + "/" + this.name;
}
clear() {
this.name = "";
this.path = "";
this.type = _ClipboardType.kTypeNone;
}
}
export default defineComponent({
name: "ComponentFileManageDialog",
@ -375,6 +458,8 @@ export default defineComponent({
let resolve_value: any = null;
const filters: Ref<string[]> = ref([]);
const clipboard = reactive(new _ClipboardType()); //
const disk_options = ref([
{
label: $t.t("local disk"),
@ -412,7 +497,7 @@ export default defineComponent({
format: (val: any) => `${val}`,
sortable: true,
},
{
/*{
name: "can_read",
align: "center",
label: $t.t("can read"),
@ -435,7 +520,7 @@ export default defineComponent({
field: (val: FileEntity) => val && val.can_exec,
format: (val: any) => `${$t.t(val ? "can true" : "can false")}`,
sortable: true,
},
},*/
{
align: "center",
name: "operator",
@ -629,6 +714,7 @@ export default defineComponent({
uploader,
disk_options,
current_file,
clipboard,
refresh_file_list,
refresh_file_list_async,
status,
@ -642,7 +728,6 @@ export default defineComponent({
show_dialog.value = true;
},
showDialogAsync(in_status: string, filter?: string) {
console.log(filter);
return new Promise((_resolve, _reject) => {
status.value = in_status;
parseFilter(filter);
@ -674,6 +759,7 @@ export default defineComponent({
path.value = default_path.value;
status.value = "normal";
upload_url.value = "";
clipboard.clear();
if (resolve) {
resolve(resolve_value);
}
@ -884,6 +970,103 @@ export default defineComponent({
loading.value = false;
loading.value = false;
},
copyFile(file: FileEntity) {
if (file) {
clipboard.name = file.name;
clipboard.path = path.value;
clipboard.type = _ClipboardType.kTypeCopy;
clipboard.is_directory = file.is_directory;
$q.notify({
color: "positive",
icon: "done",
html: true,
message:
$t.t("copy to colipboard success") +
"!" +
"<br />" +
$t.t(
"please use the paste command to paste to another directory"
) +
"!",
position: "top",
timeout: 1500,
});
}
},
cutFile(file: FileEntity) {
if (file) {
clipboard.name = file.name;
clipboard.path = path.value;
clipboard.type = _ClipboardType.kTypeCut;
clipboard.is_directory = file.is_directory;
}
},
pasteFile() {
if (clipboard && clipboard.type) {
let operator_type = "NONE";
if (clipboard.type == _ClipboardType.kTypeCopy) {
operator_type =
Protocol.FileOperatorRequestEntity.kOperatorTypeCopy;
} else if (clipboard.type == _ClipboardType.kTypeCut) {
operator_type = Protocol.FileOperatorRequestEntity.kOperatorTypeCut;
}
$q.dialog({
title: $t.t("Confirm"),
html: true,
message:
(clipboard.type == _ClipboardType.kTypeCopy
? $t.t("_copy2")
: $t.t("cut")) +
(clipboard.is_directory ? $t.t("directory") : $t.t("file")) +
$t.t("from") +
' "' +
clipboard.full_path +
'" ' +
$t.t("to") +
' "' +
(path.value + "/" + clipboard.name) +
'"' +
"<br/>" +
"<span style='color:red;'>" +
$t.t(
"if the file size is too large, wait for the result patiently. don't refresh the page or perform other operations during the process. otherwise, unexpected consequences may occur"
) +
"!" +
"</span>",
cancel: true,
persistent: true,
}).onOk(async () => {
let success = false;
loading.value = true;
try {
const reponse = await GlobalData.getInstance()
.getCurrentClient()
?.fileOperator(
clipboard.full_path,
path.value + "/" + clipboard.name,
operator_type
);
success = reponse?.success ?? false;
} catch {}
loading.value = false;
if (success) {
refresh_file_list_async();
}
$q.notify({
color: success ? "positive" : "negative",
icon: success ? "done" : "warning",
message:
$t.t("copy") +
(clipboard.is_directory ? $t.t("directory") : $t.t("file")) +
(success ? $t.t("success") : $t.t("fail")) +
"!",
position: "top",
timeout: 1500,
});
});
}
},
};
},
});

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -48,7 +48,6 @@
</div>
</q-item-section>
<q-popup-proxy context-menu>
<q-popup-proxy context-menu />
<q-list>
<q-item
v-if="

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -31,7 +31,6 @@
</div>
</q-item-section>
<q-popup-proxy context-menu>
<q-popup-proxy context-menu />
<q-list>
<q-item
v-if="

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -34,7 +34,6 @@
</div>
</q-item-section>
<q-popup-proxy context-menu>
<q-popup-proxy context-menu />
<q-list>
<q-item
v-if="

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
} else if (
evt.keyCode == 85 &&

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -40,7 +40,6 @@
</div>
</q-item-section>
<q-popup-proxy context-menu>
<q-popup-proxy context-menu />
<q-list>
<q-item
v-if="

View File

@ -6,7 +6,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -5,7 +5,7 @@
@before-hide="resetData"
@keydown="
(evt) => {
if (evt.keyCode == 27) {
if (!loading && evt.keyCode == 27) {
show_dialog = false;
}
}

View File

@ -350,6 +350,9 @@ export namespace Protocol {
public static get kRpcSetDevicePowerMode() {
return Commands.PROTOCOL_PREFIX + "RpcSetDevicePowerMode";
}
public static get kRpcFileOperator() {
return Commands.PROTOCOL_PREFIX + "RpcFileOperator";
}
static _all_commands = new Set([
Commands.kUnKnowCommand,
@ -437,6 +440,7 @@ export namespace Protocol {
Commands.kRpcSetEdgeBlendingInfo,
Commands.kSetEdgeBlendingPoint,
Commands.kRpcSetDevicePowerMode,
Commands.kRpcFileOperator,
]);
public static get AllCommands() {
@ -2123,4 +2127,44 @@ export namespace Protocol {
this.point = point;
}
}
export class FileOperatorRequestEntity extends PacketEntity {
static kOperatorTypeNone = "NONE";
static kOperatorTypeCopy = "COPY";
static kOperatorTypeCut = "CUT";
from_path = "";
to_path = "";
operator_type = "";
force_operator = false;
ext_data = "";
constructor(
from_path: string,
to_path: string,
operator_type: string,
force_operator: boolean = true,
rpcid?: number
) {
super();
this.timeout = 1000 * 60 * 5;
this.rpc_id = rpcid ?? 0;
this.command = Commands.kRpcFileOperator;
this.from_path = from_path ?? "";
this.to_path = to_path ?? "";
this.operator_type =
operator_type ?? FileOperatorRequestEntity.kOperatorTypeNone;
this.force_operator = force_operator;
}
}
export class FileOperatorResponseEntity extends PacketEntity {
success = true;
message = "";
constructor() {
super();
this.command = Commands.kRpcFileOperator;
}
}
}

View File

@ -420,4 +420,16 @@ export default {
"remember password": "记住密码",
"auto login": "自动登录",
"back to login page": "返回登录页面",
_copy2: "复制",
cut: "剪切",
paste: "粘贴",
"if the file size is too large, wait for the result patiently. don't refresh the page or perform other operations during the process. otherwise, unexpected consequences may occur":
"如果文件很大,请耐心等待结果,中途不要刷新页面或做其他操作,以免造成不可预知的严重后果",
directory: "目录",
file: "文件",
from: "从",
to: "到",
"copy to colipboard success": "成功拷贝到剪切板",
"please use the paste command to paste to another directory":
"请使用粘贴命令粘贴到其它目录",
};