# vue_oa **Repository Path**: jiely007/vue_oa ## Basic Information - **Project Name**: vue_oa - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 5 - **Forks**: 3 - **Created**: 2019-05-28 - **Last Updated**: 2023-03-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vue_oa ## 项目初始化 1. 安装element-ui并导入到main.js中 ```js import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI) ``` 2. 安装`node-sass sass-loader`并导入默认样式文件 ```js // 1. 安装解析scss文件的加载器 npm i node-sass sass-loader --save-dev "node-sass": "^4.9.0", "css-loader": "^0.28.0", "sass-loader": "^7.0.1", // 2. 将reset.scss/index.scss复制到项目文件中,并新建element.scss // 3. 在main.js中导入全局样式文件 import '@/styles/index.scss' ``` 3. 删除vue-cli默认的组件`HelloWord.vue`以及`router`文件夹`index.js`中的组件导入和路由规则 ## 登录页面路由跳转 1. `src`目录下创建`views`文件夹,并创建`login.vue`组件 2. 在`router`文件夹下的`index.js`中配置路由规则 ```js // 导入登录组件 import login from '../views/login.vue' // 在routes数组中配置路由对象 export default new Router({ routes: [ { path:'/login', name:'Login', component:login } ] }) ``` 3. 在页面中输入`http://localhost:1234/#/login`显示登录组件内容 ## 使用element-ui布局登录页面 1. 使用element-ui表单组件布局结构 ```html
``` 2. 书写样式 ```css .login { position: fixed; width: 100%; height: 100%; background-color: #2f4050; .container { position: absolute; left: 0; right: 0; width: 400px; padding: 0px 40px 15px 40px; margin: 200px auto; background: white; .avatar { position: relative; left: 50%; width: 120px; height: 120px; margin-left: -60px; margin-top: -60px; box-sizing: border-box; border-radius: 50%; border: 10px solid #fff; box-shadow: 0 1px 5px #ccc; overflow: hidden; } .login-btn { width: 100%; } } } ``` 3. 定义数据及表单验证规则 ```js export default { data () { return { form: { username: '', password: '' }, rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' } ], password: [ { required: true, message: '请输入密码', trigger: 'blur' } ] } } } } ``` ## 使用axios发送登录请求 1. 安装axios ```js npm i axios -S ``` 2. 在src目录下新建`api/index.js`文件,封装登录请求 ```js // 导入axios import axios from 'axios' // 设置请求的根路径 //const baseURL = 'http://www.lovegf.cn:8888/api/private/v1/' const baseURL = 'http://ludir.cn:8888/api/private/v1/' axios.defaults.baseURL = baseURL // 登录验证 export const checkUser = params => { return axios.post('login', params).then(res => res.data) } ``` 3. 在`login.vue`中的登录按钮上绑定点击事件,发送登录请求 ```js // 导入封装的登录请求接口 import {checkUser} from '../api/index.js' // 定义登录方法 methods: { loginSubmit (formName) { // 校验表单 this.$refs[formName].validate(valide => { if (valide) { // 发送登录请求 checkUser(this.form).then(res => { if (res.meta.status === 200) { // 如果成功要跳转至首页 this.$router.push({name: 'Home'}) } else { // 如果失败,展示提示信息 this.$message({ type: 'error', message: res.meta.msg }) } }) } else { console.log('校验不通过') } }) } } ``` 4. 在views文件夹中新建`Home.vue`文件,并配置好路由规则 ```js import home from '../views/Home.vue' routes: [ { path:'/login', name:'Login', component:login }, { path:'/home', name:'Home', component:home } ] ``` ## 存储登录状态并设置axios拦截器 > 除登录请求外,其他所有请求发送都必须保证请求头中有登录成功返回的token值,所以需要使用拦截器给请求添加`Authorization` 1. 登录成功时将后台返回的token存储起来 ```js // 存储后台返回的登录成功凭证token localStorage.setItem('mytoken', res.data.token) ``` 2. 使用axios拦截器将token添加到请求头中 ```js // 请求拦截器,给所有的请求加上token axios.interceptors.request.use(function (config) { // 取出localStorage中存储的token值 let token = localStorage.getItem('mytoken') // 设置到请求头中 Authorization这个名字是后台规定的 config.headers['Authorization'] = token return config }, function (error) { return Promise.reject(error) }) ``` 3. 封装获取用户列表请求 ```js // 获取用户列表 export const getUserList = params => { return axios.get('users', params).then(res => res.data) } ``` 4. 在`Home.vue`的生命周期函数`created`中发送获取数据列表请求 ```js created(){ let params = {params: {query: '', pagenum: 1, pagesize: 1}} getUserList(params).then(res => { console.log(res) }) } ``` ## 使用vue-router路由全局守卫进行路由拦截 > 对于需要登录的页面访问前需要判断是否已经登录,使用路由导航钩子进行拦截 1. 在`router/index.js`中使用路由全局守卫拦截所有的路由跳转 ```js // 注册一个全局守卫,作用是在路由跳转前,对路由进行判断,防止未登录的用户跳转到其他需要登录的页面去 router.beforeEach((to, from, next) => { let token = localStorage.getItem('mytoken') // 如果已经登录,放行 if (token) { next() } else { // 如果没有登录,访问非登录页面,则跳转到登录页面 if (to.path !== '/login') { next({path: '/login'}) } else { // 如果没有登录,但访问的是登录页面,直接进入 next() } } }) ``` ## 首页整体布局 1. 使用element-ui布局容器进行首页整体布局 ```html
Aside Header Main
``` 2. 调整样式 ```scss .home { height: 100%; .el-menu-admin:not(.el-menu--collapse) { width: 200px; min-height: 400px; } .el-container { height: 100%; } .el-aside { background-color: #545c64; } .el-header { display: flex; justify-content: space-between; align-items: center; background-color: #545c64; } .logo { height:60px; background: url(../assets/logo.png); background-size: cover; background-color: #989898; } .toggle-btn { font-size: 36px; color: #989898; cursor: pointer; line-height: 60px; } .system-title { font-size: 28px; color: white; } .logout-btn { color: orange; } } ``` ## 完成侧边栏布局 1. 使用element-ui的导航菜单进行结构布局 ```html 用户列表 ``` 2. 定义导航菜单的点击事件 ```js methods:{ handleOpen (key, keyPath) { console.log(key, keyPath) }, handleClose (key, keyPath) { console.log(key, keyPath) } } ``` ## 完成头部内容以及中间部分路由跳转 1. 使用element-ui完成头部导航条 ```html
电商后台管理系统
您好,xxx 退出
``` 2. data中定义`isCollapse`属性控制左侧导航的切换 ```js // 1. el-menu上绑定collapse属性 // 2. 定义isCollapse:false data() { return { isCollapse:false } } /// 3. 切换事件 toggleCollapse(){ this.isCollapse = !this.isCollapse } ``` 3. 退出登录按钮绑定事件 ```js logout () { // 1. 清除登录状态,即删除保存在localStorage中的token localStorage.removeItem('mytoken') // 2. 跳转到登录页面 this.$router.push({name: 'Login'}) } ``` 4. 定义路由规则显示中间区域 > 由于每次点击左侧导航都是中间区域变化,而整体页面的左侧和头部不变,所以中间区域应该设置成子路由 ```js // 1. 创建welcome组件并导入 import welcome from '../views/welcome/Welcome.vue' // 2. 配置子路由规则用于显示welcome组件 { path: '/', name: 'Home', component: home, redirect: { path: 'welcome' }, children: [{ name: 'Welcome', path: 'welcome', component: welcome }] } // 3. 子路由的组件需要显示到父路由对应的组件中,所以Home.vue中需要放一个router-view ``` ## 集成Vuex保存用户名 1. 新建`store/index.js`文件,定义store实例 ```js import Vue from 'vue' // 1. 导入并绑定Vuex import Vuex from 'vuex' Vue.use(Vuex) // 2. 定义数据存储仓库state const state = { username: '' } // 3. 定义用于修改数据的方法 const mutations = { setUsername: (state, username) => { state.username = username localStorage.setItem('username', username) } } // 4. 异步修改数据 const actions = {} // 5. 计算属性 const getters = { username: (state) => localStorage.getItem('username') } // 6. 导出store实例 export default new Vuex.Store({ state, getters, actions, mutations }) ``` 2. `main.js`中导入并集成store ```js // 导入 import store from './store/index.js' // 挂载到vue实例 new Vue({ el: '#app', router, store, components: { App }, template: '' }) ``` 3. 登录成功后调用修改数据的方法保存数据 ```js // 2. 使用vuex存储用户名 this.$store.commit('setUsername', res.data.username) ``` 4. 使用`$store.getters.username`显示数据 ```html 您好,{{$store.getters.username}} ``` ## 用户列表界面路由跳转及布局 1. 启用element-ui路由跳转功能,`Home.vue`组件中的`el-menu`标签上添加`:router = "true"` 2. `el-menu-item`标签的index属性设置需要跳转的路由路径 ```html 用户列表 ``` 3. 创建`User.vue`组件,并配置好路由规则 ```js // 导入组件 import user from '../views/user/User.vue' // 创建路由规则对象 { name: 'User', path: 'user', component: user } ``` 4. 使用element-ui组件进行页面布局 ```html
首页 用户管理 用户列表 添加用户
``` 5. 跳转样式 ```css /*element.scss中书写面包屑组件样式*/ .el-breadcrumb { background-color: #D3DCE6; height: 45px; font-size: 15px; padding-left: 10px; line-height: 45px; margin-bottom: 15px; } /*组件内部style标签中书写以下样式*/ .user { .margin-20 { margin: 20px 0; } .search-input { width: 300px; } .page { padding: 5px 0; background-color: #D3DCE6; } } ``` ## 用户列表数据渲染 1. 发送数据请求 ```js // 1. data中定义存储数据的数组userList // 2. 在methods中定义数据请求方法 initList () { getUserList({params: {query: '', pagenum: 1, pagesize: 3}}).then(res => { console.log(res) this.userList = res.data.users }) } // 3. 在生命周期函数created中发送请求 created(){ this.initList() } ``` 2. 渲染数据 ```css ``` ## 完成搜索功能 1. data中定义query属性保存搜索条件,并将搜索条件加入到数据请求的参数中 ```js // 由于搜索接口和获取用户列表是同一个接口,所以只需要加入搜索条件即可 initList () { getUserList({params: {query: this.query, pagenum: 1, pagesize: 3}}).then(res => { console.log(res) this.userList = res.data.users }) } ``` 2. 给搜索按钮绑定点击事件 ```html ``` 3. 给搜索框绑定keydown事件 ```html ``` ## 完成分页功能 1. 在data中定义`total`,`pagesize`,`pagenum`三个属性分别存储数据总条数、每页显示多少条、页码 2. 数据请求方法中给`total`赋值 ```js // 初始化表格数据 initList () { getUserList({params: {query: this.query, pagenum: this.pagenum, pagesize: this.pagesize}}).then(res => { console.log(res) this.userList = res.data.users this.total = res.data.total }) } ``` 3. 切换页码和切换条数事件中重新发送请求 ```js handleSizeChange (val) { console.log(`每页 ${val} 条`) this.pagesize = val this.initList() }, handleCurrentChange (val) { console.log(`当前页: ${val}`) this.pagenum = val this.initList() } ``` ## 完成修改用户状态功能 1. 使用v-model给switch开关绑定状态值,并且添加切换状态的方法 ```html ``` 2. 定义更新用户状态的网络请求 ```js // 更改用户状态 export const changeUserState = params => { return axios.put(`users/${params.uid}/state/${params.type}`).then(res => res.data) } ``` 3. 定义切换状态的方法发送网络请求更新用户状态 ```js // 改变用户状态 changeUserState (row) { console.log(row) changeUserState({uid: row.id, type: row.mg_state}).then(res => { if (res.meta.status === 200) { this.$message({ type: 'success', message: '修改用户状态成功' }) } else { this.$message({ type: 'warning', message: res.meta.msg }) } }) } ``` ## 完成添加用户功能 1. 使用`el-dialog`组件实现弹窗 ```html 添加用户 ``` 2. data中定义表单用到的数据和表单验证规则 ```js addDialogFormVisible: false, addForm: { username: '', password: '', email: '', mobile: '' }, // 添加用户的表单验证 rules: { username: [{ required: true, message: '请输入用户名', trigger: 'blur' }], password: [{ required: true, message: '请输入密码', trigger: 'blur' }], email: [{ required: true, message: '请输入邮箱地址', trigger: 'blur' },{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur,change' }], mobile: [{ required: true, message: '电话不能为空' }] } ``` 3. 定义添加用户的网络请求 ```js // 添加用户 export const addUser = params => { return axios.post('users', params).then(res => res.data) } ``` 4. 点击确定按钮发送网络请求 ```js // 添加用户 addUserSubmit (formName) { this.$refs[formName].validate(valide => { if (valide) { // 执行添加用户方法 addUser(this.addForm).then(res => { console.log(res) if (res.meta.status === 201) { this.$message({ type: 'success', message: '创建用户成功!' }) } this.addDialogFormVisible = false this.initList() }) } }) } ``` ## 完成编辑用户功能 1. 使用`el-dialog`组件实现弹窗 ```html ``` 2. 定义编辑表单中的数据 ```js editDialogFormVisible: false, editForm: { username: '', email: '', mobile: '', id: 0 } ``` 3. 定义获取用户信息的网络请求和编辑用户信息的网络请求 ```js // 根据id获取用户信息 export const getUserById = params => { return axios.get(`users/${params}`).then(res => res.data) } // 编辑用户信息 export const editUser = params => { return axios.put(`users/${params.id}`, params).then(res => res.data) } ``` 4. 点击编辑按钮发送获取用户信息的网络请求 ```js // 显示编辑用户对话框 showEditDialog (row) { this.editDialogFormVisible = true // 获取用户信息 getUserById(row.id).then(res => { if (res.meta.status === 200) { this.editForm.username = res.data.username this.editForm.email = res.data.email this.editForm.mobile = res.data.mobile this.editForm.id = res.data.id } }) }, ``` 5. 点击确定按钮发送编辑用户信息的网络请求 ```js // 编辑用户提交 editUserSubmit (formName) { this.$refs[formName].validate(valide => { if (valide) { editUser(this.editForm).then(res => { if (res.meta.status === 200) { this.$message({ type: 'success', message: '编辑成功' }) this.editDialogFormVisible = false this.initList() } }) } }) } ``` ## 完成删除用户功能 1. 添加删除按钮事件 ```html ``` 2. 定义删除用户的网络请求 ```js // 删除用户信息 export const deleteUser = params => { return axios.delete(`users/${params}`).then(res => res.data) } ``` 3. 发送删除用户网络请求 ```js // 显示删除对话框 showDeleteDialog (row) { this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { // 执行删除用户操作 deleteUser(row.id).then(res => { if (res.meta.status === 200) { this.$message({ type: 'success', message: '删除成功!' }) this.initList() } }) }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }) }) } ``` ## 完成分配用户角色功能 1. 分配角色按钮添加事件,并使用弹窗组件 ```html {{grantForm.username}} ``` 2. 定义分配角色表单需要用到的数据 ```js // 控制分配用户角色对话框显示隐藏 grantDialogFormVisible: false, // 存储分配角色时获取的用户信息 grantForm: {}, // 角色列表 roleList: [], // 角色ID roleId: '' ``` 3. 定义获取角色列表和分配角色的网络请求 ```js // 获取角色列表 export const getRoleList = params => { return axios.get('roles').then(res => res.data) } // 分配角色 export const grantUserRole = params => { return axios.put(`users/${params.id}/role`, {id: params.id, rid: params.rid}).then(res => res.data) } ``` 4. 点击分配角色按钮发送获取角色列表的请求,并使用v-for渲染数据 ```js // 显示分配角色对话框 showGrantDialog (row) { this.grantForm = row this.grantDialogFormVisible = true getRoleList().then(res => { console.log(res) if (res.meta.status === 200) { this.roleList = res.data } }) } ``` 5. 点击确定按钮发送分配角色网络请求 ```js // 分配角色 grantUserSubmit () { // 当没有选择角色时,不发送网络请求 if (!this.roleId) { this.$message({ type: 'warning', message: '角色不能为空,请选择!' }) } else { grantUserRole({id: this.grantForm.id, rid: this.roleId}).then(res => { if (res.meta.status === 200) { this.$message({ type: 'success', message: '设置角色成功' }) this.grantDialogFormVisible = false } else { this.$message({ type: 'error', message: res.meta.msg }) } }) } } ``` ## 权限管理路由跳转 1. 书写结构代码,更改index为路由路径 ```html 角色列表 权限列表 ``` 2. 新建`Roles.vue`和`Rights.vue`组件,并配置路由规则 ```js import rights from '../views/right/Rights.vue' import roles from '../views/right/Roles.vue' { name: 'Rights', path: 'rights', component: rights }, { name: 'Roles', path: 'roles', component: roles } ``` ## 权限列表数据展示 1. 结构代码 ```html
首页 权限管理 权限列表
``` 2. 定义网络请求 ```js // 获取权限列表 export const getRightList = params => { return axios.get(`rights/${params.type}`).then(res => res.data) } ``` 3. `created`钩子函数中发送网络请求 ```js created () { this.isLoading = true getRightList({type: 'list'}).then(res => { if (res.meta.status === 200) { this.rightList = res.data this.isLoading = false } }) } ``` 4. 定义过滤器过滤层级显示 ```js filters: { fmtLevel (level) { if (level === '0') { return '一级' } else if (level === '1') { return '二级' } else { return '三级' } } } ``` ## 角色列表数据展示 1. 结构代码 ```html
首页 权限管理 角色列表 添加角色
``` 2. 样式 ```scss .roles { .el-tag { margin-right: 5px; margin-bottom: 5px; } .tree-container { height: 300px; overflow: auto; } } ``` 3. 发送网络请求渲染界面 ```js data(){ return { roleList: [] } }, created () { this.initList() }, methods: { initList () { getRoleList().then(res => { if (res.meta.status === 200) { console.log(res) this.roleList = res.data } }) } } ``` ## 角色列表展开数据展示 1. 使用栅格布局渲染界面 ```html ``` ## 角色权限删除功能 1. `el-tag`标签绑定删除事件 ```html {{firstChildren.authName}} {{secondChildren.authName}} ``` 2. 定义删除权限数据请求 ```js // 删除角色指定权限 export const deleteRoleRight = params => { return axios.delete(`roles/${params.roleId}/rights/${params.rightId}`).then(res => res.data) } ``` 3. 点击删除按钮触发删除请求 ```js deleteRight (row, rightId) { deleteRoleRight({roleId: row.id, rightId: rightId}).then(res => { if (res.meta.status === 200) { row.children = res.data } else { this.$message({ type: 'error', message: res.meta.msg }) } }) } } ``` ## 授权角色树数据展示 1. 书写弹窗组件结构代码 ```html
``` 2. 发送数据请求渲染界面 ```js // 1. 定义组件需要用到的数据 dialogFormVisible: false, // 控制弹窗显示隐藏 rightList: [], // 存放权限列表 defaultProps: { children: 'children', // // 树形组件展示的数据源 label: 'authName' // 树形组件显示的标题字段 } // 2. 发送数据请求 showDialog (row) { this.dialogFormVisible = true this.currentRole = row getRightList({type: 'tree'}).then(res => { if (res.meta.status === 200) { console.log(res.data) this.rightList = res.data } else { this.$message({ type: 'error', message: res.meta.msg }) } }) } ``` ## 完成授权角色默认选中功能 1. 利用`:default-checked-keys="selectedRights"`树形控制树形组件默认选中项 2. 遍历所有权限,找到已授权的ID存放到`selectedRights`中 ```js // 遍历之前先让数组清空 this.selectedRights.length = 0 // 取出当前点击角色的所有权限, 然后遍历到它的第三个children,取出它里面的所有的项的id,存进selectedRights中 // 1. 遍历第一个children取出一级权限 this.currentRole.children.forEach(first => { if (first.children && first.children.length !== 0) { // 2. 遍历第二个children取出二级权限 first.children.forEach(second => { if (second.children && second.children.length !== 0) { // 3. 遍历第三个children取出三级权限 second.children.forEach(third => { this.selectedRights.push(third.id) }) } }) } }) ``` ## 提交授权功能 1. 定义数据请求 ```js // 角色授权 export const grantRoleRight = (roleId, rids) => { return axios.post(`roles/${roleId}/rights`, rids).then(res => res.data) } ``` 2. 点击确定按钮发送提交授权请求 ```js // 提交授权 submitGrant () { // 获取到所有选中的权限ID let rids = this.$refs.tree.getCheckedKeys().join(',') grantRoleRight(this.currentRole.id, {rids: rids}).then(res => { if (res.meta.status === 200) { this.$message({ type: 'success', message: res.meta.msg }) this.dialogFormVisible = false this.initList() } }) } ``` ## 动态获取权限菜单 1. 定义获取权限菜单的数据请求 ```js // 左侧菜单权限 export const getMenus = () => { return axios.get('menus').then(res => res.data) } ``` 2. 发送获取权限菜单的请求 ```js created() { getMenus().then(res => { if (res.meta.status === 200) { this.menuData = res.data; } }) } ``` 3. 使用`v-for`循环渲染界面 ```html {{tag.authName}} ``` ## 商品分类界面布局 1. 创建`category/Category.vue`组件,配置路由规则实现跳转 ```js { name: 'Category', path: 'categories', component: category } ``` 2. 在`componets`文件夹中放入`TreeGrid`组件,并在`Category.vue`组件中进行集成 ```js // 1. 在category.vue中导入组件 import TreeGrid from '@/components/TreeGrid/TreeGrid' // 2. 注册组件 data() { return { addDialogFormVisible: false, columns: [ { text: "分类名称", dataIndex: "cat_name", width: "" }, { text: "是否有效", dataIndex: "cat_deleted", width: "" }, { text: "排序", dataIndex: "cat_level", width: "" } ], dataSource: [], total: 10 } }, components: { TreeGrid } ``` 3. 使用`TreeGrid.vue`组件 ```html
首页 商品管理 商品分类 添加分类
``` ## 商品分类数据获取 1. 定义获取数据的请求 ```js // 获取商品分类信息 export const getCategories = (params) => { return axios.get('categories', {params: params}).then(res => res.data) } ``` 2. 发送网络请求获取数据 ```js initList() { getCategories({ type: "3", pagenum: this.pagenum, pagesize: this.pagesize }).then(res => { console.log(res); if (res.meta.status === 200) { this.total = res.data.total; this.dataSource = res.data.result; } }); } ``` ## 添加商品分类级联选择器使用 1. 添加分类弹窗布局 ```html ``` 2. 定义级联选择器需要用到的数据源 ```js addForm: { cat_name: "", cat_pid: 0, cat_level: 0 }, // 级联选择器的数据源 options: [], // 级联选择器选中后的数据 selectedOptions: [], // props表示配置级联选择器展示的数据字段 props: { value: "cat_id", label: "cat_name" } ``` 3. 点击添加分类按钮发送请求获取分类数据 ```js addCategory() { this.addDialogFormVisible = true; getCategories({ type: "2" }).then(res => { console.log(res); if (res.meta.status === 200) { this.options = res.data; } }); } ``` ## 添加商品分类数据提交 ```js addCateSubmit(formName) { this.$refs[formName].validate(valide => { if (valide) { // 添加一级分类 if (this.selectedOptions.length === 0) { this.addForm.cat_pid = 0; this.addForm.cat_level = 0; } else if (this.selectedOptions.length === 1) { // 添加二级分类 this.addForm.cat_pid = this.selectedOptions[ this.selectedOptions.length - 1 ]; this.addForm.cat_level = 1; } else { // 添加三级分类 this.addForm.cat_pid = this.selectedOptions[ this.selectedOptions.length - 1 ]; this.addForm.cat_level = 2; } addCategories(this.addForm).then(res => { if (res.meta.status === 201) { this.addDialogFormVisible = false; this.initList(); this.$message({ type: "success", message: res.meta.msg }); } }); } }); } ``` ## 添加商品步骤条组件和tabs组件集成 1. 创建商品列表组件和添加商品组件,并配置路由规则 ```js { name: 'Goods', path: 'goods', component: goods }, { name: 'AddGoods', path: 'toadd', component: addGoods } ``` 2. 商品列表组件代码 ```html ``` 3. 添加商品组件结构代码 ```html
首页 商品管理 商品列表 配置管理 角色管理 图片上传 定时任务补偿
``` 4. 点击tabs切换步骤条 ```js data () { return { active: 0, activeName: 'first' } }, methods: { handleClick (tab, event) { switch (tab.name) { case 'first': this.active = 0 break case 'second': this.active = 1 break case 'third': this.active = 2 break case 'fourth': this.active = 3 break case 'fifth': this.active = 4 break default: this.active = 0 break } } } ``` ## 图片上传组件使用 1. 使用`el-upload`组件上传图片 ```html 点击上传 ``` 2. 设置请求头处理成功回调 ```js handleRemove(file, fileList) { console.log(file, fileList); }, handlePreview(file) { console.log(file); }, // 成功后回调函数 handleSuccess(response, file, fileList) { if (response.meta.status === 200) { this.$message({ type: "success", message: response.meta.msg }); } }, // 设置请求头 setHeader() { let token = localStorage.getItem("mytoken"); return { Authorization: token }; } ``` ## axios上传图片 ```html ``` #### https://www.iplaysoft.com/free-image-hosting.html 免费图片网站 ```js update(e) { let file = e.target.files[0];// 获取文件数据 let param = new FormData(); // 创建form对象 param.append("file", file); // 通过append向form对象添加数据 console.log(param.get("file")); // FormData私有类对象,访问不到,可以通过get判断值是否传进去 let config = { headers: { "Content-Type": "multipart/form-data", } }; axios .post("http://www.lovegf.cn:8888/api/private/v1/upload", param, config) .then(response => { console.log(response.data); }); } ```