# 项目文档 ## 大卫博士app后台 ### 项目运行 1. npm run dev 项目启动 2. npm run build:prod 项目打包 ### 项目解构 1. vue.config.js 本地测试proxy 修改项目地址 2. .env.production 正式打包接口地址 3. src ### src 目录 1. api 文件夹 接口地址 2. assets 静态资源地址 3. components 组件 4. directive vue 自定义指令 v-directive 5. filterRouter 动态加载权限路由, PS: 重要,一般情况用不到 6. filters 公共方法 和 过滤器文件合集 7. icons 主要用于右侧操作栏图标 8. layout 后台框架 PS: 重要, 一般情况不会修改 9. pages 文件页面 PS: 重要 10. router 路由文件 PS: 重要 11. store 状态存储文件 PS: 重要 12. styles 样式文件 css / scss 文件 13. utils 公共方法 14. vendor excel 文件导出js 15. App.vue 16. main.js 17. permission.js 动态路由验证js PS: 重要 一般路由出错,在这里测试 18. setting.js 配置信息js ### 项目路由加载过程 > pages/backstage/role.vue 创建角色 > > 加载 router/auth.js 中 asyncRoutes import { asyncRoutes } from '@/router/auth' > > 根据 asyncRoutes 进行深度遍历, 转换 生成 tree > > 获取选择的路由, 上传服务器保存 > pages/backstage/account.vue 添加账户 > > 账户选择角色 > store/modules/user.js 用户登录 > > __getInfo()__ 方法获取用户信息, 包含角色信息, 路由信息 > > 将获取的权限路由 合并 router/auth.js 中 普通路由(defaultRoutes) 和 开发者路由(developerRoutes) > permission.js > > 将合并路由生成路由树进行页面加载 > > import { filterRouter } from '@/filterRouter' > > accessRoutes = filterRouter(routes) > > router.addRoutes(accessRoutes) __Ps: 本质是将本地路由文件和服务器保存的路由进行比对加载__ __Ps: 一般路由报错结果均为本地路由和服务器路由不一致造成__ __Ps: store/modules/user.js 中 getInfo() 里,根据角色名判断:root角色直接使用本地路由__ __Ps: 所以出现路由错误时请登录root角色账户,修改错误角色账户__ ### 按钮权限判断 > 根据 router/auth.js 中定义 meta 属性值 authList 和 buttonAuthList判断 ``` mete: { authList: [ { name: '客服审核', value: 0 }, { name: '财务审核', value: 1 } ], buttonAuthList: [] } ``` > 进行路由加载相同过程, 唯一区别为: 在创建角色中, 选择authList中权限, 赋值 buttonAuthList 中 > > 例: 选择为财务审核权限, 即 ``` buttonAuthList = [1] ``` > buttonAuthList 值为 authList 中 value 值构成的数组 > 在页面中添加权限判断, 具体请参考: pages/order/list.vue ``` data() { return { roles: this.$route.meta.buttonAuthList ? this.$route.meta.buttonAuthList : [] } } ``` ``` 财务审核 导出 ``` > 在 directive/permission/permission.js 中定义 自定义指令 v-permit > > 判断路由meta中是否包含v-permit值, 来显示或隐藏元素 __Ps: root角色同样具有所有权限指令__ ### pages 目录 __pages目录为主要修改目录, 具体功能请翻阅代码__ [地址](http://git.web.ximengnaikang.com:3000/daweiboshi-app/appadmin.git) ## 大卫博士争霸赛后台 __大卫博士争霸赛后台与H5后台使用相同后台模板, 具有相似性__ ### 项目路由加载过程 __争霸赛后台路由加载和H5后台过程基本相同, 仅有部分区别__ > 在permission.js中 >> 争霸赛后台代码为: ``` const { routes } = await store.dispatch('user/getInfo') const accessRoutes = await store.dispatch('permission/generateRoutes', routes) router.addRoutes(accessRoutes) ``` >> H5后台为 ``` const { routes } = await store.dispatch('user/getInfo') import { filterRouter } from '@/filterRouter' accessRoutes = filterRouter(routes) ``` > 其中争霸赛后台调用 store/modules/permission.js 里 generateRoutes 方法 > H5 后台为加载 filterRouter/index.js 里 filterRouter 方法 ### 按钮权限 > 争霸赛按钮权限设置在 views/role.vue 下手动定义 4个值 BP1 - BP4, 并在上传时在 路由中push了一个数组 ``` data() { return { BP1: '', BP2: '', BP3: '', BP4: '' } } /上传管理[上传成功] / 调整数据 按钮 /报名管理 / 退款 按钮 /报名管理 / 取消比赛资格 按钮 /兑换管理 / 清除兑换记录 按钮 routes.push([this.BP1 ? 'BP1' : '', this.BP2 ? 'BP2' : '', this.BP3 ? 'BP3' : '', this.BP4 ? 'BP4' : '']) ``` __routes为选择的路由数组__ > 在获取用户信息是将值赋值个 store.user.BP, 代码在 store/modules/user ``` const mutations = { SET_BP(state, BP) { state.BP = BP } } commit('SET_BP', data.routes.some(e => Array.isArray(e)) ? data.routes.pop() : ['*']) ``` > 使用时判断值是否存在, 代码如: (上传权限) views/UploadManage.vue ``` v-if="$store.state.user.BP.includes('BP1') || $store.state.user.BP.includes('*')" ``` __其他功能与H5后台类似, 具体请翻阅代码__ [地址](http://git.web.ximengnaikang.com:3000/daweiboshi/admin.git) ## 大卫博士实战营后台 __实战营后台与争霸赛后台使用相同模板, 具体功能参考争霸赛后台__ [地址](http://git.web.ximengnaikang.com:3000/daweiboshi_szy/weappadmin.git) ## 大卫博士下单微信H5 __下单H5目前正和微店项目整合, 具体功能请期待整合完毕后添加__ ### 需特别注意 1. H5项目代码里有些地方, 导航切换使用mixin, 请注意, 例如: pages/my-invite/my-invite [地址](http://git.web.ximengnaikang.com:3000/daweiboshi-app/web-app.git) ## 大卫博士争霸赛小程序 ### 争霸赛小程序代码存在大量冗余, 请注意一些问题 1. 接口封装调用, 请参考 common/js/ajax 和 pages/index/index 查看使用方法 2. 页面代码中可能会同时使用 created/mounted/onLoad/onShow, 请注意 3. 页面代码中会出现一些$on事件传递, 最好不要进行修改, 可能出现问题, 如下 ``` // pages/index/index uni.$on('MESSAGE', (m, d, p) => { //m 要提示的文字信息 d 文字信息出现的时常 p 文字信息出现的位置 this.$refs.toast.hover(m, d, p) }) uni.$on('HIDEMESSAGE', () => { // 隐藏 文字提示 this.$refs.toast.hide() }) ``` 4. 关于检测用户信号代码, 也请勿修改, 可能会出现问题, 如下 ``` // App.vue uni.onNetworkStatusChange(({ networkType, isConnected }) => {}) // pages/index/index if ('wifi2g3g4g'.indexOf(this.networkType) !== -1) {} ``` 5. 由于最初代码使用自定义导航栏, 所以页面代码中会出现如下代码: ``` ``` __这种可直接使用原生导航栏, 即:设置pages.json中style的属性__ __Ps: pages/course/list 页面比较特殊, 由于需要监听导航栏返回, 所以必须使用自定义导航栏__ 6. 可能有些页面会出现以下代码 ``` this.$scrollViewHeight('.content') //设置页面内 scroll view 的高度 ``` __这种写法请勿参考, 请使用flex布局__ 7. 由于代码中根据人物等级判断较多, 请设置store.js模拟 ``` // payload.cha_nickname = 'TEST1211313123' // payload.signuped = false // payload.score = 5000 // payload.type = 3 // payload.level_name = '代理公司' // payload.money = 1 // payload.status = 1 ``` __Ps: 上传正式代码,请注释以上代码__ [地址](http://git.web.ximengnaikang.com:3000/daweiboshi/weapp.git) ## 大卫博士争霸赛小程序-重构版 __重构版争霸赛小程序未进行大量测试, 如要上线请先对照原版小程序就行完整测试__ __具体请点击地址查看项目 [重构版-readme.md](http://git.web.ximengnaikang.com:3000/caokai/xcx_zhengbasai_reset/src/master/readme.md)文件__ [地址](http://git.web.ximengnaikang.com:3000/caokai/xcx_zhengbasai_reset.git) ## 大卫博士实战营小程序 __实战营小程序参与较少, 这里只介绍实战营登录过程__ ### 实战营登录 > 实战营登录在原有基础上有 pages/index/index 登录页变为 pages/login/login > 登录过程分为4类, 定义了 loginStatus, 0: 将要微信授权 , 1: 定位授权 , 2: 服务器登录 , 3: 服务器登录时判断需要手机号验证 ``` data() { return { loginStatus: 0 } } watch: { // 简单登陆进度状态变化 loginStatus(s) { this.toLoginProgress(s) }, } methods:{ toGetUserInfo() {}, // 获取微信授权, 成功时: ++this.loginStatus 0 -> 1 toGetUserLocation() {}, // 获取位置, 成功时: ++this.loginStatus 1 -> 2 toServerWxLogin() {}, // 服务器的登录, 根据返回code判断 code === 300 时, ++this.loginStatus 2 -> 3 toLoginProgress() { let m = new Map([ [1, this.toGetUserLocation], [2, this.toServerWxLogin], [3, () => this.phoneLogin = true] ]) let s = this.loginStatus return m.get(s)() } } ``` __具体请翻阅代码__ [地址](http://git.web.ximengnaikang.com:3000/daweiboshi_szy/weapp-online.git) ## 大卫博士扫码枪应用 __项目有原生HTML开发__ __项目分为4个部分__ > 1. 登录 index.html > > 用户登录,获取token,localStorage缓存token > 2. 商品信息 product.html > > 扫描商品码获取商品信息 > > 此页面需要注意修改所属人时, 通过合并session缓存 ``` checkSelectUser() { let data = sessionStorage.getItem("user") if(data) { let user = JSON.parse(data) this.productInfo = Object.assign(this.productInfo, user) sessionStorage.removeItem("user") this.$forceUpdate() } } ``` __Ps: this.productInfo为包含所属人信息对象__ > 3. 发货扫码 qrcode.html > > 发货扫码页面需要注意 > > 1. 因为保持连续扫码, 且扫码结果是填充input值的形式(onInput监听值), 所以需要是 input 一直保持焦点 > > ``` onFocus() { this.$nextTick(() => { this.$refs.qrcode_text.focus() }) } onBlur() { this.onFocus() } ``` > > 2. 在onInput中解析值, 因为获取的值会包含上次输入值, 所以需要解析并转化 > > ``` onInput(e) { let checkUrl = "fangw.jiuweiyun.cn" let val = e.target.value // val: http://fangw.jiuweiyun.cn/d20210318xxx 格式 if(val.indexOf(checkUrl) === -1){ // 过滤非checkUrl网站的码 window.ELEMENT.Message.error('无效防伪码,已自动过滤') return false } let _a = val.split('/') let _v = _a[_a.length - 1] if(!_v) { // 分割后如果不存在防伪码值, 结束 return false } this.old_code.push(_v) // 记录所有扫到的码 let i = this.filter_old_code.findIndex(v => v === _v) // 此防伪码是否只存在1个 if(i !== -1) { // 已经存在防伪码 this.filter_old_code.splice(i, 1) // 删除原来的 this.filter_code_type.splice(i, 1) // 删除原来的 Object.keys(this.goosQrcodeSelect).forEach(k => { // 查找在其他分类下(老人版. 简约版等)存不存在, 自己分类存不存在重复 let _i = this.goosQrcodeSelect[k].includes(_v) ? this.goosQrcodeSelect[k].findIndex(tv => tv === _v) : -1; if(_i !== -1) { if(+k !== this.good_select_id) { // 如果其他分类里有, 将其转换成当前分类 window.ELEMENT.Message.error(`防伪码由${this.goodList.find(({ id }) => +id === +k).good_name}替换为${this.goodList.find(({ id }) => +id === +this.good_select_id).good_name}`) } else { // 如果当前分类有, 提示 window.ELEMENT.Message.error('此类型下防伪码已存在') } this.goosQrcodeSelect[k].splice(_i, 1) // 重原分类删除 } }) } this.goosQrcodeSelect[String(this.good_select_id)].push(_v) // 添加进新分类 this.filter_old_code.push(_v) // 添加到过滤码中 this.filter_code_type.push(this.goodList.find(_g => +_g.id === +this.good_select_id).good_name.replace('大卫博士', '')) // 添加到过滤类型中 this.qrcode = _v // input 显示当前码的值 } ``` >> __Ps: filter_old_code 和 filter_code_type相互对应, 如果新增就同时新增,如果删除就同时删除__ >> __Ps: 具体请结合页面效果查看代码__ > 4. 切换商品所属人 search.html > > 通过页面参数id, 获取用户信息(参数可以为空) > > 此页面需要注意: 选择的所属人将会转换成固定格式缓存进 session, 并返回 product.html 执行合并 ``` let user = { belong_user_mobile: data.phone, belong_user_nickname: data.nickname, belong_user_id: data.id, belong_user_avatar: data.avatar } sessionStorage.setItem('user', JSON.stringify(user)) window.history.back() ``` __Ps: 因为合并执行 Object.assign(), 随意需要时user属性和 product.html 中 this.productInfo 属性保持一致__ __Ps: 打包时请注意安卓证书, 如果证书丢失请自行生成[安卓证书在线生成工具](http://www.appuploader.net/appuploader/keystore.php)__ [地址](http://git.web.ximengnaikang.com:3000/caokai/saomaqiang.git) ## 大卫博士手机扫码应用 __手机版扫码应用同扫码枪应用相识, 请参考扫码枪应用__ __Ps: 手机版打包发行同样需要安卓证书__ [地址](http://git.web.ximengnaikang.com:3000/caokai/saoma_mobile_app.git) ## 大卫博士授权查询web __Ps: 此项目非常简单, 具体请查看代码__ [地址](http://git.web.ximengnaikang.com:3000/caokai/dwbs_chaxunshouquan.git) ## 大卫博士授权查询Pc __Ps: 此项目非常简单, 具体请查看代码__ [地址](http://git.web.ximengnaikang.com:3000/caokai/shouquanchaxun_pc.git) ## 瞳年小程序 __Ps: 瞳年小程序由争霸赛小程序复制而来, 详情请参考争霸赛小程序__ [地址](http://git.web.ximengnaikang.com:3000/tongnian/weapp.git) ## 瞳年后台 __瞳年后台由大卫博士app后台拷贝修改而来, 具体请参考app后台__ [地址](http://git.web.ximengnaikang.com:3000/tongnian/admin-tongnian.git) ## 田知花小程序(书画绘画小程序) __田知花小程序是在[果酱社区开源小程序](https://github.com/guojiangclub/miniprogram-ecommerce-open-source.git)基础上修改的小程序__ ### 项目运行 1. npm run dev 2. 打开微信开发者工具->小程序->导入项目-> 选择src 文件夹 __Ps: 本地测试请勿关闭 npm run dev__ ### 项目打包 npm run build __Ps: 此项目非常简单, 具体请查看源代码__ [地址](http://git.web.ximengnaikang.com:3000/xmnk/course-weapp.git) ## 缴纳党费小程序 __Ps: 此项目非常简单, 具体请查看源代码__ [地址](http://git.web.ximengnaikang.com:3000/caokai/jiaonadangfei.git)