Files
jcgl-dev/docs/frontend/02-工程结构与请求链路.md
zfjia 329e27b515 初始提交:三端设计文档与 dev 代码基线
docs/:系统梳理、架构优化方案、CR-02 三端功能设计修订(含 §15 三端一致性同步与平台统计分析)、公寓端/应用端/平台端分册、公寓统计分析与排名报表、公寓端小步迭代开发计划(IT-0~IT-8)

dev/:RuoYi-Vue-master(后端)与 RuoYi-Vue2-master(前端)官方上游基线,未改动
2026-11-10 13:43:05 +08:00

14 KiB
Raw Permalink Blame History

02 工程结构与请求链路

1. 目录结构

YktVue/
├── public/
│   ├── index.html          # 先加载 config.js,再加载应用
│   ├── config.js           # 全局 apiRoot / gyid / getWebSocketUrl
│   └── favicon.ico
├── src/
│   ├── main.js             # 仅装配 ElementUI + router
│   ├── App.vue             # 仅 <router-view>
│   ├── router/index.js     # 13 条路由 + 登录守卫
│   ├── api/
│   │   ├── login.js        # /auth/captchaImage、/auth/logon
│   │   ├── jcgl/jcgl.js    # 叫乘主业务接口(35 个)
│   │   ├── jlgl/jlgl.js    # 交路管理接口(7 个)
│   │   └── zhengchuang/mealsOrdering.js  # 食堂接口(9 个)
│   ├── utils/
│   │   ├── request.js      # axios 主实例 + 拦截器 + download
│   │   ├── fileRequest.js  # 导出专用 axios 实例
│   │   ├── auth.js         # Cookie token + 清理登录信息
│   │   ├── ruoyi.js        # tansParams / blobValidate 等模板工具
│   │   └── permission.js   # 依赖不存在的 @/store,死代码
│   ├── plugins/            # RuoYi 插件(cache/download/modal/...),未安装
│   ├── components/
│   │   ├── Room.vue        # 选房器
│   │   ├── RoomLook.vue    # 房间维护
│   │   └── RoomLook copy.vue, media.vue  # 遗留
│   ├── views/
│   │   ├── Login.vue
│   │   ├── JcXx.vue        # 值班主界面(5294 行)
│   │   ├── SynJcXx.vue
│   │   ├── Home.vue / About.vue     # 模板遗留
│   │   └── JcXx.vue.bak_mojibake    # 遗留备份
│   ├── shijinpeng/main.vue # 自助登记终端
│   └── zhengchuang/
│       ├── views/          # 点餐、结算、后厨、保洁
│       ├── components/     # audioPlay / textSpeak
│       └── css/            # MealCss.css 等
├── tests/                  # 两个纯 Node 测试脚本
├── vue.config.js
├── package.json
└── .env.development / .env.production / .env.staging

2. 启动装配

src/main.js 只有 14 行:

Vue.use(ElementUI)
Vue.prototype.$axios = axios
new Vue({ router, render: h => h(App) }).$mount('#app')

因此:

  • 没有安装 Vuex,也没有 store 目录;package.json 中的 vuex 只是模板残留。
  • 没有安装 src/plugins/index.js,所以 this.$modal、this.$download、this.$tab 等 RuoYi 原型方法不存在;JcXx.vue 的 handleDelete 仍调用了 this.$modal.confirm,该分支是死路径。
  • 没有全局路由守卫之外的权限体系;utils/permission.js 因为 import @/store 会失败,且没有被引用。
  • public/index.html:9 先加载 config.js,所以页面里可以直接使用 apiRoot、gyid 这两个隐式全局变量。

3. 登录与路由守卫

3.1 登录时序

sequenceDiagram
  participant U as 用户
  participant L as Login.vue
  participant R as request.js
  participant B as 后端 /auth/logon
  participant LS as localStorage/Cookie

  U->>L: 输入用户名/密码
  L->>R: GET /auth/logon?username&password
  R->>B: baseURL + /auth/logon
  B->>B: 按用户名查 DictData_gy,校验请求 IP 是否在该公寓 ip 列表
  alt 校验通过
    B-->>R: Result.success(LogEntity)
    R-->>L: { code:'00000', data: LogEntity }
    L->>LS: setToken('fake-token-<ts>')(响应无 token)
    L->>LS: gyid=username, loginAccount=username
    L->>L: $router.push('/jcxx')
  else 用户/IP 不匹配
    B-->>R: Result.failure(msg)
    R-->>L: Promise.reject + Message.error
  end

关键代码:

  • 登录请求:api/login.js 的 login() 使用 GET /auth/logon(login.js:16)。
  • 成功处理:Login.vue 判断 response.code === '00000',没有 response.token 就写入 fake-token-时间戳,并把 用户名当成 gyid(Login.vue:83)。
  • 后端契约:/auth/logon 只校验 DictData_gy 与 IP,写入 Session 的 gyid/ip,返回 LogEntity,不签发 token(见 后端 06)。

