Initial commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
@@ -0,0 +1,45 @@
|
||||
[*]
|
||||
charset=utf-8
|
||||
end_of_line=crlf
|
||||
insert_final_newline=false
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl}]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[{.babelrc,.stylelintrc,jest.config,.eslintrc,.prettierrc,*.json,*.jsb3,*.jsb2,*.bowerrc}]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[*.svg]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[*.js.map]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[*.less]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[*.vue]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
[{.analysis_options,*.yml,*.yaml}]
|
||||
indent_style=space
|
||||
indent_size=2
|
||||
|
||||
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
@@ -0,0 +1,6 @@
|
||||
NODE_ENV=production
|
||||
VUE_APP_PLATFORM_NAME=JeroBoot 企业级快速开发平台
|
||||
VUE_APP_SSO=false
|
||||
VUE_TAG_FLAG=0
|
||||
VUE_APP_LOGIN_PAGE='/user/login'
|
||||
VUE_APP_CURRENT_SYSTEM='inner'
|
||||
@@ -0,0 +1,4 @@
|
||||
NODE_ENV=development
|
||||
VUE_APP_TAG_FLAG=0
|
||||
VUE_APP_LOGIN_PAGE='/user/login'
|
||||
VUE_APP_CURRENT_SYSTEM='inner'
|
||||
@@ -0,0 +1,4 @@
|
||||
NODE_ENV=production
|
||||
VUE_APP_TAG_FLAG=1
|
||||
VUE_APP_LOGIN_PAGE='https://iam-uat.sinotruk.com:7011/idp/oauth2/authorize?redirect_uri=http://laws-test.sinotruk.com/dashboard/analysis&state=123&client_id=SRMS&response_type=code'
|
||||
VUE_APP_CURRENT_SYSTEM='IAM'
|
||||
@@ -0,0 +1,7 @@
|
||||
NODE_ENV=production
|
||||
VUE_APP_API_BASE_URL=http://boot.jero.com:8080/laws-sinotruk
|
||||
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
|
||||
VUE_APP_ONLINE_BASE_URL=http://fileview.jero.com/onlinePreview
|
||||
VUE_APP_TAG_FLAG=1
|
||||
VUE_APP_LOGIN_PAGE='/user/login'
|
||||
VUE_APP_CURRENT_SYSTEM='inner'
|
||||
@@ -0,0 +1,3 @@
|
||||
/dist
|
||||
/public
|
||||
/node_modules
|
||||
@@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true
|
||||
},
|
||||
'extends': [
|
||||
'plugin:vue/essential',
|
||||
'@vue/standard'
|
||||
],
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
},
|
||||
rules: {
|
||||
'quotes': [2, 'single', {
|
||||
'avoidEscape': true,
|
||||
'allowTemplateLiterals': true
|
||||
}],
|
||||
'semi': [2, 'never'],
|
||||
'prefer-promise-reject-errors': 'warn'
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,24 @@
|
||||
# laws_sinotruk_mobile
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"baseUrl": "./",
|
||||
"moduleResolution": "node",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
}
|
||||
}
|
||||
Generated
+13598
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "laws_sinotruk_mobile",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"core-js": "^3.8.3",
|
||||
"jsencrypt": "^3.0.0-rc.1",
|
||||
"md5": "^2.2.1",
|
||||
"vant": "^2.13.2",
|
||||
"vue": "^2.6.14",
|
||||
"vue-i18n": "^8.7.0",
|
||||
"vue-ls": "^3.2.0",
|
||||
"vue-router": "^3.5.1",
|
||||
"vuex": "^3.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.12.16",
|
||||
"@babel/eslint-parser": "^7.12.16",
|
||||
"@vue/cli-plugin-babel": "~5.0.0",
|
||||
"@vue/cli-plugin-eslint": "~4.2.3",
|
||||
"@vue/cli-plugin-router": "~5.0.0",
|
||||
"@vue/cli-plugin-vuex": "~5.0.0",
|
||||
"@vue/cli-service": "~5.0.0",
|
||||
"@vue/eslint-config-standard": "^5.1.0",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"compression-webpack-plugin": "^10.0.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-import": "^2.20.1",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^6.1.2",
|
||||
"less": "^3.9.0",
|
||||
"less-loader": "^4.1.0",
|
||||
"vue-template-compiler": "^2.6.14"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* 防止打包部署时路径被写死
|
||||
*/
|
||||
window._CONFIG = {}
|
||||
window._CONFIG.domianURL = '/laws-sinotruk' // 路由转发 devServer
|
||||
window._CONFIG.domianWebSocketURL = 'http://localhost:8184/laws-sinotruk'
|
||||
// 单点登录地址
|
||||
window._CONFIG.staticDomainURL = window._CONFIG.domianURL + '/sys/common/download'
|
||||
window._CONFIG.pdfDomainURL = window._CONFIG.domianURL + '/sys/common/pdf/pdfPreviewIframe'
|
||||
window._CONFIG.casPrefixUrl = 'http://cas.example.org:8443/cas'
|
||||
// 预览文件地址
|
||||
window._CONFIG.onlinePreviewDomainURL = 'http://127.0.0.1:8012/onlinePreview'
|
||||
// onlyOffice前端服务地址
|
||||
window._CONFIG.onlyOfficeUrl = 'http://127.0.0.1:8080'
|
||||
// onlyOffice下载文件地址(暂时没用)
|
||||
window._CONFIG.onlyOfficeDownloadFileUrl = 'http://localhost:8184/sys/common/download'
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0, maximum-scale=1, minimum-scale=1, user-scalable=no">
|
||||
<!-- <link rel="icon" href="<%= BASE_URL %>favicon.ico">-->
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<style>
|
||||
:root {
|
||||
font-size: calc(100vw / 10);
|
||||
}
|
||||
</style>
|
||||
<script src="<%= BASE_URL %>api_address_config.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<van-nav-bar
|
||||
v-if="hasNavBar"
|
||||
:title="pageTitle"
|
||||
:left-text="hasBack ? $t('back') : ''"
|
||||
:left-arrow="hasBack"
|
||||
:right-text="isChinese ? $t('chinese') : $t('english')"
|
||||
@click-left="handleBack"
|
||||
@click-right="handleChangeLang"
|
||||
/>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Vue from 'vue'
|
||||
import { Locale } from 'vant'
|
||||
import zhCN from 'vant/es/locale/lang/zh-CN'
|
||||
import enUS from 'vant/es/locale/lang/en-US'
|
||||
|
||||
const ZH = 'zh-CN'
|
||||
const EN = 'en-US'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
data () {
|
||||
return {
|
||||
currentLang: ZH
|
||||
}
|
||||
},
|
||||
created () {
|
||||
// 默认中文
|
||||
Vue.ls.set('language', ZH, 7 * 24 * 60 * 60 * 1000)
|
||||
Locale.use('zh-CN', zhCN)
|
||||
this.$i18n.locale = ZH
|
||||
},
|
||||
computed: {
|
||||
// 是否中文
|
||||
isChinese () {
|
||||
return this.currentLang === ZH
|
||||
},
|
||||
// 是否显示导航
|
||||
hasNavBar () {
|
||||
return this.$route.meta.hasNavBar
|
||||
},
|
||||
// 是否显示返回
|
||||
hasBack () {
|
||||
return this.$route.meta.hasBack
|
||||
},
|
||||
// 导航标题(国际化)
|
||||
pageTitle () {
|
||||
if (!this.$route.meta.pageTitle) {
|
||||
return ''
|
||||
}
|
||||
return this.$t('pageTitle.' + this.$route.meta.pageTitle)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 返回上一层
|
||||
handleBack () {
|
||||
this.$router.go(-1)
|
||||
},
|
||||
// 切换语言
|
||||
handleChangeLang () {
|
||||
// 如果是中文就切换英文,否则切换中文
|
||||
const targetLang = this.isChinese ? EN : ZH
|
||||
const vantLang = this.isChinese ? enUS : zhCN
|
||||
// 更新响应式
|
||||
this.currentLang = targetLang
|
||||
// 更新本地存储
|
||||
Vue.ls.set('language', targetLang, 7 * 24 * 60 * 60 * 1000)
|
||||
// 更新vant语言
|
||||
Locale.use(targetLang, vantLang)
|
||||
// 更新i18n语言
|
||||
this.$i18n.locale = targetLang
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
</style>
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
import { getAction, httpAction, postAction, putAction } from '@/api/manage'
|
||||
import Vue from 'vue'
|
||||
import { UI_CACHE_DB_DICT_DATA } from '@/store/mutation-types'
|
||||
|
||||
// 角色管理
|
||||
const addRole = (params) => postAction('/sys/role/add', params)
|
||||
const editRole = (params) => postAction('/sys/role/edit', params)
|
||||
const checkRoleCode = (params) => getAction('/sys/role/checkRoleCode', params)
|
||||
const queryall = (params) => getAction('/sys/role/queryall', params)
|
||||
|
||||
// 用户管理
|
||||
const addUser = (params) => postAction('/sys/user/add', params)
|
||||
const editUser = (params) => postAction('/sys/user/edit', params)
|
||||
const queryUserRole = (params) => getAction('/sys/user/queryUserRole', params)
|
||||
const getUserList = (params) => getAction('/sys/user/page', params)
|
||||
const frozenBatch = (params) => postAction('/sys/user/frozenBatch', params)
|
||||
// 验证用户是否存在
|
||||
const checkOnlyUser = (params) => getAction('/sys/user/checkOnlyUser', params)
|
||||
// 改变密码
|
||||
const changePassword = (params) => postAction('/sys/user/changePassword', params)
|
||||
// 单点登录获取用户信息
|
||||
const getSSOUserInfo = (params) => postAction('/iam/loginByOauth2', params)
|
||||
|
||||
// 权限管理
|
||||
const addPermission = (params) => postAction('/sys/permission/add', params)
|
||||
const editPermission = (params) => postAction('/sys/permission/edit', params)
|
||||
const getPermissionList = (params) => getAction('/sys/permission/page', params)
|
||||
const getSystemMenuList = (params) => getAction('/sys/permission/getSystemMenuList', params)
|
||||
const getSystemSubmenu = (params) => getAction('/sys/permission/getSystemSubmenu', params)
|
||||
const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
|
||||
const queryTreeList = (params) => getAction('/sys/permission/queryTreeList', params)
|
||||
const queryTreeListForRole = (params) => getAction('/sys/role/queryTreeList', params)
|
||||
const queryListAsync = (params) => getAction('/sys/permission/queryListAsync', params)
|
||||
const queryRolePermission = (params) => getAction('/sys/permission/queryRolePermission', params)
|
||||
const saveRolePermission = (params) => postAction('/sys/permission/saveRolePermission', params)
|
||||
const queryPermissionsByUser = () => getAction('/sys/permission/getUserPermissionByToken')
|
||||
const loadAllRoleIds = (params) => getAction('/sys/permission/loadAllRoleIds', params)
|
||||
const getPermissionRuleList = (params) => getAction('/sys/permission/getPermRuleListByPermId', params)
|
||||
const queryPermissionRule = (params) => getAction('/sys/permission/queryPermissionRule', params)
|
||||
|
||||
// 部门管理
|
||||
const queryDepartTreeList = (params) => getAction('/sys/sysDepart/queryTreeList', params)
|
||||
const queryDepartTreeSync = (params) => getAction('/sys/sysDepart/queryDepartTreeSync', params)
|
||||
const queryIdTree = (params) => getAction('/sys/sysDepart/queryIdTree', params)
|
||||
const queryParentName = (params) => getAction('/sys/sysDepart/queryParentName', params)
|
||||
const searchByKeywords = (params) => getAction('/sys/sysDepart/searchBy', params)
|
||||
const deleteByDepartId = (params) => postAction('/sys/sysDepart/delete', params)
|
||||
|
||||
// 二级部门管理
|
||||
const queryDepartPermission = (params) => getAction('/sys/permission/queryDepartPermission', params)
|
||||
const saveDepartPermission = (params) => postAction('/sys/permission/saveDepartPermission', params)
|
||||
const queryTreeListForDeptRole = (params) => getAction('/sys/sysDepartPermission/queryTreeListForDeptRole', params)
|
||||
const queryDeptRolePermission = (params) => getAction('/sys/sysDepartPermission/queryDeptRolePermission', params)
|
||||
const queryMyDepartTreeList = (params) => getAction('/sys/sysDepart/queryMyDeptTreeList', params)
|
||||
|
||||
// 日志管理
|
||||
const deleteLog = (params) => postAction('/sys/log/delete', params)
|
||||
const deleteLogList = (params) => postAction('/sys/log/deleteBatch', params)
|
||||
|
||||
// 数据字典
|
||||
const addDict = (params) => postAction('/sys/dict/add', params)
|
||||
const editDict = (params) => postAction('/sys/dict/edit', params)
|
||||
const treeList = (params) => getAction('/sys/dict/treeList', params)
|
||||
const queryDictName = (params) => getAction('/sys/dict/queryDictName', params)
|
||||
const addDictItem = (params) => postAction('/sys/dictItem/add', params)
|
||||
const editDictItem = (params) => postAction('/sys/dictItem/edit', params)
|
||||
// 获得数据字典的树形格式数据
|
||||
const getDictTreeList = (params) => getAction('/sys/dictItem/treeList', params)
|
||||
// 获取能在form中使用的数据字典树形格式数据
|
||||
const getFormDictTreeList = (params) => getAction('/sys/dictItem/treeListOption', params)
|
||||
// 通过code值获取字典数据
|
||||
const getDictByCode = (params) => getAction('/sys/dictItem/listByCodes', params)
|
||||
|
||||
// 字典标签专用(通过code获取字典数组)
|
||||
export const ajaxGetDictItems = (code, params) => getAction(`/sys/dict/getDictItems/${code}`, params)
|
||||
|
||||
// 从缓存中获取字典配置
|
||||
function getDictItemsFromCache (dictCode) {
|
||||
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode] && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode].length > 0) {
|
||||
return Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]
|
||||
}
|
||||
}
|
||||
|
||||
// 系统通告
|
||||
const doReleaseData = (params) => getAction('/sys/annountCement/doReleaseData', params)
|
||||
const doReovkeData = (params) => getAction('/sys/annountCement/doReovkeData', params)
|
||||
// 获取系统访问量
|
||||
const getLoginfo = (params) => getAction('/sys/loginfo', params)
|
||||
const getVisitInfo = (params) => getAction('/sys/visitInfo', params)
|
||||
|
||||
// 根据部门主键查询用户信息
|
||||
const queryUserByDepId = (params) => getAction('/sys/user/queryUserByDepId', params)
|
||||
|
||||
// 重复校验
|
||||
const duplicateCheck = (params) => getAction('/sys/duplicate/check', params)
|
||||
// 加载分类字典
|
||||
const loadCategoryData = (params) => getAction('/sys/category/loadAllData', params)
|
||||
const checkRuleByCode = (params) => getAction('/sys/checkRule/checkByCode', params)
|
||||
// 加载我的通告信息
|
||||
const getUserNoticeInfo = (params) => getAction('/sys/sysAnnouncementSend/getMyAnnouncementSend', params)
|
||||
const getTransitURL = url => `/sys/common/transitRESTful?url=${encodeURIComponent(url)}`
|
||||
// 中转HTTP请求
|
||||
export const transitRESTful = {
|
||||
get: (url, parameter) => getAction(getTransitURL(url), parameter),
|
||||
post: (url, parameter) => postAction(getTransitURL(url), parameter),
|
||||
put: (url, parameter) => putAction(getTransitURL(url), parameter),
|
||||
http: (url, parameter) => httpAction(getTransitURL(url), parameter)
|
||||
}
|
||||
|
||||
// 标签管理- 展示区域查询接口
|
||||
const getShowAreaData = (params) => getAction('/tag/LawsArea/queryShowArea', params)
|
||||
// 标签管理-展示区域管理-新增
|
||||
const addAreaData = (params) => postAction('/tag/LawsArea/add', params)
|
||||
// 标签管理-展示区域管理-编辑
|
||||
const editAreaData = (params) => postAction('/tag/LawsArea/edit', params)
|
||||
|
||||
// 标签管理- 新增
|
||||
const addTag = (params) => postAction('/tag/lawsTag/add', params)
|
||||
// 标签管理- 编辑
|
||||
const editTag = (params) => postAction('/tag/lawsTag/edit', params)
|
||||
// 标签内容管理- 新增
|
||||
const addCategoryItem = (params) => postAction('/sys/category/add', params)
|
||||
const editCategoryItem = (params) => postAction('/sys/category/edit', params)
|
||||
|
||||
// 通过文件的id获取文件的相应信息
|
||||
const getFileInfo = (params) => getAction('/sys/oss/file/queryById', params)
|
||||
|
||||
// 标准选择框,分页查询标准数据
|
||||
const getStandardList = (params) => getAction('/laws/standard/common/getManyStandardSelectionBox', params)
|
||||
|
||||
// 内部工作组,左侧树查询
|
||||
const getWorkGroupTreeList = (params) => getAction('/sys/lawsWorkingGroup/list', params)
|
||||
|
||||
// 企业级别映射管理,获取列表
|
||||
const getEnterpriseLevelMapList = (params) => getAction('/sys/lawsGrade/list', params)
|
||||
|
||||
// ASMS接口管理-新增
|
||||
const addAsmsInterface = (params) => postAction('/docking/asms/api/lawsAsmsOpenApi/add', params)
|
||||
// ASMS接口管理-编辑
|
||||
const editAsmsInterface = (params) => postAction('/docking/asms/api/lawsAsmsOpenApi/edit', params)
|
||||
// ASMS接口管理-查看
|
||||
const getAsmsInterfaceById = (params) => getAction('/docking/asms/api/lawsAsmsOpenApi/getInfoById', params)
|
||||
// ASMS接口管理-同步
|
||||
const syncAsmsInterface = (params) => getAction('/docking/asms/api/lawsAsmsOpenApi/syncBatch', params)
|
||||
// ASMS接口管理-删除字典配置项
|
||||
const batchDelDictItemAsmsInterface = (params) => getAction('/docking/asms/api/lawsAsmsOpenApi/removeDictItemBatch', params)
|
||||
|
||||
export {
|
||||
addRole,
|
||||
editRole,
|
||||
checkRoleCode,
|
||||
addUser,
|
||||
editUser,
|
||||
queryUserRole,
|
||||
getUserList,
|
||||
queryall,
|
||||
frozenBatch,
|
||||
checkOnlyUser,
|
||||
changePassword,
|
||||
getPermissionList,
|
||||
addPermission,
|
||||
editPermission,
|
||||
queryTreeList,
|
||||
queryListAsync,
|
||||
queryRolePermission,
|
||||
saveRolePermission,
|
||||
queryPermissionsByUser,
|
||||
loadAllRoleIds,
|
||||
getPermissionRuleList,
|
||||
queryPermissionRule,
|
||||
queryDepartTreeList,
|
||||
queryDepartTreeSync,
|
||||
queryIdTree,
|
||||
queryParentName,
|
||||
searchByKeywords,
|
||||
deleteByDepartId,
|
||||
deleteLog,
|
||||
deleteLogList,
|
||||
addDict,
|
||||
editDict,
|
||||
treeList,
|
||||
queryDictName,
|
||||
addDictItem,
|
||||
editDictItem,
|
||||
getDictTreeList,
|
||||
getFormDictTreeList,
|
||||
getDictByCode,
|
||||
doReleaseData,
|
||||
doReovkeData,
|
||||
getLoginfo,
|
||||
getVisitInfo,
|
||||
queryUserByDepId,
|
||||
duplicateCheck,
|
||||
queryTreeListForRole,
|
||||
getSystemMenuList,
|
||||
getSystemSubmenu,
|
||||
getSystemSubmenuBatch,
|
||||
loadCategoryData,
|
||||
checkRuleByCode,
|
||||
queryDepartPermission,
|
||||
saveDepartPermission,
|
||||
queryTreeListForDeptRole,
|
||||
queryDeptRolePermission,
|
||||
queryMyDepartTreeList,
|
||||
getUserNoticeInfo,
|
||||
getDictItemsFromCache,
|
||||
|
||||
getShowAreaData,
|
||||
addAreaData,
|
||||
editAreaData,
|
||||
getFileInfo,
|
||||
|
||||
addTag,
|
||||
editTag,
|
||||
addCategoryItem,
|
||||
editCategoryItem,
|
||||
|
||||
getStandardList,
|
||||
|
||||
getWorkGroupTreeList,
|
||||
|
||||
getEnterpriseLevelMapList,
|
||||
getSSOUserInfo,
|
||||
|
||||
addAsmsInterface,
|
||||
editAsmsInterface,
|
||||
getAsmsInterfaceById,
|
||||
syncAsmsInterface,
|
||||
batchDelDictItemAsmsInterface
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
const api = {
|
||||
Login: '/sys/login',
|
||||
Logout: '/sys/logout',
|
||||
ForgePassword: '/auth/forge-password',
|
||||
Register: '/auth/register',
|
||||
SendSms: '/account/sms',
|
||||
// get my info
|
||||
UserInfo: '/user/info'
|
||||
}
|
||||
export default api
|
||||
@@ -0,0 +1,87 @@
|
||||
import api from './index'
|
||||
import { axios } from '@/utils/request'
|
||||
|
||||
/**
|
||||
* login func
|
||||
* parameter: {
|
||||
* username: '',
|
||||
* password: '',
|
||||
* remember_me: true,
|
||||
* captcha: '12345'
|
||||
* }
|
||||
* @param parameter
|
||||
* @returns {*}
|
||||
*/
|
||||
export function login (parameter) {
|
||||
return axios({
|
||||
url: '/sys/login',
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function phoneLogin (parameter) {
|
||||
return axios({
|
||||
url: '/sys/phoneLogin',
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function getSmsCaptcha (parameter) {
|
||||
return axios({
|
||||
url: api.SendSms,
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// export function getInfo() {
|
||||
// return axios({
|
||||
// url: '/api/user/info',
|
||||
// method: 'get',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json;charset=UTF-8'
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
export function logout (logoutToken) {
|
||||
return axios({
|
||||
url: '/sys/logout',
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=UTF-8',
|
||||
'X-Access-Token': logoutToken
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方登录
|
||||
* @param token
|
||||
* @param thirdType
|
||||
* @returns {*}
|
||||
*/
|
||||
export function thirdLogin (token, thirdType) {
|
||||
return axios({
|
||||
url: `/sys/thirdLogin/getLoginUser/${token}/${thirdType}`,
|
||||
method: 'get',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 强退其他账号
|
||||
* @returns {*}
|
||||
* @param parameter
|
||||
*/
|
||||
export function forceLogout (parameter) {
|
||||
return axios({
|
||||
url: '/sys/online/forceLogout',
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
import Vue from 'vue'
|
||||
import { axios } from '@/utils/request'
|
||||
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||
import signMd5Utils from '@/utils/encryption/signMd5Utils'
|
||||
|
||||
const api = {
|
||||
user: '/mock/api/user',
|
||||
role: '/mock/api/role',
|
||||
service: '/mock/api/service',
|
||||
permission: '/mock/api/permission',
|
||||
permissionNoPager: '/mock/api/permission/no-pager'
|
||||
}
|
||||
|
||||
export default api
|
||||
|
||||
// post
|
||||
export function postAction (url, parameter) {
|
||||
const sign = signMd5Utils.getSign(url, parameter)
|
||||
// 将签名和时间戳,添加在请求接口 Header
|
||||
const signHeader = { 'X-Sign': sign, 'X-TIMESTAMP': signMd5Utils.getDateTimeToString() }
|
||||
|
||||
return axios({
|
||||
url: url,
|
||||
method: 'post',
|
||||
data: parameter,
|
||||
headers: signHeader
|
||||
})
|
||||
}
|
||||
|
||||
// post method= {post | put}
|
||||
export function httpAction (url, parameter, method) {
|
||||
const sign = signMd5Utils.getSign(url, parameter)
|
||||
// 将签名和时间戳,添加在请求接口 Header
|
||||
const signHeader = { 'X-Sign': sign, 'X-TIMESTAMP': signMd5Utils.getDateTimeToString() }
|
||||
|
||||
return axios({
|
||||
url: url,
|
||||
method: method,
|
||||
data: parameter,
|
||||
headers: signHeader
|
||||
})
|
||||
}
|
||||
|
||||
// put
|
||||
export function putAction (url, parameter) {
|
||||
return axios({
|
||||
url: url,
|
||||
method: 'put',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
// get
|
||||
export function getAction (url, parameter) {
|
||||
const sign = signMd5Utils.getSign(url, parameter)
|
||||
// 将签名和时间戳,添加在请求接口 Header
|
||||
const signHeader = { 'X-Sign': sign, 'X-TIMESTAMP': signMd5Utils.getDateTimeToString() }
|
||||
|
||||
return axios({
|
||||
url: url,
|
||||
method: 'get',
|
||||
params: parameter,
|
||||
headers: signHeader
|
||||
})
|
||||
}
|
||||
|
||||
// deleteAction
|
||||
export function deleteAction (url, parameter) {
|
||||
return axios({
|
||||
url: url,
|
||||
method: 'delete',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function getUserList (parameter) {
|
||||
return axios({
|
||||
url: api.user,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function getRoleList (parameter) {
|
||||
return axios({
|
||||
url: api.role,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function getServiceList (parameter) {
|
||||
return axios({
|
||||
url: api.service,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function getPermissions (parameter) {
|
||||
return axios({
|
||||
url: api.permissionNoPager,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
})
|
||||
}
|
||||
|
||||
export function saveService (parameter) {
|
||||
return axios({
|
||||
url: api.service,
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件 用于excel导出
|
||||
* @param url
|
||||
* @param parameter
|
||||
* @returns {*}
|
||||
*/
|
||||
export function downFile (url, parameter) {
|
||||
return axios({
|
||||
url: url,
|
||||
params: parameter,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件 用于excel导出
|
||||
* @param url
|
||||
* @param parameter
|
||||
* @returns {*}
|
||||
*/
|
||||
export function postDownFile (url, parameter) {
|
||||
return axios({
|
||||
url: url,
|
||||
data: parameter,
|
||||
method: 'post',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
* @param url 文件路径
|
||||
* @param fileName 文件名
|
||||
* @param parameter
|
||||
* @returns {*}
|
||||
*/
|
||||
export function downloadFile (url, fileName, parameter) {
|
||||
return downFile(url, parameter).then((data) => {
|
||||
if (!data || data.size === 0) {
|
||||
Vue.prototype.$message.warning('文件下载失败')
|
||||
return
|
||||
}
|
||||
if (typeof window.navigator.msSaveBlob !== 'undefined') {
|
||||
window.navigator.msSaveBlob(new Blob([data]), fileName)
|
||||
} else {
|
||||
const url = window.URL.createObjectURL(new Blob([data]))
|
||||
const link = document.createElement('a')
|
||||
link.style.display = 'none'
|
||||
link.href = url
|
||||
link.setAttribute('download', fileName)
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link) // 下载完成移除元素
|
||||
window.URL.revokeObjectURL(url) // 释放掉blob对象
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传 用于富文本上传图片
|
||||
* @param url
|
||||
* @param parameter
|
||||
* @returns {*}
|
||||
*/
|
||||
export function uploadAction (url, parameter) {
|
||||
return axios({
|
||||
url: url,
|
||||
data: parameter,
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data' // 文件上传
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件服务访问路径
|
||||
* @param avatar
|
||||
* @param subStr
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getFileAccessHttpUrl (avatar, subStr) {
|
||||
if (!subStr) subStr = 'http'
|
||||
try {
|
||||
if (avatar && avatar.startsWith(subStr)) {
|
||||
return avatar
|
||||
} else {
|
||||
if (avatar && avatar.length > 0 && avatar.indexOf('[') === -1) {
|
||||
const token = Vue.ls.get(ACCESS_TOKEN)
|
||||
return window._CONFIG.staticDomainURL + '/' + avatar + '?token=' + token
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* params传参的post
|
||||
*/
|
||||
export function postForParams (url, parameter) {
|
||||
const sign = signMd5Utils.getSign(url, parameter)
|
||||
// 将签名和时间戳,添加在请求接口 Header
|
||||
const signHeader = { 'X-Sign': sign, 'X-TIMESTAMP': signMd5Utils.getDateTimeToString() }
|
||||
|
||||
return axios({
|
||||
url: url,
|
||||
method: 'post',
|
||||
params: parameter,
|
||||
headers: signHeader
|
||||
})
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.3 KiB |
@@ -0,0 +1 @@
|
||||
@primary-color: '#D52C26';
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
pageTitle: {
|
||||
home: 'home'
|
||||
},
|
||||
back: 'back',
|
||||
chinese: 'chinese',
|
||||
english: 'english',
|
||||
noMobile: '当前节点不支持手机端操作',
|
||||
toPc: '请前往PC端进行操作'
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
pageTitle: {
|
||||
home: '首页'
|
||||
},
|
||||
back: '返回',
|
||||
chinese: '中',
|
||||
english: '英',
|
||||
noMobile: '当前节点不支持手机端操作',
|
||||
toPc: '请前往PC端进行操作'
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import Storage from 'vue-ls'
|
||||
|
||||
import Vant from 'vant'
|
||||
import 'vant/lib/index.css'
|
||||
import 'vant/lib/index.less'
|
||||
|
||||
import VueI18n from 'vue-i18n'
|
||||
import LangENUS from './common/lang/en-us'
|
||||
import LangZHCN from './common/lang/zh-cn'
|
||||
import { ACCESS_TOKEN, USER_INFO } from '@/store/mutation-types'
|
||||
import './permission'
|
||||
Vue.config.productionTip = false
|
||||
|
||||
Vue.use(Vant)
|
||||
Vue.use(VueI18n)
|
||||
|
||||
const i18n = new VueI18n({
|
||||
locale: 'zh-CN',
|
||||
messages: {
|
||||
'en-US': LangENUS,
|
||||
'zh-CN': LangZHCN
|
||||
}
|
||||
})
|
||||
|
||||
Vue.use(Storage, {
|
||||
namespace: 'pro__', // key prefix
|
||||
name: 'ls', // name variable Vue.[ls] or this.[$ls],
|
||||
storage: 'local' // storage name session, local, memory
|
||||
})
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
i18n,
|
||||
mounted () {
|
||||
store.commit('SET_TOKEN', Vue.ls.get(ACCESS_TOKEN))
|
||||
store.commit('SET_INFO', Vue.ls.get(USER_INFO))
|
||||
},
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
@@ -0,0 +1,52 @@
|
||||
import Vue from 'vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import { ACCESS_TOKEN, UI_CACHE_DB_DICT_DATA, USER_INFO, USER_NAME } from '@/store/mutation-types'
|
||||
import { welcome } from '@/utils/util'
|
||||
import { getSSOUserInfo } from './api/api'
|
||||
|
||||
const whiteList = ['/user/login'] // no redirect whitelist
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
// 单点登录
|
||||
if (to.query.code) {
|
||||
const { result } = await getSSOUserInfo({ code: to.query.code })
|
||||
const userInfo = result.userInfo
|
||||
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(UI_CACHE_DB_DICT_DATA, result.sysAllDictItems, 7 * 24 * 60 * 60 * 1000)
|
||||
store.commit('SET_TOKEN', result.token)
|
||||
store.commit('SET_INFO', userInfo)
|
||||
store.commit('SET_NAME', { username: userInfo.username, realname: userInfo.realname, welcome: welcome() })
|
||||
store.commit('SET_AVATAR', userInfo.avatar)
|
||||
}
|
||||
if (Vue.ls.get(ACCESS_TOKEN)) {
|
||||
/* has token */
|
||||
if (to.path === '/user/login') {
|
||||
next('/')
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
} else {
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
// 在免登录白名单,直接进入
|
||||
if (to.path === '/user/login' && to.path !== process.env.VUE_APP_LOGIN_PAGE) {
|
||||
window.location.replace(process.env.VUE_APP_LOGIN_PAGE)
|
||||
return
|
||||
}
|
||||
next()
|
||||
} else {
|
||||
const path = '/user/login'
|
||||
if (path === '/user/login' && path !== process.env.VUE_APP_LOGIN_PAGE) {
|
||||
window.location.replace(process.env.VUE_APP_LOGIN_PAGE)
|
||||
return
|
||||
}
|
||||
next({ path: path, query: { redirect: to.fullPath } })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
router.afterEach(() => {
|
||||
|
||||
})
|
||||
@@ -0,0 +1,57 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const routes = [
|
||||
{ // 登录页
|
||||
path: '/user/login',
|
||||
name: 'login',
|
||||
component: () => import('@/views/user/Login'),
|
||||
meta: {
|
||||
// 是否显示头部导航
|
||||
hasNavBar: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: () => import('@/views/Home'),
|
||||
meta: {
|
||||
// 是否显示头部导航
|
||||
hasNavBar: true,
|
||||
// 当前页标题(国际化的标题,对应$t('pageTitle.home')中的home,如果为空则不显示
|
||||
pageTitle: 'home',
|
||||
// 是否显示返回
|
||||
hasBack: false
|
||||
}
|
||||
},
|
||||
|
||||
{ // 流程中节点不支持的页面
|
||||
path: '/noMobile',
|
||||
name: 'NoMobile',
|
||||
meta: {
|
||||
hasNavBar: true,
|
||||
hasBack: true
|
||||
},
|
||||
component: () => import('@/views/exception/NoMobile')
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
redirect: '/'
|
||||
}
|
||||
]
|
||||
|
||||
const originalPush = VueRouter.prototype.push
|
||||
VueRouter.prototype.push = function push (location, onResolve, onReject) {
|
||||
if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject)
|
||||
return originalPush.call(this, location).catch(err => err)
|
||||
}
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,36 @@
|
||||
import Vue from 'vue'
|
||||
import { USER_INFO, ENHANCE_PRE } from '@/store/mutation-types'
|
||||
|
||||
const getters = {
|
||||
device: state => state.app.device,
|
||||
theme: state => state.app.theme,
|
||||
color: state => state.app.color,
|
||||
token: state => state.user.token,
|
||||
avatar: state => {
|
||||
state.user.avatar = Vue.ls.get(USER_INFO).avatar
|
||||
return state.user.avatar
|
||||
},
|
||||
username: state => state.user.username,
|
||||
nickname: state => {
|
||||
state.user.realname = Vue.ls.get(USER_INFO).realname
|
||||
return state.user.realname
|
||||
},
|
||||
welcome: state => state.user.welcome,
|
||||
permissionList: state => state.user.permissionList,
|
||||
userInfo: state => {
|
||||
state.user.info = Vue.ls.get(USER_INFO)
|
||||
return state.user.info
|
||||
},
|
||||
addRouters: state => state.permission.addRouters,
|
||||
onlAuthFields: state => {
|
||||
return state.online.authFields
|
||||
},
|
||||
enhanceJs: (state) => (code) => {
|
||||
state.enhance.enhanceJs[code] = Vue.ls.get(ENHANCE_PRE + code)
|
||||
return state.enhance.enhanceJs[code]
|
||||
},
|
||||
isEmbedded: state => state.app.isEmbedded,
|
||||
defaultHeight: state => state.app.defaultHeight
|
||||
}
|
||||
|
||||
export default getters
|
||||
@@ -0,0 +1,25 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
import app from './modules/app'
|
||||
import user from './modules/user'
|
||||
import getters from './getters'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
modules: {
|
||||
app,
|
||||
user
|
||||
},
|
||||
state: {
|
||||
|
||||
},
|
||||
mutations: {
|
||||
|
||||
},
|
||||
actions: {
|
||||
|
||||
},
|
||||
getters
|
||||
})
|
||||
@@ -0,0 +1,134 @@
|
||||
import Vue from 'vue'
|
||||
import {
|
||||
SIDEBAR_TYPE,
|
||||
DEFAULT_THEME,
|
||||
DEFAULT_LAYOUT_MODE,
|
||||
DEFAULT_COLOR,
|
||||
DEFAULT_COLOR_WEAK,
|
||||
DEFAULT_FIXED_HEADER,
|
||||
DEFAULT_FIXED_SIDEMENU,
|
||||
DEFAULT_FIXED_HEADER_HIDDEN,
|
||||
DEFAULT_CONTENT_WIDTH_TYPE,
|
||||
DEFAULT_MULTI_PAGE
|
||||
} from '@/store/mutation-types'
|
||||
|
||||
const app = {
|
||||
state: {
|
||||
sidebar: {
|
||||
opened: true,
|
||||
withoutAnimation: false
|
||||
},
|
||||
device: 'desktop',
|
||||
theme: '',
|
||||
layout: '',
|
||||
contentWidth: '',
|
||||
fixedHeader: false,
|
||||
fixSiderbar: false,
|
||||
autoHideHeader: false,
|
||||
color: null,
|
||||
weak: false,
|
||||
multipage: true, // 默认多页签模式
|
||||
isEmbedded: false, // 是否嵌入其他系统
|
||||
defaultHeight: {} // 包含用户信息的高度、面包屑的高度、单行查询条件的高度、单行操作列的高度
|
||||
},
|
||||
mutations: {
|
||||
SET_SIDEBAR_TYPE: (state, type) => {
|
||||
state.sidebar.opened = type
|
||||
Vue.ls.set(SIDEBAR_TYPE, type)
|
||||
},
|
||||
CLOSE_SIDEBAR: (state, withoutAnimation) => {
|
||||
Vue.ls.set(SIDEBAR_TYPE, true)
|
||||
state.sidebar.opened = false
|
||||
state.sidebar.withoutAnimation = withoutAnimation
|
||||
},
|
||||
TOGGLE_DEVICE: (state, device) => {
|
||||
state.device = device
|
||||
},
|
||||
TOGGLE_THEME: (state, theme) => {
|
||||
// setStore('_DEFAULT_THEME', theme)
|
||||
Vue.ls.set(DEFAULT_THEME, theme)
|
||||
state.theme = theme
|
||||
},
|
||||
TOGGLE_LAYOUT_MODE: (state, layout) => {
|
||||
Vue.ls.set(DEFAULT_LAYOUT_MODE, layout)
|
||||
state.layout = layout
|
||||
},
|
||||
TOGGLE_FIXED_HEADER: (state, fixed) => {
|
||||
Vue.ls.set(DEFAULT_FIXED_HEADER, fixed)
|
||||
state.fixedHeader = fixed
|
||||
},
|
||||
TOGGLE_FIXED_SIDERBAR: (state, fixed) => {
|
||||
Vue.ls.set(DEFAULT_FIXED_SIDEMENU, fixed)
|
||||
state.fixSiderbar = fixed
|
||||
},
|
||||
TOGGLE_FIXED_HEADER_HIDDEN: (state, show) => {
|
||||
Vue.ls.set(DEFAULT_FIXED_HEADER_HIDDEN, show)
|
||||
state.autoHideHeader = show
|
||||
},
|
||||
TOGGLE_CONTENT_WIDTH: (state, type) => {
|
||||
Vue.ls.set(DEFAULT_CONTENT_WIDTH_TYPE, type)
|
||||
state.contentWidth = type
|
||||
},
|
||||
TOGGLE_COLOR: (state, color) => {
|
||||
Vue.ls.set(DEFAULT_COLOR, color)
|
||||
state.color = color
|
||||
},
|
||||
TOGGLE_WEAK: (state, flag) => {
|
||||
Vue.ls.set(DEFAULT_COLOR_WEAK, flag)
|
||||
state.weak = flag
|
||||
},
|
||||
SET_MULTI_PAGE (state, multipageFlag) {
|
||||
Vue.ls.set(DEFAULT_MULTI_PAGE, multipageFlag)
|
||||
state.multipage = multipageFlag
|
||||
},
|
||||
SET_IS_EMBEDDED (state, isEmbedded) {
|
||||
state.isEmbedded = isEmbedded
|
||||
},
|
||||
SET_DEFAULT_HEIGHT (state, defaultHeight) {
|
||||
state.defaultHeight = defaultHeight
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setSidebar: ({ commit }, type) => {
|
||||
commit('SET_SIDEBAR_TYPE', type)
|
||||
},
|
||||
CloseSidebar ({ commit }, { withoutAnimation }) {
|
||||
commit('CLOSE_SIDEBAR', withoutAnimation)
|
||||
},
|
||||
ToggleDevice ({ commit }, device) {
|
||||
commit('TOGGLE_DEVICE', device)
|
||||
},
|
||||
ToggleTheme ({ commit }, theme) {
|
||||
commit('TOGGLE_THEME', theme)
|
||||
},
|
||||
ToggleLayoutMode ({ commit }, mode) {
|
||||
commit('TOGGLE_LAYOUT_MODE', mode)
|
||||
},
|
||||
ToggleFixedHeader ({ commit }, fixedHeader) {
|
||||
if (!fixedHeader) {
|
||||
commit('TOGGLE_FIXED_HEADER_HIDDEN', false)
|
||||
}
|
||||
commit('TOGGLE_FIXED_HEADER', fixedHeader)
|
||||
},
|
||||
ToggleFixSiderbar ({ commit }, fixSiderbar) {
|
||||
commit('TOGGLE_FIXED_SIDERBAR', fixSiderbar)
|
||||
},
|
||||
ToggleFixedHeaderHidden ({ commit }, show) {
|
||||
commit('TOGGLE_FIXED_HEADER_HIDDEN', show)
|
||||
},
|
||||
ToggleContentWidth ({ commit }, type) {
|
||||
commit('TOGGLE_CONTENT_WIDTH', type)
|
||||
},
|
||||
ToggleColor ({ commit }, color) {
|
||||
commit('TOGGLE_COLOR', color)
|
||||
},
|
||||
ToggleWeak ({ commit }, weakFlag) {
|
||||
commit('TOGGLE_WEAK', weakFlag)
|
||||
},
|
||||
ToggleMultipage ({ commit }, multipageFlag) {
|
||||
commit('SET_MULTI_PAGE', multipageFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default app
|
||||
@@ -0,0 +1,218 @@
|
||||
import Vue from 'vue'
|
||||
import { login, logout, phoneLogin, thirdLogin } from '@/api/login'
|
||||
import { ACCESS_TOKEN, USER_NAME, USER_INFO, USER_AUTH, SYS_BUTTON_AUTH, UI_CACHE_DB_DICT_DATA, TENANT_ID, CACHE_INCLUDED_ROUTES } from '@/store/mutation-types'
|
||||
import store from '@/store'
|
||||
import { welcome } from '@/utils/util'
|
||||
import { queryPermissionsByUser } from '@/api/api'
|
||||
import { getAction } from '@/api/manage'
|
||||
|
||||
const user = {
|
||||
state: {
|
||||
token: '',
|
||||
username: '',
|
||||
realname: '',
|
||||
tenantid: '',
|
||||
welcome: '',
|
||||
avatar: '',
|
||||
permissionList: [],
|
||||
info: {}
|
||||
},
|
||||
|
||||
mutations: {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_NAME: (state, { username, realname, welcome }) => {
|
||||
state.username = username
|
||||
state.realname = realname
|
||||
state.welcome = welcome
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
},
|
||||
SET_PERMISSIONLIST: (state, permissionList) => {
|
||||
state.permissionList = permissionList
|
||||
},
|
||||
SET_INFO: (state, info) => {
|
||||
state.info = info
|
||||
},
|
||||
SET_TENANT: (state, id) => {
|
||||
state.tenantid = id
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
// CAS验证登录
|
||||
ValidateLogin ({ commit }, userInfo) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getAction('/sys/cas/client/validateLogin', userInfo).then(response => {
|
||||
console.log('----cas 登录--------', response)
|
||||
if (response.success) {
|
||||
const result = response.result
|
||||
const userInfo = result.userInfo
|
||||
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
|
||||
commit('SET_TOKEN', result.token)
|
||||
commit('SET_INFO', userInfo)
|
||||
commit('SET_NAME', { username: userInfo.username, realname: userInfo.realname, welcome: welcome() })
|
||||
commit('SET_AVATAR', userInfo.avatar)
|
||||
resolve(response)
|
||||
} else {
|
||||
resolve(response)
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 登录
|
||||
Login ({ commit }, userInfo) {
|
||||
return new Promise((resolve, reject) => {
|
||||
login(userInfo).then(response => {
|
||||
if (response.code + '' === '200') {
|
||||
const result = response.result
|
||||
const userInfo = result.userInfo
|
||||
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(UI_CACHE_DB_DICT_DATA, result.sysAllDictItems, 7 * 24 * 60 * 60 * 1000)
|
||||
commit('SET_TOKEN', result.token)
|
||||
commit('SET_INFO', userInfo)
|
||||
commit('SET_NAME', { username: userInfo.username, realname: userInfo.realname, welcome: welcome() })
|
||||
commit('SET_AVATAR', userInfo.avatar)
|
||||
resolve(response)
|
||||
} else {
|
||||
reject(response)
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 手机号登录
|
||||
PhoneLogin ({ commit }, userInfo) {
|
||||
return new Promise((resolve, reject) => {
|
||||
phoneLogin(userInfo).then(response => {
|
||||
if (response.code + '' === '200') {
|
||||
const result = response.result
|
||||
const userInfo = result.userInfo
|
||||
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(UI_CACHE_DB_DICT_DATA, result.sysAllDictItems, 7 * 24 * 60 * 60 * 1000)
|
||||
commit('SET_TOKEN', result.token)
|
||||
commit('SET_INFO', userInfo)
|
||||
commit('SET_NAME', { username: userInfo.username, realname: userInfo.realname, welcome: welcome() })
|
||||
commit('SET_AVATAR', userInfo.avatar)
|
||||
resolve(response)
|
||||
} else {
|
||||
reject(response)
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 获取用户信息
|
||||
GetPermissionList ({ commit }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
queryPermissionsByUser().then(response => {
|
||||
const menuData = response.result.menu
|
||||
const authData = response.result.auth
|
||||
const allAuthData = response.result.allAuth
|
||||
// Vue.ls.set(USER_AUTH,authData);
|
||||
sessionStorage.setItem(USER_AUTH, JSON.stringify(authData))
|
||||
sessionStorage.setItem(SYS_BUTTON_AUTH, JSON.stringify(allAuthData))
|
||||
if (menuData && menuData.length > 0) {
|
||||
// update--begin--autor:qinfeng-----date:20200109------for: 一级菜单的子菜单全部是隐藏路由,则一级菜单不显示------
|
||||
menuData.forEach((item) => {
|
||||
if (item.children) {
|
||||
const hasChildrenMenu = item.children.filter((i) => {
|
||||
return !i.hidden || i.hidden === false
|
||||
})
|
||||
if (hasChildrenMenu == null || hasChildrenMenu.length === 0) {
|
||||
item.hidden = true
|
||||
}
|
||||
}
|
||||
})
|
||||
// console.log(" menu show json ", menuData)
|
||||
// update--end--autor:qinfeng-----date:20200109------for: 一级菜单的子菜单全部是隐藏路由,则一级菜单不显示------
|
||||
commit('SET_PERMISSIONLIST', menuData)
|
||||
} else {
|
||||
Vue.prototype.$Jmodal.error({
|
||||
title: '无权限',
|
||||
content: '该用户无权限,请联系管理员!',
|
||||
okText: '确认',
|
||||
mask: false,
|
||||
onOk: () => {
|
||||
store.dispatch('Logout')
|
||||
}
|
||||
})
|
||||
reject(new Error('getPermissionList: permissions must be a non-null array !'))
|
||||
}
|
||||
resolve(response)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 登出
|
||||
Logout ({ commit, state }) {
|
||||
return new Promise((resolve) => {
|
||||
const logoutToken = state.token
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_PERMISSIONLIST', [])
|
||||
Vue.ls.remove(ACCESS_TOKEN)
|
||||
Vue.ls.remove(USER_INFO)
|
||||
Vue.ls.remove(USER_NAME)
|
||||
Vue.ls.remove(UI_CACHE_DB_DICT_DATA)
|
||||
Vue.ls.remove(CACHE_INCLUDED_ROUTES)
|
||||
Vue.ls.remove(TENANT_ID)
|
||||
// console.log('logoutToken: '+ logoutToken)
|
||||
logout(logoutToken).then(() => {
|
||||
if (process.env.VUE_APP_SSO + '' === 'true') {
|
||||
const sevice = 'http://' + window.location.host + '/'
|
||||
const serviceUrl = encodeURIComponent(sevice)
|
||||
window.location.href = process.env.VUE_APP_CAS_BASE_URL + '/logout?service=' + serviceUrl
|
||||
}
|
||||
resolve()
|
||||
window.location.replace(process.env.VUE_APP_LOGIN_PAGE)
|
||||
}).catch(() => {
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
},
|
||||
// 第三方登录
|
||||
ThirdLogin ({ commit }, param) {
|
||||
return new Promise((resolve, reject) => {
|
||||
thirdLogin(param.token, param.thirdType).then(response => {
|
||||
if (response.code + '' === '200') {
|
||||
const result = response.result
|
||||
const userInfo = result.userInfo
|
||||
Vue.ls.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_NAME, userInfo.username, 7 * 24 * 60 * 60 * 1000)
|
||||
Vue.ls.set(USER_INFO, userInfo, 7 * 24 * 60 * 60 * 1000)
|
||||
commit('SET_TOKEN', result.token)
|
||||
commit('SET_INFO', userInfo)
|
||||
commit('SET_NAME', { username: userInfo.username, realname: userInfo.realname, welcome: welcome() })
|
||||
commit('SET_AVATAR', userInfo.avatar)
|
||||
resolve(response)
|
||||
} else {
|
||||
reject(response)
|
||||
}
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
saveTenant ({ commit }, id) {
|
||||
Vue.ls.set(TENANT_ID, id, 7 * 24 * 60 * 60 * 1000)
|
||||
commit('SET_TENANT', id)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
export default user
|
||||
@@ -0,0 +1,28 @@
|
||||
export const ACCESS_TOKEN = 'Access-Token'
|
||||
export const SIDEBAR_TYPE = 'SIDEBAR_TYPE'
|
||||
export const DEFAULT_THEME = 'DEFAULT_THEME'
|
||||
export const DEFAULT_LAYOUT_MODE = 'DEFAULT_LAYOUT_MODE'
|
||||
export const DEFAULT_COLOR = 'DEFAULT_COLOR'
|
||||
export const DEFAULT_COLOR_WEAK = 'DEFAULT_COLOR_WEAK'
|
||||
export const DEFAULT_FIXED_HEADER = 'DEFAULT_FIXED_HEADER'
|
||||
export const DEFAULT_FIXED_SIDEMENU = 'DEFAULT_FIXED_SIDEMENU'
|
||||
export const DEFAULT_FIXED_HEADER_HIDDEN = 'DEFAULT_FIXED_HEADER_HIDDEN'
|
||||
export const DEFAULT_CONTENT_WIDTH_TYPE = 'DEFAULT_CONTENT_WIDTH_TYPE'
|
||||
export const DEFAULT_MULTI_PAGE = 'DEFAULT_MULTI_PAGE'
|
||||
export const USER_NAME = 'Login_Username'
|
||||
export const USER_INFO = 'Login_Userinfo'
|
||||
export const USER_AUTH = 'LOGIN_USER_BUTTON_AUTH'
|
||||
export const SYS_BUTTON_AUTH = 'SYS_BUTTON_AUTH'
|
||||
export const ENCRYPTED_STRING = 'ENCRYPTED_STRING'
|
||||
export const ENHANCE_PRE = 'enhance_'
|
||||
export const UI_CACHE_DB_DICT_DATA = 'UI_CACHE_DB_DICT_DATA'
|
||||
export const INDEX_MAIN_PAGE_PATH = '/dashboard/analysis'
|
||||
export const OAUTH2_LOGIN_PAGE_PATH = '/oauth2-app/login'
|
||||
export const TENANT_ID = 'TENANT_ID'
|
||||
export const ONL_AUTH_FIELDS = 'ONL_AUTH_FIELDS'
|
||||
// 路由缓存问题,关闭了tab页时再打开就不刷新 #842
|
||||
export const CACHE_INCLUDED_ROUTES = 'CACHE_INCLUDED_ROUTES'
|
||||
export const CONTENT_WIDTH_TYPE = {
|
||||
Fluid: 'Fluid',
|
||||
Fixed: 'Fixed'
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
const VueAxios = {
|
||||
vm: {},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
install (Vue, router = {}, instance) {
|
||||
if (this.installed) {
|
||||
return
|
||||
}
|
||||
this.installed = true
|
||||
|
||||
if (!instance) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('You have to install axios')
|
||||
return
|
||||
}
|
||||
|
||||
Vue.axios = instance
|
||||
|
||||
Object.defineProperties(Vue.prototype, {
|
||||
axios: {
|
||||
get: function get () {
|
||||
return instance
|
||||
}
|
||||
},
|
||||
$http: {
|
||||
get: function get () {
|
||||
return instance
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
VueAxios
|
||||
// eslint-disable-next-line no-undef
|
||||
// instance as axios
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { axios } from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 获取RSA公钥
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getRSAPublicKey () {
|
||||
return axios({
|
||||
url: `/sys/getRSAPublicKey`,
|
||||
method: 'get',
|
||||
timeout: 5000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
}
|
||||
})
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,128 @@
|
||||
import md5 from 'md5'
|
||||
// 签名密钥串(前后端要一致,正式发布请自行修改)
|
||||
const signatureSecret = 'dd05f1c54d63749eda95f9fa6d49v442a'
|
||||
|
||||
export default class signMd5Utils {
|
||||
/**
|
||||
* json参数升序
|
||||
* @param jsonObj 发送参数
|
||||
*/
|
||||
|
||||
static sortAsc (jsonObj) {
|
||||
const arr = []
|
||||
let num = 0
|
||||
for (const i in jsonObj) {
|
||||
arr[num] = i
|
||||
num++
|
||||
}
|
||||
const sortArr = arr.sort()
|
||||
const sortObj = {}
|
||||
for (const i in sortArr) {
|
||||
sortObj[sortArr[i]] = jsonObj[sortArr[i]]
|
||||
}
|
||||
return sortObj
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url 请求的url,应该包含请求参数(url的?后面的参数)
|
||||
* @param requestParams 请求参数(POST的JSON参数)
|
||||
* @returns {string} 获取签名
|
||||
*/
|
||||
static getSign (url, requestParams) {
|
||||
const urlParams = this.parseQueryString(url)
|
||||
const jsonObj = this.mergeObject(urlParams, requestParams)
|
||||
// console.log("sign jsonObj: ",jsonObj)
|
||||
const requestBody = this.sortAsc(jsonObj)
|
||||
console.log('sign requestBody: ', requestBody)
|
||||
return md5(JSON.stringify(requestBody) + signatureSecret).toUpperCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param url 请求的url
|
||||
* @returns {{}} 将url中请求参数组装成json对象(url的?后面的参数)
|
||||
*/
|
||||
static parseQueryString (url) {
|
||||
const urlReg = /^[^?]+\?([\w\W]+)$/
|
||||
const paramReg = /([^&=]+)=([\w\W]*?)(&|$|#)/g
|
||||
const urlArray = urlReg.exec(url)
|
||||
const result = {}
|
||||
|
||||
// 获取URL上最后带逗号的参数变量 sys/dict/getDictItems/sys_user,realname,username
|
||||
// 【这边条件没有encode】带条件参数例子:/sys/dict/getDictItems/sys_user,realname,id,username!='admin'%20order%20by%20create_time
|
||||
let lastpathVariable = url.substring(url.lastIndexOf('/') + 1)
|
||||
if (lastpathVariable.includes(',')) {
|
||||
if (lastpathVariable.includes('?')) {
|
||||
lastpathVariable = lastpathVariable.substring(0, lastpathVariable.indexOf('?'))
|
||||
}
|
||||
// 解决Sign 签名校验失败 #2728
|
||||
result['x-path-variable'] = decodeURIComponent(lastpathVariable)
|
||||
}
|
||||
if (urlArray && urlArray[1]) {
|
||||
const paramString = urlArray[1]; let paramResult
|
||||
while ((paramResult = paramReg.exec(paramString)) != null) {
|
||||
// 数字值转为string类型,前后端加密规则保持一致
|
||||
if (this.myIsNaN(paramResult[2])) {
|
||||
paramResult[2] = paramResult[2].toString()
|
||||
}
|
||||
result[paramResult[1]] = paramResult[2]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {*} 将两个对象合并成一个
|
||||
*/
|
||||
static mergeObject (objectOne, objectTwo) {
|
||||
if (objectTwo && Object.keys(objectTwo).length > 0) {
|
||||
for (const key in objectTwo) {
|
||||
if (Object.prototype.hasOwnProperty.call(objectTwo, key) === true) {
|
||||
// 数字值转为string类型,前后端加密规则保持一致
|
||||
if (this.myIsNaN(objectTwo[key])) {
|
||||
objectTwo[key] = objectTwo[key].toString()
|
||||
}
|
||||
objectOne[key] = objectTwo[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
return objectOne
|
||||
}
|
||||
|
||||
static urlEncode (param, key, encode) {
|
||||
if (param == null) return ''
|
||||
let paramStr = ''
|
||||
const t = typeof (param)
|
||||
if (t === 'string' || t === 'number' || t === 'boolean') {
|
||||
paramStr += '&' + key + '=' + ((encode == null || encode) ? encodeURIComponent(param) : param)
|
||||
} else {
|
||||
for (const i in param) {
|
||||
const k = key == null ? i : key + (param instanceof Array ? '[' + i + ']' : '.' + i)
|
||||
paramStr += this.urlEncode(param[i], k, encode)
|
||||
}
|
||||
}
|
||||
return paramStr
|
||||
}
|
||||
|
||||
static getDateTimeToString () {
|
||||
const date_ = new Date()
|
||||
const year = date_.getFullYear()
|
||||
let month = date_.getMonth() + 1
|
||||
let day = date_.getDate()
|
||||
if (month < 10) month = '0' + month
|
||||
if (day < 10) day = '0' + day
|
||||
let hours = date_.getHours()
|
||||
let mins = date_.getMinutes()
|
||||
let secs = date_.getSeconds()
|
||||
const msecs = date_.getMilliseconds()
|
||||
if (hours < 10) hours = '0' + hours
|
||||
if (mins < 10) mins = '0' + mins
|
||||
if (secs < 10) secs = '0' + secs
|
||||
if (msecs < 10) secs = '0' + msecs
|
||||
return year + '' + month + '' + day + '' + hours + '' + mins + '' + secs
|
||||
}
|
||||
|
||||
// true:数值型的,false:非数值型
|
||||
static myIsNaN (value) {
|
||||
return typeof value === 'number' && !isNaN(value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
import Vue from 'vue'
|
||||
import axios from 'axios'
|
||||
import store from '@/store'
|
||||
import { VueAxios } from './axios'
|
||||
import router from '@/router/index'
|
||||
import { ACCESS_TOKEN, TENANT_ID } from '@/store/mutation-types'
|
||||
import { Dialog, Toast } from 'vant'
|
||||
|
||||
/**
|
||||
* 【指定 axios的 baseURL】
|
||||
* 如果手工指定 baseURL: '/laws-sinotruk'
|
||||
* 则映射后端域名,通过 vue.config.js
|
||||
* @type {*|string}
|
||||
*/
|
||||
const apiBaseUrl = window._CONFIG.domianURL || '/laws-sinotruk'
|
||||
// console.log("apiBaseUrl= ",apiBaseUrl)
|
||||
// 创建 axios 实例
|
||||
const service = axios.create({
|
||||
// baseURL: '/laws-sinotruk',
|
||||
baseURL: apiBaseUrl, // api base_url
|
||||
timeout: 30 * 60 * 1000 // 请求超时时间
|
||||
})
|
||||
|
||||
const err = (error) => {
|
||||
if (error.response) {
|
||||
const data = error.response.data
|
||||
const token = Vue.ls.get(ACCESS_TOKEN)
|
||||
console.log('------异常响应------', token)
|
||||
console.log('------异常响应------', error.response.status)
|
||||
switch (error.response.status) {
|
||||
case 403:
|
||||
Toast('系统提示\n拒绝访问')
|
||||
break
|
||||
case 500:
|
||||
console.log('------error.response------', error.response)
|
||||
// update-begin- --- author:liusq ------ date:20200910 ---- for:处理Blob情况----
|
||||
if (error.response.request.responseType === 'blob') {
|
||||
blobToJson(data)
|
||||
break
|
||||
}
|
||||
// update-end- --- author:liusq ------ date:20200910 ---- for:处理Blob情况----
|
||||
if (data.includes('Token失效')) {
|
||||
// update-begin- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转----
|
||||
Dialog.alert({
|
||||
title: '登录已过期',
|
||||
message: '很抱歉,登录已过期,请重新登录',
|
||||
confirmButtonText: '重新登录',
|
||||
theme: 'round-button'
|
||||
}).then(() => {
|
||||
store.dispatch('Logout').then(() => {
|
||||
Vue.ls.remove(ACCESS_TOKEN)
|
||||
try {
|
||||
const path = window.document.location.pathname
|
||||
console.log('location pathname -> ' + path)
|
||||
if (path !== '/' && path.indexOf('/user/login') === -1) {
|
||||
window.location.reload()
|
||||
}
|
||||
} catch (e) {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
||||
})
|
||||
// update-end- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转----
|
||||
}
|
||||
break
|
||||
case 404:
|
||||
Toast('系统提示\n很抱歉,资源未找到!')
|
||||
break
|
||||
case 504:
|
||||
Toast('系统提示\n网络超时')
|
||||
break
|
||||
case 401:
|
||||
Toast('系统提示\n未授权,请重新登录')
|
||||
if (token) {
|
||||
store.dispatch('Logout').then(() => {
|
||||
setTimeout(() => {
|
||||
window.location.reload()
|
||||
}, 1500)
|
||||
})
|
||||
}
|
||||
break
|
||||
default:
|
||||
Toast(data.message)
|
||||
break
|
||||
}
|
||||
} else if (error.message) {
|
||||
if (error.message.includes('timeout')) {
|
||||
Toast('网络超时')
|
||||
} else {
|
||||
Toast(error.message)
|
||||
}
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
// request interceptor
|
||||
service.interceptors.request.use(config => {
|
||||
const token = Vue.ls.get(ACCESS_TOKEN)
|
||||
if (token) {
|
||||
config.headers['X-Access-Token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
|
||||
}
|
||||
// update-begin--author:sunjianlei---date:20200723---for 如果当前在low-app环境,并且携带了appId,就向Header里传递appId
|
||||
const $route = router.currentRoute
|
||||
if ($route && $route.name && $route.name.startsWith('low-app') && $route.params.appId) {
|
||||
config.headers['X-Low-App-ID'] = $route.params.appId
|
||||
}
|
||||
// update-end--author:sunjianlei---date:20200723---for 如果当前在low-app环境,并且携带了appId,就向Header里传递appId
|
||||
|
||||
// update-begin-author:taoyan date:2020707 for:多租户
|
||||
let tenantid = Vue.ls.get(TENANT_ID)
|
||||
if (!tenantid) {
|
||||
tenantid = 0
|
||||
}
|
||||
config.headers['tenant-id'] = tenantid
|
||||
|
||||
let language = localStorage.getItem('language') || ''
|
||||
if (!language) {
|
||||
language = 'zh-cn'
|
||||
}
|
||||
const cut = language === 'zh-cn' ? 'zh' : 'en'
|
||||
config.headers.Language = cut
|
||||
// update-end-author:taoyan date:2020707 for:多租户
|
||||
if (config.method === 'get') {
|
||||
if (config.url.indexOf('sys/dict/getDictItems') < 0) {
|
||||
config.params = {
|
||||
_t: Date.parse(new Date()) / 1000,
|
||||
...config.params
|
||||
}
|
||||
}
|
||||
}
|
||||
return config
|
||||
}, (error) => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
// response interceptor
|
||||
service.interceptors.response.use((response) => {
|
||||
return response.data
|
||||
}, err)
|
||||
|
||||
const installer = {
|
||||
vm: {},
|
||||
install (Vue, router = {}) {
|
||||
Vue.use(VueAxios, router, service)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Blob解析
|
||||
* @param data
|
||||
*/
|
||||
function blobToJson (data) {
|
||||
const fileReader = new FileReader()
|
||||
const token = Vue.ls.get(ACCESS_TOKEN)
|
||||
fileReader.onload = function () {
|
||||
try {
|
||||
const jsonData = JSON.parse(this.result) // 说明是普通对象数据,后台转换失败
|
||||
console.log('jsonData', jsonData)
|
||||
if (jsonData.status === 500) {
|
||||
console.log('token----------》', token)
|
||||
if (token && jsonData.message.includes('Token失效')) {
|
||||
Dialog.alert({
|
||||
title: '登录已过期',
|
||||
message: '很抱歉,登录已过期,请重新登录',
|
||||
confirmButtonText: '重新登录',
|
||||
theme: 'round-button'
|
||||
}).then(() => {
|
||||
store.dispatch('Logout').then(() => {
|
||||
Vue.ls.remove(ACCESS_TOKEN)
|
||||
try {
|
||||
const path = window.document.location.pathname
|
||||
console.log('location pathname -> ' + path)
|
||||
if (path !== '/' && path.indexOf('/user/login') === -1) {
|
||||
window.location.reload()
|
||||
}
|
||||
} catch (e) {
|
||||
window.location.reload()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// 解析成对象失败,说明是正常的文件流
|
||||
console.log('blob解析fileReader返回err', err)
|
||||
}
|
||||
}
|
||||
fileReader.readAsText(data)
|
||||
}
|
||||
|
||||
export {
|
||||
installer as VueAxios,
|
||||
service as axios
|
||||
}
|
||||
@@ -0,0 +1,526 @@
|
||||
import Vue from 'vue'
|
||||
import * as api from '@/api/api'
|
||||
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||
//
|
||||
export function timeFix () {
|
||||
const time = new Date()
|
||||
const hour = time.getHours()
|
||||
return hour < 9 ? '早上好' : (hour <= 11 ? '上午好' : (hour <= 13 ? '中午好' : (hour < 20 ? '下午好' : '晚上好')))
|
||||
}
|
||||
|
||||
export function welcome () {
|
||||
const arr = ['休息一会儿吧', '准备吃什么呢?', '要不要打一把 DOTA', '我猜你可能累了']
|
||||
const index = Math.floor((Math.random() * arr.length))
|
||||
return arr[index]
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发 window.resize
|
||||
*/
|
||||
export function triggerWindowResizeEvent () {
|
||||
const event = document.createEvent('HTMLEvents')
|
||||
event.initEvent('resize', true, true)
|
||||
event.eventType = 'message'
|
||||
window.dispatchEvent(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤对象中为空的属性
|
||||
* @param obj
|
||||
* @returns {*}
|
||||
*/
|
||||
export function filterObj (obj) {
|
||||
if (!(typeof obj === 'object')) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key) && (obj[key] == null || obj[key] === undefined || obj[key] === '')) {
|
||||
delete obj[key]
|
||||
}
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间格式化
|
||||
* @param value
|
||||
* @param fmt
|
||||
* @returns {*}
|
||||
*/
|
||||
export function formatDate (value, fmt) {
|
||||
const regPos = /^\d+(\.\d+)?$/
|
||||
if (regPos.test(value)) {
|
||||
// 如果是数字
|
||||
const getDate = new Date(value)
|
||||
const o = {
|
||||
'M+': getDate.getMonth() + 1,
|
||||
'd+': getDate.getDate(),
|
||||
'h+': getDate.getHours(),
|
||||
'm+': getDate.getMinutes(),
|
||||
's+': getDate.getSeconds(),
|
||||
'q+': Math.floor((getDate.getMonth() + 3) / 3),
|
||||
S: getDate.getMilliseconds()
|
||||
}
|
||||
if (/(y+)/.test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (getDate.getFullYear() + '').substr(4 - RegExp.$1.length))
|
||||
}
|
||||
for (const k in o) {
|
||||
if (new RegExp('(' + k + ')').test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
|
||||
}
|
||||
}
|
||||
return fmt
|
||||
} else {
|
||||
// TODO
|
||||
value = value.trim()
|
||||
return value.substr(0, fmt.length)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 深度克隆对象、数组
|
||||
* @param obj 被克隆的对象
|
||||
* @return 克隆后的对象
|
||||
*/
|
||||
export function cloneObject (obj) {
|
||||
return JSON.parse(JSON.stringify(obj))
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机生成数字
|
||||
*
|
||||
* 示例:生成长度为 12 的随机数:randomNumber(12)
|
||||
* 示例:生成 3~23 之间的随机数:randomNumber(3, 23)
|
||||
*
|
||||
* @param1 最小值 | 长度
|
||||
* @param2 最大值
|
||||
* @return int 生成后的数字
|
||||
*/
|
||||
export function randomNumber () {
|
||||
// 生成 最小值 到 最大值 区间的随机数
|
||||
const random = (min, max) => {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min)
|
||||
}
|
||||
if (arguments.length === 1) {
|
||||
const [length] = arguments
|
||||
// 生成指定长度的随机数字,首位一定不是 0
|
||||
const nums = [...Array(length).keys()].map((i) => (i > 0 ? random(0, 9) : random(1, 9)))
|
||||
return parseInt(nums.join(''))
|
||||
} else if (arguments.length >= 2) {
|
||||
const [min, max] = arguments
|
||||
return random(min, max)
|
||||
} else {
|
||||
return Number.NaN
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机生成字符串
|
||||
* @param length 字符串的长度
|
||||
* @param chats 可选字符串区间(只会生成传入的字符串中的字符)
|
||||
* @return string 生成的字符串
|
||||
*/
|
||||
export function randomString (length, chats) {
|
||||
if (!length) length = 1
|
||||
if (!chats) chats = '0123456789qwertyuioplkjhgfdsazxcvbnm'
|
||||
let str = ''
|
||||
for (let i = 0; i < length; i++) {
|
||||
const num = randomNumber(0, chats.length - 1)
|
||||
str += chats[num]
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机生成uuid
|
||||
* @return string 生成的uuid
|
||||
*/
|
||||
export function randomUUID () {
|
||||
const chats = '0123456789abcdef'
|
||||
return randomString(32, chats)
|
||||
}
|
||||
|
||||
/**
|
||||
* 下划线转驼峰
|
||||
* @param string
|
||||
* @returns {*}
|
||||
*/
|
||||
export function underLine2CamelCase (string) {
|
||||
return string.replace(/_([a-z])/g, function (all, letter) {
|
||||
return letter.toUpperCase()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否显示办理按钮
|
||||
* @param bpmStatus
|
||||
* @returns {*}
|
||||
*/
|
||||
export function showDealBtn (bpmStatus) {
|
||||
return bpmStatus + '' !== '1' && bpmStatus + '' !== '3' && bpmStatus + '' !== '4'
|
||||
}
|
||||
|
||||
/**
|
||||
* 增强CSS,可以在页面上输出全局css
|
||||
* @param css 要增强的css
|
||||
* @param id style标签的id,可以用来清除旧样式
|
||||
*/
|
||||
export function cssExpand (css, id) {
|
||||
const style = document.createElement('style')
|
||||
style.type = 'text/css'
|
||||
style.innerHTML = `@charset "UTF-8"; ${css}`
|
||||
// 清除旧样式
|
||||
if (id) {
|
||||
const $style = document.getElementById(id)
|
||||
if ($style != null) $style.outerHTML = ''
|
||||
style.id = id
|
||||
}
|
||||
// 应用新样式
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
|
||||
/** 用于js增强事件,运行JS代码,可以传参 */
|
||||
// options 所需参数:
|
||||
// 参数名 类型 说明
|
||||
// vm VueComponent vue实例
|
||||
// event Object event对象
|
||||
// jsCode String 待执行的js代码
|
||||
// errorMessage String 执行出错后的提示(控制台)
|
||||
export function jsExpand (options = {}) {
|
||||
// 绑定到window上的keyName
|
||||
const windowKeyName = 'J_CLICK_EVENT_OPTIONS'
|
||||
if (typeof window[windowKeyName] !== 'object') {
|
||||
window[windowKeyName] = {}
|
||||
}
|
||||
|
||||
// 随机生成JS增强的执行id,防止冲突
|
||||
const id = randomString(16, 'qwertyuioplkjhgfdsazxcvbnm'.toUpperCase())
|
||||
// 封装按钮点击事件
|
||||
const code = `
|
||||
(function (o_${id}) {
|
||||
try {
|
||||
(function (globalEvent, vm) {
|
||||
${options.jsCode}
|
||||
})(o_${id}.event, o_${id}.vm)
|
||||
} catch (e) {
|
||||
o_${id}.error(e)
|
||||
}
|
||||
o_${id}.done()
|
||||
})(window['${windowKeyName}']['EVENT_${id}'])
|
||||
`
|
||||
// 创建script标签
|
||||
const script = document.createElement('script')
|
||||
// 将需要传递的参数挂载到window对象上
|
||||
window[windowKeyName]['EVENT_' + id] = {
|
||||
vm: options.vm,
|
||||
event: options.event,
|
||||
// 当执行完成时,无论如何都会调用的回调事件
|
||||
done () {
|
||||
// 执行完后删除新增的 script 标签不会撤销执行结果(已产生的结果不会被撤销)
|
||||
script.outerHTML = ''
|
||||
delete window[windowKeyName]['EVENT_' + id]
|
||||
},
|
||||
// 当js运行出错的时候调用的事件
|
||||
error (e) {
|
||||
console.group(`${options.errorMessage || '用户自定义JS增强代码运行出错'}(${new Date()})`)
|
||||
console.error(e)
|
||||
console.groupEnd()
|
||||
}
|
||||
}
|
||||
// 将事件挂载到document中
|
||||
script.innerHTML = code
|
||||
document.body.appendChild(script)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重复值验证工具方法
|
||||
*
|
||||
* 使用示例:
|
||||
* { validator: (rule, value, callback) => validateDuplicateValue('sys_fill_rule', 'rule_code', value, this.model.id, callback) }
|
||||
*
|
||||
* @param tableName 被验证的表名
|
||||
* @param fieldName 被验证的字段名
|
||||
* @param fieldVal 被验证的值
|
||||
* @param dataId 数据ID,可空
|
||||
* @param callback
|
||||
*/
|
||||
export function validateDuplicateValue (tableName, fieldName, fieldVal, dataId, callback) {
|
||||
if (fieldVal) {
|
||||
const params = { tableName, fieldName, fieldVal, dataId }
|
||||
api.duplicateCheck(params).then(res => {
|
||||
res.success ? callback() : callback(res.message)
|
||||
}).catch(err => {
|
||||
callback(err.message || err)
|
||||
})
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编码校验规则code,校验传入的值是否合法
|
||||
*
|
||||
* 使用示例:
|
||||
* { validator: (rule, value, callback) => validateCheckRule('common', value, callback) }
|
||||
*
|
||||
* @param ruleCode 编码校验规则 code
|
||||
* @param value 被验证的值
|
||||
* @param callback
|
||||
*/
|
||||
export function validateCheckRule (ruleCode, value, callback) {
|
||||
if (ruleCode && value) {
|
||||
value = encodeURIComponent(value)
|
||||
api.checkRuleByCode({ ruleCode, value }).then(res => {
|
||||
res.success ? callback() : callback(res.message)
|
||||
}).catch(err => {
|
||||
callback(err.message || err)
|
||||
})
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果值不存在就 push 进数组,反之不处理
|
||||
* @param array 要操作的数据
|
||||
* @param value 要添加的值
|
||||
* @param key 可空,如果比较的是对象,可能存在地址不一样但值实际上是一样的情况,可以传此字段判断对象中唯一的字段,例如 id。不传则直接比较实际值
|
||||
* @returns {boolean} 成功 push 返回 true,不处理返回 false
|
||||
*/
|
||||
export function pushIfNotExist (array, value, key) {
|
||||
for (const item of array) {
|
||||
if (key && (item[key] === value[key])) {
|
||||
return false
|
||||
} else if (item === value) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
array.push(value)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* 可用于判断是否成功
|
||||
* @type {symbol}
|
||||
*/
|
||||
export const succeedSymbol = Symbol('')
|
||||
/**
|
||||
* 可用于判断是否失败
|
||||
* @type {symbol}
|
||||
*/
|
||||
export const failedSymbol = Symbol('')
|
||||
|
||||
/**
|
||||
* 使 promise 无论如何都会 resolve,除非传入的参数不是一个Promise对象或返回Promise对象的方法
|
||||
* 一般用在 Promise.all 中
|
||||
*
|
||||
* @param promise 可传Promise对象或返回Promise对象的方法
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export function alwaysResolve (promise) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let p = promise
|
||||
if (typeof promise === 'function') {
|
||||
p = promise()
|
||||
}
|
||||
if (p instanceof Promise) {
|
||||
p.then(data => {
|
||||
resolve({ type: succeedSymbol, data })
|
||||
}).catch(error => {
|
||||
resolve({ type: failedSymbol, error })
|
||||
})
|
||||
} else {
|
||||
reject('alwaysResolve: 传入的参数不是一个Promise对象或返回Promise对象的方法')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单实现防抖方法
|
||||
*
|
||||
* 防抖(debounce)函数在第一次触发给定的函数时,不立即执行函数,而是给出一个期限值(delay),比如100ms。
|
||||
* 如果100ms内再次执行函数,就重新开始计时,直到计时结束后再真正执行函数。
|
||||
* 这样做的好处是如果短时间内大量触发同一事件,只会执行一次函数。
|
||||
*
|
||||
* @param fn 要防抖的函数
|
||||
* @param delay 防抖的毫秒数
|
||||
* @returns {Function}
|
||||
*/
|
||||
export function simpleDebounce (fn, delay = 100) {
|
||||
let timer = null
|
||||
return function () {
|
||||
const args = arguments
|
||||
if (timer) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 不用正则的方式替换所有值
|
||||
* @param text 被替换的字符串
|
||||
* @param checker 替换前的内容
|
||||
* @param replacer 替换后的内容
|
||||
* @returns {String} 替换后的字符串
|
||||
*/
|
||||
export function replaceAll (text, checker, replacer) {
|
||||
const lastText = text
|
||||
text = text.replace(checker, replacer)
|
||||
if (lastText !== text) {
|
||||
return replaceAll(text, checker, replacer)
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取事件冒泡路径,兼容 IE11,Edge,Chrome,Firefox,Safari
|
||||
* 目前使用的地方:JEditableTable Span模式
|
||||
*/
|
||||
export function getEventPath (event) {
|
||||
const target = event.target
|
||||
const path = (event.composedPath && event.composedPath()) || event.path
|
||||
|
||||
if (path != null) {
|
||||
return (path.indexOf(window) < 0) ? path.concat(window) : path
|
||||
}
|
||||
|
||||
if (target === window) {
|
||||
return [window]
|
||||
}
|
||||
|
||||
const getParents = (node, memo) => {
|
||||
memo = memo || []
|
||||
const parentNode = node.parentNode
|
||||
|
||||
if (!parentNode) {
|
||||
return memo
|
||||
} else {
|
||||
return getParents(parentNode, memo.concat(parentNode))
|
||||
}
|
||||
}
|
||||
return [target].concat(getParents(target), window)
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据组件名获取父级
|
||||
* @param vm
|
||||
* @param name
|
||||
* @returns {Vue | null|null|Vue}
|
||||
*/
|
||||
export function getVmParentByName (vm, name) {
|
||||
const parent = vm.$parent
|
||||
if (parent && parent.$options) {
|
||||
if (parent.$options.name === name) {
|
||||
return parent
|
||||
} else {
|
||||
const res = getVmParentByName(parent, name)
|
||||
if (res) {
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 使一个值永远不会为(null | undefined)
|
||||
*
|
||||
* @param value 要处理的值
|
||||
* @param def 默认值,如果value为(null | undefined)则返回的默认值,可不传,默认为''
|
||||
*/
|
||||
export function neverNull (value, def) {
|
||||
return value == null ? (neverNull(def, '')) : value
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据元素值移除数组中的一个元素
|
||||
* @param array 数组
|
||||
* @param prod 属性名
|
||||
* @param value 属性值
|
||||
* @returns {string}
|
||||
*/
|
||||
export function removeArrayElement (array, prod, value) {
|
||||
let index = -1
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (array[i][prod] + '' === value + '') {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (index >= 0) {
|
||||
array.splice(index, 1)
|
||||
}
|
||||
}
|
||||
export function findFirstRoute (data) {
|
||||
if (data[0]) {
|
||||
if (data[0] && data[0].children && data[0].children.length > 0) {
|
||||
return findFirstRoute(data[0].children)
|
||||
} else {
|
||||
return data[0].path
|
||||
}
|
||||
} else {
|
||||
return '/'
|
||||
}
|
||||
}
|
||||
|
||||
/** 判断是否是OAuth2APP环境 */
|
||||
export function isOAuth2AppEnv () {
|
||||
return /wxwork|dingtalk/i.test(navigator.userAgent)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取积木报表打印地址
|
||||
* @param url
|
||||
* @param id
|
||||
* @param open 是否自动打开
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getReportPrintUrl (url, id, open) {
|
||||
// URL支持{{ window.xxx }}占位符变量
|
||||
url = url.replace(/{{([^}]+)?}}/g, (s1, s2) => evil(s2))
|
||||
if (url.includes('?')) {
|
||||
url += '&'
|
||||
} else {
|
||||
url += '?'
|
||||
}
|
||||
url += `id=${id}`
|
||||
url += `&token=${Vue.ls.get(ACCESS_TOKEN)}`
|
||||
if (open) {
|
||||
window.open(url)
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
/**
|
||||
* 解决eval的eslint问题
|
||||
* @param fn
|
||||
* @returns {*}
|
||||
*/
|
||||
export function evil (fn) {
|
||||
const Fn = Function // 一个变量指向Function,防止有些前端编译工具报错
|
||||
return new Fn('return ' + fn)()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将url的参数拆分成对象
|
||||
* @param url
|
||||
* @returns {{id: *, url}}
|
||||
*/
|
||||
export function urlToParams (url) {
|
||||
const commonUrl = window._CONFIG.staticDomainURL
|
||||
// url截取参数的部分
|
||||
const paramsStr = url.slice(url.indexOf('?') + 1)
|
||||
const paramsObj = {
|
||||
url,
|
||||
id: url.slice(url.indexOf(commonUrl) + commonUrl.length + 1, url.indexOf('?'))
|
||||
}
|
||||
paramsStr.split('&').forEach(item => {
|
||||
const arr = item.split('=')
|
||||
paramsObj[arr[0]] = arr[1]
|
||||
})
|
||||
return paramsObj
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 邮箱
|
||||
* @param {*} s
|
||||
* 之前的正则 /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
*/
|
||||
export function isEmail (s) {
|
||||
return /^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
* @param {*} s
|
||||
*/
|
||||
export function isMobile (s) {
|
||||
return /^1[0-9]{10}$/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* 电话号码
|
||||
* @param {*} s
|
||||
*/
|
||||
export function isPhone (s) {
|
||||
return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* URL地址
|
||||
* @param {*} s
|
||||
*/
|
||||
export function isURL (s) {
|
||||
return /^http[s]?:\/\/.*/.test(s)
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号或座机号
|
||||
*
|
||||
* /^((13[0-9])|(14[579])|(15([0-3]|[5-9]))|(17[0135678])|(18[0-9])|(19[8|9])|(16[6]))\d{8}$/
|
||||
* */
|
||||
export function phoneReg (s) {
|
||||
return /(^[1][3,456789][0-9]{9}$)|(^0\d{2,3}-?\d{7,8}$)/.test(s)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import Vue from 'vue'
|
||||
|
||||
Vue.directive('watermark', {
|
||||
bind: function (el, binding) {
|
||||
// 水印文字,父元素,画布宽度,画布高度,字体,文字颜色,画布横坐标
|
||||
function addWaterMarker (str, parentNode, width, height, font, textColor, fillTextX = '10') {
|
||||
// 检查父元素是否包含子元素
|
||||
const elementContains = (parent, child) => parent !== child && parent.contains(child)
|
||||
const flag = elementContains(parentNode, document.querySelector('canvas'))
|
||||
// 防止重复创建
|
||||
if (!flag) {
|
||||
const can = document.createElement('canvas')
|
||||
parentNode.appendChild(can)
|
||||
can.width = width || 300
|
||||
can.height = height || 140
|
||||
can.style.display = 'none'
|
||||
const cans = can.getContext('2d')
|
||||
cans.rotate(-20 * Math.PI / 180)
|
||||
cans.font = font || '13px Microsoft Yahei'
|
||||
cans.fillStyle = textColor || '#DDDDDD'
|
||||
cans.textAlign = 'left'
|
||||
cans.textBaseline = 'Middle'
|
||||
cans.fillText(str, fillTextX, can.height)
|
||||
// 设置背景图(整个项目中都添加水印建议使用此方法)
|
||||
// parentNode.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")";
|
||||
|
||||
// 创建div 定位覆盖(某个元素,如图片添加水印建议使用此方法)
|
||||
const div = document.createElement('div')
|
||||
div.id = str
|
||||
div.style.pointerEvents = 'none'
|
||||
div.style.top = '0'
|
||||
div.style.left = '0'
|
||||
div.style.position = 'absolute'
|
||||
div.style.zIndex = '100000'
|
||||
div.style.width = '100%'
|
||||
div.style.height = '100%'
|
||||
div.style.background = 'url(' + can.toDataURL('image/png') + ')'
|
||||
parentNode.appendChild(div)
|
||||
}
|
||||
}
|
||||
if (binding.value.text) {
|
||||
addWaterMarker(binding.value.text, el, binding.value.width, binding.value.height, binding.value.font, binding.value.textColor, binding.value.fillTextX)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
首页
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Home'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<!-- 移动端不支持时,显示的节点页面 -->
|
||||
<div>
|
||||
<div class="container">
|
||||
<div class="error">
|
||||
<img :src="require('@/assets/image/error.png')" alt="error">
|
||||
</div>
|
||||
<p>{{ $t('noMobile') }}</p>
|
||||
<p>{{ $t('toPc') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NoMobile'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.container {
|
||||
font-family: PingFang SC-Medium, PingFang SC, sans-serif;
|
||||
margin: 20vh auto 0;
|
||||
text-align: center;
|
||||
.error {
|
||||
font-size: 0;
|
||||
margin: 0 auto;
|
||||
width: 1.6rem;
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
p {
|
||||
font-size: 0.427rem;
|
||||
line-height: 0.607rem;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.error + p {
|
||||
margin-top: 0.773rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="less">
|
||||
@font-color: #34383F;
|
||||
#app > .van-nav-bar {
|
||||
background-color: #FFFFFF;
|
||||
|
||||
.van-nav-bar__title {
|
||||
color: @font-color;
|
||||
}
|
||||
.van-nav-bar__text {
|
||||
color: @font-color;
|
||||
}
|
||||
.van-icon {
|
||||
color: @font-color;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="login-box">
|
||||
|
||||
<van-field v-model="username" border center class="login-form-item" clearable placeholder="请输入账号"/>
|
||||
<van-field v-model="password" :autocomplete="false" border center class="login-form-item" placeholder="请输入密码" :type="passwordFieldType"
|
||||
@paste.native.capture.prevent="handleOperate">
|
||||
<template #right-icon>
|
||||
<div @click="switchPasswordType">
|
||||
<van-icon name="eye" v-if="passwordFieldType!=='password'"/>
|
||||
<van-icon name="closed-eye" v-else/>
|
||||
</div>
|
||||
</template>
|
||||
</van-field>
|
||||
<div class="random-image-box">
|
||||
<van-field v-model="captcha" maxlength="4" :autocomplete="false" border center class="login-form-item" clearable placeholder="请输入验证码"/>
|
||||
<template>
|
||||
<img class="random-image" v-if="requestCodeSuccess" :src="randCodeImage" @click="handleChangeCheckCode" alt="code"/>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<van-button class="login-btn" size="large" type="info" @click="handleSubmit">登录</van-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Toast } from 'vant'
|
||||
import { getRSAPublicKey } from '@/utils/encryption'
|
||||
import { JSEncrypt } from 'jsencrypt'
|
||||
import { mapActions } from 'vuex'
|
||||
import { getAction } from '@api/manage'
|
||||
|
||||
export default {
|
||||
name: 'LoginPage',
|
||||
data () {
|
||||
return {
|
||||
username: '',
|
||||
password: '',
|
||||
captcha: '', // 验证码
|
||||
rsaPublicKey: '', // 公钥
|
||||
requestCodeSuccess: false, // 请求验证码图片是否成功
|
||||
randCodeImage: '', // 验证码图片
|
||||
passwordFieldType: 'password'
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getPublicKey()
|
||||
this.handleChangeCheckCode()
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['Login']),
|
||||
// 获取RSA公钥
|
||||
getPublicKey () {
|
||||
// 获取公钥
|
||||
getRSAPublicKey().then(res => {
|
||||
this.rsaPublicKey = res.result
|
||||
})
|
||||
},
|
||||
handleChangeCheckCode () {
|
||||
this.currdatetime = new Date().getTime()
|
||||
getAction(`/sys/randomImage/${this.currdatetime}`).then(res => {
|
||||
if (res.success) {
|
||||
this.randCodeImage = res.result
|
||||
this.requestCodeSuccess = true
|
||||
} else {
|
||||
this.requestCodeSuccess = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.requestCodeSuccess = false
|
||||
})
|
||||
},
|
||||
handleSubmit () {
|
||||
if (!this.username) {
|
||||
Toast('请输入账号')
|
||||
return
|
||||
}
|
||||
if (!this.password) {
|
||||
Toast('请输入密码')
|
||||
return
|
||||
}
|
||||
if (!this.captcha) {
|
||||
Toast('请输入验证码')
|
||||
return
|
||||
}
|
||||
const loginParams = {
|
||||
rsaPublicKey: this.rsaPublicKey
|
||||
}
|
||||
// 新建JSEncrypt对象
|
||||
const encrypt = new JSEncrypt()
|
||||
encrypt.setPublicKey(loginParams.rsaPublicKey)
|
||||
// 公钥加密
|
||||
loginParams.username = encrypt.encrypt(this.username)
|
||||
loginParams.password = encrypt.encrypt(this.password)
|
||||
loginParams.captcha = this.captcha
|
||||
loginParams.checkKey = this.currdatetime
|
||||
this.Login(loginParams).then(res => {
|
||||
console.log(res, 'res')
|
||||
this.loginSuccess()
|
||||
}).catch((err) => {
|
||||
if (err.code === 500) {
|
||||
this.$toast(err.message)
|
||||
// 刷新验证码
|
||||
this.handleChangeCheckCode()
|
||||
this.captcha = ''
|
||||
}
|
||||
})
|
||||
},
|
||||
loginSuccess () {
|
||||
Toast('登录成功')
|
||||
this.$router.push({ path: '/' }).catch((res) => {
|
||||
console.log(res)
|
||||
})
|
||||
},
|
||||
// 密码禁止粘贴
|
||||
handleOperate () {
|
||||
return false
|
||||
},
|
||||
switchPasswordType () {
|
||||
this.passwordFieldType = this.passwordFieldType === 'password' ? 'text' : 'password'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.login-box {
|
||||
height: 100vh;
|
||||
padding: 20px;
|
||||
background-color: #ccc;
|
||||
.login-form-item {
|
||||
margin: 20px 0;
|
||||
}
|
||||
.login-btn {
|
||||
background-color: #D52C26;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,14 @@
|
||||
const primaryColor = '#D52C26'
|
||||
const white = '#FFFFFF'
|
||||
|
||||
module.exports = {
|
||||
// 定制主题:用于覆盖原组件的Less变量
|
||||
// 注意:每次修改完之后要重启服务才能生效
|
||||
theme: {
|
||||
// 导航栏
|
||||
'nav-bar-icon-color': white,
|
||||
'nav-bar-text-color': white,
|
||||
'nav-bar-title-text-color': white,
|
||||
'nav-bar-background-color': primaryColor,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
const path = require('path')
|
||||
const CompressionPlugin = require('compression-webpack-plugin')
|
||||
const { theme } = require('./vant.config')
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, dir)
|
||||
}
|
||||
|
||||
// vue.config.js
|
||||
module.exports = {
|
||||
/*
|
||||
Vue-cli3:
|
||||
Crashed when using Webpack `import()` #2463
|
||||
https://github.com/vuejs/vue-cli/issues/2463
|
||||
*/
|
||||
// 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
|
||||
productionSourceMap: false,
|
||||
// 打包app时放开该配置
|
||||
// publicPath:'./',
|
||||
configureWebpack: config => {
|
||||
// 生产环境取消 console.log
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
|
||||
}
|
||||
},
|
||||
chainWebpack: (config) => {
|
||||
config.resolve.alias
|
||||
.set('@$', resolve('src'))
|
||||
.set('@api', resolve('src/api'))
|
||||
.set('@assets', resolve('src/assets'))
|
||||
.set('@comp', resolve('src/components'))
|
||||
.set('@views', resolve('src/views'))
|
||||
|
||||
// 生产环境,开启js\css压缩
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
config.plugin('compressionPlugin').use(new CompressionPlugin({
|
||||
test: /\.(js|css|less)$/, // 匹配文件名
|
||||
threshold: 10240, // 对超过10k的数据压缩
|
||||
deleteOriginalAssets: false // 不删除源文件
|
||||
}))
|
||||
}
|
||||
|
||||
// 配置 webpack 识别 markdown 为普通的文件
|
||||
config.module
|
||||
.rule('markdown')
|
||||
.test(/\.md$/)
|
||||
.use()
|
||||
.loader('file-loader')
|
||||
.end()
|
||||
},
|
||||
|
||||
css: {
|
||||
loaderOptions: {
|
||||
less: {
|
||||
modifyVars: {
|
||||
/* less 变量覆盖,用于自定义 ant design 主题 */
|
||||
'primary-color': '#D52C26',
|
||||
'link-color': '#D52C26',
|
||||
'border-radius-base': '4px',
|
||||
/* vant组件变量覆盖 */
|
||||
...theme
|
||||
},
|
||||
javascriptEnabled: true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
devServer: {
|
||||
port: 3335,
|
||||
proxy: {
|
||||
/* '/api': {
|
||||
target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro', //mock API接口系统
|
||||
ws: false,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'/laws-sinotruk': '' //默认所有请求都加了jero-boot前缀,需要去掉
|
||||
}
|
||||
}, */
|
||||
'/laws-sinotruk': {
|
||||
target: 'http://localhost:8184',
|
||||
ws: false,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
// '/laws-sinotruk': '' // 默认所有请求都加了jero-boot前缀,需要去掉
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
lintOnSave: undefined
|
||||
}
|
||||
Reference in New Issue
Block a user