完成对接前测表单创建及列表接口

This commit is contained in:
Lrd
2026-06-22 18:24:05 +08:00
parent a37b0e4435
commit 5041660ca4
4 changed files with 403 additions and 289 deletions
+12
View File
@@ -565,4 +565,16 @@ export async function removefour(projectId: string, stepId: string ,params: any)
return api.post(`/shot-replications/projects/${projectId}/steps/${stepId}/generate-video`, params);
}
// 获取地区信息
export interface GetAreaParams {
level?: string;
parent_code?: string;
}
export async function getArea(params?: GetAreaParams): Promise<any> {
const query = new URLSearchParams();
if (params?.level) query.set('level', params.level);
if (params?.parent_code) query.set('parent_code', params.parent_code);
return api.get(`/pre-test-template/getArea?${query.toString()}`);
}
//
+33 -40
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import { Button, Table, Tag, Modal, Select, App, Input } from 'antd';
import { PlusOutlined, CheckCircleOutlined, ClockCircleOutlined, CiCircleOutlined } from '@ant-design/icons';
import { Link } from 'react-router-dom';
import { Button, Table, Tag, Modal, Select, App, Input, Pagination, Typography } from 'antd';
import { PlusOutlined, LockOutlined } from '@ant-design/icons';
import { getOAuthList, juliang_callback, requestOAuth } from '../api';
const OPEN_TYPE_MAP: Record<number, string> = {
@@ -46,13 +47,6 @@ interface AuthorizationData {
account_id?: string;
}
const statusConfig = {
active: { label: '已授权', color: 'green', icon: CheckCircleOutlined },
pending: { label: '待授权', color: 'gold', icon: ClockCircleOutlined },
expired: { label: '已过期', color: 'red', icon: CiCircleOutlined },
revoked: { label: '已撤销', color: 'gray', icon: CiCircleOutlined },
};
const AuthorizationPage: React.FC = () => {
const { message } = App.useApp();
const [authorizations, setAuthorizations] = useState<AuthorizationData[]>([]);
@@ -119,19 +113,7 @@ const AuthorizationPage: React.FC = () => {
}
};
const renderStatus = (status: string) => {
const config = statusConfig[status as keyof typeof statusConfig] || statusConfig.expired;
const Icon = config.icon;
return (
<Tag color={config.color} style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
<Icon size={14} />
{config.label}
</Tag>
);
};
const handleAuthorize = () => {
console.log('handleAuthorize');
setShowModal(true);
};
@@ -143,7 +125,6 @@ const AuthorizationPage: React.FC = () => {
setLoading(true);
try {
const response = await requestOAuth({ open_type: selectedOpenType });
console.log(response);
if (response.authUrl) {
window.open(response.authUrl, '_blank');
} else {
@@ -261,6 +242,16 @@ const AuthorizationPage: React.FC = () => {
width: 160,
render: (text: string) => <span style={{ color: '#64748b' }}>{formatDateTime(text)}</span>,
},
{
title: '操作',
key: 'action',
width: 120,
render: (_: unknown, record: AuthorizationData) => (
<Link to={`/consume?accountId=${record.id}`} style={{ color: '#6366f1' }}>
</Link>
),
},
];
const tableData = authorizations.map((item, index) => ({
@@ -271,10 +262,9 @@ const AuthorizationPage: React.FC = () => {
return (
<div style={{ minHeight: '94vh' }}>
<div>
<h1 style={{ lineHeight: '28px', fontSize: 24, fontWeight: 600, color: '#1e293b', marginBottom: 8, marginTop: 0 }}>
</h1>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
<LockOutlined style={{ color: '#6366f1', fontSize: 16 }} />
<Typography.Text strong style={{ fontSize: 16 }}></Typography.Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, marginBottom: 16 }}>
@@ -342,23 +332,26 @@ const AuthorizationPage: React.FC = () => {
dataSource={tableData}
columns={columns}
loading={listLoading}
pagination={{
current: currentPage,
pageSize: pageSize,
total: total,
showSizeChanger: true,
showTotal: (total) => `${total} 条记录`,
onChange: (page, size) => {
pagination={false}
rowKey="id"
bordered={false}
scroll={{ x: 'max-content' }}
/>
<div style={{ padding: '16px', textAlign: 'right' }}>
<Pagination
current={currentPage}
pageSize={pageSize}
total={total}
showSizeChanger
showTotal={(total) => `${total} 条记录`}
onChange={(page, size) => {
setCurrentPage(page);
setPageSize(size);
loadOAuthList(page, size);
},
}}
rowKey="id"
bordered={false}
style={{ padding: 16 }}
scroll={{ x: 'max-content' }}
/>
}}
size="small"
/>
</div>
</div>
<Modal
+17 -22
View File
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { Table, Tag, Button, message } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import { Table, Tag, Button, Pagination, Typography } from 'antd';
import { ArrowLeftOutlined, DollarOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
// 消耗记录数据类型
@@ -80,20 +80,11 @@ const ConsumePage: React.FC = () => {
};
return (
<div style={{ padding: 24, minHeight: '94vh', background: '#f8fafc' }}>
{/* 页面标题和返回按钮 */}
<div style={{ marginBottom: 20, display: 'flex', alignItems: 'center', gap: 16 }}>
<Button
type="text"
icon={<ArrowLeftOutlined />}
onClick={handleBack}
style={{ padding: 0, color: '#6366f1', fontSize: 14 }}
>
</Button>
<h1 style={{ fontSize: 24, fontWeight: 600, color: '#1e293b', marginBottom: 8 }}>
</h1>
<div style={{ minHeight: '94vh' }}>
{/* 页面标题 */}
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
<DollarOutlined style={{ color: '#6366f1', fontSize: 16 }} />
<Typography.Text strong style={{ fontSize: 16 }}></Typography.Text>
</div>
{/* 表格 */}
@@ -102,16 +93,20 @@ const ConsumePage: React.FC = () => {
dataSource={tableData}
columns={columns}
loading={loading}
pagination={{
pageSize: 10,
showSizeChanger: true,
showTotal: (total) => `${total} 条记录`,
}}
pagination={false}
rowKey="id"
bordered={false}
style={{ padding: 16 }}
scroll={{ x: 'max-content' }}
/>
<div style={{ padding: '16px', textAlign: 'right' }}>
<Pagination
pageSize={10}
total={consumptionRecords.length}
showSizeChanger
showTotal={(total) => `${total} 条记录`}
size="small"
/>
</div>
</div>
</div>
);
+341 -227
View File
@@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react';
import { Table, Tag, Button, Typography, Space, Modal, Form, Input, Select, message } from 'antd';
import { PlusOutlined, EditOutlined } from '@ant-design/icons';
import { getPreTestList, createPreTest } from '../api';
import { Table, Tag, Button, Typography, Space, Modal, Form, Input, Select, Cascader, App, Pagination } from 'antd';
import { PlusOutlined, EditOutlined, FileTextOutlined } from '@ant-design/icons';
import { getPreTestList, createPreTest, getArea } from '../api';
interface PreTestRecord {
id: string;
@@ -27,175 +27,247 @@ const statusConfig = {
};
const PRETEST_FIELDS: PreTestField[] = [
{ id: 'AD_APP_ACTIVATE', name: 'AD_APP_ACTIVATE', label: 'AD应用-激活', description: '应用激活行为' },
{ id: 'AD_APP_AUTH', name: 'AD_APP_AUTH', label: 'AD应用-授信', description: '应用授信行为' },
{ id: 'AD_APP_BOOK', name: 'AD_APP_BOOK', label: 'AD应用-预约表单', description: '应用预约表单' },
{ id: 'AD_APP_BUY', name: 'AD_APP_BUY', label: 'AD应用-APP内付费', description: 'APP内付费行为' },
{ id: 'AD_APP_CLICKS', name: 'AD_APP_CLICKS', label: 'AD应用-点击量', description: '应用点击量' },
{ id: 'AD_APP_DETAIL', name: 'AD_APP_DETAIL', label: 'AD应用-APP内详情页到站UV', description: 'APP内详情页到站UV' },
{ id: 'AD_APP_DOWNLOADED', name: 'AD_APP_DOWNLOADED', label: 'AD应用-下载完成', description: '应用下载完成' },
{ id: 'AD_APP_INSTALLED', name: 'AD_APP_INSTALLED', label: 'AD应用-安装完成', description: '应用安装完成' },
{ id: 'AD_APP_KEY_BEHAVIOR', name: 'AD_APP_KEY_BEHAVIOR', label: 'AD应用-关键行为', description: '应用关键行为' },
{ id: 'AD_APP_ORDER', name: 'AD_APP_ORDER', label: 'AD应用-APP内下单', description: 'APP内下单行为' },
{ id: 'AD_APP_PAY', name: 'AD_APP_PAY', label: 'AD应用-付费', description: '应用付费行为' },
{ id: 'AD_APP_PRE_AUTH', name: 'AD_APP_PRE_AUTH', label: 'AD应用-预授信', description: '应用预授信行为' },
{ id: 'AD_APP_PRE_DOWNLOAD', name: 'AD_APP_PRE_DOWNLOAD', label: 'AD应用-预约下载', description: '应用预约下载' },
{ id: 'AD_APP_PUSH_ORDER', name: 'AD_APP_PUSH_ORDER', label: 'AD应用-首次发单(乘客)', description: '首次发单行为' },
{ id: 'AD_APP_REGISTER', name: 'AD_APP_REGISTER', label: 'AD应用-注册', description: '应用注册行为' },
{ id: 'AD_APP_SHOW', name: 'AD_APP_SHOW', label: 'AD应用-展示量', description: '应用展示量' },
{ id: 'AD_APP_SUBMIT', name: 'AD_APP_SUBMIT', label: 'AD应用-提交认证', description: '应用提交认证' },
{ id: 'AD_APP_VIEW', name: 'AD_APP_VIEW', label: 'AD应用-APP内访问', description: 'APP内访问行为' },
{ id: 'AD_CLUE_AUTH', name: 'AD_CLUE_AUTH', label: 'AD销售线索收集-授信', description: '销售线索授信' },
{ id: 'AD_CLUE_BUTTON', name: 'AD_CLUE_BUTTON', label: 'AD销售线索收集-按钮跳转', description: '按钮跳转' },
{ id: 'AD_CLUE_CLICKS', name: 'AD_CLUE_CLICKS', label: 'AD销售线索收集-点击量', description: '点击量' },
{ id: 'AD_CLUE_CONFIRM', name: 'AD_CLUE_CONFIRM', label: 'AD销售线索收集-回访-信息确认', description: '回访信息确认' },
{ id: 'AD_CLUE_CONSULT', name: 'AD_CLUE_CONSULT', label: 'AD销售线索收集-有效咨询', description: '有效咨询' },
{ id: 'AD_CLUE_CONSULT_MSG', name: 'AD_CLUE_CONSULT_MSG', label: 'AD销售线索收集-留资咨询', description: '留资咨询' },
{ id: 'AD_CLUE_COUPON', name: 'AD_CLUE_COUPON', label: 'AD销售线索收集-卡券领取', description: '卡券领取' },
{ id: 'AD_CLUE_CUSTOMER', name: 'AD_CLUE_CUSTOMER', label: 'AD销售线索收集-有效获客', description: '有效获客' },
{ id: 'AD_CLUE_CVT', name: 'AD_CLUE_CVT', label: 'AD销售线索收集-多转化', description: '多转化' },
{ id: 'AD_CLUE_DONE', name: 'AD_CLUE_DONE', label: 'AD销售线索收集-完件', description: '完件' },
{ id: 'AD_CLUE_FORM', name: 'AD_CLUE_FORM', label: 'AD销售线索收集-表单提交', description: '表单提交' },
{ id: 'AD_CLUE_FRIENDS', name: 'AD_CLUE_FRIENDS', label: 'AD销售线索收集-回访-加为好友', description: '回访加为好友' },
{ id: 'AD_CLUE_INSURANCE', name: 'AD_CLUE_INSURANCE', label: 'AD销售线索收集-保险支付', description: '保险支付' },
{ id: 'AD_CLUE_INTENTION', name: 'AD_CLUE_INTENTION', label: 'AD销售线索收集-存在意向', description: '存在意向' },
{ id: 'AD_CLUE_INTENTION_FORM', name: 'AD_CLUE_INTENTION_FORM', label: 'AD销售线索收集-意向表单', description: '意向表单' },
{ id: 'AD_CLUE_INTENTION_TEL', name: 'AD_CLUE_INTENTION_TEL', label: 'AD销售线索收集-意向话单', description: '意向话单' },
{ id: 'AD_CLUE_MESSAGE', name: 'AD_CLUE_MESSAGE', label: 'AD销售线索收集-私信消息', description: '私信消息' },
{ id: 'AD_CLUE_MONEY', name: 'AD_CLUE_MONEY', label: 'AD销售线索收集-放款', description: '放款' },
{ id: 'AD_CLUE_MSG', name: 'AD_CLUE_MSG', label: 'AD销售线索收集-私信留资', description: '私信留资' },
{ id: 'AD_CLUE_PAGE', name: 'AD_CLUE_PAGE', label: 'AD销售线索收集-访问目标页面', description: '访问目标页面' },
{ id: 'AD_CLUE_PAY', name: 'AD_CLUE_PAY', label: 'AD销售线索收集-付费', description: '付费' },
{ id: 'AD_CLUE_PRE_AUTH', name: 'AD_CLUE_PRE_AUTH', label: 'AD销售线索收集-预授信', description: '预授信' },
{ id: 'AD_CLUE_PROTENTIAL_DEAL', name: 'AD_CLUE_PROTENTIAL_DEAL', label: 'AD销售线索收集-回访-高潜成交', description: '回访高潜成交' },
{ id: 'AD_CLUE_PUSH_ORDER', name: 'AD_CLUE_PUSH_ORDER', label: 'AD销售线索收集-首次发单(乘客)', description: '首次发单' },
{ id: 'AD_CLUE_REGISTER', name: 'AD_CLUE_REGISTER', label: 'AD销售线索收集-注册', description: '注册' },
{ id: 'AD_CLUE_SHOW', name: 'AD_CLUE_SHOW', label: 'AD销售线索收集-展示量', description: '展示量' },
{ id: 'AD_CLUE_SUBMIT', name: 'AD_CLUE_SUBMIT', label: 'AD销售线索收集-提交认证', description: '提交认证' },
{ id: 'AD_CLUE_TEL', name: 'AD_CLUE_TEL', label: 'AD销售线索收集-智能电话确认接通', description: '智能电话确认接通' },
{ id: 'AD_CLUE_TEL_CALL', name: 'AD_CLUE_TEL_CALL', label: 'AD销售线索收集-电话接通', description: '电话接通' },
{ id: 'AD_CLUE_WX_ADD', name: 'AD_CLUE_WX_ADD', label: 'AD销售线索收集-微信-添加企业微信', description: '添加企业微信' },
{ id: 'AD_CLUE_WX_COPY', name: 'AD_CLUE_WX_COPY', label: 'AD销售线索收集-微信复制', description: '微信复制' },
{ id: 'AD_CLUE_WX_MSG', name: 'AD_CLUE_WX_MSG', label: 'AD销售线索收集-微信-用户首次消息', description: '用户首次消息' },
{ id: 'AD_ECP_APP_BUY', name: 'AD_ECP_APP_BUY', label: 'AD电商-app内下单', description: '电商app内下单' },
{ id: 'AD_ECP_APP_DETAIL', name: 'AD_ECP_APP_DETAIL', label: 'AD电商-app内详情页到站uv', description: '电商app内详情页到站uv' },
{ id: 'AD_ECP_APP_VIEW', name: 'AD_ECP_APP_VIEW', label: 'AD电商-app内访问', description: '电商app内访问' },
{ id: 'AD_ECP_BUTTON', name: 'AD_ECP_BUTTON', label: 'AD电商-按钮跳转', description: '电商按钮跳转' },
{ id: 'AD_ECP_INTEREST', name: 'AD_ECP_INTEREST', label: 'AD电商-引流电商种草', description: '引流电商种草' },
{ id: 'AD_ECP_SHOP', name: 'AD_ECP_SHOP', label: 'AD电商-调起店铺', description: '调起店铺' },
{ id: 'AD_ECP_SHOP_STAY', name: 'AD_ECP_SHOP_STAY', label: 'AD电商-店铺停留', description: '店铺停留' },
{ id: 'AD_MINIAPP_ACTIVATE', name: 'AD_MINIAPP_ACTIVATE', label: 'AD快应用-激活', description: '快应用激活' },
{ id: 'AD_MINIAPP_KEY_BEHAVIOR', name: 'AD_MINIAPP_KEY_BEHAVIOR', label: 'AD快应用-关键行为', description: '快应用关键行为' },
{ id: 'AD_MINIAPP_PAY', name: 'AD_MINIAPP_PAY', label: 'AD快应用-付费', description: '快应用付费' },
{ id: 'AD_MINIAPP_REGISTER', name: 'AD_MINIAPP_REGISTER', label: 'AD快应用-注册', description: '快应用注册' },
{ id: 'AD_NATIVE_ACTIVATE', name: 'AD_NATIVE_ACTIVATE', label: 'AD原声互动-激活', description: '原声互动激活' },
{ id: 'AD_NATIVE_CLICKS', name: 'AD_NATIVE_CLICKS', label: 'AD原声互动-组件点击', description: '组件点击' },
{ id: 'AD_NATIVE_FANS_GROUP', name: 'AD_NATIVE_FANS_GROUP', label: 'AD原声互动-粉丝入群', description: '粉丝入群' },
{ id: 'AD_NATIVE_FOLLOW', name: 'AD_NATIVE_FOLLOW', label: 'AD原声互动-帐号关注', description: '帐号关注' },
{ id: 'AD_NATIVE_INTERACTIVE', name: 'AD_NATIVE_INTERACTIVE', label: 'AD原声互动-互动', description: '互动' },
{ id: 'AD_NATIVE_LIVE', name: 'AD_NATIVE_LIVE', label: 'AD原声互动-预约直播', description: '预约直播' },
{ id: 'AD_NATIVE_LIVE_DONATE', name: 'AD_NATIVE_LIVE_DONATE', label: 'AD原声互动-直播间营销捐赠', description: '直播间营销捐赠' },
{ id: 'AD_NATIVE_LIVE_PAY', name: 'AD_NATIVE_LIVE_PAY', label: 'AD原声互动-直播间打赏', description: '直播间打赏' },
{ id: 'AD_NATIVE_LIVE_STAY', name: 'AD_NATIVE_LIVE_STAY', label: 'AD原声互动-直播间停留', description: '直播间停留' },
{ id: 'AD_NATIVE_LIVE_VIEW', name: 'AD_NATIVE_LIVE_VIEW', label: 'AD原声互动-直播间观看', description: '直播间观看' },
{ id: 'AD_NATIVE_PAY', name: 'AD_NATIVE_PAY', label: 'AD原声互动-付费', description: '原声互动付费' },
{ id: 'AD_PRODUCT_ACTIVATE', name: 'AD_PRODUCT_ACTIVATE', label: 'AD商品-激活', description: '商品激活' },
{ id: 'AD_PRODUCT_APP_BUY', name: 'AD_PRODUCT_APP_BUY', label: 'AD商品-app内下单', description: '商品app内下单' },
{ id: 'AD_PRODUCT_APP_DETAIL', name: 'AD_PRODUCT_APP_DETAIL', label: 'AD商品-app内详情页到站uv', description: '商品app内详情页到站uv' },
{ id: 'AD_PRODUCT_APP_PAY', name: 'AD_PRODUCT_APP_PAY', label: 'AD商品-app内付费', description: '商品app内付费' },
{ id: 'AD_PRODUCT_APP_VIEW', name: 'AD_PRODUCT_APP_VIEW', label: 'AD商品-app内访问', description: '商品app内访问' },
{ id: 'AD_PRODUCT_FORM', name: 'AD_PRODUCT_FORM', label: 'AD商品-表单提交', description: '商品表单提交' },
{ id: 'AD_PRODUCT_KEY_BEHAVIOR', name: 'AD_PRODUCT_KEY_BEHAVIOR', label: 'AD商品-关键行为', description: '商品关键行为' },
{ id: 'AD_PRODUCT_PAY', name: 'AD_PRODUCT_PAY', label: 'AD商品-付费', description: '商品付费' },
{ id: 'AD_TINYAPP_ACTIVATE', name: 'AD_TINYAPP_ACTIVATE', label: 'AD小程序-激活', description: '小程序激活' },
{ id: 'AD_TINYAPP_KEY_BEHAVIOR', name: 'AD_TINYAPP_KEY_BEHAVIOR', label: 'AD小程序-关键行为', description: '小程序关键行为' },
{ id: 'AD_TINYAPP_PAY', name: 'AD_TINYAPP_PAY', label: 'AD小程序-付费', description: '小程序付费' },
{ id: 'QC_LIVE_BUY', name: 'QC_LIVE_BUY', label: '千川:直播投放-直播间下单', description: '直播间下单' },
{ id: 'QC_LIVE_CHECK', name: 'QC_LIVE_CHECK', label: '千川:直播投放-直播间结算', description: '直播间结算' },
{ id: 'QC_LIVE_COMMENTS', name: 'QC_LIVE_COMMENTS', label: '千川:直播投放-直播间评论', description: '直播间评论' },
{ id: 'QC_LIVE_DEAL', name: 'QC_LIVE_DEAL', label: '千川:直播投放-直播间成交', description: '直播间成交' },
{ id: 'QC_LIVE_ENTRY', name: 'QC_LIVE_ENTRY', label: '千川:直播投放-进入直播间', description: '进入直播间' },
{ id: 'QC_LIVE_FANS', name: 'QC_LIVE_FANS', label: '千川:直播投放-直播间粉丝提升', description: '直播间粉丝提升' },
{ id: 'QC_LIVE_HIT', name: 'QC_LIVE_HIT', label: '千川:直播投放-直播加热', description: '直播加热' },
{ id: 'QC_LIVE_PRODUCT_CLICKS', name: 'QC_LIVE_PRODUCT_CLICKS', label: '千川:直播投放-直播间商品点击', description: '直播间商品点击' },
{ id: 'QC_LIVE_ROI_CHECK', name: 'QC_LIVE_ROI_CHECK', label: '千川:直播投放-结算roi', description: '结算roi' },
{ id: 'QC_LIVE_ROI_DEAL', name: 'QC_LIVE_ROI_DEAL', label: '千川:直播投放-支付roi-直播间成交', description: '支付roi直播间成交' },
{ id: 'QC_LIVE_ROI_QC', name: 'QC_LIVE_ROI_QC', label: '千川:直播投放-支付roi-千川直接+间接订单', description: '支付roi千川订单' },
{ id: 'QC_PRODUCT_BUY', name: 'QC_PRODUCT_BUY', label: '千川:商品投放-商品购买', description: '商品购买' },
{ id: 'QC_PRODUCT_COMMENTS', name: 'QC_PRODUCT_COMMENTS', label: '千川:商品投放-点赞评论', description: '点赞评论' },
{ id: 'QC_PRODUCT_FANS', name: 'QC_PRODUCT_FANS', label: '千川:商品投放-粉丝提升', description: '粉丝提升' },
{ id: 'QC_PRODUCT_INTEREST', name: 'QC_PRODUCT_INTEREST', label: '千川:商品投放-人群种草', description: '人群种草' },
{ id: 'QC_PRODUCT_QC', name: 'QC_PRODUCT_QC', label: '千川:商品投放-千川直接+间接订单', description: '千川订单' },
{ id: 'QC_PRODUCT_ROI', name: 'QC_PRODUCT_ROI', label: '千川:商品投放-商品支付roi', description: '商品支付roi' },
{ id: 'AD_APP_ACTIVATE', name: 'AD_APP_ACTIVATE', label: '应用-激活', description: '应用激活行为' },
{ id: 'AD_APP_AUTH', name: 'AD_APP_AUTH', label: '应用-授信', description: '应用授信行为' },
{ id: 'AD_APP_BOOK', name: 'AD_APP_BOOK', label: '应用-预约表单', description: '应用预约表单' },
{ id: 'AD_APP_BUY', name: 'AD_APP_BUY', label: '应用-APP内付费', description: 'APP内付费行为' },
{ id: 'AD_APP_CLICKS', name: 'AD_APP_CLICKS', label: '应用-点击量', description: '应用点击量' },
{ id: 'AD_APP_DETAIL', name: 'AD_APP_DETAIL', label: '应用-APP内详情页到站UV', description: 'APP内详情页到站UV' },
{ id: 'AD_APP_DOWNLOADED', name: 'AD_APP_DOWNLOADED', label: '应用-下载完成', description: '应用下载完成' },
{ id: 'AD_APP_INSTALLED', name: 'AD_APP_INSTALLED', label: '应用-安装完成', description: '应用安装完成' },
{ id: 'AD_APP_KEY_BEHAVIOR', name: 'AD_APP_KEY_BEHAVIOR', label: '应用-关键行为', description: '应用关键行为' },
{ id: 'AD_APP_ORDER', name: 'AD_APP_ORDER', label: '应用-APP内下单', description: 'APP内下单行为' },
{ id: 'AD_APP_PAY', name: 'AD_APP_PAY', label: '应用-付费', description: '应用付费行为' },
{ id: 'AD_APP_PRE_AUTH', name: 'AD_APP_PRE_AUTH', label: '应用-预授信', description: '应用预授信行为' },
{ id: 'AD_APP_PRE_DOWNLOAD', name: 'AD_APP_PRE_DOWNLOAD', label: '应用-预约下载', description: '应用预约下载' },
{ id: 'AD_APP_PUSH_ORDER', name: 'AD_APP_PUSH_ORDER', label: '应用-首次发单(乘客)', description: '首次发单行为' },
{ id: 'AD_APP_REGISTER', name: 'AD_APP_REGISTER', label: '应用-注册', description: '应用注册行为' },
{ id: 'AD_APP_SHOW', name: 'AD_APP_SHOW', label: '应用-展示量', description: '应用展示量' },
{ id: 'AD_APP_SUBMIT', name: 'AD_APP_SUBMIT', label: '应用-提交认证', description: '应用提交认证' },
{ id: 'AD_APP_VIEW', name: 'AD_APP_VIEW', label: '应用-APP内访问', description: 'APP内访问行为' },
{ id: 'AD_CLUE_AUTH', name: 'AD_CLUE_AUTH', label: '销售线索收集-授信', description: '销售线索授信' },
{ id: 'AD_CLUE_BUTTON', name: 'AD_CLUE_BUTTON', label: '销售线索收集-按钮跳转', description: '按钮跳转' },
{ id: 'AD_CLUE_CLICKS', name: 'AD_CLUE_CLICKS', label: '销售线索收集-点击量', description: '点击量' },
{ id: 'AD_CLUE_CONFIRM', name: 'AD_CLUE_CONFIRM', label: '销售线索收集-回访-信息确认', description: '回访信息确认' },
{ id: 'AD_CLUE_CONSULT', name: 'AD_CLUE_CONSULT', label: '销售线索收集-有效咨询', description: '有效咨询' },
{ id: 'AD_CLUE_CONSULT_MSG', name: 'AD_CLUE_CONSULT_MSG', label: '销售线索收集-留资咨询', description: '留资咨询' },
{ id: 'AD_CLUE_COUPON', name: 'AD_CLUE_COUPON', label: '销售线索收集-卡券领取', description: '卡券领取' },
{ id: 'AD_CLUE_CUSTOMER', name: 'AD_CLUE_CUSTOMER', label: '销售线索收集-有效获客', description: '有效获客' },
{ id: 'AD_CLUE_CVT', name: 'AD_CLUE_CVT', label: '销售线索收集-多转化', description: '多转化' },
{ id: 'AD_CLUE_DONE', name: 'AD_CLUE_DONE', label: '销售线索收集-完件', description: '完件' },
{ id: 'AD_CLUE_FORM', name: 'AD_CLUE_FORM', label: '销售线索收集-表单提交', description: '表单提交' },
{ id: 'AD_CLUE_FRIENDS', name: 'AD_CLUE_FRIENDS', label: '销售线索收集-回访-加为好友', description: '回访加为好友' },
{ id: 'AD_CLUE_INSURANCE', name: 'AD_CLUE_INSURANCE', label: '销售线索收集-保险支付', description: '保险支付' },
{ id: 'AD_CLUE_INTENTION', name: 'AD_CLUE_INTENTION', label: '销售线索收集-存在意向', description: '存在意向' },
{ id: 'AD_CLUE_INTENTION_FORM', name: 'AD_CLUE_INTENTION_FORM', label: '销售线索收集-意向表单', description: '意向表单' },
{ id: 'AD_CLUE_INTENTION_TEL', name: 'AD_CLUE_INTENTION_TEL', label: '销售线索收集-意向话单', description: '意向话单' },
{ id: 'AD_CLUE_MESSAGE', name: 'AD_CLUE_MESSAGE', label: '销售线索收集-私信消息', description: '私信消息' },
{ id: 'AD_CLUE_MONEY', name: 'AD_CLUE_MONEY', label: '销售线索收集-放款', description: '放款' },
{ id: 'AD_CLUE_MSG', name: 'AD_CLUE_MSG', label: '销售线索收集-私信留资', description: '私信留资' },
{ id: 'AD_CLUE_PAGE', name: 'AD_CLUE_PAGE', label: '销售线索收集-访问目标页面', description: '访问目标页面' },
{ id: 'AD_CLUE_PAY', name: 'AD_CLUE_PAY', label: '销售线索收集-付费', description: '付费' },
{ id: 'AD_CLUE_PRE_AUTH', name: 'AD_CLUE_PRE_AUTH', label: '销售线索收集-预授信', description: '预授信' },
{ id: 'AD_CLUE_PROTENTIAL_DEAL', name: 'AD_CLUE_PROTENTIAL_DEAL', label: '销售线索收集-回访-高潜成交', description: '回访高潜成交' },
{ id: 'AD_CLUE_PUSH_ORDER', name: 'AD_CLUE_PUSH_ORDER', label: '销售线索收集-首次发单(乘客)', description: '首次发单' },
{ id: 'AD_CLUE_REGISTER', name: 'AD_CLUE_REGISTER', label: '销售线索收集-注册', description: '注册' },
{ id: 'AD_CLUE_SHOW', name: 'AD_CLUE_SHOW', label: '销售线索收集-展示量', description: '展示量' },
{ id: 'AD_CLUE_SUBMIT', name: 'AD_CLUE_SUBMIT', label: '销售线索收集-提交认证', description: '提交认证' },
{ id: 'AD_CLUE_TEL', name: 'AD_CLUE_TEL', label: '销售线索收集-智能电话确认接通', description: '智能电话确认接通' },
{ id: 'AD_CLUE_TEL_CALL', name: 'AD_CLUE_TEL_CALL', label: '销售线索收集-电话接通', description: '电话接通' },
{ id: 'AD_CLUE_WX_ADD', name: 'AD_CLUE_WX_ADD', label: '销售线索收集-微信-添加企业微信', description: '添加企业微信' },
{ id: 'AD_CLUE_WX_COPY', name: 'AD_CLUE_WX_COPY', label: '销售线索收集-微信复制', description: '微信复制' },
{ id: 'AD_CLUE_WX_MSG', name: 'AD_CLUE_WX_MSG', label: '销售线索收集-微信-用户首次消息', description: '用户首次消息' },
{ id: 'AD_ECP_APP_BUY', name: 'AD_ECP_APP_BUY', label: '电商-app内下单', description: '电商app内下单' },
{ id: 'AD_ECP_APP_DETAIL', name: 'AD_ECP_APP_DETAIL', label: '电商-app内详情页到站uv', description: '电商app内详情页到站uv' },
{ id: 'AD_ECP_APP_VIEW', name: 'AD_ECP_APP_VIEW', label: '电商-app内访问', description: '电商app内访问' },
{ id: 'AD_ECP_BUTTON', name: 'AD_ECP_BUTTON', label: '电商-按钮跳转', description: '电商按钮跳转' },
{ id: 'AD_ECP_INTEREST', name: 'AD_ECP_INTEREST', label: '电商-引流电商种草', description: '引流电商种草' },
{ id: 'AD_ECP_SHOP', name: 'AD_ECP_SHOP', label: '电商-调起店铺', description: '调起店铺' },
{ id: 'AD_ECP_SHOP_STAY', name: 'AD_ECP_SHOP_STAY', label: '电商-店铺停留', description: '店铺停留' },
{ id: 'AD_MINIAPP_ACTIVATE', name: 'AD_MINIAPP_ACTIVATE', label: '快应用-激活', description: '快应用激活' },
{ id: 'AD_MINIAPP_KEY_BEHAVIOR', name: 'AD_MINIAPP_KEY_BEHAVIOR', label: '快应用-关键行为', description: '快应用关键行为' },
{ id: 'AD_MINIAPP_PAY', name: 'AD_MINIAPP_PAY', label: '快应用-付费', description: '快应用付费' },
{ id: 'AD_MINIAPP_REGISTER', name: 'AD_MINIAPP_REGISTER', label: '快应用-注册', description: '快应用注册' },
{ id: 'AD_NATIVE_ACTIVATE', name: 'AD_NATIVE_ACTIVATE', label: '原声互动-激活', description: '原声互动激活' },
{ id: 'AD_NATIVE_CLICKS', name: 'AD_NATIVE_CLICKS', label: '原声互动-组件点击', description: '组件点击' },
{ id: 'AD_NATIVE_FANS_GROUP', name: 'AD_NATIVE_FANS_GROUP', label: '原声互动-粉丝入群', description: '粉丝入群' },
{ id: 'AD_NATIVE_FOLLOW', name: 'AD_NATIVE_FOLLOW', label: '原声互动-帐号关注', description: '帐号关注' },
{ id: 'AD_NATIVE_INTERACTIVE', name: 'AD_NATIVE_INTERACTIVE', label: '原声互动-互动', description: '互动' },
{ id: 'AD_NATIVE_LIVE', name: 'AD_NATIVE_LIVE', label: '原声互动-预约直播', description: '预约直播' },
{ id: 'AD_NATIVE_LIVE_DONATE', name: 'AD_NATIVE_LIVE_DONATE', label: '原声互动-直播间营销捐赠', description: '直播间营销捐赠' },
{ id: 'AD_NATIVE_LIVE_PAY', name: 'AD_NATIVE_LIVE_PAY', label: '原声互动-直播间打赏', description: '直播间打赏' },
{ id: 'AD_NATIVE_LIVE_STAY', name: 'AD_NATIVE_LIVE_STAY', label: '原声互动-直播间停留', description: '直播间停留' },
{ id: 'AD_NATIVE_LIVE_VIEW', name: 'AD_NATIVE_LIVE_VIEW', label: '原声互动-直播间观看', description: '直播间观看' },
{ id: 'AD_NATIVE_PAY', name: 'AD_NATIVE_PAY', label: '原声互动-付费', description: '原声互动付费' },
{ id: 'AD_PRODUCT_ACTIVATE', name: 'AD_PRODUCT_ACTIVATE', label: '商品-激活', description: '商品激活' },
{ id: 'AD_PRODUCT_APP_BUY', name: 'AD_PRODUCT_APP_BUY', label: '商品-app内下单', description: '商品app内下单' },
{ id: 'AD_PRODUCT_APP_DETAIL', name: 'AD_PRODUCT_APP_DETAIL', label: '商品-app内详情页到站uv', description: '商品app内详情页到站uv' },
{ id: 'AD_PRODUCT_APP_PAY', name: 'AD_PRODUCT_APP_PAY', label: '商品-app内付费', description: '商品app内付费' },
{ id: 'AD_PRODUCT_APP_VIEW', name: 'AD_PRODUCT_APP_VIEW', label: '商品-app内访问', description: '商品app内访问' },
{ id: 'AD_PRODUCT_FORM', name: 'AD_PRODUCT_FORM', label: '商品-表单提交', description: '商品表单提交' },
{ id: 'AD_PRODUCT_KEY_BEHAVIOR', name: 'AD_PRODUCT_KEY_BEHAVIOR', label: '商品-关键行为', description: '商品关键行为' },
{ id: 'AD_PRODUCT_PAY', name: 'AD_PRODUCT_PAY', label: '商品-付费', description: '商品付费' },
{ id: 'AD_TINYAPP_ACTIVATE', name: 'AD_TINYAPP_ACTIVATE', label: '小程序-激活', description: '小程序激活' },
{ id: 'AD_TINYAPP_KEY_BEHAVIOR', name: 'AD_TINYAPP_KEY_BEHAVIOR', label: '小程序-关键行为', description: '小程序关键行为' },
{ id: 'AD_TINYAPP_PAY', name: 'AD_TINYAPP_PAY', label: '小程序-付费', description: '小程序付费' },
{ id: 'QC_LIVE_BUY', name: 'QC_LIVE_BUY', label: '直播投放-直播间下单', description: '直播间下单' },
{ id: 'QC_LIVE_CHECK', name: 'QC_LIVE_CHECK', label: '直播投放-直播间结算', description: '直播间结算' },
{ id: 'QC_LIVE_COMMENTS', name: 'QC_LIVE_COMMENTS', label: '直播投放-直播间评论', description: '直播间评论' },
{ id: 'QC_LIVE_DEAL', name: 'QC_LIVE_DEAL', label: '直播投放-直播间成交', description: '直播间成交' },
{ id: 'QC_LIVE_ENTRY', name: 'QC_LIVE_ENTRY', label: '直播投放-进入直播间', description: '进入直播间' },
{ id: 'QC_LIVE_FANS', name: 'QC_LIVE_FANS', label: '直播投放-直播间粉丝提升', description: '直播间粉丝提升' },
{ id: 'QC_LIVE_HIT', name: 'QC_LIVE_HIT', label: '直播投放-直播加热', description: '直播加热' },
{ id: 'QC_LIVE_PRODUCT_CLICKS', name: 'QC_LIVE_PRODUCT_CLICKS', label: '直播投放-直播间商品点击', description: '直播间商品点击' },
{ id: 'QC_LIVE_ROI_CHECK', name: 'QC_LIVE_ROI_CHECK', label: '直播投放-结算roi', description: '结算roi' },
{ id: 'QC_LIVE_ROI_DEAL', name: 'QC_LIVE_ROI_DEAL', label: '直播投放-支付roi-直播间成交', description: '支付roi直播间成交' },
{ id: 'QC_LIVE_ROI_QC', name: 'QC_LIVE_ROI_QC', label: '直播投放-支付roi-千川直接+间接订单', description: '支付roi千川订单' },
{ id: 'QC_PRODUCT_BUY', name: 'QC_PRODUCT_BUY', label: '商品投放-商品购买', description: '商品购买' },
{ id: 'QC_PRODUCT_COMMENTS', name: 'QC_PRODUCT_COMMENTS', label: '商品投放-点赞评论', description: '点赞评论' },
{ id: 'QC_PRODUCT_FANS', name: 'QC_PRODUCT_FANS', label: '商品投放-粉丝提升', description: '粉丝提升' },
{ id: 'QC_PRODUCT_INTEREST', name: 'QC_PRODUCT_INTEREST', label: '商品投放-人群种草', description: '人群种草' },
{ id: 'QC_PRODUCT_QC', name: 'QC_PRODUCT_QC', label: '商品投放-千川直接+间接订单', description: '千川订单' },
{ id: 'QC_PRODUCT_ROI', name: 'QC_PRODUCT_ROI', label: '商品投放-商品支付roi', description: '商品支付roi' },
];
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
width: 70,
render: (text: number) => <Typography.Text style={{ color: '#94a3b8', fontSize: 13 }}>{text}</Typography.Text>,
},
{
title: '前测模板ID',
dataIndex: 'id',
key: 'id',
ellipsis: true,
width: 100,
width: 110,
render: (text: string) => <Typography.Text strong style={{ color: '#1e293b', fontSize: 13 }}>{text}</Typography.Text>,
},
{
title: '模板名称',
dataIndex: 'templateName',
key: 'templateName',
dataIndex: 'name',
key: 'name',
ellipsis: true,
width: 150,
render: (text: string) => (
<span style={{ color: '#1e293b', fontWeight: 500, fontSize: 13 }}>{text}</span>
),
},
{
title: '选中的字段',
dataIndex: 'selectedFields',
key: 'selectedFields',
render: (fields: string[]) => (
<Space wrap size={6}>
{fields.map((field) => {
const fieldInfo = PRETEST_FIELDS.find(f => f.name === field);
return (
<Tag
key={field}
style={{
background: 'rgba(99,102,241,0.08)',
color: '#6366f1',
border: 'none',
borderRadius: 6,
fontSize: 11,
padding: '2px 8px',
}}
>
{fieldInfo?.label || field}
</Tag>
);
})}
</Space>
title: '平台',
dataIndex: 'platform',
key: 'platform',
render: (text: string) => (
<Tag color={text === 'AD' ? 'blue' : text === 'QIANCHUAN' ? 'green' : 'orange'} style={{ borderRadius: 6, fontSize: 12 }}>
{text === 'AD' ? 'AD' : text === 'QIANCHUAN' ? '千川' : '本地推'}
</Tag>
),
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
title: '转化目标',
dataIndex: 'externalAction',
key: 'externalAction',
ellipsis: true,
width: 200,
render: (text: string) => {
const config = statusConfig[text as keyof typeof statusConfig] || statusConfig.pending;
if (!text) return <span style={{ color: '#94a3b8', fontSize: 13 }}>-</span>;
const actionArray = text.split(',').filter(item => item.trim());
const labels = actionArray.map(action => {
const field = PRETEST_FIELDS.find(f => f.name === action.trim());
return field ? field.label : action;
});
return (
<Tag color={config.color} style={{ borderRadius: 6, fontSize: 12, fontWeight: 500 }}>
{config.label}
</Tag>
<span style={{ color: '#1e293b', fontSize: 13 }}>{labels.join(', ')}</span>
);
},
},
{
title: '目标转化成本',
dataIndex: 'cpaBid',
key: 'cpaBid',
width: 120,
render: (text: number) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{text !== undefined ? text : '-'}</span>
),
},
{
title: '受众性别',
dataIndex: 'audienceGender',
key: 'audienceGender',
width: 90,
render: (text: string) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{text === 'ALL' ? '不限' : text === 'MALE' ? '男' : text === 'FEMALE' ? '女' : text || '-'}</span>
),
},
{
title: '受众年龄',
dataIndex: 'audienceAge',
key: 'audienceAge',
width: 90,
render: (text: string[]) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{Array.isArray(text) ? text.join(', ') : text || '-'}</span>
),
},
{
title: '受众地区',
dataIndex: 'audience_region',
key: 'audience_region',
ellipsis: true,
width: 150,
render: (text: string[]) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{Array.isArray(text) ? text.join(', ') : text || '-'}</span>
),
},
{
title: '网络类型',
dataIndex: 'audienceNetwork',
key: 'audienceNetwork',
width: 90,
render: (text: string[]) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{Array.isArray(text) ? text.join(', ') : text || '-'}</span>
),
},
{
title: '客户主体名称',
dataIndex: 'cusName',
key: 'cusName',
ellipsis: true,
width: 120,
render: (text: string) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{text || '-'}</span>
),
},
{
title: '出价类型',
dataIndex: 'pricingType',
key: 'pricingType',
width: 90,
render: (text: string) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{text || '-'}</span>
),
},
{
title: '目标点击成本',
dataIndex: 'cpcBid',
key: 'cpcBid',
width: 120,
render: (text: number) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{text !== undefined ? text : '-'}</span>
),
},
{
title: '预算金额',
dataIndex: 'budget',
key: 'budget',
width: 100,
render: (text: number) => (
<span style={{ color: '#1e293b', fontSize: 13 }}>{text !== undefined ? text : '-'}</span>
),
},
{
title: '默认模板',
dataIndex: 'isDefault',
key: 'isDefault',
width: 90,
render: (text: boolean) => (
<Tag color={text ? 'green' : 'default'} style={{ borderRadius: 6, fontSize: 12 }}>
{text ? '是' : '否'}
</Tag>
),
},
{
title: '创建时间',
dataIndex: 'createdAt',
@@ -224,6 +296,7 @@ const columns = [
];
const PreTest: React.FC = () => {
const { message } = App.useApp();
const [records, setRecords] = useState<PreTestRecord[]>([]);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
@@ -233,17 +306,25 @@ const PreTest: React.FC = () => {
const [currentPage, setCurrentPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [platform, setPlatform] = useState<string>('AD');
const [areaOptions, setAreaOptions] = useState<any[]>([]);
useEffect(() => {
loadRecords();
}, [currentPage, pageSize]);
useEffect(() => {
loadProvinceOptions();
}, []);
const loadRecords = async () => {
setLoading(true);
try {
const data = await getPreTestList({ page: currentPage, pageSize });
setRecords(data.items || []);
setTotal(data.total || 0);
const res = await getPreTestList({ page: currentPage, pageSize });
console.log(res);
setRecords(res.data || []);
setTotal(res.pagination?.total || 0);
setCurrentPage(res.pagination?.page || 1);
setPageSize(res.pagination?.pageSize || 10);
} catch (error) {
message.error('获取前测列表失败');
} finally {
@@ -251,6 +332,40 @@ const PreTest: React.FC = () => {
}
};
const loadProvinceOptions = async () => {
try {
const res = await getArea({ level: 'ONE_LEVEL' });
const options = (res.data || []).map((item: any) => ({
value: item.code,
label: item.name,
isLeaf: false,
}));
setAreaOptions(options);
} catch (error) {
message.error('获取省份信息失败');
}
};
const loadCityOptions = async (selectedOptions: any) => {
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
try {
const res = await getArea({ level: 'TWO_LEVEL', parent_code: targetOption.value });
targetOption.children = (res.data || []).map((item: any) => ({
value: item.code,
label: item.name,
isLeaf: true,
}));
targetOption.loading = false;
setAreaOptions([...areaOptions]);
} catch (error) {
message.error('获取城市信息失败');
targetOption.loading = false;
setAreaOptions([...areaOptions]);
}
};
const tableData = records.map((item, index) => ({
...item,
index: (currentPage - 1) * pageSize + index + 1,
@@ -273,16 +388,17 @@ const PreTest: React.FC = () => {
try {
const values = await form.validateFields();
setSubmitLoading(true);
const regionCodes = (values.audience_region || []).map((path: string[]) => path[path.length - 1]);
const externalActionStr = (values.external_action || []).join(',');
const result = await createPreTest({
name: values.name,
note: values.note,
platform: values.platform,
external_action: values.external_action,
external_action: externalActionStr,
cpa_bid: values.cpa_bid || 0,
audience_gender: values.audience_gender,
audience_age: values.audience_age || [],
audience_region: values.audience_region || [],
audience_region: regionCodes,
audience_network: values.audience_network || [],
cus_name: values.cus_name,
pricing_type: values.pricing_type,
@@ -298,8 +414,14 @@ const PreTest: React.FC = () => {
setModalOpen(false);
form.resetFields();
loadRecords();
} catch (error) {
message.error('创建失败,请重试');
} catch (error: any) {
if (error?.message) {
message.error(error.message);
} else if (error?.response?.data?.message) {
message.error(error.response.data.message);
} else {
message.error('创建失败,请重试');
}
} finally {
setSubmitLoading(false);
}
@@ -312,10 +434,9 @@ const PreTest: React.FC = () => {
return (
<div style={{ minHeight: 'calc(100vh - 80px)' }}>
<div>
<h1 style={{ lineHeight: '32px', fontSize: 26, fontWeight: 700, color: '#1e293b', marginBottom: 4, marginTop: 0 }}>
</h1>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 12 }}>
<FileTextOutlined style={{ color: '#6366f1', fontSize: 16 }} />
<Typography.Text strong style={{ fontSize: 16 }}></Typography.Text>
</div>
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 12, marginBottom: 16 }}>
<Button
@@ -345,19 +466,9 @@ const PreTest: React.FC = () => {
dataSource={tableData}
columns={columns}
loading={loading}
pagination={{
current: currentPage,
pageSize: pageSize,
total: total,
showSizeChanger: true,
showTotal: (total) => `${total} 条记录`,
pageSizeOptions: ['10', '20', '50', '100'],
onChange: handlePageChange,
style: { padding: '16px 24px', borderTop: '1px solid #f1f5f9' },
}}
pagination={false}
rowKey="id"
bordered={false}
style={{ padding: 0 }}
scroll={{ x: 'max-content' }}
onRow={() => ({
style: {
@@ -372,16 +483,29 @@ const PreTest: React.FC = () => {
},
})}
/>
<div style={{ padding: '16px', textAlign: 'right' }}>
<Pagination
current={currentPage}
pageSize={pageSize}
total={total}
showSizeChanger
showTotal={(total) => `${total} 条记录`}
pageSizeOptions={['10', '20', '50', '100']}
onChange={handlePageChange}
size="small"
/>
</div>
</div>
<Modal
title={<Space><PlusOutlined /></Space>}
title={<Space></Space>}
open={modalOpen}
onCancel={handleCloseModal}
onOk={handleSubmit}
okText="提交"
cancelText="取消"
width={720}
height={600}
confirmLoading={submitLoading}
style={{ borderRadius: 16 }}
>
@@ -400,18 +524,6 @@ const PreTest: React.FC = () => {
style={{ borderRadius: 8, height: 40 }}
/>
</Form.Item>
<Form.Item
name="note"
label="备注"
>
<Input.TextArea
placeholder="请输入备注"
rows={3}
style={{ borderRadius: 8 }}
/>
</Form.Item>
<Form.Item
name="platform"
label="平台"
@@ -434,12 +546,11 @@ const PreTest: React.FC = () => {
<Form.Item
name="external_action"
label="前测字段"
rules={[{ required: true, message: '请选择前测字段' }]}
label="转化目标"
>
<Select
mode="multiple"
placeholder="请选择前测字段(可多选)"
placeholder="请选择转化目标(可多选)"
style={{ borderRadius: 8, minHeight: 40 }}
maxTagCount="responsive"
options={PRETEST_FIELDS.filter(field => {
@@ -473,6 +584,7 @@ const PreTest: React.FC = () => {
rules={[
{ type: 'number', min: 1, max: 10000, message: '取值范围: 1-10000' },
]}
getValueFromEvent={(e) => parseFloat(e.target.value) || undefined}
>
<Input
type="number"
@@ -522,31 +634,24 @@ const PreTest: React.FC = () => {
name="audience_region"
label="受众地区"
>
<Select
mode="multiple"
<Cascader
multiple
placeholder="请选择受众地区(可多选)"
style={{ borderRadius: 8, minHeight: 40 }}
options={areaOptions}
loadData={loadCityOptions}
changeOnSelect
maxTagCount="responsive"
options={[
{ value: 110000, label: '北京市' },
{ value: 310000, label: '上海市' },
{ value: 440000, label: '广东省' },
{ value: 330000, label: '浙江省' },
{ value: 320000, label: '江苏省' },
{ value: 510000, label: '四川省' },
{ value: 420000, label: '湖北省' },
{ value: 370000, label: '山东省' },
]}
/>
</Form.Item>
<Form.Item
name="audience_network"
label="受众网络"
label="网络类型"
>
<Select
mode="multiple"
placeholder="请选择受众网络(可多选)"
placeholder="请选择网络类型(可多选)"
style={{ borderRadius: 8, minHeight: 40 }}
maxTagCount="responsive"
options={[
@@ -562,36 +667,36 @@ const PreTest: React.FC = () => {
<Form.Item
name="cus_name"
label="自定义名称"
label="客户主体名称"
>
<Input
placeholder="请输入自定义名称"
placeholder="请输入客户主体名称"
style={{ borderRadius: 8, height: 40 }}
/>
</Form.Item>
<Form.Item
name="pricing_type"
label="出价类型"
>
<Select
placeholder="请选择出价类型"
style={{ borderRadius: 8, height: 40 }}
options={[
{ value: 'OCPC', label: 'OCPC' },
{ value: 'CPA', label: 'CPA' },
{ value: 'OCPM', label: 'OCPM' },
]}
/>
</Form.Item>
{platform == 'AD' && (
<>
<Form.Item
name="pricing_type"
label="计费方式"
>
<Select
placeholder="请选择计费方式"
style={{ borderRadius: 8, height: 40 }}
options={[
{ value: 'OCPC', label: 'OCPC' },
{ value: 'CPA', label: 'CPA' },
{ value: 'OCPM', label: 'OCPM' },
]}
/>
</Form.Item>
<Form.Item
name="cost_cap"
label="成本上限"
label="是否最优成本出价"
valuePropName="checked"
>
<Select
placeholder="请选择成本上限"
placeholder="是否最优成本出价"
style={{ borderRadius: 8, height: 40 }}
options={[
{ value: true, label: '开启' },
@@ -602,11 +707,11 @@ const PreTest: React.FC = () => {
<Form.Item
name="target_cost"
label="目标成本"
label="是否稳定成本出价"
valuePropName="checked"
>
<Select
placeholder="请选择目标成本"
placeholder="是否稳定成本出价"
style={{ borderRadius: 8, height: 40 }}
options={[
{ value: true, label: '开启' },
@@ -617,11 +722,11 @@ const PreTest: React.FC = () => {
<Form.Item
name="nobid"
label="出价"
label="是否最大转化出价"
valuePropName="checked"
>
<Select
placeholder="请选择无出价"
placeholder="是否最大转化出价"
style={{ borderRadius: 8, height: 40 }}
options={[
{ value: true, label: '开启' },
@@ -631,15 +736,14 @@ const PreTest: React.FC = () => {
</Form.Item>
</>
)}
<Form.Item
name="cpc_bid"
label="CPC出价"
label="目标点击成本"
getValueFromEvent={(e) => parseFloat(e.target.value) || undefined}
>
<Input
type="number"
placeholder="请输入CPC出价"
placeholder="请输入目标点击成本"
style={{ borderRadius: 8, height: 40 }}
/>
</Form.Item>
@@ -647,6 +751,7 @@ const PreTest: React.FC = () => {
<Form.Item
name="budget"
label="预算金额"
getValueFromEvent={(e) => parseFloat(e.target.value) || undefined}
>
<Input
type="number"
@@ -654,7 +759,16 @@ const PreTest: React.FC = () => {
style={{ borderRadius: 8, height: 40 }}
/>
</Form.Item>
<Form.Item
name="note"
label="备注"
>
<Input.TextArea
placeholder="请输入备注"
rows={3}
style={{ borderRadius: 8 }}
/>
</Form.Item>
<Form.Item
name="is_default"
label="默认模板"