3.2 守卫逻辑

src/router/index.js:80:

const isLoggedIn = token || loginAccount
if (to.path === '/login') {
  isLoggedIn ? next('/jcxx') : next()
} else {
  isLoggedIn ? next() : next('/login')
}

含义与风险:

  • 登录态 = Cookie Admin-Token 或 localStorage.loginAccount 任一存在,不校验 token 有效性,也不校验后端 Session 是否过期。
  • 退出登录只清本地信息(clearLoginInfo()),没有调用后端 /auth/logout。
  • 只要用户手工写入 loginAccount,就能进入所有页面;真正的权限控制完全依赖后端接口和 IP 校验。
  • 登录页在已登录时会强制跳 /jcxx,无法回到登录页切换账号,除非先清 localStorage/Cookie。

4. axios 请求链路

4.1 主实例

src/utils/request.js:14 创建实例:

配置 值 说明
baseURL 开发 /dev-api,其他 /yktgl 硬编码,不读取 VUE_APP_BASE_API(request.js:17)
timeout 10000 ms 导出走 fileRequest 的 50 s
Content-Type application/json;charset=utf-8 GET 参数由拦截器拼到 URL

请求拦截器(request.js:24):

  1. 若存在 Cookie token 且未显式 isToken: false,加 Authorization: Bearer <token>;由于 token 是假的,后端并不校验。
  2. GET 请求用 tansParams 把 params 序列化到 URL,然后清空 params。
  3. POST/PUT 的防重复提交逻辑只写不校验:sessionObj 写入后,真正比较的 else 分支被整段注释(request.js:54)。

响应拦截器(request.js:75):

const { code, msg } = response.data
if (code === '00000' || code === '11111' || code === 1) return response.data
if (response.data instanceof ArrayBuffer) return response
Message({ message: msg || '系统出错', type: 'error' })
return Promise.reject(new Error(msg || 'Error'))

注意:

  • 11111 被当成成功返回。业务层需要自己判断 res.code === '11111' 并提示错误(例如 handleRechargeConfirm、handleUpdateJcXxConfirm)。这与后端“00000 成功、11111 业务失败”的约定不一致,容易漏判。
  • 二进制判断在成功码判断之后,且 axios 默认不会把 blob 转成 ArrayBuffer,所以 blob 分支实际很少命中;导出另走 fileRequest。
  • 网络错误分支整体被块注释(request.js:94),请求失败时不会弹全局错误提示,多数页面 .catch() 为空或只 console.log,表现为“点了没反应”。

4.2 导出实例

src/utils/fileRequest.js:6 固定 baseURL: '/yktgl'、timeout: 50000。开发环境没有 /yktgl 代理(只有 /dev-api),本地导出会 404;生产同域部署才可用。

4.3 环境变量现状

文件 VUE_APP_BASE_API 是否生效
.env.development /yktgl 否,request.js 写死 /dev-api
.env.production /prod-api 否,写死 /yktgl
.env.staging /stage-api 否,build:stage 也走写死值

改环境时不要只改 .env,必须同步改 request.js(以及需要时的 fileRequest.js 和 vue.config.js 代理)。

5. API 封装与后端映射

5.1 模块划分

模块 文件 接口数 用途
登录 src/api/login.js 2 验证码(未使用)、登录
叫乘主业务 src/api/jcgl/jcgl.js 35 列表、叫乘、房间、人员、导出、同步、时间规则
交路 src/api/jlgl/jlgl.js 7 交路增删改查、导入、确认
食堂 src/api/zhengchuang/mealsOrdering.js 9 菜品、订单、房间、消费、餐次

5.2 叫乘主业务接口映射

src/api/jcgl/jcgl.js 的函数与后端控制器对应关系(后端细节见 06-接口清单):

