1、vue全家桶开发后台管理系统
vue + vue-router + vuex + es6 + scss + webpack
2、vue的mixin使用
后台系统有很多页面都有类似的增删改查操作,使用mixin效果非常好,重复的劳动大大减少。
下面分4步来封装:
2-1、提取增删改查操作函数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-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-3、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-4、改写vue文件,example.vue
查询
重置
查看
复制代码
可以看到vue文件的逻辑部分被极大地简化了。
3、两点说明
3-1、vue-mixin合并说明
## mixin合并
数据对象合并【data(一层属性深度浅合并)】:多个合并在一起,有冲突的以组件数据优先;
钩子函数合并【created、mounted等】:多个合在一起,先调用mixin的再调用组件本身的;【混为同一个数组,所以都被调用】
对象选项合并【methods、components、directives】:mixin的会被vm实例的对应项覆盖。【混为同一个对象,所以键有冲突时只选一个】
复制代码
3-2、约定通用函数方法名和属性名 例如:
url: {
getData: "/custPhoneInfoService/list",
update: "/custPhoneInfoService/update",
delete: "/custPhoneInfoService/deleteById",
create: "/custPhoneInfoService/create",
mulDel: "/custPhoneInfoService/mulDelete" // 注意返回去的是id的数组['asb','sdf']
}
复制代码
例如:
doXXX // ---- 页面上实实在在触发的函数(如点击提交)
DXXX // ---- 页面上触发后经过防抖处理的函数
handleXXX // ---- 列表编辑、翻页操作
复制代码