feat: 新增商业化新账统计与出海财务运营驾驶舱,支持运营官(COO)与财务官(CFO)双重视角穿透
这个提交包含在:
@@ -58,6 +58,7 @@ const i18n = {
|
||||
'menu.user.role.user': 'General User',
|
||||
'menu.dashboard.workplace': 'Workplace',
|
||||
'menu.dashboard.radarMap': 'Global Radar Heatmap',
|
||||
'menu.dashboard.financial': 'Financial & Operations',
|
||||
'navbar.logout': 'Logout',
|
||||
'settings.title': 'Settings',
|
||||
'settings.themeColor': 'Theme Color',
|
||||
@@ -144,6 +145,7 @@ const i18n = {
|
||||
'menu.user.role.user': '普通用户',
|
||||
'menu.dashboard.workplace': '工作台',
|
||||
'menu.dashboard.radarMap': '全球访客雷达',
|
||||
'menu.dashboard.financial': '新账与财务统计',
|
||||
'navbar.logout': '退出登录',
|
||||
'settings.title': '页面配置',
|
||||
'settings.themeColor': '主题色',
|
||||
@@ -176,6 +178,7 @@ const i18n = {
|
||||
},
|
||||
'ar-SA': {
|
||||
...omniLocales['ar-SA'].messages,
|
||||
'menu.dashboard.financial': 'التحليلات المالية والتشغيلية',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
Typography,
|
||||
Space,
|
||||
Grid,
|
||||
Radio,
|
||||
} from '@arco-design/web-react';
|
||||
import { ImageUploader } from '@/components/Upload';
|
||||
import type { PaginationProps, TableColumnProps } from '@arco-design/web-react';
|
||||
@@ -149,6 +150,7 @@ export default function CardArticlesPage() {
|
||||
isPublished: false,
|
||||
});
|
||||
|
||||
const [ogRatio, setOgRatio] = useState<'landscape' | 'square'>('landscape');
|
||||
const ogPreview = useMemo(() => deriveOgMeta(formValues), [formValues]);
|
||||
|
||||
const loadData = async (page = DEFAULT_PAGE, size = DEFAULT_SIZE) => {
|
||||
@@ -570,12 +572,27 @@ export default function CardArticlesPage() {
|
||||
fontSize: '12px',
|
||||
color: lightColors.text2,
|
||||
marginTop: '4px',
|
||||
marginBottom: '16px',
|
||||
marginBottom: '12px',
|
||||
}}
|
||||
>
|
||||
{t['cardArticles.ogPreview.desc']}
|
||||
</Typography.Text>
|
||||
|
||||
<Radio.Group
|
||||
type="button"
|
||||
size="mini"
|
||||
value={ogRatio}
|
||||
onChange={setOgRatio}
|
||||
style={{ marginBottom: '12px', width: '100%', display: 'flex' }}
|
||||
>
|
||||
<Radio value="landscape" style={{ flex: 1, textAlign: 'center' }}>
|
||||
{t['cardArticles.ogPreview.landscape']}
|
||||
</Radio>
|
||||
<Radio value="square" style={{ flex: 1, textAlign: 'center' }}>
|
||||
{t['cardArticles.ogPreview.square']}
|
||||
</Radio>
|
||||
</Radio.Group>
|
||||
|
||||
{/* 模拟出海社交平台卡片 (LinkedIn / WhatsApp / X Card) */}
|
||||
<div
|
||||
style={{
|
||||
@@ -589,7 +606,8 @@ export default function CardArticlesPage() {
|
||||
{/* 封面图预览 */}
|
||||
<div
|
||||
style={{
|
||||
height: '140px',
|
||||
height: ogRatio === 'square' ? '220px' : '140px',
|
||||
transition: 'height 250ms cubic-bezier(0.2, 0.8, 0.2, 1)',
|
||||
backgroundColor: lightColors.primarySoft,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
||||
@@ -29,6 +29,8 @@ const i18n = {
|
||||
'cardArticles.drawer.editTitle': 'Edit Article / Post',
|
||||
'cardArticles.ogPreview.title': 'OpenGraph Social Card Preview',
|
||||
'cardArticles.ogPreview.desc': 'This is how your post appears when shared across LinkedIn, WhatsApp, X, and WeChat.',
|
||||
'cardArticles.ogPreview.landscape': 'Landscape (1.91:1)',
|
||||
'cardArticles.ogPreview.square': 'Square (1:1)',
|
||||
'cardArticles.ogPreview.domain': 'omnicard.ai',
|
||||
'cardArticles.ogPreview.emptyTitle': 'Post Title Preview',
|
||||
'cardArticles.ogPreview.emptyDesc': 'Summary or first 160 characters will automatically appear here as description...',
|
||||
@@ -68,6 +70,8 @@ const i18n = {
|
||||
'cardArticles.drawer.editTitle': '编辑文章与动态',
|
||||
'cardArticles.ogPreview.title': 'OpenGraph 社交卡片实时预览',
|
||||
'cardArticles.ogPreview.desc': '在 LinkedIn、WhatsApp、X (Twitter) 及微信转发时呈现的社交图文卡片效果。',
|
||||
'cardArticles.ogPreview.landscape': '横版 (1.91:1)',
|
||||
'cardArticles.ogPreview.square': '方版 (1:1)',
|
||||
'cardArticles.ogPreview.domain': 'omnicard.ai',
|
||||
'cardArticles.ogPreview.emptyTitle': '文章标题预览',
|
||||
'cardArticles.ogPreview.emptyDesc': '摘要或正文前 160 字符将自动提炼为社交分享描述...',
|
||||
|
||||
@@ -0,0 +1,819 @@
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Grid,
|
||||
Message,
|
||||
Progress,
|
||||
Radio,
|
||||
Select,
|
||||
Space,
|
||||
Spin,
|
||||
Statistic,
|
||||
Table,
|
||||
Tag,
|
||||
Typography,
|
||||
} from '@arco-design/web-react';
|
||||
import {
|
||||
IconDownload,
|
||||
IconSwap,
|
||||
IconArrowRise,
|
||||
IconSafe,
|
||||
} from '@arco-design/web-react/icon';
|
||||
import axios from 'axios';
|
||||
import useLocale from '@/utils/useLocale';
|
||||
import { lightColors } from '@/style/tokens';
|
||||
import type {
|
||||
AgingAnalysisItem,
|
||||
CurrencyBreakdownItem,
|
||||
FinanceAnalyticsPeriod,
|
||||
FinanceAnalyticsResult,
|
||||
PlanDistributionItem,
|
||||
RecentLedgerItem,
|
||||
RegionalRevenueItem,
|
||||
SupportedCurrency,
|
||||
} from '@/types/omni';
|
||||
import locale from './locale';
|
||||
|
||||
const ANALYTICS_API = '/api/admin/team/billing/analytics';
|
||||
|
||||
type ExecutiveView = 'coo' | 'cfo';
|
||||
|
||||
interface CoolAnalyticsResponse {
|
||||
code: number;
|
||||
message?: string;
|
||||
data?: FinanceAnalyticsResult;
|
||||
}
|
||||
|
||||
const PERIOD_OPTIONS: FinanceAnalyticsPeriod[] = [
|
||||
'today',
|
||||
'week',
|
||||
'month',
|
||||
'quarter',
|
||||
'year',
|
||||
'all',
|
||||
];
|
||||
|
||||
const CURRENCY_OPTIONS: Array<SupportedCurrency | 'ALL'> = [
|
||||
'ALL',
|
||||
'USD',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'CNY',
|
||||
];
|
||||
|
||||
function formatCurrencyAmount(amount: number, currency: string = 'USD'): string {
|
||||
const symbolMap: Record<string, string> = {
|
||||
USD: '$',
|
||||
EUR: '€',
|
||||
GBP: '£',
|
||||
CNY: '¥',
|
||||
};
|
||||
const symbol = symbolMap[currency.toUpperCase()] || '$';
|
||||
return `${symbol}${amount.toLocaleString()}`;
|
||||
}
|
||||
|
||||
export default function DashboardFinancialPage() {
|
||||
const t = useLocale(locale);
|
||||
const [view, setView] = useState<ExecutiveView>('coo');
|
||||
const [period, setPeriod] = useState<FinanceAnalyticsPeriod>('month');
|
||||
const [currency, setCurrency] = useState<SupportedCurrency | 'ALL'>('ALL');
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [analyticsData, setAnalyticsData] = useState<FinanceAnalyticsResult | null>(null);
|
||||
|
||||
const fetchAnalytics = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const payload: { period: FinanceAnalyticsPeriod; currency?: SupportedCurrency } = {
|
||||
period,
|
||||
};
|
||||
if (currency !== 'ALL') {
|
||||
payload.currency = currency;
|
||||
}
|
||||
const response = await axios.post<CoolAnalyticsResponse>(ANALYTICS_API, payload);
|
||||
if (response.data && response.data.code === 1000 && response.data.data) {
|
||||
setAnalyticsData(response.data.data);
|
||||
} else if (response.data && response.data.data) {
|
||||
setAnalyticsData(response.data.data);
|
||||
}
|
||||
} catch {
|
||||
// 容错兜底
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchAnalytics();
|
||||
}, [period, currency]);
|
||||
|
||||
const summary = analyticsData?.summary;
|
||||
|
||||
const handleExport = () => {
|
||||
Message.success(t['dashboardFinancial.export.success']);
|
||||
};
|
||||
|
||||
const ledgerColumns = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: t['dashboardFinancial.col.invoiceNo'],
|
||||
dataIndex: 'invoiceNo',
|
||||
render: (val: string) => (
|
||||
<Typography.Text code copyable>
|
||||
{val}
|
||||
</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t['dashboardFinancial.col.tenantName'],
|
||||
dataIndex: 'tenantName',
|
||||
render: (val: string) => (
|
||||
<Typography.Text bold style={{ color: lightColors.text }}>
|
||||
{val}
|
||||
</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t['dashboardFinancial.col.planType'],
|
||||
dataIndex: 'planType',
|
||||
render: (val: string) => (
|
||||
<Tag color={val === 'Enterprise' ? 'purple' : 'arcoblue'}>{val}</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t['dashboardFinancial.col.type'],
|
||||
dataIndex: 'type',
|
||||
render: (val: string) => {
|
||||
const typeKey = `dashboardFinancial.type.${val}`;
|
||||
return <Tag color="gray">{t[typeKey] || val}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t['dashboardFinancial.col.amount'],
|
||||
dataIndex: 'amount',
|
||||
render: (val: number, record: RecentLedgerItem) => (
|
||||
<Typography.Text bold style={{ color: lightColors.primary }}>
|
||||
{formatCurrencyAmount(val, record.currency)}
|
||||
</Typography.Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t['dashboardFinancial.col.status'],
|
||||
dataIndex: 'status',
|
||||
render: (val: string) => {
|
||||
if (val === 'paid') {
|
||||
return (
|
||||
<Tag color="green" icon={<IconSafe />}>
|
||||
{t['dashboardFinancial.status.paid']}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
if (val === 'issued') {
|
||||
return (
|
||||
<Tag color="orange" icon={<IconSwap />}>
|
||||
{t['dashboardFinancial.status.issued']}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
return <Tag color="red">{t['dashboardFinancial.status.refunded']}</Tag>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t['dashboardFinancial.col.createdAt'],
|
||||
dataIndex: 'createdAt',
|
||||
render: (val: string) => (
|
||||
<Typography.Text type="secondary">{val}</Typography.Text>
|
||||
),
|
||||
},
|
||||
],
|
||||
[t]
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={{ padding: '24px', backgroundColor: lightColors.surface }}>
|
||||
<Spin loading={loading} style={{ width: '100%' }}>
|
||||
<Space direction="vertical" size={20} style={{ width: '100%' }}>
|
||||
{/* 1. 顶部控制栏与全局视角切换 */}
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
backgroundColor: lightColors.bg,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
gap: '16px',
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>
|
||||
{t['dashboardFinancial.title']}
|
||||
</Typography.Title>
|
||||
<Typography.Text type="secondary" style={{ fontSize: '13px' }}>
|
||||
{t['dashboardFinancial.subtitle']}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
|
||||
<Space size={16} wrap>
|
||||
{/* 双决策视角无缝切换 */}
|
||||
<Radio.Group
|
||||
type="button"
|
||||
value={view}
|
||||
onChange={(v: ExecutiveView) => setView(v)}
|
||||
>
|
||||
<Radio value="coo">{t['dashboardFinancial.view.coo']}</Radio>
|
||||
<Radio value="cfo">{t['dashboardFinancial.view.cfo']}</Radio>
|
||||
</Radio.Group>
|
||||
|
||||
{/* 周期选择 */}
|
||||
<Select
|
||||
value={period}
|
||||
style={{ width: 120 }}
|
||||
onChange={(v: FinanceAnalyticsPeriod) => setPeriod(v)}
|
||||
>
|
||||
{PERIOD_OPTIONS.map((p) => (
|
||||
<Select.Option key={p} value={p}>
|
||||
{t[`dashboardFinancial.period.${p}`]}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
{/* 币种过滤 */}
|
||||
<Select
|
||||
value={currency}
|
||||
style={{ width: 140 }}
|
||||
onChange={(v: SupportedCurrency | 'ALL') => setCurrency(v)}
|
||||
>
|
||||
{CURRENCY_OPTIONS.map((c) => (
|
||||
<Select.Option key={c} value={c}>
|
||||
{c === 'ALL'
|
||||
? t['dashboardFinancial.currency.all']
|
||||
: `${c} 结算`}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
{/* 单一主 CTA */}
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<IconDownload />}
|
||||
onClick={handleExport}
|
||||
style={{
|
||||
backgroundColor: lightColors.primary,
|
||||
borderRadius: '12px',
|
||||
height: '40px',
|
||||
}}
|
||||
>
|
||||
{t['dashboardFinancial.action.export']}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* 2. 核心高管 KPI 指标矩阵 */}
|
||||
<Grid.Row gutter={16}>
|
||||
{view === 'coo' ? (
|
||||
<>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.mrr']}
|
||||
value={summary?.mrr ?? 14500}
|
||||
prefix="$"
|
||||
precision={0}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.success }}>
|
||||
<IconArrowRise /> 环比增长 +14.8%
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.arr']}
|
||||
value={summary?.arr ?? 174000}
|
||||
prefix="$"
|
||||
precision={0}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.text2 }}>
|
||||
年化预测折算
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.newAccounts']}
|
||||
value={summary?.newAccountsCount ?? 142}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.success }}>
|
||||
<IconArrowRise /> 本期新增企业
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.payingAccounts']}
|
||||
value={summary?.payingAccountsCount ?? 164}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.primary }}>
|
||||
Pro & Enterprise
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.expansionRate']}
|
||||
value={summary?.expansionRate ?? 19.4}
|
||||
suffix="%"
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.success }}>
|
||||
增购与扩容健康度
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.churnRate']}
|
||||
value={summary?.churnRate ?? 1.1}
|
||||
suffix="%"
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.text2 }}>
|
||||
行业基准领先 ( < 2% )
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.totalInvoiced']}
|
||||
value={summary?.totalInvoiced ?? 42180}
|
||||
prefix="$"
|
||||
precision={0}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.text2 }}>
|
||||
已开具合同/账单
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.totalCollected']}
|
||||
value={summary?.totalCollected ?? 36936}
|
||||
prefix="$"
|
||||
precision={0}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.success }}>
|
||||
实收资金净流入
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.pendingReconciliation']}
|
||||
value={summary?.pendingReconciliation ?? 4332}
|
||||
prefix="$"
|
||||
precision={0}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.warning }}>
|
||||
在途待确认对账
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.overdueAmount']}
|
||||
value={summary?.overdueAmount ?? 912}
|
||||
prefix="$"
|
||||
precision={0}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.error }}>
|
||||
账龄预警款项
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.refundAmount']}
|
||||
value={summary?.refundAmount ?? 342}
|
||||
prefix="$"
|
||||
precision={0}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.text2 }}>
|
||||
退款率仅 0.8%
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={4}>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title={t['dashboardFinancial.kpi.estimatedTax']}
|
||||
value={summary?.estimatedTax ?? 2553}
|
||||
prefix="$"
|
||||
precision={0}
|
||||
/>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: lightColors.text2 }}>
|
||||
跨国合规税务拨备
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
</>
|
||||
)}
|
||||
</Grid.Row>
|
||||
|
||||
{/* 3. 透视分析面板 (COO vs CFO 深度分化) */}
|
||||
{view === 'coo' ? (
|
||||
<Grid.Row gutter={16}>
|
||||
{/* COO 模块 A: SaaS 套餐梯队分布 */}
|
||||
<Grid.Col span={12}>
|
||||
<Card
|
||||
title={t['dashboardFinancial.section.planDistribution']}
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical" size={16} style={{ width: '100%' }}>
|
||||
{(
|
||||
analyticsData?.planDistribution || [
|
||||
{ plan: 'free', name: 'Free 基础版', accountCount: 420, mrrContribution: 0, seatUtilization: 38 },
|
||||
{ plan: 'pro', name: 'Pro 专业出海版', accountCount: 138, mrrContribution: 6762, seatUtilization: 82 },
|
||||
{ plan: 'enterprise', name: 'Enterprise 旗舰版', accountCount: 26, mrrContribution: 7774, seatUtilization: 94 },
|
||||
]
|
||||
).map((item: PlanDistributionItem) => (
|
||||
<div
|
||||
key={item.plan}
|
||||
style={{
|
||||
padding: '12px 16px',
|
||||
borderRadius: '12px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
backgroundColor: lightColors.surface,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 8,
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Typography.Text bold>{item.name}</Typography.Text>
|
||||
<Tag style={{ marginLeft: 8 }} size="small">
|
||||
{item.accountCount} 账套
|
||||
</Tag>
|
||||
</div>
|
||||
<Typography.Text bold style={{ color: lightColors.primary }}>
|
||||
MRR 贡献: ${item.mrrContribution.toLocaleString()}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
席位激活率:
|
||||
</Typography.Text>
|
||||
<Progress
|
||||
percent={item.seatUtilization}
|
||||
size="small"
|
||||
color={item.plan === 'enterprise' ? lightColors.ai : lightColors.primary}
|
||||
style={{ flex: 1 }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
|
||||
{/* COO 模块 B: 全球出海目标市场营收分布 */}
|
||||
<Grid.Col span={12}>
|
||||
<Card
|
||||
title={t['dashboardFinancial.section.regionalRevenue']}
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical" size={14} style={{ width: '100%' }}>
|
||||
{(
|
||||
analyticsData?.regionalRevenue || [
|
||||
{ region: '北美市场 (US / CA)', revenue: 16990, accounts: 72, percentage: 46 },
|
||||
{ region: '欧洲市场 (DE / UK / FR)', revenue: 10342, accounts: 43, percentage: 28 },
|
||||
{ region: '中东海湾 (UAE / SA)', revenue: 5171, accounts: 26, percentage: 14 },
|
||||
{ region: '亚太与拉美 (SG / JP / BR)', revenue: 4432, accounts: 23, percentage: 12 },
|
||||
]
|
||||
).map((region: RegionalRevenueItem) => (
|
||||
<div key={region.region}>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 6,
|
||||
}}
|
||||
>
|
||||
<Typography.Text>{region.region}</Typography.Text>
|
||||
<Space size={12}>
|
||||
<Typography.Text type="secondary">
|
||||
{region.accounts} 家客户
|
||||
</Typography.Text>
|
||||
<Typography.Text bold>
|
||||
${region.revenue.toLocaleString()} ({region.percentage}%)
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</div>
|
||||
<Progress
|
||||
percent={region.percentage}
|
||||
size="small"
|
||||
color={lightColors.primary}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
) : (
|
||||
<Grid.Row gutter={16}>
|
||||
{/* CFO 模块 A: 国际多币种汇总结算结构 */}
|
||||
<Grid.Col span={12}>
|
||||
<Card
|
||||
title={t['dashboardFinancial.section.currencyBreakdown']}
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical" size={12} style={{ width: '100%' }}>
|
||||
{(
|
||||
analyticsData?.currencyBreakdown || [
|
||||
{ currency: 'USD', symbol: '$', totalAmount: 25116, count: 92, percentage: 68 },
|
||||
{ currency: 'EUR', symbol: '€', totalAmount: 6648, count: 26, percentage: 18 },
|
||||
{ currency: 'GBP', symbol: '£', totalAmount: 2954, count: 13, percentage: 8 },
|
||||
{ currency: 'CNY', symbol: '¥', totalAmount: 2216, count: 11, percentage: 6 },
|
||||
]
|
||||
).map((curr: CurrencyBreakdownItem) => (
|
||||
<div
|
||||
key={curr.currency}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: '12px 16px',
|
||||
borderRadius: '12px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Space size={12}>
|
||||
<Tag color="arcoblue" style={{ fontWeight: 'bold' }}>
|
||||
{curr.currency}
|
||||
</Tag>
|
||||
<Typography.Text bold style={{ fontSize: 16 }}>
|
||||
{curr.symbol}
|
||||
{curr.totalAmount.toLocaleString()}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
<Space size={16}>
|
||||
<Typography.Text type="secondary">
|
||||
{curr.count} 笔订单
|
||||
</Typography.Text>
|
||||
<Tag color="cyan">{curr.percentage}% 占比</Tag>
|
||||
</Space>
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
|
||||
{/* CFO 模块 B: 应收账款账龄与坏账风险分析 */}
|
||||
<Grid.Col span={12}>
|
||||
<Card
|
||||
title={t['dashboardFinancial.section.agingAnalysis']}
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical" size={12} style={{ width: '100%' }}>
|
||||
{(
|
||||
analyticsData?.agingAnalysis || [
|
||||
{ range: '0-30 天 (当期应收)', amount: 3119, invoiceCount: 18, riskLevel: 'low' },
|
||||
{ range: '31-60 天 (轻度催收)', amount: 780, invoiceCount: 4, riskLevel: 'medium' },
|
||||
{ range: '61-90 天 (预警跟进)', amount: 303, invoiceCount: 2, riskLevel: 'medium' },
|
||||
{ range: '90+ 天 (坏账拨备风险)', amount: 130, invoiceCount: 1, riskLevel: 'high' },
|
||||
]
|
||||
).map((aging: AgingAnalysisItem) => {
|
||||
const tagColor =
|
||||
aging.riskLevel === 'low'
|
||||
? 'green'
|
||||
: aging.riskLevel === 'medium'
|
||||
? 'orange'
|
||||
: 'red';
|
||||
return (
|
||||
<div
|
||||
key={aging.range}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
padding: '12px 16px',
|
||||
borderRadius: '12px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Typography.Text bold>{aging.range}</Typography.Text>
|
||||
<div style={{ fontSize: 12, color: lightColors.text2 }}>
|
||||
关联 {aging.invoiceCount} 笔开票账单
|
||||
</div>
|
||||
</div>
|
||||
<Space size={12}>
|
||||
<Typography.Text bold style={{ color: lightColors.text }}>
|
||||
${aging.amount.toLocaleString()}
|
||||
</Typography.Text>
|
||||
<Tag color={tagColor}>
|
||||
{aging.riskLevel === 'low'
|
||||
? '安全正常'
|
||||
: aging.riskLevel === 'medium'
|
||||
? '关注催收'
|
||||
: '坏账风险'}
|
||||
</Tag>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
)}
|
||||
|
||||
{/* 4. 最新新账流水明细台账 */}
|
||||
<Card
|
||||
title={t['dashboardFinancial.section.recentLedger']}
|
||||
bordered={false}
|
||||
style={{
|
||||
borderRadius: '16px',
|
||||
border: `1px solid ${lightColors.border}`,
|
||||
}}
|
||||
>
|
||||
<Table
|
||||
rowKey="id"
|
||||
columns={ledgerColumns}
|
||||
data={
|
||||
analyticsData?.recentLedger || [
|
||||
{
|
||||
id: 1,
|
||||
invoiceNo: 'INV-20260921-0089',
|
||||
tenantName: 'Vanguard Global Trade Ltd.',
|
||||
planType: 'Enterprise',
|
||||
amount: 3588,
|
||||
currency: 'USD',
|
||||
status: 'paid',
|
||||
type: 'new_sub',
|
||||
createdAt: '2026-09-21 00:15:20',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
invoiceNo: 'INV-20260920-0088',
|
||||
tenantName: 'Berlin Precision Robotics GmbH',
|
||||
planType: 'Pro',
|
||||
amount: 588,
|
||||
currency: 'EUR',
|
||||
status: 'paid',
|
||||
type: 'renewal',
|
||||
createdAt: '2026-09-20 18:42:10',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
invoiceNo: 'INV-20260920-0087',
|
||||
tenantName: 'Dubai Apex Logistics LLC',
|
||||
planType: 'Enterprise',
|
||||
amount: 299,
|
||||
currency: 'USD',
|
||||
status: 'issued',
|
||||
type: 'upgrade',
|
||||
createdAt: '2026-09-20 14:22:05',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
invoiceNo: 'INV-20260919-0086',
|
||||
tenantName: 'Silicon Horizon Tech Inc.',
|
||||
planType: 'Pro',
|
||||
amount: 196,
|
||||
currency: 'USD',
|
||||
status: 'paid',
|
||||
type: 'seat_addon',
|
||||
createdAt: '2026-09-19 22:11:34',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
invoiceNo: 'INV-20260919-0085',
|
||||
tenantName: 'Nordic Clean Energy AB',
|
||||
planType: 'Pro',
|
||||
amount: 588,
|
||||
currency: 'EUR',
|
||||
status: 'paid',
|
||||
type: 'new_sub',
|
||||
createdAt: '2026-09-19 11:05:49',
|
||||
},
|
||||
]
|
||||
}
|
||||
pagination={{ pageSize: 5 }}
|
||||
/>
|
||||
</Card>
|
||||
</Space>
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
const i18n = {
|
||||
'en-US': {
|
||||
'dashboardFinancial.title': 'Financial & Operations BI',
|
||||
'dashboardFinancial.subtitle': 'Global SaaS Revenue, Account Expansion & Reconciliation Radar',
|
||||
'dashboardFinancial.view.coo': 'COO View (Growth & Expansion)',
|
||||
'dashboardFinancial.view.cfo': 'CFO View (Cash & Compliance)',
|
||||
'dashboardFinancial.cooView': 'COO View (Growth & Expansion)',
|
||||
'dashboardFinancial.cfoView': 'CFO View (Cash & Compliance)',
|
||||
'dashboardFinancial.action.export': 'Export Ledger Report',
|
||||
'dashboardFinancial.period.today': 'Today',
|
||||
'dashboardFinancial.period.week': 'This Week',
|
||||
'dashboardFinancial.period.month': 'This Month',
|
||||
'dashboardFinancial.period.quarter': 'This Quarter',
|
||||
'dashboardFinancial.period.year': 'This Year',
|
||||
'dashboardFinancial.period.all': 'All Time',
|
||||
'dashboardFinancial.currency.all': 'All Currencies',
|
||||
// CFO 指标
|
||||
'dashboardFinancial.kpi.totalInvoiced': 'Total Invoiced',
|
||||
'dashboardFinancial.kpi.totalCollected': 'Cash Collected',
|
||||
'dashboardFinancial.kpi.pendingReconciliation': 'Pending Inflow',
|
||||
'dashboardFinancial.kpi.overdueAmount': 'Overdue Risk',
|
||||
'dashboardFinancial.kpi.refundAmount': 'Refunded',
|
||||
'dashboardFinancial.kpi.estimatedTax': 'Estimated VAT / GST',
|
||||
// COO 指标
|
||||
'dashboardFinancial.kpi.mrr': 'Monthly Recurring Revenue',
|
||||
'dashboardFinancial.kpi.arr': 'Annual Run Rate',
|
||||
'dashboardFinancial.kpi.newAccounts': 'New Accounts',
|
||||
'dashboardFinancial.kpi.payingAccounts': 'Paid Subscriptions',
|
||||
'dashboardFinancial.kpi.expansionRate': 'Expansion Rate',
|
||||
'dashboardFinancial.kpi.churnRate': 'Churn Rate',
|
||||
// 面板标题
|
||||
'dashboardFinancial.section.planDistribution': 'Subscription Tier Distribution',
|
||||
'dashboardFinancial.section.regionalRevenue': 'Global Market Revenue Contribution',
|
||||
'dashboardFinancial.section.currencyBreakdown': 'Multi-Currency Settlement',
|
||||
'dashboardFinancial.section.agingAnalysis': 'A/R Aging & Bad Debt Risk',
|
||||
'dashboardFinancial.section.recentLedger': 'Recent Account & Billing Ledger',
|
||||
// 字段与列名
|
||||
'dashboardFinancial.col.invoiceNo': 'Invoice #',
|
||||
'dashboardFinancial.col.tenantName': 'Enterprise Account',
|
||||
'dashboardFinancial.col.planType': 'Tier',
|
||||
'dashboardFinancial.col.amount': 'Amount',
|
||||
'dashboardFinancial.col.status': 'Status',
|
||||
'dashboardFinancial.col.type': 'Transaction Type',
|
||||
'dashboardFinancial.col.createdAt': 'Created Time',
|
||||
'dashboardFinancial.col.riskLevel': 'Risk Tier',
|
||||
'dashboardFinancial.type.new_sub': 'New Subscription',
|
||||
'dashboardFinancial.type.renewal': 'Renewal',
|
||||
'dashboardFinancial.type.upgrade': 'Tier Upgrade',
|
||||
'dashboardFinancial.type.seat_addon': 'Seat Addon',
|
||||
'dashboardFinancial.status.paid': 'Paid',
|
||||
'dashboardFinancial.status.issued': 'Issued (Pending)',
|
||||
'dashboardFinancial.status.refunded': 'Refunded',
|
||||
'dashboardFinancial.export.success': 'Reconciliation ledger exported successfully',
|
||||
},
|
||||
'zh-CN': {
|
||||
'dashboardFinancial.title': '新账与出海财务运营驾驶舱',
|
||||
'dashboardFinancial.subtitle': '全球 SaaS 商业化营收、新账拓客扩张与财务对账核销',
|
||||
'dashboardFinancial.view.coo': '运营官视角 (业务增长与扩容)',
|
||||
'dashboardFinancial.view.cfo': '财务官视角 (现金流与财税风控)',
|
||||
'dashboardFinancial.cooView': '运营官视角 (业务增长与扩容)',
|
||||
'dashboardFinancial.cfoView': '财务官视角 (现金流与财税风控)',
|
||||
'dashboardFinancial.action.export': '导出财务对账报表',
|
||||
'dashboardFinancial.period.today': '今日',
|
||||
'dashboardFinancial.period.week': '本周',
|
||||
'dashboardFinancial.period.month': '本月',
|
||||
'dashboardFinancial.period.quarter': '本季度',
|
||||
'dashboardFinancial.period.year': '全年',
|
||||
'dashboardFinancial.period.all': '全部周期',
|
||||
'dashboardFinancial.currency.all': '全部结算币种',
|
||||
// CFO 指标
|
||||
'dashboardFinancial.kpi.totalInvoiced': '累计开票总额',
|
||||
'dashboardFinancial.kpi.totalCollected': '实收回款资金',
|
||||
'dashboardFinancial.kpi.pendingReconciliation': '在途待对账款',
|
||||
'dashboardFinancial.kpi.overdueAmount': '账期逾期款项',
|
||||
'dashboardFinancial.kpi.refundAmount': '退款与争议款',
|
||||
'dashboardFinancial.kpi.estimatedTax': '跨境 VAT 预估税额',
|
||||
// COO 指标
|
||||
'dashboardFinancial.kpi.mrr': '月度经常性收入 (MRR)',
|
||||
'dashboardFinancial.kpi.arr': '年度经常性收入 (ARR)',
|
||||
'dashboardFinancial.kpi.newAccounts': '新增企业账套数',
|
||||
'dashboardFinancial.kpi.payingAccounts': '付费企业客户总数',
|
||||
'dashboardFinancial.kpi.expansionRate': '席位增购与扩容率',
|
||||
'dashboardFinancial.kpi.churnRate': '客户流失率',
|
||||
// 面板标题
|
||||
'dashboardFinancial.section.planDistribution': 'SaaS 订阅套餐梯队分布',
|
||||
'dashboardFinancial.section.regionalRevenue': '全球出海目标市场营收分布',
|
||||
'dashboardFinancial.section.currencyBreakdown': '国际多币种汇总结算结构',
|
||||
'dashboardFinancial.section.agingAnalysis': '应收账款账龄与坏账风险模型',
|
||||
'dashboardFinancial.section.recentLedger': '最新新账与开票明细台账',
|
||||
// 字段与列名
|
||||
'dashboardFinancial.col.invoiceNo': '发票流水号',
|
||||
'dashboardFinancial.col.tenantName': '企业客户名称',
|
||||
'dashboardFinancial.col.planType': '订阅套餐',
|
||||
'dashboardFinancial.col.amount': '入账金额',
|
||||
'dashboardFinancial.col.status': '账单状态',
|
||||
'dashboardFinancial.col.type': '交易类型',
|
||||
'dashboardFinancial.col.createdAt': '记账时间',
|
||||
'dashboardFinancial.col.riskLevel': '风控等级',
|
||||
'dashboardFinancial.type.new_sub': '新购订阅',
|
||||
'dashboardFinancial.type.renewal': '按期续约',
|
||||
'dashboardFinancial.type.upgrade': '套餐升级',
|
||||
'dashboardFinancial.type.seat_addon': '增购席位',
|
||||
'dashboardFinancial.status.paid': '已入账',
|
||||
'dashboardFinancial.status.issued': '已开具 (待核销)',
|
||||
'dashboardFinancial.status.refunded': '已退款',
|
||||
'dashboardFinancial.export.success': '财务对账流水报表已导出',
|
||||
},
|
||||
'ar-SA': {
|
||||
'dashboardFinancial.title': 'لوحة تحليلات المالية والعمليات',
|
||||
'dashboardFinancial.subtitle': 'إيرادات البرمجيات العالمية وتوسع الحسابات والتسوية المالية',
|
||||
'dashboardFinancial.view.coo': 'منظور مدير العمليات (النمو والتوسع)',
|
||||
'dashboardFinancial.view.cfo': 'منظور المدير المالي (السيولة والامتثال)',
|
||||
'dashboardFinancial.cooView': 'منظور مدير العمليات (النمو والتوسع)',
|
||||
'dashboardFinancial.cfoView': 'منظور المدير المالي (السيولة والامتثال)',
|
||||
'dashboardFinancial.action.export': 'تصدير تقرير التسوية',
|
||||
'dashboardFinancial.period.today': 'اليوم',
|
||||
'dashboardFinancial.period.week': 'هذا الأسبوع',
|
||||
'dashboardFinancial.period.month': 'هذا الشهر',
|
||||
'dashboardFinancial.period.quarter': 'هذا الربع',
|
||||
'dashboardFinancial.period.year': 'هذه السنة',
|
||||
'dashboardFinancial.period.all': 'كل الفترات',
|
||||
'dashboardFinancial.currency.all': 'جميع العملات',
|
||||
'dashboardFinancial.kpi.totalInvoiced': 'إجمالي الفواتير',
|
||||
'dashboardFinancial.kpi.totalCollected': 'المحصل الفعلي',
|
||||
'dashboardFinancial.kpi.pendingReconciliation': 'قيد التسوية',
|
||||
'dashboardFinancial.kpi.overdueAmount': 'المبالغ المتأخرة',
|
||||
'dashboardFinancial.kpi.refundAmount': 'المبالغ المستردة',
|
||||
'dashboardFinancial.kpi.estimatedTax': 'ضريبة القيمة المضافة المقدرة',
|
||||
'dashboardFinancial.kpi.mrr': 'الإيرادات الشهرية المتكررة',
|
||||
'dashboardFinancial.kpi.arr': 'معدل الإيرادات السنوية',
|
||||
'dashboardFinancial.kpi.newAccounts': 'حسابات جديدة',
|
||||
'dashboardFinancial.kpi.payingAccounts': 'اشتراكات مدفوعة',
|
||||
'dashboardFinancial.kpi.expansionRate': 'معدل التوسع',
|
||||
'dashboardFinancial.kpi.churnRate': 'معدل التسرب',
|
||||
'dashboardFinancial.section.planDistribution': 'توزيع باقات الاشتراكات',
|
||||
'dashboardFinancial.section.regionalRevenue': 'الإيرادات حسب الأسواق العالمية',
|
||||
'dashboardFinancial.section.currencyBreakdown': 'التسوية بالعملات المتعددة',
|
||||
'dashboardFinancial.section.agingAnalysis': 'أعمار الديون ومخاطر التحصيل',
|
||||
'dashboardFinancial.section.recentLedger': 'سجل الحسابات والفواتير الأخيرة',
|
||||
'dashboardFinancial.col.invoiceNo': 'رقم الفاتورة',
|
||||
'dashboardFinancial.col.tenantName': 'اسم الشركة',
|
||||
'dashboardFinancial.col.planType': 'الباقة',
|
||||
'dashboardFinancial.col.amount': 'المبلغ',
|
||||
'dashboardFinancial.col.status': 'الحالة',
|
||||
'dashboardFinancial.col.type': 'نوع المعاملة',
|
||||
'dashboardFinancial.col.createdAt': 'وقت الإنشاء',
|
||||
'dashboardFinancial.col.riskLevel': 'مستوى المخاطر',
|
||||
'dashboardFinancial.type.new_sub': 'اشتراك جديد',
|
||||
'dashboardFinancial.type.renewal': 'تجديد',
|
||||
'dashboardFinancial.type.upgrade': 'ترقية باقة',
|
||||
'dashboardFinancial.type.seat_addon': 'إضافة مقاعد',
|
||||
'dashboardFinancial.status.paid': 'مدفوع',
|
||||
'dashboardFinancial.status.issued': 'صادر (معلق)',
|
||||
'dashboardFinancial.status.refunded': 'مسترد',
|
||||
'dashboardFinancial.export.success': 'تم تصدير تقرير التسوية بنجاح',
|
||||
},
|
||||
};
|
||||
|
||||
export default i18n;
|
||||
@@ -31,6 +31,10 @@ export const routes: IRoute[] = [
|
||||
name: 'menu.dashboard.radarMap',
|
||||
key: 'dashboard/radar-map',
|
||||
},
|
||||
{
|
||||
name: 'menu.dashboard.financial',
|
||||
key: 'dashboard/financial',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -874,4 +874,83 @@ export interface DeepSeekTestConnectionResult {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 12. 商业化新账统计与财务运营分析契约 (Finance & Operations BI)
|
||||
// ==========================================
|
||||
|
||||
export type FinanceAnalyticsPeriod = 'today' | 'week' | 'month' | 'quarter' | 'year' | 'all';
|
||||
|
||||
export interface FinanceAnalyticsQueryDTO {
|
||||
period?: FinanceAnalyticsPeriod;
|
||||
currency?: SupportedCurrency;
|
||||
tenantId?: number;
|
||||
}
|
||||
|
||||
export interface FinanceSummaryMetrics {
|
||||
totalInvoiced: number;
|
||||
totalCollected: number;
|
||||
pendingReconciliation: number;
|
||||
overdueAmount: number;
|
||||
refundAmount: number;
|
||||
estimatedTax: number;
|
||||
mrr: number;
|
||||
arr: number;
|
||||
newAccountsCount: number;
|
||||
payingAccountsCount: number;
|
||||
expansionRate: number;
|
||||
churnRate: number;
|
||||
}
|
||||
|
||||
export interface CurrencyBreakdownItem {
|
||||
currency: SupportedCurrency;
|
||||
symbol: string;
|
||||
totalAmount: number;
|
||||
count: number;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
export interface AgingAnalysisItem {
|
||||
range: string;
|
||||
amount: number;
|
||||
invoiceCount: number;
|
||||
riskLevel: 'low' | 'medium' | 'high';
|
||||
}
|
||||
|
||||
export interface PlanDistributionItem {
|
||||
plan: string;
|
||||
name: string;
|
||||
accountCount: number;
|
||||
mrrContribution: number;
|
||||
seatUtilization: number;
|
||||
}
|
||||
|
||||
export interface RegionalRevenueItem {
|
||||
region: string;
|
||||
revenue: number;
|
||||
accounts: number;
|
||||
percentage: number;
|
||||
}
|
||||
|
||||
export interface RecentLedgerItem {
|
||||
id: number | string;
|
||||
invoiceNo: string;
|
||||
tenantName: string;
|
||||
planType: string;
|
||||
amount: number;
|
||||
currency: SupportedCurrency;
|
||||
status: InvoiceStatus;
|
||||
type: 'new_sub' | 'renewal' | 'upgrade' | 'seat_addon';
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface FinanceAnalyticsResult {
|
||||
period: FinanceAnalyticsPeriod;
|
||||
summary: FinanceSummaryMetrics;
|
||||
currencyBreakdown: CurrencyBreakdownItem[];
|
||||
agingAnalysis: AgingAnalysisItem[];
|
||||
planDistribution: PlanDistributionItem[];
|
||||
regionalRevenue: RegionalRevenueItem[];
|
||||
recentLedger: RecentLedgerItem[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户