1.1.11 • Published 2 years ago

vue-element-customize v1.1.11

Weekly downloads
6,987
License
MIT
Repository
github
Last release
2 years ago

功能列表

组件

CustomizeTable, CustomizePagination, CustomizeSearchBar, CustomizeSwitch, CustomizeForm, CustomizeDialogForm, CustomizePage, CustomizeFormBuilder

辅助函数

isEmpty, clean, setValue, deepClone, formatDate, sleep, deepMerge,

自定义样式

select, input, el-radio-group, el-checkbox-group [round]属性
input [no-border]属性

全量引入

import Customize from 'vue-element-customize';
Vue.use(Customize);

传入配置项

Vue.use(Customize, {
  CustomizeTable: {},
  CustomizePagination: {},
  CustomizeSearchBar: {},
  CustomizeSwitch: {},
  CustomizeForm: {},
  CustomizeDialogForm: {},
  CustomizeFormBuilder: {},
});

按需引入

组件引入

import { CustomizeTable, CustomizePagination, CustomizeSearchBar, CustomizeSwitch, CustomizeForm, CustomizeDialogForm, CustomizePage, CustomizeFormBuilder } from 'vue-element-customize';
Vue.use(CustomizeTable, {});
Vue.use(CustomizePagination, {});
Vue.use(CustomizeSearchBar, {});
Vue.use(CustomizeSwitch, {});
Vue.use(CustomizeForm, {});
Vue.use(CustomizeDialogForm, {});
Vue.use(CustomizePage);
Vue.use(CustomizeFormBuilder);

辅助函数引入

辅助函数全量引入
import { CustomizeUtils } from 'vue-element-customize';
Vue.use(CustomizeUtils);
辅助函数按需引入
import { isEmpty, clean, setValue, deepClone, formatDate, sleep, deepMerge } from 'vue-element-customize';
Vue.prototype._isEmpty = isEmpty;
Vue.prototype._clean = clean;
Vue.prototype._setValue = setValue;
Vue.prototype._deepClone = deepClone;
Vue.prototype._formatDate = formatDate;
Vue.prototype._sleep = sleep;
Vue.prototype._deepMerge = deepMerge;
自定义样式引入
import 'vue-element-customize/lib/styles/index.scss'

项目级配置

CustomizeTable配置

stripe: Boolean,  // true
border: Boolean,  // false
size: String,  // medium
headerCellStyle: Object,  // { backgroundColor: '#f5f7fa', color: '#909399',  borderBottom: 0,  height: '50px', },
cellStyle: Object,  // { borderBottom: 0 },
className: String,
align: String,

CustomizePagination配置

pageSizes: Array,  // [10,20,50,100]
layout: String,  // 'total, sizes, prev, pager, next, jumper'
align: String,  // right
className: String,
pageSize: Number,  // 10

CustomizeSearchBar配置

size: String,  // medium
className: String,  //''
blockButtons: Boolean,  // false
showResetButton: Boolean,  // true
openEnterSearch: Boolean,  // false
searchButtonName: String,  // 查询
optionAllName: String,  // 全部

CustomizeSwitch配置

defaultColor: Array,  // 默认的[打开背景色, 关闭背景色]
className: String,

CustomizeForm配置

size: String,  // medium
className: String,  //''
showSubmitButton: Boolean,  // true
showResetButton: Boolean,  // true
submitButtonName: String,  // 提交
resetButtonName: String,  // 重置
openEnterSubmit: Boolean,  // false
optionAllName: String,  // 全部
labelWidth: String,  // 120px
clearable: Boolean,  // true
hideOptionAll: Boolean,  // true

CustomizeDialogForm配置

form: Object,  // 弹窗内form的配置,同CustomizeForm
size: String,  // medium
closeButtonShow: [Boolean, String],  // true
closeButtonName: String,  // 关闭
className: String,  // dialog自定义class

CustomizeTable组件

组件配置

props
data: Array,  // 渲染的数据

column: Array,  // 表格配置
  {
    prop: String,  // 渲染数据的key值
    label: String, // key值对应的表头名
    width: String, //宽度
    sortable: Function,  //排序
    formatter: Function,  //(row, column, cellValue, index) {}
    slot: String,  // 传入的slot名
  }

size: String,
type: String,  // 'index'
headerCellStyle: Function,  // ({row, column, rowIndex, columnIndex}) {} '表头样式'
cellStyle: Object,
sortable: Boolean,
stripe: Boolean,
border: Boolean,
className: String,
maxHeight: [String, Number],
align: String,  // 'center'
emit
@sortChange  //排序
@selectionChange
ref
ref: 'table'
slot
slot before // 默认slot 前
slot after  // 默认slot 最后

example

<customize-table
  :data="tableData"
  :column="tableColumn"
  v-loading="tableLoading"
>
  <template #slotName>
    <el-table-column label="slot-slotName" align="center">
      <template #default="{ row }">
        <span>{{ _isEmpty(row.status) }}</span>
      </template>
    </el-table-column>
  </template>
  <template #after>
    <el-table-column label="操作" align="center">
      <template #default="{ row }">
        <el-button type="primary" size="mini" @click="handleEdit(row.id)">编辑</el-button>
      </template>
    </el-table-column>
  </template>
</customize-table>

