From df4332a2a35e7feba666b0ec4b27cbe1f4dad761 Mon Sep 17 00:00:00 2001 From: zhengchiliu <857493511@qq.com> Date: Fri, 11 Sep 2026 01:46:36 +0800 Subject: [PATCH] first commit --- .codebuddy/plans/dashboard-enrich_f71e5cc4.md | 212 ++ .../dashboard-usage-interaction_7516102a.md | 130 + .codebuddy/plans/前后端逻辑对齐_ced8a4e5.md | 110 + .../plans/智能衣橱管理后台前端_c7c50b5f.md | 142 + .gitignore | 39 + .vscode/extensions.json | 3 + README.md | 61 + env.d.ts | 1 + index.html | 13 + package-lock.json | 3187 +++++++++++++++++ package.json | 36 + public/favicon.ico | Bin 0 -> 4286 bytes src/App.vue | 3 + src/api/admin.ts | 33 + src/api/auth.ts | 28 + src/api/content.ts | 56 + src/api/dashboard.ts | 12 + src/api/goods.ts | 34 + src/api/notification.ts | 16 + src/api/order.ts | 34 + src/api/user.ts | 46 + src/assets/element-theme.css | 35 + src/assets/main.css | 84 + src/components/BaseChart.vue | 55 + src/components/PaginationBar.vue | 67 + src/components/SearchFormCard.vue | 53 + src/layout/AdminLayout.vue | 130 + src/layout/HeaderBar.vue | 233 ++ src/layout/SidebarMenu.vue | 148 + src/main.ts | 24 + src/router/index.ts | 127 + src/stores/auth.ts | 93 + src/types/auth.ts | 52 + src/types/common.ts | 21 + src/types/content.ts | 99 + src/types/dashboard.ts | 99 + src/types/goods.ts | 61 + src/types/notification.ts | 14 + src/types/order.ts | 58 + src/types/user.ts | 68 + src/utils/constants.ts | 176 + src/utils/format.ts | 34 + src/utils/request.ts | 182 + src/views/admin/AdminListView.vue | 279 ++ src/views/dashboard/DashboardView.vue | 711 ++++ src/views/goods/GoodsListView.vue | 422 +++ src/views/login/LoginView.vue | 191 + src/views/notification/NotifyView.vue | 220 ++ src/views/order/OrderListView.vue | 192 + src/views/order/RefundListView.vue | 231 ++ src/views/review/ClothesListView.vue | 241 ++ src/views/review/OutfitListView.vue | 349 ++ src/views/review/ShareListView.vue | 142 + src/views/user/UserListView.vue | 601 ++++ tsconfig.app.json | 18 + tsconfig.json | 11 + tsconfig.node.json | 27 + vite.config.ts | 27 + 58 files changed, 9771 insertions(+) create mode 100644 .codebuddy/plans/dashboard-enrich_f71e5cc4.md create mode 100644 .codebuddy/plans/dashboard-usage-interaction_7516102a.md create mode 100644 .codebuddy/plans/前后端逻辑对齐_ced8a4e5.md create mode 100644 .codebuddy/plans/智能衣橱管理后台前端_c7c50b5f.md create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 README.md create mode 100644 env.d.ts create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/favicon.ico create mode 100644 src/App.vue create mode 100644 src/api/admin.ts create mode 100644 src/api/auth.ts create mode 100644 src/api/content.ts create mode 100644 src/api/dashboard.ts create mode 100644 src/api/goods.ts create mode 100644 src/api/notification.ts create mode 100644 src/api/order.ts create mode 100644 src/api/user.ts create mode 100644 src/assets/element-theme.css create mode 100644 src/assets/main.css create mode 100644 src/components/BaseChart.vue create mode 100644 src/components/PaginationBar.vue create mode 100644 src/components/SearchFormCard.vue create mode 100644 src/layout/AdminLayout.vue create mode 100644 src/layout/HeaderBar.vue create mode 100644 src/layout/SidebarMenu.vue create mode 100644 src/main.ts create mode 100644 src/router/index.ts create mode 100644 src/stores/auth.ts create mode 100644 src/types/auth.ts create mode 100644 src/types/common.ts create mode 100644 src/types/content.ts create mode 100644 src/types/dashboard.ts create mode 100644 src/types/goods.ts create mode 100644 src/types/notification.ts create mode 100644 src/types/order.ts create mode 100644 src/types/user.ts create mode 100644 src/utils/constants.ts create mode 100644 src/utils/format.ts create mode 100644 src/utils/request.ts create mode 100644 src/views/admin/AdminListView.vue create mode 100644 src/views/dashboard/DashboardView.vue create mode 100644 src/views/goods/GoodsListView.vue create mode 100644 src/views/login/LoginView.vue create mode 100644 src/views/notification/NotifyView.vue create mode 100644 src/views/order/OrderListView.vue create mode 100644 src/views/order/RefundListView.vue create mode 100644 src/views/review/ClothesListView.vue create mode 100644 src/views/review/OutfitListView.vue create mode 100644 src/views/review/ShareListView.vue create mode 100644 src/views/user/UserListView.vue create mode 100644 tsconfig.app.json create mode 100644 tsconfig.json create mode 100644 tsconfig.node.json create mode 100644 vite.config.ts diff --git a/.codebuddy/plans/dashboard-enrich_f71e5cc4.md b/.codebuddy/plans/dashboard-enrich_f71e5cc4.md new file mode 100644 index 0000000..7a8a1a6 --- /dev/null +++ b/.codebuddy/plans/dashboard-enrich_f71e5cc4.md @@ -0,0 +1,212 @@ +--- +name: dashboard-enrich +overview: 前后端联动丰富运营仪表盘:后端新增趋势统计接口并扩展 summary 的「内容审核 / VIP / 商品」维度,前端引入 ECharts 用折线图、环形图等呈现。 +design: + architecture: + framework: vue + styleKeywords: + - 现代清爽 + - 渐变卡片 + - 数据可视化 + - 环形图 + fontSystem: + fontFamily: PingFang SC + heading: + size: 20px + weight: 700 + subheading: + size: 15px + weight: 600 + body: + size: 13px + weight: 400 + colorSystem: + primary: + - "#4F6EF7" + - "#6A5CF0" + - "#8B5CF6" + background: + - "#F5F7FB" + - "#FFFFFF" + text: + - "#1F2437" + - "#5D6685" + - "#9AA3C0" + functional: + - "#22C55E" + - "#F59E0B" + - "#EF4444" + - "#06B6D4" +todos: + - id: extend-dashboard-dto + content: 扩展后端仪表盘 DTO(Content/VIP/Goods/Trend) + status: completed + - id: extend-stats-dao + content: StatsDao 新增内容/VIP/商品/趋势统计方法 + status: completed + - id: extend-dashboard-service + content: DashboardService 聚合新维度并实现 Trend 方法 + status: completed + dependencies: + - extend-dashboard-dto + - extend-stats-dao + - id: add-trend-route + content: 新增 Trend handler 并注册 dashboard/trends 路由 + status: completed + dependencies: + - extend-dashboard-service + - id: setup-echarts + content: 安装 echarts 并封装 BaseChart 通用组件 + status: completed + - id: extend-dashboard-api + content: 扩展前端 dashboard 类型定义与 API 函数 + status: completed + dependencies: + - extend-dashboard-dto + - id: rebuild-dashboard-view + content: 重构仪表盘页渲染趋势折线图与三个分布环形图 + status: completed + dependencies: + - setup-echarts + - extend-dashboard-api +--- + +## 产品概述 + +在现有运营仪表盘基础上进行可视化升级:保留营收、用户、订单概况与待办横幅,新增时间趋势折线图和内容审核、VIP 会员、商品分类三个分布面板,让运营人员一眼掌握核心数据动态。 + +## 核心功能 + +- 近 7/30 天可切换的趋势折线图:新增用户数、已支付订单量、营收金额(双坐标轴) +- 内容审核概况:穿搭审核状态(待审核/通过/不通过/封禁)、衣物图片处理状态(处理中/成功/失败)、衣柜分享状态(正常/取消/过期/封禁)分布 +- VIP 会员概况:有效会员类型分布(月度/年度/体验)及 7 天内即将到期会员数 +- 商品分类统计:各类型商品数量分布与上架/下架占比 +- 保留现有 summary 各指标与页面布局,新增内容向后兼容、不影响已上线展示 + +## 技术栈 + +- 后端:Go + Gin + GORM(复用现有 StatsDao 直接聚合 MySQL 业务表,不改表结构) +- 前端:Vue 3 + TypeScript + Element Plus + ECharts(新增 echarts 依赖) +- 图表:ECharts 折线图 + 环形饼图 + +## 实现方案 + +后端复用现有 `DashboardService` 与 `StatsDao` 模式,将 `GET /dashboard/summary` 的响应扩展出 `content`、`vip`、`goods` 三个子结构(一次请求拿到全部概况),另新增 `GET /dashboard/trends?days=7|30` 返回按天对齐的趋势序列(无数据日期补零)。前端引入 ECharts,封装通用 `BaseChart.vue` 管理实例生命周期,在 DashboardView 内组合趋势折线图与三个环形分布图。 + +关键决策: + +- **趋势单独一个接口**:summary 保持轻量只做概况,趋势数据按需加载并支持 7/30 天切换,避免每次都聚合全量日期序列。 +- **按天补零在 Go 端完成**:SQL 只 group by 有数据的日期,Go 端从起始日期循环补零,保证折线图 x 轴连续、时区正确。 +- **双 y 轴**:营收(元)与数量量纲不同,趋势图用左轴数量、右轴金额。 +- **向后兼容**:DashboardResponse 只增字段不改字段,前端旧字段继续渲染,新字段独立面板。 + +数据口径: + +- 趋势新增用户:`users.created_at` 按日计数;订单量:`orders.order_status IN (2,5)` 且按 `pay_time` 计数(与营收同口径);营收:`orders.pay_amount` 求和(分)。 +- VIP 有效会员:`vip_type IN (2,3,4) AND vip_expire > now`;即将到期:`vip_expire BETWEEN now AND now+7*86400`。 +- 内容审核:穿搭按 `audit_status` 与 `status=2` 封禁数;衣物按 `image_process_status` 分组(1/2/3 归为处理中、4 成功、5 失败);分享按 `status` 分组。 + +## 架构设计 + +```mermaid +flowchart LR + subgraph Frontend + DV[DashboardView.vue] --> BC[BaseChart.vue] + DV --> API[api/dashboard.ts] + DV --> TYPES[types/dashboard.ts] + end + subgraph Backend + H[SummaryHandler / TrendHandler] --> S[DashboardService] + S --> DAO[StatsDao] + DAO --> M[(MySQL 业务表)] + end + API -->|GET /dashboard/summary| H + API -->|GET /dashboard/trends| H +``` + +## 关键数据结构(后端 dto/dashboard.go 扩展) + +``` +type DashboardResponse struct { + Users DashboardUsers `json:"users"` + Orders DashboardOrders `json:"orders"` + Revenue DashboardRevenue `json:"revenue"` + Todo DashboardTodo `json:"todo"` + Content DashboardContent `json:"content"` + VIP DashboardVIP `json:"vip"` + Goods DashboardGoods `json:"goods"` +} + +type DashboardContent struct { + Outfit DashboardOutfitStats `json:"outfit"` + Clothes DashboardClothesStats `json:"clothes"` + Share DashboardShareStats `json:"share"` +} + +type DashboardVIP struct { + MemberTotal int64 `json:"member_total"` + Monthly int64 `json:"monthly"` + Yearly int64 `json:"yearly"` + Trial int64 `json:"trial"` + ExpiringSoon int64 `json:"expiring_soon"` +} + +type DashboardGoods struct { + Total int64 `json:"total"` + OnShelf int64 `json:"on_shelf"` + OffShelf int64 `json:"off_shelf"` + ByType []GoodsTypeCount `json:"by_type"` +} + +type TrendPoint struct { + Date string `json:"date"` // YYYY-MM-DD + NewUsers int64 `json:"new_users"` + Orders int64 `json:"orders"` + Revenue int64 `json:"revenue"` // 分 +} +``` + +## 目录结构 + +``` +后端 /root/zt-closet-manage-backend/ +├── internal/dto/dashboard.go # [MODIFY] 扩展 Content/VIP/Goods 结构与 Trend 请求/响应结构 +├── internal/mysqldao/stats.go # [MODIFY] 新增 ContentStatsGet/VIPStatsGet/GoodsStatsGet/TrendStatsGet +├── internal/service/dashboard.go # [MODIFY] Summary 聚合新维度,新增 Trend 方法 +├── internal/routers/api/v1/dashboard.go # [MODIFY] 新增 Trend handler +└── internal/routers/router.go # [MODIFY] 注册 GET /dashboard/trends + +前端 /root/zt-closet-manage-frontend/ +├── package.json # [MODIFY] 新增 echarts 依赖 +├── src/components/BaseChart.vue # [NEW] ECharts 通用封装(init/resize/dispose/option 更新) +├── src/types/dashboard.ts # [MODIFY] 新增 Content/VIP/Goods/Trend 类型 +├── src/api/dashboard.ts # [MODIFY] 新增 getDashboardTrends +└── src/views/dashboard/DashboardView.vue # [MODIFY] 趋势折线图 + 内容/VIP/商品三个环形图面板 +``` + +## 实现要点 + +- DAO 趋势 SQL 使用 `DATE(FROM_UNIXTIME(created_at))` / `DATE(FROM_UNIXTIME(pay_time))` 分组,参数为秒级时间戳;返回 map[date]value 后由 service 按起始日期补零。 +- StatsDao 各新方法保持 `func (d *StatsDao) Xxx(ctx context.Context, ...) (*XxxStats, error)` 风格,`WithContext` + `span.RecordError`,与现有 stats.go 一致。 +- `TrendStatsGet` 用一次循环构造 `[]TrendPoint`,避免 N+1;`days` 参数在 handler 用 `ShouldBindQuery` 校验并限制 1~90。 +- 前端 `BaseChart.vue` 使用 `echarts.init`,`watch` option 深度更新,`ResizeObserver` 监听容器尺寸,`onBeforeUnmount` 时 `dispose` 防泄漏。 +- 趋势图折线:新增用户/订单量挂左轴,营收挂右轴(`formatMoney` 转元显示);分布图用 pie 环形,复用现有 `enumLabel` 常量映射文案。 +- 不改动已有接口字段,保证 summary 旧展示路径不回归;仅在前端 `DashboardSummary` 类型上新增可选字段并渲染新面板。 + +## 设计风格 + +延续现有管理后台的现代清爽风格,在现有渐变 hero 横幅、白底圆角卡片基础上做可视化升级,强调信息密度与层次感。趋势图采用通栏大卡片,内容审核、VIP 会员、商品分类采用三列卡片布局,图表配色与页面既有渐变色系统一。 + +## 页面布局 + +- 顶部保留渐变欢迎横幅与待办数字 +- 营收四卡片行保持不变 +- 新增通栏「数据趋势」卡片:7 天 / 30 天分段切换 + 双轴折线图 +- 新增三列分布卡片:内容审核概况、VIP 会员概况、商品分类统计,各配环形图与关键数字 +- 保留原有用户概况、订单概况面板 + +## 交互 + +- 趋势图切换 7/30 天时局部刷新,不整页加载 +- 环形图悬停显示数量与占比 tooltip +- 卡片沿用 hover 上浮阴影,保持与现有 stat-card 一致的微动效 \ No newline at end of file diff --git a/.codebuddy/plans/dashboard-usage-interaction_7516102a.md b/.codebuddy/plans/dashboard-usage-interaction_7516102a.md new file mode 100644 index 0000000..c3c9902 --- /dev/null +++ b/.codebuddy/plans/dashboard-usage-interaction_7516102a.md @@ -0,0 +1,130 @@ +--- +name: dashboard-usage-interaction +overview: 在运营仪表盘新增「今日消耗、COS 图数、点赞/收藏」指标:后端扩展 summary 聚合接口,前端新增展示卡片。 +todos: + - id: add-social-models + content: 在 business.go 中新增 Like、Collect 表模型镜像 + status: completed + - id: extend-dto-dao + content: 扩展 dashboard DTO 并新增 UsageStatsGet/SocialStatsGet 聚合方法 + status: completed + dependencies: + - add-social-models + - id: aggregate-summary + content: 在 DashboardService.Summary 中聚合 usage 与 social 维度 + status: completed + dependencies: + - extend-dto-dao + - id: extend-frontend-types + content: 扩展前端 dashboard 类型定义,新增 usage/social 字段 + status: completed + dependencies: + - extend-dto-dao + - id: render-dashboard-metrics + content: 在仪表盘页新增「今日消耗」「内容互动」两列指标卡片 + status: completed + dependencies: + - extend-frontend-types +--- + +## 产品概述 + +在现有运营仪表盘基础上,新增「今日消耗」与「内容互动」两组共 6 个运营指标,让运营人员直观掌握每日额度消耗与社区内容互动数据。 + +## 核心功能 + +- 今日 AI 推荐消耗次数 +- 今日衣柜分享消耗次数 +- 今日社区分享消耗次数 +- COS 总图数 +- 点赞数 +- 收藏数 + +## 展示说明 + +- 在营收卡片下方、数据趋势面板上方,新增一行两列卡片:「今日消耗」展示 AI 推荐/衣柜分享/社区分享三项今日次数,「内容互动」展示 COS 图数/点赞数/收藏数三项累计值。 +- 沿用现有 stat-card / mini-stat 卡片风格与图标配色,保持页面整体视觉一致。 + +## 技术栈 + +- 后端:Go + Gin + GORM,复用现有 `StatsDao` / `DashboardService`,不改表结构。 +- 前端:Vue 3 + TypeScript + Element Plus,复用现有卡片样式,无需新增依赖。 + +## 实现方案 + +扩展现有 `GET /dashboard/summary` 响应的 `DashboardResponse`,新增 `usage`(今日消耗)与 `social`(互动+COS)两个子结构,一次请求返回全部新增指标;前端在 `DashboardView.vue` 中新增一行两列卡片渲染。 + +数据口径(已通过业务服务源码确认): + +| 指标 | 数据来源 | 统计口径 | +| --- | --- | --- | +| 今日 AI 推荐消耗次数 | `user_daily_usages` | `stat_date = 今日(YYYYMMDD)`,`SUM(ai_recommend_count)` | +| 今日衣柜分享消耗次数 | `user_daily_usages` | `stat_date = 今日(YYYYMMDD)`,`SUM(closet_share_count)` | +| 今日社区分享消耗次数 | `user_daily_usages` | `stat_date = 今日(YYYYMMDD)`,`SUM(outfit_share_count)` | +| COS 总图数 | `clothes` | `processed_image != ''` 的记录数 | +| 点赞数 | `likes` | `status = 1`(已点赞)计数 | +| 收藏数 | `collects` | `status = 1`(已收藏)计数 | + + +关键决策: + +- **今日消耗合并为一次查询**:`user_daily_usages` 一行同时含三项计数字段,直接 `SUM` 三列并 `WHERE stat_date = ?`,避免三次查询。 +- **COS 总图数口径**:`clothes.processed_image` 是上传 COS 成功后回填的对象键路径,非空即代表已存图。 +- **点赞/收藏按累计总数**:用户未加「今日」前缀,与「今日消耗」形成区分,取 `status=1` 全量计数。 +- **Like/Collect 模型镜像补齐**:管理后台 `business.go` 当前缺少这两个表模型,按业务服务字段镜像新增,软删除由 `Model.DeletedAt` 自动过滤。 + +## 架构设计 + +沿用现有分层:`DashboardHandler.Summary → DashboardService.Summary → StatsDao → MySQL`。本次仅扩展 summary 聚合链路,不新增路由与 handler。 + +```mermaid +flowchart LR + DV[DashboardView.vue] --> API[api/dashboard.ts] + API --> H[SummaryHandler] + H --> S[DashboardService.Summary] + S --> DAO[StatsDao] + DAO --> M[(MySQL 业务表)] +``` + +## 目录结构 + +``` +后端 /root/zt-closet-manage-backend/ +├── internal/mysqlmodel/business.go # [MODIFY] 新增 Like、Collect 表模型镜像 +├── internal/dto/dashboard.go # [MODIFY] 新增 DashboardUsage/DashboardSocial 及 DashboardResponse 字段 +├── internal/mysqldao/stats.go # [MODIFY] 新增 UsageStatsGet/SocialStatsGet +└── internal/service/dashboard.go # [MODIFY] Summary 聚合 usage/social 维度 + +前端 /root/zt-closet-manage-frontend/ +├── src/types/dashboard.ts # [MODIFY] 新增 DashboardUsage/DashboardSocial 类型及 DashboardSummary 字段 +└── src/views/dashboard/DashboardView.vue # [MODIFY] 新增「今日消耗」「内容互动」两列卡片 +``` + +## 关键代码结构 + +``` +// dto/dashboard.go +type DashboardUsage struct { + AIRecommend int64 `json:"ai_recommend"` // 今日AI推荐消耗次数 + ClosetShare int64 `json:"closet_share"` // 今日衣柜分享消耗次数 + OutfitShare int64 `json:"outfit_share"` // 今日社区分享消耗次数 +} + +type DashboardSocial struct { + CosImageCount int64 `json:"cos_image_count"` // COS总图数 + LikeCount int64 `json:"like_count"` // 点赞数 + CollectCount int64 `json:"collect_count"` // 收藏数 +} + +// mysqldao/stats.go +func (d *StatsDao) UsageStatsGet(ctx context.Context, statDate int64) (*UsageStats, error) +func (d *StatsDao) SocialStatsGet(ctx context.Context) (*SocialStats, error) +``` + +## 实现要点 + +- `UsageStatsGet` 用单条 `Select("COALESCE(SUM(ai_recommend_count),0), COALESCE(SUM(closet_share_count),0), COALESCE(SUM(outfit_share_count),0)")` 配合 `Where("stat_date = ?", statDate)`,`Scan` 到三个字段。 +- `SocialStatsGet` 三条独立计数:`clothes.processed_image <> ''`、`likes.status = 1`、`collects.status = 1`,各自带 `span.RecordError` 与现有 DAO 风格一致。 +- `Summary` 内使用已存在的 `todayStatDate()`(service/service.go)计算今日 YYYYMMDD 整数,传给 `UsageStatsGet`。 +- 前端新增字段为可选读取(`summary?.usage` / `summary?.social`),旧后端响应未升级时不会报错;采用 6 个 `mini-stat` 数字块,分组放入两个 `panel`。 +- 不改动已有接口字段与展示路径,保证向后兼容。 \ No newline at end of file diff --git a/.codebuddy/plans/前后端逻辑对齐_ced8a4e5.md b/.codebuddy/plans/前后端逻辑对齐_ced8a4e5.md new file mode 100644 index 0000000..2a59dde --- /dev/null +++ b/.codebuddy/plans/前后端逻辑对齐_ced8a4e5.md @@ -0,0 +1,110 @@ +--- +name: 前后端逻辑对齐 +overview: 以后端最新代码为准,修复前端与后端不一致的地方,重点解决用户额度调整语义错配、额度凭证(grants)功能缺失、商品与订单字段缺失等问题。 +todos: + - id: align-user-types-api + content: 对齐用户额度/凭证类型并新增 revokeGrant 回收 API + status: completed + - id: update-user-view + content: 更新用户页额度发放表单与详情凭证列表回收 + status: completed + dependencies: + - align-user-types-api + - id: align-goods-types-view + content: 补齐商品 valid_days 等字段并更新商品表单与展示 + status: completed + - id: align-order-types-view + content: 补齐订单虚拟支付字段、枚举并更新订单详情展示 + status: completed +--- + +## 用户需求 + +后端管理代码有更新,需全量核对后端(/root/zt-closet-manage-backend)与前端(/root/zt-closet-manage-frontend)的逻辑一致性。以后端最新代码为基准,前端做适配,确保接口字段、请求语义、枚举映射完全对齐。 + +## 核对结论与变更点 + +经全量对比,登录鉴权、仪表盘、内容审核、通知、退款、响应结构与错误码均已一致,无需改动。存在以下 5 处不一致需要修复: + +1. **用户额度调整语义错配(功能不可用)**:后端已改为「发放额度凭证」语义,请求体为 `quota_type + amount + expire_days`;前端仍使用旧的 `quota_type + new_total + reason`,导致提交必失败。 +2. **用户额度凭证(grants)功能缺失**:后端用户详情已返回 `grants` 列表,并提供 `DELETE /users/:uuid/grants/:id` 回收接口;前端类型、API、页面展示与回收操作均缺失。 +3. **商品字段缺失**:后端商品新增 `valid_days`(有效期天数,可编辑)及只读的 `product_id`、`product_status`(虚拟支付道具);前端类型、表单与列表展示均未覆盖。 +4. **订单字段缺失**:后端订单新增 `xpay_product_id`、`xpay_platform`、`xpay_env`(虚拟支付信息);前端类型与详情展示均未覆盖。 +5. **支付渠道枚举缺失**:后端支付渠道为「1=微信支付、2=微信虚拟支付」;前端 `PAY_CHANNEL` 仅定义 value=1,虚拟支付订单会显示为 `-`。 + +## 技术栈 + +- 前端:Vue 3 + TypeScript + Element Plus + Pinia + axios(沿用现有架构,不引入新依赖) +- 后端:Go + Gin(只读参考,不修改) + +## 实现方案 + +以后端 `internal/dto/*.go` 的 JSON tag 与路由为唯一基准,逐项对齐前端 `src/types`、`src/api`、`src/utils/constants` 与对应 `src/views` 页面。 + +### 关键决策 + +- **额度调整语义重构**:将前端 `UserQuotaAdjustRequest` 改为 `{ quota_type, amount, expire_days }`,移除 `new_total`、`reason`。页面表单同步改为「发放数量 + 有效期天数」,提交 `amount`(1~100000000)与 `expire_days`(1~3650)。这是当前最严重的不一致,修复后功能才可用。 +- **补齐凭证管理闭环**:`UserDetailResponse` 增加 `grants: UserGrantItem[]`;`api/user.ts` 新增 `revokeGrant` 调用 `DELETE /users/:uuid/grants/:id`;详情抽屉展示凭证列表(类型/来源/数量/已用/到期/关联 ID)并增加「回收」操作,回收成功后重新拉取详情刷新。 +- **只读字段与可编辑字段分离**:商品 `product_id`、`product_status` 为只读,仅展示、不参与创建/更新提交;`valid_days` 可编辑,加入表单回显与提交。商品更新接口为「传什么改什么」的指针语义,前端编辑时仅提交可编辑字段。 +- **枚举与展示对齐**:`constants.ts` 新增 `GRANT_SOURCE`(1=会员包、2=加量包、3=广告激励),`PAY_CHANNEL` 补充 value=2(微信虚拟支付)。 +- **单位约定不变**:价格仍为「分」,前端继续用 `yuanToCents`/`formatMoney` 换算,避免引入新的金额逻辑。 + +### 实现注意事项 + +- 所有字段命名严格遵循后端 JSON tag(snake_case),禁止自创字段名。 +- 复用现有 `httpGet/httpPost/httpPut/httpDelete` 与 `enumLabel/enumTag/enumOptions/formatDate/formatText` 工具,不新增请求层逻辑。 +- 回收凭证后需重新调用 `getUserDetail` 刷新详情,避免展示陈旧数据。 +- 保持现有页面结构与组件风格,仅做字段级调整,不做无关重构。 + +## 目录结构 + +``` +zt-closet-manage-frontend/ +├── src/ +│ ├── types/ +│ │ ├── user.ts # [MODIFY] UserQuotaAdjustRequest 改为 amount+expire_days;新增 UserGrantItem;UserDetailResponse 增加 grants +│ │ ├── goods.ts # [MODIFY] GoodsItem 增加 valid_days/product_id/product_status;GoodsCreateRequest、GoodsUpdateRequest 增加 valid_days +│ │ └── order.ts # [MODIFY] OrderItem 增加 xpay_product_id/xpay_platform/xpay_env +│ ├── api/ +│ │ └── user.ts # [MODIFY] 新增 revokeGrant(uuid, grantId) 调用 DELETE /users/:uuid/grants/:id +│ ├── utils/ +│ │ └── constants.ts # [MODIFY] 新增 GRANT_SOURCE 枚举;PAY_CHANNEL 补充 value=2 +│ └── views/ +│ ├── user/ +│ │ └── UserListView.vue # [MODIFY] 额度表单改为发放数量+有效期天数;详情抽屉展示 grants 并增加回收操作 +│ ├── goods/ +│ │ └── GoodsListView.vue # [MODIFY] 表单增加 valid_days;列表/详情展示 product_id、product_status +│ └── order/ +│ └── OrderListView.vue # [MODIFY] 订单详情抽屉展示虚拟支付字段 +``` + +## 关键代码结构 + +用户域核心类型(需与后端 dto/user.go 严格对齐): + +```ts +// 额度发放请求(后端 UserQuotaAdjustRequest) +export interface UserQuotaAdjustRequest { + quota_type: number // 1=上传 2=AI 3=社区分享 4=衣柜分享 + amount: number // 发放数量,min=1 + expire_days: number // 有效期天数,min=1 +} + +// 用户额度凭证(后端 UserGrantItem) +export interface UserGrantItem { + id: number + quota_type: number + amount: number + used: number + source: number // 1=会员包 2=加量包 3=广告激励 + expire_time: number // 秒,0=跟随 VIP + ref_id: string + created_at: number +} + +// 用户详情(后端 UserDetailResponse) +export interface UserDetailResponse extends UserListItem { + quotas: QuotaItem[] + grants: UserGrantItem[] +} +``` \ No newline at end of file diff --git a/.codebuddy/plans/智能衣橱管理后台前端_c7c50b5f.md b/.codebuddy/plans/智能衣橱管理后台前端_c7c50b5f.md new file mode 100644 index 0000000..b42fdb3 --- /dev/null +++ b/.codebuddy/plans/智能衣橱管理后台前端_c7c50b5f.md @@ -0,0 +1,142 @@ +--- +name: 智能衣橱管理后台前端 +overview: 基于 Vue3 + TypeScript + Vite 从零搭建「智能衣橱」管理后台前端,对接 Go 后端 /api/v1 全部接口,覆盖登录鉴权、仪表盘、用户/商品/订单退款/内容审核/通知/管理员管理 8 大模块。 +design: + architecture: + framework: react + component: mui +--- + +## 产品概述 + +基于 zt-closet-manage-backend 后端 API 契约,从零构建「智能衣橱」管理后台前端系统(Vue 3 + TypeScript + Element Plus)。系统覆盖管理员登录鉴权(JWT 双 token 自动刷新)、仪表盘统计、用户管理、商品管理、订单与退款审核、内容审核(穿搭/衣物/衣柜分享)、通知推送,以及超级管理员专属的管理员账号管理,共 9 大功能模块。 + +## 核心功能 + +- **登录与鉴权**:账号密码登录,access/refresh 双 token 管理;access 过期自动用 refresh 换新并重放原请求;登出、修改密码;按 role 区分超管/普通管理员菜单与路由权限 +- **仪表盘**:统计卡片展示用户总数/今日新增/状态分布、订单状态分布、累计与今日营收/累计退款、待办事项(待处理退款、待审核穿搭、上架商品数),金额以元展示 +- **用户管理**:分页搜索(昵称/手机号/OpenID/状态)、详情查看(含四类额度)、封禁/解封(临时按天/永久)、额度人工调整、VIP 人工调整,均带原因填写与二次确认 +- **商品管理**:分页筛选(类型/状态/关键字)、新增、编辑、上下架、软删除;商品类型含会员包/上传包/AI 包/衣柜分享包/搭配分享包,金额按分输入、按元展示 +- **订单与退款**:订单列表筛选/详情抽屉;退款单列表(状态 0-3 可显式筛选待处理)、审核通过/驳回(必填备注原因) +- **内容审核**:穿搭列表筛选/详情(含衣物明细)、审核通过/驳回、封禁/解封;衣物列表/详情;衣柜分享列表/封禁/解封 +- **通知推送**:单用户系统通知、全量广播(返回发送人数),表单带字数限制校验 +- **管理员管理(超管专属)**:管理员列表、创建、编辑(昵称/密码/角色/状态)、删除;普通管理员无权限(后端 403,前端同时隐藏入口) +- **统一交互规范**:所有业务错误以 body.code 判断并提示;金额统一 `分→元` 格式化;时间戳统一格式化展示;列表统一分页(page/page_size 1~50) + +## 视觉要求 + +深色侧边栏 + 浅色内容区的经典管理后台布局;侧边栏按业务域分组菜单并支持折叠;顶部栏含面包屑、管理员信息、修改密码、登出;状态使用彩色 Tag 标签、操作按钮使用文字链接风格;表格斑马纹、hover 高亮;统计卡片带渐变图标底;弹窗表单统一 Element Plus 风格,操作均带确认与结果反馈。 + +## 技术栈 + +- **框架**:Vue 3.5(` + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ea5fa71 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3187 @@ +{ + "name": "zt-closet-manage-frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "zt-closet-manage-frontend", + "version": "0.0.0", + "dependencies": { + "@element-plus/icons-vue": "^2.3.2", + "axios": "^1.20.0", + "echarts": "^6.1.0", + "element-plus": "^2.14.5", + "pinia": "^4.0.3", + "vue": "^3.5.40", + "vue-router": "^4.6.4" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.4", + "@types/node": "^24.13.3", + "@vitejs/plugin-vue": "^6.0.8", + "@vue/tsconfig": "^0.9.1", + "npm-run-all2": "^9.0.2", + "typescript": "~6.0.0", + "vite": "^8.1.5", + "vite-plugin-vue-devtools": "^8.1.5", + "vue-tsc": "^3.3.7" + }, + "engines": { + "node": "^22.18.0 || >=24.12.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz", + "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-decorators": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz", + "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "http://mirrors.cloud.tencent.com/npm/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "http://mirrors.cloud.tencent.com/npm/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "http://mirrors.cloud.tencent.com/npm/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "http://mirrors.cloud.tencent.com/npm/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "http://mirrors.cloud.tencent.com/npm/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.148.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@oxc-project/types/-/types-0.148.0.tgz", + "integrity": "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "http://mirrors.cloud.tencent.com/npm/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.8", + "resolved": "http://mirrors.cloud.tencent.com/npm/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz", + "integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.7.tgz", + "integrity": "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.7.tgz", + "integrity": "sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.7.tgz", + "integrity": "sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.7.tgz", + "integrity": "sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.7.tgz", + "integrity": "sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.7.tgz", + "integrity": "sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.7.tgz", + "integrity": "sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.7.tgz", + "integrity": "sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.7.tgz", + "integrity": "sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.7.tgz", + "integrity": "sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.7.tgz", + "integrity": "sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.7.tgz", + "integrity": "sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.7.tgz", + "integrity": "sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.7.tgz", + "integrity": "sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.7.tgz", + "integrity": "sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node24": { + "version": "24.0.5", + "resolved": "http://mirrors.cloud.tencent.com/npm/@tsconfig/node24/-/node24-24.0.5.tgz", + "integrity": "sha512-DWC54fGPuhZgg3Ighg4Y/A/bA3ZdB5hnzAuv/MkQ/X85sVsBsMQxu8t7khutdYeiNksBbFdDyeqv1HSW2Zl8aA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.25", + "resolved": "http://mirrors.cloud.tencent.com/npm/@types/lodash/-/lodash-4.17.25.tgz", + "integrity": "sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "http://mirrors.cloud.tencent.com/npm/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "24.13.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/@types/node/-/node-24.13.3.tgz", + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "http://mirrors.cloud.tencent.com/npm/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.8", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vitejs/plugin-vue/-/plugin-vue-6.0.8.tgz", + "integrity": "sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "http://mirrors.cloud.tencent.com/npm/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "http://mirrors.cloud.tencent.com/npm/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "http://mirrors.cloud.tencent.com/npm/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.5.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", + "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.5.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", + "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@vue/babel-helper-vue-transform-on": "1.5.0", + "@vue/babel-plugin-resolve-type": "1.5.0", + "@vue/shared": "^3.5.18" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.5.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", + "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/parser": "^7.28.0", + "@vue/compiler-sfc": "^3.5.18" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/compiler-core/-/compiler-core-3.5.42.tgz", + "integrity": "sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/shared": "3.5.42", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/compiler-dom/-/compiler-dom-3.5.42.tgz", + "integrity": "sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.42", + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/compiler-sfc/-/compiler-sfc-3.5.42.tgz", + "integrity": "sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@vue/compiler-core": "3.5.42", + "@vue/compiler-dom": "3.5.42", + "@vue/compiler-ssr": "3.5.42", + "@vue/shared": "3.5.42", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.19", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/compiler-ssr/-/compiler-ssr-3.5.42.tgz", + "integrity": "sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.42", + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/devtools-api": { + "version": "8.2.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/devtools-api/-/devtools-api-8.2.1.tgz", + "integrity": "sha512-6u4vXBlIBAC1wMplIZgpyPn7uh/s4Bf6F5bMzvLv+EdJ0aHs/+4B7Ygv864EStQSjRbsRzTko/kUG1A1IejQ3A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/devtools-kit": "^8.2.1" + } + }, + "node_modules/@vue/devtools-core": { + "version": "8.2.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/devtools-core/-/devtools-core-8.2.1.tgz", + "integrity": "sha512-s/VfAY9oDTb/kFEWmy461jaFde2MIV1RO/gi1vwM+PAZBZ/Pc2Ndu3BNBdZUze8QDUuyYvElbEEGA83syjJfzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^8.2.1", + "@vue/devtools-shared": "^8.2.1" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "8.2.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/devtools-kit/-/devtools-kit-8.2.1.tgz", + "integrity": "sha512-FIGIuq3AWReEpbAHY/cRGeHDfI0qOb8OCQ3YjbEAX04uaxIDbGc9rhkbVcG7rnfHPXE3RsU5KrWOu9V/okd8AQ==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^8.2.1", + "birpc": "^2.6.1", + "hookable": "^5.5.3", + "perfect-debounce": "^2.0.0" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "8.2.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/devtools-shared/-/devtools-shared-8.2.1.tgz", + "integrity": "sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g==", + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "3.3.11", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/language-core/-/language-core-3.3.11.tgz", + "integrity": "sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.2.1", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.4" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/reactivity/-/reactivity-3.5.42.tgz", + "integrity": "sha512-TzNNfKpb7hDxbQltwAut8VDQA5YP+BuRlxntHUuRjyKwlMvmAPbs3unhCvieijifY6vFfVBwsS7wG/C7uq+bEQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/runtime-core/-/runtime-core-3.5.42.tgz", + "integrity": "sha512-9uACtuHs7vJGkm5Bp3xu4xRDLFTIYy5DgxpToVjqGIAhAEKwQfsaLvKINhM6nFVp6bZPRFGdDqd1g52MqKsotA==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.42", + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/runtime-dom/-/runtime-dom-3.5.42.tgz", + "integrity": "sha512-rsCmhiWLaRxGltLwhlCWyYkFn7WAbKRh0q17eZ1A6Dq6eqc2ACQ61IIryxz0LrsvCzHSilLA9JHovVwM8CNE2g==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.42", + "@vue/runtime-core": "3.5.42", + "@vue/shared": "3.5.42", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/server-renderer/-/server-renderer-3.5.42.tgz", + "integrity": "sha512-2++5dUyYS4gvo7xQXSECUDhB7TS0aOl5SeVfC5qSq1Jgfhjvegw1zqhwTIR3imZ+QYPJQw9gfcFvXGAjGZ7ajQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.42", + "@vue/runtime-dom": "3.5.42", + "@vue/shared": "3.5.42" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/shared/-/shared-3.5.42.tgz", + "integrity": "sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==", + "license": "MIT" + }, + "node_modules/@vue/tsconfig": { + "version": "0.9.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/tsconfig/-/tsconfig-0.9.1.tgz", + "integrity": "sha512-buvjm+9NzLCJL29KY1j1991YYJ5e6275OiK+G4jtmfIb+z4POywbdm0wXusT9adVWqe0xqg70TbI7+mRx4uU9w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">= 5.8", + "vue": "^3.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "node_modules/@vueuse/core": { + "version": "14.4.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vueuse/core/-/core-14.4.0.tgz", + "integrity": "sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.4.0", + "@vueuse/shared": "14.4.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "14.4.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vueuse/metadata/-/metadata-14.4.0.tgz", + "integrity": "sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "14.4.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vueuse/shared/-/shared-14.4.0.tgz", + "integrity": "sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/alien-signals": { + "version": "3.2.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/alien-signals/-/alien-signals-3.2.1.tgz", + "integrity": "sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-styles": { + "version": "7.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/ansi-styles/-/ansi-styles-7.0.0.tgz", + "integrity": "sha512-kKvt3m4uwzqL0wlkPd09CmljPJGOZZ4D0fP65sqFSvPkMRKhNi+74MgIJ5QxE6SxqB4t4KyUFGg8+n5zjo6hew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.3.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/ansis/-/ansis-4.3.1.tgz", + "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "http://mirrors.cloud.tencent.com/npm/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.20.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/axios/-/axios-1.20.0.tgz", + "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.6", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.21", + "resolved": "http://mirrors.cloud.tencent.com/npm/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz", + "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/browserslist": { + "version": "4.28.9", + "resolved": "http://mirrors.cloud.tencent.com/npm/browserslist/-/browserslist-4.28.9.tgz", + "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.20", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.420", + "node-releases": "^2.0.54", + "update-browserslist-db": "^1.3.2" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "http://mirrors.cloud.tencent.com/npm/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "http://mirrors.cloud.tencent.com/npm/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "http://mirrors.cloud.tencent.com/npm/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.23", + "resolved": "http://mirrors.cloud.tencent.com/npm/dayjs/-/dayjs-1.11.23.tgz", + "integrity": "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/echarts": { + "version": "6.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/echarts/-/echarts-6.1.0.tgz", + "integrity": "sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "6.1.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.423", + "resolved": "http://mirrors.cloud.tencent.com/npm/electron-to-chromium/-/electron-to-chromium-1.5.423.tgz", + "integrity": "sha512-rRZfTSY8ptHYMQxa+uIycJMFKmY1T0GIApNMXJYGehguTZa56TEEl19pKPCoBqk5Gpf7QizZn/jt7xur+DYxag==", + "dev": true, + "license": "ISC" + }, + "node_modules/element-plus": { + "version": "2.14.5", + "resolved": "http://mirrors.cloud.tencent.com/npm/element-plus/-/element-plus-2.14.5.tgz", + "integrity": "sha512-bghYy/S+qg87enHPXELirhEdDqsVAUGcGpbGIeG8dz0kwpIkGz7gYsifulBshXX74iRtHib85XWQj0uSH2A1Yg==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.2.0", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.8.0", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.8", + "@types/lodash": "^4.17.24", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "14.4.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.20", + "lodash": "^4.18.1", + "lodash-es": "^4.18.1", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0", + "vue-component-type-helpers": "^3.3.9" + }, + "peerDependencies": { + "vue": "^3.3.7" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-stack-parser-es": { + "version": "1.0.5", + "resolved": "http://mirrors.cloud.tencent.com/npm/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "http://mirrors.cloud.tencent.com/npm/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "http://mirrors.cloud.tencent.com/npm/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "4.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "6.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/json-parse-even-better-errors/-/json-parse-even-better-errors-6.0.0.tgz", + "integrity": "sha512-2/8adwnK1/+Fdjyts4r6wSpfANWw8zdNhU9U/Llk59c6O+DjSisPWPykwoL8gZmocP9Dy64S7oie2g+Mia123A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "http://mirrors.cloud.tencent.com/npm/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "http://mirrors.cloud.tencent.com/npm/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "http://mirrors.cloud.tencent.com/npm/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.54", + "resolved": "http://mirrors.cloud.tencent.com/npm/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, + "node_modules/nostics": { + "version": "1.2.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/nostics/-/nostics-1.2.0.tgz", + "integrity": "sha512-FGqEfhQjrvo1lL8KFifdTQiNwwQHJxC1jtYE1Rc54qF/jxONUNL+kC9gS1krX8Q65PgrQ5fCqH/I4NhWBvdSqg==", + "license": "MIT" + }, + "node_modules/npm-normalize-package-bin": { + "version": "6.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/npm-normalize-package-bin/-/npm-normalize-package-bin-6.0.0.tgz", + "integrity": "sha512-tdt4aFn9QamlhdN3HV2D2ccpBwO5/fyjjbXUxYA6uBjyekMZcZvDq0aSj9t5Jo+tih6AYFnt/cuIRn9013e0Uw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/npm-run-all2": { + "version": "9.0.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/npm-run-all2/-/npm-run-all2-9.0.3.tgz", + "integrity": "sha512-BQAEdU1PtYc48qYRdghW2BVTQT3VqWCoFQmO87NlM1h1PYwMCKQpUWaNyB20V26caNzFsXQDfyOdznLlHCih6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^7.0.0", + "cross-spawn": "^7.0.6", + "memorystream": "^0.3.1", + "picomatch": "^4.0.2", + "pidtree": "^1.0.0", + "read-package-json-fast": "^6.0.0", + "shell-quote": "^1.8.4", + "which": "^7.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0", + "npm": ">= 10" + } + }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "http://mirrors.cloud.tencent.com/npm/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/ohash": { + "version": "2.0.12", + "resolved": "http://mirrors.cloud.tencent.com/npm/ohash/-/ohash-2.0.12.tgz", + "integrity": "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==", + "dev": true, + "license": "MIT" + }, + "node_modules/open": { + "version": "11.0.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/open/-/open-11.0.2.tgz", + "integrity": "sha512-RWqF+pBSkqecEvCKOn8QYhaNdRMJDZRIrlS/7rTDdLHaPcfXGCZ/h8zb413NfvdeAV0MR7T1yJcA34/q+CSm1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.5.1", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.2.1", + "wsl-utils": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "1.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/pidtree/-/pidtree-1.0.0.tgz", + "integrity": "sha512-avfAvjB9Dd0wdj3rjJX//yS+G79OO0KrS5pJHFJENjYGX6N4SMgEDBBI/yFy0lloOYSaC6XQxzpOAMPfSYFV/Q==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/pinia": { + "version": "4.0.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/pinia/-/pinia-4.0.3.tgz", + "integrity": "sha512-XMQqpvjgG7LMqVhhFUzKLT4KEbsYbfZZ0CZU9PgdFm1O2VKBmIkykL8+SfNhOaT7sR0wT6BEgKT0YNDYWgmVRA==", + "license": "MIT", + "dependencies": { + "nostics": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/devtools-api": "^8.1.5", + "typescript": ">=5.6.0", + "vue": "^3.5.11" + }, + "peerDependenciesMeta": { + "@vue/devtools-api": { + "optional": false + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "http://mirrors.cloud.tencent.com/npm/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/powershell-utils": { + "version": "0.2.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/powershell-utils/-/powershell-utils-0.2.1.tgz", + "integrity": "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json-fast": { + "version": "6.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/read-package-json-fast/-/read-package-json-fast-6.0.0.tgz", + "integrity": "sha512-PNaGjoCnw9DBA2Kl8D+8po957z778q/HOPuY2u3Bkw/JO3eC8MDx7jn/PgMtSgpcBbs+6UOjDbwReGpXmRvs0g==", + "dev": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^6.0.0", + "npm-normalize-package-bin": "^6.0.0" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/rolldown": { + "version": "1.2.7", + "resolved": "http://mirrors.cloud.tencent.com/npm/rolldown/-/rolldown-1.2.7.tgz", + "integrity": "sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.148.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.7", + "@rolldown/binding-android-arm64": "1.2.7", + "@rolldown/binding-darwin-arm64": "1.2.7", + "@rolldown/binding-darwin-x64": "1.2.7", + "@rolldown/binding-freebsd-x64": "1.2.7", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.7", + "@rolldown/binding-linux-arm64-gnu": "1.2.7", + "@rolldown/binding-linux-arm64-musl": "1.2.7", + "@rolldown/binding-linux-ppc64-gnu": "1.2.7", + "@rolldown/binding-linux-s390x-gnu": "1.2.7", + "@rolldown/binding-linux-x64-gnu": "1.2.7", + "@rolldown/binding-linux-x64-musl": "1.2.7", + "@rolldown/binding-openharmony-arm64": "1.2.7", + "@rolldown/binding-win32-arm64-msvc": "1.2.7", + "@rolldown/binding-win32-x64-msvc": "1.2.7" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.10.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "http://mirrors.cloud.tencent.com/npm/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.3.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "http://mirrors.cloud.tencent.com/npm/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/unplugin-utils": { + "version": "0.3.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/unplugin-utils/-/unplugin-utils-0.3.2.tgz", + "integrity": "sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "8.2.2", + "resolved": "http://mirrors.cloud.tencent.com/npm/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-dev-rpc": { + "version": "2.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/vite-dev-rpc/-/vite-dev-rpc-2.0.0.tgz", + "integrity": "sha512-yKwbTwdHKSD2k/aGqyWpPHepo45OQc8lH3/6IfT4ZqeKE26ooKvi4WIEKzqWav8v+9Is8u1k8q54hvOmqASazA==", + "dev": true, + "license": "MIT", + "dependencies": { + "birpc": "^4.0.0", + "vite-hot-client": "^2.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0 || ^8.0.0" + } + }, + "node_modules/vite-dev-rpc/node_modules/birpc": { + "version": "4.2.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/birpc/-/birpc-4.2.0.tgz", + "integrity": "sha512-KxgKcZPfrtzJDDALHPguGpGJUrzdgpymyiQQgzFjWreHMOpWrnFNVREr5J48x2DBh8ZVioscrV1SBkDipGiX+Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/vite-hot-client": { + "version": "2.2.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/vite-hot-client/-/vite-hot-client-2.2.0.tgz", + "integrity": "sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 || ^8.0.0" + } + }, + "node_modules/vite-plugin-inspect": { + "version": "11.4.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/vite-plugin-inspect/-/vite-plugin-inspect-11.4.1.tgz", + "integrity": "sha512-ShOFe2PURXGvRS5OrgmOLZOCwDTD7dEBVt0tMpFPKb9AsvqXKCRGM8QgKrUbRbJYFXScHvDPpGRd28rYidC0tA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^4.3.0", + "error-stack-parser-es": "^1.0.5", + "obug": "^2.1.1", + "ohash": "^2.0.11", + "open": "^11.0.0", + "perfect-debounce": "^2.1.0", + "sirv": "^3.0.2", + "unplugin-utils": "^0.3.1", + "vite-dev-rpc": "^2.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0-0 || ^8.0.0-0" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/vite-plugin-vue-devtools": { + "version": "8.2.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/vite-plugin-vue-devtools/-/vite-plugin-vue-devtools-8.2.1.tgz", + "integrity": "sha512-5JLxXWWCo5lJMw16/xVeNvJ8k2zLwZPf1vITLzya/2IePrCBeGe/p/iAokgXHZpEi39fcYtPXmO8SaKeXmqCAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/devtools-core": "^8.2.1", + "@vue/devtools-kit": "^8.2.1", + "@vue/devtools-shared": "^8.2.1", + "sirv": "^3.0.2", + "vite-plugin-inspect": "^11.3.3", + "vite-plugin-vue-inspector": "^6.0.0" + }, + "engines": { + "node": ">=v14.21.3" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/vite-plugin-vue-inspector": { + "version": "6.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/vite-plugin-vue-inspector/-/vite-plugin-vue-inspector-6.0.0.tgz", + "integrity": "sha512-OpyITJLgZNibxlrik1EmRtvXHDjLRxNPsWkGFTERZs2LgMEdG4W0WoFt5GIgp3a3jRou+eJR8U1zOBk/XQgEbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.0", + "@babel/plugin-proposal-decorators": "^7.23.0", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-transform-typescript": "^7.22.15", + "@vue/babel-plugin-jsx": "^1.1.5", + "@vue/compiler-dom": "^3.3.4", + "kolorist": "^1.8.0", + "magic-string": "^0.30.4" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/vscode-uri": { + "version": "3.2.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/vscode-uri/-/vscode-uri-3.2.0.tgz", + "integrity": "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.42", + "resolved": "http://mirrors.cloud.tencent.com/npm/vue/-/vue-3.5.42.tgz", + "integrity": "sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.42", + "@vue/compiler-sfc": "3.5.42", + "@vue/runtime-dom": "3.5.42", + "@vue/server-renderer": "3.5.42", + "@vue/shared": "3.5.42" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-component-type-helpers": { + "version": "3.3.11", + "resolved": "http://mirrors.cloud.tencent.com/npm/vue-component-type-helpers/-/vue-component-type-helpers-3.3.11.tgz", + "integrity": "sha512-LwcxzeliO9fkQcpJG0PoX8X5kmAhKmH9wkpDLxNabwzkQ9Zeib2YVHwFV4pcWmMLfXVfjr/dSV+DaJ3cIPgSNA==", + "license": "MIT" + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "http://mirrors.cloud.tencent.com/npm/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-router/node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "http://mirrors.cloud.tencent.com/npm/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/vue-tsc": { + "version": "3.3.11", + "resolved": "http://mirrors.cloud.tencent.com/npm/vue-tsc/-/vue-tsc-3.3.11.tgz", + "integrity": "sha512-gOb0B9rtU2+f1dszwPqSH5kAieIF9ReeLhD3kSRNHv5WZZUQz/JdVXW0RTdqhNTMlQkqKzrTTviqKr/4FYZraQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.3.11" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/which": { + "version": "7.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/which/-/which-7.0.0.tgz", + "integrity": "sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/wsl-utils": { + "version": "1.0.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/wsl-utils/-/wsl-utils-1.0.0.tgz", + "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "http://mirrors.cloud.tencent.com/npm/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/zrender": { + "version": "6.1.0", + "resolved": "http://mirrors.cloud.tencent.com/npm/zrender/-/zrender-6.1.0.tgz", + "integrity": "sha512-oEGMDB6pOP2S6OwRR4PdVv610zrjnA3Bh+JnSG12fYJlBKjtNAoEb5fSUoCOOINlH96I2fU38/A2UpRKs67xYQ==", + "license": "BSD-3-Clause", + "dependencies": { + "tslib": "2.3.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b729d58 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "zt-closet-manage-frontend", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "run-p type-check \"build-only {@}\" --", + "preview": "vite preview", + "build-only": "vite build", + "type-check": "vue-tsc --build" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.3.2", + "axios": "^1.20.0", + "echarts": "^6.1.0", + "element-plus": "^2.14.5", + "pinia": "^4.0.3", + "vue": "^3.5.40", + "vue-router": "^4.6.4" + }, + "devDependencies": { + "@tsconfig/node24": "^24.0.4", + "@types/node": "^24.13.3", + "@vitejs/plugin-vue": "^6.0.8", + "@vue/tsconfig": "^0.9.1", + "npm-run-all2": "^9.0.2", + "typescript": "~6.0.0", + "vite": "^8.1.5", + "vite-plugin-vue-devtools": "^8.1.5", + "vue-tsc": "^3.3.7" + }, + "engines": { + "node": "^22.18.0 || >=24.12.0" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..98240ae --- /dev/null +++ b/src/App.vue @@ -0,0 +1,3 @@ + diff --git a/src/api/admin.ts b/src/api/admin.ts new file mode 100644 index 0000000..cfbae6c --- /dev/null +++ b/src/api/admin.ts @@ -0,0 +1,33 @@ +import { httpDelete, httpGet, httpPost, httpPut } from '@/utils/request' +import type { PageResult } from '@/types/common' +import type { + AdminCreateRequest, + AdminInfo, + AdminUpdateRequest, +} from '@/types/auth' + +export interface AdminListQuery { + page?: number + page_size?: number + status?: number +} + +/** 管理员分页列表(超管专属) */ +export function getAdminList(query: AdminListQuery): Promise> { + return httpGet>('/admins', { ...query }) +} + +/** 创建管理员 */ +export function createAdmin(data: AdminCreateRequest): Promise { + return httpPost('/admins', data) +} + +/** 更新管理员 */ +export function updateAdmin(id: number, data: AdminUpdateRequest): Promise> { + return httpPut>(`/admins/${id}`, data) +} + +/** 删除管理员(软删) */ +export function deleteAdmin(id: number): Promise> { + return httpDelete>(`/admins/${id}`) +} diff --git a/src/api/auth.ts b/src/api/auth.ts new file mode 100644 index 0000000..8d09ec3 --- /dev/null +++ b/src/api/auth.ts @@ -0,0 +1,28 @@ +import { httpPost, httpPut } from '@/utils/request' +import type { + AdminChangePasswordRequest, + AdminLoginRequest, + AdminLoginResponse, + AdminRefreshTokenRequest, + AdminRefreshTokenResponse, +} from '@/types/auth' + +/** 管理员登录 */ +export function login(data: AdminLoginRequest): Promise { + return httpPost('/admin/login', data) +} + +/** 刷新双 token */ +export function refreshToken(data: AdminRefreshTokenRequest): Promise { + return httpPost('/admin/refresh-token', data) +} + +/** 登出(吊销 refresh + 当前 access) */ +export function logout(refresh_token: string): Promise> { + return httpPost>('/admin/logout', { refresh_token }) +} + +/** 修改自己密码 */ +export function changePassword(data: AdminChangePasswordRequest): Promise> { + return httpPut>('/admin/password', data) +} diff --git a/src/api/content.ts b/src/api/content.ts new file mode 100644 index 0000000..8b8829e --- /dev/null +++ b/src/api/content.ts @@ -0,0 +1,56 @@ +import { httpGet, httpPost } from '@/utils/request' +import type { PageResult } from '@/types/common' +import type { + ClosetShareItem, + ClosetShareListQuery, + ClothesItem, + ClothesListQuery, + OutfitAuditRequest, + OutfitBanRequest, + OutfitDetailResponse, + OutfitListItem, + OutfitListQuery, +} from '@/types/content' + +/* ---------------- 穿搭 ---------------- */ +export function getOutfitList(query: OutfitListQuery): Promise> { + return httpGet>('/outfits', { ...query }) +} + +export function getOutfitDetail(uuid: string): Promise { + return httpGet(`/outfits/${uuid}`) +} + +export function auditOutfit(uuid: string, data: OutfitAuditRequest): Promise> { + return httpPost>(`/outfits/${uuid}/audit`, data) +} + +export function banOutfit(uuid: string, data: OutfitBanRequest): Promise> { + return httpPost>(`/outfits/${uuid}/ban`, data) +} + +export function unbanOutfit(uuid: string): Promise> { + return httpPost>(`/outfits/${uuid}/unban`) +} + +/* ---------------- 衣物 ---------------- */ +export function getClothesList(query: ClothesListQuery): Promise> { + return httpGet>('/clothes', { ...query }) +} + +export function getClothesDetail(uuid: string): Promise { + return httpGet(`/clothes/${uuid}`) +} + +/* ---------------- 衣柜分享 ---------------- */ +export function getClosetShareList(query: ClosetShareListQuery): Promise> { + return httpGet>('/closet-shares', { ...query }) +} + +export function banClosetShare(uuid: string): Promise> { + return httpPost>(`/closet-shares/${uuid}/ban`) +} + +export function unbanClosetShare(uuid: string): Promise> { + return httpPost>(`/closet-shares/${uuid}/unban`) +} diff --git a/src/api/dashboard.ts b/src/api/dashboard.ts new file mode 100644 index 0000000..b31c46e --- /dev/null +++ b/src/api/dashboard.ts @@ -0,0 +1,12 @@ +import { httpGet } from '@/utils/request' +import type { DashboardSummary, DashboardTrends } from '@/types/dashboard' + +/** 仪表盘核心指标聚合 */ +export function getDashboardSummary(): Promise { + return httpGet('/dashboard/summary') +} + +/** 仪表盘近 N 天趋势 */ +export function getDashboardTrends(days = 30): Promise { + return httpGet('/dashboard/trends', { days }) +} diff --git a/src/api/goods.ts b/src/api/goods.ts new file mode 100644 index 0000000..3a5efe6 --- /dev/null +++ b/src/api/goods.ts @@ -0,0 +1,34 @@ +import { httpDelete, httpGet, httpPost, httpPut } from '@/utils/request' +import type { PageResult } from '@/types/common' +import type { + GoodsCreateRequest, + GoodsItem, + GoodsListQuery, + GoodsStatusRequest, + GoodsUpdateRequest, +} from '@/types/goods' + +/** 商品分页列表(含下架) */ +export function getGoodsList(query: GoodsListQuery): Promise> { + return httpGet>('/goods', { ...query }) +} + +/** 创建商品 */ +export function createGoods(data: GoodsCreateRequest): Promise { + return httpPost('/goods', data) +} + +/** 更新商品(传什么改什么) */ +export function updateGoods(id: number, data: GoodsUpdateRequest): Promise> { + return httpPut>(`/goods/${id}`, data) +} + +/** 上下架 */ +export function updateGoodsStatus(id: number, data: GoodsStatusRequest): Promise> { + return httpPut>(`/goods/${id}/status`, data) +} + +/** 软删除商品 */ +export function deleteGoods(id: number): Promise> { + return httpDelete>(`/goods/${id}`) +} diff --git a/src/api/notification.ts b/src/api/notification.ts new file mode 100644 index 0000000..7c82b5f --- /dev/null +++ b/src/api/notification.ts @@ -0,0 +1,16 @@ +import { httpPost } from '@/utils/request' +import type { + NotificationBroadcastRequest, + NotificationBroadcastResponse, + NotificationSendRequest, +} from '@/types/notification' + +/** 单用户系统通知 */ +export function sendNotification(data: NotificationSendRequest): Promise> { + return httpPost>('/notifications', data) +} + +/** 全量广播 */ +export function broadcastNotification(data: NotificationBroadcastRequest): Promise { + return httpPost('/notifications/broadcast', data) +} diff --git a/src/api/order.ts b/src/api/order.ts new file mode 100644 index 0000000..813e727 --- /dev/null +++ b/src/api/order.ts @@ -0,0 +1,34 @@ +import { httpGet, httpPost } from '@/utils/request' +import type { PageResult } from '@/types/common' +import type { + OrderItem, + OrderListQuery, + RefundAuditRequest, + RefundItem, + RefundListQuery, +} from '@/types/order' + +/** 订单分页列表 */ +export function getOrderList(query: OrderListQuery): Promise> { + return httpGet>('/orders', { ...query }) +} + +/** 订单详情 */ +export function getOrderDetail(orderNo: string): Promise { + return httpGet(`/orders/${orderNo}`) +} + +/** 退款单分页列表 */ +export function getRefundList(query: RefundListQuery): Promise> { + return httpGet>('/refunds', { ...query }) +} + +/** 退款审核通过 */ +export function approveRefund(refundNo: string, data: RefundAuditRequest): Promise> { + return httpPost>(`/refunds/${refundNo}/approve`, data) +} + +/** 退款审核驳回 */ +export function rejectRefund(refundNo: string, data: RefundAuditRequest): Promise> { + return httpPost>(`/refunds/${refundNo}/reject`, data) +} diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 0000000..de38de7 --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,46 @@ +import { httpDelete, httpGet, httpPut } from '@/utils/request' +import type { PageResult } from '@/types/common' +import type { + UserBanRequest, + UserDetailResponse, + UserListItem, + UserListQuery, + UserQuotaAdjustRequest, + UserUnbanRequest, + UserVIPAdjustRequest, +} from '@/types/user' + +/** 用户分页列表 */ +export function getUserList(query: UserListQuery): Promise> { + return httpGet>('/users', { ...query }) +} + +/** 用户详情(含四类额度) */ +export function getUserDetail(uuid: string): Promise { + return httpGet(`/users/${uuid}`) +} + +/** 封禁用户 */ +export function banUser(uuid: string, data: UserBanRequest): Promise> { + return httpPut>(`/users/${uuid}/ban`, data) +} + +/** 解封用户 */ +export function unbanUser(uuid: string, data: UserUnbanRequest): Promise> { + return httpPut>(`/users/${uuid}/unban`, data) +} + +/** 额度人工调整 */ +export function adjustUserQuota(uuid: string, data: UserQuotaAdjustRequest): Promise> { + return httpPut>(`/users/${uuid}/quota`, data) +} + +/** VIP 人工调整 */ +export function adjustUserVip(uuid: string, data: UserVIPAdjustRequest): Promise> { + return httpPut>(`/users/${uuid}/vip`, data) +} + +/** 回收额度凭证 */ +export function revokeGrant(uuid: string, grantId: number): Promise> { + return httpDelete>(`/users/${uuid}/grants/${grantId}`) +} diff --git a/src/assets/element-theme.css b/src/assets/element-theme.css new file mode 100644 index 0000000..ee266b9 --- /dev/null +++ b/src/assets/element-theme.css @@ -0,0 +1,35 @@ +/* Element Plus 主题定制:靛蓝主色 + 深色侧边栏协调色 */ +:root { + --el-color-primary: #4f6ef7; + --el-color-primary-light-3: #7d93f9; + --el-color-primary-light-5: #a7b6fb; + --el-color-primary-light-7: #d1d9fd; + --el-color-primary-light-8: #e4e9fe; + --el-color-primary-light-9: #f2f4fe; + --el-color-primary-dark-2: #3f58c6; + + --el-border-radius-base: 8px; + --el-font-size-base: 14px; + + /* 管理后台侧边栏配色 */ + --zt-sidebar-bg: #1e2438; + --zt-sidebar-bg-light: #272f4a; + --zt-sidebar-text: #9aa3c0; + --zt-sidebar-active: #4f6ef7; +} + +/* 全局滚动条 */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} +::-webkit-scrollbar-thumb { + background: #c6cbdd; + border-radius: 4px; +} +::-webkit-scrollbar-thumb:hover { + background: #a8aec7; +} +::-webkit-scrollbar-track { + background: transparent; +} diff --git a/src/assets/main.css b/src/assets/main.css new file mode 100644 index 0000000..0cdb653 --- /dev/null +++ b/src/assets/main.css @@ -0,0 +1,84 @@ +html, +body, +#app { + height: 100%; + margin: 0; + padding: 0; +} + +body { + font-family: + 'PingFang SC', + 'Helvetica Neue', + 'Microsoft YaHei', + 'Segoe UI', + Arial, + sans-serif; + font-size: 14px; + color: #2b3044; + background: #f4f6fb; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +a { + text-decoration: none; + color: inherit; +} + +/* 通用页面卡片 */ +.zt-card { + background: #fff; + border-radius: 12px; + box-shadow: 0 2px 12px rgba(30, 36, 56, 0.05); + padding: 20px; + margin-bottom: 16px; +} + +.zt-card-title { + font-size: 15px; + font-weight: 600; + color: #1f2437; + margin-bottom: 16px; +} + +/* 金额与数字 */ +.zt-money { + font-weight: 600; + color: #f56c6c; + font-variant-numeric: tabular-nums; +} + +/* 表格操作列 */ +.zt-table-actions .el-button + .el-button { + margin-left: 8px; +} + +/* 分页右对齐 */ +.zt-pagination { + display: flex; + justify-content: flex-end; + margin-top: 16px; +} + +/* 筛选区 */ +.zt-filter { + display: flex; + flex-wrap: wrap; + gap: 12px 16px; + align-items: center; +} + +.zt-filter .el-input { + width: 200px; +} + +.zt-filter .el-select { + width: 160px; +} diff --git a/src/components/BaseChart.vue b/src/components/BaseChart.vue new file mode 100644 index 0000000..af19e6c --- /dev/null +++ b/src/components/BaseChart.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/src/components/PaginationBar.vue b/src/components/PaginationBar.vue new file mode 100644 index 0000000..af69ce8 --- /dev/null +++ b/src/components/PaginationBar.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/src/components/SearchFormCard.vue b/src/components/SearchFormCard.vue new file mode 100644 index 0000000..a881cab --- /dev/null +++ b/src/components/SearchFormCard.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/src/layout/AdminLayout.vue b/src/layout/AdminLayout.vue new file mode 100644 index 0000000..c2bc990 --- /dev/null +++ b/src/layout/AdminLayout.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/src/layout/HeaderBar.vue b/src/layout/HeaderBar.vue new file mode 100644 index 0000000..a881633 --- /dev/null +++ b/src/layout/HeaderBar.vue @@ -0,0 +1,233 @@ + + + + + diff --git a/src/layout/SidebarMenu.vue b/src/layout/SidebarMenu.vue new file mode 100644 index 0000000..d71decd --- /dev/null +++ b/src/layout/SidebarMenu.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..522a4c3 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,24 @@ +import { createApp } from 'vue' +import { createPinia } from 'pinia' +import ElementPlus from 'element-plus' +import zhCn from 'element-plus/es/locale/lang/zh-cn' +import * as ElementPlusIconsVue from '@element-plus/icons-vue' + +import App from './App.vue' +import router from './router' + +import 'element-plus/dist/index.css' +import './assets/element-theme.css' +import './assets/main.css' + +const app = createApp(App) + +for (const [key, component] of Object.entries(ElementPlusIconsVue)) { + app.component(key, component) +} + +app.use(createPinia()) +app.use(router) +app.use(ElementPlus, { locale: zhCn }) + +app.mount('#app') diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..decd095 --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,127 @@ +import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' +import { ElMessage } from 'element-plus' +import { useAuthStore } from '@/stores/auth' + +declare module 'vue-router' { + interface RouteMeta { + /** 页面标题(面包屑与 document.title) */ + title?: string + /** 是否需要登录 */ + requiresAuth?: boolean + /** 是否仅超级管理员可见 */ + superOnly?: boolean + } +} + +const routes: RouteRecordRaw[] = [ + { + path: '/login', + name: 'login', + component: () => import('@/views/login/LoginView.vue'), + meta: { title: '登录' }, + }, + { + path: '/', + component: () => import('@/layout/AdminLayout.vue'), + meta: { requiresAuth: true }, + children: [ + { + path: '', + redirect: '/dashboard', + }, + { + path: 'dashboard', + name: 'dashboard', + component: () => import('@/views/dashboard/DashboardView.vue'), + meta: { title: '仪表盘', requiresAuth: true }, + }, + { + path: 'users', + name: 'users', + component: () => import('@/views/user/UserListView.vue'), + meta: { title: '用户管理', requiresAuth: true }, + }, + { + path: 'goods', + name: 'goods', + component: () => import('@/views/goods/GoodsListView.vue'), + meta: { title: '商品管理', requiresAuth: true }, + }, + { + path: 'orders', + name: 'orders', + component: () => import('@/views/order/OrderListView.vue'), + meta: { title: '订单管理', requiresAuth: true }, + }, + { + path: 'refunds', + name: 'refunds', + component: () => import('@/views/order/RefundListView.vue'), + meta: { title: '退款审核', requiresAuth: true }, + }, + { + path: 'review/outfits', + name: 'review-outfits', + component: () => import('@/views/review/OutfitListView.vue'), + meta: { title: '穿搭审核', requiresAuth: true }, + }, + { + path: 'review/clothes', + name: 'review-clothes', + component: () => import('@/views/review/ClothesListView.vue'), + meta: { title: '衣物管理', requiresAuth: true }, + }, + { + path: 'review/shares', + name: 'review-shares', + component: () => import('@/views/review/ShareListView.vue'), + meta: { title: '衣柜分享', requiresAuth: true }, + }, + { + path: 'notifications', + name: 'notifications', + component: () => import('@/views/notification/NotifyView.vue'), + meta: { title: '通知推送', requiresAuth: true }, + }, + { + path: 'admins', + name: 'admins', + component: () => import('@/views/admin/AdminListView.vue'), + meta: { title: '管理员管理', requiresAuth: true, superOnly: true }, + }, + ], + }, + { + path: '/:pathMatch(.*)*', + redirect: '/dashboard', + }, +] + +const router = createRouter({ + history: createWebHistory(), + routes, +}) + +router.beforeEach((to) => { + const authStore = useAuthStore() + const token = authStore.accessToken + + if (to.meta.requiresAuth && !token) { + return { path: '/login', query: { redirect: to.fullPath } } + } + if (to.path === '/login' && token) { + return { path: '/dashboard' } + } + // 超管专属路由:非超管重定向并提示 + if (to.meta.superOnly && token && !authStore.isSuper) { + ElMessage.warning('该功能仅超级管理员可用') + return { path: '/dashboard' } + } + + if (to.meta.title) { + document.title = `${to.meta.title} · 纸条衣橱管理后台` + } + return true +}) + +export default router diff --git a/src/stores/auth.ts b/src/stores/auth.ts new file mode 100644 index 0000000..b43034c --- /dev/null +++ b/src/stores/auth.ts @@ -0,0 +1,93 @@ +import { computed, ref } from 'vue' +import { defineStore } from 'pinia' +import type { AdminInfo } from '@/types/auth' + +const ACCESS_TOKEN_KEY = 'zt_admin_access_token' +const REFRESH_TOKEN_KEY = 'zt_admin_refresh_token' +const ADMIN_INFO_KEY = 'zt_admin_info' +const TOKEN_EXPIRE_KEY = 'zt_admin_expire_time' + +export interface StoredAuth { + accessToken: string + refreshToken: string + expireTime: number + adminInfo: AdminInfo | null +} + +function loadStored(): StoredAuth { + return { + accessToken: localStorage.getItem(ACCESS_TOKEN_KEY) ?? '', + refreshToken: localStorage.getItem(REFRESH_TOKEN_KEY) ?? '', + expireTime: Number(localStorage.getItem(TOKEN_EXPIRE_KEY) ?? '0'), + adminInfo: parseAdminInfo(localStorage.getItem(ADMIN_INFO_KEY)), + } +} + +function parseAdminInfo(raw: string | null): AdminInfo | null { + if (!raw) return null + try { + return JSON.parse(raw) as AdminInfo + } catch { + return null + } +} + +export const useAuthStore = defineStore('auth', () => { + const initial = loadStored() + const accessToken = ref(initial.accessToken) + const refreshToken = ref(initial.refreshToken) + const expireTime = ref(initial.expireTime) + const adminInfo = ref(initial.adminInfo) + + const isLoggedIn = computed(() => accessToken.value !== '') + const isSuper = computed(() => adminInfo.value?.role === 1) + + /** 请求层(utils/request.ts)刷新成功后调用,仅同步 token,不改动 adminInfo */ + function applyTokens(tokens: { access_token: string; refresh_token: string; expire_time: number }) { + accessToken.value = tokens.access_token + refreshToken.value = tokens.refresh_token + expireTime.value = tokens.expire_time + localStorage.setItem(ACCESS_TOKEN_KEY, tokens.access_token) + localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refresh_token) + localStorage.setItem(TOKEN_EXPIRE_KEY, String(tokens.expire_time)) + } + + function setSession(payload: { + access_token: string + refresh_token: string + expire_time: number + admin_info: AdminInfo + }) { + accessToken.value = payload.access_token + refreshToken.value = payload.refresh_token + expireTime.value = payload.expire_time + adminInfo.value = payload.admin_info + localStorage.setItem(ACCESS_TOKEN_KEY, payload.access_token) + localStorage.setItem(REFRESH_TOKEN_KEY, payload.refresh_token) + localStorage.setItem(TOKEN_EXPIRE_KEY, String(payload.expire_time)) + localStorage.setItem(ADMIN_INFO_KEY, JSON.stringify(payload.admin_info)) + } + + function clearSession() { + accessToken.value = '' + refreshToken.value = '' + expireTime.value = 0 + adminInfo.value = null + localStorage.removeItem(ACCESS_TOKEN_KEY) + localStorage.removeItem(REFRESH_TOKEN_KEY) + localStorage.removeItem(TOKEN_EXPIRE_KEY) + localStorage.removeItem(ADMIN_INFO_KEY) + } + + return { + accessToken, + refreshToken, + expireTime, + adminInfo, + isLoggedIn, + isSuper, + applyTokens, + setSession, + clearSession, + } +}) diff --git a/src/types/auth.ts b/src/types/auth.ts new file mode 100644 index 0000000..8fdf387 --- /dev/null +++ b/src/types/auth.ts @@ -0,0 +1,52 @@ +/** 管理员信息(与后端 AdminInfo DTO 对齐) */ +export interface AdminInfo { + id: number + username: string + nickname: string + role: number + status: number + last_login_time: number + created_at: number +} + +export interface AdminLoginRequest { + username: string + password: string +} + +export interface AdminLoginResponse { + access_token: string + refresh_token: string + expire_time: number + admin_info: AdminInfo +} + +export interface AdminRefreshTokenRequest { + refresh_token: string + access_token: string +} + +export interface AdminRefreshTokenResponse { + access_token: string + refresh_token: string + expire_time: number +} + +export interface AdminChangePasswordRequest { + old_password: string + new_password: string +} + +export interface AdminCreateRequest { + username: string + password: string + nickname?: string + role: number +} + +export interface AdminUpdateRequest { + nickname?: string + password?: string + role?: number + status?: number +} diff --git a/src/types/common.ts b/src/types/common.ts new file mode 100644 index 0000000..5f55679 --- /dev/null +++ b/src/types/common.ts @@ -0,0 +1,21 @@ +/** 后端统一响应结构 */ +export interface ApiResponse { + code: number + msg: string + data: T + details?: string[] +} + +/** 分页请求参数 */ +export interface PageQuery { + page?: number + page_size?: number +} + +/** 分页响应结构 */ +export interface PageResult { + total: number + page: number + page_size: number + list: T[] +} diff --git a/src/types/content.ts b/src/types/content.ts new file mode 100644 index 0000000..4f88532 --- /dev/null +++ b/src/types/content.ts @@ -0,0 +1,99 @@ +export interface OutfitListItem { + id: number + outfit_uuid: string + user_id: number + outfit_name: string + outfit_desc: string + scene: string + source: number + is_public: number + audit_status: number + status: number + created_at: number +} + +export interface OutfitClothesItem { + clothes_uuid: string + name: string + category_main: string + category_sub: string + processed_image: string + image_process_status: number +} + +export interface OutfitDetailResponse extends OutfitListItem { + items: OutfitClothesItem[] +} + +export interface OutfitListQuery { + page?: number + page_size?: number + user_id?: number + is_public?: number + audit_status?: number + status?: number + keyword?: string +} + +export interface OutfitAuditRequest { + result: number + reason?: string +} + +export interface OutfitBanRequest { + reason?: string +} + +export interface ClothesItem { + id: number + clothes_uuid: string + user_id: number + name: string + category_main: string + category_sub: string + style: string + color_main: string + color_sub: string + thickness: string + version: string + material: string + pattern: string + sleeve_type: string + clothes_type: string + neckline_type: string + formality: string + occasions: string + visual_impact: string + remark: string + processed_image: string + image_size: number + image_process_status: number + fail_reason: string + created_at: number +} + +export interface ClothesListQuery { + page?: number + page_size?: number + user_id?: number + image_process_status?: number + category_main?: string + keyword?: string +} + +export interface ClosetShareItem { + id: number + share_uuid: string + user_id: number + share_type: number + expire_time: number + status: number + created_at: number +} + +export interface ClosetShareListQuery { + page?: number + page_size?: number + user_id?: number + status?: number +} diff --git a/src/types/dashboard.ts b/src/types/dashboard.ts new file mode 100644 index 0000000..164a2bb --- /dev/null +++ b/src/types/dashboard.ts @@ -0,0 +1,99 @@ +export interface DashboardContent { + outfit: { + total: number + pending: number + passed: number + rejected: number + banned: number + } + clothes: { + total: number + processing: number + success: number + failed: number + } + share: { + total: number + normal: number + cancelled: number + expired: number + banned: number + } +} + +export interface DashboardVIP { + member_total: number + monthly: number + yearly: number + trial: number + expiring_soon: number +} + +export interface GoodsTypeCount { + type: number + count: number +} + +export interface DashboardGoods { + total: number + on_shelf: number + off_shelf: number + by_type: GoodsTypeCount[] +} + +export interface DashboardUsage { + ai_recommend: number + closet_share: number + outfit_share: number +} + +export interface DashboardSocial { + cos_image_count: number + like_count: number + collect_count: number +} + +export interface DashboardSummary { + users: { + total: number + today_new: number + normal: number + temp_ban: number + perm_ban: number + deactivated: number + } + orders: { + total: number + pending: number + paid: number + cancelled: number + expired: number + refunded: number + } + revenue: { + total_revenue: number + today_revenue: number + refund_total: number + } + todo: { + refund_pending: number + outfit_pending_audit: number + goods_on_shelf: number + } + content: DashboardContent + vip: DashboardVIP + goods: DashboardGoods + usage: DashboardUsage + social: DashboardSocial +} + +export interface TrendPoint { + date: string + new_users: number + orders: number + revenue: number +} + +export interface DashboardTrends { + points: TrendPoint[] +} diff --git a/src/types/goods.ts b/src/types/goods.ts new file mode 100644 index 0000000..35b391d --- /dev/null +++ b/src/types/goods.ts @@ -0,0 +1,61 @@ +export interface GoodsItem { + id: number + goods_code: string + goods_name: string + goods_type: number + price: number + discount_price: number + member_days: number + upload_quota: number + ai_recommend_quota: number + closet_share_quota: number + outfit_share_quota: number + valid_days: number + description: string + status: number + product_id: string + product_status: number + created_at: number + updated_at: number +} + +export interface GoodsListQuery { + page?: number + page_size?: number + goods_type?: number + status?: number + keyword?: string +} + +export interface GoodsCreateRequest { + goods_code: string + goods_name: string + goods_type: number + price: number + discount_price: number + member_days?: number + upload_quota?: number + ai_recommend_quota?: number + closet_share_quota?: number + outfit_share_quota?: number + valid_days?: number + description?: string + status?: number +} + +export interface GoodsUpdateRequest { + goods_name?: string + price?: number + discount_price?: number + member_days?: number + upload_quota?: number + ai_recommend_quota?: number + closet_share_quota?: number + outfit_share_quota?: number + valid_days?: number + description?: string +} + +export interface GoodsStatusRequest { + status: number +} diff --git a/src/types/notification.ts b/src/types/notification.ts new file mode 100644 index 0000000..ff1a71c --- /dev/null +++ b/src/types/notification.ts @@ -0,0 +1,14 @@ +export interface NotificationSendRequest { + user_id: number + title: string + content: string +} + +export interface NotificationBroadcastRequest { + title: string + content: string +} + +export interface NotificationBroadcastResponse { + sent_count: number +} diff --git a/src/types/order.ts b/src/types/order.ts new file mode 100644 index 0000000..c08299d --- /dev/null +++ b/src/types/order.ts @@ -0,0 +1,58 @@ +export interface OrderItem { + order_no: string + user_id: number + goods_id: number + goods_name: string + unit_price: number + total_amount: number + pay_amount: number + pay_channel: number + order_status: number + transaction_id: string + member_days: number + upload_quota: number + ai_recommend_quota: number + closet_share_quota: number + outfit_share_quota: number + expire_time: number + pay_time: number + refund_time: number + refund_amount: number + remark: string + xpay_product_id: string + xpay_platform: string + xpay_env: number + created_at: number +} + +export interface OrderListQuery { + page?: number + page_size?: number + order_no?: string + user_id?: number + status?: number +} + +export interface RefundItem { + refund_no: string + order_no: string + user_id: number + refund_amount: number + refund_reason: string + status: number + apply_time: number + success_time: number + fail_reason: string + created_at: number +} + +export interface RefundListQuery { + page?: number + page_size?: number + status?: number + order_no?: string +} + +export interface RefundAuditRequest { + reason: string +} diff --git a/src/types/user.ts b/src/types/user.ts new file mode 100644 index 0000000..ebcdfeb --- /dev/null +++ b/src/types/user.ts @@ -0,0 +1,68 @@ +export interface UserListItem { + id: number + user_uuid: string + username: string + avatar: string + sex: number + phone: string + status: number + ban_reason: string + ban_start: number + ban_expire: number + vip_type: number + vip_expire: number + last_login_time: number + created_at: number +} + +export interface QuotaItem { + quota_type: number + total: number + used: number + remain: number +} + +export interface UserGrantItem { + id: number + quota_type: number + amount: number + used: number + source: number + expire_time: number + ref_id: string + created_at: number +} + +export interface UserDetailResponse extends UserListItem { + quotas: QuotaItem[] + grants: UserGrantItem[] +} + +export interface UserListQuery { + page?: number + page_size?: number + keyword?: string + status?: number +} + +export interface UserBanRequest { + ban_type: number + ban_days?: number + reason: string +} + +export interface UserUnbanRequest { + reason?: string +} + +export interface UserQuotaAdjustRequest { + quota_type: number + amount: number + expire_days: number +} + +export interface UserVIPAdjustRequest { + vip_type: number + vip_days: number + reason: string +} diff --git a/src/utils/constants.ts b/src/utils/constants.ts new file mode 100644 index 0000000..3ffd2fb --- /dev/null +++ b/src/utils/constants.ts @@ -0,0 +1,176 @@ +import type { TagProps } from 'element-plus' + +/** 枚举映射项:value=后端数值 label=中文文案 tagType=Tag 颜色 */ +export interface EnumMapItem { + value: number + label: string + tagType?: TagProps['type'] +} + +function enumMap(items: EnumMapItem[]): Record { + const map: Record = {} + for (const item of items) { + map[item.value] = item + } + return map +} + +/* ---------------- 管理员 ---------------- */ +export const ADMIN_ROLE = enumMap([ + { value: 1, label: '超级管理员', tagType: 'danger' }, + { value: 2, label: '普通管理员', tagType: 'info' }, +]) + +export const ADMIN_STATUS = enumMap([ + { value: 1, label: '启用', tagType: 'success' }, + { value: 2, label: '禁用', tagType: 'info' }, +]) + +/* ---------------- 用户 ---------------- */ +export const USER_STATUS = enumMap([ + { value: 1, label: '正常', tagType: 'success' }, + { value: 2, label: '临时禁用', tagType: 'warning' }, + { value: 3, label: '永久禁用', tagType: 'danger' }, + { value: 4, label: '已注销', tagType: 'info' }, +]) + +export const USER_SEX = enumMap([ + { value: 1, label: '男' }, + { value: 2, label: '女' }, +]) + +export const VIP_TYPE = enumMap([ + { value: 1, label: '非会员', tagType: 'info' }, + { value: 2, label: '月度会员', tagType: 'warning' }, + { value: 3, label: '年度会员', tagType: 'danger' }, + { value: 4, label: '体验会员', tagType: 'success' }, +]) + +export const QUOTA_TYPE = enumMap([ + { value: 1, label: '上传额度' }, + { value: 2, label: 'AI 推荐额度' }, + { value: 3, label: '社区分享额度' }, + { value: 4, label: '衣柜分享额度' }, +]) + +export const BAN_TYPE = enumMap([ + { value: 1, label: '临时封禁' }, + { value: 2, label: '永久封禁' }, +]) + +export const GRANT_SOURCE = enumMap([ + { value: 1, label: '会员包' }, + { value: 2, label: '加量包' }, + { value: 3, label: '广告激励' }, +]) + +/* ---------------- 商品 ---------------- */ +export const GOODS_TYPE = enumMap([ + { value: 1, label: '会员包', tagType: 'warning' }, + { value: 2, label: '上传包' }, + { value: 3, label: 'AI 推荐包' }, + { value: 4, label: '衣柜分享包' }, + { value: 5, label: '搭配分享包' }, +]) + +export const GOODS_STATUS = enumMap([ + { value: 1, label: '上架', tagType: 'success' }, + { value: 2, label: '下架', tagType: 'info' }, +]) + +export const PRODUCT_STATUS = enumMap([ + { value: 0, label: '未发布', tagType: 'info' }, + { value: 1, label: '发布中', tagType: 'warning' }, + { value: 2, label: '已发布', tagType: 'success' }, + { value: 3, label: '发布失败', tagType: 'danger' }, +]) + +/* ---------------- 订单 / 退款 ---------------- */ +export const ORDER_STATUS = enumMap([ + { value: 1, label: '待支付', tagType: 'warning' }, + { value: 2, label: '已支付', tagType: 'success' }, + { value: 3, label: '已取消', tagType: 'info' }, + { value: 4, label: '已过期', tagType: 'info' }, + { value: 5, label: '已退款', tagType: 'danger' }, +]) + +export const PAY_CHANNEL = enumMap([ + { value: 1, label: '微信支付' }, + { value: 2, label: '微信虚拟支付' }, +]) + +export const XPAY_ENV = enumMap([ + { value: 0, label: '现网' }, + { value: 1, label: '沙箱', tagType: 'warning' }, +]) + +export const REFUND_STATUS = enumMap([ + { value: 0, label: '待处理', tagType: 'warning' }, + { value: 1, label: '退款中', tagType: 'primary' }, + { value: 2, label: '退款成功', tagType: 'success' }, + { value: 3, label: '退款失败', tagType: 'danger' }, +]) + +/* ---------------- 内容审核 ---------------- */ +export const OUTFIT_SOURCE = enumMap([ + { value: 1, label: '用户创建' }, + { value: 2, label: 'AI 推荐', tagType: 'primary' }, +]) + +export const OUTFIT_PUBLIC = enumMap([ + { value: 1, label: '不公开', tagType: 'info' }, + { value: 2, label: '公开', tagType: 'success' }, +]) + +export const OUTFIT_AUDIT_STATUS = enumMap([ + { value: 1, label: '待审核', tagType: 'warning' }, + { value: 2, label: '已通过', tagType: 'success' }, + { value: 3, label: '未通过', tagType: 'danger' }, +]) + +export const OUTFIT_STATUS = enumMap([ + { value: 1, label: '正常', tagType: 'success' }, + { value: 2, label: '已封禁', tagType: 'danger' }, + { value: 3, label: '待用户保存', tagType: 'warning' }, +]) + +export const SHARE_TYPE = enumMap([ + { value: 1, label: '部分衣物' }, + { value: 2, label: '全量快照' }, +]) + +export const SHARE_STATUS = enumMap([ + { value: 1, label: '正常', tagType: 'success' }, + { value: 2, label: '已取消', tagType: 'info' }, + { value: 3, label: '已过期', tagType: 'info' }, + { value: 4, label: '已封禁', tagType: 'danger' }, +]) + +export const IMAGE_PROCESS_STATUS = enumMap([ + { value: 1, label: '抠图中', tagType: 'warning' }, + { value: 2, label: '分类中', tagType: 'warning' }, + { value: 3, label: '排队中', tagType: 'info' }, + { value: 4, label: '处理成功', tagType: 'success' }, + { value: 5, label: '处理失败', tagType: 'danger' }, +]) + +/* ---------------- 工具函数 ---------------- */ + +/** 根据枚举表取文案,未匹配返回 '-' */ +export function enumLabel(map: Record, value?: number | null): string { + if (value === undefined || value === null) return '-' + const item = map[value] + return item ? item.label : '-' +} + +/** 根据枚举表取 Tag 颜色 */ +export function enumTag(map: Record, value?: number | null): TagProps['type'] { + if (value === undefined || value === null) return 'info' + const item = map[value] + return item?.tagType ?? 'info' +} + +/** 枚举表转下拉选项(数字值) */ +export function enumOptions(map: Record): { value: number; label: string }[] { + return Object.values(map).map((item) => ({ value: item.value, label: item.label })) +} diff --git a/src/utils/format.ts b/src/utils/format.ts new file mode 100644 index 0000000..7803c04 --- /dev/null +++ b/src/utils/format.ts @@ -0,0 +1,34 @@ +/** 金额:分 → 元字符串(保留两位小数) */ +export function formatMoney(cents?: number | null): string { + if (cents === undefined || cents === null || Number.isNaN(cents)) return '-' + const yuan = cents / 100 + return `${yuan.toFixed(2)}` +} + +/** 金额:元(字符串) → 分(整数),非法输入返回 0 */ +export function yuanToCents(yuan: number | string): number { + const num = typeof yuan === 'string' ? Number.parseFloat(yuan) : yuan + if (Number.isNaN(num) || num < 0) return 0 + return Math.round(num * 100) +} + +/** 时间戳(Unix 秒) → YYYY-MM-DD HH:mm:ss;0/空显示 '-' */ +export function formatDate(seconds?: number | null): string { + if (!seconds || seconds <= 0) return '-' + const d = new Date(seconds * 1000) + const pad = (n: number) => String(n).padStart(2, '0') + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}` +} + +/** 时间戳(Unix 秒) → YYYY-MM-DD;0/空显示 '-' */ +export function formatDateOnly(seconds?: number | null): string { + if (!seconds || seconds <= 0) return '-' + const d = new Date(seconds * 1000) + const pad = (n: number) => String(n).padStart(2, '0') + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}` +} + +/** 空字符串显示为 '-' */ +export function formatText(value?: string | null): string { + return value === undefined || value === null || value === '' ? '-' : value +} diff --git a/src/utils/request.ts b/src/utils/request.ts new file mode 100644 index 0000000..1d0a707 --- /dev/null +++ b/src/utils/request.ts @@ -0,0 +1,182 @@ +import axios, { AxiosError, type AxiosRequestConfig, type AxiosResponse, type InternalAxiosRequestConfig } from 'axios' +import { ElMessage } from 'element-plus' +import type { ApiResponse } from '@/types/common' + +/** 业务错误码:access token 过期(HTTP 401) */ +const CODE_TOKEN_TIMEOUT = 11002 + +/** 标记已尝试过 token 刷新的配置 */ +type RetriableConfig = InternalAxiosRequestConfig & { _retried?: boolean } + +const request = axios.create({ + baseURL: '/api/v1', + timeout: 15000, +}) + +/* ---------------- 请求拦截:注入 Bearer token ---------------- */ +request.interceptors.request.use((config) => { + const token = localStorage.getItem('zt_admin_access_token') + if (token) { + config.headers.Authorization = `Bearer ${token}` + } + return config +}) + +/* ---------------- 响应拦截:业务码统一处理 + 双 token 刷新重放 ---------------- */ +let refreshingPromise: Promise | null = null + +/** 调用刷新接口换取新双 token;成功返回新 access token,失败返回 null */ +function refreshTokens(): Promise { + const refreshToken = localStorage.getItem('zt_admin_refresh_token') + const oldAccessToken = localStorage.getItem('zt_admin_access_token') + if (!refreshToken || !oldAccessToken) return Promise.resolve(null) + + return axios + .post>( + '/api/v1/admin/refresh-token', + { refresh_token: refreshToken, access_token: oldAccessToken }, + ) + .then((res) => { + if (res.data.code !== 0 || !res.data.data) return null + const tokens = res.data.data + localStorage.setItem('zt_admin_access_token', tokens.access_token) + localStorage.setItem('zt_admin_refresh_token', tokens.refresh_token) + localStorage.setItem('zt_admin_expire_time', String(tokens.expire_time)) + return tokens.access_token + }) + .catch(() => null) +} + +function redirectToLogin() { + localStorage.removeItem('zt_admin_access_token') + localStorage.removeItem('zt_admin_refresh_token') + localStorage.removeItem('zt_admin_expire_time') + localStorage.removeItem('zt_admin_info') + if (window.location.pathname !== '/login') { + window.location.href = '/login' + } +} + +request.interceptors.response.use( + (response: AxiosResponse): AxiosResponse | Promise => { + const body = response.data as ApiResponse | undefined + if (body && typeof body.code === 'number') { + // 业务成功:剥离包装,直接返回 data + if (body.code === 0) { + response.data = body.data + return response + } + // access 过期:尝试刷新并重放 + const retriable = response.config as RetriableConfig + if (body.code === CODE_TOKEN_TIMEOUT && !retriable._retried) { + retriable._retried = true + return handleTokenTimeout(retriable) + } + // 其余业务错误:提示后拒绝 + const msg = buildErrorMessage(body) + ElMessage.error(msg) + return Promise.reject(new ApiBizError(body.code, msg, body.details)) + } + return response + }, + (error: AxiosError>) => { + const body = error.response?.data + const status = error.response?.status + const code = body?.code + + // access 过期(HTTP 401 且业务码 11002) + if (status === 401 && code === CODE_TOKEN_TIMEOUT && error.config) { + const retriable = error.config as RetriableConfig + if (!retriable._retried) { + retriable._retried = true + return handleTokenTimeout(retriable) + } + } + // 其余 401:会话失效,跳登录 + if (status === 401) { + ElMessage.error(body?.msg ?? '登录已失效,请重新登录') + redirectToLogin() + return Promise.reject(error) + } + // 403 无权限 + if (status === 403) { + ElMessage.error(body?.msg ?? '无权限执行该操作') + return Promise.reject(error) + } + // 系统错误 5xx / 限流 + if (status && status >= 500) { + ElMessage.error(body?.msg ?? '系统繁忙,请稍后重试') + return Promise.reject(error) + } + if (body && typeof body.code === 'number') { + const msg = buildErrorMessage(body) + ElMessage.error(msg) + return Promise.reject(new ApiBizError(body.code, msg, body.details)) + } + ElMessage.error('网络异常,请检查网络连接或后端服务是否启动') + return Promise.reject(error) + }, +) + +/** 统一错误文案:优先拼接 details 中的具体校验信息 */ +function buildErrorMessage(body: ApiResponse): string { + if (body.details && body.details.length > 0) { + return body.details.join(';') + } + return body.msg || '操作失败' +} + +/** token 过期处理:单例刷新,所有并发请求等待同一个刷新结果后重放 */ +function handleTokenTimeout(config: RetriableConfig): Promise { + if (!refreshingPromise) { + refreshingPromise = refreshTokens() + } + return refreshingPromise.then((newToken) => { + if (newToken) { + config.headers.Authorization = `Bearer ${newToken}` + return request(config) + } + ElMessage.error('登录已过期,请重新登录') + redirectToLogin() + return Promise.reject(new Error('token refresh failed')) + }) +} + +/** 业务错误对象,携带后端 code 与 details */ +export class ApiBizError extends Error { + code: number + details?: string[] + constructor(code: number, message: string, details?: string[]) { + super(message) + this.name = 'ApiBizError' + this.code = code + this.details = details + } +} + +/** 响应拦截器已将包装剥离为 data,此处直接取出业务数据 */ +function unwrap(p: Promise): Promise { + return p.then((res) => res.data as T) +} + +/** 通用 GET 请求(返回 data 部分) */ +export function httpGet(url: string, params?: Record, config?: AxiosRequestConfig): Promise { + return unwrap(request.get(url, { params, ...config })) +} + +/** 通用 POST 请求 */ +export function httpPost(url: string, data?: unknown, config?: AxiosRequestConfig): Promise { + return unwrap(request.post(url, data, config)) +} + +/** 通用 PUT 请求 */ +export function httpPut(url: string, data?: unknown, config?: AxiosRequestConfig): Promise { + return unwrap(request.put(url, data, config)) +} + +/** 通用 DELETE 请求 */ +export function httpDelete(url: string, config?: AxiosRequestConfig): Promise { + return unwrap(request.delete(url, config)) +} + +export default request diff --git a/src/views/admin/AdminListView.vue b/src/views/admin/AdminListView.vue new file mode 100644 index 0000000..174e8f7 --- /dev/null +++ b/src/views/admin/AdminListView.vue @@ -0,0 +1,279 @@ + + + + + diff --git a/src/views/dashboard/DashboardView.vue b/src/views/dashboard/DashboardView.vue new file mode 100644 index 0000000..43815a6 --- /dev/null +++ b/src/views/dashboard/DashboardView.vue @@ -0,0 +1,711 @@ + + + + + diff --git a/src/views/goods/GoodsListView.vue b/src/views/goods/GoodsListView.vue new file mode 100644 index 0000000..192bc98 --- /dev/null +++ b/src/views/goods/GoodsListView.vue @@ -0,0 +1,422 @@ + + + + + diff --git a/src/views/login/LoginView.vue b/src/views/login/LoginView.vue new file mode 100644 index 0000000..f9737c5 --- /dev/null +++ b/src/views/login/LoginView.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/src/views/notification/NotifyView.vue b/src/views/notification/NotifyView.vue new file mode 100644 index 0000000..2c97c3f --- /dev/null +++ b/src/views/notification/NotifyView.vue @@ -0,0 +1,220 @@ + + + + + diff --git a/src/views/order/OrderListView.vue b/src/views/order/OrderListView.vue new file mode 100644 index 0000000..e9e961a --- /dev/null +++ b/src/views/order/OrderListView.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/src/views/order/RefundListView.vue b/src/views/order/RefundListView.vue new file mode 100644 index 0000000..5dbe10d --- /dev/null +++ b/src/views/order/RefundListView.vue @@ -0,0 +1,231 @@ + + + + + diff --git a/src/views/review/ClothesListView.vue b/src/views/review/ClothesListView.vue new file mode 100644 index 0000000..3f836c3 --- /dev/null +++ b/src/views/review/ClothesListView.vue @@ -0,0 +1,241 @@ + + + + + diff --git a/src/views/review/OutfitListView.vue b/src/views/review/OutfitListView.vue new file mode 100644 index 0000000..a7b1057 --- /dev/null +++ b/src/views/review/OutfitListView.vue @@ -0,0 +1,349 @@ + + + + + diff --git a/src/views/review/ShareListView.vue b/src/views/review/ShareListView.vue new file mode 100644 index 0000000..61376d8 --- /dev/null +++ b/src/views/review/ShareListView.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/src/views/user/UserListView.vue b/src/views/user/UserListView.vue new file mode 100644 index 0000000..98ea13a --- /dev/null +++ b/src/views/user/UserListView.vue @@ -0,0 +1,601 @@ + + + + + diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..c0f2d86 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,18 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], + "exclude": ["src/**/__tests__/*"], + "compilerOptions": { + // Extra safety for array and object lookups, but may have false positives. + "noUncheckedIndexedAccess": true, + + // Path mapping for cleaner imports. + "paths": { + "@/*": ["./src/*"] + }, + + // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. + // Specified here to keep it out of the root directory. + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..66b5e57 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "files": [], + "references": [ + { + "path": "./tsconfig.node.json" + }, + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..c9b2bad --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,27 @@ +// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping. +{ + "extends": "@tsconfig/node24/tsconfig.json", + "include": [ + "vite.config.*", + "vitest.config.*", + "cypress.config.*", + "playwright.config.*", + "eslint.config.*" + ], + "compilerOptions": { + // Most tools use transpilation instead of Node.js's native type-stripping. + // Bundler mode provides a smoother developer experience. + "module": "preserve", + "moduleResolution": "bundler", + + // Include Node.js types and avoid accidentally including other `@types/*` packages. + "types": ["node"], + + // Disable emitting output during `vue-tsc --build`, which is used for type-checking only. + "noEmit": true, + + // `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking. + // Specified here to keep it out of the root directory. + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo" + } +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..31dce4a --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,27 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueDevTools from 'vite-plugin-vue-devtools' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueDevTools(), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, + server: { + host: '0.0.0.0', + proxy: { + '/api': { + target: 'http://localhost:8080', + changeOrigin: true, + }, + }, + }, +})