vue+element 表单嵌套表格 增删改查

  • A+
所属分类:Web前端
摘要

表单校验参考了https://blog.csdn.net/iamlujingtao/article/details/105186117效果如图所示,主要做了一些美化和解决一些看着难受的点

表单校验参考了https://blog.csdn.net/iamlujingtao/article/details/105186117

效果如图所示,主要做了一些美化和解决一些看着难受的点vue+element 表单嵌套表格 增删改查

 

代码如下,有时间再介绍

<template>   <div class="app-container">     <div class="filter-container">       <el-input         v-model="listQuery.car"         placeholder="车辆id"         style="width: 200px"         class="filter-item"         clearable         @keyup.enter.native="handleFilter"       />       <el-autocomplete         v-model="listQuery.project"         :fetch-suggestions="querySearchAsync"         placeholder="项目名称"         class="filter-item"         clearable         @clear="setBlur()"         @keyup.enter.native="handleFilter"       />       <el-date-picker         v-model="listQuery.startTime"         type="datetime"         placeholder="选择开始日期时间"         class="filter-item"         :picker-options="pickerOptions"         value-format="yyyy-MM-dd HH:mm:ss"       />       <el-date-picker         v-model="listQuery.endTime"         type="datetime"         placeholder="选择结束日期时间"         class="filter-item"         :picker-options="pickerOptions"         value-format="yyyy-MM-dd HH:mm:ss"       />       <el-button-group>         <el-button           class="filter-item"           style="margin-left: 20px"           icon="el-icon-search"           plain           round           @click="handleFilter"         > 搜索         </el-button>         <el-button           class="filter-item"           style="margin-left: 10px"           icon="el-icon-circle-plus-outline"           plain           round           @click="add"         > 新增         </el-button>       </el-button-group>     </div>      <el-form ref="form" :model="form" :rules="rules">       <el-table v-loading="loading" :data="form.tableData" style="width: 100%" border fit>         <el-table-column label="车辆" min-width="15%" prop="car" align="center">           <template v-slot="{row,$index}">             <template v-if="row.edit">               <el-form-item :prop="'tableData.'+$index+'.car'" :rules="rules.car">                 <el-input v-model="row.car" clearable size="small" />               </el-form-item>             </template>             <span v-else>{{ row.car }}</span>           </template>         </el-table-column>          <el-table-column label="项目" min-width="15%" prop="project" align="center">           <template v-slot="{row,$index}">             <template v-if="row.edit">               <el-form-item :prop="'tableData.'+$index+'.project'" :rules="rules.project">                 <el-input v-model="row.project" clearable size="small" />               </el-form-item>             </template>             <span v-else>{{ row.project }}</span>           </template>         </el-table-column>          <el-table-column label="开始日期" min-width="20%" align="center">           <template v-slot="{row,$index}">             <template v-if="row.edit">               <el-form-item :prop="'tableData.'+$index+'.startTime'" :rules="rules.startTime">                 <el-date-picker                   v-model="row.startTime"                   type="datetime"                   placeholder="请选择日期"                   align="center"                   size="small"                   :picker-options="pickerOptions"                   value-format="yyyy-MM-dd HH:mm:ss"                 />               </el-form-item>             </template>             <template v-else>               <i class="el-icon-time" />               <span>{{ row.startTime }}</span>             </template>           </template>         </el-table-column>          <el-table-column label="结束日期" min-width="20%" align="center">           <template v-slot="{row,$index}">             <template v-if="row.edit">               <el-form-item :prop="'tableData.'+$index+'.endTime'" :rules="rules.endTime">                 <el-date-picker                   v-model="row.endTime"                   type="datetime"                   placeholder="请选择日期"                   align="center"                   size="small"                   :picker-options="pickerOptions"                   value-format="yyyy-MM-dd HH:mm:ss"                 />               </el-form-item>             </template>             <template v-else>               <i class="el-icon-time" />               <span>{{ row.endTime }}</span>             </template>           </template>         </el-table-column>          <el-table-column label="操作" min-width="20%" align="center">           <template slot-scope="{row,$index}">              <template v-if="!row.edit">               <!--加div是为了和下面else中的button不一样,可以避免点击按钮后不失焦-->               <div>                 <el-button                   id="edit-button"                   size="small"                   plain                   round                   icon="el-icon-edit"                   type="primary"                   @click="handleEdit(row)"                 >                   修改                 </el-button>                 <el-button                   :id="'deleteButton'+$index"                   size="small"                   style="margin-left: 15px"                   plain                   round                   icon="el-icon-delete"                   type="danger"                   @click="confirmDelete($index,row)"                 >                   删除                 </el-button>               </div>             </template>              <template v-else>               <el-button                 id="confirm-save-button"                 size="small"                 plain                 round                 icon="el-icon-circle-check"                 type="success"                 @click="confirmSave($index,row)"               >{{                 '保存'               }}               </el-button>               <el-button                 id="cancel-save-button"                 style="margin-left: 15px"                 size="small"                 plain                 round                 icon="el-icon-circle-close"                 type="info"                 @click="cancelSave($index,row)"               >{{                 '取消保存'               }}               </el-button>             </template>            </template>         </el-table-column>        </el-table>     </el-form>     <pagination       v-show="total > 0"       :total="total"       :page.sync="listQuery.page"       :limit.sync="listQuery.limit"       :page-sizes.sync="pageSizes"       @pagination="getTableData"     />   </div> </template>  <script> import Pagination from '@/components/Pagination' // import api8899 from '@/api/api8899'  export default {   components: { Pagination },   data() {     return {       // 输入建议       restaurants: [],       // 加载状态       loading: true,       list: null,       total: 0,       listQuery: {         page: 1,         limit: 12,         car: undefined,         project: undefined,         startTime: undefined,         endTime: undefined       },       pageSizes: [12, 24, 36],       form: {         tableData: []       },       rules: {         car: [{           type: 'string',           required: true,           trigger: 'change',           message: '车辆不能为空'         }],         project: [{           type: 'string',           required: true,           trigger: 'change',           message: '项目不能为空'         }],         startTime: [{           type: 'string',           required: true,           trigger: 'change',           message: '开始时间不能为空'         }]       },       // 时间选项       pickerOptions: {         shortcuts: [           // {           //   text: '现在',           //   onClick (picker) {           //     picker.$emit('pick', new Date())           //   }           // },           {             text: '昨天',             onClick(picker) {               const date = new Date()               date.setTime(date.getTime() - 3600 * 1000 * 24)               picker.$emit('pick', date)             }           }, {             text: '三天前',             onClick(picker) {               const date = new Date()               date.setTime(date.getTime() - 3600 * 1000 * 24 * 3)               picker.$emit('pick', date)             }           }, {             text: '七天前',             onClick(picker) {               const date = new Date()               date.setTime(date.getTime() - 3600 * 1000 * 24 * 7)               picker.$emit('pick', date)             }           }]       }      }   },   mounted() {     this.getTableData()     this.inputSuggest()   },   methods: {     async getTableData() {       // const res = await api8899.search_car(this.listQuery)       // this.total = res.data.code === 200 ? res.data.data.count : 0       // this.form.tableData = res.data.data.data       this.form.tableData = [         {           car: 'Aaa012',           projectId: 'aaa',           project: '某个项目',           startTime: '2021-09-21 13:51:43',           endTime: '2021-09-26 13:51:43'         },         {           car: 'Aaa234',           projectId: 'aaa',           project: '某个项目',           startTime: '2021-08-26 13:51:43',           endTime: ''         },         {           car: 'Aaa345',           projectId: 'bbb',           project: '其他项目',           startTime: '2021-07-26 13:51:43',           endTime: '2021-07-26 13:51:43'         },         {           car: 'Aaa222',           projectId: 'bbb',           project: '其他项目',           startTime: '2021-09-09 13:51:43',           endTime: ''         }       ]       this.form.tableData.map((v) => {         this.$set(v, 'edit', false)         // v.edit = false // 不能被v-if监听到         return v       })       this.loading = false     },     handleFilter() {       this.loading = true       this.getTableData()       this.loading = false     },     handleEdit(row) {       if (row.temp === undefined) {         row.temp = Object.assign({}, row) // 复制对象,为了取消修改后还原数据       } else if (row.temp.car === '') {         delete row.temp         row.temp = Object.assign({}, row) // 复制对象,为了取消修改后还原数据       }       row.edit = !row.edit     },     validateField(form, index) {       let result = true       for (const item of this.$refs[form].fields) {         if (parseInt(item.prop.split('.')[1]) === index) {           this.$refs.form.validateField(item.prop, (error) => {             if (error) {               result = false             }           })         }         if (!result) break       }       return result     },     async confirmSave(index, row) {       if (!this.validateField('form', index)) {         this.$message({           type: 'info',           message: '保存修改失败,请检查是否有未填字段',           center: true         })         return       }       // 判断值是否有改变,如果没有则不做下面的操作       const tmp = Object.assign({}, row)       const rowTmp = Object.assign({}, tmp.temp)       delete rowTmp.edit       delete tmp.temp       delete tmp.edit       if (JSON.stringify(rowTmp) === JSON.stringify(tmp)) {         row.edit = !row.edit         return       }       // 配置发送的请求参数       // const params = {       //   'car': row.car,       //   'project': row.project,       //   'startTime': row.startTime,       //   'endTime': row.endTime,       //   'oCar': row.temp.car,       //   'oProject': row.temp.project,       //   'oStartTime': row.temp.startTime,       //   'oEndTime': row.temp.endTime       // }       this.loading = true       // const response = await api8899.upsert_car(params)       const response = { 'data': { 'code': 200 }}       // const response = { 'data': { 'code': 23423,'message':'自定义提示' }}       this.loading = false       let type, message       if (response.data.code === 500) {         type = 'error'         message = '保存出错,请联系开发人员修复'       } else if (response.data.code === 200) {         type = 'success'         message = '保存成功'       } else {         type = 'info'         message = response.data.message       }       this.$message({         type: type,         message: message,         center: true       })       // info为保存数据重复等问题,直接返回       if (type === 'info') {         return       }       row.edit = !row.edit       delete row.temp       row.temp = Object.assign({}, row) // 复制对象,为了取消修改后还原数据     },     cancelSave(index, row) {       if (row.temp.car === '') {         this.$delete(this.form.tableData, index)         return       }       this.$set(this.form.tableData, index, row.temp) // 取消后还原数据到修改前状态     },     // 删除数据     async confirmDelete(index, row) {       // 让按钮失焦防止在提示时按多次enter键导致多次提交       document.getElementById('deleteButton' + index).blur()       // 设置弹窗样式       const h = this.$createElement       const confirmText1 = ['车辆 : ', '项目 : ', '开始时间 : ', '结束时间 : ']       const confirmText2 = [row.car, row.project, row.startTime, row.endTime]       const newData = []       for (const i in confirmText1) {         newData.push(h('span', null, confirmText1[i]))         newData.push(h('i', { style: 'color: teal' }, confirmText2[i]))         newData.push(h('div', null, null))       }       const confirm = await this.$msgbox({         title: '确定删除该条数据吗',         message: h('p', null, newData),         showCancelButton: true,         confirmButtonText: '确定',         cancelButtonText: '取消'       }).catch(() => {         this.$message({           type: 'info',           message: '已取消删除',           center: true         })       })       if (confirm === 'confirm') {         this.loading = true         // const response = await api8899.delete_car({ 'car': row.car, 'project': row.project, 'startTime': row.startTime })         const response = { 'data': { 'code': 200 }}         const type = response.data.code === 200 ? 'success' : 'error'         const message = response.data.code === 200 ? '成功删除数据' : '删除数据失败,请联系开发人员修复'         this.$delete(this.form.tableData, index)         this.loading = false         this.$message({           type: type,           message: message,           center: true         })       }     },     // 新增时重新初始化一个插入第一行     add() {       const temp = {         car: '',         project: '',         projectId: '',         startTime: '',         endTime: '',         edit: true,         temp: {           car: '',           project: '',           startTime: '',           endTime: ''         }       }       this.form.tableData.unshift(temp)     },     // 获取项目输入框建议     async inputSuggest() {       // const tmp = await api8899.search_project()       const tmp = { data: { data: [{ value: '某个项目b' }, { value: '某个项目a' }] }}       this.restaurants = tmp.data.data     },     // 处理输入框建议,restaurants必须是包含value属性的对象 [ {value:'xxx'} , ...]     querySearchAsync(queryString, cb) {       const restaurants = this.restaurants       const results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants       cb(results)     },     // 输入框建议过滤规则     createStateFilter(queryString) {       return (state) => {         return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)       }     },     // 清空输入框时取消聚焦 使用户重新点击来展示建议下拉框     setBlur() {       document.activeElement.blur()     }   } } </script>  <style scoped> .filter-container {   text-align: left;   padding-bottom: 10px; }  .filter-item {   display: inline-block;   vertical-align: middle;   margin-bottom: 10px; }  .app-container {   padding: 20px; }  /deep/ .el-form-item {   margin-bottom: 0 }  /deep/ .el-input__inner {   text-align: center; }  /deep/ .el-button--text {   display: none; } </style>