文件
OmniCard/mpuniapp/pages/owner/hall/useHall.uts

333 行
8.0 KiB
Plaintext

/**
* OmniCard AI - 名片大厅人脉驱动层
*/
import {
CardContact,
OwnerPageData,
OwnerPageQuery,
} from '../../../common/types.uts';
import {
collectHallContact,
confirmHallExchange,
fetchEventFloorPage,
fetchHallContactPage,
fetchTeamWallPage,
joinHallEvent,
} from '../../../common/api.uts';
import { getCurrentLocale, getOmniText } from '../../../common/locale.uts';
export type HallCopyKey =
| 'title'
| 'subtitle'
| 'searchPlaceholder'
| 'refresh'
| 'exchangePlaceholder'
| 'exchange'
| 'empty'
| 'error'
| 'loading'
| 'scan'
| 'tabContacts'
| 'tabTeam'
| 'tabEvent'
| 'teamEmpty'
| 'eventEmpty'
| 'eventPlaceholder'
| 'eventJoin';
export type HallContactItem = {
id?: string | number;
peerCardId: number;
peerName: string;
peerTitle?: string;
peerCompany?: string;
peerSlug?: string;
source?: string;
};
export type HallTab = 'contacts' | 'team' | 'event';
export type HallState = {
tab: HallTab;
list: HallContactItem[];
page: number;
size: number;
total: number;
keyWord: string;
exchangeCode: string;
eventCode: string;
loading: boolean;
empty: boolean;
errorMessage: string;
};
export type LoadHallApi = {
fetchHallContactPage: (
query: OwnerPageQuery
) => Promise<OwnerPageData<CardContact>>;
fetchTeamWallPage?: (
query: OwnerPageQuery
) => Promise<OwnerPageData<CardContact>>;
confirmHallExchange?: (
exchangeCode: string
) => Promise<{ status: string; isDualSynced: boolean }>;
collectHallContact?: (peerCardId: string | number) => Promise<CardContact>;
fetchEventFloorPage?: (
query: OwnerPageQuery
) => Promise<OwnerPageData<CardContact>>;
joinHallEvent?: (
code: string
) => Promise<{ event: { code: string }; member: { cardId: number } }>;
};
function isZhLocale(): boolean {
return getCurrentLocale() === 'zh-CN';
}
export function resolveHallText(key: HallCopyKey): string {
const locale = getCurrentLocale();
if (key === 'empty') {
return getOmniText(locale, 'common.empty');
}
if (key === 'error') {
return getOmniText(locale, 'common.error');
}
if (key === 'loading') {
return getOmniText(locale, 'common.loading');
}
if (key === 'scan') {
return getOmniText(locale, 'card.scan_nfc');
}
const zh = isZhLocale();
if (key === 'title') {
return zh ? '名片大厅' : 'Card hall';
}
if (key === 'subtitle') {
return zh ? '已互换和收藏的名片' : 'Exchanged and saved cards';
}
if (key === 'searchPlaceholder') {
return zh ? '搜索姓名或公司' : 'Search name or company';
}
if (key === 'refresh') {
return zh ? '刷新人脉' : 'Refresh network';
}
if (key === 'exchangePlaceholder') {
return zh ? '输入 6 位互换码' : '6-digit exchange code';
}
if (key === 'exchange') {
return zh ? '确认互换' : 'Confirm exchange';
}
if (key === 'tabContacts') {
return zh ? '人脉' : 'Network';
}
if (key === 'tabTeam') {
return zh ? '团队' : 'Team';
}
if (key === 'teamEmpty') {
return zh ? '还没有同事发布名片' : 'No published teammate cards yet';
}
if (key === 'tabEvent') {
return zh ? '现场' : 'Floor';
}
if (key === 'eventEmpty') {
return zh ? '输入活动码加入现场' : 'Enter an event code to join the floor';
}
if (key === 'eventPlaceholder') {
return zh ? '输入 6 位活动码' : '6-character event code';
}
if (key === 'eventJoin') {
return zh ? '加入现场' : 'Join floor';
}
return '';
}
export function toHallItem(row: CardContact): HallContactItem {
return {
id: row.id,
peerCardId: Number(row.peerCardId),
peerName: row.peerName != null ? row.peerName : '',
peerTitle: row.peerTitle,
peerCompany: row.peerCompany,
peerSlug: row.peerSlug,
source: row.source,
};
}
export function createHallState(): HallState {
return {
tab: 'contacts',
list: [],
page: 1,
size: 20,
total: 0,
keyWord: '',
exchangeCode: '',
eventCode: '',
loading: false,
empty: false,
errorMessage: '',
};
}
function readErrorMessage(err: unknown): string {
if (err instanceof Error && err.message !== '') {
return err.message;
}
return resolveHallText('error');
}
export function buildHallPortalUrl(item: HallContactItem): string {
if (item.peerSlug != null && item.peerSlug !== '') {
return `/pages/portal/index?slug=${item.peerSlug}`;
}
return `/pages/portal/index?id=${item.peerCardId}`;
}
export function openHallPortal(item: HallContactItem): void {
uni.navigateTo({
url: buildHallPortalUrl(item),
});
}
export async function refreshHall(
state: HallState,
api?: LoadHallApi
): Promise<void> {
if (state.loading) {
return;
}
state.loading = true;
state.errorMessage = '';
const fetchPage =
state.tab === 'event'
? api != null && api.fetchEventFloorPage != null
? api.fetchEventFloorPage
: fetchEventFloorPage
: state.tab === 'team'
? api != null && api.fetchTeamWallPage != null
? api.fetchTeamWallPage
: fetchTeamWallPage
: api != null
? api.fetchHallContactPage
: fetchHallContactPage;
try {
const query: OwnerPageQuery = {
page: state.page,
size: state.size,
};
const word = state.keyWord.trim();
if (word !== '') {
query.keyWord = word;
}
const data = await fetchPage(query);
const raw = data.list != null ? data.list : [];
const list: HallContactItem[] = [];
for (let i = 0; i < raw.length; i++) {
list.push(toHallItem(raw[i]));
}
state.list = list;
state.total =
data.pagination != null ? data.pagination.total : list.length;
state.empty = list.length === 0;
} catch (err) {
state.list = [];
state.empty = false;
state.errorMessage = readErrorMessage(err);
}
state.loading = false;
}
export async function submitHallExchange(
state: HallState,
api?: LoadHallApi
): Promise<boolean> {
const code = state.exchangeCode.trim();
if (!/^\d{6}$/.test(code)) {
state.errorMessage = resolveHallText('exchangePlaceholder');
return false;
}
const confirm =
api != null && api.confirmHallExchange != null
? api.confirmHallExchange
: confirmHallExchange;
try {
await confirm(code);
state.exchangeCode = '';
await refreshHall(state, api);
return true;
} catch (err) {
state.errorMessage = readErrorMessage(err);
return false;
}
}
export async function collectPeerCard(
peerCardId: string | number,
api?: LoadHallApi
): Promise<boolean> {
const collect =
api != null && api.collectHallContact != null
? api.collectHallContact
: collectHallContact;
await collect(peerCardId);
return true;
}
export function applyHallTab(state: HallState, tab: HallTab): void {
if (tab === 'team') {
state.tab = 'team';
} else if (tab === 'event') {
state.tab = 'event';
} else {
state.tab = 'contacts';
}
state.page = 1;
state.errorMessage = '';
}
export async function submitHallEventJoin(
state: HallState,
api?: LoadHallApi
): Promise<boolean> {
const code = state.eventCode.trim();
if (!/^[A-Za-z0-9]{6}$/.test(code)) {
state.errorMessage = resolveHallText('eventPlaceholder');
return false;
}
const join =
api != null && api.joinHallEvent != null ? api.joinHallEvent : joinHallEvent;
try {
await join(code);
state.eventCode = '';
state.tab = 'event';
await refreshHall(state, api);
return true;
} catch (err) {
state.errorMessage = readErrorMessage(err);
return false;
}
}
export const PENDING_COLLECT_KEY = 'omni_pending_collect_card';
export function setPendingCollectCard(cardId: string | number): void {
try {
uni.setStorageSync(PENDING_COLLECT_KEY, String(cardId));
} catch (_e) {}
}
export function consumePendingCollectCard(): string {
try {
const raw = uni.getStorageSync(PENDING_COLLECT_KEY);
uni.removeStorageSync(PENDING_COLLECT_KEY);
if (raw == null) {
return '';
}
return String(raw).trim();
} catch (_e) {
return '';
}
}