diff --git a/frontend/.ai/specs/dashboard-stats-redesign-spec.md b/frontend/.ai/specs/dashboard-stats-redesign-spec.md
new file mode 100644
index 0000000..2def06b
--- /dev/null
+++ b/frontend/.ai/specs/dashboard-stats-redesign-spec.md
@@ -0,0 +1,163 @@
+# 技术契约与架构设计书:Dashboard 统计卡片重设计
+
+**版本**:v1.0
+**日期**:2026-03-13
+**作者**:system-architect
+**状态**:待评审
+
+---
+
+## 一、现状诊断
+
+### 当前 API 响应结构
+
+```json
+{
+ "total_auth_codes": 12,
+ "active_licenses": 2,
+ "expiring_soon": 0,
+ "abnormal_alerts": 2,
+ "growth_rate": {
+ "auth_codes": 100.00,
+ "licenses": 0.00
+ }
+}
+```
+
+### 现存问题清单
+
+| # | 问题 | 严重性 |
+|---|------|--------|
+| 1 | `growth_rate` 语义不清——是"同比"上月还是"环比"?无时间标注 | 高 |
+| 2 | 两个增长率字段(auth_codes / licenses)对用户的业务价值极低,不知道要对比什么 | 高 |
+| 3 | 前端 `statsData` 中的 `key` 映射与 i18n label 不一致(注释与实际label错位) | 中 |
+| 4 | `expiring_soon` 统计的是"30天内到期的授权码",但卡片标签写的是"即将过期",口径模糊 | 中 |
+| 5 | 没有"今日新增"这类高频关注的运营指标 | 中 |
+| 6 | 增长率算法缺陷:上月总数为0时直接返回0而非100% | 低 |
+
+---
+
+## 二、竞品分析(License Management SaaS 参考)
+
+### Keygen.sh / LicenseSpring / Cryptlex 共性 Dashboard 指标
+
+```
+┌─────────────────────────────────────────────────────────┐
+│ 高频关注(运营视角) │
+│ • 今日新增授权码 / 本月新增授权码(绝对数 + 环比昨日/上月)│
+│ • 活跃设备数(在线 License) │
+│ • 即将到期(7天 / 30天)→ 需要跟进续费 │
+│ • 异常告警(心跳超时 / 被撤销) │
+└─────────────────────────────────────────────────────────┘
+┌─────────────────────────────────────────────────────────┐
+│ 中频关注(管理视角) │
+│ • 授权码总量(存量指标) │
+│ • 活跃许可证总量(存量指标) │
+│ • 月度增长率(MoM Growth Rate,附说明文字"vs 上月") │
+└─────────────────────────────────────────────────────────┘
+```
+
+### 关键竞品设计原则
+
+1. **增长率必须标注对比周期**:统一用「vs. 上月同期」,数字旁展示箭头 ↑ ↓ 和颜色区分正负
+2. **增长率不放卡片主数值**:作为副文本展示(小字 + 颜色),主数值展示绝对数
+3. **即将到期细分**:7天 为紧急(红),30天 为预警(橙)
+4. **今日新增**:运营最关注的高频指标,竞品均在首位展示
+
+---
+
+## 三、重设计方案
+
+### 3.1 新指标体系(6张卡片)
+
+| 位置 | 指标名 | 计算口径 | 副文本 |
+|------|--------|---------|--------|
+| 卡片1 | 授权码总量 | `COUNT(authorization_codes)` | ↑ 本月新增 N 个 |
+| 卡片2 | 活跃许可证 | `COUNT(licenses WHERE status='active')` | ↑ 较上月 +X% |
+| 卡片3 | 今日新增授权 | `COUNT(licenses WHERE DATE(created_at)=TODAY)` | 昨日 N 个 |
+| 卡片4 | 7天内到期 | `COUNT(auth_codes WHERE end_date BETWEEN now AND now+7d AND NOT locked)` | 紧急跟进 |
+| 卡片5 | 30天内到期 | `COUNT(auth_codes WHERE end_date BETWEEN now AND now+30d AND NOT locked)` | 含7天内 |
+| 卡片6 | 异常告警 | `COUNT(licenses WHERE status='active' AND heartbeat_timeout)` | 心跳超时 |
+
+> 删除:`auth_codes 增长率`、`licenses 增长率` 作为独立卡片(改为副文本方式展示)
+
+### 3.2 增长率展示方式(副文本,不占卡片)
+
+```
+┌──────────────────────────┐
+│ 🔑 授权码总量 │
+│ 12 │
+│ ↑ 本月新增 2 个 │ ← 副文本:绝对增量
+└──────────────────────────┘
+
+┌──────────────────────────┐
+│ ✅ 活跃许可证 │
+│ 98 │
+│ ↑ +12.5% vs. 上月 │ ← 副文本:百分比增长率 + 标注
+└──────────────────────────┘
+```
+
+### 3.3 新 API Response Schema
+
+```go
+// StatsOverviewResponse 重设计
+type StatsOverviewResponse struct {
+ // 存量指标
+ TotalAuthCodes int64 `json:"total_auth_codes"` // 授权码总量
+ ActiveLicenses int64 `json:"active_licenses"` // 活跃许可证
+
+ // 流量指标
+ TodayNewLicenses int64 `json:"today_new_licenses"` // 今日新增许可证
+ YesterdayNewLicenses int64 `json:"yesterday_new_licenses"` // 昨日新增(用于对比)
+ MonthNewAuthCodes int64 `json:"month_new_auth_codes"` // 本月新增授权码
+
+ // 风险指标
+ ExpiringIn7Days int64 `json:"expiring_in_7days"` // 7天内到期
+ ExpiringIn30Days int64 `json:"expiring_in_30days"` // 30天内到期
+ AbnormalAlerts int64 `json:"abnormal_alerts"` // 异常告警
+
+ // 增长率(作为副文本,不占独立卡片)
+ GrowthRate struct {
+ AuthCodesMoM float64 `json:"auth_codes_mom"` // 授权码月环比
+ LicensesMoM float64 `json:"licenses_mom"` // 许可证月环比
+ } `json:"growth_rate"`
+}
+```
+
+---
+
+## 四、影响面分析(全栈)
+
+### 后端改动文件
+
+| 文件 | 操作 | 说明 |
+|------|------|------|
+| `backend/internal/models/license.go` | 修改 | 更新 `StatsOverviewResponse` struct |
+| `backend/internal/service/license_service.go` | 修改 | 重写 `GetStatsOverview()` 实现,增加今日/昨日新增查询 |
+| `backend/internal/api/handlers/license_handler.go` | 无需修改 | Handler 层直接透传 |
+
+### 前端改动文件
+
+| 文件 | 操作 | 说明 |
+|------|------|------|
+| `frontend/src/views/Dashboard.vue` | 修改 | 重新定义 `statsData` 6张卡片,增加副文本字段渲染 |
+| `frontend/src/i18n/locales/zh.json` | 修改 | 更新 `dashboard.stats.*` key |
+| `frontend/src/i18n/locales/en.json` | 修改 | 同上 |
+| `frontend/src/i18n/locales/ja.json` | 修改 | 同上 |
+| `frontend/src/api/dashboard.ts` | 修改 | 更新 `getOverviewStats` 返回类型定义 |
+
+---
+
+## 五、实施优先级建议
+
+**P0(立即)**:
+- 重命名"即将过期"为"30天内到期",语义清晰化
+- 增长率卡片改为副文本方式(不移除数据,只改展示层)
+- 增长率数字旁加"vs. 上月"标注
+
+**P1(本迭代)**:
+- 新增"今日新增"卡片(需要后端加一个 COUNT 查询)
+- "即将过期"拆分7天/30天两档
+
+**P2(下迭代)**:
+- 卡片支持点击跳转到过滤后的列表页
diff --git a/frontend/.ai/specs/login-i18n-spec.md b/frontend/.ai/specs/login-i18n-spec.md
new file mode 100644
index 0000000..36242c2
--- /dev/null
+++ b/frontend/.ai/specs/login-i18n-spec.md
@@ -0,0 +1,135 @@
+# 技术契约与架构设计书:登录页国际化补全
+
+**版本**:v1.0
+**日期**:2026-03-13
+**作者**:system-architect
+**状态**:待 task-coder 实施
+
+---
+
+## 一、问题诊断
+
+`src/views/Login.vue` 中存在 **8 处**硬编码英文字符串,未通过 `t()` 调用 i18n 系统,导致切换语言后这些文案不随语言切换。
+
+### 硬编码清单(按 DOM 位置)
+
+| 位置 | 当前硬编码值 | 目标 key |
+|------|-------------|---------|
+| `.hero-title` | `Secure License
Management` | `login.heroTitleLine1` / `login.heroTitleLine2` |
+| `.hero-subtitle` | `Streamline your software licensing...` | `login.heroSubtitle` |
+| stat-label "Active Licenses" | `Active Licenses` | `login.stats.activeLicenses` |
+| stat-label "Uptime" | `Uptime` | `login.stats.uptime` |
+| stat-label "Support" | `Support` | `login.stats.support` |
+| `.title` (card) | `Welcome back` | `login.welcomeTitle` |
+| `.subtitle` (card) | `Sign in to your account to continue` | `login.welcomeSubtitle` |
+| `.login-footer p` | `© 2025 Cedar-V. All rights reserved.` | `login.copyright` |
+
+> **保持原样(不需国际化)**:品牌名 `Cedar-V`、数字统计值 `10K+` / `99.9%` / `24/7`、语言选项标签(自语言名称自描述惯例)。
+
+---
+
+## 二、数据模型层(Schema)— i18n 键值设计
+
+### 新增键(追加至三端 `login` 对象末尾,位于 `error` 块之后)
+
+```jsonc
+// en.json
+"heroTitleLine1": "Secure License",
+"heroTitleLine2": "Management",
+"heroSubtitle": "Streamline your software licensing workflow with our enterprise-grade platform.",
+"stats": {
+ "activeLicenses": "Active Licenses",
+ "uptime": "Uptime",
+ "support": "Support"
+},
+"welcomeTitle": "Welcome back",
+"welcomeSubtitle": "Sign in to your account to continue",
+"copyright": "© 2025 Cedar-V. All rights reserved."
+
+// zh.json
+"heroTitleLine1": "安全许可证",
+"heroTitleLine2": "管理平台",
+"heroSubtitle": "使用我们的企业级平台,简化您的软件许可证管理工作流程。",
+"stats": {
+ "activeLicenses": "活跃许可证",
+ "uptime": "可用率",
+ "support": "全天支持"
+},
+"welcomeTitle": "欢迎回来",
+"welcomeSubtitle": "登录您的账户以继续",
+"copyright": "© 2025 Cedar-V. 保留所有权利。"
+
+// ja.json
+"heroTitleLine1": "セキュアな",
+"heroTitleLine2": "ライセンス管理",
+"heroSubtitle": "エンタープライズグレードのプラットフォームで、ソフトウェアライセンス管理を効率化。",
+"stats": {
+ "activeLicenses": "アクティブライセンス",
+ "uptime": "稼働率",
+ "support": "サポート"
+},
+"welcomeTitle": "おかえりなさい",
+"welcomeSubtitle": "アカウントにサインインして続けてください",
+"copyright": "© 2025 Cedar-V. All rights reserved."
+```
+
+---
+
+## 三、前端交互层(View)— 修改意图
+
+### 目标文件
+
+| 文件 | 操作 |
+|------|------|
+| `src/i18n/locales/en.json` | 追加 8 个新键至 `login` 对象 |
+| `src/i18n/locales/zh.json` | 追加 8 个新键至 `login` 对象 |
+| `src/i18n/locales/ja.json` | 追加 8 个新键至 `login` 对象 |
+| `src/views/Login.vue` | 模板层 8 处硬编码 → `{{ t('login.*') }}` |
+
+### Login.vue 模板变更对照
+
+```html
+
+
Streamline your software licensing workflow with our enterprise-grade platform.
+ + +{{ t('login.heroSubtitle') }}
+``` + +```html + +Active Licenses +Uptime +Support + + +{{ t('login.stats.activeLicenses') }} +{{ t('login.stats.uptime') }} +{{ t('login.stats.support') }} +``` + +```html + +Sign in to your account to continue
+ + +{{ t('login.welcomeSubtitle') }}
+``` + +```html + +© 2025 Cedar-V. All rights reserved.
+ + +{{ t('login.copyright') }}
+``` diff --git a/frontend/src/components/charts/LicenseTrendChart.vue b/frontend/src/components/charts/LicenseTrendChart.vue index 60a7f78..7c427fe 100644 --- a/frontend/src/components/charts/LicenseTrendChart.vue +++ b/frontend/src/components/charts/LicenseTrendChart.vue @@ -121,7 +121,6 @@ const appStore = useAppStore() // 快捷选择选项 const quickOptions = computed(() => [ - { label: t('chart.licenseTrend.quickOptions.today'), value: 'today' }, { label: t('chart.licenseTrend.quickOptions.week'), value: 'week' }, { label: t('chart.licenseTrend.quickOptions.month'), value: 'month' } ]) @@ -161,7 +160,7 @@ const chartOption = computed(() => { return { grid: { left: 60, - right: 30, + right: 50, top: 30, bottom: 60, containLabel: false @@ -277,24 +276,17 @@ const handleQuickSelect = (value: string) => { let endDate: Date switch (value) { - case 'today': - // 本日:今天到今天 + case 'week': + // 最近7天:今天往前6天 startDate = new Date(today) + startDate.setDate(today.getDate() - 6) endDate = new Date(today) break - case 'week': - // 本周:本周一到本周日 - const currentDay = today.getDay() // 0=周日, 1=周一, ..., 6=周六 - const mondayOffset = currentDay === 0 ? 6 : currentDay - 1 // 计算到周一的偏移 - startDate = new Date(today) - startDate.setDate(today.getDate() - mondayOffset) - endDate = new Date(startDate) - endDate.setDate(startDate.getDate() + 6) // 周日 - break case 'month': - // 本月:当前月1号到当前月末 - startDate = new Date(today.getFullYear(), today.getMonth(), 1) - endDate = new Date(today.getFullYear(), today.getMonth() + 1, 0) // 下个月0号=本月最后一天 + // 最近30天:今天往前29天 + startDate = new Date(today) + startDate.setDate(today.getDate() - 29) + endDate = new Date(today) break default: return diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 6c62443..1bf8125 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -17,7 +17,18 @@ "usernameMinLength": "Username must be at least 3 characters", "passwordRequired": "Please enter password", "passwordMinLength": "Password must be at least 6 characters" - } + }, + "heroTitleLine1": "Secure License", + "heroTitleLine2": "Management", + "heroSubtitle": "Streamline your software licensing workflow with our enterprise-grade platform.", + "stats": { + "activeLicenses": "Active Licenses", + "uptime": "Uptime", + "support": "Support" + }, + "welcomeTitle": "Welcome back", + "welcomeSubtitle": "Sign in to your account to continue", + "copyright": "© 2025 Cedar-V. All rights reserved." }, "sidebar": { "expand": "Expand Sidebar", @@ -295,9 +306,8 @@ "licenseTrend": { "title": "License Trend", "quickOptions": { - "today": "Today", - "week": "This Week", - "month": "This Month" + "week": "Last 7 Days", + "month": "Last 30 Days" }, "datePicker": { "rangeSeparator": "to", @@ -314,9 +324,8 @@ "endDate": "End Date", "separator": "to", "quickOptions": { - "today": "Today", - "week": "This Week", - "month": "This Month" + "week": "Last 7 Days", + "month": "Last 30 Days" } } }, diff --git a/frontend/src/i18n/locales/ja.json b/frontend/src/i18n/locales/ja.json index d682592..2c87a90 100644 --- a/frontend/src/i18n/locales/ja.json +++ b/frontend/src/i18n/locales/ja.json @@ -17,7 +17,18 @@ "usernameMinLength": "ユーザー名は3文字以上である必要があります", "passwordRequired": "パスワードを入力してください", "passwordMinLength": "パスワードは6文字以上である必要があります" - } + }, + "heroTitleLine1": "セキュアな", + "heroTitleLine2": "ライセンス管理", + "heroSubtitle": "エンタープライズグレードのプラットフォームで、ソフトウェアライセンス管理を効率化。", + "stats": { + "activeLicenses": "アクティブライセンス", + "uptime": "稼働率", + "support": "サポート" + }, + "welcomeTitle": "おかえりなさい", + "welcomeSubtitle": "アカウントにサインインして続けてください", + "copyright": "© 2025 Cedar-V. All rights reserved." }, "sidebar": { "expand": "サイドバーを展開", @@ -294,9 +305,8 @@ "licenseTrend": { "title": "ライセンストレンド", "quickOptions": { - "today": "今日", - "week": "今週", - "month": "今月" + "week": "直7日間", + "month": "直30日間" }, "datePicker": { "rangeSeparator": "から", @@ -313,9 +323,8 @@ "endDate": "終了日付", "separator": "から", "quickOptions": { - "today": "今日", - "week": "今週", - "month": "今月" + "week": "直7日間", + "month": "直30日間" } } }, diff --git a/frontend/src/i18n/locales/zh.json b/frontend/src/i18n/locales/zh.json index ded4df6..0f2a152 100644 --- a/frontend/src/i18n/locales/zh.json +++ b/frontend/src/i18n/locales/zh.json @@ -17,7 +17,18 @@ "usernameMinLength": "用户名至少需要3个字符", "passwordRequired": "请输入密码", "passwordMinLength": "密码至少需要6个字符" - } + }, + "heroTitleLine1": "软件授权", + "heroTitleLine2": "管理系统", + "heroSubtitle": "赋能软件商业化,构建 B2B 与 B2C 全场景的软件授权体系。", + "stats": { + "activeLicenses": "活跃许可证", + "uptime": "可用率", + "support": "全天支持" + }, + "welcomeTitle": "欢迎回来", + "welcomeSubtitle": "登录您的账户以继续", + "copyright": "© 2025 Cedar-V. 保留所有权利。" }, "sidebar": { "expand": "展开侧边栏", @@ -328,9 +339,8 @@ "licenseTrend": { "title": "授权趋势", "quickOptions": { - "today": "本日", - "week": "本周", - "month": "本月" + "week": "最近7天", + "month": "最近30天" }, "datePicker": { "rangeSeparator": "至", @@ -347,9 +357,8 @@ "endDate": "结束日期", "separator": "至", "quickOptions": { - "today": "本日", - "week": "本周", - "month": "本月" + "week": "最近7天", + "month": "最近30天" } } }, diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue index aa86e05..d95cc66 100644 --- a/frontend/src/views/Login.vue +++ b/frontend/src/views/Login.vue @@ -1,140 +1,138 @@{{ t('login.subtitle') }}
+ +