# Disk Monitor Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 在当前仓库内完成磁盘监控页面、前端 API 契约、数据库 SQL 交付文件和手工验证入口,为后端接入完整磁盘监控能力提供可直接联调的前端实现基础。
**Architecture:** 以前端单页容器 `frontend/src/views/systemMonitor/diskMonitor/index.vue` 负责编排状态、加载配置、保存配置、触发手动执行和展示历史结果;页面拆分为摘要卡片、全局策略表单、盘符编辑器、通知编辑器、任务历史与详情抽屉。后端按已确认的规格提供 `/disk-monitor/**` 接口,本仓库额外产出一份 `doc/系统磁盘监控数据库设计.sql` 作为数据库交付物。该计划不在当前仓库内实现真实磁盘扫描、定时器和通知发送逻辑,只实现页面、契约和 SQL 文件。
**Tech Stack:** Vue 3 `
```
- [ ] **Step 3: Create the global policy form component**
Create `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorPolicyForm.vue` with:
```vue
```
- [ ] **Step 4: Replace the placeholder page with container state and data loading**
Replace `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue` with a container that imports the new API and components, keeping the back navigation and adding concise Chinese comments on the main business flow:
```vue
```
Expected: 页面不再显示占位摘要和占位面板,而是渲染摘要卡片和全局策略卡片,并能在挂载时请求配置与最近任务。
- [ ] **Step 5: Run the first full type-check after replacing the placeholder**
Run:
```powershell
cd D:\Work\SourceCode\CN_Tool_client\frontend
npm run type-check
```
Expected: 允许失败原因为“盘符编辑组件和任务列表组件尚未创建”,不允许出现 `form.ts`、`DiskMonitorSummary.vue`、`DiskMonitorPolicyForm.vue` 的类型错误。
- [ ] **Step 6: Commit the page state skeleton**
Run:
```powershell
git add D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\utils\form.ts D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorSummary.vue D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorPolicyForm.vue D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue
git commit -m "feat: scaffold disk monitor page state"
```
## Task 3: Build The Target Editor And Notification Editors
**Files:**
- Create: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\NotificationPathEditor.vue`
- Create: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\NotificationHttpEditor.vue`
- Create: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorTargetDialog.vue`
- Create: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorTargetTable.vue`
- Modify: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue`
- [ ] **Step 1: Create the path notification array editor**
Create `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\NotificationPathEditor.vue` with:
```vue
```
Expected: 组件支持新增、删除、编辑路径通知目标,不自行维护状态。
- [ ] **Step 2: Create the HTTP notification array editor**
Create `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\NotificationHttpEditor.vue` with:
```vue
```
- [ ] **Step 3: Create the target edit dialog**
Create `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorTargetDialog.vue` with a dialog shell that hosts the two editor components:
```vue
```
Expected: 弹窗内至少包含盘符、启用开关、预警阈值、告警阈值、路径通知开关与编辑器、HTTP 通知开关与编辑器、备注。
- [ ] **Step 4: Create the target table with add/edit/delete events**
Create `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorTargetTable.vue` with:
```vue
```
Expected: 表格列至少显示盘符、是否监控、预警使用率、告警使用率、当前状态、最近扫描时间、最近使用率、操作按钮。
- [ ] **Step 5: Wire target CRUD into the page container**
Update `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue` to add:
```ts
import { createEmptyTarget, validateTarget } from './utils/form'
import DiskMonitorTargetTable from './components/DiskMonitorTargetTable.vue'
import DiskMonitorTargetDialog from './components/DiskMonitorTargetDialog.vue'
const targetDialogVisible = ref(false)
const editingTargetIndex = ref(-1)
const editingTarget = ref(createEmptyTarget())
const openAddTarget = () => {
editingTargetIndex.value = -1
editingTarget.value = createEmptyTarget()
targetDialogVisible.value = true
}
const openEditTarget = (row: DiskMonitor.TargetItem, index: number) => {
editingTargetIndex.value = index
editingTarget.value = JSON.parse(JSON.stringify(row))
targetDialogVisible.value = true
}
const confirmTarget = () => {
const duplicatePool = targetList.value
.filter((_, index) => index !== editingTargetIndex.value)
.map(item => item.driveLetter)
const error = validateTarget(editingTarget.value, duplicatePool)
if (error) {
ElMessage.warning(error)
return
}
if (editingTargetIndex.value === -1) {
targetList.value = [...targetList.value, JSON.parse(JSON.stringify(editingTarget.value))]
} else {
targetList.value = targetList.value.map((item, index) =>
index === editingTargetIndex.value ? JSON.parse(JSON.stringify(editingTarget.value)) : item
)
}
targetDialogVisible.value = false
}
const removeTarget = (index: number) => {
targetList.value = targetList.value.filter((_, rowIndex) => rowIndex !== index)
}
```
Expected: 页面可以新增、编辑、删除多个盘符,并能在保存前阻止重复盘符和非法阈值。
- [ ] **Step 6: Run lint and type-check after target editor wiring**
Run:
```powershell
cd D:\Work\SourceCode\CN_Tool_client\frontend
npm run lint -- src/views/systemMonitor/diskMonitor/index.vue src/views/systemMonitor/diskMonitor/components/NotificationPathEditor.vue src/views/systemMonitor/diskMonitor/components/NotificationHttpEditor.vue src/views/systemMonitor/diskMonitor/components/DiskMonitorTargetDialog.vue src/views/systemMonitor/diskMonitor/components/DiskMonitorTargetTable.vue
npm run type-check
```
Expected: 两个命令退出 `0`;不允许出现盘符编辑器和通知编辑器的 props/emits 类型错误。
- [ ] **Step 7: Commit the target editor slice**
Run:
```powershell
git add D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\NotificationPathEditor.vue D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\NotificationHttpEditor.vue D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorTargetDialog.vue D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorTargetTable.vue D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue
git commit -m "feat: add disk monitor target editors"
```
## Task 4: Add Manual Run, Job History, And Job Detail Views
**Files:**
- Create: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorJobTable.vue`
- Create: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorJobDetailDrawer.vue`
- Modify: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue`
- [ ] **Step 1: Create the recent job table component**
Create `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorJobTable.vue` with:
```vue
```
Expected: 表格列至少包含任务编号、来源、开始时间、结束时间、状态、预警数量、告警数量和“查看详情”按钮。
- [ ] **Step 2: Create the job detail drawer**
Create `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorJobDetailDrawer.vue` with:
```vue
```
Expected: 抽屉中分两块表格展示 `results` 与 `notifyLogs`,字段名与规格文档一致。
- [ ] **Step 3: Wire manual run and history loading into the page**
Update `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue` with:
```ts
import { getDiskMonitorJobDetail } from '@/api/system/diskMonitor'
import DiskMonitorJobTable from './components/DiskMonitorJobTable.vue'
import DiskMonitorJobDetailDrawer from './components/DiskMonitorJobDetailDrawer.vue'
const jobList = ref([])
const jobDetailVisible = ref(false)
const jobDetail = ref(null)
const detailLoading = ref(false)
const loadJobList = async () => {
loading.jobs = true
try {
const resp = await getDiskMonitorJobList({ pageNum: 1, pageSize: 10 })
jobList.value = resp.data.records || []
latestJob.value = jobList.value[0] || null
} finally {
loading.jobs = false
}
}
const openJobDetail = async (row: DiskMonitor.JobListItem) => {
detailLoading.value = true
jobDetailVisible.value = true
try {
const resp = await getDiskMonitorJobDetail(row.id)
jobDetail.value = resp.data
} finally {
detailLoading.value = false
}
}
```
Expected: 手动执行完任务后可以刷新最近任务列表,并且可点开详情查看每个盘符结果与通知日志。
- [ ] **Step 4: Keep the page refresh flow single-sourced**
Update `loadPageData` in `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue` so it only loads config + recent任务列表 once:
```ts
const loadPageData = async () => {
loading.init = true
try {
const policyResp = await getDiskMonitorPolicyDetail()
policyForm.value = policyResp.data.policy
targetList.value = policyResp.data.targets || []
await loadJobList()
} finally {
loading.init = false
}
}
```
Expected: 保存配置、手动执行、页面初始化都复用同一套刷新入口,不出现多处重复请求逻辑。
- [ ] **Step 5: Run the full frontend verification commands**
Run:
```powershell
cd D:\Work\SourceCode\CN_Tool_client\frontend
npm run lint
npm run type-check
```
Expected: 两个命令都退出 `0`。
- [ ] **Step 6: Commit the job history UI**
Run:
```powershell
git add D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorJobTable.vue D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\DiskMonitorJobDetailDrawer.vue D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue
git commit -m "feat: add disk monitor job views"
```
## Task 5: Perform Manual Verification On The Hash Route
**Files:**
- Verify only: `D:\Work\SourceCode\CN_Tool_client\frontend\src\routers\modules\staticRouter.ts`
- Verify only: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\index.vue`
- Verify only: `D:\Work\SourceCode\CN_Tool_client\frontend\src\views\systemMonitor\diskMonitor\components\*.vue`
- Verify only: `D:\Work\SourceCode\CN_Tool_client\doc\系统磁盘监控数据库设计.sql`
- [ ] **Step 1: Start the frontend dev server**
Run:
```powershell
cd D:\Work\SourceCode\CN_Tool_client\frontend
npm run dev
```
Expected: Vite 启动成功;当前开发环境使用 `hash` 路由,因此目标页面地址为 `/#/systemMonitor/diskMonitor`。
- [ ] **Step 2: Verify configuration load and save behavior**
Manual checklist:
```text
1. 访问 /#/systemMonitor/diskMonitor,能看到摘要区、全局策略区、盘符列表区、最近任务区。
2. 修改“启用监控”“启动即监控”“每日执行时间”后点击“保存配置”,页面给出成功提示。
3. 新增两个盘符,例如 C: 与 D:,分别配置不同的预警/告警阈值。
4. 为其中一个盘符新增本地目录通知和 HTTP 通知目标,保存后刷新页面,配置仍正确回显。
5. 尝试录入重复盘符或告警阈值小于预警阈值,页面必须阻止提交并给出提示。
```
Expected: 五项都成立。
- [ ] **Step 3: Verify manual run and job detail behavior**
Manual checklist:
```text
1. 点击“立即执行监控”,页面提示任务已启动。
2. 最近任务列表出现一条新的 MANUAL 任务。
3. 打开任务详情抽屉,能看到盘符结果表和通知日志表。
4. 若后端暂未接通,页面应以接口错误提示结束,不得卡死或出现未捕获异常。
```
Expected: 四项都成立。
- [ ] **Step 4: Verify the SQL artifact matches the approved spec**
Run:
```powershell
Get-Content -Raw D:\Work\SourceCode\CN_Tool_client\doc\系统磁盘监控数据库设计.sql
Get-Content -Raw D:\Work\SourceCode\CN_Tool_client\docs\superpowers\specs\2026-04-22-disk-monitor-design.md
```
Expected: SQL 文件包含同样的五张表和字段命名:`disk_monitor_policy`、`disk_monitor_target`、`disk_monitor_job`、`disk_monitor_result`、`disk_monitor_notify_log`。
- [ ] **Step 5: Record final verification status**
Run:
```powershell
cd D:\Work\SourceCode\CN_Tool_client\frontend
npm run lint
npm run type-check
git status --short
```
Expected: `lint` 和 `type-check` 退出 `0`;`git status --short` 只显示本功能相关改动和仓库原有未处理改动,不出现意外文件。
## Self-Review
- Spec coverage: 计划覆盖了静态路由兜底、前端 API 契约、数据库 SQL 文件、摘要区、全局策略区、盘符与通知编辑、手动执行、最近任务、详情抽屉和验证步骤,与已批准规格一致。
- Placeholder scan: 没有 `TODO`、`TBD`、`后续再说` 类占位语;每个任务都给了明确文件路径、代码骨架、命令和预期结果。
- Type consistency: 计划统一使用 `DiskMonitor.PolicyItem`、`DiskMonitor.TargetItem`、`DiskMonitor.JobListItem`、`DiskMonitor.JobDetailData`、`createDefaultPolicy`、`createEmptyTarget`、`validatePolicy`、`validateTarget` 等命名,没有前后不一致的接口名。