素材云添加视频图片占位符,对接授权应用接口
This commit is contained in:
@@ -137,16 +137,16 @@ const AdminOauthAppList: React.FC = () => {
|
||||
|
||||
useEffect(() => { load(); }, []);
|
||||
const columns = [
|
||||
{ title: 'ID', dataIndex: 'id',
|
||||
{ title: 'ID', dataIndex: 'id', width: 120,
|
||||
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
||||
},
|
||||
{ title: '应用ID', dataIndex: 'appId',
|
||||
{ title: '应用ID', dataIndex: 'appId', width: 120,
|
||||
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
||||
},
|
||||
{ title: '应用密钥', dataIndex: 'secret',
|
||||
{ title: '应用密钥', dataIndex: 'secret', width: 120,
|
||||
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
||||
},
|
||||
{ title: '开户方式', dataIndex: 'openType',
|
||||
{ title: '开户方式', dataIndex: 'openType', width: 90,
|
||||
render: (v: number) => {
|
||||
const typeMap: Record<number, string> = {
|
||||
1: '千川', 2: '广告', 3: '本地推', 4: '星图', 5: '快手代理商',
|
||||
@@ -155,29 +155,29 @@ const AdminOauthAppList: React.FC = () => {
|
||||
return <Typography.Text>{typeMap[v] || v}</Typography.Text>;
|
||||
},
|
||||
},
|
||||
{ title: '归属公司', dataIndex: 'company',
|
||||
{ title: '归属公司', dataIndex: 'company', width: 120,
|
||||
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
||||
},
|
||||
|
||||
{ title: '授权次数', dataIndex: 'count',
|
||||
{ title: '授权次数', dataIndex: 'maxCount', width: 90,
|
||||
render: (v: number) => <Typography.Text>{v}</Typography.Text>,
|
||||
},
|
||||
{ title: '状态', dataIndex: 'status',
|
||||
{ title: '状态', dataIndex: 'status', width: 80,
|
||||
render: (v: number) => <Tag color={v === 1 ? 'green' : 'red'}>{v === 1 ? '正常' : '禁用'}</Tag>,
|
||||
},
|
||||
{ title: '授权URL', dataIndex: 'authUrl',
|
||||
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
||||
},
|
||||
{ title: '创建人', dataIndex: 'createBy',
|
||||
{ title: '授权URL', dataIndex: 'authUrl', width: 180,
|
||||
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
||||
},
|
||||
{ title: '创建时间', dataIndex: 'createdAt',
|
||||
{ title: '创建人', dataIndex: 'createBy', width: 120,
|
||||
render: (v: string) => <Typography.Text>{v}</Typography.Text>,
|
||||
},
|
||||
// { title: '创建时间', dataIndex: 'createdAt', width: 160,
|
||||
// render: (v: string) => <Typography.Text>{formatDate(v)}</Typography.Text>,
|
||||
// },
|
||||
{ title: '更新时间', dataIndex: 'updatedAt', width: 160,
|
||||
render: (v: string) => <Typography.Text>{formatDate(v)}</Typography.Text>,
|
||||
},
|
||||
{ title: '更新时间', dataIndex: 'updatedAt',
|
||||
render: (v: string) => <Typography.Text>{formatDate(v)}</Typography.Text>,
|
||||
},
|
||||
{ title: '操作',
|
||||
{ title: '操作', width: 120, fixed: 'right' as const,
|
||||
render: (_: any, record: OAuthApp) => (
|
||||
<Space>
|
||||
<Button
|
||||
@@ -226,7 +226,7 @@ const AdminOauthAppList: React.FC = () => {
|
||||
showTotal: (t) => `共 ${t} 条记录`,
|
||||
onChange: (p) => { setPage(p); load(p); },
|
||||
}}
|
||||
scroll={{ x: 800 }}
|
||||
scroll={{ x: 'max-content' }}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
|
||||
@@ -259,6 +259,15 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-fadeInUp {
|
||||
animation: fadeInUp 0.45s ease-out both;
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ const AuthorizationPage: React.FC = () => {
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: '授权账户ID',
|
||||
title: '授权绑定账户ID',
|
||||
dataIndex: 'accountId',
|
||||
key: 'accountId',
|
||||
},
|
||||
@@ -210,7 +210,7 @@ const AuthorizationPage: React.FC = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '授权账户用户ID',
|
||||
title: '授权登录账户用户ID',
|
||||
dataIndex: 'accountUserid',
|
||||
key: 'accountUserid',
|
||||
render: (text: string) => <span style={{ color: text ? '#1e293b' : '#94a3b8' }}>{text || '-'}</span>,
|
||||
@@ -293,8 +293,16 @@ const AuthorizationPage: React.FC = () => {
|
||||
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12, marginBottom: 16 }}>
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<Input
|
||||
placeholder="授权绑定账户ID"
|
||||
value={searchParams.account_id}
|
||||
onChange={(e) => setSearchParams(prev => ({ ...prev, account_id: e.target.value }))}
|
||||
style={{ width: 180 }}
|
||||
allowClear
|
||||
onPressEnter={() => { setCurrentPage(1); loadOAuthList(1, pageSize); }}
|
||||
/>
|
||||
<Input
|
||||
placeholder="账号用户ID"
|
||||
placeholder="授权登录账户用户ID"
|
||||
value={searchParams.account_userid}
|
||||
onChange={(e) => setSearchParams(prev => ({ ...prev, account_userid: e.target.value }))}
|
||||
style={{ width: 180 }}
|
||||
@@ -309,14 +317,6 @@ const AuthorizationPage: React.FC = () => {
|
||||
allowClear
|
||||
options={openTypeOptions}
|
||||
/>
|
||||
<Input
|
||||
placeholder="账号ID"
|
||||
value={searchParams.account_id}
|
||||
onChange={(e) => setSearchParams(prev => ({ ...prev, account_id: e.target.value }))}
|
||||
style={{ width: 180 }}
|
||||
allowClear
|
||||
onPressEnter={() => { setCurrentPage(1); loadOAuthList(1, pageSize); }}
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
size="medium"
|
||||
|
||||
@@ -77,6 +77,7 @@ const GeneratedRecord: React.FC = () => {
|
||||
const [selectedOauthItems, setSelectedOauthItems] = useState<({ value: string; label: string } | undefined)[]>([undefined]);
|
||||
const [materialFileNames, setMaterialFileNames] = useState<Map<string, string>>(new Map());
|
||||
const [unifiedFileName, setUnifiedFileName] = useState('');
|
||||
const [mediaLoadStatus, setMediaLoadStatus] = useState<Map<string, 'loading' | 'loaded' | 'error'>>(new Map());
|
||||
const updateFilenameDebounceRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
@@ -1247,15 +1248,63 @@ const GeneratedRecord: React.FC = () => {
|
||||
}}
|
||||
>
|
||||
{showImage ? (
|
||||
<img
|
||||
src={displayUrl}
|
||||
alt="预览"
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
}}
|
||||
/>
|
||||
<div style={{ width: '100%', height: '100%', position: 'relative' }}>
|
||||
<img
|
||||
src={displayUrl}
|
||||
alt="预览"
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
opacity: mediaLoadStatus.get(getItemResourceId(item)) === 'loaded' ? 1 : 0,
|
||||
transition: 'opacity 0.3s',
|
||||
}}
|
||||
onLoad={() => {
|
||||
setMediaLoadStatus(prev => {
|
||||
const newMap = new Map(prev);
|
||||
newMap.set(getItemResourceId(item), 'loaded');
|
||||
return newMap;
|
||||
});
|
||||
}}
|
||||
onError={() => {
|
||||
setMediaLoadStatus(prev => {
|
||||
const newMap = new Map(prev);
|
||||
newMap.set(getItemResourceId(item), 'error');
|
||||
return newMap;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{mediaLoadStatus.get(getItemResourceId(item)) !== 'loaded' && (
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: 'linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%)',
|
||||
}}>
|
||||
<div style={{
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#cbd5e1',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
animation: mediaLoadStatus.get(getItemResourceId(item)) === 'loading' ? 'pulse 1.5s infinite' : 'none',
|
||||
}}>
|
||||
{item.mediaType === 'video' ? (
|
||||
<VideoCameraOutlined style={{ color: '#64748b', fontSize: 16 }} />
|
||||
) : (
|
||||
<PictureOutlined style={{ color: '#64748b', fontSize: 16 }} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{
|
||||
width: '100%',
|
||||
@@ -1377,6 +1426,7 @@ const GeneratedRecord: React.FC = () => {
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
{isSelectionMode && isSelectedItem && (
|
||||
<div style={{
|
||||
position: 'absolute',
|
||||
|
||||
Reference in New Issue
Block a user