本章目的:调用API实现页面功能
一、安装axios
npm install --save axiosView Code
二、封装axios调用方法
js/api.js
import axios from 'axios'; import Vue from 'vue'; let base = 'http://localhost:8022'; axios.defaults.timeout = 20000 // 自定义判断元素类型JS function toType(obj) { return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase() } // 参数过滤函数 function filterNull(o) { for (var key in o) { if (o[key] === null) { delete o[key] } if (toType(o[key]) === 'string') { o[key] = o[key].trim() } else if (toType(o[key]) === 'object') { o[key] = filterNull(o[key]) } else if (toType(o[key]) === 'array') { o[key] = filterNull(o[key]) } } return o } axios.interceptors.request.use( config => { return config }, err => { return Promise.reject(err); } ); // http response 拦截器 axios.interceptors.response.use( response => { return response; }, error => { // 超时请求处理 var originalRequest = error.config; if (error.code == 'ECONNABORTED' && error.message.indexOf('timeout') != -1 && !originalRequest._retry) { Vue.prototype.$message({ message: '请求超时!', type: 'error' }); originalRequest._retry = true return null; } if (error.response) { if (error.response.status == 401) { //需要授权 } // 403 无权限 if (error.response.status == 403) { Vue.prototype.$message({ message: '失败!该操作无权限', type: 'error' }); return null; } // 429 ip限流 if (error.response.status == 429) { Vue.prototype.$message({ message: '刷新次数过多,请稍事休息重试!', type: 'error' }); return null; } } return ""; // 返回接口返回的错误信息 } ); // 角色管理 export const getRoleListPage = params => { return axios.get(`${base}/api/role/get`, { params: params }); }; export const removeRole = params => { return axios.delete(`${base}/api/role/delete`, { params: params }); }; export const editRole = params => { return axios.put(`${base}/api/role/put`, params); }; export const addRole = params => { return axios.post(`${base}/api/role/post`, params ); };View Code
三、页面代码
角色页面 views/User/Roles.vue
<template> <section> <!--工具条--> <el-col :span="24" class="toolbar" style="padding-bottom: 0px;"> <el-form :inline="true" @submit.native.prevent> <el-form-item> <el-input v-model="filters.name" placeholder="请输入内容"></el-input> </el-form-item> <el-button type="primary" @click="getRoles">查询</el-button> <el-button type="primary" @click="handleAdd">新增</el-button> <el-button type="primary" @click="handleEdit">修改</el-button> <el-button type="danger" @click="handleDel">删除</el-button> </el-form> </el-col> <!--列表--> <el-table :data="datalist" highlight-current-row v-loading="listLoading" @current-change="selectCurrentRow" style="width: 100%;"> <el-table-column type="index" width="80"></el-table-column> <el-table-column prop="RoleName" label="角色名" width sortable></el-table-column> <el-table-column prop="Description" label="说明" width sortable></el-table-column> <el-table-column prop="CreateTime" label="创建时间" :formatter="formatCreateTime" width sortable></el-table-column> <el-table-column prop="Enabled" label="状态" width="200" sortable> <template slot-scope="scope"> <el-tag :type="scope.row.Enabled ? 'success' : 'danger'" disable-transitions>{{scope.row.Enabled ? "正常":"禁用"}}</el-tag> </template> </el-table-column> </el-table> <VuePagination ref="vuePagination" :current-page="pagination.currentPage" :pageSize="pagination.pageSize" :totals="pagination.totals" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> <!--编辑界面--> <el-dialog title="编辑" :visible.sync="editFormVisible" v-model="editFormVisible" :close-on-click-modal="false"> <el-form :model="editForm" label-width="80px" :rules="editFormRules" ref="editForm"> <el-form-item label="角色名" prop="RoleName"> <el-input v-model="editForm.RoleName" auto-complete="off"></el-input> </el-form-item> <el-form-item label="状态" prop="Enabled"> <el-select v-model="editForm.Enabled" placeholder="请选择角色状态"> <el-option v-for="item in statusList" :key="item.value" :label="item.name" :value="item.value"></el-option> </el-select> </el-form-item> <el-form-item label="说明" prop="Description"> <el-input v-model="editForm.Description" auto-complete="off"></el-input> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click.native="editFormVisible = false">取消</el-button> <el-button type="primary" @click.native="editSubmit" :loading="editLoading">提交</el-button> </div> </el-dialog> <!--新增界面--> <el-dialog title="新增" :visible.sync="addFormVisible" v-model="addFormVisible" :close-on-click-modal="false"> <el-form :model="addForm" label-width="80px" :rules="addFormRules" ref="addForm"> <el-form-item label="角色名" prop="RoleName"> <el-input v-model="addForm.RoleName" auto-complete="off"></el-input> </el-form-item> <el-form-item label="状态" prop="Enabled"> <el-select v-model="addForm.Enabled" placeholder="请选择角色状态"> <el-option label="激活" value="true"></el-option> <el-option label="禁用" value="false"></el-option> </el-select> </el-form-item> <el-form-item label="说明" prop="Description"> <el-input v-model="addForm.Description" auto-complete="off"></el-input> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click.native="addFormVisible = false">取消</el-button> <el-button type="primary" @click.native="addSubmit" :loading="addLoading">提交</el-button> </div> </el-dialog> </section> </template> <script> import util from "../../js/date"; import { getRoleListPage, removeRole, editRole, addRole } from "../../js/api"; import VuePagination from '@/components/Pager' export default { name: 'Users', components: { "VuePagination": VuePagination }, data() { return { filters: { name: "" }, datalist: [], statusList: [ { name: "激活", value: "true" }, { name: "禁用", value: "false" } ], total: 0, page: 1, listLoading: false, sels: [], //列表选中列 currentRow: null, addDialogFormVisible: false, editFormVisible: false, //编辑界面是否显示 editLoading: false, editFormRules: { RoleName: [{ required: true, message: "请输入角色名", trigger: "blur" }], Enabled: [{ required: true, message: "请选择状态", trigger: "blur" }] }, //编辑界面数据 editForm: { Id: 0, CreateBy: "", RoleName: "", Description: "", Enabled: false }, addFormVisible: false, //新增界面是否显示 addLoading: false, addFormRules: { RoleName: [{ required: true, message: "请输入角色名", trigger: "blur" }], Enabled: [{ required: true, message: "请选择状态", trigger: "blur" }] }, //新增界面数据 addForm: { CreateBy: "", CreateId: 0, RoleName: "", Description: "", Enabled: true }, pagination: { pageSize: 2, // 显示的条数 totals: 0, // 总数 currentPage: 1 // 当前第几页 }, }; }, methods: { // 改变每页的显示数量 handleSizeChange(val) { this.pagination.pageSize = val.pageSize; this.getRoles() }, // 翻页 handleCurrentChange(val) { val.totals = this.pagination.totals; this.pagination = { ...val, }; this.getRoles() }, selectCurrentRow(val) { this.currentRow = val; }, formatCreateTime: function (row, column) { return !row.CreateTime || row.CreateTime == "" ? "" : util.formatDate.format(new Date(row.CreateTime), "yyyy-MM-dd"); }, //获取列表 getRoles() { let _this = this; let para = { page: _this.pagination.currentPage, intPageSize: _this.pagination.pageSize, key: this.filters.name }; this.listLoading = true; getRoleListPage(para).then(res => { this.total = res.data.response.dataCount; this.datalist = res.data.response.data; this.pagination.totals = res.data.response.dataCount; this.pagination.currentPage = res.data.response.data; this.listLoading = false; }); }, //删除 handleDel() { let row = this.currentRow; if (!row) { this.$message({ message: "请选择要删除的一行数据!", type: "error" }); return; } this.$confirm("确认删除该记录吗?", "提示", { type: "warning" }) .then(() => { this.listLoading = true; let para = { id: row.Id }; removeRole(para).then(res => { if (util.isEmt.format(res)) { this.listLoading = false; return; } this.listLoading = false; if (res.data.success) { this.$message({ message: "删除成功", type: "success" }); } else { this.$message({ message: res.data.msg, type: "error" }); } this.getRoles(); }); }) .catch(() => { }); }, //显示编辑界面 handleEdit() { let row = this.currentRow; if (!row) { this.$message({ message: "请选择要编辑的一行数据!", type: "error" }); return; } this.editFormVisible = true; this.editForm = Object.assign({}, row); this.editForm.Enabled = this.editForm.Enabled ? "true" : "false"; }, //显示新增界面 handleAdd() { this.addFormVisible = true; this.addForm = { CreateBy: "", RoleName: "", Enabled: "" }; }, //编辑 editSubmit: function () { this.$refs.editForm.validate(valid => { if (valid) { this.$confirm("确认提交吗?", "提示", {}).then(() => { this.editLoading = true; let para = Object.assign({}, this.editForm); para.Enabled = para.Enabled === 'true'; editRole(para).then(res => { if (util.isEmt.format(res)) { this.editLoading = false; return; } if (res.data.success) { this.editLoading = false; this.$message({ message: res.data.msg, type: "success" }); this.$refs["editForm"].resetFields(); this.editFormVisible = false; this.getRoles(); } else { this.$message({ message: res.data.msg, type: "error" }); } }); }); } }); }, //新增 addSubmit: function () { let _this = this; this.$refs.addForm.validate(valid => { if (valid) { this.$confirm("确认提交吗?", "提示", {}).then(() => { this.addLoading = true; let para = Object.assign({}, this.addForm); //var user = JSON.parse(window.localStorage.user); //if (user && user.uID > 0) { para.CreateId = 1; para.CreateBy = ""; //} else { // this.$message({ // message: "用户信息为空,先登录", // type: "error" // }); // _this.$router.replace( // _this.$route.query.redirect ? _this.$route.query.redirect : "/" // ); //} para.Enabled = para.Enabled=== 'true'; addRole(para).then(res => { if (util.isEmt.format(res)) { this.addLoading = false; return; } if (res.data.success) { this.addLoading = false; this.$message({ message: res.data.msg, type: "success" }); this.$refs["addForm"].resetFields(); this.addFormVisible = false; this.getRoles(); } else { this.$message({ message: res.data.msg, type: "error" }); } }); }); } }); } }, mounted() { this.getRoles(); } } </script>View Code
今天碰到一个很大的坑,花了点时间解决,调用POST方法时,总是报400错误,刚开始以为是数据格式的问题,试了各种方法,不行。最后,最后,竟然发现是字段类型的问题,Enabled在实体里定义的是bool型,传"true"就不行,改成true就可以了。这一点还是想不通,ajax传值一直都是这样传的,为什么没办法自行匹配转换呢?
在新增和修改的保存方法里加了以下就解决了:
para.Enabled = para.Enabled=== 'true';
四、分页组件
<template> <div class="page-wrapper clearfix"> <div class="page-info fl"> <span class="item-count h50"> 总共 <span>{{totals}}</span>条, </span> <span class="h50"> <span>{{totalPages}}</span>页 </span> </div> <div class="page-tab fl clearfix"> <button class="fl h50 cursor" :class="{canNot:currentPage==1}" @click="firstPage" :disabled="preDisabled"> 首页 </button> <button class="fl h50 cursor" :class="{canNot:currentPage==1}" @click="prePage" :disabled="preDisabled"> 上一页 </button> <ul class="fl"> <li v-for="(item,index) in itemArr" :key="index" class="cursor" @click="changePage(item)" :class="{activePage:currentPage=== item}">{{item}}</li> </ul> <button class="fl h50 cursor" @click="nextPage" :class="{canNot:currentPage==totalPages}" :disabled="nextDisabled"> 下一页 </button> <button class="fl h50 cursor" :class="{canNot:currentPage==totalPages}" :disabled="nextDisabled" @click="lastPage"> 尾页 </button> </div> <div class="items-choose fl clearfix"> <span class="fl h50">每页</span> <div class="items-show fl" @click="handleChooseNumClick"> <input v-model="pageSize" class="chooseNum" @blur="blur" readonly /> <div class="per-page-items"> <!-- <input type="text" class="input-item-num"> --> <ul class="items-num" v-show="itemsShow"> <li v-for="(item,index) in pageSizeSettings" :key="index" @click.stop="chooseNum(item)">{{item}}</li> </ul> </div> </div> </div> </div> </template> <script> export default { name: "VuePagination", props: { pageSize: { // 每页显示数量 default: 0, type: Number, }, totals: { // 总数 default: 0, type: Number, }, tab: { type: Boolean, default: false, }, pageSizeSettings: { // 配置下拉 选pageSize type: Array, default() { return [10, 20, 50, 100]; }, }, }, data() { return { itemsShow: false, // 控制每页条数下拉框 itemArr: [], // 显示页数, nextDisabled: null, preDisabled: "disabled", totalPages: 1, // 默认页数 currentPage: 1, size: this.pageSize, // 获取每页数量 }; }, computed: { pageNum() { // 由于父组件传递过来的属性 子组件的钩子里面不能直接使用 用计算属性代替接收 let a = this.pageSize; return a; }, pageItems() { let b = this.totals; return b; }, }, created() { this.pages(); }, methods: { chooseNum(item) { // 改变pageSize this.itemsShow = false; this.$emit("size-change", { pageSize: item, }); }, handleChooseNumClick() { this.itemsShow = !this.itemsShow; }, blur() { var that = this; setTimeout(function () { that.itemsShow = false; }, 200); }, changePage(page) { // 切换页数 this.currentPage = page; this.pages(); }, nextPage() { // 下一页 if (this.currentPage <= this.totalPages - 1) { this.currentPage++; } }, prePage() { // 上一页 if (this.currentPage > 1) { this.currentPage--; } }, firstPage() { // 首页 this.currentPage = 1; }, lastPage() { // 尾页 this.currentPage = this.totalPages; }, pages() { // 页数改变的逻辑 this.itemArr = []; // 每次改变得清空数组 this.totalPages = Math.ceil(this.pageItems / this.pageNum); this.preDisabled = this.currentPage === 1 ? "disabled" : null; this.nextDisabled = this.currentPage === this.totalPages ? "disabled" : null; let start = this.currentPage - 2 > 1 ? this.currentPage - 2 : 1; let end = this.currentPage > 3 ? this.totalPages - this.currentPage >= 2 ? this.currentPage + 2 : this.totalPages : 5; start = this.totalPages - this.currentPage >= 2 ? start : end - 4; if (this.totalPages <= 5) { start = 1; end = this.totalPages; } for (let i = start; i <= end; i++) { this.itemArr.push(i); } }, }, watch: { pageNum() { // 每页数量变化后传递出 pageSize 重新请求数据 this.currentPage = 1; // 改变每页数据 页码回到初始值 this.pages(); this.$emit("size-change", { pageSize: this.pageNum, }); }, currentPage() { // 当前页数变化后 传递出当前页码 重新请求数据 this.pages(); this.$emit("current-change", { pageSize: this.pageNum, currentPage: this.currentPage, }); }, totals() { // 数据是异步加载的 组件刚开始totals是默认的是渲染不了的 this.pages(); }, tab() { // 点击切换条件筛选 重置currentPage this.currentPage = 1; }, }, }; </script> <style> * { padding: 0; margin: 0; } ul, li { list-style: none; } .clearfix:after { content: "."; height: 0; display: block; visibility: hidden; clear: both; overflow: hidden; } .cursor { cursor: pointer; } .clearfix { zoom: 1; } .page-wrapper .fl { float: left; } .page-wrapper { font-size: 14px; color: #5e6470; } .h50 { display: inline-block; height: 30px; line-height: 30px; padding: 0 12px; border: 1px solid #eaedf1; } .page-wrapper .page-tab li { float: left; width: 30px; height: 30px; text-align: center; line-height: 30px; border: 1px solid #eaedf1; box-sizing: border-box; } .page-wrapper .page-info { margin-right: 6px; } .page-wrapper .page-info .h50 { border: none; padding: 0; } .items-choose .h50 { padding: 0; border: none 0; border-top: 1px solid #eaedf1; border-bottom: 1px solid #eaedf1; box-sizing: border-box; padding: 0 6px; } .items-choose .items-show { height: 30px; width: 74px; position: relative; box-sizing: border-box; border: 1px solid #eaedf1; position: relative; } .items-choose .items-show input { height: 100%; width: 100%; text-align: center; } .items-choose .items-show:after { content: ""; position: absolute; height: 0; border: 4px solid transparent; border-top: 6px solid #c4ccc5; top: 50%; right: 10px; transform: translate3d(-50, -50, 0); cursor: pointer; } .items-choose .items-num { width: 100%; position: absolute; bottom: 42px; border: 1px solid #eaedf1; z-index: 100; background: #f5f7fa; z-index: 999; } .items-choose .items-num li { padding: 10px 0 10px 6px; font-size: 14px; } .items-choose .items-num li:hover { /*background: #1AB394;*/ background: #4a8df0; color: #fff; } .page-wrapper .activePage { color: #fff; /*background: #1AB394;*/ background: #4a8df0; } .canNot { cursor: not-allowed; } .page-wrapper button { background: #fff; font-size: 14px; color: #5e6470; } .chooseNum { cursor: pointer; font-size: 14px; color: #5e6470; } </style>View Code
五、运行效果