From 5f8e2ce93a462b4c9589b4282c1209d63edb1702 Mon Sep 17 00:00:00 2001 From: Lrd <13001933075@sina.cn> Date: Thu, 25 Jun 2026 14:29:20 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=B6=88=E8=80=97=E5=88=97=E8=A1=A8=E5=8F=8A?= =?UTF-8?q?=E8=A1=A8=E5=A4=B4=E6=8E=A5=E5=8F=A3=E5=AF=B9=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- video-gen-admin/src/api/index.ts | 19 +++ video-gen-admin/src/pages/AdminConsume.tsx | 176 ++++++++++++++------- video-gen-app/.env | 2 +- 3 files changed, 143 insertions(+), 54 deletions(-) diff --git a/video-gen-admin/src/api/index.ts b/video-gen-admin/src/api/index.ts index a490f048..e03d4218 100644 --- a/video-gen-admin/src/api/index.ts +++ b/video-gen-admin/src/api/index.ts @@ -624,6 +624,25 @@ export async function uploadImage(file: File): Promise<{ url: string; filename: return { url: data.url, filename: data.filename }; } +// 自定义表头字段 export async function getFields(): Promise { return api.get('/material-consumption/fields'); } + +// 查询素材消耗列表 +export interface MaterialConsumpParams { + advertiser_id?: string; + user_id?: string; + consume_date?: [string, string]; + page?: number; + page_size?: number; +} +export async function getMaterialConsumpList(params: MaterialConsumpParams): Promise { + const query = new URLSearchParams(); + if (params.advertiser_id) query.set('advertiser_id', params.advertiser_id); + if (params.user_id) query.set('user_id', params.user_id); + if (params.consume_date !== undefined) query.set('consume_date', params.consume_date[0] + ',' + params.consume_date[1]); + if (params.page !== undefined) query.set('page', String(params.page)); + if (params.page_size !== undefined) query.set('page_size', String(params.page_size)); + return api.get(`/material-consumption/admin/list?${query.toString()}`); +} \ No newline at end of file diff --git a/video-gen-admin/src/pages/AdminConsume.tsx b/video-gen-admin/src/pages/AdminConsume.tsx index c7593f02..706cc612 100644 --- a/video-gen-admin/src/pages/AdminConsume.tsx +++ b/video-gen-admin/src/pages/AdminConsume.tsx @@ -1,67 +1,81 @@ import React, { useState, useEffect } from 'react'; -import { Card, Space, Table, Button, Typography, Modal, Checkbox, Input, message } from 'antd'; -import { ArrowLeftOutlined, DollarOutlined, SettingOutlined } from '@ant-design/icons'; +import { Card, Space, Table, Button, Typography, Modal, Checkbox, Input, message, DatePicker } from 'antd'; +import { ArrowLeftOutlined, DollarOutlined, SettingOutlined, SearchOutlined, ReloadOutlined } from '@ant-design/icons'; import { useNavigate } from 'react-router-dom'; +import { getFields, getMaterialConsumpList } from '../api'; +import dayjs from 'dayjs'; -// 表头字段模拟数据 -const mockColumnsData = [ - { name: 'id', description: 'id' }, - { name: 'star_id', description: '星图ID' }, - { name: 'demand_id', description: '任务ID' }, - { name: 'demand_name', description: '任务名称' }, - { name: 'demander_name', description: '客户名称' }, - { name: 'brand', description: '品牌' }, - { name: 'max_publish_count', description: '最大发布数量' }, - { name: 'product_name', description: '产品名称' }, - { name: 'product_information', description: '产品信息' }, -]; +const { RangePicker } = DatePicker; + +const toCamelCase = (str: string) => str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase()); interface ConsumptionRecord { id: string; - star_id?: string; - demand_id?: string; - demand_name?: string; - demander_name?: string; - brand?: string; - max_publish_count?: number; - product_name?: string; - product_information?: string; + advertiser_id?: string; + user_id?: string; + consume_date?: string; + [key: string]: any; } -const mockConsumptionRecords: ConsumptionRecord[] = [ - { id: 'C001', star_id: 'ST001', demand_id: 'DM001', demand_name: '产品推广任务', demander_name: 'XX品牌方', brand: 'XX品牌', max_publish_count: 10, product_name: 'XX产品', product_information: '产品信息描述' }, - { id: 'C002', star_id: 'ST002', demand_id: 'DM002', demand_name: '新品发布任务', demander_name: 'YY品牌方', brand: 'YY品牌', max_publish_count: 5, product_name: 'YY产品', product_information: '新品信息描述' }, - { id: 'C003', star_id: 'ST003', demand_id: 'DM003', demand_name: '品牌宣传任务', demander_name: 'ZZ品牌方', brand: 'ZZ品牌', max_publish_count: 8, product_name: 'ZZ产品', product_information: '品牌信息描述' }, - { id: 'C004', star_id: 'ST001', demand_id: 'DM004', demand_name: '活动促销任务', demander_name: 'XX品牌方', brand: 'XX品牌', max_publish_count: 15, product_name: 'XX活动产品', product_information: '活动产品信息' }, - { id: 'C005', star_id: 'ST004', demand_id: 'DM005', demand_name: '节日营销任务', demander_name: 'AA品牌方', brand: 'AA品牌', max_publish_count: 20, product_name: 'AA节日产品', product_information: '节日产品信息' }, -]; - const ConsumePage: React.FC = () => { const navigate = useNavigate(); - const [consumptionRecords, setConsumptionRecords] = useState(mockConsumptionRecords); + const [consumptionRecords, setConsumptionRecords] = useState([]); + const [total, setTotal] = useState(0); const [loading, setLoading] = useState(false); const [showModal, setShowModal] = useState(false); const [columnsData, setColumnsData] = useState<{ name: string; description: string }[]>([]); const [selectedColumns, setSelectedColumns] = useState([]); const [searchText, setSearchText] = useState(''); + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [advertiserId, setAdvertiserId] = useState(''); + const [userId, setUserId] = useState(''); + const [consumeDateRange, setConsumeDateRange] = useState<[string, string] | undefined>(); useEffect(() => { - setLoading(true); - setTimeout(() => { - setConsumptionRecords(mockConsumptionRecords); - setLoading(false); - }, 500); + loadColumns(); + loadData(); + }, [page, pageSize]); - setTimeout(() => { - setColumnsData(mockColumnsData); + const loadData = async () => { + setLoading(true); + try { + const res = await getMaterialConsumpList({ + advertiser_id: advertiserId || undefined, + user_id: userId || undefined, + consume_date: consumeDateRange, + page, + page_size: pageSize, + }); + console.log(res); + setConsumptionRecords(res.data || []); + setTotal(res.pagination?.total || 0); + } catch (e: any) { + message.error('加载数据失败'); + } finally { + setLoading(false); + } + }; + + const loadColumns = async () => { + try { + const res = await getFields(); + const fields = res.data || []; + const formattedFields = fields.map((item: { field: string; description: string }) => ({ + name: toCamelCase(item.field), + description: item.description, + })); + setColumnsData(formattedFields); const saved = localStorage.getItem('consumeColumns'); if (saved) { setSelectedColumns(JSON.parse(saved)); } else { - setSelectedColumns(mockColumnsData.map(item => item.name)); + setSelectedColumns(formattedFields.map((item: { name: string }) => item.name)); } - }, 300); - }, []); + } catch (e: any) { + message.error('加载表头字段失败'); + } + }; const tableData = consumptionRecords.map((item, index) => ({ ...item, @@ -73,8 +87,22 @@ const ConsumePage: React.FC = () => { navigate('/authorization'); }; - const dynamicColumns = columnsData - .filter(col => selectedColumns.includes(col.name)) + const handleSearch = () => { + setPage(1); + loadData(); + }; + + const handleReset = () => { + setAdvertiserId(''); + setUserId(''); + setConsumeDateRange(undefined); + setPage(1); + loadData(); + }; + + const dynamicColumns = selectedColumns + .map(colName => columnsData.find(col => col.name === colName)) + .filter((col): col is { name: string; description: string } => !!col) .map(col => ({ title: col.description, dataIndex: col.name, @@ -84,7 +112,7 @@ const ConsumePage: React.FC = () => { return (
- +
@@ -95,6 +123,34 @@ const ConsumePage: React.FC = () => {
+
+ + setAdvertiserId(e.target.value)} + style={{ width: 200 }} + /> + setUserId(e.target.value)} + style={{ width: 200 }} + /> + { + if (dates && dates[0] && dates[1]) { + setConsumeDateRange([dates[0].format('YYYY-MM-DD'), dates[1].format('YYYY-MM-DD')]); + } else { + setConsumeDateRange(undefined); + } + }} + /> + + + +
{ bordered={false} scroll={{ x: 'max-content' }} pagination={{ - pageSize: 10, - total: consumptionRecords.length, + current: page, + pageSize, + total, showSizeChanger: true, showTotal: (t) => `共 ${t} 条记录`, size: 'small', + onChange: (p, ps) => { + setPage(p); + setPageSize(ps); + }, }} /> - { okText="确定" cancelText="取消" width={800} - bodyStyle={{ padding: 16 }} >
setSearchText(e.target.value)} style={{ marginBottom: 8 }} /> @@ -197,11 +257,21 @@ const ConsumePage: React.FC = () => {