问题:
echartsApi.getMonthList is not a function,阻塞页面后续加载。highRiskItems 中后端仍返回「简易精神状态」,选择「防误食」后过滤为空。改动:
filter.month、monthOptions ref、onMounted 中的 echartsApi.getMonthList() 调用、handleReset 中的 filter.month = ''。月份下拉在模板中已不存在,属于残留代码。normalizeRiskName:对 trim 后的名称做精确或包含匹配,把「简易精神状态」统一映射为「防误食」。filteredRedList:过滤时对每个 risk 再次调用 normalizeRiskName,并同时支持带「防」前缀、去前缀、互相包含等多种匹配方式,避免后端字段不统一导致过滤失败。类型检查:NO_NINE_SAFETY_ERRORS。
用户要求:不要复杂的过滤兼容逻辑,直接把 multiHighRiskElders[i].highRiskItems 字符串里的「简易精神状态」替换成「防误食」。
改动:
redList 映射中,highRiskItems 先整体 replace(/简易精神状态/g, '防误食'),再按逗号拆分,不再依赖 normalizeRiskName 逐元素映射。filteredRedList 恢复为简单的 r.risks.includes(redRiskFilter.value),因为数据源头已经统一为「防误食」。normalizeRiskName 仍保留,继续用于图表等其他接口返回的九防名称映射。类型检查:NO_NINE_SAFETY_ERRORS。
现象:选「全部」有数据,选任何具体九防风险都 0 条。
根因:后端 highRiskItems 字符串里风险项的分隔符不是 ASCII 逗号,而是顿号「、」或全角逗号「,」。原 .split(',') 拆不开,整串变成一个数组元素,导致数组 includes('防误食') 恒为 false(数组里只有一个长串 ≠ '防误食')。这也解释了上一版 normalize 逐元素版本同样失败。
改动:
risks 解析 split 改为正则 /[,,、\s]+/,支持中英文逗号、顿号、空白统一拆分。filteredRedList 改为宽松匹配:精确 / 去「防」前缀 / 子串包含,进一步兜底命名差异。类型检查:NO_NINE_SAFETY_ERRORS。
需求:
contractFormUpdate.value.contractInfo(JSON)。改动:
components/ContractBody.vue:
contractForm reactive 新增 contractType: '广州地区合同'(首字段)。contractType?: string 和 emit 'update:contractType'。contractForm.contractType。fetchContractData 末尾 emit update:contractType(用 contractForm.contractType || '广州地区合同')。saveContract 与无 contractInfo 的兜底分支)均 JSON.stringify({ ...contractForm }),自动包含 contractType。components/ContractBodyHubei.vue = ContractBody.vue 的副本(含上述 contractType 支持)。ContractManageForm.vue:
contractType ref(默认'广州地区合同')与 contractTypeOptions。合同主体 分隔栏改为 flex:左标题、右 el-select,新增 .contract-type-bar 等样式。ContractBody / ContractBodyHubei 用 v-if="contractType !== '湖北地区合同'" 条件渲染,二者共用 ref="contractBodyRef",都接收 :contract-type 并监听 @update:contract-type 回写。open() 中重置 contractType 为默认,避免上一次选择残留;实际类型由详情加载后子组件回传再切换。注意:ContractBody.vue 中 contractForm.attachments、contractFormUpdate.value.bedName/contractInfo 等为既有类型告警(非本次引入),ContractBodyHubei.vue 因复制同样存在;本次 contractType 改动未引入任何新类型错误。
报错:
ReferenceError: Cannot access 'contractForm' before initialization(ContractBody.vue:91)TypeError: Cannot read properties of null (reading 'emitsOptions')(ContractManageForm.vue:428)根因:上一版在 ContractBody.vue 顶部添加了 watch(() => props.contractType, ..., { immediate: true }),回调里访问了 contractForm.contractType,但 contractForm 的 reactive(...) 声明在文件更下方。<script setup> 中变量存在暂时性死区(TDZ),immediate: true 的 watch 在 setup 执行期间立即触发,导致 contractForm 还未初始化就被访问。
第二个 emitsOptions 错误是 Vue 在子组件 setup 失败后内部更新逻辑抛出的连锁错误。
改动:
ContractBody.vue 和 ContractBodyHubei.vue 中,把该 watch 块从 contractForm 声明之前移到 contractForm reactive 声明之后(即 stageExpenses 字段下方)。immediate: true 逻辑不变:父组件下拉切换合同类型时仍同步写入本地表单。类型检查:本次修复未引入新类型错误;剩余告警均为原文件既有问题。
现象:
根因:子组件 fetchContractData 末尾 emit('update:contractType', 存储的类型),且父组件 @update:contract-type="contractType = $event" 无差别覆盖。手动切换后 v-if 重挂载子组件,又会回传存储的旧类型,把下拉框拽回旧值(回弹)。
改动:
ContractManageForm.vue:
savedContractType(初次解析出的已保存类型)、hasSavedContract(是否已存在保存记录)、contractTypeResolved(是否已解析)三个 ref。handleContractTypeEmit:仅当 !contractTypeResolved 时接受子组件回传类型并解析,其余回传忽略(消除手动切换重挂载导致的回弹)。handleContractExists(exists):记录合同是否已存在。handleContractTypeChange(async):下拉 @change 触发;若 hasSavedContract 且类型与 savedContractType 不同,弹 ElMessageBox.confirm;确认则把 savedContractType 更新为新选择,取消则把 contractType 回退到 savedContractType。首次创建(无保存)不弹框。open() 重置三个状态;两个 ContractBody/ContractBodyHubei(含打印 Teleport 内)均绑定 :lock-contract-type="contractTypeResolved" 并改 @update:contract-type/@update:contract-exists 到新 handler。ElMessageBox from 'element-plus'。components/ContractBody.vue 与 ContractBodyHubei.vue:
update:contractExists;props 增加 lockContractType?: boolean。fetchContractData 末尾:若 props.lockContractType && props.contractType 则 contractForm.contractType = props.contractType(手动切换时用父组件选中值,保证保存值正确);emit update:contractExists(依据 contractFormUpdate.value.contractInfo 是否存在);再 emit update:contractType。注意:初次加载(lock=false)用存储类型驱动下拉;手动切换(lock=true)用父组件选中值并忽略旧回传,避免回弹且保证保存为新类型。类型检查无新增错误。
需求:合同默认区域配置项放在「合同模块配置」卡片内部,而不是独立成新的卡片;字段使用 value2 而不是 orgType。
改动:
src/views/elderly/fee/comprehensive-setting/index.vue:
children 数组内。orgTypeField 改为 value2Field。handleEdit 中:保存时 value2Field 项传 value: ''、value2: c.value。getList 中:回显时 value2Field 项读取 r.value2。src/views/elderly/contracts/ContractManageForm.vue:
loadContractTypeConfig 读取 config.value2 作为 defaultContractType。类型检查:comprehensive-setting/index.vue 与 ContractManageForm.vue 无新增错误;子组件剩余告警均为既有问题。
现象:点击保存合同,控制台报 SyntaxError: "[object Object]" is not valid JSON(ContractBody.vue:820),但保存成功。
根因:saveContract 中遍历 props.attachmentIds 时对每个 row 直接 JSON.parse(row)。当 row 已经是对象而非字符串时,JSON.parse 会把它隐式转成 "[object Object]" 再解析,导致 SyntaxError。该错误被内层 try-catch 捕获并 console.log,不影响外层保存流程,所以保存仍能成功。
改动:
src/views/elderly/contracts/components/ContractBody.vue:
const data = typeof row === 'string' ? JSON.parse(row) : row,对象直接复用。src/views/elderly/contracts/components/ContractBodyHubei.vue:
类型检查:未引入新类型错误;剩余告警均为原文件既有问题。