SysCheckRuleModal.vue 11.7 KB
<template>
  <a-modal
    :title="title"
    :width="1000"
    :visible="visible"
    :confirmLoading="confirmLoading"
    @ok="handleOk"
    @cancel="handleCancel"
    cancelText="关闭">

    <a-spin :spinning="confirmLoading">
      <a-form-model ref="form" :model="model" :rules="validatorRules">

        <a-form-model-item :labelCol="labelCol"  :wrapperCol="wrapperCol" label="规则名称" prop="ruleName" >
          <a-input placeholder="请输入规则名称" v-model="model.ruleName"/>
        </a-form-model-item>
        <a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="规则Code" prop="ruleCode">
          <a-input placeholder="请输入规则Code" v-model="model.ruleCode"/>
        </a-form-model-item>
        <a-form-model-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="规则描述" prop="ruleDescription">
          <a-textarea placeholder="请输入规则描述" v-model="model.ruleDescription"/>
        </a-form-model-item>

      </a-form-model>
      <!-- 规则设计 -->
      <a-tabs v-model="tabs.activeKey">
        <a-tab-pane tab="局部规则" :key="tabs.design.key" forceRender>
          <a-alert type="info" showIcon message="局部规则按照你输入的位数有序的校验。"/>
          <j-editable-table ref="designTable" dragSort rowNumber  :maxHeight="240" :columns="tabs.design.columns" :dataSource="tabs.design.dataSource" style="margin-top: 8px;">

            <template #action="props">
              <my-action-button :rowEvent="props"/>
            </template>

          </j-editable-table>
        </a-tab-pane>

        <a-tab-pane tab="全局规则" :key="tabs.global.key" forceRender>
          <j-editable-table ref="globalTable" dragSort rowNumber actionButton :maxHeight="240" :columns="tabs.global.columns"  :dataSource="tabs.global.dataSource">

            <template #actionButtonAfter>
              <a-alert type="info" showIcon message="全局规则可校验用户输入的所有字符;全局规则的优先级比局部规则的要高。" style="margin-bottom: 8px;"/>
            </template>

            <template #action="props">
              <my-action-button :rowEvent="props" allowEmpty/>
            </template>

          </j-editable-table>
        </a-tab-pane>
      </a-tabs>
    </a-spin>
  </a-modal>
</template>

