feat(模板创建): 改进文件选择功能并优化数据结构
重构文件对话框组件,分离文件和文件夹选择功能 更新TreeNode接口,增加sourceType字段区分来源类型 优化文件选择逻辑,提供更清晰的用户指引
This commit is contained in:
1 parent
47fb017e21
commit
f3e909923a
3 files changed
+74
-25
No files matched your search
@@ -20,17 +20,30 @@
|
||||
ref="inputRef"
|
||||
/>
|
||||
|
||||
<!-- 文件路径选择输入框 -->
|
||||
<!-- 文件选择输入框 -->
|
||||
<v-text-field
|
||||
v-model="selectedSourcePath"
|
||||
label="文件或文件夹"
|
||||
placeholder="点击输入框选择文件或文件夹"
|
||||
v-model="selectedFilePath"
|
||||
label="选择文件"
|
||||
placeholder="点击输入框选择文件"
|
||||
readonly
|
||||
:rules="isEditMode ? [] : [requiredRule('文件或文件夹')]"
|
||||
:rules="[fileSelectionRule]"
|
||||
:append-inner-icon="'mdi-file'"
|
||||
density="comfortable"
|
||||
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 class="mt-1 font-weight-bold">
|
||||
文件和文件夹选择其中一个即可
|
||||
</span>
|
||||
</div>
|
||||
</v-alert>
|
||||
</v-form>
|
||||
@@ -54,7 +70,7 @@
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="confirm"
|
||||
:disabled="!formValid || (!selectedSourcePath && !isEditMode)"
|
||||
:disabled="!formValid || (!selectedFilePath && !selectedFolderPath && !isEditMode)"
|
||||
>
|
||||
{{ isEditMode ? '保存' : '添加' }}
|
||||
</v-btn>
|
||||
@@ -76,7 +92,7 @@ interface Props {
|
||||
|
||||
interface Emits {
|
||||
(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>(), {
|
||||
@@ -91,7 +107,8 @@ const emit = defineEmits<Emits>()
|
||||
const isVisible = ref(false)
|
||||
const formValid = ref(false)
|
||||
const filePath = ref('')
|
||||
const selectedSourcePath = ref<string>('')
|
||||
const selectedFilePath = ref<string>('')
|
||||
const selectedFolderPath = ref<string>('')
|
||||
const inputRef = ref<HTMLInputElement | null>(null)
|
||||
|
||||
// Computed
|
||||
@@ -103,7 +120,8 @@ watch(() => props.modelValue, (newValue) => {
|
||||
if (newValue) {
|
||||
// Reset form when dialog opens
|
||||
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()
|
||||
}
|
||||
})
|
||||
@@ -117,6 +135,12 @@ watch(isVisible, (newValue) => {
|
||||
const requiredRule = (fieldName: string) => (v: string | null | undefined) =>
|
||||
!!v || `${fieldName}为必填项`
|
||||
|
||||
// File selection validation rule
|
||||
const fileSelectionRule = () => {
|
||||
if (isEditMode.value) return true // 编辑模式下不需要验证
|
||||
return !!selectedFilePath.value || !!selectedFolderPath.value || '请选择文件或文件夹'
|
||||
}
|
||||
|
||||
// Methods
|
||||
const autoFocusInput = async () => {
|
||||
await nextTick()
|
||||
@@ -125,22 +149,45 @@ const autoFocusInput = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const selectSourceFileOrFolder = async () => {
|
||||
// 使用现有的主进程API来选择文件或文件夹
|
||||
const result = await window.mainApi.invoke('msgSelectFileOrFolder')
|
||||
const selectSourceFile = async () => {
|
||||
// 使用主进程API来选择文件
|
||||
const result = await window.mainApi.invoke('msgOpenFile', 'any')
|
||||
|
||||
if (result && result.filePath) {
|
||||
selectedSourcePath.value = result.filePath
|
||||
if (result && !result.canceled && result.filePaths.length > 0) {
|
||||
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 = () => {
|
||||
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', {
|
||||
path: filePath.value,
|
||||
sourceFilePath: selectedSourcePath.value || undefined
|
||||
sourcePath: sourcePathValue,
|
||||
sourceType
|
||||
})
|
||||
|
||||
close()
|
||||
@@ -148,7 +195,8 @@ const confirm = () => {
|
||||
|
||||
const reset = () => {
|
||||
filePath.value = ''
|
||||
selectedSourcePath.value = ''
|
||||
selectedFilePath.value = ''
|
||||
selectedFolderPath.value = ''
|
||||
formValid.value = false
|
||||
}
|
||||
|
||||
|
||||
@@ -284,13 +284,11 @@ const handleDirectoryDialogConfirm = (data: { path: string }) => {
|
||||
path: path,
|
||||
type: 'directory'
|
||||
}
|
||||
console.log('updatedNode', updatedNode)
|
||||
treeStructure.value = updateNodeInTree(
|
||||
treeStructure.value,
|
||||
currentEditingItem.value.path,
|
||||
currentEditingItem.value.id,
|
||||
updatedNode
|
||||
)
|
||||
console.log('update treeStructure', treeStructure.value)
|
||||
} else {
|
||||
// Create new directory node
|
||||
const newNode: TreeNode = {
|
||||
@@ -360,8 +358,8 @@ const updateNodeInTree = (
|
||||
|
||||
|
||||
|
||||
const handleFileDialogConfirm = (data: { path: string; sourceFilePath?: string }) => {
|
||||
const { path, sourceFilePath } = data
|
||||
const handleFileDialogConfirm = (data: { path: string; sourcePath?: string; sourceType?: 'file' | 'folder' }) => {
|
||||
const { path, sourcePath, sourceType } = data
|
||||
|
||||
const newId = generateUniqueId('file')
|
||||
|
||||
@@ -373,7 +371,8 @@ const handleFileDialogConfirm = (data: { path: string; sourceFilePath?: string }
|
||||
name: path,
|
||||
path: path,
|
||||
type: 'file',
|
||||
sourceFilePath: sourceFilePath
|
||||
sourcePath: sourcePath,
|
||||
sourceType
|
||||
}
|
||||
treeStructure.value = updateNodeInTree(
|
||||
treeStructure.value,
|
||||
@@ -410,7 +409,8 @@ const handleFileDialogConfirm = (data: { path: string; sourceFilePath?: string }
|
||||
name: path,
|
||||
path: path,
|
||||
type: 'file',
|
||||
sourceFilePath
|
||||
sourcePath,
|
||||
sourceType
|
||||
}
|
||||
|
||||
// Add to tree structure
|
||||
|
||||
@@ -8,7 +8,8 @@ export interface TreeNode {
|
||||
path: string // 完整路径
|
||||
type: 'directory' | 'file'
|
||||
children?: TreeNode[]
|
||||
sourceFilePath?: string
|
||||
sourcePath?: string
|
||||
sourceType?: 'file' | 'folder' // 记录选择的是文件还是文件夹
|
||||
}
|
||||
|
||||
export interface Template {
|
||||
|
||||
Reference in new issue
Block a user