Skip to content

Instantly share code, notes, and snippets.

@wisetc
Last active October 19, 2017 01:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wisetc/1b4ec0f64b535659f416a81dca7e3ca6 to your computer and use it in GitHub Desktop.
Save wisetc/1b4ec0f64b535659f416a81dca7e3ca6 to your computer and use it in GitHub Desktop.
vue CRUD component base on element-ui
<template>
<div class="crud">
<div class="crud__ctrl">
<el-button type="primary" @click="create" size="small" icon="plus">新增</el-button>
</div>
<el-table :data="data" stripe border>
<template v-for="(key, index) in Object.keys(columns)">
<el-table-column v-if="(fields[key] || '').options" :label="columns[key]" show-overflow-tooltip> <!-- 如果表格中包含有选项的字段 -->
<template scope="scope">
{{ (fields[key].options.find(item => item.value === scope.row[key]) || '').label }}
</template>
</el-table-column>
<el-table-column v-else :label="columns[key]" :prop="key" show-overflow-tooltip></el-table-column>
</template>
<el-table-column label="操作" width="140" align="center">
<template scope="scope">
<el-button type="warning" size="small" @click="update(scope.row, scope.$index)">修改</el-button>
<el-button type="danger" size="small" @click="destroy(scope.row, scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog :title="dialog.title[dialog.status]" :size="dialog.size" :close-on-click-modal="false"
:visible="editing" :show-close="false" @open="handleOpen">
<el-form class="crud__form" :class="{'crud__form--inline': inline}" ref="form" :model="form" :rules="rules" @keyup.native.13="Submit">
<el-form-item v-for="(key, index) in Object.keys(labels)" :key="index" :label="labels[key]" :prop="key" :label-width="labelWidth">
<el-select v-if="fields[key].options" v-model="form[key]" style="width: 100%;">
<el-option v-for="(o, index) in fields[key].options" :key="index" :label="o.label" :value="o.value"
:disabled="fields[key].unique && repeated(key, o.value, (updatingRow || '')[key])"/>
</el-select>
<el-date-picker v-else-if="fields[key].type === TYPES.datetime" type="datetime" v-model="form[key]"></el-date-picker>
<el-input v-else v-model="form[key]" :maxlength="fields[key].length"/>
</el-form-item>
</el-form>
<div slot="footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="Submit">提交</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import TYPES from './fields'
export default {
props: {
// 表格数据
data: { required: true, type: Array },
// 表单 v-model 对象
form: { required: true, type: Object },
// 表单字段
fields: { required: true, type: Object },
// 表单验证
rules: { required: true, type: Object },
// 对话框 el-dialog 的显示和隐藏状态
editing: { required: true, type: Boolean },
// 对话框 el-dialog 的大小值
size: { default: 'large', type: String },
// 表单元素标签的尺寸
labelWidth: { default: '100px', type: String },
// 表单的显示样式,如果为真,则是行内显示
inline: { default: true, type: Boolean },
// 表格与表单的字段不一致时,传入作为表格的表头
table: { default: () => ({}), type: Object }
},
data() {
return {
dialog: {
status: 0,
title: {
0: '新增',
1: '修改'
},
size: this.inline ? this.size : 'small'
},
// 选项不可重复时,传入当前行判断选项是否为此当前行的属性
updatingRow: null,
TYPES
}
},
computed: {
labels() {
let labels = {}
let fields = this.fields
for (let key in fields) {
labels[key] = fields[key].label
}
return labels
},
columns() {
return Object.keys(this.table).length ? this.table : this.labels
}
},
methods: {
create() {
this.dialog.status = 0
this.showDialog()
this.$emit('create')
},
update(row, index) {
this.dialog.status = 1
this.updatingRow = row
this.showDialog()
this.$emit('update', row, index)
},
destroy(row, index) {
this.$confirm(`确定要删除?`, '确认', {type: 'warning'}).then(()=> {
this.$emit('destroy', row, index)
})
},
showDialog() {
this.$emit('open')
},
closeDialog() {
this.$emit('close')
},
handleOpen() {
if (this.$refs.form) {
this.$refs.form.resetFields()
}
},
Submit() {
this.$refs.form.validate(valid => {
if (valid) {
this.$emit('submit', this.dialog.status)
}
})
},
repeated(key, value, self) {
if (value === self) return false
return this.data.find(item => item[key] === value) ? true : false
},
}
}
</script>
<style>
.crud__ctrl {
margin: 8px 0;
}
.crud__form--inline:after {
content: '';
clear: both;
display: table;
}
.crud__form--inline .el-form-item {
width: 33%;
float: left;
padding: 0 8px;
box-sizing: border-box;
}
</style>
const fields = ['string', 'text', 'boolean', 'integer', 'float', 'date', 'datetime', 'objectid']
export default fields.reduce((x, y, i) => (
{...x, [y]: i + 1}
), {})
export default function report(data, type='', callback) {
let map = {
create: '新增',
update: '修改',
destroy: '删除'
}
let msg = map[type] || '操作'
if (data.code === 1) {
this.$message.success(msg + '成功!')
callback(data)
} else {
this.$message.error(msg + '失败!' + data.msg)
}
}
<template>
<div>
<crud :data="data" :form="form" :rules="rules" :fields="mapItems"
:editing="editing" @open="handleOpen" @close="handleClose"
@create="handleCreate" @update="handleUpdate" @destroy="handleDestroy" @submit="handleSubmit"/>
</div>
</template>
<script>
import { RepairStationAPI as api } from '../../api'
import CRUD from '../../components/crud'
export default {
components: { crud: CRUD },
data() {
return {
data: [],
form: {},
editing: false,
mapItems: {
name: {
label: '单位名',
length: 50,
type: String,
rules: [{ required: true, message: '此项不能为空' }]
},
shortName: {
label: '字母简称',
length: 50,
type: String,
rules: [{ required: true, message: '此项不能为空' }]
},
director: {
label: '负责人',
length: 50,
type: String,
rules: [{ required: true, message: '此项不能为空' }]
},
address: {
label: '通讯地址',
length: 50,
type: String
},
tel: {
label: '电话',
length: 11,
type: Number
},
fax: {
label: '传真',
length: 50,
type: String
},
phone: {
label: '手机',
length: 11,
type: Number
},
mail: {
label: '邮箱',
length: 50,
type: String
},
site: {
label: '网址',
length: 50,
type: String,
},
credit: {
label: '信用等级',
length: 50,
type: String,
},
depositBank: {
label: '开户银行',
length: 50,
type: String,
},
bankAccount: {
label: '银行账号',
length: 50,
type: Number
},
taxId: {
label: '税号',
length: 50,
type: String
},
remark: {
label: '备注',
length: 50,
type: String
},
}
}
},
computed: {
model() {
let model = {}
let mapItems = this.mapItems
for (let k in mapItems) {
model[k] = null
}
return model
},
rules() {
let rules = {}
let mapItems = this.mapItems
for (let k in mapItems) {
if (mapItems[k].rules) {
rules[k] = mapItems[k].rules
}
}
return rules
}
},
created() {
this.loadData()
},
methods: {
loadData() {
api.list().then(({data}) => {
this.data = data.data.data
})
},
handleCreate() {
this.form = { ...this.model }
},
handleUpdate(row, index) {
this.form = { ...row }
this.handleOpen()
},
handleDestroy(row, index) {
api.destroy({id: row.id}).then(({data}) => {
this.$report(data, 'destroy', this.deleteSuccess)
})
},
handleOpen() {
this.editing = true
},
handleClose() {
this.editing = false
},
handleSubmit(status) {
if (status === 0) {
api.create({data: JSON.stringify(this.form)}).then(({data}) => {
this.$report(data, 'create', this.createSuccess)
})
} else {
api.update({data: JSON.stringify(this.form)}).then(({data}) => {
this.$report(data, 'update', this.updateSuccess)
})
}
},
createSuccess(data) {
this.handleClose()
this.loadData()
},
updateSuccess() {
this.handleClose()
this.loadData()
},
deleteSuccess(data) {
this.loadData()
}
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment