253 lines
11 KiB
Markdown
253 lines
11 KiB
Markdown
# IT 工单跟踪系统
|
||
|
||
基于 Next.js + SQLite 的 IT 基础设施工单跟踪管理系统,域名为 `issue.tlyq.ai`,用于记录和管理故障工单,支持与 [assets.tlyq.ai](https://assets.tlyq.ai) 资产管理系统联动。
|
||
|
||
## 技术栈
|
||
|
||
| 分类 | 技术 |
|
||
|------|------|
|
||
| 框架 | Next.js 15 + TypeScript |
|
||
| UI | React 19 + Tailwind CSS v4 + lucide-react |
|
||
| 数据库 | SQLite(better-sqlite3,WAL 模式) |
|
||
| 认证 | JWT(cookie 方式)+ 自定义 session |
|
||
| 文档导出 | docx + ECharts + Puppeteer(图表渲染) |
|
||
|
||
## 功能
|
||
|
||
- 工单 CRUD(创建、编辑、删除、状态流转)
|
||
- Excel 批量导入工单
|
||
- 仪表盘统计(整体可用性、故障分类、SLA 达标率)
|
||
- 月报/周报生成(DOCX 格式,含封面、目录/图表(月报)、数据表格)
|
||
- 与 assets-ai 资产管理系统双向联动
|
||
- 用户/角色权限管理
|
||
- API Key 管理(支持服务间调用认证)
|
||
|
||
……
|
||
|
||
## 月报设计规则
|
||
|
||
### 概述
|
||
|
||
月报按自然月生成,统计当月已结单工单及跨月进行中工单,输出为 DOCX 文档。包含封面、目录及四个章节。
|
||
|
||
### 报告结构
|
||
|
||
| 章节 | 内容 |
|
||
|------|------|
|
||
| 封面 | 标题、时间范围、公司名称、生成月份 |
|
||
| 目录 | Word 目录域(打开后需更新域以刷新) |
|
||
| 第一章 — 总体运营概况 | GPU 服务器 / 存储服务器每日在线节点数折线图 |
|
||
| 第二章 — 运营数据总览 | 按日期 + 设备类型分组,自然语言描述故障及恢复情况 |
|
||
| 第三章 — 运营故障概览 | 故障工单表格(GPU 故障 / 存储故障 / 其他工单三类) |
|
||
| 第四章 — 服务可用性说明 | 每台设备服务可用性计算公式及百分比 |
|
||
|
||
### 数据采集规则
|
||
|
||
**设备清单**:从 assets-ai 拉取 `filter_status=腾讯使用` 的设备,按 `filter_device_type=GPU服务器` / `存储服务器` 分类,构建 business_ip → device_type 映射。
|
||
|
||
**工单筛选**:按 `close_time` 与 `assign_time` 双条件查询,同时覆盖当月结单工单和跨月进行中工单:
|
||
|
||
```sql
|
||
SELECT * FROM tickets WHERE (
|
||
(close_time >= periodStart AND close_time <= periodEnd + ' 23:59:59')
|
||
OR
|
||
(assign_time <= periodEnd + ' 23:59:59' AND (close_time IS NULL OR close_time > periodEnd + ' 23:59:59'))
|
||
)
|
||
ORDER BY assign_time
|
||
```
|
||
|
||
- 第一条件:当月内结单的工单(含上月派发本月恢复的跨月工单)
|
||
- 第二条件:当月结束时仍未结单的工单(含当月派发和上月派发的进行中工单)
|
||
- 使用 `close_time` 比较而非 `current_status`,保证事后补生成报告时判断不变
|
||
|
||
**工单分类**:按 device_ip 在设备清单中查找对应 device_type(gpu / storage / other)。
|
||
|
||
### 第一章规则
|
||
|
||
- 遍历当月每一天,计算当日在线节点数
|
||
- **统计范围**:排除 `fault_category = '无故障'` 或 `fault_subcategory = '其他'` 的工单("其他"工单不计入节点在线数;跨月工单如 7/31 故障 8/3 恢复正常计入,8/1、8/2 各减 1 台)
|
||
- 不在线判断:`assign_time日期 ≤ 当前日期 < close_time日期`
|
||
- 当日发生故障次日恢复 → 发生日计入不在线,恢复日不计入
|
||
- 当日发生故障当日恢复 → 不计入不在线
|
||
- 在线 = 总节点数 - 不在线节点数
|
||
- 分别统计 GPU 和存储,生成两张 ECharts 折线图
|
||
- **Y 轴动态范围**:根据实际数据波动自动调整 min/max/interval,避免总节点数较大时微小变化无法分辨
|
||
- 无波动时 Y 轴范围 = total ± 2
|
||
- 有波动时根据实际最值加 buffer,确保 8~15 个刻度
|
||
- **报告预览"无故障天数"与 DOCX 图表计算方式不同**:
|
||
- **预览**:按故障完整日期范围(`assign ~ close`,含 close 当天)计算,当日恢复也计入故障天数
|
||
- **DOCX 图表**:按 `assign ≤ date < close` 计算,当日恢复不计入离线节点
|
||
|
||
### 第二章规则
|
||
|
||
- 仅统计 GPU / 存储工单,排除 `fault_category = '无故障'` 或 `fault_subcategory = '其他'`
|
||
- 按 `device_type + assign_time日期` 分组
|
||
- 每条格式:`X月X日发生1次<故障子类>,故障节点为<IP>,<恢复描述>。`
|
||
- 恢复描述:
|
||
- 已结单:`assign_date` 与 `close_date` 天数差,0 → 当日,1 → 次日,≥2 → N日后
|
||
- 进行中:固定显示 `处理中。`(不含恢复描述)
|
||
|
||
### 第三章规则
|
||
|
||
**分流逻辑**:
|
||
|
||
| 条件 | 归类 |
|
||
|------|------|
|
||
| `fault_subcategory = '其他'` | 其他工单 |
|
||
| `fault_subcategory ≠ '其他'` 且 device_type 为 gpu | GPU 故障 |
|
||
| `fault_subcategory ≠ '其他'` 且 device_type 为 storage | 存储故障 |
|
||
| `fault_subcategory ≠ '其他'` 且 device_type 为 other | 其他工单 |
|
||
|
||
**GPU/存储故障表**(7 列):
|
||
|
||
| 列 | 来源 | 进行中工单 |
|
||
|----|------|-----------|
|
||
| 工单编号 | `ticket_id` | 正常显示 |
|
||
| 故障节点 | `device_ip` | 正常显示 |
|
||
| 故障日期 | `assign_time`(完整时间,精确到秒) | 正常显示 |
|
||
| 故障问题 | `fault_subcategory` | 正常显示 |
|
||
| 故障原因 | `parts_name` 有值 → `更换{parts_name}`,否则 → `-` | 正常显示 |
|
||
| 处理时长(分钟) | `duration_minutes`(已结单) | 显示 `进行中` |
|
||
| 是否计入 SLA | 见下方 SLA 规则 | 显示 `—` |
|
||
|
||
**其他工单表**(7 列):
|
||
|
||
| 列 | 来源 | 进行中工单 |
|
||
|----|------|-----------|
|
||
| 工单编号 | `ticket_id` | 正常显示 |
|
||
| 设备 IP 地址 | `device_ip` | 正常显示 |
|
||
| 工单日期 | `assign_time`(完整时间,精确到秒) | 正常显示 |
|
||
| 工单内容 | `content` | 正常显示 |
|
||
| 工单结论 | `conclusion` | 正常显示 |
|
||
| 处理时长(分钟) | `duration_minutes`(已结单) | 显示 `进行中` |
|
||
| 是否计入 SLA | 见下方 SLA 规则 | 显示 `—` |
|
||
|
||
### 第四章规则
|
||
|
||
- 排除 `fault_category = '无故障'` 的工单
|
||
- 按 device_ip 分组求和故障时长:
|
||
- **已结单工单**:使用实际 `duration_minutes`
|
||
- **进行中工单**:仅计算本月内部分,时长 = `(min(assign_date, 月初) → 月末最后一天) × 24 × 60` 分钟
|
||
- 公式:`可用性 = (monthDays × 24 × 60 - totalDurationMinutes) / (monthDays × 24 × 60) × 100`
|
||
- monthDays 为当月实际天数(动态计算)
|
||
- 百分比 **< 99%** 时,该值以黄底红字加粗标记
|
||
- 百分比 **≥ 99%** 时,正常样式
|
||
- 该 IP 存在进行中工单时,公式后追加橙色标注 `(故障处理中,仅计本月部分)`
|
||
|
||
### SLA 判定规则
|
||
|
||
`是否计入SLA` 字段判定逻辑:
|
||
|
||
```
|
||
IF availability IS NULL OR availability >= 0.99 → 否
|
||
IF availability < 0.99 AND conclusion 包含 "无异常" → 否
|
||
IF availability < 0.99 AND conclusion 不包含 "无异常" → 是
|
||
```
|
||
|
||
### 排版规范
|
||
|
||
| 元素 | 字体 | 字号 | 行距 | 其他 |
|
||
|------|------|------|------|------|
|
||
| 封面标题 | SimHei(黑体) | 22pt / 26pt | 1.5x | 居中 |
|
||
| 章标题(Heading 1) | SimSun | 14pt | 1.5x | 加粗 |
|
||
| 节标题(Heading 2) | SimSun | 12pt | 1.5x | 加粗 |
|
||
| 正文 | SimSun | 11pt | 1.5x | 首行缩进 2 字符 |
|
||
| 表格表头 | SimSun | 10pt | 1.5x | 蓝底白字加粗 |
|
||
| 表格内容 | SimSun | 9pt | 1.15x | 垂直居中 |
|
||
| 目录 TOC1/TOC2 | SimSun | 11pt | 1.5x | — |
|
||
|
||
## 周报设计规则
|
||
|
||
### 概述
|
||
|
||
周报按自然周(周一至周日)生成,统计当周活跃工单(含处理中和已结单),输出为 DOCX 文档。包含封面及四个章节,不含目录和图表。
|
||
|
||
### 报告结构
|
||
|
||
| 章节 | 内容 |
|
||
|------|------|
|
||
| 封面 | 标题、报告周期、生成时间、公司名称 |
|
||
| 一、总体运营概况 | GPU/存储服务器总数 + 本周故障摘要 + 每日在线节点数表格 |
|
||
| 二、GPU 服务器故障 | 故障概况表 + 已恢复工单的故障详情表 |
|
||
| 三、存储服务器故障 | 故障概况表 + 已恢复工单的故障详情表 |
|
||
| 四、其他工单 | 工单概况表 + 已恢复工单的工单详情表 |
|
||
|
||
### 数据采集规则
|
||
|
||
**设备清单**:与月报相同,从 assets-ai 拉取 GPU/存储设备,构建 IP → device_type 映射。
|
||
|
||
**工单筛选**:按周期内活跃度查询,含处理中工单(区别于月报仅统计已结单):
|
||
|
||
```sql
|
||
-- 周期内结单的工单,或周期内仍在处理中的工单
|
||
(close_time >= periodStart AND close_time <= periodEnd + ' 23:59:59')
|
||
OR
|
||
(assign_time <= periodEnd + ' 23:59:59' AND (current_status NOT IN ('resolved','closed') OR close_time > periodEnd + ' 23:59:59'))
|
||
```
|
||
|
||
**工单分类(三路分流)**:
|
||
|
||
| 条件 | 归类 |
|
||
|------|------|
|
||
| `ticket_type = 'OEM维修'` 且 `fault_category ≠ '无故障'` 且 device_type = gpu | GPU 服务器故障 |
|
||
| `ticket_type = 'OEM维修'` 且 `fault_category ≠ '无故障'` 且 device_type = storage | 存储服务器故障 |
|
||
| `ticket_type = 'OEM诊断'` 或(`ticket_type = 'OEM维修'` 且 `fault_category = '无故障'`) | 其他工单 |
|
||
|
||
### 第一章规则(总体运营概况)
|
||
|
||
**1.1 本周概览**:展示 GPU/存储服务器总数,本周故障次数及恢复/处理中数量。
|
||
|
||
**1.2 / 1.3 每日运行状态表**:遍历周期内每一天,计算当日在线节点数。
|
||
- 不在线判断:`assign_time日期 ≤ 当前日期 < close_time日期`(与月报逻辑一致)
|
||
- 当日有故障节点时:日期/在线数/故障数三列纵向合并,最后一列逐行列出故障 IP
|
||
- 当日无故障时:单行显示,故障 IP 列填 `/`
|
||
- 在线 = 总节点数 - 不在线节点数
|
||
|
||
### 第二/三/四章规则(故障详情)
|
||
|
||
**故障概况表**(5 列):
|
||
|
||
| 列 | 来源 | 列宽 |
|
||
|----|------|------|
|
||
| 工单号 | `ticketNo` | 15%(2.41cm) |
|
||
| 设备 IP | `deviceIp` | 15%(2.41cm) |
|
||
| 工单内容 | `content` 或 `faultSubcategory` | 40%(6.29cm) |
|
||
| 工单时间 | `assignTime` | 15%(2.41cm) |
|
||
| 目前状态 | 已恢复 / 处理中 | 15%(2.41cm) |
|
||
|
||
**故障详情表**(4 列,仅已恢复工单展示):
|
||
- 基本信息区:工单号、设备 IP、工单内容(3 列合并)、派单/结单时间
|
||
- 工单流程区:第一列纵向合并为「工单流程」标签,后三列为时间节点、发现人/处理人、处理过程/处理结果
|
||
- 若 steps 中无「下发工单」步骤,自动补一行
|
||
- 若 steps 中无「结单」步骤,自动补一行
|
||
- 工单结论区:标签 + 结论文字(3 列合并,居中)
|
||
|
||
### 表格列宽实现
|
||
|
||
故障概况表采用 **DXA 绝对值 + 固定布局** 方式确保列宽精确:
|
||
|
||
```typescript
|
||
// 15:15:40:15:15 比例换算 DXA(A4 内容宽度 9026 DXA)
|
||
const colDxa = [1354, 1354, 3610, 1354, 1354]
|
||
|
||
new Table({
|
||
width: { size: 9026, type: WidthType.DXA },
|
||
columnWidths: colDxa,
|
||
layout: TableLayoutType.FIXED, // 关键:禁止 Word 自动调整列宽
|
||
rows: [...],
|
||
})
|
||
```
|
||
|
||
每个单元格必须同时设置 `width: { size: colDxa[i], type: WidthType.DXA }`,确保 gridCol、表头 tcW、数据 tcW 三者值完全一致。
|
||
|
||
### 与月报的关键差异
|
||
|
||
| 维度 | 月报 | 周报 |
|
||
|------|------|------|
|
||
| 统计范围 | 自然月,仅已结单 | 自然周(周一~周日),含处理中 |
|
||
| 目录 | 有(TOC 域) | 无 |
|
||
| 图表 | ECharts 折线图(第一章) | 无(纯表格) |
|
||
| 服务可用性 | 第四章 SLA 计算 | 无 |
|
||
| 故障详情展开 | 无(仅概况表) | 有(完整工单流程时间线) |
|
||
| 表格布局 | 百分比自适应 | DXA 固定列宽 + Fixed Layout |
|