我先并行做两件事:读取并整理项目记忆文件,同时定位相关代码。Grep 在这个大工程上超时了,我换成限定文件类型来搜。找到了 /manage-income 控制器,我读一下它。前端源码不在这个工程里(tabyperf 有独立前端),我从后端入手。先看 DDManageIncomeServiceImpl 和"冻结"关键字。这些提示是前端文案,后端没有。我在 tabyperf 打包好的前端 JS 里找找。这些 JS 带 source map,可以直接还原前端源码。我解析一下。核心逻辑找到了。现在确认 maxMonth 在 Vuex store 里是怎么存的。getMaxMonth 用了自定义的 originalData: true,我看下 axios 封装是怎么处理它的。transformResponse 被替换成了空函数——这是关键。我再看下新版页面 wageManagement.vue 的对应逻辑。逻辑已经完全对上了。再确认几个细节:操作类型枚举、后端返回类型、以及时间戳换算。时间戳确认是 2026-08-01。操作枚举也对上了。最后确认下日期序列化配置。找到一条关键线索:日期格式配置写错了前缀。我看下 tabyperf 的配置文件。后端行为已完全确认。现在按系统要求整理超限的项目记忆文件。
结论:不是"冻结"逻辑的问题,也不是你操作错了 —— 是前端把时间戳当字符串解析失败了
1. 1785513600000 是什么意思
它是 2026-08-01 00:00:00(东八区)的毫秒时间戳。
来源是后端 /tabyperf/manage-income/max-month → DDCalculateIncomeBizNew.getCurrentMonth(channel):
date 存的是"月份第一天",所以这个值 = 系统里已生成工资数据的最大月份。换句话说,库里已经有 2026-08 的工资数据了。
2. "Invalid date" 是怎么冒出来的(根因)
问题出在 tabyperf 前端(源码不在本仓库,我从 tabyperf-app/.../static/static/js/app.*.js.map 里还原出来的):
| 环节 | 代码位置 | 做了什么 |
|---|---|---|
| ① | utils/request.js |
axios 实例的 transformResponse 被写成了空函数(函数体被注释掉、没有 return)→ response.data === undefined |
| ② | 同上 | 于是走 fallback 分支 data = response.request.responseText,拿到的是原始字符串 "1785513600000",不是数字 |
| ③ | api/income-manage.js |
getMaxMonth 带了 originalData: true,把这个字符串原样塞进 Vuex 的 state.incomeManage.maxMonth |
| ④ | IncomeManage.vue |
moment(this.maxMonth).format('YYYY-MM') —— moment 不把纯数字字符串当时间戳(只按日期字符串解析)→ 结果就是 "Invalid date" |
3. 两条提示都是这一个 bug 的产物
第 ④ 步之后 shouldCalMonth 变成了字符串 "Invalid date",接下来全是字符串比较:
- 选「计算工资表」(actionType=2):
"Invalid date" != "2026-08"恒为真 → "请先生成2026-08的工资表" - 选「生成工资表」(actionType=1):
"Invalid date" > "2026-08"恒为真('I'=0x49 >'2'=0x32,按字典序)→ "2026-08的工资表已经冻结,当前工资最新操作记录是Invalid date"
所以那两条看起来自相矛盾的提示,其实后端从来没有真正判断过"冻结",它只返回了一个月份时间戳。
另外注意
if (this.maxMonth)这个条件:当接口返回 null(该渠道无数据)时响应体为空,maxMonth是空字符串 → 整段校验被跳过,功能"正常"。所以这类前端缺陷是数据一多就暴露。
4. 附带发现:日期格式配置写错了前缀
tabyperf-app/src/main/resources/application.properties:
正确的 key 是 spring.jackson.date-format。因为少了前缀,Date 一律被序列化成毫秒时间戳;如果它当时是生效的,接口会返回 "2026-08-01 00:00:00" 这类字符串,moment 能解析,页面就不会报错。这很可能就是"以前能用、现在不行"的回归点。
5. 建议你先核实这两条 SQL
如果 8 月确实已有数据,说明 8 月工资表其实已经生成过,你要做的是「计算工资表」(算金额),而不是「生成工资表」;但在当前前端缺陷下,这两个操作都会被上面那句字符串比较拦下来。
浏览器控制台里也可以直接自证:new Date(1785513600000) 正常,new Date("1785513600000") 是 Invalid Date。
我没有改任何代码(按你的要求)。这个问题根子在前端,修法有两条:
- 前端:
moment(Number(this.maxMonth)),或先判断空值 —— 改动小,但需要前端发版; - 后端:让
max-month直接返回"yyyy-MM"字符串(前端 moment 就能正常解析),属于后端改动,我可以做,但这个接口目前工资管理页在用,需确认没有别处依赖时间戳格式。
你想走哪条?