feat(dashboard): 在工作台右侧扩展出海运营快捷中枢,新增8大高频业务入口、渠道矩阵与待办预警
这个提交包含在:
@@ -17,15 +17,21 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from '@arco-design/web-react';
|
} from '@arco-design/web-react';
|
||||||
import {
|
import {
|
||||||
|
IconApps,
|
||||||
IconArrowRise,
|
IconArrowRise,
|
||||||
IconCompass,
|
IconCompass,
|
||||||
|
IconDesktop,
|
||||||
IconDownload,
|
IconDownload,
|
||||||
IconEye,
|
IconEye,
|
||||||
IconIdcard,
|
IconIdcard,
|
||||||
IconMobile,
|
IconMobile,
|
||||||
IconPlus,
|
IconPlus,
|
||||||
|
IconRight,
|
||||||
IconRobot,
|
IconRobot,
|
||||||
|
IconSafe,
|
||||||
|
IconSend,
|
||||||
IconUserAdd,
|
IconUserAdd,
|
||||||
|
IconUserGroup,
|
||||||
} from '@arco-design/web-react/icon';
|
} from '@arco-design/web-react/icon';
|
||||||
import useLocale from '@/utils/useLocale';
|
import useLocale from '@/utils/useLocale';
|
||||||
import { getCssVariables, lightColors } from '@/style/tokens';
|
import { getCssVariables, lightColors } from '@/style/tokens';
|
||||||
@@ -179,20 +185,9 @@ function Workplace(): React.ReactElement {
|
|||||||
fetchOverview();
|
fetchOverview();
|
||||||
}, [fetchOverview]);
|
}, [fetchOverview]);
|
||||||
|
|
||||||
const handleCreateCard = () => {
|
// 导航路由跳转处理器
|
||||||
history.push('/card/list');
|
const handleNav = (path: string) => {
|
||||||
};
|
history.push(path);
|
||||||
|
|
||||||
const handleIssueCards = () => {
|
|
||||||
history.push('/nfc/batch');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOpenRadar = () => {
|
|
||||||
history.push('/dashboard/radar-map');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOpenAiConfig = () => {
|
|
||||||
history.push('/ai/concierge');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleExportLeads = async () => {
|
const handleExportLeads = async () => {
|
||||||
@@ -294,7 +289,7 @@ function Workplace(): React.ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.page} style={tokenStyle}>
|
<div className={styles.page} style={tokenStyle}>
|
||||||
{/* 顶部标题与唯 1 主 CTA */}
|
{/* 顶部标题与唯一主 CTA */}
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<div className={styles.headerInfo}>
|
<div className={styles.headerInfo}>
|
||||||
<div className={styles.titleRow}>
|
<div className={styles.titleRow}>
|
||||||
@@ -317,78 +312,84 @@ function Workplace(): React.ReactElement {
|
|||||||
type="primary"
|
type="primary"
|
||||||
icon={<IconPlus />}
|
icon={<IconPlus />}
|
||||||
className={styles.primaryCta}
|
className={styles.primaryCta}
|
||||||
onClick={handleCreateCard}
|
onClick={() => handleNav('/card/list')}
|
||||||
>
|
>
|
||||||
{t['workplace.cta.newCard']}
|
{t['workplace.cta.newCard']}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Spin loading={loading} style={{ display: 'block' }}>
|
<Spin loading={loading} style={{ display: 'block' }}>
|
||||||
{/* KPI 核心指标阵列 */}
|
{/* 宽屏 17 : 7 弹性整体双栏架构 */}
|
||||||
<Row gutter={[16, 16]}>
|
<Row gutter={[16, 16]}>
|
||||||
<Col xs={24} sm={12} lg={6}>
|
{/* 左侧业务主流程 (17/24 栅格) */}
|
||||||
<Card bordered={false} className={styles.kpiCard}>
|
<Col xs={24} xl={17}>
|
||||||
<div className={styles.kpiHeader}>
|
{/* KPI 核心指标阵列 */}
|
||||||
<span className={styles.kpiTitle}>{t['workplace.kpi.taps']}</span>
|
<Row gutter={[16, 16]}>
|
||||||
<span className={styles.kpiIconWrapper}>
|
<Col xs={24} sm={12} md={6}>
|
||||||
<IconMobile className={styles.kpiIcon} />
|
<Card bordered={false} className={styles.kpiCard}>
|
||||||
</span>
|
<div className={styles.kpiHeader}>
|
||||||
</div>
|
<span className={styles.kpiTitle}>{t['workplace.kpi.taps']}</span>
|
||||||
<Statistic value={kpis.tapCount} />
|
<span className={styles.kpiIconWrapper}>
|
||||||
{renderDelta(kpis.tapDelta)}
|
<IconMobile className={styles.kpiIcon} />
|
||||||
</Card>
|
</span>
|
||||||
</Col>
|
</div>
|
||||||
|
<Statistic value={kpis.tapCount} />
|
||||||
|
{renderDelta(kpis.tapDelta)}
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
|
||||||
<Col xs={24} sm={12} lg={6}>
|
<Col xs={24} sm={12} md={6}>
|
||||||
<Card bordered={false} className={styles.kpiCard}>
|
<Card bordered={false} className={styles.kpiCard}>
|
||||||
<div className={styles.kpiHeader}>
|
<div className={styles.kpiHeader}>
|
||||||
<span className={styles.kpiTitle}>{t['workplace.kpi.views']}</span>
|
<span className={styles.kpiTitle}>{t['workplace.kpi.views']}</span>
|
||||||
<span className={styles.kpiIconWrapper}>
|
<span className={styles.kpiIconWrapper}>
|
||||||
<IconEye className={styles.kpiIcon} />
|
<IconEye className={styles.kpiIcon} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Statistic value={kpis.viewCount} />
|
<Statistic value={kpis.viewCount} />
|
||||||
{renderDelta(kpis.viewDelta)}
|
{renderDelta(kpis.viewDelta)}
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={24} sm={12} lg={6}>
|
<Col xs={24} sm={12} md={6}>
|
||||||
<Card bordered={false} className={styles.kpiCard}>
|
<Card bordered={false} className={styles.kpiCard}>
|
||||||
<div className={styles.kpiHeader}>
|
<div className={styles.kpiHeader}>
|
||||||
<span className={styles.kpiTitle}>{t['workplace.kpi.leads']}</span>
|
<span className={styles.kpiTitle}>{t['workplace.kpi.leads']}</span>
|
||||||
<span className={styles.kpiIconWrapper}>
|
<span className={styles.kpiIconWrapper}>
|
||||||
<IconUserAdd className={styles.kpiIcon} />
|
<IconUserAdd className={styles.kpiIcon} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Statistic value={kpis.newLeadCount} />
|
<Statistic value={kpis.newLeadCount} />
|
||||||
{renderDelta(kpis.newLeadDelta)}
|
{renderDelta(kpis.newLeadDelta)}
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs={24} sm={12} lg={6}>
|
<Col xs={24} sm={12} md={6}>
|
||||||
<Card bordered={false} className={styles.kpiCard}>
|
<Card bordered={false} className={styles.kpiCard}>
|
||||||
<div className={styles.kpiHeader}>
|
<div className={styles.kpiHeader}>
|
||||||
<span className={styles.kpiTitle}>{t['workplace.kpi.conversion']}</span>
|
<span className={styles.kpiTitle}>{t['workplace.kpi.conversion']}</span>
|
||||||
<span className={styles.kpiIconWrapper}>
|
<span className={styles.kpiIconWrapper}>
|
||||||
<IconIdcard className={styles.kpiIcon} />
|
<IconIdcard className={styles.kpiIcon} />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Statistic
|
<Statistic
|
||||||
value={kpis.conversionRate}
|
value={kpis.conversionRate}
|
||||||
suffix="%"
|
suffix="%"
|
||||||
precision={1}
|
precision={1}
|
||||||
/>
|
/>
|
||||||
<div className={styles.kpiSubText}>
|
<div className={styles.kpiSubText}>
|
||||||
{t['workplace.kpi.conversionSub']}
|
{t['workplace.kpi.conversionSub']}
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
{/* 运营官转化漏斗与渠道矩阵 */}
|
{/* 出海转化漏斗 */}
|
||||||
<Row gutter={[16, 16]} className={styles.middleRow}>
|
<Card
|
||||||
<Col xs={24} lg={16}>
|
bordered={false}
|
||||||
<Card bordered={false} className={styles.panel} title={t['workplace.funnel.title']}>
|
className={`${styles.panel} ${styles.funnelCard}`}
|
||||||
|
title={t['workplace.funnel.title']}
|
||||||
|
>
|
||||||
<div className={styles.funnelContainer}>
|
<div className={styles.funnelContainer}>
|
||||||
<div className={styles.funnelStep}>
|
<div className={styles.funnelStep}>
|
||||||
<div className={styles.funnelLabel}>{t['workplace.funnel.tap']}</div>
|
<div className={styles.funnelLabel}>{t['workplace.funnel.tap']}</div>
|
||||||
@@ -459,43 +460,11 @@ function Workplace(): React.ReactElement {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col xs={24} lg={8}>
|
{/* 今日实时客商雷达流 */}
|
||||||
<Card bordered={false} className={styles.panel} title={t['workplace.channel.title']}>
|
|
||||||
<div className={styles.channelRow}>
|
|
||||||
<div className={styles.channelMeta}>
|
|
||||||
<span className={styles.channelName}>{t['workplace.channel.nfc']}</span>
|
|
||||||
<span className={styles.channelPercent}>{channelStats.nfc}%</span>
|
|
||||||
</div>
|
|
||||||
<Progress percent={channelStats.nfc} color={lightColors.primary} showText={false} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.channelRow}>
|
|
||||||
<div className={styles.channelMeta}>
|
|
||||||
<span className={styles.channelName}>{t['workplace.channel.qr']}</span>
|
|
||||||
<span className={styles.channelPercent}>{channelStats.qr}%</span>
|
|
||||||
</div>
|
|
||||||
<Progress percent={channelStats.qr} color={lightColors.ai} showText={false} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.channelRow}>
|
|
||||||
<div className={styles.channelMeta}>
|
|
||||||
<span className={styles.channelName}>{t['workplace.channel.link']}</span>
|
|
||||||
<span className={styles.channelPercent}>{channelStats.link}%</span>
|
|
||||||
</div>
|
|
||||||
<Progress percent={channelStats.link} color={lightColors.text2} showText={false} />
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
{/* 核心双栏:实时客商雷达流 VS 运营工具箱 */}
|
|
||||||
<Row gutter={[16, 16]} className={styles.main}>
|
|
||||||
<Col xs={24} lg={16}>
|
|
||||||
<Card
|
<Card
|
||||||
bordered={false}
|
bordered={false}
|
||||||
className={styles.panel}
|
className={`${styles.panel} ${styles.radarCard}`}
|
||||||
title={
|
title={
|
||||||
<div className={styles.panelHeader}>
|
<div className={styles.panelHeader}>
|
||||||
<span>{t['workplace.radar.title']}</span>
|
<span>{t['workplace.radar.title']}</span>
|
||||||
@@ -520,7 +489,7 @@ function Workplace(): React.ReactElement {
|
|||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Button type="text" onClick={handleOpenRadar}>
|
<Button type="text" onClick={() => handleNav('/dashboard/radar-map')}>
|
||||||
{t['workplace.radar.emptyAction']}
|
{t['workplace.radar.emptyAction']}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -568,88 +537,236 @@ function Workplace(): React.ReactElement {
|
|||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
{/* 运营工具箱 */}
|
{/* 右侧出海运营快捷中枢 (7/24 栅格,完美填补用户红框空白) */}
|
||||||
<Col xs={24} lg={8}>
|
<Col xs={24} xl={7}>
|
||||||
<Card
|
<div className={styles.hubContainer}>
|
||||||
bordered={false}
|
{/* 模块 1:触达渠道健康度 */}
|
||||||
className={styles.panel}
|
<Card bordered={false} className={styles.panel} title={t['workplace.channel.title']}>
|
||||||
title={t['workplace.shortcut.title']}
|
<div className={styles.channelRow}>
|
||||||
>
|
<div className={styles.channelMeta}>
|
||||||
<div className={styles.toolboxList}>
|
<span className={styles.channelName}>{t['workplace.channel.nfc']}</span>
|
||||||
<button
|
<span className={styles.channelPercent}>{channelStats.nfc}%</span>
|
||||||
type="button"
|
|
||||||
className={styles.shortcut}
|
|
||||||
onClick={handleIssueCards}
|
|
||||||
>
|
|
||||||
<div className={styles.shortcutIconBox}>
|
|
||||||
<IconIdcard className={styles.toolIcon} />
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.shortcutContent}>
|
<Progress percent={channelStats.nfc} color={lightColors.primary} showText={false} />
|
||||||
<span className={styles.shortcutLabel}>
|
</div>
|
||||||
{t['workplace.shortcut.issueCard']}
|
|
||||||
</span>
|
|
||||||
<span className={styles.shortcutHint}>
|
|
||||||
{t['workplace.shortcut.issueCardHint']}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<div className={styles.channelRow}>
|
||||||
type="button"
|
<div className={styles.channelMeta}>
|
||||||
className={styles.shortcut}
|
<span className={styles.channelName}>{t['workplace.channel.qr']}</span>
|
||||||
onClick={handleExportLeads}
|
<span className={styles.channelPercent}>{channelStats.qr}%</span>
|
||||||
disabled={exporting}
|
|
||||||
>
|
|
||||||
<div className={styles.shortcutIconBox}>
|
|
||||||
<IconDownload className={styles.toolIcon} />
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.shortcutContent}>
|
<Progress percent={channelStats.qr} color={lightColors.ai} showText={false} />
|
||||||
<span className={styles.shortcutLabel}>
|
</div>
|
||||||
{t['workplace.shortcut.exportLeads']}
|
|
||||||
</span>
|
|
||||||
<span className={styles.shortcutHint}>
|
|
||||||
{t['workplace.shortcut.exportLeadsHint']}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
<div className={styles.channelRow}>
|
||||||
type="button"
|
<div className={styles.channelMeta}>
|
||||||
className={styles.shortcut}
|
<span className={styles.channelName}>{t['workplace.channel.link']}</span>
|
||||||
onClick={handleOpenRadar}
|
<span className={styles.channelPercent}>{channelStats.link}%</span>
|
||||||
>
|
|
||||||
<div className={styles.shortcutIconBox}>
|
|
||||||
<IconCompass className={styles.toolIcon} />
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.shortcutContent}>
|
<Progress percent={channelStats.link} color={lightColors.text2} showText={false} />
|
||||||
<span className={styles.shortcutLabel}>
|
</div>
|
||||||
{t['workplace.shortcut.radarMap']}
|
</Card>
|
||||||
</span>
|
|
||||||
<span className={styles.shortcutHint}>
|
|
||||||
{t['workplace.shortcut.radarMapHint']}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
{/* 模块 2:高频业务快捷导航矩阵 (8大核心入口,2列微卡) */}
|
||||||
type="button"
|
<Card
|
||||||
className={styles.shortcut}
|
bordered={false}
|
||||||
onClick={handleOpenAiConfig}
|
className={styles.panel}
|
||||||
>
|
title={t['workplace.quickNav.title']}
|
||||||
<div className={styles.shortcutIconBox}>
|
>
|
||||||
<IconRobot className={styles.toolIcon} />
|
<div className={styles.navGrid}>
|
||||||
|
{/* 1. 搭建微官网 */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.navCard}
|
||||||
|
onClick={() => handleNav('/card/builder')}
|
||||||
|
>
|
||||||
|
<div className={styles.navIconBox}>
|
||||||
|
<IconApps className={styles.navIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.navTextBox}>
|
||||||
|
<span className={styles.navTitle}>{t['workplace.quick.builder']}</span>
|
||||||
|
<span className={styles.navSub}>{t['workplace.quick.builderHint']}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* 2. 潜客线索 */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.navCard}
|
||||||
|
onClick={() => handleNav('/crm/leads')}
|
||||||
|
>
|
||||||
|
<div className={styles.navIconBox}>
|
||||||
|
<IconUserGroup className={styles.navIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.navTextBox}>
|
||||||
|
<span className={styles.navTitle}>{t['workplace.quick.leads']}</span>
|
||||||
|
<span className={styles.navSub}>{t['workplace.quick.leadsHint']}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* 3. 商机看板 */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.navCard}
|
||||||
|
onClick={() => handleNav('/crm/pipeline')}
|
||||||
|
>
|
||||||
|
<div className={styles.navIconBox}>
|
||||||
|
<IconSend className={styles.navIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.navTextBox}>
|
||||||
|
<span className={styles.navTitle}>{t['workplace.quick.pipeline']}</span>
|
||||||
|
<span className={styles.navSub}>{t['workplace.quick.pipelineHint']}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* 4. 批量发卡 */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.navCard}
|
||||||
|
onClick={() => handleNav('/nfc/batch')}
|
||||||
|
>
|
||||||
|
<div className={styles.navIconBox}>
|
||||||
|
<IconIdcard className={styles.navIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.navTextBox}>
|
||||||
|
<span className={styles.navTitle}>{t['workplace.quick.batch']}</span>
|
||||||
|
<span className={styles.navSub}>{t['workplace.quick.batchHint']}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* 5. 硬件台账 */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.navCard}
|
||||||
|
onClick={() => handleNav('/nfc/devices')}
|
||||||
|
>
|
||||||
|
<div className={styles.navIconBox}>
|
||||||
|
<IconDesktop className={styles.navIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.navTextBox}>
|
||||||
|
<span className={styles.navTitle}>{t['workplace.quick.devices']}</span>
|
||||||
|
<span className={styles.navSub}>{t['workplace.quick.devicesHint']}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* 6. 全球雷达大屏 */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.navCard}
|
||||||
|
onClick={() => handleNav('/dashboard/radar-map')}
|
||||||
|
>
|
||||||
|
<div className={styles.navIconBox}>
|
||||||
|
<IconCompass className={styles.navIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.navTextBox}>
|
||||||
|
<span className={styles.navTitle}>{t['workplace.quick.radarMap']}</span>
|
||||||
|
<span className={styles.navSub}>{t['workplace.quick.radarMapHint']}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* 7. AI 顾问接待 */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.navCard}
|
||||||
|
onClick={() => handleNav('/ai/concierge')}
|
||||||
|
>
|
||||||
|
<div className={styles.navIconBox}>
|
||||||
|
<IconRobot className={styles.navIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.navTextBox}>
|
||||||
|
<span className={styles.navTitle}>{t['workplace.quick.aiConcierge']}</span>
|
||||||
|
<span className={styles.navSub}>{t['workplace.quick.aiConciergeHint']}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* 8. 财务订阅看板 */}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.navCard}
|
||||||
|
onClick={() => handleNav('/dashboard/financial')}
|
||||||
|
>
|
||||||
|
<div className={styles.navIconBox}>
|
||||||
|
<IconSafe className={styles.navIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.navTextBox}>
|
||||||
|
<span className={styles.navTitle}>{t['workplace.quick.finance']}</span>
|
||||||
|
<span className={styles.navSub}>{t['workplace.quick.financeHint']}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* 模块 3:常用效率工具 */}
|
||||||
|
<Card
|
||||||
|
bordered={false}
|
||||||
|
className={styles.panel}
|
||||||
|
title={t['workplace.shortcut.title']}
|
||||||
|
>
|
||||||
|
<div className={styles.toolboxList}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.shortcut}
|
||||||
|
onClick={handleExportLeads}
|
||||||
|
disabled={exporting}
|
||||||
|
>
|
||||||
|
<div className={styles.shortcutIconBox}>
|
||||||
|
<IconDownload className={styles.toolIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.shortcutContent}>
|
||||||
|
<span className={styles.shortcutLabel}>
|
||||||
|
{t['workplace.shortcut.exportLeads']}
|
||||||
|
</span>
|
||||||
|
<span className={styles.shortcutHint}>
|
||||||
|
{t['workplace.shortcut.exportLeadsHint']}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={styles.shortcut}
|
||||||
|
onClick={() => handleNav('/nfc/batch')}
|
||||||
|
>
|
||||||
|
<div className={styles.shortcutIconBox}>
|
||||||
|
<IconIdcard className={styles.toolIcon} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.shortcutContent}>
|
||||||
|
<span className={styles.shortcutLabel}>
|
||||||
|
{t['workplace.shortcut.issueCard']}
|
||||||
|
</span>
|
||||||
|
<span className={styles.shortcutHint}>
|
||||||
|
{t['workplace.shortcut.issueCardHint']}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* 模块 4:出海待办预警 */}
|
||||||
|
<Card
|
||||||
|
bordered={false}
|
||||||
|
className={`${styles.panel} ${styles.alertPanel}`}
|
||||||
|
title={t['workplace.alerts.title']}
|
||||||
|
>
|
||||||
|
<div className={styles.alertContent}>
|
||||||
|
<div className={styles.alertItem}>
|
||||||
|
<div className={styles.alertDot} />
|
||||||
|
<div className={styles.alertText}>
|
||||||
|
{t['workplace.alerts.highIntentLead']}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.shortcutContent}>
|
<Button
|
||||||
<span className={styles.shortcutLabel}>
|
type="outline"
|
||||||
{t['workplace.shortcut.aiConfig']}
|
size="small"
|
||||||
</span>
|
className={styles.alertActionBtn}
|
||||||
<span className={styles.shortcutHint}>
|
onClick={() => handleNav('/crm/leads')}
|
||||||
{t['workplace.shortcut.aiConfigHint']}
|
>
|
||||||
</span>
|
<span>{t['workplace.alerts.actionFollow']}</span>
|
||||||
</div>
|
<IconRight style={{ fontSize: 12, marginLeft: 4 }} />
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Spin>
|
</Spin>
|
||||||
|
|||||||
@@ -26,7 +26,25 @@ const i18n = {
|
|||||||
'workplace.funnel.interact': 'Interactions',
|
'workplace.funnel.interact': 'Interactions',
|
||||||
'workplace.funnel.lead': 'CRM Leads',
|
'workplace.funnel.lead': 'CRM Leads',
|
||||||
'workplace.channel.title': 'Touch Channels',
|
'workplace.channel.title': 'Touch Channels',
|
||||||
'workplace.shortcut.title': 'Shortcuts',
|
'workplace.quickHub.title': 'Operations Command Hub',
|
||||||
|
'workplace.quickNav.title': 'Quick Navigation',
|
||||||
|
'workplace.quick.builder': 'Mini-site Builder',
|
||||||
|
'workplace.quick.builderHint': 'Craft Bento Grid mini-sites',
|
||||||
|
'workplace.quick.leads': 'Buyer Leads',
|
||||||
|
'workplace.quick.leadsHint': 'Follow up international clients',
|
||||||
|
'workplace.quick.pipeline': 'Deal Pipeline',
|
||||||
|
'workplace.quick.pipelineHint': 'Track stages and closed deals',
|
||||||
|
'workplace.quick.batch': 'Issue NFC',
|
||||||
|
'workplace.quick.batchHint': 'Batch print files and links',
|
||||||
|
'workplace.quick.devices': 'NFC Fleet',
|
||||||
|
'workplace.quick.devicesHint': 'Hardware device activations',
|
||||||
|
'workplace.quick.radarMap': 'Radar Map',
|
||||||
|
'workplace.quick.radarMapHint': 'Global 3D visitor heatmaps',
|
||||||
|
'workplace.quick.aiConcierge': 'AI Concierge',
|
||||||
|
'workplace.quick.aiConciergeHint': 'Multi-lingual greeting policy',
|
||||||
|
'workplace.quick.finance': 'Financials',
|
||||||
|
'workplace.quick.financeHint': 'Subscription metrics & MRR',
|
||||||
|
'workplace.shortcut.title': 'Operations Arsenal',
|
||||||
'workplace.shortcut.issueCard': 'Issue NFC cards',
|
'workplace.shortcut.issueCard': 'Issue NFC cards',
|
||||||
'workplace.shortcut.issueCardHint': 'Generate short links and print files',
|
'workplace.shortcut.issueCardHint': 'Generate short links and print files',
|
||||||
'workplace.shortcut.exportLeads': 'Export leads',
|
'workplace.shortcut.exportLeads': 'Export leads',
|
||||||
@@ -35,6 +53,9 @@ const i18n = {
|
|||||||
'workplace.shortcut.radarMapHint': 'Explore real-time visitor geography and heatmaps',
|
'workplace.shortcut.radarMapHint': 'Explore real-time visitor geography and heatmaps',
|
||||||
'workplace.shortcut.aiConfig': 'AI Concierge Strategy',
|
'workplace.shortcut.aiConfig': 'AI Concierge Strategy',
|
||||||
'workplace.shortcut.aiConfigHint': 'Tune multi-lingual greeting and lead qualification',
|
'workplace.shortcut.aiConfigHint': 'Tune multi-lingual greeting and lead qualification',
|
||||||
|
'workplace.alerts.title': 'Actionable Alerts',
|
||||||
|
'workplace.alerts.highIntentLead': 'Buyer from Dubai stayed 210s in case studies without follow-up.',
|
||||||
|
'workplace.alerts.actionFollow': 'Follow Up Now',
|
||||||
'workplace.channel.nfc': 'NFC',
|
'workplace.channel.nfc': 'NFC',
|
||||||
'workplace.channel.qr': 'QR Code',
|
'workplace.channel.qr': 'QR Code',
|
||||||
'workplace.channel.link': 'Direct Link',
|
'workplace.channel.link': 'Direct Link',
|
||||||
@@ -70,7 +91,25 @@ const i18n = {
|
|||||||
'workplace.funnel.interact': '意向交互',
|
'workplace.funnel.interact': '意向交互',
|
||||||
'workplace.funnel.lead': '商机留资',
|
'workplace.funnel.lead': '商机留资',
|
||||||
'workplace.channel.title': '触达渠道分布',
|
'workplace.channel.title': '触达渠道分布',
|
||||||
'workplace.shortcut.title': '运营工具箱',
|
'workplace.quickHub.title': '出海运营快捷中枢',
|
||||||
|
'workplace.quickNav.title': '高频业务导航',
|
||||||
|
'workplace.quick.builder': '搭建微官网',
|
||||||
|
'workplace.quick.builderHint': '编辑便当盒微官网组件',
|
||||||
|
'workplace.quick.leads': '潜客线索',
|
||||||
|
'workplace.quick.leadsHint': '跟进出海海外意向买家',
|
||||||
|
'workplace.quick.pipeline': '商机看板',
|
||||||
|
'workplace.quick.pipelineHint': '推进出海商机全流程赢单',
|
||||||
|
'workplace.quick.batch': '批量制卡',
|
||||||
|
'workplace.quick.batchHint': '生成短链与批量印制物料',
|
||||||
|
'workplace.quick.devices': '硬件台账',
|
||||||
|
'workplace.quick.devicesHint': 'NFC 实体卡激活与状态',
|
||||||
|
'workplace.quick.radarMap': '雷达大屏',
|
||||||
|
'workplace.quick.radarMapHint': '全球客商访客实时热力图',
|
||||||
|
'workplace.quick.aiConcierge': 'AI 顾问',
|
||||||
|
'workplace.quick.aiConciergeHint': '多语言接待策略与留资阈值',
|
||||||
|
'workplace.quick.finance': '财务订阅',
|
||||||
|
'workplace.quick.financeHint': '订阅套餐与出海营收看板',
|
||||||
|
'workplace.shortcut.title': '运营效率工具箱',
|
||||||
'workplace.shortcut.issueCard': '批量发卡',
|
'workplace.shortcut.issueCard': '批量发卡',
|
||||||
'workplace.shortcut.issueCardHint': '生成短链与制卡打印物料',
|
'workplace.shortcut.issueCardHint': '生成短链与制卡打印物料',
|
||||||
'workplace.shortcut.exportLeads': '导出线索',
|
'workplace.shortcut.exportLeads': '导出线索',
|
||||||
@@ -79,6 +118,9 @@ const i18n = {
|
|||||||
'workplace.shortcut.radarMapHint': '查看全球访客地理分布与实时热力图',
|
'workplace.shortcut.radarMapHint': '查看全球访客地理分布与实时热力图',
|
||||||
'workplace.shortcut.aiConfig': 'AI 顾问接待策略',
|
'workplace.shortcut.aiConfig': 'AI 顾问接待策略',
|
||||||
'workplace.shortcut.aiConfigHint': '配置多语言接待话术与自动留资意向阈值',
|
'workplace.shortcut.aiConfigHint': '配置多语言接待话术与自动留资意向阈值',
|
||||||
|
'workplace.alerts.title': '出海待办预警',
|
||||||
|
'workplace.alerts.highIntentLead': '迪拜客商在精选案例停留超过 210 秒,尚未安排专属跟进。',
|
||||||
|
'workplace.alerts.actionFollow': '立即跟进',
|
||||||
'workplace.channel.nfc': 'NFC',
|
'workplace.channel.nfc': 'NFC',
|
||||||
'workplace.channel.qr': '二维码',
|
'workplace.channel.qr': '二维码',
|
||||||
'workplace.channel.link': '直链',
|
'workplace.channel.link': '直链',
|
||||||
@@ -114,7 +156,25 @@ const i18n = {
|
|||||||
'workplace.funnel.interact': 'تفاعل مهتم',
|
'workplace.funnel.interact': 'تفاعل مهتم',
|
||||||
'workplace.funnel.lead': 'عميل محتمل',
|
'workplace.funnel.lead': 'عميل محتمل',
|
||||||
'workplace.channel.title': 'قنوات الاتصال',
|
'workplace.channel.title': 'قنوات الاتصال',
|
||||||
'workplace.shortcut.title': 'صندوق أدوات التشغيل',
|
'workplace.quickHub.title': 'مركز قيادة العمليات',
|
||||||
|
'workplace.quickNav.title': 'الملاحة السريعة',
|
||||||
|
'workplace.quick.builder': 'منشئ الموقع المصغر',
|
||||||
|
'workplace.quick.builderHint': 'تصميم موقع نمط بينتو',
|
||||||
|
'workplace.quick.leads': 'العملاء المحتملون',
|
||||||
|
'workplace.quick.leadsHint': 'متابعة المشترين الدوليين',
|
||||||
|
'workplace.quick.pipeline': 'مراحل الصفقات',
|
||||||
|
'workplace.quick.pipelineHint': 'تتبع تقدم الصفقات المغلقة',
|
||||||
|
'workplace.quick.batch': 'إصدار NFC',
|
||||||
|
'workplace.quick.batchHint': 'توليد الروابط والطباعة',
|
||||||
|
'workplace.quick.devices': 'أجهزة NFC',
|
||||||
|
'workplace.quick.devicesHint': 'تنشيط الأجهزة والحالة',
|
||||||
|
'workplace.quick.radarMap': 'خريطة الرادار',
|
||||||
|
'workplace.quick.radarMapHint': 'خريطة حرارية للزوار عالمياً',
|
||||||
|
'workplace.quick.aiConcierge': 'المساعد الذكي',
|
||||||
|
'workplace.quick.aiConciergeHint': 'سياسة الترحيب متعددة اللغات',
|
||||||
|
'workplace.quick.finance': 'المالية والاشتراكات',
|
||||||
|
'workplace.quick.financeHint': 'مقاييس الاشتراكات والإيرادات',
|
||||||
|
'workplace.shortcut.title': 'صندوق أدوات العمليات',
|
||||||
'workplace.shortcut.issueCard': 'إصدار بطاقات NFC',
|
'workplace.shortcut.issueCard': 'إصدار بطاقات NFC',
|
||||||
'workplace.shortcut.issueCardHint': 'إنشاء الروابط وملفات الطباعة للبطاقات',
|
'workplace.shortcut.issueCardHint': 'إنشاء الروابط وملفات الطباعة للبطاقات',
|
||||||
'workplace.shortcut.exportLeads': 'تصدير العملاء',
|
'workplace.shortcut.exportLeads': 'تصدير العملاء',
|
||||||
@@ -123,6 +183,9 @@ const i18n = {
|
|||||||
'workplace.shortcut.radarMapHint': 'استكشف التوزيع الجغرافي للزوار وخريطة الحرارة',
|
'workplace.shortcut.radarMapHint': 'استكشف التوزيع الجغرافي للزوار وخريطة الحرارة',
|
||||||
'workplace.shortcut.aiConfig': 'استراتيجية المساعد الذكي',
|
'workplace.shortcut.aiConfig': 'استراتيجية المساعد الذكي',
|
||||||
'workplace.shortcut.aiConfigHint': 'تكوين الترحيب متعدد اللغات وتأهيل العملاء المحتملين',
|
'workplace.shortcut.aiConfigHint': 'تكوين الترحيب متعدد اللغات وتأهيل العملاء المحتملين',
|
||||||
|
'workplace.alerts.title': 'تنبيهات قابلة للتنفيذ',
|
||||||
|
'workplace.alerts.highIntentLead': 'مشتري من دبي مكث 210 ثوانٍ في دراسات الحالة دون متابعة.',
|
||||||
|
'workplace.alerts.actionFollow': 'متابعة الآن',
|
||||||
'workplace.channel.nfc': 'NFC',
|
'workplace.channel.nfc': 'NFC',
|
||||||
'workplace.channel.qr': 'رمز QR',
|
'workplace.channel.qr': 'رمز QR',
|
||||||
'workplace.channel.link': 'رابط مباشر',
|
'workplace.channel.link': 'رابط مباشر',
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
.page {
|
.page {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
max-width: 1200px;
|
width: 100%;
|
||||||
|
max-width: 1680px;
|
||||||
|
margin: 0 auto;
|
||||||
padding: var(--omni-space-24);
|
padding: var(--omni-space-24);
|
||||||
background: var(--omni-color-surface);
|
background: var(--omni-color-surface);
|
||||||
font-family: var(--omni-font-family);
|
font-family: var(--omni-font-family);
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
@@ -12,7 +15,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: var(--omni-space-16);
|
gap: var(--omni-space-16);
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
margin-bottom: var(--omni-space-24);
|
margin-bottom: var(--omni-space-20);
|
||||||
}
|
}
|
||||||
|
|
||||||
.headerInfo {
|
.headerInfo {
|
||||||
@@ -169,8 +172,8 @@
|
|||||||
color: var(--omni-color-error);
|
color: var(--omni-color-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 漏斗与渠道矩阵 */
|
/* 漏斗与雷达卡片 */
|
||||||
.middleRow {
|
.funnelCard {
|
||||||
margin-top: var(--omni-space-16);
|
margin-top: var(--omni-space-16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,35 +226,7 @@
|
|||||||
background: var(--omni-color-success);
|
background: var(--omni-color-success);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 渠道占比 */
|
.radarCard {
|
||||||
.channelRow {
|
|
||||||
margin-bottom: var(--omni-space-16);
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelRow:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelMeta {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: var(--omni-space-8);
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelName {
|
|
||||||
color: var(--omni-color-text);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.channelPercent {
|
|
||||||
color: var(--omni-color-text-2);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 主内容区域 */
|
|
||||||
.main {
|
|
||||||
margin-top: var(--omni-space-16);
|
margin-top: var(--omni-space-16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,11 +271,123 @@
|
|||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 运营工具箱 */
|
/* ========================================================
|
||||||
|
右侧出海运营快捷中枢 (Command Hub)
|
||||||
|
======================================================== */
|
||||||
|
.hubContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--omni-space-16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 渠道占比 */
|
||||||
|
.channelRow {
|
||||||
|
margin-bottom: var(--omni-space-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.channelRow:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channelMeta {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: var(--omni-space-6);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channelName {
|
||||||
|
color: var(--omni-color-text);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channelPercent {
|
||||||
|
color: var(--omni-color-text-2);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 8 大核心快捷入口网格 (2列) */
|
||||||
|
.navGrid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: var(--omni-space-10, 10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navCard {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: var(--omni-space-10, 10px);
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid var(--omni-color-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--omni-color-surface);
|
||||||
|
text-align: start;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navCard:hover {
|
||||||
|
background: var(--omni-color-bg);
|
||||||
|
border-color: rgba(11, 92, 255, 0.35);
|
||||||
|
box-shadow: 0 2px 6px rgba(11, 92, 255, 0.08);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navCard:focus-visible {
|
||||||
|
outline: 2px solid var(--omni-color-primary);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navIconBox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--omni-color-bg);
|
||||||
|
color: var(--omni-color-primary);
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 1px solid var(--omni-color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navIcon {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navTextBox {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navTitle {
|
||||||
|
display: block;
|
||||||
|
color: var(--omni-color-text);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.3;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navSub {
|
||||||
|
display: block;
|
||||||
|
margin-top: 2px;
|
||||||
|
color: var(--omni-color-text-2);
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.3;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 效率工具箱 */
|
||||||
.toolboxList {
|
.toolboxList {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--omni-space-12);
|
gap: var(--omni-space-10, 10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcut {
|
.shortcut {
|
||||||
@@ -308,7 +395,7 @@
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: var(--omni-space-12);
|
gap: var(--omni-space-12);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: var(--omni-space-12);
|
padding: 10px 12px;
|
||||||
border: 1px solid var(--omni-color-border);
|
border: 1px solid var(--omni-color-border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
background: var(--omni-color-surface);
|
background: var(--omni-color-surface);
|
||||||
@@ -338,16 +425,17 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 32px;
|
width: 30px;
|
||||||
height: 32px;
|
height: 30px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--omni-color-bg);
|
background: var(--omni-color-bg);
|
||||||
color: var(--omni-color-primary);
|
color: var(--omni-color-primary);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
border: 1px solid var(--omni-color-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolIcon {
|
.toolIcon {
|
||||||
font-size: 16px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcutContent {
|
.shortcutContent {
|
||||||
@@ -358,21 +446,68 @@
|
|||||||
.shortcutLabel {
|
.shortcutLabel {
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--omni-color-text);
|
color: var(--omni-color-text);
|
||||||
font-size: 14px;
|
font-size: 13px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shortcutHint {
|
.shortcutHint {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: var(--omni-space-4);
|
margin-top: 2px;
|
||||||
color: var(--omni-color-text-2);
|
color: var(--omni-color-text-2);
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 待办预警卡片 */
|
||||||
|
.alertPanel {
|
||||||
|
border-color: rgba(247, 144, 9, 0.3) !important;
|
||||||
|
background: #FFFDF9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alertContent {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--omni-space-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.alertItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: var(--omni-space-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.alertDot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
margin-top: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--omni-color-warning, #F79009);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alertText {
|
||||||
|
color: var(--omni-color-text);
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alertActionBtn {
|
||||||
|
align-self: flex-start;
|
||||||
|
border-radius: var(--omni-radius-button);
|
||||||
|
color: var(--omni-color-text);
|
||||||
|
border-color: var(--omni-color-border);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alertActionBtn:hover {
|
||||||
|
border-color: var(--omni-color-primary);
|
||||||
|
color: var(--omni-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.shortcut:hover {
|
.shortcut:hover,
|
||||||
|
.navCard:hover {
|
||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
.pulseDot {
|
.pulseDot {
|
||||||
|
|||||||
@@ -118,3 +118,38 @@ test('6. 专业出海运营官视角:包含全球雷达监控、渠道漏斗
|
|||||||
assert.ok(!EMOJI_RE.test(content), '页面代码严禁 emoji');
|
assert.ok(!EMOJI_RE.test(content), '页面代码严禁 emoji');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('7. 出海运营快捷中枢:覆盖8大核心业务快捷入口与运营预警,全屏仅1个主CTA', () => {
|
||||||
|
const content = fs.readFileSync(pagePath, 'utf-8');
|
||||||
|
const localeContent = fs.readFileSync(localePath, 'utf-8');
|
||||||
|
|
||||||
|
// 必须覆盖的8大核心业务快捷路由
|
||||||
|
const requiredRoutes = [
|
||||||
|
'/card/builder',
|
||||||
|
'/crm/leads',
|
||||||
|
'/crm/pipeline',
|
||||||
|
'/nfc/batch',
|
||||||
|
'/nfc/devices',
|
||||||
|
'/dashboard/radar-map',
|
||||||
|
'/ai/concierge',
|
||||||
|
'/dashboard/financial',
|
||||||
|
];
|
||||||
|
for (const route of requiredRoutes) {
|
||||||
|
assert.ok(content.includes(route), `工作台必须包含快捷业务路由入口: ${route}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 必须包含待办预警词条
|
||||||
|
assert.ok(localeContent.includes('workplace.alerts.title'), '必须包含待办预警标题');
|
||||||
|
assert.ok(localeContent.includes('workplace.quickHub.title'), '必须包含快捷中枢标题');
|
||||||
|
|
||||||
|
// 铁律:全屏主 CTA 依然严格为 1
|
||||||
|
const primaryButtons = content.match(/type=["']primary["']/g) || [];
|
||||||
|
assert.equal(
|
||||||
|
primaryButtons.length,
|
||||||
|
1,
|
||||||
|
'无论增加多少快捷入口,全屏依然必须严格保持唯 1 一个主 CTA (type="primary")'
|
||||||
|
);
|
||||||
|
assert.ok(!EMOJI_RE.test(localeContent), '语言包严禁 emoji');
|
||||||
|
assert.ok(!EMOJI_RE.test(content), '页面代码严禁 emoji');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户