diff --git a/ruoyi-ui/.env.development b/ruoyi-ui/.env.development index 18b2a3ed..c1482767 100644 --- a/ruoyi-ui/.env.development +++ b/ruoyi-ui/.env.development @@ -1,11 +1,11 @@ -# 页面标题 -VUE_APP_TITLE = 若依管理系统 - -# 开发环境配置 -ENV = 'development' - -# 若依管理系统/开发环境 -VUE_APP_BASE_API = '/dev-api' - -# 路由懒加载 -VUE_CLI_BABEL_TRANSPILE_MODULES = true +# 页面标题 +VUE_APP_TITLE = 智能作业系统 + +# 开发环境配置 +ENV = 'development' + +# 智能作业系统/开发环境 +VUE_APP_BASE_API = '/dev-api' + +# 路由懒加载 +VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/ruoyi-ui/.env.production b/ruoyi-ui/.env.production index cb064ec8..55776496 100644 --- a/ruoyi-ui/.env.production +++ b/ruoyi-ui/.env.production @@ -1,8 +1,8 @@ -# 页面标题 -VUE_APP_TITLE = 若依管理系统 - -# 生产环境配置 -ENV = 'production' - -# 若依管理系统/生产环境 -VUE_APP_BASE_API = '/prod-api' +# 页面标题 +VUE_APP_TITLE = 智能作业系统 + +# 生产环境配置 +ENV = 'production' + +# 智能作业系统/生产环境 +VUE_APP_BASE_API = '/prod-api' diff --git a/ruoyi-ui/.env.staging b/ruoyi-ui/.env.staging index a47af9a2..b4042af9 100644 --- a/ruoyi-ui/.env.staging +++ b/ruoyi-ui/.env.staging @@ -1,10 +1,10 @@ -# 页面标题 -VUE_APP_TITLE = 若依管理系统 - -NODE_ENV = production - -# 测试环境配置 -ENV = 'staging' - -# 若依管理系统/测试环境 -VUE_APP_BASE_API = '/stage-api' +# 页面标题 +VUE_APP_TITLE = 智能作业系统 + +NODE_ENV = production + +# 测试环境配置 +ENV = 'staging' + +# 智能作业系统/测试环境 +VUE_APP_BASE_API = '/stage-api' diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json index 6cebf701..1664dd20 100644 --- a/ruoyi-ui/package.json +++ b/ruoyi-ui/package.json @@ -1,90 +1,92 @@ -{ - "name": "ruoyi", - "version": "3.6.1", - "description": "若依管理系统", - "author": "若依", - "license": "MIT", - "scripts": { - "dev": "vue-cli-service serve", - "build:prod": "vue-cli-service build", - "build:stage": "vue-cli-service build --mode staging", - "preview": "node build/index.js --preview", - "lint": "eslint --ext .js,.vue src" - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } - }, - "lint-staged": { - "src/**/*.{js,vue}": [ - "eslint --fix", - "git add" - ] - }, - "keywords": [ - "vue", - "admin", - "dashboard", - "element-ui", - "boilerplate", - "admin-template", - "management-system" - ], - "repository": { - "type": "git", - "url": "https://gitee.com/y_project/RuoYi-Cloud.git" - }, - "dependencies": { - "@riophae/vue-treeselect": "0.4.0", - "axios": "0.24.0", - "clipboard": "2.0.8", - "core-js": "3.25.3", - "echarts": "4.9.0", - "element-ui": "2.15.10", - "file-saver": "2.0.5", - "fuse.js": "6.4.3", - "highlight.js": "9.18.5", - "js-beautify": "1.13.0", - "js-cookie": "3.0.1", - "jsencrypt": "3.0.0-rc.1", - "nprogress": "0.2.0", - "quill": "1.3.7", - "screenfull": "5.0.2", - "sortablejs": "1.10.2", - "vue": "2.6.12", - "vue-count-to": "1.0.13", - "vue-cropper": "0.5.5", - "vue-meta": "2.4.0", - "vue-router": "3.4.9", - "vuedraggable": "2.24.3", - "vuex": "3.6.0" - }, - "devDependencies": { - "@vue/cli-plugin-babel": "4.4.6", - "@vue/cli-plugin-eslint": "4.4.6", - "@vue/cli-service": "4.4.6", - "babel-eslint": "10.1.0", - "babel-plugin-dynamic-import-node": "2.3.3", - "chalk": "4.1.0", - "compression-webpack-plugin": "5.0.2", - "connect": "3.6.6", - "eslint": "7.15.0", - "eslint-plugin-vue": "7.2.0", - "lint-staged": "10.5.3", - "runjs": "4.4.2", - "sass": "1.32.13", - "sass-loader": "10.1.1", - "script-ext-html-webpack-plugin": "2.1.5", - "svg-sprite-loader": "5.1.1", - "vue-template-compiler": "2.6.12" - }, - "engines": { - "node": ">=8.9", - "npm": ">= 3.0.0" - }, - "browserslist": [ - "> 1%", - "last 2 versions" - ] -} +{ + "name": "ruoyi", + "version": "3.6.1", + "description": "智能作业系统", + "author": "若依", + "license": "MIT", + "scripts": { + "dev": "vue-cli-service serve", + "build:prod": "vue-cli-service build", + "build:stage": "vue-cli-service build --mode staging", + "preview": "node build/index.js --preview", + "lint": "eslint --ext .js,.vue src" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "src/**/*.{js,vue}": [ + "eslint --fix", + "git add" + ] + }, + "keywords": [ + "vue", + "admin", + "dashboard", + "element-ui", + "boilerplate", + "admin-template", + "management-system" + ], + "repository": { + "type": "git", + "url": "https://gitee.com/y_project/RuoYi-Cloud.git" + }, + "dependencies": { + "@riophae/vue-treeselect": "0.4.0", + "axios": "0.24.0", + "bpmn-js": "^7.2.1", + "clipboard": "2.0.8", + "core-js": "3.25.3", + "echarts": "4.9.0", + "element-ui": "2.15.10", + "file-saver": "2.0.5", + "fuse.js": "6.4.3", + "highlight.js": "9.18.5", + "js-beautify": "1.13.0", + "js-cookie": "3.0.1", + "jsencrypt": "3.0.0-rc.1", + "nprogress": "0.2.0", + "quill": "1.3.7", + "screenfull": "5.0.2", + "sortablejs": "1.10.2", + "vue": "2.6.12", + "vue-count-to": "1.0.13", + "vue-cropper": "0.5.5", + "vue-meta": "2.4.0", + "vue-router": "3.4.9", + "vuedraggable": "2.24.3", + "vuex": "3.6.0", + "workflow-bpmn-modeler": "^0.2.8" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "4.4.6", + "@vue/cli-plugin-eslint": "4.4.6", + "@vue/cli-service": "4.4.6", + "babel-eslint": "10.1.0", + "babel-plugin-dynamic-import-node": "2.3.3", + "chalk": "4.1.0", + "compression-webpack-plugin": "5.0.2", + "connect": "3.6.6", + "eslint": "7.15.0", + "eslint-plugin-vue": "7.2.0", + "lint-staged": "10.5.3", + "runjs": "4.4.2", + "sass": "1.32.13", + "sass-loader": "10.1.1", + "script-ext-html-webpack-plugin": "2.1.5", + "svg-sprite-loader": "5.1.1", + "vue-template-compiler": "2.6.12" + }, + "engines": { + "node": ">=8.9", + "npm": ">= 3.0.0" + }, + "browserslist": [ + "> 1%", + "last 2 versions" + ] +} diff --git a/ruoyi-ui/src/App.vue b/ruoyi-ui/src/App.vue index a2c4b872..ba498506 100644 --- a/ruoyi-ui/src/App.vue +++ b/ruoyi-ui/src/App.vue @@ -1,28 +1,112 @@ - - - - + + + + diff --git a/ruoyi-ui/src/api/login.js b/ruoyi-ui/src/api/login.js index 6b0cda03..c23e7fb2 100644 --- a/ruoyi-ui/src/api/login.js +++ b/ruoyi-ui/src/api/login.js @@ -1,61 +1,61 @@ -import request from '@/utils/request' - -// 登录方法 -export function login(username, password, code, uuid) { - return request({ - url: '/auth/login', - headers: { - isToken: false - }, - method: 'post', - data: { username, password, code, uuid } - }) -} - -// 注册方法 -export function register(data) { - return request({ - url: '/auth/register', - headers: { - isToken: false - }, - method: 'post', - data: data - }) -} - -// 刷新方法 -export function refreshToken() { - return request({ - url: '/auth/refresh', - method: 'post' - }) -} - -// 获取用户详细信息 -export function getInfo() { - return request({ - url: '/system/user/getInfo', - method: 'get' - }) -} - -// 退出方法 -export function logout() { - return request({ - url: '/auth/logout', - method: 'delete' - }) -} - -// 获取验证码 -export function getCodeImg() { - return request({ - url: '/code', - headers: { - isToken: false - }, - method: 'get', - timeout: 20000 - }) -} \ No newline at end of file +import request from '@/utils/request' + +// 登录方法 +export function login(username, password, code, uuid) { + return request({ + url: '/system/login', + headers: { + isToken: false + }, + method: 'post', + data: { username, password, code, uuid } + }) +} + +// 注册方法 +export function register(data) { + return request({ + url: '/system/register', + headers: { + isToken: false + }, + method: 'post', + data: data + }) +} + +// 刷新方法 +export function refreshToken() { + return request({ + url: '/system/refresh', + method: 'post' + }) +} + +// 获取用户详细信息 +export function getInfo() { + return request({ + url: '/system/user/getInfo', + method: 'get' + }) +} + +// 退出方法 +export function logout() { + return request({ + url: '/system/logout', + method: 'delete' + }) +} + +// 获取验证码 +export function getCodeImg() { + return request({ + url: '/code', + headers: { + isToken: false + }, + method: 'get', + timeout: 20000 + }) +} diff --git a/ruoyi-ui/src/api/system/dept.js b/ruoyi-ui/src/api/system/dept.js deleted file mode 100644 index 9ca69663..00000000 --- a/ruoyi-ui/src/api/system/dept.js +++ /dev/null @@ -1,52 +0,0 @@ -import request from '@/utils/request' - -// 查询部门列表 -export function listDept(query) { - return request({ - url: '/system/dept/list', - method: 'get', - params: query - }) -} - -// 查询部门列表(排除节点) -export function listDeptExcludeChild(deptId) { - return request({ - url: '/system/dept/list/exclude/' + deptId, - method: 'get' - }) -} - -// 查询部门详细 -export function getDept(deptId) { - return request({ - url: '/system/dept/' + deptId, - method: 'get' - }) -} - -// 新增部门 -export function addDept(data) { - return request({ - url: '/system/dept', - method: 'post', - data: data - }) -} - -// 修改部门 -export function updateDept(data) { - return request({ - url: '/system/dept', - method: 'put', - data: data - }) -} - -// 删除部门 -export function delDept(deptId) { - return request({ - url: '/system/dept/' + deptId, - method: 'delete' - }) -} \ No newline at end of file diff --git a/ruoyi-ui/src/api/system/menu.js b/ruoyi-ui/src/api/system/menu.js index 97258ee6..ece5e81c 100644 --- a/ruoyi-ui/src/api/system/menu.js +++ b/ruoyi-ui/src/api/system/menu.js @@ -1,60 +1,60 @@ -import request from '@/utils/request' - -// 查询菜单列表 -export function listMenu(query) { - return request({ - url: '/system/menu/list', - method: 'get', - params: query - }) -} - -// 查询菜单详细 -export function getMenu(menuId) { - return request({ - url: '/system/menu/' + menuId, - method: 'get' - }) -} - -// 查询菜单下拉树结构 -export function treeselect() { - return request({ - url: '/system/menu/treeselect', - method: 'get' - }) -} - -// 根据角色ID查询菜单下拉树结构 -export function roleMenuTreeselect(roleId) { - return request({ - url: '/system/menu/roleMenuTreeselect/' + roleId, - method: 'get' - }) -} - -// 新增菜单 -export function addMenu(data) { - return request({ - url: '/system/menu', - method: 'post', - data: data - }) -} - -// 修改菜单 -export function updateMenu(data) { - return request({ - url: '/system/menu', - method: 'put', - data: data - }) -} - -// 删除菜单 -export function delMenu(menuId) { - return request({ - url: '/system/menu/' + menuId, - method: 'delete' - }) -} \ No newline at end of file + import request from '@/utils/request' + +// 查询菜单列表 +export function listMenu(query) { + return request({ + url: '/system/menu/list', + method: 'get', + params: query + }) +} + +// 查询菜单详细 +export function getMenu(menuId) { + return request({ + url: '/system/menu/' + menuId, + method: 'get' + }) +} + +// 查询菜单下拉树结构 +export function treeselect() { + return request({ + url: '/system/menu/treeselect', + method: 'get' + }) +} + +// 根据角色ID查询菜单下拉树结构 +export function roleMenuTreeselect(roleId) { + return request({ + url: '/system/menu/roleMenuTreeselect/' + roleId, + method: 'get' + }) +} + +// 新增菜单 +export function addMenu(data) { + return request({ + url: '/system/menu', + method: 'post', + data: data + }) +} + +// 修改菜单 +export function updateMenu(data) { + return request({ + url: '/system/menu', + method: 'put', + data: data + }) +} + +// 删除菜单 +export function delMenu(menuId) { + return request({ + url: '/system/menu/' + menuId, + method: 'delete' + }) +} diff --git a/ruoyi-ui/src/api/system/org.js b/ruoyi-ui/src/api/system/org.js new file mode 100644 index 00000000..5d46f57b --- /dev/null +++ b/ruoyi-ui/src/api/system/org.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 查询机构列表 +export function listSysOrg(query) { + return request({ + url: '/system/org/list', + method: 'get', + params: query + }) +} + +// 查询机构列表(排除节点) +export function listSysOrgExcludeChild(orgId) { + return request({ + url: '/system/org/list/exclude/' + orgId, + method: 'get' + }) +} + +// 查询机构详细 +export function getSysOrg(orgId) { + return request({ + url: '/system/org/' + orgId, + method: 'get' + }) +} + +// 新增机构 +export function addSysOrg(data) { + return request({ + url: '/system/org', + method: 'post', + data: data + }) +} + +// 修改机构 +export function updateSysOrg(data) { + return request({ + url: '/system/org', + method: 'put', + data: data + }) +} + +// 删除机构 +export function delSysOrg(orgId) { + return request({ + url: '/system/org/' + orgId, + method: 'delete' + }) +} diff --git a/ruoyi-ui/src/api/system/role.js b/ruoyi-ui/src/api/system/role.js index 528cd186..44bb5bd3 100644 --- a/ruoyi-ui/src/api/system/role.js +++ b/ruoyi-ui/src/api/system/role.js @@ -1,119 +1,119 @@ -import request from '@/utils/request' - -// 查询角色列表 -export function listRole(query) { - return request({ - url: '/system/role/list', - method: 'get', - params: query - }) -} - -// 查询角色详细 -export function getRole(roleId) { - return request({ - url: '/system/role/' + roleId, - method: 'get' - }) -} - -// 新增角色 -export function addRole(data) { - return request({ - url: '/system/role', - method: 'post', - data: data - }) -} - -// 修改角色 -export function updateRole(data) { - return request({ - url: '/system/role', - method: 'put', - data: data - }) -} - -// 角色数据权限 -export function dataScope(data) { - return request({ - url: '/system/role/dataScope', - method: 'put', - data: data - }) -} - -// 角色状态修改 -export function changeRoleStatus(roleId, status) { - const data = { - roleId, - status - } - return request({ - url: '/system/role/changeStatus', - method: 'put', - data: data - }) -} - -// 删除角色 -export function delRole(roleId) { - return request({ - url: '/system/role/' + roleId, - method: 'delete' - }) -} - -// 查询角色已授权用户列表 -export function allocatedUserList(query) { - return request({ - url: '/system/role/authUser/allocatedList', - method: 'get', - params: query - }) -} - -// 查询角色未授权用户列表 -export function unallocatedUserList(query) { - return request({ - url: '/system/role/authUser/unallocatedList', - method: 'get', - params: query - }) -} - -// 取消用户授权角色 -export function authUserCancel(data) { - return request({ - url: '/system/role/authUser/cancel', - method: 'put', - data: data - }) -} - -// 批量取消用户授权角色 -export function authUserCancelAll(data) { - return request({ - url: '/system/role/authUser/cancelAll', - method: 'put', - params: data - }) -} - -// 授权用户选择 -export function authUserSelectAll(data) { - return request({ - url: '/system/role/authUser/selectAll', - method: 'put', - params: data - }) -} - -// 根据角色ID查询部门树结构 -export function deptTreeSelect(roleId) { - return request({ - url: '/system/role/deptTree/' + roleId, - method: 'get' - }) -} +import request from '@/utils/request' + +// 查询角色列表 +export function listRole(query) { + return request({ + url: '/system/role/list', + method: 'get', + params: query + }) +} + +// 查询角色详细 +export function getRole(roleId) { + return request({ + url: '/system/role/' + roleId, + method: 'get' + }) +} + +// 新增角色 +export function addRole(data) { + return request({ + url: '/system/role', + method: 'post', + data: data + }) +} + +// 修改角色 +export function updateRole(data) { + return request({ + url: '/system/role', + method: 'put', + data: data + }) +} + +// 角色数据权限 +export function dataScope(data) { + return request({ + url: '/system/role/dataScope', + method: 'put', + data: data + }) +} + +// 角色状态修改 +export function changeRoleStatus(roleId, status) { + const data = { + roleId, + status + } + return request({ + url: '/system/role/changeStatus', + method: 'put', + data: data + }) +} + +// 删除角色 +export function delRole(roleId) { + return request({ + url: '/system/role/' + roleId, + method: 'delete' + }) +} + +// 查询角色已授权用户列表 +export function allocatedUserList(query) { + return request({ + url: '/system/role/authUser/allocatedList', + method: 'get', + params: query + }) +} + +// 查询角色未授权用户列表 +export function unallocatedUserList(query) { + return request({ + url: '/system/role/authUser/unallocatedList', + method: 'get', + params: query + }) +} + +// 取消用户授权角色 +export function authUserCancel(data) { + return request({ + url: '/system/role/authUser/cancel', + method: 'put', + data: data + }) +} + +// 批量取消用户授权角色 +export function authUserCancelAll(data) { + return request({ + url: '/system/role/authUser/cancelAll', + method: 'put', + params: data + }) +} + +// 授权用户选择 +export function authUserSelectAll(data) { + return request({ + url: '/system/role/authUser/selectAll', + method: 'put', + params: data + }) +} + +// 根据角色ID查询机构树结构 +export function sysOrgTreeSelect(roleId) { + return request({ + url: '/system/role/orgTree/' + roleId, + method: 'get' + }) +} diff --git a/ruoyi-ui/src/api/system/user.js b/ruoyi-ui/src/api/system/user.js index f2f76ef9..e6495c4e 100644 --- a/ruoyi-ui/src/api/system/user.js +++ b/ruoyi-ui/src/api/system/user.js @@ -126,10 +126,10 @@ export function updateAuthRole(data) { }) } -// 查询部门下拉树结构 -export function deptTreeSelect() { +// 查询机构下拉树结构 +export function sysOrgTreeSelect() { return request({ - url: '/system/user/deptTree', + url: '/system/user/orgTree', method: 'get' }) } diff --git a/ruoyi-ui/src/assets/img/banner/bg.png b/ruoyi-ui/src/assets/img/banner/bg.png new file mode 100644 index 00000000..2a34a0dc Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/bg.png differ diff --git a/ruoyi-ui/src/assets/img/banner/head_avatar.png b/ruoyi-ui/src/assets/img/banner/head_avatar.png new file mode 100644 index 00000000..7854a979 Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/head_avatar.png differ diff --git a/ruoyi-ui/src/assets/img/banner/head_bank_logo.png b/ruoyi-ui/src/assets/img/banner/head_bank_logo.png new file mode 100644 index 00000000..2a2dd33c Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/head_bank_logo.png differ diff --git a/ruoyi-ui/src/assets/img/banner/header_bg.png b/ruoyi-ui/src/assets/img/banner/header_bg.png new file mode 100644 index 00000000..6f50cd0b Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/header_bg.png differ diff --git a/ruoyi-ui/src/assets/img/banner/new_pro.png b/ruoyi-ui/src/assets/img/banner/new_pro.png new file mode 100644 index 00000000..ec54678a Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/new_pro.png differ diff --git a/ruoyi-ui/src/assets/img/banner/newpro.png b/ruoyi-ui/src/assets/img/banner/newpro.png new file mode 100644 index 00000000..df89d2f8 Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/newpro.png differ diff --git a/ruoyi-ui/src/assets/img/banner/pro_hot.png b/ruoyi-ui/src/assets/img/banner/pro_hot.png new file mode 100644 index 00000000..fa19d82f Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/pro_hot.png differ diff --git a/ruoyi-ui/src/assets/img/banner/red_black.png b/ruoyi-ui/src/assets/img/banner/red_black.png new file mode 100644 index 00000000..fbf01723 Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/red_black.png differ diff --git a/ruoyi-ui/src/assets/img/banner/user.png b/ruoyi-ui/src/assets/img/banner/user.png new file mode 100644 index 00000000..bba9f171 Binary files /dev/null and b/ruoyi-ui/src/assets/img/banner/user.png differ diff --git a/ruoyi-ui/src/assets/img/home/head_bg_logo.png b/ruoyi-ui/src/assets/img/home/head_bg_logo.png new file mode 100644 index 00000000..8a250cb4 Binary files /dev/null and b/ruoyi-ui/src/assets/img/home/head_bg_logo.png differ diff --git a/ruoyi-ui/src/assets/logo-imgs/安全退出icon@2x.png b/ruoyi-ui/src/assets/logo-imgs/安全退出icon@2x.png new file mode 100644 index 00000000..1b5bd754 Binary files /dev/null and b/ruoyi-ui/src/assets/logo-imgs/安全退出icon@2x.png differ diff --git a/ruoyi-ui/src/assets/styles/index.scss b/ruoyi-ui/src/assets/styles/index.scss index 9f536ae8..1caf3ac4 100644 --- a/ruoyi-ui/src/assets/styles/index.scss +++ b/ruoyi-ui/src/assets/styles/index.scss @@ -1,191 +1,191 @@ -@import './variables.scss'; -@import './mixin.scss'; -@import './transition.scss'; -@import './element-ui.scss'; -@import './sidebar.scss'; -@import './btn.scss'; - -body { - height: 100%; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - text-rendering: optimizeLegibility; - font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; -} - -label { - font-weight: 700; -} - -html { - height: 100%; - box-sizing: border-box; -} - -#app { - height: 100%; -} - -*, -*:before, -*:after { - box-sizing: inherit; -} - -.no-padding { - padding: 0px !important; -} - -.padding-content { - padding: 4px 0; -} - -a:focus, -a:active { - outline: none; -} - -a, -a:focus, -a:hover { - cursor: pointer; - color: inherit; - text-decoration: none; -} - -div:focus { - outline: none; -} - -.fr { - float: right; -} - -.fl { - float: left; -} - -.pr-5 { - padding-right: 5px; -} - -.pl-5 { - padding-left: 5px; -} - -.block { - display: block; -} - -.pointer { - cursor: pointer; -} - -.inlineBlock { - display: block; -} - -.clearfix { - &:after { - visibility: hidden; - display: block; - font-size: 0; - content: " "; - clear: both; - height: 0; - } -} - -aside { - background: #eef1f6; - padding: 8px 24px; - margin-bottom: 20px; - border-radius: 2px; - display: block; - line-height: 32px; - font-size: 16px; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - color: #2c3e50; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - a { - color: #337ab7; - cursor: pointer; - - &:hover { - color: rgb(32, 160, 255); - } - } -} - -//main-container全局样式 -.app-container { - padding: 20px; -} - -.components-container { - margin: 30px 50px; - position: relative; -} - -.pagination-container { - margin-top: 30px; -} - -.text-center { - text-align: center -} - -.sub-navbar { - height: 50px; - line-height: 50px; - position: relative; - width: 100%; - text-align: right; - padding-right: 20px; - transition: 600ms ease position; - background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%); - - .subtitle { - font-size: 20px; - color: #fff; - } - - &.draft { - background: #d0d0d0; - } - - &.deleted { - background: #d0d0d0; - } -} - -.link-type, -.link-type:focus { - color: #337ab7; - cursor: pointer; - - &:hover { - color: rgb(32, 160, 255); - } -} - -.filter-container { - padding-bottom: 10px; - - .filter-item { - display: inline-block; - vertical-align: middle; - margin-bottom: 10px; - } -} - -//refine vue-multiselect plugin -.multiselect { - line-height: 16px; -} - -.multiselect--active { - z-index: 1000 !important; -} +@import './variables.scss'; +@import './mixin.scss'; +@import './transition.scss'; +@import './element-ui.scss'; +@import './sidebar.scss'; +@import './btn.scss'; + +body { + height: 100%; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; +} + +label { + font-weight: 700; +} + +html { + height: 100%; + box-sizing: border-box; +} + +#app { + height: 100%; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +.no-padding { + padding: 0px !important; +} + +.padding-content { + padding: 4px 0; +} + +a:focus, +a:active { + outline: none; +} + +a, +a:focus, +a:hover { + cursor: pointer; + color: inherit; + text-decoration: none; +} + +div:focus { + outline: none; +} + +.fr { + float: right; +} + +.fl { + float: left; +} + +.pr-5 { + padding-right: 5px; +} + +.pl-5 { + padding-left: 5px; +} + +.block { + display: block; +} + +.pointer { + cursor: pointer; +} + +.inlineBlock { + display: block; +} + +.clearfix { + &:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; + } +} + +aside { + background: #eef1f6; + padding: 8px 24px; + margin-bottom: 20px; + border-radius: 2px; + display: block; + line-height: 32px; + font-size: 16px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + color: #2c3e50; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + a { + color: #337ab7; + cursor: pointer; + + &:hover { + color: rgb(32, 160, 255); + } + } +} + +//main-container全局样式 +.app-container { + //padding: 20px; +} + +.components-container { + margin: 30px 50px; + position: relative; +} + +.pagination-container { + margin-top: 30px; +} + +.text-center { + text-align: center +} + +.sub-navbar { + height: 50px; + line-height: 50px; + position: relative; + width: 100%; + text-align: right; + padding-right: 20px; + transition: 600ms ease position; + background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%); + + .subtitle { + font-size: 20px; + color: #fff; + } + + &.draft { + background: #d0d0d0; + } + + &.deleted { + background: #d0d0d0; + } +} + +.link-type, +.link-type:focus { + color: #337ab7; + cursor: pointer; + + &:hover { + color: rgb(32, 160, 255); + } +} + +.filter-container { + padding-bottom: 10px; + + .filter-item { + display: inline-block; + vertical-align: middle; + margin-bottom: 10px; + } +} + +//refine vue-multiselect plugin +.multiselect { + line-height: 16px; +} + +.multiselect--active { + z-index: 1000 !important; +} diff --git a/ruoyi-ui/src/assets/styles/sidebar.scss b/ruoyi-ui/src/assets/styles/sidebar.scss index 43d5f9a9..7358c58c 100644 --- a/ruoyi-ui/src/assets/styles/sidebar.scss +++ b/ruoyi-ui/src/assets/styles/sidebar.scss @@ -1,227 +1,228 @@ -#app { - - .main-container { - min-height: 100%; - transition: margin-left .28s; - margin-left: $base-sidebar-width; - position: relative; - } - - .sidebarHide { - margin-left: 0!important; - } - - .sidebar-container { - -webkit-transition: width .28s; - transition: width 0.28s; - width: $base-sidebar-width !important; - background-color: $base-menu-background; - height: 100%; - position: fixed; - font-size: 0px; - top: 0; - bottom: 0; - left: 0; - z-index: 1001; - overflow: hidden; - -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35); - box-shadow: 2px 0 6px rgba(0,21,41,.35); - - // reset element-ui css - .horizontal-collapse-transition { - transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; - } - - .scrollbar-wrapper { - overflow-x: hidden !important; - } - - .el-scrollbar__bar.is-vertical { - right: 0px; - } - - .el-scrollbar { - height: 100%; - } - - &.has-logo { - .el-scrollbar { - height: calc(100% - 50px); - } - } - - .is-horizontal { - display: none; - } - - a { - display: inline-block; - width: 100%; - overflow: hidden; - } - - .svg-icon { - margin-right: 16px; - } - - .el-menu { - border: none; - height: 100%; - width: 100% !important; - } - - .el-menu-item, .el-submenu__title { - overflow: hidden !important; - text-overflow: ellipsis !important; - white-space: nowrap !important; - } - - // menu hover - .submenu-title-noDropdown, - .el-submenu__title { - &:hover { - background-color: rgba(0, 0, 0, 0.06) !important; - } - } - - & .theme-dark .is-active > .el-submenu__title { - color: $base-menu-color-active !important; - } - - & .nest-menu .el-submenu>.el-submenu__title, - & .el-submenu .el-menu-item { - min-width: $base-sidebar-width !important; - - &:hover { - background-color: rgba(0, 0, 0, 0.06) !important; - } - } - - & .theme-dark .nest-menu .el-submenu>.el-submenu__title, - & .theme-dark .el-submenu .el-menu-item { - background-color: $base-sub-menu-background !important; - - &:hover { - background-color: $base-sub-menu-hover !important; - } - } - } - - .hideSidebar { - .sidebar-container { - width: 54px !important; - } - - .main-container { - margin-left: 54px; - } - - .submenu-title-noDropdown { - padding: 0 !important; - position: relative; - - .el-tooltip { - padding: 0 !important; - - .svg-icon { - margin-left: 20px; - } - } - } - - .el-submenu { - overflow: hidden; - - &>.el-submenu__title { - padding: 0 !important; - - .svg-icon { - margin-left: 20px; - } - - } - } - - .el-menu--collapse { - .el-submenu { - &>.el-submenu__title { - &>span { - height: 0; - width: 0; - overflow: hidden; - visibility: hidden; - display: inline-block; - } - } - } - } - } - - .el-menu--collapse .el-menu .el-submenu { - min-width: $base-sidebar-width !important; - } - - // mobile responsive - .mobile { - .main-container { - margin-left: 0px; - } - - .sidebar-container { - transition: transform .28s; - width: $base-sidebar-width !important; - } - - &.hideSidebar { - .sidebar-container { - pointer-events: none; - transition-duration: 0.3s; - transform: translate3d(-$base-sidebar-width, 0, 0); - } - } - } - - .withoutAnimation { - - .main-container, - .sidebar-container { - transition: none; - } - } -} - -// when menu collapsed -.el-menu--vertical { - &>.el-menu { - .svg-icon { - margin-right: 16px; - } - } - - .nest-menu .el-submenu>.el-submenu__title, - .el-menu-item { - &:hover { - // you can use $subMenuHover - background-color: rgba(0, 0, 0, 0.06) !important; - } - } - - // the scroll bar appears when the subMenu is too long - >.el-menu--popup { - max-height: 100vh; - overflow-y: auto; - - &::-webkit-scrollbar-track-piece { - background: #d3dce6; - } - - &::-webkit-scrollbar { - width: 6px; - } - - &::-webkit-scrollbar-thumb { - background: #99a9bf; - border-radius: 20px; - } - } -} +#app { + + .main-container { + transition: margin-left .28s; + margin-left: $base-sidebar-width; + position: relative; + overflow-y: hidden; + top: 80px; + } + + .sidebarHide { + margin-left: 0!important; + } + + .sidebar-container { + -webkit-transition: width .28s; + transition: width 0.28s; + width: $base-sidebar-width !important; + background-color: $base-menu-background; + height: calc(100vh - 80px); + position: fixed; + font-size: 0px; + top: 80px; + bottom: 0; + left: 0; + z-index: 1001; + overflow: hidden; + -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35); + box-shadow: 2px 0 6px rgba(0,21,41,.35); + + // reset element-ui css + .horizontal-collapse-transition { + transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; + } + + .scrollbar-wrapper { + overflow-x: hidden !important; + } + + .el-scrollbar__bar.is-vertical { + right: 0px; + } + + .el-scrollbar { + height: 100%; + } + + &.has-logo { + .el-scrollbar { + height: calc(100% - 50px); + } + } + + .is-horizontal { + display: none; + } + + a { + display: inline-block; + width: 100%; + overflow: hidden; + } + + .svg-icon { + margin-right: 16px; + } + + .el-menu { + border: none; + height: 100%; + width: 100% !important; + } + + .el-menu-item, .el-submenu__title { + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + } + + // menu hover + .submenu-title-noDropdown, + .el-submenu__title { + &:hover { + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + & .theme-dark .is-active > .el-submenu__title { + color: $base-menu-color-active !important; + } + + & .nest-menu .el-submenu>.el-submenu__title, + & .el-submenu .el-menu-item { + min-width: $base-sidebar-width !important; + + &:hover { + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + & .theme-dark .nest-menu .el-submenu>.el-submenu__title, + & .theme-dark .el-submenu .el-menu-item { + background-color: $base-sub-menu-background !important; + + &:hover { + background-color: $base-sub-menu-hover !important; + } + } + } + + .hideSidebar { + .sidebar-container { + width: 54px !important; + } + + .main-container { + margin-left: 54px; + } + + .submenu-title-noDropdown { + padding: 0 !important; + position: relative; + + .el-tooltip { + padding: 0 !important; + + .svg-icon { + margin-left: 20px; + } + } + } + + .el-submenu { + overflow: hidden; + + &>.el-submenu__title { + padding: 0 !important; + + .svg-icon { + margin-left: 20px; + } + + } + } + + .el-menu--collapse { + .el-submenu { + &>.el-submenu__title { + &>span { + height: 0; + width: 0; + overflow: hidden; + visibility: hidden; + display: inline-block; + } + } + } + } + } + + .el-menu--collapse .el-menu .el-submenu { + min-width: $base-sidebar-width !important; + } + + // mobile responsive + .mobile { + .main-container { + margin-left: 0px; + } + + .sidebar-container { + transition: transform .28s; + width: $base-sidebar-width !important; + } + + &.hideSidebar { + .sidebar-container { + pointer-events: none; + transition-duration: 0.3s; + transform: translate3d(-$base-sidebar-width, 0, 0); + } + } + } + + .withoutAnimation { + + .main-container, + .sidebar-container { + transition: none; + } + } +} + +// when menu collapsed +.el-menu--vertical { + &>.el-menu { + .svg-icon { + margin-right: 16px; + } + } + + .nest-menu .el-submenu>.el-submenu__title, + .el-menu-item { + &:hover { + // you can use $subMenuHover + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + // the scroll bar appears when the subMenu is too long + >.el-menu--popup { + max-height: 100vh; + overflow-y: auto; + + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } + } +} diff --git a/ruoyi-ui/src/components/Header.vue b/ruoyi-ui/src/components/Header.vue new file mode 100644 index 00000000..d91fedfd --- /dev/null +++ b/ruoyi-ui/src/components/Header.vue @@ -0,0 +1,528 @@ + + + + + + diff --git a/ruoyi-ui/src/components/PageTabs.vue b/ruoyi-ui/src/components/PageTabs.vue new file mode 100644 index 00000000..f2bc80b4 --- /dev/null +++ b/ruoyi-ui/src/components/PageTabs.vue @@ -0,0 +1,222 @@ + + + + + diff --git a/ruoyi-ui/src/components/RightFence.vue b/ruoyi-ui/src/components/RightFence.vue new file mode 100644 index 00000000..d726d449 --- /dev/null +++ b/ruoyi-ui/src/components/RightFence.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/ruoyi-ui/src/layout/components/AppMain.vue b/ruoyi-ui/src/layout/components/AppMain.vue index 25d5a25a..a2bc023a 100644 --- a/ruoyi-ui/src/layout/components/AppMain.vue +++ b/ruoyi-ui/src/layout/components/AppMain.vue @@ -1,61 +1,70 @@ - - - - - - - + + + + + + + diff --git a/ruoyi-ui/src/layout/components/Sidebar/Logo.vue b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue index c8401c51..18acd318 100644 --- a/ruoyi-ui/src/layout/components/Sidebar/Logo.vue +++ b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue @@ -1,93 +1,93 @@ - - - - - + + + + + diff --git a/ruoyi-ui/src/layout/components/Sidebar/index.vue b/ruoyi-ui/src/layout/components/Sidebar/index.vue index 24fb533b..51d0839f 100644 --- a/ruoyi-ui/src/layout/components/Sidebar/index.vue +++ b/ruoyi-ui/src/layout/components/Sidebar/index.vue @@ -1,57 +1,57 @@ - - - + + + diff --git a/ruoyi-ui/src/layout/index.vue b/ruoyi-ui/src/layout/index.vue index 202cfcd6..241bfa86 100644 --- a/ruoyi-ui/src/layout/index.vue +++ b/ruoyi-ui/src/layout/index.vue @@ -1,111 +1,132 @@ - - - - - + + + + + diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js index ebd94b9d..1adcb485 100644 --- a/ruoyi-ui/src/main.js +++ b/ruoyi-ui/src/main.js @@ -1,86 +1,88 @@ -import Vue from 'vue' - -import Cookies from 'js-cookie' - -import Element from 'element-ui' -import './assets/styles/element-variables.scss' - -import '@/assets/styles/index.scss' // global css -import '@/assets/styles/ruoyi.scss' // ruoyi css -import App from './App' -import store from './store' -import router from './router' -import directive from './directive' // directive -import plugins from './plugins' // plugins -import { download } from '@/utils/request' - -import './assets/icons' // icon -import './permission' // permission control -import { getDicts } from "@/api/system/dict/data"; -import { getConfigKey } from "@/api/system/config"; -import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi"; -// 分页组件 -import Pagination from "@/components/Pagination"; -// 自定义表格工具组件 -import RightToolbar from "@/components/RightToolbar" -// 富文本组件 -import Editor from "@/components/Editor" -// 文件上传组件 -import FileUpload from "@/components/FileUpload" -// 图片上传组件 -import ImageUpload from "@/components/ImageUpload" -// 图片预览组件 -import ImagePreview from "@/components/ImagePreview" -// 字典标签组件 -import DictTag from '@/components/DictTag' -// 头部标签组件 -import VueMeta from 'vue-meta' -// 字典数据组件 -import DictData from '@/components/DictData' - -// 全局方法挂载 -Vue.prototype.getDicts = getDicts -Vue.prototype.getConfigKey = getConfigKey -Vue.prototype.parseTime = parseTime -Vue.prototype.resetForm = resetForm -Vue.prototype.addDateRange = addDateRange -Vue.prototype.selectDictLabel = selectDictLabel -Vue.prototype.selectDictLabels = selectDictLabels -Vue.prototype.download = download -Vue.prototype.handleTree = handleTree - -// 全局组件挂载 -Vue.component('DictTag', DictTag) -Vue.component('Pagination', Pagination) -Vue.component('RightToolbar', RightToolbar) -Vue.component('Editor', Editor) -Vue.component('FileUpload', FileUpload) -Vue.component('ImageUpload', ImageUpload) -Vue.component('ImagePreview', ImagePreview) - -Vue.use(directive) -Vue.use(plugins) -Vue.use(VueMeta) -DictData.install() - -/** - * If you don't want to use mock-server - * you want to use MockJs for mock api - * you can execute: mockXHR() - * - * Currently MockJs will be used in the production environment, - * please remove it before going online! ! ! - */ - -Vue.use(Element, { - size: Cookies.get('size') || 'medium' // set element-ui default size -}) - -Vue.config.productionTip = false - -new Vue({ - el: '#app', - router, - store, - render: h => h(App) -}) +import Vue from 'vue' + +import Cookies from 'js-cookie' + +import Element from 'element-ui' +import './assets/styles/element-variables.scss' + +import '@/assets/styles/index.scss' // global css +import '@/assets/styles/ruoyi.scss' // ruoyi css +import App from './App' +import store from './store' +import router from './router' +import directive from './directive' // directive +import plugins from './plugins' // plugins +import global from './plugins/global'; +import { download } from '@/utils/request' + +import './assets/icons' // icon +import './permission' // permission control +import { getDicts } from "@/api/system/dict/data"; +import { getConfigKey } from "@/api/system/config"; +import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi"; +// 分页组件 +import Pagination from "@/components/Pagination"; +// 自定义表格工具组件 +import RightToolbar from "@/components/RightToolbar" +// 富文本组件 +import Editor from "@/components/Editor" +// 文件上传组件 +import FileUpload from "@/components/FileUpload" +// 图片上传组件 +import ImageUpload from "@/components/ImageUpload" +// 图片预览组件 +import ImagePreview from "@/components/ImagePreview" +// 字典标签组件 +import DictTag from '@/components/DictTag' +// 头部标签组件 +import VueMeta from 'vue-meta' +// 字典数据组件 +import DictData from '@/components/DictData' + +// 全局方法挂载 +Vue.prototype.getDicts = getDicts +Vue.prototype.getConfigKey = getConfigKey +Vue.prototype.parseTime = parseTime +Vue.prototype.resetForm = resetForm +Vue.prototype.addDateRange = addDateRange +Vue.prototype.selectDictLabel = selectDictLabel +Vue.prototype.selectDictLabels = selectDictLabels +Vue.prototype.download = download +Vue.prototype.handleTree = handleTree +Vue.prototype.$global = global; + +// 全局组件挂载 +Vue.component('DictTag', DictTag) +Vue.component('Pagination', Pagination) +Vue.component('RightToolbar', RightToolbar) +Vue.component('Editor', Editor) +Vue.component('FileUpload', FileUpload) +Vue.component('ImageUpload', ImageUpload) +Vue.component('ImagePreview', ImagePreview) + +Vue.use(directive) +Vue.use(plugins) +Vue.use(VueMeta) +DictData.install() + +/** + * If you don't want to use mock-server + * you want to use MockJs for mock api + * you can execute: mockXHR() + * + * Currently MockJs will be used in the production environment, + * please remove it before going online! ! ! + */ + +Vue.use(Element, { + size: Cookies.get('size') || 'medium' // set element-ui default size +}) + +Vue.config.productionTip = false + +new Vue({ + el: '#app', + router, + store, + render: h => h(App) +}) diff --git a/ruoyi-ui/src/plugins/global.js b/ruoyi-ui/src/plugins/global.js new file mode 100644 index 00000000..706842d9 --- /dev/null +++ b/ruoyi-ui/src/plugins/global.js @@ -0,0 +1,473 @@ +import axios from 'axios' +const global = { + // 表单必输项 + requiredRule: { + required: true, + message: '该项为必输项!', + trigger: ['blur', 'change'], + }, + + // 文件上传接口 + uploadURL: process.env.VUE_APP_BASE_API + 'sys/file/upload', + + //影像平台接口上传接口文件 + uploadToIcon: process.env.VUE_APP_BASE_API + '/sys/file/uploadToIcon', + + //文件下载 + downLoadUrl: process.env.VUE_APP_BASE_API + 'sys/file/download?fileId=', + + // 公告文件上传接口 + uploadToIconSf: process.env.VUE_APP_BASE_API + '/sys/file/upload', + // 图片 + // getPicUrl:'/get/{value}/mg.do' + getPicUrl: process.env.VUE_APP_BASE_API + '/sys/file/get/{value}/mg.do', + + // 码值转换 + getNameByCode: (codeInfo, codeValue, isMult = false) => { + if (!codeInfo) { + return codeValue + } + if (!codeValue) { + return '' + } + if (isMult) codeValue = isMult ? codeValue.split(',') : codeValue + let codeName = '', + codeValues = [] + for (let i = 0; i < codeInfo.length; i++) { + if (Array.isArray(codeValue)) { + for (let j = 0; j < codeValue.length; j++) { + if (codeValue[j] == codeInfo[i].value) { + codeValues.push(codeInfo[i].content) + } + } + } else { + if (codeValue == codeInfo[i].value) { + codeName = codeInfo[i].content + break + } + } + codeName = codeValues.join(',') + } + return codeName == '' ? codeValue : codeName + }, + + // 分转元 + regFenToYuan: val => { + let num = Number(val) + if (!isNaN(num)) { + num = num * 0.01 + '' + let reg = num.indexOf('.') > -1 ? /(\d{1,3})(?=(?:\d{3})+\.)/g : /(\d{1,3})(?=(?:\d{3})+$)/g //千分符的正则 + return num.replace(reg, '$1,') + } else { + return null + } + }, + // 判断字符串是否为空 + isEmptyStr(str) { + if (str == '') return true + const regu = '^[ ]+$' + const re = new RegExp(regu) + return re.test(str) + }, + //文件下载/表格导出 + downloadFiles(_url, _params, _this, requestFn = 'download') { + + _this.$http[requestFn](_url, _params).then(response => { + if (_url === _this.$api.cmApi.exporAllCstInfo) { + console.log(response, 'response') + // if (response.isOK) { + // _this.$message.successs(response.msg) + // } else { + // _this.$message.error(response.msg) + // } + } else if (!response.data.code) { + let contentDisposition = response.headers['content-disposition'] + const blob = new Blob([response.data]) + + if ('download' in document.createElement('a')) { + const elink = document.createElement('a') + let fileName = decodeURI(contentDisposition.substring(contentDisposition.indexOf('filename=') + 9, contentDisposition.length)); + fileName = fileName.replace((/"/g), ""); + elink.download = fileName + elink.style.display = 'none' + elink.href = URL.createObjectURL(blob) + document.body.appendChild(elink) + elink.click() + URL.revokeObjectURL(elink.href) + document.body.removeChild(elink) + } else { + navigator.msSaveBlob(blob, fileName) + } + } else { + _this.$message.error(response.msg) + } + }) + }, + + /* 文件下载/表格导出 + * 支持影像平台下载 + */ + downloadImage(_url, _params, _this, requestFn = 'download') { + _this.$http[requestFn](_url, _params).then(response => { + if (!response.data.code) { + let fileName = response.headers['content-disposition'] + const blob = new Blob([response.data]) + if ('download' in document.createElement('a')) { + const elink = document.createElement('a') + // 公共方法不支持截取,去掉fileName两边的"" + fileName = fileName.substr(0, fileName.length - 1) + let spcStr = (fileName.split('=')[1]).substr(1) + elink.download = fileName && decodeURI(spcStr) + elink.style.display = 'none' + elink.href = URL.createObjectURL(blob) + document.body.appendChild(elink) + elink.click() + URL.revokeObjectURL(elink.href) + document.body.removeChild(elink) + } else { + navigator.msSaveBlob(blob, fileName) + } + } else { + _this.$message.error(response.msg) + } + }) + }, + /** + * 每隔几个字符进行添加对应标记 + * @param {*} str 需要添加标记的字符串 + * @param {*} vkey 标记 + * @param {*} vnum 字符个数 + */ + strReplace: (str, vnum = 2, vkey = '-') => { + if (!str) return '' + let result = '' + for (var i = 0, len = str.length; i < len; i++) { + result += str[i] + if (i % vnum == 1) result += vkey + } + if (result.slice(-1) == vkey) result = result.slice(0, -1) + return result + }, + /** + * 判断是否是数组 + */ + isArrayFn: value => { + if (typeof Array.isArray === 'function') { + return Array.isArray(value) + } else { + return Object.prototype.toString.call(value) === '[object Array]' + } + }, + /** + * isEmpty 判空 + */ + isEmpty: str => { + let flag = true + if (str != null && str != undefined) + flag = + str + .replace(/(^\s*)|(\s*$)/g, '') + .replace(/<\/?.+?>/g, '') + .replace(/[\r\n]/g, '').length > 0 ? + false : + true + return flag + }, + /** + * 时间格式化 + * @param {*} time 传入的时间 + */ + timeFamat(time) { + var newTime = new Date(time) + var year = newTime.getFullYear() //年 + var month = newTime.getMonth() + 1 //月 + var day = newTime.getDate() //日 + + var clock = year + '-' + + if (month < 10) clock += '0' + + clock += month + '-' + + if (day < 10) clock += '0' + + clock += day + + return clock + }, + /** + * 创建当前时间 + * @param {*} isTrue 精确到年、月、天标识 + */ + createTime: isTrue => { + var now = new Date() + + var year = now.getFullYear() //年 + var month = now.getMonth() + 1 //月 + var day = now.getDate() //日 + + var hh = now.getHours() //时 + var mm = now.getMinutes() //分 + var ss = now.getSeconds() //秒 + if (isTrue == 'year') return year + + var clock = year + '-' + + if (month < 10) clock += '0' + + if (isTrue == 'month') return (clock += month) + + clock += month + '-' + + if (day < 10) clock += '0' + + clock += day + + //精确到天 + if (isTrue == 'day') return clock + clock += clock + ' ' + + if (hh < 10) clock += '0' + + clock += hh + ':' + if (mm < 10) clock += '0' + clock += mm + ':' + + if (ss < 10) clock += '0' + clock += ss + return clock + }, + //加法 + NumberAdd: (arg1, arg2, n = 2) => { + var r1, r2, m + try { + r1 = arg1.toString().split('.')[1].length + } catch (e) { + r1 = 0 + } + try { + r2 = arg2.toString().split('.')[1].length + } catch (e) { + r2 = 0 + } + m = Math.pow(10, Math.max(r1, r2)) + return ((arg1 * m + arg2 * m) / m).toFixed(n) + }, + //减法 + NumberSub: (arg1, arg2) => { + var r1, r2, m, n + try { + r1 = arg1.toString().split('.')[1].length + } catch (e) { + r1 = 0 + } + try { + r2 = arg2.toString().split('.')[1].length + } catch (e) { + r2 = 0 + } + m = Math.pow(10, Math.max(r1, r2)) + //动态控制精度长度 + n = r1 >= r2 ? r1 : r2 + return ((arg1 * m - arg2 * m) / m).toFixed(n) + }, + //乘法 + NumberMul: (arg1, arg2) => { + var m = 0, + s1 = arg1.toString(), + s2 = arg2.toString() + try { + m += s1.split('.')[1].length + } catch (e) {} + try { + m += s2.split('.')[1].length + } catch (e) {} + return (Number(s1.replace('.', '')) * Number(s2.replace('.', ''))) / Math.pow(10, m) + }, + + //除法 + NumberDiv: (arg1, arg2) => { + var t1 = 0, + t2 = 0, + r1, + r2 + try { + t1 = arg1.toString().split('.')[1].length + } catch (e) {} + try { + t2 = arg2.toString().split('.')[1].length + } catch (e) {} + + r1 = Number(arg1.toString().replace('.', '')) + + r2 = Number(arg2.toString().replace('.', '')) + return (r1 / r2) * Math.pow(10, t2 - t1) + }, + + /* + 检查数组是否有重复 + keyName:数组里面的对象的属性名 + */ + isArrayRepeat: (arr, keyName) => { + let hash = {} + if (keyName) { + for (let i in arr) { + if (hash[arr[i][keyName]]) { + return true + } else { + hash[arr[i][keyName]] = true + } + } + } else { + for (let i in arr) { + if (hash[arr[i]]) { + return true + } else { + hash[arr[i]] = true + } + } + } + return false + }, + /* + 异步请求顺序执行 + _arr:方法名 + */ + async getAllFn(_arr, _this) { + for (let i = 0; i < _arr.length; i++) { + await this.getReqDataFn(_arr[i], _this) + } + }, + getReqDataFn(fn, _this) { + var p = new Promise(resolve => { + _this[fn]() + setTimeout(() => { + resolve() + }, 100) + }) + return p + }, + + /* + 格式化金额数字, 加千分位并保留两位小数 + params: num(传入的金额) + */ + formatAmountNum: num => { + if (num == 0) { + return num + } + if (!num) { + return + } + num = num + '' + if (!num.includes('.')) { + num += '.' + } + return num + .replace(/(\d)(?=(\d{3})+\.)/g, function ($0, $1) { + return $1 + ',' + }) + .replace(/\.$/, '.00') + }, + /** + * 时间比较大小 + */ + compareDate: (sDate, eDate, isSame = false) => { + let st = new Date(sDate) + let et = new Date(eDate) + let flag = !st && !et ? false : st.getTime() >= et.getTime() ? false : true + if (isSame) flag = !st && !et ? false : st.getTime() > et.getTime() ? false : true + return flag + }, + /** + * 手机号码验证 + */ + checkPhoneFn: (mobile) => { + let reg = /^0?(13[0-9]|14[5-9]|15[012356789]|166|17[0-8]|18[0-9]|19[0-9])[0-9]{8}$/; + return reg.test(mobile) + }, + /** + * 将指定日期区间按月份分割 + * @param {Object} beginDate 开始日期 + * @param {Object} endDate 结束日期 + * @return {Array} 分割好的array数组 + */ + dateCutByMonth(beginDate, endDate) { + //分割好的数组 + let dateCutList = new Array(); + let b_date = new Date(beginDate); + let e_date = new Date(endDate); + //获取各个年份 + let b_year = parseInt(b_date.getFullYear()); + let e_year = parseInt(e_date.getFullYear()); + //获取各个月份 + let b_month = parseInt(b_date.getMonth()) + 1; + let e_month = parseInt(e_date.getMonth()) + 1; + + //获取日期之间相差的月数 + let month_list = monthList(); + + //按月份分割日期 + for (let i = 0; i < month_list.length; i++) { + //当前月开始日期:第一天 + let i_b_date = new Date(month_list[i]); + i_b_date.setDate(1); + //当前月最后一天 + let i_e_date = new Date(month_list[i]); + i_e_date.setMonth(i_e_date.getMonth() + 1); + i_e_date.setDate(1); + i_e_date.setDate(i_e_date.getDate() - 1); + + //第一次循环:开始月份 + if (i == 0) { + let i_e_ymd = dateToString(i_e_date); + dateCutList.push([beginDate, i_e_ymd]); + + //除第一次和最后一次循环:中间月份 + } else if (i != 0 && i != month_list.length - 1) { + let i_b_ymd = dateToString(i_b_date); + let i_e_ymd = dateToString(i_e_date); + dateCutList.push([i_b_ymd, i_e_ymd]); + //最后一次循环:结束月份 + } else if (i == month_list.length - 1) { + let i_b_ymd = dateToString(i_b_date); + dateCutList.push([i_b_ymd, endDate]); + } + } + return dateCutList; + /** + * 获取日期区间的月份集合 + */ + function monthList() { + //相差的月份总数 + let result = new Array(); + + let b = new Date(b_year, b_month - 1, 1); + let e = new Date(e_year, e_month - 1, 1); + while (b < e) { + result.push(b.getFullYear() + "-" + (b.getMonth() + 1)); + b.setMonth(b.getMonth() + 1); + } + result.push(e_year + "-" + e_month); + return result; + } + /** + * 将日期转换为指定格式的字符串 + * @param {Date} date 要转换的日期 + */ + function dateToString(date) { + let month = (date.getMonth() + 1); + let day = date.getDate(); + if (month < 10) { + month = '0' + month + } + if (day < 10) { + day = '0' + day + } + return date.getFullYear() + "-" + (month) + "-" + day; + } + + }, +} + +export default global \ No newline at end of file diff --git a/ruoyi-ui/src/plugins/waterMark.js b/ruoyi-ui/src/plugins/waterMark.js new file mode 100644 index 00000000..0bb70494 --- /dev/null +++ b/ruoyi-ui/src/plugins/waterMark.js @@ -0,0 +1,32 @@ +let style +let clearWaterMark = () => { + if (style) style.remove +} +export default function createWaterMark(str,_height) { + clearWaterMark() + if (!str) return + let width = window.parseInt(document.body.clientWidth), + canvasWidth = width / window.parseInt(width / 400), + fontFamily = window.getComputedStyle(document.body)['font-family'], + canvas = document.createElement('canvas') + canvas.width = canvasWidth + canvas.height = 200 + let cxt = canvas.getContext('2d') + cxt.rotate((-20 * Math.PI) / 180) + cxt.font = `18px${fontFamily}` + cxt.fillStyle = 'rgba(8,8,8,0.2)' + cxt.fillText(str, 50, 200) + let imgSrc = canvas.toDataURL('image/png') + style = document.createElement('style') + style.innerHTML = `.with-watermark:before{ + content:""; + width:100%; + pointer-events:none; + height:${_height}px; + display:block; + position:absolute; + z-index:99999; + background-image:url("${imgSrc}") + }` + ;(document.head.append || document.head.appendChild).apply(document.head, [style]) +} diff --git a/ruoyi-ui/src/store/modules/user.js b/ruoyi-ui/src/store/modules/user.js index 262de9b0..816d5b49 100644 --- a/ruoyi-ui/src/store/modules/user.js +++ b/ruoyi-ui/src/store/modules/user.js @@ -1,115 +1,115 @@ -import { login, logout, getInfo, refreshToken } from '@/api/login' -import { getToken, setToken, setExpiresIn, removeToken } from '@/utils/auth' - -const user = { - state: { - token: getToken(), - name: '', - avatar: '', - roles: [], - permissions: [] - }, - - mutations: { - SET_TOKEN: (state, token) => { - state.token = token - }, - SET_EXPIRES_IN: (state, time) => { - state.expires_in = time - }, - SET_NAME: (state, name) => { - state.name = name - }, - SET_AVATAR: (state, avatar) => { - state.avatar = avatar - }, - SET_ROLES: (state, roles) => { - state.roles = roles - }, - SET_PERMISSIONS: (state, permissions) => { - state.permissions = permissions - } - }, - - actions: { - // 登录 - Login({ commit }, userInfo) { - const username = userInfo.username.trim() - const password = userInfo.password - const code = userInfo.code - const uuid = userInfo.uuid - return new Promise((resolve, reject) => { - login(username, password, code, uuid).then(res => { - let data = res.data - setToken(data.access_token) - commit('SET_TOKEN', data.access_token) - setExpiresIn(data.expires_in) - commit('SET_EXPIRES_IN', data.expires_in) - resolve() - }).catch(error => { - reject(error) - }) - }) - }, - - // 获取用户信息 - GetInfo({ commit, state }) { - return new Promise((resolve, reject) => { - getInfo().then(res => { - const user = res.user - const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : user.avatar; - if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 - commit('SET_ROLES', res.roles) - commit('SET_PERMISSIONS', res.permissions) - } else { - commit('SET_ROLES', ['ROLE_DEFAULT']) - } - commit('SET_NAME', user.userName) - commit('SET_AVATAR', avatar) - resolve(res) - }).catch(error => { - reject(error) - }) - }) - }, - - // 刷新token - RefreshToken({commit, state}) { - return new Promise((resolve, reject) => { - refreshToken(state.token).then(res => { - setExpiresIn(res.data) - commit('SET_EXPIRES_IN', res.data) - resolve() - }).catch(error => { - reject(error) - }) - }) - }, - - // 退出系统 - LogOut({ commit, state }) { - return new Promise((resolve, reject) => { - logout(state.token).then(() => { - commit('SET_TOKEN', '') - commit('SET_ROLES', []) - commit('SET_PERMISSIONS', []) - removeToken() - resolve() - }).catch(error => { - reject(error) - }) - }) - }, - - // 前端 登出 - FedLogOut({ commit }) { - return new Promise(resolve => { - commit('SET_TOKEN', '') - removeToken() - resolve() - }) - } - } -} - -export default user +import { login, logout, getInfo, refreshToken } from '@/api/login' +import { getToken, setToken, setExpiresIn, removeToken } from '@/utils/auth' + +const user = { + state: { + token: getToken(), + name: '', + avatar: '', + roles: [], + permissions: [] + }, + + mutations: { + SET_TOKEN: (state, token) => { + state.token = token + }, + SET_EXPIRES_IN: (state, time) => { + state.expires_in = time + }, + SET_NAME: (state, name) => { + state.name = name + }, + SET_AVATAR: (state, avatar) => { + state.avatar = avatar + }, + SET_ROLES: (state, roles) => { + state.roles = roles + }, + SET_PERMISSIONS: (state, permissions) => { + state.permissions = permissions + } + }, + + actions: { + // 登录 + Login({ commit }, userInfo) { + const username = userInfo.username.trim() + const password = userInfo.password + const code = userInfo.code + const uuid = userInfo.uuid + return new Promise((resolve, reject) => { + login(username, password, code, uuid).then(res => { + let data = res.data + setToken(data.access_token) + commit('SET_TOKEN', data.access_token) + setExpiresIn(data.expires_in) + commit('SET_EXPIRES_IN', data.expires_in) + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + + // 获取用户信息 + GetInfo({ commit, state }) { + return new Promise((resolve, reject) => { + getInfo().then(res => { + const user = res.user + const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : user.avatar; + if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 + commit('SET_ROLES', res.roles) + commit('SET_PERMISSIONS', res.permissions) + } else { + commit('SET_ROLES', ['ROLE_DEFAULT']) + } + commit('SET_NAME', user.userName) + commit('SET_AVATAR', avatar) + resolve(res) + }).catch(error => { + reject(error) + }) + }) + }, + + // 刷新token + RefreshToken({commit, state}) { + return new Promise((resolve, reject) => { + refreshToken(state.token).then(res => { + setExpiresIn(res.data) + commit('SET_EXPIRES_IN', res.data) + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + + // 退出系统 + LogOut({ commit, state }) { + return new Promise((resolve, reject) => { + logout(state.token).then(() => { + commit('SET_TOKEN', '') + commit('SET_ROLES', []) + commit('SET_PERMISSIONS', []) + removeToken() + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + + // 前端 登出 + FedLogOut({ commit }) { + return new Promise(resolve => { + commit('SET_TOKEN', '') + removeToken() + resolve() + }) + } + } +} + +export default user diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue index 1fe06763..16ad6d1e 100644 --- a/ruoyi-ui/src/views/index.vue +++ b/ruoyi-ui/src/views/index.vue @@ -1,875 +1,98 @@ - - - - - - + + + + + diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue index 074fecd3..b19d81eb 100644 --- a/ruoyi-ui/src/views/login.vue +++ b/ruoyi-ui/src/views/login.vue @@ -1,219 +1,219 @@ - - - - - + + + + + diff --git a/ruoyi-ui/src/views/register.vue b/ruoyi-ui/src/views/register.vue index d8ec3c18..b6f752b9 100644 --- a/ruoyi-ui/src/views/register.vue +++ b/ruoyi-ui/src/views/register.vue @@ -1,209 +1,209 @@ - - - - - + + + + + diff --git a/ruoyi-ui/src/views/system/dept/index.vue b/ruoyi-ui/src/views/system/org/index.vue similarity index 75% rename from ruoyi-ui/src/views/system/dept/index.vue rename to ruoyi-ui/src/views/system/org/index.vue index 486c56cc..585a7f93 100644 --- a/ruoyi-ui/src/views/system/dept/index.vue +++ b/ruoyi-ui/src/views/system/org/index.vue @@ -1,336 +1,336 @@ - - - + + + diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue index 0681d3d2..65efa569 100644 --- a/ruoyi-ui/src/views/system/role/index.vue +++ b/ruoyi-ui/src/views/system/role/index.vue @@ -1,607 +1,607 @@ - - - \ No newline at end of file + + + diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue index 2494fa24..04bc0f06 100644 --- a/ruoyi-ui/src/views/system/user/index.vue +++ b/ruoyi-ui/src/views/system/user/index.vue @@ -1,669 +1,669 @@ - - - \ No newline at end of file + + + diff --git a/ruoyi-ui/src/views/system/user/profile/index.vue b/ruoyi-ui/src/views/system/user/profile/index.vue index ad530f9a..5683d4dd 100644 --- a/ruoyi-ui/src/views/system/user/profile/index.vue +++ b/ruoyi-ui/src/views/system/user/profile/index.vue @@ -24,8 +24,8 @@
{{ user.email }}
  • - 所属部门 -
    {{ user.dept.deptName }} / {{ postGroup }}
    + 所属机构 +
    {{ user.sysOrg.orgName }} / {{ postGroup }}
  • 所属角色 diff --git a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue index bf6382d3..d97e675c 100644 --- a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue +++ b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue @@ -1,299 +1,299 @@ - - - + + + diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js index 2506c93a..3b1bbe12 100644 --- a/ruoyi-ui/vue.config.js +++ b/ruoyi-ui/vue.config.js @@ -1,136 +1,136 @@ -'use strict' -const path = require('path') - -function resolve(dir) { - return path.join(__dirname, dir) -} - -const CompressionPlugin = require('compression-webpack-plugin') - -const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题 - -const port = process.env.port || process.env.npm_config_port || 80 // 端口 - -// vue.config.js 配置说明 -//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions -// 这里只列一部分,具体配置参考文档 -module.exports = { - // 部署生产环境和开发环境下的URL。 - // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 - // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 - publicPath: process.env.NODE_ENV === "production" ? "/" : "/", - // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist) - outputDir: 'dist', - // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下) - assetsDir: 'static', - // 是否开启eslint保存检测,有效值:ture | false | 'error' - lintOnSave: process.env.NODE_ENV === 'development', - // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 - productionSourceMap: false, - // webpack-dev-server 相关配置 - devServer: { - host: '0.0.0.0', - port: port, - open: true, - proxy: { - // detail: https://cli.vuejs.org/config/#devserver-proxy - [process.env.VUE_APP_BASE_API]: { - target: `http://localhost:8080`, - changeOrigin: true, - pathRewrite: { - ['^' + process.env.VUE_APP_BASE_API]: '' - } - } - }, - disableHostCheck: true - }, - css: { - loaderOptions: { - sass: { - sassOptions: { outputStyle: "expanded" } - } - } - }, - configureWebpack: { - name: name, - resolve: { - alias: { - '@': resolve('src') - } - }, - plugins: [ - // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 - new CompressionPlugin({ - cache: false, // 不启用文件缓存 - test: /\.(js|css|html)?$/i, // 压缩文件格式 - filename: '[path].gz[query]', // 压缩后的文件名 - algorithm: 'gzip', // 使用gzip压缩 - minRatio: 0.8 // 压缩率小于1才会压缩 - }) - ], - }, - chainWebpack(config) { - config.plugins.delete('preload') // TODO: need test - config.plugins.delete('prefetch') // TODO: need test - - // set svg-sprite-loader - config.module - .rule('svg') - .exclude.add(resolve('src/assets/icons')) - .end() - config.module - .rule('icons') - .test(/\.svg$/) - .include.add(resolve('src/assets/icons')) - .end() - .use('svg-sprite-loader') - .loader('svg-sprite-loader') - .options({ - symbolId: 'icon-[name]' - }) - .end() - - config - .when(process.env.NODE_ENV !== 'development', - config => { - config - .plugin('ScriptExtHtmlWebpackPlugin') - .after('html') - .use('script-ext-html-webpack-plugin', [{ - // `runtime` must same as runtimeChunk name. default is `runtime` - inline: /runtime\..*\.js$/ - }]) - .end() - config - .optimization.splitChunks({ - chunks: 'all', - cacheGroups: { - libs: { - name: 'chunk-libs', - test: /[\\/]node_modules[\\/]/, - priority: 10, - chunks: 'initial' // only package third parties that are initially dependent - }, - elementUI: { - name: 'chunk-elementUI', // split elementUI into a single package - priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app - test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm - }, - commons: { - name: 'chunk-commons', - test: resolve('src/components'), // can customize your rules - minChunks: 3, // minimum common number - priority: 5, - reuseExistingChunk: true - } - } - }) - config.optimization.runtimeChunk('single'), - { - from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件 - to: './' //到根目录下 - } - } - ) - } -} +'use strict' +const path = require('path') + +function resolve(dir) { + return path.join(__dirname, dir) +} + +const CompressionPlugin = require('compression-webpack-plugin') + +const name = process.env.VUE_APP_TITLE || '智能作业系统' // 网页标题 + +const port = process.env.port || process.env.npm_config_port || 80 // 端口 + +// vue.config.js 配置说明 +//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions +// 这里只列一部分,具体配置参考文档 +module.exports = { + // 部署生产环境和开发环境下的URL。 + // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 + // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 + publicPath: process.env.NODE_ENV === "production" ? "/" : "/", + // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist) + outputDir: 'dist', + // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下) + assetsDir: 'static', + // 是否开启eslint保存检测,有效值:ture | false | 'error' + lintOnSave: process.env.NODE_ENV === 'development', + // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 + productionSourceMap: false, + // webpack-dev-server 相关配置 + devServer: { + host: '0.0.0.0', + port: port, + open: true, + proxy: { + // detail: https://cli.vuejs.org/config/#devserver-proxy + [process.env.VUE_APP_BASE_API]: { + target: `http://localhost:9998`, + changeOrigin: true, + pathRewrite: { + ['^' + process.env.VUE_APP_BASE_API]: '' + } + } + }, + disableHostCheck: true + }, + css: { + loaderOptions: { + sass: { + sassOptions: { outputStyle: "expanded" } + } + } + }, + configureWebpack: { + name: name, + resolve: { + alias: { + '@': resolve('src') + } + }, + plugins: [ + // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 + new CompressionPlugin({ + cache: false, // 不启用文件缓存 + test: /\.(js|css|html)?$/i, // 压缩文件格式 + filename: '[path].gz[query]', // 压缩后的文件名 + algorithm: 'gzip', // 使用gzip压缩 + minRatio: 0.8 // 压缩率小于1才会压缩 + }) + ], + }, + chainWebpack(config) { + config.plugins.delete('preload') // TODO: need test + config.plugins.delete('prefetch') // TODO: need test + + // set svg-sprite-loader + config.module + .rule('svg') + .exclude.add(resolve('src/assets/icons')) + .end() + config.module + .rule('icons') + .test(/\.svg$/) + .include.add(resolve('src/assets/icons')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ + symbolId: 'icon-[name]' + }) + .end() + + config + .when(process.env.NODE_ENV !== 'development', + config => { + config + .plugin('ScriptExtHtmlWebpackPlugin') + .after('html') + .use('script-ext-html-webpack-plugin', [{ + // `runtime` must same as runtimeChunk name. default is `runtime` + inline: /runtime\..*\.js$/ + }]) + .end() + config + .optimization.splitChunks({ + chunks: 'all', + cacheGroups: { + libs: { + name: 'chunk-libs', + test: /[\\/]node_modules[\\/]/, + priority: 10, + chunks: 'initial' // only package third parties that are initially dependent + }, + elementUI: { + name: 'chunk-elementUI', // split elementUI into a single package + priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app + test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm + }, + commons: { + name: 'chunk-commons', + test: resolve('src/components'), // can customize your rules + minChunks: 3, // minimum common number + priority: 5, + reuseExistingChunk: true + } + } + }) + config.optimization.runtimeChunk('single'), + { + from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件 + to: './' //到根目录下 + } + } + ) + } +}