data() {
  return {
    tableLoading: false,
    tableData: [],
    tableColumn: [
      // { type: 'index', index: (index) => (this.current - 1) * this.size + index + 1 },
      { label: '名称', prop: 'name' },
      { label: '属性', prop: 'aaa', width: '100px', w: '100px' },
      { label: '状态', prop: 'status', formatter(row, column, cellValue, index) { 
        const Enum = {
          0: '暂停',
          1: '启用',
        }
        return Enum[cellValue] || '--';
      }},
      { slot: 'slotName' }
    ],
  }
},

CustomizePagination组件

组件配置

props
current.sync: [Number, String],  // 当前页
size.sync: [Number, String],  // 当前每页个数
total: [Number, String],  // 总个数

pageSizes: Array,  // 每页显示个数选择器的选项设置
layout: String,  // 组件布局 'sizes, prev, pager, next, jumper, ->, total, slot',
align: String,  // 组件位置 text-align
className: String,
emit
@change

example

<customize-pagination
  :current.sync="current"
  :total="total"
  :size.sync="size"
  @change="handleChangePage"
  style="padding-bottom: 30px;"
></customize-pagination>

data() {
  return {
    current: 1,
    total: 0,
    size: 10,
  }
},

methods: {
  handleChangePage({ current, size }) {
    this.fetchData();
  },
},

CustomizeSearchBar组件

组件配置

props
loading.sync: false,  // 搜索按钮loading状态

setting: [{
  type: String,  // input/select
  label: String // 表单label名
  prop: String,  // 提交的字段名 必填
  placeholder: String,  // 默认为请输入/选择 label 
  default: Any, // 默认值
  width: String, // style中width
  rules: Array,  // 替换默认rule
  required: Boolean, // true/false
  msg: String, // 错误提示信息
  prefixIcon: String, // type input时,输入框icon
  className: String,  // type input时,el-form-item的class

  slot: String,  // slot  #slot="{ form }"

  enum: Array | Object,  // 直接传入枚举或数组  label value
  enumProp: String,  // select时,enum中传入的枚举属性值
  hideOptionAll: true, // select时,隐藏‘全部’选项传入true
  optionAllName: String,  // select,全部显示label名,默认全部
}],

enum: {
  [enumProp]: [{ label: '', prop: '' }]
}

validate: Boolean,  // 开启表单验证 配合rules
inlineButtons: Boolean  // 按钮不换行
size: String,  // 表单size
className: String,  // form自定义class
blockButtons: Boolean,  // 是否将按钮组换行展示,默认false
showResetButton: Boolean,  // 是否展示重置按钮,默认true
openEnterSearch: Boolean,  // 是否开启input的回车搜索,默认false
searchButtonName: String,  // 查询按钮文案
full-width: Boolean,  // inline模式铺满宽度,输入框宽度自适应
inline: Boolean,  // inline 默认true
margin: String,  // el-form-item margin-right '10px'
marginLeft: String,  // el-form-item margin-right设为0,margin-left为该px
showSearchButton: Boolean,  // 是否显示搜索按钮 默认true
immediate: Boolean,  // select/date,是否值改变时立即触发搜索,默认false
optionAllName: String,  // select全部选项的名称,默认全部
emit
@submit  // emit所有表单参数
slot
#after="form" 
ref
ref: form

example

<customize-search-bar
  :loading.sync="searchBarLoading"
  @submit="handleSubmitSearch"
  :setting="searchBarSetting"
  :Enum="searchBarEnum"
></customize-search-bar>

data() {
  return {
    searchBarLoading: false,
    searchBarSetting: [
      { type: 'input', label: '名称', prop: 'name' },
      { type: 'select', label: '分类', prop: 'type', enumProp: 'allList' },
      { slot: 'type', prop: 'type' },
    ],
    searchBarEnum: {
      allList: [],
    },
  }
},

methods: {
  fetchData() {
    this.searchBarLoading = false;
  },
  handleSubmitSearch(searchParams) {
    this.current = 1;
    this.fetchParams = { ...searchParams };
    this.fetchData();
  },
  async searchBarInit() {
    const { data } = await GetList({
      pageNo:1,
      paeSize: 100,
    });
    let allList = data.itemInfos || [];
    allList = allList.map(n => ({
      label: n.name,
      value: n.id,
    }))
    this.$set(this.searchBarEnum, 'allList', allList);
  },
},

slot example

<template #type="{ form }">
  <el-form-item label="分类">
    <el-select v-model="form.type" placeholder="请选择分类" @change="handleChange">
      <el-option label="全部" value=""></el-option>
      <el-option
        v-for="item in allList"
        :label="item.name"
        :value="item.id"
        :key="item.id"
      ></el-option>
    </el-select>
  </el-form-item>
</template>

CustomizeSwitch组件

组件配置

props
type: String,  // inside/right
mode: String,  // 同type

value/v-model: [Number, String, Boolean],

values: Array,  // [打开时value, 关闭时value]

text: Array,  // [打开时文案, 关闭时文案]
icon: Array,  // [打开时图标, 关闭时图标] 开启后覆盖text
color: Array,  // [打开时背景色, 关闭时背景色]
disabled: Boolean,  // 默认false,
width: Number,  // element中宽度,默认40
name: String,
validateEvent: Boolean,  // 改变后是否触发表单验证
activeTextColor: String,  // type为inside时文字颜色
className: String,
size: String,  // medium/small/mini
emit
@change
ref
ref: switch

example 双向绑定

<customize-switch
  v-model="switchValue"
  :text="['开启', '关闭']"
  :values="[1, 0]"
></customize-switch>

data() {
  return {
    switchValue: 1,
  }
},

