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}
/>