Commit d0fe4fb6 by zhaochengxiang

版本历史

parent 1d0cab49
......@@ -225,3 +225,15 @@ export function* autoCreateTable(payload) {
export function* searchModel(payload) {
return yield call(datamodelerService.searchModel, payload);
}
export function* getVersions(payload) {
return yield call(datamodelerService.getVersions, payload);
}
export function* compare(payload) {
return yield call(datamodelerService.compare, payload);
}
export function* getDataModelByVersionId(payload) {
return yield call(datamodelerService.getDataModelByVersionId, payload);
}
import { PostFile, GetJSON, PostJSON } from "../util/axios"
import { PostFile, GetJSON, PostJSON, Post } from "../util/axios"
export function loadDataModelCatalog() {
return GetJSON("/datamodeler/easyDataModelerCURD/loadDataModelCatalog");
......@@ -129,6 +129,18 @@ export function searchModel(payload) {
return GetJSON("/datamodeler/easyDataModelerCURD/searchEasyDataModelerDataModelsByNaming", payload);
}
export function getVersions(payload) {
return PostJSON("/datamodeler/easyDataModelerCURD/getVersions", payload);
}
export function compare(payload) {
return Post("/datamodeler/easyDataModelerCURD/compare", payload);
}
export function getDataModelByVersionId(payload) {
return PostJSON("/datamodeler/easyDataModelerCURD/getDataModelByVersionId", payload);
}
export function ddlGenerators() {
return GetJSON("/datamodeler/easyDataModelerExport/ddlGenerators");
}
......
......@@ -10,4 +10,5 @@ export const Hints = 'hints';
export const ModelerData = 'mdata';
export const Editable = 'editable';
export const PermitCheckOut = 'permitCheckOut';
export const StateId = 'sid';
\ No newline at end of file
export const StateId = 'sid';
export const VersionId = 'vid';
\ No newline at end of file
......@@ -226,6 +226,54 @@ export function highlightSearchContentByTerms(content, terms) {
return highlightSearchContent(processContent);
}
export function highlightVersionChangeInformation(content) {
if (content===null || content==='') return '';
const startDeleteFlag = '<DD>';
const endDeleteFlag = '</DD>';
const startAddFlag = '<AA>';
const endAddFlag = '</AA>';
const startDelete = content.indexOf(startDeleteFlag);
const endDelete = content.indexOf(endDeleteFlag);
const startAdd = content.indexOf(startAddFlag);
const endAdd = content.indexOf(endAddFlag);
let start = -1, end = 0, startFlag = '', endFlag = '', isDelete = false;
if (startDelete!==-1 && (startAdd===-1 || startDelete<startAdd)) {
start = startDelete;
end = endDelete;
startFlag = startDeleteFlag;
endFlag = endDeleteFlag;
isDelete = true;
} else if (startAdd!==-1 && (startDelete===-1 || startDelete>startAdd)) {
start = startAdd;
end = endAdd;
startFlag = startAddFlag;
endFlag = endAddFlag;
isDelete = false;
}
const beforeStr = content.substr(0, start);
const middleStr = content.substr(start + startFlag.length, end - start - startFlag.length);
const afterStr = content.substr(end + endFlag.length);
return (
<>
{
start > -1 ? <span>
{beforeStr}
<span style={{ backgroundColor: isDelete?'#ffe7e7':'#ddfade', textDecoration: isDelete?'line-through':'' }}>{middleStr}</span>
{highlightVersionChangeInformation(afterStr)}
</span> : <span>{content}</span>
}
</>
)
}
export function formatDate(t) {
if (t === null) return '';
......@@ -237,4 +285,17 @@ export function formatDate(t) {
var mm = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + ':';
var ss = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
return YY + MM + DD +" "+hh + mm + ss;
}
export function formatVersionDate(t) {
if (t === null) return '';
var date = new Date(t);
var YY = date.getFullYear() + '-';
var MM = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-';
var DD = (date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate());
var hh = (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + '-';
var mm = (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) + '-';
var ss = (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds());
return YY + MM + DD +"_"+hh + mm + ss;
}
\ No newline at end of file
......@@ -6,18 +6,20 @@ import ImportAction from './ImportAction';
import CatalogModal from './CatalogModal';
import { dispatchLatest } from '../../../../model';
import { getQueryParam, showMessage } from '../../../../util';
import { Action, CatalogId, ModelerId, Hints, ModelerData, PermitCheckOut, Editable, StateId } from '../../../../util/constant';
import { Action, CatalogId, ModelerId, Hints, ModelerData, PermitCheckOut, Editable, StateId, VersionId } from '../../../../util/constant';
import HistoryAndVersionDrawer from './HistoryAndVersionDrawer';
const EditModel = (props) => {
const [ actionData, setActionData ] = useState({ action: '', catalogId: '', modelerId: '', hints: [], roughModelerData: null, permitCheckOut: false, editable: false, stateId: '' });
const [ actionData, setActionData ] = useState({ action: '', catalogId: '', modelerId: '', hints: [], roughModelerData: null, permitCheckOut: false, editable: false, stateId: '', versionId: '' });
const [ modelerData, setModelerData ] = useState({});
const [ terms, setTerms ] = useState([]);
const [ confirmLoading, setConfirmLoading ] = useState(false);
const [ catalogModalVisible, setCatalogModalVisible ] = useState(false);
const [ historyAndVersionDrawerVisible, setHistoryAndVersionDrawerVisible ] = useState(false);
const { action, catalogId, modelerId, hints, roughModelerData, permitCheckOut, editable, stateId } = actionData;
const { action, catalogId, modelerId, hints, roughModelerData, permitCheckOut, editable, stateId, versionId } = actionData;
const [form] = Form.useForm();
......@@ -30,6 +32,7 @@ const EditModel = (props) => {
const _permitCheckOut = getQueryParam(PermitCheckOut, props.location.search);
const _editable = getQueryParam(Editable, props.location.search);
const _stateId = getQueryParam(StateId, props.location.search);
const _versionId = getQueryParam(VersionId, props.location.search);
let _hints = [];
if ((_hintsStr||'') !== '') {
......@@ -41,7 +44,7 @@ const EditModel = (props) => {
_roughModelerData = JSON.parse(_modelerDataStr);
}
setActionData({ action: _action, catalogId: _catalogId, modelerId: _modelerId, hints: _hints, roughModelerData: _roughModelerData, permitCheckOut: _permitCheckOut, editable: _editable, stateId: _stateId });
setActionData({ action: _action, catalogId: _catalogId, modelerId: _modelerId, hints: _hints, roughModelerData: _roughModelerData, permitCheckOut: _permitCheckOut, editable: _editable, stateId: _stateId, versionId: _versionId });
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
......@@ -93,7 +96,7 @@ const EditModel = (props) => {
setConfirmLoading(false);
showMessage("success", '保存模型成功');
setActionData({ ...actionData, ...{ action: 'detail', modelerId: data.id||'' } });
setActionData({ ...actionData, ...{ action: 'detail', modelerId: data.id||'', stateId: data?.state?.id||'', permitCheckOut: data?.permitCheckOut||false } });
LocalStorage.set('modelChange', !(LocalStorage.get('modelChange')||false));
}
},
......@@ -126,6 +129,14 @@ const EditModel = (props) => {
save(null, id);
}
const onHistory = () => {
setHistoryAndVersionDrawerVisible(true);
}
const onHistoryAndVersionDrawerCancel = () => {
setHistoryAndVersionDrawerVisible(false);
}
let title = '';
if (action === 'add') {
title = '新增模型';
......@@ -133,6 +144,8 @@ const EditModel = (props) => {
title = '模型编辑';
} else if (action === 'detail' || action === 'flow') {
title = '模型详情';
} else if (action === 'detail-version') {
title = '模型版本详情';
}
let actionsBtn = null;
......@@ -149,9 +162,14 @@ const EditModel = (props) => {
)
} else if (action === 'detail') {
actionsBtn = (
(editable==='true'||permitCheckOut==='true') && <Button type='primary' onClick={edit} >
编辑
</Button>
<Space>
<Button onClick={onHistory} >版本历史</Button>
{
(editable==='true'||permitCheckOut==='true') && <Button type='primary' onClick={edit} >
编辑
</Button>
}
</Space>
);
} else if (action === 'edit') {
actionsBtn = (
......@@ -159,6 +177,9 @@ const EditModel = (props) => {
<Button onClick={cancelEdit} >
取消
</Button>
<Button onClick={onHistory} >
版本历史
</Button>
<Button
type='primary'
onClick={save}
......@@ -191,13 +212,18 @@ const EditModel = (props) => {
</div>
<div className='position-absolute' style={{ top: 64, width: '100%' }}>
<div className='position-relative' style={{ margin: 15 }}>
<ImportAction hints={hints} onChange={onActionChange} action={action} modelerId={modelerId} form={form} terms={terms} roughModelerData={roughModelerData} permitCheckOut={permitCheckOut} stateId={stateId} />
<ImportAction hints={hints} onChange={onActionChange} action={action} modelerId={modelerId} form={form} terms={terms} roughModelerData={roughModelerData} permitCheckOut={permitCheckOut} stateId={stateId} versionId={versionId} />
</div>
</div>
<CatalogModal
visible={catalogModalVisible}
onCancel={onCatalogModalCancel}
/>
<HistoryAndVersionDrawer
id={modelerId}
visible={historyAndVersionDrawerVisible}
onCancel={onHistoryAndVersionDrawerCancel}
/>
</div>
);
}
......
import React from 'react';
import { Drawer, Tabs } from 'antd';
import VersionHistory from './VersionHistory';
import VersionCompare from './VersionCompare';
const { TabPane } = Tabs;
......@@ -13,7 +14,7 @@ const HistoryAndVersionDrawer = (props) => {
title=''
placement="right"
closable={true}
width={1200}
width={1000}
onClose={() => {
onCancel && onCancel();
}}
......@@ -21,10 +22,10 @@ const HistoryAndVersionDrawer = (props) => {
>
<Tabs defaultActiveKey="1" type="card" size='small'>
<TabPane tab="版本历史" key="1">
<VersionHistory id={id} />
</TabPane>
<TabPane tab="版本对比" key="2">
<VersionCompare />
<VersionCompare id={id} />
</TabPane>
</Tabs>
</Drawer>
......
......@@ -9,7 +9,7 @@ import ImportActionPartition from './ImportActionPartition';
import { dispatch } from '../../../../model';
const ImportAction = (props) => {
const { action, hints, onChange, form, modelerId, terms, ddl, roughModelerData, permitCheckOut, stateId } = props;
const { action, hints, onChange, form, modelerId, terms, ddl, roughModelerData, permitCheckOut, stateId, versionId } = props;
const [ constraints, setConstraints ] = useState([]);
const [ constraint, setConstraint ] = useState({});
......@@ -58,7 +58,7 @@ const ImportAction = (props) => {
} else {
getDraft((data.constraints||[]).length>0?data.constraints[0]:{}, {} ,[]);
}
} else if(action === 'edit' || action === 'detail' || action ==='flow') {
} else if(action === 'edit' || action === 'detail' || action ==='flow' || action === 'detail-version') {
getCurrentDataModel();
}
},
......@@ -138,6 +138,14 @@ const ImportAction = (props) => {
type = 'datamodel.getDataModelWithRecommendedDefinitionAndTermDiscovery';
} else if (action==='edit' && permitCheckOut === 'true') {
type = 'datamodel.getCheckOutDataModel';
} else if (action === 'detail-version') {
type = 'datamodel.getDataModelByVersionId';
params = {
params: {
id: modelerId||'',
versionId
}
}
} else {
params.stateId = stateId||'';
}
......@@ -322,7 +330,7 @@ const ImportAction = (props) => {
const container = (<React.Fragment>
<ImportActionHeader
form={form}
editable={action!=='detail'&&action!=='flow'}
editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'}
modelerData={modelerData||{}}
constraints={constraints}
templates={templates}
......@@ -339,7 +347,7 @@ const ImportAction = (props) => {
validateReports={validateReports}
supportedDatatypes={supportedDatatypes}
onChange={onTableChange}
editable={action!=='detail'&&action!=='flow'}
editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'}
action={action}
terms={terms}
/>
......@@ -349,7 +357,7 @@ const ImportAction = (props) => {
template={template}
validateReports={validateReports}
onChange={onIndexChange}
editable={action!=='detail'&&action!=='flow'}
editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'}
terms={terms}
/>
<ImportActionPartition
......@@ -359,7 +367,7 @@ const ImportAction = (props) => {
validateReports={validateReports}
supportedPartitionTypes={supportedPartitionTypes}
onChange={onPartitionChange}
editable={action!=='detail'&&action!=='flow'}
editable={action!=='detail'&&action!=='flow'&&action!=='detail-version'}
terms={terms}
/>
</React.Fragment>);
......
......@@ -90,9 +90,9 @@ const ModelTable = (props) => {
<Tooltip placement='bottom' title={'删除'}>
<Button icon={<DeleteOutlined />} size='small' disabled={!record.deletable} onClick={() => { deleteItem(record); }} />
</Tooltip>
{/* <Tooltip placement='bottom' title={'版本历史'}>
<Tooltip placement='bottom' title={'版本历史'}>
<Button icon={<HistoryOutlined />} size='small' onClick={() => { historyItem(record); }} />
</Tooltip> */}
</Tooltip>
</React.Fragment>
}
{
......@@ -177,7 +177,7 @@ const ModelTable = (props) => {
id: modelId
},
callback: data => {
setSubData([data]);
setSubData((data||[])?[]:[data]);
},
error: () => {
......
import React, { useState } from 'react';
import { Form, Select } from 'antd';
import React, { useEffect, useState } from 'react';
import { Form, Select, Spin } from 'antd';
import { highlightVersionChangeInformation } from '../../../../util';
import { dispatch, dispatchLatest } from '../../../../model';
import { formatVersionDate } from '../../../../util';
const { Option } = Select;
const versions = [
't_branch-2021-09-24_08-49(当前版本)',
't_branch-2021-09-23_08-49',
't_branch-2021-09-22_08-49',
't_branch-2021-09-21_08-49',
];
const basicChangeInformation = '编码:<DD>t_branch</DD>-><AA>t_branch_zcx</AA> \n 名称:<DD>t_branch</DD>-><AA>t_branch_zcx</AA>';
const fieldChangeInformation = '编码:<DD>t_branch</DD>-><AA>t_branch_zcx</AA> \n 名称:<DD>t_branch</DD>-><AA>t_branch_zcx</AA>';
const VersionCompare = (props) => {
const { id } = props;
const [ basicVersion, setBasicVersion ] = useState('');
const [ basicVersions, setBasicVersions ] = useState([]);
const [ incVersion, setIncVersion ] = useState('');
const [ incVersions, setIncVersions ] = useState([]);
const [ changeInformation, setChangeInformation ] = useState('');
const [ loading, setLoading ] = useState(false);
const [ loadingCompare, setLoadingCompare ] = useState(false);
useEffect(() => {
if ((id||'') !== '') {
getVersions();
}
}, [ id ])
const getVersions = () => {
setLoading(true);
dispatch({
type: 'datamodel.getVersions',
payload: {
params: {
id
}
},
callback: data => {
setLoading(false);
const newData = [];
(data||[]).forEach((item, index) => {
let name = formatVersionDate(item.ts);
if (index === 0) {
name = name+'(当前版本)';
}
newData.push({ id: item.id, name });
})
setBasicVersions(newData);
},
error: () => {
setLoading(false);
}
})
}
const onBasicChange = (value) => {
setBasicVersion(value);
setIncVersion('');
const index = (versions||[]).indexOf(value);
setIncVersions((versions||[]).slice(0, index));
let index = -1;
(basicVersions||[]).forEach((version, i) => {
if (version.id === value) {
index = i;
}
})
setIncVersions((basicVersions||[]).slice(0, index));
}
const onIncChange = (value) => {
setIncVersion(value);
setLoadingCompare(true);
dispatchLatest({
type: 'datamodel.compare',
payload: {
params: {
versionId1: basicVersion,
versionId2: value
}
},
callback: data => {
setLoadingCompare(false);
setChangeInformation(data||'');
},
error: () => {
setLoadingCompare(false);
}
})
}
return (
<div>
<Form layout='inline'>
<Form.Item label='基线版本'>
<Select value={basicVersion} style={{ width: 300 }} onChange={onBasicChange} >
<Select loading={loading} value={basicVersion} style={{ width: 300 }} onChange={onBasicChange} >
{
(versions||[]).map((version, index) => {
(basicVersions||[]).map((version, index) => {
return (
<Option key={index} value={version||''} disabled={index===0}>{version||''}</Option>
<Option key={index} value={version.id||''} disabled={index===0}>{version.name||''}</Option>
);
})
}
......@@ -47,13 +114,23 @@ const VersionCompare = (props) => {
{
(incVersions||[]).map((version, index) => {
return (
<Option key={index} value={version||''}>{version||''}</Option>
<Option key={index} value={version.id||''}>{version.name||''}</Option>
);
})
}
</Select>
</Form.Item>
</Form>
<Spin spinning={loadingCompare}>
{
(changeInformation||''!=='') && (
<React.Fragment>
<div>变化信息</div>
<div>{changeInformation}</div>
</React.Fragment>
)
}
</Spin>
</div>
);
}
......
import React, { useEffect, useState } from 'react';
import { Timeline, Spin } from 'antd';
import { dispatch } from '../../../../model';
import { formatVersionDate } from '../../../../util';
import { Action, ModelerId, VersionId } from '../../../../util/constant';
const VersionHistory = (props) => {
const { id } = props;
const [ versions, setVersions ] = useState([]);
const [ loading, setLoading ] = useState(false);
useEffect(() => {
if ((id||'') !== '') {
getVersions();
}
}, [ id ])
const getVersions = () => {
setLoading(true);
dispatch({
type: 'datamodel.getVersions',
payload: {
params: {
id
}
},
callback: data => {
setLoading(false);
setVersions(data||[]);
},
error: () => {
setLoading(false);
}
})
}
const onVersionItemClick = (version) => {
window.open(`/data-govern/data-model-action?${Action}=detail-version&${ModelerId}=${version.dataModelId||''}&${VersionId}=${version.id||''}`);
}
return (
<Spin spinning={loading}>
<Timeline style={{ padding: 24 }}>
{
(versions||[]).map((version, index) => {
return <Timeline.Item key={index} >
<a onClick={()=>{ onVersionItemClick(version); }}>
{formatVersionDate(version.ts)}
</a>
</Timeline.Item>
})
}
</Timeline>
</Spin>
);
}
export default VersionHistory;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment