feat(ad): 「广告数据」改「广告管理」,加穿山甲配置面板
- 顶部广告配置面板:app_id / 3 场景广告位ID / 激励验签密钥(Password) / 3 场景开关, 读写 /admin/api/ad-config - 原报表保留为下方「收益报表」;左侧菜单更名「广告管理」 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,8 @@ import {
|
|||||||
Col,
|
Col,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
Divider,
|
Divider,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
Modal,
|
Modal,
|
||||||
Popover,
|
Popover,
|
||||||
@@ -17,6 +19,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
Statistic,
|
||||||
|
Switch,
|
||||||
Table,
|
Table,
|
||||||
Tag,
|
Tag,
|
||||||
Typography,
|
Typography,
|
||||||
@@ -268,6 +271,95 @@ function TrendChart({ points }: { points: TrendPoint[] }) {
|
|||||||
|
|
||||||
// 广告数据页:单表 —— 按 用户×类型×应用×代码位 聚合,一行同时给出
|
// 广告数据页:单表 —— 按 用户×类型×应用×代码位 聚合,一行同时给出
|
||||||
// 展示条数 / 收益 / 应发金币 / 实发金币 / 是否一致(发奖对账下沉到聚合级)。
|
// 展示条数 / 收益 / 应发金币 / 实发金币 / 是否一致(发奖对账下沉到聚合级)。
|
||||||
|
// 广告配置面板:穿山甲 app_id / 各场景广告位ID / 验签密钥 / 各场景开关。
|
||||||
|
// 客户端(发版后)从 /api/v1/platform/ad-config 拉取;此处经 admin /ad-config 读写。
|
||||||
|
interface AdCfg {
|
||||||
|
app_id: string;
|
||||||
|
reward_code_id: string;
|
||||||
|
compare_feed_code_id: string;
|
||||||
|
coupon_feed_code_id: string;
|
||||||
|
reward_mkey: string;
|
||||||
|
reward_enabled: boolean;
|
||||||
|
compare_ad_enabled: boolean;
|
||||||
|
coupon_ad_enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function AdConfigPanel() {
|
||||||
|
const { message } = App.useApp();
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [saving, setSaving] = useState(false);
|
||||||
|
const load = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const r = await api.get<AdCfg>('/admin/api/ad-config');
|
||||||
|
form.setFieldsValue(r.data);
|
||||||
|
} catch (e) {
|
||||||
|
message.error(errMsg(e, '广告配置加载失败'));
|
||||||
|
}
|
||||||
|
}, [form, message]);
|
||||||
|
useEffect(() => {
|
||||||
|
load();
|
||||||
|
}, [load]);
|
||||||
|
const save = async () => {
|
||||||
|
const v = await form.validateFields();
|
||||||
|
setSaving(true);
|
||||||
|
try {
|
||||||
|
await api.patch('/admin/api/ad-config', v);
|
||||||
|
message.success('已保存。客户端下次拉取生效(应用ID需冷启,广告位ID即时)');
|
||||||
|
load();
|
||||||
|
} catch (e) {
|
||||||
|
message.error(errMsg(e, '保存失败'));
|
||||||
|
} finally {
|
||||||
|
setSaving(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title="广告配置(穿山甲)"
|
||||||
|
style={{ marginBottom: 16 }}
|
||||||
|
extra={
|
||||||
|
<Button type="primary" loading={saving} onClick={save}>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Alert
|
||||||
|
type="info"
|
||||||
|
style={{ marginBottom: 16 }}
|
||||||
|
message="应用ID改了客户端需冷启生效,广告位ID即时;换激励位必须同步换验签密钥(m-key),否则发不出金币。这些配置需客户端发版接入后才会读取。"
|
||||||
|
/>
|
||||||
|
<Form form={form} layout="vertical">
|
||||||
|
<Form.Item name="app_id" label="穿山甲应用ID (APP_ID)" rules={[{ required: true }]}>
|
||||||
|
<Input placeholder="如 5830519" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="reward_code_id" label="福利页 · 激励视频 广告位ID" rules={[{ required: true }]}>
|
||||||
|
<Input placeholder="如 104099389" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name="reward_mkey"
|
||||||
|
label="福利激励 · 验签密钥 m-key(机密,不下发客户端;换激励位必须同步换;留空回退 .env)"
|
||||||
|
>
|
||||||
|
<Input.Password placeholder="GroMore S2S 回调验签密钥" autoComplete="off" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="compare_feed_code_id" label="比价 · 信息流 广告位ID" rules={[{ required: true }]}>
|
||||||
|
<Input placeholder="如 104090333" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="coupon_feed_code_id" label="领券 · 信息流 广告位ID" rules={[{ required: true }]}>
|
||||||
|
<Input placeholder="如 104090333" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="reward_enabled" label="福利激励视频开关" valuePropName="checked">
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="compare_ad_enabled" label="比价广告开关" valuePropName="checked">
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="coupon_ad_enabled" label="领券广告开关" valuePropName="checked">
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function AdRevenuePage() {
|
export default function AdRevenuePage() {
|
||||||
const { message } = App.useApp();
|
const { message } = App.useApp();
|
||||||
const [range, setRange] = useState<[Dayjs, Dayjs]>([dayjs(), dayjs()]);
|
const [range, setRange] = useState<[Dayjs, Dayjs]>([dayjs(), dayjs()]);
|
||||||
@@ -412,8 +504,9 @@ export default function AdRevenuePage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<AdConfigPanel />
|
||||||
<Space align="center" style={{ display: 'flex', marginBottom: 16 }}>
|
<Space align="center" style={{ display: 'flex', marginBottom: 16 }}>
|
||||||
<h2 style={{ margin: 0 }}>广告数据</h2>
|
<h2 style={{ margin: 0 }}>收益报表</h2>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ const MENU = [
|
|||||||
{ key: '/price-reports', icon: <FlagOutlined />, label: '上报审核' },
|
{ key: '/price-reports', icon: <FlagOutlined />, label: '上报审核' },
|
||||||
{ key: '/comparison-records', icon: <ProfileOutlined />, label: '比价记录' },
|
{ key: '/comparison-records', icon: <ProfileOutlined />, label: '比价记录' },
|
||||||
{ key: '/feedbacks', icon: <MessageOutlined />, label: '反馈工单' },
|
{ key: '/feedbacks', icon: <MessageOutlined />, label: '反馈工单' },
|
||||||
{ key: '/ad-revenue', icon: <BarChartOutlined />, label: '广告数据' },
|
{ key: '/ad-revenue', icon: <BarChartOutlined />, label: '广告管理' },
|
||||||
{ key: '/cps', icon: <ShareAltOutlined />, label: 'CPS 分发' },
|
{ key: '/cps', icon: <ShareAltOutlined />, label: 'CPS 分发' },
|
||||||
{ key: '/config', icon: <SettingOutlined />, label: '系统配置' },
|
{ key: '/config', icon: <SettingOutlined />, label: '系统配置' },
|
||||||
{ key: '/admins', icon: <TeamOutlined />, label: '管理员', superOnly: true },
|
{ key: '/admins', icon: <TeamOutlined />, label: '管理员', superOnly: true },
|
||||||
|
|||||||
Reference in New Issue
Block a user