项目初始化
1. vue-router
默认路由使用 redirect, 例如:
{ path: "/", name: "OrderManage", redirect: "/orderManage", }
在写 redirect 的时候,可以省略 component 配置,因为它从来没有被直接访问过,所以没有组件要渲染。唯一的例外是嵌套路由:如果一个路由记录有 children 和 redirect 属性,它也应该有 component 属性。
import Vue from 'vue'
import store from "../store";
import VueRouter from "vue-router";
Vue.use(VueRouter)
const routes = [
{
path: "/",
name: "Main",
component: () => import("../views/Main.vue"),
children: [
{
path: "/",
name: "OrderManage",
redirect: "/orderManage",
},
{
path: "/orderManage",
name: "OrderManage",
component: () => import("../views/OrderManage.vue"),
},
{
path: "/userManage",
name: "UserManage",
component: () => import("../views/UserManage.vue"),
},
{
path: "/administrate",
name: "Administrate",
component: () => import("../views/Administrate.vue"),
},
],
},
{
path: "/login",
name: "Login",
component: () => import("../views/Login.vue"),
},
];
const router = new VueRouter({
routes,
});
//登录拦截
router.beforeEach(function (to, from, next) {
let userInfo = store.state.admin;
if (userInfo) {
next();
} else {
if (to.path === "/login") {
next();
} else {
next({ path: "/login" });
}
}
});
export default router
2. mock
要注意mock的写法
import Mock from "mockjs";
Mock.mock(/\/orderList.*/, "get", {
pagination: {
pageno: 3, //当前页
pagesize: 20, // 当前页的大小
pages: 12, // 总共多少页 一般不用 total/size
total: 123, // 总条数
},
data: [
{
orderID: "1236",
type: "0",
express: "京东自营",
custom: "小明",
posterNumber: "2-2-1101",
address: "大学9号宿舍楼",
money: "3",
status: "0",
admin: { name: "@cname", id: "@id" },
createAt: "@date",
updateAt: "@date",
},
],
});
Mock.mock(/\/userList.*/, "get", {
pagination: {
pageno: 4, //当前页
pagesize: 20, // 当前页的大小
pages: 12, // 总共多少页 一般不用 total/size
total: 123, // 总条数
},
data: [
{
userID: "12456789",
name: "小明",
address: "大学9号宿舍楼",
createAt: "@date",
updateAt: "@date",
},
],
});
Mock.mock("/adminList", "get", {
pagination: {
pageno: 4, //当前页
pagesize: 20, // 当前页的大小
pages: 12, // 总共多少页 一般不用 total/size
total: 123, // 总条数
},
data: [
{
account: "admin",
password: "2133224",
},
{
account: "admin2",
password: "2133224",
},
{
account: "admin3",
password: "2133224",
},
{
account: "admin4",
password: "2133224",
},
],
});
Mock.mock("/login", "post", {
message: "登陆成功!",
success: true,
});
Mock.mock("/deleteOrder", "post", {
message: "删除成功!",
success: true,
});
Mock.mock("/deleteAdmin", "post", {
message: "删除成功!",
success: true,
});
Mock.mock(/\/admin.*/, "put", {
message: "更新成功",
success: true,
});
3. axios统一拦截配置
import axios from 'axios';
// 创建axios实例
const service = axios.create({
// baseURL: process.env.BASE_API, // api的base_url
timeout: 60000 // 请求超时时间,1分钟
});
// request拦截器
service.interceptors.request.use(
(config) => {
// Do something before request is sent
// if (store.getters.token) {
// config.headers['Authorization'] = getToken(); // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
// }
return config;
},
(error) => {
Promise.reject(error);
}
);
// respone拦截器
service.interceptors.response.use(
(response) => {
/**
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
* 如通过xmlhttprequest 状态码标识 逻辑可写在下面error中
*/
return Promise.resolve(response);
},
(error) => {
return Promise.reject(error);
}
);
export default service;
1. 登录页
有admin 和 普通用户的区别,通过账号区分,admin多一个管理员管理功能
将登录信息存储在vuex中
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
admin: ''
},
mutations: {
setAdmin(state, payload) {
state.admin = payload;
}
},
});
解决vuex页面刷新数据丢失问题,vuex的持久化,使用localstorage
export default new Vuex.Store({
state: {
admin: localStorage.getItem('admin') || ''
},
mutations: {
setAdmin(state, payload) {
state.admin = payload;
if (payload) {
localStorage.setItem('admin', payload);
} else {
localStorage.removeItem('admin');
}
}
},
});
使用computed 和 v-if 来判断账号是否是admin管理员账号
<el-menu-item v-if="isAdmin" index="/administrate">
<template slot="title">
<i class="el-icon-connection"></i>
<span>管理员管理</span>
</template>
</el-menu-item>
computed: {
isAdmin() {
return this.$store.state.admin === 'admin';
}
},
2. orderManage 用户订单管理页
将快递类型和订单状态单独写为一个类:
const posterType = {
0: "京东自营",
1: "申通",
2: "圆通",
3: "顺丰",
4: "邮政",
5: "菜⻦裹裹",
};
const orderStatus = {
0: "未支付",
1: "已支付",
2: "已取件",
3: "已配送",
4: "已取消",
};
将axios请求接口方法进行封装
/**
* 请求数据
*/
getOrderList() {
let obj = {};
Object.keys(this.form).forEach(item => {
if (this.form[item] !== '') {
obj[item] = this.form[item];
}
})
this.loading = true;
this.$axios.get("/orderList", {
params: obj
})
.then((res) => {
this.orderList = res.data.data.map((item) => {
item.type = posterType[item.type];
return item;
});
this.orderList = res.data.data.map((item) => {
item.status = orderStatus[item.status];
return item;
});
this.pagination = res.data.pagination;
})
.catch((err) => {
console.log(err);
}).finally(e=> {
setTimeout(e => {
this.loading = false;
}, 1000);
});
},
要注意:无论是分页还是删除,都需要使用接口请求,而不是只在页面进行分页和删除
//处理表格的index
indexMethod(index){
return (this.pagination.pageno - 1) * this.pagination.pagesize + index + 1
},
//分页
handleSizeChange(val) {
this.form.pagesize = val;
this.getOrderList();
console.log(`每页 ${val} 条`);
},
handleCurrentChange(val) {
this.form.pageno = val;
this.getOrderList();
console.log(`当前页: ${val}`);
},
//删除功能
handleDelete(index, row) {
this.$confirm(`确认是否删除订单号为${row.orderID}的记录?`, "删除", {
confirmButtonText: "确定",
}).then(() => {
this.$axios.post("/deleteOrder", {
orderID: row.orderID,
})
.then((res) => {
if (res && res.data.success) {
this.$message.success("删除成功");
this.orderList.splice(index, 1);
this.getOrderList();
} else {
this.$message.error("删除失败");
}
});
});
}
userManage 用户管理页
与订单管理页大同小异(序号、分页),不需要考虑订单状态和快递类型
将axios请求接口方法进行封装
/**
* 请求数据
*/
getUserList() {
let obj = {};
Object.keys(this.form).forEach((item) => {
if (this.form[item] !== "") {
obj[item] = this.form[item];
}
});
this.loading = true;
this.$axios
.get("/userList", {
params: obj,
})
.then((res) => {
this.userList = res.data.data
this.pagination = res.data.pagination;
})
.catch((err) => {
console.log(err);
})
.finally((e) => {
setTimeout((e) => {
this.loading = false;
}, 1000);
});
},
表格的序号、分页功能
/**
* 处理表格的index
*/
indexMethod(index) {
return (
(this.pagination.pageno - 1) * this.pagination.pagesize + index + 1
);
},
// 分页
handleSizeChange(val) {
this.form.pagesize = val;
this.getUserList();
},
handleCurrentChange(val) {
this.form.pageno = val;
this.getUserList();
},
administrate 管理员管理页
将axios请求接口方法
mounted() {
this.$axios
.get("/adminList")
.then((res) => {
this.adminList = res.data.data;
this.pagination = res.data.pagination;
})
.catch((err) => {
console.log(err);
});
}
列表的序号、分页
//序号
indexMethod(index) {
return (
(this.pagination.pageno - 1) * this.pagination.pagesize + index + 1
);
},
//分页
handleSizeChange(val) {
this.pagination.pagesize = val;
},
handleCurrentChange(val) {
this.pagination.currentPage = val;
},
需要注意的点
密码修改
/**
* 弹出修改密码的对话框
*/
handleEdit(index, row) {
console.log(index, row);
this.dialogFormVisible = true
this.dialogForm.account = row.account
},
//对话框的密码编辑
editPassword(){
if (this.dialogForm.password !== this.dialogForm.confirmPassword) {
this.$message.warning('两次输入的密码不一致!');
return;
}
this.$axios.put(`/admin/${this.dialogForm.account}`, {
password: this.dialogForm.password
}).then(res => {
if (res.data.success) {
this.$message.success('修改成功');
let index = this.adminList.findIndex(item => item.account === this.dialogForm.account);
this.adminList[index].password = this.dialogForm.password;
} else {
this.$message.success('修改失败');
}
}).finally(e => {
this.dialogFormVisible = false;
})
},
删除功能
handleDelete(index, row) {
this.$confirm(`确认是否删除账号为${row.account}的记录?`, "删除", {
confirmButtonText: "确定",
}).then(() => {
let res = this.adminList.splice(index, 1);
let msg = "删除成功";
if (!res) {
msg = "删除失败";
}
this.$message({
type: "info",
message: msg,
});
});
},
main.js的配置
import './sass/reset.scss'
import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from "./store";
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";
import "../mock/index.js";
import axios from "axios";
Vue.use(ElementUI);
Vue.config.productionTip = false;
Vue.prototype.$axios = axios;
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
element UI需要关注的点
// Form 表单
model | 表单数据对象 | object
inline | 行内表单模式 | boolean
disabled | 是否禁用该表单内的所有组件。若设置为 true,则表单内组件上的 disabled 属性不再生效 | boolean
prop | 表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的 | string
label | 标签文本 | string
required | 是否必填,如不设置,则会根据校验规则自动生成 | boolean
// Table 表格
data | 显示的数据 | array
type | 对应列的类型。如果设置了 `selection` 则显示多选框;如果设置了 `index` 则显示该行的索引(从 1 开始计算);如果设置了 `expand` 则显示为一个可展开的按钮 | string
index | 如果设置了 `type=index`,可以通过传递 `index` 属性来自定义索引 | number, Function(index)
prop | 对应列内容的字段名,也可以使用 property 属性 | string