feat: add @mdi/font and electron-devtools-installer dependencies
- Added @mdi/font for Material Design Icons support. - Included electron-devtools-installer to facilitate Vue DevTools installation in development. refactor: enhance CreateTemplateScreen layout and functionality - Improved layout with a responsive design. - Added functionality for adding directories and files with validation. - Implemented a file content editor dialog for editing file contents. - Updated template save logic to handle changes more effectively. fix: update TemplateListScreen for better UX - Enhanced template list display with improved card layout. - Added action buttons for viewing, executing, editing, and deleting templates. - Improved dialog handling for template details and execution. chore: update vuetify plugin configuration - Removed unused icon set configuration. - Updated locale settings to use simplified Chinese. style: clean up HeaderLayout and vuetify styles - Removed commented-out code and unnecessary styles. - Improved overall styling for better readability and consistency.
This commit is contained in:
1 parent
1aecd5f4b6
commit
4f859a4933
8 files changed
+653
-394
No files matched your search
@@ -1,334 +1,557 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<h2 class="mb-4">
|
||||
{{ templateId ? '编辑模板' : '创建模板' }}
|
||||
</h2>
|
||||
|
||||
<v-form v-model="formValid">
|
||||
<v-container fluid class="pa-0 fill-height">
|
||||
<v-row class="fill-height">
|
||||
<!-- Left Panel - Template Info -->
|
||||
<v-col cols="12" md="4" class="pa-4 border-e">
|
||||
<div class="d-flex align-center mb-4">
|
||||
<h2 class="text-h5 mr-2">
|
||||
{{ isEditMode ? '编辑模板' : '创建模板' }}
|
||||
</h2>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
icon
|
||||
variant="text"
|
||||
@click="goBack"
|
||||
>
|
||||
<v-icon>mdi-close</v-icon>
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
关闭
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<v-form v-model="formValid" class="mb-4">
|
||||
<v-text-field
|
||||
v-model="template.name"
|
||||
v-model="templateName"
|
||||
label="模板名称 *"
|
||||
:rules="[(v) => !!v || '模板名称不能为空']"
|
||||
placeholder="输入模板名称"
|
||||
:rules="[requiredRule]"
|
||||
required
|
||||
data-testid="template-name-input"
|
||||
clearable
|
||||
density="comfortable"
|
||||
/>
|
||||
|
||||
|
||||
<v-textarea
|
||||
v-model="template.description"
|
||||
v-model="templateDescription"
|
||||
label="模板描述"
|
||||
placeholder="描述这个模板的用途..."
|
||||
rows="2"
|
||||
data-testid="template-description-input"
|
||||
auto-grow
|
||||
clearable
|
||||
density="comfortable"
|
||||
/>
|
||||
|
||||
<!-- Template content -->
|
||||
<v-card class="mb-4">
|
||||
<v-card-title>模板内容</v-card-title>
|
||||
<v-card-text>
|
||||
<!-- Files section -->
|
||||
<v-expansion-panels class="mb-4">
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-title>文件</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-data-table
|
||||
:headers="fileHeaders"
|
||||
:items="template.files"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
icon
|
||||
color="error"
|
||||
@click="removeFile(item)"
|
||||
>
|
||||
<v-icon>mdi-delete</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-row class="mt-4">
|
||||
<v-col cols="12">
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="showAddFileDialog = true"
|
||||
prepend-icon="mdi-file-plus"
|
||||
>
|
||||
添加文件
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
|
||||
<!-- Directories section -->
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-title>目录</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-data-table
|
||||
:headers="dirHeaders"
|
||||
:items="template.directories"
|
||||
class="elevation-1"
|
||||
>
|
||||
<template v-slot:item.actions="{ item }">
|
||||
<v-btn
|
||||
icon
|
||||
color="error"
|
||||
@click="removeDirectory(item)"
|
||||
>
|
||||
<v-icon>mdi-delete</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-data-table>
|
||||
|
||||
<v-row class="mt-4">
|
||||
<v-col cols="12">
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="showAddDirDialog = true"
|
||||
prepend-icon="mdi-folder-plus"
|
||||
>
|
||||
添加目录
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-expansion-panel-text>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-btn
|
||||
:color="templateId ? 'warning' : 'success'"
|
||||
@click="saveTemplate"
|
||||
:disabled="!formValid"
|
||||
prepend-icon="mdi-content-save"
|
||||
>
|
||||
{{ templateId ? '更新模板' : '保存模板' }}
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="ml-2"
|
||||
@click="cancel"
|
||||
prepend-icon="mdi-arrow-left"
|
||||
>
|
||||
返回
|
||||
</v-btn>
|
||||
</v-form>
|
||||
|
||||
<v-divider class="my-4" />
|
||||
|
||||
<!-- File Operations -->
|
||||
<div class="mb-4">
|
||||
<h3 class="text-subtitle-1 mb-2">添加项</h3>
|
||||
<div class="d-flex flex-column ga-2">
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
prepend-icon="mdi-folder-plus"
|
||||
@click="showAddDirectoryDialog"
|
||||
block
|
||||
>
|
||||
添加目录
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="success"
|
||||
variant="outlined"
|
||||
prepend-icon="mdi-file-plus"
|
||||
@click="showAddFileDialog"
|
||||
block
|
||||
>
|
||||
添加文件
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-divider class="my-4" />
|
||||
|
||||
<!-- Template Actions -->
|
||||
<div class="d-flex ga-2">
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="saveTemplate"
|
||||
:disabled="!formValid || !hasChanges"
|
||||
prepend-icon="mdi-content-save"
|
||||
block
|
||||
>
|
||||
保存模板
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-col>
|
||||
|
||||
<!-- Right Panel - Tree Structure -->
|
||||
<v-col cols="12" md="8" class="pa-4">
|
||||
<div class="d-flex align-center mb-4">
|
||||
<h3 class="text-h6 mr-2">模板结构</h3>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
icon
|
||||
variant="text"
|
||||
@click="expandAll"
|
||||
size="small"
|
||||
>
|
||||
<v-icon>mdi-arrow-expand-down</v-icon>
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
展开全部
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
icon
|
||||
variant="text"
|
||||
@click="collapseAll"
|
||||
size="small"
|
||||
>
|
||||
<v-icon>mdi-arrow-collapse-up</v-icon>
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
收起全部
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<v-card
|
||||
variant="outlined"
|
||||
class="pa-2"
|
||||
:height="treeHeight"
|
||||
>
|
||||
<v-treeview
|
||||
v-model:expanded="expandedNodes"
|
||||
:items="treeItems"
|
||||
item-title="name"
|
||||
item-key="id"
|
||||
item-children="children"
|
||||
activatable
|
||||
open-on-click
|
||||
:return-object="false"
|
||||
>
|
||||
<template v-slot: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 v-slot: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>
|
||||
|
||||
<template v-slot:no-data>
|
||||
<div 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>
|
||||
</template>
|
||||
</v-treeview>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- Add file dialog -->
|
||||
<v-dialog
|
||||
v-model="showAddFileDialog"
|
||||
max-width="600"
|
||||
>
|
||||
|
||||
<!-- Add Directory Dialog -->
|
||||
<v-dialog v-model="showDirectoryDialog" max-width="500">
|
||||
<v-card>
|
||||
<v-card-title>添加文件</v-card-title>
|
||||
<v-card-title>添加目录</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form v-model="fileFormValid">
|
||||
<v-form v-model="directoryFormValid">
|
||||
<v-text-field
|
||||
v-model="newFile.path"
|
||||
label="文件路径 *"
|
||||
placeholder="例如: src/index.js"
|
||||
:rules="[(v) => !!v || '文件路径不能为空']"
|
||||
data-testid="add-file-path-input"
|
||||
/>
|
||||
|
||||
<v-textarea
|
||||
v-model="newFile.content"
|
||||
label="文件内容"
|
||||
placeholder="输入文件内容..."
|
||||
rows="6"
|
||||
data-testid="add-file-content-input"
|
||||
v-model="newDirectoryPath"
|
||||
label="目录路径 *"
|
||||
placeholder="例如: src/components"
|
||||
:rules="[requiredRule]"
|
||||
required
|
||||
density="comfortable"
|
||||
/>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="showAddFileDialog = false"> 取消 </v-btn>
|
||||
<v-btn @click="showDirectoryDialog = false">
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="addFile"
|
||||
:disabled="!fileFormValid"
|
||||
@click="addDirectory"
|
||||
:disabled="!directoryFormValid"
|
||||
>
|
||||
添加
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- Add directory dialog -->
|
||||
<v-dialog
|
||||
v-model="showAddDirDialog"
|
||||
max-width="600"
|
||||
>
|
||||
|
||||
<!-- Add File Dialog -->
|
||||
<v-dialog v-model="showFileDialog" max-width="500">
|
||||
<v-card>
|
||||
<v-card-title>添加目录</v-card-title>
|
||||
<v-card-title>添加文件</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form v-model="dirFormValid">
|
||||
<v-form v-model="fileFormValid">
|
||||
<v-text-field
|
||||
v-model="newDir.path"
|
||||
label="目录路径 *"
|
||||
placeholder="例如: src/components"
|
||||
:rules="[(v) => !!v || '目录路径不能为空']"
|
||||
data-testid="add-dir-path-input"
|
||||
v-model="newFilePath"
|
||||
label="文件路径 *"
|
||||
placeholder="例如: src/index.js"
|
||||
:rules="[requiredRule]"
|
||||
required
|
||||
density="comfortable"
|
||||
/>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="showAddDirDialog = false"> 取消 </v-btn>
|
||||
<v-btn @click="showFileDialog = false">
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="addDirectory"
|
||||
:disabled="!dirFormValid"
|
||||
@click="addFile"
|
||||
:disabled="!fileFormValid"
|
||||
>
|
||||
添加
|
||||
添加并编辑
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- File Content Editor Dialog -->
|
||||
<v-dialog v-model="showEditorDialog" fullscreen>
|
||||
<v-card>
|
||||
<v-toolbar dark color="primary">
|
||||
<v-btn icon @click="showEditorDialog = false">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
<v-toolbar-title>
|
||||
编辑文件: {{ editingFile?.path }}
|
||||
</v-toolbar-title>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="saveFileContent"
|
||||
>
|
||||
保存
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
|
||||
<v-card-text class="pa-0 fill-height">
|
||||
<v-textarea
|
||||
v-model="editingFileContent"
|
||||
class="fill-height"
|
||||
style="height: calc(100vh - 120px);"
|
||||
no-resize
|
||||
spellcheck="false"
|
||||
placeholder="在此输入文件内容..."
|
||||
variant="solo-filled"
|
||||
density="comfortable"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useTemplateStore } from '@/renderer/store/template'
|
||||
import { Template } from '@/renderer/store/template'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const templateStore = useTemplateStore()
|
||||
|
||||
// Form validation
|
||||
const formValid = ref(false)
|
||||
const fileFormValid = ref(false)
|
||||
const dirFormValid = ref(false)
|
||||
// Extract methods from store
|
||||
const { getTemplateById } = templateStore
|
||||
|
||||
// Template data
|
||||
const templateId = ref(route.params.id as string)
|
||||
const template = ref({
|
||||
id: '',
|
||||
name: '',
|
||||
description: '',
|
||||
files: [] as any[],
|
||||
directories: [] as any[]
|
||||
})
|
||||
// Form state
|
||||
const formValid = ref(false)
|
||||
const templateName = ref('')
|
||||
const templateDescription = ref('')
|
||||
const hasChanges = ref(false)
|
||||
|
||||
// Dialogs
|
||||
const showAddFileDialog = ref(false)
|
||||
const showAddDirDialog = ref(false)
|
||||
const showDirectoryDialog = ref(false)
|
||||
const showFileDialog = ref(false)
|
||||
const showEditorDialog = ref(false)
|
||||
const directoryFormValid = ref(false)
|
||||
const fileFormValid = ref(false)
|
||||
|
||||
// New file data
|
||||
const newFile = ref({
|
||||
path: '',
|
||||
content: ''
|
||||
// New item state
|
||||
const newDirectoryPath = ref('')
|
||||
const newFilePath = ref('')
|
||||
const editingFile = ref<{ path: string; content: string } | null>(null)
|
||||
const editingFileContent = ref('')
|
||||
|
||||
// Tree state
|
||||
const expandedNodes = ref<string[]>([])
|
||||
const treeHeight = ref(600)
|
||||
|
||||
// Item state
|
||||
const directories = ref<{ path: string }[]>([])
|
||||
const files = ref<{ path: string; content: string }[]>([])
|
||||
|
||||
// Computed
|
||||
const isEditMode = computed(() => !!route.params.id)
|
||||
const treeItems = computed(() => {
|
||||
const items = []
|
||||
|
||||
// Add directories
|
||||
directories.value.forEach(dir => {
|
||||
items.push({
|
||||
id: `dir-${dir.path}`,
|
||||
name: dir.path,
|
||||
type: 'directory',
|
||||
children: []
|
||||
})
|
||||
})
|
||||
|
||||
// Add files
|
||||
files.value.forEach(file => {
|
||||
items.push({
|
||||
id: `file-${file.path}`,
|
||||
name: file.path,
|
||||
type: 'file'
|
||||
})
|
||||
})
|
||||
|
||||
return items
|
||||
})
|
||||
|
||||
// New directory data
|
||||
const newDir = ref({
|
||||
path: ''
|
||||
})
|
||||
// Validation rules
|
||||
const requiredRule = (v: any) => !!v || '此字段为必填项'
|
||||
|
||||
// Table headers
|
||||
const fileHeaders = ref([
|
||||
{ title: '文件路径', key: 'path' },
|
||||
{ title: '操作', key: 'actions', sortable: false }
|
||||
])
|
||||
|
||||
const dirHeaders = ref([
|
||||
{ title: '目录路径', key: 'path' },
|
||||
{ title: '操作', key: 'actions', sortable: false }
|
||||
])
|
||||
// Watch for changes to detect unsaved changes
|
||||
watch([templateName, templateDescription, directories, files], () => {
|
||||
hasChanges.value = true
|
||||
}, { deep: true })
|
||||
|
||||
// Lifecycle
|
||||
onMounted(async () => {
|
||||
await templateStore.loadTemplates()
|
||||
|
||||
if (templateId.value) {
|
||||
// Edit existing template
|
||||
const existingTemplate = templateStore.getTemplateById(templateId.value)
|
||||
if (existingTemplate) {
|
||||
template.value = { ...existingTemplate }
|
||||
|
||||
// Set tree height based on window height
|
||||
updateTreeHeight()
|
||||
|
||||
// Add resize listener
|
||||
window.addEventListener('resize', updateTreeHeight)
|
||||
|
||||
// Handle edit mode
|
||||
if (isEditMode.value) {
|
||||
const templateId = route.params.id as string
|
||||
const template = getTemplateById(templateId)
|
||||
|
||||
if (template) {
|
||||
templateName.value = template.name
|
||||
templateDescription.value = template.description
|
||||
directories.value = [...template.directories]
|
||||
files.value = [...template.files]
|
||||
hasChanges.value = false
|
||||
} else {
|
||||
// If template doesn't exist, redirect to template list
|
||||
router.push('/templates')
|
||||
}
|
||||
}
|
||||
|
||||
// Expand all nodes by default
|
||||
expandAll()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', updateTreeHeight)
|
||||
})
|
||||
|
||||
// Methods
|
||||
const updateTreeHeight = () => {
|
||||
treeHeight.value = window.innerHeight - 200
|
||||
}
|
||||
|
||||
// Methods
|
||||
const goBack = () => {
|
||||
if (hasChanges.value) {
|
||||
if (confirm('您有未保存的更改,确定要离开吗?')) {
|
||||
router.push('/templates')
|
||||
}
|
||||
} else {
|
||||
// New template
|
||||
template.value = {
|
||||
id: '',
|
||||
name: '',
|
||||
description: '',
|
||||
files: [],
|
||||
directories: []
|
||||
}
|
||||
router.push('/templates')
|
||||
}
|
||||
})
|
||||
|
||||
const addFile = () => {
|
||||
if (!newFile.value.path.trim()) return
|
||||
|
||||
// Check for duplicate file paths
|
||||
const exists = template.value.files.some((f) => f.path === newFile.value.path)
|
||||
if (exists) {
|
||||
alert('该文件路径已存在!')
|
||||
return
|
||||
}
|
||||
|
||||
template.value.files.push({
|
||||
path: newFile.value.path,
|
||||
content: newFile.value.content
|
||||
})
|
||||
|
||||
newFile.value = { path: '', content: '' }
|
||||
showAddFileDialog.value = false
|
||||
}
|
||||
|
||||
const removeFile = (file: any) => {
|
||||
template.value.files = template.value.files.filter((f) => f !== file)
|
||||
const expandAll = () => {
|
||||
expandedNodes.value = treeItems.value.map(item => item.id)
|
||||
}
|
||||
|
||||
const collapseAll = () => {
|
||||
expandedNodes.value = []
|
||||
}
|
||||
|
||||
const showAddDirectoryDialog = () => {
|
||||
newDirectoryPath.value = ''
|
||||
showDirectoryDialog.value = true
|
||||
}
|
||||
|
||||
const showAddFileDialog = () => {
|
||||
newFilePath.value = ''
|
||||
showFileDialog.value = true
|
||||
}
|
||||
|
||||
const addDirectory = () => {
|
||||
if (!newDir.value.path.trim()) return
|
||||
|
||||
// Check for duplicate directory paths
|
||||
const exists = template.value.directories.some(
|
||||
(d) => d.path === newDir.value.path
|
||||
)
|
||||
if (!newDirectoryPath.value.trim()) return
|
||||
|
||||
// Check for duplicates
|
||||
const exists = directories.value.some(d => d.path === newDirectoryPath.value)
|
||||
if (exists) {
|
||||
alert('该目录路径已存在!')
|
||||
return
|
||||
}
|
||||
|
||||
template.value.directories.push({
|
||||
path: newDir.value.path
|
||||
|
||||
directories.value.push({
|
||||
path: newDirectoryPath.value
|
||||
})
|
||||
|
||||
newDir.value = { path: '' }
|
||||
showAddDirDialog.value = false
|
||||
|
||||
showDirectoryDialog.value = false
|
||||
newDirectoryPath.value = ''
|
||||
}
|
||||
|
||||
const removeDirectory = (dir: any) => {
|
||||
template.value.directories = template.value.directories.filter(
|
||||
(d) => d !== dir
|
||||
)
|
||||
const addFile = () => {
|
||||
if (!newFilePath.value.trim()) return
|
||||
|
||||
// Check for duplicates
|
||||
const exists = files.value.some(f => f.path === newFilePath.value)
|
||||
if (exists) {
|
||||
alert('该文件路径已存在!')
|
||||
return
|
||||
}
|
||||
|
||||
const newFile = {
|
||||
path: newFilePath.value,
|
||||
content: ''
|
||||
}
|
||||
|
||||
files.value.push(newFile)
|
||||
|
||||
// Open editor for the new file
|
||||
editFileContent(newFile)
|
||||
|
||||
showFileDialog.value = false
|
||||
newFilePath.value = ''
|
||||
}
|
||||
|
||||
const editFile = (item: any) => {
|
||||
const file = files.value.find(f => `file-${f.path}` === item.id)
|
||||
if (file) {
|
||||
editFileContent(file)
|
||||
}
|
||||
}
|
||||
|
||||
const editFileContent = (file: { path: string; content: string }) => {
|
||||
editingFile.value = file
|
||||
editingFileContent.value = file.content
|
||||
showEditorDialog.value = true
|
||||
}
|
||||
|
||||
const saveFileContent = () => {
|
||||
if (editingFile.value) {
|
||||
const index = files.value.findIndex(f => f.path === editingFile.value?.path)
|
||||
if (index !== -1) {
|
||||
files.value[index].content = editingFileContent.value
|
||||
}
|
||||
}
|
||||
showEditorDialog.value = false
|
||||
}
|
||||
|
||||
const deleteItem = (item: any) => {
|
||||
if (!confirm('确定要删除此项吗?')) return
|
||||
|
||||
if (item.type === 'directory') {
|
||||
directories.value = directories.value.filter(d => `dir-${d.path}` !== item.id)
|
||||
} else {
|
||||
files.value = files.value.filter(f => `file-${f.path}` !== item.id)
|
||||
}
|
||||
}
|
||||
|
||||
const saveTemplate = () => {
|
||||
if (!formValid.value) return
|
||||
|
||||
if (templateId.value) {
|
||||
// Update existing template
|
||||
templateStore.updateTemplate(template.value)
|
||||
} else {
|
||||
// Create new template
|
||||
templateStore.addTemplate(template.value)
|
||||
|
||||
const templateData = {
|
||||
name: templateName.value,
|
||||
description: templateDescription.value,
|
||||
files: files.value,
|
||||
directories: directories.value
|
||||
}
|
||||
|
||||
router.push('/templates')
|
||||
}
|
||||
|
||||
const cancel = () => {
|
||||
|
||||
if (isEditMode.value) {
|
||||
const templateId = route.params.id as string
|
||||
templateStore.updateTemplate({
|
||||
id: templateId,
|
||||
...templateData
|
||||
})
|
||||
} else {
|
||||
templateStore.addTemplate(templateData)
|
||||
}
|
||||
|
||||
hasChanges.value = false
|
||||
router.push('/templates')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.border-e {
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.fill-height {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user