| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 | <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="排除" prop="exceptDay">          <el-select v-model="formData.exceptDay" :disabled="formData.day <= 1">            <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)//  console.log('fieldInfo',fieldInfo);//  if (fieldInfo.options && fieldInfo.options.length > 0) return 'change'//  return 'blur'//}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>
 |