VUE ElementUI 实现可编辑表格加校验

<!-- 道面巡检主页面 -->
<template>
  <div id="roadSchedule">
    <!-- 查询条件 -->
    <div class="totalCondition">
      <condition
        ref="condition"
        @setData="setData"
        @setLoading="setLoading"
        @setSelects="setSelects"
      />
    </div>
    <!-- 表格 -->
    <div class="table_wrap">
      <el-form class="tbForm" :model="fromData" ref="fromTable">
        <el-table
          height="100%"
          :data="fromData.data.slice((this.page - 1) * this.size, (this.page - 1) * this.size+ this.size)"
          stripe
          v-loading="loading"
          element-loading-background="rgba(0, 0, 0, 0.8)"
          @row-contextmenu="rightClick"
          ref="table"
        >
          <el-table-column label="日期">
            <template slot-scope="scope">
              <el-form-item
                v-show="scope.row.showRow"
                :prop="'data.'+scope.$index+'.newStartDate'"
                :rules="fromaDataRules.newStartDate"
              >
                <el-date-picker
                  v-model="scope.row.newStartDate"
                  type="date"
                  format="yyyy-MM-dd"
                  value-format="yyyy-MM-dd"
                  placeholder="请选择日期"
                  :clearable="false"
                ></el-date-picker>
              </el-form-item>
              <span v-show="!scope.row.showRow">{{scope.row.newStartDate}}</span>
            </template>
          </el-table-column>
          <el-table-column label="开始时间">
            <template slot-scope="scope">
              <el-form-item
                v-show="scope.row.showRow"
                :prop="'data.'+scope.$index+'.patrolStartTime'"
                :rules="fromaDataRules.patrolStartTime"
              >
                <el-time-picker
                  v-model="scope.row.patrolStartTime"
                  format="HH:mm"
                  value-format="HH:mm"
                  placeholder="请选择开始时间"
                  :clearable="false"
                ></el-time-picker>
              </el-form-item>
              <span v-show="!scope.row.showRow">{{scope.row.patrolStartTime}}</span>
            </template>
          </el-table-column>
          <el-table-column label="结束时间">
            <template slot-scope="scope">
              <el-form-item
                v-show="scope.row.showRow"
                :prop="'data.'+scope.$index+'.patrolEndTime'"
                :rules="fromaDataRules.patrolEndTime"
              >
                <el-date-picker
                  v-model="scope.row.patrolEndTime"
                  type="datetime"
                  format="yyyy-MM-dd HH:mm"
                  value-format="yyyy-MM-dd HH:mm"
                  placeholder="请选择结束时间"
                  :clearable="false"
                ></el-date-picker>
              </el-form-item>
              <span
                v-show="!scope.row.showRow"
              >{{diffDays(scope.row.newStartDate,scope.row.patrolEndTime)}}</span>
            </template>
          </el-table-column>
          <el-table-column label="巡检人">
            <template slot-scope="scope">
              <el-form-item
                v-show="scope.row.showRow"
                :prop="'data.'+scope.$index+'.personLiable'"
                :rules="fromaDataRules.personLiable"
              >
                <el-input placeholder="请输入巡检人" v-model="scope.row.personLiable"></el-input>
              </el-form-item>
              <span v-show="!scope.row.showRow">{{scope.row.personLiable}}</span>
            </template>
          </el-table-column>
          <el-table-column label="任务描述">
            <template slot-scope="scope">
              <el-form-item
                v-show="scope.row.showRow"
                :prop="'data.'+scope.$index+'.taskDescription'"
                :rules="fromaDataRules.taskDescription"
              >
                <el-input placeholder="请输入任务描述" v-model="scope.row.taskDescription"></el-input>
              </el-form-item>
              <span v-show="!scope.row.showRow">{{scope.row.taskDescription}}</span>
            </template>
          </el-table-column>
          <el-table-column label="任务状态">
            <template slot-scope="scope">
              <div v-show="scope.row.showRow">
                <el-form-item
                  :prop="'data.'+scope.$index+'.patrolStatus'"
                  :rules="fromaDataRules.patrolStatus"
                >
                  <el-select v-model="scope.row.patrolStatus" placeholder="请选择">
                    <el-option
                      v-for="item in options"
                      :key="item.id"
                      :label="item.content"
                      :value="item.content"
                    ></el-option>
                  </el-select>
                  <el-button type="text" @click="saveRow(scope.row)">
                    &nbsp;&nbsp;&nbsp;&nbsp;
                    <i class="el-icon-check"></i>
                  </el-button>
                </el-form-item>
              </div>
              <div v-show="!scope.row.showRow">
                <span>{{scope.row.patrolStatus}}</span>
                <el-button
                  v-if="scope.row.patrolStatus==='进行中'||scope.row.patrolStatus==='已完成'"
                  type="text"
                  size="medium"
                  @click="clickDetail(scope.row)"
                >&nbsp;&nbsp;&nbsp;&nbsp;详情</el-button>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </el-form>
    </div>
    <!-- 分页组件 -->
    <div class="pagination_wrap">
      <el-pagination
        background
        layout="total, sizes, prev, pager, next, jumper"
        :current-page.sync="page"
        :page-sizes="[20, 30, 40, 100]"
        :page-size.sync="size"
        :total="total"
      ></el-pagination>
    </div>
    <!-- 右键菜单 -->
    <v-contextmenu ref="contextmenu" :menus="menus" />
    <!-- 详情展示地图 -->
    <dialogMap v-if="isShowDialogMap" />
    <!-- 计划录入弹框 -->
    <planEnter v-if="isShowPlanEnter" @successPublic="successPublic" />
    <!-- 模板设置弹框 -->
    <templateSetting v-if="isShowTemplate" />
  </div>
