Newer
Older
smart-metering-front / src / views / system / dict / editDict.vue
<script lang="ts" setup name="SystemEditDict">
import type { Ref } from 'vue'
import { nextTick, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import type { DictDetail, DictInfo, DictListInfo } from './dict-interface'
import { addDict, updateDict } from '@/api/system/dict'
// ----------------------- 以下是字段定义 emits props ---------------------
const emits = defineEmits(['closeRefresh'])

// 对话框类型:create,update
const dialogStatus = ref('create')
const dialogVisible = ref(false)
// 显示标题
const textMap: { [key: string]: string } = {
  update: '编辑',
  create: '新增',
}
// 表单数据对象
const formData: DictInfo = reactive({
  dictId: '',
  dictCode: '',
  dictName: '',
  dictTips: '',
  dictValues: '',
})

const details: Ref<DictDetail[]> = ref([])

// 保存按钮加载状态
const btnLoading = ref(false)

// ---------------表单提交--------------------------------
// 表单对象
const dataFormRef = ref<FormInstance>()
// 校验规则
const rules = reactive<FormRules>({
  dictCode: [{ required: true, message: '字典编码不能为空', trigger: ['blur'] }],
  dictName: [{ required: true, message: '字典名称不能为空', trigger: ['blur'] }],
  value: [{ required: true, message: '值不能为空', trigger: ['blur'] }],
  name: [{ required: true, message: '名称不能为空', trigger: ['blur'] }],
  num: [{ required: true, message: '排序不能为空' }, { type: 'number', message: '必须为数字值' }],
})

// 表单提交
function submitForm() {
  if (dataFormRef) {
    dataFormRef.value?.validate((valid: boolean) => {
      if (valid) {
        const flag = arrayToString()
        if (flag) {
          if (dialogStatus.value === 'create') {
            createData()
          }
          else if (dialogStatus.value === 'update') {
            updateData()
          }
        }
      }
    })
  }
}

// 字典详情字符串转数组
function stringToArray() {
  const detailArr = formData.dictValues.split(';')
  details.value = []
  for (const detail of detailArr) {
    const detailItem = detail.split(':')
    const item: DictDetail = {
      value: detailItem[0],
      name: detailItem[1],
      num: parseInt(detailItem[2]),
    }
    details.value.push(item)
  }
}
// 数据转换, 字典详情转换为中间带冒号的
function arrayToString() {
  let detailArray = ''
  const detailList = details.value
  let passFlag = true
  if (detailList.length === 0) {
    passFlag = false
    ElMessage.warning('至少有一个字典值')
    return passFlag
  }
  detailList.forEach((detail, index) => {
    if (detail.value === '' || detail.name === '') {
      passFlag = false
    }
    detailArray += `${detail.value}:${detail.name}:${detail.num}`
    if (index !== (detailList.length - 1)) {
      detailArray += ';'
    }
  })
  if (!passFlag) {
    ElMessage.warning('请将字典值和名称都填全后再进行保存')
  }
  formData.dictValues = detailArray
  return passFlag
}
// 新增数据
function createData() {
  btnLoading.value = true
  addDict(formData).then((res) => {
    ElMessageBox.confirm(
      '新增成功,是否继续新增?',
      '提示',
      {
        confirmButtonText: '是',
        cancelButtonText: '否',
        type: 'info',
      },
    ).then(() => {
      resetForm()
    }).catch(() => {
      closeRefresh()
    })
    btnLoading.value = false
  }).catch((_) => {
    btnLoading.value = false
  })
}

// 更新数据
function updateData() {
  updateDict(formData).then((res) => {
    ElMessage.success('修改成功')
    btnLoading.value = false
    closeRefresh()
  }).catch((_) => { // 异常情况,loading置为false
    btnLoading.value = false
  })
}
// 添加一行
function addDetail() {
  details.value.push({
    value: '',
    name: '',
    num: details.value.length,
  })
}
// 删除一行
function deleteDetail(index: number) {
  details.value.splice(index, 1)
}
// 重置表单
function resetForm() {
  formData.dictId = ''
  formData.dictCode = ''
  formData.dictName = ''
  formData.dictTips = ''
  formData.dictValues = ''
  details.value = []
}

// ----------初始化、关闭对话框相关-----------------
function initDialog(dialogstatus: string, row: DictListInfo) {
  dialogStatus.value = dialogstatus
  dialogVisible.value = true
  btnLoading.value = false
  if (dialogstatus === 'create') {
    resetForm()
    nextTick(() => {
      dataFormRef.value?.clearValidate()
    })
  }
  else if (dialogstatus === 'update') {
    formData.dictId = row.id
    formData.dictCode = row.code
    formData.dictName = row.name
    formData.dictTips = row.tips
    formData.dictValues = row.detail
    stringToArray()
  }
}

// 关闭并刷新
function closeRefresh() {
  dialogVisible.value = false
  resetForm()
  emits('closeRefresh')
}
// 关闭弹窗
function dialogClose() {
  dialogVisible.value = false
  resetForm()
}
// ----------------------- 以下是暴露的方法内容 ----------------------------
defineExpose({ initDialog })
</script>

<template>
  <el-dialog
    v-model="dialogVisible"
    :title="textMap[dialogStatus]"
    width="50%"
    :before-close="dialogClose"
    append-to-body
    :open-delay="0"
    :close-on-click-modal="false"
  >
    <el-form
      ref="dataFormRef" :model="formData" :rules="rules" label-position="left" label-width="80px" class="form-container"
      size="default" @submit.prevent
    >
      <el-row :gutter="10">
        <el-col :span="12" class="grid-cell">
          <el-form-item label="字典名称" prop="dictName" class="required">
            <el-input v-model="formData.dictName" type="text" placeholder="必填" clearable />
          </el-form-item>
        </el-col>
        <el-col :span="12" class="grid-cell">
          <el-form-item label="字典编码" prop="dictCode" class="required">
            <el-input v-model="formData.dictCode" type="text" placeholder="必填" clearable />
          </el-form-item>
        </el-col>
        <el-col :span="24" class="grid-cell">
          <el-form-item label="字典描述" prop="tips" class="required">
            <el-input v-model="formData.dictTips" type="text" placeholder="非必填" clearable />
          </el-form-item>
        </el-col>
        <div class="dict-detail">
          <div class="title">
            字典值列表
            <el-button type="default" style="margin-left: 20px;" @click="addDetail()">
              添加
            </el-button>
          </div>
          <div class="body">
            <el-row v-for="(detail, index) in details" :key="index" :gutter="10">
              <el-col :span="6">
                <el-form-item :required="true" label="值" label-width="40">
                  <el-input v-model="detail.value" style="width: 100%;" placeholder="必填" />
                </el-form-item>
              </el-col>
              <el-col :span="7">
                <el-form-item :required="true" label="名称" label-width="60">
                  <el-input v-model="detail.name" style="width: 100%;" placeholder="必填" />
                </el-form-item>
              </el-col>
              <el-col :span="6">
                <el-form-item :required="true" label="排序" label-width="60">
                  <el-input-number v-model.number="detail.num" style="width: 100%;" placeholder="必填" />
                </el-form-item>
              </el-col>
              <el-col :span="2" :offset="1">
                <el-button type="primary" @click="deleteDetail(index)">
                  删除
                </el-button>
              </el-col>
            </el-row>
          </div>
        </div>
      </el-row>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button :loading="btnLoading" type="primary" @click="submitForm">
          保存
        </el-button>
        <el-button @click="dialogClose">
          取消
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<style lang="scss" scoped>
.form-container {
  width: 100%;

  .full-width-input {
    width: 100%;
  }

  .dict-detail {
    padding: 10px;

    .title {
      font-size: 16px;
      font-weight: bold;
      margin-bottom: 15px;
    }
  }
}
</style>