vue後臺管理系統,mixin妙用

一、vue全家桶開發後臺管理系統

vue + vue-router + vuex + es6 + scss + webpackjavascript

二、vue的mixin使用

後臺系統有不少頁面都有相似的增刪改查操做,使用mixin效果很是好,重複的勞動大大減小。css

下面分4步來封裝:vue

2-一、提取增刪改查操做函數formFn.js

import { doPost } from "@/tools/request.js";
import { toStringValue } from "@/utils/util.js"
// toStringValue():給對象/對象數組的屬性值爲數值型的轉爲字符串型

/** @param {Object} o爲表單默認要顯示的默認值,若是無,就不填寫,可選 */
export function createFn(o = {}) {
  this.$refs.myForm && this.$refs.myForm.resetFields();
  this.dialogForm.formData = Object.assign({}, toStringValue(o));
  this.dialogForm.isEdit = false;
  this.dialogForm.title = "新增";
  this.dialogForm.isVisible = true;
}

export function editFn(row = {}) {
  this.dialogForm.isEdit = true;
  this.dialogForm.title = "編輯";
  this.dialogForm.isVisible = true;
  this.dialogForm.formData = Object.assign({}, toStringValue(row));
}

export function delFn(row, url) {
  this.$confirm("確認刪除該數據嗎?", "提示", {
    type: "warning"
  }).then(
    () => {
      doPost(url, {
          id: row.id
        })
        .then(res => {
          this.$message.success("刪除成功");
          this.getData();
        })
        .catch(e => {
          this.$message.error(e.message);
          catchUrl(e, url)
        });
    }
  ).catch(() => {
    this.$message.info("取消刪除");
  });
}

export function delFn2(row, url) {
  this.$confirm("確認刪除該數據嗎?", "提示", {
    type: "warning"
  }).then(
    () => {
      doPost(url, {
          id: row.id
        })
        .then(res => {
          this.$message.success("刪除成功");
          this.getData();
        })
        .catch(e => {
          this.$message.error(e.message);
          catchUrl(e, url)
        });
    }
  ).catch(() => {
    this.$message.info("取消刪除");
  });
}

export function submitFn(formName, url, isEdit) {
  const title = isEdit ? '編輯' : '添加';
  this.$refs[formName].validate(valid => {
    if (valid) {
      doPost(url, this.dialogForm.formData)
        .then(() => {
          this.$message.success(`${title}成功`);
          this.getData();
          this.dialogForm.isVisible = false;
        })
        .catch(e => {
          // code=0,成功返回;反之,失敗提示
          if (e.code && e.code !== 0) {
            this.$message.error(e.message);
          }
          catchUrl(e, url, `${title}`)
        });
    } else {
      console.error("Error submit ----- Form invalid !");
      return false;
    }
  })
}

export function getDataFn(url, param = {}) {
  this.tableListLoading = true;
  doPost(url, param)
    .then(res => {
      this.tableListLoading = false;
      this.page.total = res.count;
      this.tableList = res.list;
    })
    .catch(e => {
      // code=0,成功返回;反之,失敗提示
      if (e.code && e.code !== 0) {
        this.$message.error(e.message);
      }
      catchUrl(e, url)
      this.tableListLoading = false;
    });
}

export function getDataFn2(fn, param = {}) {
  this.tableListLoading = true;
  fn(param)
    .then(res => {
      this.tableListLoading = false;
      this.page.total = res.count;
      this.tableList = res.list;
    })
    .catch(e => {
      catchFn(e, fn)
      this.tableListLoading = false;
    });
}

export function mulDelFn(url) {
  if (!this.mulSels.length) {
    this.$alert("請選擇要刪除的數據", "提示");
    return;
  }
  const deleIdArr = this.mulSels.map(o => o.id);
  this.$confirm("確認刪除該數據嗎?", "提示", {
    type: "warning"
  }).then(
    () => {
      doPost(url, {
          ids: deleIdArr
        })
        .then(res => {
          this.$message.success("刪除成功");
          this.getData();
        })
        .catch(e => {
          catchUrl(e, url)
          this.$confirm(e.message, "提示", {
            type: "warning"
          }).then(
            () => {
              this.dialogForm.isVisible = false;
            }
          );
        });
    }
  ).catch(() => {
    this.$message.info("取消刪除");
  });
}

function catchUrl(e, url, detail) {
  console.group(`Error found in doPost(${url})`)
  if (detail) console.info(`--${detail}--報錯!`)
  console.error(e)
  console.groupEnd()
}

function catchFn(e, fn) {
  console.group(`Error found in method (${fn.name})`)
  console.error(e)
  console.groupEnd()
}

複製代碼

2-二、mixin-common部分(查詢、搜索的數據和方法)commom.js