前端函数 方法 URL 典型调用方
getJcXxList POST /jcgl/getCcJcXx 值班主列表、轮询
getJcXxList_Ls POST /jcgl/getCcJcXx_Ls 历史叫乘(分页/滚动加载)
modifyJcXx POST /jcgl/modifyJcXx 修改叫乘信息
cancelTrainAssignment POST /jcgl/cancelTrainAssignment 取消叫乘
handleCheckOut POST /jcgl/handleCheckOut 出乘
handleStopCalling POST /jcgl/handleStopCalling 停止报警/暂停报警
handleTempCalling POST /jcgl/handleTempCalling 语音临叫(广播式)
handleRoomCall POST /jcgl/handleRoomCall(method=1 语音,=2 喊话) 单房间临叫
handleRoomCallEnd POST /jcgl/handleRoomCallEnd / ...End2 停止单房间呼叫
handleMultiRoomCall POST /jcgl/handleMultiRoomCall 多房间喊话
handleMultiRoomCallEnd POST /jcgl/handleMultiRoomCallEnd 停止多房间喊话
getRoomList GET /jcgl/getRoomList 选房、房间维护、终端
getRoomRecommendations GET /jcgl/getRoomRecommendations 选房推荐
modifyRoomStatus GET /jcgl/modifyRoomStatus 停用/恢复房间
startRoomCleaning POST /clean/startCleaning 开始保洁(deviceCode 固定 "123123")
endRoomCleaning POST /clean/endCleaning 结束保洁
getRyXxByRyId POST /jcgl/getRyxxByRyId 人员查询/维护
modifyRyXx POST /jcgl/modifyRyXx 人员维护保存
deleteRyXx POST /jcgl/deleteRyXx 删除人员
getWslRyXx POST /jcgl/getWslRyXx 未刷脸人员
getRyFjXx POST /jcgl/getRyFjXx 换房前查询同房间人员
exchangeRoom POST /jcgl/exchangeRoom 确认换房
getJlxxList GET /jcgl/getJlxxList 交路列表
getJlXxJcsjList POST /jlgl/getJlXxJcsjList 按开车日期取车次
addJlXx / modifyJlXx / delJlXx / deleteJlXx / confirmJlXx POST /jlgl/* 交路维护
getZbyList / getGzList GET /jcgl/getZbyList、/jcgl/getGzList 值班员/工种字典
getSjgz GET /jcgl/getSjgz 时间规则(150/120/30 分钟)
isHoliday GET /jcgl/isHoliday 食堂节假日判断
getSynJcXx GET /jcgl/getSynJcXx 运安同步数据查询
getSynJcXxIsOffline POST /jwDataLog/getSynJcXxIsOffline 运安离线检测
getLatestSyncTime GET /jcgl/getLatestSyncTime 最近同步时间
getDeviceStatusInfo POST /heartBeat/getDeviceStatusInfo 设备心跳/在线状态
getRecordingConfig GET /jcgl/getRecordingConfig 录音回放配置
handleRecharge GET /recharge/handleRecharge 现金充值办理
exportJcXxExcell GET(blob) /excel/exportJcXxExcell 定时/手工导出
getBtje_info / getBtje_infoMeal3 / updateMeal3 GET/POST /jcgl/getBtje_info*、/jcgl/updateMeal3 餐补余额
submitAll GET /jcgl/submitAll 自助终端/值班台提交入寓登记
getJcxxByRyid POST /jcgl/getJcxxByRyid 按人员查叫乘
jcAlarm POST /jcgl/jcAlarm 设备报警
login GET /auth/login 未被页面使用,登录走 api/login.js

5.3 食堂接口映射

前端函数 方法 URL
getMeals GET /Meals/getMeals
createOrder POST /Meals/createOrder
addOrders_MX POST /Meals/addOrders_MX
OrdersSearch GET /Meals/OrdersSearch
OrderMX_search GET /Meals/OrderMX_search
updateStatus POST /Meals/updateStatus
getRooms GET /Meals/getRooms
consume POST /Meals/consume
getCsLb GET /Meals/getCsLb

6. 响应契约与业务判断

后端统一返回 Result:

{ "code": "00000", "msg": "...", "data": ..., "count": 123 }

前端使用约定:

  • code === '00000':成功,data 为业务数据,count 为分页总数。
  • code === '11111':业务失败;拦截器仍返回该对象,调用方必须自己处理。
  • 其他:拦截器弹 Message.error 并 reject。
  • 导出接口返回 blob,不经过统一响应判断。

7. 工程遗留与陷阱

现象 位置 影响
JcXx.vue 导入不存在的 auditJlXx JcXx.vue:1392 构建告警;若将来使用会运行时报错
shijinpeng/main.vue 导入不存在的 getRyxx main.vue:280 刷脸登记调用时 TypeError: getRyxx is not a function
utils/permission.js 依赖不存在的 @/store src/utils/permission.js 死代码,若被引入立即失败
App.vue 结尾多一个字面量 3 App.vue:32 无效语句,构建噪音
Home.vue 使用未注册的 <test1> Home.vue:6 访问 /home 时渲染告警
README.md 命令写成 npm run serve/build YktVue/README.md 与 package.json 的 dev/build:prod 不符
防重复提交只写不判 request.js:51 双击可能重复提交
请求失败无全局提示 request.js:94 用户无感知,排障困难
build:stage 没有对应接口前缀 .env.staging 构建产物仍请求 /yktgl

8. 修改落点速查

需求 先看
新增一个后端接口 src/api/jcgl/jcgl.js 增加封装 → 页面调用
改登录/切换账号 Login.vue、utils/auth.js、router/index.js
改请求超时/前缀/错误提示 utils/request.js、fileRequest.js、vue.config.js
改开发代理指向 vue.config.js 的 devServer.proxy
新增页面 router/index.js + src/views/
清理模板遗留 plugins/、utils/permission.js、views/Home.vue、About.vue、RoomLook copy.vue、JcXx.vue.bak_mojibake