动态 modal 弹窗组件

475 阅读4分钟

环境

"ant-design-vue": "1.7.2"

功能

支持填写配置参数生成 列表页的模态框编辑,详情预览,新建等功能

组件目录

detail.vue - 详情页面

detailModel.vue - 弹框界面

detailModel.js - 弹框逻辑

index,js - 默认导出

props.js - 组件传参

演示

\

\

使用方法

引入组件

import detailModel from "@/pages/review/components/detailModel";

创建组件

<div v-if="detail_model_data.visible">
  <detailModel
		:visible="detail_model_data.visible"
    :type="detail_model_data.type"
    :title="detail_model_data.tableTitle"
    :columns="detail_model_data.columns"
    :width="detail_model_data.width"
    :record="detail_model_data.record"
    @closemodel="detail_model_data.visible = false"
	/>
</div>

组件参数配置

data(){
  return {
    detail_model_data: {
      visible: false,
      type: "edit",
      tableTitle: "编辑",
      columns: COLUMNS,
      width: 1000,
      record: {},
    },
  }
}
// 配合按钮实现打开方式切换
methods:{
  opendetailmodal(option, record) {
    console.log(option, record);
    if (option === "edit") {
      this.detail_model_data = {
        visible: true,
        tableTitle: `编辑`,
        width: 800,
        type: option,
        columns: this.columns,
        record: record,
      };
    } else {
      this.detail_model_data = {
        visible: true,
        tableTitle: `用户详情`,
        width: 1000,
        type: option,
        columns: this.columns,
        record: record,
      };
    }
  },
}

页面

detailModal.vue

<template>
  <a-modal
    :title="title"
    :visible="visible"
    :confirm-loading="confirmLoading"
    @ok="handleOk"
    @cancel="handleCancel"
    :width="width"
    :destroyOnClose="true"
  >
    <deatil v-if="type === 'info'" :columns="columns" :record="record" />

    <a-form-model
      v-show="type === 'edit'"
      ref="ruleForm"
      :model="form"
      :rules="rules"
      :label-col="labelCol"
      :wrapper-col="wrapperCol"
    >
      <a-form-model-item
        :ref="item.dataIndex"
        v-if="item.edit_show !== false && rules"
        v-for="item in columns"
        :key="item.dataIndex"
        :label="item.title"
        :prop="item.dataIndex"
      >
        <!-- 输入框 -->
        <div v-if="item.formType === 'ldq-input'">
          <a-input
            :placeholder="item.placeholder"
            v-model="form[item.dataIndex]"
            @blur="
              () => {
                $refs[item.dataIndex][0].onFieldBlur();
              }
            "
          />
        </div>
        <!-- 单选 -->
        <div v-else-if="item.formType === 'ldq-radio' && item.radios">
          <a-radio-group
            :placeholder="item.placeholder"
            v-model="form[item.dataIndex]"
            name="radioGroup"
          >
            <a-radio
              v-for="radio in item.radios"
              :key="radio.value"
              :value="radio.value"
            >
              {{ radio.label }}
            </a-radio>
          </a-radio-group>
        </div>
        <!-- 下拉选择 -->
        <div v-else-if="item.formType === 'ldq-select' && item.selects">
          <a-select
            style="width: 120px"
            v-model="form[item.dataIndex]"
            :placeholder="item.placeholder"
          >
            <!-- @change="handleChange" -->
            <a-select-option
              v-for="select in item.selects"
              :key="select.value"
              :value="select.value"
            >
              {{ select.label }}
            </a-select-option>
          </a-select>
        </div>
      </a-form-model-item>
      <a-form-model-item :wrapper-col="{ span: 14, offset: 4 }">
        <a-button @click="resetForm">
          重置
        </a-button>
        <a-button type="primary" style="margin-left: 10px;" @click="onSubmit">
          提交
        </a-button>
      </a-form-model-item>
    </a-form-model>
  </a-modal>
</template>

<script src="./detailModel.js"></script>
<style lang="less" scoped>
#svg-btn {
  cursor: pointer;
  border: 1px solid rgb(217 217 217);
  padding: 3.5px 15px;
  border-radius: 3.5px;
  transition: 0.5;
}
#svg-btn:hover {
  border: 1px solid #1890ff;
}
</style>

逻辑代码

detailModel.js

