diff --git a/mpuniapp/pages/owner/profile/index.uvue b/mpuniapp/pages/owner/profile/index.uvue
index 8d74817..d96b453 100644
--- a/mpuniapp/pages/owner/profile/index.uvue
+++ b/mpuniapp/pages/owner/profile/index.uvue
@@ -1,49 +1,36 @@
-
+
-
+
-
+
+
-
-
-
-
-
- +
-
-
- ×
-
+
+
+
+ +
+
+
+
+
-
{{ state.account.name }}
@@ -55,15 +42,52 @@
{{ state.account.department }}
-
-
+
{{ t('editProfile') }} ↗
-
+
+
+
+
+
+ {{ t('metricsCards') }}
+ ↗
+
+
+ {{ state.metrics.cardsCount }}
+ {{ isZhLocale ? '张' : 'Cards' }}
+
+
-
+
+
+
+ {{ t('metricsVisitors') }}
+ ↗
+
+
+ {{ state.metrics.visitorsCount }}
+ {{ isZhLocale ? '位' : 'Visits' }}
+
+
+
+
+
+
+ {{ t('metricsLeads') }}
+ ↗
+
+
+ {{ state.metrics.leadsCount }}
+ {{ isZhLocale ? '条' : 'Leads' }}
+
+
+
+
+
+
@@ -88,219 +112,275 @@
-
-
-
-
- {{ t('metricsCards') }}
- ›
-
-
- {{ metricsData.cards }}
- CARDS
-
-
-
-
-
- {{ t('metricsVisitors') }}
- ›
-
-
- {{ metricsData.visitors }}
- VIEWS
-
-
-
-
-
- {{ t('metricsLeads') }}
- ›
-
-
- {{ metricsData.leads }}
- LEADS
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
- ›
+
+ {{ t('myCards') }}
+ {{ t('myCardsSub') }}
+
+
+
+
+ {{ isZhLocale ? '展示中' : 'Active' }}
+
+ ›
- {{ t('myCards') }}
- {{ myCardsSubText }}
-
-
-
-
+
+
+
+
+
+
-
-
+
+
- ›
+
+ {{ t('cardEdit') }}
+ {{ t('cardEditSub') }}
+
+
+
+ ›
- {{ t('cardEdit') }}
- {{ cardEditSubText }}
-
-
-
-
+
+
+
+
+
+
-
-
+
+
- ›
+
+ {{ t('productCases') }}
+ {{ t('productCasesSub') }}
+
+
+
+
+ {{ isZhLocale ? '作品集' : 'Showcase' }}
+
+ ›
- {{ t('productCases') }}
- {{ productCasesSubText }}
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
- ›
+
+ {{ t('articleDynamics') }}
+ {{ t('articleDynamicsSub') }}
+
+
+
+
+ {{ isZhLocale ? '动态' : 'Posts' }}
+
+ ›
- {{ t('articleDynamics') }}
- {{ articleDynamicsSubText }}
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
- ›
+
+ {{ t('sharePoster') }}
+ {{ t('sharePosterSub') }}
+
+
+
+
+ {{ isZhLocale ? '高清展台' : 'Booth' }}
+
+ ›
- {{ t('sharePoster') }}
- {{ sharePosterSubText }}
-
-
-
-
+
+
+
+
+
+
-
-
+
+
- ›
+
+ {{ t('exchangeHall') }}
+ {{ t('exchangeHallSub') }}
+
+
+
+
+ {{ isZhLocale ? '碰一碰' : 'Radar' }}
+
+ ›
- {{ t('exchangeHall') }}
- {{ exchangeHallSubText }}
-
+
-
-
-
-
-
+
+
+
+
+
- ›
+
+ {{ t('nfcScan') }}
+ {{ t('nfcScanSub') }}
+
+
+
+
+ {{ isZhLocale ? '待贴卡' : 'Ready' }}
+
+ ›
- {{ t('nfcScan') }}
-
-
-
-
+
+
+
+
+
+
- ›
+
+ {{ t('nfcMode') }}
+ {{ t('nfcModeSub') }}
+
+
+
+
+ {{ isZhLocale ? '展会模式' : 'Expo' }}
+
+ ›
- {{ t('nfcMode') }}
-
-
-
-
+
+
+
+
+
+
- ›
+
+ {{ t('nfcSecurity') }}
+ {{ t('nfcSecuritySub') }}
+
+
+
+
+ {{ t('securitySafe') }}
+
+ ›
- {{ t('nfcSecurity') }}
-
-
-
-
+
+
+
+
+
+
- ›
+
+ {{ t('teamBriefing') }}
+ {{ t('teamBriefingSub') }}
+
+
+
+
+ {{ t('livePulse') }}
+
+ ›
- {{ t('teamBriefing') }}
-
+
-
-
-
-
-
+
+
+
+
diff --git a/mpuniapp/pages/owner/profile/useProfile.uts b/mpuniapp/pages/owner/profile/useProfile.uts
index 7d95364..3114522 100644
--- a/mpuniapp/pages/owner/profile/useProfile.uts
+++ b/mpuniapp/pages/owner/profile/useProfile.uts
@@ -25,9 +25,16 @@ export type NotificationSettings = {
leadNotice: boolean;
};
+export type ProfileMetrics = {
+ cardsCount: number;
+ visitorsCount: number;
+ leadsCount: number;
+};
+
export type ProfileState = {
account: UserProfileAccount;
notifications: NotificationSettings;
+ metrics: ProfileMetrics;
locale: OmniLocale;
saving: boolean;
loading: boolean;
@@ -41,6 +48,7 @@ export type StorageApi = {
export const PROFILE_ACCOUNT_STORAGE_KEY = 'omni_owner_profile_account';
export const PROFILE_NOTIFICATIONS_STORAGE_KEY = 'omni_owner_profile_notifications';
+export const PROFILE_METRICS_STORAGE_KEY = 'omni_owner_profile_metrics';
function defaultStorage(): StorageApi {
return {
@@ -80,11 +88,50 @@ export function getDefaultNotifications(): NotificationSettings {
};
}
+export function getDefaultMetrics(): ProfileMetrics {
+ return {
+ cardsCount: 6,
+ visitorsCount: 128,
+ leadsCount: 24,
+ };
+}
+
+export function loadProfileMetrics(storage?: StorageApi): ProfileMetrics {
+ const store = storage != null ? storage : defaultStorage();
+ try {
+ const raw = store.getStorageSync(PROFILE_METRICS_STORAGE_KEY);
+ const parsed = safeParseJson>(raw);
+ if (parsed != null && typeof parsed === 'object') {
+ const defaultM = getDefaultMetrics();
+ const cards = typeof parsed.cardsCount === 'number' ? parsed.cardsCount : defaultM.cardsCount;
+ const visitors = typeof parsed.visitorsCount === 'number' ? parsed.visitorsCount : defaultM.visitorsCount;
+ const leads = typeof parsed.leadsCount === 'number' ? parsed.leadsCount : defaultM.leadsCount;
+ return {
+ cardsCount: cards,
+ visitorsCount: visitors,
+ leadsCount: leads,
+ };
+ }
+ } catch (_e) {}
+ return getDefaultMetrics();
+}
+
+export function saveProfileMetrics(metrics: ProfileMetrics, storage?: StorageApi): boolean {
+ const store = storage != null ? storage : defaultStorage();
+ try {
+ store.setStorageSync(PROFILE_METRICS_STORAGE_KEY, JSON.stringify(metrics));
+ return true;
+ } catch (_e) {
+ return false;
+ }
+}
+
export function createProfileState(locale?: OmniLocale): ProfileState {
const currentLocale = locale != null && locale !== '' ? locale : getCurrentLocale();
return {
account: getDefaultAccount(),
notifications: getDefaultNotifications(),
+ metrics: getDefaultMetrics(),
locale: currentLocale,
saving: false,
loading: false,
@@ -166,6 +213,7 @@ export function loadProfileSettings(storage?: StorageApi): ProfileState {
}
state.locale = getCurrentLocale();
+ state.metrics = loadProfileMetrics(store);
return state;
}
@@ -183,6 +231,7 @@ export function saveProfileSettings(state: ProfileState, storage?: StorageApi):
PROFILE_NOTIFICATIONS_STORAGE_KEY,
JSON.stringify(state.notifications)
);
+ saveProfileMetrics(state.metrics, store);
state.errorMessage = '';
return true;
} catch (err: unknown) {
@@ -416,13 +465,13 @@ export function resolveProfileText(key: string): string {
case 'logout':
return isZh ? '退出登录' : 'Log out';
case 'workspaceSection':
- return isZh ? '智能硬件与团队' : 'Hardware & Team';
+ return isZh ? '设备与团队' : 'Hardware & Team';
case 'cardStudioSection':
- return isZh ? '名片与微官网工作室' : 'Digital Card Studio';
+ return isZh ? '名片内容管理' : 'Digital Card Studio';
case 'myCards':
return isZh ? '我的数字名片' : 'Digital Cards';
case 'cardEdit':
- return isZh ? '极速资料维护' : 'Quick Profile';
+ return isZh ? '名片编辑' : 'Edit Card';
case 'productCases':
return isZh ? '产品相册与案例' : 'Portfolio & Cases';
case 'articleDynamics':
@@ -434,7 +483,7 @@ export function resolveProfileText(key: string): string {
case 'editProfile':
return isZh ? '编辑资料' : 'Edit';
case 'nfcSection':
- return isZh ? 'NFC 智能硬件' : 'NFC Fleet';
+ return isZh ? 'NFC 设备' : 'NFC Fleet';
case 'nfcScan':
return isZh ? 'NFC 贴卡激活' : 'Activate NFC card';
case 'nfcMode':
@@ -442,7 +491,7 @@ export function resolveProfileText(key: string): string {
case 'nfcSecurity':
return isZh ? 'NFC 挂失' : 'Freeze NFC card';
case 'teamBriefing':
- return isZh ? '展会战报' : 'Team briefing';
+ return isZh ? '展会数据' : 'Team briefing';
case 'quotaSection':
return isZh ? '套餐与配额' : 'Plan & Quota';
case 'quotaCards':
@@ -457,6 +506,42 @@ export function resolveProfileText(key: string): string {
return isZh ? '确认退出' : 'Sign Out';
case 'confirmLogoutContent':
return isZh ? '确定要退出当前账号吗?' : 'Are you sure you want to sign out?';
+ case 'myCardsSub':
+ return isZh ? '查看与出示专属数字名片' : 'View and present digital cards';
+ case 'cardEditSub':
+ return isZh ? '修改履历、职业信息与社交矩阵' : 'Update profile and social links';
+ case 'productCasesSub':
+ return isZh ? '展示产品与案例' : 'Portfolio and cases';
+ case 'articleDynamicsSub':
+ return isZh ? '发布业务动态与文章' : 'Publish dynamic posts';
+ case 'sharePosterSub':
+ return isZh ? '展会专属扫码展台与立牌' : 'Expo QR poster and stand';
+ case 'exchangeHallSub':
+ return isZh ? '面对面扫码或碰卡互换' : 'Face-to-face card exchange';
+ case 'nfcScanSub':
+ return isZh ? '新实体卡贴碰写入绑定' : 'Tap and bind new NFC card';
+ case 'nfcModeSub':
+ return isZh ? '展会与拜访场景切换' : 'Switch expo and meeting modes';
+ case 'nfcSecuritySub':
+ return isZh ? '防盗刷保护与远程紧急冻结' : 'Remote freeze and theft protection';
+ case 'teamBriefingSub':
+ return isZh ? '全员名片分发与获客大盘战报' : 'Team leads and distribution briefing';
+ case 'avatarActionSheetTitle':
+ return isZh ? '头像管理' : 'Avatar Options';
+ case 'avatarActionPreview':
+ return isZh ? '查看大图' : 'View Full Photo';
+ case 'avatarActionChoose':
+ return isZh ? '从相册更换头像' : 'Change from Photos';
+ case 'avatarActionRemove':
+ return isZh ? '移除当前头像' : 'Remove Avatar';
+ case 'aboutApp':
+ return isZh ? '关于 OmniCard' : 'About OmniCard';
+ case 'appVersion':
+ return isZh ? '企业旗舰版 v1.2.0' : 'Enterprise v1.2.0';
+ case 'securitySafe':
+ return isZh ? '保护中' : 'Protected';
+ case 'livePulse':
+ return isZh ? '实时' : 'Live';
default:
return key;
}
diff --git a/mpuniapp/tests/owner-profile.test.ts b/mpuniapp/tests/owner-profile.test.ts
index b08845c..edb0c39 100644
--- a/mpuniapp/tests/owner-profile.test.ts
+++ b/mpuniapp/tests/owner-profile.test.ts
@@ -78,3 +78,20 @@ test('8. profile/index.uvue 必须符合 Bento Grid、漫反射软阴影与极
assert.ok(content.includes('linear-gradient'), '必须包含品牌微渐变或极光流光微效果');
});
+test('9. 业务入口必须为条状入口 (Grouped Inset Cell Rows),杜绝玩具方块网格', () => {
+ const content = fs.readFileSync(profileUvuePath, 'utf-8');
+
+ assert.ok(content.includes('bento-list-group'), '必须使用 bento-list-group 分组条状容器');
+ assert.ok(content.includes('bento-row-item'), '必须使用 bento-row-item 条状列表项');
+ assert.equal(content.includes('workspace-grid'), false, '必须彻底移除 workspace-grid 玩具方块网格');
+ assert.equal(content.includes('grid-item-head'), false, '必须彻底移除 grid-item-head 网格头部');
+});
+
+test('10. 头像交互必须优雅沉浸,杜绝破坏高管形象的右上角突兀红色大叉', () => {
+ const content = fs.readFileSync(profileUvuePath, 'utf-8');
+
+ assert.equal(content.includes('avatar-remove-badge'), false, '严禁在头像角部悬挂突兀红色大叉删除标');
+ assert.ok(content.includes('onAvatarClick'), '头像必须支持点击交互呼出操作面板');
+});
+
+