Commit ef3e32e8 by zhaochengxiang

支持hive

parent dea3afbc
...@@ -518,19 +518,13 @@ const ImportAction = React.forwardRef((props, ref) => { ...@@ -518,19 +518,13 @@ const ImportAction = React.forwardRef((props, ref) => {
//分区 //分区
let newPartition = {...(newModelerData.partition||{})}; let newPartition = {...(newModelerData.partition||{})};
const newKeys = []; if (newModelerData.dbType === 'Hive') {
newPartition.keys = (newPartition.keys??[]).filter(item => (newModelerData.easyDataModelerDataModelAttributes??[]).findIndex(_item => item.iid === _item.iid) === -1)
(newPartition.keys||[]).forEach((item, index) => { } else {
const _index = (newModelerData.easyDataModelerDataModelAttributes||[]).findIndex(_item => item.iid === _item.iid); newPartition.keys = (newPartition.keys??[]).filter(item => (newModelerData.easyDataModelerDataModelAttributes??[]).findIndex(_item => item.iid === _item.iid) !== -1)
}
if (_index !== -1) {
newKeys.push({...newModelerData.easyDataModelerDataModelAttributes[_index]});
}
})
newPartition.keys = newKeys;
if ((newKeys||[]).length === 0) { if ((newPartition.keys||[]).length === 0) {
newPartition = null; newPartition = null;
} }
......
...@@ -8,6 +8,7 @@ import { highlightSearchContentByTerms, generateUUID, IsArr } from '../../../../ ...@@ -8,6 +8,7 @@ import { highlightSearchContentByTerms, generateUUID, IsArr } from '../../../../
import { dispatch, dispatchLatest } from '../../../../model'; import { dispatch, dispatchLatest } from '../../../../model';
import Rule from '../../ModelConfig/Component/rule-readonly'; import Rule from '../../ModelConfig/Component/rule-readonly';
import DebounceInput from './DebounceInput'; import DebounceInput from './DebounceInput';
import HivePartitionAddKey from './hive-partition-add-key';
import './ImportActionHeader.less'; import './ImportActionHeader.less';
...@@ -127,6 +128,7 @@ const ImportActionHeader = (props) => { ...@@ -127,6 +128,7 @@ const ImportActionHeader = (props) => {
const partitionsDescription = useMemo(() => { const partitionsDescription = useMemo(() => {
let newPartitionsDescription = '' let newPartitionsDescription = ''
if (modelerData?.partition?.keys) { if (modelerData?.partition?.keys) {
(modelerData?.partition?.keys||[]).forEach((item, index) => { (modelerData?.partition?.keys||[]).forEach((item, index) => {
if (index > 0) { if (index > 0) {
newPartitionsDescription += ','; newPartitionsDescription += ',';
...@@ -391,6 +393,17 @@ const ImportActionHeader = (props) => { ...@@ -391,6 +393,17 @@ const ImportActionHeader = (props) => {
</Col> </Col>
<Col xs={24} sm={24} lg={12} xl={8}> <Col xs={24} sm={24} lg={12} xl={8}>
<Form.Item <Form.Item
label="分区键"
name="partition"
style={{ marginBottom }}
>
{
editable ? <HivePartitionSelect modelerData={modelerData} partitionTypes={supportedPartitionTypes} /> : <span className='word-wrap'>{highlightSearchContentByTerms(partitionsDescription, terms)}</span>
}
</Form.Item>
</Col>
<Col xs={24} sm={24} lg={12} xl={8}>
<Form.Item
label="分桶字段" label="分桶字段"
name="distributionKey" name="distributionKey"
style={{ marginBottom }} style={{ marginBottom }}
...@@ -976,7 +989,7 @@ const PartitionSelect = ({ value = {}, modelerData, partitionTypes = [], onChang ...@@ -976,7 +989,7 @@ const PartitionSelect = ({ value = {}, modelerData, partitionTypes = [], onChang
{ {
(partitionTypes||[]).map((partitionType, index) => { (partitionTypes||[]).map((partitionType, index) => {
return ( return (
<Option key={partitionType.name||''}>{partitionType.cnName||''}</Option> <Option key={partitionType.name} value={partitionType.name}>{partitionType.cnName}</Option>
); );
}) })
} }
...@@ -1003,6 +1016,92 @@ const PartitionSelect = ({ value = {}, modelerData, partitionTypes = [], onChang ...@@ -1003,6 +1016,92 @@ const PartitionSelect = ({ value = {}, modelerData, partitionTypes = [], onChang
); );
} }
const HivePartitionSelect = ({ value, onChange, partitionTypes, modelerData }) => {
const [popupParams, setPopupParams] = useState({
visible: false,
value: undefined,
})
const onPartitionTypeChange = (value) => {
let currentPartitionType = {};
(partitionTypes||[]).forEach((partitionType, index) => {
if (value === partitionType.name) {
currentPartitionType = partitionType;
}
})
triggerChange({ partitionType: currentPartitionType });
}
const triggerChange = (changedValue) => {
onChange?.({
...value,
...changedValue,
})
}
return (
<>
<Row gutter={10}>
<Col span={10}>
<Select
onChange={onPartitionTypeChange}
value={value?.partitionType?.name}
placeholder='请选择分区类型'
allowClear={true}
>
{
(partitionTypes||[]).map((partitionType, index) => {
return (
<Option key={partitionType.name} value={partitionType.name}>{partitionType.cnName}</Option>
);
})
}
</Select>
</Col>
<Col span={14}>
<Select
mode='multiple'
placeholder='请选择字段名称'
onDropdownVisibleChange={(open) => {
if (open) {
setPopupParams({
visible: true,
value: value?.keys??[],
})
}
}}
open={false}
style={{ width: 300 }}
value={(value?.keys??[]).map(item => item.iid)}
options={(value?.keys??[]).map(item => ({ label: item.name, value: item.iid }))}
allowClear
onChange={(newValue) => {
let newKeys = [...value?.keys??[]]
newKeys = newKeys.filter(item => newValue.indexOf(item.iid)!==-1)
triggerChange({ keys: newKeys })
}}
maxTagCount='responsive'
/>
</Col>
</Row>
<HivePartitionAddKey
{...popupParams}
modelerData={modelerData}
onChange={(data) => {
setPopupParams({
visible: false,
value: undefined,
})
if (data) {
triggerChange({ keys: data })
}
}}
/>
</>
)
}
const LoadSelect = ({ value = '', onChange, ...restProps }) => { const LoadSelect = ({ value = '', onChange, ...restProps }) => {
const onLoadChange = (value) => { const onLoadChange = (value) => {
......
...@@ -61,7 +61,7 @@ const ResizeableHeaderCell = props => { ...@@ -61,7 +61,7 @@ const ResizeableHeaderCell = props => {
); );
}; };
export const DatatypeInput = ({ value = {}, datatypes, onChange }) => { export const DatatypeInput = ({ value = {}, datatypes = [], onChange }) => {
const onNameChange = (value) => { const onNameChange = (value) => {
......
import React from 'react'
import { Button, Modal, Table, Form, Input } from 'antd'
import { generateUUID, showMessage } from '../../../../util'
import { DatatypeInput } from './ImportActionTable'
import { dispatch } from '../../../../model'
import Suggest from './suggest'
function hasDuplicates(array) {
return (new Set(array)).size !== array.length;
}
const FC = (props) => {
const { visible, value, onChange, modelerData } = props
const basicRef = React.useRef()
const close = (data = undefined) => {
onChange?.(data)
}
const save = async () => {
try {
await basicRef.current.validate()
const data = basicRef.current.data
const names = (data??[]).map(item => item.name)
const cnNames = (data??[]).map(item => item.cnName)
if (hasDuplicates(names)) {
showMessage('warn', '英文名称重复')
return
}
if (hasDuplicates(cnNames)) {
showMessage('warn', '中文名称重复')
return
}
close(data)
} catch (errInfo) {
console.log('Validate Failed:', errInfo);
}
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button key={'save'} type='primary'
onClick={() => save()}
>保存</Button>
]
}, [close, save])
return (
<Modal
visible={visible}
footer={footer}
width='80%'
bodyStyle={{ padding: '15px 15px 0px 15px', overflowX: 'auto', maxHeight: '80vh', height: 500 }}
title='编辑分区字段'
centered destroyOnClose
onCancel={() => { close() }}
>
<Basic ref={basicRef} modelerData={modelerData} value={value} />
</Modal>
)
}
export default FC
const Basic = React.forwardRef(function ({ modelerData, value }, ref) {
const [form] = Form.useForm()
const [data, setData] = React.useState()
const [supportedDatatypes, setDatatypes] = React.useState()
const [suggestParams, setSuggestParams] = React.useState({
visible: false,
name: undefined,
cnName: undefined,
triggerType: undefined,
})
const [triggerSuggestItem, setTriggerSuggestItem] = React.useState()
React.useImperativeHandle(ref, () => ({
validate: async () => {
return await form?.validateFields()
},
data
}), [form, data])
React.useEffect(() => {
getSupportedDatatypes()
}, [])
React.useEffect(() => {
setData(value)
}, [value])
const columns = [
{
title: '中文名称',
dataIndex: 'cnName',
width: 200,
render: (_, record) => {
form?.setFieldsValue({ [`cnName${record.iid}`]: record.cnName })
return (
<Form.Item name={`cnName${record.iid}`}
rules={[{ required: true, message: '请输入中文名称' }]}
style={{ marginBottom: 0 }}
>
<Input placeholder='请输入中文名称' onChange={(e) => {
const newData = [...data??[]]
const index = newData.findIndex(item => item.iid === record.iid)
if (index !== -1) {
newData[index].cnName = e.target.value
setData(newData)
}
}} onPressEnter={() => {
setTriggerSuggestItem(record)
onColumnPressEnter('cnName', record)
}} />
</Form.Item>
)
}
},
{
title: '英文名称',
dataIndex: 'name',
width: 200,
render: (_, record) => {
form?.setFieldsValue({ [`name${record.iid}`]: record.name })
return (
<Form.Item name={`name${record.iid}`}
rules={[{ required: true, message: '请输入英文名称' }]}
style={{ marginBottom: 0 }}
>
<Input placeholder='请输入英文名称' onChange={(e) => {
const newData = [...data??[]]
const index = newData.findIndex(item => item.iid === record.iid)
if (index !== -1) {
newData[index].name = e.target.value
setData(newData)
}
}} onPressEnter={() => {
setTriggerSuggestItem(record)
onColumnPressEnter('name', record)
}} />
</Form.Item>
)
}
},
{
title: '类型',
dataIndex: 'datatype',
width: 200,
render: (_, record) => {
form?.setFieldsValue({ [`datatype${record.iid}`]: record.datatype })
return (
<Form.Item name={`datatype${record.iid}`}
rules={[{ required: true, message: '请输入类型' }]}
style={{ marginBottom: 0 }}
>
<DatatypeInput
datatypes={(supportedDatatypes??[]).filter(item => item.supportedDBTypes.indexOf(modelerData?.dbType) !== -1)}
onChange={(val) => {
const newData = [...data??[]]
const index = newData.findIndex(item => item.iid === record.iid)
if (index !== -1) {
newData[index].datatype = val
setData(newData)
}
}} />
</Form.Item>
)
}
},
{
title: '业务含义',
dataIndex: 'remark',
width: 200,
render: (_, record) => {
form?.setFieldsValue({ [`remark${record.iid}`]: record.remark })
return (
<Form.Item name={`remark${record.iid}`}
rules={[{ required: true, message: '请输入业务含义' }]}
style={{ marginBottom: 0 }}
>
<Input placeholder='请输入业务含义' onChange={(e) => {
const newData = [...data??[]]
const index = newData.findIndex(item => item.iid === record.iid)
if (index !== -1) {
newData[index].remark = e.target.value
setData(newData)
}
}} />
</Form.Item>
)
}
},
{
title: '操作',
dataIndex: 'action',
width: 80,
render: (_, record) => {
return <a onClick={() => {
const newData = [...data??[]]
const index = newData.findIndex(item => item.iid === record.iid)
if (index !== -1) {
newData.splice(index, 1)
setData(newData)
}
}}>删除</a>
}
}
]
const getSupportedDatatypes = () => {
dispatch({
type: 'datamodel.getSupportedDatatypes',
callback: data => {
setDatatypes(data)
}
});
}
const onColumnPressEnter = (dataIndex, record) => {
setSuggestParams({
visible: true,
name: record.name,
cnName: record.cnName,
triggerType: dataIndex,
})
}
const onSuggestChange = (record) => {
const newData = [...data??[]]
const index = newData.findIndex(item => item.iid === triggerSuggestItem?.iid)
if (index !== -1) {
newData.splice(index, 1, record)
setData(newData)
}
}
return (
<>
<div className='mb-3 flex' style={{ justifyContent: 'flex-end' }}>
<Button onClick={() => {
const iid = generateUUID()
const newData = [...data??[], { iid }]
setData(newData)
}}>新建</Button>
</div>
<Form form={form}>
<Table
columns={columns}
dataSource={data}
pagination={false}
/>
</Form>
<Suggest
{...suggestParams}
onCancel={() => {
setSuggestParams({
visible: false,
name: undefined,
cnName: undefined,
triggerType: undefined,
})
}}
onOk={onSuggestChange}
/>
</>
)
})
\ 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