# cloudServiceFrontend **Repository Path**: big--boss/cloudServiceFrontend ## Basic Information - **Project Name**: cloudServiceFrontend - **Description**: 2020年合肥工业大学软件学院Java实训项目——云客服系统前端Frontend - **Primary Language**: JavaScript - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 4 - **Created**: 2020-06-22 - **Last Updated**: 2024-07-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # cloudServiceFrontend > 2020年合肥工业大学Java实训项目云客服前端 > > [![vue](https://img.shields.io/badge/vue-2.9.6-blue.svg?style=flat-square)](https://cn.vuejs.org/) > [![vuex](https://img.shields.io/badge/vuex-3.0.1-blue.svg?style=flat-square)](https://vuex.vuejs.org/zh/) > [![echarts](https://img.shields.io/badge/echarts-3.8.3-blue.svg?style=flat-square)](https://github.com/ecomfe/echarts) > [![iview](https://img.shields.io/badge/Axios-2.8.0-blue.svg?style=flat-square)]( https://github.com/axios/axios ) > [![element-ui](https://img.shields.io/badge/element-2.13.2-blue.svg?style=flat-square)](https://element.eleme.cn/#/zh-CN) > > 技术栈: > > - [Vue]( https://cn.vuejs.org/ ) > - [Vue-Router]( https://router.vuejs.org/zh/ ) > - [Vuex]( https://vuex.vuejs.org/zh/ ) > - [Axios]( https://github.com/axios/axios ) > - [ElementUI]( https://element.eleme.cn/#/zh-CN ) > > 开发者: > > - 软件18-1班 @杨诗杰 QQ:1729117218 > - 软件18-2班 @汪凯 **几点说明**: - 秉持着开源至上的精神,本次实训我将前端源码分享给大家,旨在帮助那些前端基础薄弱的小组 - 希望有意使用我们源码的小组同学遵循开源的相关约定,在验收的时候希望能够说明一下源码的引用出处 - 以上这点非常重要!!!如果违背开源精神只会打击想要开源的人 - 实训后期阶段我们会不定期的更新代码,本文档也会随着项目的进行不断更新,如遇问题请同学们私我`QQ:1729117218` - 目前本项目已经实现了`15`个页面,`27`个组件,几乎所有页面的样式已经完成了 - 后阶段我们将陆续增加Axios请求和Vuex以及Echarts数据可视化的内容,同时也将继续优化和完善各个页面的样式和功能 - [后端仓库]( https://gitee.com/big--boss/cloudService ) - [API接口文档]( https://88888-ccs-system.doc.coding.io/#ce9efd4cac0ea6460c0136431082d39a ) # 更新日志(2020/7/3) ### 增加 1. 工单详情页面 2. 新增角色页面 3. 新增客服信息页面 ### 优化 1. 各页面table中展示的信息,及某些标签属性显示,字体颜色显示 2. 会话页面:查看工单详情跳转 3. 访客页面:发起会话跳转至会话页 4. 历史会话页面:(1)编辑中活动性质(2)历史工单查看工单详情跳转 5. 客户详情页面:编辑创建删除拉黑返回,查看详情跳转 6. 工单页面:查看详情跳转 7. 通知公告:CUD 8. 客服页面:CUD,跳转至新增客服页面 9. 分组管理:CUD 10. 角色管理:CUD,跳转至新增角色页面 11. 常用语:CUD 12. 分配规则:解决基础分配点击不顺滑问题 13. 会话评价:好中差评笑脸 14. 客户信息:CUD 15. 客户标签:CUD 16. 黑名单:详情,解禁,详情跳转至客户详情页面 17. 工单分类:CUD 18. 消息通知:清除记录对话框 19. 点击头部header铃铛,跳转至消息通知页面 ### 尚存问题 1. 历史会话页面:筛选按钮,分页 2. 客户标签页面:选择标签颜色 3. 黑名单页面:跳转至详情后,点击返回,应返回黑名单,而不是客户页面 4. 前端表单验证还没有做 # 一、项目效果图 ### 1. 登录页面 ![login](images/login.png) ### 2. 注册页面 ![register](images/register.png) ### 3. 首页 ![index](images/index.png) ### 4. 会话页面 ![session](images/session.png) ### 5. 访客页面 ![visitor](images/visitor.png) ### 6. 工单页面 ![order](images/order.png) ### 7. 统计页面 ![statistic](images/statistic.png) ### 8. 设置页面 ![setting](images/setting.png) # 二、 使用方法 ### 1. 克隆仓库 > 通过`cmd`或`Git Bash`在合适的路径位置输入命令:`git clone git@gitee.com:big--boss/cloudServiceFrontend.git` ### 2. 打开文件夹 利用`VS CODE`(推荐VS CODE)打开克隆下来的仓库文件夹,这时候的项目是跑不起来的,因为没有安装相应的依赖 ### 3. 安装依赖 在VS CODE中通过快捷键Ctrl+`(反引号为Tab上面的那个键)唤出控制台(或终端),通过下列命令安装依赖: `npm install` 如果安装成功,你会发现在项目文件夹中出现了名叫`node_modules`的文件夹,这里面就是下载的依赖 ### 4. 运行项目 在终端输入下列命令来运行项目: `npm run dev` 如果项目正常运行,则会弹出`Your application is running here: http://localhost:8080`的信息 然后点击`http://localhost:8080`便能够在浏览器中运行项目了 ### 5. 注意事项 - 在运行项目之间请确保本地已经安装了`node.js` - 由于不同的机器分辨率的差别,会导致项目效果会有部分差异,推荐使用Chrome浏览器 - 我的机器分辨率为1920*1080,屏幕尺寸为15.6,部分华为笔记本和Mac Book渲染的效果可能会有些许差别 - 由于Vue服务器的默认端口和Spring Boot服务器默认端口相同,因此如果在Spring Boot服务器运行的情况下,是不能运行Vue项目的 - 如果想同时运行前后端项目,请配置后端服务器端口为`8081`(或者为其他),并处理跨域问题 - 如果你不想修改后端项目端口,那么通过修改前端端口也可以很容易的解决端口冲突问题,方法如下: - 找到项目文件夹的config文件夹中的index.js - 修改代码17行附近的port参数即可快速修改前端项目默认运行端口 # 三、 Axios请求基础 ## 1. Axios的安装 #### 全面安装 ` npm install axios -g ` > -g 代表全局安装模块,一般是C:\Users\Administrator\AppData\Roaming\npm\node_modules 中,或是安装在node安装目录下的node_mouldels文件夹中,全局安装只用安装一次 #### 本地安装 `npm install --save dev axios` ` npm install --save axios` `npm install axios ` > 这三种安装方式都会安装模块到项目node_modules目录下 ,只是会有一点细微的差别,不过不影响使用 ## 2. get请求 ```javascript axios.get("URL", { params: {}, headers: {} }).then(res=>{ console.log(res) }).catch(err=>{ console.log(err) }) ``` 1. 参数一代表请求地址 2. 参数二(可选)代表配置信息 - params 表示传递到服务端的数据,以URL参数的形式传递(以&作为分割符) - 例如params={page: 1, limit: 2},则URL为xxx?page=1&limit=2 - headers 表示请求头 3. then为请求成功后的回调函数,res代表请求成功后服务端发过来的返回结果 4. catch为请求失败后的回调函数,err代表请求失败后服务端发过来的返回结果 > 温馨提示:then和catch看不懂的同学可以复习一下`ES6`的`Promise`语法 ## 3. post请求 ```javascript axios.post("URL", {}, {}) .then(res=>{ console.log(res) }).catch(err=>{ console.log(err) }) ``` 1. 参数一代表请求地址 2. 参数二代表前端要向后端传递的数据,在请求体中传递,需要为对象(json)的格式 3. 参数三(可选)代表配置信息 4. then和catch回调函数的意义同上 5. 几点说明: - axios发送的数据默认情况下是`json`格式的 - 默认的headers的content-type为` 'application/json'` ## 4. put请求 ```javascript axios.put("URL", {}, {}) .then(res=>{ console.log(res) }).catch(err=>{ console.log(err) }) ``` > 温馨提示:各个参数的含义同post请求 ## 5. delete请求 ```javascript axios.delete("URL", { params: {}, headers: {} }).then(res=>{ console.log(res) }).catch(err=>{ console.log(err) }) ``` > 温馨提示:各个参数的含义同get请求 # 四、Axios请求的封装 ## 1. 封装Axios请求 > 在项目合适的文件夹位置创建request.js(名字可以自定义,比如我在/utils/request.js中创建),加入如下代码即可实现axios请求的封装 ```javascript import axios from 'axios'; // 创建新的axios实例 const ajax = axios.create({ baseURL: '/api', // 设置默认头部地址,会默认讲该地址拼接到参数的前面 withCredentials: true, // 处理跨域 }); // 写法一 export default { get(url, params) { return ajax.get(url, { params }) }, post(url, data) { return ajax.post(url, data) }, put(url, data) { return ajax.put(url, data) }, delete(url, params) { return ajax.delete(url, { params }) } } ``` ## 2. 封装的Axios请求的使用 #### 在项目的js代码块中导入封装后的axios请求 `import api from '../utils/request'` 几点说明: - 需要使用什么请求就导入什么请求,没必要一起导入 - `../utils/request`为相对路径 #### 在项目中使用封装后的axios ```javascript api.get("URL", {}) .then(res=>{ console.log(res) }).catch(err=>{ console.log(err) }) ``` > 可以看出,和之前的使用方式大体相同,只不过URL可以只写`path路径`,不用写前面的`baseURL` ## 3. 封装Axios写法二 ```javascript import axios from 'axios'; // 创建新的axios实例 const ajax = axios.create({ baseURL: '/api', // 设置默认头部地址,会默认讲该地址拼接到参数的前面 withCredentials: true, // 处理跨域 }); // 写法二 export function get(url, params) { return ajax.get(url, params) } export function post(url, data) { return ajax.post(url, data) } export function put(url, data) { return ajax.put(url, data) } // delete为js保留字,故不能将删除方法命名为delete export function _delete(url, params) { return ajax.delete(url, params) } ``` > 1. 写法二适合分功能引入接口,也就是说需要什么接口就引用什么接口 > 2. 相比较而言,写法一一次性导入了所有接口,封装成api对象,可以通过该对象调用相应接口 > 3. 写法二导入方法:`import {get, post} from '../utils/request' ` #### 在项目中使用封装后的axios ```javascript get("URL", {}) .then(res=>{ console.log(res) }).catch(err=>{ console.log(err) }) ``` > 注意:写法二不用加api.来调用get方法 > > 看不懂的同学可以复习一下ES6的import和export语法 # 五、API请求的封装 ## 1. 创建api.js文件保存所有的API > 在`src`目录下新建文件夹命名为`api`,然后在`api`文件夹中新建文件`api.js` > > 以登录API为例: > > - 先import上一步封装的axios,封装成为api对象 > - 通过api.的方式调用封装的get post put delete方法 ```javascript import api from '@/utils/request' export default { login(data) { return api.post( '/login', data ) } } ``` ## 2. 如何在项目中使用API接口 > 同样以登录为例: > > - 先import上一步创建的api.js,并封装成为api对象 > - 然后就可以在合适的位置通过api.login的方式获取到api.js中的login方法 ```javascript import api from "@/api/api"; export default { name: "Login", components: {}, data() { return { account: "", password: "" }; }, methods: { doLogin() { api.login({ email: this.account, password: this.password }).then(res => { this.$message({ message: "登录成功", type: "success" }); this.$router.replace("/index"); }).catch(err => { this.$message.error(err.response.data.message); // console.log("err"); }); } } }; ``` # 六、使用Vuex保存全局信息(如用户登录状态) ## 1. Vuex的安装和配置 #### 1.1 安装命令: `npm install vuex --save` #### 1.2 导入Vuex包: ```javascript import Vuex from 'vuex' Vue.use(Vuex) ``` #### 1.3 创建store对象: ```javascript const store = new Vuex.Store({ // state 中存放的就是全局共享的数据 state: {count: 0} }) ``` #### 1.4 将store对象挂载到vue实例中 ```javascript new Vue({ el: '#app', router, // 将创建的共享数据对象,挂载Vue实例中 // 所有的组件,就可以直接从store中获取全局的数据 store }) ``` ## 2. Vuex的核心概念 #### 2.1 State State提供了唯一的公共数据源,所有共享的数据都要统一放在Store的State中进行存储。 ```javascript // 创建store数据源,提供唯一公共数据 const store = new Vuex.Store({ state: { count: 0 } }) ``` - 组件访问State中数据的**第一种方式**: `this.$store.state.全局数据名称` - 组件访问State中数据的**第二种方式**: ```javascript // 1. 从vuex中按需导入mapState函数 import { mapState } from 'vuex' // 2. 通过刚才导入的mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性 // 3. 将全局数据,映射为当前组件的计算属性 computed: { ...mapState(['count']) // 对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中 // 可以理解为将对象的属性打散 } ``` #### 2.2 Mutation Mutation用于变更Store中的数据。 - **只能通过mutation变更Store数据,不可以直接操作Store中的数据。** - 通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。 - 组件访问Mutation的**第一种方式**: ```javascript // 定义Mutation const store = new Vuex.Store({ state: { // 需要定义的全局变量 }, mutations: { add(state) { // 变更状态 state.count++ } } }) // 触发mutation methods: { handleAdd() { // 触发mutations的第一种方式 this.$store.commit('add') } } ``` 可以在触发mutations的时候传递参数: ```javascript // 定义Mutation const store = new Vuex.Store({ state: { // 需要定义的全局变量 }, mutations: { add(state, step) { // 变更状态 state.count += step } } }) // 触发mutation methods: { handleAdd() { // 触发mutations的第一种方式 // commit函数的第二个参数就是在mutations中的函数的传参 this.$store.commit('add', 3) } } ``` - 组件访问Mutation的**第二种方式**: this.$store.commit()是触发mutations的第一种方式,下面是触发mutations的第二种方式: ```javascript // 1. 从vuex中按需要入mapMutations函数 import { mapMutations } from 'vuex' // 2. 通过刚才导入的mapMutations函数,将需要的mutations函数,映射为当前组件的methods方法: methods: { ...mapMutations(['add', 'addN']) btnHandler() { this.add() // 调用mutations中的add函数 } } ``` - **不要再mutations函数中,执行异步操作,需要执行异步操作的时候,需要在action中执行** #### 2.3 Action - Action用于处理异步任务。 - 如果通过异步操作变更数据,必须通过Action,而不能直接使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据,action中不能直接修改state中的数据。 ```javascript // 定义Action const store = new Vuex.Store({ mutations: { add(state) { state.count++ } }, actions: { addAsync(context) { setTimeout(() => { // commit的作用是触发某个mutation函数 context.commit('add') }, 1000) } } }) // 触发Action methods: { handle() { handle() { // 触发actions的第一种方式 // dispatch的作用是触发某个action函数 this.$store.dispatch('addAsync') } } } ``` #### 2.4 Getter - Getter用于对Store中的数据进行加工处理形成新的数据,类似Vue中的计算属性。 - Store中数据发生变化,Getter的数据也会跟着变化。 - **Getter不会修改State中存储的数据**,只起到一个包装的作用。 ```javascript // 定义Getter const store = new Vuex.Store({ state: { count: 0 }, getters: { showNum: state => { return state.count // 等价于 return 0 } } }) ``` - 组件访问getters的第一种方式: ```javascript this.$store.getters.方法名称 ``` - 组件访问getters的第二种方式: ```javascript import { mapGetters } from 'vuex' computed: { ...mapGetters(['showNum']) } ``` ## 3. 如何解决刷新浏览器后Vuex状态消失的问题 [推荐博客1]( https://blog.csdn.net/guzhao593/article/details/81435342 ) [推荐博客2]( https://blog.csdn.net/wang1006008051/article/details/82424335 )