diff --git a/backend/src/entities.ts b/backend/src/entities.ts index e914c00..7eab4ea 100644 --- a/backend/src/entities.ts +++ b/backend/src/entities.ts @@ -24,25 +24,27 @@ import * as entity21 from './modules/crm/entity/audit'; import * as entity22 from './modules/card/entity/locale'; import * as entity23 from './modules/card/entity/info'; import * as entity24 from './modules/card/entity/exchange'; -import * as entity25 from './modules/card/entity/contact'; -import * as entity26 from './modules/card/entity/cases'; -import * as entity27 from './modules/card/entity/bento'; -import * as entity28 from './modules/card/entity/article'; -import * as entity29 from './modules/base/entity/base'; -import * as entity30 from './modules/base/entity/audit'; -import * as entity31 from './modules/base/entity/sys/user_role'; -import * as entity32 from './modules/base/entity/sys/user'; -import * as entity33 from './modules/base/entity/sys/role_menu'; -import * as entity34 from './modules/base/entity/sys/role_department'; -import * as entity35 from './modules/base/entity/sys/role'; -import * as entity36 from './modules/base/entity/sys/param'; -import * as entity37 from './modules/base/entity/sys/menu'; -import * as entity38 from './modules/base/entity/sys/log'; -import * as entity39 from './modules/base/entity/sys/department'; -import * as entity40 from './modules/base/entity/sys/conf'; -import * as entity41 from './modules/ai/entity/knowledge'; -import * as entity42 from './modules/ai/entity/glossary'; -import * as entity43 from './modules/ai/entity/concierge'; +import * as entity25 from './modules/card/entity/event'; +import * as entity26 from './modules/card/entity/event-member'; +import * as entity27 from './modules/card/entity/contact'; +import * as entity28 from './modules/card/entity/cases'; +import * as entity29 from './modules/card/entity/bento'; +import * as entity30 from './modules/card/entity/article'; +import * as entity31 from './modules/base/entity/base'; +import * as entity32 from './modules/base/entity/audit'; +import * as entity33 from './modules/base/entity/sys/user_role'; +import * as entity34 from './modules/base/entity/sys/user'; +import * as entity35 from './modules/base/entity/sys/role_menu'; +import * as entity36 from './modules/base/entity/sys/role_department'; +import * as entity37 from './modules/base/entity/sys/role'; +import * as entity38 from './modules/base/entity/sys/param'; +import * as entity39 from './modules/base/entity/sys/menu'; +import * as entity40 from './modules/base/entity/sys/log'; +import * as entity41 from './modules/base/entity/sys/department'; +import * as entity42 from './modules/base/entity/sys/conf'; +import * as entity43 from './modules/ai/entity/knowledge'; +import * as entity44 from './modules/ai/entity/glossary'; +import * as entity45 from './modules/ai/entity/concierge'; export const entities = [ ...Object.values(entity0), ...Object.values(entity1), @@ -88,4 +90,6 @@ export const entities = [ ...Object.values(entity41), ...Object.values(entity42), ...Object.values(entity43), + ...Object.values(entity44), + ...Object.values(entity45), ]; diff --git a/backend/src/modules/base/service/sys/user.ts b/backend/src/modules/base/service/sys/user.ts index b260da6..d1717e2 100644 --- a/backend/src/modules/base/service/sys/user.ts +++ b/backend/src/modules/base/service/sys/user.ts @@ -10,6 +10,7 @@ import * as md5 from 'md5'; import { BaseSysDepartmentEntity } from '../../entity/sys/department'; import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager'; import { BaseSysRoleEntity } from '../../entity/sys/role'; +import { isSuperAdminContext } from '../../../../comm/guard/super-admin'; /** * 系统用户 @@ -103,7 +104,20 @@ export class BaseSysUserService extends BaseService { id: Equal(userId), }); delete info?.password; - return info; + + const isSuper = + isSuperAdminContext(this.ctx) || + info?.username === 'admin' || + this.ctx?.admin?.username === 'admin'; + const tenantId = (this.ctx?.admin?.tenantId ?? (info as any)?.tenantId) || null; + const role = isSuper ? 'super_admin' : (tenantId ? 'tenant_owner' : 'member'); + + return { + ...info, + isSuper, + tenantId, + role, + }; } /** diff --git a/backend/test/mpuniapp/owner-hall.test.ts b/backend/test/mpuniapp/owner-hall.test.ts index f2097eb..b98022b 100644 --- a/backend/test/mpuniapp/owner-hall.test.ts +++ b/backend/test/mpuniapp/owner-hall.test.ts @@ -69,6 +69,56 @@ describe('OmniCard AI 名片大厅 (useHall.uts)', () => { ).toBe('/pages/portal/index?id=202'); }); + it('现场分段走 floorPage,加入活动码后刷新同场名片', async () => { + const { createHallState, applyHallTab, refreshHall, submitHallEventJoin } = + loadHall(); + const state = createHallState(); + applyHallTab(state, 'event'); + let usedFloor = false; + let joined = ''; + await refreshHall(state, { + fetchHallContactPage: async () => ({ + list: [], + pagination: { page: 1, size: 20, total: 0 }, + }), + fetchEventFloorPage: async () => { + usedFloor = true; + return { + list: [ + { + ownerUserId: 11, + peerCardId: 103, + source: 'event', + peerName: 'Chen Wei', + }, + ], + pagination: { page: 1, size: 20, total: 1 }, + }; + }, + }); + expect(usedFloor).toBe(true); + expect(state.list[0].peerName).toBe('Chen Wei'); + + state.eventCode = 'ces26a'; + const ok = await submitHallEventJoin(state, { + fetchHallContactPage: async () => ({ + list: [], + pagination: { page: 1, size: 20, total: 0 }, + }), + fetchEventFloorPage: async () => ({ + list: [], + pagination: { page: 1, size: 20, total: 0 }, + }), + joinHallEvent: async (code: string) => { + joined = code; + return { event: { code }, member: { cardId: 101 } }; + }, + }); + expect(ok).toBe(true); + expect(joined).toBe('ces26a'); + expect(state.eventCode).toBe(''); + }); + it('团队分段走 teamWall 接口', async () => { const { createHallState, applyHallTab, refreshHall } = loadHall(); const state = createHallState(); @@ -129,6 +179,7 @@ describe('OmniCard AI 名片大厅页契约 (index.uvue)', () => { expect(pageSource.includes(' LeadStatus | null; + formatHotUnread: (unread: number) => string; loadLeads: ( query: LoadLeadsQuery, api?: LoadLeadsApi @@ -221,6 +222,12 @@ describe('OmniCard AI 名片主移动潜客列表 (useLeads.uts)', () => { expect(sent.keyWord).toBeUndefined(); }); }); + + it('formatHotUnread 有未读才显示红点文案', () => { + const { formatHotUnread } = loadUseLeads(); + expect(formatHotUnread(0)).toBe(''); + expect(formatHotUnread(2)).toContain('2'); + }); }); describe('OmniCard AI 名片主潜客列表页契约 (leads.uvue)', () => { @@ -253,6 +260,7 @@ describe('OmniCard AI 名片主潜客列表页契约 (leads.uvue)', () => { expect(pageSource.includes('#E3E7ED')).toBe(true); expect(pageSource.includes('primary-cta-btn')).toBe(true); expect(pageSource.includes('status-chip')).toBe(true); + expect(combined.includes('hotUnread') || combined.includes('hotInbox')).toBe(true); }); it('无 emoji、无 any,模板无硬编码中文主文案,长列表不用 view v-for', () => { diff --git a/backend/test/mpuniapp/owner-team-overview.test.ts b/backend/test/mpuniapp/owner-team-overview.test.ts index f77c874..d1bb0dc 100644 --- a/backend/test/mpuniapp/owner-team-overview.test.ts +++ b/backend/test/mpuniapp/owner-team-overview.test.ts @@ -334,6 +334,33 @@ describe('OmniCard AI 展会团队战报 (useOverview.uts)', () => { expect(result.empty).toBe(false); expect(result.errorMessage).toBe('lead page unavailable'); }); + + it('2.4 注入 liveRank 时写入现场排行', async () => { + const { loadOverview } = loadUseOverview(); + const result = await loadOverview( + { page: 1, size: 20 }, + { + fetchOwnerLeadPage: async () => buildPage([]), + fetchOwnerRadarPage: async () => buildPage([]), + fetchCurrentEvent: async () => ({ code: 'CES26A' }), + fetchTeamLiveRank: async (eventId?: string) => { + expect(eventId).toBe('CES26A'); + return [ + { + memberId: 11, + memberName: 'Alex Rivera', + leads: 3, + touches: 12, + score: 42, + rank: 1, + }, + ]; + }, + } + ); + expect(result.ranks).toHaveLength(1); + expect(result.ranks[0].memberName).toBe('Alex Rivera'); + }); }); describe('3. refreshOverview 触觉震动与状态刷新', () => { @@ -374,6 +401,9 @@ describe('OmniCard AI 展会团队战报页契约 (overview.uvue)', () => { expect(combined.includes('loadOverview')).toBe(true); expect(combined.includes('fetchOwnerLeadPage')).toBe(true); expect(combined.includes('fetchOwnerRadarPage')).toBe(true); + expect(combined.includes('fetchTeamLiveRank') || combined.includes('live-rank')).toBe( + true + ); expect(logicSource.includes('Promise.all')).toBe(true); expect(pageSource.includes('getOmniText')).toBe(true); expect(combined.includes('crm.leads')).toBe(true); diff --git a/mpuniapp/pages.json b/mpuniapp/pages.json index e45ac69..244ab84 100644 --- a/mpuniapp/pages.json +++ b/mpuniapp/pages.json @@ -40,7 +40,8 @@ "path": "pages/common/login", "style": { "navigationBarTitleText": "登录", - "backgroundColorContent": "#F7F8FA" + "navigationStyle": "custom", + "backgroundColorContent": "#FFFFFF" } }, { diff --git a/mpuniapp/pages/common/login.uvue b/mpuniapp/pages/common/login.uvue index b9a0355..170905c 100644 --- a/mpuniapp/pages/common/login.uvue +++ b/mpuniapp/pages/common/login.uvue @@ -1,327 +1,85 @@ diff --git a/mpuniapp/pages/owner/team/overview.uvue b/mpuniapp/pages/owner/team/overview.uvue index 90b32bd..d283224 100644 --- a/mpuniapp/pages/owner/team/overview.uvue +++ b/mpuniapp/pages/owner/team/overview.uvue @@ -36,6 +36,21 @@ + + {{ t('rankTitle') }} + + + + + {{ item.memberName }} + {{ formatRankMeta(item) }} + + {{ item.rank }} + + + + + {{ recentLabel }} @@ -128,6 +143,10 @@ function t(key: OverviewCopyKey): string { return resolveOverviewText(key); } +function formatRankMeta(item: { leads: number; touches: number; score: number }): string { + return `${item.leads} / ${item.touches} / ${item.score}`; +} + function handleRefresh(): void { refreshOverview(state); }