对比新文件 |
| | |
| | | <template> |
| | | <Dialog v-model="dialogVisible" :title="dialogTitle" width="55%"> |
| | | <el-form |
| | | ref="formRef" |
| | | v-loading="formLoading" |
| | | :model="formData" |
| | | :rules="formRules" label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="指标编码" prop="itemNo"> |
| | | <el-input v-model="formData.itemNo" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="指标名称" prop="itemName"> |
| | | <el-input v-model="formData.itemName" placeholder="请输入指标名称"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="指标分类" prop="itemCategory"> |
| | | <el-select v-model="formData.itemCategory" clearable placeholder="请选择指标分类"> |
| | | <el-option |
| | | v-for="item in dataCategoryList" |
| | | :key="item.id" |
| | | :label="item.label" |
| | | :value="item.id + ''" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="时间粒度" prop="timeGranularity"> |
| | | <el-select v-model="formData.timeGranularity" placeholder="请选择"> |
| | | <el-option |
| | | v-for="dict in getStrDictOptions(DICT_TYPE.TIME_GRANULARITY)" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="8"> |
| | | <el-form-item label="指标精度" prop="precision"> |
| | | <el-input v-model="formData.precision"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="转换系数" prop="coefficient"> |
| | | <el-input v-model="formData.coefficient"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="数量单位" prop="unit"> |
| | | <el-input v-model="formData.unit"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="备注" prop="remark"> |
| | | <el-input v-model="formData.remark" type="textarea" maxlength="100"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="表达式"> |
| | | <el-table :data="expressionList" border style="width: 100%"> |
| | | <el-table-column type="index" align="center" width="60" label="序号"/> |
| | | <el-table-column prop="" label="左括号" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-input size="small" v-model="scope.row.parenthesesLeft" placeholder="" readonly maxlength="10"/> |
| | | <el-button size="small" @click="addParenthesesLeft(scope.$index, scope.row)">+</el-button> |
| | | <el-button size="small" @click="removeParenthesesLeft(scope.$index, scope.row)">-</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="" label="指标" align="center"> |
| | | <template #default="scope"> |
| | | <el-select size="mini" v-model="scope.row.itemNo" filterable placeholder="请选择"> |
| | | <el-option v-for="(item, index) in itemList" |
| | | :key="index" |
| | | :label="item.itemName" |
| | | :value="item.itemNo"/> |
| | | </el-select> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="" label="运算值" align="center"> |
| | | <template #default="scope"> |
| | | <el-input size="mini" v-model="scope.row.itemNo" placeholder="运算值" clearable/> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="" label="右括号" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-input size="small" v-model="scope.row.parenthesesRight" placeholder="" readonly/> |
| | | <el-button size="small" @click="addParenthesesRight(scope.$index, scope.row, ')')">+ |
| | | </el-button> |
| | | <el-button size="small" @click="removeParenthesesRight(scope.$index, scope.row)">- |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="" label="运算符" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-select size="mini" v-model="scope.row.operator" clearable placeholder="请选择" |
| | | style="font-weight: 600;"> |
| | | <el-option v-for="item in operatorList" |
| | | :key="item" |
| | | :label="item" |
| | | :value="item"/> |
| | | </el-select> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="" label="操作" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-button @click="addExpressionRow(scope.$index, expressionList)" link type="primary" size="small">添加</el-button> |
| | | <el-button @click="deleteExpressionRow(scope.$index, expressionList)" link type="danger" size="small">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> |
| | | <el-button @click="dialogVisible = false">取 消</el-button> |
| | | </template> |
| | | </Dialog> |
| | | </template> |
| | | <script lang="ts" setup> |
| | | import {DICT_TYPE, getStrDictOptions} from '@/utils/dict' |
| | | import * as DataSetApi from '@/api/data/ind/data/data.set' |
| | | import {CommonStatusEnum} from '@/utils/constants' |
| | | import * as DataSourceConfigApi from "@/api/infra/dataSourceConfig"; |
| | | import * as ItemApi from '@/api/data/ind/item/item' |
| | | import { ElMessage } from 'element-plus' |
| | | import * as CategoryApi from '@/api/data/ind/category/index' |
| | | |
| | | defineOptions({name: 'IndDataSetForm'}) |
| | | |
| | | const {t} = useI18n() // 国际化 |
| | | const message = useMessage() // 消息弹窗 |
| | | |
| | | const dialogVisible = ref(false) // 弹窗的是否展示 |
| | | const dialogTitle = ref('') // 弹窗的标题 |
| | | const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 |
| | | const formType = ref('') // 表单的类型:create - 新增;update - 修改 |
| | | const itemList = ref([] as ItemApi.ItemVO[]) |
| | | let formData = ref({ |
| | | id: undefined, |
| | | itemNo: '', |
| | | itemName: '', |
| | | itemType: '', |
| | | itemCategory: '', |
| | | coefficient: '', |
| | | precision: '', |
| | | businessType: '', |
| | | timeRange: '', |
| | | timeGranularity: '', |
| | | remark: '', |
| | | calItem: { |
| | | id: '', |
| | | expression: '', |
| | | } |
| | | }) |
| | | let expressionList = ref([{ |
| | | parenthesesLeft: '', |
| | | itemNo: '', |
| | | parenthesesRight: '', |
| | | operator: '' |
| | | }]) |
| | | |
| | | const validateAsNumber = (rule, value, callback) => { |
| | | const regex = /^(\-|\+)?\d+(\.\d+)?$/; |
| | | if (!regex.test(value)) { |
| | | callback(new Error('请输入数字!')); |
| | | } |
| | | } |
| | | const operatorList = ref(['+', '-', '*', '/', '&', '|', '!', '>', '<']) |
| | | const formRules = reactive({ |
| | | itemName: [{required: true, message: '指标名称不能为空', trigger: 'blur'}], |
| | | itemCategory: [{required: true, message: '指标类型不能为空', trigger: 'blur'}], |
| | | precision: [{validator: validateAsNumber, trigger: 'blur' }], |
| | | coefficient: [{validator: validateAsNumber, trigger: 'blur' }], |
| | | }) |
| | | const formRef = ref() // 表单 Ref |
| | | const dataSourceList = ref([] as DataSourceConfigApi.DataSourceConfigVO[]) |
| | | const queryParams = reactive({}) |
| | | const dataCategoryList = ref([] as CategoryApi.IndItemCategoryVO[]) |
| | | /** 打开弹窗 */ |
| | | const open = async (type: string, id?: number) => { |
| | | dialogVisible.value = true |
| | | dialogTitle.value = '复合指标' |
| | | formType.value = type |
| | | resetForm() |
| | | |
| | | // 加载数据源列表 |
| | | dataCategoryList.value = await CategoryApi.getCategoryListAllSimple() |
| | | itemList.value = await ItemApi.getItemList(queryParams) |
| | | // 修改时,设置数据 |
| | | if (id) { |
| | | formLoading.value = true |
| | | try { |
| | | formData.value = await ItemApi.getItem(id) |
| | | expressionList.value = [] |
| | | let expression = formData.value.calItem.expression |
| | | do { |
| | | let indexArray = [ |
| | | expression.indexOf('+'), |
| | | expression.indexOf('-'), |
| | | expression.indexOf('*'), |
| | | expression.indexOf('/'), |
| | | expression.indexOf('&'), |
| | | expression.indexOf('|'), |
| | | expression.indexOf('!'), |
| | | expression.indexOf('>'), |
| | | expression.indexOf('<') |
| | | ].sort(numAscSort) |
| | | if (indexArray[indexArray.length - 1] !== -1) { |
| | | let endIndex = 0 |
| | | for (let key in indexArray) { |
| | | if (indexArray[key] > -1) { |
| | | endIndex = indexArray[key] |
| | | break |
| | | } |
| | | } |
| | | // 运算值 |
| | | let itemNoStr = expression.substring(0, endIndex) |
| | | |
| | | // 运算符 |
| | | let operator = expression.substr(endIndex, 1) |
| | | let indexOfParenthesesLeft = itemNoStr.indexOf('(') |
| | | let lastIndexOfParenthesesLeft = itemNoStr.lastIndexOf('(') |
| | | |
| | | // 左括号 |
| | | let parenthesesLeft = '' |
| | | if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) { |
| | | parenthesesLeft = itemNoStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1) |
| | | itemNoStr = itemNoStr.substring(lastIndexOfParenthesesLeft + 1) |
| | | } |
| | | |
| | | let indexOfParenthesesRight = itemNoStr.indexOf(')') |
| | | let lastIndexOfParenthesesRight = itemNoStr.lastIndexOf(')') |
| | | |
| | | // 右括号 |
| | | let parenthesesRight = '' |
| | | if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) { |
| | | parenthesesRight = itemNoStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1) |
| | | itemNoStr = itemNoStr.substring(0, indexOfParenthesesRight) |
| | | } |
| | | expressionList.value.push({ |
| | | parenthesesLeft: parenthesesLeft, |
| | | itemNo: itemNoStr, |
| | | parenthesesRight: parenthesesRight, |
| | | operator: operator |
| | | }) |
| | | expression = expression.substring(endIndex + 1) |
| | | } else { |
| | | let pointStr = expression |
| | | let indexOfParenthesesLeft = pointStr.indexOf('(') |
| | | let lastIndexOfParenthesesLeft = pointStr.lastIndexOf('(') |
| | | let parenthesesLeft = '' |
| | | if (indexOfParenthesesLeft !== -1 && lastIndexOfParenthesesLeft !== -1) { |
| | | parenthesesLeft = pointStr.substring(indexOfParenthesesLeft, lastIndexOfParenthesesLeft + 1) |
| | | pointStr = pointStr.substring(lastIndexOfParenthesesLeft + 1) |
| | | } |
| | | let indexOfParenthesesRight = pointStr.indexOf(')') |
| | | let lastIndexOfParenthesesRight = pointStr.lastIndexOf(')') |
| | | let parenthesesRight = '' |
| | | if (indexOfParenthesesRight !== -1 && lastIndexOfParenthesesRight !== -1) { |
| | | parenthesesRight = pointStr.substring(indexOfParenthesesRight, lastIndexOfParenthesesRight + 1) |
| | | pointStr = pointStr.substring(0, indexOfParenthesesRight) |
| | | } |
| | | expressionList.value.push({ |
| | | parenthesesLeft: parenthesesLeft, |
| | | itemNo: pointStr, |
| | | parenthesesRight: parenthesesRight, |
| | | operator: '' |
| | | }) |
| | | expression = '' |
| | | } |
| | | } while (expression && expression.length > 0) |
| | | |
| | | } finally { |
| | | formLoading.value = false |
| | | } |
| | | } |
| | | } |
| | | function numAscSort(a, b) { |
| | | return a - b |
| | | } |
| | | |
| | | defineExpose({open}) // 提供 open 方法,用于打开弹窗 |
| | | |
| | | /** 提交表单 */ |
| | | const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 |
| | | const submitForm = async () => { |
| | | // 校验表单 |
| | | if (!formRef) return |
| | | const valid = await formRef.value.validate() |
| | | if (!valid) return |
| | | // 提交请求 |
| | | formLoading.value = true |
| | | try { |
| | | if (expressionList.value && expressionList.value.length > 0) { |
| | | let parenthesesLeftRex = /^[(]*$/ |
| | | let parenthesesRightRex = /^[)]*$/ |
| | | let expression = '' |
| | | for (let i = 0; i < expressionList.value.length; i++) { |
| | | let value = expressionList.value[i] |
| | | if (!parenthesesLeftRex.test(value.parenthesesLeft)) { |
| | | ElMessage({ |
| | | message: `第${i + 1}行左括号输入不正确!`, |
| | | type: 'error', |
| | | duration: 1500 |
| | | }) |
| | | return |
| | | } |
| | | if (!parenthesesRightRex.test(value.parenthesesRight)) { |
| | | ElMessage({ |
| | | message: `第${i + 1}行右括号输入不正确!`, |
| | | type: 'error', |
| | | duration: 1500 |
| | | }) |
| | | return |
| | | } |
| | | if (i !== (expressionList.value.length - 1) && !value.operator) { |
| | | ElMessage({ |
| | | message: `第${i + 1}行运算符不能为空!`, |
| | | type: 'error', |
| | | duration: 1500 |
| | | }) |
| | | return |
| | | } |
| | | expression = expression + value.parenthesesLeft + value.itemNo + value.parenthesesRight + (i === (expressionList.value.length - 1) ? '' : value.operator) |
| | | } |
| | | formData.value.calItem.expression = expression |
| | | } else { |
| | | ElMessage({ |
| | | message: `表达式不可以为空`, |
| | | type: 'error', |
| | | duration: 1500 |
| | | }) |
| | | return |
| | | } |
| | | formData.value.itemType = 'CAL' |
| | | const data = formData.value as ItemApi.ItemVO |
| | | if (formType.value === 'create') { |
| | | await ItemApi.createItem(data) |
| | | message.success(t('common.createSuccess')) |
| | | } else { |
| | | await ItemApi.updateItem(data) |
| | | message.success(t('common.updateSuccess')) |
| | | } |
| | | dialogVisible.value = false |
| | | // 发送操作成功的事件 |
| | | emit('success') |
| | | } finally { |
| | | formLoading.value = false |
| | | } |
| | | } |
| | | |
| | | function addExpressionRow(index, rows) { |
| | | let row = JSON.parse(JSON.stringify(rows[index])) |
| | | rows.splice(index, 0, row) |
| | | } |
| | | |
| | | function addParenthesesLeft(index, row) { |
| | | if (row.parenthesesLeft) { |
| | | row.parenthesesLeft = row.parenthesesLeft + '(' |
| | | } else { |
| | | row.parenthesesLeft = '(' |
| | | } |
| | | } |
| | | |
| | | function removeParenthesesLeft(index, row) { |
| | | if (row.parenthesesLeft) { |
| | | row.parenthesesLeft = row.parenthesesLeft.substring(0, row.parenthesesLeft.length - 1) |
| | | } else { |
| | | row.parenthesesLeft = '' |
| | | } |
| | | } |
| | | |
| | | function addParenthesesRight(index, row) { |
| | | if (row.parenthesesRight) { |
| | | row.parenthesesRight = row.parenthesesRight + ')' |
| | | } else { |
| | | row.parenthesesRight = ')' |
| | | } |
| | | } |
| | | |
| | | function removeParenthesesRight(index, row) { |
| | | if (row.parenthesesRight) { |
| | | row.parenthesesRight = row.parenthesesRight.substring(0, row.parenthesesRight.length - 1) |
| | | } else { |
| | | row.parenthesesRight = '' |
| | | } |
| | | } |
| | | |
| | | function deleteExpressionRow(index, rows) { |
| | | if (!rows || rows.length === 1) { |
| | | ElMessage({ |
| | | message: '不能全部删除!', |
| | | type: 'error', |
| | | duration: 1500 |
| | | }) |
| | | return |
| | | } |
| | | rows.splice(index, 1) |
| | | } |
| | | |
| | | /** 重置表单 */ |
| | | const resetForm = () => { |
| | | formData.value = { |
| | | id: undefined, |
| | | itemNo: '', |
| | | itemName: '', |
| | | itemType: '', |
| | | itemCategory: '', |
| | | coefficient: '', |
| | | precision: '', |
| | | businessType: '', |
| | | timeRange: '', |
| | | timeGranularity: '', |
| | | remark: '', |
| | | calItem: { |
| | | id: '', |
| | | expression: '', |
| | | }} |
| | | formRef.value?.resetFields() |
| | | } |
| | | </script> |