Merge branch 'develop'
This commit is contained in:
commit
ee99467394
11 files changed
+141
-134
No files matched your search
+1
-1
@@ -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
|
||||||
@@ -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 }}
|
||||||
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 // 如果是目录,则启用自动查找模式
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user