feat(模板创建): 改进文件选择功能并优化数据结构

重构文件对话框组件,分离文件和文件夹选择功能
更新TreeNode接口,增加sourceType字段区分来源类型
优化文件选择逻辑,提供更清晰的用户指引
This commit is contained in:
zhanggy committed 2025-10-31 16:25:11 +08:00
1 parent 47fb017e21
commit f3e909923a
3 files changed
+74 -25

No files matched your search

+65 -17
View File
@@ -20,17 +20,30 @@
ref="inputRef" ref="inputRef"
/> />
<!-- 文件路径选择输入框 --> <!-- 文件选择输入框 -->
<v-text-field <v-text-field
v-model="selectedSourcePath" v-model="selectedFilePath"
label="文件或文件夹" label="选择文件"
placeholder="点击输入框选择文件或文件夹" placeholder="点击输入框选择文件"
readonly readonly
:rules="isEditMode ? [] : [requiredRule('文件或文件夹')]" :rules="[fileSelectionRule]"
:append-inner-icon="'mdi-file'" :append-inner-icon="'mdi-file'"
density="comfortable" density="comfortable"
class="mt-4" class="mt-4"
@click="selectSourceFileOrFolder()" @click="selectSourceFile"
/>
<!-- 文件夹选择输入框 -->
<v-text-field
v-model="selectedFolderPath"
label="选择文件夹"
placeholder="点击输入框选择文件夹"
readonly
:rules="[fileSelectionRule]"
:append-inner-icon="'mdi-folder'"
density="comfortable"
class="mt-4"
@click="selectSourceFolder"
/> />
<!-- 选择提示 --> <!-- 选择提示 -->
@@ -44,6 +57,9 @@
<span> <span>
选择文件夹则会自动匹配该文件夹下的文件进行复制并且重命名 选择文件夹则会自动匹配该文件夹下的文件进行复制并且重命名
</span> </span>
<span class="mt-1 font-weight-bold">
文件和文件夹选择其中一个即可
</span>
</div> </div>
</v-alert> </v-alert>
</v-form> </v-form>
@@ -54,7 +70,7 @@
<v-btn <v-btn
color="primary" color="primary"
@click="confirm" @click="confirm"
:disabled="!formValid || (!selectedSourcePath && !isEditMode)" :disabled="!formValid || (!selectedFilePath && !selectedFolderPath && !isEditMode)"
> >
{{ isEditMode ? '保存' : '添加' }} {{ isEditMode ? '保存' : '添加' }}
</v-btn> </v-btn>
@@ -76,7 +92,7 @@ interface Props {
interface Emits { interface Emits {
(e: 'update:modelValue', value: boolean): void (e: 'update:modelValue', value: boolean): void
(e: 'confirm', data: { path: string; sourceFilePath?: string }): void (e: 'confirm', data: { path: string; sourcePath?: string; sourceType?: 'file' | 'folder' }): void
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
@@ -91,7 +107,8 @@ const emit = defineEmits<Emits>()
const isVisible = ref(false) const isVisible = ref(false)
const formValid = ref(false) const formValid = ref(false)
const filePath = ref('') const filePath = ref('')
const selectedSourcePath = ref<string>('') const selectedFilePath = ref<string>('')
const selectedFolderPath = ref<string>('')
const inputRef = ref<HTMLInputElement | null>(null) const inputRef = ref<HTMLInputElement | null>(null)
// Computed // Computed
@@ -103,7 +120,8 @@ watch(() => props.modelValue, (newValue) => {
if (newValue) { if (newValue) {
// Reset form when dialog opens // Reset form when dialog opens
filePath.value = props.editingItem?.path || '' filePath.value = props.editingItem?.path || ''
selectedSourcePath.value = props.editingItem?.sourceFilePath || '' selectedFilePath.value = props.editingItem?.sourceType === 'file' ? props.editingItem?.sourcePath || '' : ''
selectedFolderPath.value = props.editingItem?.sourceType === 'folder' ? props.editingItem?.sourcePath || '' : ''
autoFocusInput() autoFocusInput()
} }
}) })
@@ -117,6 +135,12 @@ watch(isVisible, (newValue) => {
const requiredRule = (fieldName: string) => (v: string | null | undefined) => const requiredRule = (fieldName: string) => (v: string | null | undefined) =>
!!v || `${fieldName}为必填项` !!v || `${fieldName}为必填项`
// File selection validation rule
const fileSelectionRule = () => {
if (isEditMode.value) return true // 编辑模式下不需要验证
return !!selectedFilePath.value || !!selectedFolderPath.value || '请选择文件或文件夹'
}
// Methods // Methods
const autoFocusInput = async () => { const autoFocusInput = async () => {
await nextTick() await nextTick()
@@ -125,22 +149,45 @@ const autoFocusInput = async () => {
} }
} }
const selectSourceFileOrFolder = async () => { const selectSourceFile = async () => {
// 使用现有的主进程API来选择文件或文件夹 // 使用主进程API来选择文件
const result = await window.mainApi.invoke('msgSelectFileOrFolder') const result = await window.mainApi.invoke('msgOpenFile', 'any')
if (result && result.filePath) { if (result && !result.canceled && result.filePaths.length > 0) {
selectedSourcePath.value = result.filePath selectedFilePath.value = result.filePaths[0]
selectedFolderPath.value = '' // 清空文件夹选择
}
}
const selectSourceFolder = async () => {
// 使用主进程API来选择文件夹
const result = await window.mainApi.invoke('msgSelectDirectory')
if (result && !result.canceled && result.filePath) {
selectedFolderPath.value = result.filePath
selectedFilePath.value = '' // 清空文件选择
} }
} }
const confirm = () => { const confirm = () => {
if (!filePath.value.trim()) return if (!filePath.value.trim()) return
// 确定选择的源类型和路径
let sourcePathValue: string | undefined
let sourceType: 'file' | 'folder' | undefined
if (selectedFilePath.value) {
sourcePathValue = selectedFilePath.value
sourceType = 'file'
} else if (selectedFolderPath.value) {
sourcePathValue = selectedFolderPath.value
sourceType = 'folder'
}
emit('confirm', { emit('confirm', {
path: filePath.value, path: filePath.value,
sourceFilePath: selectedSourcePath.value || undefined sourcePath: sourcePathValue,
sourceType
}) })
close() close()
@@ -148,7 +195,8 @@ const confirm = () => {
const reset = () => { const reset = () => {
filePath.value = '' filePath.value = ''
selectedSourcePath.value = '' selectedFilePath.value = ''
selectedFolderPath.value = ''
formValid.value = false formValid.value = false
} }
@@ -284,13 +284,11 @@ const handleDirectoryDialogConfirm = (data: { path: string }) => {
path: path, path: path,
type: 'directory' type: 'directory'
} }
console.log('updatedNode', updatedNode)
treeStructure.value = updateNodeInTree( treeStructure.value = updateNodeInTree(
treeStructure.value, treeStructure.value,
currentEditingItem.value.path, currentEditingItem.value.id,
updatedNode updatedNode
) )
console.log('update treeStructure', treeStructure.value)
} else { } else {
// Create new directory node // Create new directory node
const newNode: TreeNode = { const newNode: TreeNode = {
@@ -360,8 +358,8 @@ const updateNodeInTree = (
const handleFileDialogConfirm = (data: { path: string; sourceFilePath?: string }) => { const handleFileDialogConfirm = (data: { path: string; sourcePath?: string; sourceType?: 'file' | 'folder' }) => {
const { path, sourceFilePath } = data const { path, sourcePath, sourceType } = data
const newId = generateUniqueId('file') const newId = generateUniqueId('file')
@@ -373,7 +371,8 @@ const handleFileDialogConfirm = (data: { path: string; sourceFilePath?: string }
name: path, name: path,
path: path, path: path,
type: 'file', type: 'file',
sourceFilePath: sourceFilePath sourcePath: sourcePath,
sourceType
} }
treeStructure.value = updateNodeInTree( treeStructure.value = updateNodeInTree(
treeStructure.value, treeStructure.value,
@@ -410,7 +409,8 @@ const handleFileDialogConfirm = (data: { path: string; sourceFilePath?: string }
name: path, name: path,
path: path, path: path,
type: 'file', type: 'file',
sourceFilePath sourcePath,
sourceType
} }
// Add to tree structure // Add to tree structure
+2 -1
View File
@@ -8,7 +8,8 @@ export interface TreeNode {
path: string // 完整路径 path: string // 完整路径
type: 'directory' | 'file' type: 'directory' | 'file'
children?: TreeNode[] children?: TreeNode[]
sourceFilePath?: string sourcePath?: string
sourceType?: 'file' | 'folder' // 记录选择的是文件还是文件夹
} }
export interface Template { export interface Template {