import TABLE from "@/utils/tableConfig.js";
import * as formFn from "@/utils/formFn.js";
import { debounce, getQueryParam } from "@/utils/util.js";
import ZSelect from "@/components/ZSelect/ZSelect.vue";``
import ZPage from "@/components/ZPage/ZPage.vue";

export default {
  components: { ZPage, ZSelect },
  data() {
    return {
      searchFilters: {},
      tableList: [],
      tableListLoading: false,
      page: {
        size: 10,
        current: 1,
        total: 0
      },
      t: {
        border: TABLE.border,
        size: TABLE.size,
        stripe: TABLE.stripe,
        maxHeight: TABLE.maxHeight
      }
    };
  },
  methods: {
    getData() {
      const param = getQueryParam(this.searchFilters, this.page);
      formFn.getDataFn.apply(this, [this.url.getData, param]);
    },
    dbnSearch() {
      this.DSearchFn();
    },
    doSearch() {
      this.page.current = 1;
      this.getData();
    },
    dbnResetSearch() {
      this.DResetSearchFn();
    },
    doResetSearch() {
      this.searchFilters = {};
      this.page.current = 1;
      this.getData();
    },
    currentPageChange(p) {
      this.page.current = p;
      this.getData();
    },
    pageSizeChange(size) {
      this.page.size = size;
      this.getData();
    },
    indexMethod(idx) {
      return (this.page.current - 1) * this.page.size + (idx + 1);
    }
  },
  mounted() {
    this.getData();
  },
  created() {
    this.DSearchFn = debounce(() => this.doSearch());
    this.DResetSearchFn = debounce(() => this.doResetSearch());
  }
}

複製代碼

2-三、mixin中CRUD的cud部分(增刪改的數據和方法)cud.js

import * as formFn from "@/utils/formFn.js";
import { debounce } from "@/utils/util.js";
import MulSelect from "@/components/ZSelect/MulSelect.vue";

