152 lines
3.7 KiB
JavaScript
152 lines
3.7 KiB
JavaScript
|
|
import React, { useState, useEffect } from 'react';
|
||
|
|
import { Spin, Alert, Tabs } from 'antd';
|
||
|
|
import ReactDiffViewer from 'react-diff-viewer-continued';
|
||
|
|
import api from '../api';
|
||
|
|
|
||
|
|
export default function FileDiff({ filePath, lobsterId }) {
|
||
|
|
const [loading, setLoading] = useState(false);
|
||
|
|
const [diffData, setDiffData] = useState(null);
|
||
|
|
const [error, setError] = useState(null);
|
||
|
|
|
||
|
|
const loadDiff = async () => {
|
||
|
|
setLoading(true);
|
||
|
|
setError(null);
|
||
|
|
|
||
|
|
try {
|
||
|
|
const response = await api.get('/diff/', {
|
||
|
|
params: { file_path: filePath, lobster_id: lobsterId }
|
||
|
|
});
|
||
|
|
|
||
|
|
if (response.success) {
|
||
|
|
setDiffData(response.data);
|
||
|
|
} else {
|
||
|
|
setError(response.error || '加载失败');
|
||
|
|
}
|
||
|
|
} catch (err) {
|
||
|
|
setError(err.message || '网络错误');
|
||
|
|
} finally {
|
||
|
|
setLoading(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (filePath) {
|
||
|
|
loadDiff();
|
||
|
|
}
|
||
|
|
}, [filePath]);
|
||
|
|
|
||
|
|
if (loading) {
|
||
|
|
return <Spin tip="加载中..." />;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (error) {
|
||
|
|
return <Alert message={error} type="error" />;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!diffData) {
|
||
|
|
return <Alert message="请选择文件" type="info" />;
|
||
|
|
}
|
||
|
|
|
||
|
|
const { local_content, db_content, status, diff } = diffData;
|
||
|
|
|
||
|
|
// 文件不存在的情况
|
||
|
|
if (!local_content && !db_content) {
|
||
|
|
return <Alert message="文件不存在" type="warning" />;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!local_content) {
|
||
|
|
return (
|
||
|
|
<Alert
|
||
|
|
message="文件仅存在于数据库"
|
||
|
|
description="点击「同步到本地」将文件恢复到本地"
|
||
|
|
type="info"
|
||
|
|
showIcon
|
||
|
|
/>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!db_content) {
|
||
|
|
return (
|
||
|
|
<Alert
|
||
|
|
message="文件仅存在于本地"
|
||
|
|
description="点击「同步到数据库」将文件备份到数据库"
|
||
|
|
type="warning"
|
||
|
|
showIcon
|
||
|
|
/>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const STATUS_MESSAGES = {
|
||
|
|
consistent: '文件内容一致',
|
||
|
|
local_newer: '本地文件有更新',
|
||
|
|
db_newer: '数据库版本更新',
|
||
|
|
conflict: '文件内容冲突',
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div>
|
||
|
|
<Alert
|
||
|
|
message={STATUS_MESSAGES[status] || '未知状态'}
|
||
|
|
type={status === 'consistent' ? 'success' : 'warning'}
|
||
|
|
style={{ marginBottom: 16 }}
|
||
|
|
showIcon
|
||
|
|
/>
|
||
|
|
|
||
|
|
<Tabs
|
||
|
|
defaultActiveKey="diff"
|
||
|
|
items={[
|
||
|
|
{
|
||
|
|
key: 'diff',
|
||
|
|
label: '差异对比',
|
||
|
|
children: (
|
||
|
|
<div style={{ overflowX: 'auto' }}>
|
||
|
|
<ReactDiffViewer
|
||
|
|
oldValue={db_content || ''}
|
||
|
|
newValue={local_content || ''}
|
||
|
|
splitView={true}
|
||
|
|
useDarkTheme={false}
|
||
|
|
leftTitle="数据库版本"
|
||
|
|
rightTitle="本地版本"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
key: 'local',
|
||
|
|
label: '本地内容',
|
||
|
|
children: (
|
||
|
|
<pre style={{
|
||
|
|
padding: '16px',
|
||
|
|
background: '#f5f5f5',
|
||
|
|
borderRadius: '4px',
|
||
|
|
maxHeight: '500px',
|
||
|
|
overflow: 'auto',
|
||
|
|
whiteSpace: 'pre-wrap',
|
||
|
|
wordBreak: 'break-word'
|
||
|
|
}}>
|
||
|
|
{local_content}
|
||
|
|
</pre>
|
||
|
|
),
|
||
|
|
},
|
||
|
|
{
|
||
|
|
key: 'db',
|
||
|
|
label: '数据库内容',
|
||
|
|
children: (
|
||
|
|
<pre style={{
|
||
|
|
padding: '16px',
|
||
|
|
background: '#f5f5f5',
|
||
|
|
borderRadius: '4px',
|
||
|
|
maxHeight: '500px',
|
||
|
|
overflow: 'auto',
|
||
|
|
whiteSpace: 'pre-wrap',
|
||
|
|
wordBreak: 'break-word'
|
||
|
|
}}>
|
||
|
|
{db_content}
|
||
|
|
</pre>
|
||
|
|
),
|
||
|
|
},
|
||
|
|
]}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|