<script lang="ts" setup>
|
import { reactive, toRefs } from 'vue';
|
|
import { useMessage } from '@jnpf/hooks';
|
import { BasicDrawer, useDrawerInner } from '@jnpf/ui/drawer';
|
import { isEmpty, treeToList } from '@jnpf/utils';
|
|
import { cloneDeep } from 'lodash-es';
|
|
interface State {
|
dataForm: any;
|
fieldList: any[];
|
}
|
|
defineProps({
|
sysVariableList: { type: Array, default: () => [] },
|
});
|
|
const emit = defineEmits(['register', 'confirm']);
|
const logicOptions = [
|
{ id: 'and', fullName: '且' },
|
{ id: 'or', fullName: '或' },
|
];
|
const dataTypeOptions = [
|
{ id: 'text', fullName: 'text' },
|
{ id: 'double', fullName: 'double' },
|
{ id: 'bigint', fullName: 'bigint' },
|
{ id: 'date', fullName: 'date' },
|
{ id: 'time', fullName: 'time' },
|
];
|
const baseSymbolOptions = [
|
{ id: '==', fullName: '等于' },
|
{ id: '<>', fullName: '不等于' },
|
{ id: 'like', fullName: '包含' },
|
{ id: 'notLike', fullName: '不包含' },
|
{ id: 'null', fullName: '为空' },
|
{ id: 'notNull', fullName: '不为空' },
|
{ id: 'in', fullName: '包含任意一个' },
|
{ id: 'notIn', fullName: '不包含任意一个' },
|
];
|
const rangeSymbolOptions = [
|
{ id: '>=', fullName: '大于等于' },
|
{ id: '>', fullName: '大于' },
|
{ id: '==', fullName: '等于' },
|
{ id: '<=', fullName: '小于等于' },
|
{ id: '<', fullName: '小于' },
|
{ id: '<>', fullName: '不等于' },
|
{ id: 'between', fullName: '介于' },
|
{ id: 'null', fullName: '为空' },
|
{ id: 'notNull', fullName: '不为空' },
|
];
|
const fieldValueTypeOptions = [
|
{ id: 1, fullName: '自定义' },
|
{ id: 2, fullName: '系统参数' },
|
];
|
const emptyChildItem = {
|
field: '',
|
dataType: 'text',
|
symbol: '==',
|
fieldValue: '',
|
fieldValueType: 1,
|
};
|
const emptyItem = { logic: 'and', groups: [emptyChildItem] };
|
const resultFilterOptions = [
|
{ id: 1, fullName: '所有数据' },
|
{ id: 2, fullName: '前N条数据' },
|
{ id: 3, fullName: '后N条数据' },
|
{ id: 4, fullName: '奇数条数据' },
|
{ id: 5, fullName: '偶数条数据' },
|
{ id: 6, fullName: '指定数据' },
|
];
|
|
const state = reactive<State>({
|
dataForm: {
|
ruleList: [],
|
matchLogic: 'and',
|
resultFilter: 1,
|
resultNum: 10,
|
specifyData: '',
|
},
|
fieldList: [],
|
});
|
const { dataForm, fieldList } = toRefs(state);
|
const [registerDrawer, { closeDrawer }] = useDrawerInner(init);
|
const { createMessage } = useMessage();
|
|
function init(data) {
|
getTableFieldList(data.visualConfigJson);
|
state.dataForm = cloneDeep(data.data);
|
state.dataForm.resultFilter = state.dataForm.resultFilter || 1;
|
state.dataForm.resultNum = state.dataForm.resultNum || 10;
|
state.dataForm.specifyData = state.dataForm.specifyData || '';
|
}
|
|
function getTableFieldList(treeList = []) {
|
const list = treeToList(treeList, { id: 'table' });
|
state.fieldList = list.map((o) => ({
|
id: o.table,
|
fullName: o.tableName,
|
options: o.fieldList.map((c) => ({ id: `${o.table}-${c.field}`, fullName: c.fieldName, dataType: c.dataType })),
|
}));
|
}
|
function addRuleItem(index) {
|
state.dataForm.ruleList[index].groups.push(cloneDeep(emptyChildItem));
|
}
|
function delRuleItem(index, childIndex) {
|
state.dataForm.ruleList[index].groups.splice(childIndex, 1);
|
if (!state.dataForm.ruleList[index].groups.length) delRuleGroup(index);
|
}
|
function addRuleGroup() {
|
state.dataForm.ruleList.push(cloneDeep(emptyItem));
|
}
|
function delRuleGroup(index) {
|
state.dataForm.ruleList.splice(index, 1);
|
}
|
function onDataTypeChange(item) {
|
item.fieldValueType = 1;
|
if (item.dataType === 'text') {
|
if (!baseSymbolOptions.some((o) => o.id === item.symbol)) {
|
item.symbol = '==';
|
}
|
item.fieldValue = '';
|
} else {
|
if (!rangeSymbolOptions.some((o) => o.id === item.symbol)) {
|
item.symbol = '==';
|
}
|
item.fieldValue = undefined;
|
}
|
}
|
function onSymbolChange(item) {
|
if (item.dataType === 'text') {
|
if (['notNull', 'null'].includes(item.symbol)) {
|
item.fieldValueType = 1;
|
item.fieldValue = '';
|
}
|
if (
|
(['in', 'notIn'].includes(item.symbol) && typeof item.fieldValue === 'string') ||
|
(!['in', 'notIn'].includes(item.symbol) && typeof item.fieldValue !== 'string')
|
)
|
item.fieldValue = undefined;
|
} else {
|
if (['notNull', 'null'].includes(item.symbol)) {
|
item.fieldValue = undefined;
|
} else if (item.symbol === 'between') {
|
!Array.isArray(item.fieldValue) && (item.fieldValue = []);
|
} else {
|
Array.isArray(item.fieldValue) && (item.fieldValue = undefined);
|
}
|
}
|
}
|
function onFieldValueTypeChange(item) {
|
item.fieldValue = undefined;
|
}
|
function conditionExist() {
|
const list = state.dataForm.ruleList;
|
let isOk = true;
|
outer: for (const e of list) {
|
for (let j = 0; j < e.groups.length; j++) {
|
const child = e.groups[j];
|
if (!child.field) {
|
createMessage.warning(`字段不能为空`);
|
isOk = false;
|
break outer;
|
}
|
if (child.fieldValueType === 2 && !child.fieldValue) {
|
createMessage.warning(`系统参数不能为空`);
|
isOk = false;
|
break outer;
|
}
|
if (
|
child.fieldValueType === 1 &&
|
!['notNull', 'null'].includes(child.symbol) &&
|
((!child.fieldValue && child.fieldValue !== 0) || isEmpty(child.fieldValue))
|
) {
|
createMessage.warning('数据值不能为空');
|
isOk = false;
|
return;
|
}
|
}
|
}
|
return isOk;
|
}
|
function handleSubmit() {
|
if (!conditionExist()) return;
|
if (!handleSpecifyData()) return;
|
emit('confirm', state.dataForm);
|
closeDrawer();
|
}
|
function handleSpecifyData() {
|
if (state.dataForm.resultFilter !== 6) return true;
|
const pattern = /^\d+(?:-\d+)?(?:,\d+(?:-\d+)?)*$/;
|
if (!state.dataForm.specifyData) {
|
createMessage.warning('指定数据不能为空');
|
return false;
|
}
|
if (!pattern.test(state.dataForm.specifyData)) {
|
createMessage.warning('指定数据值填写不正确');
|
return false;
|
}
|
return true;
|
}
|
function onNumberChange(event) {
|
if (!event.target.value) state.dataForm.resultNum = 10;
|
}
|
</script>
|
<template>
|
<BasicDrawer
|
v-bind="$attrs"
|
width="500px"
|
@register="registerDrawer"
|
title="筛选设置"
|
class="dataSet-table-config-drawer"
|
show-footer
|
:mask-closable="false"
|
@ok="handleSubmit"
|
destroy-on-close>
|
<div class="overflow-auto p-[20px]">
|
<div class="condition-main">
|
<div class="condition-text">条件筛选</div>
|
<div class="mb-[10px]" v-if="dataForm.ruleList?.length">
|
<jnpf-radio v-model:value="dataForm.matchLogic" :options="logicOptions" option-type="button" button-style="solid" />
|
</div>
|
<div class="condition-item" v-for="(item, index) in dataForm.ruleList" :key="index">
|
<div class="condition-item-title">
|
<div>条件组</div>
|
<i class="icon-ym icon-ym-nav-close" @click="delRuleGroup(index)"></i>
|
</div>
|
<div class="condition-item-content">
|
<div class="condition-item-cap">
|
以下条件全部执行:
|
<jnpf-radio v-model:value="item.logic" :options="logicOptions" option-type="button" button-style="solid" size="small" />
|
</div>
|
<a-row :gutter="8" v-for="(child, childIndex) in item.groups" :key="index + childIndex" wrap class="mb-[10px]">
|
<a-col :span="18" class="!flex items-center">
|
<jnpf-select v-model:value="child.field" :options="fieldList" placeholder="请选择字段" allow-clear show-search />
|
</a-col>
|
<a-col :span="6">
|
<jnpf-select class="w-full" v-model:value="child.dataType" :options="dataTypeOptions" @change="onDataTypeChange(child)" />
|
</a-col>
|
<a-col :span="6" class="mt-[10px]">
|
<jnpf-select
|
class="w-full"
|
v-model:value="child.symbol"
|
:options="child.dataType === 'text' ? baseSymbolOptions : rangeSymbolOptions"
|
@change="onSymbolChange(child)" />
|
</a-col>
|
<a-col :span="16" class="mt-[10px]" v-if="['double', 'bigint', 'date', 'time'].includes(child.dataType)">
|
<template v-if="['double', 'bigint'].includes(child.dataType)">
|
<jnpf-number-range v-model:value="child.fieldValue" v-if="child.symbol == 'between'" />
|
<jnpf-input-number v-model:value="child.fieldValue" placeholder="请输入" :disabled="['null', 'notNull'].includes(child.symbol)" v-else />
|
</template>
|
<template v-else-if="['date', 'time'].includes(child.dataType)">
|
<jnpf-date-range
|
v-model:value="child.fieldValue"
|
:format="child.dataType === 'time' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'"
|
allow-clear
|
v-if="child.symbol == 'between'" />
|
<jnpf-date-picker
|
v-model:value="child.fieldValue"
|
:format="child.dataType === 'time' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'"
|
allow-clear
|
:disabled="['null', 'notNull'].includes(child.symbol)"
|
v-else />
|
</template>
|
</a-col>
|
<template v-else>
|
<a-col :span="6" class="mt-[10px]">
|
<jnpf-select
|
v-model:value="child.fieldValueType"
|
:options="fieldValueTypeOptions"
|
@change="onFieldValueTypeChange(child)"
|
:disabled="['null', 'notNull'].includes(child.symbol)" />
|
</a-col>
|
<a-col :span="10" class="mt-[10px]">
|
<a-select
|
v-model:value="child.fieldValue"
|
placeholder="请输入"
|
allow-clear
|
mode="tags"
|
:open="false"
|
:disabled="child.disabled"
|
v-if="child.fieldValueType === 1 && ['in', 'notIn'].includes(child.symbol)" />
|
<a-input
|
v-model:value="child.fieldValue"
|
placeholder="请输入"
|
allow-clear
|
:disabled="['null', 'notNull'].includes(child.symbol)"
|
v-else-if="child.fieldValueType === 1" />
|
<jnpf-select v-model:value="child.fieldValue" :options="sysVariableList" allow-clear show-search placeholder="请选择系统参数" v-else />
|
</a-col>
|
</template>
|
<a-col :span="2" class="mt-[10px] text-center">
|
<i class="icon-ym icon-ym-btn-clearn" @click="delRuleItem(index, childIndex)"></i>
|
</a-col>
|
</a-row>
|
<span class="link-text inline-block" @click="addRuleItem(index)"><i class="icon-ym icon-ym-btn-add mr-[4px] text-[14px]"></i>添加条件</span>
|
</div>
|
</div>
|
<span class="link-text inline-block" @click="addRuleGroup()"><i class="icon-ym icon-ym-btn-add mr-[4px] text-[14px]"></i>添加条件组</span>
|
</div>
|
<div class="condition-text mt-[20px]">结果集筛选</div>
|
<jnpf-select class="w-full" v-model:value="dataForm.resultFilter" :options="resultFilterOptions" />
|
<div class="mt-[10px]">
|
<jnpf-input-number
|
v-model:value="dataForm.resultNum"
|
v-if="[2, 3].includes(dataForm.resultFilter)"
|
placeholder="请输入"
|
:min="1"
|
:addon-before="dataForm.resultFilter == 2 ? '前' : '后'"
|
addon-after="条"
|
@blur="onNumberChange" />
|
<template v-if="dataForm.resultFilter == 6">
|
<a-input v-model:value="dataForm.specifyData" placeholder="请输入" />
|
<div class="tip-text">
|
需要用户自己填写数据的序号,数字之间用 `,` 隔开,连续区间可以用 `-` 连接,格式:1,2-3,5-10,则显示第1、2、3、5、6、7、8、9、10条
|
</div>
|
</template>
|
</div>
|
</div>
|
</BasicDrawer>
|
</template>
|
<style lang="scss" scoped>
|
.condition-text {
|
padding-bottom: 10px;
|
font-size: 16px;
|
}
|
|
.tip-text {
|
margin-top: 10px;
|
color: var(--text-color-secondary);
|
}
|
</style>
|