Merge branch 'develop'

This commit is contained in:
zhanggy committed 2025-10-30 10:26:29 +08:00
commit ee99467394
11 files changed
+141 -134

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# GitHub Personal Access Token for private repository access # GitHub Personal Access Token for private repository access
# Required for auto-updates from private repositories # Required for auto-updates from private repositories
GH_TOKEN=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 GH_TOKEN=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
# For private repositories, you might also need: # For private repositories, you might also need:
# GITHUB_TOKEN= # Alternative token name that some tools might use # GITHUB_TOKEN= # Alternative token name that some tools might use
+25 -25
View File
@@ -24,17 +24,17 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '20' node-version: '20'
- name: Configure Git to use HTTPS instead of SSH - name: Configure Git to use HTTPS instead of SSH
run: | run: |
git config --global url."https://github.com/".insteadOf git@github.com: git config --global url."https://github.com/".insteadOf git@github.com:
git config --global url."https://".insteadOf git:// git config --global url."https://".insteadOf git://
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
with: with:
@@ -42,12 +42,12 @@ jobs:
run_install: | run_install: |
- recursive: true - recursive: true
args: [--frozen-lockfile=false] args: [--frozen-lockfile=false]
- name: Get pnpm store directory - name: Get pnpm store directory
id: pnpm-cache id: pnpm-cache
run: | run: |
echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT echo "pnpm_cache_dir=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache - name: Setup pnpm cache
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
@@ -55,48 +55,48 @@ jobs:
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: | restore-keys: |
${{ runner.os }}-pnpm-store- ${{ runner.os }}-pnpm-store-
- name: Install dependencies - name: Install dependencies
run: pnpm install --no-frozen-lockfile run: pnpm install --no-frozen-lockfile
env: env:
NPM_CONFIG_LEGACY_PEER_DEPS: true NPM_CONFIG_LEGACY_PEER_DEPS: true
- name: Setup Git user - name: Setup Git user
run: | run: |
git config --global user.name 'github-actions[bot]' git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com' git config --global user.email 'github-actions[bot]@users.noreply.github.com'
- name: Bump version and generate changelog - name: Bump version and generate changelog
run: | run: |
# 根据 commit 信息自动更新版本和生成 changelog # 根据 commit 信息自动更新版本和生成 changelog
pnpm release pnpm release
# 获取新版本号 # 获取新版本号
VERSION=$(node -p "require('./package.json').version") VERSION=$(node -p "require('./package.json').version")
echo "VERSION=$VERSION" >> $GITHUB_ENV echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Push changes - name: Push changes
run: | run: |
git push origin main git push origin main
git push origin v${{ env.VERSION }} git push origin v${{ env.VERSION }}
- name: Build for all platforms - name: Build for all platforms
run: pnpm build:all run: pnpm pub
env: env:
# 在 macOS 上禁用代码签名 # 在 macOS 上禁用代码签名
CSC_IDENTITY_AUTO_DISCOVERY: false CSC_IDENTITY_AUTO_DISCOVERY: false
# GitHub token 用于发布 # GitHub token 用于发布
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create GitHub Release # - name: Create GitHub Release
uses: softprops/action-gh-release@v2 # uses: softprops/action-gh-release@v2
with: # with:
tag_name: v${{ env.VERSION }} # tag_name: v${{ env.VERSION }}
name: Release v${{ env.VERSION }} # name: Release v${{ env.VERSION }}
body_path: CHANGELOG.md # body_path: CHANGELOG.md
draft: false # draft: false
prerelease: false # prerelease: false
files: | # files: |
release/${{ env.VERSION }}/* # release/${{ env.VERSION }}/*
env: # env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+12 -12
View File
@@ -56,18 +56,18 @@ const baseConfig = {
win: { win: {
icon: 'buildAssets/icons/icon.ico', icon: 'buildAssets/icons/icon.ico',
target: [ target: [
{ // {
target: 'appx', // target: 'appx',
arch: 'x64' // arch: 'x64'
}, // },
{ // {
target: 'zip', // target: 'zip',
arch: 'x64' // arch: 'x64'
}, // },
{ // {
target: 'portable', // target: 'portable',
arch: 'x64' // arch: 'x64'
}, // },
{ {
target: 'nsis', target: 'nsis',
arch: 'x64' arch: 'x64'
+3 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "vutron", "name": "gdt-tool",
"appId": "com.vutron.vutron", "appId": "com.tool.gdt",
"version": "0.0.5", "version": "0.0.5",
"description": "Quick Start Templates for Vite + Vue 3 + Electron", "description": "Quick Start Templates for Vite + Vue 3 + Electron",
"homepage": "https://vutron.cdget.com", "homepage": "https://vutron.cdget.com",
@@ -36,6 +36,7 @@
"lint:fix": "eslint . --ext .js,.ts,.vue --fix .", "lint:fix": "eslint . --ext .js,.ts,.vue --fix .",
"test": "npm run build:pre && playwright test", "test": "npm run build:pre && playwright test",
"test:linux": "npm run build:pre && xvfb-run --auto-servernum --server-args='-screen 0, 1280x960x24' -- playwright test", "test:linux": "npm run build:pre && xvfb-run --auto-servernum --server-args='-screen 0, 1280x960x24' -- playwright test",
"pub": "npm run build:pre && electron-builder --config=buildAssets/builder/config.js --windows --publish=always",
"release": "standard-version", "release": "standard-version",
"release:major": "standard-version --release-as major", "release:major": "standard-version --release-as major",
"release:minor": "standard-version --release-as minor", "release:minor": "standard-version --release-as minor",
+8
View File
@@ -17,6 +17,14 @@ export class AutoUpdater {
autoUpdater.allowPrerelease = false autoUpdater.allowPrerelease = false
autoUpdater.channel = 'latest' autoUpdater.channel = 'latest'
// 如果是私有仓库,设置认证信息
if (process.env.GH_TOKEN || process.env.GITHUB_TOKEN) {
// 使用环境变量中的令牌
autoUpdater.requestHeaders = {
'Authorization': `token ${process.env.GH_TOKEN || process.env.GITHUB_TOKEN}`
}
}
// 设置事件监听器 // 设置事件监听器
this.setupEventListeners() this.setupEventListeners()
} }
+35 -11
View File
@@ -57,13 +57,37 @@ export default class IPCs {
if (!dialogResult.canceled && dialogResult.filePaths.length > 0) { if (!dialogResult.canceled && dialogResult.filePaths.length > 0) {
return { return {
canceled: false, canceled: false,
filePath: dialogResult.filePaths[0] filePath: dialogResult.filePaths[0],
isDirectory: true
} }
} }
return { canceled: true } return { canceled: true }
}) })
// Select file or directory
ipcMain.handle('msgSelectFileOrFolder', async () => {
const dialogResult = await dialog.showOpenDialog({
properties: ['openFile', 'openDirectory']
})
if (!dialogResult.canceled && dialogResult.filePaths.length > 0) {
const filePath = dialogResult.filePaths[0];
const fs = require('fs');
const isDirectory = fs.statSync(filePath).isDirectory();
return {
canceled: false,
filePath: filePath,
isDirectory: isDirectory
}
}
return { canceled: true }
})
// Find all files in a folder recursively // Find all files in a folder recursively
ipcMain.handle( ipcMain.handle(
'msgFindFilesInFolder', 'msgFindFilesInFolder',
@@ -71,16 +95,16 @@ export default class IPCs {
try { try {
const { readdirSync, statSync } = require('fs') const { readdirSync, statSync } = require('fs')
const { join } = require('path') const { join } = require('path')
const foundFiles: string[] = [] const foundFiles: string[] = []
const searchFiles = (dir: string) => { const searchFiles = (dir: string) => {
const items = readdirSync(dir) const items = readdirSync(dir)
for (const item of items) { for (const item of items) {
const fullPath = join(dir, item) const fullPath = join(dir, item)
const stats = statSync(fullPath) const stats = statSync(fullPath)
if (stats.isDirectory()) { if (stats.isDirectory()) {
// Recursively search in subdirectories // Recursively search in subdirectories
searchFiles(fullPath) searchFiles(fullPath)
@@ -90,9 +114,9 @@ export default class IPCs {
} }
} }
} }
searchFiles(folderPath) searchFiles(folderPath)
return foundFiles return foundFiles
} catch (error) { } catch (error) {
console.error('Error finding files in folder:', error) console.error('Error finding files in folder:', error)
@@ -188,21 +212,21 @@ export default class IPCs {
} }
return allNodes; return allNodes;
}; };
// Collect all nodes from the tree structure // Collect all nodes from the tree structure
if (template.treeStructure && template.treeStructure.length > 0) { if (template.treeStructure && template.treeStructure.length > 0) {
const allNodes = collectAllNodes(template.treeStructure); const allNodes = collectAllNodes(template.treeStructure);
// Process all nodes, making sure directories are created before files // Process all nodes, making sure directories are created before files
for (const node of allNodes) { for (const node of allNodes) {
const nodePath = join(baseDirPath, node.path); const nodePath = join(baseDirPath, node.path);
if (node.type === 'directory') { if (node.type === 'directory') {
ensureDirSync(nodePath); ensureDirSync(nodePath);
} else if (node.type === 'file') { } else if (node.type === 'file') {
const fileDir = dirname(nodePath); const fileDir = dirname(nodePath);
ensureDirSync(fileDir); ensureDirSync(fileDir);
if (node.sourceFilePath) { if (node.sourceFilePath) {
// Copy from source file // Copy from source file
const sourceContent = readFileSync(node.sourceFilePath); const sourceContent = readFileSync(node.sourceFilePath);
+1
View File
@@ -11,6 +11,7 @@ const mainAvailChannels: string[] = [
'msgOpenExternalLink', 'msgOpenExternalLink',
'msgOpenFile', 'msgOpenFile',
'msgSelectDirectory', 'msgSelectDirectory',
'msgSelectFileOrFolder',
'msgLoadData', 'msgLoadData',
'msgSaveData', 'msgSaveData',
'msgExecuteTemplate', 'msgExecuteTemplate',
@@ -36,7 +36,9 @@ const headerMenus: {
</script> </script>
<template> <template>
<v-app-bar color="primary" density="compact"> <v-app-bar color="primary" density="compact">
<v-app-bar-title @click="handleRoute('/')">{{ t(titleKey) }}</v-app-bar-title> <v-app-bar-title @click="handleRoute('/')">
GDT Tool
</v-app-bar-title>
<!-- <template #append> <!-- <template #append>
<v-btn <v-btn
v-for="menu in headerMenus" v-for="menu in headerMenus"
+42 -71
View File
@@ -6,8 +6,7 @@
<v-row class="fill-height"> <v-row class="fill-height">
<!-- Left Panel - Template Info --> <!-- Left Panel - Template Info -->
<v-col <v-col
cols="12" cols="4"
md="4"
class="pa-4 border-e" class="pa-4 border-e"
> >
<div class="d-flex align-center mb-4"> <div class="d-flex align-center mb-4">
@@ -38,7 +37,7 @@
v-model="templateName" v-model="templateName"
label="模板名称 *" label="模板名称 *"
placeholder="输入模板名称" placeholder="输入模板名称"
:rules="[requiredRule]" :rules="[requiredRule('模板名称')]"
required required
clearable clearable
density="comfortable" density="comfortable"
@@ -73,8 +72,7 @@
<!-- Right Panel - Tree Structure --> <!-- Right Panel - Tree Structure -->
<v-col <v-col
cols="12" cols="8"
md="8"
class="pa-4" class="pa-4"
> >
<div class="d-flex align-center mb-4"> <div class="d-flex align-center mb-4">
@@ -164,9 +162,9 @@
<v-form v-model="directoryFormValid"> <v-form v-model="directoryFormValid">
<v-text-field <v-text-field
v-model="newDirectoryPath" v-model="newDirectoryPath"
:label="currentEditingItem ? '新目录路径 *' : '目录路径 *'" :label="'目录名称'"
:placeholder="currentEditingItem ? '例如: src/new-components' : '例如: src/components'" :placeholder="'请输入目录名称'"
:rules="[requiredRule]" :rules="[requiredRule('目录名称')]"
required required
density="comfortable" density="comfortable"
ref="directoryInputRef" ref="directoryInputRef"
@@ -203,34 +201,39 @@
<v-form v-model="fileFormValid"> <v-form v-model="fileFormValid">
<v-text-field <v-text-field
v-model="newFilePath" v-model="newFilePath"
:label="currentEditingItem ? '新文件路径 *' : '目标文件路径 *'" :label="'文件名'"
:placeholder="currentEditingItem ? '例如: src/new-index.js' : '例如: src/index.js'" :placeholder="'文件名需要带上后缀,如:style skech.doc'"
:rules="[requiredRule]" :rules="[requiredRule('文件名')]"
required required
density="comfortable" density="comfortable"
ref="fileInputRef" ref="fileInputRef"
@keydown.enter="selectAndAddFile" @keydown.enter="selectAndAddFile"
/> />
<v-file-input webkitdirectory directory label="选择文件或文件夹" density="comfortable"></v-file-input>
<div class="d-flex align-center my-4"> <div class="d-flex align-center my-4">
<v-btn <v-btn
@click="selectSourceFile" @click="selectSourceFileOrFolder"
variant="outlined" variant="outlined"
class="mr-2" class="mr-2"
:disabled="!!currentEditingItem" :disabled="!!currentEditingItem"
> >
选择文件 选择文件或文件夹
</v-btn>
<v-btn
@click="selectSourceFolder"
variant="outlined"
class="mr-2"
:disabled="!!currentEditingItem"
>
选择文件夹
</v-btn> </v-btn>
</div> </div>
<!-- 选择提示 -->
<v-alert
type="info"
variant="tonal"
class="mt-2"
>
<div class="d-flex align-start flex-column">
<span>选择文件会直接复制到目标位置</span>
<span>选择文件夹则会自动匹配该文件夹下的文件进行复制并且重命名</span>
</div>
</v-alert>
<!-- Display selected source --> <!-- Display selected source -->
<div v-if="selectedSourcePath" class="d-flex align-center"> <div v-if="selectedSourcePath" class="d-flex align-center">
<v-icon :color="isAutoFindMode ? 'warning' : 'info'" class="mr-2"> <v-icon :color="isAutoFindMode ? 'warning' : 'info'" class="mr-2">
@@ -238,32 +241,6 @@
</v-icon> </v-icon>
<span class="text-truncate">{{ selectedSourcePath }}</span> <span class="text-truncate">{{ selectedSourcePath }}</span>
</div> </div>
<!-- Auto-find indicator -->
<v-alert
v-if="isAutoFindMode"
type="info"
variant="tonal"
class="mt-2"
>
<div class="d-flex align-center">
<v-icon class="mr-2">mdi-auto-fix</v-icon>
<span>自动寻找文件夹内的文件</span>
</div>
</v-alert>
<!-- Note when editing -->
<v-alert
v-if="currentEditingItem"
type="warning"
variant="tonal"
class="mt-2"
>
<div class="d-flex align-center">
<v-icon class="mr-2">mdi-information</v-icon>
<span>正在编辑现有文件路径,文件源不会改变</span>
</div>
</v-alert>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
@@ -430,7 +407,7 @@ const convertToTreeItem = (node: TreeNode): TreeItem => {
} }
// Validation rules // Validation rules
const requiredRule = (v: string | null | undefined) => !!v || '此字段为必填项' const requiredRule = (fieldName: string) => (v: string | null | undefined) => !!v || `${fieldName}为必填项`
// Watch for changes to detect unsaved changes // Watch for changes to detect unsaved changes
watch( watch(
@@ -542,7 +519,7 @@ const confirmAddDirectory = () => {
// In the parent directory, check if a node with the same name already exists // In the parent directory, check if a node with the same name already exists
const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value); const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value);
if (parentNode && parentNode.children) { if (parentNode && parentNode.children) {
const duplicateExists = parentNode.children.some(child => const duplicateExists = parentNode.children.some(child =>
child.name === newDirectoryPath.value child.name === newDirectoryPath.value
); );
if (duplicateExists) { if (duplicateExists) {
@@ -552,7 +529,7 @@ const confirmAddDirectory = () => {
} }
} else { } else {
// Check at root level for duplicates // Check at root level for duplicates
const duplicateExists = treeStructure.value.some(node => const duplicateExists = treeStructure.value.some(node =>
node.name === newDirectoryPath.value node.name === newDirectoryPath.value
); );
if (duplicateExists) { if (duplicateExists) {
@@ -692,7 +669,7 @@ const selectAndAddFile = async () => {
// In the parent directory, check if a node with the same name already exists // In the parent directory, check if a node with the same name already exists
const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value); const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value);
if (parentNode && parentNode.children) { if (parentNode && parentNode.children) {
const duplicateExists = parentNode.children.some(child => const duplicateExists = parentNode.children.some(child =>
child.name === newFilePath.value child.name === newFilePath.value
); );
if (duplicateExists) { if (duplicateExists) {
@@ -702,7 +679,7 @@ const selectAndAddFile = async () => {
} }
} else { } else {
// Check at root level for duplicates // Check at root level for duplicates
const duplicateExists = treeStructure.value.some(node => const duplicateExists = treeStructure.value.some(node =>
node.name === newFilePath.value node.name === newFilePath.value
); );
if (duplicateExists) { if (duplicateExists) {
@@ -710,7 +687,7 @@ const selectAndAddFile = async () => {
return; return;
} }
} }
// Also check for duplicates using the full path (for backward compatibility) // Also check for duplicates using the full path (for backward compatibility)
const hasDuplicate = checkForDuplicateInTree(treeStructure.value, fullPath); const hasDuplicate = checkForDuplicateInTree(treeStructure.value, fullPath);
if (hasDuplicate) { if (hasDuplicate) {
@@ -733,24 +710,24 @@ const selectAndAddFile = async () => {
const hasDuplicateInTree = checkForDuplicateInTree(treeStructure.value, fullTargetPath); const hasDuplicateInTree = checkForDuplicateInTree(treeStructure.value, fullTargetPath);
if (!hasDuplicateInTree) { if (!hasDuplicateInTree) {
const fileName = fullTargetPath.split('/').pop() || fullTargetPath; const fileName = fullTargetPath.split('/').pop() || fullTargetPath;
// Additionally, check for duplicate names in the same parent directory // Additionally, check for duplicate names in the same parent directory
let duplicateNameExists = false; let duplicateNameExists = false;
if (parentDirectoryForNewItems.value) { if (parentDirectoryForNewItems.value) {
// In the parent directory, check if a node with the same name already exists // In the parent directory, check if a node with the same name already exists
const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value); const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value);
if (parentNode && parentNode.children) { if (parentNode && parentNode.children) {
duplicateNameExists = parentNode.children.some(child => duplicateNameExists = parentNode.children.some(child =>
child.name === fileName child.name === fileName
); );
} }
} else { } else {
// Check at root level for duplicates // Check at root level for duplicates
duplicateNameExists = treeStructure.value.some(node => duplicateNameExists = treeStructure.value.some(node =>
node.name === fileName node.name === fileName
); );
} }
if (duplicateNameExists) { if (duplicateNameExists) {
showSnackbar(`当前目录下已存在同名节点:${fileName}`, 'error'); showSnackbar(`当前目录下已存在同名节点:${fileName}`, 'error');
} else { } else {
@@ -799,17 +776,17 @@ const selectAndAddFile = async () => {
// In the parent directory, check if a node with the same name already exists // In the parent directory, check if a node with the same name already exists
const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value); const parentNode = findNodeInTreeByName(treeStructure.value, parentDirectoryForNewItems.value);
if (parentNode && parentNode.children) { if (parentNode && parentNode.children) {
duplicateNameExists = parentNode.children.some(child => duplicateNameExists = parentNode.children.some(child =>
child.name === newFilePath.value child.name === newFilePath.value
); );
} }
} else { } else {
// Check at root level for duplicates // Check at root level for duplicates
duplicateNameExists = treeStructure.value.some(node => duplicateNameExists = treeStructure.value.some(node =>
node.name === newFilePath.value node.name === newFilePath.value
); );
} }
if (duplicateNameExists) { if (duplicateNameExists) {
showSnackbar('当前目录下已存在同名节点!', 'error'); showSnackbar('当前目录下已存在同名节点!', 'error');
} else { } else {
@@ -1062,19 +1039,13 @@ const showSnackbar = (message: string, color: string = 'error') => {
} }
// Methods for file/folder selection // Methods for file/folder selection
const selectSourceFile = async () => { const selectSourceFileOrFolder = async () => {
const result = await window.mainApi.invoke('msgOpenFile', 'any') // 使用现有的主进程API来选择文件或文件夹
if (!result.canceled && result.filePaths && result.filePaths.length > 0) { const result = await window.mainApi.invoke('msgSelectFileOrFolder')
selectedSourcePath.value = result.filePaths[0]
isAutoFindMode.value = false // Not in auto-find mode when selecting a specific file
}
}
const selectSourceFolder = async () => { if (result && result.filePath) {
const result = await window.mainApi.invoke('msgSelectDirectory')
if (!result.canceled && result.filePath) {
selectedSourcePath.value = result.filePath selectedSourcePath.value = result.filePath
isAutoFindMode.value = true // In auto-find mode when selecting a folder isAutoFindMode.value = result.isDirectory // 如果是目录,则启用自动查找模式
} }
} }
+5 -5
View File
@@ -81,14 +81,14 @@ const navigateToCreateTemplate = () => {
<v-row class="text-center mb-6"> <v-row class="text-center mb-6">
<v-col cols="12"> <v-col cols="12">
<h1 class="text-h4 font-weight-bold mb-4"> <h1 class="text-h4 font-weight-bold mb-4">
{{ t('title.main') }} GDT Tool
</h1> </h1>
<p class="text-h6 mb-6"> <p class="text-h6 mb-6">
{{ t('desc.welcome-desc') }} {{ t('desc.welcome-desc') }}
</p> </p>
</v-col> </v-col>
</v-row> </v-row>
<v-row justify="center" class="mb-6"> <v-row justify="center" class="mb-6">
<v-col cols="12" md="8" lg="6"> <v-col cols="12" md="8" lg="6">
<v-card class="pa-6 elevation-4"> <v-card class="pa-6 elevation-4">
@@ -150,7 +150,7 @@ const navigateToCreateTemplate = () => {
</v-expansion-panels> </v-expansion-panels>
</v-col> </v-col>
</v-row> </v-row>
<v-row class="mt-6"> <v-row class="mt-6">
<v-col <v-col
cols="12" cols="12"
@@ -169,7 +169,7 @@ const navigateToCreateTemplate = () => {
{{ t('menu.change-theme') }} {{ t('menu.change-theme') }}
</v-tooltip> </v-tooltip>
</v-btn> </v-btn>
<v-btn <v-btn
color="primary" color="primary"
@click="handleOpenDocument" @click="handleOpenDocument"
@@ -178,7 +178,7 @@ const navigateToCreateTemplate = () => {
<v-icon :icon="mdiFileDocument" start /> <v-icon :icon="mdiFileDocument" start />
{{ t('menu.documentation') }} {{ t('menu.documentation') }}
</v-btn> </v-btn>
<v-btn <v-btn
color="primary" color="primary"
@click="handleOpenGitHub" @click="handleOpenGitHub"
+6 -6
View File
@@ -3,7 +3,7 @@
<v-row> <v-row>
<v-col cols="12"> <v-col cols="12">
<div class="d-flex align-center mb-4 justify-space-between flex-wrap"> <div class="d-flex align-center mb-4 justify-space-between flex-wrap">
<h2 class="mr-2 mb-2"> 模板列表 </h2> <h2 class="mr-2 mb-2"> 文件创建 </h2>
<v-btn @click="navigateToCreateTemplate" color="primary" prepend-icon="mdi-plus" class="mb-2"> <v-btn @click="navigateToCreateTemplate" color="primary" prepend-icon="mdi-plus" class="mb-2">
创建模板 创建模板
</v-btn> </v-btn>
@@ -170,7 +170,7 @@ const executeFormValid = ref(false)
const countTreeNodes = (nodes: TreeNode[]) => { const countTreeNodes = (nodes: TreeNode[]) => {
let files = 0; let files = 0;
let directories = 0; let directories = 0;
const count = (nodeList: TreeNode[]) => { const count = (nodeList: TreeNode[]) => {
nodeList.forEach(node => { nodeList.forEach(node => {
if (node.type === 'file') { if (node.type === 'file') {
@@ -183,15 +183,15 @@ const countTreeNodes = (nodes: TreeNode[]) => {
} }
}); });
}; };
count(nodes || []); count(nodes || []);
return { files, directories }; return { files, directories };
} }
const templateTree = computed<TreeNode[]>(() => { const templateTree = computed<TreeNode[]>(() => {
if (!selectedTemplate.value) return [] if (!selectedTemplate.value) return []
// 直接返回模板的树状结构 // 直接返回模板的树状结构
return selectedTemplate.value.treeStructure || [] return selectedTemplate.value.treeStructure || []
}) })
@@ -217,7 +217,7 @@ const deleteTemplate = async (template: Template) => {
cancelText: '取消', cancelText: '取消',
confirmColor: 'error' confirmColor: 'error'
}) })
if (confirmed) { if (confirmed) {
storeDeleteTemplate(template.id) storeDeleteTemplate(template.id)
} }