# 校友捐赠管理系统
**Repository Path**: xw_126754/adms
## Basic Information
- **Project Name**: 校友捐赠管理系统
- **Description**: 校友捐赠管理系统前端仓库地址
- **Primary Language**: JavaScript
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 3
- **Created**: 2023-03-19
- **Last Updated**: 2023-03-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
### 项目介绍
+ 校友捐赠管理系统(Alumni donation management system)主要用途是用于燕山大学基金会的捐赠流程管理。
+ 该仓库是项目[前端地址](https://gitee.com/wanxiaoguo/adms)
+ 项目的[微服务后端地址](https://gitee.com/liuyongtest/xiaoyou)
+ 项目的[单体程序Springboot后端地址](https://gitee.com/wanxiaoguo/adms_back)
### 项目启动
+ IDE: 我这里使用的vs-code
+ 导入后首先安装依赖
```
cnpm install
```
+ 启动项目
```
npm run serve
```
+ 生产阶段启动
```
npm run build
```
+ 使用eslint 检查
```
npm run lint
```
### 后台项目启动
+ 导入数据库`adms.sql`
+ 选择微服务或者单体应用版本
+ 打开浏览器输入 `localhost` 到后台系统登录页 默认是超级管理员账号
### 添加配置文件
+ 添加`vue.config.js`
+ 自定义`html-webpack-plugin`信息: 修改标题
+ [options参考](https://github.com/jantimon/html-webpack-plugin)
```js
module.exports = {
// 修改或新增html-webpack-plugin的值,在index.html里面能读取htmlWebpackPlugin.options.title
chainWebpack: config => {
config.plugin('html')
.tap(args => {
args[0].title = '校友捐赠管理系统'
return args
})
}
}
```
### 文件说明
+ `assets`: 放置静态资源文件
+ `views`: 放的`` 显示的视图页面
+ `components`: 放置模块所需要的组件
+ `router`: 放置路由
+ `store`: 放置`vuex`状态管理文件,并且单独写在一个文件,这里还没有进行模块管理,内容也不多
+ `utils`: 放置一些工具类
+ `axiosUtil`: 对`axios`的请求进行封装,并使用`element-ui`组件进行提示 并在 `main.js` 添加到原型上
+ `checkUtil`: 加入一些常用的校验规则, 包含手机号、邮箱、身份证号码
+ `storageUtil`: 使用浏览器的session、local存储信息
+ `commonUtil`: 通用工具类:判空
+ `main.js`: 入口文件
+ `vue.config.js`: webpack配置,标题,启动选项
### 登录
+ router/index.js 定义路由 并把'/'重定向 登录页
```js
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login')
},
```
+ 在router/index.js 添加路由守卫 , 对于本地未存储token 的路径访问强制跳转到 login
```js
// 挂载路由导航守卫
router.beforeEach((to, from, next) => {
// to 将要访问的路径
// from 代表从哪个路径跳转而来
// next 是一个函数,表示放行
// next() 放行 next('/login') 强制跳转
if (to.path === '/login') return next()
// 获取token
const tokenStr = window.sessionStorage.getItem('token')
if (!tokenStr) return next('/login')
next()
})
```
+ axios 添加拦截器 在请求头里放入 token 值
```js
axios.interceptors.request.use(config => {
config.headers.Authorization = window.sessionStorage.getItem('token')
// 在最后必须 return config
return config
})
```
+ 登录成功后把token存储起来
```js
window.sessionStorage.setItem('token', res.data.token)
```
### 使用props在父子组件传值
+ 在子组件 使用props来接收父组件传过来的值
``` html
{{msg2}}
```
+ 在父组件 导入子组件并加载到组件中,使用时传参数时 对与非字符串和变量应使用数据绑定`:`
```html
```
#### .sync 修饰符
+ [文档位置](https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-%E4%BF%AE%E9%A5%B0%E7%AC%A6)
+ 对于constant-type 和 edit.vue 组件
+ constant-type/index.vue
```html
```
+ edit.vue
```html
```
### vuex使用
+ 原理图
[](https://imgchr.com/i/dR7KWd)
+ 将vuex不同属性定义再不同的文件里,这里举一个左侧菜单栏的折叠功能
```js
//state.js
export default {
isCollapse: false
}
// 推荐把mutation里的方法采用变量定义,且将方法名定义到另外一个常量文件里 比如mutation-types.js
export const TOGGLE_COLLAPSE = 'toggleCollapse' // 折叠左侧菜单栏
// mutation.js
import { TOGGLE_COLLAPSE } from './mutation-types'
export default {
[TOGGLE_COLLAPSE] (state) {
state.isCollapse = !state.isCollapse
}
}
// action
import { TOGGLE_COLLAPSE } from './mutation-types'
export default {
toggle_collapse ({ commit }) {
commit(TOGGLE_COLLAPSE)
}
}
```
+ 在组件里的使用
+ `Menu.vue`
```js
import { mapState } from 'vuex'
export default {
/*
从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态
当 状态 变化的时候, 都会重新求取计算属性,并且触发更新相关联的 DOM。
获取方式一: this.$store.state.isCollapse
通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。
获取方式二: 使用 mapState 辅助函数帮助生成计算属性 并且使用了对象展开运算符 传对象的时候方便自己定义名称
*/
computed: {
...mapState({
isCollapse: 'isCollapse'
})
}
}
```
+ `Home.vue`
```js
import { mapState, mapActions } from 'vuex'
export default {
computed: {
...mapState({
isCollapse: 'isCollapse'
})
},
methods: {
/*
在组件中使用 this.$store.dispatch('xxx') 分发 action
mapActions 是action的辅助函数 ,同时可以传数组,选择自己需要的action 函数
*/
...mapActions([
'toggleCollapse'
])
},
}
```
### 批量删除
+ 利用post方法
```java
@Override
public boolean batchdel(Integer[] ids) {
ConstantType constantType = new ConstantType();
constantType.setActive(0);
UpdateWrapper wrapper = new UpdateWrapper<>();
List list = new ArrayList<>(ids.length);
Collections.addAll(list,ids);
wrapper.in("id",list);
return this.update(constantType,wrapper);
}
```
+ 对于使用delete 方法 直接传参时 url为 `http://127.0.0.1:8088/constantTypes/batchdel?ids[]=6`
未对数据使用深度序列化,需要配置选择
+ 我采用字符串`,`分割的方式降低难度
```js
batchdel () {
if (this.selectedrow.length === 0) {
this.$message('没有任何被选中的数据')
} else {
const ids = []
for (let i = 0; i < this.selectedrow.length; i++) {
ids.push(this.selectedrow[i].id)
}
this.$axios.del('/constantTypes/batchdel',
() => {
if (this.total === (this.queryInfo.page - 1) * this.queryInfo.limit + ids.length) this.queryInfo.page -= 1
this.getData()
},
{
ids: ids.join(',')
}
)
}
},
```
+ 后端
```java
@DeleteMapping("/batchdel")
public Result batchDel(@RequestParam String ids){
String [] idList = ids.split(",");
List list = new ArrayList<>(idList.length);
for (String id:idList){
list.add(Integer.parseInt(id));
}
if(constantTypeService.removeByIds(list)) return ResultGenerator.getSuccessResult("","删除成功");
return ResultGenerator.getFailResult("","删除失败");
}
```
+ 也可以使用mybatis-plus提供逻辑删除
### 表单添加自定义规则
```js
data () {
// name 必须唯一的
var checkName = (rule, value, cb) => {
// console.log(value)
// value 传入的校验值
const promise = this.$axios.http.get('/constantTypes/check', { params: { name: value } })
promise.then(
response => {
if (response.data.status !== 200) {
// 返回ERROR 表示 验证不符合要求
cb(new Error('该常数类别代码存在'))
}
// 这是返回正确的
cb()
}
)
},
rules: {
code: [
{ required: true, message: '编码不能为空', trigger: 'blur' },
{ min: 1, max: 100, message: '长度在 1 到 100 个字符', trigger: 'blur' },
{ validator: checkName, trigger: 'blur' }
]
}
}
}
```
### ajax请求包axios
+ 对axios进行一些处理,包装一下
+ 定义自己的请求基路径`axios.defaults.baseURL`
+ 为了能够在全局使用把axios挂载到Vue函数对象的原型上`Vue.prototype.$axios = axios`,这样在组件里通过`this.$axios`访问
### 路径使用
+ `./`指当前目录
+ `../`指当前目录的上一层目录
+ vue的使用路径中的`@`代表“src目录”这个是webpack起的别名;在`webpack.base.conf.js`中有声明
+ `extensions`: 在导入语句没带文件后缀时,webpack会自动按照顺序添加后缀名查找
```js
// 连接路径并返回
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
resolve: {
// 在导入语句没带文件后缀时,webpack会自动按照顺序添加后缀名查找
extensions: ['.js', '.vue', '.json'],
// 配置别名
alias: {
'vue$': 'vue/dist/vue.esm.js',
// 将项目根目录中,src的路径配置为别名@
'@': resolve('src'),
}
}
}
```
+ 在webpack中有这个配置`resolve.mainFiles: ["index"]` 解析目录时要使用的文件名。
+ 根据上面说的`() => import('@/views/constant-type')` 以及实际项目情况对应的路径是 `项目根路径/src/views/constant-type/index.vue`
+ >> 在浏览器的中对'/home' 中/ 会解析为 协议://主机名:端口号/ 再拼接上home 作为路径
### 问题记录
+ 如果在删除的数据,当前页的数据刚好为删除数据的个数此时 应该修改当前页
```js
this.$axios.del(`/constantTypes/${id}`, () => {
if (this.total === (this.queryInfo.page - 1) * this.queryInfo.limit + 1) this.queryInfo.page -= 1
this.getData()
})
```
+ element-ui select 下拉框位置错乱
```html
```
+ 使用`Steps`步骤条和`Tabs` 选项卡组件的 使用 `:active="parseInt(activeIndex)"` 两者使用不同的类型
+ `Steps active` 是需要数值
+ `Tab name` 需要字符串
+ element-ui `checkbox`
+ 在这里需要显示所有的角色,向后台传角色的id,前台显示角色名称
+ :label 是向后台传送的值 显示的值应使用`{{}}` 不能`true-label`和`false-label` 指定相同的值,不然如何点击
```html
{{role.name}}
```
### vscode插件推荐
