123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- <template>
- <div class="condition-group-item-wrap">
- <div>
- <el-form :model="formData" ref="formRef" label-suffix=":" label-position="right" label-width="100px" :disabled="disabled">
- <el-form-item label="数据周期" required prop="day">
- <el-select v-model="formData.day" @change="formData.exceptDay = 0">
- <el-option v-for="item in periodEnum" :key="item.value" :label="item.label" :value="item.value"></el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="排除" required prop="exceptDay">
- <el-select v-model="formData.exceptDay">
- <el-option v-for="item in excludeEnum" :key="item.value" :label="item.label" :value="item.value" :disabled="formData.day <= item.value">
- </el-option>
- </el-select>
- </el-form-item>
- <el-form-item
- v-for="(conditionInfo, index) of formData.items"
- :key="conditionInfo.dataType"
- :prop="getFormProp(conditionInfo, index)"
- :rules="{ validator: checkRight, trigger: getFormTrigger(conditionInfo) }">
- <template #label>
- <span v-if="index === 0">条件:</span>
- <span class="and-span" v-else>&</span>
- </template>
- <div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap">
- <el-select v-model="conditionInfo.dataType" style="width: 140px" @change="changeDataType(conditionInfo)">
- <el-option
- v-for="item in candidateFields"
- :key="item.value"
- :disabled="selectedFields[item.value] ? true : false"
- :label="item.label"
- :value="item.value">
- </el-option>
- </el-select>
- <el-select
- v-model="conditionInfo.dayType"
- style="width: 80px"
- v-show="conditionInfo.symbol !== 'in' && conditionInfo.symbol !== 'not_in'">
- <el-option label="总计" value="sum"></el-option>
- <el-option label="均值" value="avg"></el-option>
- </el-select>
- <el-select v-model="conditionInfo.symbol" style="width: 120px">
- <el-option v-for="info in getSymbolOptions(conditionInfo.dataType)" :label="info.label" :value="info.value" :key="info.value">
- </el-option>
- </el-select>
- <template v-if="conditionInfo.symbol === 'in' || conditionInfo.symbol === 'not_in'">
- <el-select v-if="getFieldInfo(conditionInfo.dataType).options" v-model="conditionInfo.values" multiple collapse-tags>
- <el-option
- v-for="info in getFieldInfo(conditionInfo.dataType).options"
- :label="info.label"
- :value="info.value"
- :key="info.value"></el-option>
- </el-select>
- <div v-else style="width: 90%">
- <TagsInput :data="conditionInfo.values" placeholder="请输入至少一个关键词,多个关键词用换行符分隔" :disabled="disabled"></TagsInput>
- </div>
- </template>
- <template v-else-if="conditionInfo.symbol === 'between' || conditionInfo.symbol === 'not_between'">
- <RangeFloat :ranges="conditionInfo.ranges" :prefix="findPrefix(conditionInfo.dataType)" :suffix="findSuffix(conditionInfo.dataType)">
- </RangeFloat>
- </template>
- <InputFloat
- v-else
- v-model="conditionInfo.num"
- :prefix="findPrefix(conditionInfo.dataType)"
- :suffix="findSuffix(conditionInfo.dataType)"
- style="width: 200px">
- </InputFloat>
- <el-button @click="deleteCondition(index)" type="danger" :icon="Delete" v-show="formData.items.length > 1" link></el-button>
- </div>
- </el-form-item>
- </el-form>
- <el-button
- link
- type="primary"
- @click="addConditionItem"
- :icon="Plus"
- :style="{'margin-left': '100px', color: disabled ? '': 'blue'}"
- v-show="showAddCondiBtn"
- :disabled="disabled">
- 添加条件
- </el-button>
- </div>
- <el-button type="danger" @click="deleteConditionGroup" :icon="Delete" v-show="showDelGroupBtn">删除组</el-button>
- </div>
- <el-divider border-style="dashed" class="condition-group-divider"> 或 </el-divider>
- </template>
- <script lang="ts" setup>
- import { ref, reactive, computed, watch } from 'vue'
- import { Delete, Plus } from '@element-plus/icons-vue'
- import InputFloat from '/@/components/input-float/index.vue'
- import TagsInput from '/@/components/tags-input/index.vue'
- import RangeFloat from '/@/components/range-float/index.vue'
- import { useSymbolOptions } from './utils'
- import XEUtils from 'xe-utils'
- interface Props {
- candidateFields: CandidateField[]
- data: ConditionGroupItem
- showDelGroupBtn: boolean
- disabled: boolean
- }
- const emits = defineEmits(['deleteGroup'])
- const periodEnum = [
- { label: '昨天', value: 1 },
- { label: '过去7天', value: 7 },
- { label: '过去14天', value: 14 },
- { label: '过去30天', value: 30 },
- { label: '过去60天', value: 60 },
- { label: '过去90天', value: 90 },
- ]
- const excludeEnum = [
- { label: '不排除', value: 0 },
- { label: '昨天', value: 1 },
- { label: '最近2天', value: 2 },
- { label: '最近3天', value: 3 },
- { label: '最近7天', value: 7 },
- { label: '最近14天', value: 14 },
- ]
- const props = withDefaults(defineProps<Props>(), {
- disabled: false,
- })
- const formRef = ref()
- const formData = ref(props.data)
- const { getSymbolOptions, getFieldInfo } = useSymbolOptions(props.candidateFields)
- const getFormProp = (conditionInfo: ConditionItem, index: number) => {
- if (['between', 'not_between'].includes(conditionInfo.symbol)) {
- return `items[${index}].ranges`
- }
- if (['in', 'not_in'].includes(conditionInfo.symbol)) {
- return `items[${index}].values`
- }
- return `items[${index}].num`
- }
- const getFormTrigger = (conditionInfo: ConditionItem) => {
- const fieldInfo = getFieldInfo(conditionInfo.dataType)
- if (fieldInfo.options && fieldInfo.options.length > 0) return 'change'
- return 'blur'
- }
- const checkRight = (rule: any, value: string | string[], callback: any) => {
- // console.log(139, rule, value)
- if (rule.field.includes('num')) {
- if (XEUtils.toNumber(value) <= 0 ) {
- callback(new Error('请输入大于0的数值!'))
- }
- } else if (rule.field.includes('values')) {
- if (value.length === 0) {
- callback(new Error('必填项'))
- }
- } else if (rule.field.includes('ranges')) {
- for (const val of value) {
- if (XEUtils.toNumber(val) <= 0) {
- callback(new Error('请输入大于0的数值!'))
- break
- }
- }
- if (XEUtils.toNumber(value[0]) >= XEUtils.toNumber(value[1])) {
- callback(new Error('起始值必须小于终止值!'))
- }
- }
- callback()
- }
- const validate = async () => {
- let ret = false
- await formRef.value.validate((valid: any) => {
- ret = valid
- })
- return ret
- }
- const showAddCondiBtn = computed(() => {
- return formData.value.items.length < props.candidateFields.length
- })
- const selectedFields = computed(() => {
- const ret = {}
- for (const info of formData.value.items) {
- ret[info.dataType] = true
- }
- return ret
- })
- const buildConditionItem = (field: string) => {
- const symbol = getSymbolOptions(field)[0].value
- return {
- dataType: field,
- dayType: symbol === 'in' || symbol === 'not_in' ? '' : 'sum',
- symbol: symbol,
- num: '',
- ranges: [],
- values: [],
- }
- }
- const addConditionItem = () => {
- for (const item of props.candidateFields) {
- if (!selectedFields.value[item.value]) {
- formData.value.items.push(buildConditionItem(item.value))
- break
- }
- }
- }
- // const changeSymbol = (conditionInfo: ConditionItem) => {
- // if(conditionInfo.symbol === 'between' || conditionInfo.symbol === 'not_between') {
- // if (conditionInfo.values.length !== 2) {
- // conditionInfo.values.splice(0, conditionInfo.values.length)
- // }
- // }
- // }
- const changeDataType = (conditionInfo: ConditionItem) => {
- conditionInfo.symbol = getSymbolOptions(conditionInfo.dataType)[0].value
- conditionInfo.num = ''
- // conditionInfo.ranges[0] = ''
- // conditionInfo.ranges[1] = ''
- conditionInfo.ranges.splice(0, conditionInfo.ranges.length)
- conditionInfo.values.splice(0, conditionInfo.values.length)
- }
- const findPrefix = (dataType: string) => {
- return props.candidateFields.find((item) => item.value === dataType).prefix ?? ''
- }
- const findSuffix = (dataType: string) => {
- return props.candidateFields.find((item) => item.value === dataType).suffix ?? ''
- }
- const deleteCondition = (index: number) => {
- formData.value.items.splice(index, 1)
- }
- const deleteConditionGroup = () => {
- emits('deleteGroup')
- }
- watch(
- () => props.data,
- () => {
- formData.value = props.data
- },
- { deep: true }
- )
- defineExpose({ validate })
- </script>
- <style scoped>
- .condition-group-item-wrap {
- background: #f4f7fe;
- padding: 10px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- /* position: relative; */
- }
- .and-span {
- display: inline-block;
- width: 20px;
- height: 20px;
- background: #fff;
- text-align: center;
- line-height: 20px;
- border-radius: 50%;
- margin: auto 0;
- }
- div.condition-group-divider:last-of-type {
- display: none;
- }
- </style>
|