333 行
8.0 KiB
Plaintext
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 '';
|
|
}
|
|
}
|