47 changed files with 10574 additions and 0 deletions
@ -0,0 +1,14 @@ |
|||||
|
# 页面标题 |
||||
|
VUE_APP_TITLE = 针灸管理系统 |
||||
|
|
||||
|
# 开发环境配置 |
||||
|
ENV = 'development' |
||||
|
|
||||
|
# 大唐会议管理系统/开发环境 |
||||
|
VUE_APP_BASE_API = '/dev-api' |
||||
|
VUE_APP_IMG_URL = 'https://test.tall.wiki/acupuncture' |
||||
|
VUE_APP_API_QZURL = 'https://test.tall.wiki/' |
||||
|
# 路由懒加载 |
||||
|
VUE_CLI_BABEL_TRANSPILE_MODULES = true |
||||
|
# 访问路径 |
||||
|
VUE_APP_PUBLIC_PATH = '/' |
@ -0,0 +1,11 @@ |
|||||
|
# 页面标题 |
||||
|
VUE_APP_TITLE = 针灸管理系统 |
||||
|
|
||||
|
# 生产环境配置 |
||||
|
NODE_ENV = 'production' |
||||
|
# 因孚生产 |
||||
|
VUE_APP_BASE_API = 'https://test.tall.wiki/acupuncture' |
||||
|
VUE_APP_API_QZURL = 'https://test.tall.wiki/' |
||||
|
|
||||
|
# 访问路径 |
||||
|
VUE_APP_PUBLIC_PATH = '/acupunctureClient/' |
@ -0,0 +1,12 @@ |
|||||
|
# 页面标题 |
||||
|
VUE_APP_TITLE = 针灸管理系统 |
||||
|
|
||||
|
BABEL_ENV = production |
||||
|
|
||||
|
NODE_ENV = production |
||||
|
|
||||
|
# 测试环境配置 |
||||
|
ENV = 'staging' |
||||
|
|
||||
|
# 针灸管理系统/测试环境 |
||||
|
VUE_APP_BASE_API = '/stage-api' |
@ -0,0 +1,30 @@ |
|||||
|
## 开发 |
||||
|
|
||||
|
```bash |
||||
|
# 克隆项目 |
||||
|
git clone https://gitee.com/y_project/RuoYi-Vue |
||||
|
|
||||
|
# 进入项目目录 |
||||
|
cd ruoyi-ui |
||||
|
|
||||
|
# 安装依赖 |
||||
|
npm install |
||||
|
|
||||
|
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 |
||||
|
npm install --registry=https://registry.npmmirror.com |
||||
|
|
||||
|
# 启动服务 |
||||
|
npm run dev |
||||
|
``` |
||||
|
|
||||
|
浏览器访问 http://localhost:80 |
||||
|
|
||||
|
## 发布 |
||||
|
|
||||
|
```bash |
||||
|
# 构建测试环境 |
||||
|
npm run build:stage |
||||
|
|
||||
|
# 构建生产环境 |
||||
|
npm run build:prod |
||||
|
``` |
Binary file not shown.
@ -0,0 +1,91 @@ |
|||||
|
{ |
||||
|
"name": "ruoyi", |
||||
|
"version": "3.8.9", |
||||
|
"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-Vue.git" |
||||
|
}, |
||||
|
"dependencies": { |
||||
|
"@riophae/vue-treeselect": "0.4.0", |
||||
|
"axios": "0.28.1", |
||||
|
"clipboard": "2.0.8", |
||||
|
"core-js": "3.37.1", |
||||
|
"echarts": "5.4.0", |
||||
|
"element-ui": "^2.15.14", |
||||
|
"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": "2.0.2", |
||||
|
"screenfull": "5.0.2", |
||||
|
"sortablejs": "1.10.2", |
||||
|
"splitpanes": "2.4.1", |
||||
|
"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": "6.1.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" |
||||
|
] |
||||
|
} |
@ -0,0 +1,70 @@ |
|||||
|
<template> |
||||
|
<div id="app"> |
||||
|
<router-view /> |
||||
|
<theme-picker /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import ThemePicker from "@/components/ThemePicker"; |
||||
|
|
||||
|
export default { |
||||
|
name: "App", |
||||
|
components: { ThemePicker }, |
||||
|
metaInfo() { |
||||
|
return { |
||||
|
title: |
||||
|
this.$store.state.settings.dynamicTitle && |
||||
|
this.$store.state.settings.title, |
||||
|
titleTemplate: (title) => { |
||||
|
return title |
||||
|
? `${title} - ${process.env.VUE_APP_TITLE}` |
||||
|
: process.env.VUE_APP_TITLE; |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
#app .theme-picker { |
||||
|
display: none; |
||||
|
} |
||||
|
</style> |
||||
|
<style> |
||||
|
.wj-uploader .el-icon-upload:before { |
||||
|
font-size: 100px; |
||||
|
} |
||||
|
.wj-uploader .el-upload { |
||||
|
display: flex; |
||||
|
align-content: center; |
||||
|
justify-content: center; |
||||
|
flex-wrap: wrap; |
||||
|
} |
||||
|
.wj-uploader .el-upload__text { |
||||
|
line-height: 20px; |
||||
|
width: 100% !important; |
||||
|
} |
||||
|
.avatar-uploader { |
||||
|
height: 180px; |
||||
|
} |
||||
|
.avatar-uploader .el-upload { |
||||
|
border: 1px dashed #d9d9d9 !important; |
||||
|
border-radius: 6px; |
||||
|
cursor: pointer; |
||||
|
position: relative; |
||||
|
overflow: hidden; |
||||
|
width: 100% !important; |
||||
|
height: 180px !important; |
||||
|
line-height: 150px; |
||||
|
} |
||||
|
.el-upload-dragger, |
||||
|
.el-upload { |
||||
|
width: 100% !important; |
||||
|
} |
||||
|
.el-upload-list__item { |
||||
|
transition: none !important; |
||||
|
} |
||||
|
.el-upload-list__item:first-child { |
||||
|
margin-top: 0; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,75 @@ |
|||||
|
import request from "@/utils/request"; |
||||
|
|
||||
|
// 随访队列
|
||||
|
export function followupQuery(data) { |
||||
|
return request({ |
||||
|
url: "/followup/query", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 新增随访队列
|
||||
|
export function followupAdd(data) { |
||||
|
return request({ |
||||
|
url: "/followup/add", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 新增随访队列
|
||||
|
export function followupUpd(data) { |
||||
|
return request({ |
||||
|
url: "/followup/upd", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 新增随访队列
|
||||
|
export function followupDel(data) { |
||||
|
return request({ |
||||
|
url: "/followup/del", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// ----随访对象----
|
||||
|
// 查看随访对象
|
||||
|
export function queryPatient(data) { |
||||
|
return request({ |
||||
|
url: "/followup/queryPatient", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 修改随访对象 队列信息
|
||||
|
export function updPatient(data) { |
||||
|
return request({ |
||||
|
url: "/followup/updPatient", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 随访工单
|
||||
|
export function queryTask(data) { |
||||
|
return request({ |
||||
|
url: "/followup/queryTask", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 失访
|
||||
|
export function updStatus(data) { |
||||
|
return request({ |
||||
|
url: "/followup/updStatus", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 患者随访
|
||||
|
export function followPatient(data) { |
||||
|
return request({ |
||||
|
url: "/followup/followPatient", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,60 @@ |
|||||
|
import request from "@/utils/request"; |
||||
|
|
||||
|
// 登录方法
|
||||
|
export function login(username, password, code, uuid) { |
||||
|
const data = { |
||||
|
username, |
||||
|
password, |
||||
|
code, |
||||
|
uuid, |
||||
|
}; |
||||
|
return request({ |
||||
|
url: "/web/login", |
||||
|
headers: { |
||||
|
isToken: false, |
||||
|
repeatSubmit: false, |
||||
|
}, |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 注册方法
|
||||
|
export function register(data) { |
||||
|
return request({ |
||||
|
url: "/register", |
||||
|
headers: { |
||||
|
isToken: false, |
||||
|
}, |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 获取用户详细信息
|
||||
|
export function getInfo() { |
||||
|
return request({ |
||||
|
url: "/getInfo", |
||||
|
method: "get", |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 退出方法
|
||||
|
export function logout() { |
||||
|
return request({ |
||||
|
url: "/logout", |
||||
|
method: "post", |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// 获取验证码
|
||||
|
export function getCodeImg() { |
||||
|
return request({ |
||||
|
url: "/captchaImage", |
||||
|
headers: { |
||||
|
isToken: false, |
||||
|
}, |
||||
|
method: "get", |
||||
|
timeout: 20000, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,58 @@ |
|||||
|
import request from "@/utils/request"; |
||||
|
|
||||
|
// 获取列表
|
||||
|
export function treatmentQuery(data) { |
||||
|
return request({ |
||||
|
url: "/treatment/list", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 添加患者档案
|
||||
|
export function treatmentAdd(data) { |
||||
|
return request({ |
||||
|
url: "/treatment/add", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 修改患者档案
|
||||
|
export function treatmentUpd(data) { |
||||
|
return request({ |
||||
|
url: "/treatment/upd", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 删除患者档案
|
||||
|
export function treatmentDel(data) { |
||||
|
return request({ |
||||
|
url: "/treatment/del", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 档案详情
|
||||
|
export function queryRecord(data) { |
||||
|
return request({ |
||||
|
url: "/treatment/queryRecord", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
}// 档案详情
|
||||
|
export function saveAidRecord(data) { |
||||
|
return request({ |
||||
|
url: "/treatment/saveAidRecord", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 诊疗档案绑定随访队列
|
||||
|
|
||||
|
export function queueAdd(data) { |
||||
|
return request({ |
||||
|
url: "/patientQueueRelation/add", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
import request from "@/utils/request"; |
||||
|
|
||||
|
// 获取列表
|
||||
|
export function queryPatient(data) { |
||||
|
return request({ |
||||
|
url: "/patient/list", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 添加患者档案
|
||||
|
export function patientAdd(data) { |
||||
|
return request({ |
||||
|
url: "/patient/add", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 修改患者档案
|
||||
|
export function patientUpd(data) { |
||||
|
return request({ |
||||
|
url: "/patient/upd", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
||||
|
// 删除患者档案
|
||||
|
export function patientDel(data) { |
||||
|
return request({ |
||||
|
url: "/patient/del", |
||||
|
method: "post", |
||||
|
data: data, |
||||
|
}); |
||||
|
} |
@ -0,0 +1,136 @@ |
|||||
|
import request from '@/utils/request' |
||||
|
import { parseStrEmpty } from "@/utils/ruoyi"; |
||||
|
|
||||
|
// 查询用户列表
|
||||
|
export function listUser(query) { |
||||
|
return request({ |
||||
|
url: '/system/user/list', |
||||
|
method: 'get', |
||||
|
params: query |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 查询用户详细
|
||||
|
export function getUser(userId) { |
||||
|
return request({ |
||||
|
url: '/system/user/' + parseStrEmpty(userId), |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 新增用户
|
||||
|
export function addUser(data) { |
||||
|
return request({ |
||||
|
url: '/system/user', |
||||
|
method: 'post', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 修改用户
|
||||
|
export function updateUser(data) { |
||||
|
return request({ |
||||
|
url: '/system/user', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 删除用户
|
||||
|
export function delUser(userId) { |
||||
|
return request({ |
||||
|
url: '/system/user/' + userId, |
||||
|
method: 'delete' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 用户密码重置
|
||||
|
export function resetUserPwd(userId, password) { |
||||
|
const data = { |
||||
|
userId, |
||||
|
password |
||||
|
} |
||||
|
return request({ |
||||
|
url: '/system/user/resetPwd', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 用户状态修改
|
||||
|
export function changeUserStatus(userId, status) { |
||||
|
const data = { |
||||
|
userId, |
||||
|
status |
||||
|
} |
||||
|
return request({ |
||||
|
url: '/system/user/changeStatus', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 查询用户个人信息
|
||||
|
export function getUserProfile() { |
||||
|
return request({ |
||||
|
url: '/system/user/profile', |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 修改用户个人信息
|
||||
|
export function updateUserProfile(data) { |
||||
|
return request({ |
||||
|
url: '/system/user/profile', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 用户密码重置
|
||||
|
export function updateUserPwd(oldPassword, newPassword) { |
||||
|
const data = { |
||||
|
oldPassword, |
||||
|
newPassword |
||||
|
} |
||||
|
return request({ |
||||
|
url: '/system/user/profile/updatePwd', |
||||
|
method: 'put', |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 用户头像上传
|
||||
|
export function uploadAvatar(data) { |
||||
|
return request({ |
||||
|
url: '/system/user/profile/avatar', |
||||
|
method: 'post', |
||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, |
||||
|
data: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 查询授权角色
|
||||
|
export function getAuthRole(userId) { |
||||
|
return request({ |
||||
|
url: '/system/user/authRole/' + userId, |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 保存授权角色
|
||||
|
export function updateAuthRole(data) { |
||||
|
return request({ |
||||
|
url: '/system/user/authRole', |
||||
|
method: 'put', |
||||
|
params: data |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
// 查询部门下拉树结构
|
||||
|
export function deptTreeSelect() { |
||||
|
return request({ |
||||
|
url: '/system/user/deptTree', |
||||
|
method: 'get' |
||||
|
}) |
||||
|
} |
@ -0,0 +1,135 @@ |
|||||
|
.popup { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.popup >>> .el-dialog { |
||||
|
max-height: 86vh; |
||||
|
/* margin-top: 0 !important; */ |
||||
|
overflow: auto; |
||||
|
border-radius: 6px; |
||||
|
} |
||||
|
>>>.el-dialog__header{ |
||||
|
padding-bottom: 20px; |
||||
|
} |
||||
|
.popup >>> .el-dialog::-webkit-scrollbar { |
||||
|
display: none; |
||||
|
} |
||||
|
.popup >>> .el-dialog::-webkit-scrollbar { |
||||
|
display: none; |
||||
|
} |
||||
|
.popup >>> .el-dialog:not(.is-fullscreen) { |
||||
|
margin-top: 0 !important; |
||||
|
} |
||||
|
.popup >>> .popupAdd { |
||||
|
height: 58px; |
||||
|
font-size: 14px; |
||||
|
line-height: 58px; |
||||
|
display: flex; |
||||
|
margin-bottom: 20px; |
||||
|
margin-top: 20px; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.popup >>> .popupAdd2 { |
||||
|
padding-left: 1px; |
||||
|
|
||||
|
/* background-image: url(../images/addlog.png); */ |
||||
|
background-repeat: no-repeat; |
||||
|
} |
||||
|
.popup >>> .popupAdd3 { |
||||
|
margin-top: 20px; |
||||
|
padding-left: 1px; |
||||
|
/* background-image: url(../images/tj.png); */ |
||||
|
} |
||||
|
.popup .popupbox { |
||||
|
width: 650px; |
||||
|
height: 600px; |
||||
|
/* background-image: url(../images/solid.png); */ |
||||
|
} |
||||
|
/* .popup >>> .popupAdd .popupleft { |
||||
|
font-size: 14px; |
||||
|
position: relative; |
||||
|
z-index: 2; |
||||
|
width: 68px; |
||||
|
height: 62px; |
||||
|
line-height: 62px; |
||||
|
text-align: center; |
||||
|
background-image: url(../images/addlog.png); |
||||
|
background-size: 100% 100%; |
||||
|
} */ |
||||
|
.formStep >>> .el-icon-delete { |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
.popup >>> .popupAdd .popupRight { |
||||
|
width: 100%; |
||||
|
margin-left: -20px; |
||||
|
height: 50px; |
||||
|
margin-top: 1px; |
||||
|
padding-left: 30px; |
||||
|
line-height: 50px; |
||||
|
font-size: 18px; |
||||
|
} |
||||
|
.inner::-webkit-scrollbar { |
||||
|
display: none; |
||||
|
} |
||||
|
>>>.el-dialog__body{ |
||||
|
padding: 0px 20px 0px 20px; |
||||
|
} |
||||
|
/* .popup >>> .popupAdd2 .popupleft { |
||||
|
width: 55px; |
||||
|
} */ |
||||
|
.formStep .el-button { |
||||
|
width: 68px; |
||||
|
height: 32px; |
||||
|
line-height: 32px; |
||||
|
background-size: 100% 100%; |
||||
|
border: none; |
||||
|
padding: 0; |
||||
|
opacity: 0.87; |
||||
|
} |
||||
|
.popup .el-button:hover { |
||||
|
opacity: 1; |
||||
|
} |
||||
|
.popup .popuButbox > div { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
|
||||
|
/* .formStep >>> .el-checkbox__input.is-checked .el-checkbox__inner { |
||||
|
background-color: #67defc; |
||||
|
border-color: #67defc; |
||||
|
} |
||||
|
.formStep >>> .is-checked .el-checkbox__label { |
||||
|
color: #67defc; |
||||
|
} */ |
||||
|
.formStep .formStep_StepBox { |
||||
|
display: flex; |
||||
|
} |
||||
|
.formStep .StepBox { |
||||
|
width: 620px; |
||||
|
} |
||||
|
|
||||
|
.formStep >>> .el-input__inner, |
||||
|
.formStep >>> .el-textarea__inner { |
||||
|
/* color: #fff; */ |
||||
|
background: rgba(0, 0, 0, 0); |
||||
|
} |
||||
|
.formStep >>> .el-textarea__inner { |
||||
|
/* color: rgb(191, 203, 217); */ |
||||
|
} |
||||
|
.formStep >>> .vue-treeselect__single-value { |
||||
|
color: rgb(191, 203, 217); |
||||
|
} |
||||
|
.formStep >>> .el-input__inner::input-placeholder { |
||||
|
color: #a8c9f0; |
||||
|
} |
||||
|
.formStep >>> .el-input--medium .el-input__inner, |
||||
|
.formStep >>> .el-textarea__inner, |
||||
|
.formStep >>> .el-select, |
||||
|
.formStep >>> .el-input-number--medium, |
||||
|
.formStep >>> .el-date-editor.el-input, |
||||
|
.formStep >>> .el-cascader--medium, |
||||
|
.formStep >>> .el-autocomplete { |
||||
|
width: 100% !important; |
||||
|
text-align: left; |
||||
|
} |
@ -0,0 +1,296 @@ |
|||||
|
/** |
||||
|
* 通用css样式布局处理 |
||||
|
* Copyright (c) 2019 ruoyi |
||||
|
*/ |
||||
|
|
||||
|
/** 基础通用 **/ |
||||
|
.pt5 { |
||||
|
padding-top: 5px; |
||||
|
} |
||||
|
|
||||
|
.pr5 { |
||||
|
padding-right: 5px; |
||||
|
} |
||||
|
|
||||
|
.pb5 { |
||||
|
padding-bottom: 5px; |
||||
|
} |
||||
|
|
||||
|
.mt5 { |
||||
|
margin-top: 5px; |
||||
|
} |
||||
|
|
||||
|
.mr5 { |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
|
||||
|
.mb5 { |
||||
|
margin-bottom: 5px; |
||||
|
} |
||||
|
|
||||
|
.mb8 { |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
.ml5 { |
||||
|
margin-left: 5px; |
||||
|
} |
||||
|
|
||||
|
.mt10 { |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
|
||||
|
.mr10 { |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
|
||||
|
.mb10 { |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
.ml10 { |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
|
||||
|
.mt20 { |
||||
|
margin-top: 20px; |
||||
|
} |
||||
|
|
||||
|
.mr20 { |
||||
|
margin-right: 20px; |
||||
|
} |
||||
|
|
||||
|
.mb20 { |
||||
|
margin-bottom: 20px; |
||||
|
} |
||||
|
.ml20 { |
||||
|
margin-left: 20px; |
||||
|
} |
||||
|
|
||||
|
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { |
||||
|
font-family: inherit; |
||||
|
font-weight: 500; |
||||
|
line-height: 1.1; |
||||
|
color: inherit; |
||||
|
} |
||||
|
|
||||
|
.el-message-box__status + .el-message-box__message{ |
||||
|
word-break: break-word; |
||||
|
} |
||||
|
|
||||
|
.el-dialog:not(.is-fullscreen) { |
||||
|
margin-top: 6vh !important; |
||||
|
} |
||||
|
|
||||
|
.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body { |
||||
|
overflow: auto; |
||||
|
overflow-x: hidden; |
||||
|
max-height: 70vh; |
||||
|
padding: 10px 20px 0; |
||||
|
} |
||||
|
|
||||
|
.el-table { |
||||
|
.el-table__header-wrapper, .el-table__fixed-header-wrapper { |
||||
|
th { |
||||
|
word-break: break-word; |
||||
|
background-color: #f8f8f9; |
||||
|
color: #515a6e; |
||||
|
height: 40px; |
||||
|
font-size: 13px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-table__body-wrapper { |
||||
|
.el-button [class*="el-icon-"] + span { |
||||
|
margin-left: 1px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** 表单布局 **/ |
||||
|
.form-header { |
||||
|
font-size: 15px; |
||||
|
color: #6379bb; |
||||
|
border-bottom: 1px solid #ddd; |
||||
|
margin: 8px 10px 25px 10px; |
||||
|
padding-bottom: 5px |
||||
|
} |
||||
|
|
||||
|
/** 表格布局 **/ |
||||
|
.pagination-container { |
||||
|
position: relative; |
||||
|
height: 32px; |
||||
|
margin-bottom: 10px; |
||||
|
margin-top: 15px; |
||||
|
padding: 10px 20px !important; |
||||
|
} |
||||
|
|
||||
|
/* tree border */ |
||||
|
.tree-border { |
||||
|
margin-top: 5px; |
||||
|
border: 1px solid #e5e6e7; |
||||
|
background: #FFFFFF none; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
|
||||
|
.pagination-container .el-pagination { |
||||
|
right: 0; |
||||
|
position: absolute; |
||||
|
} |
||||
|
|
||||
|
@media (max-width: 768px) { |
||||
|
.pagination-container .el-pagination > .el-pagination__jump { |
||||
|
display: none !important; |
||||
|
} |
||||
|
.pagination-container .el-pagination > .el-pagination__sizes { |
||||
|
display: none !important; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-table .fixed-width .el-button--mini { |
||||
|
padding-left: 0; |
||||
|
padding-right: 0; |
||||
|
width: inherit; |
||||
|
} |
||||
|
|
||||
|
/** 表格更多操作下拉样式 */ |
||||
|
.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine { |
||||
|
cursor: pointer; |
||||
|
margin-left: 5px; |
||||
|
} |
||||
|
|
||||
|
.el-table .el-dropdown, .el-icon-arrow-down { |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.el-tree-node__content > .el-checkbox { |
||||
|
margin-right: 8px; |
||||
|
} |
||||
|
|
||||
|
.list-group-striped > .list-group-item { |
||||
|
border-left: 0; |
||||
|
border-right: 0; |
||||
|
border-radius: 0; |
||||
|
padding-left: 0; |
||||
|
padding-right: 0; |
||||
|
} |
||||
|
|
||||
|
.list-group { |
||||
|
padding-left: 0px; |
||||
|
list-style: none; |
||||
|
} |
||||
|
|
||||
|
.list-group-item { |
||||
|
border-bottom: 1px solid #e7eaec; |
||||
|
border-top: 1px solid #e7eaec; |
||||
|
margin-bottom: -1px; |
||||
|
padding: 11px 0px; |
||||
|
font-size: 13px; |
||||
|
} |
||||
|
|
||||
|
.pull-right { |
||||
|
float: right !important; |
||||
|
} |
||||
|
|
||||
|
.el-card__header { |
||||
|
padding: 14px 15px 7px; |
||||
|
min-height: 40px; |
||||
|
} |
||||
|
|
||||
|
.el-card__body { |
||||
|
padding: 15px 20px 20px 20px; |
||||
|
} |
||||
|
|
||||
|
.card-box { |
||||
|
padding-right: 15px; |
||||
|
padding-left: 15px; |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
|
||||
|
/* button color */ |
||||
|
.el-button--cyan.is-active, |
||||
|
.el-button--cyan:active { |
||||
|
background: #20B2AA; |
||||
|
border-color: #20B2AA; |
||||
|
color: #FFFFFF; |
||||
|
} |
||||
|
|
||||
|
.el-button--cyan:focus, |
||||
|
.el-button--cyan:hover { |
||||
|
background: #48D1CC; |
||||
|
border-color: #48D1CC; |
||||
|
color: #FFFFFF; |
||||
|
} |
||||
|
|
||||
|
.el-button--cyan { |
||||
|
background-color: #20B2AA; |
||||
|
border-color: #20B2AA; |
||||
|
color: #FFFFFF; |
||||
|
} |
||||
|
|
||||
|
/* text color */ |
||||
|
.text-navy { |
||||
|
color: #1ab394; |
||||
|
} |
||||
|
|
||||
|
.text-primary { |
||||
|
color: inherit; |
||||
|
} |
||||
|
|
||||
|
.text-success { |
||||
|
color: #1c84c6; |
||||
|
} |
||||
|
|
||||
|
.text-info { |
||||
|
color: #23c6c8; |
||||
|
} |
||||
|
|
||||
|
.text-warning { |
||||
|
color: #f8ac59; |
||||
|
} |
||||
|
|
||||
|
.text-danger { |
||||
|
color: #ed5565; |
||||
|
} |
||||
|
|
||||
|
.text-muted { |
||||
|
color: #888888; |
||||
|
} |
||||
|
|
||||
|
/* image */ |
||||
|
.img-circle { |
||||
|
border-radius: 50%; |
||||
|
} |
||||
|
|
||||
|
.img-lg { |
||||
|
width: 120px; |
||||
|
height: 120px; |
||||
|
} |
||||
|
|
||||
|
.avatar-upload-preview { |
||||
|
position: relative; |
||||
|
top: 50%; |
||||
|
left: 50%; |
||||
|
transform: translate(-50%, -50%); |
||||
|
width: 200px; |
||||
|
height: 200px; |
||||
|
border-radius: 50%; |
||||
|
box-shadow: 0 0 4px #ccc; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* 拖拽列样式 */ |
||||
|
.sortable-ghost { |
||||
|
opacity: .8; |
||||
|
color: #fff !important; |
||||
|
background: #42b983 !important; |
||||
|
} |
||||
|
|
||||
|
.top-right-btn { |
||||
|
position: relative; |
||||
|
float: right; |
||||
|
} |
||||
|
|
||||
|
/* 分割面板样式 */ |
||||
|
.splitpanes.default-theme .splitpanes__pane { |
||||
|
background-color: #fff!important; |
||||
|
} |
@ -0,0 +1,216 @@ |
|||||
|
<template> |
||||
|
<div :class="{ show: show }" class="header-search"> |
||||
|
<svg-icon |
||||
|
class-name="search-icon" |
||||
|
icon-class="search" |
||||
|
@click.stop="click" |
||||
|
/> |
||||
|
<el-select |
||||
|
ref="headerSearchSelect" |
||||
|
v-model="search" |
||||
|
:remote-method="querySearch" |
||||
|
filterable |
||||
|
default-first-option |
||||
|
remote |
||||
|
placeholder="Search" |
||||
|
class="header-search-select" |
||||
|
@change="change" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="option in options" |
||||
|
:key="option.item.path" |
||||
|
:value="option.item" |
||||
|
:label="option.item.title.join(' > ')" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
// fuse is a lightweight fuzzy-search module |
||||
|
// make search results more in line with expectations |
||||
|
import Fuse from "fuse.js/dist/fuse.min.js"; |
||||
|
import path from "path"; |
||||
|
import { isHttp } from "@/utils/validate"; |
||||
|
|
||||
|
export default { |
||||
|
name: "HeaderSearch", |
||||
|
data() { |
||||
|
return { |
||||
|
search: "", |
||||
|
options: [], |
||||
|
searchPool: [], |
||||
|
show: false, |
||||
|
fuse: undefined, |
||||
|
}; |
||||
|
}, |
||||
|
computed: { |
||||
|
routes() { |
||||
|
return this.$store.getters.permission_routes; |
||||
|
}, |
||||
|
}, |
||||
|
watch: { |
||||
|
routes() { |
||||
|
this.searchPool = this.generateRoutes(this.routes); |
||||
|
}, |
||||
|
searchPool(list) { |
||||
|
this.initFuse(list); |
||||
|
}, |
||||
|
show(value) { |
||||
|
if (value) { |
||||
|
document.body.addEventListener("click", this.close); |
||||
|
} else { |
||||
|
document.body.removeEventListener("click", this.close); |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.searchPool = this.generateRoutes(this.routes); |
||||
|
}, |
||||
|
methods: { |
||||
|
click() { |
||||
|
this.show = !this.show; |
||||
|
if (this.show) { |
||||
|
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus(); |
||||
|
} |
||||
|
}, |
||||
|
close() { |
||||
|
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur(); |
||||
|
this.options = []; |
||||
|
this.show = false; |
||||
|
}, |
||||
|
change(val) { |
||||
|
const path = val.path; |
||||
|
const query = val.query; |
||||
|
if (isHttp(val.path)) { |
||||
|
// http(s):// 路径新窗口打开 |
||||
|
const pindex = path.indexOf("http"); |
||||
|
window.open(path.substr(pindex, path.length), "_blank"); |
||||
|
} else { |
||||
|
if (query) { |
||||
|
this.$router.push({ path: path, query: JSON.parse(query) }); |
||||
|
} else { |
||||
|
this.$router.push(path); |
||||
|
} |
||||
|
} |
||||
|
this.search = ""; |
||||
|
this.options = []; |
||||
|
this.$nextTick(() => { |
||||
|
this.show = false; |
||||
|
}); |
||||
|
}, |
||||
|
initFuse(list) { |
||||
|
this.fuse = new Fuse(list, { |
||||
|
shouldSort: true, |
||||
|
threshold: 0.4, |
||||
|
location: 0, |
||||
|
distance: 100, |
||||
|
minMatchCharLength: 1, |
||||
|
keys: [ |
||||
|
{ |
||||
|
name: "title", |
||||
|
weight: 0.7, |
||||
|
}, |
||||
|
{ |
||||
|
name: "path", |
||||
|
weight: 0.3, |
||||
|
}, |
||||
|
], |
||||
|
}); |
||||
|
}, |
||||
|
// Filter out the routes that can be displayed in the sidebar |
||||
|
// And generate the internationalized title |
||||
|
generateRoutes(routes, basePath = "/", prefixTitle = []) { |
||||
|
let res = []; |
||||
|
|
||||
|
for (const router of routes) { |
||||
|
// skip hidden router |
||||
|
if (router.hidden) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
const data = { |
||||
|
path: !isHttp(router.path) |
||||
|
? path.resolve(basePath, router.path) |
||||
|
: router.path, |
||||
|
title: [...prefixTitle], |
||||
|
}; |
||||
|
|
||||
|
if (router.meta && router.meta.title) { |
||||
|
data.title = [...data.title, router.meta.title]; |
||||
|
|
||||
|
if (router.redirect !== "noRedirect") { |
||||
|
// only push the routes with title |
||||
|
// special case: need to exclude parent router without redirect |
||||
|
res.push(data); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (router.query) { |
||||
|
data.query = router.query; |
||||
|
} |
||||
|
|
||||
|
// recursive child routes |
||||
|
if (router.children) { |
||||
|
const tempRoutes = this.generateRoutes( |
||||
|
router.children, |
||||
|
data.path, |
||||
|
data.title |
||||
|
); |
||||
|
if (tempRoutes.length >= 1) { |
||||
|
res = [...res, ...tempRoutes]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return res; |
||||
|
}, |
||||
|
querySearch(query) { |
||||
|
if (query !== "") { |
||||
|
this.options = this.fuse.search(query); |
||||
|
} else { |
||||
|
this.options = []; |
||||
|
} |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.header-search { |
||||
|
font-size: 0 !important; |
||||
|
|
||||
|
.search-icon { |
||||
|
cursor: pointer; |
||||
|
font-size: 18px; |
||||
|
vertical-align: middle; |
||||
|
} |
||||
|
|
||||
|
.header-search-select { |
||||
|
font-size: 18px; |
||||
|
transition: width 0.2s; |
||||
|
width: 0; |
||||
|
overflow: hidden; |
||||
|
background: transparent; |
||||
|
border-radius: 0; |
||||
|
display: inline-block; |
||||
|
vertical-align: middle; |
||||
|
|
||||
|
::v-deep .el-input__inner { |
||||
|
border-radius: 0; |
||||
|
border: 0; |
||||
|
padding-left: 0; |
||||
|
padding-right: 0; |
||||
|
box-shadow: none !important; |
||||
|
border-bottom: 1px solid #d9d9d9; |
||||
|
vertical-align: middle; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.show { |
||||
|
.header-search-select { |
||||
|
width: 210px; |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,21 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<svg-icon icon-class="question" @click="goto" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'RuoYiDoc', |
||||
|
data() { |
||||
|
return { |
||||
|
url: 'http://doc.ruoyi.vip/ruoyi-vue' |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
goto() { |
||||
|
window.open(this.url) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
@ -0,0 +1,21 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<svg-icon icon-class="github" @click="goto" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'RuoYiGit', |
||||
|
data() { |
||||
|
return { |
||||
|
url: 'https://gitee.com/y_project/RuoYi-Vue' |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
goto() { |
||||
|
window.open(this.url) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
@ -0,0 +1,64 @@ |
|||||
|
/** |
||||
|
* v-dialogDrag 弹窗拖拽 |
||||
|
* Copyright (c) 2019 ruoyi |
||||
|
*/ |
||||
|
|
||||
|
export default { |
||||
|
bind(el, binding, vnode, oldVnode) { |
||||
|
const value = binding.value |
||||
|
if (value == false) return |
||||
|
// 获取拖拽内容头部
|
||||
|
const dialogHeaderEl = el.querySelector('.el-dialog__header'); |
||||
|
const dragDom = el.querySelector('.el-dialog'); |
||||
|
dialogHeaderEl.style.cursor = 'move'; |
||||
|
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
|
||||
|
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null); |
||||
|
dragDom.style.position = 'absolute'; |
||||
|
dragDom.style.marginTop = 0; |
||||
|
let width = dragDom.style.width; |
||||
|
if (width.includes('%')) { |
||||
|
width = +document.body.clientWidth * (+width.replace(/\%/g, '') / 100); |
||||
|
} else { |
||||
|
width = +width.replace(/\px/g, ''); |
||||
|
} |
||||
|
dragDom.style.left = `${(document.body.clientWidth - width) / 2}px`; |
||||
|
// 鼠标按下事件
|
||||
|
dialogHeaderEl.onmousedown = (e) => { |
||||
|
// 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离)
|
||||
|
const disX = e.clientX - dialogHeaderEl.offsetLeft; |
||||
|
const disY = e.clientY - dialogHeaderEl.offsetTop; |
||||
|
|
||||
|
// 获取到的值带px 正则匹配替换
|
||||
|
let styL, styT; |
||||
|
|
||||
|
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
|
||||
|
if (sty.left.includes('%')) { |
||||
|
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100); |
||||
|
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100); |
||||
|
} else { |
||||
|
styL = +sty.left.replace(/\px/g, ''); |
||||
|
styT = +sty.top.replace(/\px/g, ''); |
||||
|
}; |
||||
|
|
||||
|
// 鼠标拖拽事件
|
||||
|
document.onmousemove = function (e) { |
||||
|
// 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离)
|
||||
|
const l = e.clientX - disX; |
||||
|
const t = e.clientY - disY; |
||||
|
|
||||
|
let finallyL = l + styL |
||||
|
let finallyT = t + styT |
||||
|
|
||||
|
// 移动当前元素
|
||||
|
dragDom.style.left = `${finallyL}px`; |
||||
|
dragDom.style.top = `${finallyT}px`; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
document.onmouseup = function (e) { |
||||
|
document.onmousemove = null; |
||||
|
document.onmouseup = null; |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
}; |
@ -0,0 +1,34 @@ |
|||||
|
/** |
||||
|
* v-dialogDragWidth 可拖动弹窗高度(右下角) |
||||
|
* Copyright (c) 2019 ruoyi |
||||
|
*/ |
||||
|
|
||||
|
export default { |
||||
|
bind(el) { |
||||
|
const dragDom = el.querySelector('.el-dialog'); |
||||
|
const lineEl = document.createElement('div'); |
||||
|
lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;'; |
||||
|
lineEl.addEventListener('mousedown', |
||||
|
function(e) { |
||||
|
// 鼠标按下,计算当前元素距离可视区的距离
|
||||
|
const disX = e.clientX - el.offsetLeft; |
||||
|
const disY = e.clientY - el.offsetTop; |
||||
|
// 当前宽度 高度
|
||||
|
const curWidth = dragDom.offsetWidth; |
||||
|
const curHeight = dragDom.offsetHeight; |
||||
|
document.onmousemove = function(e) { |
||||
|
e.preventDefault(); // 移动时禁用默认事件
|
||||
|
// 通过事件委托,计算移动的距离
|
||||
|
const xl = e.clientX - disX; |
||||
|
const yl = e.clientY - disY |
||||
|
dragDom.style.width = `${curWidth + xl}px`; |
||||
|
dragDom.style.height = `${curHeight + yl}px`; |
||||
|
}; |
||||
|
document.onmouseup = function(e) { |
||||
|
document.onmousemove = null; |
||||
|
document.onmouseup = null; |
||||
|
}; |
||||
|
}, false); |
||||
|
dragDom.appendChild(lineEl); |
||||
|
} |
||||
|
} |
@ -0,0 +1,30 @@ |
|||||
|
/** |
||||
|
* v-dialogDragWidth 可拖动弹窗宽度(右侧边) |
||||
|
* Copyright (c) 2019 ruoyi |
||||
|
*/ |
||||
|
|
||||
|
export default { |
||||
|
bind(el) { |
||||
|
const dragDom = el.querySelector('.el-dialog'); |
||||
|
const lineEl = document.createElement('div'); |
||||
|
lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;'; |
||||
|
lineEl.addEventListener('mousedown', |
||||
|
function (e) { |
||||
|
// 鼠标按下,计算当前元素距离可视区的距离
|
||||
|
const disX = e.clientX - el.offsetLeft; |
||||
|
// 当前宽度
|
||||
|
const curWidth = dragDom.offsetWidth; |
||||
|
document.onmousemove = function (e) { |
||||
|
e.preventDefault(); // 移动时禁用默认事件
|
||||
|
// 通过事件委托,计算移动的距离
|
||||
|
const l = e.clientX - disX; |
||||
|
dragDom.style.width = `${curWidth + l}px`; |
||||
|
}; |
||||
|
document.onmouseup = function (e) { |
||||
|
document.onmousemove = null; |
||||
|
document.onmouseup = null; |
||||
|
}; |
||||
|
}, false); |
||||
|
dragDom.appendChild(lineEl); |
||||
|
} |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
/** |
||||
|
* v-clipboard 文字复制剪贴 |
||||
|
* Copyright (c) 2021 ruoyi |
||||
|
*/ |
||||
|
|
||||
|
import Clipboard from 'clipboard' |
||||
|
export default { |
||||
|
bind(el, binding, vnode) { |
||||
|
switch (binding.arg) { |
||||
|
case 'success': |
||||
|
el._vClipBoard_success = binding.value; |
||||
|
break; |
||||
|
case 'error': |
||||
|
el._vClipBoard_error = binding.value; |
||||
|
break; |
||||
|
default: { |
||||
|
const clipboard = new Clipboard(el, { |
||||
|
text: () => binding.value, |
||||
|
action: () => binding.arg === 'cut' ? 'cut' : 'copy' |
||||
|
}); |
||||
|
clipboard.on('success', e => { |
||||
|
const callback = el._vClipBoard_success; |
||||
|
callback && callback(e); |
||||
|
}); |
||||
|
clipboard.on('error', e => { |
||||
|
const callback = el._vClipBoard_error; |
||||
|
callback && callback(e); |
||||
|
}); |
||||
|
el._vClipBoard = clipboard; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
update(el, binding) { |
||||
|
if (binding.arg === 'success') { |
||||
|
el._vClipBoard_success = binding.value; |
||||
|
} else if (binding.arg === 'error') { |
||||
|
el._vClipBoard_error = binding.value; |
||||
|
} else { |
||||
|
el._vClipBoard.text = function () { return binding.value; }; |
||||
|
el._vClipBoard.action = () => binding.arg === 'cut' ? 'cut' : 'copy'; |
||||
|
} |
||||
|
}, |
||||
|
unbind(el, binding) { |
||||
|
if (!el._vClipboard) return |
||||
|
if (binding.arg === 'success') { |
||||
|
delete el._vClipBoard_success; |
||||
|
} else if (binding.arg === 'error') { |
||||
|
delete el._vClipBoard_error; |
||||
|
} else { |
||||
|
el._vClipBoard.destroy(); |
||||
|
delete el._vClipBoard; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
/** |
||||
|
* v-hasPermi 操作权限处理 |
||||
|
* Copyright (c) 2019 ruoyi |
||||
|
*/ |
||||
|
|
||||
|
import store from '@/store' |
||||
|
|
||||
|
export default { |
||||
|
inserted(el, binding, vnode) { |
||||
|
const { value } = binding |
||||
|
const all_permission = "*:*:*"; |
||||
|
const permissions = store.getters && store.getters.permissions |
||||
|
|
||||
|
if (value && value instanceof Array && value.length > 0) { |
||||
|
const permissionFlag = value |
||||
|
|
||||
|
const hasPermissions = permissions.some(permission => { |
||||
|
return all_permission === permission || permissionFlag.includes(permission) |
||||
|
}) |
||||
|
|
||||
|
if (!hasPermissions) { |
||||
|
el.parentNode && el.parentNode.removeChild(el) |
||||
|
} |
||||
|
} else { |
||||
|
throw new Error(`请设置操作权限标签值`) |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
/** |
||||
|
* v-hasRole 角色权限处理 |
||||
|
* Copyright (c) 2019 ruoyi |
||||
|
*/ |
||||
|
|
||||
|
import store from '@/store' |
||||
|
|
||||
|
export default { |
||||
|
inserted(el, binding, vnode) { |
||||
|
const { value } = binding |
||||
|
const super_admin = "admin"; |
||||
|
const roles = store.getters && store.getters.roles |
||||
|
|
||||
|
if (value && value instanceof Array && value.length > 0) { |
||||
|
const roleFlag = value |
||||
|
|
||||
|
const hasRole = roles.some(role => { |
||||
|
return super_admin === role || roleFlag.includes(role) |
||||
|
}) |
||||
|
|
||||
|
if (!hasRole) { |
||||
|
el.parentNode && el.parentNode.removeChild(el) |
||||
|
} |
||||
|
} else { |
||||
|
throw new Error(`请设置角色权限标签值"`) |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,209 @@ |
|||||
|
<template> |
||||
|
<div class="navbar"> |
||||
|
<hamburger |
||||
|
id="hamburger-container" |
||||
|
:is-active="sidebar.opened" |
||||
|
class="hamburger-container" |
||||
|
@toggleClick="toggleSideBar" |
||||
|
/> |
||||
|
|
||||
|
<breadcrumb |
||||
|
id="breadcrumb-container" |
||||
|
class="breadcrumb-container" |
||||
|
v-if="!topNav" |
||||
|
/> |
||||
|
<top-nav id="topmenu-container" class="topmenu-container" v-if="topNav" /> |
||||
|
|
||||
|
<div class="right-menu"> |
||||
|
<template v-if="device !== 'mobile'"> |
||||
|
<search id="header-search" class="right-menu-item" /> |
||||
|
|
||||
|
<el-tooltip content="源码地址" effect="dark" placement="bottom"> |
||||
|
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" /> |
||||
|
</el-tooltip> |
||||
|
|
||||
|
<el-tooltip content="文档地址" effect="dark" placement="bottom"> |
||||
|
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" /> |
||||
|
</el-tooltip> |
||||
|
|
||||
|
<screenfull id="screenfull" class="right-menu-item hover-effect" /> |
||||
|
|
||||
|
<el-tooltip content="布局大小" effect="dark" placement="bottom"> |
||||
|
<size-select id="size-select" class="right-menu-item hover-effect" /> |
||||
|
</el-tooltip> |
||||
|
</template> |
||||
|
|
||||
|
<el-dropdown |
||||
|
class="avatar-container right-menu-item hover-effect" |
||||
|
trigger="click" |
||||
|
> |
||||
|
<div class="avatar-wrapper"> |
||||
|
<img :src="avatar" class="user-avatar" /> |
||||
|
<i class="el-icon-caret-bottom" /> |
||||
|
</div> |
||||
|
<el-dropdown-menu slot="dropdown"> |
||||
|
<router-link to="/user/profile"> |
||||
|
<el-dropdown-item>个人中心</el-dropdown-item> |
||||
|
</router-link> |
||||
|
<el-dropdown-item @click.native="setting = true"> |
||||
|
<span>布局设置</span> |
||||
|
</el-dropdown-item> |
||||
|
<el-dropdown-item divided @click.native="logout"> |
||||
|
<span>退出登录</span> |
||||
|
</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</el-dropdown> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { mapGetters } from "vuex"; |
||||
|
import Breadcrumb from "@/components/Breadcrumb"; |
||||
|
import TopNav from "@/components/TopNav"; |
||||
|
import Hamburger from "@/components/Hamburger"; |
||||
|
import Screenfull from "@/components/Screenfull"; |
||||
|
import SizeSelect from "@/components/SizeSelect"; |
||||
|
import Search from "@/components/HeaderSearch"; |
||||
|
import RuoYiGit from "@/components/RuoYi/Git"; |
||||
|
import RuoYiDoc from "@/components/RuoYi/Doc"; |
||||
|
|
||||
|
export default { |
||||
|
components: { |
||||
|
Breadcrumb, |
||||
|
TopNav, |
||||
|
Hamburger, |
||||
|
Screenfull, |
||||
|
SizeSelect, |
||||
|
Search, |
||||
|
RuoYiGit, |
||||
|
RuoYiDoc, |
||||
|
}, |
||||
|
computed: { |
||||
|
...mapGetters(["sidebar", "avatar", "device"]), |
||||
|
setting: { |
||||
|
get() { |
||||
|
return this.$store.state.settings.showSettings; |
||||
|
}, |
||||
|
set(val) { |
||||
|
this.$store.dispatch("settings/changeSetting", { |
||||
|
key: "showSettings", |
||||
|
value: val, |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
topNav: { |
||||
|
get() { |
||||
|
return this.$store.state.settings.topNav; |
||||
|
}, |
||||
|
}, |
||||
|
}, |
||||
|
methods: { |
||||
|
toggleSideBar() { |
||||
|
this.$store.dispatch("app/toggleSideBar"); |
||||
|
}, |
||||
|
async logout() { |
||||
|
this.$confirm("确定注销并退出系统吗?", "提示", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
type: "warning", |
||||
|
}) |
||||
|
.then(() => { |
||||
|
this.$store.dispatch("LogOut").then(() => { |
||||
|
location.href = process.env.VUE_APP_PUBLIC_PATH; |
||||
|
}); |
||||
|
}) |
||||
|
.catch(() => {}); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.navbar { |
||||
|
height: 50px; |
||||
|
overflow: hidden; |
||||
|
position: relative; |
||||
|
background: #fff; |
||||
|
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); |
||||
|
|
||||
|
.hamburger-container { |
||||
|
line-height: 46px; |
||||
|
height: 100%; |
||||
|
float: left; |
||||
|
cursor: pointer; |
||||
|
transition: background 0.3s; |
||||
|
-webkit-tap-highlight-color: transparent; |
||||
|
|
||||
|
&:hover { |
||||
|
background: rgba(0, 0, 0, 0.025); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.breadcrumb-container { |
||||
|
float: left; |
||||
|
} |
||||
|
|
||||
|
.topmenu-container { |
||||
|
position: absolute; |
||||
|
left: 50px; |
||||
|
} |
||||
|
|
||||
|
.errLog-container { |
||||
|
display: inline-block; |
||||
|
vertical-align: top; |
||||
|
} |
||||
|
|
||||
|
.right-menu { |
||||
|
float: right; |
||||
|
height: 100%; |
||||
|
line-height: 50px; |
||||
|
|
||||
|
&:focus { |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
.right-menu-item { |
||||
|
display: inline-block; |
||||
|
padding: 0 8px; |
||||
|
height: 100%; |
||||
|
font-size: 18px; |
||||
|
color: #5a5e66; |
||||
|
vertical-align: text-bottom; |
||||
|
|
||||
|
&.hover-effect { |
||||
|
cursor: pointer; |
||||
|
transition: background 0.3s; |
||||
|
|
||||
|
&:hover { |
||||
|
background: rgba(0, 0, 0, 0.025); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.avatar-container { |
||||
|
margin-right: 30px; |
||||
|
|
||||
|
.avatar-wrapper { |
||||
|
margin-top: 5px; |
||||
|
position: relative; |
||||
|
|
||||
|
.user-avatar { |
||||
|
cursor: pointer; |
||||
|
width: 40px; |
||||
|
height: 40px; |
||||
|
border-radius: 10px; |
||||
|
} |
||||
|
|
||||
|
.el-icon-caret-bottom { |
||||
|
cursor: pointer; |
||||
|
position: absolute; |
||||
|
right: -20px; |
||||
|
top: 25px; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,86 @@ |
|||||
|
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) |
||||
|
}) |
@ -0,0 +1,79 @@ |
|||||
|
import axios from 'axios' |
||||
|
import {Loading, Message} from 'element-ui' |
||||
|
import { saveAs } from 'file-saver' |
||||
|
import { getToken } from '@/utils/auth' |
||||
|
import errorCode from '@/utils/errorCode' |
||||
|
import { blobValidate } from "@/utils/ruoyi"; |
||||
|
|
||||
|
const baseURL = process.env.VUE_APP_BASE_API |
||||
|
let downloadLoadingInstance; |
||||
|
|
||||
|
export default { |
||||
|
name(name, isDelete = true) { |
||||
|
var url = baseURL + "/common/download?fileName=" + encodeURIComponent(name) + "&delete=" + isDelete |
||||
|
axios({ |
||||
|
method: 'get', |
||||
|
url: url, |
||||
|
responseType: 'blob', |
||||
|
headers: { 'Authorization': 'Bearer ' + getToken() } |
||||
|
}).then((res) => { |
||||
|
const isBlob = blobValidate(res.data); |
||||
|
if (isBlob) { |
||||
|
const blob = new Blob([res.data]) |
||||
|
this.saveAs(blob, decodeURIComponent(res.headers['download-filename'])) |
||||
|
} else { |
||||
|
this.printErrMsg(res.data); |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
resource(resource) { |
||||
|
var url = baseURL + "/common/download/resource?resource=" + encodeURIComponent(resource); |
||||
|
axios({ |
||||
|
method: 'get', |
||||
|
url: url, |
||||
|
responseType: 'blob', |
||||
|
headers: { 'Authorization': 'Bearer ' + getToken() } |
||||
|
}).then((res) => { |
||||
|
const isBlob = blobValidate(res.data); |
||||
|
if (isBlob) { |
||||
|
const blob = new Blob([res.data]) |
||||
|
this.saveAs(blob, decodeURIComponent(res.headers['download-filename'])) |
||||
|
} else { |
||||
|
this.printErrMsg(res.data); |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
zip(url, name) { |
||||
|
var url = baseURL + url |
||||
|
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }) |
||||
|
axios({ |
||||
|
method: 'get', |
||||
|
url: url, |
||||
|
responseType: 'blob', |
||||
|
headers: { 'Authorization': 'Bearer ' + getToken() } |
||||
|
}).then((res) => { |
||||
|
const isBlob = blobValidate(res.data); |
||||
|
if (isBlob) { |
||||
|
const blob = new Blob([res.data], { type: 'application/zip' }) |
||||
|
this.saveAs(blob, name) |
||||
|
} else { |
||||
|
this.printErrMsg(res.data); |
||||
|
} |
||||
|
downloadLoadingInstance.close(); |
||||
|
}).catch((r) => { |
||||
|
console.error(r) |
||||
|
Message.error('下载文件出现错误,请联系管理员!') |
||||
|
downloadLoadingInstance.close(); |
||||
|
}) |
||||
|
}, |
||||
|
saveAs(text, name, opts) { |
||||
|
saveAs(text, name, opts); |
||||
|
}, |
||||
|
async printErrMsg(data) { |
||||
|
const resText = await data.text(); |
||||
|
const rspObj = JSON.parse(resText); |
||||
|
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] |
||||
|
Message.error(errMsg); |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,236 @@ |
|||||
|
import Vue from "vue"; |
||||
|
import Router from "vue-router"; |
||||
|
|
||||
|
Vue.use(Router); |
||||
|
|
||||
|
/* Layout */ |
||||
|
import Layout from "@/layout"; |
||||
|
|
||||
|
/** |
||||
|
* Note: 路由配置项 |
||||
|
* |
||||
|
* hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1
|
||||
|
* alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
|
||||
|
* // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面
|
||||
|
* // 若你想不管路由下面的 children 声明的个数都显示你的根路由
|
||||
|
* // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由
|
||||
|
* redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
|
||||
|
* name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
|
||||
|
* query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
|
||||
|
* roles: ['admin', 'common'] // 访问路由的角色权限
|
||||
|
* permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
|
||||
|
* meta : { |
||||
|
noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
|
||||
|
title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
|
||||
|
icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg
|
||||
|
breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
|
||||
|
activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。
|
||||
|
} |
||||
|
*/ |
||||
|
|
||||
|
// 公共路由
|
||||
|
export const constantRoutes = [ |
||||
|
{ |
||||
|
path: "/redirect", |
||||
|
component: Layout, |
||||
|
hidden: true, |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "/redirect/:path(.*)", |
||||
|
component: () => import("@/views/redirect"), |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/login", |
||||
|
component: () => import("@/views/login"), |
||||
|
hidden: true, |
||||
|
}, |
||||
|
{ |
||||
|
path: "/register", |
||||
|
component: () => import("@/views/register"), |
||||
|
hidden: true, |
||||
|
}, |
||||
|
{ |
||||
|
path: "/404", |
||||
|
component: () => import("@/views/error/404"), |
||||
|
hidden: true, |
||||
|
}, |
||||
|
{ |
||||
|
path: "/401", |
||||
|
component: () => import("@/views/error/401"), |
||||
|
hidden: true, |
||||
|
}, |
||||
|
{ |
||||
|
path: "", |
||||
|
component: Layout, |
||||
|
redirect: "index", |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "index", |
||||
|
component: () => import("@/views/index"), |
||||
|
name: "Index", |
||||
|
meta: { title: "首页", icon: "dashboard", affix: true }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/patientFile", |
||||
|
component: Layout, |
||||
|
redirect: "index", |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "/patientIndex", |
||||
|
component: () => import("@/views/patientFile/index"), |
||||
|
name: "Index", |
||||
|
meta: { title: "患者档案", icon: "dashboard", }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/medicalFile", |
||||
|
component: Layout, |
||||
|
redirect: "medicalFile", |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "/medicalIndex", |
||||
|
component: () => import("@/views/medicalFile/index"), |
||||
|
name: "medicalIndex", |
||||
|
meta: { title: "诊疗档案", icon: "dashboard", }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/followFile", |
||||
|
meta: { title: "随访档案", icon: "dashboard", }, |
||||
|
component: Layout, |
||||
|
redirect: "followFile", |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "/followIndex", |
||||
|
component: () => import("@/views/followFile/index"), |
||||
|
name: "followIndex", |
||||
|
meta: { title: "随访队列", icon: "dashboard", }, |
||||
|
}, |
||||
|
{ |
||||
|
path: "/followSubjects", |
||||
|
component: () => import("@/views/followFile/subjects"), |
||||
|
name: "followSubjects", |
||||
|
meta: { title: "随访对象", icon: "dashboard", }, |
||||
|
}, |
||||
|
{ |
||||
|
path: "/followWork", |
||||
|
component: () => import("@/views/followFile/work"), |
||||
|
name: "followWork", |
||||
|
meta: { title: "随访工单", icon: "dashboard", }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/user", |
||||
|
component: Layout, |
||||
|
hidden: true, |
||||
|
redirect: "noredirect", |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "profile", |
||||
|
component: () => import("@/views/system/user/profile/index"), |
||||
|
name: "Profile", |
||||
|
meta: { title: "个人中心", icon: "user" }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
// 动态路由,基于用户权限动态去加载
|
||||
|
export const dynamicRoutes = [ |
||||
|
{ |
||||
|
path: "/system/user-auth", |
||||
|
component: Layout, |
||||
|
hidden: true, |
||||
|
permissions: ["system:user:edit"], |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "role/:userId(\\d+)", |
||||
|
component: () => import("@/views/system/user/authRole"), |
||||
|
name: "AuthRole", |
||||
|
meta: { title: "分配角色", activeMenu: "/system/user" }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/system/role-auth", |
||||
|
component: Layout, |
||||
|
hidden: true, |
||||
|
permissions: ["system:role:edit"], |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "user/:roleId(\\d+)", |
||||
|
component: () => import("@/views/system/role/authUser"), |
||||
|
name: "AuthUser", |
||||
|
meta: { title: "分配用户", activeMenu: "/system/role" }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/system/dict-data", |
||||
|
component: Layout, |
||||
|
hidden: true, |
||||
|
permissions: ["system:dict:list"], |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "index/:dictId(\\d+)", |
||||
|
component: () => import("@/views/system/dict/data"), |
||||
|
name: "Data", |
||||
|
meta: { title: "字典数据", activeMenu: "/system/dict" }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/monitor/job-log", |
||||
|
component: Layout, |
||||
|
hidden: true, |
||||
|
permissions: ["monitor:job:list"], |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "index/:jobId(\\d+)", |
||||
|
component: () => import("@/views/monitor/job/log"), |
||||
|
name: "JobLog", |
||||
|
meta: { title: "调度日志", activeMenu: "/monitor/job" }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
path: "/tool/gen-edit", |
||||
|
component: Layout, |
||||
|
hidden: true, |
||||
|
permissions: ["tool:gen:edit"], |
||||
|
children: [ |
||||
|
{ |
||||
|
path: "index/:tableId(\\d+)", |
||||
|
component: () => import("@/views/tool/gen/editTable"), |
||||
|
name: "GenEdit", |
||||
|
meta: { title: "修改生成配置", activeMenu: "/tool/gen" }, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
// 防止连续点击多次路由报错
|
||||
|
let routerPush = Router.prototype.push; |
||||
|
let routerReplace = Router.prototype.replace; |
||||
|
// push
|
||||
|
Router.prototype.push = function push(location) { |
||||
|
return routerPush.call(this, location).catch((err) => err); |
||||
|
}; |
||||
|
// replace
|
||||
|
Router.prototype.replace = function push(location) { |
||||
|
return routerReplace.call(this, location).catch((err) => err); |
||||
|
}; |
||||
|
|
||||
|
export default new Router({ |
||||
|
mode: "history", // 去掉url中的#
|
||||
|
base: process.env.VUE_APP_PUBLIC_PATH, |
||||
|
scrollBehavior: () => ({ y: 0 }), |
||||
|
routes: constantRoutes, |
||||
|
}); |
@ -0,0 +1,137 @@ |
|||||
|
import auth from "@/plugins/auth"; |
||||
|
import router, { constantRoutes, dynamicRoutes } from "@/router"; |
||||
|
import { getRouters } from "@/api/menu"; |
||||
|
import Layout from "@/layout/index"; |
||||
|
import ParentView from "@/components/ParentView"; |
||||
|
import InnerLink from "@/layout/components/InnerLink"; |
||||
|
|
||||
|
const permission = { |
||||
|
state: { |
||||
|
routes: [], |
||||
|
addRoutes: [], |
||||
|
defaultRoutes: [], |
||||
|
topbarRouters: [], |
||||
|
sidebarRouters: [], |
||||
|
}, |
||||
|
mutations: { |
||||
|
SET_ROUTES: (state, routes) => { |
||||
|
state.addRoutes = routes; |
||||
|
state.routes = constantRoutes.concat(routes); |
||||
|
}, |
||||
|
SET_DEFAULT_ROUTES: (state, routes) => { |
||||
|
state.defaultRoutes = constantRoutes.concat(routes); |
||||
|
}, |
||||
|
SET_TOPBAR_ROUTES: (state, routes) => { |
||||
|
state.topbarRouters = routes; |
||||
|
}, |
||||
|
SET_SIDEBAR_ROUTERS: (state, routes) => { |
||||
|
state.sidebarRouters = routes; |
||||
|
}, |
||||
|
}, |
||||
|
actions: { |
||||
|
// 生成路由
|
||||
|
GenerateRoutes({ commit }) { |
||||
|
return new Promise((resolve) => { |
||||
|
// 向后端请求路由数据
|
||||
|
getRouters().then((res) => { |
||||
|
const sdata = JSON.parse(JSON.stringify(res.data)); |
||||
|
const rdata = JSON.parse(JSON.stringify(res.data)); |
||||
|
const sidebarRoutes = filterAsyncRouter(sdata); |
||||
|
const rewriteRoutes = filterAsyncRouter(rdata, false, true); |
||||
|
const asyncRoutes = filterDynamicRoutes(dynamicRoutes); |
||||
|
rewriteRoutes.push({ path: "*", redirect: "/404", hidden: true }); |
||||
|
router.addRoutes(asyncRoutes); |
||||
|
commit("SET_ROUTES", rewriteRoutes); |
||||
|
commit("SET_SIDEBAR_ROUTERS", constantRoutes.concat(sidebarRoutes)); |
||||
|
commit("SET_DEFAULT_ROUTES", sidebarRoutes); |
||||
|
commit("SET_TOPBAR_ROUTES", sidebarRoutes); |
||||
|
resolve(rewriteRoutes); |
||||
|
}); |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
// 遍历后台传来的路由字符串,转换为组件对象
|
||||
|
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) { |
||||
|
return asyncRouterMap.filter((route) => { |
||||
|
if (type && route.children) { |
||||
|
route.children = filterChildren(route.children); |
||||
|
} |
||||
|
if (route.component) { |
||||
|
// Layout ParentView 组件特殊处理
|
||||
|
if (route.component === "Layout") { |
||||
|
route.component = Layout; |
||||
|
} else if (route.component === "ParentView") { |
||||
|
route.component = ParentView; |
||||
|
} else if (route.component === "InnerLink") { |
||||
|
route.component = InnerLink; |
||||
|
} else { |
||||
|
route.component = loadView(route.component); |
||||
|
} |
||||
|
} |
||||
|
if (route.children != null && route.children && route.children.length) { |
||||
|
route.children = filterAsyncRouter(route.children, route, type); |
||||
|
} else { |
||||
|
delete route["children"]; |
||||
|
delete route["redirect"]; |
||||
|
} |
||||
|
return true; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function filterChildren(childrenMap, lastRouter = false) { |
||||
|
var children = []; |
||||
|
childrenMap.forEach((el, index) => { |
||||
|
if (el.children && el.children.length) { |
||||
|
if (el.component === "ParentView" && !lastRouter) { |
||||
|
el.children.forEach((c) => { |
||||
|
c.path = el.path + "/" + c.path; |
||||
|
if (c.children && c.children.length) { |
||||
|
children = children.concat(filterChildren(c.children, c)); |
||||
|
return; |
||||
|
} |
||||
|
children.push(c); |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
if (lastRouter) { |
||||
|
el.path = lastRouter.path + "/" + el.path; |
||||
|
if (el.children && el.children.length) { |
||||
|
children = children.concat(filterChildren(el.children, el)); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
children = children.concat(el); |
||||
|
}); |
||||
|
return children; |
||||
|
} |
||||
|
|
||||
|
// 动态路由遍历,验证是否具备权限
|
||||
|
export function filterDynamicRoutes(routes) { |
||||
|
const res = []; |
||||
|
routes.forEach((route) => { |
||||
|
if (route.permissions) { |
||||
|
if (auth.hasPermiOr(route.permissions)) { |
||||
|
res.push(route); |
||||
|
} |
||||
|
} else if (route.roles) { |
||||
|
if (auth.hasRoleOr(route.roles)) { |
||||
|
res.push(route); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
export const loadView = (view) => { |
||||
|
if (process.env.NODE_ENV === "development") { |
||||
|
return (resolve) => require([`@/views/${view}`], resolve); |
||||
|
} else { |
||||
|
// 使用 import 实现生产环境的路由懒加载
|
||||
|
return () => import(`@/views/${view}`); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
export default permission; |
@ -0,0 +1,82 @@ |
|||||
|
import Vue from 'vue' |
||||
|
import { mergeRecursive } from "@/utils/ruoyi"; |
||||
|
import DictMeta from './DictMeta' |
||||
|
import DictData from './DictData' |
||||
|
|
||||
|
const DEFAULT_DICT_OPTIONS = { |
||||
|
types: [], |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @classdesc 字典 |
||||
|
* @property {Object} label 标签对象,内部属性名为字典类型名称 |
||||
|
* @property {Object} dict 字段数组,内部属性名为字典类型名称 |
||||
|
* @property {Array.<DictMeta>} _dictMetas 字典元数据数组 |
||||
|
*/ |
||||
|
export default class Dict { |
||||
|
constructor() { |
||||
|
this.owner = null |
||||
|
this.label = {} |
||||
|
this.type = {} |
||||
|
} |
||||
|
|
||||
|
init(options) { |
||||
|
if (options instanceof Array) { |
||||
|
options = { types: options } |
||||
|
} |
||||
|
const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options) |
||||
|
if (opts.types === undefined) { |
||||
|
throw new Error('need dict types') |
||||
|
} |
||||
|
const ps = [] |
||||
|
this._dictMetas = opts.types.map(t => DictMeta.parse(t)) |
||||
|
this._dictMetas.forEach(dictMeta => { |
||||
|
const type = dictMeta.type |
||||
|
Vue.set(this.label, type, {}) |
||||
|
Vue.set(this.type, type, []) |
||||
|
if (dictMeta.lazy) { |
||||
|
return |
||||
|
} |
||||
|
ps.push(loadDict(this, dictMeta)) |
||||
|
}) |
||||
|
return Promise.all(ps) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 重新加载字典 |
||||
|
* @param {String} type 字典类型 |
||||
|
*/ |
||||
|
reloadDict(type) { |
||||
|
const dictMeta = this._dictMetas.find(e => e.type === type) |
||||
|
if (dictMeta === undefined) { |
||||
|
return Promise.reject(`the dict meta of ${type} was not found`) |
||||
|
} |
||||
|
return loadDict(this, dictMeta) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 加载字典 |
||||
|
* @param {Dict} dict 字典 |
||||
|
* @param {DictMeta} dictMeta 字典元数据 |
||||
|
* @returns {Promise} |
||||
|
*/ |
||||
|
function loadDict(dict, dictMeta) { |
||||
|
return dictMeta.request(dictMeta) |
||||
|
.then(response => { |
||||
|
const type = dictMeta.type |
||||
|
let dicts = dictMeta.responseConverter(response, dictMeta) |
||||
|
if (!(dicts instanceof Array)) { |
||||
|
console.error('the return of responseConverter must be Array.<DictData>') |
||||
|
dicts = [] |
||||
|
} else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) { |
||||
|
console.error('the type of elements in dicts must be DictData') |
||||
|
dicts = [] |
||||
|
} |
||||
|
dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts) |
||||
|
dicts.forEach(d => { |
||||
|
Vue.set(dict.label[type], d.value, d.label) |
||||
|
}) |
||||
|
return dicts |
||||
|
}) |
||||
|
} |
@ -0,0 +1,38 @@ |
|||||
|
import { mergeRecursive } from "@/utils/ruoyi"; |
||||
|
import DictOptions from './DictOptions' |
||||
|
|
||||
|
/** |
||||
|
* @classdesc 字典元数据 |
||||
|
* @property {String} type 类型 |
||||
|
* @property {Function} request 请求 |
||||
|
* @property {String} label 标签字段 |
||||
|
* @property {String} value 值字段 |
||||
|
*/ |
||||
|
export default class DictMeta { |
||||
|
constructor(options) { |
||||
|
this.type = options.type |
||||
|
this.request = options.request |
||||
|
this.responseConverter = options.responseConverter |
||||
|
this.labelField = options.labelField |
||||
|
this.valueField = options.valueField |
||||
|
this.lazy = options.lazy === true |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 解析字典元数据 |
||||
|
* @param {Object} options |
||||
|
* @returns {DictMeta} |
||||
|
*/ |
||||
|
DictMeta.parse= function(options) { |
||||
|
let opts = null |
||||
|
if (typeof options === 'string') { |
||||
|
opts = DictOptions.metas[options] || {} |
||||
|
opts.type = options |
||||
|
} else if (typeof options === 'object') { |
||||
|
opts = options |
||||
|
} |
||||
|
opts = mergeRecursive(DictOptions.metas['*'], opts) |
||||
|
return new DictMeta(opts) |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
import { mergeRecursive } from "@/utils/ruoyi"; |
||||
|
import dictConverter from './DictConverter' |
||||
|
|
||||
|
export const options = { |
||||
|
metas: { |
||||
|
'*': { |
||||
|
/** |
||||
|
* 字典请求,方法签名为function(dictMeta: DictMeta): Promise |
||||
|
*/ |
||||
|
request: (dictMeta) => { |
||||
|
console.log(`load dict ${dictMeta.type}`) |
||||
|
return Promise.resolve([]) |
||||
|
}, |
||||
|
/** |
||||
|
* 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData |
||||
|
*/ |
||||
|
responseConverter, |
||||
|
labelField: 'label', |
||||
|
valueField: 'value', |
||||
|
}, |
||||
|
}, |
||||
|
/** |
||||
|
* 默认标签字段 |
||||
|
*/ |
||||
|
DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'], |
||||
|
/** |
||||
|
* 默认值字段 |
||||
|
*/ |
||||
|
DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'], |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 映射字典 |
||||
|
* @param {Object} response 字典数据 |
||||
|
* @param {DictMeta} dictMeta 字典元数据 |
||||
|
* @returns {DictData} |
||||
|
*/ |
||||
|
function responseConverter(response, dictMeta) { |
||||
|
const dicts = response.content instanceof Array ? response.content : response |
||||
|
if (dicts === undefined) { |
||||
|
console.warn(`no dict data of "${dictMeta.type}" found in the response`) |
||||
|
return [] |
||||
|
} |
||||
|
return dicts.map(d => dictConverter(d, dictMeta)) |
||||
|
} |
||||
|
|
||||
|
export function mergeOptions(src) { |
||||
|
mergeRecursive(options, src) |
||||
|
} |
||||
|
|
||||
|
export default options |
@ -0,0 +1,390 @@ |
|||||
|
import { parseTime } from './ruoyi' |
||||
|
|
||||
|
/** |
||||
|
* 表格时间格式化 |
||||
|
*/ |
||||
|
export function formatDate(cellValue) { |
||||
|
if (cellValue == null || cellValue == "") return ""; |
||||
|
var date = new Date(cellValue) |
||||
|
var year = date.getFullYear() |
||||
|
var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 |
||||
|
var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() |
||||
|
var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() |
||||
|
var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() |
||||
|
var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() |
||||
|
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {number} time |
||||
|
* @param {string} option |
||||
|
* @returns {string} |
||||
|
*/ |
||||
|
export function formatTime(time, option) { |
||||
|
if (('' + time).length === 10) { |
||||
|
time = parseInt(time) * 1000 |
||||
|
} else { |
||||
|
time = +time |
||||
|
} |
||||
|
const d = new Date(time) |
||||
|
const now = Date.now() |
||||
|
|
||||
|
const diff = (now - d) / 1000 |
||||
|
|
||||
|
if (diff < 30) { |
||||
|
return '刚刚' |
||||
|
} else if (diff < 3600) { |
||||
|
// less 1 hour
|
||||
|
return Math.ceil(diff / 60) + '分钟前' |
||||
|
} else if (diff < 3600 * 24) { |
||||
|
return Math.ceil(diff / 3600) + '小时前' |
||||
|
} else if (diff < 3600 * 24 * 2) { |
||||
|
return '1天前' |
||||
|
} |
||||
|
if (option) { |
||||
|
return parseTime(time, option) |
||||
|
} else { |
||||
|
return ( |
||||
|
d.getMonth() + |
||||
|
1 + |
||||
|
'月' + |
||||
|
d.getDate() + |
||||
|
'日' + |
||||
|
d.getHours() + |
||||
|
'时' + |
||||
|
d.getMinutes() + |
||||
|
'分' |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {string} url |
||||
|
* @returns {Object} |
||||
|
*/ |
||||
|
export function getQueryObject(url) { |
||||
|
url = url == null ? window.location.href : url |
||||
|
const search = url.substring(url.lastIndexOf('?') + 1) |
||||
|
const obj = {} |
||||
|
const reg = /([^?&=]+)=([^?&=]*)/g |
||||
|
search.replace(reg, (rs, $1, $2) => { |
||||
|
const name = decodeURIComponent($1) |
||||
|
let val = decodeURIComponent($2) |
||||
|
val = String(val) |
||||
|
obj[name] = val |
||||
|
return rs |
||||
|
}) |
||||
|
return obj |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {string} input value |
||||
|
* @returns {number} output value |
||||
|
*/ |
||||
|
export function byteLength(str) { |
||||
|
// returns the byte length of an utf8 string
|
||||
|
let s = str.length |
||||
|
for (var i = str.length - 1; i >= 0; i--) { |
||||
|
const code = str.charCodeAt(i) |
||||
|
if (code > 0x7f && code <= 0x7ff) s++ |
||||
|
else if (code > 0x7ff && code <= 0xffff) s += 2 |
||||
|
if (code >= 0xDC00 && code <= 0xDFFF) i-- |
||||
|
} |
||||
|
return s |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {Array} actual |
||||
|
* @returns {Array} |
||||
|
*/ |
||||
|
export function cleanArray(actual) { |
||||
|
const newArray = [] |
||||
|
for (let i = 0; i < actual.length; i++) { |
||||
|
if (actual[i]) { |
||||
|
newArray.push(actual[i]) |
||||
|
} |
||||
|
} |
||||
|
return newArray |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {Object} json |
||||
|
* @returns {Array} |
||||
|
*/ |
||||
|
export function param(json) { |
||||
|
if (!json) return '' |
||||
|
return cleanArray( |
||||
|
Object.keys(json).map(key => { |
||||
|
if (json[key] === undefined) return '' |
||||
|
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]) |
||||
|
}) |
||||
|
).join('&') |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {string} url |
||||
|
* @returns {Object} |
||||
|
*/ |
||||
|
export function param2Obj(url) { |
||||
|
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') |
||||
|
if (!search) { |
||||
|
return {} |
||||
|
} |
||||
|
const obj = {} |
||||
|
const searchArr = search.split('&') |
||||
|
searchArr.forEach(v => { |
||||
|
const index = v.indexOf('=') |
||||
|
if (index !== -1) { |
||||
|
const name = v.substring(0, index) |
||||
|
const val = v.substring(index + 1, v.length) |
||||
|
obj[name] = val |
||||
|
} |
||||
|
}) |
||||
|
return obj |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {string} val |
||||
|
* @returns {string} |
||||
|
*/ |
||||
|
export function html2Text(val) { |
||||
|
const div = document.createElement('div') |
||||
|
div.innerHTML = val |
||||
|
return div.textContent || div.innerText |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Merges two objects, giving the last one precedence |
||||
|
* @param {Object} target |
||||
|
* @param {(Object|Array)} source |
||||
|
* @returns {Object} |
||||
|
*/ |
||||
|
export function objectMerge(target, source) { |
||||
|
if (typeof target !== 'object') { |
||||
|
target = {} |
||||
|
} |
||||
|
if (Array.isArray(source)) { |
||||
|
return source.slice() |
||||
|
} |
||||
|
Object.keys(source).forEach(property => { |
||||
|
const sourceProperty = source[property] |
||||
|
if (typeof sourceProperty === 'object') { |
||||
|
target[property] = objectMerge(target[property], sourceProperty) |
||||
|
} else { |
||||
|
target[property] = sourceProperty |
||||
|
} |
||||
|
}) |
||||
|
return target |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {HTMLElement} element |
||||
|
* @param {string} className |
||||
|
*/ |
||||
|
export function toggleClass(element, className) { |
||||
|
if (!element || !className) { |
||||
|
return |
||||
|
} |
||||
|
let classString = element.className |
||||
|
const nameIndex = classString.indexOf(className) |
||||
|
if (nameIndex === -1) { |
||||
|
classString += '' + className |
||||
|
} else { |
||||
|
classString = |
||||
|
classString.substr(0, nameIndex) + |
||||
|
classString.substr(nameIndex + className.length) |
||||
|
} |
||||
|
element.className = classString |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {string} type |
||||
|
* @returns {Date} |
||||
|
*/ |
||||
|
export function getTime(type) { |
||||
|
if (type === 'start') { |
||||
|
return new Date().getTime() - 3600 * 1000 * 24 * 90 |
||||
|
} else { |
||||
|
return new Date(new Date().toDateString()) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {Function} func |
||||
|
* @param {number} wait |
||||
|
* @param {boolean} immediate |
||||
|
* @return {*} |
||||
|
*/ |
||||
|
export function debounce(func, wait, immediate) { |
||||
|
let timeout, args, context, timestamp, result |
||||
|
|
||||
|
const later = function() { |
||||
|
// 据上一次触发时间间隔
|
||||
|
const last = +new Date() - timestamp |
||||
|
|
||||
|
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
|
||||
|
if (last < wait && last > 0) { |
||||
|
timeout = setTimeout(later, wait - last) |
||||
|
} else { |
||||
|
timeout = null |
||||
|
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
|
||||
|
if (!immediate) { |
||||
|
result = func.apply(context, args) |
||||
|
if (!timeout) context = args = null |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return function(...args) { |
||||
|
context = this |
||||
|
timestamp = +new Date() |
||||
|
const callNow = immediate && !timeout |
||||
|
// 如果延时不存在,重新设定延时
|
||||
|
if (!timeout) timeout = setTimeout(later, wait) |
||||
|
if (callNow) { |
||||
|
result = func.apply(context, args) |
||||
|
context = args = null |
||||
|
} |
||||
|
|
||||
|
return result |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* This is just a simple version of deep copy |
||||
|
* Has a lot of edge cases bug |
||||
|
* If you want to use a perfect deep copy, use lodash's _.cloneDeep |
||||
|
* @param {Object} source |
||||
|
* @returns {Object} |
||||
|
*/ |
||||
|
export function deepClone(source) { |
||||
|
if (!source && typeof source !== 'object') { |
||||
|
throw new Error('error arguments', 'deepClone') |
||||
|
} |
||||
|
const targetObj = source.constructor === Array ? [] : {} |
||||
|
Object.keys(source).forEach(keys => { |
||||
|
if (source[keys] && typeof source[keys] === 'object') { |
||||
|
targetObj[keys] = deepClone(source[keys]) |
||||
|
} else { |
||||
|
targetObj[keys] = source[keys] |
||||
|
} |
||||
|
}) |
||||
|
return targetObj |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @param {Array} arr |
||||
|
* @returns {Array} |
||||
|
*/ |
||||
|
export function uniqueArr(arr) { |
||||
|
return Array.from(new Set(arr)) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* @returns {string} |
||||
|
*/ |
||||
|
export function createUniqueString() { |
||||
|
const timestamp = +new Date() + '' |
||||
|
const randomNum = parseInt((1 + Math.random()) * 65536) + '' |
||||
|
return (+(randomNum + timestamp)).toString(32) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Check if an element has a class |
||||
|
* @param {HTMLElement} elm |
||||
|
* @param {string} cls |
||||
|
* @returns {boolean} |
||||
|
*/ |
||||
|
export function hasClass(ele, cls) { |
||||
|
return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Add class to element |
||||
|
* @param {HTMLElement} elm |
||||
|
* @param {string} cls |
||||
|
*/ |
||||
|
export function addClass(ele, cls) { |
||||
|
if (!hasClass(ele, cls)) ele.className += ' ' + cls |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Remove class from element |
||||
|
* @param {HTMLElement} elm |
||||
|
* @param {string} cls |
||||
|
*/ |
||||
|
export function removeClass(ele, cls) { |
||||
|
if (hasClass(ele, cls)) { |
||||
|
const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') |
||||
|
ele.className = ele.className.replace(reg, ' ') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function makeMap(str, expectsLowerCase) { |
||||
|
const map = Object.create(null) |
||||
|
const list = str.split(',') |
||||
|
for (let i = 0; i < list.length; i++) { |
||||
|
map[list[i]] = true |
||||
|
} |
||||
|
return expectsLowerCase |
||||
|
? val => map[val.toLowerCase()] |
||||
|
: val => map[val] |
||||
|
} |
||||
|
|
||||
|
export const exportDefault = 'export default ' |
||||
|
|
||||
|
export const beautifierConf = { |
||||
|
html: { |
||||
|
indent_size: '2', |
||||
|
indent_char: ' ', |
||||
|
max_preserve_newlines: '-1', |
||||
|
preserve_newlines: false, |
||||
|
keep_array_indentation: false, |
||||
|
break_chained_methods: false, |
||||
|
indent_scripts: 'separate', |
||||
|
brace_style: 'end-expand', |
||||
|
space_before_conditional: true, |
||||
|
unescape_strings: false, |
||||
|
jslint_happy: false, |
||||
|
end_with_newline: true, |
||||
|
wrap_line_length: '110', |
||||
|
indent_inner_html: true, |
||||
|
comma_first: false, |
||||
|
e4x: true, |
||||
|
indent_empty_lines: true |
||||
|
}, |
||||
|
js: { |
||||
|
indent_size: '2', |
||||
|
indent_char: ' ', |
||||
|
max_preserve_newlines: '-1', |
||||
|
preserve_newlines: false, |
||||
|
keep_array_indentation: false, |
||||
|
break_chained_methods: false, |
||||
|
indent_scripts: 'normal', |
||||
|
brace_style: 'end-expand', |
||||
|
space_before_conditional: true, |
||||
|
unescape_strings: false, |
||||
|
jslint_happy: true, |
||||
|
end_with_newline: true, |
||||
|
wrap_line_length: '110', |
||||
|
indent_inner_html: true, |
||||
|
comma_first: false, |
||||
|
e4x: true, |
||||
|
indent_empty_lines: true |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 首字母大小
|
||||
|
export function titleCase(str) { |
||||
|
return str.replace(/( |^)[a-z]/g, L => L.toUpperCase()) |
||||
|
} |
||||
|
|
||||
|
// 下划转驼峰
|
||||
|
export function camelCase(str) { |
||||
|
return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase()) |
||||
|
} |
||||
|
|
||||
|
export function isNumberStr(str) { |
||||
|
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str) |
||||
|
} |
||||
|
|
@ -0,0 +1,152 @@ |
|||||
|
import axios from 'axios' |
||||
|
import { Notification, MessageBox, Message, Loading } from 'element-ui' |
||||
|
import store from '@/store' |
||||
|
import { getToken } from '@/utils/auth' |
||||
|
import errorCode from '@/utils/errorCode' |
||||
|
import { tansParams, blobValidate } from "@/utils/ruoyi"; |
||||
|
import cache from '@/plugins/cache' |
||||
|
import { saveAs } from 'file-saver' |
||||
|
|
||||
|
let downloadLoadingInstance; |
||||
|
// 是否显示重新登录
|
||||
|
export let isRelogin = { show: false }; |
||||
|
|
||||
|
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' |
||||
|
// 创建axios实例
|
||||
|
const service = axios.create({ |
||||
|
// axios中请求配置有baseURL选项,表示请求URL公共部分
|
||||
|
baseURL: process.env.VUE_APP_BASE_API, |
||||
|
// 超时
|
||||
|
timeout: 10000 |
||||
|
}) |
||||
|
|
||||
|
// request拦截器
|
||||
|
service.interceptors.request.use(config => { |
||||
|
// 是否需要设置 token
|
||||
|
const isToken = (config.headers || {}).isToken === false |
||||
|
// 是否需要防止数据重复提交
|
||||
|
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false |
||||
|
if (getToken() && !isToken) { |
||||
|
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
|
} |
||||
|
// get请求映射params参数
|
||||
|
if (config.method === 'get' && config.params) { |
||||
|
let url = config.url + '?' + tansParams(config.params); |
||||
|
url = url.slice(0, -1); |
||||
|
config.params = {}; |
||||
|
config.url = url; |
||||
|
} |
||||
|
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { |
||||
|
const requestObj = { |
||||
|
url: config.url, |
||||
|
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, |
||||
|
time: new Date().getTime() |
||||
|
} |
||||
|
const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
|
||||
|
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
|
||||
|
if (requestSize >= limitSize) { |
||||
|
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。') |
||||
|
return config; |
||||
|
} |
||||
|
const sessionObj = cache.session.getJSON('sessionObj') |
||||
|
if (sessionObj === undefined || sessionObj === null || sessionObj === '') { |
||||
|
cache.session.setJSON('sessionObj', requestObj) |
||||
|
} else { |
||||
|
const s_url = sessionObj.url; // 请求地址
|
||||
|
const s_data = sessionObj.data; // 请求数据
|
||||
|
const s_time = sessionObj.time; // 请求时间
|
||||
|
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
|
||||
|
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) { |
||||
|
const message = '数据正在处理,请勿重复提交'; |
||||
|
console.warn(`[${s_url}]: ` + message) |
||||
|
return Promise.reject(new Error(message)) |
||||
|
} else { |
||||
|
cache.session.setJSON('sessionObj', requestObj) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return config |
||||
|
}, error => { |
||||
|
console.log(error) |
||||
|
Promise.reject(error) |
||||
|
}) |
||||
|
|
||||
|
// 响应拦截器
|
||||
|
service.interceptors.response.use(res => { |
||||
|
// 未设置状态码则默认成功状态
|
||||
|
const code = res.data.code || 200; |
||||
|
// 获取错误信息
|
||||
|
const msg = errorCode[code] || res.data.msg || errorCode['default'] |
||||
|
// 二进制数据则直接返回
|
||||
|
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') { |
||||
|
return res.data |
||||
|
} |
||||
|
if (code === 401) { |
||||
|
if (!isRelogin.show) { |
||||
|
isRelogin.show = true; |
||||
|
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { |
||||
|
isRelogin.show = false; |
||||
|
store.dispatch('LogOut').then(() => { |
||||
|
location.href = process.env.VUE_APP_PUBLIC_PATH; |
||||
|
}) |
||||
|
}).catch(() => { |
||||
|
isRelogin.show = false; |
||||
|
}); |
||||
|
} |
||||
|
return Promise.reject('无效的会话,或者会话已过期,请重新登录。') |
||||
|
} else if (code === 500) { |
||||
|
Message({ message: msg, type: 'error' }) |
||||
|
return Promise.reject(new Error(msg)) |
||||
|
} else if (code === 601) { |
||||
|
Message({ message: msg, type: 'warning' }) |
||||
|
return Promise.reject('error') |
||||
|
} else if (code !== 200) { |
||||
|
Notification.error({ title: msg }) |
||||
|
return Promise.reject('error') |
||||
|
} else { |
||||
|
return res.data |
||||
|
} |
||||
|
}, |
||||
|
error => { |
||||
|
console.log('err' + error) |
||||
|
let { message } = error; |
||||
|
if (message == "Network Error") { |
||||
|
message = "后端接口连接异常"; |
||||
|
} else if (message.includes("timeout")) { |
||||
|
message = "系统接口请求超时"; |
||||
|
} else if (message.includes("Request failed with status code")) { |
||||
|
message = "系统接口" + message.substr(message.length - 3) + "异常"; |
||||
|
} |
||||
|
Message({ message: message, type: 'error', duration: 5 * 1000 }) |
||||
|
return Promise.reject(error) |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
// 通用下载方法
|
||||
|
export function download(url, params, filename, config) { |
||||
|
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }) |
||||
|
return service.post(url, params, { |
||||
|
transformRequest: [(params) => { return tansParams(params) }], |
||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, |
||||
|
responseType: 'blob', |
||||
|
...config |
||||
|
}).then(async (data) => { |
||||
|
const isBlob = blobValidate(data); |
||||
|
if (isBlob) { |
||||
|
const blob = new Blob([data]) |
||||
|
saveAs(blob, filename) |
||||
|
} else { |
||||
|
const resText = await data.text(); |
||||
|
const rspObj = JSON.parse(resText); |
||||
|
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] |
||||
|
Message.error(errMsg); |
||||
|
} |
||||
|
downloadLoadingInstance.close(); |
||||
|
}).catch((r) => { |
||||
|
console.error(r) |
||||
|
Message.error('下载文件出现错误,请联系管理员!') |
||||
|
downloadLoadingInstance.close(); |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
export default service |
@ -0,0 +1,233 @@ |
|||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 通用js方法封装处理 |
||||
|
* Copyright (c) 2019 ruoyi |
||||
|
*/ |
||||
|
|
||||
|
// 日期格式化
|
||||
|
export function parseTime(time, pattern) { |
||||
|
if (arguments.length === 0 || !time) { |
||||
|
return null |
||||
|
} |
||||
|
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' |
||||
|
let date |
||||
|
if (typeof time === 'object') { |
||||
|
date = time |
||||
|
} else { |
||||
|
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { |
||||
|
time = parseInt(time) |
||||
|
} else if (typeof time === 'string') { |
||||
|
time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), ''); |
||||
|
} |
||||
|
if ((typeof time === 'number') && (time.toString().length === 10)) { |
||||
|
time = time * 1000 |
||||
|
} |
||||
|
date = new Date(time) |
||||
|
} |
||||
|
const formatObj = { |
||||
|
y: date.getFullYear(), |
||||
|
m: date.getMonth() + 1, |
||||
|
d: date.getDate(), |
||||
|
h: date.getHours(), |
||||
|
i: date.getMinutes(), |
||||
|
s: date.getSeconds(), |
||||
|
a: date.getDay() |
||||
|
} |
||||
|
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { |
||||
|
let value = formatObj[key] |
||||
|
// Note: getDay() returns 0 on Sunday
|
||||
|
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } |
||||
|
if (result.length > 0 && value < 10) { |
||||
|
value = '0' + value |
||||
|
} |
||||
|
return value || 0 |
||||
|
}) |
||||
|
return time_str |
||||
|
} |
||||
|
|
||||
|
// 表单重置
|
||||
|
export function resetForm(refName) { |
||||
|
if (this.$refs[refName]) { |
||||
|
this.$refs[refName].resetFields(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 添加日期范围
|
||||
|
export function addDateRange(params, dateRange, propName) { |
||||
|
let search = params; |
||||
|
search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {}; |
||||
|
dateRange = Array.isArray(dateRange) ? dateRange : []; |
||||
|
if (typeof (propName) === 'undefined') { |
||||
|
search.params['beginTime'] = dateRange[0]; |
||||
|
search.params['endTime'] = dateRange[1]; |
||||
|
} else { |
||||
|
search.params['begin' + propName] = dateRange[0]; |
||||
|
search.params['end' + propName] = dateRange[1]; |
||||
|
} |
||||
|
return search; |
||||
|
} |
||||
|
|
||||
|
// 回显数据字典
|
||||
|
export function selectDictLabel(datas, value) { |
||||
|
if (value === undefined) { |
||||
|
return ""; |
||||
|
} |
||||
|
var actions = []; |
||||
|
Object.keys(datas).some((key) => { |
||||
|
if (datas[key].value == ('' + value)) { |
||||
|
actions.push(datas[key].label); |
||||
|
return true; |
||||
|
} |
||||
|
}) |
||||
|
if (actions.length === 0) { |
||||
|
actions.push(value); |
||||
|
} |
||||
|
return actions.join(''); |
||||
|
} |
||||
|
|
||||
|
// 回显数据字典(字符串、数组)
|
||||
|
export function selectDictLabels(datas, value, separator) { |
||||
|
if (value === undefined || value.length ===0) { |
||||
|
return ""; |
||||
|
} |
||||
|
if (Array.isArray(value)) { |
||||
|
value = value.join(","); |
||||
|
} |
||||
|
var actions = []; |
||||
|
var currentSeparator = undefined === separator ? "," : separator; |
||||
|
var temp = value.split(currentSeparator); |
||||
|
Object.keys(value.split(currentSeparator)).some((val) => { |
||||
|
var match = false; |
||||
|
Object.keys(datas).some((key) => { |
||||
|
if (datas[key].value == ('' + temp[val])) { |
||||
|
actions.push(datas[key].label + currentSeparator); |
||||
|
match = true; |
||||
|
} |
||||
|
}) |
||||
|
if (!match) { |
||||
|
actions.push(temp[val] + currentSeparator); |
||||
|
} |
||||
|
}) |
||||
|
return actions.join('').substring(0, actions.join('').length - 1); |
||||
|
} |
||||
|
|
||||
|
// 字符串格式化(%s )
|
||||
|
export function sprintf(str) { |
||||
|
var args = arguments, flag = true, i = 1; |
||||
|
str = str.replace(/%s/g, function () { |
||||
|
var arg = args[i++]; |
||||
|
if (typeof arg === 'undefined') { |
||||
|
flag = false; |
||||
|
return ''; |
||||
|
} |
||||
|
return arg; |
||||
|
}); |
||||
|
return flag ? str : ''; |
||||
|
} |
||||
|
|
||||
|
// 转换字符串,undefined,null等转化为""
|
||||
|
export function parseStrEmpty(str) { |
||||
|
if (!str || str == "undefined" || str == "null") { |
||||
|
return ""; |
||||
|
} |
||||
|
return str; |
||||
|
} |
||||
|
|
||||
|
// 数据合并
|
||||
|
export function mergeRecursive(source, target) { |
||||
|
for (var p in target) { |
||||
|
try { |
||||
|
if (target[p].constructor == Object) { |
||||
|
source[p] = mergeRecursive(source[p], target[p]); |
||||
|
} else { |
||||
|
source[p] = target[p]; |
||||
|
} |
||||
|
} catch (e) { |
||||
|
source[p] = target[p]; |
||||
|
} |
||||
|
} |
||||
|
return source; |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 构造树型结构数据 |
||||
|
* @param {*} data 数据源 |
||||
|
* @param {*} id id字段 默认 'id' |
||||
|
* @param {*} parentId 父节点字段 默认 'parentId' |
||||
|
* @param {*} children 孩子节点字段 默认 'children' |
||||
|
*/ |
||||
|
export function handleTree(data, id, parentId, children) { |
||||
|
let config = { |
||||
|
id: id || 'id', |
||||
|
parentId: parentId || 'parentId', |
||||
|
childrenList: children || 'children' |
||||
|
}; |
||||
|
|
||||
|
var childrenListMap = {}; |
||||
|
var nodeIds = {}; |
||||
|
var tree = []; |
||||
|
|
||||
|
for (let d of data) { |
||||
|
let parentId = d[config.parentId]; |
||||
|
if (childrenListMap[parentId] == null) { |
||||
|
childrenListMap[parentId] = []; |
||||
|
} |
||||
|
nodeIds[d[config.id]] = d; |
||||
|
childrenListMap[parentId].push(d); |
||||
|
} |
||||
|
|
||||
|
for (let d of data) { |
||||
|
let parentId = d[config.parentId]; |
||||
|
if (nodeIds[parentId] == null) { |
||||
|
tree.push(d); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for (let t of tree) { |
||||
|
adaptToChildrenList(t); |
||||
|
} |
||||
|
|
||||
|
function adaptToChildrenList(o) { |
||||
|
if (childrenListMap[o[config.id]] !== null) { |
||||
|
o[config.childrenList] = childrenListMap[o[config.id]]; |
||||
|
} |
||||
|
if (o[config.childrenList]) { |
||||
|
for (let c of o[config.childrenList]) { |
||||
|
adaptToChildrenList(c); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return tree; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 参数处理 |
||||
|
* @param {*} params 参数 |
||||
|
*/ |
||||
|
export function tansParams(params) { |
||||
|
let result = '' |
||||
|
for (const propName of Object.keys(params)) { |
||||
|
const value = params[propName]; |
||||
|
var part = encodeURIComponent(propName) + "="; |
||||
|
if (value !== null && value !== "" && typeof (value) !== "undefined") { |
||||
|
if (typeof value === 'object') { |
||||
|
for (const key of Object.keys(value)) { |
||||
|
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') { |
||||
|
let params = propName + '[' + key + ']'; |
||||
|
var subPart = encodeURIComponent(params) + "="; |
||||
|
result += subPart + encodeURIComponent(value[key]) + "&"; |
||||
|
} |
||||
|
} |
||||
|
} else { |
||||
|
result += part + encodeURIComponent(value) + "&"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return result |
||||
|
} |
||||
|
|
||||
|
// 验证是否为blob格式
|
||||
|
export function blobValidate(data) { |
||||
|
return data.type !== 'application/json' |
||||
|
} |
@ -0,0 +1,465 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<el-form |
||||
|
:model="queryParams" |
||||
|
ref="queryForm" |
||||
|
size="small" |
||||
|
:inline="true" |
||||
|
v-show="showSearch" |
||||
|
label-width="68px" |
||||
|
> |
||||
|
<el-form-item label="队列名称" prop="name"> |
||||
|
<el-input |
||||
|
v-model="queryParams.param.name" |
||||
|
placeholder="请输入" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
icon="el-icon-search" |
||||
|
size="mini" |
||||
|
@click="handleQuery" |
||||
|
>搜索</el-button |
||||
|
> |
||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"> |
||||
|
重置 |
||||
|
</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
|
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
plain |
||||
|
icon="el-icon-plus" |
||||
|
size="mini" |
||||
|
@click="handleAdd" |
||||
|
>新增</el-button |
||||
|
> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="danger" |
||||
|
plain |
||||
|
icon="el-icon-delete" |
||||
|
size="mini" |
||||
|
:disabled="multiple" |
||||
|
@click="handleDelete" |
||||
|
>删除</el-button |
||||
|
> |
||||
|
</el-col> |
||||
|
<right-toolbar |
||||
|
:showSearch.sync="showSearch" |
||||
|
@queryTable="getList" |
||||
|
></right-toolbar> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-table |
||||
|
v-loading="loading" |
||||
|
:data="listDat" |
||||
|
@selection-change="handleSelectionChange" |
||||
|
max-height="600" |
||||
|
> |
||||
|
<el-table-column type="selection" width="55" align="center" /> |
||||
|
<el-table-column |
||||
|
label="队列名称" |
||||
|
align="center" |
||||
|
prop="name" |
||||
|
min-width="130" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="随访方式" |
||||
|
align="center" |
||||
|
prop="followupMethod" |
||||
|
show-overflow-tooltip |
||||
|
min-width="100" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<span v-if="scope.row.followupMethod == 0">电话随访</span> |
||||
|
<span v-if="scope.row.followupMethod == 1">入户随访</span> |
||||
|
<span v-if="scope.row.followupMethod == 2">到院随访</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
|
||||
|
<el-table-column |
||||
|
label="随访类型" |
||||
|
align="center" |
||||
|
show-overflow-tooltip |
||||
|
min-width="150" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<span v-if="scope.row.followupType == 0">单次</span> |
||||
|
<span v-if="scope.row.followupType == 1">周期</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
label="随访频次" |
||||
|
align="center" |
||||
|
prop="frequency" |
||||
|
show-overflow-tooltip |
||||
|
min-width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="总月数" |
||||
|
align="center" |
||||
|
prop="followupMonth" |
||||
|
show-overflow-tooltip |
||||
|
min-width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="状态" |
||||
|
align="center" |
||||
|
prop="status" |
||||
|
show-overflow-tooltip |
||||
|
min-width="100" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<span v-if="scope.row.status == 0" style="color: red">禁用</span> |
||||
|
<span v-if="scope.row.status == 1" style="color: green">启用</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
label="创建人/创建时间" |
||||
|
align="center" |
||||
|
min-width="130" |
||||
|
fixed="right" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<div>{{ scope.row.createBy }}</div> |
||||
|
<span>{{ |
||||
|
parseTime(scope.row.createTime, "{y}-{m}-{d} {h}:{i}") |
||||
|
}}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column fixed="right" label="操作" align="center" width="150"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-edit" |
||||
|
@click="handleUpdate(scope.row)" |
||||
|
>修改</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-delete" |
||||
|
@click="handleDelete(scope.row)" |
||||
|
>删除</el-button |
||||
|
> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<pagination |
||||
|
v-show="total > 0" |
||||
|
:total="total" |
||||
|
:page.sync="queryParams.pageNum" |
||||
|
:limit.sync="queryParams.pageSize" |
||||
|
@pagination="getList" |
||||
|
/> |
||||
|
|
||||
|
<!-- 添加或修改公告对话框 --> |
||||
|
<el-dialog |
||||
|
class="popup" |
||||
|
:title="title" |
||||
|
:visible.sync="open" |
||||
|
width="780px" |
||||
|
append-to-body |
||||
|
> |
||||
|
<el-form |
||||
|
class="formStep" |
||||
|
ref="form" |
||||
|
:model="form" |
||||
|
:rules="rules" |
||||
|
label-width="90px" |
||||
|
> |
||||
|
<el-form-item label="队列名称" prop="name"> |
||||
|
<el-input v-model="form.name" placeholder="请输入" /> |
||||
|
</el-form-item> |
||||
|
|
||||
|
<el-form-item label="随访方式" prop="followupMethod"> |
||||
|
<el-select v-model="form.followupMethod" placeholder="请选择"> |
||||
|
<el-option label="电话随访" :value="0"> </el-option> |
||||
|
<el-option label="入户随访" :value="1"> </el-option> |
||||
|
<el-option label="到院随访" :value="2"> </el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="随访类型" prop="followupType"> |
||||
|
<el-radio-group v-model="form.followupType"> |
||||
|
<el-radio :label="0">单次</el-radio> |
||||
|
<el-radio :label="1">周期</el-radio> |
||||
|
</el-radio-group> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="随访频次" prop="followupType"> |
||||
|
<el-input v-model="form.frequency" placeholder="请输入cron执行表达式"> |
||||
|
<template slot="append"> |
||||
|
<el-button |
||||
|
style="width: 110px" |
||||
|
type="primary" |
||||
|
@click="handleShowCron" |
||||
|
> |
||||
|
生成表达式 |
||||
|
<i class="el-icon-time el-icon--right"></i> |
||||
|
</el-button> |
||||
|
</template> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="总月数" prop="followupMonth"> |
||||
|
<el-input v-model="form.followupMonth" placeholder="请输入" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="状态" prop="status"> |
||||
|
<el-radio-group v-model="form.status"> |
||||
|
<el-radio :label="1">启用</el-radio> |
||||
|
<el-radio :label="0">禁用</el-radio> |
||||
|
</el-radio-group> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
<el-button @click="cancel">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
<el-dialog |
||||
|
title="Cron表达式生成器" |
||||
|
:visible.sync="openCron" |
||||
|
append-to-body |
||||
|
destroy-on-close |
||||
|
class="scrollbar" |
||||
|
> |
||||
|
<crontab |
||||
|
@hide="openCron = false" |
||||
|
@fill="crontabFill" |
||||
|
:expression="expression" |
||||
|
></crontab> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import Crontab from "@/components/Crontab"; |
||||
|
import { |
||||
|
followupQuery, |
||||
|
followupAdd, |
||||
|
followupUpd, |
||||
|
followupDel, |
||||
|
} from "@/api/followupFile"; |
||||
|
export default { |
||||
|
name: "Notice", |
||||
|
components: { Crontab }, |
||||
|
data() { |
||||
|
return { |
||||
|
// 是否显示Cron表达式弹出层 |
||||
|
openCron: false, |
||||
|
// 传入的表达式 |
||||
|
expression: "", |
||||
|
idCardType: [ |
||||
|
{ |
||||
|
label: "身份证", |
||||
|
value: 0, |
||||
|
}, |
||||
|
{ |
||||
|
label: "护照或外国人永居证", |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: "港澳居民来往内地通行", |
||||
|
value: 2, |
||||
|
}, |
||||
|
{ |
||||
|
label: "台湾居民来往大陆通行证", |
||||
|
value: 3, |
||||
|
}, |
||||
|
], |
||||
|
idCardTypeValue: { |
||||
|
0: "身份证", |
||||
|
1: "护照或外国人永居证", |
||||
|
2: "港澳居民来往内地通行", |
||||
|
3: "台湾居民来往大陆通行证", |
||||
|
}, |
||||
|
loading: false, // 遮罩层 |
||||
|
ids: [], // 选中数组 |
||||
|
single: true, // 非单个禁用 |
||||
|
multiple: true, // 非多个禁用 |
||||
|
showSearch: true, // 显示搜索条件 |
||||
|
total: 0, // 总条数 |
||||
|
listDat: [{}], // 公告表格数据 |
||||
|
title: "", // 弹出层标题 |
||||
|
open: false, // 是否显示弹出层 |
||||
|
importOpen: false, // 导入弹窗 |
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
param: { |
||||
|
name: "", //关键字 |
||||
|
}, |
||||
|
}, |
||||
|
formDisabled: false, |
||||
|
importform: {}, |
||||
|
// 表单参数 |
||||
|
form: {}, |
||||
|
// 表单校验 |
||||
|
rules: { |
||||
|
name: [ |
||||
|
{ required: true, message: "队列名称不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
followupMethod: [ |
||||
|
{ required: true, message: "随访方式不能为空", trigger: "change" }, |
||||
|
], |
||||
|
followupType: [ |
||||
|
{ required: true, message: "随访类型不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
frequency: [ |
||||
|
{ required: true, message: "随访频次不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
status: [{ required: true, message: "状态不能为空", trigger: "blur" }], |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList(); |
||||
|
}, |
||||
|
methods: { |
||||
|
/** cron表达式按钮操作 */ |
||||
|
handleShowCron() { |
||||
|
this.expression = this.form.cronExpression; |
||||
|
this.openCron = true; |
||||
|
}, |
||||
|
/** 确定后回传值 */ |
||||
|
crontabFill(value) { |
||||
|
this.form.frequency = value; |
||||
|
}, |
||||
|
/** 查询公告列表 */ |
||||
|
getList() { |
||||
|
this.loading = true; |
||||
|
followupQuery(this.queryParams).then((res) => { |
||||
|
this.listDat = res.data.list; |
||||
|
this.total = res.data.total; |
||||
|
this.loading = false; |
||||
|
}); |
||||
|
}, |
||||
|
// 取消按钮 |
||||
|
cancel() { |
||||
|
this.open = false; |
||||
|
this.reset(); |
||||
|
}, |
||||
|
// 表单重置 |
||||
|
reset() { |
||||
|
this.form = { |
||||
|
name: "", // 姓名 |
||||
|
followupMethod: 0, // 随访方式 |
||||
|
followupType: 0, // 随访类型 |
||||
|
frequency: "", // cron执行表达式 |
||||
|
followupMonth: "", |
||||
|
status: 1, // 状态 |
||||
|
}; |
||||
|
this.resetForm("form"); |
||||
|
}, |
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1; |
||||
|
this.getList(); |
||||
|
}, |
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.queryParams = { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
param: { |
||||
|
name: "", |
||||
|
}, |
||||
|
}; |
||||
|
this.handleQuery(); |
||||
|
}, |
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map((item) => item.id); |
||||
|
this.single = selection.length != 1; |
||||
|
this.multiple = !selection.length; |
||||
|
}, |
||||
|
/** 新增按钮操作 */ |
||||
|
handleAdd() { |
||||
|
this.reset(); |
||||
|
this.open = true; |
||||
|
this.title = "新增随访队列"; |
||||
|
}, |
||||
|
/** 修改按钮操作 */ |
||||
|
handleUpdate(row) { |
||||
|
this.open = true; |
||||
|
this.title = "修改随访队列"; |
||||
|
this.form = JSON.parse(JSON.stringify(row)); |
||||
|
}, |
||||
|
/** 提交按钮 */ |
||||
|
submitForm: function () { |
||||
|
this.$refs["form"].validate((valid) => { |
||||
|
if (valid) { |
||||
|
if (this.form.id != undefined) { |
||||
|
followupUpd(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("修改成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} else { |
||||
|
followupAdd(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("新增成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const idList = row.id ? [row.id] : this.ids; |
||||
|
this.$modal |
||||
|
.confirm("是否确认删除当前选择的数据?") |
||||
|
.then(function () { |
||||
|
return followupDel({ idList: idList }); |
||||
|
}) |
||||
|
.then(() => { |
||||
|
this.getList(); |
||||
|
this.$modal.msgSuccess("删除成功"); |
||||
|
}) |
||||
|
.catch(() => {}); |
||||
|
}, |
||||
|
/** 导出按钮操作 */ |
||||
|
handleExport() { |
||||
|
this.download( |
||||
|
"system/user/export", |
||||
|
{ |
||||
|
...this.queryParams.params, |
||||
|
}, |
||||
|
`患者档案.xlsx` |
||||
|
); |
||||
|
}, |
||||
|
/** 导入按钮操作 */ |
||||
|
handleImport() { |
||||
|
this.upload.title = "用户导入"; |
||||
|
this.upload.open = true; |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
<style scoped src="@/assets/styles/common.css"></style> |
||||
|
<style scoped> |
||||
|
.form-item-age { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.form-item-age span { |
||||
|
margin: 0 10px; |
||||
|
} |
||||
|
.form-item-age >>> .el-input { |
||||
|
width: 100px; |
||||
|
} |
||||
|
</style> |
||||
|
<!-- >>> .el-input__inner { |
||||
|
padding: 0 15px !important; |
||||
|
} --> |
@ -0,0 +1,398 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<el-form |
||||
|
:model="queryParams" |
||||
|
ref="queryForm" |
||||
|
size="small" |
||||
|
:inline="true" |
||||
|
v-show="showSearch" |
||||
|
label-width="68px" |
||||
|
> |
||||
|
<el-form-item label="随访队列" prop="queueId"> |
||||
|
<el-select v-model="queryParams.param.queueId" placeholder="请选择"> |
||||
|
<el-option |
||||
|
v-for="item in followupList" |
||||
|
:key="item.id" |
||||
|
:label="item.name" |
||||
|
:value="item.id" |
||||
|
> |
||||
|
</el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
icon="el-icon-search" |
||||
|
size="mini" |
||||
|
@click="handleQuery" |
||||
|
>搜索</el-button |
||||
|
> |
||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"> |
||||
|
重置 |
||||
|
</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
|
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<right-toolbar |
||||
|
:showSearch.sync="showSearch" |
||||
|
@queryTable="getList" |
||||
|
></right-toolbar> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-table |
||||
|
v-loading="loading" |
||||
|
:data="listDat" |
||||
|
@selection-change="handleSelectionChange" |
||||
|
max-height="600" |
||||
|
> |
||||
|
<el-table-column type="selection" width="55" align="center" /> |
||||
|
<el-table-column label="姓名" align="center" prop="name" width="100" /> |
||||
|
<el-table-column |
||||
|
label="性别" |
||||
|
align="center" |
||||
|
prop="gender" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<span v-if="scope.row.gender == 0">男</span> |
||||
|
<span v-if="scope.row.gender == 1">女</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
|
||||
|
<el-table-column |
||||
|
label="出生日期" |
||||
|
align="center" |
||||
|
prop="birthDate" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
{{ parseTime(scope.row.createTime, "{y}-{m}-{d}") }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
label="民族" |
||||
|
align="center" |
||||
|
prop="ethnicity" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="受教育年限" |
||||
|
align="center" |
||||
|
prop="educationYears" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="手机号码" |
||||
|
align="center" |
||||
|
prop="phone" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="证件类型" |
||||
|
align="center" |
||||
|
prop="idCardType" |
||||
|
show-overflow-tooltip |
||||
|
width="200" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
{{ idCardTypeValue[scope.row.idCardType] }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
label="证件号码" |
||||
|
align="center" |
||||
|
prop="idCard" |
||||
|
show-overflow-tooltip |
||||
|
width="180" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
fixed="right" |
||||
|
label="随访队列" |
||||
|
align="center" |
||||
|
prop="queueList" |
||||
|
show-overflow-tooltip |
||||
|
width="180" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<div v-if="scope.row.queueList && scope.row.queueList.length"> |
||||
|
{{ scope.row.queueList.map((i) => i.queueName).join(",") }} |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
label="创建人/创建时间" |
||||
|
align="center" |
||||
|
width="130" |
||||
|
fixed="right" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<div>{{ scope.row.createBy }}</div> |
||||
|
<span>{{ |
||||
|
parseTime(scope.row.createTime, "{y}-{m}-{d} {h}:{i}") |
||||
|
}}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column fixed="right" label="操作" align="center" width="200"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-edit" |
||||
|
@click="handleUpdate(scope.row)" |
||||
|
>队列管理</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-tickets" |
||||
|
@click="handlePatient(scope.row)" |
||||
|
>患者档案</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-notebook-2" |
||||
|
@click="handleMedical(scope.row)" |
||||
|
>诊疗档案</el-button |
||||
|
> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<pagination |
||||
|
v-show="total > 0" |
||||
|
:total="total" |
||||
|
:page.sync="queryParams.pageNum" |
||||
|
:limit.sync="queryParams.pageSize" |
||||
|
@pagination="getList" |
||||
|
/> |
||||
|
|
||||
|
<!-- 添加或修改公告对话框 --> |
||||
|
<el-dialog |
||||
|
class="popup" |
||||
|
:title="title" |
||||
|
:visible.sync="open" |
||||
|
width="780px" |
||||
|
append-to-body |
||||
|
> |
||||
|
<el-form |
||||
|
class="formStep" |
||||
|
ref="form" |
||||
|
:model="form" |
||||
|
:rules="rules" |
||||
|
label-width="90px" |
||||
|
> |
||||
|
<el-form-item label="随访队列" prop="queueIdList"> |
||||
|
<el-select v-model="form.queueIdList" multiple placeholder="请选择"> |
||||
|
<el-option |
||||
|
v-for="item in followupList" |
||||
|
:key="item.id" |
||||
|
:label="item.name" |
||||
|
:value="item.id" |
||||
|
> |
||||
|
</el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
<el-button @click="cancel">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { queryPatient, followupQuery, updPatient } from "@/api/followupFile"; |
||||
|
export default { |
||||
|
name: "Notice", |
||||
|
data() { |
||||
|
return { |
||||
|
fileList: [], |
||||
|
idCardType: [ |
||||
|
{ |
||||
|
label: "身份证", |
||||
|
value: 0, |
||||
|
}, |
||||
|
{ |
||||
|
label: "护照或外国人永居证", |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: "港澳居民来往内地通行", |
||||
|
value: 2, |
||||
|
}, |
||||
|
{ |
||||
|
label: "台湾居民来往大陆通行证", |
||||
|
value: 3, |
||||
|
}, |
||||
|
], |
||||
|
idCardTypeValue: { |
||||
|
0: "身份证", |
||||
|
1: "护照或外国人永居证", |
||||
|
2: "港澳居民来往内地通行", |
||||
|
3: "台湾居民来往大陆通行证", |
||||
|
}, |
||||
|
loading: false, // 遮罩层 |
||||
|
ids: [], // 选中数组 |
||||
|
single: true, // 非单个禁用 |
||||
|
multiple: true, // 非多个禁用 |
||||
|
showSearch: true, // 显示搜索条件 |
||||
|
total: 0, // 总条数 |
||||
|
listDat: [{}], // 公告表格数据 |
||||
|
title: "", // 弹出层标题 |
||||
|
open: false, // 是否显示弹出层 |
||||
|
importOpen: false, // 导入弹窗 |
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
param: {}, |
||||
|
}, |
||||
|
formDisabled: false, |
||||
|
importform: {}, |
||||
|
// 表单参数 |
||||
|
form: {}, |
||||
|
// 表单校验 |
||||
|
rules: { |
||||
|
queueIdList: [ |
||||
|
{ required: true, message: "随访队列不能为空", trigger: "change" }, |
||||
|
], |
||||
|
}, |
||||
|
followupList: [], // 随访队列 |
||||
|
}; |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList(); |
||||
|
this.getFollowupQuery(); |
||||
|
}, |
||||
|
methods: { |
||||
|
// 获取随访队列信息 |
||||
|
getFollowupQuery() { |
||||
|
followupQuery({ |
||||
|
pageNum: -1, |
||||
|
param: {}, |
||||
|
}).then((res) => { |
||||
|
this.followupList = res.data.list; |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** 查询公告列表 */ |
||||
|
getList() { |
||||
|
this.loading = true; |
||||
|
queryPatient(this.queryParams).then((res) => { |
||||
|
this.listDat = res.data.list; |
||||
|
this.total = res.data.total; |
||||
|
this.loading = false; |
||||
|
}); |
||||
|
}, |
||||
|
// 取消按钮 |
||||
|
cancel() { |
||||
|
this.open = false; |
||||
|
this.reset(); |
||||
|
}, |
||||
|
// 表单重置 |
||||
|
reset() { |
||||
|
this.form = {}; |
||||
|
this.resetForm("form"); |
||||
|
}, |
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1; |
||||
|
this.getList(); |
||||
|
}, |
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.resetForm("queryForm"); |
||||
|
this.handleQuery(); |
||||
|
}, |
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map((item) => item.id); |
||||
|
this.single = selection.length != 1; |
||||
|
this.multiple = !selection.length; |
||||
|
}, |
||||
|
/** 修改按钮操作 */ |
||||
|
handleUpdate(row) { |
||||
|
this.open = true; |
||||
|
this.title = "队列管理"; |
||||
|
let queueList = row.queueList.map((item) => item.queueId); |
||||
|
this.form = JSON.parse( |
||||
|
JSON.stringify({ |
||||
|
...row, |
||||
|
patientId: row.id, |
||||
|
queueIdList: queueList, |
||||
|
}) |
||||
|
); |
||||
|
}, |
||||
|
/** 跳转患者档案 */ |
||||
|
handlePatient(row) {}, |
||||
|
/** 诊疗档案 */ |
||||
|
handleMedical(row) {}, |
||||
|
/** 提交按钮 */ |
||||
|
submitForm: function () { |
||||
|
this.$refs["form"].validate((valid) => { |
||||
|
if (valid) { |
||||
|
updPatient(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("修改成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const idList = row.id ? [row.id] : this.ids; |
||||
|
this.$modal |
||||
|
.confirm("是否确认删除当前选择的数据?") |
||||
|
.then(function () { |
||||
|
return patientDel({ idList: idList }); |
||||
|
}) |
||||
|
.then(() => { |
||||
|
this.getList(); |
||||
|
this.$modal.msgSuccess("删除成功"); |
||||
|
}) |
||||
|
.catch(() => {}); |
||||
|
}, |
||||
|
/** 导出按钮操作 */ |
||||
|
handleExport() { |
||||
|
this.download( |
||||
|
"system/user/export", |
||||
|
{ |
||||
|
...this.queryParams.params, |
||||
|
}, |
||||
|
`患者档案.xlsx` |
||||
|
); |
||||
|
}, |
||||
|
/** 导入按钮操作 */ |
||||
|
handleImport() { |
||||
|
this.upload.title = "用户导入"; |
||||
|
this.upload.open = true; |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
<style scoped src="@/assets/styles/common.css"></style> |
||||
|
<style scoped> |
||||
|
.form-item-age { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.form-item-age span { |
||||
|
margin: 0 10px; |
||||
|
} |
||||
|
.form-item-age >>> .el-input { |
||||
|
width: 100px; |
||||
|
} |
||||
|
</style> |
||||
|
<!-- >>> .el-input__inner { |
||||
|
padding: 0 15px !important; |
||||
|
} --> |
@ -0,0 +1,529 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<right-toolbar |
||||
|
:showSearch.sync="showSearch" |
||||
|
@queryTable="getList" |
||||
|
></right-toolbar> |
||||
|
</el-row> |
||||
|
<el-tabs v-model="queryParams.param.status" @tab-click="handleClick"> |
||||
|
<el-tab-pane label="待随访" name="0"></el-tab-pane> |
||||
|
<el-tab-pane label="已随访" name="1"></el-tab-pane> |
||||
|
<el-tab-pane label="失访" name="2"></el-tab-pane> |
||||
|
</el-tabs> |
||||
|
<el-table |
||||
|
v-loading="loading" |
||||
|
:data="listDat" |
||||
|
@selection-change="handleSelectionChange" |
||||
|
> |
||||
|
<el-table-column type="selection" width="55" align="center" /> |
||||
|
<el-table-column |
||||
|
label="工单id" |
||||
|
show-overflow-tooltip |
||||
|
align="center" |
||||
|
prop="" |
||||
|
width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="随访队列" |
||||
|
show-overflow-tooltip |
||||
|
align="" |
||||
|
prop="name" |
||||
|
width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="患者姓名" |
||||
|
align="center" |
||||
|
prop="name" |
||||
|
width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="性别" |
||||
|
align="center" |
||||
|
prop="gender" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<span v-if="scope.row.gender == 0">男</span> |
||||
|
<span v-if="scope.row.gender == 1">女</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
|
||||
|
<el-table-column |
||||
|
label="年龄" |
||||
|
align="center" |
||||
|
prop="age" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="证件号码" |
||||
|
align="center" |
||||
|
prop="idCard" |
||||
|
show-overflow-tooltip |
||||
|
width="180" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="手机号码" |
||||
|
align="center" |
||||
|
prop="phone" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="随访序号" |
||||
|
align="center" |
||||
|
prop="phone" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="开始时间" |
||||
|
align="center" |
||||
|
prop="startTime" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="结束时间" |
||||
|
align="center" |
||||
|
prop="endTime" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<!--待随访: 随访状态(待随访/即将超期/超期) --> |
||||
|
<!--已随访: 随访状态(已随访/超随访期) --> |
||||
|
<!--待随访: 随访状态(待随访) --> |
||||
|
<el-table-column |
||||
|
label="随访状态" |
||||
|
align="center" |
||||
|
prop="phone" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
{{ status[scope.row.status] }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<!-- <el-table-column |
||||
|
label="失访状态" |
||||
|
align="center" |
||||
|
prop="phone" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> --> |
||||
|
<el-table-column |
||||
|
label="失访原因" |
||||
|
align="center" |
||||
|
prop="reason" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
|
||||
|
<el-table-column fixed="right" label="操作" align="center" width="150"> |
||||
|
<template slot-scope="scope"> |
||||
|
<!-- :disabled="scope.row.status !== '0'" --> |
||||
|
<el-button |
||||
|
:disabled="scope.row.status !== '0'" |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-s-check" |
||||
|
@click="handleFollow(scope.row)" |
||||
|
> |
||||
|
随访 |
||||
|
</el-button> |
||||
|
<el-button |
||||
|
:disabled="scope.row.status !== '0'" |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-s-release" |
||||
|
@click="handleLossFollow(scope.row)" |
||||
|
> |
||||
|
失访 |
||||
|
</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<pagination |
||||
|
v-show="total > 0" |
||||
|
:total="total" |
||||
|
:page.sync="queryParams.pageNum" |
||||
|
:limit.sync="queryParams.pageSize" |
||||
|
@pagination="getList" |
||||
|
/> |
||||
|
|
||||
|
<!-- 失访 --> |
||||
|
<el-dialog |
||||
|
class="popup" |
||||
|
title="失访" |
||||
|
:visible.sync="open" |
||||
|
width="780px" |
||||
|
append-to-body |
||||
|
> |
||||
|
<el-form |
||||
|
class="formStep" |
||||
|
ref="form" |
||||
|
:model="form" |
||||
|
:rules="rules" |
||||
|
label-width="90px" |
||||
|
> |
||||
|
<el-form-item label="随访次数" prop="times"> |
||||
|
<el-input v-model="form.times" placeholder="请输入" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="失访原因" prop="reason"> |
||||
|
<el-select v-model="form.reason" placeholder="请选择"> |
||||
|
<el-option-group |
||||
|
v-for="group in options" |
||||
|
:key="group.label" |
||||
|
:label="group.label" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="item in group.options" |
||||
|
:key="item.value" |
||||
|
:label="item.label" |
||||
|
:value="item.value" |
||||
|
> |
||||
|
</el-option> |
||||
|
</el-option-group> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
<el-button @click="open = false">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
<!-- 随访 --> |
||||
|
<el-dialog |
||||
|
class="popup" |
||||
|
title="随访" |
||||
|
:visible.sync="open1" |
||||
|
width="780px" |
||||
|
append-to-body |
||||
|
> |
||||
|
<el-form |
||||
|
class="formStep" |
||||
|
ref="form1" |
||||
|
:model="form" |
||||
|
:rules="rules" |
||||
|
label-width="90px" |
||||
|
> |
||||
|
<el-form-item label="随访人" prop="followuper"> |
||||
|
<el-input v-model="form.followuper" placeholder="请输入" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="随访时间" prop="followupTime"> |
||||
|
<el-date-picker |
||||
|
format="yyyy-MM-dd HH:mm:ss" |
||||
|
value-format="yyyy-MM-dd HH:mm:ss" |
||||
|
v-model="form.followupTime" |
||||
|
type="datetime" |
||||
|
placeholder="选择日期" |
||||
|
> |
||||
|
</el-date-picker> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="随访次数" prop="times"> |
||||
|
<el-input v-model="form.times" placeholder="请输入" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="随访内容" prop="followupText"> |
||||
|
<el-input v-model="form.followupText" placeholder="请输入" /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm1">确 定</el-button> |
||||
|
<el-button @click="open1 = false">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { queryTask, updStatus, followPatient } from "@/api/followupFile"; |
||||
|
export default { |
||||
|
name: "Notice", |
||||
|
data() { |
||||
|
return { |
||||
|
options: [ |
||||
|
{ |
||||
|
label: "患者原因", |
||||
|
options: [ |
||||
|
{ |
||||
|
value: "患者病情加重或死亡,无法参与随访", |
||||
|
}, |
||||
|
{ |
||||
|
value: "患者依从性差,不配合随访", |
||||
|
}, |
||||
|
{ |
||||
|
value: "患者主动退出或不愿继续随访", |
||||
|
}, |
||||
|
{ |
||||
|
value: "患者搬迁、工作变动、联系方式更换,无法联系到患者", |
||||
|
}, |
||||
|
{ |
||||
|
value: "信息记录不准确,错误记录患者联系方式或地址", |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
label: "医疗机构原因", |
||||
|
options: [ |
||||
|
{ |
||||
|
value: "随访管理不足,未及时安排随访", |
||||
|
}, |
||||
|
{ |
||||
|
value: "随访人员更换,管理混乱导致遗漏", |
||||
|
}, |
||||
|
{ |
||||
|
value: "转诊或转院", |
||||
|
}, |
||||
|
{ |
||||
|
value: "医疗资源受限", |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
label: "不可抗力", |
||||
|
options: [ |
||||
|
{ |
||||
|
value: "社会动荡或自然灾害", |
||||
|
}, |
||||
|
{ |
||||
|
value: "疫情或公共卫生事件", |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
], |
||||
|
activeName: "", |
||||
|
status: { |
||||
|
0: "待随访", |
||||
|
1: "已随访", |
||||
|
2: "失访", |
||||
|
3: "即将超期", |
||||
|
4: "超期未随访", |
||||
|
5: "超期已随访", |
||||
|
}, |
||||
|
idCardType: [ |
||||
|
{ |
||||
|
label: "身份证", |
||||
|
value: 0, |
||||
|
}, |
||||
|
{ |
||||
|
label: "护照或外国人永居证", |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: "港澳居民来往内地通行", |
||||
|
value: 2, |
||||
|
}, |
||||
|
{ |
||||
|
label: "台湾居民来往大陆通行证", |
||||
|
value: 3, |
||||
|
}, |
||||
|
], |
||||
|
idCardTypeValue: { |
||||
|
0: "身份证", |
||||
|
1: "护照或外国人永居证", |
||||
|
2: "港澳居民来往内地通行", |
||||
|
3: "台湾居民来往大陆通行证", |
||||
|
}, |
||||
|
loading: false, // 遮罩层 |
||||
|
ids: [], // 选中数组 |
||||
|
single: true, // 非单个禁用 |
||||
|
multiple: true, // 非多个禁用 |
||||
|
showSearch: true, // 显示搜索条件 |
||||
|
total: 0, // 总条数 |
||||
|
listDat: [{}], // 公告表格数据 |
||||
|
title: "", // 弹出层标题 |
||||
|
open: false, // 是否显示弹出层 |
||||
|
open1: false, // 是否显示弹出层 |
||||
|
importOpen: false, // 导入弹窗 |
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
param: { |
||||
|
status: "0", |
||||
|
}, |
||||
|
}, |
||||
|
formDisabled: false, |
||||
|
importform: {}, |
||||
|
// 表单参数 |
||||
|
form: {}, |
||||
|
// 表单校验 |
||||
|
rules: { |
||||
|
followuper: [ |
||||
|
{ required: true, message: "随访人不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
followupTime: [ |
||||
|
{ required: true, message: "随访时间不能为空", trigger: "change" }, |
||||
|
], |
||||
|
followupText: [ |
||||
|
{ required: true, message: "随访内容不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
times: [ |
||||
|
{ required: true, message: "随访次数不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
|
||||
|
reason: [ |
||||
|
{ required: true, message: "失访原因不能为空", trigger: "change" }, |
||||
|
], |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList(); |
||||
|
}, |
||||
|
methods: { |
||||
|
handleClick(tab, event) { |
||||
|
this.getList(); |
||||
|
}, |
||||
|
/** 查询公告列表 */ |
||||
|
getList() { |
||||
|
this.loading = true; |
||||
|
queryTask(this.queryParams).then((res) => { |
||||
|
this.listDat = res.data.list; |
||||
|
this.total = res.data.total; |
||||
|
this.loading = false; |
||||
|
}); |
||||
|
}, |
||||
|
// 取消按钮 |
||||
|
cancel() { |
||||
|
this.open = false; |
||||
|
this.reset(); |
||||
|
}, |
||||
|
// 表单重置 |
||||
|
reset() { |
||||
|
this.form = {}; |
||||
|
this.resetForm("form"); |
||||
|
}, |
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1; |
||||
|
this.getList(); |
||||
|
}, |
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.resetForm("queryForm"); |
||||
|
this.handleQuery(); |
||||
|
}, |
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map((item) => item.id); |
||||
|
this.single = selection.length != 1; |
||||
|
this.multiple = !selection.length; |
||||
|
}, |
||||
|
/** 新增按钮操作 */ |
||||
|
handleAdd() { |
||||
|
this.reset(); |
||||
|
this.open = true; |
||||
|
}, |
||||
|
/** 随访 */ |
||||
|
handleFollow(row) { |
||||
|
this.open1 = true; |
||||
|
this.form = { |
||||
|
id: row.id, |
||||
|
followuper: "", |
||||
|
followupTime: "", |
||||
|
times: "", |
||||
|
followupText: "", |
||||
|
}; |
||||
|
}, |
||||
|
/** 失访 */ |
||||
|
handleLossFollow(row) { |
||||
|
this.open = true; |
||||
|
this.form = JSON.parse(JSON.stringify(row)); |
||||
|
this.form.status = 2; |
||||
|
}, |
||||
|
/** 提交按钮 */ |
||||
|
submitForm: function () { |
||||
|
this.$refs["form"].validate((valid) => { |
||||
|
if (valid) { |
||||
|
if (this.form.id != undefined) { |
||||
|
patientUpd(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("修改成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} else { |
||||
|
patientAdd(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("新增成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
/** 失访 */ |
||||
|
submitForm: function () { |
||||
|
this.$refs["form"].validate((valid) => { |
||||
|
if (valid) { |
||||
|
updStatus(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("操作成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
/** 随访 */ |
||||
|
submitForm1: function () { |
||||
|
this.$refs["form1"].validate((valid) => { |
||||
|
if (valid) { |
||||
|
followPatient(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("操作成功"); |
||||
|
this.open1 = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const idList = row.id ? [row.id] : this.ids; |
||||
|
this.$modal |
||||
|
.confirm("是否确认删除当前选择的数据?") |
||||
|
.then(function () { |
||||
|
return patientDel({ idList: idList }); |
||||
|
}) |
||||
|
.then(() => { |
||||
|
this.getList(); |
||||
|
this.$modal.msgSuccess("删除成功"); |
||||
|
}) |
||||
|
.catch(() => {}); |
||||
|
}, |
||||
|
/** 导出按钮操作 */ |
||||
|
handleExport() { |
||||
|
this.download( |
||||
|
"system/user/export", |
||||
|
{ |
||||
|
...this.queryParams.params, |
||||
|
}, |
||||
|
`患者档案.xlsx` |
||||
|
); |
||||
|
}, |
||||
|
/** 导入按钮操作 */ |
||||
|
handleImport() { |
||||
|
this.upload.title = "用户导入"; |
||||
|
this.upload.open = true; |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
<style scoped src="@/assets/styles/common.css"></style> |
||||
|
<style scoped> |
||||
|
.form-item-age { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.form-item-age span { |
||||
|
margin: 0 10px; |
||||
|
} |
||||
|
.form-item-age >>> .el-input { |
||||
|
width: 100px; |
||||
|
} |
||||
|
</style> |
||||
|
<!-- >>> .el-input__inner { |
||||
|
padding: 0 15px !important; |
||||
|
} --> |
File diff suppressed because it is too large
@ -0,0 +1,251 @@ |
|||||
|
<template> |
||||
|
<div class="login"> |
||||
|
<el-form |
||||
|
ref="loginForm" |
||||
|
:model="loginForm" |
||||
|
:rules="loginRules" |
||||
|
class="login-form" |
||||
|
> |
||||
|
<h3 class="title">针灸后台管理系统</h3> |
||||
|
<el-form-item prop="username"> |
||||
|
<el-input |
||||
|
v-model="loginForm.username" |
||||
|
type="text" |
||||
|
auto-complete="off" |
||||
|
placeholder="账号" |
||||
|
> |
||||
|
<svg-icon |
||||
|
slot="prefix" |
||||
|
icon-class="user" |
||||
|
class="el-input__icon input-icon" |
||||
|
/> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item prop="password"> |
||||
|
<el-input |
||||
|
v-model="loginForm.password" |
||||
|
type="password" |
||||
|
auto-complete="off" |
||||
|
placeholder="密码" |
||||
|
@keyup.enter.native="handleLogin" |
||||
|
> |
||||
|
<svg-icon |
||||
|
slot="prefix" |
||||
|
icon-class="password" |
||||
|
class="el-input__icon input-icon" |
||||
|
/> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item prop="code" v-if="captchaEnabled"> |
||||
|
<el-input |
||||
|
v-model="loginForm.code" |
||||
|
auto-complete="off" |
||||
|
placeholder="验证码" |
||||
|
style="width: 63%" |
||||
|
@keyup.enter.native="handleLogin" |
||||
|
> |
||||
|
<svg-icon |
||||
|
slot="prefix" |
||||
|
icon-class="validCode" |
||||
|
class="el-input__icon input-icon" |
||||
|
/> |
||||
|
</el-input> |
||||
|
<div class="login-code"> |
||||
|
<img :src="codeUrl" @click="getCode" class="login-code-img" /> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
<el-checkbox |
||||
|
v-model="loginForm.rememberMe" |
||||
|
style="margin: 0px 0px 25px 0px" |
||||
|
>记住密码</el-checkbox |
||||
|
> |
||||
|
<el-form-item style="width: 100%"> |
||||
|
<el-button |
||||
|
:loading="loading" |
||||
|
size="medium" |
||||
|
type="primary" |
||||
|
style="width: 100%" |
||||
|
@click.native.prevent="handleLogin" |
||||
|
> |
||||
|
<span v-if="!loading">登 录</span> |
||||
|
<span v-else>登 录 中...</span> |
||||
|
</el-button> |
||||
|
<div style="float: right" v-if="register"> |
||||
|
<router-link class="link-type" :to="'/register'" |
||||
|
>立即注册</router-link |
||||
|
> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<!-- 底部 --> |
||||
|
<div class="el-login-footer"> |
||||
|
<span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { getCodeImg } from "@/api/login"; |
||||
|
import Cookies from "js-cookie"; |
||||
|
import { encrypt, decrypt } from "@/utils/jsencrypt"; |
||||
|
|
||||
|
export default { |
||||
|
name: "Login", |
||||
|
data() { |
||||
|
return { |
||||
|
codeUrl: "", |
||||
|
loginForm: { |
||||
|
username: "admin", |
||||
|
password: "admin123", |
||||
|
rememberMe: false, |
||||
|
code: "", |
||||
|
uuid: "", |
||||
|
}, |
||||
|
loginRules: { |
||||
|
username: [ |
||||
|
{ required: true, trigger: "blur", message: "请输入您的账号" }, |
||||
|
], |
||||
|
password: [ |
||||
|
{ required: true, trigger: "blur", message: "请输入您的密码" }, |
||||
|
], |
||||
|
code: [{ required: true, trigger: "change", message: "请输入验证码" }], |
||||
|
}, |
||||
|
loading: false, |
||||
|
// 验证码开关 |
||||
|
captchaEnabled: true, |
||||
|
// 注册开关 |
||||
|
register: false, |
||||
|
redirect: undefined, |
||||
|
}; |
||||
|
}, |
||||
|
watch: { |
||||
|
$route: { |
||||
|
handler: function (route) { |
||||
|
this.redirect = route.query && route.query.redirect; |
||||
|
}, |
||||
|
immediate: true, |
||||
|
}, |
||||
|
}, |
||||
|
created() { |
||||
|
this.getCode(); |
||||
|
this.getCookie(); |
||||
|
}, |
||||
|
methods: { |
||||
|
getCode() { |
||||
|
getCodeImg().then((res) => { |
||||
|
this.captchaEnabled = |
||||
|
res.captchaEnabled === undefined ? true : res.captchaEnabled; |
||||
|
if (this.captchaEnabled) { |
||||
|
this.codeUrl = "data:image/gif;base64," + res.img; |
||||
|
this.loginForm.uuid = res.uuid; |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
getCookie() { |
||||
|
const username = Cookies.get("username"); |
||||
|
const password = Cookies.get("password"); |
||||
|
const rememberMe = Cookies.get("rememberMe"); |
||||
|
this.loginForm = { |
||||
|
username: username === undefined ? this.loginForm.username : username, |
||||
|
password: |
||||
|
password === undefined ? this.loginForm.password : decrypt(password), |
||||
|
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe), |
||||
|
}; |
||||
|
}, |
||||
|
handleLogin() { |
||||
|
this.$refs.loginForm.validate((valid) => { |
||||
|
if (valid) { |
||||
|
this.loading = true; |
||||
|
if (this.loginForm.rememberMe) { |
||||
|
Cookies.set("username", this.loginForm.username, { expires: 30 }); |
||||
|
Cookies.set("password", encrypt(this.loginForm.password), { |
||||
|
expires: 30, |
||||
|
}); |
||||
|
Cookies.set("rememberMe", this.loginForm.rememberMe, { |
||||
|
expires: 30, |
||||
|
}); |
||||
|
} else { |
||||
|
Cookies.remove("username"); |
||||
|
Cookies.remove("password"); |
||||
|
Cookies.remove("rememberMe"); |
||||
|
} |
||||
|
this.$store |
||||
|
.dispatch("Login", this.loginForm) |
||||
|
.then(() => { |
||||
|
this.$router.push({ path: this.redirect || "/" }).catch(() => {}); |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
this.loading = false; |
||||
|
if (this.captchaEnabled) { |
||||
|
this.getCode(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style rel="stylesheet/scss" lang="scss"> |
||||
|
.login { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
height: 100%; |
||||
|
background-image: url("../assets/images/login-background.jpg"); |
||||
|
background-size: cover; |
||||
|
} |
||||
|
.title { |
||||
|
margin: 0px auto 30px auto; |
||||
|
text-align: center; |
||||
|
color: #707070; |
||||
|
} |
||||
|
|
||||
|
.login-form { |
||||
|
border-radius: 6px; |
||||
|
background: #ffffff; |
||||
|
width: 400px; |
||||
|
padding: 25px 25px 5px 25px; |
||||
|
.el-input { |
||||
|
height: 38px; |
||||
|
input { |
||||
|
height: 38px; |
||||
|
} |
||||
|
} |
||||
|
.input-icon { |
||||
|
height: 39px; |
||||
|
width: 14px; |
||||
|
margin-left: 2px; |
||||
|
} |
||||
|
} |
||||
|
.login-tip { |
||||
|
font-size: 13px; |
||||
|
text-align: center; |
||||
|
color: #bfbfbf; |
||||
|
} |
||||
|
.login-code { |
||||
|
width: 33%; |
||||
|
height: 38px; |
||||
|
float: right; |
||||
|
img { |
||||
|
cursor: pointer; |
||||
|
vertical-align: middle; |
||||
|
} |
||||
|
} |
||||
|
.el-login-footer { |
||||
|
height: 40px; |
||||
|
line-height: 40px; |
||||
|
position: fixed; |
||||
|
bottom: 0; |
||||
|
width: 100%; |
||||
|
text-align: center; |
||||
|
color: #fff; |
||||
|
font-family: Arial; |
||||
|
font-size: 12px; |
||||
|
letter-spacing: 1px; |
||||
|
} |
||||
|
.login-code-img { |
||||
|
height: 38px; |
||||
|
} |
||||
|
</style> |
File diff suppressed because it is too large
@ -0,0 +1,513 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> |
||||
|
<el-form-item label="任务名称" prop="jobName"> |
||||
|
<el-input |
||||
|
v-model="queryParams.jobName" |
||||
|
placeholder="请输入任务名称" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="任务组名" prop="jobGroup"> |
||||
|
<el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable> |
||||
|
<el-option |
||||
|
v-for="dict in dict.type.sys_job_group" |
||||
|
:key="dict.value" |
||||
|
:label="dict.label" |
||||
|
:value="dict.value" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="任务状态" prop="status"> |
||||
|
<el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable> |
||||
|
<el-option |
||||
|
v-for="dict in dict.type.sys_job_status" |
||||
|
:key="dict.value" |
||||
|
:label="dict.label" |
||||
|
:value="dict.value" |
||||
|
/> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> |
||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
|
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
plain |
||||
|
icon="el-icon-plus" |
||||
|
size="mini" |
||||
|
@click="handleAdd" |
||||
|
v-hasPermi="['monitor:job:add']" |
||||
|
>新增</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="success" |
||||
|
plain |
||||
|
icon="el-icon-edit" |
||||
|
size="mini" |
||||
|
:disabled="single" |
||||
|
@click="handleUpdate" |
||||
|
v-hasPermi="['monitor:job:edit']" |
||||
|
>修改</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="danger" |
||||
|
plain |
||||
|
icon="el-icon-delete" |
||||
|
size="mini" |
||||
|
:disabled="multiple" |
||||
|
@click="handleDelete" |
||||
|
v-hasPermi="['monitor:job:remove']" |
||||
|
>删除</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="warning" |
||||
|
plain |
||||
|
icon="el-icon-download" |
||||
|
size="mini" |
||||
|
@click="handleExport" |
||||
|
v-hasPermi="['monitor:job:export']" |
||||
|
>导出</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="info" |
||||
|
plain |
||||
|
icon="el-icon-s-operation" |
||||
|
size="mini" |
||||
|
@click="handleJobLog" |
||||
|
v-hasPermi="['monitor:job:query']" |
||||
|
>日志</el-button> |
||||
|
</el-col> |
||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange"> |
||||
|
<el-table-column type="selection" width="55" align="center" /> |
||||
|
<el-table-column label="任务编号" width="100" align="center" prop="jobId" /> |
||||
|
<el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="任务组名" align="center" prop="jobGroup"> |
||||
|
<template slot-scope="scope"> |
||||
|
<dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="状态" align="center"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-switch |
||||
|
v-model="scope.row.status" |
||||
|
active-value="0" |
||||
|
inactive-value="1" |
||||
|
@change="handleStatusChange(scope.row)" |
||||
|
></el-switch> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-edit" |
||||
|
@click="handleUpdate(scope.row)" |
||||
|
v-hasPermi="['monitor:job:edit']" |
||||
|
>修改</el-button> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-delete" |
||||
|
@click="handleDelete(scope.row)" |
||||
|
v-hasPermi="['monitor:job:remove']" |
||||
|
>删除</el-button> |
||||
|
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['monitor:job:changeStatus', 'monitor:job:query']"> |
||||
|
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button> |
||||
|
<el-dropdown-menu slot="dropdown"> |
||||
|
<el-dropdown-item command="handleRun" icon="el-icon-caret-right" |
||||
|
v-hasPermi="['monitor:job:changeStatus']">执行一次</el-dropdown-item> |
||||
|
<el-dropdown-item command="handleView" icon="el-icon-view" |
||||
|
v-hasPermi="['monitor:job:query']">任务详细</el-dropdown-item> |
||||
|
<el-dropdown-item command="handleJobLog" icon="el-icon-s-operation" |
||||
|
v-hasPermi="['monitor:job:query']">调度日志</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</el-dropdown> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<pagination |
||||
|
v-show="total>0" |
||||
|
:total="total" |
||||
|
:page.sync="queryParams.pageNum" |
||||
|
:limit.sync="queryParams.pageSize" |
||||
|
@pagination="getList" |
||||
|
/> |
||||
|
|
||||
|
<!-- 添加或修改定时任务对话框 --> |
||||
|
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body> |
||||
|
<el-form ref="form" :model="form" :rules="rules" label-width="120px"> |
||||
|
<el-row> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="任务名称" prop="jobName"> |
||||
|
<el-input v-model="form.jobName" placeholder="请输入任务名称" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="任务分组" prop="jobGroup"> |
||||
|
<el-select v-model="form.jobGroup" placeholder="请选择任务分组"> |
||||
|
<el-option |
||||
|
v-for="dict in dict.type.sys_job_group" |
||||
|
:key="dict.value" |
||||
|
:label="dict.label" |
||||
|
:value="dict.value" |
||||
|
></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="24"> |
||||
|
<el-form-item prop="invokeTarget"> |
||||
|
<span slot="label"> |
||||
|
调用方法 |
||||
|
<el-tooltip placement="top"> |
||||
|
<div slot="content"> |
||||
|
Bean调用示例:ryTask.ryParams('ry') |
||||
|
<br />Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry') |
||||
|
<br />参数说明:支持字符串,布尔类型,长整型,浮点型,整型 |
||||
|
</div> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="24"> |
||||
|
<el-form-item label="cron表达式" prop="cronExpression"> |
||||
|
<el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式"> |
||||
|
<template slot="append"> |
||||
|
<el-button type="primary" @click="handleShowCron"> |
||||
|
生成表达式 |
||||
|
<i class="el-icon-time el-icon--right"></i> |
||||
|
</el-button> |
||||
|
</template> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="24" v-if="form.jobId !== undefined"> |
||||
|
<el-form-item label="状态"> |
||||
|
<el-radio-group v-model="form.status"> |
||||
|
<el-radio |
||||
|
v-for="dict in dict.type.sys_job_status" |
||||
|
:key="dict.value" |
||||
|
:label="dict.value" |
||||
|
>{{dict.label}}</el-radio> |
||||
|
</el-radio-group> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="执行策略" prop="misfirePolicy"> |
||||
|
<el-radio-group v-model="form.misfirePolicy" size="small"> |
||||
|
<el-radio-button label="1">立即执行</el-radio-button> |
||||
|
<el-radio-button label="2">执行一次</el-radio-button> |
||||
|
<el-radio-button label="3">放弃执行</el-radio-button> |
||||
|
</el-radio-group> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="是否并发" prop="concurrent"> |
||||
|
<el-radio-group v-model="form.concurrent" size="small"> |
||||
|
<el-radio-button label="0">允许</el-radio-button> |
||||
|
<el-radio-button label="1">禁止</el-radio-button> |
||||
|
</el-radio-group> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
<el-button @click="cancel">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
|
||||
|
<el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar"> |
||||
|
<crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab> |
||||
|
</el-dialog> |
||||
|
|
||||
|
<!-- 任务日志详细 --> |
||||
|
<el-dialog title="任务详细" :visible.sync="openView" width="700px" append-to-body> |
||||
|
<el-form ref="form" :model="form" label-width="120px" size="mini"> |
||||
|
<el-row> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="任务编号:">{{ form.jobId }}</el-form-item> |
||||
|
<el-form-item label="任务名称:">{{ form.jobName }}</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="任务分组:">{{ jobGroupFormat(form) }}</el-form-item> |
||||
|
<el-form-item label="创建时间:">{{ form.createTime }}</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="cron表达式:">{{ form.cronExpression }}</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="下次执行时间:">{{ parseTime(form.nextValidTime) }}</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="24"> |
||||
|
<el-form-item label="调用目标方法:">{{ form.invokeTarget }}</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="任务状态:"> |
||||
|
<div v-if="form.status == 0">正常</div> |
||||
|
<div v-else-if="form.status == 1">暂停</div> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="是否并发:"> |
||||
|
<div v-if="form.concurrent == 0">允许</div> |
||||
|
<div v-else-if="form.concurrent == 1">禁止</div> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="执行策略:"> |
||||
|
<div v-if="form.misfirePolicy == 0">默认策略</div> |
||||
|
<div v-else-if="form.misfirePolicy == 1">立即执行</div> |
||||
|
<div v-else-if="form.misfirePolicy == 2">执行一次</div> |
||||
|
<div v-else-if="form.misfirePolicy == 3">放弃执行</div> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button @click="openView = false">关 闭</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job"; |
||||
|
import Crontab from '@/components/Crontab' |
||||
|
|
||||
|
export default { |
||||
|
components: { Crontab }, |
||||
|
name: "Job", |
||||
|
dicts: ['sys_job_group', 'sys_job_status'], |
||||
|
data() { |
||||
|
return { |
||||
|
// 遮罩层 |
||||
|
loading: true, |
||||
|
// 选中数组 |
||||
|
ids: [], |
||||
|
// 非单个禁用 |
||||
|
single: true, |
||||
|
// 非多个禁用 |
||||
|
multiple: true, |
||||
|
// 显示搜索条件 |
||||
|
showSearch: true, |
||||
|
// 总条数 |
||||
|
total: 0, |
||||
|
// 定时任务表格数据 |
||||
|
jobList: [], |
||||
|
// 弹出层标题 |
||||
|
title: "", |
||||
|
// 是否显示弹出层 |
||||
|
open: false, |
||||
|
// 是否显示详细弹出层 |
||||
|
openView: false, |
||||
|
// 是否显示Cron表达式弹出层 |
||||
|
openCron: false, |
||||
|
// 传入的表达式 |
||||
|
expression: "", |
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
jobName: undefined, |
||||
|
jobGroup: undefined, |
||||
|
status: undefined |
||||
|
}, |
||||
|
// 表单参数 |
||||
|
form: {}, |
||||
|
// 表单校验 |
||||
|
rules: { |
||||
|
jobName: [ |
||||
|
{ required: true, message: "任务名称不能为空", trigger: "blur" } |
||||
|
], |
||||
|
invokeTarget: [ |
||||
|
{ required: true, message: "调用目标字符串不能为空", trigger: "blur" } |
||||
|
], |
||||
|
cronExpression: [ |
||||
|
{ required: true, message: "cron执行表达式不能为空", trigger: "blur" } |
||||
|
] |
||||
|
} |
||||
|
}; |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList(); |
||||
|
}, |
||||
|
methods: { |
||||
|
/** 查询定时任务列表 */ |
||||
|
getList() { |
||||
|
this.loading = true; |
||||
|
listJob(this.queryParams).then(response => { |
||||
|
this.jobList = response.rows; |
||||
|
this.total = response.total; |
||||
|
this.loading = false; |
||||
|
}); |
||||
|
}, |
||||
|
// 任务组名字典翻译 |
||||
|
jobGroupFormat(row, column) { |
||||
|
return this.selectDictLabel(this.dict.type.sys_job_group, row.jobGroup); |
||||
|
}, |
||||
|
// 取消按钮 |
||||
|
cancel() { |
||||
|
this.open = false; |
||||
|
this.reset(); |
||||
|
}, |
||||
|
// 表单重置 |
||||
|
reset() { |
||||
|
this.form = { |
||||
|
jobId: undefined, |
||||
|
jobName: undefined, |
||||
|
jobGroup: undefined, |
||||
|
invokeTarget: undefined, |
||||
|
cronExpression: undefined, |
||||
|
misfirePolicy: 1, |
||||
|
concurrent: 1, |
||||
|
status: "0" |
||||
|
}; |
||||
|
this.resetForm("form"); |
||||
|
}, |
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1; |
||||
|
this.getList(); |
||||
|
}, |
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.resetForm("queryForm"); |
||||
|
this.handleQuery(); |
||||
|
}, |
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map(item => item.jobId); |
||||
|
this.single = selection.length != 1; |
||||
|
this.multiple = !selection.length; |
||||
|
}, |
||||
|
// 更多操作触发 |
||||
|
handleCommand(command, row) { |
||||
|
switch (command) { |
||||
|
case "handleRun": |
||||
|
this.handleRun(row); |
||||
|
break; |
||||
|
case "handleView": |
||||
|
this.handleView(row); |
||||
|
break; |
||||
|
case "handleJobLog": |
||||
|
this.handleJobLog(row); |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
}, |
||||
|
// 任务状态修改 |
||||
|
handleStatusChange(row) { |
||||
|
let text = row.status === "0" ? "启用" : "停用"; |
||||
|
this.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function() { |
||||
|
return changeJobStatus(row.jobId, row.status); |
||||
|
}).then(() => { |
||||
|
this.$modal.msgSuccess(text + "成功"); |
||||
|
}).catch(function() { |
||||
|
row.status = row.status === "0" ? "1" : "0"; |
||||
|
}); |
||||
|
}, |
||||
|
/* 立即执行一次 */ |
||||
|
handleRun(row) { |
||||
|
this.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function() { |
||||
|
return runJob(row.jobId, row.jobGroup); |
||||
|
}).then(() => { |
||||
|
this.$modal.msgSuccess("执行成功"); |
||||
|
}).catch(() => {}); |
||||
|
}, |
||||
|
/** 任务详细信息 */ |
||||
|
handleView(row) { |
||||
|
getJob(row.jobId).then(response => { |
||||
|
this.form = response.data; |
||||
|
this.openView = true; |
||||
|
}); |
||||
|
}, |
||||
|
/** cron表达式按钮操作 */ |
||||
|
handleShowCron() { |
||||
|
this.expression = this.form.cronExpression; |
||||
|
this.openCron = true; |
||||
|
}, |
||||
|
/** 确定后回传值 */ |
||||
|
crontabFill(value) { |
||||
|
this.form.cronExpression = value; |
||||
|
}, |
||||
|
/** 任务日志列表查询 */ |
||||
|
handleJobLog(row) { |
||||
|
const jobId = row.jobId || 0; |
||||
|
this.$router.push('/monitor/job-log/index/' + jobId) |
||||
|
}, |
||||
|
/** 新增按钮操作 */ |
||||
|
handleAdd() { |
||||
|
this.reset(); |
||||
|
this.open = true; |
||||
|
this.title = "添加任务"; |
||||
|
}, |
||||
|
/** 修改按钮操作 */ |
||||
|
handleUpdate(row) { |
||||
|
this.reset(); |
||||
|
const jobId = row.jobId || this.ids; |
||||
|
getJob(jobId).then(response => { |
||||
|
this.form = response.data; |
||||
|
this.open = true; |
||||
|
this.title = "修改任务"; |
||||
|
}); |
||||
|
}, |
||||
|
/** 提交按钮 */ |
||||
|
submitForm: function() { |
||||
|
this.$refs["form"].validate(valid => { |
||||
|
if (valid) { |
||||
|
if (this.form.jobId != undefined) { |
||||
|
updateJob(this.form).then(response => { |
||||
|
this.$modal.msgSuccess("修改成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} else { |
||||
|
addJob(this.form).then(response => { |
||||
|
this.$modal.msgSuccess("新增成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const jobIds = row.jobId || this.ids; |
||||
|
this.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function() { |
||||
|
return delJob(jobIds); |
||||
|
}).then(() => { |
||||
|
this.getList(); |
||||
|
this.$modal.msgSuccess("删除成功"); |
||||
|
}).catch(() => {}); |
||||
|
}, |
||||
|
/** 导出按钮操作 */ |
||||
|
handleExport() { |
||||
|
this.download('monitor/job/export', { |
||||
|
...this.queryParams |
||||
|
}, `job_${new Date().getTime()}.xlsx`) |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,699 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<el-form |
||||
|
:model="queryParams" |
||||
|
ref="queryForm" |
||||
|
size="small" |
||||
|
:inline="true" |
||||
|
v-show="showSearch" |
||||
|
label-width="68px" |
||||
|
> |
||||
|
<el-form-item label="" prop="noticeTitle"> |
||||
|
<el-input |
||||
|
v-model="queryParams.param.keywords" |
||||
|
placeholder="支持姓名、全拼、简拼、手机号吗、证件号码" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="年龄范围" prop="createBy"> |
||||
|
<div class="form-item-age"> |
||||
|
<el-input |
||||
|
v-model="queryParams.param.startAge" |
||||
|
placeholder="最小年龄" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
<span>—</span> |
||||
|
<el-input |
||||
|
v-model="queryParams.param.endAge" |
||||
|
placeholder="最大年龄" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="建档组织" prop="tenantId"> |
||||
|
<el-select |
||||
|
v-model="queryParams.param.tenantId" |
||||
|
placeholder="请选择" |
||||
|
clearable |
||||
|
> |
||||
|
<el-option label="dict.label" value="dict.value" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="数据来源" prop="sourceId"> |
||||
|
<el-select |
||||
|
v-model="queryParams.param.sourceId" |
||||
|
placeholder="请选择" |
||||
|
clearable |
||||
|
> |
||||
|
<el-option label="筛查" :value="0" /> |
||||
|
<el-option label="录入" :value="1" /> |
||||
|
<el-option label="HIS" :value="2" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
icon="el-icon-search" |
||||
|
size="mini" |
||||
|
@click="handleQuery" |
||||
|
>搜索</el-button |
||||
|
> |
||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"> |
||||
|
重置 |
||||
|
</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
|
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
plain |
||||
|
icon="el-icon-plus" |
||||
|
size="mini" |
||||
|
@click="handleAdd" |
||||
|
>新增</el-button |
||||
|
> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="danger" |
||||
|
plain |
||||
|
icon="el-icon-delete" |
||||
|
size="mini" |
||||
|
:disabled="multiple" |
||||
|
@click="handleDelete" |
||||
|
>删除</el-button |
||||
|
> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="info" |
||||
|
plain |
||||
|
icon="el-icon-bottom" |
||||
|
size="mini" |
||||
|
:disabled="multiple" |
||||
|
@click="handleDelete" |
||||
|
>下载模版</el-button |
||||
|
> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="warning" |
||||
|
plain |
||||
|
icon="el-icon-upload2" |
||||
|
size="mini" |
||||
|
@click="handleImport" |
||||
|
>导入</el-button |
||||
|
> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="warning" |
||||
|
plain |
||||
|
icon="el-icon-download" |
||||
|
size="mini" |
||||
|
@click="handleExport" |
||||
|
>导出</el-button |
||||
|
> |
||||
|
</el-col> |
||||
|
<right-toolbar |
||||
|
:showSearch.sync="showSearch" |
||||
|
@queryTable="getList" |
||||
|
></right-toolbar> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-table |
||||
|
v-loading="loading" |
||||
|
:data="listDat" |
||||
|
@selection-change="handleSelectionChange" |
||||
|
max-height="600" |
||||
|
> |
||||
|
<el-table-column type="selection" width="55" align="center" /> |
||||
|
<el-table-column label="姓名" align="center" prop="name" width="100" /> |
||||
|
<el-table-column |
||||
|
label="性别" |
||||
|
align="center" |
||||
|
prop="gender" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<span v-if="scope.row.gender == 0">男</span> |
||||
|
<span v-if="scope.row.gender == 1">女</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
|
||||
|
<el-table-column |
||||
|
label="出生日期" |
||||
|
align="center" |
||||
|
prop="birthDate" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="民族" |
||||
|
align="center" |
||||
|
prop="ethnicity" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="受教育年限" |
||||
|
align="center" |
||||
|
prop="educationYears" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="手机号码" |
||||
|
align="center" |
||||
|
prop="phone" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="证件类型" |
||||
|
align="center" |
||||
|
prop="idCardType" |
||||
|
show-overflow-tooltip |
||||
|
width="200" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
{{ idCardTypeValue[scope.row.idCardType] }} |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
label="证件号码" |
||||
|
align="center" |
||||
|
prop="idCard" |
||||
|
show-overflow-tooltip |
||||
|
width="180" |
||||
|
/> |
||||
|
|
||||
|
<el-table-column |
||||
|
label="建档人" |
||||
|
align="center" |
||||
|
prop="createBy" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="建档组织(医院名称)" |
||||
|
align="center" |
||||
|
prop="organization" |
||||
|
show-overflow-tooltip |
||||
|
width="150" |
||||
|
/> |
||||
|
<el-table-column label="建档日期" align="center" width="130"> |
||||
|
<template slot-scope="scope"> |
||||
|
<span>{{ |
||||
|
parseTime(scope.row.createTime, "{y}-{m}-{d} {h}:{i}") |
||||
|
}}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
fixed="right" |
||||
|
label="来源" |
||||
|
align="center" |
||||
|
prop="source" |
||||
|
show-overflow-tooltip |
||||
|
width="100" |
||||
|
> |
||||
|
<template slot-scope="scope"> |
||||
|
<span v-if="scope.row.gender == 0">筛查</span> |
||||
|
<span v-if="scope.row.gender == 1">录入</span> |
||||
|
<span v-if="scope.row.gender == 2">HIS</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column fixed="right" label="操作" align="center" width="150"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-edit" |
||||
|
@click="handleUpdate(scope.row)" |
||||
|
>修改</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-delete" |
||||
|
@click="handleDelete(scope.row)" |
||||
|
>删除</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-tickets" |
||||
|
@click="handleDetails(scope.row)" |
||||
|
>详情</el-button |
||||
|
> |
||||
|
<el-button |
||||
|
size="mini" |
||||
|
type="text" |
||||
|
icon="el-icon-notebook-2" |
||||
|
@click="handleDelete(scope.row)" |
||||
|
>诊疗档案</el-button |
||||
|
> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<pagination |
||||
|
v-show="total > 0" |
||||
|
:total="total" |
||||
|
:page.sync="queryParams.pageNum" |
||||
|
:limit.sync="queryParams.pageSize" |
||||
|
@pagination="getList" |
||||
|
/> |
||||
|
|
||||
|
<!-- 添加或修改公告对话框 --> |
||||
|
<el-dialog |
||||
|
class="popup" |
||||
|
:title="title" |
||||
|
:visible.sync="open" |
||||
|
width="780px" |
||||
|
append-to-body |
||||
|
> |
||||
|
<el-form |
||||
|
class="formStep" |
||||
|
ref="form" |
||||
|
:model="form" |
||||
|
:rules="rules" |
||||
|
label-width="90px" |
||||
|
> |
||||
|
<el-form-item label="姓名" prop="name"> |
||||
|
<el-input |
||||
|
v-model="form.name" |
||||
|
:disabled="formDisabled" |
||||
|
placeholder="请输入" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="性别" prop="gender"> |
||||
|
<el-radio-group v-model="form.gender" :disabled="formDisabled"> |
||||
|
<el-radio :label="0">男</el-radio> |
||||
|
<el-radio :label="1">女</el-radio> |
||||
|
</el-radio-group> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="出生年月" prop="birthDate"> |
||||
|
<el-date-picker |
||||
|
:disabled="formDisabled" |
||||
|
format="yyyy-MM-dd" |
||||
|
value-format="yyyy-MM-dd" |
||||
|
v-model="form.birthDate" |
||||
|
type="date" |
||||
|
placeholder="选择日期" |
||||
|
> |
||||
|
</el-date-picker> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="民族" prop="ethnicity"> |
||||
|
<el-input |
||||
|
v-model="form.ethnicity" |
||||
|
placeholder="请输入" |
||||
|
:disabled="formDisabled" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="受教育年限" prop="educationYears"> |
||||
|
<el-input |
||||
|
v-model="form.educationYears" |
||||
|
placeholder="请输入" |
||||
|
:disabled="formDisabled" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="手机号码" prop="phone"> |
||||
|
<el-input |
||||
|
v-model="form.phone" |
||||
|
placeholder="请输入" |
||||
|
:disabled="formDisabled" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="证件类型" prop="idCardType"> |
||||
|
<el-select |
||||
|
v-model="form.idCardType" |
||||
|
placeholder="请选择" |
||||
|
:disabled="formDisabled" |
||||
|
> |
||||
|
<el-option |
||||
|
v-for="item in idCardType" |
||||
|
:key="item.value" |
||||
|
:label="item.label" |
||||
|
:value="item.value" |
||||
|
> |
||||
|
</el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="证件号码" prop="idCard"> |
||||
|
<el-input |
||||
|
v-model="form.idCard" |
||||
|
placeholder="请输入" |
||||
|
:disabled="formDisabled" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="现病史" prop="currentIllnessHistory"> |
||||
|
<el-checkbox-group |
||||
|
v-model="form.currentIllnessHistory" |
||||
|
:disabled="formDisabled" |
||||
|
> |
||||
|
<el-checkbox v-for="(item, index) in medicalHistory" :label="item"> |
||||
|
</el-checkbox> |
||||
|
</el-checkbox-group> |
||||
|
<el-input |
||||
|
v-model="form.currentIllnessHistoryQT" |
||||
|
placeholder="其他" |
||||
|
:disabled="formDisabled" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
<el-button @click="cancel">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
<!-- 导入患者信息 --> |
||||
|
<el-dialog |
||||
|
title="导入患者档案" |
||||
|
:visible.sync="importOpen" |
||||
|
width="640px" |
||||
|
append-to-body |
||||
|
> |
||||
|
<el-form ref="form" :model="importform"> |
||||
|
<el-form-item prop="accessUrl"> |
||||
|
<el-upload |
||||
|
:limit="1" |
||||
|
class="avatar-uploader wj-uploader" |
||||
|
:headers="headers" |
||||
|
:action="uploadFileUrl1" |
||||
|
accept=".xlsx, .xls" |
||||
|
:before-upload="handleBeforePdfUpload1" |
||||
|
:on-success="handleUploadPdfAdd1" |
||||
|
:file-list="fileList" |
||||
|
:show-file-list="true" |
||||
|
> |
||||
|
<i class="el-icon-upload"></i> |
||||
|
<div class="el-upload__text"> |
||||
|
将文件拖到此处,或 |
||||
|
<em>点击上传</em> |
||||
|
</div> |
||||
|
</el-upload> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { getToken } from "@/utils/auth"; |
||||
|
import { |
||||
|
queryPatient, |
||||
|
patientAdd, |
||||
|
patientUpd, |
||||
|
patientDel, |
||||
|
} from "@/api/patientFile"; |
||||
|
export default { |
||||
|
name: "Notice", |
||||
|
dicts: ["sys_notice_status", "sys_notice_type"], |
||||
|
data() { |
||||
|
return { |
||||
|
headers: { |
||||
|
Authorization: "Bearer " + getToken(), |
||||
|
deptId: localStorage.getItem("hospitalId"), |
||||
|
}, |
||||
|
uploadFileUrl1: process.env.VUE_APP_BASE_API + "/pms/importTjbgZip", // 上传的图片服务器地址 |
||||
|
fileList: [], |
||||
|
// 现病史 |
||||
|
medicalHistory: [ |
||||
|
"高血压", |
||||
|
"脑血管病", |
||||
|
"恶性肿瘤", |
||||
|
"冠心病", |
||||
|
"精神疾病", |
||||
|
"胃和十二指肠溃疡", |
||||
|
"肥胖症", |
||||
|
"骨质疏松症", |
||||
|
"遗传性、先天性疾病", |
||||
|
"糖尿病", |
||||
|
"慢性肺系疾病", |
||||
|
"高脂血症", |
||||
|
"肝脏疾病(脂肪肝、乙型肝炎、肝硬化等)", |
||||
|
"过敏性疾病", |
||||
|
"关节炎", |
||||
|
"痛风", |
||||
|
"肾炎、肾病", |
||||
|
"高脂血症", |
||||
|
], |
||||
|
idCardType: [ |
||||
|
{ |
||||
|
label: "身份证", |
||||
|
value: 0, |
||||
|
}, |
||||
|
{ |
||||
|
label: "护照或外国人永居证", |
||||
|
value: 1, |
||||
|
}, |
||||
|
{ |
||||
|
label: "港澳居民来往内地通行", |
||||
|
value: 2, |
||||
|
}, |
||||
|
{ |
||||
|
label: "台湾居民来往大陆通行证", |
||||
|
value: 3, |
||||
|
}, |
||||
|
], |
||||
|
idCardTypeValue: { |
||||
|
0: "身份证", |
||||
|
1: "护照或外国人永居证", |
||||
|
2: "港澳居民来往内地通行", |
||||
|
3: "台湾居民来往大陆通行证", |
||||
|
}, |
||||
|
loading: false, // 遮罩层 |
||||
|
ids: [], // 选中数组 |
||||
|
single: true, // 非单个禁用 |
||||
|
multiple: true, // 非多个禁用 |
||||
|
showSearch: true, // 显示搜索条件 |
||||
|
total: 0, // 总条数 |
||||
|
listDat: [{}], // 公告表格数据 |
||||
|
title: "", // 弹出层标题 |
||||
|
open: false, // 是否显示弹出层 |
||||
|
importOpen: false, // 导入弹窗 |
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
param: { |
||||
|
keywords: "", //关键字 |
||||
|
startAge: "", //开始年龄 |
||||
|
endAge: "", //结束年龄 |
||||
|
tenantId: "", //建档组织 |
||||
|
createBy: "", //建档人 |
||||
|
sourceId: "", //来源 |
||||
|
}, |
||||
|
}, |
||||
|
formDisabled: false, |
||||
|
importform: {}, |
||||
|
// 表单参数 |
||||
|
form: {}, |
||||
|
// 表单校验 |
||||
|
rules: { |
||||
|
name: [ |
||||
|
{ required: true, message: "患者姓名不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
gender: [ |
||||
|
{ required: true, message: "性别不能为空", trigger: "change" }, |
||||
|
], |
||||
|
phone: [ |
||||
|
{ required: true, message: "手机号码不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
ethnicity: [ |
||||
|
{ required: true, message: "民族不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
idCardType: [ |
||||
|
{ required: true, message: "证件类型不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
idCard: [ |
||||
|
{ required: true, message: "证件号码不能为空", trigger: "blur" }, |
||||
|
], |
||||
|
currentIllnessHistory: [ |
||||
|
{ |
||||
|
required: true, |
||||
|
message: "现病史不能为空", |
||||
|
trigger: "blur", |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
}; |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList(); |
||||
|
}, |
||||
|
methods: { |
||||
|
// 上传成功回 - pdg |
||||
|
handleUploadPdfAdd1(res) { |
||||
|
if (res.code == 200) { |
||||
|
this.physicaOpen = false; |
||||
|
this.getList(); |
||||
|
this.$modal.msgSuccess("导入成功"); |
||||
|
} else { |
||||
|
this.$message.error(res.msg || "导入失败"); |
||||
|
this.fileList = []; |
||||
|
} |
||||
|
}, |
||||
|
// 上传前校检格式和大小 - 图片 |
||||
|
handleBeforeUpload1(file) { |
||||
|
const isLt2M = file.size / 1024 / 1024 < 100; |
||||
|
// 校检文件大小 |
||||
|
if (!isLt2M) { |
||||
|
this.$message.error("上传文件大小不能超过 100MB!"); |
||||
|
} |
||||
|
return isLt2M; |
||||
|
}, |
||||
|
// 上传前校检格式和大小 - 文件 |
||||
|
handleBeforePdfUpload1(file) { |
||||
|
const fileSuffix = file.name.substring(file.name.lastIndexOf(".") + 1); |
||||
|
const whiteList = ["xlsx", "xls"]; |
||||
|
if (whiteList.indexOf(fileSuffix) === -1) { |
||||
|
this.$message.error("上传文件只能是.xlsx, .xls"); |
||||
|
return false; |
||||
|
} |
||||
|
}, |
||||
|
/** 查询公告列表 */ |
||||
|
getList() { |
||||
|
this.loading = true; |
||||
|
queryPatient(this.queryParams).then((res) => { |
||||
|
this.listDat = res.data.list; |
||||
|
this.total = res.data.total; |
||||
|
this.loading = false; |
||||
|
}); |
||||
|
}, |
||||
|
// 取消按钮 |
||||
|
cancel() { |
||||
|
this.open = false; |
||||
|
this.reset(); |
||||
|
}, |
||||
|
// 表单重置 |
||||
|
reset() { |
||||
|
this.form = { |
||||
|
name: "", // 姓名 |
||||
|
gender: 0, // 性别 |
||||
|
birthDate: "", // 出生日期 |
||||
|
ethnicity: "", // 民族 |
||||
|
educationYears: "", // 教育程度 |
||||
|
phone: "", // 联系电话 |
||||
|
idCardType: "", // 证件类型 |
||||
|
idCard: "", // 证件号码 |
||||
|
currentIllnessHistory: [], // 现病史 |
||||
|
currentIllnessHistoryQT: "", // 现病史 |
||||
|
}; |
||||
|
this.resetForm("form"); |
||||
|
}, |
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1; |
||||
|
this.getList(); |
||||
|
}, |
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.handleQuery(); |
||||
|
}, |
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map((item) => item.id); |
||||
|
this.single = selection.length != 1; |
||||
|
this.multiple = !selection.length; |
||||
|
}, |
||||
|
/** 新增按钮操作 */ |
||||
|
handleAdd() { |
||||
|
this.reset(); |
||||
|
this.open = true; |
||||
|
this.title = "新增患者档案"; |
||||
|
this.formDisabled = false; |
||||
|
}, |
||||
|
/** 修改按钮操作 */ |
||||
|
handleUpdate(row) { |
||||
|
this.open = true; |
||||
|
this.title = "修改患者档案"; |
||||
|
this.formDisabled = false; |
||||
|
this.form = JSON.parse(JSON.stringify(row)); |
||||
|
// 字符串转数组 |
||||
|
this.form.currentIllnessHistory = |
||||
|
this.form.currentIllnessHistory.split(","); |
||||
|
}, |
||||
|
/** 详情按钮操作 */ |
||||
|
handleDetails(row) { |
||||
|
this.open = true; |
||||
|
this.title = "患者档案详情"; |
||||
|
this.formDisabled = true; |
||||
|
this.form = JSON.parse(JSON.stringify(row)); |
||||
|
}, |
||||
|
/** 提交按钮 */ |
||||
|
submitForm: function () { |
||||
|
this.$refs["form"].validate((valid) => { |
||||
|
if (valid) { |
||||
|
if (this.form.id != undefined) { |
||||
|
patientUpd(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("修改成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} else { |
||||
|
patientAdd(this.form).then((response) => { |
||||
|
this.$modal.msgSuccess("新增成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const idList = row.id ? [row.id] : this.ids; |
||||
|
this.$modal |
||||
|
.confirm("是否确认删除当前选择的数据?") |
||||
|
.then(function () { |
||||
|
return patientDel({ idList: idList }); |
||||
|
}) |
||||
|
.then(() => { |
||||
|
this.getList(); |
||||
|
this.$modal.msgSuccess("删除成功"); |
||||
|
}) |
||||
|
.catch(() => {}); |
||||
|
}, |
||||
|
/** 导出按钮操作 */ |
||||
|
handleExport() { |
||||
|
this.download( |
||||
|
"system/user/export", |
||||
|
{ |
||||
|
...this.queryParams.params, |
||||
|
}, |
||||
|
`患者档案.xlsx` |
||||
|
); |
||||
|
}, |
||||
|
/** 导入按钮操作 */ |
||||
|
handleImport() { |
||||
|
this.upload.title = "用户导入"; |
||||
|
this.upload.open = true; |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
<style scoped src="@/assets/styles/common.css"></style> |
||||
|
<style scoped> |
||||
|
.form-item-age { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
.form-item-age span { |
||||
|
margin: 0 10px; |
||||
|
} |
||||
|
.form-item-age >>> .el-input { |
||||
|
width: 100px; |
||||
|
} |
||||
|
</style> |
||||
|
<!-- >>> .el-input__inner { |
||||
|
padding: 0 15px !important; |
||||
|
} --> |
@ -0,0 +1,263 @@ |
|||||
|
<template> |
||||
|
<div class="register"> |
||||
|
<el-form |
||||
|
ref="registerForm" |
||||
|
:model="registerForm" |
||||
|
:rules="registerRules" |
||||
|
class="register-form" |
||||
|
> |
||||
|
<h3 class="title">针灸后台管理系统</h3> |
||||
|
<el-form-item prop="username"> |
||||
|
<el-input |
||||
|
v-model="registerForm.username" |
||||
|
type="text" |
||||
|
auto-complete="off" |
||||
|
placeholder="账号" |
||||
|
> |
||||
|
<svg-icon |
||||
|
slot="prefix" |
||||
|
icon-class="user" |
||||
|
class="el-input__icon input-icon" |
||||
|
/> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item prop="password"> |
||||
|
<el-input |
||||
|
v-model="registerForm.password" |
||||
|
type="password" |
||||
|
auto-complete="off" |
||||
|
placeholder="密码" |
||||
|
@keyup.enter.native="handleRegister" |
||||
|
> |
||||
|
<svg-icon |
||||
|
slot="prefix" |
||||
|
icon-class="password" |
||||
|
class="el-input__icon input-icon" |
||||
|
/> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item prop="confirmPassword"> |
||||
|
<el-input |
||||
|
v-model="registerForm.confirmPassword" |
||||
|
type="password" |
||||
|
auto-complete="off" |
||||
|
placeholder="确认密码" |
||||
|
@keyup.enter.native="handleRegister" |
||||
|
> |
||||
|
<svg-icon |
||||
|
slot="prefix" |
||||
|
icon-class="password" |
||||
|
class="el-input__icon input-icon" |
||||
|
/> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
<el-form-item prop="code" v-if="captchaEnabled"> |
||||
|
<el-input |
||||
|
v-model="registerForm.code" |
||||
|
auto-complete="off" |
||||
|
placeholder="验证码" |
||||
|
style="width: 63%" |
||||
|
@keyup.enter.native="handleRegister" |
||||
|
> |
||||
|
<svg-icon |
||||
|
slot="prefix" |
||||
|
icon-class="validCode" |
||||
|
class="el-input__icon input-icon" |
||||
|
/> |
||||
|
</el-input> |
||||
|
<div class="register-code"> |
||||
|
<img :src="codeUrl" @click="getCode" class="register-code-img" /> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
<el-form-item style="width: 100%"> |
||||
|
<el-button |
||||
|
:loading="loading" |
||||
|
size="medium" |
||||
|
type="primary" |
||||
|
style="width: 100%" |
||||
|
@click.native.prevent="handleRegister" |
||||
|
> |
||||
|
<span v-if="!loading">注 册</span> |
||||
|
<span v-else>注 册 中...</span> |
||||
|
</el-button> |
||||
|
<div style="float: right"> |
||||
|
<router-link class="link-type" :to="'/login'" |
||||
|
>使用已有账户登录</router-link |
||||
|
> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<!-- 底部 --> |
||||
|
<div class="el-register-footer"> |
||||
|
<span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { getCodeImg, register } from "@/api/login"; |
||||
|
|
||||
|
export default { |
||||
|
name: "Register", |
||||
|
data() { |
||||
|
const equalToPassword = (rule, value, callback) => { |
||||
|
if (this.registerForm.password !== value) { |
||||
|
callback(new Error("两次输入的密码不一致")); |
||||
|
} else { |
||||
|
callback(); |
||||
|
} |
||||
|
}; |
||||
|
return { |
||||
|
codeUrl: "", |
||||
|
registerForm: { |
||||
|
username: "", |
||||
|
password: "", |
||||
|
confirmPassword: "", |
||||
|
code: "", |
||||
|
uuid: "", |
||||
|
}, |
||||
|
registerRules: { |
||||
|
username: [ |
||||
|
{ required: true, trigger: "blur", message: "请输入您的账号" }, |
||||
|
{ |
||||
|
min: 2, |
||||
|
max: 20, |
||||
|
message: "用户账号长度必须介于 2 和 20 之间", |
||||
|
trigger: "blur", |
||||
|
}, |
||||
|
], |
||||
|
password: [ |
||||
|
{ required: true, trigger: "blur", message: "请输入您的密码" }, |
||||
|
{ |
||||
|
min: 5, |
||||
|
max: 20, |
||||
|
message: "用户密码长度必须介于 5 和 20 之间", |
||||
|
trigger: "blur", |
||||
|
}, |
||||
|
{ |
||||
|
pattern: /^[^<>"'|\\]+$/, |
||||
|
message: "不能包含非法字符:< > \" ' \\\ |", |
||||
|
trigger: "blur", |
||||
|
}, |
||||
|
], |
||||
|
confirmPassword: [ |
||||
|
{ required: true, trigger: "blur", message: "请再次输入您的密码" }, |
||||
|
{ required: true, validator: equalToPassword, trigger: "blur" }, |
||||
|
], |
||||
|
code: [{ required: true, trigger: "change", message: "请输入验证码" }], |
||||
|
}, |
||||
|
loading: false, |
||||
|
captchaEnabled: true, |
||||
|
}; |
||||
|
}, |
||||
|
created() { |
||||
|
this.getCode(); |
||||
|
}, |
||||
|
methods: { |
||||
|
getCode() { |
||||
|
getCodeImg().then((res) => { |
||||
|
this.captchaEnabled = |
||||
|
res.captchaEnabled === undefined ? true : res.captchaEnabled; |
||||
|
if (this.captchaEnabled) { |
||||
|
this.codeUrl = "data:image/gif;base64," + res.img; |
||||
|
this.registerForm.uuid = res.uuid; |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
handleRegister() { |
||||
|
this.$refs.registerForm.validate((valid) => { |
||||
|
if (valid) { |
||||
|
this.loading = true; |
||||
|
register(this.registerForm) |
||||
|
.then((res) => { |
||||
|
const username = this.registerForm.username; |
||||
|
this.$alert( |
||||
|
"<font color='red'>恭喜你,您的账号 " + |
||||
|
username + |
||||
|
" 注册成功!</font>", |
||||
|
"系统提示", |
||||
|
{ |
||||
|
dangerouslyUseHTMLString: true, |
||||
|
type: "success", |
||||
|
} |
||||
|
) |
||||
|
.then(() => { |
||||
|
this.$router.push("/login"); |
||||
|
}) |
||||
|
.catch(() => {}); |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
this.loading = false; |
||||
|
if (this.captchaEnabled) { |
||||
|
this.getCode(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style rel="stylesheet/scss" lang="scss"> |
||||
|
.register { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
height: 100%; |
||||
|
background-image: url("../assets/images/login-background.jpg"); |
||||
|
background-size: cover; |
||||
|
} |
||||
|
.title { |
||||
|
margin: 0px auto 30px auto; |
||||
|
text-align: center; |
||||
|
color: #707070; |
||||
|
} |
||||
|
|
||||
|
.register-form { |
||||
|
border-radius: 6px; |
||||
|
background: #ffffff; |
||||
|
width: 400px; |
||||
|
padding: 25px 25px 5px 25px; |
||||
|
.el-input { |
||||
|
height: 38px; |
||||
|
input { |
||||
|
height: 38px; |
||||
|
} |
||||
|
} |
||||
|
.input-icon { |
||||
|
height: 39px; |
||||
|
width: 14px; |
||||
|
margin-left: 2px; |
||||
|
} |
||||
|
} |
||||
|
.register-tip { |
||||
|
font-size: 13px; |
||||
|
text-align: center; |
||||
|
color: #bfbfbf; |
||||
|
} |
||||
|
.register-code { |
||||
|
width: 33%; |
||||
|
height: 38px; |
||||
|
float: right; |
||||
|
img { |
||||
|
cursor: pointer; |
||||
|
vertical-align: middle; |
||||
|
} |
||||
|
} |
||||
|
.el-register-footer { |
||||
|
height: 40px; |
||||
|
line-height: 40px; |
||||
|
position: fixed; |
||||
|
bottom: 0; |
||||
|
width: 100%; |
||||
|
text-align: center; |
||||
|
color: #fff; |
||||
|
font-family: Arial; |
||||
|
font-size: 12px; |
||||
|
letter-spacing: 1px; |
||||
|
} |
||||
|
.register-code-img { |
||||
|
height: 38px; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,553 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<el-row :gutter="20"> |
||||
|
<splitpanes :horizontal="this.$store.getters.device === 'mobile'" class="default-theme"> |
||||
|
<!--部门数据--> |
||||
|
<pane size="16"> |
||||
|
<el-col> |
||||
|
<div class="head-container"> |
||||
|
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" /> |
||||
|
</div> |
||||
|
<div class="head-container"> |
||||
|
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current @node-click="handleNodeClick" /> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</pane> |
||||
|
<!--用户数据--> |
||||
|
<pane size="84"> |
||||
|
<el-col> |
||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> |
||||
|
<el-form-item label="用户名称" prop="userName"> |
||||
|
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="手机号码" prop="phonenumber"> |
||||
|
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter.native="handleQuery" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="状态" prop="status"> |
||||
|
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px"> |
||||
|
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="创建时间"> |
||||
|
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> |
||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
|
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button> |
||||
|
</el-col> |
||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> |
||||
|
<el-table-column type="selection" width="50" align="center" /> |
||||
|
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" /> |
||||
|
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" /> |
||||
|
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" /> |
||||
|
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160"> |
||||
|
<template slot-scope="scope"> |
||||
|
<span>{{ parseTime(scope.row.createTime) }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width"> |
||||
|
<template slot-scope="scope" v-if="scope.row.userId !== 1"> |
||||
|
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']">修改</el-button> |
||||
|
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']">删除</el-button> |
||||
|
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:user:resetPwd', 'system:user:edit']"> |
||||
|
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button> |
||||
|
<el-dropdown-menu slot="dropdown"> |
||||
|
<el-dropdown-item command="handleResetPwd" icon="el-icon-key" v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item> |
||||
|
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</el-dropdown> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
|
||||
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" /> |
||||
|
</el-col> |
||||
|
</pane> |
||||
|
</splitpanes> |
||||
|
</el-row> |
||||
|
|
||||
|
<!-- 添加或修改用户配置对话框 --> |
||||
|
<el-dialog :title="title" :visible.sync="open" width="600px" append-to-body> |
||||
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> |
||||
|
<el-row> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="用户昵称" prop="nickName"> |
||||
|
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="归属部门" prop="deptId"> |
||||
|
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="手机号码" prop="phonenumber"> |
||||
|
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="邮箱" prop="email"> |
||||
|
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName"> |
||||
|
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password"> |
||||
|
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="用户性别"> |
||||
|
<el-select v-model="form.sex" placeholder="请选择性别"> |
||||
|
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="状态"> |
||||
|
<el-radio-group v-model="form.status"> |
||||
|
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio> |
||||
|
</el-radio-group> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="岗位"> |
||||
|
<el-select v-model="form.postIds" multiple placeholder="请选择岗位"> |
||||
|
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1" ></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item label="角色"> |
||||
|
<el-select v-model="form.roleIds" multiple placeholder="请选择角色"> |
||||
|
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row> |
||||
|
<el-col :span="24"> |
||||
|
<el-form-item label="备注"> |
||||
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-form> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitForm">确 定</el-button> |
||||
|
<el-button @click="cancel">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
|
||||
|
<!-- 用户导入对话框 --> |
||||
|
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body> |
||||
|
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag> |
||||
|
<i class="el-icon-upload"></i> |
||||
|
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> |
||||
|
<div class="el-upload__tip text-center" slot="tip"> |
||||
|
<div class="el-upload__tip" slot="tip"> |
||||
|
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据 |
||||
|
</div> |
||||
|
<span>仅允许导入xls、xlsx格式文件。</span> |
||||
|
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link> |
||||
|
</div> |
||||
|
</el-upload> |
||||
|
<div slot="footer" class="dialog-footer"> |
||||
|
<el-button type="primary" @click="submitFileForm">确 定</el-button> |
||||
|
<el-button @click="upload.open = false">取 消</el-button> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"; |
||||
|
import { getToken } from "@/utils/auth"; |
||||
|
import Treeselect from "@riophae/vue-treeselect"; |
||||
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; |
||||
|
import { Splitpanes, Pane } from "splitpanes"; |
||||
|
import "splitpanes/dist/splitpanes.css"; |
||||
|
|
||||
|
export default { |
||||
|
name: "User", |
||||
|
dicts: ['sys_normal_disable', 'sys_user_sex'], |
||||
|
components: { Treeselect, Splitpanes, Pane }, |
||||
|
data() { |
||||
|
return { |
||||
|
// 遮罩层 |
||||
|
loading: true, |
||||
|
// 选中数组 |
||||
|
ids: [], |
||||
|
// 非单个禁用 |
||||
|
single: true, |
||||
|
// 非多个禁用 |
||||
|
multiple: true, |
||||
|
// 显示搜索条件 |
||||
|
showSearch: true, |
||||
|
// 总条数 |
||||
|
total: 0, |
||||
|
// 用户表格数据 |
||||
|
userList: null, |
||||
|
// 弹出层标题 |
||||
|
title: "", |
||||
|
// 所有部门树选项 |
||||
|
deptOptions: undefined, |
||||
|
// 过滤掉已禁用部门树选项 |
||||
|
enabledDeptOptions: undefined, |
||||
|
// 是否显示弹出层 |
||||
|
open: false, |
||||
|
// 部门名称 |
||||
|
deptName: undefined, |
||||
|
// 默认密码 |
||||
|
initPassword: undefined, |
||||
|
// 日期范围 |
||||
|
dateRange: [], |
||||
|
// 岗位选项 |
||||
|
postOptions: [], |
||||
|
// 角色选项 |
||||
|
roleOptions: [], |
||||
|
// 表单参数 |
||||
|
form: {}, |
||||
|
defaultProps: { |
||||
|
children: "children", |
||||
|
label: "label" |
||||
|
}, |
||||
|
// 用户导入参数 |
||||
|
upload: { |
||||
|
// 是否显示弹出层(用户导入) |
||||
|
open: false, |
||||
|
// 弹出层标题(用户导入) |
||||
|
title: "", |
||||
|
// 是否禁用上传 |
||||
|
isUploading: false, |
||||
|
// 是否更新已经存在的用户数据 |
||||
|
updateSupport: 0, |
||||
|
// 设置上传的请求头部 |
||||
|
headers: { Authorization: "Bearer " + getToken() }, |
||||
|
// 上传的地址 |
||||
|
url: process.env.VUE_APP_BASE_API + "/system/user/importData" |
||||
|
}, |
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
userName: undefined, |
||||
|
phonenumber: undefined, |
||||
|
status: undefined, |
||||
|
deptId: undefined |
||||
|
}, |
||||
|
// 列信息 |
||||
|
columns: [ |
||||
|
{ key: 0, label: `用户编号`, visible: true }, |
||||
|
{ key: 1, label: `用户名称`, visible: true }, |
||||
|
{ key: 2, label: `用户昵称`, visible: true }, |
||||
|
{ key: 3, label: `部门`, visible: true }, |
||||
|
{ key: 4, label: `手机号码`, visible: true }, |
||||
|
{ key: 5, label: `状态`, visible: true }, |
||||
|
{ key: 6, label: `创建时间`, visible: true } |
||||
|
], |
||||
|
// 表单校验 |
||||
|
rules: { |
||||
|
userName: [ |
||||
|
{ required: true, message: "用户名称不能为空", trigger: "blur" }, |
||||
|
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' } |
||||
|
], |
||||
|
nickName: [ |
||||
|
{ required: true, message: "用户昵称不能为空", trigger: "blur" } |
||||
|
], |
||||
|
password: [ |
||||
|
{ required: true, message: "用户密码不能为空", trigger: "blur" }, |
||||
|
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }, |
||||
|
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" } |
||||
|
], |
||||
|
email: [ |
||||
|
{ |
||||
|
type: "email", |
||||
|
message: "请输入正确的邮箱地址", |
||||
|
trigger: ["blur", "change"] |
||||
|
} |
||||
|
], |
||||
|
phonenumber: [ |
||||
|
{ |
||||
|
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, |
||||
|
message: "请输入正确的手机号码", |
||||
|
trigger: "blur" |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
}; |
||||
|
}, |
||||
|
watch: { |
||||
|
// 根据名称筛选部门树 |
||||
|
deptName(val) { |
||||
|
this.$refs.tree.filter(val); |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList(); |
||||
|
this.getDeptTree(); |
||||
|
this.getConfigKey("sys.user.initPassword").then(response => { |
||||
|
this.initPassword = response.msg; |
||||
|
}); |
||||
|
}, |
||||
|
methods: { |
||||
|
/** 查询用户列表 */ |
||||
|
getList() { |
||||
|
this.loading = true; |
||||
|
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => { |
||||
|
this.userList = response.rows; |
||||
|
this.total = response.total; |
||||
|
this.loading = false; |
||||
|
} |
||||
|
); |
||||
|
}, |
||||
|
/** 查询部门下拉树结构 */ |
||||
|
getDeptTree() { |
||||
|
deptTreeSelect().then(response => { |
||||
|
this.deptOptions = response.data; |
||||
|
this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data))); |
||||
|
}); |
||||
|
}, |
||||
|
// 过滤禁用的部门 |
||||
|
filterDisabledDept(deptList) { |
||||
|
return deptList.filter(dept => { |
||||
|
if (dept.disabled) { |
||||
|
return false; |
||||
|
} |
||||
|
if (dept.children && dept.children.length) { |
||||
|
dept.children = this.filterDisabledDept(dept.children); |
||||
|
} |
||||
|
return true; |
||||
|
}); |
||||
|
}, |
||||
|
// 筛选节点 |
||||
|
filterNode(value, data) { |
||||
|
if (!value) return true; |
||||
|
return data.label.indexOf(value) !== -1; |
||||
|
}, |
||||
|
// 节点单击事件 |
||||
|
handleNodeClick(data) { |
||||
|
this.queryParams.deptId = data.id; |
||||
|
this.handleQuery(); |
||||
|
}, |
||||
|
// 用户状态修改 |
||||
|
handleStatusChange(row) { |
||||
|
let text = row.status === "0" ? "启用" : "停用"; |
||||
|
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() { |
||||
|
return changeUserStatus(row.userId, row.status); |
||||
|
}).then(() => { |
||||
|
this.$modal.msgSuccess(text + "成功"); |
||||
|
}).catch(function() { |
||||
|
row.status = row.status === "0" ? "1" : "0"; |
||||
|
}); |
||||
|
}, |
||||
|
// 取消按钮 |
||||
|
cancel() { |
||||
|
this.open = false; |
||||
|
this.reset(); |
||||
|
}, |
||||
|
// 表单重置 |
||||
|
reset() { |
||||
|
this.form = { |
||||
|
userId: undefined, |
||||
|
deptId: undefined, |
||||
|
userName: undefined, |
||||
|
nickName: undefined, |
||||
|
password: undefined, |
||||
|
phonenumber: undefined, |
||||
|
email: undefined, |
||||
|
sex: undefined, |
||||
|
status: "0", |
||||
|
remark: undefined, |
||||
|
postIds: [], |
||||
|
roleIds: [] |
||||
|
}; |
||||
|
this.resetForm("form"); |
||||
|
}, |
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1; |
||||
|
this.getList(); |
||||
|
}, |
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.dateRange = []; |
||||
|
this.resetForm("queryForm"); |
||||
|
this.queryParams.deptId = undefined; |
||||
|
this.$refs.tree.setCurrentKey(null); |
||||
|
this.handleQuery(); |
||||
|
}, |
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map(item => item.userId); |
||||
|
this.single = selection.length != 1; |
||||
|
this.multiple = !selection.length; |
||||
|
}, |
||||
|
// 更多操作触发 |
||||
|
handleCommand(command, row) { |
||||
|
switch (command) { |
||||
|
case "handleResetPwd": |
||||
|
this.handleResetPwd(row); |
||||
|
break; |
||||
|
case "handleAuthRole": |
||||
|
this.handleAuthRole(row); |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
}, |
||||
|
/** 新增按钮操作 */ |
||||
|
handleAdd() { |
||||
|
this.reset(); |
||||
|
getUser().then(response => { |
||||
|
this.postOptions = response.posts; |
||||
|
this.roleOptions = response.roles; |
||||
|
this.open = true; |
||||
|
this.title = "添加用户"; |
||||
|
this.form.password = this.initPassword; |
||||
|
}); |
||||
|
}, |
||||
|
/** 修改按钮操作 */ |
||||
|
handleUpdate(row) { |
||||
|
this.reset(); |
||||
|
const userId = row.userId || this.ids; |
||||
|
getUser(userId).then(response => { |
||||
|
this.form = response.data; |
||||
|
this.postOptions = response.posts; |
||||
|
this.roleOptions = response.roles; |
||||
|
this.$set(this.form, "postIds", response.postIds); |
||||
|
this.$set(this.form, "roleIds", response.roleIds); |
||||
|
this.open = true; |
||||
|
this.title = "修改用户"; |
||||
|
this.form.password = ""; |
||||
|
}); |
||||
|
}, |
||||
|
/** 重置密码按钮操作 */ |
||||
|
handleResetPwd(row) { |
||||
|
this.$prompt('请输入"' + row.userName + '"的新密码', "提示", { |
||||
|
confirmButtonText: "确定", |
||||
|
cancelButtonText: "取消", |
||||
|
closeOnClickModal: false, |
||||
|
inputPattern: /^.{5,20}$/, |
||||
|
inputErrorMessage: "用户密码长度必须介于 5 和 20 之间", |
||||
|
inputValidator: (value) => { |
||||
|
if (/<|>|"|'|\||\\/.test(value)) { |
||||
|
return "不能包含非法字符:< > \" ' \\\ |" |
||||
|
} |
||||
|
}, |
||||
|
}).then(({ value }) => { |
||||
|
resetUserPwd(row.userId, value).then(response => { |
||||
|
this.$modal.msgSuccess("修改成功,新密码是:" + value); |
||||
|
}); |
||||
|
}).catch(() => {}); |
||||
|
}, |
||||
|
/** 分配角色操作 */ |
||||
|
handleAuthRole: function(row) { |
||||
|
const userId = row.userId; |
||||
|
this.$router.push("/system/user-auth/role/" + userId); |
||||
|
}, |
||||
|
/** 提交按钮 */ |
||||
|
submitForm: function() { |
||||
|
this.$refs["form"].validate(valid => { |
||||
|
if (valid) { |
||||
|
if (this.form.userId != undefined) { |
||||
|
updateUser(this.form).then(response => { |
||||
|
this.$modal.msgSuccess("修改成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} else { |
||||
|
addUser(this.form).then(response => { |
||||
|
this.$modal.msgSuccess("新增成功"); |
||||
|
this.open = false; |
||||
|
this.getList(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const userIds = row.userId || this.ids; |
||||
|
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() { |
||||
|
return delUser(userIds); |
||||
|
}).then(() => { |
||||
|
this.getList(); |
||||
|
this.$modal.msgSuccess("删除成功"); |
||||
|
}).catch(() => {}); |
||||
|
}, |
||||
|
/** 导出按钮操作 */ |
||||
|
handleExport() { |
||||
|
this.download('system/user/export', { |
||||
|
...this.queryParams |
||||
|
}, `user_${new Date().getTime()}.xlsx`) |
||||
|
}, |
||||
|
/** 导入按钮操作 */ |
||||
|
handleImport() { |
||||
|
this.upload.title = "用户导入"; |
||||
|
this.upload.open = true; |
||||
|
}, |
||||
|
/** 下载模板操作 */ |
||||
|
importTemplate() { |
||||
|
this.download('system/user/importTemplate', { |
||||
|
}, `user_template_${new Date().getTime()}.xlsx`) |
||||
|
}, |
||||
|
// 文件上传中处理 |
||||
|
handleFileUploadProgress(event, file, fileList) { |
||||
|
this.upload.isUploading = true; |
||||
|
}, |
||||
|
// 文件上传成功处理 |
||||
|
handleFileSuccess(response, file, fileList) { |
||||
|
this.upload.open = false; |
||||
|
this.upload.isUploading = false; |
||||
|
this.$refs.upload.clearFiles(); |
||||
|
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true }); |
||||
|
this.getList(); |
||||
|
}, |
||||
|
// 提交上传文件 |
||||
|
submitFileForm() { |
||||
|
this.$refs.upload.submit(); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,312 @@ |
|||||
|
<template> |
||||
|
<el-form ref="genInfoForm" :model="info" :rules="rules" label-width="150px"> |
||||
|
<el-row> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item prop="tplCategory"> |
||||
|
<span slot="label">生成模板</span> |
||||
|
<el-select v-model="info.tplCategory" @change="tplSelectChange"> |
||||
|
<el-option label="单表(增删改查)" value="crud" /> |
||||
|
<el-option label="树表(增删改查)" value="tree" /> |
||||
|
<el-option label="主子表(增删改查)" value="sub" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item prop="tplWebType"> |
||||
|
<span slot="label">前端类型</span> |
||||
|
<el-select v-model="info.tplWebType"> |
||||
|
<el-option label="Vue2 Element UI 模版" value="element-ui" /> |
||||
|
<el-option label="Vue3 Element Plus 模版" value="element-plus" /> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item prop="packageName"> |
||||
|
<span slot="label"> |
||||
|
生成包路径 |
||||
|
<el-tooltip content="生成在哪个java包下,例如 com.ruoyi.system" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-input v-model="info.packageName" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
|
||||
|
<el-col :span="12"> |
||||
|
<el-form-item prop="moduleName"> |
||||
|
<span slot="label"> |
||||
|
生成模块名 |
||||
|
<el-tooltip content="可理解为子系统名,例如 system" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-input v-model="info.moduleName" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
|
||||
|
<el-col :span="12"> |
||||
|
<el-form-item prop="businessName"> |
||||
|
<span slot="label"> |
||||
|
生成业务名 |
||||
|
<el-tooltip content="可理解为功能英文名,例如 user" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-input v-model="info.businessName" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
|
||||
|
<el-col :span="12"> |
||||
|
<el-form-item prop="functionName"> |
||||
|
<span slot="label"> |
||||
|
生成功能名 |
||||
|
<el-tooltip content="用作类描述,例如 用户" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-input v-model="info.functionName" /> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
|
||||
|
<el-col :span="12"> |
||||
|
<el-form-item prop="genType"> |
||||
|
<span slot="label"> |
||||
|
生成代码方式 |
||||
|
<el-tooltip content="默认为zip压缩包下载,也可以自定义生成路径" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-radio v-model="info.genType" label="0">zip压缩包</el-radio> |
||||
|
<el-radio v-model="info.genType" label="1">自定义路径</el-radio> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
|
||||
|
<el-col :span="12"> |
||||
|
<el-form-item> |
||||
|
<span slot="label"> |
||||
|
上级菜单 |
||||
|
<el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<treeselect |
||||
|
:append-to-body="true" |
||||
|
v-model="info.parentMenuId" |
||||
|
:options="menus" |
||||
|
:normalizer="normalizer" |
||||
|
:show-count="true" |
||||
|
placeholder="请选择系统菜单" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
|
||||
|
<el-col :span="24" v-if="info.genType == '1'"> |
||||
|
<el-form-item prop="genPath"> |
||||
|
<span slot="label"> |
||||
|
自定义路径 |
||||
|
<el-tooltip content="填写磁盘绝对路径,若不填写,则生成到当前Web项目下" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-input v-model="info.genPath"> |
||||
|
<el-dropdown slot="append"> |
||||
|
<el-button type="primary"> |
||||
|
最近路径快速选择 |
||||
|
<i class="el-icon-arrow-down el-icon--right"></i> |
||||
|
</el-button> |
||||
|
<el-dropdown-menu slot="dropdown"> |
||||
|
<el-dropdown-item @click.native="info.genPath = '/'">恢复默认的生成基础路径</el-dropdown-item> |
||||
|
</el-dropdown-menu> |
||||
|
</el-dropdown> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-row v-show="info.tplCategory == 'tree'"> |
||||
|
<h4 class="form-header">其他信息</h4> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item> |
||||
|
<span slot="label"> |
||||
|
树编码字段 |
||||
|
<el-tooltip content="树显示的编码字段名, 如:dept_id" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-select v-model="info.treeCode" placeholder="请选择"> |
||||
|
<el-option |
||||
|
v-for="(column, index) in info.columns" |
||||
|
:key="index" |
||||
|
:label="column.columnName + ':' + column.columnComment" |
||||
|
:value="column.columnName" |
||||
|
></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item> |
||||
|
<span slot="label"> |
||||
|
树父编码字段 |
||||
|
<el-tooltip content="树显示的父编码字段名, 如:parent_Id" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-select v-model="info.treeParentCode" placeholder="请选择"> |
||||
|
<el-option |
||||
|
v-for="(column, index) in info.columns" |
||||
|
:key="index" |
||||
|
:label="column.columnName + ':' + column.columnComment" |
||||
|
:value="column.columnName" |
||||
|
></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item> |
||||
|
<span slot="label"> |
||||
|
树名称字段 |
||||
|
<el-tooltip content="树节点的显示名称字段名, 如:dept_name" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-select v-model="info.treeName" placeholder="请选择"> |
||||
|
<el-option |
||||
|
v-for="(column, index) in info.columns" |
||||
|
:key="index" |
||||
|
:label="column.columnName + ':' + column.columnComment" |
||||
|
:value="column.columnName" |
||||
|
></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row v-show="info.tplCategory == 'sub'"> |
||||
|
<h4 class="form-header">关联信息</h4> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item> |
||||
|
<span slot="label"> |
||||
|
关联子表的表名 |
||||
|
<el-tooltip content="关联子表的表名, 如:sys_user" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-select v-model="info.subTableName" placeholder="请选择" @change="subSelectChange"> |
||||
|
<el-option |
||||
|
v-for="(table, index) in tables" |
||||
|
:key="index" |
||||
|
:label="table.tableName + ':' + table.tableComment" |
||||
|
:value="table.tableName" |
||||
|
></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<el-form-item> |
||||
|
<span slot="label"> |
||||
|
子表关联的外键名 |
||||
|
<el-tooltip content="子表关联的外键名, 如:user_id" placement="top"> |
||||
|
<i class="el-icon-question"></i> |
||||
|
</el-tooltip> |
||||
|
</span> |
||||
|
<el-select v-model="info.subTableFkName" placeholder="请选择"> |
||||
|
<el-option |
||||
|
v-for="(column, index) in subColumns" |
||||
|
:key="index" |
||||
|
:label="column.columnName + ':' + column.columnComment" |
||||
|
:value="column.columnName" |
||||
|
></el-option> |
||||
|
</el-select> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</el-form> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import Treeselect from "@riophae/vue-treeselect"; |
||||
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; |
||||
|
|
||||
|
export default { |
||||
|
components: { Treeselect }, |
||||
|
props: { |
||||
|
info: { |
||||
|
type: Object, |
||||
|
default: null |
||||
|
}, |
||||
|
tables: { |
||||
|
type: Array, |
||||
|
default: null |
||||
|
}, |
||||
|
menus: { |
||||
|
type: Array, |
||||
|
default: [] |
||||
|
}, |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
subColumns: [], |
||||
|
rules: { |
||||
|
tplCategory: [ |
||||
|
{ required: true, message: "请选择生成模板", trigger: "blur" } |
||||
|
], |
||||
|
packageName: [ |
||||
|
{ required: true, message: "请输入生成包路径", trigger: "blur" } |
||||
|
], |
||||
|
moduleName: [ |
||||
|
{ required: true, message: "请输入生成模块名", trigger: "blur" } |
||||
|
], |
||||
|
businessName: [ |
||||
|
{ required: true, message: "请输入生成业务名", trigger: "blur" } |
||||
|
], |
||||
|
functionName: [ |
||||
|
{ required: true, message: "请输入生成功能名", trigger: "blur" } |
||||
|
], |
||||
|
} |
||||
|
}; |
||||
|
}, |
||||
|
watch: { |
||||
|
'info.subTableName': function(val) { |
||||
|
this.setSubTableColumns(val); |
||||
|
}, |
||||
|
'info.tplWebType': function(val) { |
||||
|
if (val === '') { |
||||
|
this.info.tplWebType = "element-ui"; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
/** 转换菜单数据结构 */ |
||||
|
normalizer(node) { |
||||
|
if (node.children && !node.children.length) { |
||||
|
delete node.children; |
||||
|
} |
||||
|
return { |
||||
|
id: node.menuId, |
||||
|
label: node.menuName, |
||||
|
children: node.children |
||||
|
}; |
||||
|
}, |
||||
|
/** 选择子表名触发 */ |
||||
|
subSelectChange(value) { |
||||
|
this.info.subTableFkName = ''; |
||||
|
}, |
||||
|
/** 选择生成模板触发 */ |
||||
|
tplSelectChange(value) { |
||||
|
if(value !== 'sub') { |
||||
|
this.info.subTableName = ''; |
||||
|
this.info.subTableFkName = ''; |
||||
|
} |
||||
|
}, |
||||
|
/** 设置关联外键 */ |
||||
|
setSubTableColumns(value) { |
||||
|
for (var item in this.tables) { |
||||
|
const name = this.tables[item].tableName; |
||||
|
if (value === name) { |
||||
|
this.subColumns = this.tables[item].columns; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,354 @@ |
|||||
|
<template> |
||||
|
<div class="app-container"> |
||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> |
||||
|
<el-form-item label="表名称" prop="tableName"> |
||||
|
<el-input |
||||
|
v-model="queryParams.tableName" |
||||
|
placeholder="请输入表名称" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="表描述" prop="tableComment"> |
||||
|
<el-input |
||||
|
v-model="queryParams.tableComment" |
||||
|
placeholder="请输入表描述" |
||||
|
clearable |
||||
|
@keyup.enter.native="handleQuery" |
||||
|
/> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="创建时间"> |
||||
|
<el-date-picker |
||||
|
v-model="dateRange" |
||||
|
style="width: 240px" |
||||
|
value-format="yyyy-MM-dd" |
||||
|
type="daterange" |
||||
|
range-separator="-" |
||||
|
start-placeholder="开始日期" |
||||
|
end-placeholder="结束日期" |
||||
|
></el-date-picker> |
||||
|
</el-form-item> |
||||
|
<el-form-item> |
||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> |
||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
|
||||
|
<el-row :gutter="10" class="mb8"> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
plain |
||||
|
icon="el-icon-download" |
||||
|
size="mini" |
||||
|
:disabled="multiple" |
||||
|
@click="handleGenTable" |
||||
|
v-hasPermi="['tool:gen:code']" |
||||
|
>生成</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="primary" |
||||
|
plain |
||||
|
icon="el-icon-plus" |
||||
|
size="mini" |
||||
|
@click="openCreateTable" |
||||
|
v-hasRole="['admin']" |
||||
|
>创建</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="info" |
||||
|
plain |
||||
|
icon="el-icon-upload" |
||||
|
size="mini" |
||||
|
@click="openImportTable" |
||||
|
v-hasPermi="['tool:gen:import']" |
||||
|
>导入</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="success" |
||||
|
plain |
||||
|
icon="el-icon-edit" |
||||
|
size="mini" |
||||
|
:disabled="single" |
||||
|
@click="handleEditTable" |
||||
|
v-hasPermi="['tool:gen:edit']" |
||||
|
>修改</el-button> |
||||
|
</el-col> |
||||
|
<el-col :span="1.5"> |
||||
|
<el-button |
||||
|
type="danger" |
||||
|
plain |
||||
|
icon="el-icon-delete" |
||||
|
size="mini" |
||||
|
:disabled="multiple" |
||||
|
@click="handleDelete" |
||||
|
v-hasPermi="['tool:gen:remove']" |
||||
|
>删除</el-button> |
||||
|
</el-col> |
||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
||||
|
</el-row> |
||||
|
|
||||
|
<el-table v-loading="loading" :data="tableList" @selection-change="handleSelectionChange"> |
||||
|
<el-table-column type="selection" align="center" width="55"></el-table-column> |
||||
|
<el-table-column label="序号" type="index" width="50" align="center"> |
||||
|
<template slot-scope="scope"> |
||||
|
<span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
label="表名称" |
||||
|
align="center" |
||||
|
prop="tableName" |
||||
|
:show-overflow-tooltip="true" |
||||
|
width="120" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="表描述" |
||||
|
align="center" |
||||
|
prop="tableComment" |
||||
|
:show-overflow-tooltip="true" |
||||
|
width="120" |
||||
|
/> |
||||
|
<el-table-column |
||||
|
label="实体" |
||||
|
align="center" |
||||
|
prop="className" |
||||
|
:show-overflow-tooltip="true" |
||||
|
width="120" |
||||
|
/> |
||||
|
<el-table-column label="创建时间" align="center" prop="createTime" width="160" /> |
||||
|
<el-table-column label="更新时间" align="center" prop="updateTime" width="160" /> |
||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
size="small" |
||||
|
icon="el-icon-view" |
||||
|
@click="handlePreview(scope.row)" |
||||
|
v-hasPermi="['tool:gen:preview']" |
||||
|
>预览</el-button> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
size="small" |
||||
|
icon="el-icon-edit" |
||||
|
@click="handleEditTable(scope.row)" |
||||
|
v-hasPermi="['tool:gen:edit']" |
||||
|
>编辑</el-button> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
size="small" |
||||
|
icon="el-icon-delete" |
||||
|
@click="handleDelete(scope.row)" |
||||
|
v-hasPermi="['tool:gen:remove']" |
||||
|
>删除</el-button> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
size="small" |
||||
|
icon="el-icon-refresh" |
||||
|
@click="handleSynchDb(scope.row)" |
||||
|
v-hasPermi="['tool:gen:edit']" |
||||
|
>同步</el-button> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
size="small" |
||||
|
icon="el-icon-download" |
||||
|
@click="handleGenTable(scope.row)" |
||||
|
v-hasPermi="['tool:gen:code']" |
||||
|
>生成代码</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
<pagination |
||||
|
v-show="total>0" |
||||
|
:total="total" |
||||
|
:page.sync="queryParams.pageNum" |
||||
|
:limit.sync="queryParams.pageSize" |
||||
|
@pagination="getList" |
||||
|
/> |
||||
|
<!-- 预览界面 --> |
||||
|
<el-dialog :title="preview.title" :visible.sync="preview.open" width="80%" top="5vh" append-to-body class="scrollbar"> |
||||
|
<el-tabs v-model="preview.activeName"> |
||||
|
<el-tab-pane |
||||
|
v-for="(value, key) in preview.data" |
||||
|
:label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))" |
||||
|
:name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))" |
||||
|
:key="key" |
||||
|
> |
||||
|
<el-link :underline="false" icon="el-icon-document-copy" v-clipboard:copy="value" v-clipboard:success="clipboardSuccess" style="float:right">复制</el-link> |
||||
|
<pre><code class="hljs" v-html="highlightedCode(value, key)"></code></pre> |
||||
|
</el-tab-pane> |
||||
|
</el-tabs> |
||||
|
</el-dialog> |
||||
|
<import-table ref="import" @ok="handleQuery" /> |
||||
|
<create-table ref="create" @ok="handleQuery" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen"; |
||||
|
import importTable from "./importTable"; |
||||
|
import createTable from "./createTable"; |
||||
|
import hljs from "highlight.js/lib/highlight"; |
||||
|
import "highlight.js/styles/github-gist.css"; |
||||
|
hljs.registerLanguage("java", require("highlight.js/lib/languages/java")); |
||||
|
hljs.registerLanguage("xml", require("highlight.js/lib/languages/xml")); |
||||
|
hljs.registerLanguage("html", require("highlight.js/lib/languages/xml")); |
||||
|
hljs.registerLanguage("vue", require("highlight.js/lib/languages/xml")); |
||||
|
hljs.registerLanguage("javascript", require("highlight.js/lib/languages/javascript")); |
||||
|
hljs.registerLanguage("sql", require("highlight.js/lib/languages/sql")); |
||||
|
|
||||
|
export default { |
||||
|
name: "Gen", |
||||
|
components: { importTable, createTable }, |
||||
|
data() { |
||||
|
return { |
||||
|
// 遮罩层 |
||||
|
loading: true, |
||||
|
// 唯一标识符 |
||||
|
uniqueId: "", |
||||
|
// 选中数组 |
||||
|
ids: [], |
||||
|
// 选中表数组 |
||||
|
tableNames: [], |
||||
|
// 非单个禁用 |
||||
|
single: true, |
||||
|
// 非多个禁用 |
||||
|
multiple: true, |
||||
|
// 显示搜索条件 |
||||
|
showSearch: true, |
||||
|
// 总条数 |
||||
|
total: 0, |
||||
|
// 表数据 |
||||
|
tableList: [], |
||||
|
// 日期范围 |
||||
|
dateRange: "", |
||||
|
// 查询参数 |
||||
|
queryParams: { |
||||
|
pageNum: 1, |
||||
|
pageSize: 10, |
||||
|
tableName: undefined, |
||||
|
tableComment: undefined |
||||
|
}, |
||||
|
// 预览参数 |
||||
|
preview: { |
||||
|
open: false, |
||||
|
title: "代码预览", |
||||
|
data: {}, |
||||
|
activeName: "domain.java" |
||||
|
} |
||||
|
}; |
||||
|
}, |
||||
|
created() { |
||||
|
this.getList(); |
||||
|
}, |
||||
|
activated() { |
||||
|
const time = this.$route.query.t; |
||||
|
if (time != null && time != this.uniqueId) { |
||||
|
this.uniqueId = time; |
||||
|
this.queryParams.pageNum = Number(this.$route.query.pageNum); |
||||
|
this.getList(); |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
/** 查询表集合 */ |
||||
|
getList() { |
||||
|
this.loading = true; |
||||
|
listTable(this.addDateRange(this.queryParams, this.dateRange)).then(response => { |
||||
|
this.tableList = response.rows; |
||||
|
this.total = response.total; |
||||
|
this.loading = false; |
||||
|
} |
||||
|
); |
||||
|
}, |
||||
|
/** 搜索按钮操作 */ |
||||
|
handleQuery() { |
||||
|
this.queryParams.pageNum = 1; |
||||
|
this.getList(); |
||||
|
}, |
||||
|
/** 生成代码操作 */ |
||||
|
handleGenTable(row) { |
||||
|
const tableNames = row.tableName || this.tableNames; |
||||
|
if (tableNames == "") { |
||||
|
this.$modal.msgError("请选择要生成的数据"); |
||||
|
return; |
||||
|
} |
||||
|
if(row.genType === "1") { |
||||
|
genCode(row.tableName).then(response => { |
||||
|
this.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath); |
||||
|
}); |
||||
|
} else { |
||||
|
this.$download.zip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi.zip"); |
||||
|
} |
||||
|
}, |
||||
|
/** 同步数据库操作 */ |
||||
|
handleSynchDb(row) { |
||||
|
const tableName = row.tableName; |
||||
|
this.$modal.confirm('确认要强制同步"' + tableName + '"表结构吗?').then(function() { |
||||
|
return synchDb(tableName); |
||||
|
}).then(() => { |
||||
|
this.$modal.msgSuccess("同步成功"); |
||||
|
}).catch(() => {}); |
||||
|
}, |
||||
|
/** 打开导入表弹窗 */ |
||||
|
openImportTable() { |
||||
|
this.$refs.import.show(); |
||||
|
}, |
||||
|
/** 打开创建表弹窗 */ |
||||
|
openCreateTable() { |
||||
|
this.$refs.create.show(); |
||||
|
}, |
||||
|
/** 重置按钮操作 */ |
||||
|
resetQuery() { |
||||
|
this.dateRange = []; |
||||
|
this.resetForm("queryForm"); |
||||
|
this.handleQuery(); |
||||
|
}, |
||||
|
/** 预览按钮 */ |
||||
|
handlePreview(row) { |
||||
|
previewTable(row.tableId).then(response => { |
||||
|
this.preview.data = response.data; |
||||
|
this.preview.open = true; |
||||
|
this.preview.activeName = "domain.java"; |
||||
|
}); |
||||
|
}, |
||||
|
/** 高亮显示 */ |
||||
|
highlightedCode(code, key) { |
||||
|
const vmName = key.substring(key.lastIndexOf("/") + 1, key.indexOf(".vm")); |
||||
|
var language = vmName.substring(vmName.indexOf(".") + 1, vmName.length); |
||||
|
const result = hljs.highlight(language, code || "", true); |
||||
|
return result.value || ' '; |
||||
|
}, |
||||
|
/** 复制代码成功 */ |
||||
|
clipboardSuccess() { |
||||
|
this.$modal.msgSuccess("复制成功"); |
||||
|
}, |
||||
|
// 多选框选中数据 |
||||
|
handleSelectionChange(selection) { |
||||
|
this.ids = selection.map(item => item.tableId); |
||||
|
this.tableNames = selection.map(item => item.tableName); |
||||
|
this.single = selection.length != 1; |
||||
|
this.multiple = !selection.length; |
||||
|
}, |
||||
|
/** 修改按钮操作 */ |
||||
|
handleEditTable(row) { |
||||
|
const tableId = row.tableId || this.ids[0]; |
||||
|
const tableName = row.tableName || this.tableNames[0]; |
||||
|
const params = { pageNum: this.queryParams.pageNum }; |
||||
|
this.$tab.openPage("修改[" + tableName + "]生成配置", '/tool/gen-edit/index/' + tableId, params); |
||||
|
}, |
||||
|
/** 删除按钮操作 */ |
||||
|
handleDelete(row) { |
||||
|
const tableIds = row.tableId || this.ids; |
||||
|
this.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?').then(function() { |
||||
|
return delTable(tableIds); |
||||
|
}).then(() => { |
||||
|
this.getList(); |
||||
|
this.$modal.msgSuccess("删除成功"); |
||||
|
}).catch(() => {}); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
</script> |
@ -0,0 +1,130 @@ |
|||||
|
"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" ? "/acupunctureClient/" : "/", |
||||
|
// 在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, |
||||
|
transpileDependencies: ["quill"], |
||||
|
// 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: `https://test.tall.wiki/acupuncture`, |
||||
|
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|jpe?g|png|gif|svg)?$/i, // 压缩文件格式
|
||||
|
filename: "[path][base].gz[query]", // 压缩后的文件名
|
||||
|
algorithm: "gzip", // 使用gzip压缩
|
||||
|
minRatio: 0.8, // 压缩比例,小于 80% 的文件不会被压缩
|
||||
|
deleteOriginalAssets: false, // 压缩后删除原文件
|
||||
|
}), |
||||
|
], |
||||
|
}, |
||||
|
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
|
||||
|
test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
|
||||
|
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
|
||||
|
}, |
||||
|
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"); |
||||
|
}); |
||||
|
}, |
||||
|
}; |
Loading…
Reference in new issue