Files
creator-hub/web/src/utils/helpers.ts
T
rogee 6cd4cdc57f refactor(platform): 平台收敛为抖音——移除小红书全链路,监控账号新增画像字段与卡片列表
- 移除小红书:internal/platform/xiaohongshu、controlplane XHS 分支与路由、
  browser_gateway XHS 平台模块与处理器、前端平台选项;migration 038 清理
  XHS 数据并将 creator_* 平台 CHECK 收紧为 douyin
- creator_competitor 新增 follower_count/following_count/aweme_count(仅
  接口定义返回,暂不采集回填);列表接口返回 work_count 与
  latest_published_at(creator_work_source 聚合 MAX(published_at))
- 导入页账号名称列展示作者头像(share job 列表带出 avatar_url)
- 监控账号页改 antd Listy 卡片列表(头像+粉丝/关注/作品/最近发布/同步状态);
  AccountManagementList 收敛为 owned 专用
- 环境模块清理 browser_version 遗留:migration 034 补齐删列,修复 store.go
  中 hub 别名悬空引用,测试 fixture 对齐新 schema
2026-09-24 19:30:28 +08:00

106 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 公共展示工具:字段语义逐一对照 web.archived/src/shared/ui/ui.jsx
export function dateTime(value?: string | number | null): string {
if (!value) return '—';
const date = new Date(value);
return Number.isNaN(date.getTime()) ? String(value) : date.toLocaleString();
}
// 对齐归档版 conflictMessage:优先后端 error 字段,409 冲突时附加提示。
export function conflictMessage(error: any, conflictHint?: string): string {
const status = error?.status ?? error?.body?.status;
const message = error?.message || error?.body?.error || '请求失败';
if (status === 409 && conflictHint) return `${message}:${conflictHint}`;
return message;
}
export const platforms = [
{ value: 'douyin', label: '抖音' },
];
export function platformLabel(value?: string): string {
return platforms.find((item) => item.value === value)?.label || value || '—';
}
export const shareJobStatus: Record<string, { label: string; tone: 'success' | 'warning' | 'error' | 'default' }> = {
queued: { label: '待解析', tone: 'warning' },
processing: { label: '解析中', tone: 'warning' },
succeeded: { label: '已加入监控', tone: 'success' },
failed: { label: '解析失败', tone: 'error' },
};
// 对齐归档版 extractShareURL / platformForShareURL
const shareURLPattern = /https?:\/\/[^\s<>"'`]+/giu;
const trailingShareURLPunctuation = /[,。;!?、)》)】\]}>,.?!:;]+$/u;
export function platformForShareURL(value: string): string {
try {
const hostname = new URL(value).hostname.toLowerCase();
if (['www.douyin.com', 'v.douyin.com'].includes(hostname)) return 'douyin';
} catch {
return '';
}
return '';
}
export function extractShareURL(value?: string): string {
const candidates = String(value || '')
.match(shareURLPattern)
?.map((candidate) => candidate.replace(trailingShareURLPunctuation, ''))
.filter(Boolean);
return candidates?.find((candidate) => platformForShareURL(candidate)) || candidates?.[0] || '';
}
// 账号可恢复性判定(对齐归档版 accountReadiness):授权、绑定、出口健康、账号暂停四层。
export const readinessReasonText: Record<string, string> = {
account_revoked: '授权已撤销',
account_paused: '账号已暂停',
binding_missing: '未绑定运行环境',
network_exit_missing: '未绑定固定出口',
network_exit_unhealthy: '固定出口不健康',
runtime_stop_pending: '运行环境停止结果待确认',
runtime_missing: '运行环境未启动',
runtime_active: '仍有活动运行实例',
account_conflict: '账号状态已变化,请刷新后重试',
environment_unavailable: '环境状态未知',
};
export interface AccountReadiness {
label: string;
reason: string;
canResume: boolean;
ready: boolean;
}
export function accountReadiness(account: any, binding: any, bindingError: any = null): AccountReadiness {
if (account.authorization_status !== 'authorized')
return { label: '授权已撤销', reason: 'account_revoked', canResume: false, ready: false };
if (bindingError) return { label: '环境状态未知', reason: 'environment_unavailable', canResume: false, ready: false };
if (!binding) return { label: '未绑定运行环境', reason: 'binding_missing', canResume: false, ready: false };
let blocked = '';
if (binding.cleanup_pending) {
blocked = 'runtime_stop_pending';
} else if (binding.network_exit_id && binding.network_exit_health !== 'healthy') {
blocked = 'network_exit_unhealthy';
}
if (blocked) return { label: readinessReasonText[blocked], reason: blocked, canResume: false, ready: false };
if (account.runtime_status === 'paused') {
const stopped = !binding.runtime_instance_id;
return { label: stopped ? '资源就绪,可恢复' : '等待运行环境停止', reason: stopped ? '' : 'runtime_stop_pending', canResume: stopped, ready: false };
}
const schedule = binding.schedule_block_reason || '';
return {
label: schedule ? readinessReasonText[schedule] || `不可调度:${schedule}` : '可调度',
reason: schedule,
canResume: false,
ready: !schedule,
};
}
export function isCollectionAccount(account: any): boolean {
return (
account.authorization_status === 'authorized' &&
['normal', 'muted'].includes(account.business_status) &&
account.login_status === 'logged_in'
);
}