فهرست منبع

Merge branch 'master' of http://1.14.104.71:10880/zhouyang/saasadminui

云联一号 2 هفته پیش
والد
کامیت
0cb2c17162

+ 383 - 0
docs/登录与首页仪表盘-问题清单.md

@@ -0,0 +1,383 @@
+# 租户总后台(saasadminui + fs-admin-saas)登录与首页仪表盘 — 问题清单
+
+> **范围**:`saasadminui` 登录链路、路由守卫、`/index` 首页仪表盘(`src/views/index.vue`)  
+> **后端**:`fs-admin-saas:8004`(profile=`admin`),业务实现 `fs-service`  
+> **排查日期**:2026-05-27  
+> **说明**:本文档记录问题点与修复状态。  
+> **修复批次**:2026-05-27(登录 + 首页 P0/P1 首批)
+
+---
+
+## 修复状态(2026-05-27)
+
+| 编号 | 状态 |
+|------|------|
+| P0-2 getFirstLogin | ✅ 已在 `SysLoginController` 实现 |
+| P0-3 dealerChart 初始化 | ✅ 已移除无效图表初始化 |
+| P0-5 authorizationInfo | ✅ 已修正返回对象 |
+| P0-6 trafficLog null | ✅ 已保证返回空 DTO |
+| P0-8 登出 tenantCode | ✅ 已清理 Cookie |
+| P1-4/5 路由守卫 | ✅ GetInfo/菜单失败跳转登录 |
+| P1-6~8 首页展示 | ✅ 短信/流量/较昨日绑定数据 |
+| P1-11 收款图表 option | ✅ 已修正 |
+| P0-4 统计任务 NPE | ✅ `statis.config` 空 JSON 防护 |
+| setPassword API | ✅ 改用 `/system/user/profile/updatePwd` |
+
+---
+
+## 一、链路总览
+
+```mermaid
+sequenceDiagram
+  participant UI as saasadminui
+  participant API as fs-admin-saas:8004
+  participant Redis as Redis
+  participant DB as 租户库/主库
+
+  UI->>API: POST /login (tenantCode+账号密码)
+  API->>DB: 主库查租户 + 切租户库认证
+  API-->>UI: token
+  UI->>API: GET /getInfo
+  UI->>API: GET /getRouters (AdminMenu)
+  UI->>UI: 进入 /index
+  UI->>API: 并行 N 个 /index/statistics/*
+  API->>Redis: 读统计缓存
+  API-->>UI: 仪表盘数据
+```
+
+| 环节 | 前端 | 后端(fs-admin-saas) |
+|------|------|------------------------|
+| 登录 | `views/login.vue` → `api/login.js` | `SysLoginController`(@Profile admin) |
+| 验证码 | `getCodeImg` | `CaptchaController` |
+| 用户信息 | `store/user.js` GetInfo | `GET /getInfo` |
+| 动态菜单 | `store/permission.js` | `GET /getRouters` → `IAdminMenuService` |
+| 首页 | `views/index.vue` | `com.fs.api.controller.IndexStatisticsController` |
+| 红包概览 | `api/company/redPacket.js` | `FsRedPacketController` `/his/redPacket/info` |
+
+---
+
+## 二、问题统计摘要
+
+| 级别 | 数量 | 说明 |
+|------|------|------|
+| **P0** | 8 | 阻塞登录/首页白屏/核心数据全空 |
+| **P1** | 12 | 功能错误、数据不准、易引发线上故障 |
+| **P2** | 10 | 体验、规范、技术债 |
+| **配置/环境** | 5 | 代理、Redis、定时任务、JDK |
+
+---
+
+## 三、P0 — 必须优先处理
+
+### P0-1 前端代理曾指向错误服务(已局部修正,需验证)
+
+| 项 | 内容 |
+|----|------|
+| **现象** | 开发环境请求打到 `fs-company:8006`,租户总后台接口 404 或行为与 company 端混淆 |
+| **正确** | `saasadminui` → `fs-admin-saas:8004` |
+| **相关文件** | `saasadminui/vue.config.js`、`saasadminui/nginx.conf` |
+| **状态** | 已改为 8004;需在本地 `npm run dev` + 启动 8004 后回归验证 |
+| **建议** | 生产 Nginx 同步检查,勿再指向 8006 |
+
+### P0-2 `GET /getFirstLogin` 在 fs-admin-saas 上不存在(404)
+
+| 项 | 内容 |
+|----|------|
+| **现象** | 登录成功后调用 `getFirstLogin` 失败;`login.vue` 的 `catch` 仍跳转首页,首次改密流程失效 |
+| **原因** | `getFirstLogin` 仅在 `CompanyLoginController`(`@Profile("company")`)中实现,且该类在 `com.fs.company.controller.*` 被启动类 **排除扫描** |
+| **活跃登录** | `SysLoginController`(admin)**无** `getFirstLogin` |
+| **前端** | `api/login.js` → `GET /getFirstLogin`;`login.vue` `checkFirstLogin()` |
+| **建议** | 在 `SysLoginController` 或独立 admin Controller 中实现租户总后台版「首次登录改密」(基于 `SysUser` + `his.login` 配置),或前端暂时关闭该流程 |
+
+### P0-3 首页 ECharts 初始化访问已注释的 DOM(可能白屏/控制台报错)
+
+| 项 | 内容 |
+|----|------|
+| **现象** | `mounted` 中仍调用 `initDealerChart()`、`handleDealerChartData()`,但模板中 `ref="dealerChart"` 的图表区域已被注释 |
+| **文件** | `saasadminui/src/views/index.vue`(约 1027–1028、1451–1463 行 vs 412–426 行注释块) |
+| **影响** | `echarts.init(undefined)` 抛错,可能中断同 `mounted` 内其它图表初始化 |
+| **建议** | 删除或恢复对应 DOM;仅保留 `dealerChartNew` |
+
+### P0-4 仪表盘数据强依赖 Redis 缓存,定时任务存在 NPE
+
+| 项 | 内容 |
+|----|------|
+| **现象** | 企业数据、资产、分析概览等卡片长期为 0 |
+| **后端** | `IndexStatisticsController` 多数接口从 Redis 读 `DATA_OVERVIEW_*` 等 key |
+| **写入** | 依赖 `statisticsService.dataOverviewTask()` 等 Quartz 任务 |
+| **日志** | `sys-error.log`:`StatisticsServiceImpl.rechargeConsumption` 中 `jsonObject` 为 null → 租户任务失败 |
+| **其它** | `No bean named 'qwTask'` 等任务 Bean 缺失,可能影响调度器整体稳定性 |
+| **建议** | 修复 `fs-service` 统计任务 NPE;确认 SaaS 租户任务分发器正常;缓存未命中时降级查库或返回明确提示 |
+
+### P0-5 `authorizationInfo` 部门聚合分支返回错误对象(后端逻辑 Bug)
+
+| 项 | 内容 |
+|----|------|
+| **文件** | `fs-admin-saas/.../api/controller/IndexStatisticsController.java` `authorizationInfo()` |
+| **现象** | `else` 分支累加结果写入 `authorizationInfoDTO1`,但 `return` 的是未赋值的 `authorizationInfoDTO` |
+| **影响** | 按部门筛选时「平台今日看课人数 / 配额上限」恒为空或 0 |
+| **建议** | 返回 `authorizationInfoDTO1` 或统一赋值后返回 |
+
+### P0-6 `trafficLog` 接口可能返回 `null` 响应体
+
+| 项 | 内容 |
+|----|------|
+| **文件** | 同上 `getTrafficLog()` |
+| **现象** | `result == null \|\| sysConfig == null` 时 `return null` |
+| **影响** | 前端 `trafficLog().then` 可能异常;且 UI 上「剩余流量」为写死 `100.00GB`(见 P1-8),接口失败用户无感知 |
+| **建议** | 统一 `R.ok().put("data", emptyDto)`;前端绑定真实字段 |
+
+### P0-7 `X-Frontend-Type` 与后端 profile 曾不一致(已改 admin,需联调)
+
+| 项 | 内容 |
+|----|------|
+| **原状** | 前端发 `company`,后端为 `admin` profile |
+| **影响** | Token 无 `tenantId` 时,`tenant-code` 回退切库行为与菜单数据源(`AdminMenu` vs `CompanyMenu`)不一致 |
+| **现状** | `request.js` 已改为 `admin`;登录必须带 `tenantCode` 以保证 `LoginUser.tenantId` |
+| **建议** | 联调确认 `getRouters` 读的是租户库 `admin_menu` 数据 |
+
+### P0-8 登出未清除 `tenantCode` Cookie
+
+| 项 | 内容 |
+|----|------|
+| **文件** | `store/modules/user.js` `LogOut` / `FedLogOut` |
+| **现象** | 仅 `removeToken()`,未 `Cookies.remove('tenantCode')` |
+| **影响** | 换租户登录可能携带旧 `tenant-code` 请求头(与 body 不一致) |
+| **建议** | 登出时同步清理 `tenantCode` |
+
+---
+
+## 四、P1 — 功能/数据错误
+
+### P1-1 登录文案与校验矛盾
+
+| 文件 | `login.vue` |
+|------|-------------|
+| **现象** | placeholder「企业编号(选填)」 vs `loginRules.tenantCode` **required** |
+| **建议** | 租户总后台应必填;改文案为「请输入企业编号」 |
+
+### P1-2 短信二次验证未实现
+
+| 文件 | `login.vue` `handleLogin` |
+|------|---------------------------|
+| **现象** | `needSms: true` 时仅提示「验证组件未启用」 |
+| **后端** | `checkIsNeedCheck` 在 admin 端存在,但前端无弹窗流程 |
+
+### P1-3 `checkIsNeedCheck` 返回类型与拦截器
+
+| 项 | 内容 |
+|----|------|
+| **后端** | 返回原始 `boolean` |
+| **前端** | `if (!resp)` 依赖拦截器返回体为布尔值;若将来改为 `AjaxResult` 会失效 |
+| **建议** | 约定统一 `AjaxResult` 或文档化 |
+
+### P1-4 路由守卫失败后的跳转逻辑
+
+| 文件 | `permission.js` |
+|------|-----------------|
+| **现象** | `GetInfo` 失败 → `LogOut` → `next({ path: '/' })`,仍可能再次触发 GetInfo |
+| **建议** | 失败应 `next('/login')` 并带 redirect |
+
+### P1-5 动态路由 `getRouters` 无错误处理
+
+| 文件 | `store/modules/permission.js` |
+|------|-------------------------------|
+| **现象** | `getRouters()` 无 `.catch`,菜单接口失败时 Promise 悬挂,页面卡在 NProgress |
+| **建议** | 增加 catch + 提示 |
+
+### P1-6 首页短信余额未绑定接口数据
+
+| 文件 | `index.vue` 约 224–226 行 |
+|------|---------------------------|
+| **现象** | 已调用 `smsBalance()` 赋值 `smsRemainCount`,模板写死 `0` |
+| **建议** | 使用 `{{ smsRemainCount }}` |
+
+### P1-7 资产「较昨日」写死
+
+| 文件 | `index.vue` 约 78–79 行 |
+|------|---------------------------|
+| **现象** | 显示「较昨日 +1」,未使用 `yesterdayComsumption` |
+| **建议** | 计算真实环比 |
+
+### P1-8 流量卡片 UI 写死
+
+| 文件 | `index.vue` 约 197–204 行 |
+|------|---------------------------|
+| **现象** | 「剩余流量 100.00GB」、进度 90% 硬编码;仅「今日/本月消耗」用接口 |
+| **建议** | 对接 `trafficLog` 的 `traffic` 等字段 |
+
+### P1-9 看课配额进度条分子分母相同
+
+| 文件 | `index.vue` 约 159–163 行 |
+|------|---------------------------|
+| **现象** | 配额展示 `todayWatchUserCount / versionLimit`,但分子也绑定了 `todayWatchUserCount`(应为当前使用 vs 上限) |
+| **建议** | 核对产品设计后改绑定字段 |
+
+### P1-10 `thisMonthOrderCount` / `thisMonthRecvCount` 返回结构不统一
+
+| 项 | 内容 |
+|----|------|
+| **后端** | 默认分支:`return redisCache.getCacheObject(...)` 可能为顶层含 `dates` 的 `R`;部门聚合:`R.ok().put("dates",...)` |
+| **前端** | 使用 `res.dates`、`res.orderCount`(非 `res.data.dates`) |
+| **风险** | Redis 存的对象结构变化会导致图表无数据 |
+| **建议** | 统一 `R.ok().put("data", chartDto)`;前端统一读 `res.data` |
+
+### P1-11 `initThisMonthRecvChart` 使用了错误 option
+
+| 文件 | `index.vue` `initThisMonthRecvChart` |
+|------|--------------------------------------|
+| **现象** | `setOption(thisMonthOrderCountOption)` 应为 `thisMonthRecvCountOption` |
+| **影响** | 「本月收款数」图表轴/系列配置错误 |
+
+### P1-12 红包接口遍历全量公司
+
+| 文件 | `FsRedPacketController.info()` |
+|------|--------------------------------|
+| **现象** | `companyService.selectCompanyList(new Company())` 无租户/权限过滤 |
+| **影响** | 租户总后台可能汇总到越权数据或性能差 |
+| **建议** | 按当前租户/数据权限过滤;逻辑下沉 `fs-service` |
+
+---
+
+## 五、P2 — 体验与规范
+
+### P2-1 `$runtimeConfig` 初始化时机
+
+| 项 | 内容 |
+|----|------|
+| **现象** | `index.vue` `data()` 使用 `this.$runtimeConfig.VUE_APP_COURSE_DEFAULT`,登录前为 `{}`,默认会员/企微可能不准 |
+| **依赖** | 登录后 `reloadRuntimeConfig()` 读 `his.adminUi.config` |
+| **建议** | 进入首页前 await 配置加载,或 GetInfo 后刷新 |
+
+### P2-2 头像 URL 拼接
+
+| 文件 | `store/modules/user.js` |
+|------|-------------------------|
+| **现象** | `VUE_APP_BASE_API + user.avatar`,若 avatar 已是完整 URL 会重复 |
+| **建议** | 判断 `http` 前缀 |
+
+### P2-3 请求超时 20 分钟
+
+| 文件 | `utils/request.js` `timeout: 1200000` |
+|------|----------------------------------------|
+| **建议** | 登录/统计接口单独合理超时(如 30s) |
+
+### P2-4 环境变量命名误导
+
+| 文件 | `.env.development` 中 `ENV = 'production'` |
+|------|---------------------------------------------|
+
+### P2-5 缺少 `.catch` 的仪表盘并行请求
+
+| 文件 | `index.vue` `refresh()` |
+|------|-------------------------|
+| **现象** | 多个 API 无 catch,单个 500 仅控制台/拦截器弹窗,卡片静默为 0 |
+| **建议** | 统一错误态或骨架屏 |
+
+### P2-6 重复/死代码
+
+| 项 | 内容 |
+|----|------|
+| `initDealerChart` / `handleDealerChartData` | 对应 UI 已注释 |
+| `api/tenant.js` vs `api/tenant/tenant.js` | 路径重复(非本页核心) |
+
+### P2-7 后端双份 `IndexStatisticsController`
+
+| 路径 | Profile | 是否加载 |
+|------|---------|----------|
+| `com.fs.api.controller.IndexStatisticsController` | **admin** | ✅ fs-admin-saas 使用 |
+| `com.fs.company.controller.company.IndexStatisticsController` | company | ❌ 排除扫描 |
+
+**建议**:避免误改 company 包下文件;文档标明以 `api` 包为准。
+
+### P2-8 拼写与命名技术债
+
+| 位置 | 说明 |
+|------|------|
+| `rechargeComsumption` | 应为 Consumption |
+| `dealderCount` | 应为 dealer |
+| 前后端需保持一致以免改 URL |
+
+### P2-9 注释与 JavaDoc 不足
+
+| 建议 |
+|------|
+| `IndexStatisticsController` 各接口补充:Redis key、租户范围、依赖定时任务 |
+| `SysLoginController` 注明租户总后台登录与 company 端差异 |
+
+### P2-10 JDK 版本
+
+| 项 | 内容 |
+|----|------|
+| **目标** | JDK 17 |
+| **现状** | 父 POM `java.version=1.8` |
+| **建议** | 功能稳定后单独立项升级 |
+
+---
+
+## 六、配置与环境依赖
+
+| 编号 | 检查项 | 说明 |
+|------|--------|------|
+| E-1 | `fs-admin-saas` 端口 **8004** 已启动 | profile `dev,admin` |
+| E-2 | Redis 可连 | 统计接口几乎全依赖缓存 |
+| E-3 | MySQL 主库 + 租户库 | 登录 `tenantCode` 切库 |
+| E-4 | `tenant_info` 中租户 status=1 | 否则「企业已禁用」 |
+| E-5 | Quartz / `statisticsService.dataOverviewTask` | 缓存写入;需先修 NPE |
+
+---
+
+## 七、首页 API 对照表(前端 → 后端)
+
+| # | 前端方法 | URL | 后端类 | 主要风险 |
+|---|----------|-----|--------|----------|
+| 1 | `login` | POST `/login` | `SysLoginController` | 租户码错误 |
+| 2 | `getCodeImg` | GET `/captchaImage` | `CaptchaController` | 403 若未放行 |
+| 3 | `checkIsNeedCheck` | POST `/checkIsNeedCheck` | `SysLoginController` | 返回格式 |
+| 4 | `getFirstLogin` | GET `/getFirstLogin` | **缺失** | **404** |
+| 5 | `getInfo` | GET `/getInfo` | `SysLoginController` | 租户库用户/角色 |
+| 6 | `getRouters` | GET `/getRouters` | `SysLoginController` | AdminMenu 数据 |
+| 7 | `getConfigByKey` | GET `/system/config/getConfigByKey/his.adminUi.config` | SysConfig | 运行时配置 |
+| 8 | `rechargeComsumption` | GET `/index/statistics/rechargeComsumption` | IndexStatisticsController | Redis 空 |
+| 9 | `redPacketInfo` | GET `/his/redPacket/info` | FsRedPacketController | 全表公司汇总 |
+| 10 | `trafficLog` | GET `/index/statistics/trafficLog` | IndexStatisticsController | **可 null** |
+| 11 | `dealerAggregated` | GET `/index/statistics/dealerAggregated` | 同上 | Redis 空 |
+| 12 | `analysisPreview` | POST `/index/statistics/analysisPreview` | 同上 | Redis 空 |
+| 13 | `smsBalance` | GET `/index/statistics/smsBalance` | 同上 | 前端未展示 |
+| 14 | `authorizationInfo` | GET `/index/statistics/authorizationInfo` | 同上 | **返回错对象** |
+| 15 | `watchEndPlayTrend` | POST `.../watchEndPlayTrend` | 同上 | Redis 空 |
+| 16 | `deaMemberTopTen` | POST `.../deaMemberTopTen` | 同上 | ref 已删 |
+| 17 | `watchCourseTopTen` | POST `.../watchCourseTopTen` | 同上 | — |
+| 18 | `getWatchCourseStatisticsData` | POST `.../getWatchCourseStatisticsData` | 同上 | 实时查库 |
+| 19 | `rewardMoneyTopTen` | POST `.../rewardMoneyTopTen` | 同上 | — |
+| 20 | `rewardMoneyTrend` | POST `.../rewardMoneyTrend` | 同上 | — |
+| 21 | `thisMonthOrderCount` | GET `.../thisMonthOrderCount` | 同上 | 返回结构 |
+| 22 | `thisMonthRecvCount` | GET `.../thisMonthRecvCount` | 同上 | option 用错 |
+
+---
+
+## 八、建议修复顺序(供下一阶段开发)
+
+1. **环境**:确认 8004 + Redis + 修复统计定时任务 NPE  
+2. **登录**:补 `getFirstLogin`(admin)、登出清 Cookie、路由失败跳登录页  
+3. **首页 P0**:修 `dealerChart` 初始化、修 `authorizationInfo` return、修 `trafficLog` null  
+4. **首页 P1**:短信/流量/较昨日绑定真实数据、修收款图表 option  
+5. **数据**:缓存未命中降级 + 前端 loading/错误态  
+6. **规范**:接口注释、统一 R 返回结构、逻辑收拢 `fs-service`  
+
+---
+
+## 九、验证清单(修复后自检)
+
+- [ ] 正确 `tenantCode` + 账号密码可登录,验证码开关开/关均正常  
+- [ ] 登录后侧边栏菜单正常,刷新页面不掉线  
+- [ ] 首页无控制台 ECharts 报错  
+- [ ] 企业数据/资产/经营数据非全 0(或明确提示「统计任务未跑」)  
+- [ ] 分析概览切换「今日/昨日/本周」有变化  
+- [ ] 本月订单/收款图表有曲线  
+- [ ] 换租户登录后数据隔离正确  
+- [ ] 登出再登录另一租户,请求头 `tenant-code` 正确  
+
+---
+
+*文档维护:随修复进展更新对应条目的「状态」列。*

