“历史素材”

This commit is contained in:
sjy
2026-07-11 11:35:18 +08:00
6 changed files with 476 additions and 451 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -28,7 +28,7 @@
}
})();
</script>
<script type="module" crossorigin src="/assets/index-B8KgQUTE.js"></script>
<script type="module" crossorigin src="/assets/index-BRGpXFCL.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-JhRVnnL-.css">
</head>
<body>
@@ -0,0 +1,186 @@
import React from 'react';
import { Button, DatePicker, Input, Space } from 'antd';
import {
CheckOutlined,
ClearOutlined,
DeleteOutlined,
DownloadOutlined,
SearchOutlined,
UploadOutlined,
} from '@ant-design/icons';
import type { Dayjs } from 'dayjs';
interface UnifiedFilterBarProps {
// 搜索
searchValue: string;
searchPlaceholder?: string;
onSearchChange: (value: string) => void;
onSearch: () => void;
// 日期
showDate?: boolean;
dateValue?: Dayjs | null;
onDateChange?: (date: Dayjs | null) => void;
datePlaceholder?: string;
// 批量操作
batchCount: number;
totalCount: number;
onSelectAll: () => void;
onClearSelection: () => void;
onDelete: () => void;
onDownload?: () => void;
onPush?: () => void;
pushLoading?: boolean;
pushText?: string;
// 右侧额外操作
extraActions?: React.ReactNode;
}
const btnBase: React.CSSProperties = {
borderRadius: 8,
fontWeight: 600,
height: 36,
};
const btnSecondary: React.CSSProperties = {
...btnBase,
background: '#f8f9fc',
border: '1px solid #e2e8f0',
color: '#334155',
};
const btnDanger: React.CSSProperties = {
...btnBase,
background: 'linear-gradient(135deg, #ef4444, #dc2626)',
border: 'none',
color: '#fff',
};
const btnPrimary: React.CSSProperties = {
...btnBase,
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
border: 'none',
color: '#fff',
};
const UnifiedFilterBar: React.FC<UnifiedFilterBarProps> = ({
searchValue,
searchPlaceholder = '搜索...',
onSearchChange,
onSearch,
showDate = false,
dateValue,
onDateChange,
datePlaceholder = '选择日期',
batchCount,
totalCount,
onSelectAll,
onClearSelection,
onDelete,
onDownload,
onPush,
pushLoading = false,
pushText = '推送至账户',
extraActions,
}) => {
const allSelected = batchCount === totalCount && totalCount > 0;
return (
<div
style={{
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-between',
alignItems: 'center',
gap: 12,
marginBottom: 16,
padding: '12px 16px',
borderRadius: 12,
background: '#fff',
border: '1px solid #f0f0f5',
}}
>
{/* 左侧:搜索 + 日期 */}
<Space size={8} wrap>
<Input.Search
placeholder={searchPlaceholder}
allowClear
value={searchValue}
onChange={(e) => {
const val = e.target.value;
onSearchChange(val);
if (!val) onSearch();
}}
onSearch={onSearch}
style={{ width: 240, borderRadius: 8 }}
enterButton
/>
{showDate && (
<>
<DatePicker
value={dateValue || undefined}
onChange={(date) => onDateChange?.(date)}
format="YYYY-MM-DD"
placeholder={datePlaceholder}
style={{ width: 160, borderRadius: 8 }}
allowClear
/>
</>
)}
</Space>
{/* 右侧:批量操作 + 额外操作 */}
<Space size={8} wrap>
{/* 全选 / 取消选择 */}
<Button
icon={allSelected ? <ClearOutlined /> : <CheckOutlined />}
onClick={allSelected ? onClearSelection : onSelectAll}
style={btnSecondary}
>
{allSelected ? '取消全选' : '全选'}
</Button>
{/* 删除 */}
<Button
danger
icon={<DeleteOutlined />}
onClick={onDelete}
disabled={batchCount === 0}
style={batchCount === 0 ? { ...btnSecondary, opacity: 0.5 } : btnDanger}
>
{batchCount > 0 && `(${batchCount})`}
</Button>
{/* 下载 */}
{onDownload && (
<Button
icon={<DownloadOutlined />}
onClick={onDownload}
disabled={batchCount === 0}
style={batchCount === 0 ? { ...btnSecondary, opacity: 0.5 } : btnPrimary}
>
{batchCount > 0 && `(${batchCount})`}
</Button>
)}
{/* 推送 */}
{onPush && (
<Button
type="primary"
icon={<UploadOutlined />}
onClick={onPush}
loading={pushLoading}
disabled={batchCount === 0}
style={batchCount === 0 ? { ...btnBase, opacity: 0.5 } : btnPrimary}
>
{pushLoading ? '推送中...' : `${pushText} ${batchCount > 0 ? `(${batchCount})` : ''}`}
</Button>
)}
{/* 额外操作按钮 */}
{extraActions}
</Space>
</div>
);
};
export default UnifiedFilterBar;
+28 -7
View File
@@ -7,6 +7,9 @@ import dayjs from 'dayjs';
const { RangePicker } = DatePicker;
// 统一按钮样式
const btnBase: React.CSSProperties = { borderRadius: 8, fontWeight: 600 };
const toCamelCase = (str: string) => str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
interface ConsumptionRecord {
@@ -164,13 +167,24 @@ const ConsumePage: React.FC = () => {
<Typography.Text strong style={{ fontSize: 16 }}></Typography.Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, marginBottom: 16 }}>
<div style={{ display: 'flex', gap: 12 }}>
<div style={{
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-between',
alignItems: 'center',
gap: 12,
marginBottom: 16,
padding: '12px 16px',
borderRadius: 12,
background: '#fff',
border: '1px solid #f0f0f5',
}}>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<Input
placeholder="广告主ID"
value={advertiserId}
onChange={(e) => setAdvertiserId(e.target.value)}
style={{ width: 180 }}
style={{ width: 180, borderRadius: 8 }}
allowClear
onPressEnter={() => { setCurrentPage(1); loadData(1, pageSize); }}
/>
@@ -183,25 +197,32 @@ const ConsumePage: React.FC = () => {
setConsumeDateRange(undefined);
}
}}
style={{ borderRadius: 8 }}
/>
<Button
type="primary"
size="medium"
onClick={handleSearch}
style={{ ...btnBase, borderColor: 'transparent' }}
>
</Button>
</div>
<div style={{ display: 'flex', gap: 12 }}>
<div style={{ display: 'flex', gap: 8 }}>
<Button
icon={<SyncOutlined />}
onClick={handleSync}
loading={syncLoading}
style={{ borderRadius: 8 }}
style={btnBase}
>
</Button>
<Button icon={<SettingOutlined />} onClick={() => setShowModal(true)} style={{ borderRadius: 8 }}></Button>
<Button
icon={<SettingOutlined />}
onClick={() => setShowModal(true)}
style={{ ...btnBase, background: '#f8f9fc', border: '1px solid #e2e8f0', color: '#334155' }}
>
</Button>
</div>
</div>
+137 -318
View File
@@ -17,6 +17,8 @@ import {
DeleteOutlined,
LoadingOutlined,
UserOutlined,
CheckOutlined,
ClearOutlined,
} from '@ant-design/icons';
import { useSearchParams } from 'react-router-dom';
import { PrivatePortraitLibraryPanel } from '../components/privatePortrait';
@@ -909,225 +911,86 @@ const GeneratedRecord: React.FC = () => {
}, [filterType, filterMedia]);
return (
<div className="content_box" >
{/* 操作栏:筛选 + 推送按钮 */}
{/* 顶部:标签切换 + 批量操作按钮 */}
<div style={{
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-between',
alignItems: 'center',
gap: 12,
marginBottom: 16,
padding: '12px 16px',
borderRadius: 12,
background: '#fff',
border: '1px solid #f0f0f5',
justifyContent: 'space-between',
marginBottom: 12,
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: 4, flexWrap: 'wrap' }}>
<FilterOutlined style={{ color: '#090a0cff', fontSize: 14 }} />
<Space size={8} wrap={true}>
<Button
type={filterType === 'project' ? 'primary' : 'default'}
onClick={() => {
setFilterType('project');
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: filterType === 'project'
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
: '#f8f9fc',
border: filterType === 'project' ? 'none' : '1px solid #e2e8f0',
color: filterType === 'project' ? '#fff' : '#64748b',
fontWeight: 600,
}}
icon={<FolderOpenOutlined />}
>
</Button>
<Button
type={filterType === 'creation' ? 'primary' : 'default'}
onClick={() => {
setFilterType('creation');
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: filterType === 'creation'
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
: '#f8f9fc',
border: filterType === 'creation' ? 'none' : '1px solid #e2e8f0',
color: filterType === 'creation' ? '#fff' : '#64748b',
fontWeight: 600,
}}
icon={<FileTextOutlined />}
>
</Button>
<Button
type={filterType === 'hot_opening_replicate' ? 'primary' : 'default'}
onClick={() => {
setFilterType('hot_opening_replicate');
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: filterType === 'hot_opening_replicate'
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
: '#f8f9fc',
border: filterType === 'hot_opening_replicate' ? 'none' : '1px solid #e2e8f0',
color: filterType === 'hot_opening_replicate' ? '#fff' : '#64748b',
fontWeight: 600,
}}
icon={<StarOutlined />}
>
</Button>
<Button
type={filterType === 'shot_replicate' ? 'primary' : 'default'}
onClick={() => {
setFilterType('shot_replicate');
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: filterType === 'shot_replicate'
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
: '#f8f9fc',
border: filterType === 'shot_replicate' ? 'none' : '1px solid #e2e8f0',
color: filterType === 'shot_replicate' ? '#fff' : '#64748b',
fontWeight: 600,
}}
icon={<PlayCircleOutlined />}
>
</Button>
<Button
type={filterType === 'private_portrait' ? 'primary' : 'default'}
onClick={() => {
setFilterType('private_portrait');
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: filterType === 'private_portrait'
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
: '#f8f9fc',
border: filterType === 'private_portrait' ? 'none' : '1px solid #e2e8f0',
color: filterType === 'private_portrait' ? '#fff' : '#64748b',
fontWeight: 600,
}}
icon={<UserOutlined />}
>
</Button>
<Button
type={filterType === 'upload_resource' ? 'primary' : 'default'}
onClick={() => {
setFilterType('upload_resource');
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: filterType === 'upload_resource'
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
: '#f8f9fc',
border: filterType === 'upload_resource' ? 'none' : '1px solid #e2e8f0',
color: filterType === 'upload_resource' ? '#fff' : '#64748b',
fontWeight: 600,
}}
icon={<UploadOutlined />}
>
</Button>
</Space>
</div>
<Tabs
activeKey={filterType}
onChange={(key) => {
setFilterType(key as typeof filterType);
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
items={[
{ key: 'project', label: <span><FolderOpenOutlined /> </span> },
{ key: 'creation', label: <span><FileTextOutlined /> </span> },
{ key: 'hot_opening_replicate', label: <span><StarOutlined /> </span> },
{ key: 'shot_replicate', label: <span><PlayCircleOutlined /> </span> },
{ key: 'private_portrait', label: <span><UserOutlined /> </span> },
{ key: 'upload_resource', label: <span><UploadOutlined /> </span> },
]}
size="middle"
/>
{filterType !== 'private_portrait' && filterType !== 'upload_resource' && (
<div style={{ display: 'flex', alignItems: 'center', gap: 4, flexWrap: 'wrap' }}>
{/* 多选模式按钮 */}
{isSelectionMode ? (
<Space size={8} wrap={true}>
<Button
onClick={handleSelectAll}
style={{
borderRadius: 8,
background: '#f8f9fc',
border: '1px solid #e2e8f0',
color: '#222222ff',
fontWeight: 600,
}}
>
{selectedItems.size === recordlist.reduce((sum: number, group: any) => sum + group.items.length, 0) ? '取消全选' : '全选'}
</Button>
<Button
onClick={() => {
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: '#f8f9fc',
border: '1px solid #e2e8f0',
color: '#64748b',
fontWeight: 600,
}}
>
</Button>
<Button
onClick={() => handleDeleteSelected()}
style={{ borderRadius: 8, background: 'linear-gradient(135deg, #bf0b0a 0%, #ff8165 100%)', fontWeight: 600, padding: '8px 24px', color: '#fff' }}
>
({selectedItems.size})
</Button>
<Button
onClick={() => handleDownloadSelected()}
style={{
borderRadius: 8,
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
color: '#fff',
fontWeight: 600,
}}
>
({selectedItems.size})
</Button>
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
{isSelectionMode ? (
<Space size={8}>
<Button
icon={selectedItems.size === recordlist.reduce((sum: number, group: any) => sum + group.items.length, 0) && recordlist.length > 0 ? <ClearOutlined /> : <CheckOutlined />}
onClick={selectedItems.size === recordlist.reduce((sum: number, group: any) => sum + group.items.length, 0) && recordlist.length > 0 ? () => { setSelectedItems(new Set()); } : handleSelectAll}
style={{ borderRadius: 8, fontWeight: 600, background: '#f8f9fc', border: '1px solid #e2e8f0', color: '#334155' }}
>
{selectedItems.size === recordlist.reduce((sum: number, group: any) => sum + group.items.length, 0) && recordlist.length > 0 ? '取消全选' : '全选'}
</Button>
<Button
onClick={() => { setIsSelectionMode(false); setSelectedItems(new Set()); }}
style={{ borderRadius: 8, fontWeight: 600, background: '#f8f9fc', border: '1px solid #e2e8f0', color: '#64748b' }}
>
</Button>
<Button
danger
icon={<DeleteOutlined />}
onClick={handleDeleteSelected}
style={{ borderRadius: 8, fontWeight: 600, background: 'linear-gradient(135deg, #ef4444, #dc2626)', border: 'none', color: '#fff' }}
>
{selectedItems.size > 0 && `(${selectedItems.size})`}
</Button>
<Button
icon={<DownloadOutlined />}
onClick={handleDownloadSelected}
style={{ borderRadius: 8, fontWeight: 600, background: 'linear-gradient(135deg, #6366f1, #8b5cf6)', border: 'none', color: '#fff' }}
>
{selectedItems.size > 0 && `(${selectedItems.size})`}
</Button>
<Button
type="primary"
icon={<UploadOutlined />}
onClick={handleBatchUploadSelected}
loading={uploading}
disabled={uploading || selectedItems.size === 0}
style={{ borderRadius: 8, fontWeight: 600, background: 'linear-gradient(135deg, #6366f1, #8b5cf6)', border: 'none', color: '#fff' }}
>
{uploading ? '推送中...' : `推送至账户 ${selectedItems.size > 0 ? `(${selectedItems.size})` : ''}`}
</Button>
</Space>
) : (
<Button
type="primary"
onClick={handleBatchUploadSelected}
loading={uploading}
disabled={uploading || selectedItems.size === 0}
style={{
borderRadius: 8,
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
color: '#fff',
fontWeight: 600,
}}
icon={<UploadOutlined />}
onClick={() => setIsSelectionMode(true)}
style={{ borderRadius: 8, fontWeight: 600, background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', border: 'none' }}
>
{uploading ? '推送中...' : `推送至账户 (${selectedItems.size})`}
</Button>
</Space>
) : (
<Button
type="primary"
icon={<UploadOutlined />}
onClick={() => setIsSelectionMode(true)}
style={{
borderRadius: 8,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none',
fontWeight: 600,
}}
>
</Button>
)}
</div>
)}
</div>
)}
</div>
{filterType === 'private_portrait' ? (
@@ -1136,122 +999,75 @@ const GeneratedRecord: React.FC = () => {
<UploadResourceHistoryPanel />
) : (
<>
{/* Second row filter: 视频 / 图片 */}
{/* 统一筛选栏:搜索 + 日期 */}
<div style={{
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-between',
alignItems: 'center',
gap: 12,
marginBottom: 24,
marginBottom: 16,
padding: '12px 16px',
borderRadius: 12,
background: '#fff',
border: '1px solid #f0f0f5',
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
<Typography.Text style={{ color: '#94a3b8', fontSize: 14 }}></Typography.Text>
<Space size={8} wrap={true}>
<Button
type={filterMedia === 'video' ? 'primary' : 'default'}
onClick={() => {
setFilterMedia('video');
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: filterMedia === 'video'
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
: '#f8f9fc',
border: filterMedia === 'video' ? 'none' : '1px solid #e2e8f0',
color: filterMedia === 'video' ? '#fff' : '#64748b',
fontWeight: 600,
}}
icon={<VideoCameraOutlined />}
>
</Button>
<Button
type={filterMedia === 'image' ? 'primary' : 'default'}
onClick={() => {
setFilterMedia('image');
setIsSelectionMode(false);
setSelectedItems(new Set());
}}
style={{
borderRadius: 8,
background: filterMedia === 'image'
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
: '#f8f9fc',
border: filterMedia === 'image' ? 'none' : '1px solid #e2e8f0',
color: filterMedia === 'image' ? '#fff' : '#64748b',
fontWeight: 600,
}}
icon={<PictureOutlined />}
>
</Button>
<DatePicker
picker="date"
value={selectedDate ? dayjs(selectedDate) : undefined}
onChange={(date, dateString) => handleDateChange(dateString || '')}
format="YYYY-MM-DD"
style={{ width: 160, borderRadius: 8, border: '1px solid #e2e8f0' }}
placeholder="选择日期"
/>
{selectedDate && (
<Button
type="text"
onClick={() => handleDateChange('')}
style={{ color: '#94a3b8', fontSize: 12 }}
>
</Button>
)}
<Input.Search
placeholder="搜索提示词"
allowClear
value={searchKeyword}
onChange={(e) => {
const val = e.target.value;
setSearchKeyword(val);
if (!val) {
setPagebreak(prev => ({ ...prev, page: 1 }));
loadRecordList();
}
}}
onSearch={() => {
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<Typography.Text style={{ color: '#94a3b8', fontSize: 14, marginRight: 4 }}></Typography.Text>
<Button
type={filterMedia === 'video' ? 'primary' : 'default'}
onClick={() => { setFilterMedia('video'); setIsSelectionMode(false); setSelectedItems(new Set()); }}
style={{ borderRadius: 8, fontWeight: 600, borderColor: filterMedia === 'video' ? 'transparent' : '#e2e8f0', color: filterMedia === 'video' ? '#fff' : '#64748b' }}
icon={<VideoCameraOutlined />}
>
</Button>
<Button
type={filterMedia === 'image' ? 'primary' : 'default'}
onClick={() => { setFilterMedia('image'); setIsSelectionMode(false); setSelectedItems(new Set()); }}
style={{ borderRadius: 8, fontWeight: 600, borderColor: filterMedia === 'image' ? 'transparent' : '#e2e8f0', color: filterMedia === 'image' ? '#fff' : '#64748b' }}
icon={<PictureOutlined />}
>
</Button>
</div>
<Space size={8} wrap>
<DatePicker
picker="date"
value={selectedDate ? dayjs(selectedDate) : undefined}
onChange={(date, dateString) => handleDateChange(dateString || '')}
format="YYYY-MM-DD"
style={{ width: 160, borderRadius: 8, border: '1px solid #e2e8f0' }}
placeholder="选择日期"
allowClear
/>
<Input.Search
placeholder="搜索提示词"
allowClear
value={searchKeyword}
onChange={(e) => {
const val = e.target.value;
setSearchKeyword(val);
if (!val) {
setPagebreak(prev => ({ ...prev, page: 1 }));
loadRecordList();
}}
style={{ width: 240, borderRadius: 8 }}
/>
</Space>
</div>
<Button
icon={<ClockCircleOutlined />}
onClick={handleOpenUploadHistory}
style={{
borderRadius: 8,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none',
color: '#ffffff',
fontWeight: 600,
boxShadow: '0 4px 15px rgba(102, 126, 234, 0.4)',
transition: 'all 0.3s ease',
}}
onMouseEnter={(e) => {
e.currentTarget.style.transform = 'translateY(-2px)';
e.currentTarget.style.boxShadow = '0 6px 20px rgba(102, 126, 234, 0.6)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.transform = 'translateY(0)';
e.currentTarget.style.boxShadow = '0 4px 15px rgba(102, 126, 234, 0.4)';
}}
>
</Button>
}
}}
onSearch={() => {
setPagebreak(prev => ({ ...prev, page: 1 }));
loadRecordList();
}}
style={{ width: 240, borderRadius: 8 }}
enterButton
/>
<Button
icon={<ClockCircleOutlined />}
onClick={handleOpenUploadHistory}
style={{ borderRadius: 8, fontWeight: 600, background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', border: 'none', color: '#fff' }}
>
</Button>
</Space>
</div>
{/* Content area */}
{loading ? (
@@ -1408,18 +1224,20 @@ const GeneratedRecord: React.FC = () => {
<div
style={{
position: 'absolute',
top: 8,
left: 8,
width: 20,
height: 20,
top: 6,
left: 6,
width: 22,
height: 22,
borderRadius: '50%',
backgroundColor: isSelectedItem ? '#10b981' : 'rgba(255,255,255,0.9)',
border: isSelectedItem ? '2px solid #10b981' : '2px solid #d1d5db',
backgroundColor: isSelectedItem ? '#6366f1' : 'rgba(255,255,255,0.92)',
border: isSelectedItem ? '2px solid #6366f1' : '2px solid #cbd5e1',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
zIndex: 10,
boxShadow: isSelectedItem ? '0 2px 8px rgba(99,102,241,0.4)' : '0 1px 3px rgba(0,0,0,0.1)',
transition: 'all 0.15s ease',
}}
onClick={(e) => {
e.stopPropagation();
@@ -1517,10 +1335,11 @@ const GeneratedRecord: React.FC = () => {
left: 0,
right: 0,
bottom: 0,
border: '3px solid #10b981',
border: '3px solid #6366f1',
borderRadius: 4,
pointerEvents: 'none',
zIndex: 5,
boxShadow: 'inset 0 0 0 1px rgba(99,102,241,0.2)',
}} />
)}
</div>
+23 -24
View File
@@ -383,13 +383,24 @@ const MaterialListPage: React.FC = () => {
<FolderOpenOutlined style={{ color: '#6366f1', fontSize: 16 }} />
<Typography.Text strong style={{ fontSize: 16 }}></Typography.Text>
</div>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'top', marginBottom: 16 }}>
<div style={{ display: 'flex', gap: 16, alignItems: 'center', flexWrap: 'wrap' }}>
<div style={{
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-between',
alignItems: 'center',
gap: 12,
marginBottom: 16,
padding: '12px 16px',
borderRadius: 12,
background: '#fff',
border: '1px solid #f0f0f5',
}}>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<Input
placeholder="广告主ID"
value={searchParams.advertiser_id}
onChange={(e) => setSearchParams(prev => ({ ...prev, advertiser_id: e.target.value }))}
style={{ width: 160 }}
style={{ width: 150, borderRadius: 8 }}
allowClear
onPressEnter={() => { setCurrentPage(1); loadMaterialList(1, pageSize); }}
/>
@@ -397,7 +408,7 @@ const MaterialListPage: React.FC = () => {
placeholder="素材ID"
value={searchParams.material_id}
onChange={(e) => setSearchParams(prev => ({ ...prev, material_id: e.target.value }))}
style={{ width: 160 }}
style={{ width: 150, borderRadius: 8 }}
allowClear
onPressEnter={() => { setCurrentPage(1); loadMaterialList(1, pageSize); }}
/>
@@ -405,7 +416,7 @@ const MaterialListPage: React.FC = () => {
placeholder="上传ID"
value={searchParams.upload_id}
onChange={(e) => setSearchParams(prev => ({ ...prev, upload_id: e.target.value }))}
style={{ width: 160 }}
style={{ width: 150, borderRadius: 8 }}
allowClear
onPressEnter={() => { setCurrentPage(1); loadMaterialList(1, pageSize); }}
/>
@@ -413,7 +424,7 @@ const MaterialListPage: React.FC = () => {
placeholder="文件名"
value={searchParams.file_name}
onChange={(e) => setSearchParams(prev => ({ ...prev, file_name: e.target.value }))}
style={{ width: 140 }}
style={{ width: 140, borderRadius: 8 }}
allowClear
onPressEnter={() => { setCurrentPage(1); loadMaterialList(1, pageSize); }}
/>
@@ -421,7 +432,7 @@ const MaterialListPage: React.FC = () => {
placeholder="资源类型"
value={searchParams.resource_type}
onChange={(value) => setSearchParams(prev => ({ ...prev, resource_type: value }))}
style={{ width: 120 }}
style={{ width: 110, borderRadius: 8 }}
allowClear
options={[
{ value: 'image', label: '图片' },
@@ -431,21 +442,16 @@ const MaterialListPage: React.FC = () => {
<Button
type="primary"
onClick={() => { setCurrentPage(1); loadMaterialList(1, pageSize); }}
style={{ borderRadius: 8, fontWeight: 600, borderColor: 'transparent' }}
>
</Button>
</div>
<div style={{ display: 'flex', gap: 12 }}>
<div style={{ display: 'flex', gap: 8 }}>
<Button
icon={<RobotOutlined />}
onClick={() => navigate('/generated?filterType=private_portrait&portraitTab=aigc_virtual')}
style={{
borderRadius: 12,
fontSize: 14,
borderColor: '#8b5cf6',
color: '#7c3aed',
background: '#f5f3ff',
}}
style={{ borderRadius: 8, fontWeight: 600, borderColor: '#8b5cf6', color: '#7c3aed', background: '#f5f3ff' }}
>
</Button>
@@ -454,16 +460,9 @@ const MaterialListPage: React.FC = () => {
loading={pushTemplatesLoading}
onClick={handleOpenPushModal}
disabled={selectedRows.size === 0}
style={{
borderRadius: 12,
fontSize: 14,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none',
color: '#fff',
boxShadow: '0 4px 14px rgba(99,102,241,0.3)',
}}
style={{ borderRadius: 8, fontWeight: 600, background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)', border: 'none', color: '#fff' }}
>
({selectedRows.size})
{selectedRows.size > 0 && `(${selectedRows.size})`}
</Button>
</div>
</div>