文件
OmniCard/mpuniapp/pages/owner/team/useOverview.uts

331 行
7.5 KiB
Plaintext

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

/**
* OmniCard AI (CRMmp) - 展会团队战报业务驱动层
* 并行汇总线索分页与雷达足迹,产出数字摘要
*/
import {
LeadEntity,
OwnerPageData,
OwnerPageQuery,
RadarTrack,
} from '../../../common/types.uts';
import {
fetchOwnerLeadPage,
fetchOwnerRadarPage,
} from '../../../common/api.uts';
import { getCurrentLocale, getOmniText } from '../../../common/locale.uts';
export type OverviewCopyKey =
| 'title'
| 'desc'
| 'totalLeads'
| 'hotCount'
| 'totalTracks'
| 'topCountry'
| 'recent'
| 'refresh'
| 'empty'
| 'error'
| 'loading'
| 'unknownCountry';
export type OverviewSummary = {
totalLeads: number;
hotCount: number;
totalTracks: number;
topCountry: string;
};
export type LoadOverviewInput = {
page?: number;
size?: number;
cardId?: string | number;
};
export type LoadOverviewApi = {
fetchOwnerLeadPage?: (
query: OwnerPageQuery
) => Promise<OwnerPageData<LeadEntity>>;
fetchOwnerRadarPage?: (
query: OwnerPageQuery
) => Promise<OwnerPageData<RadarTrack>>;
};
export type LoadOverviewResult = {
leads: LeadEntity[];
tracks: RadarTrack[];
summary: OverviewSummary;
empty: boolean;
errorMessage: string;
};
export type OverviewState = {
leads: LeadEntity[];
tracks: RadarTrack[];
summary: OverviewSummary;
loading: boolean;
empty: boolean;
errorMessage: string;
};
const DEFAULT_PAGE = 1;
const DEFAULT_SIZE = 20;
function isZhLocale(): boolean {
return getCurrentLocale() === 'zh-CN';
}
/**
* 页面文案:线索 / 足迹走词典,其余中英本地词典
*/
export function resolveOverviewText(key: OverviewCopyKey): string {
const locale = getCurrentLocale();
if (key === 'totalLeads') {
return getOmniText(locale, 'crm.leads');
}
if (key === 'totalTracks') {
return getOmniText(locale, 'radar.visitor_trace');
}
if (key === 'recent') {
return getOmniText(locale, 'crm.follow_up');
}
if (key === 'empty') {
return getOmniText(locale, 'common.empty');
}
if (key === 'error') {
return getOmniText(locale, 'common.error');
}
if (key === 'loading') {
return getOmniText(locale, 'common.loading');
}
const zh = isZhLocale();
if (key === 'title') {
return zh ? '展会战报' : 'Expo briefing';
}
if (key === 'desc') {
return zh ? '汇总线索与足迹' : 'Leads and visitor trail at a glance';
}
if (key === 'hotCount') {
return zh ? '高意向' : 'Hot leads';
}
if (key === 'topCountry') {
return zh ? '主要国家' : 'Top country';
}
if (key === 'refresh') {
return zh ? '刷新战报' : 'Refresh briefing';
}
if (key === 'unknownCountry') {
return zh ? '未标注' : 'Unspecified';
}
return '';
}
function normalizePage(raw: number | null | undefined): number {
if (raw == null || !Number.isFinite(raw) || raw < 1) {
return DEFAULT_PAGE;
}
return Math.floor(raw);
}
function normalizeSize(raw: number | null | undefined): number {
if (raw == null || !Number.isFinite(raw) || raw < 1) {
return DEFAULT_SIZE;
}
return Math.floor(raw);
}
function parseList<T>(payload: OwnerPageData<T> | null | undefined): T[] {
if (payload == null || payload.list == null) {
return [];
}
if (!Array.isArray(payload.list)) {
return [];
}
return payload.list;
}
function readErrorMessage(err: unknown): string {
if (err instanceof Error && err.message !== '') {
return err.message;
}
return resolveOverviewText('error');
}
function emptySummary(): OverviewSummary {
return {
totalLeads: 0,
hotCount: 0,
totalTracks: 0,
topCountry: '',
};
}
function pickTopCountry(tracks: RadarTrack[]): string {
const names: string[] = [];
const counts: number[] = [];
for (let i = 0; i < tracks.length; i++) {
const raw = tracks[i].country;
const country = raw != null ? String(raw).trim() : '';
if (country === '') {
continue;
}
let idx = -1;
for (let j = 0; j < names.length; j++) {
if (names[j] === country) {
idx = j;
break;
}
}
if (idx < 0) {
names.push(country);
counts.push(1);
} else {
counts[idx] = counts[idx] + 1;
}
}
let topCountry = '';
let topCount = 0;
for (let i = 0; i < names.length; i++) {
if (counts[i] > topCount) {
topCount = counts[i];
topCountry = names[i];
}
}
return topCountry;
}
/**
* 按线索与足迹列表汇总战报数字
*/
export function summarize(
leads: LeadEntity[],
tracks: RadarTrack[]
): OverviewSummary {
const safeLeads = leads != null ? leads : [];
const safeTracks = tracks != null ? tracks : [];
let hotCount = 0;
for (let i = 0; i < safeLeads.length; i++) {
if (safeLeads[i].status === 'hot') {
hotCount += 1;
}
}
return {
totalLeads: safeLeads.length,
hotCount,
totalTracks: safeTracks.length,
topCountry: pickTopCountry(safeTracks),
};
}
function buildQuery(input?: LoadOverviewInput): OwnerPageQuery {
const query: OwnerPageQuery = {
page: normalizePage(input != null ? input.page : null),
size: normalizeSize(input != null ? input.size : null),
};
if (input != null && input.cardId != null) {
query.cardId = input.cardId;
}
return query;
}
/**
* 并行拉取线索分页与雷达足迹。可注入两个 page API
*/
export async function loadOverview(
input?: LoadOverviewInput,
api?: LoadOverviewApi
): Promise<LoadOverviewResult> {
const query = buildQuery(input);
const fetchLead =
api != null && api.fetchOwnerLeadPage != null
? api.fetchOwnerLeadPage
: fetchOwnerLeadPage;
const fetchRadar =
api != null && api.fetchOwnerRadarPage != null
? api.fetchOwnerRadarPage
: fetchOwnerRadarPage;
try {
const pages = await Promise.all([fetchLead(query), fetchRadar(query)]);
const leads = parseList(pages[0]);
const tracks = parseList(pages[1]);
const summary = summarize(leads, tracks);
return {
leads,
tracks,
summary,
empty: leads.length === 0 && tracks.length === 0,
errorMessage: '',
};
} catch (err) {
return {
leads: [],
tracks: [],
summary: emptySummary(),
empty: false,
errorMessage: readErrorMessage(err),
};
}
}
export function createOverviewState(): OverviewState {
return {
leads: [],
tracks: [],
summary: emptySummary(),
loading: false,
empty: true,
errorMessage: '',
};
}
export function applyOverviewResult(
state: OverviewState,
result: LoadOverviewResult
): void {
state.leads = result.leads;
state.tracks = result.tracks;
state.summary = result.summary;
state.empty = result.empty;
state.errorMessage = result.errorMessage;
}
export function formatTopCountry(country: string): string {
if (country != null && country.trim() !== '') {
return country.trim();
}
return resolveOverviewText('unknownCountry');
}
/**
* 页面主 CTA:刷新战报
*/
export async function refreshOverview(
state: OverviewState,
api?: LoadOverviewApi
): Promise<LoadOverviewResult> {
if (state.loading) {
return {
leads: state.leads,
tracks: state.tracks,
summary: state.summary,
empty: state.empty,
errorMessage: state.errorMessage,
};
}
state.loading = true;
state.errorMessage = '';
const result = await loadOverview({ page: DEFAULT_PAGE, size: DEFAULT_SIZE }, api);
applyOverviewResult(state, result);
state.loading = false;
if (result.errorMessage === '') {
try {
uni.vibrateShort();
} catch (_e) {
// 兼容不支持振动的端环境
}
}
return result;
}