</template>

<script type="text/ecmascript-6">
import condition from './components/condition/index';
import dialogMap from './components/dialogMap/index';
import planEnter from './components/dialogs/planEnter';
import templateSetting from './components/dialogs/templateSetting';
import { mapState, mapMutations } from 'vuex';
import { formatTime } from '@/utils/time.js';

export default {
  components: {
    condition, // 查询条件
    dialogMap, // 详情地图
    planEnter, // 计划录入弹框
    templateSetting // 模板设置弹框
  },
  data() {
    const self = this;
    return {
      // 校验规则
      fromaDataRules: {
        personLiable: [
          { required: true, message: '巡检人不能为空', trigger: 'blur,change' }
        ],
        taskDescription: [
          {
            required: true,
            message: '任务描述不能为空',
            trigger: 'blur,change'
          }
        ],
        patrolEndTime: [
          {
            required: true,
            message: '结束时间不能为空',
            trigger: 'blur,change'
          }
        ],
        patrolStartTime: [
          {
            required: true,
            message: '开始时间不能为空',
            trigger: 'blur,change'
          }
        ],
        newStartDate: [
          { required: true, message: '日期不能为空', trigger: 'blur,change' }
        ]
      },
      // 表格主数据
      fromData: {
        data: []
      },
      // 编辑时任务状态列表
      options: [],
      page: 1,
      size: 20,
      loading: false,
      // 当前行数据
      currentRow: {},
      // 当前行数据索引值
      currentRowIndex: '',
      // 右键菜单项数据
      menus: [
        {
          name: '编辑',
          group: '1',
          handler() {
            self.edit();
          }
        },
        {
          name: '删除',
          group: '1',
          handler() {
            self.remove();
          }
        }
      ]
    };
  },
  // 监听的数据
  computed: {
    ...mapState('roadSchedule', [
      'isShowPlanEnter',
      'isShowTemplate',
      'isShowDialogMap'
    ]),
    /**
     * 计算数据总数
     * @returns {Number}
     */
    total() {
      return this.fromData.data.length;
    },
    /**
     * 计算当前页开始索引
     * @returns {Number}
     */
    index() {
      return (this.page - 1) * this.size + 1;
    }
  },
  methods: {
    ...mapMutations('roadSchedule', [
      'setShowPlanEnter',
      'setTemplateTableData',
      'setShowDialogMap',
      'setDialogMapData'
    ]),
    /**
     * 右键菜单的显示
     */
    handleContextmenu(evt) {
      // 禁用浏览器默认行为
      evt.preventDefault();
      // 调用弹出方法
      this.$refs.contextmenu.popover(evt);
    },
    /**
     * 监听计划发布传递的数据,如果发布成功,再次重新查询列表
     * @params {Boolean} val-子组件传递的数据
     */
    successPublic(val) {
      if (val) {
        this.$refs.condition.search();
      }
    },
    /**
     * 点击详情,传入详情数据
     */
    clickDetail(row) {
      this.setShowDialogMap(true);
      this.setDialogMapData(row);
    },
    /**
     * 保存当前行
     */
    saveRow(row) {
      const seleted = row;
      // 匹配后台参数yyyy-MM-DD HH:mm:ss格式
      seleted.patrolStartTime = `${seleted.newStartDate} ${seleted.patrolStartTime}:00`;
      seleted.patrolEndTime = `${seleted.patrolEndTime}:00`;
      // 表单校验通过
      this.$refs.fromTable.validate((valid) => {
        if (valid) {
          this.$api.roadSchedule
            .updatePatrolTasks(seleted)
            .then((res) => {
              this.$utils.vIfElse(
                res && res.error,
                () => {
                  // 返回错误信息
                  this.$message.error(_.get(res.error, 'message'));
                },
                () => {
                  // 请求成功处理
                  this.$refs.condition.search();
                  this.clearCurrentRow('');
                  this.$message.success('保存成功!'); // 消息弹框
                }
              );
            })
            .catch((error) => {
              this.$message.error(_.get(error, 'response.data.message') || '保存失败!');
            });
        } else {
          return false;
        }
      });
    },
    /**
     * 右键菜单-编辑
     */
    edit() {
      this.currentRow.showRow = true;
      this.$set(this.fromData.data, this.currentRowIndex, this.currentRow);
    },
    /**
     * 右键菜单-删除
     */
    remove() {
      this.$confirm('此操作将永久删除, 是否继续?', '', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          this.$api.roadSchedule
            .deletePatrolTasks(this.currentRow.id)
            .then((res) => {
              this.$message.success('删除成功!'); // 消息弹框
              this.$refs.condition.search();
              this.clearCurrentRow('');
            })
            .catch((error) => {
              this.$message.error(_.get(error, 'response.data.message') || '删除失败!');
            });
        })
        .catch(() => {
          this.$message('已取消删除!');
        });
    },
    /**
     * 右击表格当前行触发
     */
    rightClick(row, column, event) {
      // 阻止浏览器右键默认
      event.preventDefault();
      // 当前行在编辑状态时 或者 有正在编辑的行
      // TODO 等后台把接口的任务状态返回符合要求
      if (
        row.patrolStatus === '未进行' &&
        row.showRow === false &&
        (!this.currentRow.id || this.currentRow.showRow === false)
      ) {
        // 定义变量接收该节点所对应的对象
        this.currentRow = row;
        // 调用弹出方法
        this.$refs.contextmenu.popover(event);
        // 获取当前右键点击table下标
        this.fromData.data.forEach((item, index) => {
          if (item.id === row.id) {
            this.currentRowIndex = index;
            return false;
          }
        });
      }
    },
    /**
     * 计算开始时间和结束时间间隔天数 格式化列表结束时间 HHmm格式或HHmm(+n)
     * @param {Date} strDateStart strDateEnd:开始时间;strDateEnd:
     */
    diffDays(strDateStart, strDateEnd) {
      const HHMM = formatTime(strDateEnd, 'hhmm', true);
      const strDateS = new Date(strDateStart).getTime();
      const strDateE = new Date(strDateEnd).getTime();
      const days = parseInt((strDateE - strDateS) / 1000 / 60 / 60 / 24, 10); // 把相差的毫秒数转换为天数
      if (days > 0) {
        return `${HHMM}(+${days})`;
      }
      return `${HHMM}`;
    },
    /**
     * 日期转毫秒数
     */
    dateToTime(str) {
      return new Date(str.replace(/-/g, '/')).getTime(); // 用/替换日期中的-是为了解决Safari的兼容
    },
    /**
     * 设置表格数据
     */
    setData(data) {
      this.fromData.data = data;
    },
    /**
     * 设置加载中转圈圈
     */
    setLoading(val) {
      this.loading = val;
    },
    /**
     * 设置下拉数据
     */
    setSelects(arr) {
      this.options = arr;
    },
    /**
     * 清空当前行
     */
    clearCurrentRow(val) {
      this.currentRow = {};
      this.currentRowIndex = '';
    }
  }
};
</script>

