<template>
|
<app-dialog-form
|
v-bind="dialogFormProps"
|
class="rules-dialog"
|
>
|
<app-form-fields v-bind="formFieldsProps" v-loading="loading">
|
<template #format_show="scope">
|
<el-form-item label="规则配置" required>
|
|
<el-tooltip
|
effect="dark"
|
:content="form[scope.model.format_type]?.desc"
|
placement="top-start"
|
>
|
<el-button class="prompt" icon="QuestionFilled" link></el-button>
|
</el-tooltip>
|
|
<div class="price" v-if="scope.model.format_type === 'number'">
|
<el-select v-model="form.number.prefix" placeholder="请选择" readonly>
|
<el-option label="无" value=""/>
|
<el-option label="¥" value="¥"/>
|
<el-option label="$" value="$"/>
|
</el-select>
|
<el-select v-model="form.number.suffix" placeholder="请选择" readonly>
|
<el-option label="整数" value="."/>
|
<el-option label="1位小数" value=".0"/>
|
<el-option label="2位小数" value=".00"/>
|
<el-option label="3位小数" value=".000"/>
|
<el-option label="4位小数" value=".0000"/>
|
<el-option label="5位小数" value=".00000"/>
|
</el-select>
|
</div>
|
|
<div class="date" v-if="scope.model.format_type === 'date'">
|
<el-input v-model="form.date.format" placeholder="请输入模版" readonly/>
|
<div class="example" v-if="form.date.format">{{ form.date.example }}</div>
|
</div>
|
</el-form-item>
|
</template>
|
<template #format_calc="scope">
|
<el-form-item label="公式配置" required>
|
<el-input v-model="form.calc.formula"
|
input-style="cursor: pointer"
|
placeholder="请输入公式"
|
readonly
|
@click="openCalcDialog"/>
|
</el-form-item>
|
</template>
|
<template #data_standrad="scope">
|
<app-collapse-form title="前置过滤字段">
|
<template #header-button="scope">
|
<el-button size="small" type="primary" @click="onFilterAdd" icon="Plus">
|
新增
|
</el-button>
|
</template>
|
<app-table-list v-bind="filterListProps">
|
<template #table-criterion="scope">
|
<el-select
|
v-model="scope.row.criterion_field_name"
|
placeholder="请选择原字段"
|
>
|
<el-option
|
v-for="item in form.filter.criterionFields"
|
:key="item.field"
|
:label="item.labelchinese"
|
:value="item.field"
|
/>
|
</el-select>
|
</template>
|
|
<template #table-relation="scope">
|
<el-select
|
v-model="scope.row.relation"
|
placeholder="请选择公式"
|
>
|
<el-option
|
v-for="item in dictMapEntity.filter_type"
|
:key="item.code"
|
:label="item.value"
|
:value="item.code"
|
/>
|
</el-select>
|
</template>
|
|
<template #table-data="scope">
|
<el-input
|
input-style="cursor: pointer;"
|
v-model="scope.row.data_field_label_chinese"
|
placeholder="请选择字段"
|
readonly
|
@click="onRadioProperties({key:'filter',index:scope.$index})"
|
/>
|
</template>
|
|
<template #table-remark="scope">
|
<el-input v-model="scope.row.remark" placeholder="请输入描述"/>
|
</template>
|
|
<template #table-operate="scope">
|
<el-button
|
size="small"
|
type="danger"
|
icon="Delete"
|
@click="onFieldDel('filter',scope.row)"
|
>
|
</el-button>
|
</template>
|
</app-table-list>
|
</app-collapse-form>
|
<app-collapse-form title="标准化字段">
|
<template #header-button="scope">
|
<el-button size="small" type="primary" @click="onStandradAdd" icon="Plus">
|
新增
|
</el-button>
|
</template>
|
<app-table-list v-bind="standradListProps">
|
<template #table-criterion="scope">
|
<el-select
|
v-model="scope.row.criterion_field_name"
|
placeholder="请选择原字段"
|
>
|
<el-option
|
v-for="item in form.standrad.criterionFields"
|
:key="item.field"
|
:label="item.labelchinese"
|
:value="item.field"
|
/>
|
</el-select>
|
</template>
|
|
<template #table-data="scope">
|
<el-input
|
input-style="cursor: pointer;"
|
v-model="scope.row.data_field_label_chinese"
|
placeholder="请选择参数字段"
|
readonly
|
@click="onRadioProperties({key:'standrad',index:scope.$index})"
|
/>
|
</template>
|
|
<template #table-remark="scope">
|
<el-input v-model="scope.row.remark" placeholder="请输入描述"/>
|
</template>
|
|
<template #table-operate="scope">
|
<el-button
|
size="small"
|
type="danger"
|
icon="Delete"
|
@click="onFieldDel('standrad',scope.row)"
|
>
|
</el-button>
|
</template>
|
</app-table-list>
|
</app-collapse-form>
|
</template>
|
</app-form-fields>
|
</app-dialog-form>
|
<rules-table-dialog v-bind="rulesTableDialogProps"/>
|
<selection-properties-dialog v-bind="selectionPropertiesDialogProps"/>
|
<calc-dialog v-bind="calcDialogProps"/>
|
<monaco-dialog v-bind="monacoDialogProps"/>
|
<radio-properties-dialog v-bind="radioPropertiesDialogProps"/>
|
</template>
|
|
<script setup>
|
import CalcDialog from './CalcDialog';
|
import MonacoDialog from './MonacoDialog';
|
import RadioPropertiesDialog from './RadioPropertiesDialog';
|
import SelectionPropertiesDialog from './SelectionPropertiesDialog';
|
import RulesTableDialog from './RulesTableDialog';
|
import {modal} from '@/plugins';
|
|
import {decode} from '@/utils/tools.js';
|
|
import dayjs from 'dayjs';
|
|
import {useI18n} from 'vue-i18n';
|
|
const {t} = useI18n();
|
|
import {meta, dict, structure} from '@/hooks';
|
|
const {useStructureData} = structure;
|
|
const {useMetaData} = meta;
|
|
const {useDictMap} = dict;
|
|
import {useEntityStore, useAppStore} from '@/store/modules/index.js';
|
import {formatDateformat} from "@/utils/format.js";
|
import * as tools from "@/utils/tools.js";
|
|
const entityStore = useEntityStore();
|
const appStore = useAppStore();
|
|
const dialogFormRef = ref();
|
const formFieldsRef = ref();
|
|
const props = defineProps({
|
subReload: {
|
type: Function,
|
default: () => {
|
}
|
},
|
options: {
|
type: Object,
|
default: {
|
lib: {},
|
rule: {},
|
property: {}
|
}
|
}
|
});
|
|
const baseFields = ['ruleType', 'level_code', 'control', 'title', 'business_object_code', 'error_msg_cn', 'remark'];
|
|
const readonlyFields = ['level_code', 'control', 'title', 'business_object_code', 'format_type'];
|
|
const codeFields = {
|
'calculate': {
|
'calculate': ['selectionProperties', 'format_calc', ...baseFields],
|
},
|
'data_standrad': ['data_standrad', ...baseFields],
|
'format': ['selectionProperties', 'format_show', 'format_type', ...baseFields],
|
'others': ['selectionProperties', 'sqlSegment', ...baseFields],
|
'required': ['selectionProperties', ...baseFields],
|
'unique': {
|
'unique': ['selectionProperties', ...baseFields],
|
'unique_business': ['selectionProperties', ...baseFields]
|
},
|
};
|
|
const loading = ref(false);
|
|
let editRow = {};
|
|
const rulesTableDialogRef = ref();
|
|
const selectionPropertiesDialogRef = ref();
|
|
const radioPropertiesDialogRef = ref();
|
|
const calcDialogRef = ref();
|
|
const monacoDialogRef = ref();
|
|
const [actionStructure] = useStructureData([
|
{
|
target: {name: 'sys_data_field_rule', field: 'rule_code'},
|
entity: {name: 'sys_library_rule', field: 'code'},
|
type: 'object'
|
},
|
{
|
target: {name: 'sys_data_field_rule_filter', field: 'data_field_name'},
|
entity: {name: props.options.property.dataName, field: props.options.property.value},
|
type: 'object'
|
},
|
{
|
target: {name: 'sys_data_field_rule_standrad', field: 'data_field_name'},
|
entity: {name: props.options.property.dataName, field: props.options.property.value},
|
type: 'object'
|
}
|
]);
|
|
const calcDialogProps = {
|
options: props.options,
|
ref: calcDialogRef,
|
subSubmit(text) {
|
form.calc.formula = text;
|
}
|
}
|
|
const monacoDialogProps = {
|
options: props.options,
|
ref: monacoDialogRef,
|
subSubmit: (current) => {
|
formFieldsRef.value.assignModel({
|
'sqlSegment': current
|
});
|
}
|
}
|
|
|
const filterListRef = ref();
|
|
const filterListProps = {
|
ref: filterListRef,
|
title: '过滤列表',
|
complementHeight: -1,
|
columns: [
|
{
|
type: 'slot',
|
prop: 'criterion',
|
label: "原字段",
|
table: {
|
width: 190
|
}
|
},
|
{
|
type: 'slot',
|
prop: 'relation',
|
label: "公式",
|
table: {
|
width: 130
|
}
|
},
|
{
|
type: 'slot',
|
prop: 'data',
|
label: "参数字段",
|
table: {
|
width: 250
|
}
|
},
|
{
|
type: 'slot',
|
prop: 'remark',
|
label: "描述"
|
},
|
{
|
type: 'slot',
|
prop: 'operate',
|
label: "操作",
|
table: {
|
width: 70
|
}
|
},
|
]
|
};
|
|
|
const standradListRef = ref();
|
|
const standradListProps = {
|
ref: standradListRef,
|
title: '标准化列表',
|
complementHeight: -1,
|
columns: [
|
{
|
type: 'slot',
|
prop: 'criterion',
|
label: "原字段",
|
table: {
|
width: 190
|
}
|
},
|
{
|
type: 'slot',
|
prop: 'data',
|
label: "参数字段",
|
table: {
|
width: 250
|
}
|
},
|
{
|
type: 'slot',
|
prop: 'remark',
|
label: "描述"
|
},
|
{
|
type: 'slot',
|
prop: 'operate',
|
label: "操作",
|
table: {
|
width: 70
|
}
|
},
|
]
|
};
|
|
const [dictMapEntity] = useDictMap(['filter_type'])
|
|
const rulesTableDialogProps = {
|
options: props.options,
|
ref: rulesTableDialogRef,
|
subSubmit: async (current) => {
|
formFieldsProps.fields = fields.filter(e => {
|
if (codeFields[current.type_code] instanceof Array) {
|
return codeFields[current.type_code].includes(e.prop);
|
}
|
return codeFields[current.type_code][current.code].includes(e.prop);
|
});
|
formFieldsRef.value.$forceUpdate(formFieldsProps);
|
formFieldsRef.value.setDefaultModel({'ruleType': {...current}, ...current});
|
|
if (current.id) {
|
if (current.format_type === 'number') {
|
form.number.prefix = current.format_content.split('.')[0];
|
form.number.suffix = `.${current.format_content.split('.')[1]}`;
|
}
|
if (current.format_type === 'date') {
|
form.date.format = current.format_content;
|
}
|
}
|
|
if (current.type_code === 'data_standrad') {
|
const {meta} = await entityStore.getEntitySet({
|
dataName: current.object_code,
|
attachMeta: true,
|
filter: `1 != 1`
|
});
|
meta[current.object_code].fields.forEach(e => {
|
e.labelchinese = decode(e.labelchinese)
|
})
|
form.standrad.criterionFields = meta[current.object_code].fields;
|
standradListRef.value.setTableData([]);
|
form.filter.criterionFields = meta[current.object_code].fields;
|
filterListRef.value.setTableData([]);
|
}
|
}
|
}
|
|
const openCalcDialog = () => {
|
calcDialogRef.value.onOpen(form.calc.formula);
|
}
|
|
const form = reactive({
|
number: {
|
prefix: '',
|
suffix: '',
|
desc: '选择前缀和尾号小数位'
|
},
|
date: {
|
format: '',
|
example: computed(() => dayjs(new Date()).format(formatDateformat(form.date.format)).toString()),
|
desc: 'yyyy 年份 MM 月份 dd日期 HH时 mm分 ss秒'
|
},
|
calc: {
|
formula: ''
|
},
|
standrad: {
|
criterionFields: [],
|
},
|
filter: {
|
criterionFields: [],
|
},
|
});
|
|
const onStandradAdd = () => {
|
const tableList = standradListRef.value.getTableData();
|
tableList.push({
|
id: tools.uuid(),
|
data_field_name: '',
|
data_field_label_chinese: '',
|
criterion_field_name: '',
|
remark: '',
|
});
|
standradListRef.value.setTableData([...tableList]);
|
}
|
|
const onFilterAdd = () => {
|
const tableList = filterListRef.value.getTableData();
|
tableList.push({
|
id: tools.uuid(),
|
data_field_name: '',
|
data_field_label_chinese: '',
|
criterion_field_name: '',
|
remark: '',
|
relation: ''
|
});
|
filterListRef.value.setTableData([...tableList]);
|
|
}
|
|
const onRadioProperties = async (options) => {
|
radioPropertiesDialogRef.value.onOpen(options);
|
}
|
|
const radioPropertiesDialogProps = {
|
options: props.options,
|
ref: radioPropertiesDialogRef,
|
subSubmit: ({key, index}, row) => {
|
let refNode;
|
if (key === 'filter') {
|
refNode = filterListRef;
|
}
|
if (key === 'standrad') {
|
refNode = standradListRef;
|
}
|
const tableList = refNode.value.getTableData();
|
tableList[index].data_field_name = row[props.options.property.value];
|
tableList[index].data_field_label_chinese = row[props.options.property.name];
|
refNode.value.setTableData([...tableList]);
|
}
|
}
|
|
const selectionPropertiesDialogProps = {
|
options: props.options,
|
ref: selectionPropertiesDialogRef,
|
subSubmit: (current) => {
|
formFieldsRef.value.assignModel({
|
'selectionProperties': {
|
label_chinese: current.map((item) => item[props.options.property.name]).toString(),
|
list: current
|
}
|
});
|
}
|
}
|
|
const onFieldDel = async (key, row) => {
|
await modal.confirm("是否确认删除?");
|
let refNode;
|
if (key === 'filter') {
|
refNode = filterListRef;
|
}
|
if (key === 'standrad') {
|
refNode = standradListRef;
|
}
|
let tableList = refNode.value.getTableData();
|
tableList.forEach((e, i) => {
|
if (e.id === row.id) {
|
tableList[i] = null;
|
}
|
});
|
tableList = tableList.filter(Boolean);
|
tableList.forEach((e, index) => {
|
e.order_no = index + 1;
|
});
|
refNode.value.setTableData([...tableList]);
|
}
|
|
const [columns, filters, fields] = useMetaData(
|
'sys_library_rule',
|
async ({fields, fieldsTools}) => {
|
readonlyFields.forEach(prop => {
|
fieldsTools.assign(prop, {input: {readonly: true}, select: {disabled: true}});
|
});
|
|
|
fieldsTools.splice(0, 0,
|
{
|
type: 'el-input-dialog',
|
prop: "ruleType",
|
label: '类型',
|
col: {span: 24},
|
inputDialog: {
|
labelKey: 'title',
|
},
|
item: {
|
rules: [{required: true, message: '规则参数为必填!'}],
|
prop: 'ruleType',
|
label: '规则类型'
|
}
|
}
|
);
|
|
fieldsTools.splice(1, 0, {
|
type: 'slot',
|
prop: "format_calc",
|
col: {span: 12},
|
}
|
);
|
|
fieldsTools.splice(2, 0, {
|
type: 'slot',
|
prop: "format_show",
|
col: {span: 12},
|
}
|
);
|
|
fieldsTools.splice(fields.length, 0,
|
{
|
type: 'el-input-dialog',
|
prop: "radioProperties",
|
label: '规则参数',
|
col: {span: 24},
|
inputDialog: {
|
labelKey: 'label_chinese',
|
},
|
item: {
|
rules: [{required: true, message: '规则参数为必填!'}],
|
prop: 'radioProperties',
|
label: '规则参数'
|
}
|
}
|
);
|
|
fieldsTools.splice(fields.length + 1, 0, {
|
type: 'el-input-dialog',
|
prop: 'sqlSegment',
|
label: '检查sql',
|
col: {span: 24},
|
inputDialog: {
|
labelKey: 'value',
|
},
|
item: {
|
rules: [{required: true, message: '检查sql必填!'}],
|
prop: 'sqlSegment',
|
label: '检查sql'
|
}
|
});
|
|
|
fieldsTools.splice(fields.length + 2, 0,
|
{
|
type: 'el-input-dialog',
|
prop: "selectionProperties",
|
label: '规则参数',
|
col: {span: 24},
|
inputDialog: {
|
labelKey: 'label_chinese',
|
},
|
item: {
|
rules: [{required: true, message: '规则参数为必填!'}],
|
prop: 'selectionProperties',
|
label: '规则参数'
|
}
|
}
|
);
|
|
fieldsTools.splice(fields.length + 3, 0,
|
{
|
type: 'el-textarea',
|
prop: "remark",
|
label: '备注',
|
col: {span: 24},
|
textarea: {
|
placeholder: '请输入',
|
},
|
item: {
|
prop: 'remark',
|
label: '备注'
|
}
|
}
|
);
|
|
fieldsTools.splice(fields.length + 4, 0,
|
{
|
type: 'slot',
|
prop: "data_standrad",
|
col: {span: 24},
|
}
|
);
|
}
|
);
|
|
const formFieldsProps = {
|
options: props.options,
|
ref: formFieldsRef,
|
fields: [],
|
subInputDialog: async (key, row) => {
|
if (key === 'ruleType') {
|
rulesTableDialogRef.value.onOpen(row);
|
}
|
if (key === 'selectionProperties') {
|
selectionPropertiesDialogRef.value.onOpen(row);
|
}
|
if (key === 'sqlSegment') {
|
monacoDialogRef.value.onOpen(row);
|
}
|
}
|
}
|
|
const dialogFormProps = {
|
width: 1000,
|
title: '',
|
ref: dialogFormRef,
|
subSubmit: async () => {
|
const {
|
ruleType,
|
remark,
|
selectionProperties,
|
error_msg_cn,
|
sqlSegment
|
} = await formFieldsRef.value.onValidate();
|
|
let filterList = [];
|
let ruleList = [];
|
|
if (Object.keys(selectionProperties || {}).length) {
|
ruleList = selectionProperties.list.map(e => ({
|
"criterion_field_name": e.criterion_field_name,
|
"data_field_name": e[props.options.property.value],
|
"data_field_display_name": e[props.options.property.name],
|
"remark": ""
|
}));
|
}
|
|
if (standradListRef.value) {
|
filterList = filterListRef.value.getTableData().map(e => ({
|
"criterion_field_name": e.criterion_field_name,
|
"data_field_name": e.data_field_name,
|
"data_field_display_name": e.data_field_label_chinese,
|
'relation': e.relation,
|
"remark": e.remark
|
}));
|
|
ruleList = standradListRef.value.getTableData().map(e => ({
|
"criterion_field_name": e.criterion_field_name,
|
"data_field_name": e.data_field_name,
|
"data_field_display_name": e.data_field_label_chinese,
|
"remark": e.remark
|
}));
|
}
|
|
if (!ruleList.length) {
|
modal.msgError('请选择规则参数!');
|
throw '';
|
}
|
|
await entityStore.dataEntity({
|
dataName: 'pkg_data_field_rule',
|
data: {
|
'sys_data_field_rule': {
|
...(editRow.id ? {id: editRow.id} : {}),
|
"data_name": props.options.type,
|
"rule_code": ruleType.code,
|
"rule_name": ruleType.title,
|
sql_segment: sqlSegment?.value || '',
|
message: error_msg_cn || '',
|
formula: form.calc.formula || '',
|
'remark': remark || '',
|
"data_name_remark": '',
|
},
|
"sys_data_field_rule_standrad": ruleList,
|
"sys_data_field_rule_filter": filterList,
|
}
|
});
|
props.subReload(true);
|
},
|
subReset: async () => {
|
if (editRow.id) {
|
await editReset();
|
return;
|
}
|
formFieldsRef.value.onReset();
|
}
|
};
|
|
const editReset = async () => {
|
loading.value = true;
|
const {data} = await entityStore.getEntity({
|
dataName: "pkg_data_field_rule",
|
attachMeta: false,
|
id: editRow.id,
|
});
|
|
const structureData = await actionStructure(data);
|
|
await rulesTableDialogProps.subSubmit(structureData.sys_data_field_rule.$rule_code);
|
|
formFieldsRef.value.assignModel({
|
error_msg_cn: editRow.message,
|
remark: editRow.remark
|
});
|
|
form.calc.formula = data.sys_data_field_rule.formula || '';
|
monacoDialogProps.subSubmit({value: editRow.sql_segment || ''});
|
|
if (formFieldsProps.fields.find(e => e.prop === 'selectionProperties')) {
|
selectionPropertiesDialogProps.subSubmit(structureData.sys_data_field_rule_standrad.map(e => e.$data_field_name).filter(Boolean));
|
}
|
|
const standradList = [];
|
if (formFieldsProps.fields.find(e => e.prop === 'data_standrad')) {
|
structureData.sys_data_field_rule_standrad.forEach(e => {
|
standradList.push({
|
id: e.id,
|
data_field_label_chinese: e.$data_field_name ? e.$data_field_name[props.options.property.name] : '',
|
data_field_name: e.data_field_name,
|
criterion_field_name: e.criterion_field_name,
|
remark: e.remark
|
});
|
});
|
|
standradListRef.value.setTableData(standradList)
|
|
|
const filterList = [];
|
structureData.sys_data_field_rule_filter.forEach(e => {
|
|
filterList.push({
|
id: e.id,
|
data_field_label_chinese: e.$data_field_name ? e.$data_field_name[props.options.property.name] : '',
|
data_field_name: e.data_field_name,
|
criterion_field_name: e.criterion_field_name,
|
relation: e.relation,
|
remark: e.remark
|
});
|
|
});
|
|
filterListRef.value.setTableData(filterList);
|
}
|
|
loading.value = false;
|
}
|
|
const onOpen = async (row) => {
|
|
editRow = row;
|
dialogFormProps.title = t(row.id ? 'common.dialog.title.edit' : 'common.dialog.title.add');
|
await dialogFormRef.value.$forceUpdate(dialogFormProps);
|
|
dialogFormRef.value.onOpen();
|
|
await nextTick();
|
|
if (editRow.id) {
|
await editReset();
|
return;
|
}
|
|
formFieldsProps.fields = fields.filter(e => baseFields.includes(e.prop));
|
await formFieldsRef.value.$forceUpdate(formFieldsProps);
|
formFieldsRef.value.setDefaultModel(row);
|
|
}
|
|
defineExpose({
|
onOpen
|
});
|
|
</script>
|
|
<style lang="scss">
|
|
.rules-dialog {
|
.calc {
|
width: 100%;
|
}
|
|
.prompt {
|
position: absolute;
|
left: -83px;
|
}
|
|
.price {
|
width: 100%;
|
display: flex;
|
justify-content: space-between;
|
|
.el-select:first-child {
|
margin-right: 20px;
|
}
|
}
|
|
.date {
|
width: 100%;
|
display: flex;
|
justify-content: space-around;
|
|
.example {
|
position: absolute;
|
left: 0;
|
top: 32px;
|
}
|
}
|
|
.prompt {
|
position: absolute;
|
left: -90px;
|
}
|
}
|
</style>
|