14 KiB
14 KiB
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 守卫逻辑
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):
- 若存在 Cookie token 且未显式
isToken: false,加Authorization: Bearer <token>;由于 token 是假的,后端并不校验。 - GET 请求用
tansParams把params序列化到 URL,然后清空params。 - 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 |