后台项目的总结
路由方向的:
1.路由跳转
1 this.$router.push({ 2 name: "OrderRefundDetails", 3 params: { id: row.refundId } 4 });
2.路由返回时需要重新拉去列表的数据(如果页面销毁,返回时没数据的)
1 watch: { 2 $route: 'onRouteChange' 3 }, 4 methods: 5 onRouteChange(to) { 6 if (to.name === 'OrderRefundDetails') { 7 this.getServicelist(); 8 } 9 }, 10 OrderRefundDetails 是本页面的name
3.返回和销毁页面
1 this.$router.go(-1); 2 this.$store.dispatch("delView", this.$route);
// 这里涉及到了状态管理器,所以用的时候注意搞清原理而不是照搬
4.关于和后台对接时候api规范问题
1 export function exportRefundOrder(params) { 2 return request({ 3 url: apiPre + '/expert/order/pmrefund/exportByRefundId', 4 method: 'get', 5 params, 6 }); 7 } 8 get请求放在请求头----params,network顶部 9 10 export function exportRefundOrderAll(data) { 11 return request({ 12 url: apiPre + '/expert/order/pmrefund/exportAll', 13 method: 'post', 14 data, 15 }); 16 } 17 post 请求放在请求体,也就是network底部 18 19 delete,put(修改)请求和post一致 20 21 如果后台是resful风格:比如说批量操作数据的时候。 22 export function delmanagementList(params) { 23 return request({ 24 url: `/expert/inf/infcrawler/infcrawler/${params.newStr}`, 25 method: 'delete', 26 }); 27 }
5.router-link
1 <router-link 2 v-if="scope.row.refendStatus > 0" 3 :to="{ name: 'OrderRefundDetails', params: { id: scope.row.refendId } }" 4 style="margin-right: 10px;" 5 > 6 <el-button plain type="primary">详情</el-button> 7 </router-link>
后台页面难点的方向
1.二级联动
1 <el-col :span="3"> 2 <el-select v-model="valueType" placeholder="请选择咨询类别" @change="changeHandler"> 3 <el-option 4 v-for="item in optiontype" 5 :key="item.valueType" 6 :label="item.label" 7 :value="item.valueType" 8 ></el-option> 9 </el-select> 10 </el-col> 11 12 13 changeHandler(id) { 14 // 二级联动-顶部 15 console.log(id, "二级联动-顶部"); 16 this.valueScond = ""; 17 getChildtype({ id }).then(response => { 18 console.log("3333333", response); 19 this.optionsecond = response.result.map(item => { 20 return { 21 valueScond: item.id, 22 label: item.name 23 }; 24 }); 25 }); 26 }, 27 28 把后台返回的数据去匹配下拉列表然后利用一级类目的id去请求二级类目的数据最后匹配到二级类目
2.同样利用对象的属性去给对象添加属性,从而不改变列表的数据
1 getList() { 2 // 列表数据 3 const loop = list => { 4 list.map(val => { 5 if (val.status === -1) { 6 val.$status = "已下架"; 7 } else if (val.status === 0) { 8 val.$status = "未发布"; 9 } else { 10 val.$status = "已上架"; 11 } 12 if (val.subInfCategoryVOList) { 13 loop(val.subInfCategoryVOList); 14 } 15 return val; 16 }); 17 }; 18 getCategoryList().then(response => { 19 console.log("列表信息", response.result); 20 loop(response.result); 21 // response.result.forEach(val => { 22 // if (val.status === '-1') { 23 // val.$status = "已下架"; 24 // } else if (val.status === '0') { 25 // val.$status = "未发布"; 26 // } else { 27 // val.$status = "已上架"; 28 // } 29 // if (val.subInfCategoryVOList) { 30 // val.subInfCategoryVOList.forEach(item => { 31 // if (item.status === '-1') { 32 // (item.$status = "已下架"); 33 // } else if (item.$status === '0') { 34 // (item.$status = "未发布"); 35 // } else { 36 // (item.$status = "已上架"); 37 // } 38 // }); 39 // } 40 // }); 41 this.data = response.result; 42 }); 43 },
这里有个递归,吧多级数组对象的数组数据来渲染到列表中,好好领会。
3.三级联动
1 <el-form :inline="true" :model="formSearch" class="flex-center"> 2 <el-form-item label style="width:150px;"> 3 <el-select 4 v-model="selectedCategoryMenu" 5 placeholder="课程一级类目" 6 @change="(val) => { onSelectedCategory(val, 1) }" 7 > 8 <el-option 9 v-for="(item,index) in categoryMenuData" 10 :key="item.id" 11 :label="item.name" 12 :value="item.id" 13 ></el-option> 14 </el-select> 15 </el-form-item> 16 <el-form-item label style="width:150px;"> 17 <el-select 18 v-model="selectedCategoryMenu2" 19 placeholder="课程二级类目" 20 @change="(val) => { onSelectedCategory(val, 2) }" 21 > 22 <el-option 23 v-for="(item,index) in categoryMenuData2" 24 :key="item.id" 25 :label="item.name" 26 :value="item.id" 27 ></el-option> 28 </el-select> 29 </el-form-item> 30 <el-form-item label style="width:150px;"> 31 <el-select 32 v-model="selectedCategoryMenu3" 33 placeholder="课程三级类目" 34 @change="(val) => { onSelectedCategory(val, 3) }" 35 > 36 <el-option 37 v-for="(item, index) in categoryMenuData3" 38 :key="item.id" 39 :label="item.name" 40 :value="item.id" 41 ></el-option> 42 </el-select> 43 </el-form-item> 44 <el-form-item class="magin-left"> 45 <el-input 46 :remote-method="remoteMethod" 47 :loading="loading" 48 v-model="getDialogData.goodsCategoryName" 49 multiple 50 filterable 51 remote 52 reserve-keyword 53 placeholder="商品名称" 54 style="width:200px;" 55 ></el-input> 56 </el-form-item> 57 <el-form-item class="magin-left"> 58 <el-button icon="el-icon-search" @click="onSubmit">搜索</el-button> 59 </el-form-item> 60 </el-form> 61 62 63 methods: 64 65 // 弹窗 => 选择类目 66 onSelectedCategory(id, level) { 67 if (level === 1) { 68 this.selectedCategoryMenu = id; 69 console.log("类目一", this.selectedCategoryMenu); 70 // 第一个select框数据有子级则附到一级后面 71 this.categoryMenuData.some(item => { 72 // 从一级里面拿到二级 73 if (item.id === id) { 74 this.categoryMenuData2 = item.childList; 75 return true; 76 } 77 return false; 78 }); 79 // 清空三级 80 this.categoryMenuData3 = []; 81 } else if (level === 2) { 82 this.selectedCategoryMenu2 = id; 83 console.log("类目二", this.selectedCategoryMenu2); 84 this.categoryMenuData2.some(item => { 85 // 从二级里面拿到三级 86 if (item.id === id) { 87 this.categoryMenuData3 = item.childList; 88 return true; 89 } 90 return false; 91 }); 92 } else if (level === 3) { 93 this.selectedCategoryMenu3 = id; 94 console.log("类目三", this.selectedCategoryMenu3); 95 } 96 },
4.组件的封装
1 <template> 2 <el-upload 3 ref="single-upload" 4 :action="uploadConf.action" 5 :multiple="false" 6 :headers="uploadConf.headers" 7 :data="uploadConf.data" 8 :before-upload="onBeforeUpload" 9 :on-progress="onProgress" 10 :on-success="onSuccess" 11 :show-file-list="false" 12 > 13 <slot></slot> 14 </el-upload> 15 </template> 16 17 <script> 18 import getUploadSign from "@/api"; 19 import nanoid from "nanoid"; 20 21 // 随机文件名 22 export default { 23 name: "CSingleUpload", 24 components: {}, 25 props: { 26 accept: { 27 type: Array, 28 default: () => ["image/jpeg", "image/jpg", "image/png"] 29 }, 30 maxFileSize: { 31 type: Number, 32 default: 0.3 33 }, 34 files: { 35 type: Array, 36 default: () => [] 37 } 38 }, 39 data() { 40 return { 41 fileList: [], 42 uploadConf: { 43 action: "", 44 headers: {}, 45 data: {}, 46 fileList: [] 47 }, 48 fileObj: null, 49 }; 50 }, 51 methods: { 52 // 上传前拦截 53 async onBeforeUpload(file) { 54 const { size, type, name, uid } = file; 55 const oldName = name; 56 const fileName = 57 nanoid(28) + 58 oldName 59 .substring(oldName.lastIndexOf("."), oldName.length) 60 .toLowerCase(); 61 62 // 判断文件类型 63 const isFileType = this.accept.some(accept => accept === type); 64 if (!isFileType) { 65 this.$message.warning(`该文件(${oldName})类型(${type})不支持`); 66 return Promise.reject(); 67 } 68 69 // 判断文件大小 70 const KB = size / 1024; 71 const MB = KB / 1000; 72 if (MB > this.maxFileSize) { 73 let unit = `${this.maxFileSize}m`; 74 if (this.maxFileSize < 1) { 75 unit = `${Math.floor(this.maxFileSize * 1000)}kb`; 76 } 77 this.$message.warning(`该文件(${oldName})大小已超过限制(${unit})`); 78 return Promise.reject(); 79 } 80 81 // 请求签名 82 const sign = await getUploadSign({ dir: type.split('/')[0], key: fileName }); 83 84 // 显示上传对象 85 this.fileObj = { 86 type, 87 size, 88 uid, 89 oldName, 90 name: fileName, 91 url: (window.URL || window.webkitURL).createObjectURL(file), 92 ossUrl: `${sign.host}/${sign.dir}${fileName}`, 93 progress: 0, 94 isUpload: false 95 }; 96 97 // 填充签名参数 98 this.uploadConf.data = { 99 key: `${sign.dir}${fileName}`, 100 policy: sign.policy, 101 OSSAccessKeyId: sign.accessid, 102 success_action_status: 200, 103 signature: sign.signature, 104 callback: sign.callback, 105 }; 106 this.uploadConf.action = sign.host; 107 this.uploadConf.headers = { 108 "Access-Control-Allow-Origin": "*", 109 "Access-Control-Allow-Methods": "GET, POST" 110 }; 111 // return Promise.reject(); 112 }, 113 114 // 更新文件上传进度 115 onProgress(event) { 116 const { percent } = event; 117 this.$emit("on-progress", percent); 118 }, 119 120 // 更新文件上传成功状态 121 onSuccess(response, file) { 122 this.$emit('successCBK', this.fileObj.ossUrl); 123 }, 124 } 125 }; 126 </script> 127 128 <style lang="less" scoped> 129 </style>
学习封装的风格,如何把变量抛出让他人更好的灵活利用组件,而不改变组件。
导出excel表的实现,不过是后端处理的,非前段处理;
1 async exportDataAll() { 2 // 导出查询的数据 3 const params = { 4 beginDate: this.refundSearchData.timers[0] || null, 5 endDate: this.refundSearchData.timers[1] || null, 6 refundStatus: this.refundSearchData.status || null, 7 source: this.refundSearchData.source || null, 8 keyword: this.refundSearchData.keyword || null, 9 keywordValue: this.refundSearchData.keywordValue || null, 10 goodsName: this.refundSearchData.goodsName || null 11 }; 12 // exportRefundOrderAll(params).then(res => { 13 // console.log(res, "导出查询的数据"); 14 // }); 15 const response = await exportRefundOrderAll(params); 16 if (response.code !== 200) return Promise.reject(); 17 const { url } = response.result; 18 if (url) { 19 window.open(url, '_self'); 20 } 21 console.log("导出的列表excel", response); 22 },
1 <el-button type="primary" @click.native="getLecturerList()">查询</el-button> /**** 查询列表的时候可以,简化为pageNum===1****/ 2 3 <el-row style="margin-top: 20px;"> 4 <el-col :span="24" center> 5 <el-pagination 6 :current-page.sync="selectLecturerForm.currPage" 7 :page-size="selectLecturerForm.pageSize" 8 :total="selectLecturerForm.totalCount" 9 background 10 layout="prev, pager, next, jumper" 11 @current-change="getLecturerList(selectLecturerForm.currPage)" 12 ></el-pagination> 13 </el-col> 14 </el-row> 15 16 getLecturerList(pageNum = 1) { 17 const options = { 18 lecturerName: this.selectLecturerForm.lecturerName.trim(), 19 page: pageNum, 20 limit: 10 21 };
/*******再data里面去命名数据的时候,可以把数据归类用对象的形式去命名弹窗里面的数据,对于弹窗的dialog数据用state以对象的形式存储,分门别类的有序排列********/
/***********去大型的网站(淘宝)看看大佬如何命名,形成一种固定的规范,利于理解和维护代码************/
前段导出实现的话可以看gethub上的
vue-element-admin星号最多的,下载下来看下就知道了。
elemnet ui 的页面构建和组件的利用
后面慢慢更新。