import { props, CONFIG } from "./props";
import deatil from "./detail.vue";
console.log(props, CONFIG);
export default {
  name: "detailModel",
  props: props,
  components: { deatil },
  data() {
    const form = {};
    const rules = {};
    this.columns.forEach(_ => {
      form[_.dataIndex] = this.record[_.dataIndex];
      // console.log(_.edit_show === false);
      // 去掉不需要编辑的
      if (_.edit_show === false) {
        // console.log(form, _.dataIndex);
        delete form[_.dataIndex];
        // console.log(form, _.dataIndex);
      }
      // rule
      console.log(_.rule);
      if (_.rule) {
        rules[_.dataIndex] = _.rule;
      }
    });
    console.log(this.columns);
    return {
      confirmLoading: false,
      // formLayout: "horizontal",
      // form: this.$form.createForm(this, { name: "coordinated" }),
      labelCol: { span: 4 },
      wrapperCol: { span: 14 },
      other: "",
      resetFormBtn: true,
      form: {
        ...form,
        // name: "",
        // region: undefined,
        // date1: undefined,
        // delivery: false,
        // type: [],
        // resource: "",
        // desc: "",
      },
      rules: rules,
      //  {
      // name: [
      //   {
      //     required: true,
      //     message: "Please input Activity name",
      //     trigger: "blur",
      //   },
      //   {
      //     min: 3,
      //     max: 5,
      //     message: "Length should be 3 to 5",
      //     trigger: "blur",
      //   },
      // ],
      // region: [
      //   {
      //     required: true,
      //     message: "Please select Activity zone",
      //     trigger: "change",
      //   },
      // ],
      // date1: [
      //   { required: true, message: "Please pick a date", trigger: "change" },
      // ],
      // type: [
      //   {
      //     type: "array",
      //     required: true,
      //     message: "Please select at least one activity type",
      //     trigger: "change",
      //   },
      // ],
      // resource: [
      //   {
      //     required: true,
      //     message: "Please select activity resource",
      //     trigger: "change",
      //   },
      // ],
      // desc: [
      //   {
      //     required: true,
      //     message: "Please input activity form",
      //     trigger: "blur",
      //   },
      // ],
      // teacherName: [
      //   {
      //     required: true,
      //     message: "Please input activity form",
      //     trigger: "blur",
      //   },
      // ],
      // },
    };
  },
  created() {
    // 赋值
    this.columns.forEach(_ => {
      this.form[_.dataIndex] = this.record[_.dataIndex];
    });
  },
  mounted() {
    // console.log("type", this.type);
    // console.log("visible", this.visible);
    // console.log("title", this.title);
    // console.log("columns", this.columns);
    // console.log("wdith", this.width);
    // console.log("wdith", this.record);
    console.log(this.rules);
  },
  methods: {
    handleBlur(ref) {
      console.log(this.$refs[ref][0]);
      if (this.rules[ref]) {
        this.$refs[ref][0].onFieldBlur();
      }
    },
    onSubmit() {
      this.$refs.ruleForm.validate(valid => {
        if (valid) {
          // alert("submit!");
          console.log(this.form);
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    resetForm() {
      this.$refs.ruleForm.resetFields();
      // console.log(this.form)
      // this.resetFormBtn = false;
      // this.columns.forEach(_ => {
      //   // console.log(this.form[_.dataIndex], this.record[_?.dataIndex]);
      //   this.form[_.dataIndex] = this.record[_.dataIndex];
      // });
      // this.resetFormBtn = true;
    },
    handleSubmit(e) {
      e.preventDefault();
      // console.log(this.columns);
      this.form.validateFields((err, values) => {
        if (!err) {
          console.log("Received values of form: ", values);
        }
      });
    },
    // handleSelectChange(value) {
    //   console.log(value);
    //   this.form.setFieldsValue({
    //     note: `Hi, ${value === "male" ? "man" : "lady"}!`,
    //   });
    // },
    // handleClick(e) {
    //   this.$emit("click", e);
    // },
    // showModal() {
    //   // this.visible = true;
    //   this.$emit("closemodel");
    // },
    // eslint-disable-next-line no-unused-vars
    handleOk(e) {
      this.ModalText = "The modal will be closed after two seconds";
      this.confirmLoading = true;
      setTimeout(() => {
        // this.visible = false;
        this.$emit("closemodel");
        this.confirmLoading = false;
      }, 2000);
    },
    // eslint-disable-next-line no-unused-vars
    handleCancel(e) {
      // console.log("Clicked cancel button");
      this.$emit("closemodel");
      // this.visible = false;
    },
  },
};

\

\

组件接受参数

\

const props = {
  // 显示隐藏
  visible: {
    type: Boolean,
    required: true,
    default: false,
  },
  // 类型  编辑、详情
  type: {
    type: String,
    required: true,
  },
  // 宽度
  width: {
    type: Number,
    required: true,
    default: 1000,
  },
  // 标题
  title: {
    type: String,
    required: true,
  },
  // 数据配置
  columns: {
    type: Array,
    default: function() {
      return CONFIG;
    },
  },
  // 用户数据
  record: {
    type: Object,
    default: function() {
      return {};
    },
  },
};

\

数据配置 columns

\

const columns = [
  {
    title: "用户名",
    dataIndex: "name",
    scopedSlots: { customRender: "description" },
    width: 150,
    fixed: "left",
    ellipsis: true,
    // 是否在详情页展示
    info_show: true,
    // 是否可编辑
    edit_show: true,
    // 校验规则
    rule: [
      {
        required: true,
        message: "请填写用户名",
        trigger: "blur",
      },
      {
        min: 3,
        max: 10,
        message: "字符长度3-10",
        trigger: "blur",
      },
    ],
    // 输入框类型
    formType: "a-input",
    //
  },
];

\

数据配置 record

\

const record = {
  id: 1,
  name: "sadmin",
  secondarySectorId: 1,
  secondarySectorName: "二级学院a",
  updateTime: 1642837141,
},

表格配置

faculty.js

export const COLUMNS = [
  // {
  //   title: "id",
  //   dataIndex: "id",
  //   scopedSlots: { customRender: "description" },
  //   width: 150,
  //   fixed: "left",
  //   ellipsis: true,
  //   是否在详情页展示
  //   info_show: false,
  //   是否在编辑页展示
  //   edit_show: false,
  // },
  {
    title: "用户名",
    dataIndex: "name",
    scopedSlots: { customRender: "description" },
    width: 150,
    fixed: "left",
    ellipsis: true,
    // 动态modal配置
    formType: "ldq-input",
    info_show: true,
    edit_show: true,
    rule: [
      {
        required: true,
        message: "请填写用户名",
        trigger: "blur",
      },
      {
        min: 3,
        max: 10,
        message: "字符长度3-10",
        trigger: "blur",
      },
    ],
    placeholder: "请填写用户名,字符长度3-10",
  },
  {
    title: "允许登陆",
    dataIndex: "allowLogin",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
    // 动态modal配置
    formType: "ldq-radio",
    info_show: true,
    edit_show: true,
    rule: [
      {
        required: true,
        message: "请设置是否允许改用户登陆",
        trigger: "change",
      },
    ],
    placeholder: "请设置是否允许改用户登陆",
    radios: [
      {
        label: "允许",
        value: 1,
      },
      {
        label: "不允许",
        value: 0,
      },
    ],
  },
  {
    title: "更新时间",
    dataIndex: "updateTime",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
    info_show: true,
    edit_show: false,
    // // 动态modal配置 日期
    // formType: "ldq-DatePicker",
    // // timeType 时间格式
    // // 1. 时间戳
    // // 2. YY-M
    // dataeType: "",
    // info_show: true,
    // rule: [
    //   {
    //     required: true,
    //     message: "请选择时间",
    //     trigger: "change",
    //   },
    // ],
    // placeholder: "请选择时间",
  },
  {
    title: "教师姓名",
    dataIndex: "teacherName",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
    // 动态modal配置
    formType: "ldq-input",
    info_show: true,
    edit_show: true,
    rule: [
      {
        required: true,
        message: "请填写教师姓名",
        trigger: "blur",
      },
      {
        min: 2,
        max: 5,
        message: "字符长度2-5",
        trigger: "blur",
      },
    ],
    placeholder: "教师姓名,字符长度2-5",
  },
  {
    title: "岗位",
    dataIndex: "jobs",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
    // 动态modal配置
    formType: "ldq-select",
    info_show: true,
    edit_show: true,
    rule: [
      {
        required: true,
        message: "请选择岗位",
        trigger: "blur",
      },
    ],
    placeholder: "请选择岗位",
    selects: [
      {
        label: "校聘",
        value: "校聘",
      },
      {
        label: "院聘",
        value: "院聘",
      },
    ],
  },
  {
    title: "岗位系列",
    dataIndex: "postSeries",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
  },
  {
    title: "岗位等级",
    dataIndex: "postGrades",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
  },
  {
    title: "岗位类型",
    dataIndex: "postType",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
  },
  {
    title: "二级部门编号",
    dataIndex: "secondarySectorNumber",
    scopedSlots: { customRender: "description" },
    width: 150,
  },
  {
    title: "二级部门信息id",
    dataIndex: "secondarySectorId",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
  },
  {
    title: "二级部门名称",
    dataIndex: "secondarySectorName",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
  },
  {
    title: "职能部门信息id",
    dataIndex: "functionId",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
  },
  {
    title: "职能部门编号",
    dataIndex: "functionNumber",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
  },
  {
    title: "职能部门名称",
    dataIndex: "functionName",
    scopedSlots: { customRender: "description" },
    width: 150,
    ellipsis: true,
  },
  {
    title: "操作",
    scopedSlots: { customRender: "action" },
    width: 200,
    fixed: "right",
    // 是否在详情页展示
    info_show: false,
    // 是否在编辑页展示
    edit_show: false,
  },
];

API

COLUMNS

antd

参数说明类型默认值
title显示名称string
dataIndexkeystring
width宽度number
ellipsis省略booleanfalse

detailModal 动态modal配置

formType输入框类型string
info_show查看详情时是否显示boolean
edit_show更新时是否显示boolean
is_Editable更新时是否可编辑boolean
add_show新增时是否可编辑boolean
rule校验规则array

formType

ldq-input

功能组件

\

允许登陆

<div slot="allowLogin" slot-scope="{ text }">
  <a-tag color="green" v-if="text === 1">
    允许
  </a-tag>
  <a-tag color="red" v-if="text === 0">
    禁止
  </a-tag>
</div>
  {
    title: "允许登陆",
    dataIndex: "allowLogin",
    scopedSlots: { customRender: "allowLogin" },
    ellipsis: true,
    // 动态modal配置
    formType: "ldq-radio",
    info_show: true,
    edit_show: true,
    add_show: true,
    is_Editable: true,
    rule: [
      {
        required: true,
        message: "请设置是否允许用户登陆",
        trigger: "change",
      },
    ],
    placeholder: "请设置是否允许用户登陆",
    radios: [
      {
        label: "允许",
        value: 1,
      },
      {
        label: "不允许",
        value: 0,
      },
    ],
  },
   
    

显示隐藏api

const a = {
    // 查看详情时是否显示
    info_show: true,
    // 更新时是否显示
    edit_show: true,
    // 更新时是否可编辑
    is_Editable: false,
    // 新增时是否可编辑
    add_show: false,
}

列表隐藏

const a = {
  colSpan: 0,
  customRender: value => {
    const obj = {
      children: value,
      attrs: {
        colSpan: 0,
      },
    };
    return obj;
  },
}

tag

<div slot="allowLogin" slot-scope="{ text }">
  <a-tag color="green" v-if="text === 1">
    允许
  </a-tag>
  <a-tag color="red" v-if="text === 0">
    禁止
  </a-tag>
</div>

时间转换

          <div slot="updateTime" slot-scope="{ text }">
            {{ timestampToTime(text) }}
          </div>
    timestampToTime(timestamp) {
      var date = new Date(timestamp * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
      var Y = date.getFullYear() + "-";
      var M =
        (date.getMonth() + 1 < 10
          ? "0" + (date.getMonth() + 1)
          : date.getMonth() + 1) + "-";
      var D = date.getDate() + " ";
      var h = date.getHours() + ":";
      var m = date.getMinutes() + ":";
      var s = date.getSeconds();
      return Y + M + D + h + m + s;
    },

下拉框

const a = 
      {
        title: "二级部门名称",
        dataIndex: "secondarySectorId",
        scopedSlots: { customRender: "secondarySectorId" },
        ellipsis: false,
        // 动态modal配置
        formType: "ldq-select",
        info_show: true,
        edit_show: true,
        add_show: true,
        is_Editable: true,
        rule: [
          {
            required: true,
            message: "请选择二级部门名称",
            trigger: "blur",
          },
        ],
        placeholder: "请选择二级部门名称",
        selectType: "api",
        Api: "searchSecondarySectorDepartmentList",
        selects: [],
      },

内嵌表格

        <!-- 内嵌表格 -->
        <DetailTable
          :columns="columns"
          :formType="'ldq-list'"
          :records="record"
          :option="type === 'Info'"
          v-if="record.author"
          :id="record.id"
          :userType="userType"
        />
数据库读写,
费用,

demo

demo