example 非双向绑定

<customize-switch
  :value="switchValue"
  :disabled="switchDisabled"
  :text="['开启', '关闭']"
  :values="[1, 0]"
  @change="handleSwitchChange"
></customize-switch>

data() {
  return {
    switchValue: 1,
    switchDisabled: false,
  }
},

methods: {
  async handleSwitchChange(value) {
    try {
      this.switchDisabled = true;
      await this._sleep(1);
      this.switchValue = value;
      this.$message.success('操作成功');
    } catch (error) {
      
    }
    this.switchDisabled = false;
  },
},

example type="inside"

<customize-switch
  :value="switchValue"
  :disabled="switchDisabled"
  :text="['开启', '关闭']"
  :values="[1, 0]"
  @change="handleSwitchChange"
  type='inside'
  :width="54"
  :color="['#67C23A', '#909399']"
  active-text-color="#fff"
  size="small"
></customize-switch>

CustomizeForm组件

组件配置

props
loading.sync: false,  // 搜索按钮loading状态

setting: [{
  type: String,  // input/textarea/inputNumber/select/text/date/datepicker/switch/image/object/array/
  label: String // 表单label名
  prop: String,  // 提交的字段名 必填
  placeholder: String,  // 默认为请输入/选择 label 
  default: Any, // 默认值
  width: String, // style中width
  rules: Array,  // 替换默认rule
  required: Boolean, // true/false
  msg: String, // 错误提示信息
  validType: String,  // rules type, url/email/date
  prefixIcon: String, // type input时,输入框icon
  className: String,  // type input时,el-form-item的class
  labelWidth: String,  // label-width

  slot: String,  // slot  #slot="{ form }"
  slotInside: String,  // 插入至el-form-item内

  enum: Array | Object,  // 直接传入枚举或数组  label value
  enumProp: String,  // select时,enum中传入的枚举属性值
  enumKey: Array,  // select时,enum的key值,默认['label', 'value']
  hideOptionAll: true, // select时,隐藏‘全部’选项传入true
  optionAllName: String,  // select,全部显示label名,默认全部
  clearable: Boolean,  // date时,el-date-picker的 clearable,默认true
  disabled: Boolean,  // disabled状态,默认false
  dataType: Number/Boolean,  // 数据类型,默认String
  inputNumber: Boolean,  // true且type number时显示el-input-number

  visible: Array | Function,  // [属性名, 属性值] 设置后 当某属性为该值时,渲染该条。为function时return true时显示
}],

enum: {
  [enumProp]: [{ label: '', prop: '' }]
}

validate: Boolean,  // 开启表单验证 配合rules
size: String,  // 表单size
className: String,  // form自定义class
showSubmitButton: Boolean,  // 是否展示提交按钮,默认true
showResetButton: Boolean,  // 是否展示重置按钮,默认true
submitButtonName: String,  // 提交按钮文案,默认提交
resetButtonName: String,  // 重置按钮文案,默认重置
openEnterSearch: Boolean,  // 是否开启input的回车搜索,默认false
margin: String,  // el-form-item margin-bottom
immediate: Boolean,  // select/date,是否值改变时立即触发搜索,默认false
optionAllName: String,  // 下拉选择全部的名称,默认全部
labelWidth: String,  // el-form label-width,默认120px
itemWidth: String,  // form-item的宽度,默认auto
clearable: Boolean,  // el-date-picker clearable,默认true
hideOptionAll: Boolean, // select时,隐藏‘全部’选项传入true
hideOperate: Boolean,  // 隐藏操作el-form-item
cleanProps: Boolean,  // submit时仅传出setting中有的属性,删除其它属性
fn: Array,  // 传入的函数 配合image中fnName
emit
@submit  // emit所有表单参数
slot
#button-before
#button
slot-scope
#after="form" 
ref
ref: form

example

<template>
  <customize-form
    :loading.sync="formLoading"
    @submit="handleSubmit"
    :setting="formSetting"
    :Enum="formEnum"
    validate
  ></customize-form>
</template>

<script>
export default {
  data() {
    return {
      formLoading: false,
      formSetting: [
        { type: 'input', label: '名称', prop: 'name', disabled: true },
        { type: 'select', label: '分类', prop: 'type', enumProp: 'allList', enumKey: ['label', 'value'], default: '' },
        { slot: 'slotName', prop: 'slotName' },
        { type: 'text', label: '啊啊', default: 'text' },
        { type: 'radio', label: '单选', prop: 'radio', enum: {
          1: 'a',
          2: 'b',
        } },
        { type: 'checkbox', label: '多选', prop: 'checkbox', enum: [
          { label: 'aa', value: 11 },
          { label: 'bb', value: 22 },
          { label: 'cc', value: 33 },
          { label: 'dd', value: 44 },
          { label: 'ee', value: 55 },
        ], default: [] },
        { type: 'switch', label: '开关', prop: 'switch', text: ['开启', '关闭'], values: [1, 0], default: 0 },
        { type: 'switch', label: '开关', prop: 'switch', text: ['开启', '关闭'], values: [1, 0], default: 0 },
        { type: 'object', label: '对象', prop: 'obj', default: {}, children: [
          { type: 'input', label: '名称', prop: 'name', required: true },
          { type: 'select', label: '分类', prop: 'type', enum: { 1: 'a', 2: 'b' }, default: '1' },
        ] },
        { type: 'array', label: '数组', prop: 'arr', len: 3, default: [], children: [
          { type: 'input', label: '名称', prop: 'name' },
          { type: 'input', label: '名称2', prop: 'name2', required: true },
          { type: 'select', label: '分类', prop: 'type', enum: { 1: 'a', 2: 'b' }, default: '1' },
        ] },
        { type: 'image', label: '图片', prop: 'image', fn: this.uploadFn },
      ],
      formEnum: {
        allList: [],
      },
    }
  },

  methods: {
    async handleSubmit(form) {
      console.log(form)
      /* 提交表单 */
      await this._sleep(1);

      this.$message.success('提交成功');
      this.formLoading = false;
    },

    async uploadFn() {
      const url = '';
      await this._sleep(1);

      return Promise.resolve(url);
    },

    async formInit() {
      const data = {
        itemInfos: [
          { name: 'a', id: 1 },
          { name: 'b', id: 2 },
          { name: 'c', id: 3 },
        ],
      };
      await this._sleep(1);

      let allList = data.itemInfos || [];
      allList = allList.map(n => ({
        label: n.name,
        value: n.id,
      }))
      this.$set(this.formEnum, 'allList', allList);
    },
  },

  created() {
    this.formInit();
  },
}
</script>

