Files
aiops/docs/dev-log.md
T

318 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# EZOps AIOps 开发日志
## 2026-06-13 项目初始化
### 完成项
| 项目 | 状态 | 说明 |
|------|------|------|
| 前端 (React+TS+Vite) | ✅ | React 18 + TypeScript + Tailwind CSS + shadcn/ui |
| 后端 (Go+Gin+GORM) | ✅ | Go + Gin + GORM + JWT + SQLite |
| 数据库 (SQLite) | ✅ | sqlite3.db,CGO 编译 |
| run.sh 启动脚本 | ✅ | 一键 start/stop/restart/status/logs |
| Vite Proxy | ✅ | /api → localhost:8080 |
| docs 文档 | ✅ | 项目结构/API/部署/开发指南 |
### 编译修复记录
| 文件 | 问题 | 修复 |
|------|------|------|
| `auth.go` | jwt/v5 移除了 `TimeFunc()` | 改用 `time.Now()` |
| `mock.go` | 匹配实际 model 定义 | 完全重写 |
| `audit.go` | 编译错误 | 修复字段引用 |
| `database.go` | 不支持 SQLite | 添加 `gorm.io/driver/sqlite` |
| `config.go` | DSN 中 Port 类型转换错误 | 在 database.go 用 `fmt.Sprintf("%d", port)` |
### 技术栈
**后端**
- Go 1.21+ / Gin / GORM
- SQLite (开发环境默认) / MySQL / PostgreSQL (生产可选)
- JWT 认证 / Zap 日志
**前端**
- React 18 + TypeScript + Vite
- Tailwind CSS + shadcn/ui 组件库
- Zustand 状态管理
### 端口分配
| 服务 | 端口 |
|------|------|
| 后端 API | 8080 |
| 前端 Dev Server | 5173 |
### 快速启动
```bash
cd ~/devops/aiops
./run.sh start # 启动前后端
./run.sh status # 查看状态
./run.sh stop # 停止
./run.sh restart # 重启
./run.sh logs # 实时日志
```
访问地址:
- 前端: http://localhost:5173
- 后端: http://localhost:8080
- 健康检查: http://localhost:8080/health
### 数据库
开发环境使用 SQLite,数据库文件位于 `backend/sqlite3.db`,首次启动时 GORM AutoMigrate 自动建表。
## 2026-06-14 02:30 自动推进
- **任务**: 修复仪表盘数据管线 — 补充应用发布种子数据 + 修复 limit 参数解析 bug + LDAP 认证集成 + User 类型完善
- **修改**:
- `backend/internal/api/handlers/dashboard.go` — 修复 GetRecentAlerts 的 limit 参数解析(原代码错误地将数字 limit 解析为日期字符串 `time.Parse("2006-01-02")`),为 GetRecentReleases 添加 limit 参数支持
- `backend/scripts/mock.go` — 新增 generateAppReleases() 生成 10 条应用发布种子数据;修复 AlertEvent 的 rule_id/rule_name/severity 数据一致性(原代码从不同随机规则分别取 id 和 name 导致不匹配)
- `backend/go.mod` / `go.sum` — 添加 github.com/go-ldap/ldap/v3 v3.4.10 依赖(GOTOOLCHAIN=local 避免 Go 1.24+ 工具链升级)
- `backend/cmd/seed.go` — 种子数据初始化(admin 用户 + LDAP 配置,仅首次启动)
- `backend/internal/api/handlers/ldap.go` — LDAP 认证处理器
- `backend/internal/models/user.go` — User model 添加 AuthSource 字段 + LDAPConfig model
- `frontend/src/types/index.ts` — 修复 User 类型定义,添加 real_name/is_admin/auth_source 等字段以匹配后端 API
- 多个前端组件联调优化(暗色主题、API 服务层、组件数据对接)
- **结果**:
- `go build ./...` 编译通过 ✅
- `npm run build` 构建通过 ✅
- 仪表盘「发布历史」区域从空白变为展示 5 条真实发布记录 ✅
- `?limit=N` 参数现在被正确解析 ✅
- 健康检查 /health 正常 ✅
- git push origin master 成功 (commit ff0b268) ✅
- **下一步建议**:
- 服务器管理模块的增删改查前后端联调验证
- K8s 集群监控数据展示(Pod/Deployment/Service 列表页面)
- 告警规则配置页面前端完善
- 成本统计从硬编码改为基于实际云账号数据计算
## 2026-06-14 03:10 自动推进
- **任务**: 完善告警规则配置页面 — 实现增删改查弹窗 + 修复白屏bug + 后端UpdateRule序列化修复
- **修改**:
- `frontend/src/components/monitor/AlertManager.tsx` — 新建/编辑告警规则弹窗(规则名称/描述/类型/数据源/触发表达式/告警级别/持续时间/通知渠道Switch选择); 修复白屏bug(getRules返回{list,total}未解包导致rules.map崩溃); 修复规则列表字段显示(原引用不存在的rule.metric/operator/threshold改为rule.source/expression); 新增规则删除按钮(带确认); 新增parseChannels()统一解析通知渠道
- `backend/internal/api/handlers/alert.go` — 修复UpdateRule的notify_channels序列化bug(原直接赋值[]string到text列导致500错误,改用toJSON()序列化)
- **结果**:
- `go build ./...` 编译通过 ✅
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- 告警页面白屏修复 — 页面正常加载,展示6条规则/20条告警事件 ✅
- 创建规则弹窗UI验证通过 — 通过浏览器填表提交,规则数从6增至7 ✅
- CRUD API端到端验证: create→update→delete 全部200 ✅
- git push origin master 成功 (commit 00d5510) ✅
- **下一步建议**:
- K8s 集群监控数据展示(Pod/Deployment/Service 列表页面前后端联调)
- 服务器管理模块增删改查前后端联调验证
- 成本统计从硬编码改为基于实际云账号数据计算
- 告警"通知配置"按钮功能实现(通知渠道管理弹窗)
## 2026-06-14 04:00 自动推进
- **任务**: K8s集群监控数据展示 — 修复集群详情标签数据加载(数组响应未解包bug) + 补充Pod/Deployment/Service/Ingress种子数据 + deployment_count字段
- **修改**:
- `frontend/src/components/k8s/K8sClusters.tsx` — **核心bug修复**: loadClusterDetail 中 Promise.all 的 catch fallback 返回 `{list:[]}` 但后端 ListNodes/ListPods/ListDeployments/ListServices/ListIngresses 返回 data 直接为数组(非{list,total}), 导致 `(res)?.list` 永远 undefined → 所有标签页空白; 改用 `toArray(v)` 兼容数组和对象响应; 修复 Pod 表格字段名(restarts→restart_count, cpu→cpu_usage, memory→memory_usage, node→node_name); 修复状态徽章大小写比较(status='Running' vs 'running')
- `backend/internal/models/k8s.go` — K8sCluster model 添加 DeploymentCount 字段(前端引用 cluster.deployment_count 但 model 缺失)
- `backend/scripts/mock.go` — generateK8sClusters 补充生成 Deployment/Pod/Service/Ingress 种子数据(原仅生成 Cluster+Node)
- `backend/scripts/seed_k8s_resources.go` — 新增独立种子脚本, 为已有集群补充 K8s 资源数据(幂等, 跳过已有 Pod 的集群)
- **结果**:
- `go build ./...` 编译通过 ✅
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- 种子数据写入: 4集群 → 20节点 + 80 Pod + 41 Deployment + 29 Service + 14 Ingress ✅
- API 端到端验证: `/k8s-clusters/1/pods` 返回21条Pod数据, 字段名正确(restart_count/node_name等) ✅
- 浏览器验证: 集群卡片显示4集群(含deployment_count), 集群详情标签页计数正确: 节点(10)/Pod(21)/Deployment(6)/Service(8)/Ingress(4) ✅
- 无 console 错误 ✅
- git push origin master 成功 (commit 8d47f8d) ✅
- **下一步建议**:
- 服务器管理模块增删改查前后端联调验证
- 成本统计从硬编码改为基于实际云账号数据计算
- K8s 集群拓扑图(TopologyView)前后端数据联调
- 告警"通知配置"按钮功能实现(通知渠道管理弹窗)
## 2026-06-14 05:15 自动推进
- **任务**: 服务器管理模块前后端字段对齐 — 修复前端表单使用后端不支持的CMDB幽灵字段导致数据丢失 + 内存单位 GB→MB 转换 + 表格列重构
- **修改**:
- `backend/internal/models/server.go` — CreateServerRequest 添加 Status 字段(原硬编码 "stopped")
- `backend/internal/api/handlers/server.go` — CreateServer handler 改用 req.Status 替代硬编码值
- `frontend/src/components/server/ServerManager.tsx` — 完全重写表单/表格/过滤器:
- 移除后端不支持的幽灵字段:asset_type/connect_type/floatingip/instance_id/expire_time/remark/region/region_id
- 表单改为SSH连接导向:主机名/IP/公网IP/SSH端口/登录用户/认证方式(密码/密钥)/密码 + 可折叠详情区(OS/状态/CPU/内存/磁盘/标签/描述)
- 内存字段前端输入GB,提交时 ×1024 转换为MB(后端存储MB)
- 表格列从11列精简到8列,新增公网IP列,移除资产类型/连接方式/区域列
- 移除不存在的区域筛选器(servers 无 region_id 数据)
- 移除未实现的"查看详情"下拉项(无详情页)
- **结果**:
- `go build -o aiops-server cmd/main.go` 编译通过 ✅
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- API端到端验证: POST /servers → Code 200,hostname/ip/public_ip/port/username/auth_type/memory(16384MB=16GB)/status/tags 全部正确保存 ✅
- API端到端验证: PUT /servers/:id → Code 200,更新成功 ✅
- API端到端验证: DELETE /servers/:id → Code 200 "删除成功" ✅
- 浏览器UI验证: 服务器列表页正常渲染,内存显示为GB(128GB而非131072MB),公网IP列正确显示 ✅
- 表单UI验证: 添加服务器弹窗字段正确,验证逻辑正常(hostname+ip必填时按钮启用)✅
- 服务运行中: 后端:8080 + 前端:5173 ✅
## 2026-06-14 06:30 自动推进
- **任务**: 仪表盘成本统计从硬编码改为基于实际云账号月费用计算 — 新增 CloudAccount.MonthlyCost 字段,dashboard 接口实时聚合
- **修改**:
- `backend/internal/models/server.go` — CloudAccount model 新增 `MonthlyCost float64` 字段(AutoMigrate 自动加列)
- `backend/internal/api/handlers/dashboard.go` — 重写成本统计逻辑:查询 cloud_accounts 表,按 provider 聚合 monthly_cost 得到 CloudCosts 饼图数据;month_cost = 各账号月费用之和(真实);month_trend 以本月实际费用为锚向前回推 6 个月(轻微增长趋势),total_cost = 6 个月趋势合计;provider 代码映射为中文名
- `backend/scripts/mock.go` — generateCloudAccounts 种子数据设置 MonthlyCost(阿里云28500/腾讯云15800/AWS42000/华为云8900)
- `frontend/src/components/cloud/CloudAccountManager.tsx` — 云账号卡片「区域数」改为「月费用」展示(¥ 格式,翡翠绿色高亮),移除永远为0的 regionCount
- **结果**:
- `go build -o aiops-server cmd/main.go` 编译通过 ✅
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- API 验证: `/dashboard/stats` cost_stats.month_cost=95200 (=28500+15800+42000+8900 真实求和), cloud_costs 4 条真实平台数据, month_trend 6个月(1月~6月)当前月=95200 ✅
- 已有 DB 4 个账号 backfill monthly_cost(AutoMigrate 加列后 SQL UPDATE)✅
- 浏览器验证: 仪表盘「本月云成本」显示 ¥95,200(真实计算值)✅
- 健康检查 /health 正常 ✅
- **下一步建议**:
- ~~云账号「添加账号」按钮弹窗表单实现(当前点击无响应,无法录入月费用)~~ ✅ 已完成
- K8s 集群拓扑图(TopologyView)前后端数据联调
- 告警「通知配置」按钮功能实现(通知渠道管理弹窗)
- 仪表盘「+12.5%」等增长率标签从硬编码改为基于 month_trend 真实计算
- 云账号「编辑」功能(需后端新增 PUT /cloud-accounts/:id 端点)
## 2026-06-14 07:10 自动推进
- **任务**: 云账号创建表单实现 — 修复后端创建接口无法接收凭证的 bug + 前端添加账号弹窗表单
- **修改**:
- `backend/internal/api/handlers/server.go` — 重构 `CreateCloudAccount`:新增独立的 `createCloudAccountRequest` struct(遵循 Go Pitfall #8)。原代码直接绑定 `models.CloudAccount`,但 AccessKey/SecretKey 字段标记 `json:"-"` 会导致反序列化时被跳过,凭证永远为空。现用独立 request struct 接收后映射到 model;新增 name/provider 非空校验,status 默认 active;补充 `strings` 导入
- `frontend/src/components/cloud/CloudAccountManager.tsx` — 「添加账号」按钮接入创建表单 Dialog(账号名称/云平台/AccessKey/SecretKey/月费用/状态),提交调用 cloudApi.createAccount 后刷新列表;移除无 handler 的刷新/编辑按钮(编辑需后端新增 PUT 端点,留待后续);按钮 disabled 校验(名称必填)
- **结果**:
- `go build ./cmd/` 编译通过 ✅
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- API 验证: POST /cloud-accounts → Code 200,DB 验证 access_key/secret_key 正确持久化(原 bug 下为空字符串)✅
- 联动验证: 新增账号后 dashboard month_cost 实时更新(95200→100200)✅
- 浏览器 UI 验证: 添加账号弹窗正常打开、字段填写、提交后列表刷新显示新账号 ✅
- 服务运行中: 后端:8080 + 前端:5173 ✅
## 2026-06-14 08:15 自动推进
- **任务**: 云账号编辑功能 + 修复 scripts/mock.go 编译错误(generateNotifyChannels 未定义)+ 提交前序未入库的告警通知渠道 CRUD
- **修改**:
- `backend/scripts/mock.go` — **编译错误修复**: 补充缺失的 `generateNotifyChannels` 函数(5种渠道种子:邮件/短信/钉钉/企业微信/Webhook),解决 `go build ./...` 失败
- `backend/internal/api/handlers/server.go` — 新增 `UpdateCloudAccount` handler:查询现有记录→仅在提供非空值时更新凭证字段(AccessKey/SecretKey 留空保持不变)→db.Save
- `backend/internal/api/routes/routes.go` — 注册 `PUT /cloud-accounts/:id` 路由
- `frontend/src/services/api.ts` — cloudApi 新增 `updateAccount(id, data)` 方法
- `frontend/src/components/cloud/CloudAccountManager.tsx` — 编辑功能:添加 editingAccount 状态 + handleOpenEdit 预填表单 + handleSubmit 统一处理创建/编辑 + 卡片新增编辑按钮(Pencil图标) + Dialog 标题/描述/按钮文案动态切换 + AccessKey/SecretKey 标签"留空保持不变"提示
- 包含前序未提交的变更(已验证编译通过):告警通知渠道 CRUD 后端API(alert.go handlers + models)、AlertManager 通知配置前端UI、AlertCenter 通知渠道管理弹窗
- **结果**:
- `go build ./...` 全包编译通过(含 scripts/)✅
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- API 验证: PUT /cloud-accounts/1 → Code 200 "更新成功",monthly_cost 28500→30000 ✅
- 凭证安全验证: 更新请求不含 access_key/secret_key,DB 中原凭证 LTAIDuBzWq... / pQyacN59tQ... 保持不变 ✅
- 浏览器 UI 验证: 编辑弹窗正常打开,4个字段预填正确,标题显示"编辑云账号",凭证字段显示"留空保持不变"提示 ✅
- git push origin master 成功 (commit af2e60a) ✅
- **下一步建议**:
- K8s 集群拓扑图(TopologyView)前后端数据联调
- 仪表盘「+12.5%」等增长率标签从硬编码改为基于 month_trend 真实计算
- 域名管理编辑功能(当前仅有 GET/POST/DELETE,缺 PUT 端点,与云账号编辑同理)
- 告警规则关联通知渠道 — 规则创建时可选择已配置的通知渠道
## 2026-06-14 09:10 自动推进
- **任务**: 域名管理增删改查完整实现 — 新增 PUT /domains/:id 编辑端点 + 创建/编辑弹窗 + 日期字段解析修复
- **修改**:
- `backend/internal/api/handlers/server.go` — 新增 `updateDomainRequest` 请求结构体(日期字段用 string 接收避免 RFC3339 解析失败)+ `parseDateStr()` 工具函数(YYYY-MM-DD → *time.Time)+ `UpdateDomain` handler(查询记录→按字段更新→db.Save);重构 `CreateDomain` 改用 request struct + parseDateStr(原直接绑定 models.Domain 导致 HTML date input 的 YYYY-MM-DD 格式无法解析为 *time.Time,创建含日期的域名报 400)
- `backend/internal/api/routes/routes.go` — 注册 `PUT /domains/:id` 路由
- `frontend/src/services/api.ts` — cloudApi 新增 `updateDomain(id, data)` 方法
- `frontend/src/components/cloud/DomainManager.tsx` — 添加域名弹窗 + 编辑弹窗(域名/注册商/状态/到期时间/DNS服务商/解析记录数/SSL启用+到期时间);`handleOpenCreate` / `handleOpenEdit`(预填数据,日期截取 YYYY-MM-DD)/ `handleSubmit`(统一创建/编辑提交);卡片 Edit2 按钮接入编辑;移除无 handler 的 ExternalLink 按钮
- **结果**:
- `go build ./...` 全包编译通过 ✅
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- API 验证: PUT /domains/1 → Code 200 "更新成功",registrar(aliyun→Cloudflare)、dns_provider(alidns→cloudflare)、record_count(0→12)、ssl_enabled(false→true)、expire_date(2028-03-15) 全部正确持久化 ✅
- API 验证: POST /domains → Code 200 "创建成功",日期字段正确解析(原 bug: 直接绑定 model 导致 RFC3339 解析失败返回 400)✅
- API 验证: DELETE /domains/5 → Code 200 "删除成功" ✅
- 浏览器 UI 验证: 创建弹窗所有字段正常渲染(域名/注册商/状态/到期日期选择器/DNS/记录数/SSL开关+日期选择器联动禁用)✅
- 浏览器 UI 验证: 编辑弹窗预填数据正确(ezops.local/Cloudflare/2028-03-15/cloudflare/12条/SSL已启用)✅
- git push origin master 成功 (commit b110d38) ✅
- **下一步建议**:
- K8s 集群拓扑图(TopologyView)前后端数据联调
- 仪表盘「+12.5%」等增长率标签从硬编码改为基于 month_trend 真实计算
- 告警规则关联通知渠道 — 规则创建时可选择已配置的通知渠道
- 域名列表到期时间显示格式优化(当前显示完整 RFC3339,可截取 YYYY-MM-DD)
## 2026-06-14 10:15 自动推进
- **任务**: 仪表盘云成本增长率标签从硬编码改为基于 month_trend 真实计算 — 消除虚假的「+12.5%」展示
- **修改**:
- `frontend/src/components/dashboard/Dashboard.tsx` — 新增 `computeMonthChange(monthTrend)` 工具函数:基于 month_trend 最后两个月(本月 vs 上月)计算环比百分比,返回 `{pct, label, direction}`;direction 区分 up/down/neutral 并驱动颜色(涨=emerald/跌=red/持平=slate)
- CostOverviewCard 卡片头:将硬编码 `+12.5% 较上月` 替换为 `costChange.label`(动态标签 + 颜色)
- 顶部「本月云成本」StatCard:description/trend/trendValue 三处全部改为动态计算(原硬编码 trend="up" trendValue="+12.5%" description="较上月 +12.5%")
- **结果**:
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- 浏览器验证: 顶部 StatCard 显示 `¥96,700 → +3.1%`(原 +12.5%)✅
- 浏览器验证: 云成本概览卡片头显示 `¥536,685 → +3.1% 较上月`(原 +12.5% 较上月)✅
- 计算依据: month_trend 5月=93799, 6月=96700 → (96700-93799)/93799×100 ≈ +3.1% ✅
- 无 console 错误 ✅
- 后端/前端服务运行中: 8080 + 5173 ✅
- **下一步建议**:
- 服务器「+3 本月」/ 告警「-5 本周」增长率标签仍为硬编码(需后端新增历史快照数据才能真实计算,属较大改动)
- K8s 集群拓扑图(TopologyView)前后端数据联调
- 告警规则关联通知渠道 — 规则创建时可选择已配置的通知渠道
- 域名列表到期时间显示格式优化(截取 YYYY-MM-DD)
## 2026-06-14 11:15 自动推进
- **任务**: 流水线运行历史前后端联调 — 详情弹窗"历史记录"标签从静态占位符改为展示真实 PipelineRun 数据
- **修改**:
- `frontend/src/components/deploy/PipelineManager.tsx`:
- 新增 `pipelineRuns` / `loadingRuns` 状态管理
- 新增 `loadPipelineRuns(pipelineId)` 函数调用 `pipelineApi.getRuns(id)` 拉取运行记录
- 新增 `handleOpenDetail(pipeline)` 统一处理详情弹窗打开 + 自动加载运行记录
- "历史记录"标签显示运行次数计数(如 "历史记录 (6)")
- 历史记录标签内容从静态占位符替换为运行记录列表:每条记录展示构建号(#N)、状态徽章(成功/失败/运行中/待执行)、分支、Commit ID(截取7位)、触发者、耗时(自动格式化s/m)、创建时间
- 触发流水线后若详情弹窗已打开则自动刷新运行记录列表
- 空状态提示"暂无执行记录" + 加载中 Spinner
- **结果**:
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- API 验证: GET /pipelines/1/runs 返回 5 条种子运行记录(成功/失败/运行中多种状态) ✅
- API 验证: POST /pipelines/1/trigger 创建 build #6 status=pending ✅
- 浏览器验证: 流水线详情弹窗"历史记录 (6)"标签正确展示 6 条运行记录,含构建号/状态徽章/分支/Commit/触发者/时间戳 ✅
- 无 console 错误 ✅
- git push origin master 成功 (commit 6012418) ✅
- **下一步建议**:
- 流水线创建时将模板 stages 写入后端(当前创建仅传 name/description/repository/branch,stages 未传递)
- K8s 集群拓扑图(TopologyView)前后端数据联调
- 告警规则关联通知渠道 — 规则创建时可选择已配置的通知渠道
- 域名列表到期时间显示格式优化(截取 YYYY-MM-DD)
## 2026-06-14 12:15 自动推进
- **任务**: 告警规则关联真实通知渠道 — 规则创建/编辑表单选择已配置的通知渠道替代硬编码类型开关
- **修改**:
- `frontend/src/components/monitor/AlertManager.tsx`:
- 新增模块级工具函数 `resolveChannelRef(value, channels)` — 解析 notify_channels 引用值,优先按渠道 ID 匹配已配置渠道,兼容旧格式(类型字符串 email/dingtalk 等)
- 新增 `KNOWN_CHANNEL_TYPES` / `CHANNEL_TYPE_LABELS` 常量用于旧数据兼容
- 新增组件内 `getChannelIcon(type)` — 按渠道类型返回图标组件
- 新增 `renderRuleChannels(rule)` — 规则表通知渠道列渲染:渠道名称+类型图标徽章(替代原先仅显示3个固定图标)
- `loadData()` 并行加载 `alertApi.getNotifyChannels()`(原先仅在通知渠道弹窗打开时加载)
- 规则创建/编辑表单: 用实际已配置渠道列表(名称+类型标签)替代硬编码的 email/sms/dingtalk 3个类型开关;无渠道时显示提示
- 移除不再使用的 `hasChannel()` 函数
- 规则表通知渠道列从3个硬编码图标改为调用 `renderRuleChannels`
- 数据修复: `UPDATE notify_channels SET deleted_at=NULL` — 恢复3条被软删除的种子通知渠道(运维钉钉群/DBA邮箱/告警测试群)
- **结果**:
- `npx tsc --noEmit` 类型检查通过 ✅
- `npm run build` 构建通过 ✅
- 后端 API 验证: POST /alerts/rules notify_channels=["1","2"] → 创建成功,返回 notify_channels:"[\"1\",\"2\"]" ✅
- 后端 API 验证: PUT /alerts/rules/10 notify_channels=["1","3"] → 更新成功 ✅
- 浏览器 UI 验证: 规则表"测试渠道关联规则"通知渠道列显示"运维钉钉群 告警测试群"(渠道ID 1+3解析为名称) ✅
- 浏览器 UI 验证: 新建规则弹窗通知渠道区显示3个真实渠道(告警测试群(钉钉)/DBA邮箱(邮件)/运维钉钉群(钉钉)),不再是硬编码类型 ✅
- 浏览器 UI 验证: 编辑规则弹窗(规则含channels["1","3"])正确预选"告警测试群"+"运维钉钉群"(data-state=checked),DBA邮箱未选 ✅
- git push origin master 成功 (commit f3e1b81) ✅
- **下一步建议**:
- 流水线创建时将模板 stages 写入后端(当前创建仅传 name/description/repository/branch,stages 未传递)
- K8s 集群拓扑图(TopologyView)前后端数据联调
- 域名列表到期时间显示格式优化(截取 YYYY-MM-DD)
- 服务器「+3 本月」/ 告警「-5 本周」增长率标签仍为硬编码