<script>
  import pick from 'lodash.pick'
  import { httpAction } from '@/api/manage'
  import { validateDuplicateValue, alwaysResolve, failedSymbol } from '@/utils/util'
  import { FormTypes } from '@/utils/JEditableTableUtil'
  import JEditableTable from '@comp/jeecg/JEditableTable'

  export default {
    name: 'SysCheckRuleModal',
    components: {
      JEditableTable,
      'my-action-button': {
        props: { rowEvent: Object, allowEmpty: Boolean },
        methods: {
          confirmIsShow() {
            const { index, allValues: { inputValues } } = this.rowEvent
            let value = inputValues[index]
            return value.digits || value.pattern
          },
          handleLineAdd() {
            const { target } = this.rowEvent
            target.add()
          },
          handleLineDelete() {
            const { rowId, target } = this.rowEvent
            target.removeRows(rowId)
          },
          renderDeleteButton() {
            if (this.allowEmpty || this.rowEvent.index > 0) {
              if (this.confirmIsShow()) {
                return (
                  <a-popconfirm title="确定要删除吗?" onConfirm={this.handleLineDelete}>
                    <a-button icon="minus"/>
                  </a-popconfirm>
                )
              } else {
                return (
                  <a-button icon="minus" onClick={this.handleLineDelete}/>
                )
              }
            }
            return ''
          },
        },
        render() {
          return (
            <div>
              <a-button onClick={this.handleLineAdd} icon="plus"/>
              &nbsp;
              {this.renderDeleteButton()}
            </div>
          )
        }
      }
    },
    data() {
      return {
        title: '操作',
        visible: false,
        model: {},
        labelCol: {
          xs: { span: 24 },
          sm: { span: 5 },
        },
        wrapperCol: {
          xs: { span: 24 },
          sm: { span: 16 },
        },
        confirmLoading: false,
        validatorRules: {
          ruleName: [{required: true, message: '请输入规则名称!'}],
          ruleCode: [
            {required: true, message: '请输入规则Code!'},
            {validator: (rule, value, callback) => validateDuplicateValue('sys_check_rule', 'rule_code', value, this.model.id, callback)}
          ],
        },
        tabs: {
          activeKey: 'design',
          global: {
            key: 'global',
            columns: [
              {
                title: '优先级',
                key: 'priority',
                width: '15%',
                type: FormTypes.select,
                defaultValue: '1',
                options: [
                  { title: '优先运行', value: '1' },
                  { title: '最后运行', value: '0' },
                ],
                validateRules: []
              },
              {
                title: '规则(正则表达式)',
                key: 'pattern',
                width: '50%',
                type: FormTypes.input,
                validateRules: [
                  { required: true, message: '规则不能为空' },
                  { handler: this.validatePatternHandler },
                ]
              },
              {
                title: '提示文本',
                key: 'message',
                width: '20%',
                type: FormTypes.input,
                validateRules: [
                  { required: true, message: '${title}不能为空' },
                ]
              },
              {
                title: '操作',
                key: 'action',
                width: '15%',
                slotName: 'action',
                type: FormTypes.slot
              }
            ],
            dataSource: [],
          },
          design: {
            key: 'design',
            columns: [
              {
                title: '位数',
                key: 'digits',
                width: '15%',
                type: FormTypes.inputNumber,
                validateRules: [
                  { required: true, message: '${title}不能为空' },
                  { pattern: /^[1-9]\d*$/, message: '请输入零以上的正整数' },
                ]
              },
              {
                title: '规则(正则表达式)',
                key: 'pattern',
                width: '50%',
                type: FormTypes.input,
                validateRules: [
                  { required: true, message: '规则不能为空' },
                  { handler: this.validatePatternHandler }
                ]
              },
              {
                title: '提示文本',
                key: 'message',
                width: '20%',
                type: FormTypes.input,
                validateRules: [
                  { required: true, message: '${title}不能为空' },
                ]
              },
              {
                title: '操作',
                key: 'action',
                width: '15%',
                slotName: 'action',
                type: FormTypes.slot
              },
            ],
            dataSource: [],
          }
        },
        url: {
          add: '/sys/checkRule/add',
          edit: '/sys/checkRule/edit',
        },
      }
    },
    created() {
    },
    methods: {

      validatePatternHandler(type, value, row, column, callback, target) {
        if (type === 'blur' || type === 'getValues') {
          try {
            new RegExp(value)
            callback(true)
          } catch (e) {
            callback(false, '请输入正确的正则表达式')
          }
        } else {
          callback(true) // 不填写或者填写 null 代表不进行任何操作
        }
      },

      add() {
        this.edit({})
      },
      edit(record) {
        this.tabs.activeKey = this.tabs.design.key
        this.tabs.global.dataSource = []
        this.tabs.design.dataSource = [{ digits: '', pattern: '', message: '' }]
        this.visible = true
        this.$nextTick(() => {
          this.$refs.form.resetFields()
          this.model = Object.assign({}, record)

          // 子表数据
          let ruleJson = this.model.ruleJson
          if (ruleJson) {
            let ruleList = JSON.parse(ruleJson)
            // 筛选出全局规则和局部规则
            let global = [], design = [], priority = '1'
            ruleList.forEach(rule => {
              if (rule.digits === '*') {
                global.push(Object.assign(rule, { priority }))
              } else {
                priority = '0'
                design.push(rule)
              }
            })
            this.tabs.global.dataSource = global
            this.tabs.design.dataSource = design
          }
        })
      },
      close() {
        this.$emit('close')
        this.visible = false
      },
      handleOk() {
        Promise.all([
          // 主表单校验
          alwaysResolve(new Promise((resolve, reject) => {
            this.$refs.form.validate((ok, err) => ok ? resolve(this.model) : reject(err))
          })),
          // 局部规则子表校验
          alwaysResolve(this.$refs.designTable.getValuesPromise),
          // 全局规则子表校验
          alwaysResolve(this.$refs.globalTable.getValuesPromise),
        ]).then(results => {
          let [mainResult, designResult, globalResult] = results

          if (mainResult.type === failedSymbol) {
            return Promise.reject('主表校验未通过')
          } else if (designResult.type === failedSymbol) {
            this.tabs.activeKey = this.tabs.design.key
            return Promise.reject('局部规则子表校验未通过')
          } else if (globalResult.type === failedSymbol) {
            this.tabs.activeKey = this.tabs.global.key
            return Promise.reject('全局规则子表校验未通过')
          } else {
            // 所有校验已通过,这一步是整合数据
            let mainValues = mainResult.data, globalValues = globalResult.data, designValues = designResult.data

            // 整合两个子表的数据
            let firstGlobal = [], afterGlobal = []
            globalValues.forEach(v => {
              v.digits = '*'
              if (v.priority === '1') {
                firstGlobal.push(v)
              } else {
                afterGlobal.push(v)
              }
            })
            let concatValues = firstGlobal.concat(designValues).concat(afterGlobal)
            let subValues = concatValues.map(i => pick(i, 'digits', 'pattern', 'message'))

            // 生成 formData,用于传入后台
            let ruleJson = JSON.stringify(subValues)
            let formData = Object.assign(this.model, mainValues, { ruleJson })

            // 判断请求方式和请求地址,并发送请求
            let method = 'post', httpUrl = this.url.add
            if (this.model.id) {
              method = 'put'
              httpUrl = this.url.edit
            }
            this.confirmLoading = true
            return httpAction(httpUrl, formData, method)
          }
        }).then((res) => {
          if (res.success) {
            this.$message.success(res.message)
            this.$emit('ok')
            this.close()
          } else {
            this.$message.warning(res.message)
          }
        }).catch(e => {
          console.error(e)
        }).finally(() => {
          this.confirmLoading = false
        })
      },
      handleCancel() {
        this.close()
      },

    }
  }
</script>

<style lang="less" scoped></style>