slot example

<template #slotName="{ form }">
  <el-form-item label="分类">
    <el-select v-model="form.type" placeholder="请选择分类" @change="handleChange">
      <el-option label="全部" value=""></el-option>
      <el-option
        v-for="item in allList"
        :label="item.name"
        :value="item.id"
        :key="item.id"
      ></el-option>
    </el-select>
  </el-form-item>
</template>

CustomizeDialogForm组件

组件配置

props
visible.sync: Boolean,  // 弹窗是否显示
editData: Any,  // 以编辑进入时回显数据
title: [String, Array],  // 弹窗标题,为数组时[新建title, 编辑title]
top: String,  // el-dialog top
width: String,  // el-dialog width
size: String,  // medium
closeButtonShow:  [Boolean, String],  // 是否展示关闭弹窗按钮,默认展示。传入String时控制slot(button-before, button)
closeButtonName: String,  // 关闭弹窗按钮名称,默认关闭
className: String,  // dialog自定义class
其他prop同CustomizeForm
emit
@submit form
slot
同CustomizeForm
#button-before
#button
slot-scope
同CustomizeForm
#after="form" 
ref
ref: dialog

example

<customize-dialog-form
  title='123'
  :visible.sync="dialogVisible" 
  @submit="handleSubmitDialog"
  :loading.sync="submitLoading"
  :setting="formSetting"
  :Enum="formEnum"
  validate  
></customize-dialog-form>

<script>
export default {
  /* 作为单独组件引入时 */
  // props: {
  //   visible: Boolean,
  // },

  data() {
    return { 
      submitLoading: false,
      formSetting: [
        { type: 'input', label: '名称', prop: 'name', default: '1', required: true },
        { type: 'select', label: '分类', prop: 'type', enumProp: 'allList' },
        { slot: 'type', prop: 'type' },
      ],
      formEnum: {
        allList: [],
      },
  
      editData: null,

      dialogVisible: false,
    }
  },

  computed: {
    /* 作为单独组件引入时,外部 :visible.sync */
    // dialogVisible: {
    //   get() {
    //     return this.visible;
    //   },
    //   set(val) {
    //     this.$emit('update:visible', val);
    //   },
    // },
  },

  methods: {
    async handleSubmitDialog(form) {
      console.log(form);
      try {
        /* 提交表单 */
        await this._sleep(1)
        
        this.$message.success('提交成功');
        this.dialogVisible = false;
      } catch (error) {
        console.log('submitDialogError', error);
      }
      this.submitLoading = false;
    },

    handleCreate() {
      // 以创建进入
      this.editData = null 
      this.dialogVisible = true;    
    },
    handleEdit() {
      // 以编辑进入 同步数据
      this.editData = {
        name: 'name',
        type: 2,
      }
      this.dialogVisible = true;    
    },
    async handleEditAsync() {   
      // 以编辑进入 异步数据
      this.editData = null
      this.dialogVisible = true;
      await this._sleep(1);
      this.editData = { 
        name: 'name2',
        type: 3,
      }
    }, 
    
    async formInit() {
      const data = {
        itemInfos: [
          {name:'a',id:1},
          {name:'b',id:2},
          {name:'c',id:3},
        ]
      } 
      this._sleep(2)
      let allList = data.itemInfos || [];  
      allList = allList.map(n => ({ 
        label: n.name, 
        value: n.id,
      }))
      this.$set(this.formEnum, 'allList', allList); 
    },
  }
}
</script>

CustomizePage组件

example

<template>
  <customize-page
    :pageSetting="pageSetting"
    :searchBarProps="searchBarProps"
    :dialogProps="dialogProps"
    :Enum="Enum"
    :tableProps="tableProps"
    :tableDataFn="tableDataFn"
    :editDataFn="editDataFn"
    :submitFn="submitFn"
  >
    <template #slotName>
      <el-table-column label="slot" prop="slotName">
        <template #default="{ row }">
          {{ row.id }}
        </template>
      </el-table-column>
    </template>

    <template #tableButton="{ id }">
      <el-button type="danger" size="mini" @click="handleDelete(id)">删除</el-button>
    </template>
  </customize-page>
</template>

