From 1d34e5745d90ba488150a5824f8912a16ef28b15 Mon Sep 17 00:00:00 2001 From: chenxing Date: Fri, 2 Oct 2026 08:56:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(settings):=20=E4=B8=AA=E4=BA=BA=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E6=89=8B=E6=9C=BA=E5=8F=B7/=E9=82=AE=E7=AE=B1?= =?UTF-8?q?=E5=BC=80=E6=94=BE=E8=87=AA=E5=8A=A9=E4=BF=AE=E6=94=B9=E2=80=94?= =?UTF-8?q?=E2=80=94=E4=BF=9D=E5=AD=98=E6=8C=89=E9=92=AE=E5=90=AF=E7=94=A8?= =?UTF-8?q?=E8=B5=B0=20/api/user/UpdateContact=EF=BC=88=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E4=B8=8E=E5=90=8E=E7=AB=AF=E5=90=8C=E5=8F=A3?= =?UTF-8?q?=E5=BE=84=EF=BC=9A=E6=89=8B=E6=9C=BA=E5=8F=B7=201[3-9]=20?= =?UTF-8?q?=E6=AE=B5=E4=BD=8D/=E9=82=AE=E7=AE=B1=E6=A0=BC=E5=BC=8F/?= =?UTF-8?q?=E9=95=BF=E5=BA=A6=EF=BC=89=EF=BC=8C=E6=88=90=E5=8A=9F=E4=BB=A5?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=BF=94=E5=9B=9E=E7=9A=84=E6=9C=80=E6=96=B0?= =?UTF-8?q?=20BoaUser=20=E5=90=88=E5=B9=B6=20store.userInfo=20=E5=8D=B3?= =?UTF-8?q?=E6=97=B6=E5=9B=9E=E6=98=BE=EF=BC=88=E8=A7=84=E9=81=BF=20CAS=20?= =?UTF-8?q?principal=20=E7=BC=93=E5=AD=98=E6=97=A7=E5=80=BC=EF=BC=89?= =?UTF-8?q?=EF=BC=9BBaseApi=20=E6=96=B0=E5=A2=9E=20updateContact=EF=BC=88?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1B=C2=B7=E5=89=8D=E7=AB=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/BaseApi.ts | 9 ++++++++ src/views/Settings.vue | 49 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/api/BaseApi.ts b/src/api/BaseApi.ts index 84cc6e7..c8bf3ba 100644 --- a/src/api/BaseApi.ts +++ b/src/api/BaseApi.ts @@ -14,6 +14,15 @@ class Base extends Abstract { return this.getRequest({ url, isMsg: false }); } + /** + * 修改本人联系方式(手机号/邮箱,至少一项非空;后端经 UserBase 开放接口落库)。 + * 成功返回更新后的最新用户信息(BoaUser,含新 phone/email),供调用方刷新 store 规避 CAS principal 旧值。 + */ + updateContact(phone: string, email: string) { + const url = path + "/user/UpdateContact"; + return this.postRequest({ url, data: { phone, email } }); + } + /** *获取用户全部角色 * @memberof Basic diff --git a/src/views/Settings.vue b/src/views/Settings.vue index b3bb459..d61b6e8 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -88,8 +88,8 @@
- - + +
@@ -533,7 +533,7 @@ import { Message } from "view-ui-plus"; /** * 设置中心(/settings):左 216px 分组导航卡 + 右内容卡(B 方案左右双卡)。 * 五个 pane 已对接真实数据(设置对接 2026-09-30,零新接口): - * profile 读 store.userInfo(保存占位——接口待 UserBase 支持本人自助修改,本轮不做); + * profile 读 store.userInfo(手机/邮箱本人可改:UpdateContact 直写 UserBase,2026-10-02 任务B); * password 走 updatePassword + 确认登出流程(照抄 UserInfoModal); * avatar 移植 UserInfoModal 直传上传(预设色块/「使用默认头像」保持占位); * logo/wallpaper 管理列表 + 直传 + 删除照抄 SysSetting.vue,LOGO 保存走 saveSchLogo(schId 后端按登录人推断), @@ -662,7 +662,48 @@ function resetProfileForm() { profileForm.mobile = profileView.value.phone; profileForm.email = profileView.value.email; } -/** 保存占位:接口待 UserBase 支持本人自助修改,本轮不做(拍板结论) */ + +/* ===== 手机/邮箱保存(任务B 2026-10-02):/api/user/UpdateContact → UserBase /oapi/user/self/contact ===== */ +const profileSaving = ref(false); +/** 前端校验与后端同口径(UserBase ValidatorUtil.isPhone / CONTACT_EMAIL),双端拦截不一致数据 */ +const PHONE_RE = /^1[3-9]\d{9}$/; +const EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)+$/; + +async function onSaveProfile() { + const phone = profileForm.mobile.trim(); + const email = profileForm.email.trim(); + if (!phone && !email) { + Message.warning("手机号与邮箱至少填写一项"); + return; + } + if (phone && !PHONE_RE.test(phone)) { + Message.warning("手机号格式不正确"); + return; + } + if (email && email.length > 100) { + Message.warning("邮箱长度不能超过100字符"); + return; + } + if (email && !EMAIL_RE.test(email)) { + Message.warning("邮箱格式不正确"); + return; + } + if (profileSaving.value) return; + profileSaving.value = true; + try { + // 成功返回 UserBase 更新后的最新 BoaUser:合并进 store.userInfo 即时回显, + // 规避 CAS principal 缓存旧值(UserBase 侧缓存已随更新驱逐,下次 GetUserInfo 也是新值) + const fresh: any = await BaseApi.updateContact(phone, email); + if (fresh && typeof fresh === "object") { + store.userInfo = { ...store.userInfo, ...fresh }; + } + Message.success("保存成功"); + } catch (error) { + Message.error("保存失败:" + error); + } finally { + profileSaving.value = false; + } +} /* ===== password:updatePassword + 确认登出(流程照抄 UserInfoModal) ===== */ const passwordForm = reactive({ old: "", next: "", confirm: "" });