<style lang="scss">
#roadSchedule {
  //设置列表表单的 高度
  .tbForm {
    height: 100%;
    .el-input {
      & > input {
        border: 1px solid #2050a0;
      }
    }
    .el-icon-check {
      font-size: 22px;
      font-weight: bolder;
      vertical-align: middle;
    }
  }
  // 隐藏默认图标
  .el-icon-date {
    position: absolute;
    display: none;
  }
  //分隔符 - 的颜色
  .el-range-separator {
    color: rgb(255, 255, 255);
  }
  padding-left: 10px;
  padding-right: 10px;
  height: 100%;
  width: 100%;
  display: flex;
  flex-direction: column;
  .box-card {
    position: absolute;
    z-index: 1000;
    .edit {
      cursor: pointer;
    }
    .delete {
      cursor: pointer;
      margin-top: 5px;
    }
  }
  .el-card__body {
    padding-top: 5px;
    padding-right: 15px;
    padding-bottom: 5px;
    padding-left: 15px;
  }
  .el-table--enable-row-hover .el-table__body tr:hover > td {
    background-color: #2050a0 !important;
  }
  .title {
    height: 40px;
    line-height: 40px;
    font-size: 16px;
  }

  .planBtn {
    width: 107px;
    height: 30px;
    line-height: 30px;
    text-align: center;
    background-color: #01bba7;
    cursor: pointer;
    border-radius: 4px;
  }
  .amvs_dialog {
    background: rgba(0, 0, 0, 0.5);
    z-index: 100;
  }
  .table_wrap {
    margin-top: 10px;
    flex: 1;
    .el-input__inner {
      height: 30px;
      background: #383838;
      border: none;
      border-radius: 1px;
      width: 220px;
      color: #fff;
    }
    .el-input__icon {
      line-height: 28px;
    }
  }
  .pagination_wrap {
    height: 80px;
    display: flex;
    justify-content: flex-end;
    align-items: center;
  }
  .el-table th {
    color: #cbcbcb;
  }
  .el-table {
    color: #bcbcbc;
  }
}
</style>

 

