Compare commits

..

7 Commits

Author SHA1 Message Date
e6182b6c36 支持大文件
Some checks failed
CI/CD / Code Check (push) Has been cancelled
CI/CD / Build Windows (push) Has been cancelled
2026-03-16 19:21:06 +08:00
9ed40b384d 支持大文件 2026-03-16 19:20:26 +08:00
ee28b380f6 更新 README-EN.md
Some checks failed
CI/CD / Code Check (push) Has been cancelled
CI/CD / Build Windows (push) Has been cancelled
2026-03-16 13:00:26 +08:00
7988cafc0f 更新 README.md
Some checks failed
CI/CD / Code Check (push) Has been cancelled
CI/CD / Build Windows (push) Has been cancelled
2026-03-16 13:00:02 +08:00
0e053a7809 添加 README-EN.md
Some checks failed
CI/CD / Code Check (push) Has been cancelled
CI/CD / Build Windows (push) Has been cancelled
2026-03-16 12:53:24 +08:00
41c80af92d 更新 README.md
Some checks failed
CI/CD / Code Check (push) Has been cancelled
CI/CD / Build Windows (push) Has been cancelled
2026-03-16 12:50:22 +08:00
5c278e1925 支持大文件
Some checks failed
CI/CD / Code Check (push) Has been cancelled
CI/CD / Build Windows (push) Has been cancelled
2026-03-15 09:02:02 +08:00
25 changed files with 2254 additions and 289 deletions

View File

@@ -3,115 +3,210 @@
## 项目分析
DeEarthX-CE 是一个与 Minecraft 相关的工具,包含以下组件:
- **后端**TypeScript + Express 构建,提供模组检测、过滤、平台集成等功能
- **端**Vue 3 + Ant Design Vue + Tauri 构建的桌面应用
- **文档**VitePress 构建的文档网站
* **端**TypeScript + Express 构建,提供模组检测、过滤、平台集成等功能
* **前端**Vue 3 + Ant Design Vue + Tauri 构建的桌面应用
* **文档**VitePress 构建的文档网站
## 改进任务列表
### [ ] 任务 1代码质量检查与优化
- **Priority**P1
- **Depends On**None
- **Description**
- 检查并清理未使用的依赖
- 统一代码风格和命名规范
- 优化错误处理机制
- 提高代码可读性和可维护性
- **Success Criteria**
- 所有依赖都是必要的
- 代码风格统一
- 错误处理完善
- **Test Requirements**
- `programmatic` TR-1.1:运行 `npm run build` 无错误
- `programmatic` TR-1.2:运行代码检查工具无严重警告
- `human-judgement` TR-1.3:代码结构清晰,注释完善
### \[ ] 任务 1代码质量检查与优化
### [ ] 任务 2性能优化
- **Priority**P2
- **Depends On**:任务 1
- **Description**
- 优化文件操作性能
- 优化网络请求和响应
- 减少不必要的计算和重复操作
- 提高模组处理速度
- **Success Criteria**
- 文件操作速度提升
- 网络请求响应时间减少
- 模组处理效率提高
- **Test Requirements**
- `programmatic` TR-2.1:模组处理时间减少 20%
- `programmatic` TR-2.2:内存使用降低 15%
- `human-judgement` TR-2.3:用户操作响应更流畅
* **Priority**P1
### [ ] 任务 3安全性增强
- **Priority**P1
- **Depends On**:任务 1
- **Description**
- 检查并修复安全漏洞
- 加强输入验证
- 优化文件操作安全性
- 检查依赖的安全状态
- **Success Criteria**
- 无安全漏洞
- 输入验证完善
- 依赖无安全问题
- **Test Requirements**
- `programmatic` TR-3.1:运行安全扫描工具无严重漏洞
- `programmatic` TR-3.2:所有输入都经过验证
- `human-judgement` TR-3.3:安全措施到位
* **Depends On**None
### [ ] 任务 4功能增强
- **Priority**P2
- **Depends On**:任务 1, 任务 3
- **Description**
- 完善用户界面交互
- 增加更多模组平台支持
- 优化模板管理功能
- 增强多语言支持
- **Success Criteria**
- 用户界面更友好
- 支持更多模组平台
- 模板管理更便捷
- 多语言支持更完善
- **Test Requirements**
- `programmatic` TR-4.1:所有新增功能正常工作
- `human-judgement` TR-4.2:用户界面美观易用
- `human-judgement` TR-4.3:多语言支持准确
* **Description**
### [ ] 任务 5构建和部署优化
- **Priority**P2
- **Depends On**:任务 1, 任务 2
- **Description**
- 优化构建流程
- 减少构建时间
- 优化打包大小
- 完善部署文档
- **Success Criteria**
- 构建流程更高效
- 构建时间减少
- 打包大小优化
- 部署文档完善
- **Test Requirements**
- `programmatic` TR-5.1:构建时间减少 25%
- `programmatic` TR-5.2:打包大小减少 20%
- `human-judgement` TR-5.3:部署文档清晰完整
* 检查并清理未使用的依赖
### [ ] 任务 6测试覆盖度提升
- **Priority**P3
- **Depends On**:任务 1
- **Description**
- 增加单元测试
- 增加集成测试
- 提高测试覆盖度
- 建立测试自动化流程
- **Success Criteria**
- 测试覆盖度达到 80% 以上
- 关键功能有测试用例
- 测试自动化流程建立
- **Test Requirements**
- `programmatic` TR-6.1:测试覆盖度达到 80% 以上
- `programmatic` TR-6.2:所有测试用例通过
- `human-judgement` TR-6.3:测试用例设计合理
* 统一代码风格和命名规范
* 优化错误处理机制
* 提高代码可读性和可维护性
* **Success Criteria**
* 所有依赖都是必要的
* 代码风格统一
* 错误处理完善
* **Test Requirements**
* `programmatic` TR-1.1:运行 `npm run build` 无错误
* `programmatic` TR-1.2:运行代码检查工具无严重警告
* `human-judgement` TR-1.3:代码结构清晰,注释完善
### \[ ] 任务 2性能优化
* **Priority**P2
* **Depends On**:任务 1
* **Description**
* 优化文件操作性能
* 优化网络请求和响应
* 减少不必要的计算和重复操作
* 提高模组处理速度
* **Success Criteria**
* 文件操作速度提升
* 网络请求响应时间减少
* 模组处理效率提高
* **Test Requirements**
* `programmatic` TR-2.1:模组处理时间减少 20%
* `programmatic` TR-2.2:内存使用降低 15%
* `human-judgement` TR-2.3:用户操作响应更流畅
### \[ ] 任务 3安全性增强
* **Priority**P1
* **Depends On**:任务 1
* **Description**
* 检查并修复安全漏洞
* 加强输入验证
* 优化文件操作安全性
* 检查依赖的安全状态
* **Success Criteria**
* 无安全漏洞
* 输入验证完善
* 依赖无安全问题
* **Test Requirements**
* `programmatic` TR-3.1:运行安全扫描工具无严重漏洞
* `programmatic` TR-3.2:所有输入都经过验证
* `human-judgement` TR-3.3:安全措施到位
### \[ ] 任务 4功能增强
* **Priority**P2
* **Depends On**:任务 1, 任务 3
* **Description**
* 完善用户界面交互
* 增加更多模组平台支持
* 优化模板管理功能
* 增强多语言支持
* **Success Criteria**
* 用户界面更友好
* 支持更多模组平台
* 模板管理更便捷
* 多语言支持更完善
* **Test Requirements**
* `programmatic` TR-4.1:所有新增功能正常工作
* `human-judgement` TR-4.2:用户界面美观易用
* `human-judgement` TR-4.3:多语言支持准确
### \[ ] 任务 5构建和部署优化
* **Priority**P2
* **Depends On**:任务 1, 任务 2
* **Description**
* 优化构建流程
* 减少构建时间
* 优化打包大小
* 完善部署文档
* **Success Criteria**
* 构建流程更高效
* 构建时间减少
* 打包大小优化
* 部署文档完善
* **Test Requirements**
* `programmatic` TR-5.1:构建时间减少 25%
* `programmatic` TR-5.2:打包大小减少 20%
* `human-judgement` TR-5.3:部署文档清晰完整
### \[ ] 任务 6测试覆盖度提升
* **Priority**P3
* **Depends On**:任务 1
* **Description**
* 增加单元测试
* 增加集成测试
* 提高测试覆盖度
* 建立测试自动化流程
* **Success Criteria**
* 测试覆盖度达到 80% 以上
* 关键功能有测试用例
* 测试自动化流程建立
* **Test Requirements**
* `programmatic` TR-6.1:测试覆盖度达到 80% 以上
* `programmatic` TR-6.2:所有测试用例通过
* `human-judgement` TR-6.3:测试用例设计合理
## 实施步骤
@@ -125,9 +220,16 @@ DeEarthX-CE 是一个与 Minecraft 相关的工具,包含以下组件:
## 预期成果
通过以上改进DeEarthX-CE 项目将:
- 代码质量更高,更易维护
- 性能更优,响应更快
- 安全性更强,更可靠
- 能更完善,用户体验更好
- 构建和部署更高效
- 测试覆盖更全面,质量更有保障
* 代码质量更高,更易维护
* 能更优,响应更快
* 安全性更强,更可靠
* 功能更完善,用户体验更好
* 构建和部署更高效
* 测试覆盖更全面,质量更有保障

