1、电商管理系统
本系统前端页面基于Vue和ElementUI,后端为node.js编写,主要应用于当下市场所流行的电商模式,通过科技的手段,使传统的商户交易模式变为更为高效率的电商交易模式,面向全国各地更多的客户。
2、项目演示
(1)登录页面
(2)主页
(3)用户管理
管理员可进入:实现模糊搜索、多条件分页、添加用户、编辑用户信息、删除、分配用户角色等功能。
(4)权限管理
分为1、角色列表;2、权限列表。
角色列表:可通过树状结构,查看、添加、修改、删除不同层级的权限可访问的菜单项。
权限列表:可查询上级菜单所对应的下级菜单。
(5)商品管理
分为:1、商品分类;2、商品列表;3、分类参数
商品分类:
可实现 查看、编辑不同层级的商品分类名称以及父子级关系。
商品列表:
可实现商品的多条件搜索分页,以及对具体商品的添加、修改和删除操作
本系统对于商品的添加进行了严格的校验和细致的划分。
对于商品的每一信息都进行了严格的校验,且未完成前一个步骤的情况下,无法直接跳过去进行下一个步骤的操作。
可上传商品的图片。
分类参数:负责查看、修改、删除商品分类的动态参数和静态属性
(6)订单管理
可实现查看订单的详情、修改订单付款状态、修改订单地址等功能。
(7)数据统计
通过可视化工具实现不同地区用户的来源数量。
3、源码
(1)登录页面
<template>
<div class="login_container">
<img src="../assets/img/bizhi2.png" style="width: 100%;height: 850px">
<!-- 登录盒子 -->
<div class="login_box">
<!-- 头像 -->
<div class="avatar_box">
<img src="../assets/img/沃尔玛.jpg" alt="">
</div>
<!-- 登录表单 -->
<el-form :model="loginForm" ref="LoginFormRef" :rules="loginFormRules" label-width="0px" class="login_form">
<!-- 用户名 -->
<el-form-item prop="username">
<el-input v-model="loginForm.username" prefix-icon="iconfont icon-user" ></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item prop="password">
<el-input type="password" v-model="loginForm.password" prefix-icon="iconfont icon-3702mima"></el-input>
</el-form-item>
<!-- 按钮 -->
<el-form-item class="btns">
<el-button type="primary" @click="login">登录</el-button>
<el-button type="info" @click="resetLoginForm">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
//数据绑定
loginForm: {
username: 'admin',
password: '123456'
},
//表单验证规则
loginFormRules: {
username: [
{ required: true, message: '请输入登录名', trigger: 'blur' },
{
min: 3,
max: 10,
message: '登录名长度在 3 到 10 个字符',
trigger: 'blur'
}
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{
min: 6,
max: 15,
message: '密码长度在 6 到 15 个字符',
trigger: 'blur'
}
]
}
}
},
//添加行为,
methods: {
//添加表单重置方法
resetLoginForm() {
//this=>当前组件对象,其中的属性$refs包含了设置的表单ref
console.log(this)
this.loginForm.username = '';
this.loginForm.password = '';
// this.$refs.LoginFormRef.resetFields()
},
login() {
//点击登录的时候先调用validate方法验证表单内容是否有误
this.$refs.LoginFormRef.validate(async valid => {
console.log(this.loginFormRules)
//如果valid参数为true则验证通过
if (!valid) {
return
}
//发送请求进行登录
const { data: res } = await this.$http.post('login', this.loginForm)
// console.log(res);
if (res.meta.status !== 200) {
return this.$message.error('登录失败:' + res.meta.msg) //console.log("登录失败:"+res.meta.msg)
}
this.$message.success('登录成功')
console.log(res)
//保存token
window.sessionStorage.setItem('token', res.data.token)
// 导航至/home
this.$router.push('/home')
})
}
}
}
</script>
<style lang="less" scoped>
.login_container {
background-color: #2b5b6b;
height: 100%;
}
.login_box {
width: 450px;
height: 300px;
background: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.avatar_box {
height: 130px;
width: 130px;
border: 1px solid #eee;
border-radius: 50%;
padding: 10px;
box-shadow: 0 0 10px #ddd;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eee;
}
}
}
.login_form {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
.btns {
display: flex;
justify-content: flex-end;
}
</style>
(2)主页
<template>
<el-container class="home-container" >
<!-- 头部区域 -->
<el-header >
<div>
<!-- logo -->
<!-- <a href="Home.vue"><img src="../assets/logo.png" alt=""></a>-->
<a href="/welcome"><img src="../assets/img/jdd.jpg" alt="" style="width: 200px;height: 20%;padding-left: 0" ></a>
<!-- 顶部标题 -->
<!-- <span>电商后台管理系统</span>-->
<img src="../assets/img/apple.jpg" style="width: 1350px">
</div>
<el-button type="info" @click="logout"> 退出 </el-button>
</el-header>
<!-- 页面主体区域 -->
<el-container>
<!-- 侧边栏 -->
<el-aside width="200px">
<!-- 侧边栏菜单 -->
<el-menu
background-color="#333744"
text-color="#fff"
active-text-color="#ffd04b" router
unique-opened
:default-active="activePath"
>
<!-- 一级菜单 -->
<el-submenu v-for="item in menuList" :key="item.id" :index="item.id+''">
<!-- 一级菜单模板 -->
<template slot="title">
<!-- 图标 -->
<i :class="item.psIcon"></i>
<!-- 文本 -->
<span>{{item.authName}}</span>
</template>
<!-- 二级子菜单 -->
<el-menu-item :index="'/'+subItem.path" v-for="subItem in item.children" :key="subItem.id">
<!-- 二级菜单模板 -->
<template slot="title">
<!-- 图标 -->
<i class="el-icon-location"></i>
<!-- 文本 -->
<span>{{subItem.authName}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- 主体结构 -->
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
data() {
return {
// 左侧菜单数据
menuList: null,
// 被激活的链接地址
activePath: ''
}
},
created() {
// 在created阶段请求左侧菜单数据
this.getMenuList()
this.activePath = window.sessionStorage.getItem('activePath')
},
methods: {
logout() {
window.sessionStorage.clear()
this.$router.push('/login')
},
async getMenuList() {
// 发送请求获取左侧菜单数据
const { data: res } = await this.$http.get('menus')
if (res.meta.status !== 200) return this.$message.error(res.meta.msg)
this.menuList = res.data
console.log(this.menuList)
}
}
}
</script>
<style lang="less" scoped>
.home-container {
height: 100%;
}
.el-header {
background-color: #373d41;
display: flex;
justify-content: space-between;
padding-left: 0;
align-items: center;
color: #fff;
font-size: 20px;
> div {
display: flex;
align-items: center;
span {
margin-left: 15px;
}
}
}
.el-aside {
background-color: #333744;
.el-menu {
border-right: none;
}
}
.el-main {
background-color: #eaedf1;
}
.iconfont {
margin-right: 10px;
}
.toggle-button {
background-color: #4a5064;
font-size: 10px;
line-height: 24px;
color: #fff;
text-align: center;
letter-spacing: 0.2em;
cursor: pointer;
}
</style>
<template>
<el-carousel :interval="4000" type="card" height="500px" >
<el-carousel-item v-for="item in urls" :key="item">
<img :src="item" >
</el-carousel-item>
</el-carousel>
</template>
<script>
export default {
data() {
return {
urls: [
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg',
'https://2oa-file.oss-cn-beijing.aliyuncs.com/t/2021-11-29/7954995fda494741af1e62d0f067ba68-car.jpg'
],
currentDate: new Date()
}
}
}
</script>
<style scoped>
.el-carousel__item h3 {
color: #475669;
font-size: 14px;
opacity: 0.75;
line-height: 200px;
margin: 0;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n+1) {
background-color: #d3dce6;
}
.time {
font-size: 13px;
color: #999;
}
.bottom {
margin-top: 13px;
line-height: 12px;
}
.button {
padding: 0;
float: right;
}
.image {
width: 100%;
display: block;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
</style>
(3)用户管理
<template>
<div>
<!-- 面包屑导航 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>用户管理</el-breadcrumb-item>
<el-breadcrumb-item>用户列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<!-- 搜索与添加区域 -->
<el-row :gutter="20">
<el-col :span="7">
<el-input placeholder="请输入内容" v-model="queryInfo.query" clearable @clear="getUserList">
<el-button slot="append" icon="el-icon-search" @click="serch"></el-button>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="add()">添加用户</el-button>
</el-col>
<el-dialog :title=title :visible.sync="dialogFormVisible">
<el-form :model="users" ref="LoginFormRef" :rules="loginFormRules">
<el-form-item label="用户名称" prop="username">
<el-input v-model="users.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="用户密码" prop="password" v-if="users.id == null">
<el-input v-model="users.password" autocomplete="off" v-if="users.id == null"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="users.email" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input v-model="users.mobile" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="update(users.id)">确 定</el-button>
</div>
</el-dialog>
</el-row>
</el-card>
<!-- 用户列表区域 -->
<el-table :data="userlist" border stripe>
<el-table-column type="index"></el-table-column>
<el-table-column label="姓名" prop="username"></el-table-column>
<el-table-column label="邮箱" prop="email"></el-table-column>
<el-table-column label="电话" prop="mobile"></el-table-column>
<el-table-column label="角色" prop="role_name"></el-table-column>
<el-table-column label="状态">
<template slot-scope="scope">
<el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" width="180px">
<template slot-scope="scope">
<!-- 修改按钮 -->
<el-button type="primary" icon="el-icon-edit" size="mini" @click="showEditDialog(scope.row.id)"></el-button>
<!-- 删除按钮 -->
<el-button type="danger" icon="el-icon-delete" size="mini" @click="removeUserById(scope.row.id)"></el-button>
<!-- 分配角色按钮 -->
<el-tooltip effect="dark" content="分配角色" placement="top" :enterable="false">
<el-button type="warning" icon="el-icon-setting" size="mini" @click="setRole(scope.row)"></el-button>
</el-tooltip>
<template>
<el-dialog :title="title" :visible.sync="duoxuan">
<el-select v-model="rid" autocomplete="off">
<el-option
v-for="role in rolelist"
:key="role.id"
:label="role.roleName"
:value="role.id">
</el-option>
</el-select>
<el-button type="primary" @click="setR(rid)">确 定</el-button>
</el-dialog>
</template>
</template>
</el-table-column>
</el-table>
<!-- 分页导航区域
@size-change(pagesize改变时触发)
@current-change(页码发生改变时触发)
:current-page(设置当前页码)
:page-size(设置每页的数据条数)
:total(设置总页数) -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[1, 2, 5, 10]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</template>
<script>
export default {
data () {
return {
// 获取查询用户信息的参数
title:'',
sea:false,
duoxuan:false,
users: {
id: '',
username: '',
password: '',
email: '',
mobile: ''
},
rid:'',
rolelist:[],
visible: false,
formLabelWidth: '120px',
dialogFormVisible: false,
form2:{
email:'',mobile:''
},
queryInfo: {
query: '',
pagenum: 1,
pagesize: 2
},
//表单验证规则
loginFormRules: {
username: [
{required: true, message: '请输入登录名', trigger: 'blur'},
{
min: 3,
max: 10,
message: '登录名长度在 3 到 10 个字符',
trigger: 'blur'
}
],
password: [
{required: true, message: '请输入密码', trigger: 'blur'},
{
min: 6,
max: 15,
message: '密码长度在 6 到 15 个字符',
trigger: 'blur'
}
],
email: [
// {required: true, message: '请输入邮箱', triggger: 'blur'},
{
pattern: /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
message: "正确的邮箱格式为xxx@xx.com",
trigger: 'blur'
}
],
mobile: [
// {required: true, message: "请输入手机号码", trigger: "blur"},
{
pattern: /^1[356789]\d{9}$/,
message: "请填写11位正确的手机号码",
trigger: "blur"
}]
},
// 保存请求回来的用户列表数据
userlist: [],
total: 0,
options: [{}],
value: ''
}
},
created () {
this.getUserList()
},
methods: {
serch(){
if (this.queryInfo.query.trim()!=""){
this.sea = true;
}
this.queryInfo.pagenum = 1;
this.getUserList();
},
async getUserList() {
const { data: res } = await this.$http.get('users', {
params: this.queryInfo
})
if (res.meta.status !== 200) {
return this.$message.error('获取用户列表失败!')
}
this.userlist = res.data.users
this.total = res.data.total
console.log(res)
},
async setRole(row){
this.duoxuan = true;
this.id = row.id;
this.rid = row.roleId;
const { data: res } = await this.$http.get('roles/')
if (res.meta.status !== 200) {
return this.$message.error('获取角色列表失败!')
}
this.rolelist = res.data;
},
setR(rid){
console.log("rid="+rid);
console.log("this.id="+this.id);
console.log("users/:"+this.id+"/"+rid);
this.$http.put("users/"+this.id+"/"+rid);
this.getUserList();
this.id = '';
this.duoxuan = false;
},
handleSizeChange(newSize) {
//pagesize改变时触发,当pagesize发生改变的时候,我们应该
//以最新的pagesize来请求数据并展示数据
// console.log(newSize)
// this.search?this.queryInfo.pagesize=1:this.queryInfo.pagesize = newSize;
this.queryInfo.pagesize = newSize;
//重新按照pagesize发送请求,请求最新的数据
this.getUserList();
},
handleCurrentChange( current ) {
//页码发生改变时触发当current发生改变的时候,我们应该
//以最新的current页码来请求数据并展示数据
// console.log(current)
if (!this.search){
this.queryInfo.pagenum = current;
}
//重新按照pagenum发送请求,请求最新的数据
this.getUserList();
},
async userStateChanged(row) {
//发送请求进行状态修改
const { data: res } = await this.$http.put(
`users/${row.id}/state/${row.mg_state}`
)
//如果返回状态为异常状态则报错并返回
if (res.meta.status !== 200) {
row.mg_state = !row.mg_state
return this.$message.error('修改状态失败')
}
this.$message.success('更新状态成功')
},
//添加
add() {
this.users = {};
this.title = "添加";
this.dialogFormVisible = true;
},
// 修改
async showEditDialog(id) {
//找出需要修改的数据的信息
const {data: res} = await this.$http.get("users/" + id);
if (res.meta.status !== 200) {
return this.$message.error('查询失败')
}
this.$message.success('查询成功');
this.users = res.data;
console.log(this.users);
this.title = "修改";
this.dialogFormVisible = true;
},
//添加/修改
async update(id) {
this.$refs.LoginFormRef.validate(async valid => {
console.log(this.loginFormRules);
//如果valid参数为true则验证通过
if (!valid) {
return
}
if (id != null) {
const {data: res} = await this.$http.put(`users/${id}`, this.users);
if (res.meta.status !== 200) {
return this.$message.error('修改失败')
}
this.$message.success('修改成功');
} else {
const {data: res} = await this.$http.post("users", this.users);
if (res.meta.status !== 201) {
return this.$message.error('添加失败')
} else {
this.$message.success('添加成功');
}
}
this.users = '';
this.dialogFormVisible = false;
this.getUserList()
})
},
removeUserById(id){
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http.delete("users/"+id).then(() => {
this.queryInfo.pagenum = this.userlist.length === 1 ? this.queryInfo.pagenum - 1 : this.queryInfo.pagenum;
this.queryInfo.pagenum = this.queryInfo.pagenum < 1 ? 1 : this.queryInfo.pagenum;
this.getUserList();
}),
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
//获取角色列表
}
}
</script>
<style scoped>
</style>
(4)权限管理
1、角色列表;
<template>
<div>
<!-- 面包屑导航区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>角色列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图 -->
<el-card>
<!-- 添加角色按钮区域 -->
<el-row>
<el-col>
<el-button type="primary" @click="res()">添加角色</el-button>
<el-dialog :visible.sync="dialogFormVisible">
<el-form :model="role1" >
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="role1.roleName" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="role1.roleDesc" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="insert()">确 定</el-button>
</div>
</el-dialog>
</el-col>
</el-row>
<!-- 角色列表区域 -->
<el-table :data="roleList" border stripe>
<!-- 展开列 -->
<el-table-column type="expand">
<template slot-scope="scope">
<el-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '', 'vcenter']" v-for="(item1, i1) in scope.row.children" :key="item1.id">
<!-- 渲染一级权限 -->
<el-col :span="5">
<el-tag closable >{{item1.authName}}</el-tag>
<i class="el-icon-caret-right" @close="removeRightById(scope.row, item1.id)"></i>
</el-col>
<!-- 渲染二级和三级权限 -->
<el-col :span="19">
<!-- 通过 for 循环 嵌套渲染二级权限 -->
<el-row :class="[i2 === 0 ? '' : 'bdtop', 'vcenter']" v-for="(item2, i2) in item1.children" :key="item2.id">
<el-col :span="6">
<el-tag type="success" closable>{{item2.authName}}</el-tag>
<i class="el-icon-caret-right" @close="removeRightById(scope.row, item2.id)"></i>
</el-col>
<el-col :span="18">
<el-tag closable type="warning" v-for="item3 in item2.children" :key="item3.id">{{item3.authName}}</el-tag>
<i class="el-icon-caret-right" @close="removeRightById(scope.row, item3.id)"></i>
</el-col>
</el-row>
</el-col>
</el-row>
</template>
</el-table-column>
<el-table-column label="角色名称" prop="roleName"></el-table-column>
<el-table-column label="角色描述" prop="roleDesc"></el-table-column>
<el-table-column label="操作" width="300px">
<template slot-scope="scope">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="selectById(scope.row.id)" >编辑</el-button>
<el-dialog :visible.sync="dialogFormVisible2">
<el-form :model="role" ref="LoginFormRef">
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="role.roleName" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="role.roleDesc" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible2 = false">取 消</el-button>
<el-button type="primary" @click="upda(scope.row.id)">确 定</el-button>
</div>
</el-dialog>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="delRole(scope.row.id)">删除</el-button>
<el-button size="mini" type="warning" icon="el-icon-setting" @click="showSetRightDialog(scope.row)">分配权限</el-button>
<!-- 分配权限对话框 -->
<el-dialog title="分配权限" :visible.sync="setRightDialogVisible" width="50%" @close="setRightDialogClose">
<!-- 树形组件
show-checkbox:显示复选框
node-key:设置选中节点对应的值
default-expand-all:是否默认展开所有节点
:default-checked-keys 设置默认选中项的数组
ref:设置引用 -->
<el-tree :data="rightsList" :props="treeProps" show-checkbox node-key="id" default-expand-all :default-checked-keys="defKeys" ref="treeRef"></el-tree>
<span slot="footer" class="dialog-footer">
<el-button @click="setRightDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="allotRights">确 定</el-button>
</span>
</el-dialog>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
// 角色列表数据
roleList: [],
// 控制分配权限对话框的显示
setRightDialogVisible: false,
// 权限树数据
rightsList: [],
// 树形控件的属性绑定对象
treeProps: {
// 通过label设置树形节点文本展示authName
label: 'authName',
// 设置通过children属性展示子节点信息
children: 'children'
},
// 设置树形控件中默认选中的内容
defKeys: [],
// 保存正在操作的角色id
roleId: '',
role1:{
roleName:'',roleDesc:''
},
role:{
id:'',roleName:'',roleDesc:''
},
dialogFormVisible:false,
dialogFormVisible2:false
}
},
created() {
this.getRoleList()
},
methods: {
async getRoleList() {
const { data: res } = await this.$http.get('roles')
// 如果返回状态为异常状态则报错并返回
if (res.meta.status !== 200) { return this.$message.error('获取角色列表失败') }
// 如果返回状态正常,将请求的数据保存在data中
// this.roleList = res.data
console.log(res.data)
this.roleList = res.data
},
async removeRightById(role, rightId) {
// 弹窗提示用户是否要删除
const confirmResult = await this.$messagebox.confirm(
'请问是否要删除该权限',
'删除提示',
{
confirmButtonText: '确认删除',
cancelButtonText: '取消',
type: 'warning'
}
).catch(err => err)
// 如果用户点击确认,则confirmResult 为'confirm'
// 如果用户点击取消, 则confirmResult获取的就是catch的错误消息'cancel'
if (confirmResult !== 'confirm') {
return this.$message.info('已经取消删除')
}
// 用户点击了确定表示真的要删除
// 当发送delete请求之后,返回的数据就是最新的角色权限信息
const { data: res } = await this.$http.delete(
`roles/${role.id}/rights/${rightId}`
)
if (res.meta.status !== 200) { return this.$message.error('删除角色权限失败') }
// 无需再重新加载所有权限
// 只需要对现有的角色权限进行更新即可
role.children = res.data
// this.getRoleList();
},
async showSetRightDialog(role) {
// 将role.id保存起来以供保存权限时使用
this.roleId = role.id
// 获取所有权限的数据
const { data: res } = await this.$http.get('rights/tree')
// 如果返回状态为异常状态则报错并返回
if (res.meta.status !== 200) return this.$message.error('获取权限树失败')
// 如果返回状态正常,将请求的数据保存在data中
this.rightsList = res.data
// 调用getLeafKeys进行递归,将三级权限添加到数组中
this.getLeafKeys(role, this.defKeys)
// 当点击分配权限按钮时,展示对应的对话框
this.setRightDialogVisible = true
console.log(this.defKeys)
},
getLeafKeys(node, arr) {
// 该函数会获取到当前角色的所有三级权限id并添加到defKeys中
// 如果当前节点不包含children属性,则表示node为三级权限
if (!node.children) {
return arr.push(node.id)
}
// 递归调用
node.children.forEach(item => this.getLeafKeys(item, arr))
},
setRightDialogClose() {
// 当用户关闭树形权限对话框的时候,清除掉所有选中状态
this.defKeys = []
},
async allotRights() {
// 当用户在树形权限对话框中点击确定,将用户选择的
// 权限发送请求进行更新
// 获取所有选中及半选的内容
const keys = [
...this.$refs.treeRef.getCheckedKeys(),
...this.$refs.treeRef.getHalfCheckedKeys()
]
// 将数组转换为 , 拼接的字符串
const idStr = keys.join(',')
// 发送请求完成更新
const { data: res } = await this.$http.post(
`roles/${this.roleId}/rights`,
{ rids: idStr }
)
if (res.meta.status !== 200) { return this.$message.error('分配权限失败') }
this.$message.success('分配权限成功')
this.getRoleList()
// 关闭对话框
this.setRightDialogVisible = false
},
res(){
this.role1 = {};
this.dialogFormVisible = true;
},
//新增
async insert(){
//新增
console.log("新增");
const {data: res} = await this.$http.post(`roles`, this.role1);
if (res.meta.status !== 201) {
return this.$message.error('添加失败')
} else {
this.$message.success('添加成功');
}
this.role1 = '';
this.dialogFormVisible = false;
this.getRoleList();
},
async selectById(id){
const {data: res} = await this.$http.get(`roles/`+id, this.role);
if (res.meta.status !== 200) {
return this.$message.error('查询失败')
}
this.$message.success('查询成功');
this.role.id = res.data.id;
this.role.roleName = res.data.roleName;
this.role.roleDesc = res.data.roleDesc;
console.log(this.role);
this.dialogFormVisible2 = true;
},
//修改
async upda(id){
console.log("id="+id);
const {data: res} = await this.$http.put(`roles/${id}`,this.role);
if (res.meta.status !== 200) {
return this.$message.error('修改失败')
} else {
this.$message.success('修改成功');
}
this.role = {};
this.dialogFormVisible2 = false;
this.getRoleList();
},
delRole(id){
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
console.log("id="+id);
this.$http.delete(`roles/${id}`).then(() => {
this.getRoleList();
})
}),this.$message({
type: 'success',
message: '删除成功!'
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
}
}
</script>
<style lang="less" scoped>
.el-tag {
margin: 7px;
}
.bdtop {
border-top: 1px solid #eee;
}
.bdbottom {
border-bottom: 1px solid #eee;
}
.vcenter {
display: flex;
align-items: center;
}
</style>
2、权限列表。
<template>
<div>
<!-- 面包屑导航区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>权限管理</el-breadcrumb-item>
<el-breadcrumb-item>权限列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图 -->
<el-card>
<!-- <tree-table :data="quanxianList" :columns="columns" :selection-type="false"-->
<!-- :expand-type="false" show-index index-text="#" :show-row-hover="false">-->
<!-- <template slot="level" scope="scope">-->
<!-- <el-tag type="primary" effect="plain" size="mini" v-if="scope.row.children!=null && scope.row.pid==0">一级</el-tag>-->
<!-- <el-tag type="success" effect="plain" size="mini" v-else-if="scope.row.children!=null && scope.row.pid!=0">二级</el-tag>-->
<!-- <el-tag type="warning" effect="plain" size="mini" v-else>三级</el-tag>-->
<!-- </template>-->
<!-- </tree-table>-->
<!-- 角色列表区域-->
<el-table :data="quanxianList" border stripe>
<!-- 展开列 -->
<el-table-column type="expand">
<!-- <el-table-column label="" prop="authName"></el-table-column>-->
<template slot-scope="scope">
<el-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '', 'vcenter']" v-for="(item1, i1) in scope.row.children" :key="item1.id">
<!-- 渲染一级权限 -->
<el-col :span="5">
<el-tag >{{item1.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<!-- 渲染二级和三级权限 -->
<el-col :span="19">
<!-- 通过 for 循环 嵌套渲染二级权限 -->
<el-row :class="[i2 === 0 ? '' : 'bdtop', 'vcenter']" v-for="(item2, i2) in item1.children" :key="item2.id">
<el-col :span="6">
<el-tag type="success" >{{item2.authName}}</el-tag>
<i class="el-icon-caret-right"></i>
</el-col>
<el-col :span="18">
<el-row :class="[i2 === 0 ? '' : 'bdtop', 'vcenter']" v-for="(item3, i2) in item1.children" :key="item3.id">
<el-tag type="warning">
{{item3.authName}}
</el-tag>
<i class="el-icon-caret-right"></i>
</el-row>
</el-col>
</el-row>
</el-col>
</el-row>
</template>
</el-table-column>
<!-- 角色列表区域 -->
<!-- 添加展开列 -->
<!-- <el-table-column label="权限ID" prop="id"></el-table-column>-->
<el-table-column label="权限说明" prop="authName"></el-table-column>
<el-table-column label="权限层级" prop="level"></el-table-column>
<el-table-column label="权限父ID" prop="pid"></el-table-column>
<el-table-column label="对应访问路径" prop="path"></el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
export default {
data () {
return {
// quanxianList: [],
quanxianList: {
// 通过label设置树形节点文本展示authName
label: 'authName',
// 设置通过children属性展示子节点信息
children: 'children'
},
menus:{
id:'',authName:'',path:'',children:''
}
}
},
created () {
this.getRoleList()
},
methods: {
async getRoleList () {
const { data: res } = await this.$http.get('rights/tree')
// 如果返回状态为异常状态则报错并返回
if (res.meta.status !== 200) {
return this.$message.error('获取角色列表失败')
}
console.log(res.data)
// 如果返回状态正常,将请求的数据保存在data中
this.quanxianList = res.data
},
async getLeftList () {
const { data: res } = await this.$http.get('menus')
// 如果返回状态为异常状态则报错并返回
if (res.meta.status !== 200) {
return this.$message.error('获取菜单列表失败')
}
console.log(res.data)
// 如果返回状态正常,将请求的数据保存在data中
this.menus = res.data
}
}
}
</script>
(5)商品管理
1、商品分类;
<template>
<div>
<!-- 面包屑导航 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>商品分类</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<!-- 添加分类按钮区域 -->
<el-row>
<el-col>
<el-button type="primary" @click="showAddCateDialog">添加分类</el-button>
</el-col>
</el-row>
<!-- 添加分类对话框 -->
<el-dialog title="添加分类" :visible.sync="addCateDialogVisible" width="50%" @close="addCateDialogClosed">
<!-- 添加分类表单 -->
<el-form :model="addCateForm" :rules="addCateFormRules" ref="addCateFormRef" label-width="100px">
<el-form-item label="分类名称" prop="cat_name">
<el-input v-model="addCateForm.cat_name"></el-input>
</el-form-item>
<el-form-item label="父级分类" prop="cat_pid" v-if="this.pid==''">
<!-- expandTrigger='hover'(鼠标悬停触发级联) v-model(设置级联菜单绑定数据) :options(指定级联菜单数据源) :props(用来配置数据显示的规则)
clearable(提供“X”号完成删除文本功能) change-on-select(是否可以选中任意一级的菜单) -->
<el-cascader expandTrigger='hover' v-model="selectedKeys" :options="parentCateList" :props="cascaderProps" @change="parentCateChange" clearable change-on-select></el-cascader>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="res">取 消</el-button>
<el-button type="primary" @click="addCate">确 定</el-button>
</span>
</el-dialog>
<!-- 分类表格 -->
<!-- 分类表格
:data(设置数据源) :columns(设置表格中列配置信息) :selection-type(是否有复选框)
:expand-type(是否展开数据) show-index(是否设置索引列) index-text(设置索引列头)
border(是否添加纵向边框) :show-row-hover(是否鼠标悬停高亮) -->
<tree-table :data="cateList" :columns="columns" :selection-type="false"
:expand-type="false" show-index index-text="#" border :show-row-hover="false">
<!-- 排序 -->
<template slot="order" slot-scope="scope">
<el-tag size="mini" v-if="scope.row.cat_level===0">一级</el-tag>
<el-tag size="mini" type="success" v-else-if="scope.row.cat_level===1">二级</el-tag>
<el-tag size="mini" type="warning" v-else>三级</el-tag>
</template>
<!-- 操作 -->
<template slot="opt" slot-scope="scope">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="bj(scope.row.cat_id)">编辑</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="del(scope.row.cat_id)">删除</el-button>
</template>
</tree-table>
<!-- 分页 -->
<!-- 分页 -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[3, 5, 10, 15]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
// 商品分类数据列表
cateList: [],
columns: [
{label:'分类名称',prop:'cat_name'},
{label:'排序',prop:'',type:'template',template:'order'},
{label:'操作',prop:'',type:'template',template:'opt'}
],
// 查询分类数据的条件
queryInfo: {
type: 3,
pagenum: 1,
pagesize: 5
},
pid:'',
// 保存总数据条数
total: 0,
//用来显示或隐藏添加分类对话框
addCateDialogVisible: false,
dialogFormVisible2: false,
//添加分类的表单数据对象
addCateForm:{
//分类名称
cat_name:'',
//添加分类的父级id,0则表示父级为0.添加一级分类
cat_pid:0,
//添加分类的等级,0则表示添加一级分类
cat_level:0
},
//保存1,2级父级分类的列表
parentCateList:[],
//添加分类校验规则
addCateFormRules:{
//验证规则
cat_name:[ {required:true , message:'请输入分类名称',trigger:'blur'} ]
},
//配置级联菜单中数据如何展示
cascaderProps:{
value:'cat_id',
label:'cat_name',
children:'children',
expandTrigger:'hover'
},
//绑定用户选择的分类值
selectedKeys:[]
}
},
created() {
this.getCateList()
},
methods: {
async getCateList() {
// 获取商品分类数据
const { data: res } = await this.$http.get('categories', {
params: this.queryInfo
})
if (res.meta.status !== 200) {
return this.$message.error('获取商品列表数据失败')
}
// 将数据列表赋值给cateList
this.cateList = res.data.result
// 保存总数据条数
this.total = res.data.total
// console.log(res.data);
},
handleSizeChange(newSize){
//当pagesize发生改变时触发
this.queryInfo.pagesize = newSize;
this.getCateList();
},
handleCurrentChange(newPage){
//当pagenum发生改变时触发
this.queryInfo.pagenum = newPage;
this.getCateList();
},
showAddCateDialog() {
//调用getParentCateList获取分类列表
this.getParentCateList()
//显示添加分类对话框
this.addCateDialogVisible = true;
},
res(){
this.addCateForm.cat_name = '';
this.addCateDialogVisible = false;
this.pid = '';
},
async getParentCateList(){
//获取父级分类数据列表
const { data: res } = await this.$http.get('categories', {
params: {type:2}
})
if (res.meta.status !== 200) {
return this.$message.error('获取商品分类列表数据失败')
}
this.parentCateList = res.data
},
parentCateChange(){
//级联菜单中选择项发生变化时触发
console.log(this.selectedKeys)
//如果用户选择了父级分类
if(this.selectedKeys.length > 0){
//则将数组中的最后一项设置为父级分类
this.addCateForm.cat_pid = this.selectedKeys[this.selectedKeys.length - 1]
//level也要跟着发生变化
this.addCateForm.cat_level = this.selectedKeys.length
return
}else{
this.addCateForm.cat_pid = 0
this.addCateForm.cat_level = 0
return
}
},
addCateDialogClosed(){
//当关闭添加分类对话框时,重置表单
//this.$refs.addCateFormRef.resetFields()
this.selectedKeys = [];
this.addCateForm.cat_pid = 0
this.addCateForm.cat_level = 0
},
async addCate() {
console.log('pid='+this.pid);
if (this.pid==''){
console.log('添加');
//点击确定,完成添加分类
console.log('cat_name='+this.addCateForm.cat_name)
console.log('cat_pid='+this.addCateForm.cat_pid)
this.$refs.addCateFormRef.validate(async valid => {
if (!valid) return
//发送请求完成添加分类
const {data: res} = await this.$http.post(
'categories',
this.addCateForm
)
if (res.meta.status !== 201) {
return this.$message.error('添加分类失败')
}
this.$message.success('添加分类成功')
this.getCateList()
this.addCateDialogVisible = false;
this.addCateForm = {};
});
}else {
//编辑
console.log('编辑');
const {data: res} = await this.$http.put('categories/'+this.pid, this.addCateForm);
if (res.meta.status !== 200) {
return this.$message.error('编辑分类失败')
}else {
this.$message.success('编辑分类成功')
}
this.getCateList();
this.addCateDialogVisible = false;
this.addCateForm = {};
this.pid = '';
}
},
async bj(id){
this.pid = id;
console.log("id="+id);
this.addCateDialogVisible= true;
const {data: res} = await this.$http.get('categories/'+this.pid);
this.addCateForm = res.data;
},
del(id){
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
console.log("id="+id);
this.$http.delete("categories/"+id).then(() => {
this.queryInfo.pagenum = this.cateList.length === 1 ? this.queryInfo.pagenum - 1 : this.queryInfo.pagenum;
this.queryInfo.pagenum = this.queryInfo.pagenum < 1 ? 1 : this.queryInfo.pagenum;
this.getCateList();
}),
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
}
}
</script>
<style scoped>
</style>
2、商品列表;
<template>
<div>
<!-- 面包屑导航 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>商品列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<!-- 搜索栏 -->
<el-row :gutter="20">
<el-col :span="8">
<el-input placeholder="请输入内容" v-model="queryInfo.query" clearable>
<el-button slot="append" icon="el-icon-search" @click="sea()"/>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="goAddPage">添加商品</el-button>
</el-col>
</el-row>
<!-- 表格区域 -->
<el-table :data="goodsList" border stripe>
<el-table-column type="index"/>
<el-table-column label="商品名称" prop="goods_name"/>
<el-table-column label="商品价格(元)" prop="goods_price" width="95px"/>
<el-table-column label="商品重量" prop="goods_weight" width="95px"/>
<el-table-column label="创建时间" prop="add_time" width="140px">
<template slot-scope="scope">
{{scope.row.add_time | dateFormat}}
</template>
</el-table-column>
<el-table-column label="操作" width="125px">
<template slot-scope="scope">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="update(scope.row.goods_id)"/>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="del(scope.row.goods_id)"/>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
:current-page="queryInfo.pagenum" :page-sizes="[3, 5, 10, 15]"
:page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<el-dialog title="修改商品" :visible.sync="dialogFormVisible" width="60%">
<el-scrollbar style="height: 400px">
<el-form :model="good" ref="updateGoodsForm">
<el-form-item label="商品名称" :label-width="formLabelWidth" prop="goods_name">
<el-input v-model="good.goods_name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="商品价格" :label-width="formLabelWidth" prop="goods_price">
<el-input v-model="good.goods_price" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="商品重量" :label-width="formLabelWidth" prop="goods_weight">
<el-input v-model="good.goods_weight" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="商品数量" :label-width="formLabelWidth" prop="goods_number">
<el-input v-model="good.goods_number" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="商品介绍" :label-width="formLabelWidth" prop="goods_introduce">
<quill-editor v-model="good.goods_introduce" autocomplete="off"></quill-editor>
</el-form-item>
</el-form>
</el-scrollbar>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="updateGood()">确 定</el-button>
</div>
</el-dialog>
</el-card>
</div>
</template>
<script>
export default {
name: "goods",
data() {
return {
dialogFormVisible: false,
formLabelWidth: '120px',
sear: false,
good: {
},
//查询参数
queryInfo: {
query: '',
pagenum: 1,
pagesize: 10
},
//保存商品列表信息
goodsList: [],
//总数据条数
total: 0,
}
},
created() {
this.getGoodsList()
},
methods: {
sea() {
if (this.queryInfo.query.trim() !== '') {
this.sear = true;
}
this.queryInfo.pagenum = 1;
this.getGoodsList();
},
async getGoodsList() {
// 根据分页获取对应的商品列表
const {data: res} = await this.$http.get('goods', {
params: this.queryInfo
});
if (res.meta.status !== 200) {
return this.$message.error('获取商品列表失败')
}
console.log(res.data);
this.$message.success('获取商品列表成功');
this.goodsList = res.data.goods;
this.total = res.data.total
},
handleSizeChange(newSize) {
//当页号发生改变时,更改pagesize,重新请求
this.queryInfo.pagesize = newSize;
this.getGoodsList();
},
handleCurrentChange(newPage) {
//当页码发生改变时,更改pagesize,重新请求
if (!this.sear) {
this.queryInfo.query = '';
}
this.queryInfo.pagenum = newPage;
this.getGoodsList();
},
goAddPage() {
this.$router.push('/goods/add')
},
async update(id) {
const {data: res} = await this.$http.get("goods/" + id);
if (res.meta.status !== 200) {
return this.$message.error('查询商品失败')
}
this.$message.success('查询商品成功');
this.good = res.data;
console.log(this.good);
this.dialogFormVisible = true;
},
async updateGood() {
const {data: res} = await this.$http.put(`goods/${this.good.goods_id}`, this.good);
console.log(res);
if (res.meta.status !== 200) {
return this.$message.error('修改商品失败')
}
this.$message.success('修改商品成功');
// 关闭对话框
this.dialogFormVisible = false;
this.getGoodsList()
},
async del(id) {
const {data: res} = await this.$http.delete(`goods/${id}`);
if (res.meta.status !== 200) {
return this.$message.error('删除商品失败')
}
this.$message.success('删除商品成功');
this.getGoodsList();
}
}
}
</script>
<style scoped>
</style>
添加商品
<template>
<div>
<h3>添加商品</h3>
<!-- 面包屑导航 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>添加商品</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<!-- 消息提示 -->
<el-alert title="添加商品信息" type="info" center show-icon :closable="false">
</el-alert>
<!-- 步骤条组件 -->
<!-- align-center(居中效果) -->
<el-steps :space="200" :active="activeIndex - 0" finish-status="success" align-center>
<el-step title="基本信息"></el-step>
<el-step title="商品参数"></el-step>
<el-step title="商品属性"></el-step>
<el-step title="商品图片"></el-step>
<el-step title="商品内容"></el-step>
<el-step title="完成"></el-step>
</el-steps>
<!-- tab栏区域:el-tab-pane必须是el-tabs的子节点
:tab-position="'left'"(设置tab栏为左右结构tab栏) -->
<!-- 表单:label-position="top"(设置label在文本框上方) -->
<el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px" label-position="top">
<el-tabs v-model="activeIndex" :tab-position="'left'" :before-leave="beforeTabLeave" @tab-click="tabClicked">
<el-tab-pane label="基本信息" name="0">
<el-form-item label="商品名称" prop="goods_name">
<el-input v-model="addForm.goods_name"></el-input>
</el-form-item>
<el-form-item label="商品价格" prop="goods_price">
<el-input v-model="addForm.goods_price" type="number"></el-input>
</el-form-item>
<el-form-item label="商品重量" prop="goods_weight">
<el-input v-model="addForm.goods_weight" type="number"></el-input>
</el-form-item>
<el-form-item label="商品数量" prop="goods_number">
<el-input v-model="addForm.goods_number" type="number"></el-input>
</el-form-item>
<el-form-item label="商品分类" prop="goods_cat">
<!-- 选择商品分类的级联选择框 -->
<el-cascader expandTrigger='hover' v-model="addForm.goods_cat" :options="cateList" :props="cateProps" @change="handleChange" clearable></el-cascader>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="商品参数" name="1">
<!-- 渲染表单item项 -->
<el-form-item :label="item.attr_name" :key="item.attr_id" v-for="item in manyTableData">
<!-- 使用数组渲染复选框组 -->
<el-checkbox-group v-model="item.attr_vals">
<el-checkbox border :label="val" v-for="(val,i) in item.attr_vals" :key="i"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="商品属性" name="2">
<!-- 循环生成静态属性 -->
<el-form-item :label="item.attr_name" v-for="item in onlyTableData" :key="item.attr_id">
<el-input v-model="item.attr_vals"></el-input>
</el-form-item>
</el-tab-pane>
<!-- //在页面中添加upload组件,并设置对应的事件和属性-->
<el-tab-pane label="商品图片" name="3">
<!-- 商品图片上传
action:指定图片上传api接口
:on-preview : 当点击图片时会触发该事件进行预览操作,处理图片预览
:on-remove : 当用户点击图片右上角的X号时触发执行
:on-success:当用户点击上传图片并成功上传时触发
list-type :设置预览图片的方式
:headers :设置上传图片的请求头 -->
<el-upload :action="uploadURL" :on-preview="handlePreview" :on-remove="handleRemove" :on-success="handleSuccess" list-type="picture" :headers="headerObj">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</el-tab-pane>
<!-- 富文本编辑器组件 -->
<el-tab-pane label="商品内容" name="4">
<!-- 富文本编辑器组件 -->
<quill-editor v-model="addForm.goods_introduce"></quill-editor>
<!-- 添加商品按钮 -->
<el-button type="primary" class="btnAdd" @click="add">添加商品</el-button>
</el-tab-pane>
</el-tabs>
</el-form>
</el-card>
<!-- //在el-card卡片视图下面添加对话框用来预览图片-->
<!-- 预览图片对话框 -->
<el-dialog title="图片预览" :visible.sync="previewVisible" width="50%">
<img :src="previewPath" class="previewImg" />
</el-dialog>
</div>
</template>
<script>
var _ = require('lodash');
export default {
data() {
return {
//保存步骤条激活项索引
activeIndex: '0',
//添加商品的表单数据对象
addForm: {
goods_name: '',
goods_price: 0,
goods_weight: 0,
goods_number: 0,
goods_cat: [],
//上传图片数组
pics: [],
//商品的详情介绍
goods_introduce:'',
attrs: []
},
//上传图片的url地址
uploadURL: 'http://127.0.0.1:8888/api/private/v1/upload',
//图片上传组件的headers请求头对象
headerObj: { Authorization: window.sessionStorage.getItem('token') },
//保存预览图片的url地址
previewPath: '',
//控制预览图片对话框的显示和隐藏
previewVisible:false,
//动态参数列表
manyTableData: [],
//静态属性列表
onlyTableData:[],
//验证规则
addFormRules: {
goods_name: [
{ required: true, message: '请输入商品名称', trigger: 'blur' }
],
goods_price: [
{ required: true, message: '请输入商品价格', trigger: 'blur' }
],
goods_weight: [
{ required: true, message: '请输入商品重量', trigger: 'blur' }
],
goods_number: [
{ required: true, message: '请输入商品数量', trigger: 'blur' }
],
goods_cat: [
{ required: true, message: '请选择商品分类', trigger: 'blur' }
]
},
//用来保存分类数据
cateList: [],
//配置级联菜单中数据如何展示
cateProps: {
value: 'cat_id',
label: 'cat_name',
children: 'children'
}
}
},
created() {
this.getCateList()
},
methods: {
async getCateList() {
const { data: res } = await this.$http.get('categories')
if (res.meta.status !== 200) {
return this.$message.error('获取商品分类数据失败')
}
this.cateList = res.data
},
handleChange(){
//如果用户选择的不是三级分类,该次选择无效,因为必须选择三级分类
if(this.addForm.goods_cat.length !== 3){
this.addForm.goods_cat = []
return
}
},
beforeTabLeave (activeName, oldActiveName) {
// 在tab栏切换之前触发,两个形参为切换前,后的tab栏name
if (oldActiveName === '0') {
// 在第一个标签页的时候
if (this.addForm.goods_cat.length !== 3) {
this.$message.error('请选择商品的分类')
return false
} else if (this.addForm.goods_name.trim() === '') {
this.$message.error('请输入商品名称')
return false
} else if (this.addForm.goods_price === '0') {
this.$message.error('请输入商品价格')
return false
} else if (this.addForm.goods_weight === '0') {
this.$message.error('请输入商品重量')
return false
} else if (this.addForm.goods_number === '0') {
this.$message.error('请输入商品数量')
return false
}
}
},
// 获取商品参数和属性
async tabClicked () {
if (this.addForm.goods_cat.length === 3) {
// 当用户点击切换tab栏时触发
if (this.activeIndex === '1') {
// 发送请求获取动态参数
const { data: res } = await this.$http.get('categories/' + this.addForm.goods_cat[2] + '/attributes',
{ params: { sel: 'many' } }
)
if (res.meta.status !== 200) {
return this.$message.error('获取动态参数列表失败')
}
// 将attr_vals字符串转换为数组
res.data.forEach(item => {
item.attr_vals =
item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ')
})
this.manyTableData = res.data
} else if (this.activeIndex === '2') {
// 发送请求获取静态属性
const { data: res } = await this.$http.get('categories/' + this.addForm.goods_cat[2] + '/attributes',
{ params: { sel: 'only' } }
)
if (res.meta.status !== 200) {
return this.$message.error('获取静态属性列表失败')
}
this.onlyTableData = res.data
}
}
},
handlePreview(file) {
//当用户点击图片进行预览时执行,处理图片预览
//形参file就是用户预览的那个文件
this.previewPath = file.response.data.url
//显示预览图片对话框
this.previewVisible = true
},
handleRemove(file) {
//当用户点击X号删除时执行
//形参file就是用户点击删除的文件
//获取用户点击删除的那个图片的临时路径
const filePath = file.response.data.tmp_path
//使用findIndex来查找符合条件的索引
const index = this.addForm.pics.findIndex(item => item.pic === filePath)
//移除索引对应的图片
this.addForm.pics.splice(index, 1)
},
handleSuccess(response) {
//当上传成功时触发执行
//形参response就是上传成功之后服务器返回的结果
//将服务器返回的临时路径保存到addForm表单的pics数组中
this.addForm.pics.push({ pic: response.data.tmp_path })
},
//编写点击事件完成商品添加
add(){
this.$refs.addFormRef.validate(async valid=>{
if(!valid) return this.$message.error("请填写必要的表单项!")
//将addForm进行深拷贝,避免goods_cat数组转换字符串之后导致级联选择器报错
const form = _.cloneDeep(this.addForm)
//将goods_cat从数组转换为"1,2,3"字符串形式
form.goods_cat = form.goods_cat.join(",")
//处理attrs数组,数组中需要包含商品的动态参数和静态属性
//将manyTableData(动态参数)处理添加到attrs
this.manyTableData.forEach(item=>{
form.attrs.push({ attr_id:item.attr_id, attr_value:item.attr_vals.join(" ") })
})
//将onlyTableData(静态属性)处理添加到attrs
this.onlyTableData.forEach(item=>{
form.attrs.push({ attr_id:item.attr_id, attr_value:item.attr_vals })
})
//发送请求完成商品的添加,商品名称必须是唯一的
const {data:res} = await this.$http.post('goods',form)
if(res.meta.status !== 201){
return this.$message.error('添加商品失败')
}
this.$message.success('添加商品成功')
//编程式导航跳转到商品列表
this.$router.push('/goods')
})
},
}
}
</script>
<style scoped>
.el-checkbox {
margin: 0 10px 0 0 !important;
}
.previewImg {
width: 100%;
}
.btnAdd {
margin-top: 15px;
}
.el-checkbox {
margin: 0 10px 0 0 !important;
}
.previewImg {
width: 100%;
}
.btnAdd {
margin-top: 15px;
}
</style>
3、分类参数
<template>
<div>
<!-- 面包屑导航 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>分类参数</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<!-- 警告区域 :closable="false"(是否展示“X”号) show-icon(显示图标) -->
<el-alert title="注意:只允许为第三级分类设置相关参数" type="warning" :closable="false" show-icon>
</el-alert>
<!-- 选择商品分类区域 -->
<el-row class="cat_opt">
<el-col>
<span>选择商品分类:</span>
<!-- 选择商品分类的级联选择框 -->
<el-cascader expandTrigger='hover' v-model="selectedCateKeys" :options="cateList" :props="cateProps" @change="handleChange" clearable></el-cascader>
</el-col>
<el-col>
<!-- tab页签区域 -->
<el-tabs v-model="activeName" @tab-click="handleTabClick">
<!-- 添加动态参数的面板 将标签页改为many -->
<el-tab-pane label="动态参数" name="many">
<el-button size="mini" type="primary" :disabled="isButtonDisabled" @click="add()">添加参数</el-button>
<!-- 添加分类对话框 -->
<el-dialog title="添加动态参数" :visible.sync="addCateDialogVisible" width="50%" @close="addCateDialogClosed">
<!-- 添加分类表单 -->
<el-form :model="param" label-width="100px">
<el-form-item label="参数名称" prop="attr_name">
<el-input v-model="param.attr_name"></el-input>
</el-form-item>
<el-form-item label="[only,many]" prop="attr_sel" v-show="false">
<el-input v-model="param.attr_sel">many</el-input>
</el-form-item>
<el-form-item label="参数详情" prop="attr_vals">
<el-input v-model="param.attr_vals"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="res">取 消</el-button>
<el-button type="primary" @click="addMany">确 定</el-button>
</span>
</el-dialog>
<!-- 动态参数表格 -->
<el-table :data="manyTableData" border stripe>
<!-- 展开行 -->
<el-table-column type="expand">
<template slot-scope="scope">
<!-- 循环渲染Tag标签 -->
<el-tag v-for="(item,i) in scope.row.attr_vals" :key="i" closable @close="handleClose(i,scope.row)">{{item}}</el-tag>
<!-- 输入的文本框 -->
<el-input class="input-new-tag" v-if="scope.row.inputVisible" v-model="scope.row.inputValue" ref="saveTagInput" size="small" @keyup.enter.native="handleInputConfirm(scope.row)" @blur="handleInputConfirm(scope.row)"></el-input>
<!-- 添加按钮 -->
<el-button v-else class="button-new-tag" size="small" @click="showInput(scope.row)">+ New Tag</el-button>
</template>
</el-table-column>
<!-- 索引列 -->
<el-table-column type="index"></el-table-column>
<el-table-column label="参数名称" prop="attr_name"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="bj(scope.row.attr_id)">编辑</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="del(scope.row.attr_id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<!-- 添加静态属性的面板 将标签页改为only -->
<el-tab-pane label="静态属性" name="only">
<el-button size="mini" type="primary" :disabled="isButtonDisabled" @click="oponly">添加属性</el-button>
<el-dialog title="添加静态属性" :visible.sync="addCateDialogVisible2" width="50%" @close="addCateDialogClosed">
<!-- 添加分类表单 -->
<el-form :model="param" label-width="100px">
<el-form-item label="参数名称" prop="attr_name">
<el-input v-model="param.attr_name"></el-input>
</el-form-item>
<el-form-item label="[only,many]" prop="attr_sel" v-show="false">
<el-input v-model="param.attr_sel" >only</el-input>
</el-form-item>
<el-form-item label="参数详情" prop="attr_vals">
<el-input v-model="param.attr_vals"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="res">取 消</el-button>
<el-button type="primary" @click="addonly">确 定</el-button>
</span>
</el-dialog>
<!-- 静态属性表格 -->
<el-table :data="onlyTableData" border stripe>
<!-- 索引列 -->
<el-table-column type="index"></el-table-column>
<el-table-column label="属性名称" prop="attr_name"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" type="primary" icon="el-icon-edit" @click="bj2(scope.row.attr_id)">编辑</el-button>
<el-button size="mini" type="danger" icon="el-icon-delete" @click="del(scope.row.attr_id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
addCateDialogVisible:false,
addCateDialogVisible2:false,
//分类列表
cateList: [],
//用户在级联下拉菜单中选中的分类id
selectedCateKeys: [],
//配置级联菜单中数据如何展示
cateProps: {
value: 'cat_id',
label: 'cat_name',
children: 'children'
},
pid:'',
param:{
attr_name:'',attr_sel:'',attr_vals:''
},
//tab页签激活显示的页签项
activeName: 'many',
//用来保存动态参数数据
manyTableData: [],
//用来保存静态属性数据
onlyTableData: []
}
},
created() {
this.getCateList()
},
methods: {
add(){
this.pid = '';
this.addCateDialogVisible = true;
},
oponly(){
this.pid = '';
this.addCateDialogVisible2 = true;
},
res(){
this.param = {};
this.addCateDialogVisible = false;
this.addCateDialogVisible2 = false;
this.pid = '';
},
async addMany(){
console.log("cateId="+this.cateId);
console.log("this.pid"+this.pid);
if (this.pid==''){
console.log("新增动态");
this.param.attr_sel = "many";
const { data: res } = await this.$http.post(`categories/${this.cateId}/attributes`,this.param);
if (res.meta.status !== 201) {
return this.$message.error('创建动态参数失败')
}
this.$message.success('创建动态参数成功');
}else {
console.log("编辑动态");
const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${this.pid}`,this.param);
if (res.meta.status !== 200) {
return this.$message.error('编辑动态参数失败')
}
this.$message.success('编辑动态参数成功');
}
this.handleChange();
this.param = {};
this.addCateDialogVisible = false;
},
async addonly(){
console.log("cateId="+this.cateId);
console.log("this.pid"+this.pid);
if (this.pid==''){
console.log("新增静态");
this.param.attr_sel = "only";
const { data: res } = await this.$http.post(`categories/${this.cateId}/attributes`,this.param);
if (res.meta.status !== 201) {
return this.$message.error('新增静态失败')
}
this.$message.success('新增静态成功');
}else {
console.log("编辑静态");
const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${this.pid}`,this.param);
if (res.meta.status !== 200) {
return this.$message.error('编辑静态参数失败')
}
this.$message.success('编辑静态参数成功');
}
this.handleChange();
this.param = {};
this.addCateDialogVisible2 = false;
},
async bj(id){
console.log("id="+id);
this.pid = id;
this.addCateDialogVisible = true;
const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes/${id}`);
this.param = res.data;
if (res.meta.status !== 200) {
return this.$message.error('查询分类失败')
}else {
this.$message.success('查询分类成功')
}
},
async bj2(id){
console.log("id="+id);
this.pid = id;
this.addCateDialogVisible2 = true;
const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes/${id}`);
this.param = res.data;
if (res.meta.status !== 200) {
return this.$message.error('查询分类失败')
}else {
this.$message.success('查询分类成功')
}
},
del(id){
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
console.log("id="+id);
console.log(`categories/${this.cateId}/attributes/${id}`)
this.$http.delete(`categories/${this.cateId}/attributes/${id}`).then(() => {
this.handleChange();
}),
this.$message({
type: 'success',
message: '删除成功!'
});
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
},
async getCateList(){
//获取所有的商品分类列表
const { data: res } = await this.$http.get('categories')
if (res.meta.status !== 200) {
return this.$message.error('获取分类数据失败')
}
//将数据列表赋值给cateList
this.cateList = res.data
// //保存总数据条数
// this.total = res.data.total
// console.log(res.data);
},
// 修改原handleChange方法
async handleChange() {
// 证明选中的不是三级分类
if (this.selectedCateKeys.length !== 3) {
this.selectedCateKeys = []
this.manyTableData = []
this.onlyTableData = []
return
}
// 证明选中的是三级分类
console.log(this.selectedCateKeys)
// 根据所选分类的Id,和当前所处的面板,获取对应的参数
const { data: res } = await this.$http.get(
`categories/${this.cateId}/attributes`,
{
params: { sel: this.activeName }
}
)
if (res.meta.status !== 200) {
return this.$message.error('获取参数列表失败!')
}
// 处理文本框中的值
res.data.forEach(item => {
item.attr_vals = item.attr_vals ? item.attr_vals.split(' ') : []
// 控制文本框的显示与隐藏
item.inputVisible = false
// 文本框中输入的值
item.inputValue = ''
})
console.log(res.data)
if (this.activeName === 'many') {
this.manyTableData = res.data
} else {
this.onlyTableData = res.data
}
},
handleTabClick() {
console.log(this.activeName)
this.handleChange()
},
// 展示输入框
showInput(row){
//用户点击添加按钮时触发
row.inputVisible = true
//$nextTick:在页面上元素被重新渲染之后,调用回调函数的代码
this.$nextTick.then(()=>{
//让文本框自动获得焦点
this.$refs.saveTagInput.$refs.input.focus()
})
},
handleInputConfirm(row){
//当用户在文本框中按下enter键或者焦点离开时都会触发执行
//判断用户在文本框中输入的内容是否合法
if(row.inputValue.trim().length===0){
row.inputValue = ''
row.inputVisible = false
return
}
// row.inputVisible = false
//如果用户输入了真实合法的数据,需要保存起来
row.attr_vals.push(row.inputValue.trim())
row.inputValue = ''
row.inputVisible = false
this.saveAttrVals(row)
},
handleClose(index,row){
//删除对应索引的参数可选项
row.attr_vals.splice(index,1)
//调用函数,完成保存可选项的操作
this.saveAttrVals(row)
},
async saveAttrVals(row){
//封装函数,完成保存可选项的操作
//发起请求,保存参数细项
const {data:res} = await this.$http.put(`categories/${this.cateId}/attributes/${row.attr_id}`,
{attr_name:row.attr_name,attr_sel:row.attr_sel,attr_vals:row.attr_vals.join(' ')})
if (res.meta.status !== 200) {
return this.$message.error('修改参数项失败')
}
this.$message.success('修改参数项成功')
}
},
computed: {
//添加计算属性用来获取按钮禁用与否
isButtonDisabled() {
return this.selectedCateKeys.length !== 3
},
//获取选中的三级分类id
cateId() {
if (this.selectedCateKeys.length === 3) {
return this.selectedCateKeys[this.selectedCateKeys.length - 1]
}
return null
},
}
}
</script>
(6)订单管理
<template>
<div>
<h3>订单列表</h3>
<!-- 面包屑导航 -->
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>订单管理</el-breadcrumb-item>
<el-breadcrumb-item>订单列表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<!-- 搜索栏 -->
<el-row :gutter="20">
<el-col :span="8">
<el-input placeholder="请输入内容" v-model="queryInfo.query" clearable>
<el-button slot="append" icon="el-icon-search" @click="getOrderList"></el-button>
</el-input>
</el-col>
</el-row>
<!-- 订单表格 -->
<el-table :data="orderList" border stripe>
<el-table-column type="index"></el-table-column>
<el-table-column label="订单编号" prop="order_number"></el-table-column>
<el-table-column label="订单价格" prop="order_price"></el-table-column>
<el-table-column label="是否付款" prop="pay_status">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.pay_status === '1'">已付款</el-tag>
<el-tag type="danger" v-else>未付款</el-tag>
</template>
</el-table-column>
<el-table-column label="是否发货" prop="is_send"></el-table-column>
<el-table-column label="下单时间" prop="create_time">
<template slot-scope="scope">
{{scope.row.create_time | dateFormat}}
</template>
</el-table-column>
<el-table-column label="操作" width="125px">
<template slot-scope="scope">
<!-- 给修改地址按钮添加点击事件 -->
<el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditAddress(scope.row.order_id)" ></el-button>
<!-- 给查看物流添加点击事件 -->
<el-button size="mini" type="success" icon="el-icon-location" @click="showProgress(scope.row.order_id)"></el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[3, 5, 10, 15]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</el-card>
<!-- 修改地址对话框 -->
<el-dialog title="修改收货地址" :visible.sync="addressVisible" width="50%" @close="addressDialogClosed">
<!-- 添加表单 -->
<el-form :model="addressForm" :rules="addressFormRules" ref="addressFormRef" label-width="100px">
<el-form-item label="省市区县" prop="address1">
<el-cascader :options="cityData" v-model="addressForm.address1"></el-cascader>
</el-form-item>
<el-form-item label="详细地址" prop="address2">
<el-input v-model="addressForm.address2"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addressVisible = false">取 消</el-button>
<el-button type="primary" @click="addressVisible = false">确 定</el-button>
</span>
</el-dialog>
<!-- 物流信息进度对话框 -->
<el-dialog title="物流进度" :visible.sync="progressVisible" width="50%">
<!-- 时间线组件 -->
<el-timeline>
<el-timeline-item v-for="(activity, index) in progressInfo"
:key="index" :timestamp="activity.time">
{{activity.context}}
</el-timeline-item>
</el-timeline>
</el-dialog>
</div>
</template>
<script>
import cityData from './citydata.js'
export default {
data() {
return {
//查询条件
queryInfo: {
query: '',
pagenum: 1,
pagesize: 10
},
//订单列表数据
orderList: [],
//数据总条数
total: 0,
//控制修改地址对话框的显示和隐藏
addressVisible:false,
//修改收货地址的表单
addressForm: {
address1: [],
address2: ''
},
//控制物流进度对话框的显示和隐藏
progressVisible: false,
//保存物流信息
progressInfo: [],
addressFormRules:{
address1:[{ required: true, message: '请选择省市区县', trigger: 'blur' }],
address2:[{ required: true, message: '请输入详细地址', trigger: 'blur' }],
},
//将导入的cityData数据保存起来
cityData:cityData
}
},
created() {
this.getOrderList()
},
methods: {
async getOrderList() {
console.log("query="+this.queryInfo.query)
const { data: res } = await this.$http.get('orders', {
params: this.queryInfo
})
if (res.meta.status !== 200) {
return this.$message.error('获取订单列表数据失败!')
}
this.total = res.data.total
this.orderList = res.data.goods
},
handleSizeChange(newSize){
this.queryInfo.pagesize = newSize
this.getOrderList()
},
handleCurrentChange(newPage){
this.queryInfo.pagenum = newPage
this.getOrderList()
},
async showEditAddress(id) {
//当用户点击修改收货地址按钮时触发
this.addressVisible = true;
console.log("id="+id);
const { data: res } = await this.$http.get('orders/'+id);
this.addressForm = res.data;
},
addressDialogClosed(){
this.$refs.addressFormRef.resetFields()
},
async showProgress(id) {
//发送请求获取物流数据
console.log(id)
const { data: res } = await this.$http.get('/kuaidi/'+id);
if (res.meta.status !== 200) {
return this.$message.error('获取物流进度失败!')
}
this.progressInfo = res.data
//显示对话框
this.progressVisible = true
},
}
}
</script>
<style lang="less" scoped>
.el-cascader{
width: 100%;
}
</style>
(7)数据统计
<template>
<div>
<!-- 面包屑导航区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>数据统计</el-breadcrumb-item>
<el-breadcrumb-item>数据报表</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<!-- 2. 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 750px;height:400px;"></div>
</el-card>
</div>
</template>
<script>
// 1. 导入 echarts
import echarts from 'echarts'
import _ from 'lodash'
export default {
data() {
return {
// 需要合并的数据
options: {
title: {
text: '用户来源'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#E9EEF3'
}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
boundaryGap: false
}
],
yAxis: [
{
type: 'value'
}
]
}
}
},
created() {},
// 此时,页面上的元素,已经被渲染完毕了!
async mounted() {
// 3. 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'))
const { data: res } = await this.$http.get('reports/type/1')
if (res.meta.status !== 200) {
return this.$message.error('获取折线图数据失败!')
}
// 4. 准备数据和配置项
const result = _.merge(res.data, this.options)
console.log("result="+result);
// 5. 展示数据
myChart.setOption(result)
},
methods: {}
}
</script>
<style lang="less" scoped>
</style>