1.index.vue(遍历菜单)
<!-- 遍历菜单 -->
<template v-for="item in user.menus">
<!-- 判断是否包含有children,如果有就是目录 -->
<!-- 此处遍历的是有目录 -->
<el-submenu :index="item.id" :key="item.id" v-if="item.children">
<template slot="title">
<i :class="item.icon"></i>
<span>{{item.title}}</span>
</template>
<el-menu-item v-for="i in item.children" :key="i.id" :index="'/'+i.url">{{i.title}}</el-menu-item>
</el-submenu>
<!-- 此处遍历的是只有菜单 -->
<el-menu-item v-else :key="item.id" :index="'/'+item.url">{{item.title}}</el-menu-item>
</template>
<script>
import {mapGetters,mapActions} from 'vuex'
export default {
computed:{
...mapGetters({
'user':'user'
})
},
methods:{
...mapActions({
"requestUser":"userActions"
}),
logout(){
// 1.清空用户信息
this.requestUser(null)
//2.跳转登录页
this.$router.push('/login')
}
}
}
</script>
2.请求头的设置
在请求拦截中设置
// 在请求拦截中设置请求头
axios.interceptors.request.use(config=>{
console.group('本次请求路径为:'+config.url)
if(config.url !== baseUrl+'/api/userlogin'){
// 需要设置请求头
config.headers.authorization = store.state.user.token
}
console.log(config);
return config
})
3.商品分类
cate.vue
<template>
<div>
<el-button type="success" @click="add">添加</el-button>
<!-- 添加子组件 -->
<v-add :info="info" ref="add"></v-add>
<!-- 列表子组件 -->
<v-list @edit="edit"></v-list>
</div>
</template>
<script>
import vAdd from './components/add.vue'
import vList from './components/list.vue'
export default {
data(){
return {
info:{
show:false,
title:'',
isAdd:true,
}
}
},
methods:{
add(){
this.info.show = true;
this.info.title = '添加商品分类';
this.info.isAdd = true;
},
edit(id){
this.info.show = true;
this.info.title = "编辑商品分类";
this.info.isAdd = false;
this.$refs.add.getDetail(id)
}
},
components:{
vAdd,
vList,
}
}
</script>
<style scoped>
.el-button{
margin-top:10px;
}
</style>
add.vue
<template>
<div>
<el-dialog :title="info.title" :visible.sync="info.show">
<el-form :model="form">
<el-form-item label="上级分类" :label-width="formLabelWidth">
<el-select v-model="form.pid" >
<el-option label="--请选择--" disabled value=""></el-option>
<el-option label="顶级分类" :value="0"></el-option>
<!-- 遍历分类列表 -->
<el-option v-for="item in cateList" :key="item.id" :label="item.catename" :value="item.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="分类名称" :label-width="formLabelWidth">
<el-input v-model="form.catename"></el-input>
</el-form-item>
<el-form-item label="图片" :label-width="formLabelWidth">
<!-- 自定义文件上传 -->
<div class="img-box">
<h3>+</h3>
<img v-if="imageUrl" :src="imageUrl" alt="">
<input type="file" @change="changeImg1">
</div>
<!-- 采用element-ui方式上传 -->
<!-- <el-upload
class="avatar-uploader"
action="#"
:show-file-list="false"
:on-change="changeImg"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar" >
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload> -->
</el-form-item>
<el-form-item label="分类状态" :label-width="formLabelWidth">
<el-switch
v-model="form.status"
active-color="blue"
inactive-color="grey" :active-value="1" :inactive-value="2">
</el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="confirm" v-if="info.isAdd"> 确 定</el-button>
<el-button type="primary" @click="update" v-else>修 改</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { addCate, oneCate, updateCate } from '../../../utils/request';
import { successAlert, warningAlert } from '../../../utils/alert';
import {mapGetters,mapActions} from 'vuex'
export default {
props:['info'],
data(){
return {
imageUrl:'',//要显示的图片地址
formLabelWidth:'120px',
form:{
pid:0,
catename:'',
img:'',
status:1, //1正常 2 禁用
}
}
},
computed:{
...mapGetters({
"cateList":"cate/cateList"
})
},
methods:{
...mapActions({
"requestCateList":"cate/cateListActions"
}),
changeImg1(e){
// 取出上传文件信息
var file = e.target.files[0];
// 处理文件大小
if(file.size > 2*1024*1024){
warningAlert("文件大小不能超过2M");
return;
}
// 处理文件后缀
var ext = ['.jpg','.png','.jpeg','.gif'];
var extName = file.name.slice(file.name.lastIndexOf('.'));
if(!ext.some(item=>item==extName)){
warningAlert('上传文件格式不正确')
return;
}
// 将图片显示在页面中
this.imageUrl = URL.createObjectURL(file);
this.form.img = file;
},
//改变图片时,获取图片路径及信息
changeImg(e){
// 1.处理文件大小
if(e.size > 2*1024*1024){
warningAlert('文件大小不能超过2M')
return
}
// 2.处理文件后缀
var ext = ['.jpg','.png','.jpeg','.gif'];
var extName = e.name.slice(e.name.lastIndexOf('.'));
if(!ext.some(item=>item==extName)){
warningAlert('上传文件格式不正确')
return
}
// 上传显示的文件
// 将文件生成url地址,并显示在页面中
this.imageUrl = URL.createObjectURL(e.raw)
// 将文件存放到form.img中
this.form.img = e.raw;
},
cancel(){
this.info.show = false;
this.form = {
pid:0,
catename:'',
img:'',
status:1, //1正常 2 禁用
};
this.imageUrl = '';
},
confirm(){
addCate(this.form).then(res=>{
successAlert(res.data.msg)
this.cancel()
this.requestCateList()
})
},
getDetail(id){
// 获取分类详情
oneCate({id}).then(res=>{
this.form = res.data.list;
this.form.id = id;
this.imageUrl = this.$preImg+this.form.img;
})
},
update(){
updateCate(this.form).then(res=>{
successAlert(res.data.msg)
this.cancel()
this.requestCateList()
})
}
},
mounted(){
this.requestCateList()
}
}
</script>
<style scoped>
.img-box{
width:150px;
height: 150px;
border:1px dashed green;
position: relative;
}
.img-box h3{
width:100%;
height: 100%;
text-align: center;
line-height: 150px;
}
.img-box img{
width:100%;
height: 100%;
position: absolute;
left:0;
top:0;
}
.img-box input{
width:100%;
height: 100%;
position: absolute;
left:0;
top:0;
opacity: 0;
}
.avatar-uploader >>> .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader >>> .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
request.js
// 修改商品分类
export const updateCate = (data)=>{
var form = new FormData()
for(let i in data){
form.append(i,data[i])
}
return axios({
method:'post',
url:baseUrl+'/api/cateedit',
data:form,
})
}
list.vue
<template>
<div>
<el-table
:data="cateData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
:tree-props="{ children: 'children'}"
>
<el-table-column prop="id" label="分类编号" >
</el-table-column>
<el-table-column prop="catename" label="分类名称" >
</el-table-column>
<el-table-column label="图片">
<template v-slot="prop">
<img :src="$preImg+prop.row.img" alt="">
</template>
</el-table-column>
<el-table-column prop="status" label="状态">
<template v-slot="prop">
<el-button type="primary" v-if="prop.row.status==1">启用</el-button>
<el-button type="danger" v-else>禁止</el-button>
</template>
</el-table-column>
<el-table-column prop="status" label="操作">
<template v-slot="prop">
<el-button type="primary" @click="edit(prop.row.id)">编辑</el-button>
<el-button type="danger" @click="del(prop.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import {mapGetters,mapActions} from 'vuex'
import {delCate} from '../../../utils/request'
import {successAlert} from '../../../utils/alert'
export default {
computed:{
...mapGetters({
"cateData":"cate/cateList"
})
},
methods:{
...mapActions({
"requestCateList":"cate/cateListActions"
}),
edit(id){
this.$emit("edit",id);
},
del(id){
this.$confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 发起删除分类请求
delCate({id}).then(res=>{
// 已经删除成功
successAlert(res.data.msg);
this.requestCateList()
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
},
mounted(){
this.requestCateList()
}
}
</script>
<style scoped>
img{
width:100px;
}
</style>
4.商品规格
spec.vue
<template>
<div>
<el-button type="success" @click="add">添加</el-button>
<v-add :info="info" ref="add"></v-add>
<v-list @edit="edit"></v-list>
</div>
</template>
<script>
import vAdd from './components/add.vue'
import vList from './components/list.vue'
export default {
data(){
return {
info:{
show:false,
title:'',
isAdd:true,
}
}
},
methods:{
add(){
this.info.show = true;
this.info.title = "添加规格属性";
this.info.isAdd = true;
},
edit(id){
this.info.show = true;
this.info.title = "编辑规格属性";
this.info.isAdd = false;
this.$refs.add.getDetail(id)
}
},
components:{
vAdd,
vList
}
}
</script>
<style scoped>
.el-button{
margin-top:10px;
}
</style>
add.vue
<template>
<div>
<el-dialog :title="info.title" :visible.sync="info.show">
<el-form :model="form">
<el-form-item label="规格名称" :label-width="formLabelWidth">
<el-input v-model="form.specsname"></el-input>
</el-form-item>
<el-form-item v-for="(item,index) in attrArr" :key="index" label="规格属性" :label-width="formLabelWidth">
<el-col :span="16">
<el-input v-model="item.value"></el-input>
</el-col>
<el-button type="primary" v-if="index==0" @click="addAttr">添加规格属性</el-button>
<el-button type="danger" v-else @click="delAttr(index)">删除</el-button>
</el-form-item>
<el-form-item label="规格状态" :label-width="formLabelWidth">
<el-switch
v-model="form.status"
active-color="blue"
inactive-color="grey" :active-value="1" :inactive-value="2">
</el-switch>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="confirm" v-if="info.isAdd"> 确 定</el-button>
<el-button type="primary" @click="update" v-else>修 改</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { warningAlert, successAlert } from '../../../utils/alert'
import { addSpec, oneSpec, updateSpec } from '../../../utils/request'
import {mapActions} from 'vuex'
export default {
props:['info'],
data(){
return {
formLabelWidth:'120px',
attrArr:[{value:''}],//规格属性值
form:{
specsname:'',
attrs:'',
status:1,
}
}
},
methods:{
...mapActions({
"requestCount":"spec/countActions",
"requestSpecList":"spec/specListActions",
}),
// 添加规格属性
addAttr(){
this.attrArr.push({value:''})
},
// 删除规格属性
delAttr(index){
this.attrArr.splice(index,1)
},
cancel(){
this.info.show = false;
this.form = {
specsname:'',
attrs:'',
status:1,
};
this.attrArr = [{value:''}];//规格属性值
},
confirm(){
// 处理规格属性
if(this.attrArr.some(item=>item.value === '')){
warningAlert("规格属性值不能为空");
return;
}
this.form.attrs = this.attrArr.map(item=>item.value).join(',');
addSpec(this.form).then(res=>{
successAlert(res.data.msg);
this.cancel()
this.requstCount()
this.requestSpecList()
})
},
getDetail(id){
oneSpec({id}).then(res=>{
this.form = res.data.list[0];
this.form.id = id;
var arr = this.form.attrs.split(',');
this.attrArr = [];
for(let i in arr){
this.attrArr.push({value:arr[i]});
}
})
},
update(){
// 处理规格属性
if(this.attrArr.some(item=>item.value === '')){
warningAlert("规格属性值不能为空");
return;
}
this.form.attrs = this.attrArr.map(item=>item.value).join(',');
updateSpec(this.form).then(res=>{
successAlert(res.data.msg)
this.cancel()
this.requestSpecList()
})
}
}
}
</script>
<style>
</style>
list.vue
<template>
<div>
<el-table
:data="specData"
style="width: 100%;margin-bottom: 20px;"
row-key="id"
border
:tree-props="{ children: 'children'}"
>
<el-table-column prop="id" label="规格编号" ></el-table-column>
<el-table-column prop="specsname" label="规格名称" ></el-table-column>
<el-table-column label="规格属性">
<template v-slot="prop">
<el-tag v-for="(item,index) in prop.row.attrs" :key="index" >{{item}}</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态">
<template v-slot="prop">
<el-button type="primary" v-if="prop.row.status==1">启用</el-button>
<el-button type="danger" v-else>禁止</el-button>
</template>
</el-table-column>
<el-table-column prop="status" label="操作">
<template v-slot="prop">
<el-button type="primary" @click="edit(prop.row.id)">编辑</el-button>
<el-button type="danger" @click="del(prop.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
background
layout="prev, pager, next"
:page-size="10"
@current-change="cPage"
:total="count">
</el-pagination>
</div>
</template>
<script>
import {mapGetters,mapActions} from 'vuex'
import {delSpec} from '../../../utils/request'
import {successAlert} from '../../../utils/alert'
export default {
computed:{
...mapGetters({
"specData":"spec/specList",
"count":"spec/count",
})
},
methods:{
...mapActions({
'requestSpecList':"spec/specListActions",
"requestCount":"spec/countActions",
"requestPage":"spec/pageActions",
}),
cPage(page){
this.requestPage(page)
this.requestSpecList()
},
edit(id){
this.$emit('edit',id)
},
del(id){
this.$confirm('确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 发起删除菜单请求
delSpec({id}).then(res=>{
// 已经删除成功
successAlert(res.data.msg);
this.requestCount()
this.requestSpecList()
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});
}
},
mounted(){
this.requestSpecList()
this.requestCount()
}
}
</script>
<style>
</style>
5.图表
- echarts
地址:https://echarts.apache.org/
1.下载
npm i echarts@4.9.0 --save
2.使用
<template>
<div>
<!-- 1.容器 -->
<div id="main"></div>
</div>
</template>
<script>
import echarts from 'echarts'
export default {
mounted(){
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'),'light');
// 指定图表的配置项和数据
var option = {
title: {
text: '产品月销量'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["电器","服装","厨具","家具","零食","电子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'line',
data: [200, 20000, 203, 230, 50000, 3000]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
}
}
</script>
<style scoped>
#main{
width:600px;
height: 400px;
margin:20px auto;
}
</style>
- highcharts
网址:https://www.highcharts.com.cn/docs/start-helloworld
1.下载
cnpm i highcharts --save
2.使用
<template>
<div>
<!-- 1.容器 -->
<div id="container" style="width: 600px;height:400px;margin:20px auto;"></div>
</div>
</template>
<script>
import Highcharts from 'highcharts/highstock';
export default {
mounted(){
var Highcharts = require('highcharts');
// 在 Highcharts 加载之后加载功能模块
require('highcharts/modules/exporting')(Highcharts);
// 图表配置
var options = {
chart: {
type: 'bar' //指定图表的类型,默认是折线图(line)
},
title: {
text: '我的第一个图表' // 标题
},
xAxis: {
categories: ['苹果', '香蕉', '橙子'] // x 轴分类
},
yAxis: {
title: {
text: '吃水果个数' // y 轴标题
}
},
series: [{ // 数据列
name: '小明', // 数据列名
data: [1, 0, 4] // 数据
}, {
name: '小红',
data: [5, 7, 3]
}]
};
// 图表初始化函数
var chart = Highcharts.chart('container', options);
}
}
</script>
<style scoped>
#main{
width:600px;
height: 400px;
margin:20px auto;
}
</style>