<script>
export default {
  data() {
    return {
      pageSetting: [
        { label: 'ID', prop: 'id', width: '100px' },
        { type: 'input', label: '名称', prop: 'name', required: true, msg: '321' },
        { type: 'select', label: '分类', prop: 'type', enumProp: 'allSelectList', enumKey: ['label', 'value'], default: '', rules: [
          { required: true, message: 'message' }
        ], formatter: (row, column, cellValue, index) => (this.Enum.allSelectList.find(n => n.value == cellValue) || {})['label'] || '' },
        { type: 'text', label: '啊啊', default: 'text', prop: 'text' },
        { type: 'radio', label: '单选', prop: 'radio', enum: {
          1: 'a',
          2: 'b',
        }, disabled: true },
        { type: 'checkbox', label: '多选', prop: 'checkbox', enum: [
          { label: 'aa', value: 11 },
          { label: 'bb', value: 22 },
          { label: 'cc', value: 33 },
          { label: 'dd', value: 44 },
          { label: 'ee', value: 55 },
        ], default: [] },
        { type: 'switch', label: '开关', prop: 'switch', text: ['开启', '关闭'], values: [1, 0], default: 0 },
        { slot: 'slotName', prop: 'slotName' },
      ],

      Enum: {
        allSelectList: [],
      },
      
      searchBarProps: ['name', 'type'],
      dialogProps: ['name', 'type', 'text', 'radio', 'checkbox', 'switch'],
      tableProps: ['id', 'name', 'type', 'slotName'],
    }
  },

  methods: {
    async tableDataFn(form) {
      console.log(form);

      /* 获取列表 */
      const data = [
        { id: '1', name: 'aaa', type: 1 },
        { id: '2', name: 'bbb', type: 2 },
        { id: '3', name: 'ccc', type: 3 },
        { id: '4', name: 'ddd', type: 1 },
      ];
      const total = 100;
      await this._sleep(1);

      return Promise.resolve({ data, total });
    },
    async editDataFn(id) {
      /* 获取详情 */
      const data = {
        id,
        name: '1',
        type: 2,
        checkbox: [22, 33],
        switch: 1,
      }
      this._sleep(1);

      return Promise.resolve(data);
    },
    async submitFn(form) {
      console.log(form);
      /* 提交表单 */
      await this._sleep(1);

      return Promise.resolve();
    },
    
    async init() {
      const allSelectList = [
        { label: 'a', value: 1 },
        { label: 'b', value: 2 },
        { label: 'c', value: 3 },
      ];
      await this._sleep(1);
      this.$set(this.Enum, 'allSelectList', allSelectList);
    },

    handleDelete(id) {
      this.$alert(`删除 ${id}`);
    },
  },

  created() {
    this.init();
  },

}
</script>

<style>
html, body {
  margin: 0;
}
</style>

CustomizeFormBuilder组件

组件配置

props
debug: Boolean,  // 实时显示formSetting数据
operate: Array,  // 操作区展示的按钮 ['import', 'clear', 'preview', 'schema', 'code']
event
getSchema,  // 获取当前配置转码的schema
setSchema,  // 设置schema字符串并重新渲染
slot
#operate-title 操作区域标题名
#operate-before 操作区域前置按钮
#operate-after 操作区域后置按钮

example

<template>
  <customize-form-builder ref="formBuilder"></customize-form-builder>
</template>

<script>
export default {
  methods: {
    getSchema() {
      const result = this.$refs.formBuilder.getSchema();
      console.log(result)
    },
    setSchema() {
      const schemaStr = `{"$schema":"http://json-schema.org/draft-04/schema#","type":"object","properties":{"input_1588506741033":{"type":"input","label":"单行文本","prop":"input_1588506741033","key":1588506741033}}}`
      this.$refs.formBuilder.setSchema(schemaStr);
    },
  },

}
</script>

辅助函数

_isEmpty

判断是否不为空
@return { Boolean }

_clean

删除对象中值为空的属性
@param { Object }
@return { Object }

_setValue

值不为空直接返回,为空返回默认值
@param { Any, Any } 需判断的值,默认值
@return { Any }

_formatDate

时间格式化
@params { String, Number, Date, String } 时间,格式(默认 yyyy-MM-dd hh:mm:ss)
@return { String }

_deepClone

深拷贝
@params { Object }
@return { Object }

_sleep

延迟几秒后继续执行
@params { Number } 延迟秒数
@return { Promise } resolve

_deepMerge

对象深度合并
@params { Object, Object } 延迟秒数
@return { Object }
_deepMerge(a, b, ..option)
_deepMerge.all(a, b, c, ..option)

常用增删改查页面完整事例(无弹窗)

<template>
  <div class="home">
    <customize-search-bar
      :loading.sync="searchBarLoading"
      @submit="handleSubmitSearch"
      :setting="searchBarSetting"
    ></customize-search-bar>

    <customize-table
      :data="tableData"
      :column="tableColumn"
      v-loading="tableLoading"
    >
      <template #slotName>
        <el-table-column label="slot-slotName" align="center">
          <template #default="{ row }">
            <span>_isEmpty  {{ _isEmpty(row.status) }}</span>
          </template>
        </el-table-column>
      </template>
      <template #after>
        <el-table-column label="操作" align="center">
          <template #default="{ row }">
            <el-button type="primary" size="mini" @click="handleEdit(row.id)">编辑</el-button>
          </template>
        </el-table-column>
      </template>
    </customize-table>

    <customize-pagination
      :current.sync="current"
      :total="total"
      :size.sync="size"
      @change="handleChangePage"
      style="padding-bottom: 30px;"
    ></customize-pagination>
  </div>
