feat: 添加 @vueuse/core 依赖并重构模板树组件,优化创建模板界面
This commit is contained in:
1 parent
2f85832b89
commit
87ce5cb24f
5 files changed
+306
-156
No files matched your search
@@ -43,6 +43,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdi/font": "^7.4.47",
|
"@mdi/font": "^7.4.47",
|
||||||
|
"@vueuse/core": "^14.0.0",
|
||||||
"electron-log": "^5.4.3",
|
"electron-log": "^5.4.3",
|
||||||
"fs-extra": "^11.3.2",
|
"fs-extra": "^11.3.2",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
|
|||||||
Generated
+38
-4
@@ -11,6 +11,9 @@ importers:
|
|||||||
'@mdi/font':
|
'@mdi/font':
|
||||||
specifier: ^7.4.47
|
specifier: ^7.4.47
|
||||||
version: 7.4.47
|
version: 7.4.47
|
||||||
|
'@vueuse/core':
|
||||||
|
specifier: ^14.0.0
|
||||||
|
version: 14.0.0(vue@3.5.22(typescript@5.9.3))
|
||||||
electron-log:
|
electron-log:
|
||||||
specifier: ^5.4.3
|
specifier: ^5.4.3
|
||||||
version: 5.4.3
|
version: 5.4.3
|
||||||
@@ -286,8 +289,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==}
|
resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
'@electron/node-gyp@git+https://git@github.com:electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2':
|
'@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2':
|
||||||
resolution: {commit: 06b29aafb7708acef8b3669835c8a7857ebc92d2, repo: git@github.com:electron/node-gyp.git, type: git}
|
resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2}
|
||||||
version: 10.2.0-electron.1
|
version: 10.2.0-electron.1
|
||||||
engines: {node: '>=12.13.0'}
|
engines: {node: '>=12.13.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -802,6 +805,9 @@ packages:
|
|||||||
'@types/verror@1.10.11':
|
'@types/verror@1.10.11':
|
||||||
resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==}
|
resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==}
|
||||||
|
|
||||||
|
'@types/web-bluetooth@0.0.21':
|
||||||
|
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
|
||||||
|
|
||||||
'@types/yauzl@2.10.3':
|
'@types/yauzl@2.10.3':
|
||||||
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
|
resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
|
||||||
|
|
||||||
@@ -976,6 +982,19 @@ packages:
|
|||||||
vue: ^3.0.0
|
vue: ^3.0.0
|
||||||
vuetify: ^3.0.0
|
vuetify: ^3.0.0
|
||||||
|
|
||||||
|
'@vueuse/core@14.0.0':
|
||||||
|
resolution: {integrity: sha512-d6tKRWkZE8IQElX2aHBxXOMD478fHIYV+Dzm2y9Ag122ICBpNKtGICiXKOhWU3L1kKdttDD9dCMS4bGP3jhCTQ==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.0
|
||||||
|
|
||||||
|
'@vueuse/metadata@14.0.0':
|
||||||
|
resolution: {integrity: sha512-6yoGqbJcMldVCevkFiHDBTB1V5Hq+G/haPlGIuaFZHpXC0HADB0EN1ryQAAceiW+ryS3niUwvdFbGiqHqBrfVA==}
|
||||||
|
|
||||||
|
'@vueuse/shared@14.0.0':
|
||||||
|
resolution: {integrity: sha512-mTCA0uczBgurRlwVaQHfG0Ja7UdGe4g9mwffiJmvLiTtp1G4AQyIjej6si/k8c8pUwTfVpNufck+23gXptPAkw==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.0
|
||||||
|
|
||||||
'@xmldom/xmldom@0.8.10':
|
'@xmldom/xmldom@0.8.10':
|
||||||
resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==}
|
resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
@@ -3403,7 +3422,7 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@electron/node-gyp@git+https://git@github.com:electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2':
|
'@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2':
|
||||||
dependencies:
|
dependencies:
|
||||||
env-paths: 2.2.1
|
env-paths: 2.2.1
|
||||||
exponential-backoff: 3.1.2
|
exponential-backoff: 3.1.2
|
||||||
@@ -3440,7 +3459,7 @@ snapshots:
|
|||||||
|
|
||||||
'@electron/rebuild@3.7.2':
|
'@electron/rebuild@3.7.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@electron/node-gyp': git+https://git@github.com:electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2
|
'@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2
|
||||||
'@malept/cross-spawn-promise': 2.0.0
|
'@malept/cross-spawn-promise': 2.0.0
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
debug: 4.4.0
|
debug: 4.4.0
|
||||||
@@ -3853,6 +3872,8 @@ snapshots:
|
|||||||
'@types/verror@1.10.11':
|
'@types/verror@1.10.11':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@types/web-bluetooth@0.0.21': {}
|
||||||
|
|
||||||
'@types/yauzl@2.10.3':
|
'@types/yauzl@2.10.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.15.15
|
'@types/node': 22.15.15
|
||||||
@@ -4136,6 +4157,19 @@ snapshots:
|
|||||||
vue: 3.5.22(typescript@5.9.3)
|
vue: 3.5.22(typescript@5.9.3)
|
||||||
vuetify: 3.10.5(typescript@5.9.3)(vite-plugin-vuetify@2.1.2)(vue@3.5.22(typescript@5.9.3))
|
vuetify: 3.10.5(typescript@5.9.3)(vite-plugin-vuetify@2.1.2)(vue@3.5.22(typescript@5.9.3))
|
||||||
|
|
||||||
|
'@vueuse/core@14.0.0(vue@3.5.22(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
'@types/web-bluetooth': 0.0.21
|
||||||
|
'@vueuse/metadata': 14.0.0
|
||||||
|
'@vueuse/shared': 14.0.0(vue@3.5.22(typescript@5.9.3))
|
||||||
|
vue: 3.5.22(typescript@5.9.3)
|
||||||
|
|
||||||
|
'@vueuse/metadata@14.0.0': {}
|
||||||
|
|
||||||
|
'@vueuse/shared@14.0.0(vue@3.5.22(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
vue: 3.5.22(typescript@5.9.3)
|
||||||
|
|
||||||
'@xmldom/xmldom@0.8.10': {}
|
'@xmldom/xmldom@0.8.10': {}
|
||||||
|
|
||||||
abbrev@1.1.1: {}
|
abbrev@1.1.1: {}
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
<template>
|
||||||
|
<v-card
|
||||||
|
variant="outlined"
|
||||||
|
class="pa-2"
|
||||||
|
:height="height"
|
||||||
|
@contextmenu.prevent="emit('showContextMenu', $event, null)"
|
||||||
|
>
|
||||||
|
<v-treeview
|
||||||
|
v-model:expanded="localExpanded"
|
||||||
|
:items="items"
|
||||||
|
item-title="name"
|
||||||
|
item-key="id"
|
||||||
|
item-children="children"
|
||||||
|
activatable
|
||||||
|
open-on-click
|
||||||
|
:return-object="false"
|
||||||
|
>
|
||||||
|
<template #prepend="{ item }">
|
||||||
|
<v-icon
|
||||||
|
:color="item.type === 'directory' ? 'warning' : 'info'"
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
item.type === 'directory'
|
||||||
|
? 'mdi-folder-outline'
|
||||||
|
: 'mdi-file-document-outline'
|
||||||
|
}}
|
||||||
|
</v-icon>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #title="{ item }">
|
||||||
|
<span
|
||||||
|
@contextmenu.prevent="emit('showContextMenu', $event, item)"
|
||||||
|
class="cursor-pointer d-flex align-center"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
<v-btn
|
||||||
|
v-if="!readOnly && item.type === 'directory'"
|
||||||
|
icon
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
class="ml-2"
|
||||||
|
@click.stop="emit('addNewItemToCurrentDirectory', item)"
|
||||||
|
>
|
||||||
|
<v-icon size="small">mdi-plus</v-icon>
|
||||||
|
<v-tooltip
|
||||||
|
v-if="!readOnly"
|
||||||
|
activator="parent"
|
||||||
|
location="top"
|
||||||
|
>
|
||||||
|
添加到目录
|
||||||
|
</v-tooltip>
|
||||||
|
</v-btn>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #append="{ item }">
|
||||||
|
<div
|
||||||
|
v-if="!readOnly"
|
||||||
|
class="d-flex align-center ga-1"
|
||||||
|
>
|
||||||
|
<v-btn
|
||||||
|
v-if="item.type === 'file'"
|
||||||
|
icon
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
@click.stop="emit('editFile', item)"
|
||||||
|
>
|
||||||
|
<v-icon size="small"> mdi-pencil </v-icon>
|
||||||
|
<v-tooltip
|
||||||
|
activator="parent"
|
||||||
|
location="top"
|
||||||
|
>
|
||||||
|
编辑内容
|
||||||
|
</v-tooltip>
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
<v-btn
|
||||||
|
icon
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
@click.stop="emit('deleteItem', item)"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
v-if="!readOnly"
|
||||||
|
size="small"
|
||||||
|
color="error"
|
||||||
|
>
|
||||||
|
mdi-delete
|
||||||
|
</v-icon>
|
||||||
|
<v-tooltip
|
||||||
|
activator="parent"
|
||||||
|
location="top"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</v-tooltip>
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-treeview>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="items.length === 0"
|
||||||
|
class="text-center pa-4"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
size="48"
|
||||||
|
color="grey-lighten-1"
|
||||||
|
>
|
||||||
|
mdi-folder-open-outline
|
||||||
|
</v-icon>
|
||||||
|
<p class="text-body-2 mt-2">
|
||||||
|
{{ emptyText }}
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
v-if="!readOnly"
|
||||||
|
class="text-caption"
|
||||||
|
>
|
||||||
|
右键点击空白区域添加根目录或文件
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</v-card>
|
||||||
|
|
||||||
|
<!-- Context Menu -->
|
||||||
|
<v-menu
|
||||||
|
v-if="!readOnly"
|
||||||
|
v-model="localShowContextMenuVar"
|
||||||
|
:position-x="contextMenuX"
|
||||||
|
:position-y="contextMenuY"
|
||||||
|
absolute
|
||||||
|
>
|
||||||
|
<v-list density="compact">
|
||||||
|
<v-list-item @click="emit('addDirectory', currentContextItem)">
|
||||||
|
<template #prepend>
|
||||||
|
<v-icon>mdi-folder-plus</v-icon>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>
|
||||||
|
{{ currentContextItem ? '添加子目录' : '添加根目录' }}
|
||||||
|
</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item @click="emit('addFile', currentContextItem)">
|
||||||
|
<template #prepend>
|
||||||
|
<v-icon>mdi-file-plus</v-icon>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>
|
||||||
|
{{ currentContextItem ? '添加子文件' : '添加根文件' }}
|
||||||
|
</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useVModel } from '@vueuse/core'
|
||||||
|
|
||||||
|
interface TreeItem {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
type: 'directory' | 'file'
|
||||||
|
children?: TreeItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
items: TreeItem[]
|
||||||
|
height?: number
|
||||||
|
readOnly?: boolean
|
||||||
|
emptyText?: string
|
||||||
|
expanded?: string[]
|
||||||
|
showContextMenuVar?: boolean
|
||||||
|
contextMenuX?: number
|
||||||
|
contextMenuY?: number
|
||||||
|
currentContextItem?: TreeItem | null
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
height: 600,
|
||||||
|
readOnly: false,
|
||||||
|
emptyText: '暂无文件或目录',
|
||||||
|
expanded: () => [],
|
||||||
|
showContextMenuVar: false,
|
||||||
|
contextMenuX: 0,
|
||||||
|
contextMenuY: 0,
|
||||||
|
currentContextItem: null
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits([
|
||||||
|
'showContextMenu',
|
||||||
|
'addNewItemToCurrentDirectory',
|
||||||
|
'editFile',
|
||||||
|
'deleteItem',
|
||||||
|
'addDirectory',
|
||||||
|
'addFile',
|
||||||
|
'update:showContextMenuVar',
|
||||||
|
'update:expanded'
|
||||||
|
])
|
||||||
|
|
||||||
|
// Use useVModel to create two-way binding for props
|
||||||
|
const localShowContextMenuVar = useVModel(props, 'showContextMenuVar', emit)
|
||||||
|
const localExpanded = useVModel(props, 'expanded', emit)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.v-treeview-node__root),
|
||||||
|
:deep(.v-treeview-node__children .v-treeview-node__root) {
|
||||||
|
padding: 4px;
|
||||||
|
margin: 2px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.v-treeview-node__root:hover),
|
||||||
|
:deep(.v-treeview-node__children .v-treeview-node__root:hover) {
|
||||||
|
background-color: rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.v-treeview-node__level) {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -138,143 +138,25 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-card
|
<TemplateTree
|
||||||
variant="outlined"
|
:items="treeItems"
|
||||||
class="pa-2"
|
|
||||||
:height="treeHeight"
|
:height="treeHeight"
|
||||||
@contextmenu.prevent="showContextMenu($event, null)"
|
:expanded="expandedNodes"
|
||||||
>
|
:show-context-menu-var="showContextMenuVar"
|
||||||
<v-treeview
|
:context-menu-x="contextMenuX"
|
||||||
v-model:expanded="expandedNodes"
|
:context-menu-y="contextMenuY"
|
||||||
:items="treeItems"
|
:current-context-item="currentContextItem"
|
||||||
item-title="name"
|
:empty-text="'暂无文件或目录'"
|
||||||
item-key="id"
|
:read-only="false"
|
||||||
item-children="children"
|
@showContextMenu="showContextMenu"
|
||||||
activatable
|
@add-new-item-to-current-directory="addNewItemToCurrentDirectory"
|
||||||
open-on-click
|
@edit-file="editFile"
|
||||||
:return-object="false"
|
@delete-item="deleteItem"
|
||||||
>
|
@add-directory="addDirectory"
|
||||||
<template #prepend="{ item }">
|
@add-file="addFile"
|
||||||
<v-icon
|
@update:showContextMenuVar="handleContextMenuUpdate"
|
||||||
:color="item.type === 'directory' ? 'warning' : 'info'"
|
@update:expanded="expandedNodes = $event"
|
||||||
size="large"
|
/>
|
||||||
>
|
|
||||||
{{
|
|
||||||
item.type === 'directory'
|
|
||||||
? 'mdi-folder-outline'
|
|
||||||
: 'mdi-file-document-outline'
|
|
||||||
}}
|
|
||||||
</v-icon>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #title="{ item }">
|
|
||||||
<span
|
|
||||||
@contextmenu.prevent="showContextMenu($event, item)"
|
|
||||||
class="cursor-pointer d-flex align-center"
|
|
||||||
>
|
|
||||||
{{ item.name }}
|
|
||||||
<v-btn
|
|
||||||
v-if="item.type === 'directory'"
|
|
||||||
icon
|
|
||||||
variant="text"
|
|
||||||
size="small"
|
|
||||||
class="ml-2"
|
|
||||||
@click.stop="addNewItemToCurrentDirectory(item)"
|
|
||||||
>
|
|
||||||
<v-icon size="small">mdi-plus</v-icon>
|
|
||||||
<v-tooltip
|
|
||||||
activator="parent"
|
|
||||||
location="top"
|
|
||||||
>
|
|
||||||
添加到目录
|
|
||||||
</v-tooltip>
|
|
||||||
</v-btn>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #append="{ item }">
|
|
||||||
<div class="d-flex align-center ga-1">
|
|
||||||
<v-btn
|
|
||||||
v-if="item.type === 'file'"
|
|
||||||
icon
|
|
||||||
variant="text"
|
|
||||||
size="small"
|
|
||||||
@click.stop="editFile(item)"
|
|
||||||
>
|
|
||||||
<v-icon size="small"> mdi-pencil </v-icon>
|
|
||||||
<v-tooltip
|
|
||||||
activator="parent"
|
|
||||||
location="top"
|
|
||||||
>
|
|
||||||
编辑内容
|
|
||||||
</v-tooltip>
|
|
||||||
</v-btn>
|
|
||||||
|
|
||||||
<v-btn
|
|
||||||
icon
|
|
||||||
variant="text"
|
|
||||||
size="small"
|
|
||||||
@click.stop="deleteItem(item)"
|
|
||||||
>
|
|
||||||
<v-icon
|
|
||||||
size="small"
|
|
||||||
color="error"
|
|
||||||
>
|
|
||||||
mdi-delete
|
|
||||||
</v-icon>
|
|
||||||
<v-tooltip
|
|
||||||
activator="parent"
|
|
||||||
location="top"
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</v-tooltip>
|
|
||||||
</v-btn>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</v-treeview>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="treeItems.length === 0"
|
|
||||||
class="text-center pa-4"
|
|
||||||
>
|
|
||||||
<v-icon
|
|
||||||
size="48"
|
|
||||||
color="grey-lighten-1"
|
|
||||||
>
|
|
||||||
mdi-folder-open-outline
|
|
||||||
</v-icon>
|
|
||||||
<p class="text-body-2 mt-2"> 暂无文件或目录 </p>
|
|
||||||
<p class="text-caption"> 右键点击空白区域添加根目录或文件 </p>
|
|
||||||
</div>
|
|
||||||
</v-card>
|
|
||||||
|
|
||||||
<!-- Context Menu -->
|
|
||||||
<v-menu
|
|
||||||
v-model="showContextMenuVar"
|
|
||||||
:position-x="contextMenuX"
|
|
||||||
:position-y="contextMenuY"
|
|
||||||
absolute
|
|
||||||
>
|
|
||||||
<v-list density="compact">
|
|
||||||
<v-list-item @click="addDirectory(currentContextItem)">
|
|
||||||
<template #prepend>
|
|
||||||
<v-icon>mdi-folder-plus</v-icon>
|
|
||||||
</template>
|
|
||||||
<v-list-item-title>
|
|
||||||
{{ currentContextItem ? '添加子目录' : '添加根目录' }}
|
|
||||||
</v-list-item-title>
|
|
||||||
</v-list-item>
|
|
||||||
|
|
||||||
<v-list-item @click="addFile(currentContextItem)">
|
|
||||||
<template #prepend>
|
|
||||||
<v-icon>mdi-file-plus</v-icon>
|
|
||||||
</template>
|
|
||||||
<v-list-item-title>
|
|
||||||
{{ currentContextItem ? '添加子文件' : '添加根文件' }}
|
|
||||||
</v-list-item-title>
|
|
||||||
</v-list-item>
|
|
||||||
</v-list>
|
|
||||||
</v-menu>
|
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
@@ -295,6 +177,7 @@
|
|||||||
required
|
required
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
ref="directoryInputRef"
|
ref="directoryInputRef"
|
||||||
|
@keydown.enter="confirmAddDirectory"
|
||||||
/>
|
/>
|
||||||
</v-form>
|
</v-form>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@@ -329,6 +212,7 @@
|
|||||||
required
|
required
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
ref="fileInputRef"
|
ref="fileInputRef"
|
||||||
|
@keydown.enter="confirmAddFile"
|
||||||
/>
|
/>
|
||||||
</v-form>
|
</v-form>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@@ -394,6 +278,7 @@ import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
|
|||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useTemplateStore } from '@/renderer/store/template'
|
import { useTemplateStore } from '@/renderer/store/template'
|
||||||
import { Template } from '@/renderer/store/template'
|
import { Template } from '@/renderer/store/template'
|
||||||
|
import TemplateTree from '@/renderer/components/TemplateTree.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -425,6 +310,11 @@ const contextMenuX = ref(0)
|
|||||||
const contextMenuY = ref(0)
|
const contextMenuY = ref(0)
|
||||||
const currentContextItem = ref<TreeItem | null>(null)
|
const currentContextItem = ref<TreeItem | null>(null)
|
||||||
|
|
||||||
|
// Handler for context menu visibility updates from TemplateTree component
|
||||||
|
const handleContextMenuUpdate = (value: boolean) => {
|
||||||
|
showContextMenuVar.value = value
|
||||||
|
}
|
||||||
|
|
||||||
// New item state
|
// New item state
|
||||||
const newDirectoryPath = ref('')
|
const newDirectoryPath = ref('')
|
||||||
const newFilePath = ref('')
|
const newFilePath = ref('')
|
||||||
@@ -677,14 +567,14 @@ const deleteItem = (item: TreeItem) => {
|
|||||||
const autoFocusDirectoryInput = async () => {
|
const autoFocusDirectoryInput = async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
if (directoryInputRef.value) {
|
if (directoryInputRef.value) {
|
||||||
(directoryInputRef.value as HTMLInputElement).focus()
|
;(directoryInputRef.value as HTMLInputElement).focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const autoFocusFileInput = async () => {
|
const autoFocusFileInput = async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
if (fileInputRef.value) {
|
if (fileInputRef.value) {
|
||||||
(fileInputRef.value as HTMLInputElement).focus()
|
;(fileInputRef.value as HTMLInputElement).focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,18 +98,14 @@
|
|||||||
<v-spacer />
|
<v-spacer />
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-treeview :items="templateTree" item-title="name" item-key="id" item-children="children" activatable
|
<TemplateTree
|
||||||
open-all>
|
:items="templateTree"
|
||||||
<template v-slot:prepend="{ item }">
|
:height="400"
|
||||||
<v-icon>
|
:read-only="true"
|
||||||
{{
|
:empty-text="'模板结构为空'"
|
||||||
item.type === 'directory'
|
:expanded="expandedTreeNodes"
|
||||||
? 'mdi-folder'
|
@update:expanded="expandedTreeNodes = $event"
|
||||||
: 'mdi-file'
|
/>
|
||||||
}}
|
|
||||||
</v-icon>
|
|
||||||
</template>
|
|
||||||
</v-treeview>
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
@@ -144,6 +140,7 @@ import { ref, computed, onMounted } from 'vue'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useTemplateStore } from '@/renderer/store/template'
|
import { useTemplateStore } from '@/renderer/store/template'
|
||||||
import { Template } from '@/renderer/store/template'
|
import { Template } from '@/renderer/store/template'
|
||||||
|
import TemplateTree from '@/renderer/components/TemplateTree.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const templateStore = useTemplateStore()
|
const templateStore = useTemplateStore()
|
||||||
@@ -160,6 +157,7 @@ const templates = computed(() => templateStore.templates)
|
|||||||
// Template detail view
|
// Template detail view
|
||||||
const showTemplateDetail = ref(false)
|
const showTemplateDetail = ref(false)
|
||||||
const selectedTemplate = ref<Template | null>(null)
|
const selectedTemplate = ref<Template | null>(null)
|
||||||
|
const expandedTreeNodes = ref<string[]>([])
|
||||||
|
|
||||||
// Execute template
|
// Execute template
|
||||||
const showExecuteDialog = ref(false)
|
const showExecuteDialog = ref(false)
|
||||||
@@ -184,7 +182,7 @@ const templateTree = computed<TreeNode[]>(() => {
|
|||||||
selectedTemplate.value.directories.forEach((dir) => {
|
selectedTemplate.value.directories.forEach((dir) => {
|
||||||
items.push({
|
items.push({
|
||||||
id: `dir-${dir.path}`,
|
id: `dir-${dir.path}`,
|
||||||
name: dir.path,
|
name: dir.path.split('/').pop() || dir.path, // Show just the directory name, not full path
|
||||||
type: 'directory',
|
type: 'directory',
|
||||||
children: []
|
children: []
|
||||||
})
|
})
|
||||||
@@ -194,11 +192,14 @@ const templateTree = computed<TreeNode[]>(() => {
|
|||||||
selectedTemplate.value.files.forEach((file) => {
|
selectedTemplate.value.files.forEach((file) => {
|
||||||
items.push({
|
items.push({
|
||||||
id: `file-${file.path}`,
|
id: `file-${file.path}`,
|
||||||
name: file.path,
|
name: file.path.split('/').pop() || file.path, // Show just the file name, not full path
|
||||||
type: 'file'
|
type: 'file'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Auto-expand all nodes when showing template details
|
||||||
|
expandedTreeNodes.value = items.map(item => item.id)
|
||||||
|
|
||||||
return items
|
return items
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user