diff --git a/video-gen-admin/dist/index.html b/video-gen-admin/dist/index.html index 7a38c2e4..071987f3 100644 --- a/video-gen-admin/dist/index.html +++ b/video-gen-admin/dist/index.html @@ -1,37 +1,37 @@ - - - - - - - - - - 后台管理 - + + + + + + + + + + 后台管理 + - - -
- - + + +
+ + diff --git a/video-gen-admin/src/api/index.ts b/video-gen-admin/src/api/index.ts index b4f64473..b32559e2 100644 --- a/video-gen-admin/src/api/index.ts +++ b/video-gen-admin/src/api/index.ts @@ -932,3 +932,55 @@ export async function regenerateHomeMaterialWatermark(id: string, payload: HomeM export async function deleteHomeMaterialAsset(id: string): Promise { await api.delete(`/admin/home-material/assets/${id}`); } + +export interface OAuthAccountParams { + id?: string; + phone?: string; + account_id?: string; + account_userid?: string; + created_at?: [string, string]; + appid?: string; + open_type?: number; + page?: number; + page_size?: number; +} +export async function getOAuthAccountList(params: OAuthAccountParams): Promise { + const query = new URLSearchParams(); + if (params.id) query.set('id', params.id); + if (params.phone) query.set('phone', params.phone); + if (params.account_id) query.set('account_id', params.account_id); + if (params.account_userid) query.set('account_userid', params.account_userid); + if (params.created_at !== undefined) query.set('created_at', params.created_at[0] + ',' + params.created_at[1]); + if (params.appid) query.set('appid', params.appid); + if (params.open_type !== undefined) query.set('open_type', String(params.open_type)); + 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-admin/oauth-list?${query.toString()}`); +} + +export interface MaterialListParams { + id?: string; + phone?: string; + resource_type?: string; + advertiser_id?: string; + material_id?: string; + upload_id?: string; + created_at?: [string, string]; + status?: string; + page?: number; + page_size?: number; +} +export async function getMaterialList(params: MaterialListParams): Promise { + const query = new URLSearchParams(); + if (params.id) query.set('id', params.id); + if (params.phone) query.set('phone', params.phone); + if (params.resource_type) query.set('resource_type', params.resource_type); + if (params.advertiser_id) query.set('advertiser_id', params.advertiser_id); + if (params.material_id) query.set('material_id', params.material_id); + if (params.upload_id) query.set('upload_id', params.upload_id); + if (params.created_at !== undefined) query.set('created_at', params.created_at[0] + ',' + params.created_at[1]); + if (params.status) query.set('status', params.status); + 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-admin/material-list?${query.toString()}`); +} \ No newline at end of file diff --git a/video-gen-admin/src/pages/AdminMaterialList.tsx b/video-gen-admin/src/pages/AdminMaterialList.tsx index 86b0a6e7..8394d224 100644 --- a/video-gen-admin/src/pages/AdminMaterialList.tsx +++ b/video-gen-admin/src/pages/AdminMaterialList.tsx @@ -1,6 +1,18 @@ import React, { useEffect, useState } from 'react'; import { Button, Input, Select, Table, Pagination, Tag, Typography } from 'antd'; import { FileTextOutlined, SearchOutlined } from '@ant-design/icons'; +import { getMaterialList } from '../api'; +const formatDateTime = (dateStr: string) => { + if (!dateStr) return ''; + const date = new Date(dateStr); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +}; const { Text } = Typography; @@ -12,7 +24,6 @@ const AdminMaterialList: React.FC = () => { const [total, setTotal] = useState(0); const [searchMaterialId, setSearchMaterialId] = useState(''); const [searchUploadId, setSearchUploadId] = useState(''); - const [searchFileName, setSearchFileName] = useState(''); const [searchResourceType, setSearchResourceType] = useState(''); const columns = [ @@ -23,6 +34,56 @@ const AdminMaterialList: React.FC = () => { width: 60, render: (text: number) => {text}, }, + { + title: 'ID', + dataIndex: 'id', + key: 'id', + }, + { + title: '广告主账户ID', + dataIndex: 'advertiserId', + key: 'advertiserId', + }, + { + title: '备注', + dataIndex: 'note', + key: 'note', + }, + { + title: '授权ID', + dataIndex: 'oauthId', + key: 'oauthId', + }, + { + title: '预测试结果', + dataIndex: 'preResult', + key: 'preResult', + }, + { + title: '预测试模板ID', + dataIndex: 'preTestTemplateId', + key: 'preTestTemplateId', + }, + { + title: '目标标ID', + dataIndex: 'targetId', + key: 'targetId', + }, + { + title: '目标表', + dataIndex: 'targetTable', + key: 'targetTable', + }, + { + title: '任务ID', + dataIndex: 'taskId', + key: 'taskId', + }, + { + title: '用户ID', + dataIndex: 'userId', + key: 'userId', + }, { title: '素材ID', dataIndex: 'materialId', @@ -35,12 +96,6 @@ const AdminMaterialList: React.FC = () => { key: 'uploadId', width: 160, }, - { - title: '文件名', - dataIndex: 'fileName', - key: 'fileName', - width: 200, - }, { title: '资源类型', dataIndex: 'resourceType', @@ -63,41 +118,40 @@ const AdminMaterialList: React.FC = () => { ), }, - { - title: '文件大小', - dataIndex: 'fileSize', - key: 'fileSize', - width: 120, - render: (text: string) => {text}, - }, { title: '创建时间', dataIndex: 'createdAt', key: 'createdAt', width: 180, - render: (text: string) => {text}, + render: (text: string) => { formatDateTime(text)}, + }, + + { + title: '更新时间', + dataIndex: 'updatedAt', + key: 'updatedAt', + width: 180, + render: (text: string) => { formatDateTime(text)}, }, ]; const loadMaterialList = async () => { setLoading(true); try { - const mockData = { - items: Array.from({ length: pageSize }, (_, i) => ({ - id: `${currentPage}-${i}`, - index: (currentPage - 1) * pageSize + i + 1, - materialId: `MAT-${(currentPage - 1) * pageSize + i + 1}`, - uploadId: `UP-${(currentPage - 1) * pageSize + i + 1}`, - fileName: `file_${(currentPage - 1) * pageSize + i + 1}.mp4`, - resourceType: ['video', 'image'][i % 2], - status: ['SUCCESS', 'PENDING', 'FAILED'][i % 3], - fileSize: `${(Math.random() * 50 + 10).toFixed(1)} MB`, - createdAt: '2026-07-01 10:00:00', - })), - total: 120, - }; - setTableData(mockData.items); - setTotal(mockData.total); + const res = await getMaterialList({ + material_id: searchMaterialId || undefined, + upload_id: searchUploadId || undefined, + resource_type: searchResourceType || undefined, + page: currentPage, + page_size: pageSize, + }); + const data = res.items || []; + const tableData = data.map((item: any, index: number) => ({ + ...item, + index: (currentPage - 1) * pageSize + index + 1, + })); + setTableData(tableData); + setTotal(res.total || 0); } catch (error) { console.error('加载数据失败:', error); } finally { @@ -140,8 +194,8 @@ const AdminMaterialList: React.FC = () => { /> setSearchFileName(e.target.value)} + value={searchResourceType} + onChange={(e) => setSearchResourceType(e.target.value)} style={{ width: 140 }} allowClear onPressEnter={handleSearch} diff --git a/video-gen-admin/src/pages/AdminOAuthList.tsx b/video-gen-admin/src/pages/AdminOAuthList.tsx index 7540185b..31762135 100644 --- a/video-gen-admin/src/pages/AdminOAuthList.tsx +++ b/video-gen-admin/src/pages/AdminOAuthList.tsx @@ -1,7 +1,18 @@ import React, { useEffect, useState } from 'react'; import { Button, Input, Select, Table, Pagination, Tag, Typography } from 'antd'; import { LockOutlined, SearchOutlined } from '@ant-design/icons'; - +import { getOAuthAccountList, getOpenTypeAll } from '../api'; +const formatDateTime = (dateStr: string) => { + if (!dateStr) return ''; + const date = new Date(dateStr); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +}; const { Text } = Typography; const AdminOAuthList: React.FC = () => { @@ -12,13 +23,9 @@ const AdminOAuthList: React.FC = () => { const [total, setTotal] = useState(0); const [searchAccountId, setSearchAccountId] = useState(''); const [searchUserId, setSearchUserId] = useState(''); - const [searchOpenType, setSearchOpenType] = useState(''); - - const openTypeOptions = [ - { value: 'AD', label: 'AD' }, - { value: 'QIANCHUAN', label: '千川' }, - { value: 'LOCAL', label: '本地推' }, - ]; + const [openTypeMap, setOpenTypeMap] = useState>({}); + const [openTypeOptions, setOpenTypeOptions] = useState<{ value: number; label: string }[]>([]); + const [searchOpenType, setSearchOpenType] = useState(undefined); const columns = [ { @@ -28,74 +35,168 @@ const AdminOAuthList: React.FC = () => { width: 60, render: (text: number) => {text}, }, + { + title: 'ID', + dataIndex: 'id', + key: 'id', + }, + { + title: '前台用户ID', + dataIndex: 'userId', + key: 'userId', + }, + { + title: '前台用户手机号', + dataIndex: 'userPhone', + key: 'userPhone', + }, + { + title: '授权应用ID', + dataIndex: 'appid', + key: 'appid', + }, { title: '授权绑定账户ID', dataIndex: 'accountId', key: 'accountId', - width: 180, + }, + { + title: '授权绑定账户名称', + dataIndex: 'accountName', + key: 'accountName', + }, + { + title: '授权绑定账户角色', + dataIndex: 'accountRole', + key: 'accountRole', + render: (role: string) => { + const roleMap: Record = { + ADVERTISER: '客户', + CUSTOMER_ADMIN: '普通版工作台-管理员', + CUSTOMER_OPERATOR: '普通版工作台-协作者', + AGENT: '代理商', + CHILD_AGENT: '二级代理商', + PLATFORM_ROLE_STAR: '星图账户', + PLATFORM_ROLE_SHOP_ACCOUNT: '抖音店铺账户', + PLATFORM_ROLE_QIANCHUAN_AGENT: '千川代理商', + PLATFORM_ROLE_STAR_AGENT: '星图代理商', + PLATFORM_ROLE_AWEME: '抖音号', + PLATFORM_ROLE_STAR_MCN: '星图MCN机构', + PLATFORM_ROLE_STAR_ISV: '星图服务商', + AGENT_SYSTEM_ACCOUNT: '代理商系统账户', + PLATFORM_ROLE_LOCAL_AGENT: '本地推代理商', + PLATFORM_ROLE_YUNTU_BRAND_ISV_ADMIN: '云图品牌服务商管理员', + PLATFORM_ROLE_LIFE: '抖音来客账户', + PLATFORM_ROLE_ENTERPRISE_BP_ADMIN: '升级版工作台管理员', + PLATFORM_ROLE_ENTERPRISE_BP_OPERATOR: '升级版工作台协作者', + }; + return roleMap[role] || role; + }, }, { title: '授权登录账户用户ID', - dataIndex: 'accountUserId', - key: 'accountUserId', - width: 180, + dataIndex: 'accountUserid', + key: 'accountUserid', + }, + { + title: '授权登录账户用户名', + dataIndex: 'accountUsername', + key: 'accountUsername', }, { title: '开户方式', dataIndex: 'openType', key: 'openType', width: 120, - render: (text: string) => ( - - {text === 'AD' ? 'AD' : text === 'QIANCHUAN' ? '千川' : '本地推'} - - ), + render: (text: number) => {openTypeMap[text] || text}, }, { - title: '状态', - dataIndex: 'status', - key: 'status', - width: 100, - render: (text: string) => ( - - {text === 'active' ? '有效' : '失效'} - - ), + title: '平台端口', + dataIndex: 'portType', + key: 'portType', + render: (role: string) => { + const roleMap: Record = { + 1: '巨量', + 2: '磁力', + 3: '巨量星图', + 4: '服务单', + 5: '腾讯', + }; + return roleMap[role] || role; + }, + // 1=巨量,2=磁力,3=巨量星图,4=服务单,5=腾讯 + // render: (text: number) => {text}, + }, + { + title: '授权刷新Token', + dataIndex: 'refreshToken', + key: 'refreshToken', + }, + { + title: '刷新Token过期时间', + dataIndex: 'refreshTokenExpired', + key: 'refreshTokenExpired', + render: (text: string) => {formatDateTime(text)}, + }, + { + title: '授权Token', + dataIndex: 'accessToken', + key: 'accessToken', + }, + { + title: 'Token过期时间', + dataIndex: 'accessTokenExpired', + key: 'accessTokenExpired', + render: (text: string) => {formatDateTime(text)}, }, { title: '创建时间', dataIndex: 'createdAt', key: 'createdAt', width: 180, - render: (text: string) => {text}, + render: (text: string) => {formatDateTime(text)}, }, { title: '更新时间', dataIndex: 'updatedAt', key: 'updatedAt', width: 180, - render: (text: string) => {text}, + render: (text: string) => {formatDateTime(text)}, }, ]; - + const loadOpenTypeList = async () => { + try { + const res = await getOpenTypeAll(); + const data = res.data || []; + const map: Record = {}; + const options: { value: number; label: string }[] = []; + data.forEach(item => { + map[item.openType] = item.typeName; + options.push({ value: item.openType, label: item.typeName }); + }); + setOpenTypeMap(map); + setOpenTypeOptions(options); + } catch (error) { + console.error('加载开户方式列表失败:', error); + } + }; const loadOAuthList = async () => { setLoading(true); try { - const mockData = { - items: Array.from({ length: pageSize }, (_, i) => ({ - id: `${currentPage}-${i}`, - index: (currentPage - 1) * pageSize + i + 1, - accountId: `ACC-${(currentPage - 1) * pageSize + i + 1}`, - accountUserId: `USER-${(currentPage - 1) * pageSize + i + 1}`, - openType: ['AD', 'QIANCHUAN', 'LOCAL'][i % 3], - status: i % 6 === 0 ? 'inactive' : 'active', - createdAt: '2026-07-01 10:00:00', - updatedAt: '2026-07-02 14:30:00', - })), - total: 80, - }; - setTableData(mockData.items); - setTotal(mockData.total); + const res = await getOAuthAccountList({ + account_id: searchAccountId || undefined, + account_userid: searchUserId || undefined, + open_type: searchOpenType, + page: currentPage, + page_size: pageSize, + }); + const data = res.data || []; + const tableData = data.map((item: any, index: number) => ({ + ...item, + index: (currentPage - 1) * pageSize + index + 1, + })); + setTableData(tableData); + setTotal(res.pagination?.total || 0); } catch (error) { console.error('加载数据失败:', error); } finally { @@ -104,6 +205,7 @@ const AdminOAuthList: React.FC = () => { }; useEffect(() => { + loadOpenTypeList(); loadOAuthList(); }, [currentPage, pageSize]); @@ -126,6 +228,7 @@ const AdminOAuthList: React.FC = () => { onChange={(e) => setSearchAccountId(e.target.value)} style={{ width: 180 }} allowClear + prefix={} onPressEnter={handleSearch} /> { onChange={(e) => setSearchUserId(e.target.value)} style={{ width: 180 }} allowClear + prefix={} onPressEnter={handleSearch} />