Commit 106d7371 authored by LiXuyang's avatar LiXuyang

文件加载-映射规则配置改

parent 1da26f8b
<template>
<BasicModal width="40%" v-bind="$attrs" @register="registerModal" @ok="handleSubmit">
<template #title>
<span style="font-size: 23px; font-weight: lighter">新建规则</span>
</template>
<Span style="font-size: 18px">
<Icon
style="margin-right: 5px; font-size: 18px"
:color="'#5cb3ff'"
icon="material-symbols:table-convert-outline"
/>数据转换规则
</Span>
<List>
<Row :gutter="16">
<template v-for="item in cardRuleList" :key="item.title">
<Col :span="12">
<ListItem>
<Card :hoverable="true" class="sceneSelectionCard" @click="handleNewModal(item.type)">
<div class="sceneSelectionTitle">
{{ item.title }}
</div>
<div class="sceneSelectionDescription">
{{ item.description }}
</div>
</Card>
</ListItem>
</Col>
</template>
</Row>
</List>
</BasicModal>
<NewFieldRuleModal @register="registerNewFieldRuleModal" />
<DataTransformationRuleModal @register="registerDataTransformationRuleModal" />
<DataFilterRuleModal @register="dataFilterRuleModal" />
</template>
<script lang="ts" setup>
import { onMounted } from 'vue';
import Icon from '@/components/Icon/Icon.vue';
import { BasicModal, useModal, useModalInner } from '@/components/Modal';
import { Card, Row, Col, List, ListItem } from 'ant-design-vue';
import { cardRuleList } from './fileData';
import NewFieldRuleModal from '@/views/dataIntegration/dataLoading/dataEntryLake/newFieldRuleModal.vue';
import DataTransformationRuleModal from '@/views/dataIntegration/dataLoading/dataEntryLake/dataTransformationRuleModal.vue';
import SingleTableFieldMappingRuleModal from '@/views/dataIntegration/dataLoading/dataEntryLake/singleTableFieldMappingRuleModal.vue';
import DataFilterRuleModal from './dataFilterRuleModal.vue';
const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => {});
const [registerNewFieldRuleModal, { openModal: openNewFieldRuleModal }] = useModal();
const [registerDataTransformationRuleModal, { openModal: openDataTransformationRuleModal }] =
useModal();
const [dataFilterRuleModal, { openModal: openDataFilterRuleModal }] = useModal();
function handleNewModal(type) {
console.log(type);
switch (type) {
case 'newFieldRule':
openNewFieldRuleModal(true);
break;
case 'dataTransformationRule':
openDataTransformationRuleModal(true);
break;
case 'dataFilterRule':
openDataFilterRuleModal(true);
break;
default:
console.log('Unknown rule type');
}
}
function handleSubmit() {
closeModal();
}
onMounted(() => {
setModalProps({ canFullscreen: false, okText: '下一步' });
});
</script>
<style lang="scss" scoped>
.sceneSelectionCard {
height: 120px;
flex-direction: column;
}
.sceneSelectionIcon {
font-size: 40px !important;
margin-bottom: 16px;
}
.sceneSelectionTitle {
font-size: 18px;
font-weight: bold;
margin-bottom: 8px;
}
.sceneSelectionDescription {
font-size: 14px;
color: #78787c;
text-align: left;
line-height: 1.2;
}
</style>
<template>
<BasicModal
width="40%"
v-bind="$attrs"
@register="registerModal"
:title="getTitle"
@ok="handleSubmit"
@cancel="handleCancel"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, unref } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { BasicForm, useForm } from '@/components/Form';
import { dataFilterRuleModalFormSchema } from '@/views/dataIntegration/dataLoading/fileLoading/file.data';
const isUpdate = ref(false);
const isMove = ref(false);
const rowId = ref('');
const getTitle = '数据过滤规则';
//获取接口数据并放在下拉框里(这里是打开了一个弹框)
//初始化表单
const [registerForm, { getFieldsValue, setFieldsValue, updateSchema, resetFields, validate, clearValidate }] =
useForm({
labelWidth: 100,
baseColProps: { span: 24 },
schemas: dataFilterRuleModalFormSchema,
showActionButtonGroup: false,
actionColOptions: {
span: 23,
},
});
//初始化弹框
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
await resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
isMove.value = !!data?.isMove;
if (unref(isUpdate)) {
// 获取行数据的id
rowId.value = data.record.businessId;
// 塞值
await setFieldsValue({
...data.record,
});
}
});
/**确定按钮*/
async function handleSubmit() {
await validate();
closeModal();
}
function handleCancel() {
clearValidate();
}
</script>
import {FormSchema} from "@/components/Form"; import {FormSchema} from "@/components/Form";
import {BasicColumn} from "@/components/Table"; import {BasicColumn} from "@/components/Table";
import {InputProps} from "ant-design-vue";
export const fileUploadSchema: FormSchema[] = [ export const fileUploadSchema: FormSchema[] = [
{ {
...@@ -51,19 +52,7 @@ export const fileUploadSchema: FormSchema[] = [ ...@@ -51,19 +52,7 @@ export const fileUploadSchema: FormSchema[] = [
return model.type === '文件系统'; return model.type === '文件系统';
}, },
defaultValue: '全量文件加载', defaultValue: '全量文件加载',
component: 'RadioGroup', slot: 'loadingType',
componentProps: {
options: [
{
label: '全量文件加载',
value: '全量文件加载',
},
{
label: '增量文件加载',
value: '增量文件加载',
},
],
},
}, },
{ {
label: '数据源', label: '数据源',
...@@ -475,3 +464,20 @@ export const showTableColumn: BasicColumn[] = [ ...@@ -475,3 +464,20 @@ export const showTableColumn: BasicColumn[] = [
slots: { customRender: 'targetColumnName' }, slots: { customRender: 'targetColumnName' },
}, },
]; ];
export const dataFilterRuleModalFormSchema: FormSchema[] = [
{
label: '规则名称',
field: 'name',
required: true,
component: 'Input',
},
{
label: '自定义规则',
field: 'rule',
component: 'InputTextArea',
componentProps: {
placeholder: '请输入自定义过滤规则',
rows: 4,
} as InputProps,
},
];
export const fileData = [ import Mock, { Random } from 'mockjs';
{
c1: '100', // 自定义函数:生成在指定日期范围内的随机日期
c2: '1132', function getRandomDate(start, end) {
c3: '', const startTime = new Date(start).getTime();
c4: '', const endTime = new Date(end).getTime();
c5: '1.1', const randomTime = new Date(startTime + Math.random() * (endTime - startTime));
c6: '', return randomTime.toISOString().slice(0, 19).replace('T', ' '); // 格式化为 "yyyy-MM-dd HH:mm:ss"
c7: '', }
c8: '', const startDate = '2023-01-01 00:00:00'; // 起始日期
c9: '', const endDate = '2024-12-31 23:59:59'; // 结束日期
c10: '',
}, export const fileData = (num) => {
{ return Mock.mock({
c1: '101', [`list|${num}`]: [
c2: '1200', // 根据 num 动态生成用户数量
c3: '', {
c4: '', 'c1|+1': 1,
c5: '1.1', 'c2|18-60': 1,
c6: '', c3: '@cname',
c7: '', c4: '@pick(["男", "女"])',
c8: '', 'c5|170-190': 1,
c9: '', c6: function () {
c10: '', return getRandomDate(startDate, endDate);
}, },
{ c7: function () {
c1: '102', return getRandomDate(startDate, endDate);
c2: '1200', },
c3: '', c8: '@cname',
c4: '', c9: '@cname',
c5: '1.1', c10: '@sentence(5, 10)',
c6: '', },
c7: '', ],
c8: '', }).list;
c9: '', };
c10: '',
},
{
c1: '103',
c2: '1200',
c3: '',
c4: '',
c5: '1.1',
c6: '',
c7: '',
c8: '',
c9: '',
c10: '',
},
];
export const dataSourceData = [ export const dataSourceData = [
{ {
businessId: 1, businessId: 1,
...@@ -77,3 +62,37 @@ export const dataSourceFieldData = [ ...@@ -77,3 +62,37 @@ export const dataSourceFieldData = [
fieldRemark: null, fieldRemark: null,
}, },
]; ];
export const cardRuleList = [
{
title: '【全局】新增字段规则',
type: 'newFieldRule',
description: '为源端所有数据表都新增一个字段,例如为每张表增加一个入库时间列',
},
{
title: '数据转换规则',
type: 'dataTransformationRule',
description: '根据业务需求,对源端单张数据表的单个字段进行数据转换操作',
},
{
title: '数据过滤规则',
type: 'dataFilterRule',
description: '根据业务需求,对源端单张数据表的数据进行过滤操作',
},
];
export const mappingRuleConfigurationTableList = [
{
businessId: 1,
ruleName: '[全局] 新增字段规则',
ruleContent: '新增字段名称:a, 字段类型:string, 字段表达式:asd',
},
{
businessId: 2,
ruleName: '数据转换规则',
ruleContent: '数据表: table1, 已有字段: field1, 转换规则: 配置规则',
},
{
businessId: 3,
ruleName: '数据过滤规则',
ruleContent: "自定义规则:field1 != 'axxc'",
},
];
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<template #footer> <template #footer>
<Tabs v-model:activeKey="activeKey"> <Tabs v-model:activeKey="activeKey">
<TabPane key="1" tab="源端配置"> <TabPane key="1" tab="源端配置">
<div style="display: flex"> <div style="display: flex; padding-top: 20px; gap: 20px">
<BasicForm class="w-1/3" @register="fileForm"> <BasicForm class="w-1/3" @register="fileForm">
<template #file="{ field, model }"> <template #file="{ field, model }">
<Upload <Upload
...@@ -20,6 +20,15 @@ ...@@ -20,6 +20,15 @@
</Upload> </Upload>
<span style="color: #dbdcdd; font-size: 12px">仅支持上传单个文件或zip包</span> <span style="color: #dbdcdd; font-size: 12px">仅支持上传单个文件或zip包</span>
</template> </template>
<template #loadingType="{ field, model }">
<RadioGroup v-model:value="model[field]" :options="loadingTypeOptions" />
<Alert
v-if="model[field] === '增量文件加载'"
show-icon
message="仅支持HDFS类型的文件系统"
style="margin-top: 15px"
/>
</template>
<template #path="{ field, model }"> <template #path="{ field, model }">
<div style="display: flex"> <div style="display: flex">
<Input v-model:value="model[field]" /> <Input v-model:value="model[field]" />
...@@ -59,8 +68,12 @@ ...@@ -59,8 +68,12 @@
</BasicForm> </BasicForm>
<div class="w-2/3"> <div class="w-2/3">
<Alert show-icon message="由于数据量太大,只展示前10行数据" /> <Alert show-icon message="由于数据量太大,只展示前10行数据" />
<Alert show-icon message="当前服务将会表头中把除了下划线以外其他特殊字符转为下划线" /> <Alert
<BasicTable v-if="showFileTable" @register="fileTable"> style="margin-top: 10px"
show-icon
message="当前服务将会表头中把除了下划线以外其他特殊字符转为下划线"
/>
<BasicTable style="margin-top: 15px" v-if="showFileTable" @register="fileTable">
<template #toolbar> <template #toolbar>
<div style="flex: 1; display: flex; justify-content: space-between"> <div style="flex: 1; display: flex; justify-content: space-between">
<Input style="width: 200px" v-model:value="key" placeholder="关键字搜索" /> <Input style="width: 200px" v-model:value="key" placeholder="关键字搜索" />
...@@ -400,7 +413,8 @@ ...@@ -400,7 +413,8 @@
import { import {
compareColumns, compareColumns,
compareSearchFormSchema, compareSearchFormSchema,
getMetadataColumns, mappingRuleConfigurationColumns, getMetadataColumns,
mappingRuleConfigurationColumns,
tabularPresentationColumns, tabularPresentationColumns,
tabularPresentationSearchFormSchema, tabularPresentationSearchFormSchema,
} from '@/views/dataIntegration/dataLoading/dataEntryLake/offlineLoading.data'; } from '@/views/dataIntegration/dataLoading/dataEntryLake/offlineLoading.data';
...@@ -412,18 +426,19 @@ ...@@ -412,18 +426,19 @@
dataSourceData, dataSourceData,
dataSourceFieldData, dataSourceFieldData,
fileData, fileData,
mappingRuleConfigurationTableList,
} from '@/views/dataIntegration/dataLoading/fileLoading/fileData'; } from '@/views/dataIntegration/dataLoading/fileLoading/fileData';
import { useMessage } from '@/hooks/web/useMessage'; import { useMessage } from '@/hooks/web/useMessage';
import type { UploadChangeParam } from 'ant-design-vue'; import type { UploadChangeParam } from 'ant-design-vue';
import { import {
compareTableList, mappingRuleConfigurationTableList, compareTableList,
tabularPresentationTableList, tabularPresentationTableList,
} from '@/views/dataIntegration/dataLoading/dataEntryLake/mock'; } from '@/views/dataIntegration/dataLoading/dataEntryLake/mock';
import ViewLogModal from '@/views/dataIntegration/dataLoading/dataEntryLake/ViewLogModal.vue'; import ViewLogModal from '@/views/dataIntegration/dataLoading/dataEntryLake/ViewLogModal.vue';
import PartitionedDataProcessingModal from '@/views/dataIntegration/dataLoading/dataEntryLake/PartitionedDataProcessingModal.vue'; import PartitionedDataProcessingModal from '@/views/dataIntegration/dataLoading/dataEntryLake/PartitionedDataProcessingModal.vue';
import ClearConfigurationModal from '@/views/dataIntegration/dataLoading/dataEntryLake/ClearConfigurationModal.vue'; import ClearConfigurationModal from '@/views/dataIntegration/dataLoading/dataEntryLake/ClearConfigurationModal.vue';
import BatchScaleNameMappingModal from '@/views/dataIntegration/dataLoading/dataEntryLake/BatchScaleNameMappingModal.vue'; import BatchScaleNameMappingModal from '@/views/dataIntegration/dataLoading/dataEntryLake/BatchScaleNameMappingModal.vue';
import AddDataConversionRuleModal from '@/views/dataIntegration/dataLoading/dataEntryLake/addDataConversionRuleModal.vue'; import AddDataConversionRuleModal from '@/views/dataIntegration/dataLoading/fileLoading/addDataConversionRuleModal.vue';
const key = ref(''); const key = ref('');
const activeKey = ref('1'); const activeKey = ref('1');
...@@ -444,6 +459,16 @@ ...@@ -444,6 +459,16 @@
model.fileName = fileList.value[0].name; model.fileName = fileList.value[0].name;
model.sheetName = 'Sheet1,Sheet2,Sheet3'; model.sheetName = 'Sheet1,Sheet2,Sheet3';
}; };
const loadingTypeOptions = [
{
label: '全量文件加载',
value: '全量文件加载',
},
{
label: '增量文件加载',
value: '增量文件加载',
},
];
const [fileForm, { validate: fileValidate, getFieldsValue: getFileFormValue }] = useForm({ const [fileForm, { validate: fileValidate, getFieldsValue: getFileFormValue }] = useForm({
labelWidth: 100, labelWidth: 100,
baseColProps: { lg: 24, md: 24 }, baseColProps: { lg: 24, md: 24 },
...@@ -461,6 +486,7 @@ ...@@ -461,6 +486,7 @@
content: '确认覆盖之前的解析结果吗?', content: '确认覆盖之前的解析结果吗?',
onOk() { onOk() {
createMessage.success('覆盖成功!'); createMessage.success('覆盖成功!');
fileReload();
}, },
}); });
} }
...@@ -668,16 +694,16 @@ ...@@ -668,16 +694,16 @@
}, },
]; ];
const showFileTable = ref(false); const showFileTable = ref(false);
const [fileTable] = useTable({ const [fileTable, { reload: fileReload }] = useTable({
api: async () => { api: async () => {
const response = { const response = {
pageNu: '1', pageNu: '1',
pageSize: '5', pageSize: '5',
pages: '1', pages: '1',
total: fileData.length, total: fileData(10).length,
code: '', code: '',
message: '', message: '',
data: fileData, data: fileData(10),
}; };
return { ...response }; return { ...response };
}, },
......
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