解决冲突

This commit is contained in:
Lrd
2026-06-30 14:48:30 +08:00
18 changed files with 2212 additions and 838 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+37 -37
View File
@@ -1,37 +1,37 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<title>民众智创</title>
<script>
(function() {
var cached = localStorage.getItem('siteInfo');
if (cached) {
try {
var info = JSON.parse(cached);
if (info.siteName) {
document.title = info.siteName;
}
if (info.siteLogo) {
var link = document.querySelector('link[rel="icon"]');
if (link) {
link.href = info.siteLogo;
link.type = 'image/png';
}
}
} catch (e) {}
}
})();
</script>
<script type="module" crossorigin src="/assets/index-BVNhLxFb.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D3IaMBsq.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<title>民众智创</title>
<script>
(function() {
var cached = localStorage.getItem('siteInfo');
if (cached) {
try {
var info = JSON.parse(cached);
if (info.siteName) {
document.title = info.siteName;
}
if (info.siteLogo) {
var link = document.querySelector('link[rel="icon"]');
if (link) {
link.href = info.siteLogo;
link.type = 'image/png';
}
}
} catch (e) {}
}
})();
</script>
<script type="module" crossorigin src="/assets/index-B2ULZowz.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BhPFzWLH.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
+12
View File
@@ -27,6 +27,18 @@ const MOCK_USER: User = {
username: 'videomaker',
email: 'demo@videogen.ai',
credits: 2680,
resourceCapacity: {
enabled: true,
source: 'user',
hasUserConfig: true,
usedBytes: 298161654,
availableBytes: 300349549066,
totalBytes: 300647710720,
usagePercent: 0.1,
exceeded: false,
limitValue: '280.000',
limitUnit: 'GB',
},
};
const MOCK_CREDIT_RECORDS: CreditRecord[] = [
@@ -61,10 +61,146 @@ import {
} from '@ant-design/icons';
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
import { useAuthStore } from '../../store/useAuthStore';
import { getMenuConfigs, getRechargePackages, getPaymentMethods, createRechargeOrder, getPaymentOrder, cancelPaymentOrder, getSiteInfo, getUnreadCount, createContactRequest } from '../../api';
import { getMenuConfigs, getRechargePackages, getPaymentMethods, createRechargeOrder, getPaymentOrder, cancelPaymentOrder, getSiteInfo, getUnreadCount, createContactRequest, getUser } from '../../api';
import NotificationPopup from '../NotificationPopup';
import './AppLayout.css';
// ── ResourceCapacity 类型(与 src/types/index.ts 保持一致) ──
type ResourceCapacityData = {
enabled: boolean;
usedBytes: number;
totalBytes: number;
availableBytes: number;
usagePercent: number;
exceeded: boolean;
limitValue: string;
limitUnit: string;
};
/**
* 资源存储展示卡片
* - enabled === true:显示「已用 / 总额」+ 进度条(超额时变红并提示)
* - enabled === false:按 usedBytes 大小自动选 KB / MB / GB / TB 单位显示「当前使用」
*/
const StorageCard: React.FC<{ data: ResourceCapacityData | null }> = ({ data }) => {
if (!data) return null;
// 单位:后端返回的 limitUnitKB / MB / GB
const unit = (data.limitUnit || 'GB').toUpperCase();
const divisor = unit === 'GB' ? 1024 ** 3 : unit === 'MB' ? 1024 ** 2 : 1024;
// 百分比(可能 > 100
const rawPercent = Number(data.usagePercent) || 0;
// 进度条宽度最多 100%
const barPercent = Math.min(100, Math.max(0, rawPercent));
// 总额:优先用后端 limitValue,兜底 totalBytes / divisor
const total = data.limitValue
? parseFloat(data.limitValue)
: data.totalBytes / divisor;
// 已用 = 总额 × 百分比 / 100(保证数字与 percent 自洽)
const used = (total * rawPercent) / 100;
// 剩余 = 总额 - 已用
const available = total - used;
// 超额判断
const isOver = data.exceeded || rawPercent >= 100;
// enabled === false 时按 usedBytes 自动选单位
const KB = 1024;
const MB = 1024 ** 2;
const GB = 1024 ** 3;
const TB = 1024 ** 4;
const formatUsedAuto = (bytes: number) => {
const b = Number(bytes) || 0;
if (b >= TB) return { val: (b / TB).toFixed(2), unit: 'TB' };
if (b >= GB) return { val: (b / GB).toFixed(2), unit: 'GB' };
if (b >= MB) return { val: (b / MB).toFixed(2), unit: 'MB' };
return { val: (b / KB).toFixed(2), unit: 'KB' };
};
const usedAuto = formatUsedAuto(data.usedBytes);
return (
<div
style={{
marginTop: 12,
padding: '10px 12px',
borderRadius: 10,
background: 'linear-gradient(135deg, rgba(248, 250, 252, 0.9) 0%, rgba(241, 245, 249, 0.9) 100%)',
border: `1px solid ${isOver ? 'rgba(239, 68, 68, 0.25)' : 'rgba(99, 102, 241, 0.15)'}`,
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.04)',
}}
>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 6,
fontSize: 12,
color: '#475569',
}}
>
<span style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
<DatabaseOutlined style={{ fontSize: 12, color: isOver ? '#ef4444' : '#6366f1' }} />
</span>
{data.enabled ? (
<span style={{ fontWeight: 500, color: isOver ? '#ef4444' : '#1e293b' }}>
{used.toFixed(2)} / {total.toFixed(2)} {unit}
</span>
) : (
<span style={{ fontWeight: 500, color: '#1e293b' }}>
使 {usedAuto.val} {usedAuto.unit}
</span>
)}
</div>
{data.enabled && (
<>
<div
style={{
width: '100%',
height: 6,
background: '#e2e8f0',
borderRadius: 3,
overflow: 'hidden',
}}
>
<div
style={{
width: `${barPercent}%`,
height: '100%',
background: isOver
? 'linear-gradient(90deg, #ef4444, #dc2626)'
: 'linear-gradient(90deg, #6366f1, #8b5cf6)',
borderRadius: 3,
transition: 'width 0.4s ease',
}}
/>
</div>
<div
style={{
marginTop: 4,
display: 'flex',
justifyContent: 'space-between',
fontSize: 11,
color: isOver ? '#ef4444' : '#94a3b8',
}}
>
<span>
{isOver
? `存储超额 · 超用 ${Math.abs(available).toFixed(2)} ${unit}`
: `剩余 ${available.toFixed(2)} ${unit}`}
</span>
<span>{rawPercent.toFixed(1)}%</span>
</div>
</>
)}
</div>
);
};
interface MenuConfig {
id: string;
key?: string;
@@ -186,6 +322,18 @@ const AppLayout: React.FC = () => {
const currentOrderNoRef = useRef<string | null>(null);
const [enabledMethods, setEnabledMethods] = useState<{ alipay: boolean; wechat: boolean }>({ alipay: false, wechat: false });
// 资源存储容量(从 getUser().resource_capacity 获取)
const [resourceCapacity, setResourceCapacity] = useState<{
enabled: boolean;
usedBytes: number;
totalBytes: number;
availableBytes: number;
usagePercent: number;
exceeded: boolean;
limitValue: string;
limitUnit: string;
} | null>(null);
const PENDING_ORDER_KEY = 'pending_payment_order';
useEffect(() => {
@@ -212,6 +360,30 @@ const AppLayout: React.FC = () => {
localStorage.setItem('siteInfo', JSON.stringify({ siteName: name, siteLogo: logo }));
}).catch(() => { });
getUser().then((res: any) => {
// console.log('[Storage] getUser 返回:', res);
const rc = res?.resourceCapacity;
if (rc) {
setResourceCapacity({
enabled: !!rc.enabled,
usedBytes: Number(rc.usedBytes) || 0,
totalBytes: Number(rc.totalBytes) || 0,
availableBytes: Number(rc.availableBytes) || 0,
usagePercent: Number(rc.usagePercent) || 0,
exceeded: !!rc.exceeded,
limitValue: rc.limitValue ?? '',
limitUnit: rc.limitUnit || 'GB',
});
}
// 没数据时不显示
}).catch((err: any) => {
// console.error('[Storage] getUser 失败:', err);
// 接口失败也不显示
});
}, []);
const handleContactMouseDown = (e: React.MouseEvent) => {
@@ -674,6 +846,9 @@ const AppLayout: React.FC = () => {
</div>
</div>
</Dropdown>
{/* 资源存储容量展示(来自 getUser.resourceCapacity */}
<StorageCard data={resourceCapacity} />
</div>
</div>
@@ -768,6 +943,9 @@ const AppLayout: React.FC = () => {
</div>
</div>
{/* 资源存储容量展示(与桌面端共用 StorageCard */}
<StorageCard data={resourceCapacity} />
{topLevelItems.map(item => {
const menuType = item.menu_type ?? item.menuType;
const hasChildren = childMap[item.id] && childMap[item.id].length > 0;
+564 -158
View File
@@ -3,20 +3,26 @@
:root {
--font-sans: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--nav-bg: #f8f9fb;
--nav-surface: rgba(0,0,0,0.02);
--nav-surface: rgba(0, 0, 0, 0.02);
--nav-border: #e5e7eb;
--nav-text: #1f2937;
--nav-text-muted: #6b7280;
--nav-hover: rgba(0,0,0,0.04);
--nav-active: rgba(99,102,241,0.08);
--nav-hover: rgba(0, 0, 0, 0.04);
--nav-active: rgba(99, 102, 241, 0.08);
}
*,
*::before,
*::after { box-sizing: border-box; }
*::after {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html, body {
margin: 0; padding: 0;
html,
body {
margin: 0;
padding: 0;
font-family: var(--font-sans);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -24,23 +30,68 @@ html, body {
color: #1a1a2e;
letter-spacing: -0.01em;
}
#root { min-height: 100vh; }
#root {
min-height: 100vh;
}
/* ── Scrollbar ─────────────────────────── */
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: #9ca3af; }
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #d1d5db;
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: #9ca3af;
}
/* ── Electric Border Animation ─────────── */
@keyframes electric-pulse {
0%, 100% { opacity: 0.4; filter: blur(1px); }
50% { opacity: 1; filter: blur(0); }
0%,
100% {
opacity: 0.4;
filter: blur(1px);
}
50% {
opacity: 1;
filter: blur(0);
}
}
@keyframes electric-flow {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.content_box {
margin: -24px -32px -32px;
border-radius: 0 0 16px 16px;
height: calc(100vh - 34px);
overflow: auto;
scrollbar-width: none;
padding: 20px;
}
.electric-border-card {
@@ -51,16 +102,14 @@ html, body {
position: absolute;
inset: -2px;
border-radius: 16px;
background: linear-gradient(
90deg,
#6366f1,
#8b5cf6,
#a855f7,
#6366f1,
#8b5cf6,
#a855f7,
#6366f1
);
background: linear-gradient(90deg,
#6366f1,
#8b5cf6,
#a855f7,
#6366f1,
#8b5cf6,
#a855f7,
#6366f1);
background-size: 300% 100%;
animation: electric-flow 3s linear infinite, electric-pulse 2s ease-in-out infinite;
z-index: 0;
@@ -85,6 +134,7 @@ html, body {
0% {
background-position: -200% center;
}
100% {
background-position: 200% center;
}
@@ -97,16 +147,14 @@ html, body {
.shiny-text {
font-size: 24px;
font-weight: 700;
background: linear-gradient(
90deg,
#6366f1 0%,
#8b5cf6 20%,
#a855f7 40%,
#c084fc 50%,
#a855f7 60%,
#8b5cf6 80%,
#6366f1 100%
);
background: linear-gradient(90deg,
#6366f1 0%,
#8b5cf6 20%,
#a855f7 40%,
#c084fc 50%,
#a855f7 60%,
#8b5cf6 80%,
#6366f1 100%);
background-size: 200% auto;
-webkit-background-clip: text;
background-clip: text;
@@ -118,92 +166,225 @@ html, body {
/* ── Keyframe Animations ───────────────── */
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInLeft {
from { opacity: 0; transform: translateX(-20px); }
to { opacity: 1; transform: translateX(0); }
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes fadeInRight {
from { opacity: 0; transform: translateX(20px); }
to { opacity: 1; transform: translateX(0); }
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes float1 {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(20px, -30px) scale(1.05); }
0%,
100% {
transform: translate(0, 0) scale(1);
}
50% {
transform: translate(20px, -30px) scale(1.05);
}
}
@keyframes float2 {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(-15px, 20px) scale(0.95); }
0%,
100% {
transform: translate(0, 0) scale(1);
}
50% {
transform: translate(-15px, 20px) scale(0.95);
}
}
@keyframes float3 {
0%, 100% { transform: translate(0, 0) rotate(0deg); }
50% { transform: translate(10px, -15px) rotate(3deg); }
0%,
100% {
transform: translate(0, 0) rotate(0deg);
}
50% {
transform: translate(10px, -15px) rotate(3deg);
}
}
@keyframes slideInCard {
from { opacity: 0; transform: translateY(14px) scale(0.97); }
to { opacity: 1; transform: translateY(0) scale(1); }
from {
opacity: 0;
transform: translateY(14px) scale(0.97);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes spinSlow {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.animate-fadeInUp { animation: fadeInUp 0.45s ease-out both; }
.animate-fadeInLeft { animation: fadeInLeft 0.55s ease-out both; }
.animate-fadeInRight { animation: fadeInRight 0.55s ease-out both; }
.animate-slideInCard { animation: slideInCard 0.4s ease-out both; }
.animate-float1 { animation: float1 8s ease-in-out infinite; }
.animate-float2 { animation: float2 10s ease-in-out infinite; }
.animate-float3 { animation: float3 12s ease-in-out infinite; }
.animate-fadeInUp {
animation: fadeInUp 0.45s ease-out both;
}
.ref-thumb:hover .ref-delete { opacity: 1 !important; }
.animate-fadeInLeft {
animation: fadeInLeft 0.55s ease-out both;
}
.stagger-children > *:nth-child(1) { animation-delay: 0.04s; }
.stagger-children > *:nth-child(2) { animation-delay: 0.10s; }
.stagger-children > *:nth-child(3) { animation-delay: 0.16s; }
.stagger-children > *:nth-child(4) { animation-delay: 0.22s; }
.stagger-children > *:nth-child(5) { animation-delay: 0.28s; }
.stagger-children > *:nth-child(6) { animation-delay: 0.34s; }
.animate-fadeInRight {
animation: fadeInRight 0.55s ease-out both;
}
.animate-slideInCard {
animation: slideInCard 0.4s ease-out both;
}
.animate-float1 {
animation: float1 8s ease-in-out infinite;
}
.animate-float2 {
animation: float2 10s ease-in-out infinite;
}
.animate-float3 {
animation: float3 12s ease-in-out infinite;
}
.ref-thumb:hover .ref-delete {
opacity: 1 !important;
}
.stagger-children>*:nth-child(1) {
animation-delay: 0.04s;
}
.stagger-children>*:nth-child(2) {
animation-delay: 0.10s;
}
.stagger-children>*:nth-child(3) {
animation-delay: 0.16s;
}
.stagger-children>*:nth-child(4) {
animation-delay: 0.22s;
}
.stagger-children>*:nth-child(5) {
animation-delay: 0.28s;
}
.stagger-children>*:nth-child(6) {
animation-delay: 0.34s;
}
/* ── Ant Design Overrides ──────────────── */
.ant-input, .ant-input-affix-wrapper, .ant-select-selector, .ant-input-number {
.ant-input,
.ant-input-affix-wrapper,
.ant-select-selector,
.ant-input-number {
border-radius: 10px !important;
transition: all 0.25s ease !important;
}
.ant-input:focus, .ant-input-affix-wrapper:focus, .ant-input-affix-wrapper-focused,
.ant-input:focus,
.ant-input-affix-wrapper:focus,
.ant-input-affix-wrapper-focused,
.ant-select-focused .ant-select-selector {
box-shadow: 0 0 0 3px rgba(99,102,241,0.12) !important;
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.12) !important;
border-color: #6366f1 !important;
}
.ant-btn {
border-radius: 10px !important;
transition: all 0.25s ease !important;
font-weight: 500 !important;
}
.ant-btn:hover { transform: none; }
.ant-btn:active { transform: translateY(0); }
.ant-card { border-radius: 16px !important; transition: all 0.3s ease !important; }
.ant-modal-content { border-radius: 20px !important; overflow: hidden; }
.ant-tag { font-size: 12px; border-radius: 8px !important; }
.ant-btn:hover {
transform: none;
}
.ant-btn:active {
transform: translateY(0);
}
.ant-card {
border-radius: 16px !important;
transition: all 0.3s ease !important;
}
.ant-modal-content {
border-radius: 20px !important;
overflow: hidden;
}
.ant-tag {
font-size: 12px;
border-radius: 8px !important;
}
/* ── Recharge card hover ───────────────── */
.recharge-card {
transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important;
cursor: pointer;
}
.recharge-card:hover {
transform: translateY(-8px) scale(1.02) !important;
box-shadow: 0 20px 40px rgba(99,102,241,0.15) !important;
box-shadow: 0 20px 40px rgba(99, 102, 241, 0.15) !important;
}
.recharge-card .recharge-price {
transition: all 0.3s ease;
}
.recharge-card:hover .recharge-price {
transform: scale(1.08);
}
.recharge-card .recharge-price { transition: all 0.3s ease; }
.recharge-card:hover .recharge-price { transform: scale(1.08); }
/* ── Homepage tabs ────────────────────── */
.homepage-tabs .ant-tabs-nav {
margin-bottom: 8px !important;
}
.homepage-tabs .ant-tabs-tab {
padding: 8px 16px !important;
font-size: 13px !important;
@@ -211,13 +392,16 @@ html, body {
color: #6b7280 !important;
transition: all 0.25s !important;
}
.homepage-tabs .ant-tabs-tab:hover {
color: #6366f1 !important;
}
.homepage-tabs .ant-tabs-tab-active .ant-tabs-tab-btn {
color: #6366f1 !important;
font-weight: 600 !important;
}
.homepage-tabs .ant-tabs-ink-bar {
background: linear-gradient(90deg, #6366f1, #a855f7) !important;
height: 3px !important;
@@ -230,108 +414,249 @@ html, body {
position: relative;
overflow: visible;
}
.project-card:hover {
transform: translateY(-4px) !important;
box-shadow: 0 16px 40px rgba(99,102,241,0.12) !important;
box-shadow: 0 16px 40px rgba(99, 102, 241, 0.12) !important;
border-color: #6366f1 !important;
}
/* ── Mobile Bottom Nav ─────────────────── */
.mobile-bottom-nav {
display: none;
position: fixed; bottom: 0; left: 0; right: 0; z-index: 200;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 200;
height: 60px;
background: rgba(255,255,255,0.95);
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(24px);
border-top: 1px solid rgba(0,0,0,0.05);
box-shadow: 0 -4px 20px rgba(0,0,0,0.06);
border-top: 1px solid rgba(0, 0, 0, 0.05);
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.06);
}
.mobile-bottom-nav .nav-item {
flex: 1; display: flex; flex-direction: column;
align-items: center; justify-content: center; gap: 2px;
cursor: pointer; transition: all 0.2s;
color: #8b8fa3; font-size: 9px; font-weight: 400;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
cursor: pointer;
transition: all 0.2s;
color: #8b8fa3;
font-size: 9px;
font-weight: 400;
letter-spacing: 0;
}
.mobile-bottom-nav .nav-item.active {
color: #08080c;
}
.mobile-bottom-nav .nav-item .nav-icon {
font-size: 18px; transition: transform 0.2s;
font-size: 18px;
transition: transform 0.2s;
}
.mobile-bottom-nav .nav-item.active .nav-icon {
transform: scale(1.05);
}
/* ── Responsive Breakpoints ────────────── */
@media (max-width: 768px) {
.desktop-sidebar { display: none !important; }
.desktop-content { margin-left: 0 !important; padding: 16px !important; padding-bottom: 80px !important; overflow-x: hidden !important; }
.desktop-sidebar-toggle-zone { display: none !important; }
.mobile-bottom-nav { display: flex !important; }
.desktop-sidebar {
display: none !important;
}
.desktop-content {
margin-left: 0 !important;
padding: 16px !important;
padding-bottom: 80px !important;
overflow-x: hidden !important;
}
.desktop-sidebar-toggle-zone {
display: none !important;
}
.mobile-bottom-nav {
display: flex !important;
}
/* Prevent horizontal overflow globally */
html, body { overflow-x: hidden !important; }
html,
body {
overflow-x: hidden !important;
}
.mobile-hide { display: none !important; }
.mobile-full { width: 100% !important; max-width: 100% !important; }
.mobile-stack { flex-direction: column !important; }
.mobile-p-16 { padding: 16px !important; }
.mobile-gap-12 { gap: 12px !important; }
.mobile-hide {
display: none !important;
}
.mobile-full {
width: 100% !important;
max-width: 100% !important;
}
.mobile-stack {
flex-direction: column !important;
}
.mobile-p-16 {
padding: 16px !important;
}
.mobile-gap-12 {
gap: 12px !important;
}
/* Login page */
.login-page { flex-direction: column !important; }
.login-left { display: none !important; }
.login-right { padding: 24px 16px !important; }
.login-card { width: 100% !important; }
.login-page {
flex-direction: column !important;
}
.login-left {
display: none !important;
}
.login-right {
padding: 24px 16px !important;
}
.login-card {
width: 100% !important;
}
/* Project list */
.project-item { flex-direction: column !important; align-items: flex-start !important; }
.project-item .project-actions { margin-left: 0 !important; margin-top: 12px; width: 100%; justify-content: flex-end; }
.project-item {
flex-direction: column !important;
align-items: flex-start !important;
}
.project-item .project-actions {
margin-left: 0 !important;
margin-top: 12px;
width: 100%;
justify-content: flex-end;
}
/* Generate page header */
.gen-header { flex-direction: column !important; gap: 12px !important; padding: 16px 18px !important; }
.gen-header {
flex-direction: column !important;
gap: 12px !important;
padding: 16px 18px !important;
}
/* Operation flow bar */
.gen-flow-bar { flex-direction: column !important; gap: 14px !important; padding: 16px !important; }
.gen-flow-divider { display: none !important; }
.gen-flow-bar {
flex-direction: column !important;
gap: 14px !important;
padding: 16px !important;
}
.gen-flow-divider {
display: none !important;
}
/* Config form params row */
.gen-form-row { flex-direction: column !important; gap: 0 !important; }
.gen-form-row {
flex-direction: column !important;
gap: 0 !important;
}
/* Credits estimate bar */
.gen-credits-bar { flex-direction: column !important; gap: 8px !important; text-align: center; }
.gen-credits-bar {
flex-direction: column !important;
gap: 8px !important;
text-align: center;
}
/* Prompt rows */
.gen-prompt-row { flex-direction: column !important; }
.gen-prompt-row > * { width: 100% !important; }
.gen-params { flex-wrap: wrap !important; gap: 8px !important; }
.gen-params > div { flex: 1 1 45% !important; min-width: 0; }
.gen-prompt-row {
flex-direction: column !important;
}
.gen-prompt-row>* {
width: 100% !important;
}
.gen-params {
flex-wrap: wrap !important;
gap: 8px !important;
}
.gen-params>div {
flex: 1 1 45% !important;
min-width: 0;
}
/* Expanded detail left+right stacks */
.gen-detail-row { flex-direction: column !important; }
.gen-detail-row > * { width: 100% !important; min-width: 0 !important; flex: 1 1 auto !important; }
.gen-detail-row {
flex-direction: column !important;
}
.gen-detail-row>* {
width: 100% !important;
min-width: 0 !important;
flex: 1 1 auto !important;
}
/* Record filter bar stacks */
.record-filter-bar { flex-direction: column !important; }
.record-filter-bar .ant-space { flex-wrap: wrap !important; }
.record-filter-bar .ant-select { width: 100% !important; }
.record-filter-bar {
flex-direction: column !important;
}
.record-filter-bar .ant-space {
flex-wrap: wrap !important;
}
.record-filter-bar .ant-select {
width: 100% !important;
}
/* Record summary row stacks */
.record-item { flex-direction: column !important; align-items: flex-start !important; gap: 8px !important; overflow: hidden !important; }
.record-item .record-actions { width: 100% !important; justify-content: flex-end; }
.record-item > span[style*="textOverflow"] { white-space: normal !important; overflow: visible !important; text-overflow: unset !important; }
.record-item {
flex-direction: column !important;
align-items: flex-start !important;
gap: 8px !important;
overflow: hidden !important;
}
.record-item .record-actions {
width: 100% !important;
justify-content: flex-end;
}
.record-item>span[style*="textOverflow"] {
white-space: normal !important;
overflow: visible !important;
text-overflow: unset !important;
}
/* Hide less important meta on mobile */
.mobile-meta { display: none !important; }
.mobile-meta {
display: none !important;
}
/* Credits page */
.credits-balance { flex-direction: column !important; }
.recharge-grid { flex-direction: column !important; }
.recharge-grid > * { width: 100% !important; }
.credits-balance {
flex-direction: column !important;
}
.recharge-grid {
flex-direction: column !important;
}
.recharge-grid>* {
width: 100% !important;
}
/* Video player fits mobile */
video { max-width: 100% !important; }
video {
max-width: 100% !important;
}
/* InitialReplication page */
.replication-container {
@@ -340,17 +665,20 @@ html, body {
padding: 16px !important;
height: calc(100vh - 64px) !important;
}
.replication-preview {
width: 100% !important;
height: 30vh !important;
border-radius: 12px !important;
}
.replication-form {
width: 100% !important;
height: auto !important;
max-height: calc(70vh - 32px) !important;
border-radius: 12px !important;
}
.replication-form-content {
padding: 16px !important;
max-height: calc(70vh - 64px) !important;
@@ -358,56 +686,92 @@ html, body {
}
/* ── Date Display ──────────────────────── */
.date-display { font-family: 'SF Mono', 'Menlo', 'Consolas', monospace; }
.date-display {
font-family: 'SF Mono', 'Menlo', 'Consolas', monospace;
}
/* ── Small Mobile Breakpoint (max-width: 480px) ────────────── */
@media (max-width: 480px) {
/* Base styles */
html, body { font-size: 14px !important; }
html,
body {
font-size: 14px !important;
}
/* Login page */
.login-card { width: 100% !important; }
.login-right { padding: 16px !important; }
.login-card {
width: 100% !important;
}
.login-right {
padding: 16px !important;
}
/* Header adjustments */
.gen-header { padding: 12px 14px !important; }
.gen-header {
padding: 12px 14px !important;
}
/* Form elements */
.gen-form-row { gap: 8px !important; }
.gen-form-row {
gap: 8px !important;
}
/* Button adjustments */
.ant-btn { height: 36px !important; font-size: 13px !important; padding: 0 12px !important; }
.ant-btn {
height: 36px !important;
font-size: 13px !important;
padding: 0 12px !important;
}
/* Input adjustments */
.ant-input, .ant-input-affix-wrapper, .ant-select-selector {
height: 36px !important;
.ant-input,
.ant-input-affix-wrapper,
.ant-select-selector {
height: 36px !important;
font-size: 13px !important;
}
/* Card padding */
.ant-card { padding: 12px !important; }
.ant-card {
padding: 12px !important;
}
/* Mobile bottom nav adjustments */
.mobile-bottom-nav { height: 56px !important; }
.mobile-bottom-nav .nav-item .nav-icon { font-size: 18px !important; }
.mobile-bottom-nav .nav-item { font-size: 9px !important; gap: 2px !important; }
.mobile-bottom-nav {
height: 56px !important;
}
.mobile-bottom-nav .nav-item .nav-icon {
font-size: 18px !important;
}
.mobile-bottom-nav .nav-item {
font-size: 9px !important;
gap: 2px !important;
}
/* InitialReplication page - Small Mobile */
.replication-container {
padding: 12px !important;
gap: 12px !important;
}
.replication-preview {
height: 25vh !important;
border-radius: 10px !important;
}
.replication-form-content {
padding: 12px !important;
}
.replication-form-content .ant-btn {
height: 36px !important;
font-size: 13px !important;
}
.replication-form-content .ant-input,
.replication-form-content .ant-input-affix-wrapper {
height: 36px !important;
@@ -415,30 +779,56 @@ html, body {
}
/* Video and image containers */
video, img {
max-height: 160px !important;
video,
img {
max-height: 160px !important;
border-radius: 6px !important;
}
/* Upload areas */
.upload-area { padding: 12px !important; }
.upload-area {
padding: 12px !important;
}
/* Spacing adjustments */
.mobile-p-16 { padding: 12px !important; }
.mobile-gap-12 { gap: 8px !important; }
.mobile-p-16 {
padding: 12px !important;
}
.mobile-gap-12 {
gap: 8px !important;
}
/* Font size adjustments */
h1 { font-size: 18px !important; }
h2 { font-size: 16px !important; }
h3 { font-size: 14px !important; }
p { font-size: 12px !important; }
h1 {
font-size: 18px !important;
}
h2 {
font-size: 16px !important;
}
h3 {
font-size: 14px !important;
}
p {
font-size: 12px !important;
}
/* Button text */
.btn-text-sm { font-size: 12px !important; }
.btn-text-sm {
font-size: 12px !important;
}
/* Margin adjustments */
.mobile-mb-8 { margin-bottom: 8px !important; }
.mobile-mb-12 { margin-bottom: 12px !important; }
.mobile-mb-8 {
margin-bottom: 8px !important;
}
.mobile-mb-12 {
margin-bottom: 12px !important;
}
}
/* ── Tablet Breakpoint (769px to 1024px) ────────────── */
@@ -450,33 +840,49 @@ html, body {
*/
/* Card max-width */
.ant-card { max-width: calc(50% - 8px) !important; }
.ant-card {
max-width: calc(50% - 8px) !important;
}
/* Font adjustments */
html, body { font-size: 15px !important; }
html,
body {
font-size: 15px !important;
}
}
/* ── Large Desktop Breakpoint (min-width: 1200px) ────────────── */
@media (min-width: 1200px) {
/* Max width container */
.max-w-container { max-width: 1400px; margin: 0 auto; }
.max-w-container {
max-width: 1400px;
margin: 0 auto;
}
/* Card grid */
.card-grid { grid-template-columns: repeat(3, 1fr) !important; }
.card-grid {
grid-template-columns: repeat(3, 1fr) !important;
}
}
/* ── HomePage Tabs ────────────── */
.homepage-tabs .ant-tabs-nav { margin-bottom: 0; }
.homepage-tabs .ant-tabs-nav {
margin-bottom: 0;
}
.homepage-tabs .ant-tabs-tab {
font-size: 14px;
font-weight: 500;
padding: 8px 20px;
margin-right: 4px;
}
.homepage-tabs .ant-tabs-tab-active {
color: #6366f1;
font-weight: 600;
}
.homepage-tabs .ant-tabs-ink-bar {
background: linear-gradient(135deg, #6366f1, #8b5cf6);
}
}
+271 -72
View File
@@ -8,127 +8,326 @@ import {
PlayCircleOutlined,
CheckCircleOutlined,
HeartOutlined,
EyeOutlined,
ArrowRightOutlined,
CrownOutlined,
} from '@ant-design/icons';
const CreativePlazaPage: React.FC = () => {
const handleUnlock = () => {
message.info('请联系客服开通');
message.info('请联系客服开通会员');
};
// 顶部特性卡片
const features = [
{
icon: <ThunderboltOutlined style={{ fontSize: 28, color: '#8b5cf6' }} />,
title: 'AI智能生成',
description: '先进AI技术一键生成高质量视频内容',
icon: <ThunderboltOutlined style={{ fontSize: 26, color: '#8b5cf6' }} />,
title: 'AI 智能生成',
description: '先进 AI 技术一键产出高质量视频内容',
},
{
icon: <PlayCircleOutlined style={{ fontSize: 28, color: '#ec4899' }} />,
icon: <PlayCircleOutlined style={{ fontSize: 26, color: '#ec4899' }} />,
title: '多格式输出',
description: '支持多种视频格式满足不同场景需求',
description: '支持多种视频格式,满足不同场景需求',
},
{
icon: <CheckCircleOutlined style={{ fontSize: 28, color: '#10b981' }} />,
icon: <CheckCircleOutlined style={{ fontSize: 26, color: '#10b981' }} />,
title: '品质保证',
description: '专业级画质细节清晰色彩鲜艳',
description: '专业级画质,细节清晰,色彩鲜艳',
},
{
icon: <HeartOutlined style={{ fontSize: 28, color: '#f59e0b' }} />,
icon: <HeartOutlined style={{ fontSize: 26, color: '#f59e0b' }} />,
title: '创意无限',
description: '丰富模板风格激发创作灵感',
description: '丰富模板风格,激发创作灵感',
},
];
// 精选案例占位
const caseList = [
{ title: '美妆直播切片', tag: '热门', tagColor: '#ef4444' },
{ title: '3C 数码测评', tag: '推荐', tagColor: '#6366f1' },
{ title: '美食探店 vlog', tag: '推荐', tagColor: '#6366f1' },
{ title: '服饰穿搭合集', tag: '热门', tagColor: '#ef4444' },
{ title: '家居场景展示', tag: '推荐', tagColor: '#6366f1' },
{ title: '母婴亲子内容', tag: '热门', tagColor: '#ef4444' },
];
return (
<div style={{ padding: '20px 0' }}>
<div style={{ marginBottom: 32 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12 }}>
<div style={{
width: 48,
height: 48,
borderRadius: 14,
background: 'linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 4px 16px rgba(139,92,246,0.3)',
}}>
<GiftOutlined style={{ fontSize: 22, color: '#fff' }} />
<div className="content_box">
{/* 顶部 Hero 区域 */}
<div
className="animate-fadeInUp"
style={{
padding: '28px 32px',
borderRadius: 16,
background: 'linear-gradient(135deg, #f5f3ff 0%, #ede9fe 50%, #fce7f3 100%)',
border: '1px solid rgba(139, 92, 246, 0.12)',
marginBottom: 24,
position: 'relative',
overflow: 'hidden',
}}
>
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 12 }}>
<div
style={{
width: 52,
height: 52,
borderRadius: 14,
background: 'linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 6px 20px rgba(139, 92, 246, 0.3)',
}}
>
<GiftOutlined style={{ fontSize: 24, color: '#fff' }} />
</div>
<div>
<Typography.Title level={2} style={{ margin: 0, color: '#1e293b', fontWeight: 700 }}>
<span style={{ color: '#6366f1', fontSize: 14, fontWeight: 400, marginLeft: 8 }}>
AI创作无限可能
<div className="shiny-text-container" style={{ marginBottom: 4 }}>
<span className="shiny-text" style={{ fontSize: 26, fontWeight: 700 }}>
</span>
</Typography.Title>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: '#7c3aed' }}>
<CrownOutlined style={{ fontSize: 12 }} />
<span> AI </span>
</div>
</div>
</div>
<Typography.Text style={{ color: '#64748b' }}>
AI生成的优秀素材案例AI创作的无限潜力与创意灵感
<Typography.Text style={{ color: '#64748b', fontSize: 14, lineHeight: 1.7 }}>
AI , AI
</Typography.Text>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 20, marginBottom: 32 }}>
{/* 特性卡片 */}
{/* <div
className="animate-fadeInUp stagger-children"
style={{
display: 'grid',
gridTemplateColumns: 'repeat(4, 1fr)',
gap: 16,
marginBottom: 24,
}}
>
{features.map((feature, index) => (
<Card
key={index}
bordered={false}
hoverable
className="project-card"
style={{
borderRadius: 16,
background: 'linear-gradient(135deg, rgba(139,92,246,0.04) 0%, rgba(99,102,241,0.04) 100%)',
border: '1px solid rgba(139,92,246,0.1)',
padding: 20,
background: '#fff',
border: '1px solid #e2e8f0',
padding: '4px 0',
}}
styles={{ body: { padding: 20 } }}
>
<div style={{ textAlign: 'center' }}>
<div style={{ marginBottom: 16 }}>{feature.icon}</div>
<Typography.Title level={4} style={{ marginBottom: 8, color: '#1e293b' }}>
<div style={{ textAlign: 'left' }}>
<div
style={{
width: 48,
height: 48,
borderRadius: 12,
background: 'linear-gradient(135deg, rgba(139, 92, 246, 0.08), rgba(99, 102, 241, 0.08))',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 14,
}}
>
{feature.icon}
</div>
<div style={{ fontSize: 15, fontWeight: 600, color: '#1e293b', marginBottom: 6 }}>
{feature.title}
</Typography.Title>
<Typography.Text style={{ color: '#64748b', fontSize: 13 }}>
</div>
<div style={{ fontSize: 13, color: '#64748b', lineHeight: 1.6 }}>
{feature.description}
</Typography.Text>
</div>
</div>
</Card>
))}
</div>
</div> */}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
<Typography.Title level={4} style={{ margin: 0, color: '#1e293b' }}>
<StarOutlined style={{ marginRight: 8, color: '#f59e0b' }} />
</Typography.Title>
<Button
type="primary"
size="middle"
onClick={handleUnlock}
style={{
borderRadius: 10,
background: 'linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)',
border: 'none',
}}
>
<LockOutlined style={{ marginRight: 6 }} />
</Button>
</div>
<Card
bordered={false}
{/* 精选案例展示区域 */}
<div
className="animate-fadeInUp"
style={{
padding: '24px 28px',
borderRadius: 16,
background: '#fafafa',
padding: 40,
textAlign: 'center',
background: '#fff',
// border: '1px solid #e2e8f0',
position: 'relative',
}}
>
<div style={{ color: '#94a3b8', fontSize: 14 }}>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 20,
}}
>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div
style={{
width: 4,
height: 18,
background: 'linear-gradient(180deg, #6366f1, #8b5cf6)',
borderRadius: 2,
marginRight: 10,
}}
/>
<StarOutlined style={{ marginRight: 8, color: '#f59e0b', fontSize: 16 }} />
<span style={{ fontSize: 17, fontWeight: 600, color: '#1f2937' }}></span>
</div>
{/* <Button
type="primary"
size="middle"
onClick={handleUnlock}
style={{
borderRadius: 10,
fontWeight: 500,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none',
boxShadow: '0 4px 14px rgba(99, 102, 241, 0.28)',
}}
>
<LockOutlined style={{ marginRight: 6 }} />
解锁全部案例
<ArrowRightOutlined style={{ marginLeft: 4, fontSize: 12 }} />
</Button> */}
</div>
</Card>
{/* 案例网格 */}
<div
className="stagger-children"
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
gap: 16,
marginBottom: 16,
position: 'relative',
}}
>
<div
style={{
position: 'absolute',
inset: 0,
zIndex: 1,
background: 'rgb(255,255,255)',
// background:
// 'linear-gradient(180deg, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.55) 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
borderRadius: 14,
// boxShadow: '0px 4px 16px rgba(0, 0, 0, 0.08)',
gap: 4,
color: '#fff',
}}
>
<Button
type="primary"
size="middle"
onClick={handleUnlock}
style={{
borderRadius: 10,
fontWeight: 500,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none',
boxShadow: '0 4px 14px rgba(99, 102, 241, 0.28)',
}}
>
<LockOutlined style={{ marginRight: 6 }} />
<ArrowRightOutlined style={{ marginLeft: 4, fontSize: 12 }} />
</Button>
{/* <LockOutlined style={{ fontSize: 22, color: '#94a3b8', cursor: 'pointer' }}
onClick={handleUnlock}
/>
<span style={{ fontSize: 16, color: '#1f2937', opacity: 0.9 }}>会员可查看</span> */}
</div>
{caseList.map((item, index) => (
<div
key={index}
className="project-card animate-fadeInUp"
style={{
position: 'relative',
borderRadius: 14,
overflow: 'hidden',
cursor: 'pointer',
border: '1px solid #e2e8f0',
background: '#fff',
}}
>
<div
style={{
position: 'relative',
aspectRatio: '16/9',
background:
'linear-gradient(135deg, #1e1b4b 0%, #312e81 50%, #4c1d95 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{/* 模糊视频缩略图占位 */}
<PlayCircleOutlined style={{ fontSize: 36, color: 'rgba(255,255,255,0.6)' }} />
{/* 标签 */}
<div
style={{
position: 'absolute',
top: 10,
left: 10,
padding: '2px 8px',
borderRadius: 6,
background: item.tagColor,
color: '#fff',
fontSize: 11,
fontWeight: 500,
}}
>
{item.tag}
</div>
</div>
<div
style={{
padding: '10px 14px',
background: '#f8fafc',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<span
style={{
fontSize: 13,
color: '#334155',
fontWeight: 500,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{item.title}
</span>
<EyeOutlined style={{ fontSize: 13, color: '#94a3b8' }} />
</div>
</div>
))}
</div>
{/* 锁定遮罩 */}
</div>
</div>
);
};
export default CreativePlazaPage;
export default CreativePlazaPage;
+4 -5
View File
@@ -111,11 +111,7 @@ const AIChatPage: React.FC = () => {
const [conversations, setConversations] = useState<Conversation[]>([
]);
const [inputValue, setInputValue] = useState<string>('');
// 从 store 读取生成配置状态
// 从 store 读取生成配置状态(包括输入框内容)
const {
mediaType,
countType,
@@ -128,6 +124,7 @@ const AIChatPage: React.FC = () => {
videoResolution,
engineOptions,
enginesele,
inputValue,
setMediaType,
setCountType,
setSelectedRatio,
@@ -139,6 +136,7 @@ const AIChatPage: React.FC = () => {
setVideoResolution,
setEngineOptions,
setEnginesele,
setInputValue,
} = useAppStore();
const [uploading, setUploading] = useState<boolean>(false);
@@ -2223,6 +2221,7 @@ const AIChatPage: React.FC = () => {
<span style={{ fontSize: 12, color: '#9ca3af' }}></span>
</div>
</div>
</div>
{/* 选择分辨率 */}
+40 -30
View File
@@ -45,7 +45,6 @@ const HomePage: React.FC = () => {
try {
getmedit(5).then((res) => {
console.log('getmedit:', res);
for (let item in res) {
res[item].forEach(element => {
// 给每条 element 标记它所属的模块(item 是接口返回的 key)
@@ -56,13 +55,11 @@ const HomePage: React.FC = () => {
}
// 最终再打印一次汇总(state 异步更新,这里打印的是本次追加的累计长度)
setMockVideos(prev => {
console.log('mockVideos 最终条数:', prev.length);
return prev;
});
});
} catch (err) {
console.error('HomePage fetch error:', err);
}
};
fetchAll();
@@ -72,7 +69,7 @@ const HomePage: React.FC = () => {
setActiveTab(key);
};
const aiEntries = [
{
@@ -120,21 +117,43 @@ const HomePage: React.FC = () => {
];
return (
<div style={{
margin: '-24px -32px -32px',
borderRadius: 20,
height: 'calc(100vh - 34px)',
overflow: 'auto',
scrollbarWidth: 'none',
padding: '0 28px 32px',
}}>
<div className="content_box">
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
<h3></h3>
<p
style={{
cursor: 'pointer',
fontSize: 12, letterSpacing: 0.3,
padding: '10px 16px',
backgroundColor: '#ffffffff',
borderRadius: 30,
boxShadow: '0px 4px 12px 0px rgba(0, 0, 0, 0.1)',
}}
>
<span
style={{
color: '#1a50bbff',
}}
onClick={() => {
navigate('/authorization')
}}>
<ArrowRightOutlined style={{ marginLeft: 8, transform: 'rotate(0deg)' }} />
</span>
</p>
</div>
{/* ========== 顶部工作台引导区域(三步流程) ========== */}
<div className="animate-fadeInUp" style={{
padding: '24px 28px',
borderRadius: 16,
background: 'linear-gradient(135deg, #f0f9ff 0%, #faf5ff 50%, #fef3c7 100%)',
border: '1px solid rgba(99,102,241,0.10)',
margin: '24px 0 20px',
margin: '0 0 20px',
position: 'relative',
overflow: 'hidden',
}}>
@@ -151,7 +170,7 @@ const HomePage: React.FC = () => {
</div>
</div>
</div>
<div >
{/* <div >
<span style={{
cursor: 'pointer',
fontSize: 12, color: '#1a50bbff', letterSpacing: 0.3,
@@ -159,11 +178,11 @@ const HomePage: React.FC = () => {
onClick={() => {
navigate('/authorization')
}}
>
>如需进行账户素材推送 一键推送
<ArrowRightOutlined style={{ marginLeft: 8, transform: 'rotate(0deg)' }} />
</span>
</div>
</div> */}
</div>
@@ -553,7 +572,7 @@ const HomePage: React.FC = () => {
</div>
</div>
</div>
{/* Tab切换 */}
<div style={{ marginBottom: 20 }}>
@@ -679,17 +698,8 @@ const HomePage: React.FC = () => {
<div style={{
padding: '10px 12px',
background: '#f8fafc',
paddingTop: 0,
}}>
{/* <div style={{
fontSize: 13,
color: '#334155',
fontWeight: 500,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}>
{video.title || video.name || video.originalPrompt || video.prompt || '未命名作品'}
</div> */}
<div style={{
marginTop: 6,
display: 'flex',
@@ -739,7 +749,7 @@ const HomePage: React.FC = () => {
{/* ========== 素材案例区域 ========== */}
<div className="animate-fadeInUp" style={{
{/* <div className="animate-fadeInUp" style={{
padding: '24px 28px',
borderRadius: 16,
background: '#fff',
@@ -800,7 +810,7 @@ const HomePage: React.FC = () => {
alt={`素材案例 ${index + 1}`}
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
/>
{/* 案例悬停遮罩(由父级 hover 触发) */}
案例悬停遮罩(由父级 hover 触发)
<div
className="case-overlay"
style={{
@@ -824,7 +834,7 @@ const HomePage: React.FC = () => {
</div>
))}
</div>
</div>
</div> */}
</div>
);
};
+8 -2
View File
@@ -31,6 +31,8 @@ function InitialInfo() {
// 引擎和视频参数相关状态
const [enginesele, setEnginesele] = useState<any>({});
const [countType, setCountType] = useState('');
// 图片引擎 id:取自 getEngine().engine.image[0].id
const [imageEngineId, setImageEngineId] = useState<string>('');
const [showEngineModal, setShowEngineModal] = useState(false);
const [showVideoSettingsModal, setShowVideoSettingsModal] = useState(false);
const [videoDuration, setVideoDuration] = useState(5);
@@ -160,6 +162,10 @@ function InitialInfo() {
durations: firstEngine.supportedDurations || [5, 8, 10, 12, 15],
});
}
// 默认选中第一个图片引擎
if (data.engine?.image && data.engine.image.length > 0) {
setImageEngineId(data.engine.image[0].id);
}
})
.catch((error: any) => {
});
@@ -335,7 +341,7 @@ function InitialInfo() {
const createimage = (stepId: number) => {
let params = {
engine_id: "0019e3dac0b795b925b",
engine_id: imageEngineId,
image_proportion: "1:1",
image_px: "2048x2048",
image_size: "2K"
@@ -349,7 +355,7 @@ function InitialInfo() {
const newcreateimage = () => {
// console.log('下一步:', stepId);
let params = {
engine_id: "0019e3dac0b795b925b",
engine_id: imageEngineId,
image_proportion: "1:1",
image_px: "2048x2048",
image_size: "2K"
@@ -852,6 +852,7 @@ const GenerateConver: React.FC = () => {
</div>
) : (
<Upload
style={{ width: '100%' }}
beforeUpload={beforeVideoUpload}
showUploadList={false}
accept="video/mp4,video/quicktime,.mp4,.mov"
@@ -967,6 +968,8 @@ const GenerateConver: React.FC = () => {
</div>
) : (
<Upload
style={{ width: '100%' }}
beforeUpload={beforeImageUpload}
showUploadList={false}
accept="image/jpeg,image/jpg,image/png,.jpg,.jpeg,.png"
+621 -81
View File
@@ -1,115 +1,655 @@
import React from 'react';
import { Button, Card, message, Typography } from 'antd';
import { Button, message, Typography } from 'antd';
import {
StarOutlined,
CrownOutlined,
LockOutlined,
ThunderboltOutlined,
GiftOutlined,
BarChartOutlined,
FireOutlined,
TrophyOutlined,
LockOutlined,
ArrowRightOutlined,
PlayCircleOutlined,
EyeOutlined,
LikeOutlined,
CommentOutlined,
ShareAltOutlined,
RiseOutlined,
ThunderboltOutlined,
} from '@ant-design/icons';
const PopularPage: React.FC = () => {
const handleUnlock = () => {
message.info('请联系客服开通');
message.info('请联系客服开通会员');
};
// 顶部统计 KPI
const stats = [
{
icon: <FireOutlined style={{ fontSize: 22, color: '#f59e0b' }} />,
label: '今日爆款',
value: '1,286',
unit: '条',
trend: '+12.5%',
color: '#f59e0b',
},
{
icon: <EyeOutlined style={{ fontSize: 22, color: '#6366f1' }} />,
label: '总浏览量',
value: '428',
unit: '万',
trend: '+8.2%',
color: '#6366f1',
},
{
icon: <LikeOutlined style={{ fontSize: 22, color: '#ec4899' }} />,
label: '总互动数',
value: '76.4',
unit: '万',
trend: '+15.7%',
color: '#ec4899',
},
{
icon: <ThunderboltOutlined style={{ fontSize: 22, color: '#10b981' }} />,
label: '上升最快',
value: '美妆',
unit: '赛道',
trend: '+28.3%',
color: '#10b981',
},
];
// 行业热度排行(假数据)
const industryRank = [
{ rank: 1, name: '美妆个护', hot: 98.5, change: 'up' as const, value: 98234 },
{ rank: 2, name: '服饰穿搭', hot: 95.2, change: 'up' as const, value: 87643 },
{ rank: 3, name: '美食探店', hot: 91.7, change: 'up' as const, value: 78921 },
{ rank: 4, name: '3C 数码', hot: 87.3, change: 'down' as const, value: 65432 },
{ rank: 5, name: '家居生活', hot: 82.6, change: 'up' as const, value: 54321 },
{ rank: 6, name: '母婴亲子', hot: 78.1, change: 'flat' as const, value: 43210 },
{ rank: 7, name: '运动健身', hot: 72.4, change: 'up' as const, value: 38765 },
];
// 爆款素材榜单
const popularList = [
{
rank: 1,
title: '夏日美妆教程:3 步打造奶油肌',
author: '美妆博主·小雅',
views: '128.4w',
likes: '12.6w',
comments: '8,234',
tag: 'NO.1',
tagColor: '#f59e0b',
},
{
rank: 2,
title: '平价穿搭 | 学生党一周不重样',
author: '穿搭达人·Miki',
views: '96.2w',
likes: '9.8w',
comments: '6,128',
tag: 'NO.2',
tagColor: '#a78bfa',
},
{
rank: 3,
title: '探店 vlog | 网红咖啡馆测评',
author: '美食探店·阿伦',
views: '78.5w',
likes: '7.4w',
comments: '4,892',
tag: 'NO.3',
tagColor: '#6366f1',
},
{
rank: 4,
title: 'iPhone 16 Pro 一周深度体验',
author: '数码评测·老王',
views: '65.7w',
likes: '6.1w',
comments: '3,847',
tag: 'NO.4',
tagColor: '#94a3b8',
},
];
return (
<div style={{ padding: '20px 0' }}>
<div style={{ marginBottom: 32 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12 }}>
<div style={{
width: 48,
height: 48,
borderRadius: 14,
background: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 4px 16px rgba(245,158,11,0.3)',
}}>
<BarChartOutlined style={{ fontSize: 22, color: '#fff' }} />
<div className="content_box">
{/* Hero 区域 - 橙金主题(区别创意素材案例的紫粉) */}
<div
className="animate-fadeInUp"
style={{
padding: '28px 32px',
borderRadius: 16,
background: 'linear-gradient(135deg, #fffbeb 0%, #fef3c7 50%, #fed7aa 100%)',
border: '1px solid rgba(245, 158, 11, 0.18)',
marginBottom: 24,
position: 'relative',
overflow: 'hidden',
}}
>
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 12 }}>
<div
style={{
width: 52,
height: 52,
borderRadius: 14,
background: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 6px 20px rgba(245, 158, 11, 0.3)',
}}
>
<BarChartOutlined style={{ fontSize: 24, color: '#fff' }} />
</div>
<div>
<Typography.Title level={2} style={{ margin: 0, color: '#1e293b', fontWeight: 700 }}>
<span style={{ color: '#6366f1', fontSize: 14, fontWeight: 400, marginLeft: 8 }}>
<div className="shiny-text-container" style={{ marginBottom: 4 }}>
<span
className="shiny-text"
style={{
fontSize: 26,
fontWeight: 700,
backgroundImage:
'linear-gradient(90deg, #f59e0b 0%, #d97706 30%, #ea580c 50%, #d97706 70%, #f59e0b 100%)',
}}
>
</span>
</Typography.Title>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: '#b45309' }}>
<RiseOutlined style={{ fontSize: 12 }} />
<span></span>
</div>
</div>
</div>
<Typography.Text style={{ color: '#64748b' }}>
<Typography.Text style={{ color: '#78716c', fontSize: 14, lineHeight: 1.7 }}>
,,
</Typography.Text>
</div>
<Card
bordered={false}
{/* 4 个 KPI 统计卡片 */}
{/* <div
className="animate-fadeInUp stagger-children"
style={{
borderRadius: 20,
background: 'linear-gradient(135deg, rgba(245,158,11,0.04) 0%, rgba(217,119,6,0.04) 100%)',
border: '1px solid rgba(245,158,11,0.1)',
padding: 10,
marginBottom: 32,
display: 'grid',
gridTemplateColumns: 'repeat(4, 1fr)',
gap: 16,
marginBottom: 24,
}}
>
<Typography.Title level={4} style={{ marginBottom: 20, color: '#1e293b' }}>
<FireOutlined style={{ marginRight: 8, color: '#f59e0b' }} />
</Typography.Title>
<Card
bordered={false}
style={{
borderRadius: 16,
background: '#fafafa',
padding: 40,
textAlign: 'center',
}}
>
<div style={{ color: '#94a3b8', fontSize: 14 }}>
{stats.map((item, index) => (
<div
key={index}
className="project-card"
style={{
padding: 20,
borderRadius: 16,
background: '#fff',
border: '1px solid #e2e8f0',
}}
>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 14,
}}
>
<div
style={{
width: 44,
height: 44,
borderRadius: 12,
background: `linear-gradient(135deg, ${item.color}15, ${item.color}08)`,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{item.icon}
</div>
<div
style={{
display: 'flex',
alignItems: 'center',
gap: 2,
fontSize: 12,
fontWeight: 600,
color: '#10b981',
background: 'rgba(16, 185, 129, 0.08)',
padding: '2px 8px',
borderRadius: 6,
}}
>
<RiseOutlined style={{ fontSize: 10 }} />
{item.trend}
</div>
</div>
<div style={{ display: 'flex', alignItems: 'baseline', gap: 4, marginBottom: 4 }}>
<span style={{ fontSize: 24, fontWeight: 700, color: '#1e293b' }}>{item.value}</span>
<span style={{ fontSize: 13, color: '#94a3b8' }}>{item.unit}</span>
</div>
<div style={{ fontSize: 13, color: '#64748b' }}>{item.label}</div>
</div>
</Card>
</Card>
))}
</div> */}
{/* 行业热度排行 */}
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
<Typography.Title level={4} style={{ margin: 0, color: '#1e293b' }}>
<TrophyOutlined style={{ marginRight: 8, color: '#6366f1' }} />
</Typography.Title>
<Button
type="primary"
size="middle"
onClick={handleUnlock}
<div style={{ position: 'relative' }}>
{/* <div
className="animate-fadeInUp"
style={{
borderRadius: 10,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none',
padding: '24px 28px',
borderRadius: 16,
background: '#fff',
border: '1px solid #e2e8f0',
marginBottom: 24,
}}
>
<LockOutlined style={{ marginRight: 6 }} />
</Button>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 20,
}}
>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div
style={{
width: 4,
height: 18,
background: 'linear-gradient(180deg, #f59e0b, #d97706)',
borderRadius: 2,
marginRight: 10,
}}
/>
<FireOutlined style={{ marginRight: 8, color: '#f59e0b', fontSize: 16 }} />
<span style={{ fontSize: 17, fontWeight: 600, color: '#1f2937' }}>行业热度排行</span>
<span
style={{
marginLeft: 10,
fontSize: 12,
fontWeight: 400,
color: '#94a3b8',
}}
>
基于近 7 天数据 · 实时更新
</span>
</div>
<span style={{ fontSize: 12, color: '#94a3b8' }}>更新时间: 10 分钟前</span>
</div>
<div style={{position: 'relative', height: 300}}>
<Typography.Text style={{ width: '100%', textAlign: 'center', color: '#64748b', display: 'block', height: 100, background: '#f3f4f6', marginTop: 20, marginBottom: 20, padding: 20, }}>
实时追踪各行业爆款素材,把握创作风向,打造热门内容
</Typography.Text>
<div
style={{
position: 'absolute',
inset: 0,
// background:
// ' linear-gradient(180deg, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.7) 100%)',
background: 'rgb(255,255,255)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
gap: 2,
color: '#fff',
borderRadius: 6,
// boxShadow: '0 0 10px rgba(0,0,0,0.5)',
}}
>
<LockOutlined style={{ fontSize: 18, color: '#94a3b8', cursor: 'pointer' }}
onClick={handleUnlock}
/>
<span style={{ fontSize: 16, color: '#1f2937', opacity: 0.9 }}>立即解锁全部</span>
</div>
</div>
<div className="stagger-children">
{industryRank.map((item) => {
const rankColors: Record<number, string> = {
1: 'linear-gradient(135deg, #f59e0b, #d97706)',
2: 'linear-gradient(135deg, #94a3b8, #64748b)',
3: 'linear-gradient(135deg, #ea580c, #c2410c)',
};
const rankColor = rankColors[item.rank] || '#cbd5e1';
const trendIcon =
item.change === 'up' ? (
<RiseOutlined style={{ fontSize: 11, color: '#10b981' }} />
) : item.change === 'down' ? (
<RiseOutlined
style={{ fontSize: 11, color: '#ef4444', transform: 'rotate(180deg)' }}
/>
) : (
<span style={{ fontSize: 11, color: '#94a3b8' }}>—</span>
);
return (
<div
key={item.rank}
className="project-card animate-fadeInUp"
style={{
display: 'flex',
alignItems: 'center',
padding: '12px 16px',
borderRadius: 12,
marginBottom: 8,
background: '#f8fafc',
border: '1px solid transparent',
cursor: 'pointer',
}}
>
<div
style={{
width: 32,
height: 32,
borderRadius: 8,
background: rankColor,
color: '#fff',
fontSize: 14,
fontWeight: 700,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginRight: 14,
boxShadow: item.rank <= 3 ? '0 2px 8px rgba(0,0,0,0.15)' : 'none',
}}
>
{item.rank}
</div>
<div style={{ flex: 1, minWidth: 0 }}>
<div
style={{
fontSize: 14,
fontWeight: 600,
color: '#1e293b',
marginBottom: 6,
}}
>
{item.name}
</div>
<div
style={{
height: 6,
background: '#e2e8f0',
borderRadius: 3,
overflow: 'hidden',
}}
>
<div
style={{
width: `${item.hot}%`,
height: '100%',
background:
item.rank === 1
? 'linear-gradient(90deg, #f59e0b, #d97706)'
: item.rank === 2
? 'linear-gradient(90deg, #94a3b8, #64748b)'
: item.rank === 3
? 'linear-gradient(90deg, #ea580c, #c2410c)'
: 'linear-gradient(90deg, #6366f1, #8b5cf6)',
borderRadius: 3,
}}
/>
</div>
</div>
<div
style={{
width: 80,
textAlign: 'right',
fontSize: 14,
fontWeight: 600,
color: '#1e293b',
marginLeft: 16,
}}
>
{item.hot}
</div>
<div
style={{
width: 80,
textAlign: 'right',
fontSize: 12,
color: '#64748b',
marginLeft: 12,
}}
>
{item.value.toLocaleString()} 素材
</div>
<div style={{ width: 24, marginLeft: 12, textAlign: 'center' }}>{trendIcon}</div>
</div>
);
})}
</div>
</div> */}
{/* 爆款素材榜单 */}
<div
className="animate-fadeInUp"
style={{
padding: '24px 28px',
borderRadius: 16,
background: '#fff',
// border: '1px solid #e2e8f0',
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 20,
}}
>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div
style={{
width: 4,
height: 18,
background: 'linear-gradient(180deg, #6366f1, #8b5cf6)',
borderRadius: 2,
marginRight: 10,
}}
/>
<TrophyOutlined style={{ marginRight: 8, color: '#6366f1', fontSize: 16 }} />
<span style={{ fontSize: 17, fontWeight: 600, color: '#1f2937' }}></span>
<span
style={{
marginLeft: 10,
fontSize: 12,
fontWeight: 400,
color: '#94a3b8',
}}
>
{/* TOP 100 */}
</span>
</div>
{/* <Button
type="primary"
size="middle"
onClick={handleUnlock}
style={{
borderRadius: 10,
fontWeight: 500,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none',
boxShadow: '0 4px 14px rgba(99, 102, 241, 0.28)',
}}
>
<LockOutlined style={{ marginRight: 6 }} />
立即解锁全部
<ArrowRightOutlined style={{ marginLeft: 4, fontSize: 12 }} />
</Button> */}
</div>
<div
className="stagger-children"
style={{
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gap: 16,
position: 'relative',
}}
>
<div
style={{
position: 'absolute',
zIndex: 1,
inset: 0,
// background:
// ' linear-gradient(180deg, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.7) 100%)',
background: 'rgb(255,255,255)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
gap: 2,
color: '#fff',
borderRadius: 6,
// boxShadow: '0 0 10px rgba(0,0,0,0.5)',
}}
>
<Button
type="primary"
size="middle"
onClick={handleUnlock}
style={{
borderRadius: 10,
fontWeight: 500,
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%)',
border: 'none',
boxShadow: '0 4px 14px rgba(99, 102, 241, 0.28)',
}}
>
<LockOutlined style={{ marginRight: 6 }} />
<ArrowRightOutlined style={{ marginLeft: 4, fontSize: 12 }} />
</Button>
{/* <LockOutlined style={{ fontSize: 18, color: '#94a3b8', cursor: 'pointer' }}
onClick={handleUnlock}
/>
<span style={{ fontSize: 16, color: '#1f2937', opacity: 0.9 }}>立即解锁全部</span> */}
</div>
{popularList.map((item) => (
<div
key={item.rank}
className="project-card animate-fadeInUp"
style={{
display: 'flex',
gap: 14,
padding: 14,
borderRadius: 14,
background: '#fff',
border: '1px solid #e2e8f0',
cursor: 'pointer',
}}
>
<div
style={{
position: 'relative',
width: 140,
height: 80,
flexShrink: 0,
borderRadius: 10,
overflow: 'hidden',
background: 'linear-gradient(135deg, #1e1b4b 0%, #312e81 50%, #4c1d95 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<PlayCircleOutlined style={{ fontSize: 28, color: 'rgba(255,255,255,0.6)' }} />
{/* 排名徽章 */}
<div
style={{
position: 'absolute',
top: 6,
left: 6,
padding: '2px 8px',
borderRadius: 6,
background: item.tagColor,
color: '#fff',
fontSize: 11,
fontWeight: 600,
}}
>
{item.tag}
</div>
</div>
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column' }}>
<div
style={{
fontSize: 14,
fontWeight: 600,
color: '#1e293b',
marginBottom: 4,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
}}
>
{item.title}
</div>
<div style={{ fontSize: 12, color: '#94a3b8', marginBottom: 8 }}>
{item.author}
</div>
<div style={{ display: 'flex', gap: 12, fontSize: 12, color: '#64748b' }}>
<span>
<EyeOutlined style={{ marginRight: 3 }} />
{item.views}
</span>
<span>
<LikeOutlined style={{ marginRight: 3 }} />
{item.likes}
</span>
<span>
<CommentOutlined style={{ marginRight: 3 }} />
{item.comments}
</span>
</div>
</div>
{/* 锁定遮罩 */}
{/* <div
style={{
position: 'absolute',
inset: 0,
background:
' linear-gradient(to right, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.7) 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
gap: 2,
color: '#fff',
borderRadius: 6,
}}
>
<LockOutlined style={{ fontSize: 18 }} />
<span style={{ fontSize: 10, opacity: 0.9 }}>会员可看</span>
</div> */}
</div>
))}
</div>
</div>
</div>
<Card
bordered={false}
style={{
borderRadius: 16,
background: '#fafafa',
padding: 40,
textAlign: 'center',
}}
>
<div style={{ color: '#94a3b8', fontSize: 14 }}>
</div>
</Card>
</div>
);
};
export default PopularPage;
export default PopularPage;
-6
View File
@@ -116,7 +116,6 @@ function RemoveInfo() {
}
}
} catch (error) {
console.error('轮询获取拆镜列表失败:', error);
}
}, 30000); // 30秒轮询
}
@@ -155,7 +154,6 @@ function RemoveInfo() {
if (!taskDetail) return;
if (taskDetail.analysisStatus === 'processing') {
console.log("开始轮询");
analysisPollingRef.current = window.setInterval(async () => {
try {
@@ -236,7 +234,6 @@ function RemoveInfo() {
material_image_url: buildAssetUrl(productImage),
idempotency_key: `replication_${Date.now()}`,
};
console.log(currentSegment,params);
setLoading(true);
@@ -245,10 +242,8 @@ function RemoveInfo() {
message.success('视频生成任务创建成功');
handleCloseDrawer();
Removelist(creatID).then((res: any) => {
console.log('123123123123',res);
const targetItem = res.items.find((item: any) => item.id === currentSegment);
console.log(targetItem);
message.loading('创建中...', 3);
setTimeout(() => {
@@ -355,7 +350,6 @@ function RemoveInfo() {
render: (_: any, record: any) => (
<div style={{ position: 'relative', width: 120, height: 80, borderRadius: 6, overflow: 'hidden', background: '#f1f5f9', cursor: 'pointer' }}
onClick={() => {
console.log('video clicked:', record.segmentVideoUrl);
if (record.segmentVideoUrl) {
setPreviewVideoUrl(buildAssetUrl(record.segmentVideoUrl));
setPreviewModalVisible(true);
+8 -3
View File
@@ -31,6 +31,8 @@ function InitialInfo() {
// 引擎和视频参数相关状态
const [enginesele, setEnginesele] = useState<any>({});
const [countType, setCountType] = useState('');
// 图片引擎 id:取自 getEngine().engine.image[0].id
const [imageEngineId, setImageEngineId] = useState<string>('');
const [showEngineModal, setShowEngineModal] = useState(false);
const [showVideoSettingsModal, setShowVideoSettingsModal] = useState(false);
const [videoDuration, setVideoDuration] = useState(5);
@@ -155,6 +157,10 @@ function InitialInfo() {
durations: firstEngine.supportedDurations || [5, 8, 10, 12, 15],
});
}
// 默认选中第一个图片引擎
if (data.engine?.image && data.engine.image.length > 0) {
setImageEngineId(data.engine.image[0].id);
}
})
.catch((error: any) => {
});
@@ -188,7 +194,6 @@ function InitialInfo() {
// 获取任务详情数据
useEffect(() => {
console.log('creatID', creatID);
if (creatID) {
removeDetail(creatID).then((res: any) => {
@@ -341,7 +346,7 @@ function InitialInfo() {
const createimage = (stepId: number) => {
let params = {
engine_id: "0019e3dac0b795b925b",
engine_id: imageEngineId,
image_proportion: "1:1",
image_px: "2048x2048",
image_size: "2K"
@@ -355,7 +360,7 @@ function InitialInfo() {
const newcreateimage = () => {
// console.log('下一步:', stepId);
let params = {
engine_id: "0019e3dac0b795b925b",
engine_id: imageEngineId,
image_proportion: "1:1",
image_px: "2048x2048",
image_size: "2K"
+5
View File
@@ -31,6 +31,7 @@ interface AppState {
durations: number[];
};
enginesele: any;
inputValue: string;
fetchProjects: () => Promise<void>;
createProject: (name: string, industry: Industry) => Promise<Project>;
@@ -56,6 +57,7 @@ interface AppState {
setVideoAspectRatio: (aspectRatio: string) => void;
setVideoResolution: (resolution: string) => void;
setEnginesele: (enginesele: any) => void;
setInputValue: (inputValue: string) => void;
resetGenerationConfig: () => void;
}
@@ -80,6 +82,7 @@ export const useAppStore = create<AppState>((set, get) => ({
durations: [5, 8, 10, 12, 15],
},
enginesele: [],
inputValue: '',
fetchProjects: async () => {
set({ loading: true });
@@ -168,6 +171,7 @@ export const useAppStore = create<AppState>((set, get) => ({
setVideoAspectRatio: (aspectRatio) => set({ videoAspectRatio: aspectRatio }),
setVideoResolution: (resolution) => set({ videoResolution: resolution }),
setEnginesele: (enginesele) => set({ enginesele }),
setInputValue: (inputValue) => set({ inputValue }),
resetGenerationConfig: () => set({
mediaType: 'image',
countType: '请选择',
@@ -184,5 +188,6 @@ export const useAppStore = create<AppState>((set, get) => ({
durations: [5, 8, 10, 12, 15],
},
enginesele: [],
inputValue: '',
}),
}));
+17
View File
@@ -1,10 +1,27 @@
export interface ResourceCapacity {
enabled: boolean;
source?: string;
hasUserConfig?: boolean;
usedBytes: number;
availableBytes: number;
totalBytes: number;
usagePercent: number;
exceeded: boolean;
limitValue?: string;
limitUnit: string; // 'KB' | 'MB' | 'GB' 等
}
export interface User {
id: string;
username: string;
email: string;
avatar?: string;
credits: number;
isAdmin?: boolean;
phone?: string;
allowedMenus?: string[] | null;
mustSetPassword?: boolean;
resourceCapacity?: ResourceCapacity;
}
export interface CreditRecord {