先提交上去
@@ -0,0 +1,6 @@
|
|||||||
|
[target.x86_64-pc-windows-msvc]
|
||||||
|
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
|
||||||
|
|
||||||
|
[alias]
|
||||||
|
dev = "tauri dev"
|
||||||
|
build = "tauri build"
|
||||||
@@ -7,10 +7,10 @@ on:
|
|||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: '版本号(例如 1.2.3 或 v1.2.3)'
|
description: '版本号(例如 1.2.3 或 v1.2.3)'
|
||||||
required: false
|
required: true
|
||||||
build:
|
build:
|
||||||
description: '构建命令标记(build:win|build:mac|build:linux|build:unpack|build:all)'
|
description: '构建命令标记(build:win|build:mac|build:linux|build:all)'
|
||||||
required: false
|
required: true
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -25,7 +25,6 @@ jobs:
|
|||||||
run_win: ${{ steps.parse.outputs.run_win }}
|
run_win: ${{ steps.parse.outputs.run_win }}
|
||||||
run_mac: ${{ steps.parse.outputs.run_mac }}
|
run_mac: ${{ steps.parse.outputs.run_mac }}
|
||||||
run_linux: ${{ steps.parse.outputs.run_linux }}
|
run_linux: ${{ steps.parse.outputs.run_linux }}
|
||||||
run_unpack: ${{ steps.parse.outputs.run_unpack }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
@@ -74,6 +73,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: 10
|
version: 10
|
||||||
|
|
||||||
|
- name: 安装 Rust
|
||||||
|
uses: dtolnay/rust-action@stable
|
||||||
|
|
||||||
- name: 应用版本号
|
- name: 应用版本号
|
||||||
run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }}
|
run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }}
|
||||||
|
|
||||||
@@ -81,21 +83,12 @@ jobs:
|
|||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: 构建(Windows)
|
- name: 构建(Windows)
|
||||||
run: pnpm build:win
|
run: pnpm tauri build --target x86_64-pc-windows-msvc
|
||||||
|
|
||||||
- name: 清理 unpacked 目录
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
if (Test-Path dist) {
|
|
||||||
Get-ChildItem -Path dist -Directory -ErrorAction SilentlyContinue |
|
|
||||||
Where-Object { $_.Name -like '*unpacked*' } |
|
|
||||||
ForEach-Object { Remove-Item -Recurse -Force $_.FullName }
|
|
||||||
}
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dist-win
|
name: dist-win
|
||||||
path: dist/**
|
path: src-tauri/target/release/bundle/**
|
||||||
|
|
||||||
build_mac:
|
build_mac:
|
||||||
needs: parse
|
needs: parse
|
||||||
@@ -112,6 +105,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: 10
|
version: 10
|
||||||
|
|
||||||
|
- name: 安装 Rust
|
||||||
|
uses: dtolnay/rust-action@stable
|
||||||
|
|
||||||
- name: 应用版本号
|
- name: 应用版本号
|
||||||
run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }}
|
run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }}
|
||||||
|
|
||||||
@@ -119,15 +115,12 @@ jobs:
|
|||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: 构建(macOS)
|
- name: 构建(macOS)
|
||||||
run: pnpm -s build:mac
|
run: pnpm tauri build --target x86_64-apple-darwin
|
||||||
|
|
||||||
- name: 清理 unpacked 目录
|
|
||||||
run: rm -rf dist/*unpacked*
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dist-mac
|
name: dist-mac
|
||||||
path: dist/**
|
path: src-tauri/target/release/bundle/**
|
||||||
|
|
||||||
build_linux:
|
build_linux:
|
||||||
needs: parse
|
needs: parse
|
||||||
@@ -144,6 +137,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: 10
|
version: 10
|
||||||
|
|
||||||
|
- name: 安装 Rust
|
||||||
|
uses: dtolnay/rust-action@stable
|
||||||
|
|
||||||
|
- name: 安装系统依赖
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
|
||||||
|
|
||||||
- name: 应用版本号
|
- name: 应用版本号
|
||||||
run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }}
|
run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }}
|
||||||
|
|
||||||
@@ -151,61 +152,15 @@ jobs:
|
|||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
- name: 构建(Linux)
|
- name: 构建(Linux)
|
||||||
run: pnpm -s build:linux
|
run: pnpm tauri build --target x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
- name: 清理 unpacked 目录
|
|
||||||
run: rm -rf dist/*unpacked*
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dist-linux
|
name: dist-linux
|
||||||
path: dist/**
|
path: src-tauri/target/release/bundle/**
|
||||||
|
|
||||||
build_unpack:
|
|
||||||
needs: parse
|
|
||||||
if: ${{ needs.parse.outputs.run_unpack == 'true' }}
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: 22
|
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
version: 10
|
|
||||||
|
|
||||||
- name: 应用版本号
|
|
||||||
run: node scripts/ci/apply-version.mjs ${{ needs.parse.outputs.version }}
|
|
||||||
|
|
||||||
- name: 安装依赖
|
|
||||||
run: pnpm install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: 构建(dir)
|
|
||||||
run: pnpm -s build:unpack
|
|
||||||
|
|
||||||
- name: 打包并移除 unpacked 目录
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
if (Test-Path dist) {
|
|
||||||
$dirs = Get-ChildItem -Path dist -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -like '*unpacked*' }
|
|
||||||
foreach ($d in $dirs) {
|
|
||||||
$zipBase = ($d.Name -replace 'unpacked', 'dir')
|
|
||||||
$zipPath = Join-Path dist "$zipBase.zip"
|
|
||||||
if (Test-Path $zipPath) { Remove-Item -Force $zipPath }
|
|
||||||
Compress-Archive -Path (Join-Path $d.FullName '*') -DestinationPath $zipPath -Force
|
|
||||||
Remove-Item -Recurse -Force $d.FullName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: dist-unpack
|
|
||||||
path: dist/**
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
needs: [parse, build_win, build_mac, build_linux, build_unpack]
|
needs: [parse, build_win, build_mac, build_linux]
|
||||||
if: ${{ always() && needs.parse.outputs.tag != '' }}
|
if: ${{ always() && needs.parse.outputs.tag != '' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -213,12 +168,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- name: 清理 unpacked 目录
|
|
||||||
run: |
|
|
||||||
if [ -d artifacts ]; then
|
|
||||||
find artifacts -type d -name '*unpacked*' -prune -exec rm -rf {} +
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: 发布 Release
|
- name: 发布 Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
@@ -227,7 +176,10 @@ jobs:
|
|||||||
draft: True
|
draft: True
|
||||||
prerelease: ${{ contains(needs.parse.outputs.version, '-') }}
|
prerelease: ${{ contains(needs.parse.outputs.version, '-') }}
|
||||||
files: |
|
files: |
|
||||||
artifacts/**/*.zip
|
artifacts/**/*.msi
|
||||||
|
artifacts/**/*.exe
|
||||||
artifacts/**/*.dmg
|
artifacts/**/*.dmg
|
||||||
artifacts/**/*.AppImage
|
artifacts/**/*.app.tar.gz
|
||||||
artifacts/**/*.deb
|
artifacts/**/*.deb
|
||||||
|
artifacts/**/*.rpm
|
||||||
|
artifacts/**/*.AppImage
|
||||||
|
|||||||
@@ -1,20 +1,52 @@
|
|||||||
|
# Dependencies
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
.pnp
|
||||||
out
|
.pnp.js
|
||||||
.DS_Store
|
|
||||||
.eslintcache
|
|
||||||
*.log*
|
|
||||||
logs
|
|
||||||
docs
|
|
||||||
configs
|
|
||||||
|
|
||||||
build/*
|
# Build outputs
|
||||||
!build/entitlements.mac.plist
|
dist
|
||||||
db.sqlite
|
dist-ssr
|
||||||
*.local
|
*.local
|
||||||
|
|
||||||
|
# Tauri
|
||||||
|
src-tauri/target
|
||||||
|
src-tauri/Cargo.lock
|
||||||
|
src-tauri/gen
|
||||||
|
|
||||||
|
# Database
|
||||||
|
data.sql
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.DS_Store
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
.vscode
|
|
||||||
!.vscode/extensions.json
|
# Testing
|
||||||
!.vscode/launch.json
|
coverage
|
||||||
!.vscode/settings.json
|
|
||||||
|
# Cache
|
||||||
|
.cache
|
||||||
|
.temp
|
||||||
|
.tmp
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
Thumbs.db
|
||||||
|
|||||||
@@ -1,6 +1,26 @@
|
|||||||
out
|
# Build outputs
|
||||||
dist
|
dist
|
||||||
|
dist-ssr
|
||||||
|
out
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# Lock files
|
||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
src-tauri/target
|
||||||
|
src-tauri/gen
|
||||||
|
src-tauri/Cargo.lock
|
||||||
|
|
||||||
|
# Config files
|
||||||
LICENSE.md
|
LICENSE.md
|
||||||
|
*.config.js
|
||||||
|
*.config.ts
|
||||||
|
|
||||||
|
# TypeScript configs
|
||||||
tsconfig.json
|
tsconfig.json
|
||||||
tsconfig.*.json
|
tsconfig.*.json
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": false,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"printWidth": 100
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
# Checklist
|
||||||
|
|
||||||
|
## Phase 1: 项目初始化
|
||||||
|
- [x] Tauri 项目在 SecScore-Rust 目录下正确创建
|
||||||
|
- [x] Cargo.toml 包含所有必要依赖
|
||||||
|
- [x] tauri.conf.json 配置正确
|
||||||
|
- [x] 前端代码成功复制并配置
|
||||||
|
- [x] 开发服务器可以正常启动
|
||||||
|
|
||||||
|
## Phase 2: 数据库层
|
||||||
|
- [x] SQLite 数据库可以正常创建和连接
|
||||||
|
- [x] PostgreSQL 数据库可以正常连接
|
||||||
|
- [x] 数据库迁移可以正常执行
|
||||||
|
- [x] 所有数据库表结构与原项目一致
|
||||||
|
- [x] 数据库连接切换功能正常
|
||||||
|
|
||||||
|
## Phase 3: 核心服务
|
||||||
|
- [x] 设置服务:所有设置项可以正常读写
|
||||||
|
- [x] 设置服务:设置变更可以正确通知前端
|
||||||
|
- [x] 安全服务:密码加密解密正确
|
||||||
|
- [x] 权限服务:权限检查逻辑正确
|
||||||
|
- [x] 认证服务:登录登出功能正常
|
||||||
|
- [x] 认证服务:密码设置和恢复功能正常
|
||||||
|
- [x] 主题服务:内置主题正确加载
|
||||||
|
- [x] 主题服务:自定义主题可以保存和删除
|
||||||
|
- [x] 主题服务:主题切换可以正确通知前端
|
||||||
|
- [x] 自动评分服务:规则可以正确添加和执行
|
||||||
|
- [x] 日志服务:日志可以正确写入和查询
|
||||||
|
- [x] 数据服务:数据导入导出功能正常
|
||||||
|
|
||||||
|
## Phase 4: Tauri Commands
|
||||||
|
- [x] 学生相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 标签相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 原因相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 事件相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 结算相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 设置相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 认证相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 主题相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 自动评分相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 日志相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 数据导入导出 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 窗口相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 数据库连接相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 文件系统相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] HTTP 服务器相关 Commands 返回数据格式与原项目一致
|
||||||
|
- [x] 应用相关 Commands 返回数据格式与原项目一致
|
||||||
|
|
||||||
|
## Phase 5: 系统功能
|
||||||
|
- [x] 系统托盘图标正确显示
|
||||||
|
- [x] 托盘菜单功能正常
|
||||||
|
- [x] 双击托盘可以显示主窗口
|
||||||
|
- [x] URL 协议可以正确注册和处理
|
||||||
|
- [x] 单实例运行检测正常
|
||||||
|
|
||||||
|
## Phase 6: 前端适配
|
||||||
|
- [x] 所有 window.api 调用已替换为 Tauri invoke
|
||||||
|
- [x] 事件监听(theme_updated, settings_changed 等)正常工作
|
||||||
|
- [x] 窗口控制按钮功能正常
|
||||||
|
- [x] 窗口拖拽区域正常工作
|
||||||
|
- [x] Electron 特定代码已移除
|
||||||
|
|
||||||
|
## Phase 7: 构建与测试
|
||||||
|
- [ ] 开发环境可以正常运行
|
||||||
|
- [ ] 生产构建成功
|
||||||
|
- [ ] Windows 安装包可以正常安装和运行
|
||||||
|
- [ ] 所有 UI 功能与原项目完全一致
|
||||||
|
- [ ] 学生管理功能正常
|
||||||
|
- [ ] 积分操作功能正常
|
||||||
|
- [ ] 排行榜功能正常
|
||||||
|
- [ ] 结算功能正常
|
||||||
|
- [ ] 原因管理功能正常
|
||||||
|
- [ ] 标签管理功能正常
|
||||||
|
- [ ] 设置功能正常
|
||||||
|
- [ ] 认证功能正常
|
||||||
|
- [ ] 主题切换功能正常
|
||||||
|
- [ ] 自动评分功能正常
|
||||||
|
- [ ] 数据导入导出功能正常
|
||||||
|
- [ ] 日志查看功能正常
|
||||||
|
- [ ] 窗口控制功能正常
|
||||||
|
- [ ] 系统托盘功能正常
|
||||||
|
- [ ] URL 协议功能正常
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
# SecScore Electron 到 Tauri 迁移规格
|
||||||
|
|
||||||
|
## Why
|
||||||
|
将现有的 Electron 项目迁移到 Rust + Tauri 框架,以获得更小的打包体积、更好的性能和更低的资源消耗,同时保持所有现有功能和 UI 逻辑完全一致。
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
- **BREAKING**: 后端从 Node.js/TypeScript 迁移到 Rust
|
||||||
|
- **BREAKING**: 框架从 Electron 迁移到 Tauri 2.x
|
||||||
|
- 前端 React 代码保持不变,仅修改 IPC 通信层
|
||||||
|
- 数据库层从 TypeORM + better-sqlite3 迁移到 Rust 的 SeaORM + Rusqlite
|
||||||
|
- 所有后端服务用 Rust 重写,功能实现保持一致
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
- Affected specs: 整个后端架构
|
||||||
|
- Affected code:
|
||||||
|
- `src/main/` - 全部重写为 Rust
|
||||||
|
- `src/preload/` - 替换为 Tauri commands
|
||||||
|
- `src/renderer/` - 仅修改 API 调用层
|
||||||
|
- `src/shared/` - 部分逻辑迁移到 Rust
|
||||||
|
|
||||||
|
## ADDED Requirements
|
||||||
|
|
||||||
|
### Requirement: Tauri 项目初始化
|
||||||
|
系统 SHALL 在 `SecScore-Rust` 目录下创建 Tauri 2.x 项目结构,包含:
|
||||||
|
- Rust 后端 (src-tauri/)
|
||||||
|
- React 前端 (复用现有前端代码)
|
||||||
|
- Tauri 配置文件
|
||||||
|
|
||||||
|
#### Scenario: 项目结构创建
|
||||||
|
- **WHEN** 初始化 Tauri 项目
|
||||||
|
- **THEN** 应创建标准 Tauri 2.x 项目结构
|
||||||
|
- **AND** 前端使用现有的 React + Ant Design 技术栈
|
||||||
|
|
||||||
|
### Requirement: 数据库层迁移
|
||||||
|
系统 SHALL 使用 Rust 实现数据库功能,支持 SQLite 和 PostgreSQL:
|
||||||
|
|
||||||
|
#### Scenario: SQLite 支持
|
||||||
|
- **WHEN** 未配置 PostgreSQL 连接字符串
|
||||||
|
- **THEN** 使用 SQLite 作为默认数据库
|
||||||
|
- **AND** 数据库文件路径与原项目一致
|
||||||
|
|
||||||
|
#### Scenario: PostgreSQL 支持
|
||||||
|
- **WHEN** 配置了有效的 PostgreSQL 连接字符串
|
||||||
|
- **THEN** 系统应能连接到 PostgreSQL 数据库
|
||||||
|
- **AND** 支持连接测试和切换
|
||||||
|
|
||||||
|
#### Scenario: 数据库迁移
|
||||||
|
- **WHEN** 系统启动
|
||||||
|
- **THEN** 自动运行数据库迁移
|
||||||
|
- **AND** 表结构与原项目完全一致
|
||||||
|
|
||||||
|
### Requirement: 学生管理功能
|
||||||
|
系统 SHALL 提供完整的学生管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 查询学生列表
|
||||||
|
- **WHEN** 调用查询学生接口
|
||||||
|
- **THEN** 返回所有学生信息,包含 id、name、score、tags
|
||||||
|
- **AND** 按 score DESC, name ASC 排序
|
||||||
|
|
||||||
|
#### Scenario: 创建学生
|
||||||
|
- **WHEN** 调用创建学生接口
|
||||||
|
- **THEN** 创建新学生记录,初始分数为 0
|
||||||
|
- **AND** 返回新创建的学生 ID
|
||||||
|
|
||||||
|
#### Scenario: 更新学生
|
||||||
|
- **WHEN** 调用更新学生接口
|
||||||
|
- **THEN** 更新指定学生的信息
|
||||||
|
- **AND** 自动更新 updated_at 时间戳
|
||||||
|
|
||||||
|
#### Scenario: 删除学生
|
||||||
|
- **WHEN** 调用删除学生接口
|
||||||
|
- **THEN** 删除学生及其关联的积分记录
|
||||||
|
- **AND** 使用事务确保数据一致性
|
||||||
|
|
||||||
|
#### Scenario: 导入学生名单
|
||||||
|
- **WHEN** 调用导入学生接口
|
||||||
|
- **THEN** 批量创建学生记录
|
||||||
|
- **AND** 跳过已存在的学生
|
||||||
|
|
||||||
|
### Requirement: 积分事件管理
|
||||||
|
系统 SHALL 提供完整的积分事件管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 创建积分事件
|
||||||
|
- **WHEN** 调用创建积分事件接口
|
||||||
|
- **THEN** 创建积分记录并更新学生分数
|
||||||
|
- **AND** 使用事务确保数据一致性
|
||||||
|
- **AND** 自动生成 UUID
|
||||||
|
|
||||||
|
#### Scenario: 撤销积分事件
|
||||||
|
- **WHEN** 调用撤销积分事件接口
|
||||||
|
- **THEN** 撤销积分记录并回退学生分数
|
||||||
|
- **AND** 已结算的记录不可撤销
|
||||||
|
|
||||||
|
#### Scenario: 查询积分事件
|
||||||
|
- **WHEN** 调用查询积分事件接口
|
||||||
|
- **THEN** 返回指定条件的积分记录
|
||||||
|
- **AND** 支持按学生、时间范围筛选
|
||||||
|
|
||||||
|
#### Scenario: 查询排行榜
|
||||||
|
- **WHEN** 调用查询排行榜接口
|
||||||
|
- **THEN** 返回指定时间范围的排行榜数据
|
||||||
|
- **AND** 支持 today、week、month 三种范围
|
||||||
|
|
||||||
|
### Requirement: 原因管理功能
|
||||||
|
系统 SHALL 提供完整的积分原因管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 查询原因列表
|
||||||
|
- **WHEN** 调用查询原因接口
|
||||||
|
- **THEN** 返回所有积分原因
|
||||||
|
- **AND** 按 category ASC, content ASC 排序
|
||||||
|
|
||||||
|
#### Scenario: 创建原因
|
||||||
|
- **WHEN** 调用创建原因接口
|
||||||
|
- **THEN** 创建新的积分原因
|
||||||
|
- **AND** 默认 is_system 为 0
|
||||||
|
|
||||||
|
#### Scenario: 更新原因
|
||||||
|
- **WHEN** 调用更新原因接口
|
||||||
|
- **THEN** 更新指定原因的信息
|
||||||
|
|
||||||
|
#### Scenario: 删除原因
|
||||||
|
- **WHEN** 调用删除原因接口
|
||||||
|
- **THEN** 删除指定原因
|
||||||
|
|
||||||
|
### Requirement: 结算功能
|
||||||
|
系统 SHALL 提供完整的结算功能:
|
||||||
|
|
||||||
|
#### Scenario: 查询结算列表
|
||||||
|
- **WHEN** 调用查询结算接口
|
||||||
|
- **THEN** 返回所有结算记录
|
||||||
|
- **AND** 包含每个结算的事件数量
|
||||||
|
|
||||||
|
#### Scenario: 创建结算
|
||||||
|
- **WHEN** 调用创建结算接口
|
||||||
|
- **THEN** 将所有未结算事件标记为已结算
|
||||||
|
- **AND** 重置所有学生分数为 0
|
||||||
|
- **AND** 使用事务确保数据一致性
|
||||||
|
|
||||||
|
#### Scenario: 查询结算排行榜
|
||||||
|
- **WHEN** 调用查询结算排行榜接口
|
||||||
|
- **THEN** 返回指定结算的排行榜数据
|
||||||
|
|
||||||
|
### Requirement: 标签管理功能
|
||||||
|
系统 SHALL 提供完整的学生标签管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 查询所有标签
|
||||||
|
- **WHEN** 调用查询标签接口
|
||||||
|
- **THEN** 返回所有标签列表
|
||||||
|
|
||||||
|
#### Scenario: 创建标签
|
||||||
|
- **WHEN** 调用创建标签接口
|
||||||
|
- **THEN** 创建新标签或返回已存在的标签
|
||||||
|
|
||||||
|
#### Scenario: 删除标签
|
||||||
|
- **WHEN** 调用删除标签接口
|
||||||
|
- **THEN** 删除指定标签及其关联
|
||||||
|
|
||||||
|
#### Scenario: 更新学生标签
|
||||||
|
- **WHEN** 调用更新学生标签接口
|
||||||
|
- **THEN** 更新指定学生的标签关联
|
||||||
|
|
||||||
|
### Requirement: 设置管理功能
|
||||||
|
系统 SHALL 提供完整的设置管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 获取所有设置
|
||||||
|
- **WHEN** 调用获取所有设置接口
|
||||||
|
- **THEN** 返回所有设置项
|
||||||
|
|
||||||
|
#### Scenario: 获取单个设置
|
||||||
|
- **WHEN** 调用获取设置接口
|
||||||
|
- **THEN** 返回指定设置项的值
|
||||||
|
|
||||||
|
#### Scenario: 设置值
|
||||||
|
- **WHEN** 调用设置值接口
|
||||||
|
- **THEN** 更新指定设置项
|
||||||
|
- **AND** 通知所有窗口设置变更
|
||||||
|
|
||||||
|
#### Scenario: 设置项定义
|
||||||
|
- **AND** 支持以下设置项:
|
||||||
|
- is_wizard_completed: boolean
|
||||||
|
- log_level: string (debug/info/warn/error)
|
||||||
|
- window_zoom: number
|
||||||
|
- themes_custom: json array
|
||||||
|
- auto_score_enabled: boolean
|
||||||
|
- auto_score_rules: json array
|
||||||
|
- current_theme_id: string
|
||||||
|
- pg_connection_string: string
|
||||||
|
- pg_connection_status: json object
|
||||||
|
|
||||||
|
### Requirement: 认证与安全功能
|
||||||
|
系统 SHALL 提供完整的认证与安全功能:
|
||||||
|
|
||||||
|
#### Scenario: 获取认证状态
|
||||||
|
- **WHEN** 调用获取认证状态接口
|
||||||
|
- **THEN** 返回当前权限级别和密码设置状态
|
||||||
|
|
||||||
|
#### Scenario: 登录
|
||||||
|
- **WHEN** 调用登录接口
|
||||||
|
- **THEN** 验证密码并设置权限级别
|
||||||
|
- **AND** 支持 admin 和 points 两种密码
|
||||||
|
|
||||||
|
#### Scenario: 登出
|
||||||
|
- **WHEN** 调用登出接口
|
||||||
|
- **THEN** 重置权限级别为默认值
|
||||||
|
|
||||||
|
#### Scenario: 设置密码
|
||||||
|
- **WHEN** 调用设置密码接口
|
||||||
|
- **THEN** 加密存储密码
|
||||||
|
- **AND** 自动生成恢复字符串
|
||||||
|
|
||||||
|
#### Scenario: 恢复密码
|
||||||
|
- **WHEN** 调用恢复密码接口
|
||||||
|
- **THEN** 使用恢复字符串重置所有密码
|
||||||
|
|
||||||
|
#### Scenario: 加密实现
|
||||||
|
- **WHEN** 存储敏感数据
|
||||||
|
- **THEN** 使用 AES-256-CBC 加密
|
||||||
|
- **AND** 使用应用数据目录派生的密钥
|
||||||
|
|
||||||
|
### Requirement: 主题管理功能
|
||||||
|
系统 SHALL 提供完整的主题管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 获取主题列表
|
||||||
|
- **WHEN** 调用获取主题列表接口
|
||||||
|
- **THEN** 返回内置主题和自定义主题
|
||||||
|
|
||||||
|
#### Scenario: 获取当前主题
|
||||||
|
- **WHEN** 调用获取当前主题接口
|
||||||
|
- **THEN** 返回当前激活的主题配置
|
||||||
|
|
||||||
|
#### Scenario: 设置主题
|
||||||
|
- **WHEN** 调用设置主题接口
|
||||||
|
- **THEN** 切换到指定主题
|
||||||
|
- **AND** 通知所有窗口主题变更
|
||||||
|
|
||||||
|
#### Scenario: 保存自定义主题
|
||||||
|
- **WHEN** 调用保存主题接口
|
||||||
|
- **THEN** 保存自定义主题配置
|
||||||
|
- **AND** 不允许覆盖内置主题
|
||||||
|
|
||||||
|
#### Scenario: 删除自定义主题
|
||||||
|
- **WHEN** 调用删除主题接口
|
||||||
|
- **THEN** 删除指定的自定义主题
|
||||||
|
- **AND** 不允许删除内置主题
|
||||||
|
|
||||||
|
### Requirement: 自动评分功能
|
||||||
|
系统 SHALL 提供完整的自动评分功能:
|
||||||
|
|
||||||
|
#### Scenario: 规则管理
|
||||||
|
- **WHEN** 管理自动评分规则
|
||||||
|
- **THEN** 支持添加、更新、删除、排序规则
|
||||||
|
|
||||||
|
#### Scenario: 规则执行
|
||||||
|
- **WHEN** 规则触发条件满足
|
||||||
|
- **THEN** 自动执行规则动作
|
||||||
|
- **AND** 记录执行时间
|
||||||
|
|
||||||
|
#### Scenario: 触发器类型
|
||||||
|
- **AND** 支持以下触发器:
|
||||||
|
- interval_time_passed: 定时触发
|
||||||
|
- student_has_tag: 学生标签触发
|
||||||
|
|
||||||
|
#### Scenario: 动作类型
|
||||||
|
- **AND** 支持以下动作:
|
||||||
|
- add_score: 添加积分
|
||||||
|
- add_tag: 添加标签
|
||||||
|
|
||||||
|
### Requirement: 数据导入导出功能
|
||||||
|
系统 SHALL 提供完整的数据导入导出功能:
|
||||||
|
|
||||||
|
#### Scenario: 导出数据
|
||||||
|
- **WHEN** 调用导出数据接口
|
||||||
|
- **THEN** 导出所有数据为 JSON 格式
|
||||||
|
|
||||||
|
#### Scenario: 导入数据
|
||||||
|
- **WHEN** 调用导入数据接口
|
||||||
|
- **THEN** 从 JSON 导入数据
|
||||||
|
- **AND** 重新加载设置
|
||||||
|
|
||||||
|
### Requirement: 日志管理功能
|
||||||
|
系统 SHALL 提供完整的日志管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 查询日志
|
||||||
|
- **WHEN** 调用查询日志接口
|
||||||
|
- **THEN** 返回最近的日志记录
|
||||||
|
|
||||||
|
#### Scenario: 清除日志
|
||||||
|
- **WHEN** 调用清除日志接口
|
||||||
|
- **THEN** 删除所有日志文件
|
||||||
|
|
||||||
|
#### Scenario: 设置日志级别
|
||||||
|
- **WHEN** 调用设置日志级别接口
|
||||||
|
- **THEN** 更新日志级别
|
||||||
|
|
||||||
|
#### Scenario: 日志文件
|
||||||
|
- **AND** 日志文件按日期滚动
|
||||||
|
- **AND** 保留最近 30 天的日志
|
||||||
|
|
||||||
|
### Requirement: 窗口管理功能
|
||||||
|
系统 SHALL 提供完整的窗口管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 窗口控制
|
||||||
|
- **WHEN** 调用窗口控制接口
|
||||||
|
- **THEN** 支持最小化、最大化、关闭操作
|
||||||
|
|
||||||
|
#### Scenario: 窗口状态
|
||||||
|
- **WHEN** 查询窗口状态
|
||||||
|
- **THEN** 返回窗口最大化状态
|
||||||
|
|
||||||
|
#### Scenario: 窗口缩放
|
||||||
|
- **WHEN** 设置窗口缩放
|
||||||
|
- **THEN** 应用缩放比例到所有窗口
|
||||||
|
|
||||||
|
#### Scenario: 窗口导航
|
||||||
|
- **WHEN** 调用导航接口
|
||||||
|
- **THEN** 在窗口中导航到指定路由
|
||||||
|
|
||||||
|
### Requirement: 系统托盘功能
|
||||||
|
系统 SHALL 提供系统托盘功能:
|
||||||
|
|
||||||
|
#### Scenario: 托盘初始化
|
||||||
|
- **WHEN** 应用启动
|
||||||
|
- **THEN** 创建系统托盘图标
|
||||||
|
|
||||||
|
#### Scenario: 托盘菜单
|
||||||
|
- **WHEN** 右键点击托盘图标
|
||||||
|
- **THEN** 显示菜单:显示主窗口、重启应用、关闭应用
|
||||||
|
|
||||||
|
#### Scenario: 双击托盘
|
||||||
|
- **WHEN** 双击托盘图标
|
||||||
|
- **THEN** 显示主窗口
|
||||||
|
|
||||||
|
### Requirement: URL 协议功能
|
||||||
|
系统 SHALL 提供自定义 URL 协议功能:
|
||||||
|
|
||||||
|
#### Scenario: 协议注册
|
||||||
|
- **WHEN** 应用启动(非开发模式)
|
||||||
|
- **THEN** 注册 secscore:// 协议
|
||||||
|
|
||||||
|
#### Scenario: 协议处理
|
||||||
|
- **WHEN** 收到协议 URL
|
||||||
|
- **THEN** 解析并导航到对应路由
|
||||||
|
- **AND** 支持路由:home、students、score、leaderboard、settlements、reasons、settings
|
||||||
|
|
||||||
|
### Requirement: 单实例运行
|
||||||
|
系统 SHALL 确保应用单实例运行:
|
||||||
|
|
||||||
|
#### Scenario: 单实例检查
|
||||||
|
- **WHEN** 启动第二个实例
|
||||||
|
- **THEN** 激活已有实例并退出
|
||||||
|
|
||||||
|
### Requirement: 前端 API 适配
|
||||||
|
系统 SHALL 保持前端 API 调用接口不变:
|
||||||
|
|
||||||
|
#### Scenario: API 兼容
|
||||||
|
- **WHEN** 前端调用 window.api
|
||||||
|
- **THEN** 返回与原项目相同格式的响应
|
||||||
|
- **AND** 所有接口签名保持一致
|
||||||
|
|
||||||
|
### Requirement: 文件系统功能
|
||||||
|
系统 SHALL 提供配置文件管理功能:
|
||||||
|
|
||||||
|
#### Scenario: 获取配置目录结构
|
||||||
|
- **WHEN** 调用获取配置目录结构接口
|
||||||
|
- **THEN** 返回 automatic 和 script 目录路径
|
||||||
|
|
||||||
|
#### Scenario: 读写 JSON 文件
|
||||||
|
- **WHEN** 调用读写 JSON 接口
|
||||||
|
- **THEN** 在指定目录读写 JSON 文件
|
||||||
|
|
||||||
|
#### Scenario: 读写文本文件
|
||||||
|
- **WHEN** 调用读写文本接口
|
||||||
|
- **THEN** 在指定目录读写文本文件
|
||||||
|
|
||||||
|
#### Scenario: 文件列表
|
||||||
|
- **WHEN** 调用文件列表接口
|
||||||
|
- **THEN** 返回指定目录的文件列表
|
||||||
|
|
||||||
|
### Requirement: HTTP 服务器功能
|
||||||
|
系统 SHALL 提供可选的 HTTP API 服务:
|
||||||
|
|
||||||
|
#### Scenario: 启动服务器
|
||||||
|
- **WHEN** 调用启动服务器接口
|
||||||
|
- **THEN** 启动 HTTP 服务器
|
||||||
|
- **AND** 支持自定义端口和 CORS 配置
|
||||||
|
|
||||||
|
#### Scenario: 停止服务器
|
||||||
|
- **WHEN** 调用停止服务器接口
|
||||||
|
- **THEN** 停止 HTTP 服务器
|
||||||
|
|
||||||
|
#### Scenario: 服务器状态
|
||||||
|
- **WHEN** 调用服务器状态接口
|
||||||
|
- **THEN** 返回服务器运行状态
|
||||||
|
|
||||||
|
## MODIFIED Requirements
|
||||||
|
无修改的需求,所有功能保持原有实现逻辑。
|
||||||
|
|
||||||
|
## REMOVED Requirements
|
||||||
|
无移除的需求。
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
# Tasks
|
||||||
|
|
||||||
|
## Phase 1: 项目初始化
|
||||||
|
|
||||||
|
- [x] Task 1: 创建 Tauri 项目结构
|
||||||
|
- [x] SubTask 1.1: 在 SecScore-Rust 目录初始化 Tauri 2.x 项目
|
||||||
|
- [x] SubTask 1.2: 配置 Cargo.toml 依赖(tauri, serde, tokio, sqlx, sea-orm 等)
|
||||||
|
- [x] SubTask 1.3: 配置 tauri.conf.json 基本设置
|
||||||
|
- [x] SubTask 1.4: 复制前端代码到新项目
|
||||||
|
- [x] SubTask 1.5: 配置前端构建脚本
|
||||||
|
|
||||||
|
## Phase 2: 数据库层实现
|
||||||
|
|
||||||
|
- [x] Task 2: 实现数据库实体和迁移
|
||||||
|
- [x] SubTask 2.1: 定义数据库实体结构(Student, Reason, ScoreEvent, Settlement, Setting, Tag, StudentTag)
|
||||||
|
- [x] SubTask 2.2: 实现 SQLite 数据库连接
|
||||||
|
- [x] SubTask 2.3: 实现 PostgreSQL 数据库连接
|
||||||
|
- [x] SubTask 2.4: 实现数据库迁移逻辑
|
||||||
|
- [x] SubTask 2.5: 实现连接切换功能
|
||||||
|
|
||||||
|
- [x] Task 3: 实现数据库仓储层
|
||||||
|
- [x] SubTask 3.1: 实现 StudentRepository(查询、创建、更新、删除、导入)
|
||||||
|
- [x] SubTask 3.2: 实现 EventRepository(查询、创建、删除、排行榜)
|
||||||
|
- [x] SubTask 3.3: 实现 ReasonRepository(查询、创建、更新、删除)
|
||||||
|
- [x] SubTask 3.4: 实现 SettlementRepository(查询、创建、排行榜)
|
||||||
|
- [x] SubTask 3.5: 实现 TagRepository(查询、创建、删除、学生标签关联)
|
||||||
|
|
||||||
|
## Phase 3: 核心服务实现
|
||||||
|
|
||||||
|
- [x] Task 4: 实现设置服务
|
||||||
|
- [x] SubTask 4.1: 定义设置项结构和默认值
|
||||||
|
- [x] SubTask 4.2: 实现设置缓存机制
|
||||||
|
- [x] SubTask 4.3: 实现设置的增删改查
|
||||||
|
- [x] SubTask 4.4: 实现设置变更通知
|
||||||
|
|
||||||
|
- [x] Task 5: 实现安全服务
|
||||||
|
- [x] SubTask 5.1: 实现 AES-256-CBC 加密解密
|
||||||
|
- [x] SubTask 5.2: 实现密码验证
|
||||||
|
- [x] SubTask 5.3: 实现恢复字符串生成
|
||||||
|
|
||||||
|
- [x] Task 6: 实现权限服务
|
||||||
|
- [x] SubTask 6.1: 定义权限级别(admin, points, view)
|
||||||
|
- [x] SubTask 6.2: 实现权限检查逻辑
|
||||||
|
- [x] SubTask 6.3: 实现权限状态管理
|
||||||
|
|
||||||
|
- [x] Task 7: 实现认证服务
|
||||||
|
- [x] SubTask 7.1: 实现登录/登出功能
|
||||||
|
- [x] SubTask 7.2: 实现密码设置功能
|
||||||
|
- [x] SubTask 7.3: 实现恢复功能
|
||||||
|
|
||||||
|
- [x] Task 8: 实现主题服务
|
||||||
|
- [x] SubTask 8.1: 定义内置主题
|
||||||
|
- [x] SubTask 8.2: 实现主题管理功能
|
||||||
|
- [x] SubTask 8.3: 实现主题变更通知
|
||||||
|
|
||||||
|
- [x] Task 9: 实现自动评分服务
|
||||||
|
- [x] SubTask 9.1: 定义规则结构
|
||||||
|
- [x] SubTask 9.2: 实现规则引擎
|
||||||
|
- [x] SubTask 9.3: 实现触发器逻辑(定时、标签)
|
||||||
|
- [x] SubTask 9.4: 实现动作执行(加分、加标签)
|
||||||
|
- [x] SubTask 9.5: 实现规则调度
|
||||||
|
|
||||||
|
- [x] Task 10: 实现日志服务
|
||||||
|
- [x] SubTask 10.1: 配置日志框架
|
||||||
|
- [x] SubTask 10.2: 实现日志文件滚动
|
||||||
|
- [x] SubTask 10.3: 实现日志查询和清除
|
||||||
|
|
||||||
|
- [x] Task 11: 实现数据服务
|
||||||
|
- [x] SubTask 11.1: 实现数据导出为 JSON
|
||||||
|
- [x] SubTask 11.2: 实现数据导入
|
||||||
|
|
||||||
|
## Phase 4: Tauri Commands 实现
|
||||||
|
|
||||||
|
- [x] Task 12: 实现学生相关 Commands
|
||||||
|
- [x] SubTask 12.1: db_student_query
|
||||||
|
- [x] SubTask 12.2: db_student_create
|
||||||
|
- [x] SubTask 12.3: db_student_update
|
||||||
|
- [x] SubTask 12.4: db_student_delete
|
||||||
|
- [x] SubTask 12.5: db_student_import_from_xlsx
|
||||||
|
|
||||||
|
- [x] Task 13: 实现标签相关 Commands
|
||||||
|
- [x] SubTask 13.1: tags_get_all
|
||||||
|
- [x] SubTask 13.2: tags_get_by_student
|
||||||
|
- [x] SubTask 13.3: tags_create
|
||||||
|
- [x] SubTask 13.4: tags_delete
|
||||||
|
- [x] SubTask 13.5: tags_update_student_tags
|
||||||
|
|
||||||
|
- [x] Task 14: 实现原因相关 Commands
|
||||||
|
- [x] SubTask 14.1: db_reason_query
|
||||||
|
- [x] SubTask 14.2: db_reason_create
|
||||||
|
- [x] SubTask 14.3: db_reason_update
|
||||||
|
- [x] SubTask 14.4: db_reason_delete
|
||||||
|
|
||||||
|
- [x] Task 15: 实现事件相关 Commands
|
||||||
|
- [x] SubTask 15.1: db_event_query
|
||||||
|
- [x] SubTask 15.2: db_event_create
|
||||||
|
- [x] SubTask 15.3: db_event_delete
|
||||||
|
- [x] SubTask 15.4: db_event_query_by_student
|
||||||
|
- [x] SubTask 15.5: db_leaderboard_query
|
||||||
|
|
||||||
|
- [x] Task 16: 实现结算相关 Commands
|
||||||
|
- [x] SubTask 16.1: db_settlement_query
|
||||||
|
- [x] SubTask 16.2: db_settlement_create
|
||||||
|
- [x] SubTask 16.3: db_settlement_leaderboard
|
||||||
|
|
||||||
|
- [x] Task 17: 实现设置相关 Commands
|
||||||
|
- [x] SubTask 17.1: settings_get_all
|
||||||
|
- [x] SubTask 17.2: settings_get
|
||||||
|
- [x] SubTask 17.3: settings_set
|
||||||
|
- [x] SubTask 17.4: settings_changed 事件
|
||||||
|
|
||||||
|
- [x] Task 18: 实现认证相关 Commands
|
||||||
|
- [x] SubTask 18.1: auth_get_status
|
||||||
|
- [x] SubTask 18.2: auth_login
|
||||||
|
- [x] SubTask 18.3: auth_logout
|
||||||
|
- [x] SubTask 18.4: auth_set_passwords
|
||||||
|
- [x] SubTask 18.5: auth_generate_recovery
|
||||||
|
- [x] SubTask 18.6: auth_reset_by_recovery
|
||||||
|
- [x] SubTask 18.7: auth_clear_all
|
||||||
|
|
||||||
|
- [x] Task 19: 实现主题相关 Commands
|
||||||
|
- [x] SubTask 19.1: theme_list
|
||||||
|
- [x] SubTask 19.2: theme_current
|
||||||
|
- [x] SubTask 19.3: theme_set
|
||||||
|
- [x] SubTask 19.4: theme_save
|
||||||
|
- [x] SubTask 19.5: theme_delete
|
||||||
|
- [x] SubTask 19.6: theme_updated 事件
|
||||||
|
|
||||||
|
- [x] Task 20: 实现自动评分相关 Commands
|
||||||
|
- [x] SubTask 20.1: auto_score_get_rules
|
||||||
|
- [x] SubTask 20.2: auto_score_add_rule
|
||||||
|
- [x] SubTask 20.3: auto_score_update_rule
|
||||||
|
- [x] SubTask 20.4: auto_score_delete_rule
|
||||||
|
- [x] SubTask 20.5: auto_score_toggle_rule
|
||||||
|
- [x] SubTask 20.6: auto_score_get_status
|
||||||
|
- [x] SubTask 20.7: auto_score_sort_rules
|
||||||
|
|
||||||
|
- [x] Task 21: 实现日志相关 Commands
|
||||||
|
- [x] SubTask 21.1: log_query
|
||||||
|
- [x] SubTask 21.2: log_clear
|
||||||
|
- [x] SubTask 21.3: log_set_level
|
||||||
|
- [x] SubTask 21.4: log_write
|
||||||
|
|
||||||
|
- [x] Task 22: 实现数据导入导出 Commands
|
||||||
|
- [x] SubTask 22.1: data_export_json
|
||||||
|
- [x] SubTask 22.2: data_import_json
|
||||||
|
|
||||||
|
- [x] Task 23: 实现窗口相关 Commands
|
||||||
|
- [x] SubTask 23.1: window_minimize
|
||||||
|
- [x] SubTask 23.2: window_maximize
|
||||||
|
- [x] SubTask 23.3: window_close
|
||||||
|
- [x] SubTask 23.4: window_is_maximized
|
||||||
|
- [x] SubTask 23.5: window_toggle_devtools
|
||||||
|
- [x] SubTask 23.6: window_resize
|
||||||
|
- [x] SubTask 23.7: window_maximized_changed 事件
|
||||||
|
- [x] SubTask 23.8: app_navigate 事件
|
||||||
|
|
||||||
|
- [x] Task 24: 实现数据库连接相关 Commands
|
||||||
|
- [x] SubTask 24.1: db_test_connection
|
||||||
|
- [x] SubTask 24.2: db_switch_connection
|
||||||
|
- [x] SubTask 24.3: db_get_status
|
||||||
|
- [x] SubTask 24.4: db_sync
|
||||||
|
|
||||||
|
- [x] Task 25: 实现文件系统相关 Commands
|
||||||
|
- [x] SubTask 25.1: fs_get_config_structure
|
||||||
|
- [x] SubTask 25.2: fs_read_json
|
||||||
|
- [x] SubTask 25.3: fs_write_json
|
||||||
|
- [x] SubTask 25.4: fs_read_text
|
||||||
|
- [x] SubTask 25.5: fs_write_text
|
||||||
|
- [x] SubTask 25.6: fs_delete_file
|
||||||
|
- [x] SubTask 25.7: fs_list_files
|
||||||
|
- [x] SubTask 25.8: fs_file_exists
|
||||||
|
|
||||||
|
- [x] Task 26: 实现 HTTP 服务器相关 Commands
|
||||||
|
- [x] SubTask 26.1: http_server_start
|
||||||
|
- [x] SubTask 26.2: http_server_stop
|
||||||
|
- [x] SubTask 26.3: http_server_status
|
||||||
|
|
||||||
|
- [x] Task 27: 实现应用相关 Commands
|
||||||
|
- [x] SubTask 27.1: app_register_url_protocol
|
||||||
|
|
||||||
|
## Phase 5: 系统功能实现
|
||||||
|
|
||||||
|
- [x] Task 28: 实现系统托盘
|
||||||
|
- [x] SubTask 28.1: 创建托盘图标
|
||||||
|
- [x] SubTask 28.2: 实现托盘菜单
|
||||||
|
- [x] SubTask 28.3: 实现双击显示窗口
|
||||||
|
|
||||||
|
- [x] Task 29: 实现 URL 协议处理
|
||||||
|
- [x] SubTask 29.1: 注册 secscore:// 协议
|
||||||
|
- [x] SubTask 29.2: 处理协议 URL 并导航
|
||||||
|
|
||||||
|
- [x] Task 30: 实现单实例运行
|
||||||
|
- [x] SubTask 30.1: 检测已有实例
|
||||||
|
- [x] SubTask 30.2: 激活已有实例
|
||||||
|
|
||||||
|
## Phase 6: 前端适配
|
||||||
|
|
||||||
|
- [x] Task 31: 修改前端 API 调用层
|
||||||
|
- [x] SubTask 31.1: 创建 Tauri invoke 封装
|
||||||
|
- [x] SubTask 31.2: 修改所有 window.api 调用为 Tauri invoke
|
||||||
|
- [x] SubTask 31.3: 实现事件监听(theme_updated, settings_changed 等)
|
||||||
|
- [x] SubTask 31.4: 移除 Electron 特定代码
|
||||||
|
|
||||||
|
- [x] Task 32: 适配窗口控制
|
||||||
|
- [x] SubTask 32.1: 修改标题栏组件使用 Tauri API
|
||||||
|
- [x] SubTask 32.2: 实现窗口拖拽区域
|
||||||
|
|
||||||
|
## Phase 7: 构建与测试
|
||||||
|
|
||||||
|
- [ ] Task 33: 配置构建脚本
|
||||||
|
- [ ] SubTask 33.1: 配置开发环境脚本
|
||||||
|
- [ ] SubTask 33.2: 配置生产构建脚本
|
||||||
|
- [ ] SubTask 33.3: 配置 Windows 打包
|
||||||
|
|
||||||
|
- [ ] Task 34: 功能验证
|
||||||
|
- [ ] SubTask 34.1: 验证所有数据库操作
|
||||||
|
- [ ] SubTask 34.2: 验证所有 UI 功能
|
||||||
|
- [ ] SubTask 34.3: 验证主题切换
|
||||||
|
- [ ] SubTask 34.4: 验证认证流程
|
||||||
|
- [ ] SubTask 34.5: 验证自动评分
|
||||||
|
- [ ] SubTask 34.6: 验证数据导入导出
|
||||||
|
- [ ] SubTask 34.7: 验证系统托盘
|
||||||
|
- [ ] SubTask 34.8: 验证 URL 协议
|
||||||
|
|
||||||
|
# Task Dependencies
|
||||||
|
- [Task 2] depends on [Task 1]
|
||||||
|
- [Task 3] depends on [Task 2]
|
||||||
|
- [Task 4] depends on [Task 2]
|
||||||
|
- [Task 5] depends on [Task 4]
|
||||||
|
- [Task 6] depends on [Task 5]
|
||||||
|
- [Task 7] depends on [Task 5, Task 6]
|
||||||
|
- [Task 8] depends on [Task 4]
|
||||||
|
- [Task 9] depends on [Task 3]
|
||||||
|
- [Task 10] depends on [Task 1]
|
||||||
|
- [Task 11] depends on [Task 3]
|
||||||
|
- [Task 12-27] depend on [Task 3-11]
|
||||||
|
- [Task 28] depends on [Task 1]
|
||||||
|
- [Task 29] depends on [Task 1]
|
||||||
|
- [Task 30] depends on [Task 1]
|
||||||
|
- [Task 31] depends on [Task 12-27]
|
||||||
|
- [Task 32] depends on [Task 31]
|
||||||
|
- [Task 33] depends on [Task 32]
|
||||||
|
- [Task 34] depends on [Task 33]
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>com.apple.security.cs.allow-jit</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.cs.disable-library-validation</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,40 +1,49 @@
|
|||||||
import { defineConfig } from 'eslint/config'
|
import { defineConfig } from "eslint/config"
|
||||||
import tseslint from '@electron-toolkit/eslint-config-ts'
|
import tseslint from "typescript-eslint"
|
||||||
import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier'
|
import eslintConfigPrettier from "eslint-config-prettier"
|
||||||
import eslintPluginReact from 'eslint-plugin-react'
|
import eslintPluginReact from "eslint-plugin-react"
|
||||||
import eslintPluginReactHooks from 'eslint-plugin-react-hooks'
|
import eslintPluginReactHooks from "eslint-plugin-react-hooks"
|
||||||
import eslintPluginReactRefresh from 'eslint-plugin-react-refresh'
|
import eslintPluginReactRefresh from "eslint-plugin-react-refresh"
|
||||||
|
|
||||||
export default defineConfig(
|
export default defineConfig(
|
||||||
{ ignores: ['**/node_modules', '**/dist', '**/out', 'scripts/**', 'secrandom_ipc_send_url.js'] },
|
{
|
||||||
|
ignores: [
|
||||||
|
"**/node_modules",
|
||||||
|
"**/dist",
|
||||||
|
"**/dist-ssr",
|
||||||
|
"**/out",
|
||||||
|
"**/src-tauri/target",
|
||||||
|
"**/src-tauri/gen",
|
||||||
|
"scripts/**",
|
||||||
|
],
|
||||||
|
},
|
||||||
tseslint.configs.recommended,
|
tseslint.configs.recommended,
|
||||||
eslintPluginReact.configs.flat.recommended,
|
eslintPluginReact.configs.flat.recommended,
|
||||||
eslintPluginReact.configs.flat['jsx-runtime'],
|
eslintPluginReact.configs.flat["jsx-runtime"],
|
||||||
{
|
{
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
version: 'detect'
|
version: "detect",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['**/*.{ts,tsx}'],
|
files: ["**/*.{ts,tsx}"],
|
||||||
plugins: {
|
plugins: {
|
||||||
'react-hooks': eslintPluginReactHooks,
|
"react-hooks": eslintPluginReactHooks,
|
||||||
'react-refresh': eslintPluginReactRefresh
|
"react-refresh": eslintPluginReactRefresh,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
...eslintPluginReactHooks.configs.recommended.rules,
|
...eslintPluginReactHooks.configs.recommended.rules,
|
||||||
...eslintPluginReactRefresh.configs.vite.rules,
|
...eslintPluginReactRefresh.configs.vite.rules,
|
||||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
"@typescript-eslint/explicit-function-return-type": "off",
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
'react-refresh/only-export-components': 'off',
|
"react-refresh/only-export-components": "off",
|
||||||
'react-hooks/exhaustive-deps': 'warn',
|
"react-hooks/exhaustive-deps": "warn",
|
||||||
'react-hooks/set-state-in-effect': 'off',
|
"react-hooks/set-state-in-effect": "off",
|
||||||
'@typescript-eslint/no-require-imports': 'off',
|
"@typescript-eslint/no-require-imports": "off",
|
||||||
// we use TypeScript types instead of PropTypes in React components
|
"react/prop-types": "off",
|
||||||
'react/prop-types': 'off'
|
},
|
||||||
}
|
|
||||||
},
|
},
|
||||||
eslintConfigPrettier
|
eslintConfigPrettier
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>SecScore</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
out
|
||||||
|
.DS_Store
|
||||||
|
.eslintcache
|
||||||
|
*.log*
|
||||||
|
logs
|
||||||
|
docs
|
||||||
|
configs
|
||||||
|
|
||||||
|
build/*
|
||||||
|
!build/entitlements.mac.plist
|
||||||
|
db.sqlite
|
||||||
|
*.local
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
.vscode
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/settings.json
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
out
|
||||||
|
dist
|
||||||
|
pnpm-lock.yaml
|
||||||
|
LICENSE.md
|
||||||
|
tsconfig.json
|
||||||
|
tsconfig.*.json
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
singleQuote: true
|
||||||
|
semi: false
|
||||||
|
printWidth: 100
|
||||||
|
trailingComma: none
|
||||||
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,40 @@
|
|||||||
|
import { defineConfig } from 'eslint/config'
|
||||||
|
import tseslint from '@electron-toolkit/eslint-config-ts'
|
||||||
|
import eslintConfigPrettier from '@electron-toolkit/eslint-config-prettier'
|
||||||
|
import eslintPluginReact from 'eslint-plugin-react'
|
||||||
|
import eslintPluginReactHooks from 'eslint-plugin-react-hooks'
|
||||||
|
import eslintPluginReactRefresh from 'eslint-plugin-react-refresh'
|
||||||
|
|
||||||
|
export default defineConfig(
|
||||||
|
{ ignores: ['**/node_modules', '**/dist', '**/out', 'scripts/**', 'secrandom_ipc_send_url.js'] },
|
||||||
|
tseslint.configs.recommended,
|
||||||
|
eslintPluginReact.configs.flat.recommended,
|
||||||
|
eslintPluginReact.configs.flat['jsx-runtime'],
|
||||||
|
{
|
||||||
|
settings: {
|
||||||
|
react: {
|
||||||
|
version: 'detect'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.{ts,tsx}'],
|
||||||
|
plugins: {
|
||||||
|
'react-hooks': eslintPluginReactHooks,
|
||||||
|
'react-refresh': eslintPluginReactRefresh
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
...eslintPluginReactHooks.configs.recommended.rules,
|
||||||
|
...eslintPluginReactRefresh.configs.vite.rules,
|
||||||
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'react-refresh/only-export-components': 'off',
|
||||||
|
'react-hooks/exhaustive-deps': 'warn',
|
||||||
|
'react-hooks/set-state-in-effect': 'off',
|
||||||
|
'@typescript-eslint/no-require-imports': 'off',
|
||||||
|
// we use TypeScript types instead of PropTypes in React components
|
||||||
|
'react/prop-types': 'off'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
eslintConfigPrettier
|
||||||
|
)
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
{
|
||||||
|
"name": "secscore",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "SecScore – Your Education Points Management Expert",
|
||||||
|
"main": "./out/main/index.js",
|
||||||
|
"author": "example.com",
|
||||||
|
"homepage": "https://example.org",
|
||||||
|
"scripts": {
|
||||||
|
"format": "prettier --write .",
|
||||||
|
"lint": "eslint --cache .",
|
||||||
|
"lint:fix": "eslint --cache . --fix",
|
||||||
|
"typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false",
|
||||||
|
"typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false",
|
||||||
|
"typecheck": "pnpm -s typecheck:node && pnpm -s typecheck:web",
|
||||||
|
"start": "electron-vite preview",
|
||||||
|
"dev": "electron-vite dev",
|
||||||
|
"build": "node scripts/clean-db.mjs && pnpm -s typecheck && electron-vite build",
|
||||||
|
"postinstall": "electron-builder install-app-deps",
|
||||||
|
"build:unpack": "pnpm -s build && electron-builder --dir --publish never",
|
||||||
|
"build:win": "pnpm -s build && electron-builder --win --publish never",
|
||||||
|
"build:mac": "electron-vite build && electron-builder --mac --publish never",
|
||||||
|
"build:linux": "electron-vite build && electron-builder --linux --publish never",
|
||||||
|
"build:mobile": "vite build --config vite.mobile.config.ts",
|
||||||
|
"cap:sync": "npx cap sync",
|
||||||
|
"cap:open:android": "npx cap open android",
|
||||||
|
"mobile:build": "pnpm build:mobile && pnpm cap:sync",
|
||||||
|
"mobile:android": "pnpm mobile:build && npx cap open android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ant-design/icons": "^6.1.0",
|
||||||
|
"@capacitor/android": "^8.1.0",
|
||||||
|
"@capacitor/cli": "^8.1.0",
|
||||||
|
"@capacitor/core": "^8.1.0",
|
||||||
|
"@capacitor/preferences": "^8.0.1",
|
||||||
|
"@electron-toolkit/preload": "^3.0.2",
|
||||||
|
"@electron-toolkit/utils": "^4.0.0",
|
||||||
|
"@react-querybuilder/antd": "^8.14.0",
|
||||||
|
"@react-querybuilder/dnd": "^8.14.0",
|
||||||
|
"antd": "^6.3.1",
|
||||||
|
"antd-mobile": "^5.42.3",
|
||||||
|
"better-sqlite3": "^12.6.0",
|
||||||
|
"chokidar": "^5.0.0",
|
||||||
|
"dayjs": "^1.11.20",
|
||||||
|
"es-object-atoms": "^1.1.1",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"i18next": "^25.8.14",
|
||||||
|
"json-rules-engine": "^7.3.1",
|
||||||
|
"math-intrinsics": "^1.1.0",
|
||||||
|
"mica-electron": "^1.5.16",
|
||||||
|
"os": "^0.1.2",
|
||||||
|
"pg": "^8.19.0",
|
||||||
|
"pinyin-pro": "^3.27.0",
|
||||||
|
"react-dnd": "^16.0.1",
|
||||||
|
"react-dnd-html5-backend": "^16.0.1",
|
||||||
|
"react-dnd-touch-backend": "^16.0.1",
|
||||||
|
"react-i18next": "^16.5.6",
|
||||||
|
"react-querybuilder": "^8.14.0",
|
||||||
|
"react-router-dom": "^6.28.0",
|
||||||
|
"reflect-metadata": "^0.2.2",
|
||||||
|
"typeorm": "^0.3.27",
|
||||||
|
"uuid": "^13.0.0",
|
||||||
|
"winston": "^3.19.0",
|
||||||
|
"winston-daily-rotate-file": "^5.0.0",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
|
||||||
|
"@electron-toolkit/eslint-config-ts": "^3.1.0",
|
||||||
|
"@electron-toolkit/tsconfig": "^2.0.0",
|
||||||
|
"@types/better-sqlite3": "^7.6.13",
|
||||||
|
"@types/node": "^22.19.1",
|
||||||
|
"@types/pg": "^8.18.0",
|
||||||
|
"@types/react": "^19.2.7",
|
||||||
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"@types/uuid": "^11.0.0",
|
||||||
|
"@vitejs/plugin-react": "^5.1.1",
|
||||||
|
"electron": "^39.2.6",
|
||||||
|
"electron-builder": "^26.0.12",
|
||||||
|
"electron-vite": "^5.0.0",
|
||||||
|
"eslint": "^9.39.1",
|
||||||
|
"eslint-plugin-react": "^7.37.5",
|
||||||
|
"eslint-plugin-react-hooks": "^7.0.1",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.24",
|
||||||
|
"prettier": "^3.7.4",
|
||||||
|
"react": "^19.2.1",
|
||||||
|
"react-dom": "^19.2.1",
|
||||||
|
"terser": "^5.46.0",
|
||||||
|
"typescript": "^5.9.3",
|
||||||
|
"vite": "^7.2.6"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"onlyBuiltDependencies": [
|
||||||
|
"electron",
|
||||||
|
"electron-winstaller",
|
||||||
|
"esbuild"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 401 KiB |