91
README-EN.md Normal file
View File

@@ -0,0 +1,91 @@
# DeEarthX-CE
[简体中文](README.md) | English
## Project Overview
DeEarthX V3 is a Minecraft server-side modpack creation tool that helps you quickly convert client-side modpacks into runnable servers, while also providing template management capabilities.
QQ Group: 1090666196
Documentation: [https://dex.xcclyc.cn/](https://dex.xcclyc.cn/)
## Core Features
### Modpack Support
- CurseForge
- Modrinth
- MCBBS
### Mod Processing
Automatically distinguish between client-side and server-side mods, keeping what the server needs and removing client-exclusive ones (shaders, resource packs, etc.).
### Working Modes
- **Server Mode**: Downloads server and mod loaders, fully generates the server
- **Upload Mode**: Only performs mod filtering, without downloading server files
### Mod Loaders
- Forge
- NeoForge
- Fabric
### Version Support
Supports versions from 1.16.5 to the latest.
### Template Management
- Create, edit, and delete local templates
- Import/export templates
- Template store, support downloading templates from remote servers
- Smart download speed test, select the fastest download link
## Technical Architecture
### Backend
TypeScript + Node.js, Express provides web services, WebSocket real-time communication, packaged as standalone exe using Node.js SEA.
### Frontend
Vue 3 + TypeScript, Tauri 2 desktop framework, Ant Design Vue UI components, Tailwind CSS styling.
## Usage Process
1. Prepare the modpack file
2. Select the mode (Server/Upload)
3. Upload the file
4. Wait for processing to complete
5. Download the server
## Template Management Process
1. Enter the template management page
2. Select local templates or template store
3. Local templates: Create, edit, delete, export templates
4. Template store: Browse and download templates
## Project Features
- Upload and use immediately, no configuration required
- Real-time progress display
- Built-in BMCLAPI and MCIM mirror sources for accelerated downloads
- Multi-language support
- Smart template management system
- Template store provides rich preset templates
> [!WARNING]
> Mods may not be filtered completely, and the generated server is prohibited from being used for sale!
## Installation Instructions
Simply download and install the installer to use.
**Note**: It is recommended not to install on drive C to avoid permission issues.
## System Requirements
- Operating System: Windows
- Server mode requires Java environment
- Upload mode does not require Java
## Development Team
- **Tianpao**: Core development, original author
- **XCC**: Feature optimization, CE version author

View File

@@ -1,4 +1,6 @@
# DeEarthX V3
# DeEarthX-CE
[English](README-EN.md) | 简体中文
## 项目概述
@@ -6,6 +8,10 @@ DeEarthX V3 是一个 Minecraft 整合包服务端制作工具,帮你快速把
QQ群1090666196
## 文档地址
文档地址:[https://dex.xcclyc.cn/](https://dex.xcclyc.cn/)
## 核心功能
### 整合包支持
@@ -83,5 +89,5 @@ Vue 3 + TypeScriptTauri 2 桌面框架Ant Design Vue UI 组件Tailwind
## 开发团队
- **Tianpao**:核心开发
- **XCC**:功能优化
- **Tianpao**:核心开发,原作者
- **XCC**:功能优化CE版作者

View File

@@ -550,12 +550,12 @@ export class ModCheckService {
jarData = fs.readFileSync(file.filename);
}
const { Azip } = await import("../utils/ziplib.js");
const zipEntries = Azip(jarData);
const { yauzl_promise } = await import("../utils/ziplib.js");
const zipEntries = await yauzl_promise(jarData);
for (const entry of zipEntries) {
if (entry.entryName === iconPath || entry.entryName.endsWith(iconPath)) {
const data = await entry.getData();
if (entry.fileName === iconPath || entry.fileName.endsWith(iconPath)) {
const data = await entry.ReadEntry;
const ext = iconPath.split('.').pop()?.toLowerCase();
const mimeType = ext === 'png' ? 'png' : 'jpeg';

View File

@@ -22,23 +22,18 @@ export class FileExtractor {
const fullPath = path.join(this.modsPath, jarFilename);
try {
let fileData: Buffer | null = null;
try {
fileData = fs.readFileSync(fullPath);
const mixins = await JarParser.extractMixins(fileData);
const infos = await JarParser.extractModInfo(fileData);
const hash = await this.calculateFileHash(fullPath);
const mixins = await JarParser.extractMixinsFromFile(fullPath);
const infos = await JarParser.extractModInfoFromFile(fullPath);
files.push({
filename: fullPath,
hash: crypto.createHash('sha1').update(fileData).digest('hex'),
hash,
mixins,
infos,
});
logger.debug("文件已处理", { 文件名: fullPath, 绝对路径: path.resolve(fullPath), Mixin数量: mixins.length });
} finally {
fileData = null;
}
} catch (error: any) {
logger.error("处理文件时出错", { 文件名: fullPath, 错误: error.message });
}
@@ -48,6 +43,25 @@ export class FileExtractor {
return files;
}
private async calculateFileHash(filePath: string): Promise<string> {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('sha1');
const stream = fs.createReadStream(filePath);
stream.on('data', (chunk) => {
hash.update(chunk);
});
stream.on('end', () => {
resolve(hash.digest('hex'));
});
stream.on('error', (error) => {
reject(error);
});
});
}
private getJarFiles(): string[] {
if (!fs.existsSync(this.modsPath)) {
fs.mkdirSync(this.modsPath, { recursive: true });

View File

@@ -2,7 +2,7 @@ import got, { Got } from "got";
import fs from "node:fs";
import fse from "fs-extra";
import { execPromise, fastdownload, version_compare, verifySHA1 } from "../utils/utils.js";
import { Azip } from "../utils/ziplib.js";
import { yauzl_promise } from "../utils/ziplib.js";
import { Config } from "../utils/config.js";
import { logger } from "../utils/logger.js";
@@ -84,18 +84,20 @@ export class Forge {
async library() {
const _downlist: [string, string][] = [];
const data = await fs.promises.readFile(`${this.path}/forge-${this.minecraft}-${this.loaderVersion}-installer.jar`);
const zip = Azip(data);
const zip = await yauzl_promise(data);
for await (const entry of zip) {
if (entry.entryName === "version.json" || entry.entryName === "install_profile.json") {
JSON.parse((entry.getData()).toString()).libraries.forEach(async (e: any) => {
for (const entry of zip) {
if (entry.fileName === "version.json" || entry.fileName === "install_profile.json") {
const entryData = await entry.ReadEntry;
JSON.parse(entryData.toString()).libraries.forEach(async (e: any) => {
const t = e.downloads.artifact.path;
_downlist.push([`https://bmclapi2.bangbang93.com/maven/${t}`, `${this.path}/libraries/${t}`]);
});
}
if (entry.entryName === "install_profile.json") {
const json = JSON.parse((entry.getData()).toString()) as IForge;
if (entry.fileName === "install_profile.json") {
const entryData = await entry.ReadEntry;
const json = JSON.parse(entryData.toString()) as IForge;
const vjson = await this.got.get(`version/${this.minecraft}/json`).json<IVersion>();
console.log(`${new URL(vjson.downloads.server_mappings.url).pathname}`);
const mojpath = this.MTP(json.data.MOJMAPS.server);

View File

@@ -2,7 +2,7 @@ import fs from "node:fs";
import { fastdownload, version_compare } from "../utils/utils.js";
import got from "got";
import p from "path";
import { Azip } from "../utils/ziplib.js";
import { yauzl_promise } from "../utils/ziplib.js";
import { Config } from "../utils/config.js";
interface ILInfo {
@@ -54,12 +54,12 @@ export class Minecraft {
if (version_compare(this.minecraft, "1.18") === 1) {
const mcpath = `${this.path}/libraries/net/minecraft/server/${this.minecraft}/server-${this.minecraft}.jar`;
await fastdownload([`https://bmclapi2.bangbang93.com/version/${this.minecraft}/server`, mcpath]);
const zip = await Azip(await fs.promises.readFile(mcpath));
for await (const entry of zip) {
if (entry.entryName.startsWith("META-INF/libraries/") && !entry.entryName.endsWith("/")) {
console.log(entry.entryName);
const data = entry.getData();
const filepath = `${this.path}/libraries/${entry.entryName.replace("META-INF/libraries/", "")}`;
const zip = await yauzl_promise(await fs.promises.readFile(mcpath));
for (const entry of zip) {
if (entry.fileName.startsWith("META-INF/libraries/") && !entry.fileName.endsWith("/")) {
console.log(entry.fileName);
const data = await entry.ReadEntry;
const filepath = `${this.path}/libraries/${entry.fileName.replace("META-INF/libraries/", "")}`;
const dir = p.dirname(filepath);
await fs.promises.mkdir(dir, { recursive: true });
await fs.promises.writeFile(filepath, data);

View File

@@ -1,20 +1,124 @@
import { IInfoFile, IMixinFile } from "../dearth/types.js";
import { Azip } from "./ziplib.js";
import { yauzl_promise } from "./ziplib.js";
import toml from "smol-toml";
import fs from "node:fs";
import yauzl from "yauzl";
export class JarParser {
static async extractModInfo(jarData: Buffer): Promise<IInfoFile[]> {
return this.extractModInfoFromBuffer(jarData);
}
static async extractMixins(jarData: Buffer): Promise<IMixinFile[]> {
return this.extractMixinsFromBuffer(jarData);
}
static async extractModInfoFromFile(filePath: string): Promise<IInfoFile[]> {
return new Promise((resolve, reject) => {
const infos: IInfoFile[] = [];
const zipEntries = Azip(jarData);
yauzl.open(filePath, (err, zipfile) => {
if (err) {
reject(err);
return;
}
zipfile.on("entry", (entry) => {
if (entry.fileName.endsWith("neoforge.mods.toml") || entry.fileName.endsWith("mods.toml") || entry.fileName.endsWith("fabric.mod.json")) {
zipfile.openReadStream(entry, (err, stream) => {
if (err) {
return;
}
const chunks: Buffer[] = [];
stream.on("data", (chunk) => {
chunks.push(chunk);
});
stream.on("end", () => {
try {
const data = Buffer.concat(chunks);
if (entry.fileName.endsWith(".toml")) {
infos.push({ name: entry.fileName, data: JSON.stringify(toml.parse(data.toString())) });
} else if (entry.fileName.endsWith(".json")) {
infos.push({ name: entry.fileName, data: data.toString() });
}
} catch (error) {
// 忽略解析错误
}
});
});
}
});
zipfile.on("end", () => {
resolve(infos);
});
zipfile.on("error", (err) => {
reject(err);
});
});
});
}
static async extractMixinsFromFile(filePath: string): Promise<IMixinFile[]> {
return new Promise((resolve, reject) => {
const mixins: IMixinFile[] = [];
yauzl.open(filePath, (err, zipfile) => {
if (err) {
reject(err);
return;
}
zipfile.on("entry", (entry) => {
if (entry.fileName.endsWith(".mixins.json") && !entry.fileName.includes("/")) {
zipfile.openReadStream(entry, (err, stream) => {
if (err) {
return;
}
const chunks: Buffer[] = [];
stream.on("data", (chunk) => {
chunks.push(chunk);
});
stream.on("end", () => {
try {
const data = Buffer.concat(chunks);
mixins.push({ name: entry.fileName, data: data.toString() });
} catch (error) {
// 忽略解析错误
}
});
});
}
});
zipfile.on("end", () => {
resolve(mixins);
});
zipfile.on("error", (err) => {
reject(err);
});
});
});
}
private static async extractModInfoFromBuffer(jarData: Buffer): Promise<IInfoFile[]> {
const infos: IInfoFile[] = [];
const zipEntries = await yauzl_promise(jarData);
for (const entry of zipEntries) {
try {
if (entry.entryName.endsWith("neoforge.mods.toml") || entry.entryName.endsWith("mods.toml")) {
const data = await entry.getData();
infos.push({ name: entry.entryName, data: JSON.stringify(toml.parse(data.toString())) });
} else if (entry.entryName.endsWith("fabric.mod.json")) {
const data = await entry.getData();
infos.push({ name: entry.entryName, data: data.toString() });
if (entry.fileName.endsWith("neoforge.mods.toml") || entry.fileName.endsWith("mods.toml")) {
const data = await entry.ReadEntry;
infos.push({ name: entry.fileName, data: JSON.stringify(toml.parse(data.toString())) });
} else if (entry.fileName.endsWith("fabric.mod.json")) {
const data = await entry.ReadEntry;
infos.push({ name: entry.fileName, data: data.toString() });
}
} catch (error: any) {
continue;
@@ -24,15 +128,15 @@ export class JarParser {
return infos;
}
static async extractMixins(jarData: Buffer): Promise<IMixinFile[]> {
private static async extractMixinsFromBuffer(jarData: Buffer): Promise<IMixinFile[]> {
const mixins: IMixinFile[] = [];
const zipEntries = Azip(jarData);
const zipEntries = await yauzl_promise(jarData);
for (const entry of zipEntries) {
if (entry.entryName.endsWith(".mixins.json") && !entry.entryName.includes("/")) {
if (entry.fileName.endsWith(".mixins.json") && !entry.fileName.includes("/")) {
try {
const data = await entry.getData();
mixins.push({ name: entry.entryName, data: data.toString() });
const data = await entry.ReadEntry;
mixins.push({ name: entry.fileName, data: data.toString() });
} catch (error: any) {
continue;
}

View File

@@ -1,4 +1,3 @@
import admZip from "adm-zip";
import yauzl from "yauzl";
import Stream from "node:stream";
@@ -11,7 +10,7 @@ export async function yauzl_promise(buffer: Buffer): Promise<IentryP[]> {
const zip = await (new Promise((resolve, reject) => {
yauzl.fromBuffer(
buffer,
/*{lazyEntries:true},*/ (err, zipfile) => {
(err, zipfile) => {
if (err) {
reject(err);
return;
@@ -43,6 +42,9 @@ export async function yauzl_promise(buffer: Buffer): Promise<IentryP[]> {
stream.on("end", () => {
resolve(Buffer.concat(chunks));
});
stream.on("error", (err) => {
reject(err);
});
});
});
};
@@ -64,16 +66,15 @@ export async function yauzl_promise(buffer: Buffer): Promise<IentryP[]> {
return new Promise((resolve, reject) => {
const entries: IentryP[] = [];
zip.on("entry", async (entry: yauzl.Entry) => {
zip.on("entry", (entry: yauzl.Entry) => {
const entryP = entry as IentryP;
//console.log(entry.fileName);
entryP.openReadStream = _openReadStream(zip, entry);
entryP.ReadEntry = _ReadEntry(zip, entry);
entries.push(entryP);
if (zip.entryCount === entries.length) {
});
zip.on("end", () => {
zip.close();
resolve(entries);
}
});
zip.on("error", (err) => {
reject(err);
@@ -81,8 +82,15 @@ export async function yauzl_promise(buffer: Buffer): Promise<IentryP[]> {
});
}
export function Azip(buffer: Buffer) {
const zip = new admZip(buffer);
const entries = zip.getEntries();
return entries;
// 从文件路径打开 zip 文件的函数
export async function yauzl_from_file(filePath: string): Promise<yauzl.ZipFile> {
return new Promise((resolve, reject) => {
yauzl.open(filePath, { lazyEntries: true }, (err, zipfile) => {
if (err) {
reject(err);
return;
}
resolve(zipfile);
});
});
}

View File

@@ -34,6 +34,7 @@
"@vitejs/plugin-vue": "^5.2.4",
"typescript": "~5.6.3",
"vite": "^6.4.1",
"vue-tsc": "^2.2.12"
"vue-tsc": "^2.2.12",
"tslib": "^2.8.1"
}
}

View File

@@ -1,5 +1,5 @@
{
"version": "3.0.35",
"buildTime": "2026-03-10",
"author": "DeEarthX Team"
"version": "3.0.36",
"buildTime": "2026-03-15",
"author": "xcclyc"
}

View File

@@ -27,6 +27,11 @@
"csp": null
}
},
"plugins": {
"shell": {
"open": true
}
},
"bundle": {
"active": true,
"targets": "all",

View File

@@ -5,6 +5,7 @@ import { SettingOutlined, UploadOutlined, UserOutlined, WindowsOutlined, Loading
import { useRouter, useRoute } from 'vue-router';
import { Command } from '@tauri-apps/plugin-shell';
import { useI18n } from 'vue-i18n';
import { ErrorCode, createErrorInfo } from './utils/errorCodes';
const router = useRouter();
const route = useRoute();
@@ -82,9 +83,11 @@ async function runCoreProcess() {
if (portStatus === 'wrong_app') {
// 端口被其他应用占用
const errorInfo = createErrorInfo(ErrorCode.BACKEND_PORT_OCCUPIED);
backendStatus.value = 'error';
backendErrorInfo.value = t('message.backend_port_occupied');
message.error(t('message.backend_port_occupied'));
backendErrorInfo.value = `${errorInfo.message} (错误码: ${errorInfo.code})`;
message.error(backendErrorInfo.value);
router.push(`/error?e=${encodeURIComponent(backendErrorInfo.value)}&code=${errorInfo.code}`);
return;
}
@@ -105,15 +108,19 @@ async function runCoreProcess() {
backendErrorInfo.value = '';
message.success(t('message.backend_started'));
} else {
const errorInfo = createErrorInfo(ErrorCode.BACKEND_RESPONSE_ERROR, `HTTP 状态码: ${response.status}`);
backendStatus.value = 'error';
backendErrorInfo.value = t('common.status_error');
router.push('/error');
backendErrorInfo.value = `${errorInfo.message} (错误码: ${errorInfo.code})`;
message.error(backendErrorInfo.value);
router.push(`/error?e=${encodeURIComponent(backendErrorInfo.value)}&code=${errorInfo.code}`);
}
} catch (error) {
console.error("后端连接失败:", error);
const errorInfo = createErrorInfo(ErrorCode.BACKEND_CONNECTION_FAILED, error instanceof Error ? error.message : String(error));
backendStatus.value = 'error';
backendErrorInfo.value = t('common.status_error');
router.push('/error');
backendErrorInfo.value = `${errorInfo.message} (错误码: ${errorInfo.code})`;
message.error(backendErrorInfo.value);
router.push(`/error?e=${encodeURIComponent(backendErrorInfo.value)}&code=${errorInfo.code}`);
}
}, 3000); // 等待3秒让后端启动
})
@@ -127,9 +134,11 @@ async function runCoreProcess() {
runCoreProcess();
}, 2000);
} else {
const errorInfo = createErrorInfo(ErrorCode.BACKEND_START_FAILED, `已重试 ${maxRetries}`);
backendStatus.value = 'error';
backendErrorInfo.value = t('message.backend_start_failed', { count: maxRetries });
message.error(t('message.backend_start_failed', { count: maxRetries }));
backendErrorInfo.value = `${errorInfo.message} (错误码: ${errorInfo.code})`;
message.error(backendErrorInfo.value);
router.push(`/error?e=${encodeURIComponent(backendErrorInfo.value)}&code=${errorInfo.code}`);
}
});
}

View File

@@ -3,6 +3,7 @@ import { ref, inject, watch, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { message, notification } from 'ant-design-vue';
import { sendNotification } from '@tauri-apps/plugin-notification';
import { ErrorCode, createErrorInfo } from '../utils/errorCodes';
const { t } = useI18n();
@@ -239,61 +240,49 @@ onUnmounted(() => {
function handleError(result: any) {
if (result === 'jini') {
javaAvailable.value = false;
const errorInfo = createErrorInfo(ErrorCode.JAVA_NOT_FOUND);
notification.error({
message: t('home.java_error_title'),
description: t('home.java_error_desc'),
message: `${t('home.java_error_title')} (错误码: ${errorInfo.code})`,
description: `${t('home.java_error_desc')}\n\n${t('home.suggestions')}:\n${errorInfo.suggestions?.map((s, i) => `${i + 1}. ${s}`).join('\n')}`,
duration: 0
});
} else if (typeof result === 'string') {
let errorTitle = t('home.backend_error');
let errorDesc = t('home.backend_error_desc', { error: result });
let suggestions: string[] = [];
let errorInfo;
if (result.includes('network') || result.includes('connection') || result.includes('timeout')) {
errorTitle = t('home.network_error_title');
errorDesc = t('home.network_error_desc', { error: result });
suggestions = [
t('home.suggestion_check_network'),
t('home.suggestion_check_firewall'),
t('home.suggestion_retry')
];
errorInfo = createErrorInfo(ErrorCode.NETWORK_ERROR, result);
} else if (result.includes('file') || result.includes('permission') || result.includes('disk')) {
errorTitle = t('home.file_error_title');
errorDesc = t('home.file_error_desc', { error: result });
suggestions = [
t('home.suggestion_check_disk_space'),
t('home.suggestion_check_permission'),
t('home.suggestion_check_file_format')
];
} else if (result.includes('memory') || result.includes('out of memory') || result.includes('heap')) {
errorTitle = t('home.memory_error_title');
errorDesc = t('home.memory_error_desc', { error: result });
suggestions = [
t('home.suggestion_increase_memory'),
t('home.suggestion_close_other_apps'),
t('home.suggestion_restart_application')
];
if (result.includes('not found')) {
errorInfo = createErrorInfo(ErrorCode.FILE_NOT_FOUND, result);
} else if (result.includes('permission')) {
errorInfo = createErrorInfo(ErrorCode.FILE_PERMISSION_ERROR, result);
} else if (result.includes('format')) {
errorInfo = createErrorInfo(ErrorCode.FILE_FORMAT_ERROR, result);
} else {
suggestions = [
t('home.suggestion_check_backend'),
t('home.suggestion_check_logs'),
t('home.suggestion_contact_support')
];
errorInfo = createErrorInfo(ErrorCode.FILE_NOT_FOUND, result);
}
} else if (result.includes('memory') || result.includes('out of memory') || result.includes('heap')) {
errorInfo = createErrorInfo(ErrorCode.MEMORY_INSUFFICIENT, result);
} else if (result.includes('disk') || result.includes('space')) {
errorInfo = createErrorInfo(ErrorCode.DISK_SPACE_INSUFFICIENT, result);
} else {
errorInfo = createErrorInfo(ErrorCode.UNKNOWN_ERROR, result);
}
const fullDescription = `${errorDesc}\n\n${t('home.suggestions')}:\n${suggestions.map((s, i) => `${i + 1}. ${s}`).join('\n')}`;
const fullDescription = `${errorInfo.message}: ${errorInfo.details}\n\n${t('home.suggestions')}:\n${errorInfo.suggestions?.map((s, i) => `${i + 1}. ${s}`).join('\n')}`;
notification.error({
message: errorTitle,
message: `${errorInfo.message} (错误码: ${errorInfo.code})`,
description: fullDescription,
duration: 0
});
resetState();
} else {
const errorInfo = createErrorInfo(ErrorCode.UNKNOWN_ERROR);
notification.error({
message: t('home.unknown_error_title'),
description: t('home.unknown_error_desc'),
message: `${t('home.unknown_error_title')} (错误码: ${errorInfo.code})`,
description: `${t('home.unknown_error_desc')}\n\n${t('home.suggestions')}:\n${errorInfo.suggestions?.map((s, i) => `${i + 1}. ${s}`).join('\n')}`,
duration: 0
});
resetState();

View File

@@ -0,0 +1,153 @@
// 错误码定义
export enum ErrorCode {
// 后端启动相关错误
BACKEND_START_FAILED = 1001,
BACKEND_PORT_OCCUPIED = 1002,
BACKEND_CONNECTION_FAILED = 1003,
BACKEND_RESPONSE_ERROR = 1004,
// 网络相关错误
NETWORK_ERROR = 2001,
NETWORK_TIMEOUT = 2002,
NETWORK_CONNECTION_REFUSED = 2003,
// 文件相关错误
FILE_NOT_FOUND = 3001,
FILE_PERMISSION_ERROR = 3002,
FILE_FORMAT_ERROR = 3003,
FILE_SIZE_ERROR = 3004,
// 系统相关错误
JAVA_NOT_FOUND = 4001,
DISK_SPACE_INSUFFICIENT = 4002,
MEMORY_INSUFFICIENT = 4003,
// 未知错误
UNKNOWN_ERROR = 9999
}
// 错误信息映射
export const errorMessages: Record<ErrorCode, string> = {
[ErrorCode.BACKEND_START_FAILED]: '后端服务启动失败',
[ErrorCode.BACKEND_PORT_OCCUPIED]: '后端服务端口被占用',
[ErrorCode.BACKEND_CONNECTION_FAILED]: '后端服务连接失败',
[ErrorCode.BACKEND_RESPONSE_ERROR]: '后端服务响应错误',
[ErrorCode.NETWORK_ERROR]: '网络连接错误',
[ErrorCode.NETWORK_TIMEOUT]: '网络连接超时',
[ErrorCode.NETWORK_CONNECTION_REFUSED]: '网络连接被拒绝',
[ErrorCode.FILE_NOT_FOUND]: '文件未找到',
[ErrorCode.FILE_PERMISSION_ERROR]: '文件权限错误',
[ErrorCode.FILE_FORMAT_ERROR]: '文件格式错误',
[ErrorCode.FILE_SIZE_ERROR]: '文件大小错误',
[ErrorCode.JAVA_NOT_FOUND]: 'Java 未找到',
[ErrorCode.DISK_SPACE_INSUFFICIENT]: '磁盘空间不足',
[ErrorCode.MEMORY_INSUFFICIENT]: '内存不足',
[ErrorCode.UNKNOWN_ERROR]: '未知错误'
};
// 错误建议映射
export const errorSuggestions: Record<ErrorCode, string[]> = {
[ErrorCode.BACKEND_START_FAILED]: [
'检查 37019 端口是否被占用',
'检查后端服务是否正常',
'重启应用程序'
],
[ErrorCode.BACKEND_PORT_OCCUPIED]: [
'关闭占用 37019 端口的其他应用',
'检查是否有其他 DeEarthX 实例在运行',
'重启计算机后再试'
],
[ErrorCode.BACKEND_CONNECTION_FAILED]: [
'检查后端服务是否正在运行',
'检查网络连接是否正常',
'重启应用程序'
],
[ErrorCode.BACKEND_RESPONSE_ERROR]: [
'检查后端服务是否正常',
'重启后端服务',
'联系技术支持'
],
[ErrorCode.NETWORK_ERROR]: [
'检查网络连接是否正常',
'检查防火墙设置',
'稍后重试'
],
[ErrorCode.NETWORK_TIMEOUT]: [
'检查网络连接速度',
'稍后重试',
'检查目标服务器是否可访问'
],
[ErrorCode.NETWORK_CONNECTION_REFUSED]: [
'检查目标服务器是否正在运行',
'检查网络连接是否正常',
'检查防火墙设置'
],
[ErrorCode.FILE_NOT_FOUND]: [
'确认文件路径是否正确',
'检查文件是否存在',
'重新上传文件'
],
[ErrorCode.FILE_PERMISSION_ERROR]: [
'检查文件权限设置',
'以管理员身份运行应用程序',
'检查文件是否被其他程序占用'
],
[ErrorCode.FILE_FORMAT_ERROR]: [
'确认文件格式是否正确',
'重新上传正确格式的文件',
'检查文件是否损坏'
],
[ErrorCode.FILE_SIZE_ERROR]: [
'检查文件大小是否符合要求',
'压缩文件后再上传',
'检查磁盘空间是否充足'
],
[ErrorCode.JAVA_NOT_FOUND]: [
'安装 Java 17 或更高版本',
'配置 Java 环境变量',
'重启应用程序'
],
[ErrorCode.DISK_SPACE_INSUFFICIENT]: [
'清理磁盘空间',
'选择其他存储位置',
'删除不必要的文件'
],
[ErrorCode.MEMORY_INSUFFICIENT]: [
'增加系统内存',
'关闭其他占用内存的应用程序',
'减少同时处理的任务数量'
],
[ErrorCode.UNKNOWN_ERROR]: [
'重启应用程序',
'检查系统日志',
'联系技术支持'
]
};
// 获取错误信息
export function getErrorMessage(code: ErrorCode): string {
return errorMessages[code] || errorMessages[ErrorCode.UNKNOWN_ERROR];
}
// 获取错误建议
export function getErrorSuggestions(code: ErrorCode): string[] {
return errorSuggestions[code] || errorSuggestions[ErrorCode.UNKNOWN_ERROR];
}
// 错误对象接口
export interface ErrorInfo {
code: ErrorCode;
message: string;
details?: string;
suggestions?: string[];
}
// 创建错误信息
export function createErrorInfo(code: ErrorCode, details?: string): ErrorInfo {
return {
code,
message: getErrorMessage(code),
details,
suggestions: getErrorSuggestions(code)
};
}

View File

@@ -36,7 +36,7 @@ async function getVersionFromJson(): Promise<VersionInfo> {
return {
version: '1.0.0',
buildTime: 'Unknown',
author: 'Tianpao'
author: 'DeEarthX Team'
};
}
}

View File

@@ -1,22 +1,67 @@
<template>
<div class="tw:h-full tw:w-full tw:flex tw:flex-col tw:justify-center tw:items-center">
<div class="tw:w-32 tw:h-32 tw:mb-25">
<div class="tw:w-32 tw:h-32 tw:mb-8">
<svg class="w-32 h-32 mb-4" viewBox="0 0 120 120">
<circle cx="60" cy="60" r="50" fill="#ef4444" />
<path d="M40,40 L80,80 M80,40 L40,80" stroke="white" stroke-width="10" stroke-linecap="round" />
</svg>
<p class="tw:text-2xl tw:font-bold tw:text-center tw:mb-20 tw:text-red-500">Error</p>
<p class="tw:text-sm tw:text-center tw:text-gray-500">
</div>
<p class="tw:text-2xl tw:font-bold tw:text-center tw:mb-6 tw:text-red-500">Error</p>
<div class="tw:w-1/2 tw:max-w-md tw:bg-white tw:p-6 tw:rounded-lg tw:shadow-lg">
<p class="tw:text-sm tw:text-center tw:text-gray-500 mb-4">
{{ errorMessage }}
</p>
<div v-if="errorCode" class="tw:text-sm tw:text-center tw:text-gray-500 mb-6">
错误码{{ errorCode }}
</div>
<div v-if="suggestions.length > 0" class="tw:mt-6">
<p class="tw:text-sm tw:font-medium tw:text-gray-700 mb-2">建议解决方案</p>
<ul class="tw:text-xs tw:text-gray-600 tw:list-disc tw:pl-5">
<li v-for="(suggestion, index) in suggestions" :key="index" class="tw:mb-1">
{{ suggestion }}
</li>
</ul>
</div>
<div class="tw:mt-6 tw:flex tw:justify-center tw:gap-4">
<button
class="tw:px-4 tw:py-2 tw:bg-[#67eac3] tw:text-gray-800 tw:rounded-md tw:hover:bg-[#56d9b0] tw:transition-colors"
@click="goBack"
>
返回首页
</button>
<button
v-if="errorCode"
class="tw:px-4 tw:py-2 tw:bg-[#67eac3] tw:text-gray-800 tw:rounded-md tw:hover:bg-[#56d9b0] tw:transition-colors"
@click="openErrorDoc"
>
文档帮助
</button>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { ErrorCode, getErrorSuggestions } from '../utils/errorCodes';
import { open } from '@tauri-apps/plugin-shell';
const route = useRoute();
const router = useRouter();
const errorReason = route.query.e as string;
const errorMessage = errorReason ? `错误原因:${errorReason}` : 'DeEarthX.Core 启动失败!';
const errorCodeStr = route.query.code as string;
const errorCode = errorCodeStr ? parseInt(errorCodeStr) as ErrorCode : undefined;
const errorMessage = errorReason ? errorReason : 'DeEarthX.Core 启动失败!';
const suggestions = errorCode ? getErrorSuggestions(errorCode) : [];
function goBack() {
router.push('/');
}
function openErrorDoc() {
if (errorCode) {
const url = `https://dex.xcclyc.cn/api/error-codes.html#_${errorCode}`;
open(url);
}
}
</script>

View File

@@ -4,7 +4,7 @@
"description": "main",
"repository": {
"type": "git",
"url": "https://git.xcclyc.cn/15736060610/DeEarthX-CE.git"
"url": "https://git.xcclyc.cn/xcclyc/DeEarthX-CE.git"
},
"license": "ISC",
"author": "DexV3 Team",

1179
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,59 +8,59 @@ import {
watch
} from "./chunk-VIGQSUQT.js";
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/index.js
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/index.js
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/without-fonts.js
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/base.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/icons.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
import VPBadge from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import Layout from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/Layout.vue";
import { default as default2 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import { default as default3 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
import { default as default4 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
import { default as default5 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPFeatures.vue";
import { default as default6 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue";
import { default as default7 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
import { default as default8 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
import { default as default9 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
import { default as default10 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
import { default as default11 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue";
import { default as default12 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
import { default as default13 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue";
import { default as default14 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue";
import { default as default15 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
import { default as default16 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
import { default as default17 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
import { default as default18 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
import { default as default19 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/without-fonts.js
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/base.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/icons.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
import "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
import VPBadge from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import Layout from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/Layout.vue";
import { default as default2 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import { default as default3 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
import { default as default4 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
import { default as default5 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPFeatures.vue";
import { default as default6 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue";
import { default as default7 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
import { default as default8 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
import { default as default9 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
import { default as default10 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
import { default as default11 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue";
import { default as default12 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
import { default as default13 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue";
import { default as default14 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue";
import { default as default15 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
import { default as default16 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
import { default as default17 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
import { default as default18 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
import { default as default19 } from "D:/Users/Grace-X/Desktop/DeEarthX-CE/node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
import { onContentUpdated } from "vitepress";
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/composables/outline.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/composables/outline.js
import { getScrollOffset } from "vitepress";
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/support/utils.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/support/utils.js
import { withBase } from "vitepress";
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/composables/data.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/composables/data.js
import { useData as useData$ } from "vitepress";
var useData = useData$;
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/support/utils.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/support/utils.js
function ensureStartingSlash(path) {
return path.startsWith("/") ? path : `/${path}`;
}
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/support/sidebar.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/support/sidebar.js
function getSidebar(_sidebar, path) {
if (Array.isArray(_sidebar))
return addBase(_sidebar);
@@ -103,7 +103,7 @@ function addBase(items, _base) {
});
}
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/composables/sidebar.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/composables/sidebar.js
function useSidebar() {
const { frontmatter, page, theme: theme2 } = useData();
const is960 = useMediaQuery("(min-width: 960px)");
@@ -160,7 +160,7 @@ function useSidebar() {
};
}
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/composables/outline.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/composables/outline.js
var ignoreRE = /\b(?:VPBadge|header-anchor|footnote-ref|ignore-header)\b/;
var resolvedHeaders = [];
function getHeaders(range) {
@@ -225,7 +225,7 @@ function buildTree(data, min, max) {
return result;
}
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
function useLocalNav() {
const { theme: theme2, frontmatter } = useData();
const headers = shallowRef([]);
@@ -241,7 +241,7 @@ function useLocalNav() {
};
}
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/without-fonts.js
// ../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/without-fonts.js
var theme = {
Layout,
enhanceApp: ({ app }) => {

File diff suppressed because one or more lines are too long

View File

@@ -1,31 +1,31 @@
{
"hash": "6976e0a7",
"configHash": "16b5e256",
"lockfileHash": "b21b0169",
"browserHash": "1a32ef31",
"hash": "c346a9bf",
"configHash": "efc30d79",
"lockfileHash": "1f28932e",
"browserHash": "a0a1bed8",
"optimized": {
"vue": {
"src": "../../../../node_modules/.pnpm/vue@3.5.29_typescript@5.9.3/node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "7e923f01",
"fileHash": "f9cb5b91",
"needsInterop": false
},
"vitepress > @vue/devtools-api": {
"src": "../../../../node_modules/.pnpm/@vue+devtools-api@7.7.9/node_modules/@vue/devtools-api/dist/index.js",
"file": "vitepress___@vue_devtools-api.js",
"fileHash": "0373f16c",
"fileHash": "6601cb18",
"needsInterop": false
},
"vitepress > @vueuse/core": {
"src": "../../../../node_modules/.pnpm/@vueuse+core@12.8.2_typescript@5.9.3/node_modules/@vueuse/core/index.mjs",
"file": "vitepress___@vueuse_core.js",
"fileHash": "67853364",
"fileHash": "37e71cfa",
"needsInterop": false
},
"@theme/index": {
"src": "../../../../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_b21953e64bdc687d6358312771661039/node_modules/vitepress/dist/client/theme-default/index.js",
"src": "../../../../node_modules/.pnpm/vitepress@1.6.4_@algolia+cl_24d2dfd0c17bd24a27a1736f87e83da8/node_modules/vitepress/dist/client/theme-default/index.js",
"file": "@theme_index.js",
"fileHash": "58797fc7",
"fileHash": "8723d3d2",
"needsInterop": false
}
},

View File

@@ -33,7 +33,8 @@ export default defineConfig({
items: [
{ text: '核心模块', link: '/api/core' },
{ text: '后端 API', link: '/api/backend' },
{ text: '前端 API', link: '/api/frontend' }
{ text: '前端 API', link: '/api/frontend' },
{ text: '错误码说明', link: '/api/error-codes' }
]
}
]

256
word/api/error-codes.md Normal file
View File

@@ -0,0 +1,256 @@
# 错误码说明
本文档详细说明了 DeEarthX 应用中使用的错误码系统,帮助用户和开发者理解和排查错误。
## 错误码格式
错误码采用四位数字格式,第一位数字表示错误类别,后三位数字表示具体错误:
- `1xxx`: 后端启动相关错误
- `2xxx`: 网络相关错误
- `3xxx`: 文件相关错误
- `4xxx`: 系统相关错误
- `9999`: 未知错误
## 错误码详情
### 1. 后端启动相关错误
#### 1001
**错误信息**: 后端服务启动失败
**可能原因**:
- 后端服务无法启动
- 可能是权限问题
- 可能是文件损坏
- 可能是端口被占用
**解决方案**:
1. 检查 37019 端口是否被占用
2. 检查后端服务是否正常
3. 重启应用程序
#### 1002
**错误信息**: 后端服务端口被占用
**可能原因**:
- 37019 端口已被其他应用占用
- 可能有其他 DeEarthX 实例在运行
**解决方案**:
1. 关闭占用 37019 端口的其他应用
2. 检查是否有其他 DeEarthX 实例在运行
3. 重启计算机后再试
#### 1003
**错误信息**: 后端服务连接失败
**可能原因**:
- 无法连接到后端服务
- 后端服务可能未启动
- 网络连接可能存在问题
**解决方案**:
1. 检查后端服务是否正在运行
2. 检查网络连接是否正常
3. 重启应用程序
#### 1004
**错误信息**: 后端服务响应错误
**可能原因**:
- 后端服务返回错误响应
- 后端服务可能出现内部错误
**解决方案**:
1. 检查后端服务是否正常
2. 重启后端服务
3. 联系技术支持
### 2. 网络相关错误
#### 2001
**错误信息**: 网络连接错误
**可能原因**:
- 网络连接出现问题
- 网络不稳定
- 网络中断
**解决方案**:
1. 检查网络连接是否正常
2. 检查防火墙设置
3. 稍后重试
#### 2002
**错误信息**: 网络连接超时
**可能原因**:
- 网络连接超时
- 网络速度过慢
- 目标服务器响应缓慢
**解决方案**:
1. 检查网络连接速度
2. 稍后重试
3. 检查目标服务器是否可访问
#### 2003
**错误信息**: 网络连接被拒绝
**可能原因**:
- 网络连接被拒绝
- 目标服务器可能未运行
- 防火墙可能阻止连接
**解决方案**:
1. 检查目标服务器是否正在运行
2. 检查网络连接是否正常
3. 检查防火墙设置
### 3. 文件相关错误
#### 3001
**错误信息**: 文件未找到
**可能原因**:
- 文件不存在
- 文件路径不正确
- 文件可能被删除或移动
**解决方案**:
1. 确认文件路径是否正确
2. 检查文件是否存在
3. 重新上传文件
#### 3002
**错误信息**: 文件权限错误
**可能原因**:
- 没有文件操作权限
- 文件可能被其他程序占用
- 应用程序可能没有足够的权限
**解决方案**:
1. 检查文件权限设置
2. 以管理员身份运行应用程序
3. 检查文件是否被其他程序占用
#### 3003
**错误信息**: 文件格式错误
**可能原因**:
- 文件格式不正确
- 文件可能损坏
- 文件类型不符合要求
**解决方案**:
1. 确认文件格式是否正确
2. 重新上传正确格式的文件
3. 检查文件是否损坏
#### 3004
**错误信息**: 文件大小错误
**可能原因**:
- 文件大小不符合要求
- 磁盘空间可能不足
- 文件可能过大
**解决方案**:
1. 检查文件大小是否符合要求
2. 压缩文件后再上传
3. 检查磁盘空间是否充足
### 4. 系统相关错误
#### 4001
**错误信息**: Java 未找到
**可能原因**:
- 系统中未安装 Java
- Java 环境变量未配置
- Java 版本可能不兼容
**解决方案**:
1. 安装 Java 17 或更高版本
2. 配置 Java 环境变量
3. 重启应用程序
#### 4002
**错误信息**: 磁盘空间不足
**可能原因**:
- 磁盘空间不足
- 目标存储位置空间已满
**解决方案**:
1. 清理磁盘空间
2. 选择其他存储位置
3. 删除不必要的文件
#### 4003
**错误信息**: 内存不足
**可能原因**:
- 系统内存不足
- 应用程序占用内存过多
- 其他应用程序占用大量内存
**解决方案**:
1. 增加系统内存
2. 关闭其他占用内存的应用程序
3. 减少同时处理的任务数量
### 5. 未知错误
#### 9999
**错误信息**: 未知错误
**可能原因**:
- 发生未知错误
- 可能是应用程序内部错误
- 可能是系统环境问题
**解决方案**:
1. 重启应用程序
2. 检查系统日志
3. 联系技术支持
## 错误处理流程
当应用遇到错误时,会:
1. 生成相应的错误码和错误信息
2. 在界面上显示错误信息和错误码
3. 提供可能的解决方案
4. 记录错误日志以便排查
## 如何使用错误码
当您遇到错误时:
1. 查看错误信息和错误码
2. 参考本文档中的解决方案尝试解决
3. 如果问题仍然存在,请联系技术支持并提供错误码和详细的错误信息
## 注意事项
- 错误码仅用于参考,具体错误原因可能因环境不同而有所差异
- 如遇到持续的错误,请检查系统环境和网络连接
- 定期更新应用程序以获取最新的错误处理机制

View File

@@ -4,13 +4,15 @@
感谢您对 DeEarthX-CE 项目的关注和支持!我们欢迎来自社区的贡献,包括代码提交、问题报告、功能建议等。本指南将帮助您了解如何参与项目开发。
[XCCGit仓库](https://git.xcclyc.cn/xcclyc/DeEarthX-CE)
## 开发环境设置
### 前提条件
在开始贡献之前,请确保您的系统满足以下要求:
- **Node.js**v16.0+(推荐使用最新稳定版)
- **Node.js**v22.0+(推荐使用最新稳定版)
- **pnpm**v8.0+(包管理器)
- **Rust**:最新稳定版(用于 Tauri 构建)
- **Git**:用于版本控制
@@ -18,7 +20,7 @@
### 克隆仓库
```bash
git clone https://github.com/yourusername/DeEarthX-CE.git
git clone https://git.xcclyc.cn/xcclyc/DeEarthX-CE.git
cd DeEarthX-CE
```
@@ -35,7 +37,7 @@ pnpm install
pnpm run dev
# 启动后端开发服务器(如果需要)
pnpm run backend:dev
pnpm run test
```
## 代码规范
@@ -123,7 +125,7 @@ pnpm run test
## 问题报告
如果您发现了 bug 或有功能建议,请在 GitHub Issues 页面提交:
如果您发现了 bug 或有功能建议,请在 XCCGit Issues 页面提交:
1. **搜索现有问题**:确保问题尚未被报告
2. **创建新问题**:提供详细的问题描述
@@ -133,7 +135,9 @@ pnpm run test
## 功能请求
如果您有新功能的想法,请在 GitHub Issues 页面提交功能请求:
如果您有新功能的想法,请在 XCCGit Issues 页面提交功能请求:
[XCCGit](https://git.xcclyc.cn/xcclyc/DeEarthX-CE/issues)
1. **搜索现有请求**:确保功能尚未被请求
2. **创建新请求**:提供详细的功能描述
@@ -179,7 +183,7 @@ MAJOR.MINOR.PATCH
2. **更新 CHANGELOG**:记录版本变更内容
3. **构建项目**:确保项目能够正常构建
4. **运行测试**:确保所有测试通过
5. **创建发布**:在 GitHub 上创建新的发布
5. **创建发布**:在 XCCGit 上创建新的发布
6. **部署**:部署到相关平台
## 行为准则
@@ -196,8 +200,8 @@ MAJOR.MINOR.PATCH
如果您有任何问题或需要帮助,可以通过以下方式联系我们:
- **GitHub Issues**:用于问题报告和功能请求
- **Discord**:用于实时讨论和社区交流
- **XCCGit Issues**:用于问题报告和功能请求
- **QQ**:简单直接
- **Email**:用于重要事项的沟通
## 致谢