</template>

<script>
export default {
  name: 'home',
  data() {
    return {
      /* 列表请求参数 */
      fetchParams: {},

      /* 搜索相关 */
      searchBarLoading: false,
      searchBarSetting: [
        { type: 'input', label: '名称', prop: 'name' },
        { type: 'select', label: '分类', prop: 'type', enum: {
          0: '暂停',
          1: '启用',
        } },
        { slot: 'type', prop: 'type' },
      ],

      /* 表格相关 */
      tableLoading: false,
      tableData: [],
      tableColumn: [
        // { type: 'index', index: (index) => (this.current - 1) * this.size + index + 1 },
        { label: '名称', prop: 'name' },
        { label: '属性', prop: 'aaa', width: '100px', w: '100px' },
        { label: '状态', prop: 'status', formatter(row, column, cellValue, index) { 
          const Enum = {
            0: '暂停',
            1: '启用',
          }
          return Enum[cellValue] || '--';
        }},
        { slot: 'slotName' }
      ],

      /* 分页相关 */
      current: 1,
      total: 0,
      size: 10,
    }
  },

  methods: {
    /* 请求数据 */
    async fetchData() {
      this.tableLoading = true;
      try {
        const response = await new Promise(resolve => {
          setTimeout(_ => {
            console.log(this._clean({
              ...this.fetchParams,
              page: this.current,
              size: this.size,
            }))
            const response = {
              data: [
                { name: 'a', aaa: 2, status: 0 },
                { name: 'b', aaa: 3, status: null },
                { name: 'c', aaa: 4, status: 1 },
                { name: 'd', aaa: 5, status: 0 },
              ],
              total: 100,
            }
            resolve(response);
          }, 1111)
        })

        // const response = await GetList(this._clean({
        //   ...this.fetchParams,
        //   page: this.current,
        //   size: this.size,
        // }))
        this.tableData = response.data || [];
        this.total = response.total || 0;
      } catch (error) {
        this.tableData = [];
        this.total = 0;
      }
      this.tableLoading = false;
      this.searchBarLoading = false;
    },

    /* 搜索相关 */
    handleSubmitSearch(searchParams) {
      this.current = 1;
      this.fetchParams = searchParams;
      this.fetchData();
    },

    /* 分页相关 */
    handleChangePage() {
      this.fetchData();
    },
  },

  created() {
    this.fetchData();
  },
}
</script>

常用增删改查页面完整事例(带弹窗)

<template>
  <div class="home">
    <customize-search-bar
      :loading.sync="searchBarLoading"
      @submit="handleSubmitSearch"
      :setting="searchBarSetting"
    >
      <template #button>
        <el-button type="primary" @click="handleAdd">新建</el-button>
      </template>
    </customize-search-bar>

    <customize-table
      :data="tableData"
      :column="tableColumn"
      v-loading="tableLoading"
    >
      <template #slotName>
        <el-table-column label="slot-slotName" align="center">
          <template #default="{ row }">
            <span>_isEmpty  {{ _isEmpty(row.status) }}</span>
          </template>
        </el-table-column>
      </template>
      <template #after>
        <el-table-column label="操作" align="center">
          <template #default="{ row }">
            <el-button type="primary" size="mini" @click="handleEdit(row.id)">编辑</el-button>
          </template>
        </el-table-column>
      </template>
    </customize-table>

    <customize-pagination
      :current.sync="current"
      :total="total"
      :size.sync="size"
      @change="handleChangePage"
      style="padding-bottom: 30px;"
    ></customize-pagination>

    <dialog-create
      :editId="editId" 
      :visible.sync="dialogVisible" 
      @submit="handleSubmitDialog"
    ></dialog-create>
  </div>
</template>

<script>
import DialogCreate from './DialogCreate';

export default {
  components: {
    DialogCreate,
  },

  data() {
    return {
      /* 列表请求参数 */
      fetchParams: {},

      /* 搜索相关 */
      searchBarLoading: false,
      searchBarSetting: [
        { type: 'input', label: '名称', prop: 'name' },
        { type: 'select', label: '分类', prop: 'type', enum: {
          0: '暂停',
          1: '启用',
        } },
        { slot: 'type', prop: 'type' },
      ],

      /* 表格相关 */
      tableLoading: false,
      tableData: [],
      tableColumn: [
        // { type: 'index', index: (index) => (this.current - 1) * this.size + index + 1 },
        { label: '名称', prop: 'name' },
        { label: '属性', prop: 'aaa', width: '100px', w: '100px' },
        { label: '状态', prop: 'status', formatter(row, column, cellValue, index) { 
          const Enum = {
            0: '暂停',
            1: '启用',
          }
          return Enum[cellValue] || '--';
        }},
        { slot: 'slotName' }
      ],

      /* 分页相关 */
      current: 1,
      total: 0,
      size: 10,

      /* 弹窗相关 */
      dialogVisible: false,
      editId: null,
    }
  },

  methods: {
    /* 请求数据 */
    async fetchData() {
      this.tableLoading = true;
      try {
        const response = await new Promise(resolve => {
          setTimeout(_ => {
            
            const response = {
              data: [
                { id: 1, name: 'a', aaa: 2, status: 0 },
                { id: 2, name: 'b', aaa: 3, status: null },
                { id: 3, name: 'c', aaa: 4, status: 1 },
                { id: 4, name: 'd', aaa: 5, status: 0 },
              ],
              total: 100,
            }
            resolve(response);
          }, 222)

          // const response = await GetList(this._clean({
          //   ...this.fetchParams,
          //   page: this.current,
          //   size: this.size,
          // }))
          this.tableData = response.data || [];
          this.total = response.total || 0;
        })
      } catch (error) {
        this.tableData = [];
        this.total = 0;
      }
      this.tableLoading = false;
      this.searchBarLoading = false;
    },

    /* 搜索相关 */
    handleSubmitSearch(searchParams) {
      this.current = 1;
      this.fetchParams = searchParams;
      this.fetchData();
    },

    /* 分页相关 */
    handleChangePage() {
      this.fetchData();
    },

    /* 弹窗相关 */
    handleAdd() {
      this.editId = null;
      this.dialogVisible = true;
    },
    handleEdit(id) {
      this.editId = id;
      this.dialogVisible = true;
    },
    handleSubmitDialog() {
      console.log('handleDialog');
      this.fetchData();
    },
  },

  created() {
    this.fetchData();
  },
}
</script>

