Browse Source

Merge branch 'master' of https://gitee.com/godoos/godoos

master
godo 5 months ago
parent
commit
b0c72a8ae5
  1. 352
      frontend/src/components/builtin/FileList.vue

352
frontend/src/components/builtin/FileList.vue

@ -17,7 +17,10 @@
</div> </div>
</div> </div>
</template> </template>
<div draggable="true" class="file-item" :class="{ <div
draggable="true"
class="file-item"
:class="{
chosen: chosenIndexs.includes(index), chosen: chosenIndexs.includes(index),
'no-chosen': !chosenIndexs.includes(index), 'no-chosen': !chosenIndexs.includes(index),
'mode-icon': mode === 'icon', 'mode-icon': mode === 'icon',
@ -26,27 +29,52 @@
'mode-middle': mode === 'middle', 'mode-middle': mode === 'middle',
'mode-detail': mode === 'detail', 'mode-detail': mode === 'detail',
'drag-over': hoverIndex === index, 'drag-over': hoverIndex === index,
}" :style="{ }"
:style="{
'--theme-color': theme === 'light' ? '#ffffff6b' : '#3bdbff3d', '--theme-color': theme === 'light' ? '#ffffff6b' : '#3bdbff3d',
}" v-for="(item, index) in fileList" :key="item.path" @dblclick="handleOnOpen(item)" }"
v-for="(item, index) in fileList"
:key="item.path"
@dblclick="handleOnOpen(item)"
@touchstart.passive="doubleTouch($event, item)" @touchstart.passive="doubleTouch($event, item)"
@contextmenu.stop.prevent="handleRightClick($event, item, index)" @drop="hadnleDrop($event, item.path)" @contextmenu.stop.prevent="handleRightClick($event, item, index)"
@dragenter.prevent="handleDragEnter(index)" @dragover.prevent @dragleave="handleDragLeave()" @drop="hadnleDrop($event, item.path)"
@dragstart.stop="startDragApp($event, item)" @click="handleClick(index, item)" @mousedown.stop :ref="(ref: any) => { @dragenter.prevent="handleDragEnter(index)"
@dragover.prevent
@dragleave="handleDragLeave()"
@dragstart.stop="startDragApp($event, item)"
@click="handleClick(index, item)"
@mousedown.stop
:ref="(ref: any) => {
if (ref) { if (ref) {
appPositions[index] = markRaw(ref as Element); appPositions[index] = markRaw(ref as Element);
} }
} }
"> "
>
<div class="file-item_img"> <div class="file-item_img">
<FileIcon :file="item" /> <FileIcon :file="item" />
</div> </div>
<span v-if="editIndex !== index" class="file-item_title"> <span
v-if="editIndex !== index"
class="file-item_title"
>
{{ getName(item) }} {{ getName(item) }}
</span> </span>
<textarea autofocus draggable="false" @dragover.stop @dragstart.stop @dragenter.stop @mousedown.stop <textarea
@dblclick.stop @click.stop @blur="onEditNameEnd" v-if="editIndex === index" autofocus
class="file-item_title file-item_editing" v-model="editName"></textarea> draggable="false"
@dragover.stop
@dragstart.stop
@dragenter.stop
@mousedown.stop
@dblclick.stop
@click.stop
@keydown.enter.prevent="onEditNameEnd"
v-if="editIndex === index"
class="file-item_title file-item_editing"
v-model="editName"
></textarea>
<template v-if="mode === 'detail'"> <template v-if="mode === 'detail'">
<div class="file-item_type"> <div class="file-item_type">
<span>{{ item.isDirectory ? "-" : dealSize(item.size) }}</span> <span>{{ item.isDirectory ? "-" : dealSize(item.size) }}</span>
@ -64,33 +92,33 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useAppMenu } from "@/hook/useAppMenu"; import { useAppMenu } from "@/hook/useAppMenu";
import { useContextMenu } from "@/hook/useContextMenu.ts"; import { useContextMenu } from "@/hook/useContextMenu.ts";
import { useFileDrag } from "@/hook/useFileDrag"; import { useFileDrag } from "@/hook/useFileDrag";
import { Rect } from "@/hook/useRectChosen"; import { Rect } from "@/hook/useRectChosen";
import { dealSystemName, t } from "@/i18n"; import { dealSystemName, t } from "@/i18n";
import { useChooseStore } from "@/stores/choose"; import { useChooseStore } from "@/stores/choose";
import { getSystemKey } from "@/system/config"; import { getSystemKey } from "@/system/config";
import { emitEvent, mountEvent } from "@/system/event"; import { emitEvent, mountEvent } from "@/system/event";
import { addKnowledge } from "@/hook/useAi"; import { addKnowledge } from "@/hook/useAi";
import { import {
basename, basename,
BrowserWindow, BrowserWindow,
Notify, Notify,
OsFileWithoutContent, OsFileWithoutContent,
useSystem, useSystem,
} from "@/system/index.ts"; } from "@/system/index.ts";
import { Menu } from "@/system/menu/Menu"; import { Menu } from "@/system/menu/Menu";
import { throttle } from "@/util/debounce"; import { throttle } from "@/util/debounce";
import { dealSize } from "@/util/file"; import { dealSize } from "@/util/file";
import { markRaw, onMounted, ref } from "vue"; import { markRaw, onMounted, ref } from "vue";
import { notifyError, notifySuccess } from "@/util/msg";
const { openPropsWindow, copyFile, createLink, deleteFile } = const { openPropsWindow, copyFile, createLink, deleteFile } =
useContextMenu(); useContextMenu();
const sys = useSystem(); const sys = useSystem();
const { startDrag, folderDrop } = useFileDrag(sys); const { startDrag, folderDrop } = useFileDrag(sys);
const choose = useChooseStore(); const choose = useChooseStore();
const props = defineProps({ const props = defineProps({
onChosen: { onChosen: {
type: Function, type: Function,
required: true, required: true,
@ -119,9 +147,9 @@ const props = defineProps({
type: String, type: String,
default: "icon", default: "icon",
}, },
}); });
function getName(item: any) { function getName(item: any) {
const name = dealSystemName(basename(item.path)); const name = dealSystemName(basename(item.path));
// console.log(name) // console.log(name)
// console.log(item.path) // console.log(item.path)
@ -130,9 +158,9 @@ function getName(item: any) {
} else { } else {
return name; return name;
} }
} }
function handleOnOpen(item: OsFileWithoutContent) { function handleOnOpen(item: OsFileWithoutContent) {
// props.onOpen(item); // props.onOpen(item);
// emitEvent('desktop.app.open'); // emitEvent('desktop.app.open');
chosenIndexs.value = []; chosenIndexs.value = [];
@ -145,14 +173,14 @@ function handleOnOpen(item: OsFileWithoutContent) {
props.onOpen(item); props.onOpen(item);
emitEvent("desktop.app.open"); emitEvent("desktop.app.open");
} }
} }
function hadnleDrop(mouse: DragEvent, path: string) { function hadnleDrop(mouse: DragEvent, path: string) {
hoverIndex.value = -1; hoverIndex.value = -1;
folderDrop(mouse, path); folderDrop(mouse, path);
chosenIndexs.value = []; chosenIndexs.value = [];
} }
let expired: number | null = null; let expired: number | null = null;
function doubleTouch(e: TouchEvent, item: OsFileWithoutContent) { function doubleTouch(e: TouchEvent, item: OsFileWithoutContent) {
if (e.touches.length === 1) { if (e.touches.length === 1) {
if (!expired) { if (!expired) {
expired = e.timeStamp + 400; expired = e.timeStamp + 400;
@ -167,49 +195,40 @@ function doubleTouch(e: TouchEvent, item: OsFileWithoutContent) {
expired = e.timeStamp + 400; expired = e.timeStamp + 400;
} }
} }
} }
const editIndex = ref<number>(-1); const editIndex = ref<number>(-1);
const editName = ref<string>(""); const editName = ref<string>("");
async function onEditNameEnd() {
async function onEditNameEnd() {
const editEndName = editName.value.trim(); const editEndName = editName.value.trim();
if (editEndName && editIndex.value >= 0) { if (editIndex.value >= 0) {
const editpath: any = const currentItem = props.fileList[editIndex.value];
props.fileList[editIndex.value].path.toString(); const success = await renameFile(currentItem, editEndName);
let newPath: any; if (!success) {
let sp = "/"; editName.value = basename(currentItem.path);
if (editpath.indexOf("/") === -1) {
sp = "\\";
}
newPath = editpath?.split(sp);
newPath.pop();
newPath.push(editEndName);
newPath = newPath.join(sp);
await sys?.fs.rename(editpath, newPath);
props.onRefresh();
if (newPath.indexOf("Desktop") !== -1) {
sys.refershAppList();
} }
} }
editIndex.value = -1; editIndex.value = -1;
} }
mountEvent("edit.end", () => {
mountEvent("edit.end", () => {
onEditNameEnd(); onEditNameEnd();
}); });
const hoverIndex = ref<number>(-1); const hoverIndex = ref<number>(-1);
const appPositions = ref<Array<Element>>([]); const appPositions = ref<Array<Element>>([]);
const chosenIndexs = ref<Array<number>>([]); const chosenIndexs = ref<Array<number>>([]);
import { isMobileDevice } from "@/util/device"; import { isMobileDevice } from "@/util/device";
const isMobile = ref<boolean>(false); const isMobile = ref<boolean>(false);
function handleClick(index: number, item: OsFileWithoutContent) { function handleClick(index: number, item: OsFileWithoutContent) {
chosenIndexs.value = [index]; chosenIndexs.value = [index];
if (isMobile.value) { if (isMobile.value) {
handleOnOpen(item) handleOnOpen(item);
} }
} }
onMounted(() => { onMounted(() => {
isMobile.value = isMobileDevice(); isMobile.value = isMobileDevice();
chosenIndexs.value = []; chosenIndexs.value = [];
props.onChosen( props.onChosen(
@ -233,9 +252,9 @@ onMounted(() => {
chosenIndexs.value = tempChosen; chosenIndexs.value = tempChosen;
}, 100) }, 100)
); );
}); });
function startDragApp(mouse: DragEvent, item: OsFileWithoutContent) { function startDragApp(mouse: DragEvent, item: OsFileWithoutContent) {
if (chosenIndexs.value.length) { if (chosenIndexs.value.length) {
startDrag( startDrag(
mouse, mouse,
@ -251,34 +270,31 @@ function startDragApp(mouse: DragEvent, item: OsFileWithoutContent) {
chosenIndexs.value = []; chosenIndexs.value = [];
}); });
} }
} }
document.addEventListener('copy', function () { document.addEventListener("copy", function () {
const files = chosenIndexs.value.map( const files = chosenIndexs.value.map((index) => props.fileList[index]);
(index) => props.fileList[index]
)
if (files.length > 0) { if (files.length > 0) {
copyFile(files); copyFile(files);
chosenIndexs.value = []; chosenIndexs.value = [];
} }
});
}); // document.addEventListener('keydown', function (event) {
// document.addEventListener('keydown', function (event) { // // Control + C
// // Control + C // if (event.ctrlKey && event.key === 'c') {
// if (event.ctrlKey && event.key === 'c') { // //console.log('Control + C ');
// //console.log('Control + C '); // copyFile(
// copyFile( // chosenIndexs.value.map(
// chosenIndexs.value.map( // (index) => props.fileList[index]
// (index) => props.fileList[index] // )
// ) // );
// ); // chosenIndexs.value = [];
// chosenIndexs.value = []; // }
// } // });
// }); function handleRightClick(
function handleRightClick(
mouse: MouseEvent, mouse: MouseEvent,
item: OsFileWithoutContent, item: OsFileWithoutContent,
index: number index: number
) { ) {
if (chosenIndexs.value.length <= 1) { if (chosenIndexs.value.length <= 1) {
chosenIndexs.value = [ chosenIndexs.value = [
props.fileList.findIndex((app) => app.path === item.path), props.fileList.findIndex((app) => app.path === item.path),
@ -369,9 +385,9 @@ function handleRightClick(
menuArr.push({ menuArr.push({
label: "加入知识库", label: "加入知识库",
click: () => { click: () => {
console.log(item) console.log(item);
addKnowledge(item.path).then((res: any) => { addKnowledge(item.path).then((res: any) => {
console.log(res) console.log(res);
if (res.code != 0) { if (res.code != 0) {
new Notify({ new Notify({
title: t("tips"), title: t("tips"),
@ -384,7 +400,7 @@ function handleRightClick(
}); });
props.onRefresh(); props.onRefresh();
} }
}) });
}, },
}); });
} else { } else {
@ -406,7 +422,6 @@ function handleRightClick(
}, },
}); });
} }
} }
if (choose.ifShow) { if (choose.ifShow) {
menuArr.push({ menuArr.push({
@ -538,22 +553,65 @@ function handleRightClick(
//console.log(ext) //console.log(ext)
Menu.buildFromTemplate(menuArr).popup(mouse); Menu.buildFromTemplate(menuArr).popup(mouse);
} }
function handleDragEnter(index: number) { function handleDragEnter(index: number) {
hoverIndex.value = index; hoverIndex.value = index;
} }
function handleDragLeave() { function handleDragLeave() {
hoverIndex.value = -1; hoverIndex.value = -1;
} }
// function dealtName(name: string) { // function dealtName(name: string) {
// return name; // return name;
// } // }
function getPathSeparator(path: string): string {
return path.indexOf("/") === -1 ? "\\" : "/";
}
function buildNewPath(editpath: string, editEndName: string): string {
const sp = getPathSeparator(editpath);
const pathParts = editpath.split(sp);
pathParts.pop();
pathParts.push(editEndName);
return pathParts.join(sp);
}
async function renameFile(
currentItem: OsFileWithoutContent,
newName: string
) {
const currentName = basename(currentItem.path);
if (newName && newName !== currentName) {
const editpath = currentItem.path.toString();
const newPath = buildNewPath(editpath, newName);
if (await sys?.fs.exists(newPath)) {
notifyError("文件名已存在,请选择其他名称。");
return false;
}
try {
await sys?.fs.rename(editpath, newPath);
props.onRefresh();
if (newPath.includes("Desktop")) {
sys.refershAppList();
}
notifySuccess("重命名成功");
return true;
} catch (error) {
console.error("重命名失败:", error);
notifyError("重命名失败,请重试。");
return false;
}
}
return false;
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.file-item { .file-item {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -585,21 +643,36 @@ function handleDragLeave() {
display: inline-block !important; display: inline-block !important;
outline: none; outline: none;
pointer-events: all; pointer-events: all;
padding: 0; padding: 6px 10px;
margin: 0; margin: 0;
min-width: 0; min-width: 120px;
height: min-content !important; max-width: 100%;
width: min-content !important; height: auto !important;
width: auto !important;
resize: none; resize: none;
border-radius: 0; border-radius: 6px;
border: 1px solid var(--border-color, #ccc);
background-color: var(--input-bg-color, #f9f9f9);
color: var(--input-text-color, #333);
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15);
transition: border-color 0.3s, box-shadow 0.3s,
background-color 0.3s;
overflow-x: auto;
white-space: nowrap;
} }
}
.file-item:hover { .file-item_editing:focus {
border-color: var(--focus-border-color, #0056b3);
box-shadow: 0 3px 8px rgba(0, 86, 179, 0.3);
background-color: var(--focus-bg-color, #e6f7ff);
}
}
.file-item:hover {
background-color: #b1f1ff4c; background-color: #b1f1ff4c;
} }
.chosen { .chosen {
border: 1px dashed #3bdbff3d; border: 1px dashed #3bdbff3d;
// background-color: #ffffff6b; // background-color: #ffffff6b;
background-color: var(--theme-color); background-color: var(--theme-color);
@ -612,9 +685,9 @@ function handleDragLeave() {
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
} }
} }
.no-chosen { .no-chosen {
.file-item_title { .file-item_title {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -623,15 +696,15 @@ function handleDragLeave() {
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
} }
} }
.drag-over { .drag-over {
border: 1px dashed #3bdbff3d; border: 1px dashed #3bdbff3d;
// background-color: #ffffff6b; // background-color: #ffffff6b;
background-color: var(--theme-color); background-color: var(--theme-color);
} }
.mode-icon { .mode-icon {
.file-item_img { .file-item_img {
width: 60%; width: 60%;
height: calc(0.6 * var(--desk-item-size)); height: calc(0.6 * var(--desk-item-size));
@ -648,9 +721,9 @@ function handleDragLeave() {
word-break: break-all; word-break: break-all;
flex-grow: 0; flex-grow: 0;
} }
} }
.mode-list { .mode-list {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
@ -669,24 +742,24 @@ function handleDragLeave() {
height: min-content; height: min-content;
word-break: break-all; word-break: break-all;
} }
} }
.mode-icon { .mode-icon {
width: var(--desk-item-size); width: var(--desk-item-size);
height: var(--desk-item-size); height: var(--desk-item-size);
} }
.mode-big { .mode-big {
width: calc(var(--desk-item-size) * 2.5); width: calc(var(--desk-item-size) * 2.5);
height: calc(var(--desk-item-size) * 2.5); height: calc(var(--desk-item-size) * 2.5);
} }
.mode-middle { .mode-middle {
width: calc(var(--desk-item-size) * 1.5); width: calc(var(--desk-item-size) * 1.5);
height: calc(var(--desk-item-size) * 1.5); height: calc(var(--desk-item-size) * 1.5);
} }
.mode-detail { .mode-detail {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
@ -716,14 +789,14 @@ function handleDragLeave() {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
} }
.file-bar:hover { .file-bar:hover {
background-color: unset; background-color: unset;
user-select: none; user-select: none;
} }
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
.file-item { .file-item {
height: vh(70); height: vh(70);
display: flex; display: flex;
@ -751,6 +824,5 @@ function handleDragLeave() {
background-color: transparent; background-color: transparent;
border: 1px solid transparent; border: 1px solid transparent;
} }
}
}
</style> </style>

Loading…
Cancel
Save