拆镜复刻
This commit is contained in:
@@ -1 +1,20 @@
|
|||||||
{}
|
{
|
||||||
|
"src/pages/GenerateConver.tsx": {
|
||||||
|
"description": "ai创建"
|
||||||
|
},
|
||||||
|
"src/pages/GeneratedRecord.tsx": {
|
||||||
|
"description": "生成历史"
|
||||||
|
},
|
||||||
|
"src/pages/GeneratePage.tsx": {
|
||||||
|
"description": "生成记录"
|
||||||
|
},
|
||||||
|
"src/pages/ProjectsPage.tsx": {
|
||||||
|
"description": "我的项目"
|
||||||
|
},
|
||||||
|
"src/pages/RemoveLens.tsx": {
|
||||||
|
"description": "拆镜复刻"
|
||||||
|
},
|
||||||
|
"src/pages/InitialReplication.tsx": {
|
||||||
|
"description": "爆款开头复刻"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import InitialInfo from './pages/InitialInfo';
|
|||||||
import RemoveLens from './pages/RemoveLens';
|
import RemoveLens from './pages/RemoveLens';
|
||||||
import GeneratedRecord from './pages/GeneratedRecord';
|
import GeneratedRecord from './pages/GeneratedRecord';
|
||||||
import AuthorizationPage from './pages/AuthorizationPage';
|
import AuthorizationPage from './pages/AuthorizationPage';
|
||||||
|
import RemoveInfo from './pages/RemoveInfo';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -96,6 +97,7 @@ const App = () => {
|
|||||||
<Route path="initial" element={<InitialReplication />} />
|
<Route path="initial" element={<InitialReplication />} />
|
||||||
<Route path="initial/:creatID/initialinfo" element={<InitialInfo />} />
|
<Route path="initial/:creatID/initialinfo" element={<InitialInfo />} />
|
||||||
<Route path="removelens" element={<RemoveLens />} />
|
<Route path="removelens" element={<RemoveLens />} />
|
||||||
|
<Route path="removelens/:creatID/removeinfo" element={<RemoveInfo />} />
|
||||||
<Route path="generated" element={<GeneratedRecord />} />
|
<Route path="generated" element={<GeneratedRecord />} />
|
||||||
<Route path="authorization" element={<AuthorizationPage />} />
|
<Route path="authorization" element={<AuthorizationPage />} />
|
||||||
|
|
||||||
|
|||||||
@@ -1069,7 +1069,7 @@ const GeneratedRecord: React.FC = () => {
|
|||||||
style={{ width: '100%', borderRadius: 8, marginTop: 20, color: '#4c49cc' }}
|
style={{ width: '100%', borderRadius: 8, marginTop: 20, color: '#4c49cc' }}
|
||||||
>
|
>
|
||||||
|
|
||||||
推送巨量引擎后台
|
推送媒体后台
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ function InitialInfo() {
|
|||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div style={{ height: '94vh', background: '#f8fafc' }}>
|
<div style={{ height: '94vh', background: '#f8fafc' }}>
|
||||||
<div style={{ height: 'calc(94vh)', padding: 24, }}>
|
<div style={{ height: 'calc(94vh)', }}>
|
||||||
<div style={{ height: '100%', display: 'flex', justifyContent: 'space-between', gap: '2%' }}>
|
<div style={{ height: '100%', display: 'flex', justifyContent: 'space-between', gap: '2%' }}>
|
||||||
<div style={{ width: '70%', background: '#fff', borderRadius: 12, overflowY: 'auto' }}>
|
<div style={{ width: '70%', background: '#fff', borderRadius: 12, overflowY: 'auto' }}>
|
||||||
<div style={{ borderBottom: '1px solid #e2e8f0', width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '14px', boxSizing: 'border-box' }}>
|
<div style={{ borderBottom: '1px solid #e2e8f0', width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '14px', boxSizing: 'border-box' }}>
|
||||||
|
|||||||
@@ -0,0 +1,419 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
|
import { Button, Table, Tag, Drawer, Input, Upload, message } from 'antd';
|
||||||
|
import { ArrowLeftOutlined, PlayCircleOutlined, XOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons';
|
||||||
|
import type { UploadFile } from 'antd';
|
||||||
|
|
||||||
|
const { TextArea } = Input;
|
||||||
|
|
||||||
|
function RemoveInfo() {
|
||||||
|
const { creatID } = useParams<{ creatID: string }>();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [drawerVisible, setDrawerVisible] = useState(false);
|
||||||
|
const [currentSegment, setCurrentSegment] = useState<number | null>(null);
|
||||||
|
const [productName, setProductName] = useState('');
|
||||||
|
const [productSellingPoint, setProductSellingPoint] = useState('');
|
||||||
|
const [productImage, setProductImage] = useState('');
|
||||||
|
const [detailImage, setDetailImage] = useState('');
|
||||||
|
|
||||||
|
const handleGenerate = (segmentId: number) => {
|
||||||
|
setCurrentSegment(segmentId);
|
||||||
|
setDrawerVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCloseDrawer = () => {
|
||||||
|
setDrawerVisible(false);
|
||||||
|
setCurrentSegment(null);
|
||||||
|
setProductName('');
|
||||||
|
setProductSellingPoint('');
|
||||||
|
setProductImage('');
|
||||||
|
setDetailImage('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleProductImageChange: any = (info: any) => {
|
||||||
|
if (info.fileList.length > 0) {
|
||||||
|
const file = info.fileList[0];
|
||||||
|
if (file.originFileObj) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
setProductImage(e.target?.result as string);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file.originFileObj);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setProductImage('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDetailImageChange: any = (info: any) => {
|
||||||
|
if (info.fileList.length > 0) {
|
||||||
|
const file = info.fileList[0];
|
||||||
|
if (file.originFileObj) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
setDetailImage(e.target?.result as string);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file.originFileObj);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setDetailImage('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleManualGenerate = () => {
|
||||||
|
// 必填校验
|
||||||
|
if (!productImage) {
|
||||||
|
message.warning('请上传产品图');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!productName.trim()) {
|
||||||
|
message.warning('请输入产品名称');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!productSellingPoint.trim()) {
|
||||||
|
message.warning('请输入产品卖点');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输出内容
|
||||||
|
console.log('手动生成 - 片段', currentSegment);
|
||||||
|
console.log('产品图:', productImage);
|
||||||
|
console.log('细节图:', detailImage);
|
||||||
|
console.log('产品名称:', productName);
|
||||||
|
console.log('产品卖点:', productSellingPoint);
|
||||||
|
|
||||||
|
message.success(`手动生成成功!片段: ${currentSegment}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockData = {
|
||||||
|
productName: '返回',
|
||||||
|
uploadTime: '2026-06-09 09:01:16',
|
||||||
|
sellingPoints: ['一键匹配', '连麦聊天'],
|
||||||
|
audience: '123123',
|
||||||
|
audienceAnalysis: '123123',
|
||||||
|
videoUrl: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=320&h=180&fit=crop',
|
||||||
|
segments: [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
id: 1,
|
||||||
|
timeRange: '00:00 - 00:03',
|
||||||
|
thumbnail: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=120&h=80&fit=crop',
|
||||||
|
content: '11111',
|
||||||
|
lines: 'qqqqqqqqqqq',
|
||||||
|
contentStrategy: '展示礼盒'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
id: 2,
|
||||||
|
timeRange: '00:03 - 00:06',
|
||||||
|
thumbnail: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=120&h=80&fit=crop',
|
||||||
|
content: '1231231231',
|
||||||
|
lines: 'qqqqqqqqqqq',
|
||||||
|
contentStrategy: '开箱展示'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '3',
|
||||||
|
id: 3,
|
||||||
|
timeRange: '00:06 - 00:09',
|
||||||
|
thumbnail: 'https://images.unsplash.com/photo-1522202176988-66273c2fd55f?w=120&h=80&fit=crop',
|
||||||
|
content: '123123',
|
||||||
|
lines: 'qqqqqqqqqqq',
|
||||||
|
contentStrategy: '取出产品'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '片段',
|
||||||
|
width: 100,
|
||||||
|
render: (text: any, record: any) => (
|
||||||
|
<div>
|
||||||
|
<div style={{ fontSize: 16, fontWeight: 600, color: '#333' }}>片段{record.id}</div>
|
||||||
|
<div style={{ fontSize: 12, color: '#999' }}>{record.timeRange}</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '片段视频',
|
||||||
|
width: 120,
|
||||||
|
render: (text: any, record: any) => (
|
||||||
|
<div style={{ position: 'relative', width: 120, height: 80, borderRadius: 6, overflow: 'hidden' }}>
|
||||||
|
<img
|
||||||
|
src={record.thumbnail}
|
||||||
|
alt={`片段${record.id}`}
|
||||||
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||||
|
/>
|
||||||
|
<div style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 28,
|
||||||
|
height: 28,
|
||||||
|
background: 'rgba(0,0,0,0.6)',
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}>
|
||||||
|
<PlayCircleOutlined style={{ fontSize: 16, color: '#fff' }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '画面内容',
|
||||||
|
width: 250,
|
||||||
|
|
||||||
|
render: (text: any, record: any) => (
|
||||||
|
<div style={{ fontSize: 14, color: '#333', lineHeight: 1.6 }}>
|
||||||
|
{record.content}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '台词',
|
||||||
|
width: 250,
|
||||||
|
|
||||||
|
render: (text: any, record: any) => (
|
||||||
|
<div style={{ fontSize: 14, color: '#333', lineHeight: 1.6 }}>
|
||||||
|
{record.lines}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '内容策略',
|
||||||
|
width: 120,
|
||||||
|
align: 'left' as const,
|
||||||
|
render: (text: any, record: any) => (
|
||||||
|
<div style={{ fontSize: 14, color: '#333', fontWeight: 500 }}>
|
||||||
|
{record.contentStrategy || '-'}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '素材',
|
||||||
|
width: 140,
|
||||||
|
align: 'center' as const,
|
||||||
|
render: (text: any, record: any) => (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
|
||||||
|
<div style={{ fontSize: 12, color: '#999', padding: '12px 24px', border: '1px dashed #ddd', borderRadius: 4 }}>
|
||||||
|
等待生成
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
onClick={() => handleGenerate(record.id)}
|
||||||
|
style={{ color: '#656efa', fontSize: 12, padding: 0, display: 'flex', alignItems: 'center', gap: 4 }}
|
||||||
|
>
|
||||||
|
视频生成
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div style={{ minHeight: '94vh', background: '#f5f5f5' }}>
|
||||||
|
<div style={{ background: '#fff', padding: '16px 24px 0 24px', boxShadow: '0 2px 8px rgba(0,0,0,0.06)' }}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<ArrowLeftOutlined />}
|
||||||
|
onClick={() => navigate(-1)}
|
||||||
|
style={{ fontSize: 16, color: '#666' }}
|
||||||
|
/>
|
||||||
|
<span style={{ fontSize: 18, fontWeight: 600 }}>{mockData.productName}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ }}>
|
||||||
|
<div style={{ background: '#fff', borderRadius: 12, padding: '10px 20px 20px 20px', marginBottom: 20 }}>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 30, marginBottom: 12 }}>
|
||||||
|
<div style={{ position: 'relative', width: 280, height: 160, borderRadius: 8, overflow: 'hidden', flexShrink: 0 }}>
|
||||||
|
<img
|
||||||
|
src={mockData.videoUrl}
|
||||||
|
alt="视频缩略图"
|
||||||
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||||
|
/>
|
||||||
|
<div style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
background: 'rgba(0,0,0,0.6)',
|
||||||
|
borderRadius: '50%',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}>
|
||||||
|
<PlayCircleOutlined style={{ fontSize: 28, color: '#fff' }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
|
||||||
|
<div>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
|
<h2 style={{ fontSize: 20, fontWeight: 600, marginBottom: 16 }}>视频总结</h2>
|
||||||
|
<div style={{ textAlign: 'right' }}>
|
||||||
|
<span style={{ color: '#999', fontSize: 12 }}>上传时间: {mockData.uploadTime}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', marginBottom: 12 }}>
|
||||||
|
<span style={{ color: '#999', fontSize: 14, marginRight: 12 }}>产品名称:</span>
|
||||||
|
<span style={{ color: '#333', fontWeight: 500 }}>{mockData.productName}</span>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', marginBottom: 12 }}>
|
||||||
|
<span style={{ color: '#999', fontSize: 14, marginRight: 12 }}>卖点词:</span>
|
||||||
|
<div style={{ display: 'flex', gap: 8 }}>
|
||||||
|
{mockData.sellingPoints.map((point, index) => (
|
||||||
|
<Tag key={index} color="purple" style={{ fontSize: 12 }}>
|
||||||
|
{point}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', marginBottom: 12 }}>
|
||||||
|
<span style={{ color: '#999', fontSize: 14, marginRight: 12 }}>受众群体:</span>
|
||||||
|
<span style={{ color: '#333' }}>{mockData.audience}</span>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<span style={{ color: '#999', fontSize: 14, marginRight: 12 }}>受众分析:</span>
|
||||||
|
<span style={{ color: '#333' }}>{mockData.audienceAnalysis}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ background: '#fff', borderRadius: 12, overflow: 'hidden' }}>
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
dataSource={mockData.segments}
|
||||||
|
pagination={false}
|
||||||
|
bordered={false}
|
||||||
|
rowKey="key"
|
||||||
|
scroll={{ y: 520 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Drawer
|
||||||
|
title={
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
|
||||||
|
<span>
|
||||||
|
<span style={{ color: '#6366f1' }}>智能视频复刻</span>
|
||||||
|
<span style={{ color: '#6366f1' }}>-片段{currentSegment}</span>
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<XOutlined />}
|
||||||
|
onClick={handleCloseDrawer}
|
||||||
|
style={{ padding: 0 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
placement="right"
|
||||||
|
closable={false}
|
||||||
|
onClose={handleCloseDrawer}
|
||||||
|
open={drawerVisible}
|
||||||
|
width={480}
|
||||||
|
bodyStyle={{ padding: '24px' }}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
|
||||||
|
<div>
|
||||||
|
<label style={{ fontWeight: 400, color: '#333', marginBottom: 12, display: 'block' }}>
|
||||||
|
产品白底图 <span style={{ color: '#ff4d4f' }}>*</span>
|
||||||
|
</label>
|
||||||
|
<div style={{ display: 'flex', gap: 16 }}>
|
||||||
|
<Upload
|
||||||
|
listType="picture-card"
|
||||||
|
onChange={handleProductImageChange}
|
||||||
|
maxCount={1}
|
||||||
|
accept="image/*"
|
||||||
|
style={{ width: 140, height: 140 }}
|
||||||
|
>
|
||||||
|
{!productImage && (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
|
||||||
|
<PlusOutlined style={{ fontSize: 24, color: '#999' }} />
|
||||||
|
<span style={{ fontSize: 12, color: '#999' }}>产品图 *</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Upload>
|
||||||
|
<Upload
|
||||||
|
listType="picture-card"
|
||||||
|
onChange={handleDetailImageChange}
|
||||||
|
maxCount={1}
|
||||||
|
accept="image/*"
|
||||||
|
style={{ width: 140, height: 140 }}
|
||||||
|
>
|
||||||
|
{!detailImage && (
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8 }}>
|
||||||
|
<PlusOutlined style={{ fontSize: 24, color: '#999' }} />
|
||||||
|
<span style={{ fontSize: 12, color: '#999' }}>细节图</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Upload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label style={{ fontWeight: 500, color: '#333', marginBottom: 12, display: 'block' }}>
|
||||||
|
产品名称
|
||||||
|
</label>
|
||||||
|
<Input
|
||||||
|
value={productName}
|
||||||
|
onChange={(e) => setProductName(e.target.value)}
|
||||||
|
placeholder="请输入产品名称"
|
||||||
|
style={{ height: 48, borderRadius: 8 }}
|
||||||
|
maxLength={10}
|
||||||
|
showCount
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label style={{ fontWeight: 500, color: '#333', marginBottom: 12, display: 'block' }}>
|
||||||
|
产品卖点
|
||||||
|
</label>
|
||||||
|
<TextArea
|
||||||
|
value={productSellingPoint}
|
||||||
|
onChange={(e) => setProductSellingPoint(e.target.value)}
|
||||||
|
placeholder="请输入产品卖点"
|
||||||
|
style={{ borderRadius: 8 }}
|
||||||
|
maxLength={100}
|
||||||
|
showCount
|
||||||
|
rows={3}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ display: 'flex', gap: 16, marginTop: 24 }}>
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
onClick={handleManualGenerate}
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
height: 48,
|
||||||
|
borderRadius: 8,
|
||||||
|
borderColor: '#6366f1',
|
||||||
|
color: '#6366f1',
|
||||||
|
fontWeight: 500
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
手动生成
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RemoveInfo;
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user