From 1b7ee59d236a743449ba01c6720061c8ef5f7b7b Mon Sep 17 00:00:00 2001 From: owenchen Date: Sat, 17 Oct 2026 22:31:52 +0800 Subject: [PATCH] ow --- .../Security/SecurityUserRequest.auto.cs | 4 + .../SecurityUserService.cs | 22 ++ .../Data/SecurityUserDisplayData.cs | 24 ++ .../Service/ISecurityUserService.auto.cs | 2 + .../Security/SecurityUserController.auto.cs | 19 + .../src/data/auto/securityUserDisplayData.ts | 8 + uniapp/youjiala/src/locale/lang/en-US.json | 17 + uniapp/youjiala/src/locale/lang/zh-CN.json | 17 + uniapp/youjiala/src/pages.json | 4 + .../src/pages/login/change-local-name.vue | 5 + .../src/pages/login/identity-verification.vue | 348 ++++++++++++++++++ uniapp/youjiala/src/pages/tab/mine.vue | 59 ++- uniapp/youjiala/src/router/routes.ts | 2 + .../service/security/securityUserService.ts | 11 + 14 files changed, 538 insertions(+), 4 deletions(-) create mode 100644 uniapp/youjiala/src/pages/login/identity-verification.vue diff --git a/CloudBuilder/CloudBuilder.Request/Security/SecurityUserRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Security/SecurityUserRequest.auto.cs index b223254..a800ec5 100644 --- a/CloudBuilder/CloudBuilder.Request/Security/SecurityUserRequest.auto.cs +++ b/CloudBuilder/CloudBuilder.Request/Security/SecurityUserRequest.auto.cs @@ -71,6 +71,10 @@ return Task.Run(() => serviceRequest.PostAsJsonAsync serviceRequest.PostAsync("/SecurityUser/UpdateLocalName?localName=" + localName.ToString())).GetAwaiter().GetResult(); } + public void UpdateSecurityUserIdCard(SecurityUserDisplayData user) + { + Task.Run(() => serviceRequest.PostAsJsonAsync("/SecurityUser/UpdateSecurityUserIdCard" , user)).GetAwaiter().GetResult(); } + } } \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Security.Service/SecurityUserService.cs b/CloudBuilder/CloudBuilder.Security.Service/SecurityUserService.cs index ae032f4..5b9b67e 100644 --- a/CloudBuilder/CloudBuilder.Security.Service/SecurityUserService.cs +++ b/CloudBuilder/CloudBuilder.Security.Service/SecurityUserService.cs @@ -349,5 +349,27 @@ namespace CloudBuilder.Security.Service repository.UpdateNow(securityUser); } + + [AllowAnonymous] + public void UpdateSecurityUserIdCard(SecurityUserDisplayData user) + { + PermissionContext permissionContext = new PermissionContext(service); + + if (permissionContext.CanView(SecurityPermissionPolicy.CanSeeAllUser)) + { + return ; + } + + SecurityUserEntity securityUser = repository.DetachedEntities.Where(x => x.UserName == service.UserId && x.UserIsValidIndc == YesNoPolicy.YES).FirstOrDefault(); + + if (securityUser == null) + { + throw new ValidatedException("用户不存在."); + } + securityUser.UserLocalName = user.UserLocalName; + securityUser.UserType = SecurityUserTypePolicy.NORMAL_USERS; + securityUser.UserRemark = user.UserRemark; + repository.UpdateNow(securityUser); + } } } diff --git a/CloudBuilder/CloudBuilder.Security/Data/SecurityUserDisplayData.cs b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserDisplayData.cs index 783e5c2..7e8d5bd 100644 --- a/CloudBuilder/CloudBuilder.Security/Data/SecurityUserDisplayData.cs +++ b/CloudBuilder/CloudBuilder.Security/Data/SecurityUserDisplayData.cs @@ -23,6 +23,30 @@ namespace CloudBuilder.Security.Data public string? OrgUserPassword { get; set; } + + public bool? IsCanAmend { get; set; } = false; + + // ===== 身份证 OCR 识别信息(transient 显示字段:识别后回填表单,随保存提交但不落 family_person 表) ===== + /// 民族(OCR nation) + public string? Nation { get; set; } + + /// 住址(OCR address) + public string? Address { get; set; } + + /// 公民身份号码(OCR id_number) + public string? IdNumber { get; set; } + + /// 签发机关(OCR issuer,仅背面) + public string? Issuer { get; set; } + + /// 有效期限(OCR validity,仅背面) + public string? Validity { get; set; } + + /// 身份证照片物理文件名(上传到 idcard 目录后回写,与头像 AvatarFilename 同口径) + public string? IdCardFilename { get; set; } + + /// 身份证照片预览 URL(本地临时预览,不入库) + public string? IdCardUrl { get; set; } } } diff --git a/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserService.auto.cs b/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserService.auto.cs index 3576815..30e7901 100644 --- a/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserService.auto.cs +++ b/CloudBuilder/CloudBuilder.Security/Service/ISecurityUserService.auto.cs @@ -19,5 +19,7 @@ namespace CloudBuilder.Security.Service void Deletes(string[] keys); void UpdateLocalName(string localName); + + void UpdateSecurityUserIdCard(SecurityUserDisplayData securityUser); } } diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserController.auto.cs index 9c58c8b..60e3043 100644 --- a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserController.auto.cs +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Security/SecurityUserController.auto.cs @@ -254,6 +254,25 @@ this.securityUserService= securityUserService; } } + [AllowAnonymous] + [HttpPost] + public dynamic UpdateSecurityUserIdCard(SecurityUserDisplayData user){ + try + { + securityUserService.UpdateSecurityUserIdCard(user); + + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + } } \ No newline at end of file diff --git a/uniapp/youjiala/src/data/auto/securityUserDisplayData.ts b/uniapp/youjiala/src/data/auto/securityUserDisplayData.ts index 22e0392..7e751fa 100644 --- a/uniapp/youjiala/src/data/auto/securityUserDisplayData.ts +++ b/uniapp/youjiala/src/data/auto/securityUserDisplayData.ts @@ -3,5 +3,13 @@ import { SecurityUserEntity } from "./securityUserEntity"; export class SecurityUserDisplayData extends SecurityUserEntity { public OrgUserPassword: string = ""; + public IsCanAmend?: Date= null!; + public Nation: string = ""; + public Address: string = ""; + public IdNumber: string = ""; + public Issuer: string = ""; + public Validity: string = ""; + public IdCardFilename: string = ""; + public IdCardUrl: string = ""; } diff --git a/uniapp/youjiala/src/locale/lang/en-US.json b/uniapp/youjiala/src/locale/lang/en-US.json index c09990d..2816ae3 100644 --- a/uniapp/youjiala/src/locale/lang/en-US.json +++ b/uniapp/youjiala/src/locale/lang/en-US.json @@ -28,6 +28,10 @@ "loginAgent": "Agent Login", "changePassword": "Change Password", "changeLocalName": "Change Nickname", + "verifiedLocalName": "Verified Nickname", + "identityVerification": "Identity Verification", + "verified": "Verified", + "verifiedNoRename": "Verified users cannot change nickname", "logout": "Log Out", "logoutConfirmTitle": "Log Out", "logoutConfirmContent": "Are you sure you want to log out?", @@ -88,6 +92,19 @@ "nameTooShort": "User name must be at least 2 characters", "success": "Updated, please log in again" }, + "IdentityVerificationPage": { + "title": "Identity Verification", + "intro": "After uploading your ID card, the system recognizes it and writes all information into the remark; the nickname becomes the name on the ID and the account is marked verified (applies to normal users only)", + "uploadBut": "Upload & Verify", + "uploadingTip": "Recognizing…", + "savingTip": "Submitting…", + "success": "Identity verified", + "failed": "Recognition or submission failed", + "noResult": "Nothing recognized, please try a clearer photo", + "previewTitle": "Recognized Info (will be saved to remark)", + "reloginTip": "Verification takes effect immediately; on another device or after clearing cache the server is the source of truth", + "verifiedDone": "You have already completed identity verification" + }, "ThemePage": { "title": "My Theme", "themeTitle": "Theme Color", diff --git a/uniapp/youjiala/src/locale/lang/zh-CN.json b/uniapp/youjiala/src/locale/lang/zh-CN.json index 810790f..50c964e 100644 --- a/uniapp/youjiala/src/locale/lang/zh-CN.json +++ b/uniapp/youjiala/src/locale/lang/zh-CN.json @@ -28,6 +28,10 @@ "loginAgent": "代理登录", "changePassword": "修改密码", "changeLocalName": "修改昵称", + "verifiedLocalName": "认证昵称", + "identityVerification": "身份验证", + "verified": "已认证", + "verifiedNoRename": "已认证用户不能修改昵称", "logout": "退出登录", "logoutConfirmTitle": "退出登录", "logoutConfirmContent": "确定要退出当前账号吗?", @@ -88,6 +92,19 @@ "nameTooShort": "用户名称不能少于两个字", "success": "修改成功,请重新登录" }, + "IdentityVerificationPage": { + "title": "身份验证", + "intro": "上传身份证后,系统自动识别并将全部信息写入备注,昵称为身份证姓名,账号置为已认证(仅普通用户生效)", + "uploadBut": "上传并认证", + "uploadingTip": "识别中…", + "savingTip": "提交中…", + "success": "身份验证成功", + "failed": "识别或提交失败", + "noResult": "未识别到信息,请换一张更清晰的照片", + "previewTitle": "识别结果(将写入备注)", + "reloginTip": "认证结果已即时生效;换设备或清除缓存后以服务端为准", + "verifiedDone": "您已完成身份认证,无需重复认证" + }, "ThemePage": { "title": "我的主题", "themeTitle": "主题颜色", diff --git a/uniapp/youjiala/src/pages.json b/uniapp/youjiala/src/pages.json index f3c76ba..eef50a4 100644 --- a/uniapp/youjiala/src/pages.json +++ b/uniapp/youjiala/src/pages.json @@ -24,6 +24,10 @@ { "path": "pages/login/change-local-name" }, + // 身份验证(/identity-verification):从「我的」跳入,上传身份证→后端 OCR→识别信息写入 UserRemark 并置认证态 + { + "path": "pages/login/identity-verification" + }, // 错误页:H5 短地址由 CLEAN_PATH_OVERRIDES 指定为 /error/page40x,与旧 WebVue 地址一致 { "path": "pages/error/page401" diff --git a/uniapp/youjiala/src/pages/login/change-local-name.vue b/uniapp/youjiala/src/pages/login/change-local-name.vue index be69c31..d823b45 100644 --- a/uniapp/youjiala/src/pages/login/change-local-name.vue +++ b/uniapp/youjiala/src/pages/login/change-local-name.vue @@ -33,6 +33,11 @@ async function doLogout(): Promise { } async function handleSubmit() { + // 已认证用户昵称锁定为身份证姓名,禁止再改(冷启动直达本页时的兜底) + if (loginProfileStore.userType === "N") { + uni.showToast({ title: t("MinePage.verifiedNoRename"), icon: "none" }); + return; + } const name = localName.value.trim(); if (!name) { uni.showToast({ title: t("ChangeLocalNamePage.nameRequired"), icon: "none" }); diff --git a/uniapp/youjiala/src/pages/login/identity-verification.vue b/uniapp/youjiala/src/pages/login/identity-verification.vue new file mode 100644 index 0000000..20840b6 --- /dev/null +++ b/uniapp/youjiala/src/pages/login/identity-verification.vue @@ -0,0 +1,348 @@ + + + + + diff --git a/uniapp/youjiala/src/pages/tab/mine.vue b/uniapp/youjiala/src/pages/tab/mine.vue index 2255da7..46f4083 100644 --- a/uniapp/youjiala/src/pages/tab/mine.vue +++ b/uniapp/youjiala/src/pages/tab/mine.vue @@ -28,6 +28,9 @@ const loginProfileStore = useLoginProfileStore(); const { can } = usePermission(); const canSeeLoginAgent = computed(() => can("none", "SecurityUser", "LoginAgent")); +/* 「已认证」判定:与后端 UpdateSecurityUserIdCard 口径一致——UserType=NORMAL_USERS("N") 即视为已认证(身份验证成功后本地快照同步) */ +const isVerified = computed(() => loginProfileStore.userType === "N"); + /* 统一风格:主题渐变底 + 主题色变量(与 family-person-enquiry / 族谱首页同一接线口径) */ const { themeBackground } = useThemeGradient(); const { primary, accentGradient, accentSoft, accentShadow } = useThemeTokens(); @@ -63,11 +66,22 @@ function goChangePassword(): void { uni.navigateTo({ url: pageUrl("changePassword") }); } -/** 进入「修改昵称」页(/change-local-name):改用户名,成功后按旧系统约定退出重登刷新快照 */ +/** 进入「修改昵称」页(/change-local-name):改用户名,成功后按旧系统约定退出重登刷新快照;已认证用户昵称锁定为身份证姓名,单击无效(改由右侧直接展示昵称) */ function goChangeLocalName(): void { + if (isVerified.value) { + return; + } uni.navigateTo({ url: pageUrl("changeLocalName") }); } +/** 进入「身份验证」页(/identity-verification):上传身份证 OCR 后把信息写入备注并置认证态;已认证后不再重复认证,单击无效 */ +function goIdentityVerification(): void { + if (isVerified.value) { + return; + } + uni.navigateTo({ url: pageUrl("identityVerification") }); +} + /** 退出登录:确认后调后端 Logout、清本地档案,回登录页 */ async function handleLogout(): Promise { const confirmed = await new Promise((resolve) => { @@ -156,15 +170,32 @@ async function handleLogout(): Promise { - + - {{ t("MinePage.changeLocalName") }} + {{ isVerified ? t("MinePage.verifiedLocalName") : t("MinePage.changeLocalName") }} - + + {{ loginProfileStore.userLocalName }} + + + + + + + + + + + {{ t("MinePage.identityVerification") }} + + + {{ t("MinePage.verified") }} + + @@ -272,6 +303,26 @@ async function handleLogout(): Promise { color: #1f2329; } +/* 已认证徽标:替换右箭头,绿色描边胶囊,与主题橙入口区分状态语义 */ +.mine-cell__tag { + padding: 6rpx 20rpx; + border: 2rpx solid #52c41a; + border-radius: 999rpx; + font-size: 24rpx; + font-weight: 600; + color: #52c41a; +} + +/* 已认证锁定的展示值(如昵称):右对齐灰字省略,替代不可点的箭头 */ +.mine-cell__value { + max-width: 60%; + overflow: hidden; + font-size: 28rpx; + color: #8f959e; + white-space: nowrap; + text-overflow: ellipsis; +} + /* 退出登录:降权为描边行,标题居中、危险色,与普通入口区分 */ .mine-cell--logout { justify-content: center; diff --git a/uniapp/youjiala/src/router/routes.ts b/uniapp/youjiala/src/router/routes.ts index 10a4df6..c3ce8d4 100644 --- a/uniapp/youjiala/src/router/routes.ts +++ b/uniapp/youjiala/src/router/routes.ts @@ -19,6 +19,8 @@ export const PAGE_PATHS = { changePassword: "pages/login/change-password", // 修改昵称(短地址 /change-local-name):需登录,从「我的」页跳入,成功后按旧系统约定退出重登刷新快照 changeLocalName: "pages/login/change-local-name", + // 身份验证(短地址 /identity-verification):从「我的」跳入,上传身份证 OCR 后写入 UserRemark 并置认证态 + identityVerification: "pages/login/identity-verification", dashboard: "pages/dashboard/dashboard", error401: "pages/error/page401", error403: "pages/error/page403", diff --git a/uniapp/youjiala/src/service/security/securityUserService.ts b/uniapp/youjiala/src/service/security/securityUserService.ts index 32cf8be..23e6a01 100644 --- a/uniapp/youjiala/src/service/security/securityUserService.ts +++ b/uniapp/youjiala/src/service/security/securityUserService.ts @@ -5,6 +5,7 @@ import { request,download } from "@/utils/request"; import type { SecurityUserSearchCriteria } from "@/data/auto/securityUserSearchCriteria"; import type { SecurityUserResultData } from "@/data/auto/securityUserResultData"; import type { SecurityFunctionResultData } from "@/data/auto/securityFunctionResultData"; + import type { SecurityUserDisplayData } from "@/data/auto/securityUserDisplayData"; class SecurityUserService{ @@ -117,6 +118,16 @@ class SecurityUserService{ ) }; + async UpdateSecurityUserIdCard(data: SecurityUserDisplayData) { + return request( + { + url: "/SecurityUser/UpdateSecurityUserIdCard", + method: "post", + data, + } + ) + }; + } const securityUserService= new SecurityUserService();