├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── client ├── assets │ ├── README.md │ ├── images │ │ ├── 403.svg │ │ ├── 404.svg │ │ ├── default-avatar.png │ │ ├── default-img.png │ │ ├── login-bg-0.jpg │ │ ├── login-bg-1.jpg │ │ └── login-bg-2.jpg │ ├── scripts │ │ └── i18n │ │ │ ├── en-us.js │ │ │ └── zh-cn.js │ └── styles │ │ ├── common │ │ ├── constant.css │ │ ├── constant.less │ │ ├── reset.css │ │ ├── theme.default.css │ │ └── theme.default.less │ │ ├── default-theme │ │ ├── config.json │ │ ├── style.zip │ │ └── theme │ │ │ ├── fonts │ │ │ ├── element-icons.ttf │ │ │ └── element-icons.woff │ │ │ └── index.css │ │ └── layout │ │ ├── index.css │ │ └── index.less ├── base │ └── config.js ├── components │ ├── AppTables │ │ └── index.vue │ ├── AppTreeTable │ │ ├── eval.js │ │ └── index.vue │ ├── CardContainer │ │ └── index.vue │ ├── Dialog copy │ │ └── index.vue │ ├── DialogContainer │ │ └── index.vue │ ├── ImgDialog │ │ └── index.vue │ ├── Layout │ │ ├── components │ │ │ ├── 403 │ │ │ │ └── index.vue │ │ │ ├── 404 │ │ │ │ └── index.vue │ │ │ ├── Header │ │ │ │ ├── BreadcrumbBar │ │ │ │ │ └── index.vue │ │ │ │ ├── PersonalCenter │ │ │ │ │ └── index.vue │ │ │ │ └── index.vue │ │ │ ├── Sidebar │ │ │ │ └── index.vue │ │ │ └── TagsView │ │ │ │ └── index.vue │ │ └── index.vue │ ├── README.md │ ├── ReadFileDialog │ │ └── index.vue │ ├── ScrollPane │ │ └── index.vue │ └── index.js ├── filters │ └── index.js ├── http │ ├── index.js │ ├── interceptor.js │ ├── models │ │ ├── common.js │ │ ├── index.js │ │ ├── system.js │ │ └── types.js │ └── wrapper.js ├── layouts │ ├── default.vue │ ├── empty.vue │ └── error.vue ├── lib │ └── util.js ├── middleware │ ├── README.md │ ├── authorities.js │ ├── stats.js │ └── test.js ├── pages │ ├── Home │ │ └── Welcome │ │ │ └── index.vue │ ├── Login │ │ ├── LoginForm │ │ │ └── index.vue │ │ └── index.vue │ ├── README.md │ └── System │ │ ├── AdminManage │ │ ├── AdminForm │ │ │ └── index.vue │ │ ├── BindRoleForm │ │ │ └── index.vue │ │ └── index.vue │ │ ├── FilesManage │ │ ├── FileForm │ │ │ └── index.vue │ │ └── index.vue │ │ ├── LogsManage │ │ ├── ReadLogDialog │ │ │ └── index.vue │ │ └── index.vue │ │ ├── PermissionManage │ │ ├── PermissionForm │ │ │ └── index.vue │ │ └── index.vue │ │ └── RolesManage │ │ ├── RoleForm │ │ └── index.vue │ │ ├── Settings │ │ └── _id.vue │ │ └── index.vue ├── plugins │ ├── README.md │ ├── axios.js │ ├── components.js │ ├── element-ui.js │ ├── filters.js │ └── i18n.js └── store │ ├── README.md │ ├── actions.js │ ├── getters.js │ ├── index.js │ ├── models │ ├── tabsview.js │ ├── test.js │ └── users.js │ ├── mutations.js │ ├── state.js │ └── types.js ├── docs-v1.0.0.zip ├── docs-v1.0.0 ├── deploy.sh ├── docs │ ├── .vuepress │ │ ├── config.js │ │ └── public │ │ │ └── images │ │ │ ├── favicon.ico │ │ │ └── logo.png │ ├── README.md │ └── zh │ │ └── guide │ │ ├── README.md │ │ ├── directory-structure.md │ │ ├── install.md │ │ └── test.md └── package.json ├── jsconfig.json ├── nuxt.config.js ├── package.json ├── pm2.config.js ├── server-dist.zip ├── server-dist ├── index.js └── src │ ├── bin │ └── Server.js │ ├── config │ └── server.base.config.js │ ├── controllers │ ├── index.js │ └── models │ │ ├── common │ │ ├── FilesController.js │ │ ├── LoginController.js │ │ └── UtilsController.js │ │ ├── index.js │ │ └── system │ │ ├── AdminController.js │ │ ├── LogsController.js │ │ ├── PermissionController.js │ │ └── RolesController.js │ ├── lib │ ├── Email.js │ ├── FileUtils.js │ ├── Result.js │ ├── Utils.js │ ├── logger4.js │ ├── sequelize.js │ └── userAgents.js │ ├── middleware │ ├── ErrorRoutesCatch.js │ └── index.js │ ├── models │ ├── common │ │ ├── FilesBaseModel.js │ │ └── RegionModel.js │ └── system │ │ ├── AdminBaseModel.js │ │ ├── PermissionModel.js │ │ ├── RolesAuthModel.js │ │ └── RolesBaseModel.js │ └── services │ ├── common │ ├── FilesService.js │ ├── LoginService.js │ └── UtilsService.js │ └── system │ ├── AdminService.js │ ├── LogsService.js │ ├── PermissionService.js │ ├── RolesService.js │ └── SysRolesService.js ├── server ├── index.js └── src │ ├── bin │ └── Server.js │ ├── config │ └── server.base.config.js │ ├── controllers │ ├── index.js │ └── models │ │ ├── common │ │ ├── FilesController.js │ │ ├── LoginController.js │ │ └── UtilsController.js │ │ ├── index.js │ │ └── system │ │ ├── AdminController.js │ │ ├── LogsController.js │ │ ├── PermissionController.js │ │ └── RolesController.js │ ├── lib │ ├── Email.js │ ├── FileUtils.js │ ├── Result.js │ ├── Utils.js │ ├── logger4.js │ ├── sequelize.js │ └── userAgents.js │ ├── middleware │ ├── ErrorRoutesCatch.js │ └── index.js │ ├── models │ ├── common │ │ ├── FilesBaseModel.js │ │ └── RegionModel.js │ └── system │ │ ├── AdminBaseModel.js │ │ ├── PermissionModel.js │ │ ├── RolesAuthModel.js │ │ └── RolesBaseModel.js │ ├── public │ └── uploads │ │ └── 20191104 │ │ └── BIUXS_WEB_69B09D4F1CE6816CEE4E0C5015B9996C.jpg │ └── services │ ├── common │ ├── FilesService.js │ ├── LoginService.js │ └── UtilsService.js │ └── system │ ├── AdminService.js │ ├── LogsService.js │ ├── PermissionService.js │ └── RolesService.js ├── sqls └── biu_server_db.sql └── 代码提示.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"] 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .nuxt 2 | .vscode 3 | /nuxt-dist 4 | /node_modules 5 | /client/router 6 | /client/base 7 | /client/http/interceptor.js 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | //https://vuejs.github.io/eslint-plugin-vue/rules/ 2 | module.exports = { 3 | root: true, 4 | //想要支持的JS语言选项 5 | parserOptions: { 6 | parser: 'babel-eslint', 7 | //启用ES6语法支持(如果支持es6的全局变量{env: {es6: true}},则默认启用ES6语法支持) 8 | //此处也可以使用年份命名的版本号:2015 9 | ecmaVersion: 6, 10 | //默认为script 11 | sourceType: 'module', 12 | //支持其他的语言特性 13 | ecmaFeatures: { 14 | //... 15 | } 16 | }, 17 | env: { 18 | browser: true, 19 | es6: true 20 | }, 21 | //集成推荐的规则 22 | extends: ['standard', 'plugin:vue/recommended'], 23 | plugins: ['html', 'vue'], 24 | globals: { 25 | 'filterVal': false 26 | }, 27 | // add your custom rules here 28 | rules: { 29 | // allow async-await 30 | 'generator-star-spacing': 'off', 31 | // allow debugger during development 32 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 33 | 'semi': [2, 'always'], //语句强制分号结尾. 34 | //"indent": ["error", "tab"], //缩进风格 35 | 'indent': [2, 4], //缩进风格 36 | 'no-mixed-spaces-and-tabs': [2, true], 37 | 'vue/max-attributes-per-line': 0, 38 | 'spaced-comment': 0, //注释风格要不要有空格什么的 39 | 'eqeqeq': 0, //必须使用全等 40 | 'no-tabs': 'off', //禁止使用tab 41 | 'no-return-assign': 0, //return 语句中不能有赋值表达式 42 | 'no-extra-parens': 'off', //禁止混用不同的操作符 43 | 'no-mixed-operators': 'off', //禁止混合使用不同的操作符 44 | 'space-before-function-paren': [0, 'always'], //方法空格 45 | 'eol-last': [0, 'always'], //结尾换行 46 | 'vue/html-indent': ['error', 4, { //vue缩进 47 | 'attribute': 1, 48 | 'baseIndent': 1, 49 | 'closeBracket': 0, 50 | 'alignAttributesVertically': true, 51 | 'ignores': [] 52 | }], 53 | 'vue/no-multi-spaces': ['error', { //去除多余的空格 54 | 'ignoreProperties': false 55 | }], 56 | 'vue/component-name-in-template-casing': ['error', 'kebab-case', { //全部使用小写 - 命名 57 | 'ignores': [] 58 | }], 59 | 'vue/no-v-html': 'off', //禁止使用v-html指令 60 | 'vue/require-valid-default-prop': 'off' //需要化有效默认prop 61 | } 62 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # Nuxt generate 72 | dist 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless 79 | 80 | # IDE 81 | .idea 82 | 83 | #自定义忽略 84 | /nuxt-dist 85 | /yarn.lock 86 | /biu-server-admin.zip 87 | /.vscode 88 | /docs/docs/yarn.lock 89 | /docs-v1.0.0/yarn.lock 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 langyuxiansheng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # base-nuxt-admin 2 | 一套node后台服务框架,自带管理后台页面.基于nuxt,也可以作为纯api服务器使用.移除client及server/src/bin/Server.js 里的 isNuxtRender 覆盖的,然后移除,package.json里nuxt相关包和UI框架即可.正在完善中...... 3 | 4 | ## 目前项目正在完善中...... 5 | 6 | > API服务器 7 | 8 | ## Build Setup 9 | 10 | ``` bash 11 | # install dependencies 12 | $ npm install 13 | 14 | # serve with hot reload at localhost:3000 15 | $ npm run dev 16 | 17 | # build for production and launch server 18 | $ npm run build 19 | $ npm start 20 | 21 | # generate static project 22 | $ npm run generate 23 | ``` 24 | 25 | ## 特殊点配置 MD5 加密配置 26 | 27 | 1. 由 str + _SERVICE.MU.HOME 生成md5 然后转成大写 28 | ``` 29 | MD5(`${str}_SERVICE.MU.HOME`).toUpperCase(); 30 | ``` 31 | 32 | 2. 设置数据库配置 33 | ``` 34 | server/src/lib/sequelize.js 35 | 36 | const config = { 37 | DB_type: 'mysql', // 数据库类型 38 | host: 'localhost', // 服务器地址 39 | port: 3306, // 数据库端口号 40 | username: 'root', // 数据库用户名 41 | password: '', // 数据库密码 42 | database: 'biu_server_db', // 数据库名称 43 | dialectOptions: { // MySQL > 5.5,其它数据库删除此项 44 | charset: 'utf8mb4', 45 | supportBigNumbers: true, 46 | bigNumberStrings: true 47 | //collate: 'utf8mb4_unicode_520_ci', 48 | //requestTimeout: 60 * 1000 //设置连接超时时间 49 | }, 50 | define: { 51 | underscored: false, // 转换列名的驼峰命名规则为下划线命令规则 52 | freezeTableName: true, //设置为true时,sequelize不会改变表名,否则可能会按其规则有所调整 53 | charset: 'utf8mb4', 54 | timestamps: false //为模型添加 createdAt 和 updatedAt 两个时间戳字段 55 | }, 56 | pool: { 57 | max: 50, // 连接池中最大连接数量 58 | min: 0, // 连接池中最小连接数量 59 | idle: 10000 // 如果一个线程 10 秒钟内没有被使用过的话,那么就释放线程 60 | } 61 | }; 62 | ``` 63 | # nodejs中使用别名映射,兼容webpack的@和best-require 的:xxx 别名映射 64 | 65 | 1. 安装库 best-require 进行别名映射 66 | 67 | ```bash 68 | npm i best-require --save 69 | ``` 70 | 71 | 2. 映射别名. 实例在本项目中 server/index.js 中 72 | 73 | ```javascript 74 | const path = require('path'); 75 | const ROOT_PATH = process.cwd(); 76 | const SRC_PATH = path.join(ROOT_PATH, `/server/src`); 77 | console.log(ROOT_PATH, SRC_PATH); 78 | //映射目录别名 79 | require('best-require')(ROOT_PATH, { 80 | root: ROOT_PATH, 81 | src: SRC_PATH, 82 | controllers: path.join(SRC_PATH, '/controllers'), 83 | models: path.join(SRC_PATH, '/models'), 84 | routes: path.join(SRC_PATH, '/routes'), 85 | crawlers: path.join(SRC_PATH, '/crawlers'), 86 | services: path.join(SRC_PATH, '/services'), 87 | middleware: path.join(SRC_PATH, '/middleware'), 88 | lib: path.join(SRC_PATH, '/lib'), 89 | config: path.join(SRC_PATH, '/config'), 90 | logs: path.join(SRC_PATH, '/logs') 91 | }); 92 | 93 | //运行服务 94 | require('./src/bin/Server').run(); 95 | 96 | ``` 97 | 98 | 3. 设置 jsconfig.json 99 | 100 | ```json 101 | { 102 | "compilerOptions": { 103 | "allowSyntheticDefaultImports": true, 104 | "baseUrl": "./", 105 | "paths": { 106 | "@/*": ["client/*"], 107 | ":root/*": ["*"], 108 | ":config/*": ["server/src/config/*"], 109 | ":lib/*": ["server/src/lib/*"], 110 | ":services/*": ["server/src/services/*"], 111 | ":controllers/*":["server/src/controllers/*"], 112 | ":models/*": ["server/src/models/*"], 113 | ":routes/*": ["server/src/routes/*"], 114 | ":crawlers/*": ["server/src/crawlers/*"], 115 | ":middleware/*": ["server/src/middleware/*"], 116 | ":logs/*": ["server/src/logs/*"] 117 | } 118 | }, 119 | "include": ["server/**/*","client/*"], 120 | "exclude": [ 121 | "node_modules", 122 | "nuxt-dist", 123 | "server-dist" 124 | ] 125 | } 126 | ``` 127 | 4. vscode要安装 path-intellisense 插件 128 | 129 | ```json 130 | { 131 | "path-intellisense.mappings": { 132 | "@": "${workspaceRoot}/client", 133 | ":root": "${workspaceRoot}", 134 | ":lib": "${workspaceRoot}/server/src/lib", 135 | ":controllers": "${workspaceRoot}/server/src/controllers", 136 | ":models": "${workspaceRoot}/server/src/models", 137 | ":routes": "${workspaceRoot}/server/src/routes", 138 | ":crawlers": "${workspaceRoot}/server/src/crawlers", 139 | ":services": "${workspaceRoot}/server/src/services", 140 | ":middleware": "${workspaceRoot}/server/src/middleware", 141 | ":config": "${workspaceRoot}/server/src/config", 142 | ":logs": "${workspaceRoot}/server/src/logs", 143 | } 144 | } 145 | ``` 146 | 147 | 5. 重启vscode,试试看吧! 148 | -------------------------------------------------------------------------------- /client/assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#webpacked). 8 | -------------------------------------------------------------------------------- /client/assets/images/default-avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/assets/images/default-avatar.png -------------------------------------------------------------------------------- /client/assets/images/default-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/assets/images/default-img.png -------------------------------------------------------------------------------- /client/assets/images/login-bg-0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/assets/images/login-bg-0.jpg -------------------------------------------------------------------------------- /client/assets/images/login-bg-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/assets/images/login-bg-1.jpg -------------------------------------------------------------------------------- /client/assets/images/login-bg-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/assets/images/login-bg-2.jpg -------------------------------------------------------------------------------- /client/assets/scripts/i18n/en-us.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Simple on 2018/1/14 0014. 3 | * 英文语言包 4 | */ 5 | export default { 6 | 7 | //操作提示 8 | msg: { 9 | add_success: '添加成功', 10 | update_success: '修改成功', 11 | operation_success: '操作成功', 12 | remove_success: '注销成功', 13 | checked_success: '核收成功', 14 | unbind_success: '解绑成功', 15 | deleted_success: '删除成功', 16 | verification_success: '核销成功', 17 | set_success: '设置成功', 18 | import_success: '导入成功', 19 | add_black_success: '拉黑成功', 20 | moved_success: '移除成功', 21 | update_please_new_password_login: '修改成功,请用新密码重新登录', 22 | please_input_account_num: '请输入账号', 23 | please_input_password: '请输入密码', 24 | please_input_check_password: '请再次输入密码', 25 | input_password_inconsistencies: '两次输入密码不一致!', 26 | please_input_name: '请输入姓名', 27 | please_phone_num: '请输入电话', 28 | please_input_id_card_num: '请输入身份证号', 29 | please_input_position_desc: '请输入职位描述', 30 | please_select_role: '请选择角色', 31 | the_phone_number_is_not_correct_please_reenter_it: '手机号码不正确,请重新输入!', 32 | please_fill_out_the_form: '请填写完表单', 33 | please_input_content: '请输入内容', 34 | 35 | failed: '关于', 36 | welcome: '欢迎' 37 | }, 38 | 39 | //界面语言 如按钮名、标签名字等 40 | html: { 41 | login: '登录', 42 | logout: '退出登录', 43 | immediately_add: '立即添加', 44 | refill: '重置', 45 | add_platform_admin: '添加平台管理员' 46 | 47 | }, 48 | 49 | //表单名称类 50 | label: { 51 | set_account: '设置账号', 52 | set_password: '设置密码', 53 | check_password: '确认密码', 54 | phone_num: '电话号码', 55 | name: '姓名', 56 | id_card_num: '身份证号', 57 | position_desc: '职位描述', 58 | select_role: '选择角色', 59 | user_avatar: '用户头像', 60 | search_items: '搜索项', 61 | index_num: '序号' 62 | 63 | }, 64 | 65 | //文本 66 | text: { 67 | //platform_name:'熊猫停车管理平台', 68 | platform_name: '熊猫停车管理平台', 69 | version_and_name: '业主端:V1.0.0', 70 | aware: '暂无' 71 | }, 72 | 73 | //其它 74 | other: { 75 | lang: 'en_US' 76 | } 77 | }; -------------------------------------------------------------------------------- /client/assets/scripts/i18n/zh-cn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Simple on 2018/1/14 0014. 3 | * 中文语言包 4 | */ 5 | export default { 6 | 7 | //操作提示 8 | msg: { 9 | add_success: '添加成功', 10 | update_success: '修改成功', 11 | operation_success: '操作成功', 12 | remove_success: '注销成功', 13 | checked_success: '核收成功', 14 | unbind_success: '解绑成功', 15 | deleted_success: '删除成功', 16 | verification_success: '核销成功', 17 | set_success: '设置成功', 18 | import_success: '导入成功', 19 | add_black_success: '拉黑成功', 20 | moved_success: '移除成功', 21 | update_please_new_password_login: '修改成功,请用新密码重新登录', 22 | please_input_account_num: '请输入账号', 23 | please_input_password: '请输入密码', 24 | please_input_check_password: '请再次输入密码', 25 | input_password_inconsistencies: '两次输入密码不一致!', 26 | please_input_name: '请输入姓名', 27 | please_phone_num: '请输入电话', 28 | please_input_id_card_num: '请输入身份证号', 29 | please_input_position_desc: '请输入职位描述', 30 | please_select_role: '请选择角色', 31 | the_phone_number_is_not_correct_please_reenter_it: '手机号码不正确,请重新输入!', 32 | please_fill_out_the_form: '请填写完表单', 33 | please_input_content: '请输入内容', 34 | 35 | failed: '关于', 36 | welcome: '欢迎' 37 | }, 38 | 39 | //界面语言 如按钮名、标签名字等 40 | html: { 41 | login: '登录', 42 | logout: '退出登录', 43 | immediately_add: '立即添加', 44 | refill: '重置', 45 | add_platform_admin: '添加平台管理员' 46 | 47 | }, 48 | 49 | //表单名称类 50 | label: { 51 | set_account: '设置账号', 52 | set_password: '设置密码', 53 | check_password: '确认密码', 54 | phone_num: '电话号码', 55 | name: '姓名', 56 | id_card_num: '身份证号', 57 | position_desc: '职位描述', 58 | select_role: '选择角色', 59 | user_avatar: '用户头像', 60 | search_items: '搜索项', 61 | index_num: '序号' 62 | 63 | }, 64 | 65 | //文本 66 | text: { 67 | //platform_name:'熊猫停车管理平台', 68 | platform_name: '熊猫停车管理平台', 69 | version_and_name: '业主端:V1.0.0', 70 | aware: '暂无' 71 | }, 72 | 73 | //其它 74 | other: { 75 | lang: 'en_US' 76 | } 77 | }; -------------------------------------------------------------------------------- /client/assets/styles/common/constant.css: -------------------------------------------------------------------------------- 1 | .clearfix:after { 2 | content: ""; 3 | height: 0; 4 | line-height: 0; 5 | display: block; 6 | visibility: hidden; 7 | clear: both; 8 | } 9 | .clearfix { 10 | zoom: 1; 11 | } 12 | /*fade*/ 13 | .fade-enter-active, 14 | .fade-leave-active { 15 | transition: opacity 0.28s; 16 | } 17 | .fade-enter, 18 | .fade-leave-active { 19 | opacity: 0; 20 | } 21 | /*fade*/ 22 | .breadcrumb-enter-active, 23 | .breadcrumb-leave-active { 24 | transition: all 0.5s; 25 | } 26 | .breadcrumb-enter, 27 | .breadcrumb-leave-active { 28 | opacity: 0; 29 | transform: translateX(20px); 30 | } 31 | .breadcrumb-move { 32 | transition: all 0.5s; 33 | } 34 | .breadcrumb-leave-active { 35 | position: absolute; 36 | } 37 | /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/ 38 | ::-webkit-scrollbar { 39 | width: 5px; 40 | height: 5px; 41 | background-color: #fafbfc; 42 | } 43 | /*定义滚动条轨道 内阴影+圆角*/ 44 | ::-webkit-scrollbar-track { 45 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); 46 | border-radius: 10px; 47 | background-color: #fafbfc; 48 | } 49 | /*定义滑块 内阴影+圆角*/ 50 | ::-webkit-scrollbar-thumb { 51 | border-radius: 10px; 52 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); 53 | background-color: rgba(0, 0, 0, 0.1); 54 | } 55 | -------------------------------------------------------------------------------- /client/assets/styles/common/constant.less: -------------------------------------------------------------------------------- 1 | //常量文件 2 | @app-bg-color:#f4f5ff; 3 | //主题颜色 4 | @app-theme-color:#8a8dec; 5 | 6 | @app-boder-color: #bdbff9; 7 | 8 | @app-font-color: #606266; 9 | 10 | .clearfix:after { 11 | content: ""; 12 | height: 0; 13 | line-height: 0; 14 | display: block; 15 | visibility: hidden; 16 | clear: both; 17 | } 18 | 19 | .clearfix{ 20 | zoom:1; 21 | } 22 | 23 | //面包屑导航动画 24 | /*fade*/ 25 | .fade-enter-active, 26 | .fade-leave-active { 27 | transition: opacity 0.28s; 28 | } 29 | 30 | .fade-enter, 31 | .fade-leave-active { 32 | opacity: 0; 33 | } 34 | 35 | /*fade*/ 36 | .breadcrumb-enter-active, 37 | .breadcrumb-leave-active { 38 | transition: all .5s; 39 | } 40 | 41 | .breadcrumb-enter, 42 | .breadcrumb-leave-active { 43 | opacity: 0; 44 | transform: translateX(20px); 45 | } 46 | 47 | .breadcrumb-move { 48 | transition: all .5s; 49 | } 50 | 51 | .breadcrumb-leave-active { 52 | position: absolute; 53 | } 54 | 55 | 56 | /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/ 57 | ::-webkit-scrollbar 58 | { 59 | width: 5px; 60 | height: 5px; 61 | background-color: #fafbfc; 62 | } 63 | 64 | /*定义滚动条轨道 内阴影+圆角*/ 65 | ::-webkit-scrollbar-track 66 | { 67 | box-shadow: inset 0 0 6px rgba(0,0,0,0.1); 68 | border-radius: 10px; 69 | background-color: #fafbfc; 70 | } 71 | 72 | /*定义滑块 内阴影+圆角*/ 73 | ::-webkit-scrollbar-thumb 74 | { 75 | border-radius: 10px; 76 | box-shadow: inset 0 0 6px rgba(0,0,0,.1); 77 | background-color: rgba(0,0,0,.1); 78 | } 79 | 80 | 81 | // 文本溢出省略号显示 (多行) 82 | // 只支持 webkit 浏览器, 解决方案:高度 = 行高*行数 83 | // height: 90px; line-height: 30px; -webkit-line-clamp: 3; 84 | .ellipsis-mult(@n: 3) { 85 | display: -webkit-box; -webkit-box-orient: vertical;-webkit-line-clamp: @n; word-break: break-all; 86 | -o-text-overflow: ellipsis; -ms-text-overflow: ellipsis; text-overflow:ellipsis; overflow: hidden; 87 | } 88 | 89 | // 书写模式:牌匾从右至左水平单行排版效果、文笺从右至左、从上至下排版效果 90 | .retext(x) { direction: rtl; unicode-bidi: bidi-override; } 91 | .retext(y) { writing-mode: tb-rl; writing-mode: vertical-rl; } 92 | 93 | // 文字透明 94 | .transparent-text() { font: 0/0 serif; text-shadow: none; color: transparent; } 95 | 96 | // 文字隐藏(常用于SEO优化) 97 | .hidden-text() { text-indent : -9999px; overflow: hidden; text-align: left; } 98 | // 文字外发光效果 99 | .glow-text(@r: 10px, @color: gold) { text-shadow: 0 0 @r @color; } 100 | 101 | //------------------------------------- ├ 图像 ┆ └------------------------------------ 102 | 103 | // 用 max-width 来防止图片撑破容器 104 | .max-img() { display: block; max-width: 100%; height: auto; } 105 | 106 | // 2x 3x 背景图片 107 | .bg-image(@url) { 108 | background-image: url("@url + '@2x.png'"); 109 | @media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) { 110 | background-image: url("@url + '@3x.png'"); 111 | } 112 | } 113 | // 全屏大图背景 114 | .fullscreen-bg(@url) { 115 | width: 100vw; 116 | height: 100vh; 117 | background: url(@url) no-repeat 50% 50%; 118 | background-size: cover; 119 | } 120 | // 滤镜: 将彩色照片显示为黑白照片 121 | .grayscale() { 122 | filter: grayscale(100%); 123 | -webkit-filter: grayscale(100%); 124 | -moz-filter: grayscale(100%); 125 | -ms-filter: grayscale(100%); 126 | -o-filter: grayscale(100%); 127 | } 128 | -------------------------------------------------------------------------------- /client/assets/styles/common/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } 49 | a{ 50 | text-decoration: none; 51 | color: #303133; 52 | } 53 | -------------------------------------------------------------------------------- /client/assets/styles/common/theme.default.css: -------------------------------------------------------------------------------- 1 | .clearfix:after { 2 | content: ""; 3 | height: 0; 4 | line-height: 0; 5 | display: block; 6 | visibility: hidden; 7 | clear: both; 8 | } 9 | .clearfix { 10 | zoom: 1; 11 | } 12 | /*fade*/ 13 | .fade-enter-active, 14 | .fade-leave-active { 15 | transition: opacity 0.28s; 16 | } 17 | .fade-enter, 18 | .fade-leave-active { 19 | opacity: 0; 20 | } 21 | /*fade*/ 22 | .breadcrumb-enter-active, 23 | .breadcrumb-leave-active { 24 | transition: all 0.5s; 25 | } 26 | .breadcrumb-enter, 27 | .breadcrumb-leave-active { 28 | opacity: 0; 29 | transform: translateX(20px); 30 | } 31 | .breadcrumb-move { 32 | transition: all 0.5s; 33 | } 34 | .breadcrumb-leave-active { 35 | position: absolute; 36 | } 37 | /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/ 38 | ::-webkit-scrollbar { 39 | width: 5px; 40 | height: 5px; 41 | background-color: #fafbfc; 42 | } 43 | /*定义滚动条轨道 内阴影+圆角*/ 44 | ::-webkit-scrollbar-track { 45 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); 46 | border-radius: 10px; 47 | background-color: #fafbfc; 48 | } 49 | /*定义滑块 内阴影+圆角*/ 50 | ::-webkit-scrollbar-thumb { 51 | border-radius: 10px; 52 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); 53 | background-color: rgba(0, 0, 0, 0.1); 54 | } 55 | .app-bg-white { 56 | background: #f4f5ff; 57 | } 58 | * { 59 | box-sizing: border-box; 60 | } 61 | html, 62 | body { 63 | width: 100%; 64 | height: 100%; 65 | color: #909399; 66 | background-color: #f4f5ff; 67 | } 68 | #__nuxt, 69 | #__layout { 70 | width: 100%; 71 | height: 100%; 72 | } 73 | #__nuxt .el-header, 74 | #__layout .el-header { 75 | padding: 0; 76 | height: auto; 77 | } 78 | #__nuxt .el-main, 79 | #__layout .el-main { 80 | padding: 0; 81 | } 82 | #__nuxt .el-main .no-padding, 83 | #__layout .el-main .no-padding { 84 | padding: 0; 85 | } 86 | #__nuxt .layout-container, 87 | #__layout .layout-container { 88 | width: 100%; 89 | height: 100%; 90 | } 91 | #__nuxt .layout-container .layout-view, 92 | #__layout .layout-container .layout-view { 93 | padding: 20px 20px 44px 20px; 94 | overflow: auto; 95 | max-height: calc(100% - 56px); 96 | } 97 | #__nuxt .app-dialog, 98 | #__layout .app-dialog { 99 | border-radius: 10px; 100 | } 101 | #__nuxt .app-text-left, 102 | #__layout .app-text-left { 103 | text-align: left; 104 | } 105 | #__nuxt .app-href-link, 106 | #__layout .app-href-link { 107 | color: #409EFF; 108 | } 109 | .app-form .app-submit-btns { 110 | text-align: center; 111 | margin-top: 50px; 112 | } 113 | .app-form .select-block { 114 | display: block; 115 | } 116 | /**图片放大**/ 117 | .vue-directive-image-previewer { 118 | z-index: 10000000; 119 | } 120 | .vue-directive-image-previewer .vue-directive-image-previewer-pic { 121 | z-index: 10000002; 122 | } 123 | .app-image-previewer { 124 | cursor: pointer; 125 | } 126 | .sidebar-submenu { 127 | background: linear-gradient(160deg, #7faadc, #8a8dec 66%); 128 | } 129 | -------------------------------------------------------------------------------- /client/assets/styles/common/theme.default.less: -------------------------------------------------------------------------------- 1 | @import './constant.less'; 2 | //主背景色 3 | .app-bg-white{ 4 | background:@app-bg-color; 5 | } 6 | *{ 7 | box-sizing: border-box; 8 | } 9 | html, 10 | body{ 11 | width: 100%; 12 | height: 100%; 13 | color: @app-font-color; 14 | background-color: @app-bg-color; 15 | } 16 | #__nuxt, 17 | #__layout{ 18 | width: 100%; 19 | height: 100%; 20 | .el-header{ 21 | padding: 0; 22 | height: auto; 23 | } 24 | .el-main{ 25 | padding: 0; 26 | .no-padding{ 27 | padding: 0; 28 | } 29 | } 30 | .layout-container{ 31 | width: 100%; 32 | height: 100%; 33 | .layout-view{ 34 | padding: 20px 20px 44px 20px; 35 | overflow: auto; 36 | max-height: calc(100% - 56px); 37 | } 38 | } 39 | .app-dialog{ 40 | border-radius: 10px; 41 | } 42 | .app-text-left{ 43 | text-align: left; 44 | } 45 | .app-href-link{ 46 | color: #409EFF; 47 | } 48 | } 49 | 50 | .app-form{ 51 | .app-submit-btns{ 52 | text-align: center; 53 | margin-top: 50px; 54 | } 55 | .select-block{ 56 | display: block; 57 | } 58 | } 59 | 60 | /**图片放大**/ 61 | .vue-directive-image-previewer{ 62 | z-index: 10000000; 63 | } 64 | 65 | .vue-directive-image-previewer .vue-directive-image-previewer-pic{ 66 | z-index: 10000002; 67 | } 68 | 69 | .app-image-previewer{ 70 | cursor: pointer; 71 | } 72 | .sidebar-submenu{ 73 | background: linear-gradient(160deg, #7faadc, @app-theme-color 66%); 74 | } 75 | -------------------------------------------------------------------------------- /client/assets/styles/default-theme/config.json: -------------------------------------------------------------------------------- 1 | {"global":{"$--color-primary":"#8A8DEC","$--color-success":"#5CCD5E","$--color-warning":"#E7AC53","$--color-danger":"#FF8A8A","$--color-info":"#A6AAB3"},"local":{"$--table-border-color":"#BDBFF9","$--table-row-hover-background-color":"#E6E7FE","$--table-header-background-color":"#FBFBFB"}} -------------------------------------------------------------------------------- /client/assets/styles/default-theme/style.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/assets/styles/default-theme/style.zip -------------------------------------------------------------------------------- /client/assets/styles/default-theme/theme/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/assets/styles/default-theme/theme/fonts/element-icons.ttf -------------------------------------------------------------------------------- /client/assets/styles/default-theme/theme/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/assets/styles/default-theme/theme/fonts/element-icons.woff -------------------------------------------------------------------------------- /client/assets/styles/layout/index.css: -------------------------------------------------------------------------------- 1 | .app-breadcrumb { 2 | display: inline-block; 3 | font-size: 16px; 4 | margin-left: 20px; 5 | align-self: center; 6 | } 7 | .app-breadcrumb .no-redirect { 8 | color: #3d9eff; 9 | cursor: text; 10 | } 11 | .home-link { 12 | color: #334495; 13 | } 14 | -------------------------------------------------------------------------------- /client/assets/styles/layout/index.less: -------------------------------------------------------------------------------- 1 | .app-breadcrumb { 2 | display: inline-block; 3 | font-size: 16px; 4 | margin-left: 20px; 5 | align-self: center; 6 | .no-redirect { 7 | color: #3d9eff; 8 | cursor: text; 9 | } 10 | } 11 | .home-link { 12 | color: #334495; 13 | } 14 | -------------------------------------------------------------------------------- /client/base/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2019年4月3日22:51:28 3 | * 公共插件功能配置文件 4 | */ 5 | const pkg = require('../../package.json'); 6 | export default { 7 | name:"BiuServerAdmin", //系统名称 8 | version: `V ${pkg.version}`, //版本号 9 | devUrl: 'http://192.168.0.59:8000', 10 | productionUrl: 'http://192.168.0.59:8000', 11 | // devUrl: 'https://api.pandaparking.cn', 12 | // productionUrl: 'https://api.pandaparking.cn', 13 | table: { 14 | pagination: { 15 | size: 10, //默认大小 16 | layout: 'total,prev, pager, next, jumper', //配置 17 | sizes: [5, 10, 15, 20] //每页x条 18 | } 19 | }, 20 | baseImageURL: "/images/ebook/", //基础图片路径 21 | size: 'small', 22 | tableSize: 'mini', 23 | defaultTime: ['00:00:00', '23:59:59'], 24 | baiDuMapKey: '3GGKnVpSku9u2S17oalzlU6LmYHZoGLy', //百度地图秘钥 25 | aMapKey: '58d947beaa66523514fdeffe22dd3c59', //高德地图秘钥 26 | labelPosition: 'top', //表单对齐方式 27 | dialogFormWidth: '850px', //表单弹出层宽度 28 | dialogSingleFormWidth: '500px', //单列表单弹出层宽度 29 | dialogPrompt: '500px', //弹出输入框 30 | dialogFormGutterWidth: 82, //表单列间隔 31 | dialogDetailWidth: '1000px', //详情弹出层宽度 32 | dialogMapWidth: '1200px', //地图弹出层宽度 33 | qiNiuURL: 'http://up-z2.qiniu.com', //七牛上传路径 34 | // qrUrl: 'http://b.bshare.cn/barCode?site=weixin&url=', //二维码链接 35 | qrUrl: 'https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=', //二维码链接 36 | defaultAvatarUrl: "this.src='../../../static/img/default-avatar.png'", //默认头像 37 | collectorUrl: 'http://collector.pandaparking.cn', //岗亭端链接 38 | datePrickValueFormat: 'timestamp', //日期选择器的绑定值格式 39 | monthPrickValueFormat: 'yyyy-MM', //月选择器的绑定值格式 40 | yearPrickValueFormat: 'yyyy', //年选择器的绑定值格式 41 | dayPrickValueFormat: 'yyyy-MM-dd', //日选择器的绑定值格式 42 | 43 | //日期选择器配置 44 | pickerOptions: { 45 | shortcuts: [{ 46 | text: '最近一周', 47 | onClick(picker) { 48 | const end = new Date(); 49 | const start = new Date(new Date(new Date().toLocaleDateString()).getTime()); 50 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); 51 | picker.$emit('pick', [start, end]); 52 | } 53 | }, 54 | { 55 | text: '最近一个月', 56 | onClick(picker) { 57 | const end = new Date(); 58 | const start = new Date(new Date(new Date().toLocaleDateString()).getTime()); 59 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); 60 | picker.$emit('pick', [start, end]); 61 | } 62 | }, 63 | { 64 | text: '最近三个月', 65 | onClick(picker) { 66 | const end = new Date(); 67 | const start = new Date(new Date(new Date().toLocaleDateString()).getTime()); 68 | start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); 69 | picker.$emit('pick', [start, end]); 70 | } 71 | } 72 | ] 73 | }, 74 | //月天数 75 | monthDays() { 76 | let arr = []; 77 | for (let i = 1; i < 32; i++) { 78 | arr.push(i + '日'); 79 | } 80 | return arr; 81 | }, 82 | 83 | //年月份数 84 | yearMonths() { 85 | let arr = []; 86 | for (let i = 1; i < 13; i++) { 87 | arr.push(i + '月'); 88 | } 89 | return arr; 90 | }, 91 | 92 | //小时数 93 | hours() { 94 | let arr = []; 95 | for (let i = 0; i < 24; i++) { 96 | i < 10 ? arr.push('0' + i + ':00') : arr.push(i + ':00'); 97 | } 98 | return arr; 99 | } 100 | }; 101 | -------------------------------------------------------------------------------- /client/components/AppTreeTable/eval.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | const treeToArray = (data, expandAll, parent = null, level = null) => { 3 | let tmp = []; 4 | Array.from(data).forEach((record) => { 5 | if (record._expanded === undefined) { 6 | Vue.set(record, '_expanded', expandAll); 7 | } 8 | let _level = 1; 9 | if (level !== undefined && level !== null) { 10 | _level = level + 1; 11 | } 12 | Vue.set(record, '_level', _level); 13 | // 如果有父元素 14 | if (parent) { 15 | Vue.set(record, 'parent', parent); 16 | } 17 | tmp.push(record); 18 | if (record.children && record.children.length > 0) { 19 | const children = treeToArray(record.children, expandAll, record, _level); 20 | tmp = tmp.concat(children); 21 | } 22 | }); 23 | return tmp; 24 | }; 25 | export default treeToArray; -------------------------------------------------------------------------------- /client/components/CardContainer/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 26 | 27 | 40 | -------------------------------------------------------------------------------- /client/components/Dialog copy/index.vue: -------------------------------------------------------------------------------- 1 | 44 | 89 | 107 | -------------------------------------------------------------------------------- /client/components/DialogContainer/index.vue: -------------------------------------------------------------------------------- 1 | 20 | 40 | 43 | -------------------------------------------------------------------------------- /client/components/ImgDialog/index.vue: -------------------------------------------------------------------------------- 1 | 28 | 57 | 71 | -------------------------------------------------------------------------------- /client/components/Layout/components/403/index.vue: -------------------------------------------------------------------------------- 1 | 38 | 47 | 75 | -------------------------------------------------------------------------------- /client/components/Layout/components/404/index.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/client/components/Layout/components/404/index.vue -------------------------------------------------------------------------------- /client/components/Layout/components/Header/BreadcrumbBar/index.vue: -------------------------------------------------------------------------------- 1 | 18 | 75 | 78 | -------------------------------------------------------------------------------- /client/components/Layout/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 55 | -------------------------------------------------------------------------------- /client/components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | The components directory contains your Vue.js Components. 6 | 7 | _Nuxt.js doesn't supercharge these components._ 8 | -------------------------------------------------------------------------------- /client/components/ReadFileDialog/index.vue: -------------------------------------------------------------------------------- 1 | 14 | 59 | 71 | -------------------------------------------------------------------------------- /client/components/ScrollPane/index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 70 | 71 | 82 | -------------------------------------------------------------------------------- /client/components/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 同一导出自定义的全局组件 3 | */ 4 | 5 | // 卡片布局容器 6 | import CardContainer from './CardContainer'; 7 | // 图片显示 8 | import ImgDialog from './ImgDialog'; 9 | import DialogContainer from './DialogContainer'; 10 | import AppTables from './AppTables'; 11 | import AppTreeTable from './AppTreeTable'; 12 | //预览文件 13 | import ReadFileDialog from './ReadFileDialog'; 14 | export default { 15 | CardContainer, 16 | ImgDialog, 17 | DialogContainer, 18 | AppTables, 19 | AppTreeTable, 20 | ReadFileDialog 21 | }; 22 | -------------------------------------------------------------------------------- /client/filters/index.js: -------------------------------------------------------------------------------- 1 | import util from '@/lib/util'; 2 | 3 | export default { 4 | 5 | /** 6 | * 格式化时间 2018-07-02 13:12:12 7 | * @param {*} value 8 | */ 9 | formatDateYearMonthDayAndHms(value) { 10 | return util.formatDateYearMonthDayAndHms(value); 11 | }, 12 | 13 | /** 14 | * 时长 15 | * @param {*} value 16 | */ 17 | formatCountTime(value) { 18 | if (value) { 19 | return util.secondToDate(value); 20 | } 21 | return '0秒'; 22 | }, 23 | 24 | /** 25 | * 书本状态 26 | * @param {*} value 27 | */ 28 | formatBaseBookStatus(value) { 29 | switch (value) { 30 | case 1: 31 | return '已完结'; 32 | case 2: 33 | return '连载中'; 34 | case 3: 35 | return '3禁用下架'; 36 | default: 37 | return '其它'; 38 | } 39 | }, 40 | 41 | /** 42 | * 格式化文件大小 43 | * @param {*} value 44 | */ 45 | formatFileSize(size) { 46 | let value = Number(size); 47 | if (size && !isNaN(value)) { 48 | const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'BB']; 49 | let index = 0; 50 | let k = value; 51 | if (value >= 1024) { 52 | while (k > 1024) { 53 | k = k / 1024; 54 | index++; 55 | } 56 | } 57 | return `${(k).toFixed(2)}${units[index]}`; 58 | } 59 | return '-'; 60 | } 61 | 62 | }; 63 | -------------------------------------------------------------------------------- /client/http/index.js: -------------------------------------------------------------------------------- 1 | import apis from './wrapper'; 2 | export const { 3 | userLoginForSysAdmin, 4 | getImgValidate, 5 | //系统设置 6 | getSysAdminList, 7 | addSysAdmin, 8 | delSysAdminByIds, 9 | updateSysAdmin, 10 | getSysRoleList, 11 | addSysRole, 12 | delSysRoleByIds, 13 | updateSysRole, 14 | getSysPermissionList, 15 | addSysPermission, 16 | delSysPermissionByIds, 17 | updateSysPermission, 18 | getSysPermissionListToTree, 19 | getSysRolePermissionListToTree, 20 | setSysRolePermission, 21 | bindSysAdminRole, 22 | clearSysRoleAllPermission, 23 | getSysAdminBaseInfo, 24 | getSysRoleMenusToTree, 25 | updateSysPassword, 26 | getFiles, 27 | readeFileContent, 28 | deleteFiles, 29 | getSysLogList, 30 | getSysLogContent, 31 | delSysLogByPaths 32 | //555 33 | } = apis; 34 | -------------------------------------------------------------------------------- /client/http/interceptor.js: -------------------------------------------------------------------------------- 1 | /*** 2 | * Created by Simple on 2019年3月25日14:33:01 3 | * Http请求控制器模块 4 | */ 5 | 6 | import axios from 'axios'; 7 | import { Loading, Message } from 'element-ui'; 8 | import util from '@/lib/util'; 9 | // const productionUrl = ''; 10 | // const devUrl = 'http://192.168.0.220'; 11 | const devUrl = '/'; 12 | // axios 配置 13 | axios.defaults.timeout = 1000 * 60 * 5; 14 | // axios.defaults.baseURL = process.env.NODE_ENV === 'production' ? productionUrl : devUrl; 15 | axios.defaults.baseURL = devUrl; 16 | // 配置通用请求动画 17 | let loading = null; 18 | 19 | //http request 拦截 20 | axios.interceptors.request.use(config => { 21 | config.headers.Authorization = util.getCookie(`BIU-SERVER-ADMIN-JWT`); 22 | loading = Loading.service({ 23 | lock: true, 24 | text: '拼命加载中...', 25 | background: 'rgba(255, 255, 255, .1)' 26 | }); 27 | return config; 28 | }, err => { 29 | if (loading) loading.close(); 30 | return Promise.reject(err); 31 | }); 32 | 33 | // http response 拦截 34 | axios.interceptors.response.use(response => { 35 | let data = {}; 36 | if (response && response.data) { 37 | const { code, msg } = response.data; 38 | if (code == 200) { 39 | data = response.data; 40 | } else if (code == 401) { 41 | setTimeout(() => { 42 | const fullPath = location.pathname; 43 | location.href = `/login?redirect=${fullPath}`; 44 | }, 1200); 45 | Message.error(msg); 46 | } else { 47 | Message.error(msg); 48 | } 49 | } 50 | if (loading) loading.close(); 51 | return data; 52 | }, error => { 53 | if (loading) loading.close(); 54 | Message.error('哎呀~ (ಥ﹏ಥ)网络又开小差了,请稍后刷新重试!'); 55 | return Promise.reject(error.response.data); 56 | }); 57 | 58 | export default axios; 59 | -------------------------------------------------------------------------------- /client/http/models/common.js: -------------------------------------------------------------------------------- 1 | import { API_SERVER } from './types'; 2 | export default { 3 | 4 | /** 5 | * 获取图片验证码 6 | * @param {*} data 7 | */ 8 | getImgValidate: { 9 | url: `${API_SERVER}/common/getImgValidate`, 10 | method: 'get' 11 | }, 12 | 13 | /** 14 | * 系统用户登录 15 | * @param {*} data 16 | */ 17 | userLoginForSysAdmin: { 18 | url: `${API_SERVER}/common/userLoginForSysAdmin`, 19 | method: 'post' 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /client/http/models/index.js: -------------------------------------------------------------------------------- 1 | import system from './system'; 2 | import common from './common'; 3 | export default { 4 | ...system, 5 | ...common 6 | }; 7 | -------------------------------------------------------------------------------- /client/http/models/types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 常量文件 3 | */ 4 | export const API_SERVER = '/v1/api'; 5 | export const FILE_UPLOAD_URL = `${API_SERVER}/common/uploadFile`; 6 | export const FILES_UPLOAD_URL = `${API_SERVER}/common/uploadFiles`; 7 | -------------------------------------------------------------------------------- /client/http/wrapper.js: -------------------------------------------------------------------------------- 1 | /*** 2 | * Created by Simple on 2019年3月25日14:32:25 3 | * mergedApis模块 4 | */ 5 | import mergedApis from './models'; 6 | export default (() => { 7 | return Object 8 | .keys(mergedApis) 9 | .reduce((acc, apiKey) => { 10 | return { 11 | ...acc, 12 | [apiKey]: mergedApis[apiKey] 13 | }; 14 | }, {}); 15 | })(); 16 | -------------------------------------------------------------------------------- /client/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 4 | 14 | -------------------------------------------------------------------------------- /client/layouts/empty.vue: -------------------------------------------------------------------------------- 1 | 4 | 12 | -------------------------------------------------------------------------------- /client/layouts/error.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /client/middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your application middleware. 6 | The middleware lets you define custom function to be ran before rendering a page or a group of pages (layouts). 7 | 8 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing#middleware). 9 | -------------------------------------------------------------------------------- /client/middleware/authorities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 路由鉴权中间件 3 | * @description 配置侧边栏菜单和权限使用 4 | */ 5 | // import menus from '@/router'; 6 | 7 | /** 8 | * 递归查询路由权限 9 | * @param {*} list 10 | * @param {*} menu 11 | */ 12 | /* const iterator = (list) => { 13 | for (let item in list) { 14 | for (const m in menus) { 15 | if ((list[item].name === menus[m].name) && (list[item].path === menus[m].path)) { 16 | console.log((list[item].name === menus[m].name) && (list[item].path === menus[m].path)); 17 | list[item].meta = menus[m].meta; 18 | list[item].meta.requireAuth = true; 19 | } 20 | } 21 | if (list[item].children && list[item].children.length > 0) { 22 | iterator(list[item].children); 23 | } else { 24 | return list; 25 | }; 26 | } 27 | }; */ 28 | export default ({ app }) => { 29 | // console.log(`路由鉴权中间件`, app.router.options); 30 | //let routes = app.router.options.routes; 31 | //app.router.options.routes = iterator(routes); 32 | // console.log(iterator); 33 | return app; 34 | }; -------------------------------------------------------------------------------- /client/middleware/stats.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export default function({ route }) { 4 | // console.log(`route`, route); 5 | console.log(`route`, axios); 6 | return route; 7 | /* return axios.post('http://my-stats-api.com', { 8 | url: route.fullPath 9 | }); */ 10 | } -------------------------------------------------------------------------------- /client/middleware/test.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export default function({ route }) { 4 | // console.log(`test`, route); 5 | console.log(axios); 6 | return route; 7 | /* return axios.post('http://my-stats-api.com', { 8 | url: route.fullPath 9 | }); */ 10 | }; -------------------------------------------------------------------------------- /client/pages/Home/Welcome/index.vue: -------------------------------------------------------------------------------- 1 | 56 | 113 | -------------------------------------------------------------------------------- /client/pages/Login/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 37 | 38 | 66 | -------------------------------------------------------------------------------- /client/pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the `*.vue` files inside this directory and create the router of your application. 5 | 6 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing). 7 | -------------------------------------------------------------------------------- /client/pages/System/AdminManage/BindRoleForm/index.vue: -------------------------------------------------------------------------------- 1 | 33 | 124 | -------------------------------------------------------------------------------- /client/pages/System/LogsManage/ReadLogDialog/index.vue: -------------------------------------------------------------------------------- 1 | 20 | 66 | 85 | -------------------------------------------------------------------------------- /client/pages/System/RolesManage/RoleForm/index.vue: -------------------------------------------------------------------------------- 1 | 26 | 107 | -------------------------------------------------------------------------------- /client/pages/System/RolesManage/Settings/_id.vue: -------------------------------------------------------------------------------- 1 | 23 | 104 | 109 | -------------------------------------------------------------------------------- /client/plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Javascript plugins that you want to run before mounting the root Vue.js application. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins). 8 | -------------------------------------------------------------------------------- /client/plugins/axios.js: -------------------------------------------------------------------------------- 1 | import util from '@/lib/util'; 2 | import { Loading, Message } from 'element-ui'; 3 | export default ({ $axios, redirect }) => { 4 | // axios 配置 5 | $axios.defaults.timeout = 1000 * 60 * 5; 6 | $axios.defaults.baseURL = '/'; 7 | let loading = null; 8 | $axios.onRequest(config => { 9 | config.headers.Authorization = util.getCookie(`BIU-SERVER-ADMIN-JWT`); 10 | if (config.url.indexOf('api.tryto.cn') > -1) return config; 11 | loading = Loading.service({ 12 | lock: true, 13 | text: '拼命加载中...', 14 | background: 'rgba(255, 255, 255, .1)' 15 | }); 16 | // console.log(config); 17 | // { withCredentials: true } 18 | 19 | return config; 20 | }); 21 | 22 | $axios.onResponse(response => { 23 | let data = {}; 24 | if (response && response.data) { 25 | const { code, msg } = response.data; 26 | if (code == 200) { 27 | data = response.data; 28 | } else if (code == 401) { 29 | setTimeout(() => { 30 | const fullPath = location.pathname; 31 | location.href = `/login?redirect=${fullPath}`; 32 | }, 1200); 33 | Message.error(msg); 34 | } else { 35 | Message.error(msg); 36 | } 37 | } 38 | if (loading) loading.close(); 39 | return data; 40 | }); 41 | 42 | $axios.onError(error => { 43 | if (loading) loading.close(); 44 | Message.error('哎呀~ (ಥ﹏ಥ)网络又开小差了,请稍后刷新重试!'); 45 | return Promise.reject(error.response.data); 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /client/plugins/components.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | // 图片放大 3 | import VueDirectiveImagePreviewer from 'vue-directive-image-previewer'; 4 | import 'vue-directive-image-previewer/dist/assets/style.css'; 5 | //自定义全局组件 6 | import components from '@/components'; 7 | Vue.use(VueDirectiveImagePreviewer, { background: 'rgba(0,0,0,.5)' }); 8 | export default () => { 9 | Object.keys(components).forEach((key) => { 10 | Vue.component(key, components[key]); 11 | }); 12 | }; -------------------------------------------------------------------------------- /client/plugins/element-ui.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Element from 'element-ui/lib/element-ui.common'; 3 | import locale from 'element-ui/lib/locale/lang/zh-CN'; 4 | 5 | export default () => { 6 | Vue.use(Element, { locale, size: 'mini' }); 7 | }; -------------------------------------------------------------------------------- /client/plugins/filters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Vue 全局过滤器 3 | */ 4 | 5 | import Vue from 'vue'; 6 | import filters from '@/filters'; 7 | for (let k in filters) { 8 | Vue.filter(k, filters[k]); 9 | } 10 | export default ({ app }) => { 11 | app.$appFilters = filters; 12 | }; 13 | -------------------------------------------------------------------------------- /client/plugins/i18n.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | // 导入语言国际化插件 3 | import VueI18n from 'vue-i18n'; 4 | // 导入语言包 5 | import ZHCN from '@/assets/scripts/i18n/zh-cn'; 6 | import ENUS from '@/assets/scripts/i18n/en-us'; 7 | Vue.use(VueI18n); 8 | /** 9 | * 配置语言国际化和自定义语言包 10 | */ 11 | const i18n = new VueI18n({ 12 | locale: 'ZHCN', 13 | messages: { ZHCN, ENUS } 14 | }); 15 | export default ({ app }) => { 16 | app.i18n = i18n; 17 | // app.$i18n.locale = 'ENUS'; //动态切换语言 18 | }; -------------------------------------------------------------------------------- /client/store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Vuex Store files. 6 | Vuex Store option is implemented in the Nuxt.js framework. 7 | 8 | Creating a file in this directory activate the option in the framework automatically. 9 | 10 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store). 11 | -------------------------------------------------------------------------------- /client/store/actions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/1/12 0012. 3 | * store 公共方法类 4 | */ 5 | import types from './types.js'; 6 | const actions = { 7 | 8 | /** 9 | * 设置权限 10 | */ 11 | setPermission({ commit, state }, route) { 12 | commit(types.SET_PERMISSION, route); 13 | } 14 | }; 15 | 16 | export default actions; 17 | -------------------------------------------------------------------------------- /client/store/getters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/1/12 0012. 3 | * store 公共方法类 4 | */ 5 | 6 | //导入公共状态模块 7 | 8 | const getters = { 9 | //配置文件 10 | config: state => state.config, 11 | //权限 12 | permission: state => state.permission 13 | 14 | }; 15 | 16 | export default getters; 17 | -------------------------------------------------------------------------------- /client/store/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * _ooOoo_ 3 | * o8888888o 4 | * 88" . "88 5 | * (| -_- |) 6 | * O\ = /O 7 | * ____/`---'\____ 8 | * . ' \\| |// `. 9 | * / \\||| : |||// \ 10 | * / _||||| -:- |||||- \ 11 | * | | \\\ - /// | | 12 | * | \_| ''\---/'' | | 13 | * \ .-\__ `-` ___/-. / 14 | * ___`. .' /--.--\ `. . __ 15 | * ."" '< `.___\_<|>_/___.' >'"". 16 | * | | : `- \`.;`\ _ /`;.`/ - ` : | | 17 | * \ \ `-. \_ __\ /__ _/ .-` / / 18 | * ======`-.____`-.___\_____/___.-`____.-'====== 19 | * `=---=' 20 | * 21 | * ............................................. 22 | * 佛祖保佑 永无BUG 23 | * 24 | * Created by Simple on 2018/1/12 0012. 25 | * vuex 状态管理器 26 | */ 27 | 28 | import Vue from 'vue'; 29 | import Vuex from 'vuex'; 30 | import VuexPersistence from 'vuex-persist'; 31 | import state from './state'; 32 | import getters from './getters'; 33 | import actions from './actions'; 34 | import mutations from './mutations'; 35 | import users from './models/users'; 36 | import tabsview from './models/tabsview'; 37 | const vuexLocal = new VuexPersistence({ 38 | storage: window.localStorage, 39 | key: 'BIU-SERVER-ADMIN-STORE-VUEX' 40 | }); 41 | 42 | Vue.use(Vuex); 43 | 44 | const store = () => new Vuex.Store({ 45 | state, 46 | getters, 47 | actions, 48 | mutations, 49 | modules: { 50 | users, 51 | tabsview 52 | }, 53 | plugins: [vuexLocal.plugin] 54 | }); 55 | 56 | export default store; 57 | -------------------------------------------------------------------------------- /client/store/models/tabsview.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Simple on 2018/4/26 0020. 3 | * 标签导航 4 | */ 5 | const state = { 6 | visitedViews: [], 7 | cachedViews: [] 8 | }; 9 | 10 | const getters = { 11 | 12 | /** 13 | * 当前标签 14 | * @param state 15 | * @return {Array|*} 16 | */ 17 | visitedViews(state) { 18 | return state.visitedViews; 19 | }, 20 | 21 | /** 22 | * 缓存标签 23 | * @param state 24 | * @return {Array|*} 25 | */ 26 | cachedViews(state) { 27 | return state.cachedViews; 28 | } 29 | }; 30 | 31 | const actions = { 32 | 33 | /** 34 | * 新增标签 35 | * @param commit 36 | * @param view 37 | */ 38 | addVisitedViews({ commit }, view) { 39 | commit('ADD_VISITED_VIEWS', view); 40 | }, 41 | 42 | /** 43 | * 关闭当前标签 44 | * @param commit 45 | * @param state 46 | * @param view 47 | * @return {Promise} 48 | */ 49 | delVisitedViews({ commit, state }, view) { 50 | return new Promise((resolve) => { 51 | commit('DEL_VISITED_VIEWS', view); 52 | resolve([...state.visitedViews]); 53 | }); 54 | }, 55 | 56 | /** 57 | * 关闭其它标签 58 | * @param commit 59 | * @param state 60 | * @param view 61 | * @return {Promise} 62 | */ 63 | delOthersViews({ commit, state }, view) { 64 | return new Promise((resolve) => { 65 | commit('DEL_OTHERS_VIEWS', view); 66 | resolve([...state.visitedViews]); 67 | }); 68 | }, 69 | 70 | /** 71 | * 关闭所有标签 72 | * @param commit 73 | * @param state 74 | * @return {Promise} 75 | */ 76 | delAllViews({ commit, state }) { 77 | return new Promise((resolve) => { 78 | commit('DEL_ALL_VIEWS'); 79 | resolve([...state.visitedViews]); 80 | }); 81 | } 82 | }; 83 | 84 | const mutations = { 85 | 86 | /** 87 | * 新增标签 88 | * @param state 89 | * @param view 90 | * @constructor 91 | */ 92 | ADD_VISITED_VIEWS: (state, view) => { 93 | if (state.visitedViews.some(v => v.path === view.path)) return; 94 | state.visitedViews.push({ 95 | name: view.name, 96 | path: view.path, 97 | title: view.title || view.name || '欢迎页' 98 | }); 99 | 100 | if (!view.meta.noCache) { 101 | state.cachedViews.push(view.name); 102 | } 103 | }, 104 | 105 | /** 106 | * 关闭当前标签 107 | * @param state 108 | * @param view 109 | * @constructor 110 | */ 111 | DEL_VISITED_VIEWS: (state, view) => { 112 | for (const [i, v] of state.visitedViews.entries()) { 113 | if (v.path === view.path) { 114 | state.visitedViews.splice(i, 1); 115 | break; 116 | } 117 | } 118 | 119 | for (const i of state.cachedViews) { 120 | if (i === view.name) { 121 | const index = state.cachedViews.indexOf(i); 122 | state.cachedViews.splice(index, 1); 123 | break; 124 | } 125 | } 126 | }, 127 | 128 | /** 129 | * 关闭其他标签 130 | * @param state 131 | * @param view 132 | * @constructor 133 | */ 134 | DEL_OTHERS_VIEWS: (state, view) => { 135 | for (const [i, v] of state.visitedViews.entries()) { 136 | if (v.path === view.path) { 137 | state.visitedViews = state.visitedViews.slice(i, i + 1); 138 | break; 139 | } 140 | } 141 | for (const i of state.cachedViews) { 142 | if (i === view.name) { 143 | const index = state.cachedViews.indexOf(i); 144 | state.cachedViews = state.cachedViews.slice(index, i + 1); 145 | break; 146 | } 147 | } 148 | }, 149 | 150 | /** 151 | * 关闭所有标签 152 | * @param state 153 | * @constructor 154 | */ 155 | DEL_ALL_VIEWS: (state) => { 156 | state.visitedViews = []; 157 | state.cachedViews = []; 158 | } 159 | }; 160 | 161 | export default { 162 | state, 163 | getters, 164 | actions, 165 | mutations 166 | }; 167 | -------------------------------------------------------------------------------- /client/store/models/test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Simple on 2018/1/12 0012. 3 | * test 4 | */ 5 | 6 | //import types from '../types.js'; 7 | const state = { 8 | 9 | }; 10 | 11 | const getters = { 12 | 13 | }; 14 | 15 | const actions = { 16 | 17 | }; 18 | 19 | const mutations = { 20 | 21 | }; 22 | 23 | export default { 24 | state, 25 | getters, 26 | actions, 27 | mutations 28 | }; -------------------------------------------------------------------------------- /client/store/models/users.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Simple on 2018/1/12 0012. 3 | * 用户模块 4 | */ 5 | import types from '../types.js'; 6 | const state = { 7 | userInfo: null //用户信息 8 | }; 9 | 10 | const getters = { 11 | 12 | /** 13 | * 用户信息 14 | * @param {*} state 15 | */ 16 | userInfo(state) { 17 | const user = window.localStorage.getItem('BIU-SERVER-ADMIN-INFO'); 18 | if (user) return JSON.parse(user); 19 | return state.userInfo; 20 | } 21 | 22 | }; 23 | 24 | const actions = { 25 | setToken({ commit }, token) { 26 | commit(types.SET_USER_TOKEN, token); 27 | } 28 | }; 29 | 30 | const mutations = { 31 | 32 | /* [types.GET_OWNER_ITEM](state, data) { 33 | state.ownerItem = data; 34 | }, */ 35 | }; 36 | 37 | export default { 38 | state, 39 | getters, 40 | actions, 41 | mutations 42 | }; 43 | -------------------------------------------------------------------------------- /client/store/mutations.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Simple on 2018/1/12 0012. 3 | * store 公共方法类 4 | */ 5 | 6 | // 导入公共状态模块 7 | import types from './types.js'; 8 | const mutations = { 9 | 10 | //设置权限 11 | [types.SET_PERMISSION] (state, data) { 12 | state.permission = data; 13 | } 14 | }; 15 | 16 | export default mutations; 17 | -------------------------------------------------------------------------------- /client/store/state.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/1/14 0014. 3 | * 公共状态模块 4 | */ 5 | 6 | //导入公共方法 7 | import config from '@/base/config'; 8 | const state = { 9 | config: config, //配置 10 | permission: [] //权限数组 11 | }; 12 | 13 | export default state; 14 | -------------------------------------------------------------------------------- /client/store/types.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Simple on 2018/1/12 0012. 3 | * 常量工具库 4 | */ 5 | 6 | // 设置权限 7 | const SET_PERMISSION = 'SET_PERMISSION'; 8 | export default { 9 | SET_PERMISSION 10 | }; 11 | -------------------------------------------------------------------------------- /docs-v1.0.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/docs-v1.0.0.zip -------------------------------------------------------------------------------- /docs-v1.0.0/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 确保脚本抛出遇到的错误 4 | set -e 5 | 6 | # 生成静态文件 7 | npm run d:build 8 | 9 | # 进入生成的文件夹 10 | cd docs/.vuepress/dist 11 | 12 | # 如果是发布到自定义域名 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | git commit -m 'deploy' 18 | 19 | # 如果发布到 https://.github.io USERNAME=你的用户名 20 | # git push -f git@github.com:/.github.io.git master 21 | 22 | # 如果发布到 https://.github.io/ REPO=github上的项目 23 | # git push -f git@github.com:/.git master:gh-pages 24 | 25 | cd - 26 | -------------------------------------------------------------------------------- /docs-v1.0.0/docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | head: [ // 注入到当前页面的 HTML 中的标签 3 | // ['link', { rel: 'manifest', href: '/manifest.json' }], 4 | ['link', { rel: 'icon', href: '/images/favicon.ico' }], // 增加一个自定义的 favicon(网页标签的图标) 5 | ['link', { rel: 'apple-touch-icon', href: '/images/logo.png' }], 6 | ], 7 | serviceWorker: true, // 是否开启 PWA 8 | base: '/', // 这是部署到github相关的配置 9 | markdown: { 10 | lineNumbers: true // 代码块显示行号 11 | }, 12 | locales: { 13 | // 键名是该语言所属的子路径 14 | // 作为特例,默认语言可以使用 '/' 作为其路径。 15 | '/': { 16 | lang: 'zh-CN', 17 | title: 'BiuServerAdmin', 18 | description: '基于Node Koa2的RESTful API 应用级Node服务器' 19 | }, 20 | '/en/': { 21 | lang: 'en-US', // 将会被设置为 的 lang 属性 22 | title: 'VuePress', 23 | description: 'Vue-powered Static Site Generator' 24 | } 25 | }, 26 | themeConfig: { 27 | locales: { 28 | '/': { 29 | smoothScroll: true, //启用页面滚动效果 30 | sidebarDepth: 2, //提取的侧边栏深度 6 31 | // 多语言下拉菜单的标题 32 | selectText: '选择语言', 33 | // 该语言在下拉菜单中的标签 34 | label: '简体中文', 35 | // 编辑链接文字 36 | editLinkText: '在 GitHub 上编辑此页', 37 | // Service Worker 的配置 38 | serviceWorker: { 39 | updatePopup: { 40 | message: "发现新内容可用.", 41 | buttonText: "刷新" 42 | } 43 | }, 44 | // 当前 locale 的 algolia docsearch 选项 45 | algolia: {}, 46 | nav: [ 47 | { text: '指南', link: '/zh/guide/' }, 48 | { text: '了解更多', link: 'https://google.com' }, 49 | ], 50 | sidebar: [ 51 | ['/zh/guide/','简介'], 52 | ['/zh/guide/install','安装'], 53 | ['/zh/guide/directory-structure', '目录结构'], 54 | ['/zh/guide/test', 'Test'], 55 | ] 56 | }, 57 | '/en/': { 58 | selectText: 'Languages', 59 | label: 'English', 60 | ariaLabel: 'Languages', 61 | editLinkText: 'Edit this page on GitHub', 62 | serviceWorker: { 63 | updatePopup: { 64 | message: "New content is available.", 65 | buttonText: "Refresh" 66 | } 67 | }, 68 | algolia: {} 69 | } 70 | } 71 | }, 72 | plugins: ['autobar'] 73 | } 74 | -------------------------------------------------------------------------------- /docs-v1.0.0/docs/.vuepress/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/docs-v1.0.0/docs/.vuepress/public/images/favicon.ico -------------------------------------------------------------------------------- /docs-v1.0.0/docs/.vuepress/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/docs-v1.0.0/docs/.vuepress/public/images/logo.png -------------------------------------------------------------------------------- /docs-v1.0.0/docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | defaultHome: true 3 | home: true 4 | # heroImage: /images/logo.png 5 | # heroText: Hero 标题 6 | # tagline: Hero 副标题 7 | actionText: 快速上手 → 8 | actionLink: /zh/guide/ 9 | features: 10 | - title: RESTful API 11 | details: 遵循统一接口原则,使用标准的HTTP请求方法,统一状态码等,返回标准的JSON格式。 12 | - title: Nodejs Koa2 13 | details: 基于现在主流的koa2服务框架,高性能和高可用性,毫秒级请求响应。 14 | - title: 工程化项目 15 | details: 使用清晰明了的项目结构,统一方法封装等,使整个项目内容有条不紊。 16 | - title: 易用 17 | details: 假如你已经有ES6和koa相关的知识,分分钟即可上手。 18 | - title: 灵活 19 | details: 模块化的应用开发,一个接口分分钟搞定,可选的管理后台页面(基于Nuxt开发,只要你会Vue即可开发)。 20 | - title: 高效 21 | details: 使用JWT身份认证,项目中使用了MySQL数据库,集成Sequelize等ORM工具。 22 | footer: MIT Licensed | Copyright © 2018-present 狼丶宇先生 23 | --- 24 | -------------------------------------------------------------------------------- /docs-v1.0.0/docs/zh/guide/README.md: -------------------------------------------------------------------------------- 1 | ## 此项目的初衷 2 | 3 | 项目的起因是这样的,nodejs发布了这么久了,但是翻了几乎很多项目,发现每个人的写法以及风格都不一样,导致开发出来的项目难维护,代码太乱。 4 | 此项目仅仅作为最精简的框架使用,没有太多的插件和配置。可根据需要进行集成。 5 | 6 | 1. 这是一个基于Node和Koa2开发的restfulAPI服务器,自带了一套后台管理系统的基础UI框架,可以实现,API服务和数据管理一体的部署. 7 | 2. 如果你的需求只是作为纯API服务器来使用,可以根据相关配置来移除管理后台的页面,也可以根据配置选择不渲染管理后台的UI。 8 | 9 | ## 基于nuxt集成管理后台 10 | 11 | 如果仅仅是做数据展示,或者一些简单的数据操作等,可以选择是否使用此项目里的管理后台页面。 12 | 13 | ## 技术栈 14 | 15 | - node后台部分使用了,koa2以及koa相关的模块,数据库使用的MySQL,集成ORM工具Sequelize 16 | - 管理后台是基于nuxt的,因为和服务端结合比较方便无需单独启动服务,直接集成.UI部分使用的Element-UI框架. 17 | - async 函数,彻底的告别了回调地狱. 18 | -------------------------------------------------------------------------------- /docs-v1.0.0/docs/zh/guide/install.md: -------------------------------------------------------------------------------- 1 | ## 安装使用 2 | 3 | ### 1.下载项目 4 | ```bash 5 | git clone https://github.com/langyuxiansheng/biu-server-admin.git 6 | 7 | cd biu-server-admin 8 | 9 | yarn # or npm install 10 | ``` 11 | ### 2.新建数据库,导入SQL 12 | 13 | ``` 14 | 导入 biu-server-admin/sqls/biu_server_db.sql 15 | ``` 16 | 17 | ### 3.配置服务器相关的信息 18 | 19 | :::tip server.base.config.js 20 | 需要配置数据库的地址,用户名及用户密码 21 | 22 | 找到服务器的配置文件: biu-server-admin/server/src/config/server.base.config.js 如下: 23 | ::: 24 | 25 | ```javascript 26 | const path = require('path'); //路径模块 27 | 28 | /** 29 | * 主配置 30 | */ 31 | module.exports = { 32 | port: 3010, // default: 3000 33 | host: '127.0.0.1', // default: '127.0.0.1', 34 | jwtPublicKey: 'jwtPublicKey', //公钥, 加解密jwt使用,建议使用自定义复杂的字符串 35 | isNuxtRender: true, //是否启用nuxt渲染 true启用管理后台界面,false 不使用管理后台,只是使用API服务器 36 | uploadDir: path.join(__dirname, `../public/uploads/tmp`), //上传文件缓存路径,相对于 server.base.config.js 的路径 37 | staticPath: path.join(__dirname, `../public`), //静态文件路径,相对于 server.base.config.js 的路径 38 | crawler: { 39 | start: true, //是否开启爬虫系统 40 | settimeout: 1 //延时多少s启动 41 | }, 42 | saltMD5: '_SERVICE.BIU.COM', //md5 加盐的字符,随意更改可能会造成密码错误等. 43 | filePrefix: 'BIU_WEB_', //上传的文件名前缀 44 | email: { 45 | host: 'smtp.qq.com', //邮箱服务器地址 46 | port: 465, //服务器端口 默认 465 47 | fromUser: '"发送人" <1096432936@qq.com>', //发送人 48 | secureConnection: true, //仅安全连接模式 49 | // 我们需要登录到网页邮箱中,然后配置SMTP和POP3服务器的密码 50 | auth: { 51 | user: '1096432936@qq.com', 52 | pass: 'kqpzjioamhbdbaec' 53 | } 54 | }, 55 | dbs: { //数据源配置 56 | BiuDB: { //可根据实际项目名定义,需要全局更改 57 | name: 'BiuDB', //ORM中使用的名称 建议和key一样的名称 58 | type: 'sequelize', //orm类型 类型可选sequelize redis等 59 | config: { 60 | username: 'biu_server_db', // 数据库用户名 61 | password: '123456', // 数据库密码 62 | database: 'biu_server_db', // 数据库名称 63 | options: { //配置项 64 | dialect: 'mysql', // 数据库类型 65 | host: 'localhost', // 服务器地址 66 | port: 3306, // 数据库端口号 67 | dialectOptions: { // MySQL > 5.5,其它数据库删除此项 68 | charset: 'utf8mb4', 69 | supportBigNumbers: true, 70 | bigNumberStrings: true 71 | //collate: 'utf8mb4_unicode_520_ci', 72 | //requestTimeout: 60 * 1000 //设置连接超时时间 73 | }, 74 | define: { 75 | underscored: false, // 转换列名的驼峰命名规则为下划线命令规则 76 | freezeTableName: true, //设置为true时,sequelize不会改变表名,否则可能会按其规则有所调整 77 | charset: 'utf8mb4', 78 | timestamps: false //为模型添加 createdAt 和 updatedAt 两个时间戳字段 79 | }, 80 | pool: { 81 | max: 50, // 连接池中最大连接数量 82 | min: 0, // 连接池中最小连接数量 83 | idle: 10000 // 如果一个线程 10 秒钟内没有被使用过的话,那么就释放线程 84 | } 85 | } 86 | } 87 | } 88 | }, 89 | unlessPath: [ //url白名单 如果不设置默认都是没权限访问的,会返回{code:401} 90 | /^\/public/, //公共资源 91 | /^\/_nuxt/, //nuxt页面 92 | /^\/login/, //登录 93 | /^\/favicon.ico/, 94 | /^\/__webpack_hmr/, 95 | /^\/System/, //系统设置 96 | /^\/Home/, //主页 97 | //api部分 98 | /^\/v1\/api\/common\/getImgValidate/, //验证码 99 | /^\/v1\/api\/common\/userLoginForSysAdmin/ //登录接口 100 | ] 101 | }; 102 | ``` 103 | 104 | ### 4.依赖安装和数据库相关配置完成后 105 | ```bash 106 | npm run dev #or yarn run dev 107 | 108 | # 启动成功后访问http://localhost:3010/login 即可进入管理后台 109 | ``` 110 | -------------------------------------------------------------------------------- /docs-v1.0.0/docs/zh/guide/test.md: -------------------------------------------------------------------------------- 1 | ## faakf 2 | 3 | --- fahjsagsagds 4 | 5 | ```javascript 6 | 7 | 8 | 9 | ``` 10 | 11 | 12 | --- 13 | title: Blogging Like a Hacker 14 | lang: en-US 15 | --- 16 | 17 | 18 | | Tables | Are | Cool | 19 | | ------------- |:-------------:| -----:| 20 | | col 3 is | right-aligned | $1600 | 21 | | col 2 is | centered | $12 | 22 | | zebra stripes | are neat | $1 | 23 | 24 | 25 | ::: tip 26 | This is a tip 27 | ::: 28 | 29 | ::: warning 30 | This is a warning 31 | ::: 32 | 33 | ::: danger 34 | This is a dangerous warning 35 | ::: 36 | 37 | ::: danger STOP 38 | Danger zone, do not proceed 39 | ::: 40 | 41 | 42 | ``` js 43 | export default { 44 | name: 'MyComponent', 45 | // ... 46 | } 47 | ``` 48 | 49 | ``` html 50 |
    51 |
  • 55 | {{ todo.text }} 56 |
  • 57 |
58 | ``` 59 | 60 | ``` js {4} 61 | export default { 62 | data () { 63 | return { 64 | msg: 'Highlighted!' 65 | } 66 | } 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /docs-v1.0.0/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs-v1.0.0", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "d:dev": "vuepress dev docs", 8 | "d:build": "vuepress build docs" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "baseUrl": "./", 5 | "paths": { 6 | "@/*": ["client/*"], 7 | ":root/*": ["*"], 8 | ":config/*": ["server/src/config/*"], 9 | ":lib/*": ["server/src/lib/*"], 10 | ":services/*": ["server/src/services/*"], 11 | ":controllers/*":["server/src/controllers/*"], 12 | ":models/*": ["server/src/models/*"], 13 | ":routes/*": ["server/src/routes/*"], 14 | ":crawlers/*": ["server/src/crawlers/*"], 15 | ":middleware/*": ["server/src/middleware/*"], 16 | ":logs/*": ["server/src/logs/*"] 17 | } 18 | }, 19 | "include": ["server/**/*","client/**/*"], 20 | "exclude": [ 21 | "node_modules", 22 | "nuxt-dist", 23 | "server-dist" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /nuxt.config.js: -------------------------------------------------------------------------------- 1 | const pkg = require('./package.json'); 2 | module.exports = { 3 | mode: 'spa', //非单页 //universal 4 | buildDir: 'nuxt-dist', //打包输出文件夹 5 | srcDir: 'client/', //设置 Nuxt.js 应用的源码目录 6 | head: { 7 | title: pkg.title, 8 | meta: [ 9 | { charset: 'utf-8' }, 10 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 11 | { hid: 'description', name: 'description', content: pkg.description } 12 | ], 13 | link: [ 14 | // { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, 15 | { rel: 'stylesheet', href: 'https://at.alicdn.com/t/font_1054677_wrbfln7pseg.css' } 16 | ] 17 | }, 18 | loading: { color: '#fff' }, 19 | css: [ 20 | // 'element-ui/lib/theme-chalk/index.css', 21 | '@/assets/styles/default-theme/theme/index.css', 22 | '@/assets/styles/common/reset.css', 23 | '@/assets/styles/common/theme.default.less' 24 | ], 25 | plugins: [ 26 | '@/plugins/element-ui', 27 | '@/plugins/components', 28 | '@/plugins/i18n', 29 | '@/plugins/filters', 30 | '@/plugins/axios' 31 | ], 32 | modules: [ 33 | '@nuxtjs/axios' 34 | ], 35 | build: { 36 | extend(config, ctx) { 37 | if (ctx.isDev && ctx.isClient) { 38 | config.module.rules.push({ 39 | enforce: 'pre', 40 | test: /\.(js|vue)$/, 41 | loader: 'eslint-loader', 42 | exclude: /(node_modules)/ 43 | }); 44 | }; 45 | } 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "biu-server-admin", 3 | "title": "基于Node-Koa2的restfulAPI服务器", 4 | "version": "1.0.0", 5 | "description": "基于Node-Koa2的restfulAPI服务器,自带一套管理后台系统,也可以独立出来作为纯API服务器使用", 6 | "author": "simple", 7 | "private": true, 8 | "scripts": { 9 | "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server --exec babel-node", 10 | "build": "nuxt build", 11 | "start": "cross-env NODE_ENV=production nodemon server/index.js", 12 | "dist": "nuxt generate", 13 | "service": "babel server -d server-dist", 14 | "lint": "eslint --ext .js,.vue --ignore-path .gitignore .", 15 | "pm": "pm2 start npm --name 'BiuXS' -- run start", 16 | "precommit": "npm run lint" 17 | }, 18 | "dependencies": { 19 | "@nuxtjs/axios": "^5.3.6", 20 | "@nuxtjs/proxy": "^1.3.3", 21 | "acorn": "^6.0.5", 22 | "best-require": "^1.1.4", 23 | "blueimp-md5": "^2.10.0", 24 | "cheerio": "^1.0.0-rc.3", 25 | "cross-env": "^5.2.0", 26 | "element-ui": "^2.4.11", 27 | "ip": "^1.1.5", 28 | "js-cookie": "^2.2.0", 29 | "koa": "^2.6.2", 30 | "koa-body": "^4.1.0", 31 | "koa-cors": "0.0.16", 32 | "koa-jwt": "^3.5.1", 33 | "koa-log4": "^2.3.2", 34 | "koa-response-time": "^2.1.0", 35 | "koa-router": "^7.4.0", 36 | "koa-static": "^3.0.0", 37 | "log4js": "^4.1.0", 38 | "mysql2": "^1.6.5", 39 | "node-pre-gyp": "^0.10.0", 40 | "node-schedule": "^1.3.2", 41 | "nodemailer": "^6.3.1", 42 | "nuxt": "^2.3.4", 43 | "request": "^2.88.2", 44 | "require-directory": "^2.1.1", 45 | "sequelize": "^5.3.0", 46 | "superagent": "^5.0.2", 47 | "superagent-charset": "^1.2.0", 48 | "superagent-proxy": "^2.0.0", 49 | "svg-captcha": "^1.3.12", 50 | "uuid": "^3.3.2", 51 | "vue-directive-image-previewer": "^2.2.1", 52 | "vue-i18n": "^8.10.0", 53 | "vuex-persist": "^2.2.0" 54 | }, 55 | "devDependencies": { 56 | "babel-cli": "^6.26.0", 57 | "babel-core": "^6.26.3", 58 | "babel-eslint": "^10.0.1", 59 | "babel-plugin-component": "^1.1.1", 60 | "babel-plugin-import": "^1.11.0", 61 | "babel-plugin-transform-runtime": "^6.22.0", 62 | "babel-preset-es2015": "^6.24.1", 63 | "babel-preset-stage-2": "^6.24.1", 64 | "babel-register": "^6.26.0", 65 | "eslint": "^5.8.0", 66 | "eslint-config-standard": "^12.0.0", 67 | "eslint-loader": "^2.1.1", 68 | "eslint-plugin-html": "^5.0.0", 69 | "eslint-plugin-import": "^2.14.0", 70 | "eslint-plugin-node": "^8.0.0", 71 | "eslint-plugin-promise": "^4.0.1", 72 | "eslint-plugin-standard": "^4.0.0", 73 | "eslint-plugin-vue": "^5.0.0-0", 74 | "less": "^3.9.0", 75 | "less-loader": "^4.1.0", 76 | "nodemon": "^1.18.9" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /pm2.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [{ 3 | name: 'BiuServerAdmin', 4 | script: './server/index.js', 5 | cwd: './', 6 | // script: 'cross-env NODE_ENV=production nodemon ./server/index.js --exec babel-node', 7 | watch: ['server'], // 默认关闭watch 可替换为 ['src'] 8 | ignore_watch: ['node_modules', 'build', 'logs', 'client'], 9 | out_file: './logs/out.log', // 日志输出 10 | error_file: './logs/error.log', // 错误日志 11 | max_memory_restart: '2G', // 超过多大内存自动重启,仅防止内存泄露有意义,需要根据自己的业务设置 12 | env: { 13 | NODE_ENV: 'production' 14 | }, 15 | exec_mode: 'cluster', // 开启多线程模式,用于负载均衡 16 | instances: 'max', // 启用多少个实例,可用于负载均衡 17 | autorestart: true, // 程序崩溃后自动重启. 18 | log_date_format: 'YYYY-MM-DD HH:mm:ss' 19 | }] 20 | }; 21 | -------------------------------------------------------------------------------- /server-dist.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/server-dist.zip -------------------------------------------------------------------------------- /server-dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var ROOT_PATH = process.cwd(); 5 | var SRC_PATH = path.join(ROOT_PATH, '/server/src'); 6 | console.log(ROOT_PATH, SRC_PATH); 7 | //映射目录别名 8 | require('best-require')(ROOT_PATH, { 9 | root: ROOT_PATH, 10 | src: SRC_PATH, 11 | controllers: path.join(SRC_PATH, '/controllers'), 12 | models: path.join(SRC_PATH, '/models'), 13 | routes: path.join(SRC_PATH, '/routes'), 14 | crawlers: path.join(SRC_PATH, '/crawlers'), 15 | services: path.join(SRC_PATH, '/services'), 16 | middleware: path.join(SRC_PATH, '/middleware'), 17 | lib: path.join(SRC_PATH, '/lib'), 18 | config: path.join(SRC_PATH, '/config'), 19 | logs: path.join(SRC_PATH, '/logs') 20 | }); 21 | //运行服务 22 | require('./src/bin/Server').run(); -------------------------------------------------------------------------------- /server-dist/src/config/server.base.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); //路径模块 4 | 5 | /** 6 | * 主配置 7 | */ 8 | module.exports = { 9 | port: 3010, // default: 3000 10 | host: '127.0.0.1', // default: '127.0.0.1', 11 | jwtPublicKey: 'jwtPublicKey', //公钥, 加解密jwt使用,建议使用自定义复杂的字符串 12 | isNuxtRender: true, //是否启用nuxt渲染 true启用管理后台界面,false 不使用管理后台,只是使用API服务器 13 | uploadDir: path.join(__dirname, '../public/uploads/tmp'), //上传文件缓存路径,相对于 server.base.config.js 的路径 14 | staticPath: path.join(__dirname, '../public'), //静态文件路径,相对于 server.base.config.js 的路径 15 | crawler: { 16 | start: true, //是否开启爬虫系统 17 | settimeout: 1 //延时多少s启动 18 | }, 19 | saltMD5: '_SERVICE.BIU.COM', //md5 加盐的字符,随意更改可能会造成密码错误等. 20 | filePrefix: 'BIU_WEB_', //上传的文件名前缀 21 | email: { 22 | host: 'smtp.qq.com', //邮箱服务器地址 23 | port: 465, //服务器端口 默认 465 24 | fromUser: '"发送人" <1096432936@qq.com>', //发送人 25 | secureConnection: true, //仅安全连接模式 26 | // 我们需要登录到网页邮箱中,然后配置SMTP和POP3服务器的密码 27 | auth: { 28 | user: '1096432936@qq.com', 29 | pass: 'kqpzjioamhbdbaec' 30 | } 31 | }, 32 | dbs: { //数据源配置 33 | BiuDB: { 34 | name: 'BiuDB', //ORM中使用的名称 建议和key一样的名称 35 | type: 'sequelize', //orm类型 类型可选sequelize redis等 36 | config: { 37 | username: 'biu_server_db', // 数据库用户名 38 | password: 'mWTNrJ7ewJFDkAd5', // 数据库密码 39 | database: 'biu_server_db', // 数据库名称 40 | options: { //配置项 41 | dialect: 'mysql', // 数据库类型 42 | host: '111.231.225.103', // 服务器地址 43 | port: 3306, // 数据库端口号 44 | dialectOptions: { // MySQL > 5.5,其它数据库删除此项 45 | charset: 'utf8mb4', 46 | supportBigNumbers: true, 47 | bigNumberStrings: true 48 | //collate: 'utf8mb4_unicode_520_ci', 49 | //requestTimeout: 60 * 1000 //设置连接超时时间 50 | }, 51 | define: { 52 | underscored: false, // 转换列名的驼峰命名规则为下划线命令规则 53 | freezeTableName: true, //设置为true时,sequelize不会改变表名,否则可能会按其规则有所调整 54 | charset: 'utf8mb4', 55 | timestamps: false //为模型添加 createdAt 和 updatedAt 两个时间戳字段 56 | }, 57 | pool: { 58 | max: 50, // 连接池中最大连接数量 59 | min: 0, // 连接池中最小连接数量 60 | idle: 10000 // 如果一个线程 10 秒钟内没有被使用过的话,那么就释放线程 61 | } 62 | } 63 | } 64 | } 65 | }, 66 | unlessPath: [//url白名单 如果不设置默认都是没权限访问的,会返回{code:401} 67 | /^\/public/, //公共资源 68 | /^\/_nuxt/, //nuxt页面 69 | /^\/login/, //登录 70 | /^\/favicon.ico/, /^\/__webpack_hmr/, /^\/System/, //系统设置 71 | /^\/Home/, //主页 72 | //api部分 73 | /^\/v1\/api\/common\/getImgValidate/, //验证码 74 | /^\/v1\/api\/common\/userLoginForSysAdmin/ //登录接口 75 | ] 76 | }; -------------------------------------------------------------------------------- /server-dist/src/controllers/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _keys = require('babel-runtime/core-js/object/keys'); 4 | 5 | var _keys2 = _interopRequireDefault(_keys); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 8 | 9 | //主路由文件 10 | var KoaRouter = require('koa-router'); 11 | var models = require(':controllers/models'); 12 | var result = require(':lib/Result'); 13 | //所有的API接口都以/v1/api开头 14 | var router = new KoaRouter({ prefix: '/v1/api/' }); 15 | //整合路由 16 | (0, _keys2.default)(models).forEach(function (key) { 17 | (0, _keys2.default)(models[key]).forEach(function (k2) { 18 | router.use(key.toLowerCase(), models[key][k2].routes(), models[key][k2].allowedMethods()); 19 | }); 20 | }); 21 | 22 | /** 23 | * 所有的非法请求全都返回统一结果 24 | */ 25 | router.all('*', function (ctx) { 26 | ctx.body = result.failed('\u975E\u6CD5\u8BF7\u6C42!'); 27 | }); 28 | 29 | // console.log(router); 30 | module.exports = router; -------------------------------------------------------------------------------- /server-dist/src/controllers/models/common/LoginController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _regenerator = require('babel-runtime/regenerator'); 4 | 5 | var _regenerator2 = _interopRequireDefault(_regenerator); 6 | 7 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); 8 | 9 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | /** 14 | * 用户登录路由入口 15 | */ 16 | var KoaRouter = require('koa-router'); 17 | var LoginService = require(':services/common/LoginService'); 18 | var controller = new KoaRouter(); 19 | var service = new LoginService(); 20 | 21 | //系统管理员登录 22 | controller.post('/userLoginForSysAdmin', function () { 23 | var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(ctx) { 24 | return _regenerator2.default.wrap(function _callee$(_context) { 25 | while (1) { 26 | switch (_context.prev = _context.next) { 27 | case 0: 28 | _context.next = 2; 29 | return service.userLoginForSysAdmin({ data: ctx.request.body, cookies: ctx.cookies }); 30 | 31 | case 2: 32 | ctx.body = _context.sent; 33 | 34 | case 3: 35 | case 'end': 36 | return _context.stop(); 37 | } 38 | } 39 | }, _callee, undefined); 40 | })); 41 | 42 | return function (_x) { 43 | return _ref.apply(this, arguments); 44 | }; 45 | }()); 46 | 47 | //商家登录 48 | controller.post('/loginForBusiness', function () { 49 | var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(ctx) { 50 | return _regenerator2.default.wrap(function _callee2$(_context2) { 51 | while (1) { 52 | switch (_context2.prev = _context2.next) { 53 | case 0: 54 | _context2.next = 2; 55 | return service.loginForBusiness({ data: ctx.request.body, cookies: ctx.cookies }); 56 | 57 | case 2: 58 | ctx.body = _context2.sent; 59 | 60 | case 3: 61 | case 'end': 62 | return _context2.stop(); 63 | } 64 | } 65 | }, _callee2, undefined); 66 | })); 67 | 68 | return function (_x2) { 69 | return _ref2.apply(this, arguments); 70 | }; 71 | }()); 72 | 73 | module.exports = controller; -------------------------------------------------------------------------------- /server-dist/src/controllers/models/common/UtilsController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _regenerator = require('babel-runtime/regenerator'); 4 | 5 | var _regenerator2 = _interopRequireDefault(_regenerator); 6 | 7 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); 8 | 9 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | /** 14 | * 用户登录路由入口 15 | */ 16 | var KoaRouter = require('koa-router'); 17 | var UtilsService = require(':services/common/UtilsService'); 18 | var controller = new KoaRouter(); 19 | var service = new UtilsService(); 20 | //登录 21 | controller.get('/getImgValidate', function () { 22 | var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(ctx) { 23 | var res; 24 | return _regenerator2.default.wrap(function _callee$(_context) { 25 | while (1) { 26 | switch (_context.prev = _context.next) { 27 | case 0: 28 | _context.next = 2; 29 | return service.getImgValidate(); 30 | 31 | case 2: 32 | res = _context.sent; 33 | 34 | //设置验证码 35 | ctx.cookies.set('IMG-VALIDATE-DATA', res.data.text, { httpOnly: true, maxAge: 1000 * 60 * 5 }); 36 | ctx.body = res; 37 | 38 | case 5: 39 | case 'end': 40 | return _context.stop(); 41 | } 42 | } 43 | }, _callee, undefined); 44 | })); 45 | 46 | return function (_x) { 47 | return _ref.apply(this, arguments); 48 | }; 49 | }()); 50 | module.exports = controller; -------------------------------------------------------------------------------- /server-dist/src/controllers/models/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('require-directory')(module); -------------------------------------------------------------------------------- /server-dist/src/controllers/models/system/LogsController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _regenerator = require('babel-runtime/regenerator'); 4 | 5 | var _regenerator2 = _interopRequireDefault(_regenerator); 6 | 7 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); 8 | 9 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | /** 14 | * 系统管理员管理 15 | */ 16 | var KoaRouter = require('koa-router'); 17 | var LogsService = require(':services/system/LogsService'); 18 | var controller = new KoaRouter(); 19 | var service = new LogsService(); 20 | 21 | //获取系统日志 22 | controller.get('/getSysLogList', function () { 23 | var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(ctx) { 24 | return _regenerator2.default.wrap(function _callee$(_context) { 25 | while (1) { 26 | switch (_context.prev = _context.next) { 27 | case 0: 28 | _context.next = 2; 29 | return service.getSysLogList(ctx.state.user.data); 30 | 31 | case 2: 32 | ctx.body = _context.sent; 33 | 34 | case 3: 35 | case 'end': 36 | return _context.stop(); 37 | } 38 | } 39 | }, _callee, undefined); 40 | })); 41 | 42 | return function (_x) { 43 | return _ref.apply(this, arguments); 44 | }; 45 | }()); 46 | 47 | //获取系统日志内容 48 | controller.get('/getSysLogContent', function () { 49 | var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(ctx) { 50 | return _regenerator2.default.wrap(function _callee2$(_context2) { 51 | while (1) { 52 | switch (_context2.prev = _context2.next) { 53 | case 0: 54 | _context2.next = 2; 55 | return service.getSysLogContent(ctx.request.query, ctx.state.user.data); 56 | 57 | case 2: 58 | ctx.body = _context2.sent; 59 | 60 | case 3: 61 | case 'end': 62 | return _context2.stop(); 63 | } 64 | } 65 | }, _callee2, undefined); 66 | })); 67 | 68 | return function (_x2) { 69 | return _ref2.apply(this, arguments); 70 | }; 71 | }()); 72 | 73 | //删除系统日志 74 | controller.delete('/delSysLogByPaths', function () { 75 | var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(ctx) { 76 | return _regenerator2.default.wrap(function _callee3$(_context3) { 77 | while (1) { 78 | switch (_context3.prev = _context3.next) { 79 | case 0: 80 | _context3.next = 2; 81 | return service.delSysLogByPaths(ctx.request.body, ctx.state.user.data); 82 | 83 | case 2: 84 | ctx.body = _context3.sent; 85 | 86 | case 3: 87 | case 'end': 88 | return _context3.stop(); 89 | } 90 | } 91 | }, _callee3, undefined); 92 | })); 93 | 94 | return function (_x3) { 95 | return _ref3.apply(this, arguments); 96 | }; 97 | }()); 98 | 99 | module.exports = controller; -------------------------------------------------------------------------------- /server-dist/src/controllers/models/system/RolesController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _regenerator = require('babel-runtime/regenerator'); 4 | 5 | var _regenerator2 = _interopRequireDefault(_regenerator); 6 | 7 | var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator'); 8 | 9 | var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | /** 14 | * 角色管理 15 | */ 16 | var KoaRouter = require('koa-router'); 17 | var RolesService = require(':services/system/RolesService'); 18 | var controller = new KoaRouter(); 19 | var service = new RolesService(); 20 | 21 | //添加角色 22 | controller.post('/addSysRole', function () { 23 | var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(ctx) { 24 | return _regenerator2.default.wrap(function _callee$(_context) { 25 | while (1) { 26 | switch (_context.prev = _context.next) { 27 | case 0: 28 | _context.next = 2; 29 | return service.addSysRole(ctx.request.body); 30 | 31 | case 2: 32 | ctx.body = _context.sent; 33 | 34 | case 3: 35 | case 'end': 36 | return _context.stop(); 37 | } 38 | } 39 | }, _callee, undefined); 40 | })); 41 | 42 | return function (_x) { 43 | return _ref.apply(this, arguments); 44 | }; 45 | }()); 46 | 47 | //获取系统角色 48 | controller.get('/getSysRoleList', function () { 49 | var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(ctx) { 50 | return _regenerator2.default.wrap(function _callee2$(_context2) { 51 | while (1) { 52 | switch (_context2.prev = _context2.next) { 53 | case 0: 54 | _context2.next = 2; 55 | return service.getSysRoleList(ctx.request.query); 56 | 57 | case 2: 58 | ctx.body = _context2.sent; 59 | 60 | case 3: 61 | case 'end': 62 | return _context2.stop(); 63 | } 64 | } 65 | }, _callee2, undefined); 66 | })); 67 | 68 | return function (_x2) { 69 | return _ref2.apply(this, arguments); 70 | }; 71 | }()); 72 | 73 | //删除系统角色 74 | controller.delete('/delSysRoleByIds', function () { 75 | var _ref3 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(ctx) { 76 | return _regenerator2.default.wrap(function _callee3$(_context3) { 77 | while (1) { 78 | switch (_context3.prev = _context3.next) { 79 | case 0: 80 | _context3.next = 2; 81 | return service.delSysRoleByIds(ctx.request.body); 82 | 83 | case 2: 84 | ctx.body = _context3.sent; 85 | 86 | case 3: 87 | case 'end': 88 | return _context3.stop(); 89 | } 90 | } 91 | }, _callee3, undefined); 92 | })); 93 | 94 | return function (_x3) { 95 | return _ref3.apply(this, arguments); 96 | }; 97 | }()); 98 | 99 | //更新系统角色 100 | controller.put('/updateSysRole', function () { 101 | var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(ctx) { 102 | return _regenerator2.default.wrap(function _callee4$(_context4) { 103 | while (1) { 104 | switch (_context4.prev = _context4.next) { 105 | case 0: 106 | _context4.next = 2; 107 | return service.updateSysRole(ctx.request.body); 108 | 109 | case 2: 110 | ctx.body = _context4.sent; 111 | 112 | case 3: 113 | case 'end': 114 | return _context4.stop(); 115 | } 116 | } 117 | }, _callee4, undefined); 118 | })); 119 | 120 | return function (_x4) { 121 | return _ref4.apply(this, arguments); 122 | }; 123 | }()); 124 | 125 | module.exports = controller; -------------------------------------------------------------------------------- /server-dist/src/lib/Email.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 4 | 5 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 6 | 7 | var _createClass2 = require('babel-runtime/helpers/createClass'); 8 | 9 | var _createClass3 = _interopRequireDefault(_createClass2); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var nodemailer = require('nodemailer'); 14 | module.exports = function () { 15 | function EMail(options) { 16 | (0, _classCallCheck3.default)(this, EMail); 17 | 18 | this.options = { 19 | host: 'smtp.qq.com', 20 | port: 465, 21 | fromUser: '"发送人" ', 22 | secureConnection: true, 23 | // 我们需要登录到网页邮箱中,然后配置SMTP和POP3服务器的密码 24 | auth: { 25 | user: 'user@qq.com', 26 | pass: 'loginkey' //邮箱生成的登录key 27 | } 28 | }; 29 | if (options) { 30 | for (var key in options) { 31 | this.options[key] = options[key]; 32 | } 33 | } 34 | this.mailer = nodemailer.createTransport(this.options); 35 | } 36 | 37 | /** 38 | * 发送邮件 39 | * @param {*} toName 接收者的名字 40 | * @param {*} toEmail 接收邮件的地址 41 | */ 42 | 43 | 44 | (0, _createClass3.default)(EMail, [{ 45 | key: 'sendEmail', 46 | value: function sendEmail(_ref) { 47 | var toName = _ref.toName, 48 | toEmail = _ref.toEmail, 49 | subject = _ref.subject, 50 | message = _ref.message; 51 | 52 | var sendHtml = '
' + toName + ',' + message + '
'; 53 | var mailOptions = { 54 | // 发送邮件的地址 55 | from: this.options.fromUser, // login user must equal to this user 56 | // 接收邮件的地址 57 | to: toEmail, // xrj0830@gmail.com 58 | // 邮件主题 59 | subject: subject || '你有一条新消息', 60 | // 以HTML的格式显示,这样可以显示图片、链接、字体颜色等信息 61 | html: sendHtml 62 | }; 63 | return this.mailer.sendMail(mailOptions); 64 | } 65 | }]); 66 | return EMail; 67 | }(); -------------------------------------------------------------------------------- /server-dist/src/lib/logger4.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); // 引入原生path模块 4 | var log4js = require('koa-log4'); // 引入koa-log4 5 | 6 | var _require = require(':lib/Utils'), 7 | SRC_PATH = _require.SRC_PATH; 8 | 9 | log4js.configure({ 10 | appenders: { 11 | // 访问日志 12 | access: { 13 | type: 'dateFile', 14 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 15 | alwaysIncludePattern: true, // 文件名始终以日期区分 16 | encoding: 'utf-8', 17 | filename: path.join(SRC_PATH + '/logs/access/', 'access.log') // 生成文件路径和文件名 18 | }, 19 | // 系统日志 20 | application: { 21 | type: 'dateFile', 22 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 23 | alwaysIncludePattern: true, // 文件名始终以日期区分 24 | encoding: 'utf-8', 25 | filename: path.join(SRC_PATH + '/logs/application/', 'application.log') // 生成文件路径和文件名 26 | }, 27 | accessErrorLogger: { 28 | type: 'dateFile', 29 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 30 | alwaysIncludePattern: true, // 文件名始终以日期区分 31 | encoding: 'utf-8', 32 | filename: path.join(SRC_PATH + '/logs/accessErrorLogger/', 'accessErrorLogger.log') // 生成文件路径和文件名 33 | }, 34 | accessSimpleLogger: { 35 | type: 'dateFile', 36 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 37 | alwaysIncludePattern: true, // 文件名始终以日期区分 38 | encoding: 'utf-8', 39 | filename: path.join(SRC_PATH + '/logs/accessSimpleLogger/', 'accessSimpleLogger.log') // 生成文件路径和文件名 40 | }, 41 | sqlLog: { 42 | type: 'dateFile', 43 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 44 | alwaysIncludePattern: true, // 文件名始终以日期区分 45 | encoding: 'utf-8', 46 | filename: path.join(SRC_PATH + '/logs/sqlLog/', 'sqlLog.log') // 生成文件路径和文件名 47 | }, 48 | out: { 49 | type: 'console' 50 | } 51 | }, 52 | categories: { 53 | default: { appenders: ['out'], level: 'info' }, 54 | access: { appenders: ['access'], level: 'info' }, 55 | application: { appenders: ['application', 'out'], level: 'WARN' }, 56 | accessErrorLogger: { appenders: ['accessErrorLogger', 'out'], level: 'WARN' }, 57 | accessSimpleLogger: { appenders: ['accessSimpleLogger', 'out'], level: 'WARN' }, 58 | sqlLog: { appenders: ['sqlLog', 'out'], level: 'info' } 59 | } 60 | }); 61 | 62 | module.exports = { 63 | accessLogger: function accessLogger() { 64 | return log4js.koaLogger(log4js.getLogger('access')); 65 | }, // 记录所有访问级别的日志 66 | systemLogger: log4js.getLogger('application'), //记录所有应用级别的日志 67 | accessErrorLogger: log4js.getLogger('accessErrorLogger'), //记录所有访问时报错的日志 68 | accessSimpleLogger: log4js.getLogger('accessSimpleLogger'), //记录所有简单访问时报错的日志 69 | sqlLog: log4js.getLogger('sqlLog') //记录所有SQL的日志 70 | }; -------------------------------------------------------------------------------- /server-dist/src/lib/sequelize.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _extends2 = require('babel-runtime/helpers/extends'); 4 | 5 | var _extends3 = _interopRequireDefault(_extends2); 6 | 7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 8 | 9 | /** 10 | * Sequelize.js api说明文档 11 | * https: //itbilu.com/nodejs/npm/V1PExztfb.html 12 | */ 13 | // const sequelize = require('./init.sequelize')(); 14 | var Sequelize = require('sequelize/index'); 15 | var config = require(':config/server.base.config'); //配置文件 16 | 17 | var _require = require(':lib/logger4'), 18 | systemLogger = _require.systemLogger, 19 | sqlLog = _require.sqlLog; 20 | 21 | var SOP = Sequelize.Op; 22 | /** 23 | * 列关联 24 | * @param {*} table 25 | * @param {*} col 26 | */ 27 | var COL = function COL(table, col) { 28 | return Sequelize.col(table + '.' + col); 29 | }; 30 | 31 | /** 32 | * attr合成 33 | * @param {*} table 34 | * @param {*} list 35 | */ 36 | var Attrs = function Attrs(table, list) { 37 | var arr = []; 38 | for (var x in list) { 39 | arr.push(COL(table, list[x])); 40 | } 41 | return arr; 42 | }; 43 | 44 | var BiuDB = new Sequelize(config.dbs.BiuDB.config.database, config.dbs.BiuDB.config.username, config.dbs.BiuDB.config.password, (0, _extends3.default)({}, config.dbs.BiuDB.config.options, { 45 | logging: function logging(sql) { 46 | //日志输出 不显示的输出设置为false 47 | sqlLog.info(config.dbs.BiuDB.config.database + '----' + sql); 48 | } 49 | })); 50 | BiuDB.authenticate().then(function (res) { 51 | systemLogger.info('\u8FDE\u63A5\u6570\u636E\u5E93\uFF1A' + config.dbs.BiuDB.config.database + ' \u6210\u529F!'); 52 | }).catch(function (err) { 53 | systemLogger.info('\u8FDE\u63A5\u6570\u636E\u5E93\uFF1A' + config.dbs.BiuDB.config.database + ' \u51FA\u9519!', err); 54 | }); 55 | 56 | //同步数据库模型专用 此操作将会删除数据库的表重新创建,请谨慎使用 57 | // BiuDB.sync({ force: true }).then(function(result) { 58 | // console.log('result'); 59 | // }); 60 | 61 | //配置关系型数据库ORM 62 | module.exports = { 63 | Sequelize: Sequelize, 64 | SOP: SOP, 65 | COL: COL, 66 | Attrs: Attrs, 67 | BiuDB: BiuDB 68 | }; -------------------------------------------------------------------------------- /server-dist/src/lib/userAgents.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var userAgents = ['Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0) ,Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre', 'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6', 'Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6', 'Opera/9.25 (Windows NT 5.1; U; en), Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36']; 4 | 5 | module.exports = userAgents[parseInt(Math.random() * userAgents.length)]; -------------------------------------------------------------------------------- /server-dist/src/middleware/ErrorRoutesCatch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*** 4 | * 错误捕获 5 | */ 6 | var result = require(':lib/Result'); 7 | module.exports = function (ctx, next) { 8 | return next().catch(function (err) { 9 | var status = err.status; 10 | if (status == 401) { 11 | ctx.body = result.authorities(); 12 | } else if (status == 404) { 13 | ctx.body = result.failed(204, '非法请求!'); 14 | } else { 15 | ctx.body = result.failed(null, String(err)); 16 | } 17 | }); 18 | }; -------------------------------------------------------------------------------- /server-dist/src/middleware/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _requireDirectory = require('require-directory'); 8 | 9 | var _requireDirectory2 = _interopRequireDefault(_requireDirectory); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | exports.default = function () { 14 | return (0, _requireDirectory2.default)(module); 15 | }; -------------------------------------------------------------------------------- /server-dist/src/models/common/FilesBaseModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * 文件基础表数据模型 5 | * @param {*} sequelize 6 | * @param {*} dataTypes 7 | * 此模型仅限关系型数据库使用 8 | */ 9 | // const { getTimeStampUUID } = require(':lib/Utils'); 10 | module.exports = function (sequelize, dataTypes) { 11 | return sequelize.define('FilesBase', { 12 | 13 | //文件ID 14 | fileId: { 15 | type: dataTypes.STRING(50), 16 | allowNull: false, 17 | primaryKey: true 18 | }, 19 | 20 | //文件名 21 | fileName: { 22 | type: dataTypes.STRING(100), 23 | allowNull: true 24 | }, 25 | 26 | //文件别名 27 | aliasName: { 28 | type: dataTypes.STRING(100), 29 | allowNull: true 30 | }, 31 | 32 | //上传人ID 33 | userId: { 34 | type: dataTypes.STRING(50), 35 | allowNull: true 36 | }, 37 | 38 | //上传人名称 39 | userName: { 40 | type: dataTypes.STRING(100), 41 | allowNull: true 42 | }, 43 | 44 | //文件大小 45 | size: { 46 | type: dataTypes.BIGINT(20), 47 | allowNull: true 48 | }, 49 | 50 | //文件类型 51 | type: { 52 | type: dataTypes.STRING(100), 53 | allowNull: true 54 | }, 55 | 56 | //文件后缀 57 | suffix: { 58 | type: dataTypes.STRING(30), 59 | allowNull: true 60 | }, 61 | 62 | //文件存放的路径 63 | path: { 64 | type: dataTypes.STRING(200), 65 | allowNull: true 66 | }, 67 | 68 | fileMD5: { //文件指纹 69 | type: dataTypes.STRING(40), 70 | allowNull: true 71 | }, 72 | 73 | //文件状态 74 | status: { 75 | type: dataTypes.INTEGER(2), 76 | allowNull: true 77 | }, 78 | 79 | //备注 80 | remark: { 81 | type: dataTypes.STRING(255), 82 | allowNull: true 83 | }, 84 | 85 | //是否删除 true是 false否 86 | isDelete: { 87 | type: dataTypes.BOOLEAN(), 88 | allowNull: true, 89 | defaultValue: function defaultValue() { 90 | return false; 91 | } 92 | }, 93 | 94 | //创建时间 95 | createdTime: { 96 | type: dataTypes.INTEGER(), 97 | allowNull: true, 98 | defaultValue: function defaultValue() { 99 | return Date.parse(new Date()) / 1000; 100 | } 101 | }, 102 | 103 | //修改时间 104 | updatedTime: { 105 | type: dataTypes.INTEGER(), 106 | allowNull: true, 107 | defaultValue: function defaultValue() { 108 | return Date.parse(new Date()) / 1000; 109 | } 110 | } 111 | }, { 112 | tableName: 'biu_files_base' 113 | }); 114 | }; -------------------------------------------------------------------------------- /server-dist/src/models/common/RegionModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * 地址基础表数据模型 5 | * @param {*} sequelize 6 | * @param {*} dataTypes 7 | * 此模型仅限关系型数据库使用 8 | */ 9 | var _require = require(':lib/Utils'), 10 | getTimeStampUUID = _require.getTimeStampUUID; 11 | 12 | module.exports = function (sequelize, dataTypes) { 13 | return sequelize.define('Region', { 14 | 15 | //地址ID 16 | regionId: { 17 | type: dataTypes.STRING(50), 18 | allowNull: false, 19 | primaryKey: true, 20 | defaultValue: function defaultValue() { 21 | return getTimeStampUUID(); 22 | } 23 | }, 24 | 25 | //名称 26 | name: { 27 | type: dataTypes.STRING(50), 28 | allowNull: true 29 | }, 30 | 31 | //父级ID 32 | pid: { 33 | type: dataTypes.STRING(50), 34 | allowNull: true 35 | }, 36 | 37 | //简称 38 | sname: { 39 | type: dataTypes.STRING(40), 40 | allowNull: true 41 | }, 42 | 43 | //级别 44 | level: { 45 | type: dataTypes.STRING(10), 46 | allowNull: true 47 | }, 48 | 49 | //地址代码 50 | citycode: { 51 | type: dataTypes.STRING(20), 52 | allowNull: true 53 | }, 54 | 55 | //邮政编码 56 | yzcode: { 57 | type: dataTypes.STRING(20), 58 | allowNull: true 59 | }, 60 | 61 | //全称 62 | mername: { 63 | type: dataTypes.STRING(100), 64 | allowNull: true 65 | }, 66 | 67 | //经度 68 | lng: { 69 | type: dataTypes.FLOAT(), 70 | allowNull: true 71 | }, 72 | 73 | //纬度 74 | lat: { 75 | type: dataTypes.FLOAT(), 76 | allowNull: true 77 | }, 78 | 79 | //拼音 80 | pinyin: { 81 | type: dataTypes.STRING(100), 82 | allowNull: true 83 | }, 84 | 85 | //备注 86 | remark: { 87 | type: dataTypes.STRING(255), 88 | allowNull: true 89 | }, 90 | 91 | //是否删除 true是 false否 92 | isDelete: { 93 | type: dataTypes.BOOLEAN(), 94 | allowNull: true, 95 | defaultValue: function defaultValue() { 96 | return false; 97 | } 98 | }, 99 | 100 | //创建时间 101 | createdTime: { 102 | type: dataTypes.INTEGER(), 103 | allowNull: true, 104 | defaultValue: function defaultValue() { 105 | return Date.parse(new Date()) / 1000; 106 | } 107 | }, 108 | 109 | //修改时间 110 | updatedTime: { 111 | type: dataTypes.INTEGER(), 112 | allowNull: true, 113 | defaultValue: function defaultValue() { 114 | return Date.parse(new Date()) / 1000; 115 | } 116 | } 117 | }, { 118 | tableName: 'mu_region' 119 | }); 120 | }; -------------------------------------------------------------------------------- /server-dist/src/models/system/AdminBaseModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * 平台管理员基础表数据模型 5 | * @param {*} sequelize 6 | * @param {*} dataTypes 7 | * 此模型仅限关系型数据库使用 8 | */ 9 | var _require = require(':lib/Utils'), 10 | getTimeStampUUID = _require.getTimeStampUUID; 11 | 12 | module.exports = function (sequelize, dataTypes) { 13 | return sequelize.define('sys_admin_base', { 14 | 15 | //管理员ID 16 | adminId: { 17 | type: dataTypes.STRING(), 18 | allowNull: false, 19 | primaryKey: true, 20 | defaultValue: function defaultValue() { 21 | return getTimeStampUUID(); 22 | } 23 | }, 24 | 25 | //管理员名称 26 | adminName: { 27 | type: dataTypes.STRING(), 28 | allowNull: false 29 | }, 30 | 31 | //管理员账号 32 | account: { 33 | type: dataTypes.STRING(), 34 | allowNull: false 35 | }, 36 | 37 | //管理员密码 38 | password: { 39 | type: dataTypes.STRING(), 40 | allowNull: false 41 | }, 42 | 43 | //账号状态是否禁用 true禁用 false没有禁用 44 | status: { 45 | type: dataTypes.INTEGER(2), 46 | allowNull: true 47 | }, 48 | 49 | //是否超级管理员 true是 false普通管理员 50 | isAdmin: { 51 | type: dataTypes.BOOLEAN(), 52 | allowNull: true 53 | }, 54 | 55 | //头像路径 56 | avatar: { 57 | type: dataTypes.STRING(), 58 | allowNull: true 59 | }, 60 | 61 | //角色名称 62 | roleName: { 63 | type: dataTypes.STRING(), 64 | allowNull: true 65 | }, 66 | 67 | //角色ID 68 | roleId: { 69 | type: dataTypes.STRING(), 70 | allowNull: true 71 | }, 72 | 73 | //是否删除 true是 false否 74 | isDelete: { 75 | type: dataTypes.BOOLEAN(), 76 | allowNull: true, 77 | defaultValue: function defaultValue() { 78 | return false; 79 | } 80 | }, 81 | 82 | //创建时间 83 | createdTime: { 84 | type: dataTypes.INTEGER(), 85 | allowNull: true, 86 | defaultValue: function defaultValue() { 87 | return Date.parse(new Date()) / 1000; 88 | } 89 | }, 90 | 91 | //修改时间 92 | updatedTime: { 93 | type: dataTypes.INTEGER(), 94 | allowNull: true, 95 | defaultValue: function defaultValue() { 96 | return Date.parse(new Date()) / 1000; 97 | } 98 | } 99 | }, { 100 | freezeTableName: true, 101 | tableName: 'sys_admin_base', 102 | timestamps: false //是否需要增加createdAt、updatedAt、deletedAt字段 103 | }); 104 | }; -------------------------------------------------------------------------------- /server-dist/src/models/system/PermissionModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * 角色权限表数据模型 5 | * @param {*} sequelize 6 | * @param {*} dataTypes 7 | * 此模型仅限关系型数据库使用 8 | */ 9 | var _require = require(':lib/Utils'), 10 | getTimeStampUUID = _require.getTimeStampUUID; 11 | 12 | module.exports = function (sequelize, dataTypes) { 13 | return sequelize.define('sys_permission', { 14 | 15 | //权限ID 16 | permissionId: { 17 | type: dataTypes.STRING(), 18 | allowNull: false, 19 | primaryKey: true, 20 | defaultValue: function defaultValue() { 21 | return getTimeStampUUID(); 22 | } 23 | }, 24 | 25 | //权限父级ID 26 | parentId: { 27 | type: dataTypes.STRING(), 28 | allowNull: true, 29 | defaultValue: 0 30 | }, 31 | 32 | //菜单名 33 | title: { 34 | type: dataTypes.STRING(), 35 | allowNull: true 36 | }, 37 | 38 | //菜单类型 1菜单,2按钮 39 | type: { 40 | type: dataTypes.STRING(10), 41 | allowNull: true, 42 | defaultValue: function defaultValue() { 43 | return 1; 44 | } 45 | }, 46 | 47 | //菜单路径 48 | path: { 49 | type: dataTypes.STRING(), 50 | allowNull: true 51 | }, 52 | 53 | //组件name 54 | name: { 55 | type: dataTypes.STRING(), 56 | allowNull: true 57 | }, 58 | 59 | //组件名称 60 | component: { 61 | type: dataTypes.STRING(), 62 | allowNull: true 63 | }, 64 | 65 | //菜单图标 66 | icon: { 67 | type: dataTypes.STRING(), 68 | allowNull: true 69 | }, 70 | 71 | // //查看权限 72 | // find: { 73 | // type: dataTypes.INTEGER(2), 74 | // allowNull: true, 75 | // defaultValue: 0 76 | // }, 77 | 78 | // //添加权限 79 | // add: { 80 | // type: dataTypes.INTEGER(2), 81 | // allowNull: true, 82 | // defaultValue: 0 83 | // }, 84 | 85 | // //编辑权限 86 | // edit: { 87 | // type: dataTypes.INTEGER(2), 88 | // allowNull: true, 89 | // defaultValue: 0 90 | // }, 91 | 92 | // //删除权限 93 | // del: { 94 | // type: dataTypes.INTEGER(2), 95 | // allowNull: true, 96 | // defaultValue: 0 97 | // }, 98 | 99 | // //列表权限 100 | // list: { 101 | // type: dataTypes.INTEGER(2), 102 | // allowNull: true, 103 | // defaultValue: 0 104 | // }, 105 | 106 | //排序 107 | sort: { 108 | type: dataTypes.INTEGER(), 109 | allowNull: true 110 | }, 111 | 112 | //备注 113 | remark: { 114 | type: dataTypes.STRING(), 115 | allowNull: true 116 | }, 117 | 118 | //是否删除 true是 false否 119 | isDelete: { 120 | type: dataTypes.BOOLEAN(), 121 | allowNull: true, 122 | defaultValue: function defaultValue() { 123 | return false; 124 | } 125 | }, 126 | 127 | //创建时间 128 | createdTime: { 129 | type: dataTypes.INTEGER(), 130 | allowNull: true, 131 | defaultValue: function defaultValue() { 132 | return Date.parse(new Date()) / 1000; 133 | } 134 | }, 135 | 136 | //修改时间 137 | updatedTime: { 138 | type: dataTypes.INTEGER(), 139 | allowNull: true, 140 | defaultValue: function defaultValue() { 141 | return Date.parse(new Date()) / 1000; 142 | } 143 | } 144 | }, { 145 | tableName: 'sys_permission', 146 | timestamps: false //是否需要增加createdAt、updatedAt、deletedAt字段 147 | }); 148 | }; -------------------------------------------------------------------------------- /server-dist/src/models/system/RolesAuthModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * 角色权限过渡中间表数据模型 5 | * @param {*} sequelize 6 | * @param {*} dataTypes 7 | * 此模型仅限关系型数据库使用 8 | */ 9 | module.exports = function (sequelize, dataTypes) { 10 | return sequelize.define('sys_roles_auth', { 11 | 12 | //过度中间表ID 13 | roleId: { 14 | type: dataTypes.STRING(), 15 | allowNull: false, 16 | primaryKey: true 17 | }, 18 | 19 | //权限 20 | permissionId: { 21 | type: dataTypes.STRING(), 22 | allowNull: false, 23 | primaryKey: true 24 | }, 25 | 26 | //权限父级ID 27 | parentId: { 28 | type: dataTypes.STRING(), 29 | allowNull: true 30 | }, 31 | 32 | // //查看权限 33 | // find: { 34 | // type: dataTypes.INTEGER(2), 35 | // allowNull: true, 36 | // defaultValue: 0 37 | // }, 38 | 39 | // //添加权限 40 | // add: { 41 | // type: dataTypes.INTEGER(2), 42 | // allowNull: true, 43 | // defaultValue: 0 44 | // }, 45 | 46 | // //编辑权限 47 | // edit: { 48 | // type: dataTypes.INTEGER(2), 49 | // allowNull: true, 50 | // defaultValue: 0 51 | // }, 52 | 53 | // //删除权限 54 | // del: { 55 | // type: dataTypes.INTEGER(2), 56 | // allowNull: true, 57 | // defaultValue: 0 58 | // }, 59 | 60 | // //列表权限 61 | // list: { 62 | // type: dataTypes.INTEGER(2), 63 | // allowNull: true, 64 | // defaultValue: 0 65 | // }, 66 | 67 | //创建时间 68 | createdTime: { 69 | type: dataTypes.INTEGER(), 70 | allowNull: true, 71 | defaultValue: function defaultValue() { 72 | return Date.parse(new Date()) / 1000; 73 | } 74 | }, 75 | 76 | //修改时间 77 | updatedTime: { 78 | type: dataTypes.INTEGER(), 79 | allowNull: true, 80 | defaultValue: function defaultValue() { 81 | return Date.parse(new Date()) / 1000; 82 | } 83 | } 84 | }, { 85 | tableName: 'sys_roles_auth', 86 | timestamps: false //是否需要增加createdAt、updatedAt、deletedAt字段 87 | }); 88 | }; -------------------------------------------------------------------------------- /server-dist/src/models/system/RolesBaseModel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * 角色基础表数据模型 5 | * @param {*} sequelize 6 | * @param {*} dataTypes 7 | * 此模型仅限关系型数据库使用 8 | */ 9 | var _require = require(':lib/Utils'), 10 | getTimeStampUUID = _require.getTimeStampUUID; 11 | 12 | module.exports = function (sequelize, dataTypes) { 13 | return sequelize.define('sys_roles_base', { 14 | //角色ID 15 | roleId: { 16 | type: dataTypes.STRING(), 17 | allowNull: false, 18 | primaryKey: true, 19 | defaultValue: function defaultValue() { 20 | return getTimeStampUUID(); 21 | } 22 | }, 23 | 24 | //角色名称 25 | roleName: { 26 | type: dataTypes.STRING(), 27 | allowNull: true 28 | }, 29 | 30 | //是否删除 true是 false否 31 | isDelete: { 32 | type: dataTypes.BOOLEAN(), 33 | allowNull: true, 34 | defaultValue: function defaultValue() { 35 | return false; 36 | } 37 | }, 38 | 39 | //创建时间 40 | createdTime: { 41 | type: dataTypes.INTEGER(), 42 | allowNull: true, 43 | defaultValue: function defaultValue() { 44 | return Date.parse(new Date()) / 1000; 45 | } 46 | }, 47 | 48 | //修改时间 49 | updatedTime: { 50 | type: dataTypes.INTEGER(), 51 | allowNull: true, 52 | defaultValue: function defaultValue() { 53 | return Date.parse(new Date()) / 1000; 54 | } 55 | } 56 | }, { 57 | tableName: 'sys_roles_base', 58 | timestamps: false //是否需要增加createdAt、updatedAt、deletedAt字段 59 | }); 60 | }; -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ROOT_PATH = process.cwd(); 3 | const SRC_PATH = path.join(ROOT_PATH, `/server/src`); 4 | console.log(ROOT_PATH, SRC_PATH); 5 | //映射目录别名 6 | require('best-require')(ROOT_PATH, { 7 | root: ROOT_PATH, 8 | src: SRC_PATH, 9 | controllers: path.join(SRC_PATH, '/controllers'), 10 | models: path.join(SRC_PATH, '/models'), 11 | routes: path.join(SRC_PATH, '/routes'), 12 | crawlers: path.join(SRC_PATH, '/crawlers'), 13 | services: path.join(SRC_PATH, '/services'), 14 | middleware: path.join(SRC_PATH, '/middleware'), 15 | lib: path.join(SRC_PATH, '/lib'), 16 | config: path.join(SRC_PATH, '/config'), 17 | logs: path.join(SRC_PATH, '/logs') 18 | }); 19 | //运行服务 20 | require('./src/bin/Server').run(); 21 | -------------------------------------------------------------------------------- /server/src/bin/Server.js: -------------------------------------------------------------------------------- 1 | const Koa2 = require('koa'); //koa 2 | const KoaCors = require('koa-cors'); //核心文件 3 | const KoaBody = require('koa-body'); //koa文件上传 4 | const koaJWT = require('koa-jwt'); //jwt生成解析 5 | const koaStatic = require('koa-static'); //静态文件 6 | const responseTime = require('koa-response-time'); 7 | const consola = require('consola'); //打印 8 | const { Nuxt, Builder } = require('nuxt'); //nuxt渲染框架 9 | const config = require(':config/server.base.config'); //配置文件 10 | const nuxtConfig = require(':root/nuxt.config'); //nuxt配置文件 11 | const controllers = require(':controllers/index'); //路由入口 12 | const ErrorRoutesCatch = require(':middleware/ErrorRoutesCatch'); //全局错误捕获 13 | const { accessLogger } = require(':lib/logger4'); //日志系统 14 | const app = new Koa2(); 15 | const host = process.env.HOST || config.host || '127.0.0.1'; 16 | const port = process.env.PORT || config.port || 3000; 17 | config.dev = !(app.env === 'production'); 18 | module.exports = class Server { 19 | static async run() { 20 | const nuxt = new Nuxt(nuxtConfig); 21 | if (config.isNuxtRender) { 22 | if (config.dev) { 23 | const builder = new Builder(nuxt); 24 | await builder.build(); 25 | } 26 | } 27 | app.use(accessLogger()); 28 | app.use(responseTime({ hrtime: true })); 29 | app.use(KoaCors()); 30 | app.use(ErrorRoutesCatch); 31 | app.use(koaStatic(config.staticPath)); 32 | app.use(KoaBody({ 33 | multipart: true, 34 | strict: false, 35 | formidable: { 36 | uploadDir: config.uploadDir, //设置上传缓存文件夹 37 | maxFileSize: 1024 * 1024 * 10 * 1024 // 设置上传文件大小最大限制,默认1G 1024M 38 | }, 39 | jsonLimit: '10mb', 40 | formLimit: '10mb', 41 | textLimit: '10mb' 42 | })); 43 | app.use(koaJWT({ secret: config.jwtPublicKey }).unless({ path: config.unlessPath })); //jwt 注入 44 | app.use(controllers.routes()); //路由注入 45 | app.use(controllers.allowedMethods()); 46 | if (config.isNuxtRender) { 47 | app.use(ctx => { 48 | ctx.status = 200; 49 | return new Promise((resolve, reject) => { 50 | ctx.res.on('close', resolve); 51 | ctx.res.on('finish', resolve); 52 | nuxt.render(ctx.req, ctx.res, promise => { 53 | console.log(`Nuxt 渲染完成!`); 54 | promise.then(resolve).catch(reject); 55 | }); 56 | }); 57 | }); 58 | } 59 | app.listen(port, host); 60 | consola.ready({ 61 | message: `Server listening on http://${host}:${port}/login`, 62 | badge: true 63 | }); 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /server/src/config/server.base.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); //路径模块 2 | 3 | /** 4 | * 主配置 5 | */ 6 | module.exports = { 7 | port: 3010, // default: 3000 8 | host: '127.0.0.1', // default: '127.0.0.1', 9 | jwtPublicKey: 'jwtPublicKey', //公钥, 加解密jwt使用,建议使用自定义复杂的字符串 10 | isNuxtRender: true, //是否启用nuxt渲染 true启用管理后台界面,false 不使用管理后台,只是使用API服务器 11 | uploadDir: path.join(__dirname, `../public/uploads/tmp`), //上传文件缓存路径,相对于 server.base.config.js 的路径 12 | staticPath: path.join(__dirname, `../public`), //静态文件路径,相对于 server.base.config.js 的路径 13 | crawler: { 14 | start: true, //是否开启爬虫系统 15 | settimeout: 1 //延时多少s启动 16 | }, 17 | saltMD5: '_SERVICE.BIU.COM', //md5 加盐的字符,随意更改可能会造成密码错误等. 18 | filePrefix: 'BIU_WEB_', //上传的文件名前缀 19 | email: { 20 | host: 'smtp.qq.com', //邮箱服务器地址 21 | port: 465, //服务器端口 默认 465 22 | fromUser: '"发送人" <1096432936@qq.com>', //发送人 23 | secureConnection: true, //仅安全连接模式 24 | // 我们需要登录到网页邮箱中,然后配置SMTP和POP3服务器的密码 25 | auth: { 26 | user: '1096432936@qq.com', 27 | pass: 'k1q2p41zj41ioamhbdbaec' 28 | } 29 | }, 30 | dbs: { //数据源配置 31 | BiuDB: { 32 | name: 'BiuDB', //ORM中使用的名称 建议和key一样的名称 33 | type: 'sequelize', //orm类型 类型可选sequelize redis等 34 | config: { 35 | username: 'biu_server_db', // 数据库用户名 36 | password: 'm24WTNrJ7ewJFDkAd5', // 数据库密码 37 | database: 'biu_server_db', // 数据库名称 38 | options: { //配置项 39 | dialect: 'mysql', // 数据库类型 40 | host: '111.231.225.106', // 服务器地址 41 | port: 3306, // 数据库端口号 42 | dialectOptions: { // MySQL > 5.5,其它数据库删除此项 43 | charset: 'utf8mb4', 44 | supportBigNumbers: true, 45 | bigNumberStrings: true 46 | //collate: 'utf8mb4_unicode_520_ci', 47 | //requestTimeout: 60 * 1000 //设置连接超时时间 48 | }, 49 | define: { 50 | underscored: false, // 转换列名的驼峰命名规则为下划线命令规则 51 | freezeTableName: true, //设置为true时,sequelize不会改变表名,否则可能会按其规则有所调整 52 | charset: 'utf8mb4', 53 | timestamps: false //为模型添加 createdAt 和 updatedAt 两个时间戳字段 54 | }, 55 | pool: { 56 | max: 50, // 连接池中最大连接数量 57 | min: 0, // 连接池中最小连接数量 58 | idle: 10000 // 如果一个线程 10 秒钟内没有被使用过的话,那么就释放线程 59 | } 60 | } 61 | } 62 | } 63 | }, 64 | unlessPath: [ //url白名单 如果不设置默认都是没权限访问的,会返回{code:401} 65 | /^\/public/, //公共资源 66 | /^\/_nuxt/, //nuxt页面 67 | /^\/login/, //登录 68 | /^\/favicon.ico/, 69 | /^\/__webpack_hmr/, 70 | /^\/System/, //系统设置 71 | /^\/Home/, //主页 72 | //api部分 73 | /^\/v1\/api\/common\/getImgValidate/, //验证码 74 | /^\/v1\/api\/common\/userLoginForSysAdmin/ //登录接口 75 | ] 76 | }; 77 | -------------------------------------------------------------------------------- /server/src/controllers/index.js: -------------------------------------------------------------------------------- 1 | //主路由文件 2 | const KoaRouter = require('koa-router'); 3 | const models = require(':controllers/models'); 4 | const result = require(':lib/Result'); 5 | //所有的API接口都以/v1/api开头 6 | const router = new KoaRouter({ prefix: '/v1/api/' }); 7 | //整合路由 8 | Object.keys(models).forEach(key => { 9 | Object.keys(models[key]).forEach(k2 => { 10 | router.use((key).toLowerCase(), models[key][k2].routes(), models[key][k2].allowedMethods()); 11 | }); 12 | }); 13 | 14 | /** 15 | * 所有的非法请求全都返回统一结果 16 | */ 17 | router.all('*', (ctx) => { 18 | ctx.body = result.failed(`非法请求!`); 19 | }); 20 | 21 | // console.log(router); 22 | module.exports = router; 23 | -------------------------------------------------------------------------------- /server/src/controllers/models/common/FilesController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 公共信息入口 3 | */ 4 | const KoaRouter = require('koa-router'); 5 | const FilesService = require(':services/common/FilesService'); 6 | const controller = new KoaRouter(); 7 | const service = new FilesService(); 8 | 9 | //文件上传接口(单文件) 10 | controller.post('/uploadFile', async(ctx) => { 11 | ctx.body = await service.uploadFile({ state: ctx.state, files: ctx.request.files }); 12 | }); 13 | 14 | //文件上传接口(多文件) 15 | controller.post('/uploadFiles', async(ctx) => { 16 | ctx.body = await service.uploadFiles({ state: ctx.state, files: ctx.request.files }); 17 | }); 18 | 19 | //文件删除接口(多文件) 20 | controller.delete('/deleteFiles', async(ctx) => { 21 | ctx.body = await service.deleteFiles({ state: ctx.state, body: ctx.request.body }); 22 | }); 23 | 24 | //获取文件列表接口 25 | controller.get('/getFiles', async(ctx) => { 26 | ctx.body = await service.getFiles({ state: ctx.state, query: ctx.request.query }); 27 | }); 28 | 29 | //获取文件列表接口 30 | controller.get('/getFileById/:fileId', async(ctx) => { 31 | ctx.body = await service.getFileById(ctx.params); 32 | }); 33 | 34 | //获取文件列表接口 35 | controller.get('/readeFileContent', async(ctx) => { 36 | ctx.body = await service.readeFileContent(ctx.request.query); 37 | }); 38 | 39 | module.exports = controller; 40 | -------------------------------------------------------------------------------- /server/src/controllers/models/common/LoginController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户登录路由入口 3 | */ 4 | const KoaRouter = require('koa-router'); 5 | const LoginService = require(':services/common/LoginService'); 6 | const controller = new KoaRouter(); 7 | const service = new LoginService(); 8 | 9 | //系统管理员登录 10 | controller.post('/userLoginForSysAdmin', async(ctx) => { 11 | ctx.body = await service.userLoginForSysAdmin({ data: ctx.request.body, cookies: ctx.cookies }); 12 | }); 13 | 14 | //商家登录 15 | controller.post('/loginForBusiness', async(ctx) => { 16 | ctx.body = await service.loginForBusiness({ data: ctx.request.body, cookies: ctx.cookies }); 17 | }); 18 | 19 | module.exports = controller; 20 | -------------------------------------------------------------------------------- /server/src/controllers/models/common/UtilsController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户登录路由入口 3 | */ 4 | const KoaRouter = require('koa-router'); 5 | const UtilsService = require(':services/common/UtilsService'); 6 | const controller = new KoaRouter(); 7 | const service = new UtilsService(); 8 | //登录 9 | controller.get('/getImgValidate', async(ctx) => { 10 | const res = await service.getImgValidate(); 11 | //设置验证码 12 | ctx.cookies.set('IMG-VALIDATE-DATA', res.data.text, { httpOnly: true, maxAge: 1000 * 60 * 5 }); 13 | ctx.body = res; 14 | }); 15 | module.exports = controller; 16 | -------------------------------------------------------------------------------- /server/src/controllers/models/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('require-directory')(module); -------------------------------------------------------------------------------- /server/src/controllers/models/system/AdminController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 系统管理员管理 3 | */ 4 | const KoaRouter = require('koa-router'); 5 | const AdminService = require(':services/system/AdminService'); 6 | const controller = new KoaRouter(); 7 | const service = new AdminService(); 8 | 9 | //添加 10 | controller.post('/addSysAdmin', async(ctx) => { 11 | ctx.body = await service.addSysAdmin(ctx.request.body, ctx.state.user.data); 12 | }); 13 | 14 | //查询系统管理员 15 | controller.get('/getSysAdminList', async(ctx) => { 16 | ctx.body = await service.getSysAdminList(ctx.request.query, ctx.state.user.data); 17 | }); 18 | 19 | //删除系统管理员 20 | controller.delete('/delSysAdminByIds', async(ctx) => { 21 | ctx.body = await service.delSysAdminByIds(ctx.request.body, ctx.state.user.data); 22 | }); 23 | 24 | //更新系统管理员信息 25 | controller.put('/updateSysAdmin', async(ctx) => { 26 | ctx.body = await service.updateSysAdmin(ctx.request.body); 27 | }); 28 | 29 | //绑定管理员的角色 30 | controller.put('/bindSysAdminRole', async(ctx) => { 31 | ctx.body = await service.bindSysAdminRole(ctx.request.body, ctx.state.user.data); 32 | }); 33 | 34 | //获取管理员的基础信息 35 | controller.get('/getSysAdminBaseInfo', async(ctx) => { 36 | ctx.body = await service.getSysAdminBaseInfo(ctx.request.query); 37 | }); 38 | 39 | //编辑系统管理员密码 40 | controller.put('/updateSysPassword', async(ctx) => { 41 | ctx.body = await service.updateSysPassword({ data: ctx.request.body }, ctx.state.user.data); 42 | }); 43 | 44 | module.exports = controller; 45 | -------------------------------------------------------------------------------- /server/src/controllers/models/system/LogsController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 系统管理员管理 3 | */ 4 | const KoaRouter = require('koa-router'); 5 | const LogsService = require(':services/system/LogsService'); 6 | const controller = new KoaRouter(); 7 | const service = new LogsService(); 8 | 9 | //获取系统日志 10 | controller.get('/getSysLogList', async(ctx) => { 11 | ctx.body = await service.getSysLogList(ctx.state.user.data); 12 | }); 13 | 14 | //获取系统日志内容 15 | controller.get('/getSysLogContent', async(ctx) => { 16 | ctx.body = await service.getSysLogContent(ctx.request.query, ctx.state.user.data); 17 | }); 18 | 19 | //删除系统日志 20 | controller.delete('/delSysLogByPaths', async(ctx) => { 21 | ctx.body = await service.delSysLogByPaths(ctx.request.body, ctx.state.user.data); 22 | }); 23 | 24 | module.exports = controller; 25 | -------------------------------------------------------------------------------- /server/src/controllers/models/system/PermissionController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 系统管理员管理 3 | */ 4 | const KoaRouter = require('koa-router'); 5 | const PermissionService = require(':services/system/PermissionService'); 6 | const controller = new KoaRouter(); 7 | const service = new PermissionService(); 8 | 9 | //添加权限菜单 10 | controller.post('/addSysPermission', async(ctx) => { 11 | ctx.body = await service.addSysPermission(ctx.request.body, ctx.state.user.data); 12 | }); 13 | 14 | //查询权限菜单 15 | controller.get('/getSysPermissionList', async(ctx) => { 16 | ctx.body = await service.getSysPermissionList(ctx.request.query, ctx.state.user.data); 17 | }); 18 | 19 | //删除权限菜单 20 | controller.delete('/delSysPermissionByIds', async(ctx) => { 21 | ctx.body = await service.delSysPermissionByIds(ctx.request.body, ctx.state.user.data); 22 | }); 23 | 24 | //更新权限菜单 25 | controller.put('/updateSysPermission', async(ctx) => { 26 | ctx.body = await service.updateSysPermission(ctx.request.body, ctx.state.user.data); 27 | }); 28 | 29 | //权限菜单树形 30 | controller.get('/getSysPermissionListToTree', async(ctx) => { 31 | ctx.body = await service.getSysPermissionListToTree(ctx.request.query, ctx.state.user.data); 32 | }); 33 | 34 | //获取角色的权限 35 | controller.get('/getSysRolePermissionListToTree', async(ctx) => { 36 | ctx.body = await service.getSysRolePermissionListToTree(ctx.request.query, ctx.state.user.data); 37 | }); 38 | 39 | //设置角色权限 40 | controller.put('/setSysRolePermission', async(ctx) => { 41 | ctx.body = await service.setSysRolePermission(ctx.request.body, ctx.state.user.data); 42 | }); 43 | 44 | //清除角色的所有权限 45 | controller.delete('/clearSysRoleAllPermission', async(ctx) => { 46 | ctx.body = await service.clearSysRoleAllPermission(ctx.request.body, ctx.state.user.data); 47 | }); 48 | 49 | //获取角色的树形菜单 50 | controller.get('/getSysRoleMenusToTree', async(ctx) => { 51 | ctx.body = await service.getSysRoleMenusToTree(ctx.state.user.data); 52 | }); 53 | 54 | module.exports = controller; 55 | -------------------------------------------------------------------------------- /server/src/controllers/models/system/RolesController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 角色管理 3 | */ 4 | const KoaRouter = require('koa-router'); 5 | const RolesService = require(':services/system/RolesService'); 6 | const controller = new KoaRouter(); 7 | const service = new RolesService(); 8 | 9 | //添加角色 10 | controller.post('/addSysRole', async(ctx) => { 11 | ctx.body = await service.addSysRole(ctx.request.body); 12 | }); 13 | 14 | //获取系统角色 15 | controller.get('/getSysRoleList', async(ctx) => { 16 | ctx.body = await service.getSysRoleList(ctx.request.query); 17 | }); 18 | 19 | //删除系统角色 20 | controller.delete('/delSysRoleByIds', async(ctx) => { 21 | ctx.body = await service.delSysRoleByIds(ctx.request.body); 22 | }); 23 | 24 | //更新系统角色 25 | controller.put('/updateSysRole', async(ctx) => { 26 | ctx.body = await service.updateSysRole(ctx.request.body); 27 | }); 28 | 29 | module.exports = controller; 30 | -------------------------------------------------------------------------------- /server/src/lib/Email.js: -------------------------------------------------------------------------------- 1 | 2 | const nodemailer = require('nodemailer'); 3 | module.exports = class EMail { 4 | constructor(options) { 5 | this.options = { 6 | host: 'smtp.qq.com', 7 | port: 465, 8 | fromUser: '"发送人" ', 9 | secureConnection: true, 10 | // 我们需要登录到网页邮箱中,然后配置SMTP和POP3服务器的密码 11 | auth: { 12 | user: 'user@qq.com', 13 | pass: 'loginkey' //邮箱生成的登录key 14 | } 15 | }; 16 | if (options) { 17 | for (const key in options) { 18 | this.options[key] = options[key]; 19 | } 20 | } 21 | this.mailer = nodemailer.createTransport(this.options); 22 | } 23 | 24 | /** 25 | * 发送邮件 26 | * @param {*} toName 接收者的名字 27 | * @param {*} toEmail 接收邮件的地址 28 | */ 29 | sendEmail({ toName, toEmail, subject, message }) { 30 | const sendHtml = `
${toName},${message}
`; 31 | const mailOptions = { 32 | // 发送邮件的地址 33 | from: this.options.fromUser, // login user must equal to this user 34 | // 接收邮件的地址 35 | to: toEmail, // xrj0830@gmail.com 36 | // 邮件主题 37 | subject: subject || '你有一条新消息', 38 | // 以HTML的格式显示,这样可以显示图片、链接、字体颜色等信息 39 | html: sendHtml 40 | }; 41 | return this.mailer.sendMail(mailOptions); 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /server/src/lib/Result.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 返回数据实体对象 3 | */ 4 | module.exports = { 5 | /** 6 | * 状态码 获取表示 7 | * 变更时获取表示(缓存) 8 | * 200(OK) - 表示已在响应中发出 9 | * 204(无内容) - 资源有空表示 10 | * 301(Moved Permanently) - 资源的URI已被更新 11 | * 303(See Other) - 其他(如,负载均衡) 12 | * 304(not modified)- 资源未更改(缓存) 13 | * 400 (bad request)- 指代坏请求(如,参数错误) 14 | * 404 (not found)- 资源不存在 15 | * 406 (not acceptable)- 服务端不支持所需表示 16 | * 500 (internal server error)- 通用错误响应 17 | * 503 (Service Unavailable)- 服务端当前无法处理请求 18 | */ 19 | CODE: { 20 | SUCCESS: 200, //表示已在响应中发出 21 | OTHER: 204, //(无内容) - 资源有空表示 22 | FAILED: 400, //操作失败 23 | AUTHORITIES: 401, //身份验证失败 24 | NO_AUTHORITY: 403, //无权限 25 | SERVER_ERROR: 500 //通用服务器内部错误响应 26 | }, 27 | /** 28 | * 返回提示 29 | */ 30 | MESSAGE: { 31 | SUCCESS: `SUCCESS!`, 32 | FAILED: `操作失败!`, 33 | PARAMS_LACK: `参数不齐!`, 34 | AUTHORITIES: `登陆失效或身份过期!`, //身份验证失败 35 | NO_AUTHORITY: `无权访问!`, //无权限 36 | SERVER_ERROR: `服务器内容错误!` 37 | }, 38 | 39 | /** 40 | * 返回成功结果 41 | */ 42 | success(msg, data) { 43 | return { 44 | code: this.CODE.SUCCESS, 45 | data, 46 | msg: msg || this.MESSAGE.SUCCESS 47 | }; 48 | }, 49 | 50 | /** 51 | * 请求操作失败 52 | */ 53 | failed(msg, code, data) { 54 | return { 55 | data, 56 | msg: msg || this.MESSAGE.FAILED, 57 | code: code || this.CODE.FAILED 58 | }; 59 | }, 60 | 61 | /** 62 | * 参数不齐 63 | * @param {*} msg 64 | * @param {*} code 65 | * @param {*} data 66 | */ 67 | paramsLack(msg, code, data) { 68 | return { 69 | code: code || this.CODE.FAILED, 70 | data, 71 | msg: msg || this.MESSAGE.PARAMS_LACK 72 | }; 73 | }, 74 | 75 | /** 76 | * 身份过期 77 | * @param {*} msg 78 | * @param {*} code 79 | * @param {*} data 80 | */ 81 | authorities(msg, code, data) { 82 | return { 83 | code: code || this.CODE.AUTHORITIES, 84 | data, 85 | msg: msg || this.MESSAGE.AUTHORITIES 86 | }; 87 | }, 88 | 89 | /** 90 | * 无权访问 91 | * @param {*} msg 92 | * @param {*} code 93 | * @param {*} data 94 | */ 95 | noAuthority(msg, code, data) { 96 | return { 97 | data, 98 | code: code || this.CODE.NO_AUTHORITY, 99 | msg: msg || this.MESSAGE.NO_AUTHORITY 100 | }; 101 | }, 102 | 103 | /** 104 | * 服务器内容错误 105 | * @param {*} msg 106 | * @param {*} code 107 | * @param {*} data 108 | */ 109 | serverError(err, msg, code) { 110 | return { 111 | error: err || '-', 112 | msg: msg || this.MESSAGE.SERVER_ERROR, 113 | code: code || this.CODE.SERVER_ERROR 114 | }; 115 | }, 116 | 117 | /** 118 | * 带分页的数据对象 119 | * @param {*} msg 120 | * @param {*} code 121 | * @param {*} data 122 | * @param {*} total 123 | * @param {*} page 124 | * @param {*} limit 125 | */ 126 | pageData(msg, code, data, total, page, limit) { 127 | return { 128 | code: code || this.CODE.SUCCESS, 129 | data, 130 | total, 131 | page, 132 | limit, 133 | msg: msg || this.MESSAGE.SUCCESS 134 | }; 135 | }, 136 | 137 | /** 138 | * 代码分页(非数据库分页) 139 | * @param {*} msg 140 | * @param {*} code 141 | * @param {*} data 数据列表 142 | * @param {*} page 当前页 143 | * @param {*} limit 每页大小 144 | */ 145 | totalPageData(msg, code, data, page, limit) { 146 | let result = { 147 | code: code || this.CODE.SUCCESS, 148 | data: [], 149 | limit, 150 | page, 151 | total: 0, 152 | msg: msg || this.MESSAGE.SUCCESS 153 | }; 154 | 155 | //分页 156 | if (data && limit && page) { 157 | if (data && data.length > 0) { 158 | //索引 159 | let index = (page - 1) * limit; 160 | for (let i = index; i < page * limit; i++) { 161 | if (data[i]) result.data.push(data[i]); 162 | } 163 | } 164 | //总大小 165 | result.total = data.length; 166 | } else { 167 | result.data = data; 168 | } 169 | return result; 170 | } 171 | }; 172 | -------------------------------------------------------------------------------- /server/src/lib/logger4.js: -------------------------------------------------------------------------------- 1 | const path = require('path');// 引入原生path模块 2 | const log4js = require('koa-log4');// 引入koa-log4 3 | const { SRC_PATH } = require(':lib/Utils'); 4 | log4js.configure({ 5 | appenders: { 6 | // 访问日志 7 | access: { 8 | type: 'dateFile', 9 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 10 | alwaysIncludePattern: true, // 文件名始终以日期区分 11 | encoding: 'utf-8', 12 | filename: path.join(SRC_PATH + '/logs/access/', 'access.log') // 生成文件路径和文件名 13 | }, 14 | // 系统日志 15 | application: { 16 | type: 'dateFile', 17 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 18 | alwaysIncludePattern: true, // 文件名始终以日期区分 19 | encoding: 'utf-8', 20 | filename: path.join(SRC_PATH + '/logs/application/', 'application.log') // 生成文件路径和文件名 21 | }, 22 | accessErrorLogger: { 23 | type: 'dateFile', 24 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 25 | alwaysIncludePattern: true, // 文件名始终以日期区分 26 | encoding: 'utf-8', 27 | filename: path.join(SRC_PATH + '/logs/accessErrorLogger/', 'accessErrorLogger.log') // 生成文件路径和文件名 28 | }, 29 | accessSimpleLogger: { 30 | type: 'dateFile', 31 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 32 | alwaysIncludePattern: true, // 文件名始终以日期区分 33 | encoding: 'utf-8', 34 | filename: path.join(SRC_PATH + '/logs/accessSimpleLogger/', 'accessSimpleLogger.log') // 生成文件路径和文件名 35 | }, 36 | sqlLog: { 37 | type: 'dateFile', 38 | pattern: '-yyyy-MM-dd.log', // 通过日期来生成文件 39 | alwaysIncludePattern: true, // 文件名始终以日期区分 40 | encoding: 'utf-8', 41 | filename: path.join(SRC_PATH + '/logs/sqlLog/', 'sqlLog.log') // 生成文件路径和文件名 42 | }, 43 | out: { 44 | type: 'console' 45 | } 46 | }, 47 | categories: { 48 | default: { appenders: ['out'], level: 'info' }, 49 | access: { appenders: ['access'], level: 'info' }, 50 | application: { appenders: ['application', 'out'], level: 'WARN' }, 51 | accessErrorLogger: { appenders: ['accessErrorLogger', 'out'], level: 'WARN' }, 52 | accessSimpleLogger: { appenders: ['accessSimpleLogger', 'out'], level: 'WARN' }, 53 | sqlLog: { appenders: ['sqlLog', 'out'], level: 'info' } 54 | } 55 | }); 56 | 57 | module.exports = { 58 | accessLogger: () => log4js.koaLogger(log4js.getLogger('access')), // 记录所有访问级别的日志 59 | systemLogger: log4js.getLogger('application'), //记录所有应用级别的日志 60 | accessErrorLogger: log4js.getLogger('accessErrorLogger'), //记录所有访问时报错的日志 61 | accessSimpleLogger: log4js.getLogger('accessSimpleLogger'), //记录所有简单访问时报错的日志 62 | sqlLog: log4js.getLogger('sqlLog') //记录所有SQL的日志 63 | }; 64 | -------------------------------------------------------------------------------- /server/src/lib/sequelize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sequelize.js api说明文档 3 | * https: //itbilu.com/nodejs/npm/V1PExztfb.html 4 | */ 5 | // const sequelize = require('./init.sequelize')(); 6 | const Sequelize = require('sequelize/index'); 7 | const config = require(':config/server.base.config'); //配置文件 8 | const { systemLogger, sqlLog } = require(':lib/logger4'); 9 | const SOP = Sequelize.Op; 10 | /** 11 | * 列关联 12 | * @param {*} table 13 | * @param {*} col 14 | */ 15 | const COL = (table, col) => { 16 | return Sequelize.col(`${table}.${col}`); 17 | }; 18 | 19 | /** 20 | * attr合成 21 | * @param {*} table 22 | * @param {*} list 23 | */ 24 | const Attrs = (table, list) => { 25 | let arr = []; 26 | for (let x in list) { 27 | arr.push(COL(table, list[x])); 28 | } 29 | return arr; 30 | }; 31 | 32 | const BiuDB = new Sequelize(config.dbs.BiuDB.config.database, config.dbs.BiuDB.config.username, config.dbs.BiuDB.config.password, { 33 | ...config.dbs.BiuDB.config.options, 34 | logging(sql) { //日志输出 不显示的输出设置为false 35 | sqlLog.info(`${config.dbs.BiuDB.config.database}----${sql}`); 36 | } 37 | }); 38 | BiuDB.authenticate().then((res) => { 39 | systemLogger.info(`连接数据库:${config.dbs.BiuDB.config.database} 成功!`); 40 | }).catch(err => { 41 | systemLogger.info(`连接数据库:${config.dbs.BiuDB.config.database} 出错!`, err); 42 | }); 43 | 44 | //同步数据库模型专用 此操作将会删除数据库的表重新创建,请谨慎使用 45 | // BiuDB.sync({ force: true }).then(function(result) { 46 | // console.log('result'); 47 | // }); 48 | 49 | //配置关系型数据库ORM 50 | module.exports = { 51 | Sequelize, 52 | SOP, 53 | COL, 54 | Attrs, 55 | BiuDB 56 | }; 57 | -------------------------------------------------------------------------------- /server/src/lib/userAgents.js: -------------------------------------------------------------------------------- 1 | const userAgents = [ 2 | 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12', 3 | 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)', 4 | 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11', 5 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20', 6 | 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6', 7 | 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER', 8 | 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0) ,Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9', 9 | 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)', 10 | 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)', 11 | 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)', 12 | 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre', 13 | 'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52', 14 | 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12', 15 | 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)', 16 | 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6', 17 | 'Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6', 18 | 'Opera/9.25 (Windows NT 5.1; U; en), Lynx/2.8.5rel.1 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.2.9', 19 | 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36', 20 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36' 21 | ]; 22 | 23 | module.exports = userAgents[parseInt(Math.random() * userAgents.length)]; -------------------------------------------------------------------------------- /server/src/middleware/ErrorRoutesCatch.js: -------------------------------------------------------------------------------- 1 | /*** 2 | * 错误捕获 3 | */ 4 | const result = require(':lib/Result'); 5 | module.exports = (ctx, next) => { 6 | return next().catch((err) => { 7 | const status = err.status; 8 | if (status == 401) { 9 | ctx.body = result.authorities(); 10 | } else if (status == 404) { 11 | ctx.body = result.failed(204, '非法请求!'); 12 | } else { 13 | ctx.body = result.failed(null, String(err)); 14 | } 15 | }); 16 | }; -------------------------------------------------------------------------------- /server/src/middleware/index.js: -------------------------------------------------------------------------------- 1 | import requireDirectory from 'require-directory'; 2 | export default () => requireDirectory(module); -------------------------------------------------------------------------------- /server/src/models/common/FilesBaseModel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 文件基础表数据模型 3 | * @param {*} sequelize 4 | * @param {*} dataTypes 5 | * 此模型仅限关系型数据库使用 6 | */ 7 | // const { getTimeStampUUID } = require(':lib/Utils'); 8 | module.exports = (sequelize, dataTypes) => { 9 | return sequelize.define('FilesBase', { 10 | 11 | //文件ID 12 | fileId: { 13 | type: dataTypes.STRING(50), 14 | allowNull: false, 15 | primaryKey: true 16 | }, 17 | 18 | //文件名 19 | fileName: { 20 | type: dataTypes.STRING(100), 21 | allowNull: true 22 | }, 23 | 24 | //文件别名 25 | aliasName: { 26 | type: dataTypes.STRING(100), 27 | allowNull: true 28 | }, 29 | 30 | //上传人ID 31 | userId: { 32 | type: dataTypes.STRING(50), 33 | allowNull: true 34 | }, 35 | 36 | //上传人名称 37 | userName: { 38 | type: dataTypes.STRING(100), 39 | allowNull: true 40 | }, 41 | 42 | //文件大小 43 | size: { 44 | type: dataTypes.BIGINT(20), 45 | allowNull: true 46 | }, 47 | 48 | //文件类型 49 | type: { 50 | type: dataTypes.STRING(100), 51 | allowNull: true 52 | }, 53 | 54 | //文件后缀 55 | suffix: { 56 | type: dataTypes.STRING(30), 57 | allowNull: true 58 | }, 59 | 60 | //文件存放的路径 61 | path: { 62 | type: dataTypes.STRING(200), 63 | allowNull: true 64 | }, 65 | 66 | fileMD5: { //文件指纹 67 | type: dataTypes.STRING(40), 68 | allowNull: true 69 | }, 70 | 71 | //文件状态 72 | status: { 73 | type: dataTypes.INTEGER(2), 74 | allowNull: true 75 | }, 76 | 77 | //备注 78 | remark: { 79 | type: dataTypes.STRING(255), 80 | allowNull: true 81 | }, 82 | 83 | //是否删除 true是 false否 84 | isDelete: { 85 | type: dataTypes.BOOLEAN(), 86 | allowNull: true, 87 | defaultValue: () => false 88 | }, 89 | 90 | //创建时间 91 | createdTime: { 92 | type: dataTypes.INTEGER(), 93 | allowNull: true, 94 | defaultValue: () => (Date.parse(new Date()) / 1000) 95 | }, 96 | 97 | //修改时间 98 | updatedTime: { 99 | type: dataTypes.INTEGER(), 100 | allowNull: true, 101 | defaultValue: () => (Date.parse(new Date()) / 1000) 102 | } 103 | }, { 104 | tableName: 'biu_files_base' 105 | }); 106 | }; 107 | -------------------------------------------------------------------------------- /server/src/models/common/RegionModel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 地址基础表数据模型 3 | * @param {*} sequelize 4 | * @param {*} dataTypes 5 | * 此模型仅限关系型数据库使用 6 | */ 7 | const { getTimeStampUUID } = require(':lib/Utils'); 8 | module.exports = (sequelize, dataTypes) => { 9 | return sequelize.define('Region', { 10 | 11 | //地址ID 12 | regionId: { 13 | type: dataTypes.STRING(50), 14 | allowNull: false, 15 | primaryKey: true, 16 | defaultValue: () => getTimeStampUUID() 17 | }, 18 | 19 | //名称 20 | name: { 21 | type: dataTypes.STRING(50), 22 | allowNull: true 23 | }, 24 | 25 | //父级ID 26 | pid: { 27 | type: dataTypes.STRING(50), 28 | allowNull: true 29 | }, 30 | 31 | //简称 32 | sname: { 33 | type: dataTypes.STRING(40), 34 | allowNull: true 35 | }, 36 | 37 | //级别 38 | level: { 39 | type: dataTypes.STRING(10), 40 | allowNull: true 41 | }, 42 | 43 | //地址代码 44 | citycode: { 45 | type: dataTypes.STRING(20), 46 | allowNull: true 47 | }, 48 | 49 | //邮政编码 50 | yzcode: { 51 | type: dataTypes.STRING(20), 52 | allowNull: true 53 | }, 54 | 55 | //全称 56 | mername: { 57 | type: dataTypes.STRING(100), 58 | allowNull: true 59 | }, 60 | 61 | //经度 62 | lng: { 63 | type: dataTypes.FLOAT(), 64 | allowNull: true 65 | }, 66 | 67 | //纬度 68 | lat: { 69 | type: dataTypes.FLOAT(), 70 | allowNull: true 71 | }, 72 | 73 | //拼音 74 | pinyin: { 75 | type: dataTypes.STRING(100), 76 | allowNull: true 77 | }, 78 | 79 | //备注 80 | remark: { 81 | type: dataTypes.STRING(255), 82 | allowNull: true 83 | }, 84 | 85 | //是否删除 true是 false否 86 | isDelete: { 87 | type: dataTypes.BOOLEAN(), 88 | allowNull: true, 89 | defaultValue: () => false 90 | }, 91 | 92 | //创建时间 93 | createdTime: { 94 | type: dataTypes.INTEGER(), 95 | allowNull: true, 96 | defaultValue: () => (Date.parse(new Date()) / 1000) 97 | }, 98 | 99 | //修改时间 100 | updatedTime: { 101 | type: dataTypes.INTEGER(), 102 | allowNull: true, 103 | defaultValue: () => (Date.parse(new Date()) / 1000) 104 | } 105 | }, { 106 | tableName: 'mu_region' 107 | }); 108 | }; 109 | -------------------------------------------------------------------------------- /server/src/models/system/AdminBaseModel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 平台管理员基础表数据模型 3 | * @param {*} sequelize 4 | * @param {*} dataTypes 5 | * 此模型仅限关系型数据库使用 6 | */ 7 | const { getTimeStampUUID } = require(':lib/Utils'); 8 | module.exports = (sequelize, dataTypes) => { 9 | return sequelize.define('sys_admin_base', { 10 | 11 | //管理员ID 12 | adminId: { 13 | type: dataTypes.STRING(), 14 | allowNull: false, 15 | primaryKey: true, 16 | defaultValue: () => getTimeStampUUID() 17 | }, 18 | 19 | //管理员名称 20 | adminName: { 21 | type: dataTypes.STRING(), 22 | allowNull: false 23 | }, 24 | 25 | //管理员账号 26 | account: { 27 | type: dataTypes.STRING(), 28 | allowNull: false 29 | }, 30 | 31 | //管理员密码 32 | password: { 33 | type: dataTypes.STRING(), 34 | allowNull: false 35 | }, 36 | 37 | //账号状态是否禁用 true禁用 false没有禁用 38 | status: { 39 | type: dataTypes.INTEGER(2), 40 | allowNull: true 41 | }, 42 | 43 | //是否超级管理员 true是 false普通管理员 44 | isAdmin: { 45 | type: dataTypes.BOOLEAN(), 46 | allowNull: true 47 | }, 48 | 49 | //头像路径 50 | avatar: { 51 | type: dataTypes.STRING(), 52 | allowNull: true 53 | }, 54 | 55 | //角色名称 56 | roleName: { 57 | type: dataTypes.STRING(), 58 | allowNull: true 59 | }, 60 | 61 | //角色ID 62 | roleId: { 63 | type: dataTypes.STRING(), 64 | allowNull: true 65 | }, 66 | 67 | //是否删除 true是 false否 68 | isDelete: { 69 | type: dataTypes.BOOLEAN(), 70 | allowNull: true, 71 | defaultValue: () => false 72 | }, 73 | 74 | //创建时间 75 | createdTime: { 76 | type: dataTypes.INTEGER(), 77 | allowNull: true, 78 | defaultValue: () => (Date.parse(new Date()) / 1000) 79 | }, 80 | 81 | //修改时间 82 | updatedTime: { 83 | type: dataTypes.INTEGER(), 84 | allowNull: true, 85 | defaultValue: () => (Date.parse(new Date()) / 1000) 86 | } 87 | }, { 88 | freezeTableName: true, 89 | tableName: 'sys_admin_base', 90 | timestamps: false //是否需要增加createdAt、updatedAt、deletedAt字段 91 | }); 92 | }; 93 | -------------------------------------------------------------------------------- /server/src/models/system/PermissionModel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 角色权限表数据模型 3 | * @param {*} sequelize 4 | * @param {*} dataTypes 5 | * 此模型仅限关系型数据库使用 6 | */ 7 | const { getTimeStampUUID } = require(':lib/Utils'); 8 | module.exports = (sequelize, dataTypes) => { 9 | return sequelize.define('sys_permission', { 10 | 11 | //权限ID 12 | permissionId: { 13 | type: dataTypes.STRING(), 14 | allowNull: false, 15 | primaryKey: true, 16 | defaultValue: () => getTimeStampUUID() 17 | }, 18 | 19 | //权限父级ID 20 | parentId: { 21 | type: dataTypes.STRING(), 22 | allowNull: true, 23 | defaultValue: 0 24 | }, 25 | 26 | //菜单名 27 | title: { 28 | type: dataTypes.STRING(), 29 | allowNull: true 30 | }, 31 | 32 | //菜单类型 1菜单,2按钮 33 | type: { 34 | type: dataTypes.STRING(10), 35 | allowNull: true, 36 | defaultValue: () => 1 37 | }, 38 | 39 | //菜单路径 40 | path: { 41 | type: dataTypes.STRING(), 42 | allowNull: true 43 | }, 44 | 45 | //组件name 46 | name: { 47 | type: dataTypes.STRING(), 48 | allowNull: true 49 | }, 50 | 51 | //组件名称 52 | component: { 53 | type: dataTypes.STRING(), 54 | allowNull: true 55 | }, 56 | 57 | //菜单图标 58 | icon: { 59 | type: dataTypes.STRING(), 60 | allowNull: true 61 | }, 62 | 63 | // //查看权限 64 | // find: { 65 | // type: dataTypes.INTEGER(2), 66 | // allowNull: true, 67 | // defaultValue: 0 68 | // }, 69 | 70 | // //添加权限 71 | // add: { 72 | // type: dataTypes.INTEGER(2), 73 | // allowNull: true, 74 | // defaultValue: 0 75 | // }, 76 | 77 | // //编辑权限 78 | // edit: { 79 | // type: dataTypes.INTEGER(2), 80 | // allowNull: true, 81 | // defaultValue: 0 82 | // }, 83 | 84 | // //删除权限 85 | // del: { 86 | // type: dataTypes.INTEGER(2), 87 | // allowNull: true, 88 | // defaultValue: 0 89 | // }, 90 | 91 | // //列表权限 92 | // list: { 93 | // type: dataTypes.INTEGER(2), 94 | // allowNull: true, 95 | // defaultValue: 0 96 | // }, 97 | 98 | //排序 99 | sort: { 100 | type: dataTypes.INTEGER(), 101 | allowNull: true 102 | }, 103 | 104 | //备注 105 | remark: { 106 | type: dataTypes.STRING(), 107 | allowNull: true 108 | }, 109 | 110 | //是否删除 true是 false否 111 | isDelete: { 112 | type: dataTypes.BOOLEAN(), 113 | allowNull: true, 114 | defaultValue: () => false 115 | }, 116 | 117 | //创建时间 118 | createdTime: { 119 | type: dataTypes.INTEGER(), 120 | allowNull: true, 121 | defaultValue: () => (Date.parse(new Date()) / 1000) 122 | }, 123 | 124 | //修改时间 125 | updatedTime: { 126 | type: dataTypes.INTEGER(), 127 | allowNull: true, 128 | defaultValue: () => (Date.parse(new Date()) / 1000) 129 | } 130 | }, { 131 | tableName: 'sys_permission', 132 | timestamps: false //是否需要增加createdAt、updatedAt、deletedAt字段 133 | }); 134 | }; 135 | -------------------------------------------------------------------------------- /server/src/models/system/RolesAuthModel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 角色权限过渡中间表数据模型 3 | * @param {*} sequelize 4 | * @param {*} dataTypes 5 | * 此模型仅限关系型数据库使用 6 | */ 7 | module.exports = (sequelize, dataTypes) => { 8 | return sequelize.define('sys_roles_auth', { 9 | 10 | //过度中间表ID 11 | roleId: { 12 | type: dataTypes.STRING(), 13 | allowNull: false, 14 | primaryKey: true 15 | }, 16 | 17 | //权限 18 | permissionId: { 19 | type: dataTypes.STRING(), 20 | allowNull: false, 21 | primaryKey: true 22 | }, 23 | 24 | //权限父级ID 25 | parentId: { 26 | type: dataTypes.STRING(), 27 | allowNull: true 28 | }, 29 | 30 | // //查看权限 31 | // find: { 32 | // type: dataTypes.INTEGER(2), 33 | // allowNull: true, 34 | // defaultValue: 0 35 | // }, 36 | 37 | // //添加权限 38 | // add: { 39 | // type: dataTypes.INTEGER(2), 40 | // allowNull: true, 41 | // defaultValue: 0 42 | // }, 43 | 44 | // //编辑权限 45 | // edit: { 46 | // type: dataTypes.INTEGER(2), 47 | // allowNull: true, 48 | // defaultValue: 0 49 | // }, 50 | 51 | // //删除权限 52 | // del: { 53 | // type: dataTypes.INTEGER(2), 54 | // allowNull: true, 55 | // defaultValue: 0 56 | // }, 57 | 58 | // //列表权限 59 | // list: { 60 | // type: dataTypes.INTEGER(2), 61 | // allowNull: true, 62 | // defaultValue: 0 63 | // }, 64 | 65 | //创建时间 66 | createdTime: { 67 | type: dataTypes.INTEGER(), 68 | allowNull: true, 69 | defaultValue: () => (Date.parse(new Date()) / 1000) 70 | }, 71 | 72 | //修改时间 73 | updatedTime: { 74 | type: dataTypes.INTEGER(), 75 | allowNull: true, 76 | defaultValue: () => (Date.parse(new Date()) / 1000) 77 | } 78 | }, { 79 | tableName: 'sys_roles_auth', 80 | timestamps: false //是否需要增加createdAt、updatedAt、deletedAt字段 81 | }); 82 | }; 83 | -------------------------------------------------------------------------------- /server/src/models/system/RolesBaseModel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 角色基础表数据模型 3 | * @param {*} sequelize 4 | * @param {*} dataTypes 5 | * 此模型仅限关系型数据库使用 6 | */ 7 | const { getTimeStampUUID } = require(':lib/Utils'); 8 | module.exports = (sequelize, dataTypes) => { 9 | return sequelize.define('sys_roles_base', { 10 | //角色ID 11 | roleId: { 12 | type: dataTypes.STRING(), 13 | allowNull: false, 14 | primaryKey: true, 15 | defaultValue: () => getTimeStampUUID() 16 | }, 17 | 18 | //角色名称 19 | roleName: { 20 | type: dataTypes.STRING(), 21 | allowNull: true 22 | }, 23 | 24 | //是否删除 true是 false否 25 | isDelete: { 26 | type: dataTypes.BOOLEAN(), 27 | allowNull: true, 28 | defaultValue: () => false 29 | }, 30 | 31 | //创建时间 32 | createdTime: { 33 | type: dataTypes.INTEGER(), 34 | allowNull: true, 35 | defaultValue: () => (Date.parse(new Date()) / 1000) 36 | }, 37 | 38 | //修改时间 39 | updatedTime: { 40 | type: dataTypes.INTEGER(), 41 | allowNull: true, 42 | defaultValue: () => (Date.parse(new Date()) / 1000) 43 | } 44 | }, { 45 | tableName: 'sys_roles_base', 46 | timestamps: false //是否需要增加createdAt、updatedAt、deletedAt字段 47 | }); 48 | }; 49 | -------------------------------------------------------------------------------- /server/src/public/uploads/20191104/BIUXS_WEB_69B09D4F1CE6816CEE4E0C5015B9996C.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/langyuxiansheng/biu-server-admin/4ae8ebf3be07ef2e3f268fd15c508b991a062447/server/src/public/uploads/20191104/BIUXS_WEB_69B09D4F1CE6816CEE4E0C5015B9996C.jpg -------------------------------------------------------------------------------- /server/src/services/common/LoginService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户登录 3 | */ 4 | const result = require(':lib/Result'); 5 | const { MODELS_PATH, getLC, signJWT, deepCloneObject } = require(':lib/Utils'); 6 | const { systemLogger } = require(':lib/logger4'); 7 | const { BiuDB } = require(':lib/sequelize'); 8 | const AdminBaseModel = BiuDB.import(`${MODELS_PATH}/system/AdminBaseModel`); 9 | module.exports = class { 10 | /** 11 | * 管理员登录 12 | * @param data 登录数据 13 | * @param cookies cookie 14 | */ 15 | async userLoginForSysAdmin({ data, cookies }) { 16 | const cookieCode = cookies.get('IMG-VALIDATE-DATA'); 17 | if (!cookieCode) return result.failed(`验证码已过期!`); 18 | const { account, password, code } = data; 19 | if (!account || !password || !code) return result.paramsLack(); 20 | if (getLC(code) !== getLC(cookieCode)) return result.failed(`验证码错误!`); 21 | let queryData = { 22 | where: { account, isDelete: false }, 23 | attributes: { exclude: ['isDelete', 'createdTime', 'updatedTime'] } 24 | }; 25 | try { 26 | const user = await AdminBaseModel.findOne(queryData); 27 | if (!user) return result.failed('用户不存在!'); 28 | if (password !== user.password) return result.failed('账号或密码输入错误!'); //对比密码 29 | if (!user.roleId) return result.failed('账号异常请联系管理员,异常信息:"未设置用户的角色!"'); 30 | const info = deepCloneObject(user);//克隆一个对象 31 | info['userId'] = user.adminId; //设置通用id名 32 | info['userName'] = user.adminName; //设置通用用户名 33 | const jwt = signJWT({ 34 | userId: user.adminId, 35 | isAdmin: user.isAdmin, 36 | roleId: user.roleId 37 | }, '2h'); //验证通过签发jwt,2小时有效! 38 | return result.success(null, { jwt, user: info }); 39 | } catch (error) { 40 | systemLogger.error(`管理员登录`, `LoginService.userLoginForSysAdmin`, error); 41 | return result.failed(); 42 | } 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /server/src/services/common/UtilsService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 公共工具类 3 | */ 4 | const svgCaptcha = require('svg-captcha'); 5 | const result = require(':lib/Result'); 6 | const Email = require(':lib/Email'); 7 | const config = require(':config/server.base.config'); //配置文件 8 | const email = new Email(config.email); 9 | module.exports = class { 10 | async getImgValidate() { 11 | const { text, data } = svgCaptcha.create({ 12 | inverse: false, // 翻转颜色 13 | size: 4, //随机字符串长度 14 | noise: 1, // 噪声线条数 15 | fontSize: 46, 16 | width: 100, 17 | height: 30, 18 | color: true //随机颜色 19 | // background: true 20 | }); 21 | return result.success(null, { img: data, text }); 22 | } 23 | 24 | /** 25 | * 发送邮件 26 | * @param {*} data 27 | */ 28 | async sendEmail(data) { 29 | const { toName, toEmail, message } = data; 30 | if (!toName || !toEmail || !message) return result.paramsLack(); 31 | try { 32 | console.log(email); 33 | const res = await email.sendEmail(data); 34 | if (res && res.messageId) { 35 | return result.success(); 36 | } 37 | } catch (error) { 38 | console.log(error); 39 | return result.failed('邮件发送失败!', null, error); 40 | } 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /server/src/services/system/LogsService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 系统日志管理 3 | */ 4 | const path = require('path'); 5 | const result = require(':lib/Result'); 6 | const { SRC_PATH } = require(':lib/Utils'); 7 | const { getLogsFileList, readerFile, writeFile } = require(':lib/FileUtils'); 8 | module.exports = class { 9 | /** 10 | * 获取系统日志列表 11 | * @param {*} param0 12 | */ 13 | async getSysLogList({ isAdmin }) { 14 | //非超级管理员不可获取此数据 15 | if (!isAdmin) return result.noAuthority(); 16 | try { 17 | const res = await getLogsFileList(path.join(SRC_PATH, '/logs')); 18 | return result.success(null, { list: res }); 19 | } catch (error) { 20 | console.log(error); 21 | return result.failed(error); 22 | } 23 | } 24 | 25 | /** 26 | * 获取系统日志内容 27 | * @param {*} param0 28 | * @param {*} param1 29 | */ 30 | async getSysLogContent({ logPath }, { isAdmin }) { 31 | //非超级管理员不可获取此数据 32 | if (!isAdmin) return result.noAuthority(); 33 | try { 34 | const { code, data } = await readerFile(path.join(SRC_PATH, logPath), 'utf-8'); 35 | if (code == 200) { 36 | return result.success(null, data); 37 | } 38 | return result.failed('读取日志失败!'); 39 | } catch (error) { 40 | console.log(error); 41 | return result.failed(error); 42 | } 43 | } 44 | 45 | /** 46 | * 删除系统日志内容 47 | * @param {*} param0 48 | * @description 只能清空内容不能直接删除文件,否则没释放资源的情况下会报错 49 | */ 50 | async delSysLogByPaths({ paths, isDelete }, { isAdmin }) { 51 | //非超级管理员不可获取此菜单 52 | if (!isAdmin) return result.noAuthority(); 53 | if (!paths || !isDelete || !Array.isArray(paths)) return result.paramsLack(); 54 | try { 55 | const deleteFiles = paths.map((logPath) => { //批量删除 56 | return new Promise(async (resolve, reject) => { 57 | try { 58 | const res = await writeFile(path.join(SRC_PATH, logPath), ''); //上传成功后删除临时文件 59 | if (res && res.code == 200) { 60 | resolve(logPath); 61 | } else { 62 | reject(res); 63 | } 64 | } catch (error) { 65 | reject(error); 66 | } 67 | }); 68 | }); 69 | //返回删除文件的结果 70 | const delData = await Promise.all(deleteFiles); 71 | return result.success(null, { list: delData }); 72 | } catch (error) { 73 | console.log(error); 74 | return result.failed(error); 75 | } 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /server/src/services/system/RolesService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 用户登录 3 | */ 4 | const result = require(':lib/Result'); 5 | const { MODELS_PATH } = require(':lib/Utils'); 6 | const { SOP, BiuDB } = require(':lib/sequelize'); 7 | const RolesBaseModel = BiuDB.import(`${MODELS_PATH}/system/RolesBaseModel`); 8 | module.exports = class { 9 | /** 10 | * 添加系统角色 11 | * @param {*} param0 12 | */ 13 | async addSysRole({ roleName }) { 14 | if (!roleName) return result.paramsLack(); 15 | try { 16 | //查询角色是否存在 17 | const count = await RolesBaseModel.count({ 18 | where: { roleName, isDelete: false } 19 | }); 20 | if (count > 0) return result.failed('角色已存在!'); 21 | const save = { roleName }; //保存数据 22 | await RolesBaseModel.create(save); 23 | return result.success(); 24 | } catch (error) { 25 | console.log(error); 26 | return result.failed(error); 27 | } 28 | } 29 | 30 | /** 31 | * 获取系统角色列表 32 | * @param {*} param0 33 | */ 34 | async getSysRoleList({ roleName, page, limit }) { 35 | let queryData = { 36 | where: { isDelete: false }, 37 | order: [ 38 | ['createdTime', 'DESC'] 39 | ], 40 | attributes: { exclude: ['isDelete'] } 41 | }; 42 | if (roleName) { 43 | queryData.where['roleName'] = { 44 | [SOP.like]: `%${roleName}%` 45 | }; 46 | } 47 | //分页 48 | if (page && limit) { 49 | queryData.offset = Number((page - 1) * limit); //开始的数据索引 50 | queryData.limit = Number(limit); //每页限制返回的数据条数 51 | }; 52 | try { 53 | const { rows, count } = await RolesBaseModel.findAndCountAll(queryData); 54 | return result.success(null, { list: rows, total: count }); 55 | } catch (error) { 56 | console.log(error); 57 | return result.failed(error); 58 | } 59 | } 60 | 61 | /** 62 | * 删除系统角色 63 | * @param {*} param0 64 | */ 65 | async delSysRoleByIds({ ids, isDelete }) { 66 | if (!ids || !isDelete || !Array.isArray(ids)) return result.paramsLack(); 67 | try { 68 | //批量软删除 69 | const del = { where: { roleId: ids } }; 70 | await RolesBaseModel.update({ isDelete }, del); 71 | return result.success(); 72 | } catch (error) { 73 | console.log(error); 74 | return result.failed(error); 75 | } 76 | } 77 | 78 | /** 79 | * 编辑系统角色 80 | * @param {*} data 81 | */ 82 | async updateSysRole(data) { 83 | if (!data.roleId) return result.paramsLack(); 84 | try { 85 | await RolesBaseModel.update(data, { where: { roleId: data.roleId } }); 86 | return result.success(); 87 | } catch (error) { 88 | console.log(error); 89 | return result.failed(error); 90 | } 91 | } 92 | }; 93 | -------------------------------------------------------------------------------- /代码提示.md: -------------------------------------------------------------------------------- 1 | 使用typings给vscode添加更多的智能提示 2 | 2017-09-15 11:04:55 疯狂紫萧 阅读数 9135 收藏 更多 3 | 分类专栏: 开发工具 4 | 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 5 | 本文链接:https://blog.csdn.net/cuo9958/article/details/77989407 6 | vscode真的是一个非常好用的IDE,但是智能提示这块还是不能提示所有的东西,这个真的是非常的麻烦的。 7 | 8 | 下面就教大家使用typing来给没有提示的关键字、对象、方法等添加提示。 9 | 10 | 安装typings 11 | 1.前提是有npm 12 | 2.在项目目录下执行npm install typings -g全局安装更放心 13 | 14 | 初始化项目 15 | 1.在项目下执行typings init项目下会自动生成文件typings.json这个文件给typings使用,类似于package.json 16 | 2.检查是否有jsconfig.json文件,如果没有就新建一个,内容无要求 17 | 18 | 添加第一个插件 19 | 1.添加一个node的智能提示 20 | 2.某些插件需要加全局参数--global,比如node。不加这个参数安装报错,提示需要加这个参数 21 | 3.执行typings install dt~node --global --save安装成功 22 | 4.现在编写node也有语法提示领。 23 | 5.其他插件可以自行搜索添加 24 | 6.所有插件都在typings这个文件夹下 25 | 7.安装完最好重启一次 26 | 27 | 安装express提示 28 | typings install dt~express dt~serve-static dt~express-serve-static-core --global 29 | 30 | 编写自己的智能提示 31 | 1.在typings文件夹下创建对应的文件夹 32 | 2.添加index.d.ts文件,在里面写各种提示的逻辑 33 | 3.将文件路径添加到typings文件夹下的index.d.ts中,类似: 34 | 35 | /// 36 | 37 | 编写提示代码 38 | 1.使用declare来定义 39 | 2.使用export来开放 40 | 3.地址1 地址2 41 | 42 | declare function domready (...): any; 43 | 44 | export = domready 45 | --------------------------------------------------------------------------------