对话框的表单校验——模板笔记
目的:
减少重复工作、简化开发速度
案例:
1.设置一个对话框:
<el-dialog width="50%" top="60px" :title='dialogTitle' :visible.sync="dialogVisible" :show-close="false" :append-to-body="false" :close-on-click-modal='false' :lock-scroll="false" > 111 </el-dialog>
2.抽离表单:
<template>
<div>
<el-form
:model="form"
:rules="rules"
ref="ruleForm"
label-width="120px"
>
<el-form-item
label="中文名"
prop="name">
<template slot="label">
<span>
<span>特征中文名</span>
<el-tooltip
content="同一业务下'中文名'不可重名"
placement="bottom"><i class="fa fa-info-circle"/>
</el-tooltip>
</span>
</template>
<el-input
v-model="form.name"
placeholder="请输入中文名"/>
</el-form-item>
<el-form-item>
<span class="form-item-submit">
<el-button
@click="cancelForm">取消</el-button>
<el-button
type="primary"
:loading="loadSubmit"
@click="submitForm">确定</el-button>
</span>
</el-form-item>
</el-form>
<!--嵌套的对话框-->
<el-dialog
title="特征模板列表"
width="50%"
top="60px"
:visible.sync="dialogVisibleNest"
:append-to-body="true"
:show-close="false"
:close-on-click-modal='false'
:lock-scroll="false"
>
<div>222
</div>
</el-dialog>
</div>
</template>
<script>
export default {
props: {// 需要的参数统一传过来
formInfo: {
type: Object,
default () {
return {
isEdit: false, // 新建与编辑
allName: [],
form: {
name: ''
}
}
}
}
},
data () {
const validateName = (rule, value, callback) => {
if (value) {
const rtx = /^[\u4E00-\u9FA5a-zA-Z0-9_]+$/
if (!value.match(rtx)) {
callback(new Error('只允许中英文、数字、下划线'))
} else if (this.formInfo.allName.indexOf(value) !== -1) {
callback(new Error('该命名已存在'))
} else {
callback()
}
} else {
callback(new Error('不能为空'))
}
}
const validateType = (rule, value, callback) => {
if (value) {
const rtx = /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/
if (!value.match(rtx)) {
callback(new Error('字母开头,允许5-16字节,允许字母数字下划线'))
} else if (this.formInfo.allName.indexOf(value) !== -1) {
callback(new Error('该命名已存在'))
} else {
callback()
}
} else {
callback(new Error('不能为空'))
}
}
// const validatePass = (rule, value, callback) => {
// if (value === '') {
// callback(new Error('不可为空'))
// } else {
// let result = this.removeStrNotes(value) // 去除注释
// if (typeof result === 'string') {
// try {
// let obj = JSON.parse(result) // 转换成json对象
// if (typeof obj === 'object' && obj) {
// callback()
// } else {
// callback(new Error('json格式有误'))
// }
// } catch (e) {
// callback(new Error(e))
// }
// } else {
// callback(new Error('json格式有误'))
// }
// }
// }
return {
form: {
name: '',
type: '',
user: '',
checked: 0
},
rules: {
name: [
{ required: true, validator: validateName, trigger: 'blur' }
],
type: [
{ required: true, validator: validateType, trigger: 'blur' }
],
checked: [
{ required: true, message: '请选择是否使用模板', trigger: 'change' }
],
user: [// 多选是数组
{ required: false, type: 'array', message: '请输入关键字,匹配特征关系人,可多选', trigger: 'change' }
]
},
dialogVisibleNest: false, // 查看嵌套的对话框
loadSubmit: false // 提交
}
},
watch: {
'formInfo': {
immediate: true,
handler (val) { // 初始化
console.log(val, '初始化')
if (!val.isEdit) {
this.allName = val.allName
this.form = {
name: '',
}
} else{
this.allName = []
this.form = val.form
}
this.$nextTick(function () {
// this.$refs['ruleForm'].resetFields()// 清空表单内容
this.$refs['ruleForm'].clearValidate()// 清空报错
this.$refs['inputFocus'].$el.querySelector('input').focus()
})
}
}
},
methods: {
submitForm () {
this.$refs['ruleForm'].validate((valid) => {
if (valid) {
this.$emit('form-change', this.form, this.formInfo.type)// 回调:成功提交
}
})
},
cancelForm () {
this.$emit('form-change')// 回调:关闭对话框
this.$refs['ruleForm'].resetFields()// 清空表单内容
this.$refs['ruleForm'].clearValidate()// 清空报错
}
}
}
</script>
【实例】:可编辑的表格:对话框形式+下拉选项+表格内容编辑
<template>
<div>
<el-table
ref="multipleTable"
:data="tableData"
border
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55">
</el-table-column>
<el-table-column label="名称(弹框编辑)" align="center" prop="name">
<template slot-scope="scope">
<editRowDialog :allName="allName" :scope="scope" @dialog-change="dialogChange"></editRowDialog>
</template>
</el-table-column>
<el-table-column label="类型(点击切换)" align="center" prop="type">
<template slot-scope="scope">
<editRowSelect :options="options" :scope="scope" @select-change="selectChange"></editRowSelect>
</template>
</el-table-column>
<el-table-column label="描述(点击编辑)" align="center" prop="desc">
<template slot-scope="scope">
<editRowInput :scope="scope" @input-change="inputChange"></editRowInput>
</template>
</el-table-column>
</el-table>
<el-button @click="handleCheck">手动选中</el-button>
</div>
</template>
<script>
import editRowDialog from './editRowDialog'
import editRowSelect from './editRowSelect'
import editRowInput from './editRowInput'
export default {
components:{
editRowDialog,
editRowSelect,
editRowInput,
},
data () {
return {
saveFlag:false,
options: ['int', 'string', 'number'],
tableData: [{
name:'a',
type:'int',
desc:0,
}],
}
},
computed: {
allName () {
return this.tableData.map(item =>item.name)
}
},
methods: {
handleSelectionChange (val) {
console.log(val,"全选");
},
// 手动触发
handleCheck () {
const rows = [this.tableData[0]]
if (rows) {
rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row);
});
} else {
this.$refs.multipleTable.clearSelection();
}
},
// 抽离编辑的组件
dialogChange (val,index) {
this.$message.success("修改成功")
this.tableData[index].name = val.name
},
selectChange (val,index) {
this.$message.success("修改成功")
this.tableData[index].type = val
},
inputChange (val,index) {
this.$message.success("修改成功")
// this.tableData[index].desc = val
this.tableData[index].name = val
}
}
}
</script>
1.新建或重命名:对话框或表格内操作表单
<template>
<div @click.self="dialogVisible = true">
<span>
{{scope.row.name}}
<i class="el-icon-edit" />
</span>
<el-dialog
style="text-align: left;"
title="重命名:"
width="30%"
:visible.sync="dialogVisible"
:show-close="false"
:append-to-body="false"
:close-on-click-modal="false"
:lock-scroll="false"
>
<newEditForm :dialogVisible="dialogVisible" :data="data" @form-call-back="formCallBack" />
</el-dialog>
</div>
</template>
<script>
import newEditForm from './newEditForm'
export default {
components: {
newEditForm
},
props: {
scope: {
type: Object,
default(){
return {
$index:0,
row:{name:''}
}
}
},
allName: {
type: Array,
default(){
return []
}
},
isEdit: {
type: Boolean,
default: false
}
},
computed:{
data(){
return {
isEdit: this.isEdit,
allName: this.allName,
form: {
name: this.scope.row.name
},
}
}
},
data () {
return {
dialogVisible: false,
}
},
methods: {
formCallBack (val) {
console.log(val,"提交或取消");
if(val && val.name){
this.$emit('dialog-change', val, this.scope.$index)
}else{
this.$message("已取消修改")
}
this.dialogVisible = false
}
}
}
</script>
设置了对话框的话,把表单抽离:
<template>
<div>
<el-form
:model="form"
:rules="rules"
ref="ruleForm"
label-position="left"
label-width="80px"
@submit.native.prevent
@keyup.enter.native="submitForm('ruleForm')"
>
<el-form-item
label="画布名:"
prop="name">
<el-input
placeholder="请输入画布名"
clearable
v-model="form.name"
ref="inputFocus"
spellcheck="false"/>
</el-form-item>
<el-form-item>
<span class="form-item-submit">
<el-button
@click="cancelForm">取消</el-button>
<el-button
type="primary"
:loading="loadSubmit"
@click="submitForm('ruleForm')">确定</el-button>
</span>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
props: {
dialogVisible:{
type:Boolean,
default:false
},
data: {
type: Object,
default () {
return {
isEdit:false,
allName: [],
form: {
name: ''
}
}
}
}
},
data () {
const validateName = (rule, value, callback) => {
if (value) {
const rtx = /^[\u4E00-\u9FA5a-zA-Z0-9_]+$/
if (!value.match(rtx)) {
callback(new Error('只允许中英文、数字、下划线'))
} else if (this.allName.indexOf(value) !== -1) {
callback(new Error('该命名已存在'))
} else if (this.oldName === value) {
callback(new Error('该命名未修改'))
} else {
callback()
}
} else {
callback(new Error('不能为空'))
}
}
return {
allName:[],
oldName:'',
form: {
name: '',
},
rules: {
name: [
{ required: true, validator: validateName, trigger: 'blur' }
]
},
loadSubmit: false // 提交
}
},
watch: {
'dialogVisible': {
immediate: true,
// deep:true,
handler (val) { // 初始化
if(val){
this.$nextTick(function () {
// this.$refs['ruleForm'].resetFields()// 清空表单内容
this.$refs['ruleForm'].clearValidate()// 清空报错
this.$refs['inputFocus'].$el.querySelector('input').focus()
})
if (this.data && this.data.isEdit) { //新建
this.allName = this.data.allName
this.form = {name: ''}
} else { // 编辑:默认
this.allName = []
this.oldName = this.form.name = this.data.form.name
}
}
}
},
'data': {
immediate: false,
// deep:true,
handler (val) {
if (val && val.isEdit) { //新建
this.allName = val.allName
this.form = {name: ''}
} else { // 编辑:默认
this.allName = []
this.oldName = this.form.name = val.form.name
}
}
},
},
methods: {
submitForm () {
this.$refs['ruleForm'].validate((valid) => {
if (valid) {
this.$emit('form-call-back', this.form)// 回调:成功提交
this.$refs['ruleForm'].resetFields()// 清空表单内容
this.$refs['ruleForm'].clearValidate()// 清空报错
}else{
return
}
})
},
cancelForm () {
this.$emit('form-call-back')// 回调:关闭对话框
this.$refs['ruleForm'].resetFields()// 清空表单内容
this.$refs['ruleForm'].clearValidate()// 清空报错
}
}
}
</script>
<!-- 不校验去除低栏边距 -->
<style scoped>
.form-item-bottom{
margin-bottom: 0;
}
.form-item-submit{
margin-top: 20px;
float: right
}
</style>
2.表格内编辑,不需要进行表单校验,即:未修改直接提示,不拦截
<template>
<div @click="getInputFocus(scope.row.name)">
<span v-if="!isEdit">
{{scope.row.name}}
<i class="el-icon-edit"/>
</span>
<el-input
v-else
:ref="`focusInput${scope.$index}`"
v-model="inputVal"
@blur="blurChange(inputVal)"
spellcheck="false"
/>
</div>
</template>
<script>
export default {
props: {
scope: {
type: Object,
default(){
return {
$index:0,
row:{name:''}
}
}
}
},
data () {
return {
isEdit:false,
oldName:'',
inputVal:''
}
},
methods:{
getInputFocus(val){ // 获取焦点
this.oldName = this.inputVal = val
this.isEdit = true
this.$nextTick(() => {
this.$refs[`focusInput${this.scope.$index}`].focus()
})
},
blurChange(val){ // 失去焦点
if(val !== this.oldName){
this.$emit('input-change', val,this.scope.$index)
}else{
this.$message.warning("内容未修改")
}
this.isEdit = false
}
}
}
</script>
3.表格内操作:下拉选项
<template>
<div @click="getSelectFocus(scope.row.type)">
<span v-if="!isEdit">
{{scope.row.type}}
<i class="el-icon-edit"/>
</span>
<el-select
v-else
:ref="`toFoucus${scope.$index}`"
automatic-dropdown
v-model="selectedVal"
placeholder="请选择"
style="text-align:center;width: 100%"
@change='selectChange'
@visible-change='visibleChange'
>
<el-option v-for="item in options" :key="item" :label="item" :value="item" />
</el-select>
</div>
</template>
<script>
export default {
props: {
scope: {
type: Object,
default(){
return {
$index:0,
row:{type:'int'}
}
}
},
options: {
type: Array,
default () {
return []
}
}
},
data () {
return {
isEdit:false,
selectedOld: '',
selectedVal: ''
}
},
methods:{
getSelectFocus(val){ // 获取焦点
this.selectedOld = this.selectedVal = val
this.isEdit = true
this.$nextTick(() => {
this.$refs[`toFoucus${this.scope.$index}`].focus()
})
},
selectChange(val){ //提交
this.$emit('select-change', val,this.scope.$index)
},
visibleChange(val){ // 失去焦点
if(!val){
if(this.selectedOld === this.selectedVal){
this.$message.warning("内容未修改")
}
this.isEdit = false
}
}
}
}
</script>
其他:新增一行、删除一行的校验与重置按钮(禁止添加或校验重名)
最外层的结构:
<template>
<el-form :rules="rules" :model="form" ref="rulesForm">
<el-form-item prop="tableData">
<dragTableDialog
:table-data="form.tableData"
:drop-col="column"
tab-show
dialog-title="编辑"
@save-drag-table="saveDragTable"
/>
</el-form-item>
</el-form>
</template>
<script>
import dragTableDialog from './module-components/formTable/dragTableDialog'
export default {
components: {
dragTableDialog
},
data () {
return {
rules: {
tableData: { type: 'array', required: true, message: '输出列表不可为空', trigger: 'blur' }
},
form: {
tableData: []
},
column: [
{
default: '',
label: '字段',
prop: 'field_name'
},
{
default: 'string',
label: '类型',
prop: 'field_type'
},
{
default: '',
label: '描述',
prop: 'field_desc'
}
]
}
},
methods: {
saveDragTable (val) {
this.form.tableData = val
if(val.length===0){
this.$refs['rulesForm'].validateField('tableData') //校验某个字段
}else{
// this.$refs['copyForm'].resetFields()// 清空表单内容
this.$refs['rulesForm'].clearValidate()// 清空报错
}
},
}
}
</script>
表格与字符串的切换:
<!--可拖拽的表格:表格内容+行参数+按钮名称(对话框标题) --> <template> <div> <el-button type="primary" @click="showDialog">{{ dialogTitle }}</el-button> <CommonTable style="marginTop:10px" :table-data="tableDataBeigin" :table-column="dropCol" /> <el-dialog :visible.sync="dialogVisible" :close-on-click-modal="false" append-to-body show-close :before-close="beforeClose" :title="dialogTitle" width="40%" > <div v-if="!tabShow" style="margin-top:-20px;"> <dragTableForm :table-data="tableDataDialog" :table-column="dropCol" :save-disabled="saveDisabled" @save-call-back="saveCallBack" @save-data-back="saveDataBack" /> </div> <el-tabs v-else @tab-click="handleClickTab" style="margin-top:-20px;" v-model="activeName" type="card" > <el-tab-pane label="表格编辑模式" name="table"> <dragTableForm :size="size" :table-data="tableDataDialog" :drop-col="dropCol" :save-disabled="saveDisabled" @save-call-back="saveCallBack" @save-data-back="saveDataBack" /> </el-tab-pane> <el-tab-pane label="文本编辑模式" name="txt"> <el-input @change="inputChange" v-model="strSplit" type="textarea" :rows="6" placeholder="例:a,int,描述a,类型int。" spellcheck="false" /> <h4 style="margin:5px 0">注意:</h4> <ol style="text-align:left"> <li>可将导出的csv文件内容,直接复制过来使用,若有数据类型且不符合规范,转换后默认为string;</li> <li>手动编辑时,注意分隔符为英文逗号(第3个逗号后面的内容合并到最后一列),新的一行用Enter键换行。</li> </ol> </el-tab-pane> </el-tabs> <!--保存操作 --> <span slot="footer" class="dialog-footer"> <el-button :size="size" type="primary" @click="submitDialog" :disabled="saveDisabled">保存</el-button> </span> </el-dialog> </div> </template> <script> import _ from 'lodash' import CommonTable from './commonTable' import dragTableForm from './dragTableForm' export default { components: { CommonTable, dragTableForm }, props: { 'size': { type: String, default: 'mini' }, 'tableData': { type: Array, default () { return [] } }, 'dropCol': { type: Array, default () { return [ { default: '', label: '字段', prop: 'field_name' }, { default: 'string', label: '类型', prop: 'field_type' }, { default: '', label: '描述', prop: 'field_desc' } ] } }, 'dialogTitle': { type: String, default: '新建' }, 'tabShow': { type: Boolean, default: false } }, data () { return { strSplit: '', activeName: 'table', dialogVisible: false, saveDisabled: false, tableDataBeigin: [], tableDataDialog: [] } }, watch: { 'tableData': { immediate: true, handler (val) { const tableData = [] val.forEach((item, index) => { const obj = {} obj.id = index this.dropCol.forEach(e => { obj[e.prop] = item[e.prop] }) tableData.push(obj) }) console.log("监听提交"); this.tableDataBeigin = tableData this.tableDataDialog = _.cloneDeep(tableData) } } }, methods: { showDialog () { if (this.activeName === 'txt') { let str = '' this.tableDataDialog.forEach(item => { delete item.id str += Object.values(item) + '\n' }) this.strSplit = str } this.dialogVisible = true }, beforeClose () { const tableData = [] this.tableData.forEach((item, index) => { const obj = {} obj.id = index this.dropCol.forEach(e => { obj[e.prop] = item[e.prop] }) tableData.push(obj) }) this.tableDataDialog = _.cloneDeep(tableData) this.dialogVisible = false this.saveDisabled = false }, findStrIndex (str, cha, num) { var x = str.indexOf(cha) for (var i = 0; i < num; i++) { x = str.indexOf(cha, x + 1) } return x }, handleClickTab (tab, event) { if (tab.name === 'txt') { let str = '' this.tableDataDialog.forEach(item => { delete item.id str += Object.values(item) + '\n' }) this.strSplit = str } else { const array = this.strSplit.split('\n') if (!array[array.length - 1]) { array.pop() } const tableDataDialog = [] array.forEach((item, index) => { const allIndex = this.findStrIndex(item, ',', 1) let array2 = [] if (item.split(',').length > 3) { array2 = item.substring(0, allIndex).split(',') array2.push(item.substring(allIndex + 1)) } else { if (item.split(',').length === 1) { array2 = [item, this.dropCol[1].prop === 'field_type' ? 'string' : '', ''] } else { array2 = item.split(',') } } const obj = {} array2.forEach((e, i) => { obj.id = index if (this.dropCol[i].prop === 'field_type') { const options = ['tinyint', 'smallint', 'int', 'bigint', 'boolean', 'float', 'double', 'string'] obj[this.dropCol[i].prop] = options.indexOf(array2[i]) !== -1 ? array2[i] : 'string' } else if (this.dropCol[i].prop === 'field_key') { const keyOptions = ['qq', 'area', 'roleid', 'os', 'commid', 'openid', 'null'] obj[this.dropCol[i].prop] = keyOptions.indexOf(array2[i]) !== -1 ? array2[i] : 'null' } else { obj[this.dropCol[i].prop] = array2[i] ? array2[i] : '' } }) tableDataDialog.push(obj) }) this.tableDataDialog = tableDataDialog } }, saveCallBack (disabled) { this.saveDisabled = disabled }, saveDataBack (data) { this.tableDataDialog = data }, inputChange (val) { // 转换+校验 const array = this.strSplit.split('\n') if (!array[array.length - 1]) { array.pop() } const tableDataDialog = [] array.forEach((item, index) => { const allIndex = this.findStrIndex(item, ',', 1) let array2 = [] if (item.split(',').length > 3) { array2 = item.substring(0, allIndex).split(',') array2.push(item.substring(allIndex + 1)) } else { if (item.split(',').length === 1) { array2 = [item, this.dropCol[1].prop === 'field_type' ? 'string' : '', ''] } else { array2 = item.split(',') } } const obj = {} array2.forEach((e, i) => { obj.id = index if (this.dropCol[i].prop === 'field_type') { const options = ['tinyint', 'smallint', 'int', 'bigint', 'boolean', 'float', 'double', 'string'] obj[this.dropCol[i].prop] = options.indexOf(array2[i]) !== -1 ? array2[i] : 'string' } else if (this.dropCol[i].prop === 'field_key') { const keyOptions = ['qq', 'area', 'roleid', 'os', 'commid', 'openid', 'null'] obj[this.dropCol[i].prop] = keyOptions.indexOf(array2[i]) !== -1 ? array2[i] : 'null' } else { obj[this.dropCol[i].prop] = array2[i] ? array2[i] : '' } }) tableDataDialog.push(obj) }) this.tableDataDialog = tableDataDialog //校验 const tableData = [] this.tableDataDialog.forEach((item, index) => { const obj = {} this.dropCol.forEach(e => { obj[e.prop] = item[e.prop] }) tableData.push(obj) }) const arr = tableData.map(item => item[this.dropCol[0].prop]) if ((new Set(arr)).size !== arr.length) { this.$message.warning(this.dropCol[0].label + '不可重名') } }, submitDialog () { console.log("提交"); const tableData = [] this.tableDataDialog.forEach((item, index) => { const obj = {} this.dropCol.forEach(e => { obj[e.prop] = item[e.prop] }) tableData.push(obj) }) this.tableDataBeigin = tableData const arr = tableData.map(item => item[this.dropCol[0].prop]) if ((new Set(arr)).size !== arr.length) { this.$message.warning(this.dropCol[0].label + '不可重名') } else { this.$emit('save-drag-table', tableData) this.dialogVisible = false } } } } </script>
设置公共组件:el-table
/*** * 通用的table展示 * @param {Array} tableData * @param {Array} tableColumn * @return {Number/String} height(参考element) * @return {String} size(参考element) * @return {Boolean} stripe 默认显示 * @return {Boolean} sortable 默认显示 * @return {Boolean} loading * @return {Function} filterChange * @return {Function / String} tableRowClassName 底色 * @return {String} slot 插入的位置:header、footer * */ <template> <div> <el-table ref="commonTable" :data="tableData" :size="size" :stripe="stripe" border highlight-current-row v-loading="loading" :row-class-name="tableRowClassName" @filter-change="filterChange" @selection-change="handleSelectionChange" :row-key="rowKey" > <!--自定义插入--> <slot name="header" /> <el-table-column v-for="(item, index) in tableColumn" :key="`key_${index}`" :prop="item.prop" :label="item.label" show-overflow-tooltip :sortable="sortable" align="center" > <template slot-scope="scope"> <div v-if="tableColumn[index].prop === 'field_key'"> <span>{{ keyOptionsObj[scope.row.field_key] || '-空-' }}</span> </div> <div v-else> <span>{{ scope.row[tableColumn[index].prop] || '-空-' }}</span> </div> </template> </el-table-column> <!--自定义插入--> <slot name="footer" /> </el-table> </div> </template> <script> export default { props: { tableData: { type: Array, default () { return [] } }, tableColumn: { type: Array, default () { return [ { default: '', label: '字段名称', prop: 'field_name' }, { default: 'string', label: '字段类型', prop: 'field_type' }, { default: '', label: '字段描述', prop: 'field_desc' } ] } }, size: { type: String, default: 'mini' }, sortable: { type: Boolean, default: true }, stripe: { type: Boolean, default: true }, loading: { type: Boolean, default: false }, filterChange: { type: Function, default () { return '' } }, tableRowClassName: { type: Function, default () { return '' } }, rowKey: { type: String, default: '' }, initSelection: { type: Boolean, default: false } }, data () { return { keyOptionsObj: { qq: 'QQ号', area: '大区ID', roleid: '角色ID', os: '手机操作系统', commid: '微信Commid', openid: 'Open ID', null: '不关联' } } }, watch: { initSelection: { immediate: true, handler (val) { if (val) { this.$nextTick(() => { this.$refs.commonTable.clearSelection() }) } } } }, methods: { handleSelectionChange (val) { this.$emit('handleSelectionChange', val) } } } </script>
设置可拖拽的表格:
<template>
<div>
<el-button
:size="size"
type="primary"
@click="addRow"
style="margin-bottom: 10px"
:disabled="disabledAdd"
>新增一行</el-button>
<el-form :model="form" :rules="rules" ref="form">
<el-table
border
:size="size"
id="dragTable_sql"
:row-key="getRowKeys"
:data="form.tableData"
style="width: 100%;"
>
<!-- 拖拽图标 -->
<el-table-column width="40" align="center">
<template>
<i class="el-icon-rank" style="font-size:large;cursor:grab" />
</template>
</el-table-column>
<!-- 输入选择 -->
<el-table-column
v-for="(item, index) in tableColumn"
:key="index"
:prop="item.prop"
:label="item.label"
align="center"
>
<template slot-scope="scope">
<el-form-item
v-if="index===0"
:size="size"
:prop="`tableData.${scope.$index}.${item.prop}`"
:rules="rules[item.prop]"
>
<el-input
v-focus
clearable
v-model="scope.row[item.prop]"
:placeholder="`请输入${item.label}`"
@change="inputChange"
@clear="inputChange"
/>
</el-form-item>
<el-form-item v-else-if="item.prop === 'field_type'" :size="size">
<el-select
@change="saveChange"
:size="size"
v-model="scope.row[item.prop]"
:placeholder="'请选择'+item.label"
>
<el-option
v-for="item in options"
:key="item"
:label="item"
:value="item"
style="text-align: center;"
/>
</el-select>
</el-form-item>
<el-form-item v-else-if="item.prop === 'field_key'" :size="size">
<el-select
clearable
v-model="scope.row[item.prop]"
:placeholder="'请选择'+item.label"
@change="saveChange"
>
<el-option
style="text-align: center;"
v-for="(item,index) in keyOptions"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-else :size="size">
<el-input
clearable
v-model="scope.row[item.prop]"
:placeholder="`请输入${item.label}`"
@change="saveChange"
@clear="saveChange"
/>
</el-form-item>
</template>
</el-table-column>
<!--操作 -->
<el-table-column width="80" align="center" label="操作" fixed="right">
<template slot-scope="scope">
<el-button :size="size" type="danger" @click="deleteRow(scope.$index, scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form>
<el-link type="danger" v-show="isRepeatName">{{tableColumn[0].label}}命名已存在!</el-link>
</div>
</template>
<script>
import _ from 'lodash'
import Sortable from 'sortablejs'
export default {
directives: {
focus: {
inserted: function (el) {
el.querySelector('input').focus()
}
}
},
props: {
'size': {
type: String,
default: 'mini'
},
'tableData': {
type: Array,
default () {
return []
}
},
'tableColumn': {
type: Array,
default () {
return [
{
default: '',
label: '字段',
prop: 'field_name'
},
{
default: 'string',
label: '类型',
prop: 'field_type'
},
{
default: '',
label: '描述',
prop: 'field_desc'
}
]
}
}
},
watch: {
'form.tableData': {
immediate: false,
handler (val) {
this.$emit('save-data-back', val)
if (val.length > 0) {
const fieldName = val.map(item => item[this.tableColumn[0].prop])
this.isRepeatName = this.isRepeat(fieldName)
val.forEach(item => {
if (!item[this.tableColumn[0].prop]) {// 只有有空就禁止提交
this.disabledAdd = true
this.$emit('save-call-back', true)
} else {
this.disabledAdd = false
this.$emit('save-call-back', false)
}
})
if (this.isRepeatName) { // 有重复值
this.disabledAdd = true
this.$emit('save-call-back', true)
}
}
}
},
'tableData': {
immediate: true,
handler (val) {
this.$nextTick(function () {
this.rowDropDialog()
})
if(val.length > 0){
this.form.tableData = val
}
}
}
},
computed: {
rules () {
const rules = {}
this.tableColumn.forEach((item, index) => {
rules[item.prop] = [
{ required: true, message: '请输入' + item.label, trigger: 'blur' },
{ pattern: /^[a-zA-Z][a-zA-Z0-9_]*$/, message: '须字母开头,不含特殊符号', trigger: 'blur' },
]
})
return rules
}
},
data () {
return {
getRowKeys (row) {
return row.id
},
form: {
tableData: []
},
fieldName: [],
disabledAdd: false,
isRepeatName: false,
options: [
'tinyint',
'smallint',
'int',
'bigint',
'boolean',
'float',
'double',
'string'
],
keyOptions: [
{ value: 'qq', label: 'QQ号' },
{ value: 'area', label: '大区ID' },
{ value: 'roleid', label: '角色ID' },
{ value: 'os', label: '手机操作系统' },
{ value: 'commid', label: '微信Commid' },
{ value: 'openid', label: 'Open ID' },
{ value: 'null', label: '不关联' }
]
}
},
methods: {
rowDropDialog () {
const tbody = document.querySelector('#dragTable_sql tbody')
const _this = this
Sortable.create(tbody, {
handle: '.el-icon-rank',
animation: 150,
onEnd ({ newIndex, oldIndex }) {
const currRow = _this.form.tableData.splice(oldIndex, 1)[0]
_this.form.tableData.splice(newIndex, 0, currRow)
}
})
},
inputChange (val) {
if (val) { //必要字段更新
this.disabledAdd = this.fieldName.indexOf(val) !== -1
this.isRepeatName = this.fieldName.indexOf(val) !== -1
this.$emit('save-call-back', this.disabledAdd)
this.$emit('save-data-back', this.form.tableData)
} else {
this.$refs['form'].validate(valid => {
if (valid) {
//清除不计重复
this.$emit('save-data-back', this.form.tableData)
} else {
this.disabledAdd = true
this.$emit('save-call-back', true)
return valid
}
});
}
},
saveChange () {
this.$emit('save-data-back', this.form.tableData)
},
addRow () {
this.$refs['form'].validate((valid) => {
if (valid) {
// 1.读取已有命名
if (this.form.tableData.length > 0) {
this.fieldName = this.form.tableData.map(item => item[this.tableColumn[0].prop])
}
// 2.添加一行:id++1
const tableRowKey = this.tableColumn.map(item => item.prop)
const tableRowVal = this.tableColumn.map(item => item.default)
const tableRow = _.zipObject(tableRowKey, tableRowVal) // 映射
tableRow.id = _.uniqueId(Date.now().toString()) // 拖拽
this.form.tableData.push(tableRow)
this.disabledAdd = true
this.$emit('save-call-back', true)
} else {
return false;
}
});
},
deleteRow (index, row) {
//1.删除
this.form.tableData.splice(index, 1)
// 2.去重
if(this.form.tableData.length === 0){
this.fieldName = []
}else{
this.fieldName = this.fieldName.filter(item => item !== row[this.tableColumn[0].prop])
}
},
isRepeat (arr) {
return _.uniq(arr).length !== arr.length;
}
}
}
</script>
-end-

浙公网安备 33010602011771号