chore(ci): 移除 Woodpecker CI 配置,全面采用 Jenkins

- 删除 .woodpecker.yml
- 删除 .woodpecker-e2e.yml
- 删除 .woodpecker-test-suite.yml
This commit is contained in:
张翔
2026-04-27 15:38:41 +08:00
parent d03253617c
commit 0c3b67eb64
13 changed files with 165 additions and 557 deletions
Vendored
BIN
View File
Binary file not shown.
+12
View File
@@ -166,3 +166,15 @@ nbdist/
# git worktrees # git worktrees
.worktrees/ .worktrees/
# docs
docs/
# macOS specific
.DS_Store
Thumbs.db
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
-94
View File
@@ -1,94 +0,0 @@
# Woodpecker CI/CD 配置 - E2E/UAT测试集成
# 集成Python pytest测试套件
pipeline:
# E2E/UAT测试阶段
test-e2e-uat:
image: python:3.11
environment:
- BASE_URL=http://localhost:8084
- FRONTEND_URL=http://localhost:3000
- ENV=test
- DATABASE=h2
commands:
- echo "开始E2E/UAT测试..."
- cd test-suite
- pip install -r requirements.txt
- pip install pytest-xdist pytest-rerunfailures
- python3 run_tests.py --parallel --reruns 2 --coverage
- echo "✅ E2E/UAT测试完成"
when:
event: [push, pull_request]
# 生成测试报告
generate-report:
image: python:3.11
commands:
- echo "生成测试报告..."
- cd test-suite
- pip install -r requirements.txt
- pip install allure-pytest
- pytest tests/ --alluredir=allure-results
- echo "✅ 报告生成完成"
when:
event: [push, pull_request]
# 质量门禁
quality-gates:
image: python:3.11
commands:
- echo "开始质量门禁检查..."
- cd test-suite
- pip install -r requirements.txt
- pytest tests/ --cov=. --cov-report=term-missing --cov-fail-under=80
- echo "✅ 质量门禁检查通过"
when:
event: [pull_request]
# 工作流配置
workflows:
# 开发分支工作流
develop:
when:
event: [push]
branch: [develop]
steps:
- test-e2e-uat
- generate-report
# 主分支工作流
main:
when:
event: [push]
branch: [main]
steps:
- test-e2e-uat
- quality-gates
- generate-report
# Pull Request工作流
pull-request:
when:
event: [pull_request]
steps:
- test-e2e-uat
- quality-gates
# 通知配置
notifications:
slack:
webhook: ${SLACK_WEBHOOK_URL}
channel: '#ci-cd'
on_success: true
on_failure: true
# 环境变量
environment:
- PYTHONUNBUFFERED=1
- PYTHONDONTWRITEBYTECODE=1
# 缓存配置
cache:
paths:
- ~/.pip/cache
- test-suite/.pytest_cache
-155
View File
@@ -1,155 +0,0 @@
# Woodpecker CI/CD - 测试套件专用流水线
# 用途: 执行系统性的测试套件(E2E、UAT、性能、安全测试)
pipeline:
# 环境准备阶段
prepare:
image: python:3.11-slim
commands:
- echo "准备测试环境..."
- cd test-suite
- pip install -r requirements.txt
- echo "✅ 测试环境准备完成"
when:
event: [push, pull_request]
# 集成测试阶段
test-integration:
image: python:3.11-slim
commands:
- echo "开始集成测试..."
- cd test-suite
- pytest tests/integration/ -v --tb=short --cov=. --cov-report=xml --alluredir=allure-results/integration
- echo "✅ 集成测试完成"
when:
event: [push, pull_request]
# E2E测试阶段
test-e2e:
image: python:3.11-slim
commands:
- echo "开始E2E测试..."
- cd test-suite
- pytest tests/e2e/ -v --tb=short --cov=. --cov-report=xml --alluredir=allure-results/e2e -m "e2e"
- echo "✅ E2E测试完成"
when:
event: [push, pull_request]
# UAT验收测试阶段
test-uat:
image: python:3.11-slim
commands:
- echo "开始UAT验收测试..."
- cd test-suite
- pytest tests/uat/ -v --tb=short --cov=. --cov-report=xml --alluredir=allure-results/uat -m "uat"
- echo "✅ UAT测试完成"
when:
event: [push, pull_request]
# 性能测试阶段
test-performance:
image: python:3.11-slim
commands:
- echo "开始性能测试..."
- cd test-suite
- pytest tests/performance/ -v --tb=short --cov=. --cov-report=xml --alluredir=allure-results/performance -m "performance"
- echo "✅ 性能测试完成"
when:
event: [push]
branch: [main, develop]
# 安全测试阶段
test-security:
image: python:3.11-slim
commands:
- echo "开始安全测试..."
- cd test-suite
- pytest tests/security/ -v --tb=short --cov=. --cov-report=xml --alluredir=allure-results/security -m "security"
- echo "✅ 安全测试完成"
when:
event: [pull_request]
# 测试报告生成
generate-reports:
image: python:3.11-slim
commands:
- echo "生成测试报告..."
- cd test-suite
- mkdir -p reports
- cp -r htmlcov reports/
- cp -r allure-results reports/
- echo "✅ 测试报告生成完成"
when:
event: [push, pull_request]
status: [success, failure]
# 质量门禁检查
quality-gates:
image: python:3.11-slim
commands:
- echo "开始质量门禁检查..."
- cd test-suite
- |
# 检查测试覆盖率
if [ -f coverage.xml ]; then
coverage_percent=$(python -c "import xml.etree.ElementTree as ET; tree = ET.parse('coverage.xml'); root = tree.getroot(); print(float(root.attrib['line-rate']) * 100)")
echo "测试覆盖率: ${coverage_percent}%"
if (( $(echo "$coverage_percent < 80" | bc -l) )); then
echo "❌ 测试覆盖率不足80%"
exit 1
fi
fi
- echo "✅ 测试覆盖率检查通过"
- echo "✅ 所有测试用例通过"
- echo "✅ 质量门禁检查通过"
when:
event: [pull_request]
# 工作流配置
workflows:
# 完整测试工作流(主分支)
full-test:
when:
event: [push]
branch: [main, develop]
steps:
- prepare
- test-integration
- test-e2e
- test-uat
- test-performance
- generate-reports
# 快速测试工作流(Pull Request)
quick-test:
when:
event: [pull_request]
steps:
- prepare
- test-integration
- test-e2e
- test-uat
- test-security
- quality-gates
- generate-reports
# 通知配置
notifications:
slack:
webhook: ${SLACK_WEBHOOK_URL}
channel: '#test-reports'
on_success: true
on_failure: true
on_start: false
# 环境变量
environment:
- PYTHONPATH=/woodpecker/src/github.com/novalon/novalon-manage-system/test-suite
- TEST_ENV=ci
# 缓存配置
cache:
paths:
- test-suite/.pytest_cache
- test-suite/htmlcov
- test-suite/allure-results
-263
View File
@@ -1,263 +0,0 @@
# Woodpecker CI/CD 流水线配置 - 企业级质量门禁
# 基于Docker化部署的完整CI/CD流水线
pipeline:
# 代码质量检查阶段
code-quality:
group: 质量检查
image: maven:3.9-openjdk-21
commands:
- echo "🔍 开始代码质量检查..."
- cd novalon-manage-api
- echo "📊 运行静态代码分析..."
- mvn spotbugs:check
- echo "📏 检查代码规范..."
- mvn checkstyle:check
- echo "📈 生成代码质量报告..."
- mvn pmd:check
- echo "✅ 代码质量检查完成"
when:
event: [push, pull_request]
# 后端测试阶段
test-backend:
group: 后端测试
image: maven:3.9-openjdk-21
commands:
- echo "🚀 开始后端测试..."
- cd novalon-manage-api
- echo "🧪 运行单元测试..."
- mvn clean test jacoco:report
- echo "📊 生成测试覆盖率报告..."
- mvn jacoco:check
- echo "✅ 后端测试完成,覆盖率: $(cat target/site/jacoco/jacoco.xml | grep -oP 'lineCoverage=\"\K[0-9.]+')%"
when:
event: [push, pull_request]
# 前端测试阶段
test-frontend:
group: 前端测试
image: node:20
commands:
- echo "🚀 开始前端测试..."
- cd novalon-manage-web
- echo "📦 安装依赖..."
- npm ci
- echo "🧪 运行单元测试..."
- npm run test:unit
- echo "📏 检查代码规范..."
- npm run lint
- echo "✅ 前端测试完成"
when:
event: [push, pull_request]
# Docker化构建阶段
docker-build:
group: 容器化构建
image: docker:24
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- echo "🐳 开始Docker化构建..."
- echo "📦 构建后端镜像..."
- docker build -t novalon/backend:${CI_COMMIT_SHA:0:8} -f novalon-manage-api/Dockerfile ./novalon-manage-api
- echo "🌐 构建前端镜像..."
- docker build -t novalon/frontend:${CI_COMMIT_SHA:0:8} -f novalon-manage-web/Dockerfile ./novalon-manage-web
- echo "✅ Docker镜像构建完成"
when:
event: [push]
branch: [main, develop]
# 集成测试阶段(使用Docker Compose
integration-test:
group: 集成测试
image: docker:24
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- echo "🧪 开始集成测试..."
- echo "🐳 启动测试环境..."
- docker-compose -f docker-compose.test.yml up -d
- echo "⏳ 等待服务就绪..."
- sleep 60
- echo "🔍 检查服务健康状态..."
- curl -f http://localhost:8085/actuator/health || (docker-compose -f docker-compose.test.yml logs && exit 1)
- curl -f http://localhost:3002 || (docker-compose -f docker-compose.test.yml logs && exit 1)
- echo "✅ 集成测试环境就绪"
when:
event: [push]
branch: [main, develop]
# E2E测试阶段
e2e-test:
group: E2E测试
image: mcr.microsoft.com/playwright:v1.58.2-jammy
commands:
- echo "🎭 开始E2E测试..."
- cd novalon-manage-web
- echo "📦 安装依赖..."
- npm ci
- echo "🔧 安装浏览器..."
- npx playwright install --with-deps chromium
- echo "🧪 运行E2E测试..."
- npx playwright test --project=journeys --reporter=html,json,junit
- echo "✅ E2E测试完成"
when:
event: [push]
branch: [main, develop]
# 安全扫描阶段
security-scan:
group: 安全扫描
image: aquasec/trivy:latest
commands:
- echo "🔒 开始安全扫描..."
- echo "📊 扫描后端镜像..."
- trivy image novalon/backend:${CI_COMMIT_SHA:0:8}
- echo "📊 扫描前端镜像..."
- trivy image novalon/frontend:${CI_COMMIT_SHA:0:8}
- echo "✅ 安全扫描完成"
when:
event: [push]
branch: [main, develop]
# 部署阶段
deploy:
group: 部署
image: alpine:latest
commands:
- echo "🚀 开始部署..."
- echo "📦 推送镜像到仓库..."
- docker tag novalon/backend:${CI_COMMIT_SHA:0:8} ${DOCKER_REGISTRY}/novalon/backend:${CI_COMMIT_SHA:0:8}
- docker tag novalon/frontend:${CI_COMMIT_SHA:0:8} ${DOCKER_REGISTRY}/novalon/frontend:${CI_COMMIT_SHA:0:8}
- docker push ${DOCKER_REGISTRY}/novalon/backend:${CI_COMMIT_SHA:0:8}
- docker push ${DOCKER_REGISTRY}/novalon/frontend:${CI_COMMIT_SHA:0:8}
- echo "✅ 部署完成"
when:
event: [push]
branch: [main]
# 清理阶段
cleanup:
group: 清理
image: docker:24
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- echo "🧹 开始清理..."
- docker-compose -f docker-compose.test.yml down -v
- docker system prune -f
- echo "✅ 清理完成"
when:
event: [push]
branch: [main, develop]
# 安全扫描
security-scan:
image: aquasec/trivy:latest
commands:
- echo "🔒 开始安全漏洞扫描..."
- trivy filesystem --severity HIGH,CRITICAL --exit-code 1 .
- echo "✅ 安全扫描通过"
when:
event: [pull_request]
# 发布测试报告
publish-test-reports:
image: alpine:latest
commands:
- echo "📊 发布测试报告..."
- mkdir -p reports
- cp -r novalon-manage-api/target/site/jacoco reports/backend-coverage || true
- cp -r novalon-manage-web/playwright-report reports/e2e-report || true
- echo "✅ 测试报告已发布到 reports/"
when:
event: [push, pull_request]
status: [success, failure]
# 部署到测试环境
deploy-staging:
image: alpine/k8s:1.29
commands:
- echo "🚀 部署到测试环境..."
- kubectl apply -f k8s/staging/
- echo "✅ 测试环境部署完成"
when:
event: [push]
branch: [develop]
# 部署到生产环境
deploy-production:
image: alpine/k8s:1.29
commands:
- echo "🚀 部署到生产环境..."
- kubectl apply -f k8s/production/
- echo "✅ 生产环境部署完成"
when:
event: [push]
branch: [main]
# 工作流配置
workflows:
# 开发分支工作流
develop:
when:
event: [push]
branch: [develop]
steps:
- test-backend
- build-backend-jar
- test-frontend-unit
- test-frontend-e2e
- publish-test-reports
- build
- deploy-staging
# 主分支工作流
main:
when:
event: [push]
branch: [main]
steps:
- test-backend
- build-backend-jar
- test-frontend-unit
- test-frontend-e2e
- publish-test-reports
- security-scan
- build
- deploy-production
# Pull Request工作流
pull-request:
when:
event: [pull_request]
steps:
- test-backend
- build-backend-jar
- test-frontend-unit
- test-frontend-e2e
- publish-test-reports
- quality-gates
- security-scan
# 通知配置
notifications:
slack:
webhook: ${SLACK_WEBHOOK_URL}
channel: '#ci-cd'
on_success: true
on_failure: true
on_start: false
# 环境变量
environment:
- JAVA_HOME=/usr/lib/jvm/java-21-openjdk
- NODE_ENV=test
- SPRING_PROFILES_ACTIVE=test
# 缓存配置
cache:
paths:
- ~/.m2/repository
- novalon-manage-web/node_modules
+75
View File
@@ -0,0 +1,75 @@
# 全局 Agent 规则
本文件用于约束自动化代理在本机工作区中的默认工作方式,并将 Superpowers 作为主工作流体系按需激活。
## 指令优先级
- 默认以 **Superpowers** 作为主工作流体系,但不默认启用 full Superpowers。
- 只读分析任务可不进入完整实现流程,但结论必须清晰、可追溯。
- 若用户明确要求 `continue nonstop`,默认持续推进,直到满足验收标准或出现真实阻塞。
## 默认原则
### 最短路径与并行轻重分流
- 默认采用“满足质量要求的最短路径”。
- 能直接完成并验证的,不升级为更重流程。
- 能用轻量 planning 解决的小任务,不升级为重文档流程。
- 能用单一专项 skill 解决的问题,不扩展为 full Superpowers。
### 轻量任务默认策略(Codex / Superpowers
- 轻量任务:单文件或小范围修改、明确 bug 修复、配置 / 文案调整、小测试补充、局部
文档修改。
- 默认可跳过完整 `brainstorming``writing-plans``using-git-worktrees` 与重 review 链,直接实现并做定向验证;仅在关键不确定且无法从当前对话、项目上下文、`AGENTS.md`、现有代码回答时才提问。
- 总原则:将 Superpowers 视为可调节的工程纪律层——小任务走轻量路径,中任务保留简短 brainstorming 与短计划,大任务再启用完整流程。
### 流程升级 / 降级
- 升级到更重流程:影响边界超出初始判断、涉及公共 API / schema / 持久化 / 并发 /
共享逻辑、需求仍不清晰、验证覆盖不足、任务演变为中大型实现或重构。
- 降级到更轻流程:改动局部且边界清晰、不涉及共享核心逻辑、验证直接、补长计划或补
测试的成本明显高于收益、问题已收敛为单点修复。
### Step by Step Reasoning Workflow
### 执行原则
1. 先澄清,再实现;先缩小边界,再扩展范围。
2. 优先局部修改与最小充分实现,避免无关扩张。
3. 若复杂度上升,及时升级流程,而不是硬撑轻流程。
4. 若任务已收敛为局部改动,及时降级流程。
### 编码质量原则(Karpathy Guidelines
在编写、审查或重构代码时,遵循以下原则:
1. **编码前先思考** — 明确假设,不隐藏困惑,展示权衡
2. **简单优先** — 只写解决问题的最小代码,拒绝过度抽象
3. **精准修改** — 只触碰必须修改的部分,不"改进"相邻代码
4. **目标驱动执行** — 定义可验证的成功标准,循环直到验证通过
## 技能协同迭代项目工作流
### 技能组合策略
基于 Superpowers-ZH 技能框架,推荐以下技能协同组合用于复杂项目迭代:
#### 核心技能组合
- **gsd** - 综合性项目管理系统,适用于个人开发者使用 Claude 代理进行任务管理、进度跟踪和项目规划
- **gstack-workflow-assistant** - 工作流助手技能,提供结构化的工作流程支持,适用于团队协作、任务分配和项目分工管理
- **superpower-zh** - 技能框架,提供 27 个专业技能的集成管理
- **karpathy-guidelines** - 编码质量指南,避免过度复杂化,确保代码简洁有效
#### 协同工作流程
```
项目规划 (gsd) → 工作流管理 (gstack-workflow-assistant) → 技能执行 (superpower-zh) → 质量检查 (karpathy)
```
### 适用场景
- 复杂软件项目开发
- 需要严格质量控制的迭代过程
- 跨团队协作项目
- 长期维护的项目
### 使用建议
1. **项目启动阶段**:使用 gsd 进行项目规划和任务分解
2. **团队协作阶段**:使用 gstack-workflow-assistant 进行任务分配和分工管理
3. **开发执行阶段**:使用 superpower-zh 中的具体技能(如 TDD、代码审查等)
4. **质量保障阶段**:使用 karpathy 进行代码质量检查
### 技能安装与更新
- 所有技能已全局安装,支持 Trae、Trae CN 等 45 个代理
- 技能列表维护在 `.trae/rules/superpowers-zh.md`
- 定期使用 `npx skills check` 检查技能更新
### 协同优势
- **完整闭环**:形成项目管理→协作→执行→质量保障的完整开发闭环
- **质量保障**:通过技能协同确保代码质量和项目进度
- **效率提升**:系统化的工作流程减少重复劳动和错误
- **团队协作**:支持多人协作和任务分工管理
-21
View File
@@ -1,21 +0,0 @@
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class PasswordTest {
public static void main(String[] args) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
String hash = "$2a$12$nZ1EMUpZQljbnEdIKzH72eHlDJKUmHmHppnTTVth/SlHs5VpSAr8C";
// 测试常见密码
String[] passwords = {"admin", "Admin@123", "Test@123", "password", "123456", "admin123"};
for (String password : passwords) {
boolean matches = encoder.matches(password, hash);
System.out.println(password + ": " + matches);
}
// 生成新的哈希
String newHash = encoder.encode("Test@123");
System.out.println("\nNew hash for 'Test@123': " + newHash);
}
}
+69 -13
View File
@@ -59,7 +59,7 @@ importers:
version: 6.21.0(eslint@8.57.1)(typescript@5.9.3) version: 6.21.0(eslint@8.57.1)(typescript@5.9.3)
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^6.0.3 specifier: ^6.0.3
version: 6.0.5(vite@7.3.1(@types/node@20.19.37))(vue@3.5.30(typescript@5.9.3)) version: 6.0.5(vite@7.3.1(@types/node@20.19.37)(terser@5.46.2))(vue@3.5.30(typescript@5.9.3))
'@vitest/coverage-v8': '@vitest/coverage-v8':
specifier: ^4.1.1 specifier: ^4.1.1
version: 4.1.2(vitest@4.1.0) version: 4.1.2(vitest@4.1.0)
@@ -81,15 +81,18 @@ importers:
prettier: prettier:
specifier: ^3.1.1 specifier: ^3.1.1
version: 3.8.1 version: 3.8.1
terser:
specifier: ^5.46.1
version: 5.46.2
typescript: typescript:
specifier: ^5.9.3 specifier: ^5.9.3
version: 5.9.3 version: 5.9.3
vite: vite:
specifier: ^7.3.1 specifier: ^7.3.1
version: 7.3.1(@types/node@20.19.37) version: 7.3.1(@types/node@20.19.37)(terser@5.46.2)
vitest: vitest:
specifier: ^4.0.16 specifier: ^4.0.16
version: 4.1.0(@types/node@20.19.37)(@vitest/ui@4.1.0)(jsdom@27.4.0)(vite@7.3.1(@types/node@20.19.37)) version: 4.1.0(@types/node@20.19.37)(@vitest/ui@4.1.0)(jsdom@27.4.0)(vite@7.3.1(@types/node@20.19.37)(terser@5.46.2))
vue-tsc: vue-tsc:
specifier: ^3.2.2 specifier: ^3.2.2
version: 3.2.5(typescript@5.9.3) version: 3.2.5(typescript@5.9.3)
@@ -390,10 +393,16 @@ packages:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'} engines: {node: '>=12'}
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
'@jridgewell/resolve-uri@3.1.2': '@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
'@jridgewell/source-map@0.3.11':
resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==}
'@jridgewell/sourcemap-codec@1.5.5': '@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
@@ -858,6 +867,9 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'} engines: {node: '>=8'}
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
call-bind-apply-helpers@1.0.2: call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -889,6 +901,9 @@ packages:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
engines: {node: '>=14'} engines: {node: '>=14'}
commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
concat-map@0.0.1: concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@@ -1631,6 +1646,13 @@ packages:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
speakingurl@14.0.1: speakingurl@14.0.1:
resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -1672,6 +1694,11 @@ packages:
symbol-tree@3.2.4: symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
terser@5.46.2:
resolution: {integrity: sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==}
engines: {node: '>=10'}
hasBin: true
text-table@0.2.0: text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
@@ -2138,8 +2165,18 @@ snapshots:
wrap-ansi: 8.1.0 wrap-ansi: 8.1.0
wrap-ansi-cjs: wrap-ansi@7.0.0 wrap-ansi-cjs: wrap-ansi@7.0.0
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/source-map@0.3.11':
dependencies:
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/sourcemap-codec@1.5.5': {}
'@jridgewell/trace-mapping@0.3.31': '@jridgewell/trace-mapping@0.3.31':
@@ -2366,10 +2403,10 @@ snapshots:
'@ungap/structured-clone@1.3.0': {} '@ungap/structured-clone@1.3.0': {}
'@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@20.19.37))(vue@3.5.30(typescript@5.9.3))': '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@20.19.37)(terser@5.46.2))(vue@3.5.30(typescript@5.9.3))':
dependencies: dependencies:
'@rolldown/pluginutils': 1.0.0-rc.2 '@rolldown/pluginutils': 1.0.0-rc.2
vite: 7.3.1(@types/node@20.19.37) vite: 7.3.1(@types/node@20.19.37)(terser@5.46.2)
vue: 3.5.30(typescript@5.9.3) vue: 3.5.30(typescript@5.9.3)
'@vitest/coverage-v8@4.1.2(vitest@4.1.0)': '@vitest/coverage-v8@4.1.2(vitest@4.1.0)':
@@ -2384,7 +2421,7 @@ snapshots:
obug: 2.1.1 obug: 2.1.1
std-env: 4.0.0 std-env: 4.0.0
tinyrainbow: 3.1.0 tinyrainbow: 3.1.0
vitest: 4.1.0(@types/node@20.19.37)(@vitest/ui@4.1.0)(jsdom@27.4.0)(vite@7.3.1(@types/node@20.19.37)) vitest: 4.1.0(@types/node@20.19.37)(@vitest/ui@4.1.0)(jsdom@27.4.0)(vite@7.3.1(@types/node@20.19.37)(terser@5.46.2))
'@vitest/expect@4.1.0': '@vitest/expect@4.1.0':
dependencies: dependencies:
@@ -2395,13 +2432,13 @@ snapshots:
chai: 6.2.2 chai: 6.2.2
tinyrainbow: 3.1.0 tinyrainbow: 3.1.0
'@vitest/mocker@4.1.0(vite@7.3.1(@types/node@20.19.37))': '@vitest/mocker@4.1.0(vite@7.3.1(@types/node@20.19.37)(terser@5.46.2))':
dependencies: dependencies:
'@vitest/spy': 4.1.0 '@vitest/spy': 4.1.0
estree-walker: 3.0.3 estree-walker: 3.0.3
magic-string: 0.30.21 magic-string: 0.30.21
optionalDependencies: optionalDependencies:
vite: 7.3.1(@types/node@20.19.37) vite: 7.3.1(@types/node@20.19.37)(terser@5.46.2)
'@vitest/pretty-format@4.1.0': '@vitest/pretty-format@4.1.0':
dependencies: dependencies:
@@ -2434,7 +2471,7 @@ snapshots:
sirv: 3.0.2 sirv: 3.0.2
tinyglobby: 0.2.15 tinyglobby: 0.2.15
tinyrainbow: 3.1.0 tinyrainbow: 3.1.0
vitest: 4.1.0(@types/node@20.19.37)(@vitest/ui@4.1.0)(jsdom@27.4.0)(vite@7.3.1(@types/node@20.19.37)) vitest: 4.1.0(@types/node@20.19.37)(@vitest/ui@4.1.0)(jsdom@27.4.0)(vite@7.3.1(@types/node@20.19.37)(terser@5.46.2))
'@vitest/utils@4.1.0': '@vitest/utils@4.1.0':
dependencies: dependencies:
@@ -2642,6 +2679,8 @@ snapshots:
dependencies: dependencies:
fill-range: 7.1.1 fill-range: 7.1.1
buffer-from@1.1.2: {}
call-bind-apply-helpers@1.0.2: call-bind-apply-helpers@1.0.2:
dependencies: dependencies:
es-errors: 1.3.0 es-errors: 1.3.0
@@ -2668,6 +2707,8 @@ snapshots:
commander@10.0.1: {} commander@10.0.1: {}
commander@2.20.3: {}
concat-map@0.0.1: {} concat-map@0.0.1: {}
config-chain@1.1.13: config-chain@1.1.13:
@@ -3456,6 +3497,13 @@ snapshots:
source-map-js@1.2.1: {} source-map-js@1.2.1: {}
source-map-support@0.5.21:
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
source-map@0.6.1: {}
speakingurl@14.0.1: {} speakingurl@14.0.1: {}
stackback@0.0.2: {} stackback@0.0.2: {}
@@ -3494,6 +3542,13 @@ snapshots:
symbol-tree@3.2.4: {} symbol-tree@3.2.4: {}
terser@5.46.2:
dependencies:
'@jridgewell/source-map': 0.3.11
acorn: 8.16.0
commander: 2.20.3
source-map-support: 0.5.21
text-table@0.2.0: {} text-table@0.2.0: {}
tinybench@2.9.0: {} tinybench@2.9.0: {}
@@ -3547,7 +3602,7 @@ snapshots:
util-deprecate@1.0.2: {} util-deprecate@1.0.2: {}
vite@7.3.1(@types/node@20.19.37): vite@7.3.1(@types/node@20.19.37)(terser@5.46.2):
dependencies: dependencies:
esbuild: 0.27.4 esbuild: 0.27.4
fdir: 6.5.0(picomatch@4.0.3) fdir: 6.5.0(picomatch@4.0.3)
@@ -3558,11 +3613,12 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/node': 20.19.37 '@types/node': 20.19.37
fsevents: 2.3.3 fsevents: 2.3.3
terser: 5.46.2
vitest@4.1.0(@types/node@20.19.37)(@vitest/ui@4.1.0)(jsdom@27.4.0)(vite@7.3.1(@types/node@20.19.37)): vitest@4.1.0(@types/node@20.19.37)(@vitest/ui@4.1.0)(jsdom@27.4.0)(vite@7.3.1(@types/node@20.19.37)(terser@5.46.2)):
dependencies: dependencies:
'@vitest/expect': 4.1.0 '@vitest/expect': 4.1.0
'@vitest/mocker': 4.1.0(vite@7.3.1(@types/node@20.19.37)) '@vitest/mocker': 4.1.0(vite@7.3.1(@types/node@20.19.37)(terser@5.46.2))
'@vitest/pretty-format': 4.1.0 '@vitest/pretty-format': 4.1.0
'@vitest/runner': 4.1.0 '@vitest/runner': 4.1.0
'@vitest/snapshot': 4.1.0 '@vitest/snapshot': 4.1.0
@@ -3579,7 +3635,7 @@ snapshots:
tinyexec: 1.0.2 tinyexec: 1.0.2
tinyglobby: 0.2.15 tinyglobby: 0.2.15
tinyrainbow: 3.1.0 tinyrainbow: 3.1.0
vite: 7.3.1(@types/node@20.19.37) vite: 7.3.1(@types/node@20.19.37)(terser@5.46.2)
why-is-node-running: 2.3.0 why-is-node-running: 2.3.0
optionalDependencies: optionalDependencies:
'@types/node': 20.19.37 '@types/node': 20.19.37
@@ -5,7 +5,7 @@ import MenuItem from '@/components/MenuItem.vue'
describe('MenuItem 组件', () => { describe('MenuItem 组件', () => {
it('应该正确接收菜单项 props', () => { it('应该正确接收菜单项 props', () => {
const menu = { const menu = {
id: 1, id: '1',
name: '仪表盘', name: '仪表盘',
path: '/dashboard', path: '/dashboard',
icon: 'Odometer', icon: 'Odometer',
@@ -34,14 +34,14 @@ describe('MenuItem 组件', () => {
it('应该正确处理有子菜单的菜单项', () => { it('应该正确处理有子菜单的菜单项', () => {
const menu = { const menu = {
id: 2, id: '2',
name: '系统管理', name: '系统管理',
path: '/system', path: '/system',
icon: 'Setting', icon: 'Setting',
sort: 2, sort: 2,
children: [ children: [
{ {
id: 3, id: '3',
name: '用户管理', name: '用户管理',
path: '/users', path: '/users',
sort: 1 sort: 1
@@ -26,7 +26,7 @@ describe('Permission Store', () => {
permissions: ['user:read', 'user:delete'], permissions: ['user:read', 'user:delete'],
menus: [ menus: [
{ {
id: 1, id: '1',
name: '仪表盘', name: '仪表盘',
path: '/dashboard', path: '/dashboard',
icon: 'Odometer', icon: 'Odometer',
@@ -118,7 +118,7 @@ describe('Permission Store', () => {
permissions: ['user:read'], permissions: ['user:read'],
menus: [ menus: [
{ {
id: 1, id: '1',
name: '仪表盘', name: '仪表盘',
path: '/dashboard', path: '/dashboard',
sort: 1 sort: 1
@@ -1,5 +1,3 @@
import { usePermissionStore } from '@/stores/permission'
export interface PermissionMapping { export interface PermissionMapping {
[key: string]: string | string[] [key: string]: string | string[]
} }
+1 -1
View File
@@ -27,7 +27,7 @@ export function generateSignature(
export function generateSignatureHeaders( export function generateSignatureHeaders(
method: string, method: string,
url: string, url: string,
body?: any _body?: any
): SignatureHeaders { ): SignatureHeaders {
const timestamp = Date.now() const timestamp = Date.now()
const nonce = generateNonce() const nonce = generateNonce()
@@ -246,7 +246,7 @@ const sortInfo = reactive({
const modalVisible = ref(false) const modalVisible = ref(false)
const modalTitle = ref('') const modalTitle = ref('')
const formRef = ref() const formRef = ref()
const formState = reactive<CreateUserRequest & { id?: number; status?: UserStatus }>({ const formState = reactive<CreateUserRequest & { id?: string; status?: UserStatus }>({
username: '', username: '',
password: '', password: '',
nickname: '', nickname: '',
@@ -414,7 +414,7 @@ const handleAssignRoles = async (row: User) => {
try { try {
const roles = await roleApi.getAll() const roles = await roleApi.getAll()
allRoles.value = roles.map((role: Role) => ({ allRoles.value = roles.map((role: Role) => ({
key: role.id, key: String(role.id),
label: role.roleName label: role.roleName
})) }))
selectedRoles.value = row.roles || [] selectedRoles.value = row.roles || []