<template>
  <el-dialog
    title="title"
    top="15vh"
    width="600px"
    :visible.sync="dialogVisible"
    @close="handleClosed"
  >
    <el-form :model="form" :rules="rules" ref="form" label-width="180px" size="small">
      <el-form-item label="名称:" prop="name">
        <el-input v-model="form.name"></el-input>
      </el-form-item>

      <el-form-item>
        <el-button type="primary" @click="handleSubmit" :loading="loading">提交</el-button>
        <el-button @click="handleCancel">取消</el-button>
      </el-form-item>
    </el-form>
  </el-dialog>
</template>

<script>
const DEFAULT_FORM = () => ({
  name: '',
});

export default {
  props: {
    visible: Boolean,
    editId: {},
  },

  data() {
    return {
      dialogVisible: false,

      form: DEFAULT_FORM(),
      rules: {
        name: { required: true, message: '请输入名称' },
      },
      loading: false,
    }
  },

  methods: {
    handleClosed() {
      // reset here
      this.$refs.form.resetFields();
      this.form = DEFAULT_FORM();
      this.$emit('update:visible', false);
    },

    async handleSubmit() {
      console.log(this.form);
      try {
        await this.$refs.form.validate();

        await this.$confirm(`是否确定提交`, "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        });

        this.loading = true;
        let params = this._deepClone(this.form);
        if (!!this.editId) {
          params.id = this.editId;
          await Update(params);
        }else{
          await Save(params);
        }

        this.$message.success(`${!!this.editId ? '编辑' : '新增'}成功`);
        this.dialogVisible = false;
        this.$emit('submit');
      } catch (error) {
        console.log(error);
      }
      this.loading = false;
    },
    handleCancel() {
      this.dialogVisible = false;
    },
  },

  watch: {
    visible: {
      handler(newVal, oldVal) {
        this.dialogVisible = newVal;
      },
      immediate: true,
    }
  },

}
</script>

<style lang='scss' scoped>

</style>

常用增删改查页面完整事例(带弹窗)单页

<template>
  <div class="home">
    <customize-search-bar
      :loading.sync="searchBarLoading"
      @submit="handleSubmitSearch"
      :setting="searchBarSetting"
    >
      <template #button>
        <el-button type="primary" @click="handleAdd">新建</el-button>
      </template>
    </customize-search-bar>

    <customize-table
      :data="tableData"
      :column="tableColumn"
      v-loading="tableLoading"
    >
      <template #slotName>
        <el-table-column label="slot-slotName" align="center">
          <template #default="{ row }">
            <span>_isEmpty  {{ _isEmpty(row.status) }}</span>
          </template>
        </el-table-column>
      </template>
      <template #after>
        <el-table-column label="操作" align="center">
          <template #default="{ row }">
            <el-button type="primary" size="mini" @click="handleEdit(row.id)">编辑</el-button>
          </template>
        </el-table-column>
      </template>
    </customize-table>

    <customize-pagination
      :current.sync="current"
      :total="total"
      :size.sync="size"
      @change="handleChangePage"
      style="padding-bottom: 30px;"
    ></customize-pagination>

    <customize-dialog-form
      :editData="editData"
      title='title'
      :visible.sync="dialogVisible" 
      @submit="handleSubmitDialog"
      :loading.sync="formLoading"
      :setting="formSetting"
      :Enum="formEnum"
      validate  
    ></customize-dialog-form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      /* 列表请求参数 */
      fetchParams: {},

      /* 搜索相关 */
      searchBarLoading: false,
      searchBarSetting: [
        { type: 'input', label: '名称', prop: 'name' },
        { type: 'select', label: '分类', prop: 'type', enum: {
          0: '暂停',
          1: '启用',
        } },
        { slot: 'type', prop: 'type' },
      ],

      /* 表格相关 */
      tableLoading: false,
      tableData: [],
      tableColumn: [
        // { type: 'index', index: (index) => (this.current - 1) * this.size + index + 1 },
        { label: '名称', prop: 'name' },
        { label: '属性', prop: 'aaa', width: '100px', w: '100px' },
        { label: '状态', prop: 'status', formatter(row, column, cellValue, index) { 
          const Enum = {
            0: '暂停',
            1: '启用',
          }
          return Enum[cellValue] || '--';
        }},
        { slot: 'slotName' }
      ],

      /* 分页相关 */
      current: 1,
      total: 0,
      size: 10,

      /* 弹窗相关 */
      formLoading: false,
      formSetting: [
        { type: 'input', label: '名称', prop: 'name', required: true, msg: '321' },
        { type: 'select', label: '分类', prop: 'type', enumProp: 'allList', enumKey: ['label', 'value'], default: '', rules: [
          { required: true, message: 'message' }
        ] },
        { slot: 'slotName', prop: 'slotName' },
        { type: 'text', label: '啊啊', default: 'text' },
        { type: 'radio', label: '单选', prop: 'radio', enum: {
          1: 'a',
          2: 'b',
        }, disabled: true },
        { type: 'checkbox', label: '多选', prop: 'checkbox', enum: [
          { label: 'aa', value: 11 },
          { label: 'bb', value: 22 },
          { label: 'cc', value: 33 },
          { label: 'dd', value: 44 },
          { label: 'ee', value: 55 },
        ], default: [] },
        { type: 'switch', label: '开关', prop: 'switch', text: ['开启', '关闭'], values: [1, 0], default: 0 },
      ],
      formEnum: {
        allList: [],
      },
      dialogVisible: false,
      editData: null,
    }
  },

  methods: {
    /* 请求数据 */
    async fetchData() {
      const params = this._clean({
        ...this.fetchParams,
        current: this.current,
        size: this.size,
      });
      console.log(params);
      this.tableLoading = true;
      try {
        const response = {
          data: [
            { id: 1, name: 'a', aaa: 2, status: 0 },
            { id: 2, name: 'b', aaa: 3, status: null },
            { id: 3, name: 'c', aaa: 4, status: 1 },
            { id: 4, name: 'd', aaa: 5, status: 0 },
          ],
          total: 100,
        }
        await this._sleep(1);

        this.tableData = response.data || [];
        this.total = response.total || 0;
      } catch (error) {
        this.tableData = [];
        this.total = 0;
      }
      this.tableLoading = false;
      this.searchBarLoading = false;
    },

    /* 搜索相关 */
    handleSubmitSearch(searchParams) {
      this.current = 1;
      this.fetchParams = searchParams;
      this.fetchData();
    },

    /* 分页相关 */
    handleChangePage() {
      this.fetchData();
    },

    /* 弹窗相关 */
    handleAdd() {
      this.editData = null
      this.dialogVisible = true;
    },
    async handleEdit(id) {
      this.dialogVisible = true;

      await this._sleep(1);
      const editData = {
        id,
        name: '1',
        type: 2,
        checkbox: [22, 33],
        switch: 1,
      }
      this.editData = editData;
    },
    async handleSubmitDialog(form) {
      console.log(form)
      /* 提交表单 */
      await this._sleep(1);

      this.$message.success('提交成功');
      this.formLoading = false;
      this.dialogVisible = false;
      this.editData = null;
    },

    async formInit() {
      const data = {
        itemInfos: [
          { name: 'a', id: 1 },
          { name: 'b', id: 2 },
          { name: 'c', id: 3 },
        ],
      };
      await this._sleep(1);

      let allList = data.itemInfos || [];
      allList = allList.map(n => ({
        label: n.name,
        value: n.id,
      }))
      this.$set(this.formEnum, 'allList', allList);
    },
  },

  created() {
    this.fetchData();
    this.formInit();
  },
}
</script>
0.0.1-next

