diff --git a/pages_tool/card/contact-edit.vue b/pages_tool/card/contact-edit.vue index 9accd1f..0c5a472 100644 --- a/pages_tool/card/contact-edit.vue +++ b/pages_tool/card/contact-edit.vue @@ -110,10 +110,13 @@ export default { }, save() { if (this.saving) return; - if (!this.form.name.trim()) { + // 防御式取值: 任何非字符串/undefined 都不会让校验误判或抛错 + const name = String(this.form.name || '').trim(); + if (!name) { uni.showToast({ title: '请填写姓名', icon: 'none' }); return; } + this.form.name = name; this.saving = true; const data = { id: this.id, fields: {} }; @@ -125,7 +128,9 @@ export default { uni.showToast({ title: '保存成功', icon: 'success' }); setTimeout(() => this.backToList(), 600); } else { - uni.showToast({ title: res.message || '保存失败', icon: 'none' }); + // 后端错误文案有时放在 message, 有时放在 data(字符串), 两者都兜住 + const msg = res.message || (typeof res.data === 'string' ? res.data : '') || '保存失败'; + uni.showToast({ title: msg, icon: 'none' }); } }; const onFail = () => { @@ -133,11 +138,18 @@ export default { uni.showToast({ title: '网络异常,请稍后重试', icon: 'none' }); }; - // add/update 都走 JSON body:fields 为嵌套对象,跨端序列化零歧义 + // add/update 都走 JSON body,跨端序列化零歧义。 + // ⚠️ 契约差异(见 docs/CARD_API_REFERENCE.md §1.4.2 / §1.4.4): + // contact/add → 入参是「顶层平铺字段」, name 必须在 body 顶层; + // contact/update→ 额外兼容 fields 对象。 + // 历史 bug: 新增时也包成 { fields: {...} }, 后端在顶层读不到 name, + // 返回「请填写姓名」→ 表现为"明明填了姓名还提示填写姓名"。 + // 这里新增按契约平铺, 同时保留一份 fields 兼容旧后端(多余键会被白名单忽略)。 if (this.isEdit) { this.$cardApi.contactUpdate({ data: data, success: onOk, fail: onFail }); } else { - this.$cardApi.contactAdd({ data: { fields: data.fields }, success: onOk, fail: onFail }); + const addPayload = Object.assign({}, data.fields, { fields: data.fields }); + this.$cardApi.contactAdd({ data: addPayload, success: onOk, fail: onFail }); } }, // 鸿蒙安全回列表: $util.redirectTo(禁裸 uni.switchTab/uni.navigateBack 兜底)