+ 2 - 2
nginx.conf

@@ -27,7 +27,7 @@ http {
 
         # 关键:反向代理 API(解决跨域,替换为你的真实后端地址)
         location /prod-api/ {
-            proxy_pass http://192.168.58.159:7772/;  # 后端 API 地址(末尾加 / 避免路径拼接问题)
+            proxy_pass http://192.168.58.159:8004/;  # fs-admin-saas 租户总后台(末尾加 / 避免路径拼接问题)
             proxy_set_header Host $host;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@@ -35,4 +35,4 @@ http {
         }
 
      }
-}
+}

+ 9 - 0
src/api/company/moduleUsage.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function listModuleUsage(params) {
+  return request({
+    url: '/company/module-usage/list',
+    method: 'get',
+    params
+  })
+}

+ 6 - 1
src/permission.js

@@ -26,11 +26,16 @@ router.beforeEach((to, from, next) => {
             // 根据roles权限生成可访问的路由表
             router.addRoutes(accessRoutes) // 动态添加可访问路由表
             next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
+          }).catch(err => {
+            store.dispatch('LogOut').then(() => {
+              Message.error(err)
+              next({ path: '/login', query: { redirect: to.fullPath } })
+            })
           })
         }).catch(err => {
             store.dispatch('LogOut').then(() => {
               Message.error(err)
-              next({ path: '/' })
+              next({ path: '/login', query: { redirect: to.fullPath } })
             })
           })
       } else {

+ 3 - 1
src/store/modules/permission.js

@@ -64,6 +64,8 @@ const permission = {
           commit('SET_DEFAULT_ROUTES', sidebarRoutes)
           commit('SET_TOPBAR_ROUTES', sidebarRoutes)
           resolve(rewriteRoutes)
+        }).catch(err => {
+          reject(err)
         })
       })
     }