2 years ago

3.0.3

2 years ago

3.0.2

2 years ago

3.0.1

2 years ago

3.0.0

2 years ago

3.0.0-next

2 years ago

0.0.3-next

2 years ago

0.0.2-next

2 years ago

1.1.9

3 years ago

1.1.8

3 years ago

1.1.7

3 years ago

1.1.6

3 years ago

1.1.5

3 years ago

1.1.11

3 years ago

1.1.10

3 years ago

1.1.4

3 years ago

1.1.3

3 years ago

1.1.2

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.9

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.4

4 years ago

1.0.3

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago

0.0.50

4 years ago

0.0.49

4 years ago

0.0.48

4 years ago

0.0.47

4 years ago

0.0.46

4 years ago

0.0.45

4 years ago

0.0.44

4 years ago

0.0.43

4 years ago

0.0.41

4 years ago

0.0.42

4 years ago

0.0.40

4 years ago

0.0.39

4 years ago

0.0.38

4 years ago

0.0.37

4 years ago

0.0.36

4 years ago

0.0.34

4 years ago

0.0.35

4 years ago

0.0.33

4 years ago

0.0.31

4 years ago

0.0.32

4 years ago

0.0.30

4 years ago

0.0.29

4 years ago

0.0.28

4 years ago

0.0.27

4 years ago

0.0.26

4 years ago

0.0.25

4 years ago

0.0.24

4 years ago

0.0.23

4 years ago

0.0.22

4 years ago

0.0.21

4 years ago

0.0.20

4 years ago

0.0.19

4 years ago

0.0.17

4 years ago

0.0.18

4 years ago

0.0.16

4 years ago

0.0.15

4 years ago

0.0.14

4 years ago

0.0.13

4 years ago

0.0.11

4 years ago

0.0.12

4 years ago

0.0.10

4 years ago

0.0.9

4 years ago

0.0.8

4 years ago

0.0.7

4 years ago

0.0.6

4 years ago

0.0.5

4 years ago

0.0.4

4 years ago

0.0.3

4 years ago

0.0.2

4 years ago

0.0.1

4 years ago