Vue 中使用 ElementUI 实现编辑表格,可以通过以下几个步骤实现: 1. 在 Vue 组件中引入 ElementUI 的表格组件和按钮组件。可以使用 `el-table` 实现表格,使用 `el-button` 实现按钮。 2. 在 `data` 中定义表格的数据源,以及保存编辑状态的变量。例如,定义一个 `tableData` 数组来保存表格的数据,定义一个 `editIndex` 变量来保存当前编辑的行的索引。 3. 在表格中添一个列,用于显示编辑按钮。该列的 `slot` 属性可以设置为 `header`,表示该列是表头,且表头内容由自定义模板来渲染。在自定义模板中,可以添一个按钮来触发编辑操作。 4. 添编辑操作的方法。当点击编辑按钮时,将当前行的索引保存到 `editIndex` 变量中。在表格中的每一行中,可以通过 `v-if` 指令来判断当前行是否处于编辑状态,从而决定是否显示编辑框。 5. 添保存操作的方法。当点击保存按钮时,将编辑后的数据发送给后端,同时将 `editIndex` 变量重置为 `-1`,表示当前不处于编辑状态。 代码示例: ```html <template> <div> <el-table :data="tableData"> <el-table-column prop="name" label="姓名"></el-table-column> <el-table-column prop="age" label="年龄"></el-table-column> <<el-table-column label="操作"> <template slot="header"> <el-button type="primary" @click="handleAdd">添</el-button> </template> <template slot-scope="scope"> <el-button v-if="editIndex !== scope.$index" @click="handleEdit(scope.$index)">编辑</el-button> <el-button v-else @click="handleSave(scope.$index)">保存</el-button> </template> </el-table-column> </el-table> </div> </template> <script> export default { data() { return { tableData: [ { name: '张三', age: 20 }, { name: '李四', age: 25 }, { name: '王五', age: 30 } ], editIndex: -1 }; }, methods: { handleAdd() { this.tableData.push({ name: '', age: '' }); }, handleEdit(index) { this.editIndex = index; }, handleSave(index) { const editedData = this.tableData[index]; // 将编辑后的数据发送给后端 console.log('保存数据:', editedData); this.editIndex = -1; } } }; </script> ``` 在上面的代码示例中,编辑按钮的显示与隐藏通过 `v-if` 指令来实现。当 `editIndex` 等于当前行的索引时,显示保存按钮;否则,显示编辑按钮。编辑后的数据可以通过表格的 `data` 属性来绑定。当数据发生变化时,表格会自动重渲染。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值