export default {
  components: { MulSelect },
  data() {
    return {
      dialogForm: {
        isEdit: false,
        isVisible: false,
        title: "",
        formData: {},
        formRule: {}
      },
      mulSels: [] //選中列,主要用於批量刪除
    };
  },
  watch: {
    'dialogForm.isVisible': {
      handler(newV) {
        if (newV === false) {
          this.$refs.myForm && this.$refs.myForm.resetFields();
        }
      }
    }
  },
  methods: {
    handleEdit(row, col, idx) {
      formFn.editFn.apply(this, [row]);
    },
    handleDel(row, col, idx) {
      formFn.delFn.apply(this, [row, this.url.delete]);
    },

    // 表單新增/編輯+表單重置 start
    debounceSubmit(formName) {
      this.DSubmitFn(formName);
    },
    doSubmitForm(formName) {
      /* 分別是「修改」和「新增」的url */
      let _url = this.dialogForm.isEdit ? this.url.update : this.url.create;
      formFn.submitFn.apply(this, [formName, _url, this.dialogForm.isEdit]);
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
    handleBeforeClose() {
      this.$refs["myForm"].resetFields();
      this.dialogForm.isVisible = false;
    },
    // 表單新增/編輯+表單重置 end

    // 批量選擇-刪除start
    handleSelectionChange(val) {
      this.mulSels = val;
    },
    handleMulDel() {
      if (this.url && this.url.mulDel) {
        formFn.mulDelFn.call(this, this.url.mulDel);
      } else {
        console.log('多選刪除失敗:獲取不到刪除地址');
      }

    },
    // 批量選擇-刪除end

    handleCreate() {
      formFn.createFn.apply(this);
    }
  },
  created() {
    this.DSubmitFn = debounce(v => this.doSubmitForm(v));
  }
}

複製代碼

2-四、改寫vue文件,example.vue

<template>
  <section class="table-wrap">
    <!-- 查詢 -->
    <div class="search">
      <el-form :inline="true" :model="searchFilters">
        <el-row>
          <el-col :span="5">
            <el-form-item label="客戶名">
              <el-input v-model="searchFilters.custName" placeholder="客戶名"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="城市">
              <el-input v-model="searchFilters.cityName" placeholder="城市"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="品牌">
              <el-input v-model="searchFilters.brandName" placeholder="品牌"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="上牌時間">
              <el-date-picker type="month" v-model="searchFilters.firstLicenseTime" placeholder="上牌時間" value-format="yyyy-MM-dd HH:mm:ss"></el-date-picker>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <span class="search">
              <el-button type="primary" @click.stop="dbnSearch">查詢</el-button>
            </span>
            <span class="reset">
              <el-button type="danger" @click.stop="dbnResetSearch">重置</el-button>
            </span>
          </el-col>
        </el-row>
      </el-form>
    </div>
    <!--列表-->
    <el-table :data="tableList" highlight-current-row style="width: 100%;" v-loading="tableListLoading" 
    :stripe="t.stripe" :border="t.border" :size="t.size" :max-height="t.maxHeight" @selection-change="handleSelectionChange">
      <el-table-column type="index" width="55" :index="indexMethod">
      </el-table-column>
      <el-table-column prop="custName" label="客戶名" width="140">
      </el-table-column>
      <el-table-column prop="carInfo.brandName" label="品牌" width="140">
      </el-table-column>
      <el-table-column prop="carInfo.seriesName" label="系列" width="140">
      </el-table-column>
      <el-table-column prop="carInfo.modelName" label="車型" width="480"> 
      </el-table-column>
      <el-table-column prop="carInfo.firstLicenseTime" label="上牌時間" width="180">
      </el-table-column>
      <el-table-column prop="cityName" label="城市" width="100">
      </el-table-column>
      <el-table-column prop="mortgageAmount" label="按揭欠款" width="100">
      </el-table-column>
      <el-table-column prop="estimatePrice" label="評估金額" width="100">
      </el-table-column>
      <el-table-column prop="canLoanAmount" label="可貸金額" width="100">
      </el-table-column>
      <el-table-column label="操做" fixed="right" width="90px">
        <template slot-scope="scope">
          <span class="edit">
            <el-button size="small" @click.stop="handleEdit(scope.row, scope.column, scope.$index)">查看</el-button>
          </span>
        </template>
      </el-table-column>
    </el-table>
    <!-- 表格底部操做/分頁 -->
    <div class="table-bottom-wrap">
      <div class="page-box">
        <z-page  @current-change="currentPageChange" :current-page="page.current" :total="page.total">
        </z-page>
      </div>
    </div>
    <!-- 新增-編輯 -->
    <el-dialog :title="dialogForm.title" custom-class="addDialog" :visible.sync="dialogForm.isVisible">
      <el-form :model="dialogForm.formData" :rules="dialogForm.formRule" ref="myForm" label-width="120px" label-position="right">
        <el-row>
          <el-col :span="12">
            <el-form-item label="客戶名" prop="custName">
              <el-input v-model="dialogForm.formData.custName" placeholder="客戶名" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="品牌" prop="brandName">
              <el-input v-model="dialogForm.formData.brandName" placeholder="品牌" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="系列" prop="seriesName">
              <el-input v-model="dialogForm.formData.seriesName" placeholder="系列" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="車型" prop="modelName">
              <el-input v-model="dialogForm.formData.modelName" placeholder="車型" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="上牌世間" prop="firstLicenseTime">
              <el-date-picker type="month" v-model="dialogForm.formData.firstLicenseTime" placeholder="上牌時間" :disabled="true"></el-date-picker>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="城市" prop="cityName">
              <el-input v-model="dialogForm.formData.cityName" placeholder="城市" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="按揭欠款" prop="mortgageAmount">
              <el-input v-model="dialogForm.formData.mortgageAmount" placeholder="按揭欠款" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="評估金額" prop="estimatePrice">
              <el-input v-model="dialogForm.formData.estimatePrice" placeholder="評估金額" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="可貸金額" prop="canLoanAmount">
              <el-input v-model="dialogForm.formData.canLoanAmount" placeholder="可貸金額" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="行程(萬千米)" prop="kilometers">
              <el-input v-model="dialogForm.formData.kilometers" placeholder="行程(萬千米)" :disabled="true"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click.stop="dialogForm.isVisible = false">取 消</el-button>
      </div>
    </el-dialog>
  </section>
</template>
<script>
import common from '@/mixins/common.js'
import cud from '@/mixins/cud.js'

export default {
  mixins: [common, cud],
  data() {
    return {
      url: {
        getData: '/carEvaluationService/listCarEstimate'
      }
    }
  }
}
</script>

複製代碼

能夠看到vue文件的邏輯部分被極大地簡化了。java

三、兩點說明

3-一、vue-mixin合併說明webpack

## mixin合併

數據對象合併【data(一層屬性深度淺合併)】:多個合併在一塊兒,有衝突的以組件數據優先;
鉤子函數合併【created、mounted等】:多個合在一塊兒,先調用mixin的再調用組件自己的;【混爲同一個數組,因此都被調用】
對象選項合併【methods、components、directives】:mixin的會被vm實例的對應項覆蓋。【混爲同一個對象,因此鍵有衝突時只選一個】

複製代碼

3-二、約定通用函數方法名和屬性名 例如:es6

url: {
  getData: "/custPhoneInfoService/list",
  update: "/custPhoneInfoService/update",
  delete: "/custPhoneInfoService/deleteById",
  create: "/custPhoneInfoService/create",
  mulDel: "/custPhoneInfoService/mulDelete" // 注意返回去的是id的數組['asb','sdf']
}
複製代碼

例如:web

doXXX     // ---- 頁面上實實在在觸發的函數(如點擊提交)
DXXX      // ---- 頁面上觸發後通過防抖處理的函數
handleXXX // ---- 列表編輯、翻頁操做
複製代碼
相關文章
相關標籤/搜索