【Vue】动态增减表单、表单验证
业务需求:在添加维度时,需要为其动态添加子维度,要求至少一个且名称不能重复,同时进行表单验证。vue页面代码如下:
<template>
<div>
<el-form class="mt10 pd10 elForm" ref="form" :model="form" label-width="130px" :label-position="labelPosition">
<el-form-item label="维度名称:" prop="name" :rules="[
{ required: true, message: '请输入维度名称', trigger: 'blur' }
]">
<el-col :span="8">
<el-input placeholder="请输入维度名称" v-model="form.name"></el-input>
</el-col>
</el-form-item>
<el-form-item label="子维度名称:" >
<el-button size="medium" type="primary" @click="addList" class="btn-min-w">添加</el-button>
</el-form-item>
<el-form-item
v-for="(item,index) in form.list"
:key="index"
:prop="'list.' + index + '.name'"
:rules="{
required: true, message: '请输入子维度名称', trigger: 'blur'
}">
<table>
<tr>
<td>
<el-input v-model="item.name"></el-input>
</td>
<td style="padding-right:0">
<el-button icon="el-icon-minus" type="danger" size="mini" circle @click="delList(index)">
</el-button>
</td>
</tr>
</table>
</el-form-item>
<el-form-item>
<template slot-scope="scope">
<el-button size="medium" type="primary" @click="submit('form')" class="btn-min-w">提交</el-button>
<el-button size="medium" @click="cancel()" class="btn-min-w">返回</el-button>
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
import tableOperation from '@/components/layout/tableOperation'
import * as api from '@/api/ptms'
import {tips} from '../../static/js/global.js'
export default {
components:{ tableOperation},
data(){
return{
labelPosition: 'right',
form:{
name:'',
list:[
{
name: ''
},
{
name: ''
}
]
}
}
},
created() {
// 跳转页面获取信息
api.dimensionForm({id: this.$route.params.id})
.then((res)=>{
console.log(res);
if(res.ret > -1){
if(this.$route.params.id != null){
this.form.name = res.data.dimension.name;
this.form.list = res.data.subDimension;
// console.log(this.form)
}
}
})
},
methods:{
addList() {
this.form.list.push({name: ''})
},
delList(index) {
if(this.form.list.length === 1){
tips(this, '至少需要一个子维度', 'warning');
return;
}
this.form.list.splice(index, 1)
},
// 添加、修改维度
submit(formName) {
this.$refs[formName].validate((valid) => {
if(valid){
// console.log(this.form.list)
const id = (typeof (this.$route.params.id) === 'undefined') ? null : this.$route.params.id;
let subDimensionsName = this.form.list.map((item) => item.name);
if(isDuplicate(subDimensionsName) === true){
tips(this, '子维度名称不能重复', 'warning');
return;
}
api.dimensionFormAction({id: id, name: this.form.name, subDimensions: this.form.list})
.then((res)=>{
if(res.data === "existed"){
tips(this, '该维度名称已存在', 'warning');
return;
}
tips(this, id == null ? '添加成功!' :'修改成功!', 'success');
this.$router.push('/dimensionList');
})
}
})
},
// 取消返回上一页
cancel() {
this.$router.back(-1);
}
}
}
// 判断子维度是否重复
function isDuplicate(arr) {
let hash = {};
for(let i in arr) {
if(hash[arr[i]]) {
return true;
}
hash[arr[i]] = true;
}
return false;
}
</script>
<style lang="scss" scoped>
</style>
效果如下:
在该项目中,还有一个需求同样用到动态表单,只是不再是文本框,而是变成两个下拉单选框。这里要求前一个下拉框是必选,代码如下:
<template>
<div>
<el-form class="mt10 pd10 elForm" :rules="rules" ref="ruleForm" :model="ruleForm" label-width="130px" :label-position="labelPosition">
<el-form-item label="需求名称:" prop="name">
<el-col :span="8">
<el-input placeholder="请输入需求名称" v-model="ruleForm.name"></el-input>
</el-col>
</el-form-item>
<el-form-item label="创建人员:" prop="createdByName">
<el-col :span="8">
<el-input v-model="ruleForm.createdByName" disabled></el-input>
</el-col>
</el-form-item>
<el-form-item label="负责人:" prop="chargeBy">
<el-col :span="8">
<el-select v-model="ruleForm.chargeBy" placeholder="请选择负责人" @change="chooseOrgs" filterable clearable size="medium">
<el-option v-for="item in orgs" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="所属项目:" prop="projectId">
<el-col :span="8">
<el-select v-model="ruleForm.projectId" placeholder="请选择所属项目" @change="chooseProjects" filterable clearable size="medium">
<el-option v-for="item in projects" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-col>
</el-form-item>
<el-form-item label="需求描述:" prop="description">
<el-col :span="8">
<el-input placeholder="请输入需求描述" v-model="ruleForm.description" type="textarea"></el-input>
</el-col>
</el-form-item>
<el-form-item label="模块与评估人员:">
<el-button size="medium" type="primary" @click="addList" class="btn-min-w">添加</el-button>
</el-form-item>
<el-form-item>
<table v-for="(item,index) in ruleForm.list" :key="index" >
<tr>
<td>
涉及模块:
</td>
<td>
<el-form-item :prop="'list.' + index + '.moduleId'" :rules="{ required: true, message: '请选择涉及模块', trigger: 'change' } ">
<el-select v-model="item.moduleId" placeholder="请选择涉及模块" @change="chooseModules" filterable clearable size="medium">
<el-option v-for="item in modules" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</el-form-item>
</td>
<td>
评估人员:
</td>
<td>
<el-select v-model="item.evaluator" placeholder="请选择评估人员" @change="chooseEvaluators" filterable clearable size="medium">
<el-option v-for="item in evaluators" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</td>
<td style="padding-right:0">
<el-button icon="el-icon-minus" type="danger" size="mini" circle @click="delList(index)">
</el-button>
</td>
</tr>
</table>
</el-form-item>
<el-form-item label="操作备注:" v-if="this.$route.params.id != null">
<el-col :span="8">
<el-input placeholder="请输入操作备注" v-model="ruleForm.remark" type="textarea"></el-input>
</el-col>
</el-form-item>
<el-form-item>
<template slot-scope="scope">
<el-button size="medium" type="primary" @click="submit('ruleForm')" class="btn-min-w">保存</el-button>
<el-button size="medium" type="primary" @click="submitAndAssign('ruleForm')" class="btn-min-w">保存并指派评估</el-button>
<el-button size="medium" @click="cancel()" class="btn-min-w">返回</el-button>
</template>
</el-form-item>
</el-form>
</div>
</template>
<script>
import tableOperation from '@/components/layout/tableOperation'
import * as api from '@/api/ptms'
import {tips} from '../../static/js/global.js'
export default {
components:{ tableOperation},
data(){
return{
labelPosition: 'right',
actionType: "",
ruleForm: {
name:'',
description:'',
projectId: '',
chargeBy: '',
createdByName: '',
createdBy: '5', // TODO 直接取的登录用户信息
actor: '张俊', // TODO 直接取的登录用户信息
remark: '',
list:[
{
moduleId: '',
evaluator: '',
},
{
moduleId: '',
evaluator: '',
}
]
},
projects: [],
orgs: [],
modules: [],
evaluators: [],
rules: {
name: [
{ required: true, message: '请输入需求名称', trigger: 'blur' }
],
description: [
{ required: true, message: '请输入需求描述', trigger: 'blur' }
],
chargeBy: [
{ required: true, message: '请选择负责人', trigger: 'change' }
],
projectId: [
{ required: true, message: '请选择所属项目', trigger: 'change' }
],
}
}
},
created() {
// 跳转页面获取信息
api.requirementForm({id: this.$route.params.id})
.then((res)=>{
if(res.ret > -1){
this.orgs = res.data.orgs;
this.projects = res.data.projects;
this.modules = res.data.modules;
this.evaluators = res.data.orgs;
// this.ruleForm.createdBy = "";
this.ruleForm.createdByName = "admin";
// 从项目页面新增需求自动填充所属项目
if(this.$route.query.projectId != null){
this.ruleForm.projectId = this.$route.query.projectId;
}
if(this.$route.params.id != null){
this.ruleForm.name = res.data.requirement.name;
this.ruleForm.description = res.data.requirement.description;
this.ruleForm.createdBy = res.data.requirement.createdBy;
this.ruleForm.createdByName = res.data.requirement.createdByName;
this.ruleForm.chargeBy = res.data.requirement.chargeBy;
this.ruleForm.projectId = res.data.requirement.projectId;
if(res.data.requirementModuleOrgs != null){
this.ruleForm.list = res.data.requirementModuleOrgs;
}
}
}
})
},
methods:{
addList() {
this.ruleForm.list.push({moduleId: '', evaluator:''})
},
delList(index) {
this.ruleForm.list.splice(index, 1)
},
chooseOrgs(val){
this.ruleForm.orgId = val;
},
chooseProjects(val){
this.ruleForm.projectId = val;
},
chooseModules(val){
this.ruleForm.list.moduleId = val;
},
chooseEvaluators(val){
this.ruleForm.list.evaluator = val;
},
// 添加、修改需求
submit(formName) {
this.actionType = "submit";
this.action(formName);
},
submitAndAssign(formName){
this.actionType = "submitAndAssign";
let moduleAndEvaluator = this.ruleForm.list;
for(let i=0; i<moduleAndEvaluator.length; i++){
if(moduleAndEvaluator[i].evaluator == null || moduleAndEvaluator[i].evaluator === ''){
tips(this, '请选择评估人员', 'warning');
return;
}
}
this.action(formName);
},
action(formName){
this.$refs[formName].validate((valid) => {
if(valid){
const id = (typeof (this.$route.params.id) === 'undefined') ? null : this.$route.params.id;
api.requirementFormAction({id: id, name: this.ruleForm.name, createdBy: this.ruleForm.createdBy, chargeBy: this.ruleForm.chargeBy,
description:this.ruleForm.description, projectId: this.ruleForm.projectId, actor: this.ruleForm.actor,
remark: this.ruleForm.remark, requirementModuleOrgs: this.ruleForm.list, actionType: this.actionType})
.then((res)=>{
if(res.data === "existed"){
tips(this, '该需求名称已存在', 'warning');
return;
}
tips(this, id == null ? '添加成功!' :'修改成功!', 'success');
this.$router.push('/requirementList');
})
}
})
},
// 取消返回上一页
cancel() {
this.$router.back(-1);
}
}
}
</script>
<style lang="scss" scoped>
</style>
效果如下: