From 51397fda0c6401fc889e41bfa15f08d7c1d0d098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 14:49:48 +0800 Subject: [PATCH 001/142] =?UTF-8?q?chore:=20=E8=A7=A6=E5=8F=91CI/CD?= =?UTF-8?q?=E9=87=8D=E6=96=B0=E9=83=A8=E7=BD=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -- 2.52.0 From 92b702776bc26a5204c4af95288488c6859b37f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 16:05:06 +0800 Subject: [PATCH 002/142] =?UTF-8?q?feat(ci):=20=E4=BC=98=E5=8C=96CI/CD?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=EF=BC=8C=E6=94=AF=E6=8C=81feature->dev->rele?= =?UTF-8?q?ase->main=E5=AE=8C=E6=95=B4=E8=87=AA=E5=8A=A8=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增feature/**分支支持:Lint + TypeCheck + Unit Test + Smoke E2E - 新增dev分支支持:完整测试套件(不部署) - 优化release/**分支触发条件 - 修复归档逻辑,支持动态分支名称 - 完善测试策略分层 - 增强部署安全机制 --- .woodpecker.yml | 83 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index fcdfab1..6e96801 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -1,20 +1,36 @@ # ============================================ # Novalon Website - 全自动CI/CD工作流 # ============================================ -# 发布策略:release分支发布 + main分支归档 +# 发布策略:feature -> dev -> release -> main # -# 分支角色: -# - feature分支:开发新功能 -# - release分支:生产环境代码,合并后自动部署 -# - main分支:稳定代码归档,只读 +# 分支角色与流程: +# 1. feature/** 分支:开发新功能 +# - 触发:PR和push +# - 执行:Lint + TypeCheck + Smoke Test +# - 合并到:dev分支 +# +# 2. dev 分支:开发集成 +# - 触发:push +# - 执行:完整测试套件(不部署) +# - 创建/合并到:release/**分支 +# +# 3. release/** 分支:生产环境代码 +# - 触发:push +# - 执行:完整测试 + 构建 + 部署 + 归档 +# - 部署到:生产环境(139.155.109.62) +# - 归档到:main分支 +# +# 4. main 分支:稳定代码归档 +# - 只读分支 +# - 仅接收来自release的自动归档 # # 流水线阶段: # 1. 代码质量检查 (lint, type-check, security) # 2. 单元测试和集成测试 # 3. E2E测试 (分层测试) -# 4. 构建Docker镜像 -# 5. 部署到生产环境 (release分支) -# 6. 归档到main分支 +# 4. 构建Docker镜像 (仅release分支) +# 5. 部署到生产环境 (仅release分支) +# 6. 归档到main分支 (仅release分支) # 7. 通知和监控 # ============================================ @@ -27,7 +43,6 @@ variables: # 阶段1: 代码质量检查 # ============================================ steps: - # 1.1 Lint检查 lint: image: *node_image environment: @@ -39,8 +54,12 @@ steps: event: - push - pull_request + branch: + - feature/** + - dev + - release + - release/** - # 1.2 类型检查 type-check: image: *node_image environment: @@ -52,8 +71,12 @@ steps: event: - push - pull_request + branch: + - feature/** + - dev + - release + - release/** - # 1.3 安全漏洞扫描 security-scan: image: *node_image environment: @@ -65,11 +88,13 @@ steps: event: - push - pull_request + branch: + - feature/** + - dev + - release + - release/** failure: ignore - # ============================================ - # 阶段2: 单元测试和集成测试 - # ============================================ unit-tests: image: *node_image environment: @@ -82,11 +107,15 @@ steps: event: - push - pull_request + branch: + - feature/** + - dev + - release + - release/** # ============================================ # 阶段3: E2E测试 (分层测试) # ============================================ - # 3.1 Smoke测试 (PR快速验证) e2e-smoke: image: mcr.microsoft.com/playwright:v1.48.0-jammy environment: @@ -99,9 +128,11 @@ steps: - npm run test:smoke when: event: + - push - pull_request + branch: + - feature/** - # 3.2 标准测试 (release分支) e2e-standard: image: mcr.microsoft.com/playwright:v1.48.0-jammy environment: @@ -116,10 +147,10 @@ steps: event: - push branch: + - dev - release - release/** - # 3.3 深度测试 (release分支) e2e-deep: image: mcr.microsoft.com/playwright:v1.48.0-jammy environment: @@ -137,7 +168,6 @@ steps: - release - release/** - # 3.4 性能测试 (release分支) e2e-performance: image: mcr.microsoft.com/playwright:v1.48.0-jammy environment: @@ -155,7 +185,6 @@ steps: - release - release/** - # 3.5 可访问性测试 (release分支) e2e-accessibility: image: mcr.microsoft.com/playwright:v1.48.0-jammy environment: @@ -173,7 +202,6 @@ steps: - release - release/** - # 3.6 视觉回归测试 (release分支) e2e-visual: image: mcr.microsoft.com/playwright:v1.48.0-jammy environment: @@ -336,22 +364,21 @@ steps: git config --global user.email "ci@novalon.cn" git config --global user.name "Woodpecker CI" - # 使用SSH而不是HTTPS+Token git remote set-url origin git@git.f.novalon.cn:novalon/novalon-website.git - # 拉取最新代码 git fetch origin + + CURRENT_BRANCH="${CI_COMMIT_BRANCH}" + echo "Current branch: $CURRENT_BRANCH" + git checkout main git pull origin main - # 合并release分支 - git merge release --no-ff -m "chore: 归档release ${CI_COMMIT_SHA:0:7}" + git merge "$CURRENT_BRANCH" --no-ff -m "chore: 归档${CURRENT_BRANCH} ${CI_COMMIT_SHA:0:7}" - # 创建版本标签 VERSION_TAG="v$(date +%Y.%m.%d)-${CI_COMMIT_SHA:0:7}" - git tag -a "$VERSION_TAG" -m "Release $(date +%Y-%m-%d)" + git tag -a "$VERSION_TAG" -m "Release $(date +%Y-%m-%d) from ${CURRENT_BRANCH}" - # 推送到远程(带重试) for i in {1..3}; do if git push origin main && git push origin --tags; then echo "✅ Archive succeeded! Version: $VERSION_TAG" @@ -363,7 +390,7 @@ steps: echo "⚠️ Archive failed, but deployment succeeded" echo "Manual archive may be needed" - exit 0 # 不阻止部署成功 + exit 0 when: event: - push -- 2.52.0 From 82534303ecbf555b305d0451b616bd8e267c4fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 16:22:48 +0800 Subject: [PATCH 003/142] =?UTF-8?q?fix(ci):=20=E4=BF=AE=E5=A4=8DDocker?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E9=85=8D=E7=BD=AE=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 volumes 挂载,避免与 DinD 服务冲突 - 统一使用 Docker-in-Docker 服务进行构建 - 解决 /proc/net/ip6_tables_names 错误 --- .woodpecker.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 6e96801..17d9b06 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -238,8 +238,6 @@ steps: - docker push registry.f.novalon.cn/novalon-website:${CI_COMMIT_SHA} - docker push registry.f.novalon.cn/novalon-website:latest - docker push registry.f.novalon.cn/novalon-website:release-${CI_COMMIT_SHA:0:7} - volumes: - - /var/run/docker.sock:/var/run/docker.sock when: - event: push branch: -- 2.52.0 From 159f2ce148b6578400cc86f7e60b4fc72406aa11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 16:27:52 +0800 Subject: [PATCH 004/142] =?UTF-8?q?refactor(ci):=20=E9=87=87=E7=94=A8?= =?UTF-8?q?=E8=BD=BB=E9=87=8F=E7=BA=A7Docker=E6=9E=84=E5=BB=BA=E6=96=B9?= =?UTF-8?q?=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 Docker-in-Docker 服务 - 使用宿主机 Docker socket 挂载 - 移除 DOCKER_HOST 环境变量 - 简化配置,提高性能和稳定性 --- .woodpecker.yml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 17d9b06..31eda2b 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -225,7 +225,6 @@ steps: build-image: image: *docker_image environment: - DOCKER_HOST: tcp://docker:2375 REGISTRY_PASSWORD: from_secret: registry_password commands: @@ -238,6 +237,8 @@ steps: - docker push registry.f.novalon.cn/novalon-website:${CI_COMMIT_SHA} - docker push registry.f.novalon.cn/novalon-website:latest - docker push registry.f.novalon.cn/novalon-website:release-${CI_COMMIT_SHA:0:7} + volumes: + - /var/run/docker.sock:/var/run/docker.sock when: - event: push branch: @@ -398,16 +399,6 @@ steps: status: - success -# ============================================ -# 服务配置 -# ============================================ -services: - docker: - image: docker:24-dind - privileged: true - environment: - DOCKER_TLS_CERTDIR: "" - # ============================================ # 工作区配置 # ============================================ -- 2.52.0 From 3eca3b4478102559aca2e08faca5367d38b3e810 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 16:33:58 +0800 Subject: [PATCH 005/142] =?UTF-8?q?test:=20=E9=AA=8C=E8=AF=81=20webhook=20?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A7=A6=E5=8F=91=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2b2f568..6f92c6c 100644 --- a/README.md +++ b/README.md @@ -703,3 +703,4 @@ NEXT_PUBLIC_SITE_URL=https://novalon.cn ## 许可证 Copyright © 2026 四川睿新致远科技有限公司 +# Webhook test 2026年 3月28日 星期六 16时33分58秒 CST -- 2.52.0 From b886050e71abc34efad0d4c0b423dce23bfaa59f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 16:37:00 +0800 Subject: [PATCH 006/142] =?UTF-8?q?test:=20=E9=AA=8C=E8=AF=81CI=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=A7=A6=E5=8F=91=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6f92c6c..6717154 100644 --- a/README.md +++ b/README.md @@ -704,3 +704,4 @@ NEXT_PUBLIC_SITE_URL=https://novalon.cn Copyright © 2026 四川睿新致远科技有限公司 # Webhook test 2026年 3月28日 星期六 16时33分58秒 CST +# Auto trigger test 16:37:00 -- 2.52.0 From 2fdde39d87e0d78e5d8278f1217cee0d81e03afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 16:47:05 +0800 Subject: [PATCH 007/142] =?UTF-8?q?test:=20=E8=A7=A6=E5=8F=91webhook?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .woodpecker.yml | 9 +++++---- README.md | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.woodpecker.yml b/.woodpecker.yml index 31eda2b..10053cd 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -240,10 +240,11 @@ steps: volumes: - /var/run/docker.sock:/var/run/docker.sock when: - - event: push - branch: - - release - - release/** + event: + - push + branch: + - release + - release/** # ============================================ # 阶段5: 部署到生产环境 (release分支) diff --git a/README.md b/README.md index 6717154..317a27e 100644 --- a/README.md +++ b/README.md @@ -705,3 +705,4 @@ NEXT_PUBLIC_SITE_URL=https://novalon.cn Copyright © 2026 四川睿新致远科技有限公司 # Webhook test 2026年 3月28日 星期六 16时33分58秒 CST # Auto trigger test 16:37:00 +# Webhook test 16:47:05 -- 2.52.0 From 0bc36ca815be1b16a164e0982b44d95bcccef71b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 16:56:11 +0800 Subject: [PATCH 008/142] =?UTF-8?q?test:=20=E9=AA=8C=E8=AF=81Nginx?= =?UTF-8?q?=E5=8F=8D=E5=90=91=E4=BB=A3=E7=90=86=E4=BF=AE=E5=A4=8D=E5=90=8E?= =?UTF-8?q?webhook=E6=98=AF=E5=90=A6=E5=B7=A5=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 317a27e..1d145ea 100644 --- a/README.md +++ b/README.md @@ -706,3 +706,4 @@ Copyright © 2026 四川睿新致远科技有限公司 # Webhook test 2026年 3月28日 星期六 16时33分58秒 CST # Auto trigger test 16:37:00 # Webhook test 16:47:05 +# Test webhook after nginx fix 16:56:11 -- 2.52.0 From 83de0fa3bdcbc69e0923f6b99d77531b53fead6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 16:59:24 +0800 Subject: [PATCH 009/142] =?UTF-8?q?test:=20=E9=AA=8C=E8=AF=81debug?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E7=BA=A7=E5=88=AB=E7=9A=84webhook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1d145ea..43c4754 100644 --- a/README.md +++ b/README.md @@ -707,3 +707,4 @@ Copyright © 2026 四川睿新致远科技有限公司 # Auto trigger test 16:37:00 # Webhook test 16:47:05 # Test webhook after nginx fix 16:56:11 +# Test with debug logging 16:59:24 -- 2.52.0 From 91780e66a09765afb50cbe697d02d802a18f27fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 17:01:05 +0800 Subject: [PATCH 010/142] =?UTF-8?q?test:=20=E6=9C=80=E7=BB=88=E9=AA=8C?= =?UTF-8?q?=E8=AF=81webhook=E8=87=AA=E5=8A=A8=E8=A7=A6=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 43c4754..63c3d61 100644 --- a/README.md +++ b/README.md @@ -708,3 +708,4 @@ Copyright © 2026 四川睿新致远科技有限公司 # Webhook test 16:47:05 # Test webhook after nginx fix 16:56:11 # Test with debug logging 16:59:24 +# Final test after header fix 17:01:05 -- 2.52.0 From 4b80f590d19852cf33bbbdd907ddde2cceee1606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 17:14:00 +0800 Subject: [PATCH 011/142] =?UTF-8?q?test:=20=E9=AA=8C=E8=AF=81Gitea=20forge?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=90=8Ewebhook=E8=87=AA=E5=8A=A8=E8=A7=A6?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 63c3d61..df0cd72 100644 --- a/README.md +++ b/README.md @@ -709,3 +709,4 @@ Copyright © 2026 四川睿新致远科技有限公司 # Test webhook after nginx fix 16:56:11 # Test with debug logging 16:59:24 # Final test after header fix 17:01:05 +# Test after Gitea forge fix 17:14:00 -- 2.52.0 From cba3cb5bc6a6d8c52d92cd74578064fcf19c098a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 17:23:42 +0800 Subject: [PATCH 012/142] =?UTF-8?q?test:=20=E6=9C=80=E7=BB=88=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=AE=8C=E6=95=B4CI/CD=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index df0cd72..1bafd0c 100644 --- a/README.md +++ b/README.md @@ -710,3 +710,4 @@ Copyright © 2026 四川睿新致远科技有限公司 # Test with debug logging 16:59:24 # Final test after header fix 17:01:05 # Test after Gitea forge fix 17:14:00 +# Final test with all fixes 17:23:42 -- 2.52.0 From 96e57b19eef953db344f5ac21af25569d9fc514b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 17:25:14 +0800 Subject: [PATCH 013/142] =?UTF-8?q?test:=20=E5=AE=8C=E6=95=B4CI/CD?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E9=AA=8C=E8=AF=81=EF=BC=88=E6=89=80=E6=9C=89?= =?UTF-8?q?secrets=E5=B7=B2=E9=85=8D=E7=BD=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1bafd0c..b87bb4e 100644 --- a/README.md +++ b/README.md @@ -711,3 +711,4 @@ Copyright © 2026 四川睿新致远科技有限公司 # Final test after header fix 17:01:05 # Test after Gitea forge fix 17:14:00 # Final test with all fixes 17:23:42 +# Complete CI/CD test 17:25:14 -- 2.52.0 From b71d6aa1d18c492b6f48320e9b58f44bca2fce9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Sat, 28 Mar 2026 17:45:30 +0800 Subject: [PATCH 014/142] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DTypeScript?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E9=94=99=E8=AF=AF=E5=B9=B6=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 useEffect 返回值类型错误 (TS7030) - 修复未使用的 catch 变量错误 - 排除测试文件的类型检查以减少误报 - 添加企业微信通知功能,支持成功/失败状态推送 - 优化通知格式,包含项目信息、提交信息和构建详情链接 --- .woodpecker.yml | 55 +++- src/app/admin/settings/page.tsx | 449 ++++++++++++++++++++++---------- tsconfig.json | 6 +- tsconfig.test.json | 17 ++ 4 files changed, 389 insertions(+), 138 deletions(-) create mode 100644 tsconfig.test.json diff --git a/.woodpecker.yml b/.woodpecker.yml index 10053cd..0401ba9 100644 --- a/.woodpecker.yml +++ b/.woodpecker.yml @@ -240,11 +240,10 @@ steps: volumes: - /var/run/docker.sock:/var/run/docker.sock when: - event: - - push - branch: - - release - - release/** + - event: push + branch: + - release + - release/** # ============================================ # 阶段5: 部署到生产环境 (release分支) @@ -400,6 +399,52 @@ steps: status: - success + # ============================================ + # 阶段7: 企业微信通知 + # ============================================ + notify-wechat: + image: alpine:latest + environment: + WECHAT_WEBHOOK: + from_secret: wechat_webhook + commands: + - echo "Sending notification to WeChat Work..." + - apk add --no-cache curl + - | + STATUS="${CI_PIPELINE_STATUS}" + BRANCH="${CI_COMMIT_BRANCH}" + COMMIT="${CI_COMMIT_SHA:0:7}" + MESSAGE="${CI_COMMIT_MESSAGE}" + AUTHOR="${CI_COMMIT_AUTHOR}" + PIPELINE_NUMBER="${CI_PIPELINE_NUMBER}" + PIPELINE_URL="https://ci.f.novalon.cn/repos/${CI_REPO_ID}/pipeline/${PIPELINE_NUMBER}" + + if [ "$STATUS" = "success" ]; then + STATUS_TEXT="成功" + STATUS_COLOR="info" + else + STATUS_TEXT="失败" + STATUS_COLOR="warning" + fi + + curl -X POST "$WECHAT_WEBHOOK" \ + -H 'Content-Type: application/json' \ + -d '{ + "msgtype": "markdown", + "markdown": { + "content": "'"## 🚀 Novalon Website 部署通知\n\n> **构建状态**: '"${STATUS_TEXT}"'\n\n**项目信息**\n> 分支: `'"${BRANCH}"'`\n> 提交: `'"${COMMIT}"'`\n> 作者: '"${AUTHOR}"'\n\n**提交信息**\n> '"${MESSAGE}"'\n\n**操作**\n> [查看构建详情]('"${PIPELINE_URL}"')\n\n---\n> 时间: $(date "+%Y-%m-%d %H:%M:%S")\n> Pipeline #${PIPELINE_NUMBER}"'" + } + }' + when: + event: + - push + branch: + - release + - release/** + status: + - success + - failure + # ============================================ # 工作区配置 # ============================================ diff --git a/src/app/admin/settings/page.tsx b/src/app/admin/settings/page.tsx index 731eb2b..ce7e95d 100644 --- a/src/app/admin/settings/page.tsx +++ b/src/app/admin/settings/page.tsx @@ -1,12 +1,18 @@ 'use client'; import { useState, useEffect } from 'react'; -import { - Save, +import { + Save, RefreshCw, Loader2, ChevronDown, - ChevronUp + Settings2, + Palette, + Globe, + SlidersHorizontal, + Check, + X, + AlertCircle, } from 'lucide-react'; interface ConfigItem { @@ -18,31 +24,69 @@ interface ConfigItem { updatedAt: string; } -const categoryLabels = { - feature: '功能配置', - style: '样式配置', - seo: 'SEO 配置', - general: '常规配置' -}; - -const categoryColors = { - feature: 'bg-blue-100 text-blue-800', - style: 'bg-purple-100 text-purple-800', - seo: 'bg-green-100 text-green-800', - general: 'bg-gray-100 text-gray-800' +const categoryConfig = { + feature: { + label: '功能配置', + description: '控制网站各功能模块的启用与参数', + icon: SlidersHorizontal, + color: 'from-blue-500 to-cyan-500', + bgColor: 'bg-blue-50', + borderColor: 'border-blue-200', + textColor: 'text-blue-700', + iconBg: 'bg-blue-100', + }, + style: { + label: '样式配置', + description: '自定义网站视觉风格和主题色彩', + icon: Palette, + color: 'from-purple-500 to-pink-500', + bgColor: 'bg-purple-50', + borderColor: 'border-purple-200', + textColor: 'text-purple-700', + iconBg: 'bg-purple-100', + }, + seo: { + label: 'SEO 配置', + description: '搜索引擎优化和元数据设置', + icon: Globe, + color: 'from-emerald-500 to-teal-500', + bgColor: 'bg-emerald-50', + borderColor: 'border-emerald-200', + textColor: 'text-emerald-700', + iconBg: 'bg-emerald-100', + }, + general: { + label: '常规配置', + description: '网站基本信息和通用设置', + icon: Settings2, + color: 'from-amber-500 to-orange-500', + bgColor: 'bg-amber-50', + borderColor: 'border-amber-200', + textColor: 'text-amber-700', + iconBg: 'bg-amber-100', + }, }; export default function SettingsPage() { const [configs, setConfigs] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(null); - const [expandedCategories, setExpandedCategories] = useState>(new Set(['feature', 'seo'])); + const [expandedCategories, setExpandedCategories] = useState>(new Set(['feature'])); const [editedValues, setEditedValues] = useState>>({}); + const [saveSuccess, setSaveSuccess] = useState(null); useEffect(() => { fetchConfigs(); }, []); + useEffect(() => { + if (saveSuccess) { + const timer = setTimeout(() => setSaveSuccess(null), 3000); + return () => clearTimeout(timer); + } + return undefined; + }, [saveSuccess]); + const fetchConfigs = async () => { try { setLoading(true); @@ -60,7 +104,7 @@ export default function SettingsPage() { const handleSave = async (configId: string) => { const editedValue = editedValues[configId]; - if (!editedValue) return; + if (!editedValue) {return;} try { setSaving(configId); @@ -79,6 +123,7 @@ export default function SettingsPage() { delete updated[configId]; return updated; }); + setSaveSuccess(configId); await fetchConfigs(); } } catch (error) { @@ -88,6 +133,14 @@ export default function SettingsPage() { } }; + const handleCancel = (configId: string) => { + setEditedValues(prev => { + const updated = { ...prev }; + delete updated[configId]; + return updated; + }); + }; + const toggleCategory = (category: string) => { setExpandedCategories(prev => { const updated = new Set(prev); @@ -129,149 +182,281 @@ export default function SettingsPage() { return acc; }, {} as Record); + const getFieldLabel = (field: string) => { + const labels: Record = { + enabled: '启用状态', + displayCount: '显示数量', + categories: '分类列表', + sortOrder: '排序方式', + showPricing: '显示价格', + featuredProducts: '推荐产品', + items: '项目列表', + title: '标题', + description: '描述', + keywords: '关键词', + }; + return labels[field] || field; + }; + + const renderFieldInput = (configItem: ConfigItem, field: string, value: any) => { + const currentValue = getConfigValue(configItem, field); + + if (typeof value === 'boolean') { + return ( +