From 6db736a6f400a57d66d7dda1335ec54a871e48ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=90=A6?= Date: Tue, 11 Aug 2026 13:30:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=201.=20=E6=9B=B4=E6=96=B0=E6=A1=86?= =?UTF-8?q?=E6=9E=B6=202.=20=E4=BF=AE=E5=A4=8D=E6=A1=86=E6=9E=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=90=8E=E5=AF=BC=E8=87=B4=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=203.=20=E6=B6=88=E6=81=AF=E7=B3=BB=E7=BB=9F=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/adapter/form.ts | 14 +++++ .../src/components/vip/StoreVipCell.vue | 28 ++++------ .../src/components/vip/VipHubModal.vue | 33 ++++++++++- apps/web-antd/src/layouts/basic.vue | 23 +++++--- apps/web-antd/src/utils/vip.ts | 55 +++++++++++++++++++ .../business/store/settings/config/form.ts | 5 +- .../src/views/doctor/doctor/config/form.ts | 3 +- .../views/doctor/pharmacist/config/form.ts | 3 +- .../system/admin/_shared/form-schemas.ts | 3 +- .../src/views/system/admin/config/form.ts | 3 +- .../system/delivery-warehouse/config/form.ts | 3 +- .../views/system/doctor-input/config/form.ts | 3 +- .../src/views/system/pharmacy/config/form.ts | 3 +- .../views/system/store-input/config/form.ts | 3 +- .../src/views/system/store/config/form.ts | 3 +- .../src/views/system/store/config/table.ts | 3 +- .../views/system/vip/store/config/table.ts | 21 ++----- packages/locales/src/langs/en-US/ui.json | 1 + packages/locales/src/langs/zh-CN/ui.json | 1 + 19 files changed, 158 insertions(+), 53 deletions(-) diff --git a/apps/web-antd/src/adapter/form.ts b/apps/web-antd/src/adapter/form.ts index 831c2b32..0354edfd 100644 --- a/apps/web-antd/src/adapter/form.ts +++ b/apps/web-antd/src/adapter/form.ts @@ -40,6 +40,20 @@ async function initSetupVbenForm() { } return true; }, + /** + * 大陆手机号:必填 + 11 位且号段 13-19(与后端 UtilsService::checkPhone 一致) + * 表单字段 rules: 'mobile' 即可,无需再叠 required + */ + mobile: (value, _params, ctx) => { + const phone = typeof value === 'string' ? value.trim() : value; + if (phone === undefined || phone === null || phone === '') { + return $t('ui.formRules.required', [ctx.label]); + } + if (!/^1[3456789]\d{9}$/.test(String(phone))) { + return $t('ui.formRules.mobile', [ctx.label]); + } + return true; + }, }, }); } diff --git a/apps/web-antd/src/components/vip/StoreVipCell.vue b/apps/web-antd/src/components/vip/StoreVipCell.vue index a7ebd325..6aba069b 100644 --- a/apps/web-antd/src/components/vip/StoreVipCell.vue +++ b/apps/web-antd/src/components/vip/StoreVipCell.vue @@ -1,16 +1,22 @@ @@ -56,14 +60,14 @@ const emit = defineEmits<{ .store-vip-cell__name { font-size: 13px; font-weight: 600; - color: var(--foreground, #1f1f1f); + color: hsl(var(--foreground)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .store-vip-cell__sub { font-size: 11px; - color: #8c8c8c; + color: hsl(var(--muted-foreground)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -72,12 +76,4 @@ html.dark .store-vip-cell:hover, .dark .store-vip-cell:hover { background: rgba(106, 205, 187, 0.2); } -html.dark .store-vip-cell__name, -.dark .store-vip-cell__name { - color: #f4f4f5; -} -html.dark .store-vip-cell__sub, -.dark .store-vip-cell__sub { - color: #a1a1aa; -} diff --git a/apps/web-antd/src/components/vip/VipHubModal.vue b/apps/web-antd/src/components/vip/VipHubModal.vue index e19cb069..5c6c9098 100644 --- a/apps/web-antd/src/components/vip/VipHubModal.vue +++ b/apps/web-antd/src/components/vip/VipHubModal.vue @@ -10,6 +10,7 @@ import { useVbenModal } from '@vben/common-ui'; import VipBadgeCombo from '#/components/vip/VipBadgeCombo.vue'; import VipStoreRecordsModal from '#/components/vip/VipStoreRecordsModal.vue'; import VipUpgradeModal from '#/components/vip/VipUpgradeModal.vue'; +import { formatVipExpireAt } from '#/utils/vip'; const gridApi = ref(); const onSuccess = ref void)>(null); @@ -21,6 +22,7 @@ const title = computed( () => `VIP管理 - ${storeName.value || storeId.value || ''}`, ); +/** 当前等级 + 时长类型 */ const currentLevelText = computed(() => { const v = vip.value; if (!v) return '当前:普通会员'; @@ -32,6 +34,20 @@ const currentLevelText = computed(() => { return duration ? `当前:${level} · ${duration}` : `当前:${level}`; }); +/** 到期时间独立一行,打开弹窗时一眼可见 */ +const currentExpireText = computed(() => { + const v = vip.value; + if (!v) return ''; + const code = String(v.level_code || 'V0').trim() || 'V0'; + if (code === 'V0') return ''; + const expire = formatVipExpireAt(v, { + lifetimeText: '终身', + withPrefix: false, + }); + if (!expire) return ''; + return expire === '终身' ? '到期时间:终身' : `到期时间:${expire}`; +}); + const [UpgradeModalComp, upgradeModalApi] = useVbenModal({ connectedComponent: VipUpgradeModal, }); @@ -107,7 +123,12 @@ function openRecords() { :level-name="vip?.level_name" :duration-label="vip?.duration_label" /> -
{{ currentLevelText }}
+
+
{{ currentLevelText }}
+
+ {{ currentExpireText }} +
+