@@ -143,4 +145,4 @@ export const loadView = (view) => { // 路由懒加载
   return (resolve) => require([`@/views/${view}`], resolve)
 }
 
-export default permission
+export default permission

+ 2 - 0
src/store/modules/user.js

@@ -119,6 +119,7 @@ const user = {
           commit('SET_PERMISSIONS', [])
           commit('SET_TENANT_CODE', null)
           removeToken()
+          Cookies.remove('tenantCode')
           resolve()
         }).catch(error => {
           reject(error)
@@ -132,6 +133,7 @@ const user = {
         commit('SET_TOKEN', '')
         commit('SET_TENANT_CODE', null)
         removeToken()
+        Cookies.remove('tenantCode')
         resolve()
       })
     }

+ 3 - 2
src/utils/request.js

@@ -23,8 +23,9 @@ service.interceptors.request.use(config => {
 
   // 是否需要设置 token
   const isToken = (config.headers || {}).isToken === false
-  // 始终发送 X-Frontend-Type 和 tenant-code(登录时也需要)
-  config.headers['X-Frontend-Type'] = 'company'
+  // 租户总后台(saasadminui) → fs-admin-saas(profile=admin);登录后 token 含 tenantId 切租户库
+  // 租户销售端(companyUI) → fs-company(profile=company),使用 X-Frontend-Type: company
+  config.headers['X-Frontend-Type'] = 'admin'
   const tenantCode = getTenantCode()
   if (tenantCode) {
     config.headers['tenant-code'] = tenantCode

+ 43 - 43
src/views/index.vue

@@ -76,7 +76,7 @@
                 <count-to :start-val="0" :end-val="todayComsumption" :duration="3600" class="card-panel-num" />
               </div>
               <div class="card-compare">
-                较昨日 <span>+1</span>
+                较昨日 <span>{{ consumptionDayCompareText }}</span>
               </div>
             </div>
           </div>
@@ -195,11 +195,11 @@
                   <img src="../assets/images/liuliang.png" alt=""><span>剩余流量</span>
                 </div>
                 <div class="cardtopnumber">
-                  100.00GB
+                  {{ trafficRemainText }}
                 </div>
               </div>
-              <div class="progress">
-                <el-progress :percentage="90" :show-text="false" define-back-color="#000">
+              <div class="progress" v-if="trafficUsagePercent != null">
+                <el-progress :percentage="trafficUsagePercent" :show-text="false" define-back-color="#000">
 
                 </el-progress>
               </div>
@@ -222,7 +222,7 @@
                 </span>
               </div>
               <div class="internet-number">
-                0
+                {{ smsRemainCount }}
               </div>
             </div>
           </div>
@@ -552,7 +552,7 @@ import CountTo from "vue-count-to";
 import {
   analysisPreview,
   authorizationInfo,
-  dealerAggregated, deaMemberTopTen, rechargeComsumption, rewardMoneyTopTen, rewardMoneyTrend,
+  dealerAggregated, rechargeComsumption, rewardMoneyTopTen, rewardMoneyTrend,
   smsBalance, thisMonthOrderCount, thisMonthRecvCount, trafficLog,
   watchCourseTopTen, watchEndPlayTrend,getWatchCourseStatisticsData,
 } from "@/api/statistics/statistics";
@@ -1018,14 +1018,29 @@ export default {
       // 商品总数
       goodsTotalNum: 0,
       // 今日商品总数
-      todayGoodsNum: 0
+      todayGoodsNum: 0,
+      trafficRemainText: '--',
+      trafficUsagePercent: null
+    }
+  },
+  computed: {
+    consumptionDayCompareText() {
+      const today = Number(this.todayComsumption) || 0
+      const yesterday = Number(this.yesterdayComsumption) || 0
+      const diff = today - yesterday
+      if (diff > 0) {
+        return '+' + diff.toFixed(2)
+      }
+      if (diff < 0) {
+        return diff.toFixed(2)
+      }
+      return '0'
     }
   },
   mounted() {
     this.$nextTick(() => {
       this.initViewerChart()
       this.initDealerChartNew();
-      this.initDealerChart()
       this.initCourseWatchChart();
       this.initAnswerRedPackViewerChart();
       this.initAnswerRedPackMoneyViewerChart();
@@ -1035,9 +1050,8 @@ export default {
       // 监听窗口大小变化,重新渲染图表
       window.addEventListener('resize', () => {
         this.viewerChart && this.viewerChart.resize()
-        this.dealerChart && this.dealerChart.resize()
         this.dealerChartNew && this.dealerChartNew.resize()
-
+        this.courseWatchChart && this.courseWatchChart.resize()
       })
     })
   },
@@ -1184,10 +1198,19 @@ export default {
       })
 
       trafficLog().then(res=>{
-        if(res.code === 200) {
-          this.todayTraffic = res.data.today;
-          this.thisMonthTraffic = res.data.thisMonth;
+        if(res.code === 200 && res.data) {
+          this.todayTraffic = res.data.today || 0;
+          this.thisMonthTraffic = res.data.thisMonth || 0;
+          if (res.data.traffic) {
+            this.trafficRemainText = res.data.traffic
+          } else if (this.thisMonthTraffic > 0) {
+            this.trafficRemainText = this.formatBytes(this.thisMonthTraffic)
+          } else {
+            this.trafficRemainText = '--'
+          }
         }
+      }).catch(() => {
+        this.trafficRemainText = '--'
       })
 
       dealerAggregated().then(res=>{
@@ -1248,9 +1271,6 @@ export default {
       this.handleViewChartData()
       this.handleDealerChartDataNew()
 
-      // 经销商会员观看TOP10
-      this.handleDealerChartData()
-
       this.handleAnswerRedPackViewerChart()
 
       this.handleAnswerRedPackMoneyViewerChart()
@@ -1298,7 +1318,7 @@ export default {
       else if (selected === 0) {
         this.$nextTick(() => {
           if (this.viewerChart) this.viewerChart.resize();
-          if (this.dealerChart) this.dealerChart.resize();
+          if (this.dealerChartNew) this.dealerChartNew.resize();
         });
       } else if (selected === 2) {
         this.$nextTick(() => {
@@ -1308,7 +1328,6 @@ export default {
       }
       if (this.selectedDiv === 0) {
         this.handleViewChartData()
-        this.handleDealerChartData()
         this.handleDealerChartDataNew()
       } else if (this.selectedDiv === 1) {
         this.handleCourseWatchChart()
@@ -1384,7 +1403,6 @@ export default {
 
       if (this.selectedDiv === 0) {
         this.handleViewChartData()
-        this.handleDealerChartData()
         this.handleDealerChartDataNew()
       } else if (this.selectedDiv === 1) {
         this.handleCourseWatchChart()
@@ -1446,23 +1464,6 @@ export default {
         }
       })
     },
-    handleDealerChartData(){
-      let param = this.getParam();
-
-      // 经销商会员观看TOP10
-      deaMemberTopTen({...param,statisticalType: this.viewerType}).then(res=>{
-        if(res.code === 200){
-          let data = res.data;
-          let companyNameList = data.map(e=>e.companyName);
-          let watchUserList = data.map(e=>e.watchUserCount);
-          dealerOption.yAxis.data = companyNameList;
-          dealerOption.series[0].data = watchUserList;
-
-          this.dealerChart.setOption(dealerOption)
-        }
-      })
-
-    },
     handleDealerChartDataNew() {
       let param = this.getParam();
 
@@ -1542,17 +1543,12 @@ export default {
     },
     initThisMonthRecvChart(){
       this.thisMonthRecvChart = echarts.init(this.$refs.viewerReceiveChart)
-      this.thisMonthRecvChart.setOption(thisMonthOrderCountOption)
+      this.thisMonthRecvChart.setOption(thisMonthRecvCountOption)
     },
     initViewerChart() {
       this.viewerChart = echarts.init(this.$refs.viewerChart)
       this.viewerChart.setOption(viewCharOption)
     },
-    initDealerChart() {
-      this.dealerChart = echarts.init(this.$refs.dealerChart)
-
-      this.dealerChart.setOption(dealerOption)
-    },
     initCourseWatchChart() {
       this.courseWatchChart = echarts.init(this.$refs.courseWatchChart)
 
@@ -1578,8 +1574,12 @@ export default {
     }
     // window.removeEventListener('resize', this.resizeHandler)
     this.viewerChart && this.viewerChart.dispose()
-    this.dealerChart && this.dealerChart.dispose()
     this.dealerChartNew && this.dealerChartNew.dispose()
+    this.courseWatchChart && this.courseWatchChart.dispose()
+    this.answerRedPackViewerChart && this.answerRedPackViewerChart.dispose()
+    this.answerRedPackMoneyViewerChart && this.answerRedPackMoneyViewerChart.dispose()
+    this.thisMonthOrderChart && this.thisMonthOrderChart.dispose()
+    this.thisMonthRecvChart && this.thisMonthRecvChart.dispose()
 
   }
 }

+ 1 - 1
src/views/login.vue

@@ -16,7 +16,7 @@
         <div class="title">{{vueAppTitle}}</div>
         <div class="title-line"></div>
         <el-form-item prop="tenantCode">
-          <el-input v-model="loginForm.tenantCode" type="text" auto-complete="off" placeholder="企业编号(选填,如 test001)" class="tenantCode" >
+          <el-input v-model="loginForm.tenantCode" type="text" auto-complete="off" placeholder="请输入企业编号(如 test001)" class="tenantCode" >
             <img slot="prefix" src="../assets/images/user.png" class="input-icon "/>
           </el-input>
         </el-form-item>

+ 1 - 1
src/views/setPassword.vue

@@ -27,7 +27,7 @@
 </template>
 
 <script>
-import { updateUserPwd } from "@/api/company/companyUser";
+import { updateUserPwd } from "@/api/system/user";
 import { removeToken } from "@/utils/auth";
 
 export default {

+ 5 - 7
vue.config.js

@@ -48,17 +48,15 @@ module.exports = {
           '^/watch-api': ''
         }
       },
-      // 默认所有请求代理到 fs-saas(8006) - 租户服务端
-      // 前端API路径已与后端Controller路径统一,无需pathRewrite
+
+      // ===== 默认所有其他请求 → fs-admin-saas(8004) 租户总后台 =====
+      // 租户销售端(总公司/分公司)走 fs-company(8006) + ylrz_saas_his_scrm_companyUI
       [process.env.VUE_APP_BASE_API]: {
-        target: 'http://localhost:8006',
+        target: 'http://localhost:8004',
         changeOrigin: true,
-        pathRewrite: {
-          ['^' + process.env.VUE_APP_BASE_API]: ''
-        }
+        pathRewrite: { ['^' + process.env.VUE_APP_BASE_API]: '' }
       }
     }
-    
   },
   configureWebpack: {
     name: name,