This commit is contained in:
yy 2024-05-17 12:06:29 +08:00
parent c05e694e38
commit 147e82c394
41 changed files with 3201 additions and 2134 deletions

View File

@ -10,11 +10,11 @@
"type-check": "vue-tsc --noEmit" "type-check": "vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@stomp/stompjs": "^7.0.0",
"axios": "^1.3.3", "axios": "^1.3.3",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"echarts": "^5.4.1", "echarts": "^5.4.1",
"element-plus": "2.3.1", "element-china-area-data": "^6.1.0",
"element-plus": "2.7.2",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"pinia": "^2.1.7", "pinia": "^2.1.7",
@ -22,8 +22,8 @@
"sass": "^1.58.3", "sass": "^1.58.3",
"uuid": "^9.0.1", "uuid": "^9.0.1",
"vant": "^4.8.3", "vant": "^4.8.3",
"vue": "^3.2.45", "vue": "^3.4.21",
"vue-router": "^4.1.6", "vue-router": "^4.3.0",
"xlsx": "^0.18.5" "xlsx": "^0.18.5"
}, },
"devDependencies": { "devDependencies": {

99
src/api/dict.ts Normal file
View File

@ -0,0 +1,99 @@
import request from "@/utils/request";
const dictUrl = "/admin/dict";
const dictPageUrl = "/admin/dict/tree";
const dictItemUrl = "/admin/dict/item";
const dictItemPageUrl = "/admin/dict/item/page";
export function dictPage(current: number, size: number, name?: string) {
return new Promise(resolve => {
request.get(dictPageUrl, {
params: {
current,
size,
name
}
}).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function dictItemPage(dictId: string, name?: string) {
return new Promise(resolve => {
request.get(dictItemPageUrl, {
params: {
dictId,
name
}
}).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function saveDict(dict: any): Promise<any> {
return new Promise(resolve => {
request.post(dictUrl, dict).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function updateDict(dict: any): Promise<any> {
return new Promise(resolve => {
request.put(dictUrl, dict).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function saveDictItem(item: any): Promise<any> {
return new Promise(resolve => {
request.post(dictItemUrl, item).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function updateDictItem(item: any): Promise<any> {
return new Promise(resolve => {
request.put(dictItemUrl, item).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function deleteDict(ids: any[]): Promise<any> {
return new Promise(resolve => {
request.delete(dictUrl, {
data: ids
}).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function deleteDictItem(id: string): Promise<any> {
return new Promise(resolve => {
request.delete(dictItemUrl + "/" + id).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}

View File

@ -1,18 +1,122 @@
import request, {CommonHeaderEnum} from "@/utils/request"; import request, {CommonHeaderEnum} from "@/utils/request";
const getHospitalListUrl = "/admin/hospital/getHospitalList" const getHospitalListUrl = "/admin/hospital/getHospitalList"
const getHospitalPageUrl = "/admin/hospital/getHospitalPage" const getMyHospitalListUrl = "/admin/hospital/getMyHospitalList";
const saveHospitalUrl = "/admin/hospital/saveHospital";
const getHospitalPageUrl = "/admin/hospital/getHospitalPage";
const deleteHospitalByIdsUrl = "/admin/hospital/deleteHospitalByIds";
const saveHospitalManagerUrl = "/admin/hospital/saveHospitalManager";
const updateHospitalUrl = "/admin/hospital/updateHospital";
const getHospitalManagerUrl = "/admin/hospital/getHospitalManager";
const changeHospitalUrl = "/admin/hospital/changeHospital";
const getCurrentHospitalUrl = "/admin/hospital/getCurrentHospital";
export const getHospitalList = () => { export const getHospitalList = () => {
return new Promise(resolve => { return new Promise(resolve => {
request({ request({
url: getHospitalListUrl, url: getHospitalListUrl,
method: 'post', method: 'post',
headers: { headers: {
'Content-Type': CommonHeaderEnum.FORM_CONTENT_TYPE, 'Content-Type': CommonHeaderEnum.FORM_CONTENT_TYPE,
}, },
}).then(res => { }).then(res => {
resolve(res.data); resolve(res.data);
})
}) })
})
}
export function getMyHospitalList() {
return new Promise(resolve => {
request.post(getMyHospitalListUrl).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function saveHospital(hospital: any) {
return new Promise(resolve => {
request.postForm(saveHospitalUrl, hospital).then(res => {
resolve(res.data);
}).catch(err => {
resolve(err);
})
})
}
export function getHospitalPage(current: number, size: number, name?: string) {
return new Promise(resolve => {
request.postForm(getHospitalPageUrl, {
offset: current,
limit: size,
name: name
}).then(res => {
resolve(res.data);
}).catch(err => {
resolve(err);
})
})
}
export function deleteHospitalByIds(ids: string) {
return new Promise(resolve => {
request.postForm(deleteHospitalByIdsUrl, {ids}).then(res => {
resolve(res.data);
}).catch(err => {
resolve(err);
})
})
}
export function saveHospitalManager(hospitalId: string, userId: string) {
return new Promise(resolve => {
request.postForm(saveHospitalManagerUrl, {hospitalId, userId}).then((res: any) => {
resolve(res.data);
}).catch(err => {
resolve(err);
})
})
}
export function updateHospital(form: any) {
return new Promise(resolve => {
request.postForm(updateHospitalUrl, form).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function getHospitalManager(hospitalId: string) {
return new Promise(resolve => {
request.postForm(getHospitalManagerUrl, {
hospitalId
}).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function changeHospital(id: string) {
return new Promise(resolve => {
request.postForm(changeHospitalUrl, {id}).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err);
})
})
}
export function getCurrentHospital() {
return new Promise(resolve => {
request.post(getCurrentHospitalUrl).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
} }

57
src/api/medicine.ts Normal file
View File

@ -0,0 +1,57 @@
import request from "@/utils/request";
const getDatabaseListUrl = "/admin/medicine/getDatabaseList";
const getSurgeryCountUrl = "/admin/medicine/getSurgeryCount";
const getSurgeryDurationUrl = "/admin/medicine/getSurgeryDuration";
const getSurgeryTypeProportionUrl = "/admin/medicine/getSurgeryTypeProportion";
const getSurgeryOtherDurationUrl = "/admin/medicine/getSurgeryOtherDuration";
export function getDatabaseList() {
return new Promise(resolve => {
request.post(getDatabaseListUrl).then(res => {
resolve(res.data);
}).catch(err => {
resolve(err)
})
})
}
export function getSurgeryCount(start: string, end: string): Promise<any> {
return new Promise(resolve => {
request.postForm(getSurgeryCountUrl, {start, end}).then(res => {
resolve(res.data);
}).catch(err => {
resolve(err)
})
})
}
export function getSurgeryDuration(start: string, end: string): Promise<any> {
return new Promise(resolve => {
request.postForm(getSurgeryDurationUrl, {start, end}).then(res => {
resolve(res.data);
}).catch(err => {
resolve(err);
})
})
}
export function getSurgeryTypeProportion(start: string, end: string): Promise<any> {
return new Promise(resolve => {
request.postForm(getSurgeryTypeProportionUrl, {start, end}).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}
export function getSurgeryOtherDuration(start: string, end: string): Promise<any> {
return new Promise(resolve => {
request.postForm(getSurgeryOtherDurationUrl, {start, end}).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err)
})
})
}

View File

@ -4,76 +4,76 @@ const getMenuTreeUrl = "/admin/menu/tree";
const menuUrl = "/admin/menu"; const menuUrl = "/admin/menu";
export function getMenuTree(menuName?: string, parent?: string, type?: string) { export function getMenuTree(menuName?: string, parent?: string, type?: string) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const params: any = []; const params: any = [];
if (parent) { if (parent) {
params.push("parent=" + parent); params.push("parent=" + parent);
} }
if (menuName) { if (menuName) {
params.push("menuName=" + menuName); params.push("menuName=" + menuName);
} }
if (type) { if (type) {
params.push("type=" + type); params.push("type=" + type);
} }
request.get(getMenuTreeUrl + (params.length > 0 ? "?" + params.join("&") : "")) request.get(getMenuTreeUrl + (params.length > 0 ? "?" + params.join("&") : ""))
.then((res) => { .then((res) => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
reject(err); resolve(err);
}) })
}) })
} }
export function getRoleTree(roleId: string) { export function getRoleTree(roleId: string) {
return new Promise(resolve => { return new Promise(resolve => {
request.get(getMenuTreeUrl + "/" + roleId).then(res => { request.get(getMenuTreeUrl + "/" + roleId).then(res => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
resolve(err); resolve(err);
}); });
}) })
} }
export function saveMenu(menu: any) { export function saveMenu(menu: any) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.post(menuUrl, menu).then((res: any) => { request.post(menuUrl, menu).then((res: any) => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
reject(err); resolve(err);
}) })
}) })
} }
export function updateMenu(menu: any) { export function updateMenu(menu: any) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.put(menuUrl, menu).then((res: any) => { request.put(menuUrl, menu).then((res: any) => {
resolve(res); resolve(res.data);
}).catch(err => { }).catch(err => {
reject(err); resolve(err);
}) })
}) })
} }
export function deleteById(id: string) { export function deleteById(id: string) {
return new Promise((resolve) => { return new Promise((resolve) => {
request.delete(menuUrl + "/" + id).then((res: any) => { request.delete(menuUrl + "/" + id).then((res: any) => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
resolve(err); resolve(err);
}) })
}) })
} }
export function getUserMenu(type?: string, parentId?: string) { export function getUserMenu(type?: string, parentId?: string) {
return new Promise(resolve => { return new Promise(resolve => {
const params: string[] = []; const params: string[] = [];
if (type) params.push("type=" + type); if (type) params.push("type=" + type);
if (parentId) params.push("parentId=" + parentId); if (parentId) params.push("parentId=" + parentId);
request.get(menuUrl + (params.length > 0 ? "?" + params.join("&") : "")) request.get(menuUrl + (params.length > 0 ? "?" + params.join("&") : ""))
.then((res: any) => { .then((res: any) => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
resolve(err); resolve(err);
}); });
}) })
} }

View File

@ -6,46 +6,46 @@ const updateUrl = "/admin/sysMessage/update";
const deleteUrl = "/admin/sysMessage/delete"; const deleteUrl = "/admin/sysMessage/delete";
export function save(message: any, organization?: [], permissions?: []) { export function save(message: any, organization?: [], permissions?: []) {
return new Promise(resolve => { return new Promise(resolve => {
request.postForm(saveUrl, message).then(res => { request.postForm(saveUrl, message).then(res => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
resolve(err); resolve(err);
})
}) })
})
} }
export function update(message: any) { export function update(message: any) {
return new Promise(resolve => { return new Promise(resolve => {
request.postForm(updateUrl, message).then(res => { request.postForm(updateUrl, message).then(res => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
resolve(err); resolve(err);
})
}) })
})
} }
export function deleteByIds(ids: string[]) { export function deleteByIds(ids: string[]) {
return new Promise(resolve => { return new Promise(resolve => {
request.postForm(deleteUrl, {ids: ids.join(",")}).then(res => { request.postForm(deleteUrl, {ids: ids.join(",")}).then(res => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
resolve(err); resolve(err);
})
}) })
})
} }
export function page(current: number, size: number, condition?: { category: string, message: string }) { export function page(current: number, size: number, condition?: { category: string, message: string }): Promise<any> {
return new Promise(resolve => { return new Promise(resolve => {
request.postForm(pageUrl, { request.postForm(pageUrl, {
current: current, current: current,
size: size, size: size,
category: condition?.category, category: condition?.category,
message: condition?.message message: condition?.message
}).then(res => { }).then(res => {
resolve(res.data) resolve(res.data)
}).catch(err => { }).catch(err => {
resolve(err); resolve(err);
})
}) })
})
} }

View File

@ -12,6 +12,8 @@ const userUrl = '/admin/user'
const modifyPwUrl = "/admin/user/modifyPw" const modifyPwUrl = "/admin/user/modifyPw"
const getUserListByHospitalUrl = "/admin/user/getUserListByHospital";
export function getUserInfo() { export function getUserInfo() {
return new Promise(resolve => { return new Promise(resolve => {
getData(userInfoUrl).then((data: any) => { getData(userInfoUrl).then((data: any) => {
@ -117,3 +119,13 @@ export function deleteU(ids: any[]) {
}) })
}) })
} }
export function getUserListByHospital(hospitalId: string) {
return new Promise(resolve => {
request.postForm(getUserListByHospitalUrl, {hospitalId}).then(res => {
resolve(res.data)
}).catch(err => {
resolve(err);
})
})
}

View File

@ -51,16 +51,16 @@
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import {onMounted, reactive, ref, toRefs, watch} from 'vue' import {onMounted, reactive, ref} from 'vue'
import {ElMessage} from 'element-plus'
import type {UploadProps} from 'element-plus' import type {UploadProps} from 'element-plus'
import {useLoginStore} from '@/stores/user-info-store' import {ElMessage} from 'element-plus'
import {editPassword, getUserInfo, updateUserInfo} from "@/api/user"; import {editPassword, getUserInfo, updateUserInfo} from "@/api/user";
import {handleHttpUpload} from "@/api/file-upload"; import {handleHttpUpload} from "@/api/file-upload";
import {useUserStore} from "@/stores/user-info-store";
const emit = defineEmits(['close']) const emit = defineEmits(['close'])
// const userInfo = useLoginStore().getlogin() const userInfo = useUserStore().getlogin()
const formRef = ref() const formRef = ref()
const uploadRef = ref() const uploadRef = ref()
@ -188,7 +188,7 @@ const submitForm = async () => {
if (valid) { if (valid) {
// console.log('submit!') // console.log('submit!')
// //
// useLoginStore().setlogin('name', formData.value.name) useUserStore().setlogin('name', formData.value.name)
if (tabActive.value == 0) { if (tabActive.value == 0) {
const param = { const param = {
name: formData.value.name, name: formData.value.name,

View File

@ -1,11 +1,10 @@
import { createApp, defineComponent, ref, reactive } from 'vue' import {createApp} from 'vue'
import main from './main.vue' import main from './main.vue'
import router from './router' import router from './router'
import { createPinia } from 'pinia' import {createPinia} from 'pinia'
import ElementPlus from 'element-plus'; import ElementPlus, {ElDialog} from 'element-plus';
import * as ElementPlusIconsVue from '@element-plus/icons-vue' import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { ElDialog } from 'element-plus'
import TableAbility from '@/components/table-ability.vue' import TableAbility from '@/components/table-ability.vue'
@ -16,8 +15,6 @@ import '@/assets/css/custom-element.scss';
import '@/assets/css/animastore.css'; import '@/assets/css/animastore.css';
import '../permisstion'; import '../permisstion';
// import '@/utils/debugger'
const pinia = createPinia() const pinia = createPinia()
const app = createApp(main) const app = createApp(main)
@ -31,7 +28,7 @@ app.use(router)
app.component('el-dialog', ElDialog) app.component('el-dialog', ElDialog)
app.component('TableAbility', TableAbility) app.component('TableAbility', TableAbility)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component) app.component(key, component)
} }
app.mount('#app') app.mount('#app')

View File

@ -1,100 +1,63 @@
import {createRouter, createWebHistory} from 'vue-router' import {createRouter, createWebHistory} from 'vue-router'
import {useLoginStore} from '@/stores/user-info-store' import {useUserStore} from '@/stores/user-info-store'
import {ElMessage} from 'element-plus' import {ElMessage} from 'element-plus'
import {constantRoute} from './routes' import {constantRoute} from './routes'
import {decrypt, decryption, encrypt, encryption, isBase64} from "@/utils/other"; import {decrypt, encrypt, isBase64} from "@/utils/other";
import {Session} from "@/utils/storage";
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: constantRoute, routes: constantRoute,
stringifyQuery: stringifyQuery, stringifyQuery: stringifyQuery,
parseQuery: parseQuery, parseQuery: parseQuery,
}) })
const kk = "raxipnenttlewe"; const kk = "raxipnenttlewe";
router.beforeEach((to, from, next) => { router.beforeEach(async (to, from, next) => {
const loginInfo = useLoginStore().getlogin() if (to.fullPath.startsWith("/login")) {
// const isLogin = loginInfo.isLogin next()
// 普通用户 return
const commonUser = [ }
'/login',
'/home', const b = await isViewRoute(to);
'/patients-manage', if (!b) {
'/patients-manage/patients-manage', ElMessage.error('无权访问!')
'/patients-manage/surgery-info' next(from.fullPath)
] } else next()
// 中级管理员
const IntermediateAdmin = [
'/login',
'/home',
'/patients-manage',
'/patients-manage/patients-manage',
'/patients-manage/surgery-info',
'/remote-manage',
'/remote-manage/remote-manage',
'/remote-manage/remote-control'
]
// 高级管理员
const SeniorAdmin = [
'/login',
'/home',
'/patients-manage',
'/patients-manage/patients-manage',
'/patients-manage/surgery-info',
'/remote-manage',
'/remote-manage/remote-manage',
'/remote-manage/remote-control',
'/permissions-manage',
'/permissions-manage/doctor-manage',
'/permissions-manage/role-manage',
'/permissions-manage/menu-manage',
'/logs-manage',
'/logs-manage/message-manage',
'/logs-manage/logs-manage'
]
const isViewRoute = () => {
let release = true
/*switch (loginInfo.permissions) {
case '超级管理员':
release = true
break;
case '高级管理员':
release = SeniorAdmin.some((p: string) => p === to.path)
break;
case '中级管理员':
release = IntermediateAdmin.some((p: string) => p === to.path)
break;
case '普通用户':
release = commonUser.some((p: string) => p === to.path)
break;
default:
break;
}*/
return release
}
if (to.fullPath === '/login') {
next()
return
}
/*if (!isLogin) next('/login') //
else */
if (!isViewRoute()) {
ElMessage.error('无权访问!')
next(from.fullPath)
} else next()
}); });
const isViewRoute = async (to: any) => {
const data: any = await useUserStore().getMenuPathList();
return data.paths.indexOf(to.path) != -1
}
function stringifyQuery(query: any) { function stringifyQuery(query: any) {
return btoa(encrypt(JSON.stringify(query), kk)); return btoa(encrypt(JSON.stringify(query), kk));
} }
function parseQuery(query: any) { function parseQuery(query: any) {
if (isBase64(query)) { if (isBase64(query)) {
return JSON.parse(decrypt(atob(query), kk)); return JSON.parse(decrypt(atob(query), kk));
} else { } else {
return query; return query;
} }
}
const token = Session.get("token");
if (token) {
router.addRoute({
name: "root",
path: "/",
redirect: "/home"
})
} else {
router.addRoute({
name: "root",
path: "/",
redirect: "/login"
})
} }
export default router export default router

View File

@ -1,131 +1,138 @@
export const constantRoute=[ export const constantRoute = [
{
{ path: '/:pathMatch(.*)*', name: 'not-found', redirect: '/login' }, path: '/404',
{ name: "404",
path: '/login', component: () => import('@/views/404/404.vue')
name: '登录', },
component: () => import('@/views/login/login.vue'), {
}, path: '/login',
{ name: '登录',
path: '/', component: () => import('@/views/login/login.vue'),
redirect: '/login', },
component: () => import('@/views/index.vue'), {
path: '/page',
component: () => import('@/views/index.vue'),
children: [
{
path: '/home',
name: '首页',
component: () => import('@/views/home/index.vue'),
},
{
path: '/permissions-manage',
name: '权限管理',
redirect: '/permissions-manage/doctor-manage',
component: () => import('@/views/permissions-manage/index.vue'),
children: [ children: [
{ {
path: '/home', path: '/permissions-manage/doctor-manage',
name: '首页', name: '医生管理',
component: () => import('@/views/home/index.vue'), component: () => import('@/views/permissions-manage/doctor-manage.vue'),
}, },
{ {
path: '/permissions-manage', path: '/permissions-manage/role-manage',
name: '权限管理', name: '角色管理',
redirect: '/permissions-manage/doctor-manage', component: () => import('@/views/permissions-manage/role-manage.vue'),
component: () => import('@/views/permissions-manage/index.vue'), },
children: [ {
{ path: '/permissions-manage/menu-manage',
path: '/permissions-manage/doctor-manage', name: '菜单管理',
name: '医生管理', component: () => import('@/views/permissions-manage/menu-manage.vue'),
component: () => import('@/views/permissions-manage/doctor-manage.vue'), }
},
{
path: '/permissions-manage/role-manage',
name: '角色管理',
component: () => import('@/views/permissions-manage/role-manage.vue'),
},
{
path: '/permissions-manage/menu-manage',
name: '菜单管理',
component: () => import('@/views/permissions-manage/menu-manage.vue'),
}
]
},
{
path: '/patients-manage',
name: '患者管理',
redirect: '/patients-manage/patients-manage',
component: () => import('@/views/patients-manage/index.vue'),
children: [
{
path: '/patients-manage/patients-manage',
name: '患者管理',
component: () => import('@/views/patients-manage/patients-manage.vue'),
},
{
path: '/patients-manage/surgery-info',
name: '手术信息',
component: () => import('@/views/patients-manage/surgery-info.vue'),
}
]
},
{
path: '/remote-manage',
name: '远程管理',
redirect: '/remote-manage/remote-manage',
component: () => import('@/views/remote-manage/index.vue'),
children: [
{
path: '/remote-manage/remote-manage',
name: '远程管理',
component: () => import('@/views/remote-manage/remote-manage.vue'),
},
{
path: '/remote-manage/remote-thumbnail',
name: '预览缩略图',
component: () => import('@/views/remote-manage/remote-thumbnail.vue'),
},
{
path: '/remote-manage/remote-control',
name: '远程控制',
component: () => import('@/views/remote-manage/remote-control.vue'),
}
]
},
{
path: '/system-manage',
name: '后台管理',
redirect: '/system-manage/system-home',
component: () => import('@/views/system-manage/index.vue'),
children: [
{
path: '/system-manage/system-home',
name: '后台首页',
component: () => import('@/views/system-manage/system-home.vue'),
},
{
path: '/system-manage/hospitals',
name: '合作医院',
component: () => import('@/views/system-manage/hospitals.vue'),
},
{
path: '/system-manage/hospitals-map',
name: '合作医院地图',
component: () => import('@/views/system-manage/hospitals-map.vue'),
},
{
path: '/system-manage/user-list',
name: '用户列表',
component: () => import('@/views/system-manage/user-list.vue'),
}
]
},
{
path: '/logs-manage',
name: '系统管理',
redirect: '/logs-manage/message-manage',
component: () => import('@/views/logs-manage/index.vue'),
children: [
{
path: '/logs-manage/message-manage',
name: '消息管理',
component: () => import('@/views/logs-manage/message-manage.vue'),
},
{
path: '/logs-manage/logs-manage',
name: '日志管理',
component: () => import('@/views/logs-manage/logs-manage.vue'),
}
]
}
] ]
} },
{
path: '/patients-manage',
name: '患者管理',
redirect: '/patients-manage/patients-manage',
component: () => import('@/views/patients-manage/index.vue'),
children: [
{
path: '/patients-manage/patients-manage',
name: '患者管理',
component: () => import('@/views/patients-manage/patients-manage.vue'),
},
{
path: '/patients-manage/surgery-info',
name: '手术信息',
component: () => import('@/views/patients-manage/surgery-info.vue'),
}
]
},
{
path: '/remote-manage',
name: '远程管理',
redirect: '/remote-manage/remote-manage',
component: () => import('@/views/remote-manage/index.vue'),
children: [
{
path: '/remote-manage/remote-manage',
name: '远程管理',
component: () => import('@/views/remote-manage/remote-manage.vue'),
},
{
path: '/remote-manage/remote-thumbnail',
name: '预览缩略图',
component: () => import('@/views/remote-manage/remote-thumbnail.vue'),
},
{
path: '/remote-manage/remote-control',
name: '远程控制',
component: () => import('@/views/remote-manage/remote-control.vue'),
}
]
},
{
path: '/system-manage',
name: '后台管理',
redirect: '/system-manage/system-home',
component: () => import('@/views/system-manage/index.vue'),
children: [
{
path: '/system-manage/system-home',
name: '后台首页',
component: () => import('@/views/system-manage/system-home.vue'),
},
{
path: '/system-manage/hospitals',
name: '合作医院',
component: () => import('@/views/system-manage/hospitals.vue'),
},
{
path: '/system-manage/hospitals-map',
name: '合作医院地图',
component: () => import('@/views/system-manage/hospitals-map.vue'),
},
{
path: '/system-manage/user-list',
name: '用户列表',
component: () => import('@/views/system-manage/user-list.vue'),
}
]
},
{
path: '/logs-manage',
name: '系统管理',
redirect: '/logs-manage/message-manage',
component: () => import('@/views/logs-manage/index.vue'),
children: [
{
path: '/logs-manage/message-manage',
name: '消息管理',
component: () => import('@/views/logs-manage/message-manage.vue'),
},
{
path: '/logs-manage/logs-manage',
name: '日志管理',
component: () => import('@/views/logs-manage/logs-manage.vue'),
},
{
path: "/logs-manage/dict-manage",
name: "词典管理",
component: () => import("@/views/logs-manage/dict-manage.vue")
}
]
}
]
}
] ]

View File

View File

@ -18,7 +18,7 @@ export const useRemoteWsStore = defineStore("remoteWs", {
exceptionMsg: { exceptionMsg: {
"BIS_except": "脑电双频指数异常", "DBP_except": "舒张压异常", "EtCO2_except": "呼气末二氧化碳异常", "BIS_except": "脑电双频指数异常", "DBP_except": "舒张压异常", "EtCO2_except": "呼气末二氧化碳异常",
"HR_except": "心率异常", "SBP_except": "收缩压异常", "ST_except": "ST异常" "HR_except": "心率异常", "SBP_except": "收缩压异常", "ST_except": "ST异常"
}, } as any,
} }
}, },
actions: { actions: {

View File

@ -1,9 +1,12 @@
import { defineStore } from 'pinia' import {defineStore} from 'pinia'
import {getUserMenu} from "@/api/menu";
import {Session} from "@/utils/storage";
import router from "@/router";
export const useLoginStore = defineStore('login', { export const useUserStore = defineStore('login', {
state: () => { state: () => {
return { return {
login: { userInfo: {
account: '', account: '',
name: '', name: '',
/** /**
@ -12,21 +15,65 @@ export const useLoginStore = defineStore('login', {
* *
* *
*/ */
hospital: '' hospitalName: '',
} as any hospitalId: '',
menuPathList: {
paths: [],
menus: []
},
roleName: ''
} as any,
showHomeMsg: false
} }
}, },
// 也可以这样定义
// state: () => ({ count: 0 })
actions: { actions: {
getlogin() { getlogin() {
return this.login const onlineUser = Session.get("onlineUser");
return this.userInfo.account ? this.userInfo : onlineUser
}, },
setlogin(key: string, e: any) { setlogin(key: string, e: any) {
this.login[key] = e this.userInfo[key] = e
Session.set("onlineUser", this.userInfo);
}, },
logout() { logout() {
this.login.isLogin = false Session.clear();
router.removeRoute("root");
router.addRoute({
name: "root",
path: "/",
redirect: "/login"
})
},
getMenuPathList(): Promise<any> {
return new Promise(resolve => {
if (this.userInfo.menuPathList.paths.length == 0) {
getUserMenu().then((res: any) => {
if (res.code == 0) {
const paths: any = [];
const menus: any = [];
res.data.forEach((item: any) => {
handleMenuPath(item, paths, menus);
});
this.userInfo.menuPathList = {paths, menus};
resolve(this.userInfo.menuPathList);
}
})
} else {
resolve(this.userInfo.menuPathList)
}
})
} }
}, },
}) })
function handleMenuPath(menu: any, paths: any, menus?: any) {
paths.push(menu.path);
if (menus) {
menus.push(menu);
}
if (menu.children && menu.children.length > 0) {
menu.children.forEach((child: any) => {
handleMenuPath(child, paths);
})
}
}

View File

@ -3,21 +3,21 @@
* @returns * @returns
*/ */
export function dateFormater(formater: string, time?: any) { export function dateFormater(formater: string, time?: any) {
let date = time ? new Date(time) : new Date(), let date = time ? new Date(time) : new Date(),
Y = date.getFullYear() + '', Y = date.getFullYear() + '',
M = date.getMonth() + 1, M = date.getMonth() + 1,
D = date.getDate(), D = date.getDate(),
H = date.getHours(), H = date.getHours(),
m = date.getMinutes(), m = date.getMinutes(),
s = date.getSeconds(); s = date.getSeconds();
return formater return formater
.replace(/YYYY|yyyy/g, Y) .replace(/YYYY|yyyy/g, Y)
.replace(/YY|yy/g, Y.substr(2, 2)) .replace(/YY|yy/g, Y.substr(2, 2))
.replace(/MM/g, (M < 10 ? '0' : '') + M) .replace(/MM/g, (M < 10 ? '0' : '') + M)
.replace(/DD|dd/g, (D < 10 ? '0' : '') + D) .replace(/DD|dd/g, (D < 10 ? '0' : '') + D)
.replace(/HH|hh/g, (H < 10 ? '0' : '') + H) .replace(/HH|hh/g, (H < 10 ? '0' : '') + H)
.replace(/mm/g, (m < 10 ? '0' : '') + m) .replace(/mm/g, (m < 10 ? '0' : '') + m)
.replace(/ss/g, (s < 10 ? '0' : '') + s); .replace(/ss/g, (s < 10 ? '0' : '') + s);
} }
/** /**
@ -26,20 +26,20 @@ export function dateFormater(formater: string, time?: any) {
* @returns * @returns
*/ */
export function getMonthDays(time: any) { export function getMonthDays(time: any) {
if (!time) time = new Date(); if (!time) time = new Date();
const now = new Date(time); const now = new Date(time);
const year = now.getFullYear(); const year = now.getFullYear();
const month = now.getMonth() + 1; const month = now.getMonth() + 1;
const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
const daysInMonth = month === 2 const daysInMonth = month === 2
? isLeapYear ? 29 : 28 ? isLeapYear ? 29 : 28
: month === 4 || month === 6 || month === 9 || month === 11 : month === 4 || month === 6 || month === 9 || month === 11
? 30 ? 30
: 31; : 31;
return daysInMonth; return daysInMonth;
} }
/** /**
@ -47,22 +47,22 @@ export function getMonthDays(time: any) {
* @returns * @returns
*/ */
export function getFirstDayOfWeek(date: string | Date | number, i: number) { export function getFirstDayOfWeek(date: string | Date | number, i: number) {
let temp: any; let temp: any;
if (!(date instanceof Date)) { if (!(date instanceof Date)) {
if (typeof date == "number") { if (typeof date == "number") {
temp = new Date(date); temp = new Date(date);
} else { } else {
const s = date.replace(/-/g, "/"); const s = date.replace(/-/g, "/");
temp = new Date(s); temp = new Date(s);
} }
} else { } else {
temp = new Date(date.getTime()) temp = new Date(date.getTime())
} }
if (i < 1 || i > 7) { if (i < 1 || i > 7) {
return null; return null;
} }
const day = temp.getDay() || 7; const day = temp.getDay() || 7;
return new Date(temp.getFullYear(), temp.getMonth(), temp.getDate() + i - day); return new Date(temp.getFullYear(), temp.getMonth(), temp.getDate() + i - day);
} }
/** /**
@ -72,18 +72,18 @@ export function getFirstDayOfWeek(date: string | Date | number, i: number) {
const weekArray = ['周天', '周一', '周二', '周三', '周四', '周五', '周六']; const weekArray = ['周天', '周一', '周二', '周三', '周四', '周五', '周六'];
export function getCurrentDate(date: any) { export function getCurrentDate(date: any) {
let myDate = new Date(); let myDate = new Date();
if (date) { if (date) {
if (date instanceof Date) { if (date instanceof Date) {
myDate = date; myDate = date;
} else { } else {
date = date.replace(/-/g, '/'); date = date.replace(/-/g, '/');
myDate = new Date(date); myDate = new Date(date);
} }
} }
const days = myDate.getDay(); const days = myDate.getDay();
return weekArray[days]; return weekArray[days];
} }
/** /**
@ -91,20 +91,44 @@ export function getCurrentDate(date: any) {
* @returns * @returns
*/ */
export function getDays(date: any, days: number) { export function getDays(date: any, days: number) {
if (date) { if (date) {
let temp: any; let temp: any;
if (!(date instanceof Date)) { if (!(date instanceof Date)) {
date = date.replace(/-/g, '/'); date = date.replace(/-/g, '/');
temp = new Date(date); temp = new Date(date);
} else { } else {
temp = new Date(date.getTime()); temp = new Date(date.getTime());
} }
const time = temp.setDate(temp.getDate() + days); const time = temp.setDate(temp.getDate() + days);
return new Date(time); return new Date(time);
} }
} }
export function getEndOfMonth(year: number, month: number) { export function getEndOfMonth(year: number, month: number) {
return new Date(year, month, 0).getDate() return new Date(year, month, 0).getDate()
}
export function getWeekDates(d: any) {
let temp: Date;
if (!(d instanceof Date)) {
if (typeof d == 'number') {
temp = new Date(d)
} else {
temp = new Date(d.replace(/-/g, "/"))
}
} else {
temp = d
}
const day = temp.getDay();
const date = temp.getDate() + 1
const startOfWeek = new Date(temp)
const startDate = new Date(startOfWeek.setDate(date - day));
const endOfWeek = new Date(temp)
const endDate = new Date(endOfWeek.setDate(date + (6 - day)));
return {start: startDate, end: endDate};
} }

View File

@ -49,3 +49,23 @@ export function isBase64(s: string) {
return false; return false;
} }
} }
export function generateRandomColor() {
// 生成随机的 RGB 值
const red = Math.floor(Math.random() * 256);
const green = Math.floor(Math.random() * 256);
const blue = Math.floor(Math.random() * 256);
// 将 RGB 值转换为 16 进制格式
return rgbToHex(red, green, blue);
}
// 将 RGB 值转换为 16 进制格式
function rgbToHex(r: number, g: number, b: number) {
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
function componentToHex(c: number) {
const hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}

View File

@ -3,11 +3,7 @@ import axios from "axios";
import {Session} from "@/utils/storage"; import {Session} from "@/utils/storage";
import {decryption, encryption} from "@/utils/other"; import {decryption, encryption} from "@/utils/other";
import {ElMessageBox} from "element-plus"; import {ElMessageBox} from "element-plus";
/* import {useUserStore} from "@/stores/user-info-store";
import { ElMessage } from 'element-plus'
//引入用户相关的仓库
import useUserStore from '@/stores/modules/user'
*/
const BASE_URL = import.meta.env.VITE_RAX_BASE_URL const BASE_URL = import.meta.env.VITE_RAX_BASE_URL
@ -49,7 +45,7 @@ export const post = (url: any, params: any, success: any) => {
}; };
export const getMapJson = (name: string) => { export const getMapJson = (name: string) => {
return axiosInstance.post(BASE_URL+'/static/json/' + name) return axios.post('/static/json/' + name)
} }
export const getData = (url: string, params?: any) => { export const getData = (url: string, params?: any) => {
return axiosInstance.get(url, params) return axiosInstance.get(url, params)
@ -83,14 +79,14 @@ function handleResponse(response: any) {
axiosInstance.interceptors.response.use(handleResponse, error => { axiosInstance.interceptors.response.use(handleResponse, error => {
const code = error.response.status || 200 const code = error.response.status || 200
if (code == 424) { if (code == 424 || code == 401) {
ElMessageBox.confirm('令牌状态已过期,请点击重新登录', "系统提示", { ElMessageBox.confirm('令牌状态已过期,请点击重新登录', "系统提示", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: 'warning', type: 'warning',
}); });
Session.clear(); useUserStore().logout();
window.location.href = '/'; window.location.replace("/");
} }
return error return error
}) })

11
src/views/404/404.vue Normal file
View File

@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped lang="scss">
</style>

View File

@ -1,67 +1,100 @@
<template> <template>
<div class="home-page"> <div class="home-page">
<div class="background-box"> <div class="background-box">
<div class="left-content"> <div class="left-content">
<div class="message-box"> <div class="message-box">
<el-carousel height="32px" direction="vertical" indicator-position="none" autoplay> <el-carousel height="32px" direction="vertical" indicator-position="none" autoplay>
<el-carousel-item v-for="(item, index) in messages" :key="'message-' + index"> <el-carousel-item v-for="(item, index) in messages" :key="'message-' + index">
<p class="text-row-1" style="line-height: 32px;" :class="{'is-link': item.link}" <p class="text-row-1" style="line-height: 32px;" :class="{'is-link': item.href}"
@click="() => {item.link && router.push(item.link)}">{{ item.type }} {{ item.content }}</p> @click="userStore.showHomeMsg=true">{{ item.category }} {{ item.message }}</p>
</el-carousel-item> </el-carousel-item>
</el-carousel> </el-carousel>
</div> </div>
<div class="header-box"> <div class="header-box">
<div class="header-item"> <div class="header-item">
<span class="main-color f20" style="font-weight: 600;">{{ userInfo.name }}</span> <span class="main-color f20" style="font-weight: 600;">{{ userInfo.name }}</span>
<span class="text2-color f14">{{ userInfo.permissions }}</span> <span class="text2-color f14">{{ userInfo.roleName }}</span>
</div> </div>
<div class="header-item"> <div class="header-item">
<el-icon class="text1-color" style="font-size: 26px;margin-right: 20px;"> <el-icon class="text1-color" style="font-size: 26px;margin-right: 20px;">
<Calendar/> <Calendar/>
</el-icon> </el-icon>
<div> <div>
<p class="text1-color f14">待办任务</p> <p class="text1-color f14">待办任务</p>
<p class="main-color f20">{{ total }}</p> <p class="main-color f20">{{ todoTotal }}</p>
</div> </div>
</div> </div>
</div> </div>
<div class="echart-box"> <div class="echart-box">
<div class="echart-item"> <div class="echart-item">
<NumberChart/> <NumberChart/>
</div> </div>
<div class="echart-item"> <div class="echart-item">
<NumberPieChart/> <NumberPieChart/>
</div> </div>
<div class="echart-item"> <div class="echart-item">
<TimeChart/> <TimeChart/>
</div> </div>
<div class="echart-item"> <div class="echart-item">
<TimeBarChart/> <TimeBarChart/>
</div> </div>
</div> </div>
</div> </div>
<div class="right-content"> <div class="right-content">
<div class="week-calendar"> <div class="week-calendar">
<WeekCalendar/> <WeekCalendar/>
</div> </div>
<div class="system-logs"> <div class="system-logs" v-if="showLogMod">
<div class="title"> <div class="title">
<span>系统日志</span> <span>系统日志</span>
<span class="f14" style="cursor: pointer;" @click="router.push('./logs-manage/logs-manage')">更多</span> <span class="f14" style="cursor: pointer;" @click="router.push('./logs-manage/logs-manage')">更多</span>
</div> </div>
<div class="content"> <div class="content">
<SystemLogs/> <SystemLogs/>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> <el-drawer
class="message-drawer-box"
v-model="userStore.showHomeMsg"
title="通知消息"
>
<div class="body">
<el-card style="margin-top: 10px;" v-for="(item, index) in messageTable">
<template #header>
<div class="card-header">
<span>{{ item.category }}</span>
</div>
</template>
<p class="text item">{{ item.message }}</p>
<template #footer>
<span>{{ item.creatorName }}</span>
<span style="float: inline-end;">{{ item.createTime }}</span>
</template>
</el-card>
</div>
<div class="footer">
<el-pagination
v-model:page-size="size"
v-model:current-page="current"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
background
layout="prev, pager, next, jumper, sizes"
:page-sizes="[10, 20, 30, 50]"
:total="total"
/>
</div>
</el-drawer>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import {onMounted, ref} from 'vue' import {onMounted, ref} from 'vue'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import {useLoginStore} from '@/stores/user-info-store' import {useUserStore} from '@/stores/user-info-store'
import NumberChart from "./number-chart.vue"; import NumberChart from "./number-chart.vue";
import NumberPieChart from "./number-pie-chart.vue"; import NumberPieChart from "./number-pie-chart.vue";
import TimeChart from "./time-chart.vue"; import TimeChart from "./time-chart.vue";
@ -70,161 +103,208 @@ import WeekCalendar from "./week-calendar.vue";
import SystemLogs from "@/components/system-logs.vue"; import SystemLogs from "@/components/system-logs.vue";
import * as dailyPlanApi from "@/api/daily-plan"; import * as dailyPlanApi from "@/api/daily-plan";
import {dateFormater} from "@/utils/date-util"; import {dateFormater} from "@/utils/date-util";
import * as msgApi from "@/api/sys-message";
const router = useRouter() const router = useRouter()
const userInfo = useLoginStore().getlogin() const userStore = useUserStore();
const userInfo = userStore.getlogin()
const showLogMod = ref(false)
const messages = ref([] as any) const messages = ref([] as any)
const total = ref(0) // const messageTable = ref([] as any)
const current = ref(1);
messages.value.push({ const size = ref(10);
type: '通知', const total = ref(0);
content: '测试测试测试测试测试测试测试测试测试测试', const todoTotal = ref(0) //
link: '/system-manage/system-home'
})
messages.value.push({
type: '公告',
content: '公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试公告测试'
})
onMounted(() => { onMounted(() => {
getTodoCount(); init();
}) })
function init() {
const path = router.currentRoute.value.path;
userStore.getMenuPathList().then(res => {
res.menus.filter((menu: any) => menu.path == path).forEach((menu: any) => {
menu.children.filter((child: any) => child.permission == 'home_sys_log_view').forEach(() => {
showLogMod.value = true;
})
})
});
getTodoCount();
messages.value = [];
messageTable.value = [];
current.value = 1
total.value = 0
loadMsg();
}
function getTodoCount() { function getTodoCount() {
dailyPlanApi.getTodoCountByDate(dateFormater("yyyy-MM-dd", new Date())).then((res: any) => { dailyPlanApi.getTodoCountByDate(dateFormater("yyyy-MM-dd", new Date())).then((res: any) => {
if (res.code == 0) { if (res.code == 0) {
total.value = res.data; todoTotal.value = res.data;
} }
}); });
}
function handleSizeChange() {
messageTable.value = [];
loadMsg()
}
function handleCurrentChange() {
messageTable.value = [];
loadMsg()
}
async function loadMsg() {
const res = await msgApi.page(current.value, size.value)
if (res.code == 0) {
total.value = res.data.total
res.data.records.forEach((row: any) => {
if (current.value == 1) {
messages.value.push(row)
}
messageTable.value.push(row)
})
}
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.home-page { .home-page {
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 15px; padding: 15px;
overflow-y: auto; overflow-y: auto;
.background-box { .background-box {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: white; background: white;
padding: 20px 35px; padding: 20px 35px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
min-height: 900px; min-height: 900px;
} }
.left-content { .left-content {
width: calc(100% - 350px); width: calc(100% - 350px);
height: 100%; height: 100%;
.message-box { .message-box {
height: 34px; height: 34px;
background: #f8f8f8; background: #f8f8f8;
color: $text-color; color: $text-color;
padding: 0 30px; padding: 0 30px;
border: 1px solid $border1-color; border: 1px solid $border1-color;
margin-bottom: 20px; margin-bottom: 20px;
.is-link { .is-link {
cursor: pointer; cursor: pointer;
color: $main-color; color: $main-color;
} }
} }
.header-box { .header-box {
width: 100%; width: 100%;
height: 90px; height: 90px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.header-item { .header-item {
width: calc(60% - 20px); width: calc(60% - 20px);
height: 100%; height: 100%;
border: 1px solid $border-color; border: 1px solid $border-color;
border-radius: 5px; border-radius: 5px;
box-shadow: 1px 1px 5px $border2-color; box-shadow: 1px 1px 5px $border2-color;
padding: 0 90px; padding: 0 90px;
line-height: 1.5; line-height: 1.5;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
& ~ .header-item { & ~ .header-item {
width: 40%; width: 40%;
flex-direction: row; flex-direction: row;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
} }
} }
} }
.echart-box { .echart-box {
width: 100%; width: 100%;
height: calc(100% - 164px); height: calc(100% - 164px);
margin-top: 20px; margin-top: 20px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
.echart-item { .echart-item {
width: calc(60% - 20px); width: calc(60% - 20px);
height: calc(50% - 10px); height: calc(50% - 10px);
border: 1px solid $border-color; border: 1px solid $border-color;
border-radius: 5px; border-radius: 5px;
padding: 20px; padding: 20px;
box-shadow: 1px 1px 5px $border2-color; box-shadow: 1px 1px 5px $border2-color;
&:nth-child(even) { &:nth-child(even) {
width: 40%; width: 40%;
} }
&:nth-child(n + 3) { &:nth-child(n + 3) {
margin-top: 20px; margin-top: 20px;
} }
} }
} }
} }
.right-content { .right-content {
width: 330px; width: 330px;
height: 100%; height: 100%;
.week-calendar { .week-calendar {
width: 100%; width: 100%;
height: 50%; height: 50%;
} }
.system-logs { .system-logs {
width: 100%; width: 100%;
height: calc(50% - 20px); height: calc(50% - 20px);
margin-top: 20px; margin-top: 20px;
overflow: hidden; overflow: hidden;
.title { .title {
width: 100%; width: 100%;
height: 40px; height: 40px;
padding: 0 20px; padding: 0 20px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.content { .content {
width: 100%; width: 100%;
height: calc(100% - 50px); height: calc(100% - 50px);
margin-top: 10px; margin-top: 10px;
border: 1px solid $border-color; border: 1px solid $border-color;
padding: 30px; padding: 30px;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
} }
} }
} }
.message-drawer-box {
.body {
margin-bottom: 20px;
}
.footer {
position: fixed;
bottom: 6px;
background: white;
}
}
}</style> }</style>

View File

@ -1,21 +1,27 @@
<template> <template>
<div class="chart-box"> <div class="chart-box">
<div class="date-btn text-color"> <div class="date-btn text-color">
<div class="btn-box"> <div class="btn-box">
<el-icon @click="getData(upMonth)"><ArrowLeft /></el-icon> <el-icon @click="getData(upMonth)">
<el-date-picker v-model="currentMonth" format="YYYY年MM月" type="month" :editable="false" :clearable="false" @change="getData" /> <ArrowLeft/>
<el-icon @click="getData(downMonth)"><ArrowRight /></el-icon> </el-icon>
</div> <el-date-picker v-model="currentMonth" format="YYYY年MM月" type="month" :editable="false" :clearable="false"
</div> @change="getData"/>
<div ref="chartDom" class="chart-dom"></div> <el-icon @click="getData(downMonth)">
<div class="total-mini">本月共计{{ total }}台手术</div> <ArrowRight/>
</el-icon>
</div>
</div> </div>
<div ref="chartDom" class="chart-dom"></div>
<div class="total-mini">本月共计{{ total }}台手术</div>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, ref} from 'vue'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { dateFormater, getMonthDays } from '@/utils/date-util' import {dateFormater, getMonthDays} from '@/utils/date-util'
import * as medicineApi from "@/api/medicine";
const chartDom = ref() const chartDom = ref()
@ -25,159 +31,173 @@ const downMonth = ref()
const total = ref(0) const total = ref(0)
onMounted(() => { onMounted(() => {
getData(new Date()) init();
}) })
// true function init() {
function calcTime(time: any) { getData(new Date())
return Boolean(new Date().getTime() < new Date(time).getTime())
} }
function initChart(chartData: any) { function initChart(chartData: any) {
const chart = echarts.init(chartDom.value as HTMLElement); const chart = echarts.init(chartDom.value as HTMLElement);
chart.clear(); chart.clear();
const option = { const option = {
color: [], color: [],
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
formatter: (params: any) => { formatter: (params: any) => {
return dateFormater('yyyy年MM月', currentMonth.value) + params[0].axisValue + '<br>手术数量 <b>' + params[0].value + '</b> 台' return dateFormater('yyyy年MM月', currentMonth.value) + params[0].axisValue + '<br>手术数量 <b>' + params[0].value + '</b> 台'
} }
}, },
grid: { grid: {
left: 20, left: 20,
right: 50, right: 50,
bottom: 5, bottom: 5,
top: 50, top: 50,
containLabel: true, containLabel: true,
}, },
xAxis: { xAxis: {
name: '日期', name: '日期',
show: true, show: true,
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
nameTextStyle: { color: '#909399' }, nameTextStyle: {color: '#909399'},
axisLine: { show: true, lineStyle: { color: '#006080', width: 2 } }, axisLine: {show: true, lineStyle: {color: '#006080', width: 2}},
axisTick: { show: false }, axisTick: {show: false},
axisLabel: { show: true, interval: chartData.xData.length - 2 }, axisLabel: {show: true, interval: chartData.xData.length - 2},
splitLine: { show: true, lineStyle: { color: 'rgba(0, 96, 128, .05)', width: 1, type: 'solid' } }, splitLine: {show: true, lineStyle: {color: 'rgba(0, 96, 128, .05)', width: 1, type: 'solid'}},
data: chartData.xData, data: chartData.xData,
}, },
yAxis: { yAxis: {
name: '数量', name: '数量',
show: true, show: true,
type: 'value', type: 'value',
min: 0, min: 0,
nameTextStyle: { color: '#909399', align: 'center', verticalAlign: 'top', padding: [0, 0] }, nameTextStyle: {color: '#909399', align: 'center', verticalAlign: 'top', padding: [0, 0]},
axisLine: { show: true, lineStyle: { color: '#006080', width: 2 } }, axisLine: {show: true, lineStyle: {color: '#006080', width: 2}},
axisTick: { show: false }, axisTick: {show: false},
axisLabel: { show: false }, axisLabel: {show: false},
splitLine: { show: false, lineStyle: { color: '#D4E8F0', width: 1, type: 'solid' } }, splitLine: {show: false, lineStyle: {color: '#D4E8F0', width: 1, type: 'solid'}},
}, },
series: [{ series: [{
type: 'line', type: 'line',
symbol: 'none', symbol: 'none',
smooth: true, smooth: true,
showSymbol: false, showSymbol: false,
lineStyle: { lineStyle: {
color: 'rgb(0, 96, 128)', color: 'rgb(0, 96, 128)',
width: 2, width: 2,
shadowColor: 'rgba(0, 96, 128, .3)', shadowColor: 'rgba(0, 96, 128, .3)',
shadowBlur: 10, shadowBlur: 10,
shadowOffsetY: 20 shadowOffsetY: 20
}, },
areaStyle: { areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0, offset: 0,
color: 'rgba(0, 96, 128, 1)' color: 'rgba(0, 96, 128, 1)'
}, { }, {
offset: 0.8, offset: 0.8,
color: 'rgba(255, 255, 255, 0.1)' color: 'rgba(255, 255, 255, 0.1)'
}], false) }], false)
}, },
data: chartData.data data: chartData.data
}], }],
}; };
chart.setOption(option); chart.setOption(option);
chart.resize();
window.addEventListener('resize', () => {
chart.resize(); chart.resize();
window.addEventListener('resize', () => { });
chart.resize();
});
} }
const getData = (date: any) => { const getData = (date: any) => {
currentMonth.value = new Date(date) currentMonth.value = new Date(date)
upMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() - 1, 1) upMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() - 1, 1)
downMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 1) downMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 1)
const days = getMonthDays(currentMonth.value) const xData: any = []
const xData = [] const data: any = []
const data = [] let num = 0
let num = 0 const start = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth(), 1)
for (let i = 0; i < days; i++) { const end = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 0)
xData.push((i < 9 ? '0' : '') + (i + 1)) medicineApi.getSurgeryCount(dateFormater("yyyy-MM-dd", start), dateFormater("yyyy-MM-dd", end)).then(res => {
data.push(Math.ceil(Math.random() * 10)) if (res.code == 0) {
num += data[i] res.data.forEach((item: any) => {
xData.push(item.time)
data.push(item.count)
num += item.count
})
total.value = num
} }
total.value = num initChart({xData, data})
initChart({ xData, data }) })
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.chart-box { .chart-box {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
.date-btn {
position: absolute; .date-btn {
height: 50px; position: absolute;
top: 0; height: 50px;
left: 20px; top: 0;
right: 230px; left: 20px;
display: flex; right: 230px;
justify-content: space-between; display: flex;
z-index: 1; justify-content: space-between;
.btn-box { z-index: 1;
height: 30px;
display: flex; .btn-box {
align-items: center; height: 30px;
color: $text2-color; display: flex;
&>:deep(.el-date-editor) { align-items: center;
font-size: 14px; color: $text2-color;
.el-input__wrapper {
box-shadow: none; & > :deep(.el-date-editor) {
padding: 0; font-size: 14px;
.el-input__prefix,
.el-input__suffix { .el-input__wrapper {
display: none; box-shadow: none;
} padding: 0;
.el-input__inner {
cursor: pointer; .el-input__prefix,
width: 100px; .el-input__suffix {
color: $text2-color; display: none;
text-align: center; }
}
} .el-input__inner {
} cursor: pointer;
.el-icon { width: 100px;
cursor: pointer; color: $text2-color;
} text-align: center;
} }
}
.chart-dom {
width: 100%;
height: 100%;
}
.total-mini {
position: absolute;
top: 0;
right: 40px;
color: $main-color;
border: 1px solid $main-color;
font-size: 14px;
padding: 3px 8px;
} }
}
.el-icon {
cursor: pointer;
}
} }
}
.chart-dom {
width: 100%;
height: 100%;
}
.total-mini {
position: absolute;
top: 0;
right: 40px;
color: $main-color;
border: 1px solid $main-color;
font-size: 14px;
padding: 3px 8px;
}
}
</style> </style>

View File

@ -1,27 +1,30 @@
<template> <template>
<div class="chart-box"> <div class="chart-box">
<div class="date-btn text-color"> <div class="date-btn text-color">
<div class="btn-box"> <div class="btn-box">
<el-icon @click="getData(upMonth)"> <el-icon @click="getData(upMonth)">
<ArrowLeft /> <ArrowLeft/>
</el-icon> </el-icon>
<el-date-picker v-model="currentMonth" format="YYYY年MM月" type="month" :editable="false" :clearable="false" @change="getData" /> <el-date-picker v-model="currentMonth" format="YYYY年MM月" type="month" :editable="false" :clearable="false"
<el-icon @click="getData(downMonth)"> @change="getData"/>
<ArrowRight /> <el-icon @click="getData(downMonth)">
</el-icon> <ArrowRight/>
</div> </el-icon>
</div> </div>
<div class="total-box">
<div class="total-item" v-for="item in pieData" :key="item.name">{{ item.name }}:{{ item.value }}</div>
</div>
<div ref="chartDom" class="chart-dom"></div>
</div> </div>
<div class="total-box">
<div class="total-item" v-for="item in pieData" :key="item.name">{{ item.name }}:{{ item.value }}</div>
</div>
<div ref="chartDom" class="chart-dom"></div>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, ref} from 'vue'
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { dateFormater, getMonthDays } from '@/utils/date-util'; import * as medicineApi from '@/api/medicine'
import {dateFormater, getWeekDates} from "@/utils/date-util";
import {generateRandomColor} from "@/utils/other";
const chartDom = ref() const chartDom = ref()
@ -31,140 +34,156 @@ const downMonth = ref()
const pieData = ref([] as any) const pieData = ref([] as any)
onMounted(() => { onMounted(() => {
getData(new Date()) getData(new Date())
}) })
function initChart(chartData: any) { function initChart(chartData: any) {
const chart = echarts.init(chartDom.value as HTMLElement); const chart = echarts.init(chartDom.value as HTMLElement);
chart.clear(); chart.clear();
const option = { const option = {
color: chartData.color, color: chartData.color,
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
formatter: (params: any) => { formatter: (params: any) => {
return params.marker + params.name + '<br>数量:' + params.value + '<br>占比:' + params.percent + '%' return params.marker + params.name + '<br>数量:' + params.value + '<br>占比:' + params.percent + '%'
} }
}, },
grid: { grid: {
left: 0, left: 0,
right: 0, right: 0,
bottom: 0, bottom: 0,
top: 0, top: 0,
containLabel: true, containLabel: true,
}, },
series: [{ series: [{
type: 'pie', type: 'pie',
center: ['50%', '50%'], center: ['50%', '50%'],
radius: ['0%', '60%'], radius: ['0%', '60%'],
clockwise: true, clockwise: true,
label: { label: {
show: true, show: true,
position: 'outter', position: 'outter',
color: 'inherit', color: 'inherit',
overflow: 'break', overflow: 'break',
formatter: function (params: any) { formatter: function (params: any) {
return params.name + params.percent + '%' return params.name + params.percent + '%'
} }
}, },
labelLine: { labelLine: {
show: false, show: false,
length: 3, length: 3,
length2: 0, length2: 0,
smooth: true, smooth: true,
}, },
data: chartData.data data: chartData.data
}], }],
}; };
chart.setOption(option); chart.setOption(option);
chart.resize();
window.addEventListener('resize', () => {
chart.resize(); chart.resize();
window.addEventListener('resize', () => { });
chart.resize();
});
} }
const getData = (date: any) => { const getData = (date: any) => {
currentMonth.value = new Date(date) currentMonth.value = new Date(date)
upMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() - 1, 1) upMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() - 1, 1)
downMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 1) downMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 1)
const types = ['心脏病手术', '骨科手术', '阑尾炎手术'] const color: any = []
const color = ['#ffde69', '#f8b300', '#006080'] pieData.value = []
pieData.value = []
types.forEach((item: string, index: number) => { const start = dateFormater("yyyy-MM-dd", new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth(), 1))
pieData.value.push({value: Math.ceil(Math.random() * 10), name: item, itemStyle: { const end = dateFormater("yyyy-MM-dd", new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 0))
color: color[index] medicineApi.getSurgeryTypeProportion(start, end).then(res => {
}}) if (res.code == 0) {
}) res.data.forEach((item: any, i: number) => {
initChart({ data: pieData.value, color }) const c = generateRandomColor()
color.push(c)
pieData.value.push({
value: item.count,
name: item._id,
itemStyle: {
color: c
}
})
})
}
initChart({data: pieData.value, color})
});
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.chart-box { .chart-box {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.date-btn {
position: absolute;
height: 50px;
top: 0;
left: 20px;
right: 20px;
display: flex; display: flex;
justify-content: space-between; z-index: 1;
align-items: center;
.date-btn { .btn-box {
position: absolute; height: 30px;
height: 50px; display: flex;
top: 0; align-items: center;
left: 20px; color: $text2-color;
right: 20px;
display: flex;
z-index: 1;
.btn-box { & > :deep(.el-date-editor) {
height: 30px;
display: flex;
align-items: center;
color: $text2-color;
&>:deep(.el-date-editor) {
font-size: 14px;
.el-input__wrapper {
box-shadow: none;
padding: 0;
.el-input__prefix,
.el-input__suffix {
display: none;
}
.el-input__inner {
cursor: pointer;
width: 100px;
color: $text2-color;
text-align: center;
}
}
}
.el-icon {
cursor: pointer;
}
}
}
.chart-dom {
width: 70%;
height: 100%;
margin-left: 30%;
}
.total-box {
position: absolute;
width: 30%;
top: 30px;
left: 20px;
bottom: 0;
color: $text2-color;
font-size: 14px; font-size: 14px;
display: flex;
flex-direction: column; .el-input__wrapper {
justify-content: center; box-shadow: none;
.total-item { padding: 0;
padding: 5px 0;
.el-input__prefix,
.el-input__suffix {
display: none;
}
.el-input__inner {
cursor: pointer;
width: 100px;
color: $text2-color;
text-align: center;
}
} }
}
.el-icon {
cursor: pointer;
}
} }
}
.chart-dom {
width: 70%;
height: 100%;
margin-left: 30%;
}
.total-box {
position: absolute;
width: 30%;
top: 30px;
left: 20px;
bottom: 0;
color: $text2-color;
font-size: 14px;
display: flex;
flex-direction: column;
justify-content: center;
.total-item {
padding: 5px 0;
}
}
}</style> }</style>

View File

@ -1,200 +1,211 @@
<template> <template>
<div class="chart-box"> <div class="chart-box">
<div class="date-btn text-color"> <div class="date-btn text-color">
<div class="btn-box"> <div class="btn-box">
<el-icon @click="setDate('up')"> <el-icon @click="setDate('up')">
<ArrowLeft /> <ArrowLeft/>
</el-icon> </el-icon>
<el-date-picker v-model="currentMonth" format="第ww周" type="week" :editable="false" :clearable="false" <el-date-picker v-model="currentMonth" format="第ww周" type="week" :editable="false" :clearable="false"
@change="getData" /> @change="getData"/>
<el-icon @click="setDate('down')"> <el-icon @click="setDate('down')">
<ArrowRight /> <ArrowRight/>
</el-icon> </el-icon>
</div> </div>
</div>
<div ref="chartDom" class="chart-dom"></div>
</div> </div>
<div ref="chartDom" class="chart-dom"></div>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, ref} from 'vue'
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { dateFormater, getFirstDayOfWeek, getCurrentDate, getDays } from '@/utils/date-util'; import {dateFormater, getCurrentDate, getDays, getFirstDayOfWeek, getWeekDates} from '@/utils/date-util';
import * as medicineApi from "@/api/medicine";
const chartDom = ref() const chartDom = ref()
const currentMonth = ref(new Date()) const currentMonth = ref(new Date())
onMounted(() => { onMounted(() => {
getData(new Date()) getData(new Date())
}) })
// true // true
function calcTime(time: any) { function calcTime(time: any) {
return Boolean(new Date().getTime() < new Date(time).getTime()) return Boolean(new Date().getTime() < new Date(time).getTime())
} }
function initChart(chartData: any) { function initChart(chartData: any) {
const chart = echarts.init(chartDom.value as HTMLElement); const chart = echarts.init(chartDom.value as HTMLElement);
chart.clear(); chart.clear();
const option = { const option = {
color: ['#006080', '#f8b300'], color: ['#006080', '#f8b300'],
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
type: 'shadow' type: 'shadow'
}, },
formatter: (params: any) => { formatter: (params: any) => {
let str = dateFormater('yyyy-MM-dd', params[0].axisValue) + '<b style="padding: 0 10px;">' + getCurrentDate(params[0].axisValue) + '</b>' let str = dateFormater('yyyy-MM-dd', params[0].axisValue) + '<b style="padding: 0 10px;">' + getCurrentDate(params[0].axisValue) + '</b>'
params.forEach((item: any) => { params.forEach((item: any) => {
str += '<br>' str += '<br>'
str += item.marker + item.seriesName + '' + item.value + '小时' str += item.marker + item.seriesName + '' + item.value + '小时'
}) })
return str return str
} }
},
legend: {
right: 0,
data: chartData.dataName
},
grid: {
left: 20,
right: 50,
bottom: 5,
top: 50,
containLabel: true,
},
xAxis: {
name: '日期',
show: true,
type: 'category',
nameTextStyle: {color: '#909399'},
axisLine: {show: true, lineStyle: {color: '#006080', width: 2}},
axisTick: {show: false},
axisLabel: {show: true, color: '#909399', formatter: (value: any) => getCurrentDate(value)},
splitLine: {show: true, lineStyle: {color: 'rgba(212, 130, 1, .05)', width: 1, type: 'solid'}},
data: chartData.xData,
},
yAxis: {
name: '时间',
show: true,
type: 'value',
min: 0,
nameTextStyle: {color: '#909399', align: 'center', verticalAlign: 'top', padding: [0, 0]},
axisLine: {show: true, lineStyle: {color: '#006080', width: 2}},
axisTick: {show: false},
axisLabel: {show: false},
splitLine: {show: false, lineStyle: {color: '#D4E8F0', width: 1, type: 'solid'}},
},
series: [{
name: chartData.dataName[0],
type: 'bar',
label: {
show: true,
rotate: -90,
align: 'left',
verticalAlign: 'center',
position: 'insideTop',
color: '#ffffff',
textBorderColor: '#006080',
textBorderWidth: 3,
formatter: (params: any) => params.value.toFixed(0) + 'h' + Number((params.value % 1).toFixed(1)) * 60 + 'm'
},
data: chartData.data[0]
},
{
name: chartData.dataName[1],
type: 'bar',
label: {
show: true,
rotate: -90,
align: 'left',
verticalAlign: 'center',
position: 'insideTop',
color: '#ffffff',
textBorderColor: '#f8b300',
textBorderWidth: 3,
formatter: (params: any) => params.value.toFixed(0) + 'h' + Number((params.value % 1).toFixed(1)) * 60 + 'm'
}, },
legend: { data: chartData.data[1]
right: 0, }],
data: chartData.dataName };
}, chart.setOption(option);
grid: { chart.resize();
left: 20, window.addEventListener('resize', () => {
right: 50,
bottom: 5,
top: 50,
containLabel: true,
},
xAxis: {
name: '日期',
show: true,
type: 'category',
nameTextStyle: { color: '#909399' },
axisLine: { show: true, lineStyle: { color: '#006080', width: 2 } },
axisTick: { show: false },
axisLabel: { show: true, color: '#909399', formatter: (value: any) => getCurrentDate(value) },
splitLine: { show: true, lineStyle: { color: 'rgba(212, 130, 1, .05)', width: 1, type: 'solid' } },
data: chartData.xData,
},
yAxis: {
name: '时间',
show: true,
type: 'value',
min: 0,
nameTextStyle: { color: '#909399', align: 'center', verticalAlign: 'top', padding: [0, 0] },
axisLine: { show: true, lineStyle: { color: '#006080', width: 2 } },
axisTick: { show: false },
axisLabel: { show: false },
splitLine: { show: false, lineStyle: { color: '#D4E8F0', width: 1, type: 'solid' } },
},
series: [{
name: chartData.dataName[0],
type: 'bar',
label: {
show: true,
rotate: -90,
align: 'left',
verticalAlign: 'center',
position: 'insideTop',
color: '#ffffff',
textBorderColor: '#006080',
textBorderWidth: 3,
formatter: (params: any) => params.value.toFixed(0) + 'h' + Number((params.value % 1).toFixed(1)) * 60 + 'm'
},
data: chartData.data[0]
},
{
name: chartData.dataName[1],
type: 'bar',
label: {
show: true,
rotate: -90,
align: 'left',
verticalAlign: 'center',
position: 'insideTop',
color: '#ffffff',
textBorderColor: '#f8b300',
textBorderWidth: 3,
formatter: (params: any) => params.value.toFixed(0) + 'h' + Number((params.value % 1).toFixed(1)) * 60 + 'm'
},
data: chartData.data[1]
}],
};
chart.setOption(option);
chart.resize(); chart.resize();
window.addEventListener('resize', () => { });
chart.resize();
});
} }
const setDate = (type: string) => { const setDate = (type: string) => {
getData(getDays(currentMonth.value, type === 'up' ? -7 : 7)) getData(getDays(currentMonth.value, type === 'up' ? -7 : 7))
} }
const getData = (date: any) => { const getData = (date: any) => {
currentMonth.value = new Date(date) currentMonth.value = new Date(date)
const dataName = ['麻醉给药时长', '人工给药时长'] const dataName = ['麻醉给药时长', '人工给药时长']
const xData = [] const xData: any = []
const data = [[], []] as any const data = [[], []] as any
for (let i = 1; i < 8; i++) {
xData.push(getFirstDayOfWeek(date, i)) const weekDates = getWeekDates(currentMonth.value)
data[0].push(Number((Math.random() * 16 + 2).toFixed(1))) const start = dateFormater("yyyy-MM-dd", weekDates.start)
data[1].push(Number((Math.random() * 16 + 2).toFixed(1))) const end = dateFormater("yyyy-MM-dd", weekDates.end.setDate(weekDates.end.getDate() + 1))
medicineApi.getSurgeryOtherDuration(start, end).then(res => {
if (res.code == 0) {
res.data.forEach((item: any) => {
xData.push(new Date(item._id))
data[0].push(item.aicount)
data[1].push(item.doccount)
})
} }
initChart({ dataName, xData, data }) initChart({dataName, xData, data})
})
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.chart-box { .chart-box {
position: relative; position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.date-btn {
position: absolute;
width: 150px;
height: 50px;
top: 0;
left: 20px;
display: flex;
z-index: 1;
.btn-box {
height: 30px;
display: flex;
align-items: center;
color: $text2-color;
& > :deep(.el-date-editor) {
font-size: 14px;
.el-input__wrapper {
box-shadow: none;
padding: 0;
.el-input__prefix,
.el-input__suffix {
display: none;
}
.el-input__inner {
cursor: pointer;
width: 100px;
color: $text2-color;
text-align: center;
}
}
}
.el-icon {
cursor: pointer;
}
}
}
.chart-dom {
// width: calc(100% - 180px);
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; }
justify-content: space-between;
align-items: center;
.date-btn {
position: absolute;
width: 150px;
height: 50px;
top: 0;
left: 20px;
display: flex;
z-index: 1;
.btn-box {
height: 30px;
display: flex;
align-items: center;
color: $text2-color;
&>:deep(.el-date-editor) {
font-size: 14px;
.el-input__wrapper {
box-shadow: none;
padding: 0;
.el-input__prefix,
.el-input__suffix {
display: none;
}
.el-input__inner {
cursor: pointer;
width: 100px;
color: $text2-color;
text-align: center;
}
}
}
.el-icon {
cursor: pointer;
}
}
}
.chart-dom {
// width: calc(100% - 180px);
width: 100%;
height: 100%;
}
}</style> }</style>

View File

@ -1,25 +1,27 @@
<template> <template>
<div class="chart-box"> <div class="chart-box">
<div class="date-btn text-color"> <div class="date-btn text-color">
<div class="btn-box"> <div class="btn-box">
<el-icon @click="getData(upMonth)"> <el-icon @click="getData(upMonth)">
<ArrowLeft /> <ArrowLeft/>
</el-icon> </el-icon>
<el-date-picker v-model="currentMonth" format="YYYY年MM月" type="month" :editable="false" :clearable="false" @change="getData" /> <el-date-picker v-model="currentMonth" format="YYYY年MM月" type="month" :editable="false" :clearable="false"
<el-icon @click="getData(downMonth)"> @change="getData"/>
<ArrowRight /> <el-icon @click="getData(downMonth)">
</el-icon> <ArrowRight/>
</div> </el-icon>
</div> </div>
<div ref="chartDom" class="chart-dom"></div>
<div class="total-mini">本月共计{{ total.toFixed(0) }}小时{{ Number((total % 1).toFixed(1)) * 60 }}分钟</div>
</div> </div>
<div ref="chartDom" class="chart-dom"></div>
<div class="total-mini">本月共计{{ total.toFixed(0) }}小时{{ Number((total % 1).toFixed(1)) * 60 }}分钟</div>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, ref} from 'vue'
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { dateFormater, getMonthDays } from '@/utils/date-util'; import {dateFormater, getMonthDays} from '@/utils/date-util';
import * as medicineApi from '@/api/medicine';
const chartDom = ref() const chartDom = ref()
@ -29,160 +31,169 @@ const downMonth = ref()
const total = ref(0) const total = ref(0)
onMounted(() => { onMounted(() => {
getData(new Date()) getData(new Date())
}) })
function initChart(chartData: any) { function initChart(chartData: any) {
const chart = echarts.init(chartDom.value as HTMLElement); const chart = echarts.init(chartDom.value as HTMLElement);
chart.clear(); chart.clear();
const option = { const option = {
color: [], color: [],
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
formatter: (params: any) => { formatter: (params: any) => {
return dateFormater('yyyy年MM月', currentMonth.value) + params[0].axisValue + '<br>手术时长 <b>' + params[0].value + '</b> h' return dateFormater('yyyy年MM月', currentMonth.value) + params[0].axisValue + '<br>手术时长 <b>' + params[0].value + '</b> h'
} }
}, },
grid: { grid: {
left: 20, left: 20,
right: 50, right: 50,
bottom: 5, bottom: 5,
top: 50, top: 50,
containLabel: true, containLabel: true,
}, },
xAxis: { xAxis: {
name: '日期', name: '日期',
show: true, show: true,
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
nameTextStyle: { color: '#909399' }, nameTextStyle: {color: '#909399'},
axisLine: { show: true, lineStyle: { color: '#D58301', width: 2 } }, axisLine: {show: true, lineStyle: {color: '#D58301', width: 2}},
axisTick: { show: false }, axisTick: {show: false},
axisLabel: { show: true, interval: chartData.xData.length - 2 }, axisLabel: {show: true, interval: chartData.xData.length - 2},
splitLine: { show: true, lineStyle: { color: 'rgba(212, 130, 1, .05)', width: 1, type: 'solid' } }, splitLine: {show: true, lineStyle: {color: 'rgba(212, 130, 1, .05)', width: 1, type: 'solid'}},
data: chartData.xData, data: chartData.xData,
}, },
yAxis: { yAxis: {
name: '时间', name: '时间',
show: true, show: true,
type: 'value', type: 'value',
min: 0, min: 0,
nameTextStyle: { color: '#909399', align: 'center', verticalAlign: 'top', padding: [0, 0] }, nameTextStyle: {color: '#909399', align: 'center', verticalAlign: 'top', padding: [0, 0]},
axisLine: { show: true, lineStyle: { color: '#D58301', width: 2 } }, axisLine: {show: true, lineStyle: {color: '#D58301', width: 2}},
axisTick: { show: false }, axisTick: {show: false},
axisLabel: { show: false }, axisLabel: {show: false},
splitLine: { show: false, lineStyle: { color: '#D4E8F0', width: 1, type: 'solid' } }, splitLine: {show: false, lineStyle: {color: '#D4E8F0', width: 1, type: 'solid'}},
}, },
series: [{ series: [{
type: 'line', type: 'line',
symbol: 'none', symbol: 'none',
smooth: true, smooth: true,
showSymbol: false, showSymbol: false,
lineStyle: { lineStyle: {
color: 'rgb(212, 130, 1)', color: 'rgb(212, 130, 1)',
width: 2, width: 2,
shadowColor: 'rgba(212, 130, 1, .3)', shadowColor: 'rgba(212, 130, 1, .3)',
shadowBlur: 10, shadowBlur: 10,
shadowOffsetY: 20 shadowOffsetY: 20
}, },
areaStyle: { areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0, offset: 0,
color: 'rgba(212, 130, 1, 1)' color: 'rgba(212, 130, 1, 1)'
}, { }, {
offset: 0.8, offset: 0.8,
color: 'rgba(255, 255, 255, 0.1)' color: 'rgba(255, 255, 255, 0.1)'
}], false) }], false)
}, },
data: chartData.data data: chartData.data
}], }],
}; };
chart.setOption(option); chart.setOption(option);
chart.resize();
window.addEventListener('resize', () => {
chart.resize(); chart.resize();
window.addEventListener('resize', () => { });
chart.resize();
});
} }
const getData = (date: any) => { const getData = (date: any) => {
currentMonth.value = new Date(date) currentMonth.value = new Date(date)
upMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() - 1, 1) upMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() - 1, 1)
downMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 1) downMonth.value = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 1)
const days = getMonthDays(currentMonth.value)
const xData = [] const start = dateFormater("yyyy-MM-dd", new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth(), 1))
const data = [] const end = dateFormater("yyyy-MM-dd", new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 0))
medicineApi.getSurgeryDuration(start, end).then(res => {
const xData: any = []
const data: any = []
let num = 0 let num = 0
for (let i = 0; i < days; i++) { if (res.code == 0) {
xData.push((i < 9 ? '0' : '') + (i + 1)) res.data.forEach((item: any) => {
data.push(Number((Math.random() * 16 + 2).toFixed(1))) xData.push(item._id)
num += data[i] data.push(item.duration)
num += item.duration
})
} }
total.value = Number(num.toFixed(1)) total.value = Number(num.toFixed(1))
initChart({ xData, data }) initChart({xData, data})
})
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.chart-box { .chart-box {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.date-btn {
position: absolute;
height: 50px;
top: 0;
left: 20px;
right: 230px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; z-index: 1;
.date-btn { .btn-box {
position: absolute; height: 30px;
height: 50px; display: flex;
top: 0; align-items: center;
left: 20px; color: $text2-color;
right: 230px;
display: flex;
justify-content: space-between;
z-index: 1;
.btn-box { & > :deep(.el-date-editor) {
height: 30px;
display: flex;
align-items: center;
color: $text2-color;
&>:deep(.el-date-editor) {
font-size: 14px;
.el-input__wrapper {
box-shadow: none;
padding: 0;
.el-input__prefix,
.el-input__suffix {
display: none;
}
.el-input__inner {
cursor: pointer;
width: 100px;
color: $text2-color;
text-align: center;
}
}
}
.el-icon {
cursor: pointer;
}
}
}
.chart-dom {
width: 100%;
height: 100%;
}
.total-mini {
position: absolute;
top: 0;
right: 40px;
color: #D58301;
border: 1px solid #D58301;
font-size: 14px; font-size: 14px;
padding: 3px 8px;
.el-input__wrapper {
box-shadow: none;
padding: 0;
.el-input__prefix,
.el-input__suffix {
display: none;
}
.el-input__inner {
cursor: pointer;
width: 100px;
color: $text2-color;
text-align: center;
}
}
}
.el-icon {
cursor: pointer;
}
} }
}
.chart-dom {
width: 100%;
height: 100%;
}
.total-mini {
position: absolute;
top: 0;
right: 40px;
color: #D58301;
border: 1px solid #D58301;
font-size: 14px;
padding: 3px 8px;
}
}</style> }</style>

View File

@ -7,23 +7,22 @@
<ul class="menu-box"> <ul class="menu-box">
<li class="menu-item" v-for="item in menus" :key="item.path" <li class="menu-item" v-for="item in menus" :key="item.path"
:class="{ 'active': menuActive.indexOf(item.path) === 0 }" :class="{ 'active': menuActive.indexOf(item.path) === 0 }"
@click="menuToPath(item)"><i :class="item.icon"></i><span>{{ @click="menuToPath(item)"><i :class="item.meta.icon"></i><span>{{
item.label item.name
}}</span></li> }}</span></li>
</ul> </ul>
<div class="user-box"> <div class="user-box">
<!-- 超级管理员可切换医院 --> <!-- 超级管理员可切换医院 -->
<el-select v-if="userInfo.permissions === '超级管理员'" class="select-hospital" style="width: 150px;" <el-select class="select-hospital" style="width: 150px;"
:model-value="userInfo.hospital" size="small" @change="selectHospital"> v-model="hospital" size="small" @change="selectHospital">
<el-option v-for="item in hospitals" :key="item.value" :label="item.label" :value="item.value"/> <el-option v-for="item in hospitals" :key="item.id" :label="item.name" :value="item.id"/>
</el-select> </el-select>
<span v-else class="area">{{ userInfo.hospital }}</span> <!-- <el-button text>
<el-button text> <el-icon>
<el-icon> <Search/>
<Search/> </el-icon>
</el-icon> </el-button>-->
</el-button> <el-button text @click="userStore.showHomeMsg=true">
<el-button text>
<el-badge is-dot> <el-badge is-dot>
<el-icon> <el-icon>
<Bell/> <Bell/>
@ -36,12 +35,12 @@
</el-icon> </el-icon>
</el-button> </el-button>
<el-dropdown trigger="click" @command="userCommand"> <el-dropdown trigger="click" @command="userCommand">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
{{ userInfo.name }} {{ userInfo.name }}
<el-icon class="el-icon--right"> <el-icon class="el-icon--right">
<arrow-down/> <arrow-down/>
</el-icon> </el-icon>
</span> </span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="info">个人信息</el-dropdown-item> <el-dropdown-item command="info">个人信息</el-dropdown-item>
@ -61,59 +60,22 @@
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import {onMounted, reactive, ref, toRefs, watch} from 'vue' import {onMounted, ref} from 'vue'
import {useRouter, useRoute} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {ElMessage, ElMessageBox} from 'element-plus' import {ElMessage, ElMessageBox} from 'element-plus'
import {useLoginStore} from '@/stores/user-info-store' import {useUserStore} from '@/stores/user-info-store'
import {getHospitalsData} from '@/static-data/core'
import userInfoForm from '@/components/user-info.vue' import userInfoForm from '@/components/user-info.vue'
import {Session} from "@/utils/storage";
import {logout} from "@/api/login"; import {logout} from "@/api/login";
import * as hospitalApi from "@/api/hospital";
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const userStore = useUserStore();
const userInfo = useLoginStore().getlogin() const userInfo = userStore.getlogin()
const hospital = ref("");
const preHospital = ref("");
const hospitals = ref([] as any) const hospitals = ref([] as any)
getHospitalsData().then((res: any) => { const menus = ref([] as any)
hospitals.value = res
})
const menus = [] as any
switch (userInfo.permissions) {
case '超级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '权限管理', path: '/permissions-manage', icon: 'icon-users'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
menus.push({label: '后台管理', path: '/system-manage', icon: 'icon-houtaiguanli'})
menus.push({label: '系统管理', path: '/logs-manage', icon: 'icon-setting'})
break;
case '高级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '权限管理', path: '/permissions-manage', icon: 'icon-users'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
menus.push({label: '系统管理', path: '/logs-manage', icon: 'icon-setting'})
break;
case '中级管理员':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
break;
case '普通用户':
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
break;
default:
menus.push({label: '首页', path: '/home', icon: 'icon-shouye'})
menus.push({label: '权限管理', path: '/permissions-manage', icon: 'icon-users'})
menus.push({label: '患者管理', path: '/patients-manage', icon: 'icon-renyuanguanli'})
menus.push({label: '远程管理', path: '/remote-manage', icon: 'icon-anquanbaozhang'})
menus.push({label: '后台管理', path: '/system-manage', icon: 'icon-houtaiguanli'})
menus.push({label: '系统管理', path: '/logs-manage', icon: 'icon-setting'})
}
const isShowUserInfoDrawer = ref(false) const isShowUserInfoDrawer = ref(false)
const menuActive = ref('/') const menuActive = ref('/')
@ -126,18 +88,45 @@ router.beforeEach((to, from, next) => {
}); });
onMounted(() => { onMounted(() => {
init();
}) })
function init() {
getHospitalList();
handleMenu();
}
function handleMenu() {
useUserStore().getMenuPathList().then((res: any) => {
menus.value = res.menus;
});
}
const menuToPath = (e: any) => { const menuToPath = (e: any) => {
menuActive.value = e.path menuActive.value = e.path
router.push(e.path) router.push(e.path)
} }
async function getHospitalList() {
const data: any = await hospitalApi.getCurrentHospital();
hospitalApi.getMyHospitalList().then((res: any) => {
hospitals.value = [];
if (res.code == 0 && res.data.length > 0) {
hospitals.value = res.data;
if (data.data) {
hospital.value = data.data;
}
preHospital.value = hospital.value
}
})
}
// //
const selectHospital = (e: any) => { const selectHospital = (e: any) => {
if (hospitals.value.length == 0) return;
// //
ElMessageBox.confirm( ElMessageBox.confirm(
'是否跳转到登录页面登录到所选择医院?', '是否跳转到所选择医院?',
{ {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
@ -145,9 +134,16 @@ const selectHospital = (e: any) => {
draggable: true draggable: true
} }
).then(() => { ).then(() => {
// useLoginStore().setlogin('hospital', e) hospitalApi.changeHospital(hospital.value).then((res: any) => {
router.push('/login') if (res.code == 0) {
window.location.reload();
} else {
hospital.value = preHospital.value;
ElMessage.error("切换失败")
}
})
}).catch(() => { }).catch(() => {
hospital.value = preHospital.value;
}) })
} }
const toggleFullscreen = () => { const toggleFullscreen = () => {
@ -157,13 +153,13 @@ const toggleFullscreen = () => {
document.documentElement.requestFullscreen(); document.documentElement.requestFullscreen();
} }
} }
const userCommand = async (e: string) => { const userCommand = async (e: string) => {
switch (e) { switch (e) {
case 'logout': case 'logout':
// useLoginStore().logout()
await logout() await logout()
Session.clear(); useUserStore().logout();
window.location.reload(); window.location.replace("/");
break; break;
case 'info': case 'info':
isShowUserInfoDrawer.value = true isShowUserInfoDrawer.value = true

View File

@ -8,120 +8,120 @@
</el-select> </el-select>
</div> </div>
<img v-show="!isShowRegister" class="logo move_2" src="@/assets/imgs/logo.png"> <img v-show="!isShowRegister" class="logo move_2" src="@/assets/imgs/logo.png">
<div v-if="!isShowRegister" class="login-block move_2"> <div v-if="!isShowRegister" class="login-block move_2">
<div class="login-way"> <div class="login-way">
<span :class="passwordLogin && 'active'" @click="passwordLogin = true">密码登录</span> <span :class="passwordLogin && 'active'" @click="passwordLogin = true">密码登录</span>
<span :class="!passwordLogin && 'active'" @click="passwordLogin = false">验证码登录</span> <span :class="!passwordLogin && 'active'" @click="passwordLogin = false">验证码登录</span>
</div> </div>
<el-form ref="loginFormRef" :model="loginParams" :rules="loginRules" label-width="0" size="small"> <el-form ref="loginFormRef" :model="loginParams" :rules="loginRules" label-width="0" size="small">
<div class="login-form password-login" v-if="passwordLogin"> <div class="login-form password-login" v-if="passwordLogin">
<el-form-item prop="account"> <el-form-item prop="account">
<el-input v-model="loginParams.account" placeholder="请输入用户名"> <el-input v-model="loginParams.account" placeholder="请输入用户名">
<template #prepend> <template #prepend>
<el-icon> <el-icon>
<User/> <User/>
</el-icon> </el-icon>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="password"> <el-form-item prop="password">
<el-input v-model="loginParams.password" type="password" show-password placeholder="请输入密码"> <el-input v-model="loginParams.password" type="password" show-password placeholder="请输入密码">
<template #prepend> <template #prepend>
<el-icon> <el-icon>
<Lock/> <Lock/>
</el-icon> </el-icon>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-button :loading="loading" class="login-btn" type="primary" @click="login('password')">登录</el-button> <el-button :loading="loading" class="login-btn" type="primary" @click="login('password')">登录</el-button>
<span class="register-btn" @click="getCaptchaCode()">注册账号</span> <span class="register-btn" @click="getCaptchaCode()">注册账号</span>
</div> </div>
<div class="login-form code-login" v-else> <div class="login-form code-login" v-else>
<el-form-item prop="phone"> <el-form-item prop="phone">
<el-input v-model="loginParams.phone" placeholder="请输入手机号"> <el-input v-model="loginParams.phone" placeholder="请输入手机号">
<template #prepend> <template #prepend>
<div @click.stop style="display: flex;align-items: center;"> <div @click.stop style="display: flex;align-items: center;">
<el-dropdown @command="selectPhoneArea"> <el-dropdown @command="selectPhoneArea">
<span style="color: #909399;">{{ loginParams.phoneArea }}<el-icon> <span style="color: #909399;">{{ loginParams.phoneArea }}<el-icon>
<DCaret/> <DCaret/>
</el-icon></span> </el-icon></span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item v-for="item in phoneAreas" :command="item">{{ <el-dropdown-item v-for="item in phoneAreas" :command="item">{{
item item
}} }}
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
</div> </div>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="code"> <el-form-item prop="code">
<el-input v-model="loginParams.code" placeholder="请输入6位短信验证码"> <el-input v-model="loginParams.code" placeholder="请输入6位短信验证码">
<template #append> <template #append>
<span class="send-btn" @click="sendCode">{{ loginParams.sendText }}</span> <span class="send-btn" @click="sendCode">{{ loginParams.sendText }}</span>
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-button class="login-btn" type="primary" @click="login('code')">登录</el-button> <el-button class="login-btn" type="primary" @click="login('code')">登录</el-button>
</div> </div>
</el-form> </el-form>
</div> </div>
<div v-else class="register-block move_2"> <div v-else class="register-block move_2">
<div class="header-box"> <div class="header-box">
<span class="title">新用户申请</span> <span class="title">新用户申请</span>
<el-icon @click="isShowRegister = false"> <el-icon @click="isShowRegister = false">
<Close/> <Close/>
</el-icon> </el-icon>
</div> </div>
<el-form ref="registerFormRef" :model="registerParams" :rules="registerRules" label-width="100"> <el-form ref="registerFormRef" :model="registerParams" :rules="registerRules" label-width="100">
<el-form-item label="用户名" prop="username"> <el-form-item label="用户名" prop="username">
<el-input v-model="registerParams.username" placeholder="请输入用户名"></el-input> <el-input v-model="registerParams.username" placeholder="请输入用户名"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="密码" prop="password"> <el-form-item label="密码" prop="password">
<el-input v-model="registerParams.password" type="password" show-password <el-input v-model="registerParams.password" type="password" show-password
placeholder="请输入密码"></el-input> placeholder="请输入密码"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="姓名" prop="name"> <el-form-item label="姓名" prop="name">
<el-input v-model="registerParams.name" placeholder="请输入姓名"></el-input> <el-input v-model="registerParams.name" placeholder="请输入姓名"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="手机号" prop="phone"> <el-form-item label="手机号" prop="phone">
<el-input v-model="registerParams.phone" placeholder="请输入手机号"></el-input> <el-input v-model="registerParams.phone" placeholder="请输入手机号"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="医院" prop="hospital"> <el-form-item label="医院" prop="hospital">
<el-select v-model="registerParams.hospital" style="width: 100%;"> <el-select v-model="registerParams.hospital" style="width: 100%;">
<el-option v-for="item in hospitals" :key="item.id" :label="item.name" <el-option v-for="item in hospitals" :key="item.id" :label="item.name"
:value="item.id"/> :value="item.id"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="性别" prop="sex"> <el-form-item label="性别" prop="sex">
<el-radio-group v-model="registerParams.sex"> <el-radio-group v-model="registerParams.sex">
<el-radio label="男"/> <el-radio label="男"/>
<el-radio label="女"/> <el-radio label="女"/>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="验证码" prop="code"> <el-form-item label="验证码" prop="code">
<el-input v-model="registerParams.code" placeholder="请输入验证码" <el-input v-model="registerParams.code" placeholder="请输入验证码"
style="width: calc(100% - 110px);"></el-input> style="width: calc(100% - 110px);"></el-input>
<img width="100" height="32" style="margin-left: 10px;" :src="captchaImgUrl"/> <img width="100" height="32" style="margin-left: 10px;" :src="captchaImgUrl"/>
<a class="change_img" @click="refreshImg" href="#">看不清</a> <a class="change_img" @click="refreshImg" href="#">看不清</a>
</el-form-item> </el-form-item>
</el-form> </el-form>
<div class="footer-box"> <div class="footer-box">
<el-button type="primary" @click="register"> </el-button> <el-button type="primary" @click="register"> </el-button>
<span @click="isShowRegister = false">已有账号?</span> <span @click="isShowRegister = false">已有账号?</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<SliderVerify v-model:isShowSelf="sliderVConf.isShowSelf" :width="sliderVConf.width" :imgUrl="sliderImgUrl" <SliderVerify v-model:isShowSelf="sliderVConf.isShowSelf" :width="sliderVConf.width" :imgUrl="sliderImgUrl"
:height="sliderVConf.height" @success="sliderSuccess" @close="sliderClose"></SliderVerify> :height="sliderVConf.height" @success="sliderSuccess" @close="sliderClose"></SliderVerify>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
@ -130,7 +130,7 @@ import {ElMessage, ElMessageBox, ElNotification} from 'element-plus';
import {getTime} from '@/utils/time'; import {getTime} from '@/utils/time';
import {onMounted, reactive, ref} from 'vue' import {onMounted, reactive, ref} from 'vue'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {useLoginStore} from '@/stores/user-info-store' import {useUserStore} from '@/stores/user-info-store'
import {getPhoneAreasData} from '@/static-data/core' import {getPhoneAreasData} from '@/static-data/core'
import {v4} from "uuid"; import {v4} from "uuid";
import SliderVerify from "@/components/SliderVerify/index.vue"; import SliderVerify from "@/components/SliderVerify/index.vue";
@ -144,40 +144,32 @@ import * as hospitalApi from "@/api/hospital";
//let useStore = useUserStore(); //let useStore = useUserStore();
const router = useRouter() const router = useRouter()
const hospitals = ref([] as any)
const hospitals = ref([])
const phoneAreas: any = getPhoneAreasData() const phoneAreas: any = getPhoneAreasData()
// //
let loading = ref(false); let loading = ref(false);
// //
const validatorPhone = (rule: any, value: any, callback: any) => { const validatorPhone = (rule: any, value: any, callback: any) => {
var isPhone = /^1[34578]\d{9}$/; var isPhone = /^1[34578]\d{9}$/;
if (value.indexOf('****') >= 0) { if (value.indexOf('****') >= 0) {
return callback().trim(); return callback().trim();
} }
if (!isPhone.test(value)) { if (!isPhone.test(value)) {
callback(new Error('请输入合法手机号')); callback(new Error('请输入合法手机号'));
} else { } else {
callback(); callback();
} }
} }
const loginRules = reactive({ const loginRules = reactive({
account: [ account: [
{required: true,message: '请输入用户名', trigger: 'change'}, {required: true, message: '请输入用户名', trigger: 'change'},
{ min: 2, max: 18, message: "长度在 6 到 18个字符" }, {min: 2, max: 18, message: "长度在 6 到 18个字符"},
//{pattern:/^(?![^A-Za-z]+$)(?![^0-9]+$)[0-9A-Za-z_]{4,15}$/, message: '4-15线'} //{pattern:/^(?![^A-Za-z]+$)(?![^0-9]+$)[0-9A-Za-z_]{4,15}$/, message: '4-15线'}
], ],
password: [ password: [
{required: true, message: '请输入密码', trigger: 'blur'}, {required: true, message: '请输入密码', trigger: 'blur'},
{ min: 5,max: 25,message: '长度在 5 到 25个字符'}, {min: 5, max: 25, message: '长度在 5 到 25个字符'},
{pattern: /^(\w){5,25}$/, message: '长度在5-25之间以字母、数字、下划线'} {pattern: /^(\w){5,25}$/, message: '长度在5-25之间以字母、数字、下划线'}
], ],
phone: [ phone: [
@ -190,17 +182,17 @@ const loginRules = reactive({
const registerRules = reactive({ const registerRules = reactive({
username: [ username: [
{required: true, message: '请输入用户名', trigger: 'change'}, {required: true, message: '请输入用户名', trigger: 'change'},
{ min: 2, max: 18, message: "长度在 6 到 18个字符" }, {min: 2, max: 18, message: "长度在 6 到 18个字符"},
//{pattern:/^(?![^A-Za-z]+$)(?![^0-9]+$)[0-9A-Za-z_]{4,15}$/, message: '4-15线'} //{pattern:/^(?![^A-Za-z]+$)(?![^0-9]+$)[0-9A-Za-z_]{4,15}$/, message: '4-15线'}
], ],
password: [ password: [
{required: true, message: '请输入密码', trigger: 'blur'}, {required: true, message: '请输入密码', trigger: 'blur'},
{ min: 5,max: 25,message: '长度在 5 到 25个字符'}, {min: 5, max: 25, message: '长度在 5 到 25个字符'},
{pattern: /^(\w){5,25}$/, message: '长度在5-25之间以字母、数字、下划线'} {pattern: /^(\w){5,25}$/, message: '长度在5-25之间以字母、数字、下划线'}
], ],
name: [ name: [
{required: true, message: '请输入真实姓名', trigger: 'blur'}, {required: true, message: '请输入真实姓名', trigger: 'blur'},
{pattern:/^[\u4E00-\u9FA5]{2,6}$/, message: '请输入2-6个汉字'} {pattern: /^[\u4E00-\u9FA5]{2,6}$/, message: '请输入2-6个汉字'}
], ],
phone: [ phone: [
{required: true, validator: validatorPhone, trigger: 'change'}, {required: true, validator: validatorPhone, trigger: 'change'},
@ -212,15 +204,10 @@ const registerRules = reactive({
{required: true, message: '请输入验证码', trigger: 'blur'}, {required: true, message: '请输入验证码', trigger: 'blur'},
] ]
}) })
//
let $router = useRouter();
//
let $route = useRoute();
const loginFormRef = ref() const loginFormRef = ref()
const registerFormRef = ref() const registerFormRef = ref()
const slideVerifyRef = ref() const slideVerifyRef = ref()
const currentHospital = ref(useLoginStore().getlogin().hospital) const currentHospital = ref("")
const isShowRegister = ref(false) const isShowRegister = ref(false)
const passwordLogin = ref(true) const passwordLogin = ref(true)
const loginParams = ref({ const loginParams = ref({
@ -264,8 +251,8 @@ onMounted(() => {
}) })
const selectHospital = (e: string) => { const selectHospital = (e: string) => {
// console.log(e)
} }
const register = async () => { const register = async () => {
await registerFormRef.value.validate((valid: any, fields: any) => { await registerFormRef.value.validate((valid: any, fields: any) => {
if (valid) { if (valid) {
@ -313,20 +300,19 @@ const sendCode = () => {
}, 1000); }, 1000);
} }
const login = async (type: string) => { const login = async (type: string) => {
//: //:
loading.value = true; if (!currentHospital.value) {
/*if (!currentHospital.value) { ElMessage.warning('请在右上角选择院区')
ElMessage.warning('请在右上角选择院区') return
return }
}*/ //:
//: loading.value = true;
loading.value = true; //
// await loginFormRef.value.validate((valid: any, fields: any) => {
await loginFormRef.value.validate((valid: any, fields: any) => { if (valid) {
if (valid) { sliderVConf.value.isShowSelf = true;
sliderVConf.value.isShowSelf = true; }
} })
})
} }
@ -344,7 +330,8 @@ function sliderSuccess() {
loginApi.login({ loginApi.login({
username: loginParams.value.account, // username: loginParams.value.account, //
password: loginParams.value.password, // password: loginParams.value.password, //
randomStr: v4() randomStr: v4(),
hospitalId: currentHospital.value
}).then((data: any) => { }).then((data: any) => {
sliderVConf.value.isShowSelf = false sliderVConf.value.isShowSelf = false
if (data.code == 1 || data.error) { if (data.code == 1 || data.error) {
@ -352,28 +339,33 @@ function sliderSuccess() {
loading.value = false loading.value = false
} else { } else {
// token // token
console.log(data) ElNotification({
ElNotification({ type: 'success',
type: 'success', message: '欢迎回来',
message: '欢迎回来', title: `HI,${getTime()}`
title: `HI,${getTime()}` });
}); loginPost(data)
loginPost(data) router.removeRoute("root");
router.push('/home') router.addRoute({
} name: "root",
}) path: "/",
redirect: "/home"
})
router.replace('/home')
}
})
} }
function sliderClose() { function sliderClose() {
loading.value = false loading.value = false
} }
const loginPost = (data: any) => { const loginPost = (data: any) => {
Session.set('token', data.access_token); Session.set('token', data.access_token);
Session.set('refresh_token', data.refresh_token); Session.set('refresh_token', data.refresh_token);
useLoginStore().setlogin('account', data.username) useUserStore().setlogin('account', data.username)
console.log(data) useUserStore().setlogin('name', data.user_info.chineseName || '暂未设置姓名')
useLoginStore().setlogin('name', data.user_info.name || '暂未设置姓名') useUserStore().setlogin("hospitalId", data.user_info.hospitalId)
} }
</script> </script>
@ -405,6 +397,11 @@ const loginPost = (data: any) => {
position: absolute; position: absolute;
top: 25px; top: 25px;
right: 25px; right: 25px;
.select-hospital {
width: 12rem;
margin-right: 20px;
}
} }
.logo { .logo {

View File

@ -0,0 +1,185 @@
<template>
<div class="table-page">
<div class="search-part" v-show="isSearch">
<div class="search-cell">
<span class="label">词典名称</span>
<el-input v-model="queryParams" placeholder="请输入名称"></el-input>
</div>
<el-button type="primary" icon="Search" @click="search">查询</el-button>
<el-button icon="Refresh" @click="resetSearch">重置</el-button>
</div>
<div class="button-part" style="justify-content: space-between;">
<div>
<el-button type="primary" icon="FirstAidKit" @click="addDict()">新增</el-button>
</div>
<TableAbility :isDownload="false" @searchBtn="isSearch = !isSearch" @refreshBtn="init()"></TableAbility>
</div>
<div class="table-part">
<el-table ref="tableRef"
:data="tableData"
row-key="id" height="100%"
border
show-overflow-tooltip
>
<el-table-column property="description" label="描述" width="300" align="center"/>
<el-table-column property="label" label="标签名" width="260" align="center"/>
<el-table-column property="value" label="值" width="260" align="center"/>
<el-table-column property="remarks" label="备注" width="260" align="center"/>
<el-table-column property="dictType" label="类型" width="180" align="center"/>
<el-table-column property="sortOrder" label="排序" width="80" align="center"/>
<el-table-column label="操作" align="center">
<template #default="scope">
<div @click.stop>
<el-button link icon="EditPen" v-if="!scope.row.dictId" @click="addDictItem(scope.row)">添加字典项
</el-button>
<el-button link icon="EditPen" @click="edit(scope.row)">修改</el-button>
<el-button link icon="Delete" @click="remove(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-part">
<CommonPagination :total="total" @paginationChange="paginationChange"/>
</div>
</div>
<el-dialog v-model="showFormDialog" :title="formDialogTitle" width="30%">
<DictForm ref="dictFormRef" :type="formDialogTitle === '添加' ? 'add' : 'edit'"
@save-or-update-event="dictFormEvent" @close="showFormDialog = false"/>
</el-dialog>
<el-dialog v-model="showItemDialog" :title="formDialogTitle" width="30%">
<DictItemForm ref="dictItemFormRef" :type="formDialogTitle === '添加' ? 'add' : 'edit'"
@save-or-update-event="dictItemFormEvent" @close="showItemDialog = false"/>
</el-dialog>
</template>
<script setup lang="ts">
import DictForm from "@/views/logs-manage/form/dict-form.vue";
import CommonPagination from "@/components/common-pagination.vue";
import {onMounted, ref} from "vue";
import * as dictApi from "@/api/dict";
import DictItemForm from "@/views/logs-manage/form/dict-item-form.vue";
import {ElMessage, ElMessageBox} from "element-plus";
const tableData = ref([] as any)
let current = 0
let size = 10
const total = ref(0)
const queryParams = ref("")
const isSearch = ref(true)
const showFormDialog = ref(false)
const showItemDialog = ref(false)
const formDialogTitle = ref('')
const tableRef = ref()
const dictFormRef = ref();
const dictItemFormRef = ref();
onMounted(() => {
init()
})
function init() {
current = 0;
total.value = 0;
queryParams.value = "";
getList()
}
function getList() {
dictApi.dictPage(current, size, queryParams.value).then((res: any) => {
if (res.code == 0) {
total.value = res.data.total
tableData.value = res.data.records;
}
})
}
function search() {
}
function resetSearch() {
}
function addDict() {
formDialogTitle.value = "添加";
showFormDialog.value = true;
setTimeout(() => {
dictFormRef.value.resetData();
})
}
function dictFormEvent() {
showFormDialog.value = false;
getList()
}
function dictItemFormEvent() {
showItemDialog.value = false;
getList()
}
function addDictItem(row: any) {
formDialogTitle.value = "添加";
showItemDialog.value = true;
setTimeout(() => {
dictItemFormRef.value.resetData(row);
})
}
function edit(row: any) {
formDialogTitle.value = "编辑";
if (row.dictId) {
showItemDialog.value = true;
setTimeout(() => {
dictItemFormRef.value.resetData(row);
})
} else {
showFormDialog.value = true;
setTimeout(() => {
dictFormRef.value.resetData(row);
})
}
}
function remove(row: any) {
ElMessageBox.confirm("是否删除?", "提示", {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
draggable: true
}).then(() => {
if (row.dictId) {
dictApi.deleteDictItem(row.id).then(res => {
if (res.code == 0) {
ElMessage.success("删除成功")
getList()
} else {
ElMessage.error(res.msg ? res.msg : "删除失败")
}
})
} else {
dictApi.deleteDict([row.id]).then(res => {
if (res.code == 0) {
ElMessage.success("删除成功")
getList()
} else {
ElMessage.error(res.msg ? res.msg : "删除失败")
}
})
}
}).catch(() => {
})
}
const paginationChange = (page: number, s: number) => {
current = page - 1
size = s
getList()
}
</script>
<style scoped lang="scss">
</style>

View File

@ -0,0 +1,114 @@
<template>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100">
<el-form-item label="名称" prop="description">
<el-input v-model="formData.description" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item v-if="props.type == 'edit'" label="字典类型">
<span>{{ formData.dictType }}</span>
</el-form-item>
<el-form-item v-else label="字典类型" prop="dictType">
<el-input v-model="formData.dictType" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="是否系统内置" prop="systemFlag">
<el-radio-group v-model="formData.systemFlag">
<el-radio value="1" border></el-radio>
<el-radio value="0" border></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input v-model="formData.remarks" placeholder="请输入"></el-input>
</el-form-item>
<div class="submit-btn">
<el-button class="f18" @click="close">取消</el-button>
<el-button class="f18" type="primary" @click="saveData">确认</el-button>
</div>
</el-form>
</template>
<script setup lang="ts">
import {reactive, ref} from "vue";
import * as dictApi from "@/api/dict";
import {ElMessage} from "element-plus";
const emit = defineEmits(['close', "saveOrUpdateEvent"])
const props = defineProps({
type: String
})
defineExpose({
resetData
})
const rules = reactive({
description: [
{required: true, message: '请输入名称', trigger: ['blur', 'change']},
],
dictType: [
{required: true, message: '请输入字典类型', trigger: ['blur', 'change']},
]
})
const formData = ref({} as any)
const formRef = ref()
function resetData(item?: any) {
if (item) {
formData.value = {
id: item.id,
description: item.description,
dictType: item.dictType,
systemFlag: item.systemFlag,
remarks: item.remarks
}
} else {
formData.value = {
id: "",
description: "",
dictType: "",
systemFlag: "0",
remarks: ""
}
}
}
function saveData() {
formRef.value.validate((valid: any, fields: any) => {
if (valid) {
const form = Object.assign({}, formData.value);
if (form.id) {
dictApi.updateDict(form).then(res => {
if (res.code == 0) {
ElMessage.success("更新成功")
emit("saveOrUpdateEvent");
} else {
ElMessage.error(res.msg ? res.msg : "更新失败")
}
})
} else {
dictApi.saveDict(form).then(res => {
if (res.code == 0) {
ElMessage.success("保存成功")
emit("saveOrUpdateEvent")
} else {
ElMessage.error(res.msg ? res.msg : "保存失败")
}
})
}
}
})
}
function close() {
emit('close')
}
</script>
<style scoped lang="scss">
.submit-btn {
text-align: right;
padding-top: 0;
}
</style>

View File

@ -0,0 +1,138 @@
<template>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100">
<el-form-item label="名称" prop="description">
<el-input v-model="formData.description" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="字典类型">
<span>{{ formData.dictType }}</span>
</el-form-item>
<el-form-item label="标签名" prop="label">
<el-input v-model="formData.label" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="数据值" prop="value">
<el-input v-model="formData.value" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="排序" prop="sortOrder">
<el-input class="number-input" v-model="formData.sortOrder"
type="number" input-style="text-align: center;"
@change="numberInputChange">
<template #prepend>
<el-button text icon="Minus" :disabled="formData.sortOrder <= 0"
@click="formData.sortOrder--"/>
</template>
<template #append>
<el-button text icon="Plus" @click="formData.sortOrder++"/>
</template>
</el-input>
</el-form-item>
<el-form-item label="备注" prop="remarks">
<el-input v-model="formData.remarks" placeholder="请输入"></el-input>
</el-form-item>
<div class="submit-btn">
<el-button class="f18" @click="close">取消</el-button>
<el-button class="f18" type="primary" @click="saveData">确认</el-button>
</div>
</el-form>
</template>
<script setup lang="ts">
import {reactive, ref} from "vue";
import * as dictApi from "@/api/dict";
import {ElMessage} from "element-plus";
const emit = defineEmits(['close', "saveOrUpdateEvent"])
const props = defineProps({
type: String
})
defineExpose({
resetData,
})
const rules = reactive({
description: [
{required: true, message: '请输入名称', trigger: ['blur', 'change']},
],
dictType: [
{required: true, message: '请输入字典类型', trigger: ['blur', 'change']},
]
})
const formData = ref({} as any)
const formRef = ref()
function resetData(item?: any) {
if (item.id && item.dictId) {
formData.value = {
id: item.id,
dictId: item.dictId,
description: item.description,
dictType: item.dictType,
label: item.label,
value: item.value,
sortOrder: item.sortOrder,
remarks: item.remarks
}
} else {
formData.value = {
id: "",
dictId: item.id,
description: "",
dictType: item.dictType,
label: "",
value: "",
sortOrder: "",
remarks: ""
}
}
}
function saveData() {
formRef.value.validate((valid: any, fields: any) => {
if (valid) {
const form = Object.assign({}, formData.value);
if (form.id) {
dictApi.updateDictItem(form).then(res => {
if (res.code == 0) {
ElMessage.success("更新成功")
emit("saveOrUpdateEvent");
} else {
ElMessage.error(res.msg ? res.msg : "更新失败")
}
})
} else {
dictApi.saveDictItem(form).then(res => {
if (res.code == 0) {
ElMessage.success("保存成功")
emit("saveOrUpdateEvent")
} else {
ElMessage.error(res.msg ? res.msg : "保存失败")
}
})
}
}
})
}
function close() {
emit('close')
}
const numberInputChange = (e: any) => {
if (!Number(e)) {
formData.value.sortOrder = 0
}
}
</script>
<style scoped lang="scss">
.submit-btn {
text-align: right;
padding-top: 0;
}
</style>

View File

@ -1,76 +1,78 @@
<template> <template>
<div class="permissions-manage-page"> <div class="permissions-manage-page">
<div class="menu-box"> <div class="menu-box">
<CommonMenu :menuData="menuData" @selectMenu="selectMenu" /> <CommonMenu :menuData="menuData" @selectMenu="selectMenu"/>
</div>
<div class="content-box">
<!-- <div class="header-box">
<PageTabs ref="pageTabsRef" />
</div> -->
<div class="main-box">
<div class="background-block">
<RouterView />
</div>
</div>
</div>
</div> </div>
<div class="content-box">
<!-- <div class="header-box">
<PageTabs ref="pageTabsRef" />
</div> -->
<div class="main-box">
<div class="background-block">
<RouterView/>
</div>
</div>
</div>
</div>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, reactive, ref, toRefs, watch} from 'vue'
import type { MenuItem } from '@/utils/public-interface' import type {MenuItem} from '@/utils/public-interface'
import CommonMenu from '@/components/common-menu.vue' import CommonMenu from '@/components/common-menu.vue'
import PageTabs from '@/components/page-tabs.vue' import PageTabs from '@/components/page-tabs.vue'
const menuData = [ const menuData = [
{ name: '消息管理', path: '/logs-manage/message-manage' }, {name: '消息管理', path: '/logs-manage/message-manage'},
{ name: '日志管理', path: '/logs-manage/logs-manage' } {name: '日志管理', path: '/logs-manage/logs-manage'},
{name: "词典管理", path: '/logs-manage/dict-manage'}
] ]
const pageTabsRef = ref() const pageTabsRef = ref()
const selectMenu = (e: MenuItem) => { const selectMenu = (e: MenuItem) => {
// pageTabsRef.value.setTab(e) // pageTabsRef.value.setTab(e)
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.permissions-manage-page { .permissions-manage-page {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
overflow-y: auto; overflow-y: auto;
.menu-box { .menu-box {
width: 200px; width: 200px;
height: 100%;
background: white;
overflow-x: hidden;
overflow-y: auto;
}
.content-box {
width: calc(100% - 200px);
height: 100%;
.header-box {
width: 100%;
height: 50px;
}
.main-box {
width: 100%;
// height: calc(100% - 50px);
height: 100%;
padding: 10px;
.background-block {
width: 100%;
height: 100%; height: 100%;
background: white; background: white;
overflow-x: hidden; border-radius: 15px;
overflow-y: auto; padding: 20px;
} min-height: 510px;
.content-box { }
width: calc(100% - 200px);
height: 100%;
.header-box {
width: 100%;
height: 50px;
}
.main-box {
width: 100%;
// height: calc(100% - 50px);
height: 100%;
padding: 10px;
.background-block {
width: 100%;
height: 100%;
background: white;
border-radius: 15px;
padding: 20px;
min-height: 510px;
}
}
} }
}
}</style> }</style>

View File

@ -93,6 +93,8 @@ onMounted(() => {
function init() { function init() {
loading.value = true; loading.value = true;
current = 0;
total.value = 0;
getList(); getList();
loading.value = false; loading.value = false;
} }

View File

@ -27,7 +27,8 @@ const props = {
label: 'name', label: 'name',
children: 'children' children: 'children'
} }
const treeIds: Array<string> = [] //
const treeIds: Array<string> = [];
const treeRef = ref() const treeRef = ref()
const dialogVisible = ref(false) const dialogVisible = ref(false)
const toggleExpand = ref(false) const toggleExpand = ref(false)
@ -45,7 +46,6 @@ function open(role: any) {
dialogVisible.value = true dialogVisible.value = true
roleObj = role; roleObj = role;
getMenuTree(); getMenuTree();
getRoleMenu();
} }
function close() { function close() {
@ -56,11 +56,25 @@ const getMenuTree = () => {
menuApi.getMenuTree().then((res: any) => { menuApi.getMenuTree().then((res: any) => {
treeData.value = res.data; treeData.value = res.data;
setTreeIds(res.data, treeIds); setTreeIds(res.data, treeIds);
getRoleMenu();
}); });
} }
const getRoleMenu = () => { const getRoleMenu = () => {
menuApi.getRoleTree(roleObj.roleId).then((res: any) => { menuApi.getRoleTree(roleObj.roleId).then((res: any) => {
treeData.value.forEach((row: any) => {
let childrenCount = 0;
if (res.data.indexOf(row.id) != -1) {
row.children.forEach((child: any) => {
if (res.data.indexOf(child.id) != -1) {
childrenCount++;
}
})
if (row.children.length != childrenCount) {
res.data.splice(res.data.indexOf(row.id), 1);
}
}
})
treeRef.value.setCheckedKeys(res.data); treeRef.value.setCheckedKeys(res.data);
}) })
} }
@ -93,8 +107,9 @@ const toggleSelectAllChange = (e: boolean) => {
} }
const updateData = () => { const updateData = () => {
const menuIds = treeRef.value.getCheckedKeys().join(","); const menuIds = treeRef.value.getCheckedKeys();
roleApi.saveRoleMenus(roleObj.roleId, menuIds) const halfMenuIds = treeRef.value.getHalfCheckedKeys();
roleApi.saveRoleMenus(roleObj.roleId, menuIds.concat(halfMenuIds).join(','))
.then((res: any) => { .then((res: any) => {
if (res.code == 0) { if (res.code == 0) {
ElMessage.success('更新成功'); ElMessage.success('更新成功');

View File

@ -1,61 +1,73 @@
<template> <template>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100"> <el-form ref="formRef" :model="formData" :rules="rules" label-width="100">
<el-form-item label="类型" prop="type">
<el-radio-group v-model="formData.menuType" :disabled="type === 'edit'">
<el-radio label="0" border>菜单</el-radio>
<el-radio label="1" border v-if="formData.parentId != -1">按钮</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="上级菜单" prop="parentName">
<!-- <el-select v-model="formData.parentMenu" placeholder="请选择上级菜单" clearable>
<el-option v-for="item in parentMenu" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>-->
<el-input v-model="formData.parentName" readonly placeholder="请输入菜单名称"></el-input>
</el-form-item>
<el-form-item label="菜单名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入菜单名称"></el-input>
</el-form-item>
<el-form-item label="图标" prop="icon">
<i :class="formData.icon" style="font-size: 26px;margin: 0 10px;"></i>
<el-button @click="isIconDialog = true">选择图标</el-button>
</el-form-item>
<el-form-item label="路由" prop="route">
<el-input v-model="formData.path" placeholder="请输入路由"></el-input>
</el-form-item>
<el-form-item label="排序" prop="order">
<el-input class="number-input" v-model="formData.sortOrder"
type="number" input-style="text-align: center;"
@change="numberInputChange">
<template #prepend>
<el-button text icon="Minus" :disabled="formData.sortOrder <= 1"
@click="formData.sortOrder--"/>
</template>
<template #append>
<el-button text icon="Plus" @click="formData.sortOrder++"/>
</template>
</el-input>
</el-form-item>
<el-form-item label="是否显示" prop="visible">
<el-radio-group v-model="formData.visible">
<el-radio label="1" border></el-radio>
<el-radio label="0" border></el-radio>
</el-radio-group>
</el-form-item>
<div style="text-align: right;padding-top: 0;"> <el-form-item label="上级菜单">
<el-button class="f18" @click="close">取消</el-button> <span>{{ formData.parentName }}</span>
<el-button class="f18" type="primary" @click="saveData">确认</el-button> </el-form-item>
</div>
</el-form>
<el-dialog v-model="isIconDialog" title="选择图标" top="20vh" width="25%"> <el-form-item label="类型" v-if="type === 'edit'">
<div class="iconfont-box"> <span>{{ formData.menuType == 0 ? "菜单" : "按钮" }}</span>
<div class="iconfont-item" v-for="item in iconfont.glyphs" </el-form-item>
:key="item.font_class" @click="iconClick(item)">
<i :class="'icon-' + item.font_class"></i> <el-form-item label="类型" prop="type" v-else>
</div> <el-radio-group v-model="formData.menuType">
</div> <el-radio value="0" border>菜单</el-radio>
</el-dialog> <el-radio value="1" border v-if="formData.parentId != -1">按钮</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="菜单名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入菜单名称"></el-input>
</el-form-item>
<el-form-item label="图标" prop="icon">
<i :class="formData.icon" style="font-size: 26px;margin: 0 10px;"></i>
<el-button @click="isIconDialog = true">选择图标</el-button>
</el-form-item>
<el-form-item label="路由" prop="route">
<el-input v-model="formData.path" placeholder="请输入路由"></el-input>
</el-form-item>
<el-form-item label="权限标识" prop="permission">
<el-input v-model="formData.permission" placeholder="请输入"></el-input>
</el-form-item>
<el-form-item label="排序" prop="order">
<el-input class="number-input" v-model="formData.sortOrder"
type="number" input-style="text-align: center;"
@change="numberInputChange">
<template #prepend>
<el-button text icon="Minus" :disabled="formData.sortOrder <= 0"
@click="formData.sortOrder--"/>
</template>
<template #append>
<el-button text icon="Plus" @click="formData.sortOrder++"/>
</template>
</el-input>
</el-form-item>
<el-form-item label="是否显示" prop="visible">
<el-radio-group v-model="formData.visible">
<el-radio value="1" border></el-radio>
<el-radio value="0" border></el-radio>
</el-radio-group>
</el-form-item>
<div style="text-align: right;padding-top: 0;">
<el-button class="f18" @click="close">取消</el-button>
<el-button class="f18" type="primary" @click="saveData">确认</el-button>
</div>
</el-form>
<el-dialog v-model="isIconDialog" title="选择图标" top="20vh" width="25%">
<div class="iconfont-box">
<div class="iconfont-item" v-for="item in iconfont.glyphs"
:key="item.font_class" @click="iconClick(item)">
<i :class="'icon-' + item.font_class"></i>
</div>
</div>
</el-dialog>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
@ -66,18 +78,18 @@ import * as menuApi from "@/api/menu";
const emit = defineEmits(['close', "saveOrUpdateEvent"]) const emit = defineEmits(['close', "saveOrUpdateEvent"])
const props = defineProps({ const props = defineProps({
type: String type: String
}) })
defineExpose({ defineExpose({
resetData, resetData,
}) })
const rules = reactive({ const rules = reactive({
name: [ name: [
{required: true, message: '请输入菜单名称', trigger: ['blur', 'change']}, {required: true, message: '请输入菜单名称', trigger: ['blur', 'change']},
], ],
path: [ path: [
{required: true, message: '请输入路由地址', trigger: ['blur', 'change']}, {required: true, message: '请输入路由地址', trigger: ['blur', 'change']},
] ]
}) })
const formRef = ref() const formRef = ref()
const isIconDialog = ref(false) const isIconDialog = ref(false)
@ -85,115 +97,117 @@ const formData = ref({} as any)
onMounted(() => { onMounted(() => {
resetData() resetData()
}) })
function close() { function close() {
emit('close') emit('close')
} }
function resetData(menu?: any, form?: any) { function resetData(menu?: any, form?: any) {
formRef.value.resetFields() formRef.value.resetFields()
if (form) { if (form) {
formData.value = { formData.value = {
menuId: form.id, menuId: form.id,
menuType: form.menuType, menuType: form.menuType,
parentName: form.parentName, parentName: form.parentName,
parentId: form.parentId, parentId: form.parentId,
name: form.name, name: form.name,
icon: form.meta.icon, icon: form.meta.icon,
path: form.path, path: form.path,
sortOrder: form.sortOrder, sortOrder: form.sortOrder,
visible: form.visible visible: form.visible,
} permission: form.permission
}
} else { } else {
formData.value = { formData.value = {
menuId: '', menuId: '',
menuType: '0', menuType: '0',
parentName: menu ? menu.name : "无", parentName: menu ? menu.name : "无",
parentId: menu ? menu.id : "-1", parentId: menu ? menu.id : "-1",
name: '', name: '',
icon: '', icon: '',
path: '', path: '',
sortOrder: 1, sortOrder: 0,
visible: "1" visible: "1",
} permission: ""
} }
}
} }
const numberInputChange = (e: any) => { const numberInputChange = (e: any) => {
if (!Number(e)) { if (!Number(e)) {
formData.value.sortOrder = 1 formData.value.sortOrder = 0
} }
} }
const iconClick = (e: any) => { const iconClick = (e: any) => {
formData.value.icon = 'icon-' + e.font_class formData.value.icon = 'icon-' + e.font_class
isIconDialog.value = false isIconDialog.value = false
} }
const saveData = async () => { const saveData = async () => {
await formRef.value.validate((valid: any, fields: any) => { await formRef.value.validate((valid: any, fields: any) => {
if (valid) { if (valid) {
const form = Object.assign({}, formData.value); const form = Object.assign({}, formData.value);
if (form.menuId) { if (form.menuId) {
menuApi.updateMenu(form).then((res: any) => { menuApi.updateMenu(form).then((res: any) => {
if (res.code == 0) { if (res.code == 0) {
ElMessage.success("修改成功"); ElMessage.success("修改成功");
emit("saveOrUpdateEvent"); emit("saveOrUpdateEvent");
} else { } else {
ElMessage.error("修改失败"); ElMessage.error("修改失败");
} }
}) })
} else { } else {
menuApi.saveMenu(form).then((res: any) => { menuApi.saveMenu(form).then((res: any) => {
if (res.code == 0) { if (res.code == 0) {
ElMessage.success('保存成功!'); ElMessage.success('保存成功!');
emit("saveOrUpdateEvent"); emit("saveOrUpdateEvent");
} else { } else {
ElMessage.error("保存失败"); ElMessage.error("保存失败");
} }
}) })
} }
} }
}) })
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
:deep(.el-form-item) { :deep(.el-form-item) {
.el-form-item__label { .el-form-item__label {
display: block; display: block;
// text-align: justify; // text-align: justify;
// text-align-last: justify; // text-align-last: justify;
padding: 0 10px 0 20px; padding: 0 10px 0 20px;
&:before { &:before {
display: none; display: none;
} }
} }
} }
.iconfont-box { .iconfont-box {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
max-height: 300px; max-height: 300px;
overflow-y: auto; overflow-y: auto;
.iconfont-item { .iconfont-item {
width: 50px; width: 50px;
height: 50px; height: 50px;
line-height: 50px; line-height: 50px;
text-align: center; text-align: center;
font-size: 30px; font-size: 30px;
&:hover { &:hover {
background: rgba($main-color, .1); background: rgba($main-color, .1);
} }
&:focus, &:active { &:focus, &:active {
background: rgba($main-color, .2); background: rgba($main-color, .2);
color: $main-color; color: $main-color;
} }
} }
} }
</style> </style>

View File

@ -3,8 +3,11 @@
<el-form-item label="角色名称" prop="roleName"> <el-form-item label="角色名称" prop="roleName">
<el-input v-model="formData.roleName" placeholder="请输入角色名称"></el-input> <el-input v-model="formData.roleName" placeholder="请输入角色名称"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="角色标识" prop="roleCode"> <el-form-item label="角色标识" v-if="type == 'edit'">
<el-input v-model="formData.roleCode" placeholder="请输入角色标识" :disabled="type === 'edit'"></el-input> {{formData.roleCode}}
</el-form-item>
<el-form-item v-else label="角色标识" prop="roleCode">
<el-input v-model="formData.roleCode" placeholder="请输入角色标识"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="角色描述" prop="roleDesc"> <el-form-item label="角色描述" prop="roleDesc">
<el-input v-model="formData.roleDesc" type="textarea" :rows="3" placeholder="请输入角色描述"></el-input> <el-input v-model="formData.roleDesc" type="textarea" :rows="3" placeholder="请输入角色描述"></el-input>

View File

@ -17,8 +17,8 @@
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {ref} from 'vue'
import type { MenuItem } from '@/utils/public-interface' import type {MenuItem} from '@/utils/public-interface'
import CommonMenu from '@/components/common-menu.vue' import CommonMenu from '@/components/common-menu.vue'
import PageTabs from '@/components/page-tabs.vue' import PageTabs from '@/components/page-tabs.vue'

View File

@ -1,46 +1,52 @@
<template> <template>
<div class="table-page"> <div class="table-page">
<div class="search-part" v-show="isSearch"> <div class="search-part" v-show="isSearch">
<div class="search-cell"> <div class="search-cell">
<span class="label">菜单名称</span> <span class="label">菜单名称</span>
<el-input v-model="queryParams" placeholder="请输入菜单名称"></el-input> <el-input v-model="queryParams" placeholder="请输入菜单名称"></el-input>
</div> </div>
<el-button type="primary" icon="Search" @click="searchList">查询</el-button> <el-button type="primary" icon="Search" @click="searchList">查询</el-button>
<el-button icon="Refresh" @click="resetSearch">重置</el-button> <el-button icon="Refresh" @click="resetSearch">重置</el-button>
</div> </div>
<div class="button-part" style="justify-content: space-between;"> <div class="button-part" style="justify-content: space-between;">
<div> <div>
<el-button type="primary" icon="FirstAidKit" @click="addData()">新增</el-button> <el-button type="primary" icon="FirstAidKit" @click="addData()">新增</el-button>
<el-button @click="expandTable">展开/折叠</el-button> <el-button @click="expandTable">展开/折叠</el-button>
</div> </div>
<TableAbility :isDownload="false" @searchBtn="isSearch = !isSearch" @refreshBtn="initData()"></TableAbility> <TableAbility :isDownload="false" @searchBtn="isSearch = !isSearch" @refreshBtn="initData()"></TableAbility>
</div> </div>
<div class="table-part"> <div class="table-part">
<el-table ref="tableRef" :data="tableData" row-key="id" height="100%" border show-overflow-tooltip <el-table ref="tableRef" :data="tableData" row-key="id" height="100%" border show-overflow-tooltip
@row-click="tableRowClick"> @row-click="tableRowClick">
<el-table-column property="name" label="菜单名称" width="180" align="center"/> <el-table-column property="name" label="菜单名称" width="180" align="center"/>
<el-table-column property="sortOrder" label="排序" width="80" align="center"/> <el-table-column label="图标" width="80" align="center">
<el-table-column label="图标" width="80" align="center"> <template #default="scope"><i class="main-color f20" :class="scope.row.meta.icon"></i></template>
<template #default="scope"><i class="main-color f20" :class="scope.row.meta.icon"></i></template> </el-table-column>
</el-table-column> <el-table-column property="path" label="路由" width="260" align="center"/>
<el-table-column property="path" label="路由" width="260" align="center"/> <el-table-column label="类型" width="180" align="center">
<el-table-column property="menuType" label="类型" width="180" align="center"/> <template #default="scope">
<el-table-column label="操作" align="center"> <span>{{ scope.row.menuType == 0 ? "菜单" : "按钮" }}</span>
<template #default="scope"> </template>
<div @click.stop> </el-table-column>
<el-button link icon="EditPen" @click="addData(scope.row)">新建下级</el-button> <el-table-column property="sortOrder" label="排序" width="80" align="center"/>
<el-button link icon="EditPen" @click="editData(scope.row)">修改</el-button> <el-table-column label="操作" align="center">
<el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button> <template #default="scope">
</div> <div @click.stop>
</template> <el-button link icon="EditPen" v-if="scope.row.menuType == 0" @click="addData(scope.row)">
</el-table-column> 新建下级
</el-table> </el-button>
</div> <el-button link icon="EditPen" @click="editData(scope.row)">修改</el-button>
</div> <el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button>
<el-dialog v-model="isFormDialog" :title="formDialogTitle" width="30%"> </div>
<MenuForm ref="menuFormRef" :type="formDialogTitle === '添加' ? 'add' : 'edit'" </template>
@save-or-update-event="formSaveUpdateEvent" @close="isFormDialog = false"/> </el-table-column>
</el-dialog> </el-table>
</div>
</div>
<el-dialog v-model="isFormDialog" :title="formDialogTitle" width="30%">
<MenuForm ref="menuFormRef" :type="formDialogTitle === '添加' ? 'add' : 'edit'"
@save-or-update-event="formSaveUpdateEvent" @close="isFormDialog = false"/>
</el-dialog>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
@ -50,7 +56,6 @@ import * as menuApi from "@/api/menu";
import {ElMessage, ElMessageBox} from "element-plus"; import {ElMessage, ElMessageBox} from "element-plus";
let isExpand = false // let isExpand = false //
const tableRef = ref() const tableRef = ref()
const menuFormRef = ref() const menuFormRef = ref()
const isSearch = ref(true) const isSearch = ref(true)
@ -62,102 +67,102 @@ const tableData = ref([] as any)
const tableMap: any = {}; const tableMap: any = {};
onMounted(() => { onMounted(() => {
initData(); initData();
}) })
function initData() { function initData() {
loading.value = true; loading.value = true;
tableData.value = []; tableData.value = [];
getMenuTree(); getMenuTree();
} }
function searchList() { function searchList() {
loading.value = true; loading.value = true;
tableData.value = []; tableData.value = [];
getMenuTree(queryParams.value) getMenuTree(queryParams.value)
} }
function resetSearch() { function resetSearch() {
queryParams.value = ''; queryParams.value = '';
initData(); initData();
} }
function getMenuTree(name?: string) { function getMenuTree(name?: string) {
menuApi.getMenuTree(name).then((res: any) => { menuApi.getMenuTree(name).then((res: any) => {
tableData.value = res.data; tableData.value = res.data ? res.data : [];
initTableMap(tableData.value); initTableMap(tableData.value);
}) })
} }
function initTableMap(data: any) { function initTableMap(data: any) {
data.forEach((row: any, i: number) => { data.forEach((row: any, i: number) => {
handleInitTree(row, i, []); handleInitTree(row, i, []);
}); });
} }
function handleInitTree(row: any, i: number, pArr: any) { function handleInitTree(row: any, i: number, pArr: any) {
// //
const cArr: any = [].concat(pArr); const cArr: any = [].concat(pArr);
cArr.push(i); cArr.push(i);
tableMap[row.id] = cArr; tableMap[row.id] = cArr;
row.indexArr = cArr; row.indexArr = cArr;
if (row.children) { if (row.children) {
row.children.forEach((row: any, i: number) => { row.children.forEach((row: any, i: number) => {
handleInitTree(row, i, cArr); handleInitTree(row, i, cArr);
}) })
} }
} }
const addData = (menu?: any) => { const addData = (menu?: any) => {
isFormDialog.value = true isFormDialog.value = true
formDialogTitle.value = '添加' formDialogTitle.value = '添加'
setTimeout(() => { setTimeout(() => {
menuFormRef.value.resetData(menu) menuFormRef.value.resetData(menu)
}, 0) }, 0)
} }
const expandTable = () => { const expandTable = () => {
isExpand = !isExpand isExpand = !isExpand
tableData.value.forEach((row: any) => { tableData.value.forEach((row: any) => {
tableRef.value.toggleRowExpansion(row, isExpand) tableRef.value.toggleRowExpansion(row, isExpand)
}) })
} }
const removeData = (e?: any) => { const removeData = (e?: any) => {
ElMessageBox.confirm( ElMessageBox.confirm(
'是否删除?', '是否删除?',
{ {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
draggable: true draggable: true
} }
).then(() => { ).then(() => {
menuApi.deleteById(e.id).then((res: any) => { menuApi.deleteById(e.id).then((res: any) => {
if (res.code == 0) { if (res.code == 0) {
ElMessage.success("删除成功"); ElMessage.success("删除成功");
initData(); initData();
} else { } else {
ElMessage.error(res.msg ? res.msg : "删除失败"); ElMessage.error(res.msg ? res.msg : "删除失败");
} }
}) })
}).catch(() => { }).catch(() => {
}) })
} }
const editData = (e: any) => { const editData = (e: any) => {
isFormDialog.value = true isFormDialog.value = true
formDialogTitle.value = '修改' formDialogTitle.value = '修改'
setTimeout(() => { setTimeout(() => {
menuFormRef.value.resetData(null, JSON.parse(JSON.stringify(e))) menuFormRef.value.resetData(null, JSON.parse(JSON.stringify(e)))
}, 0) }, 0)
} }
const tableRowClick = (row: any) => { const tableRowClick = (row: any) => {
tableRef.value.toggleRowExpansion(row) tableRef.value.toggleRowExpansion(row)
} }
function formSaveUpdateEvent() { function formSaveUpdateEvent() {
isFormDialog.value = false; isFormDialog.value = false;
initData(); initData();
} }
</script> </script>

View File

@ -1,68 +1,61 @@
<template> <template>
<div class="table-page"> <div class="table-page">
<div class="search-part" v-show="isSearch"> <div class="search-part" v-show="isSearch">
<div class="search-cell"> <div class="search-cell">
<span class="label">角色名称</span> <span class="label">角色名称</span>
<el-input v-model="queryParams" placeholder="请输入角色名称"></el-input> <el-input v-model="queryParams" placeholder="请输入角色名称"></el-input>
</div> </div>
<el-button type="primary" icon="Search" @click="search">查询</el-button> <el-button type="primary" icon="Search" @click="search">查询</el-button>
<el-button icon="Refresh" @click="resetSearch">重置</el-button> <el-button icon="Refresh" @click="resetSearch">重置</el-button>
</div> </div>
<div class="button-part" style="justify-content: space-between;"> <div class="button-part" style="justify-content: space-between;">
<div> <div>
<el-button type="primary" icon="FirstAidKit" @click="addData">新增</el-button> <el-button type="primary" icon="FirstAidKit" @click="addData">新增</el-button>
<el-button icon="FirstAidKit" @click="importData">导入</el-button> <el-button icon="FirstAidKit" @click="importData">导入</el-button>
<el-button icon="Delete" @click="removeData()">删除</el-button> <el-button icon="Delete" @click="removeData()">删除</el-button>
</div> </div>
<TableAbility @searchBtn="isSearch = !isSearch" @refreshBtn="init" <TableAbility @searchBtn="isSearch = !isSearch" @refreshBtn="init"
@downloadBtn="exportData('角色数据', tableData)"></TableAbility> @downloadBtn="exportData('角色数据', tableData)"></TableAbility>
</div> </div>
<div class="table-part"> <div class="table-part">
<el-table ref="tableRef" v-loading="loading" :data="tableData" height="100%" border show-overflow-tooltip <el-table ref="tableRef" v-loading="loading" :data="tableData" height="100%" border show-overflow-tooltip
@row-click="tableRowClick"> @row-click="tableRowClick">
<el-table-column type="selection" width="55"/> <el-table-column type="selection" width="55"/>
<el-table-column type="index" label="#" width="55" align="center"/> <el-table-column type="index" label="#" width="55" align="center"/>
<el-table-column property="roleName" label="角色名称" width="120" align="center"/> <el-table-column property="roleName" label="角色名称" width="120" align="center"/>
<el-table-column property="roleCode" label="角色标识" width="180" align="center"/> <el-table-column property="roleCode" label="角色标识" width="180" align="center"/>
<el-table-column property="roleDesc" label="角色描述" width="120" align="center"/> <el-table-column property="roleDesc" label="角色描述" width="120" align="center"/>
<el-table-column label="数据权限" width="120" align="center"> <el-table-column label="数据权限" width="120" align="center">
<template #default="scope"> <template #default="scope">
<el-popover <div class="cell-content">
trigger="hover" {{ scope.row.menu }}
:content="scope.row.menu" </div>
> </template>
<template #reference> </el-table-column>
<div class="cell-content"> <el-table-column label="创建时间" width="220" align="center">
{{ scope.row.menu }} <template #default="scope">{{ scope.row.createTime }}</template>
</div> </el-table-column>
</template> <el-table-column label="操作" align="center">
</el-popover> <template #default="scope">
</template> <div @click.stop>
</el-table-column> <el-button link icon="RefreshLeft" @click="empower(scope.row)">授权</el-button>
<el-table-column label="创建时间" width="220" align="center"> <el-button link icon="EditPen" @click="editData(scope.row)">修改</el-button>
<template #default="scope">{{ scope.row.createTime }}</template> <el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button>
</el-table-column> </div>
<el-table-column label="操作" align="center"> </template>
<template #default="scope"> </el-table-column>
<div @click.stop> </el-table>
<el-button link icon="RefreshLeft" @click="empower(scope.row)">授权</el-button> </div>
<el-button link icon="EditPen" @click="editData(scope.row)">修改</el-button> <div class="pagination-part">
<el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button> <CommonPagination :total="total" @paginationChange="paginationChange"/>
</div> </div>
</template> </div>
</el-table-column> <el-dialog v-model="isFormDialog" :title="formDialogTitle" width="30%">
</el-table> <RoleForm ref="RoleFormRef" :type="formDialogTitle === '添加' ? 'add' : 'edit'" @close="isFormDialog = false"/>
</div> </el-dialog>
<div class="pagination-part"> <ImportDialog ref="importDialogRef" title="角色导入" templateUrl="/admin/sys-file/local/file/role.xlsx"
<CommonPagination :total="total" @paginationChange="paginationChange"/> importUrl="/admin/role/import" @success="importSuccessEvent"/>
</div> <EmpowerDialog ref="empowerDialogRef"/>
</div>
<el-dialog v-model="isFormDialog" :title="formDialogTitle" width="30%">
<RoleForm ref="RoleFormRef" :type="formDialogTitle === '添加' ? 'add' : 'edit'" @close="isFormDialog = false"/>
</el-dialog>
<ImportDialog ref="importDialogRef" title="角色导入" templateUrl="/admin/sys-file/local/file/role.xlsx"
importUrl="/admin/role/import" @success="importSuccessEvent"/>
<EmpowerDialog ref="empowerDialogRef"/>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
@ -91,108 +84,108 @@ let size = 10;
const total = ref(0); const total = ref(0);
onMounted(() => { onMounted(() => {
init(); init();
}) })
function init() { function init() {
loading.value = true loading.value = true
total.value = 0; total.value = 0;
current = 0; current = 0;
tableData.value = []; tableData.value = [];
getRoleList(); getRoleList();
loading.value = false loading.value = false
} }
function getRoleList() { function getRoleList() {
roleApi.getRoleTree(current, size, queryParams.value).then((res: any) => { roleApi.getRoleTree(current, size, queryParams.value).then((res: any) => {
if (res.code == 0) { if (res.code == 0) {
total.value = res.data.total total.value = res.data.total
tableData.value = res.data.records tableData.value = res.data.records
} }
}) })
} }
function search() { function search() {
init(); init();
} }
function resetSearch() { function resetSearch() {
queryParams.value = ""; queryParams.value = "";
init(); init();
} }
const addData = () => { const addData = () => {
isFormDialog.value = true isFormDialog.value = true
formDialogTitle.value = '添加' formDialogTitle.value = '添加'
setTimeout(() => { setTimeout(() => {
RoleFormRef.value.resetData() RoleFormRef.value.resetData()
}, 0) }, 0)
} }
const importData = () => { const importData = () => {
setTimeout(() => { setTimeout(() => {
importDialogRef.value.open() importDialogRef.value.open()
}, 0); }, 0);
} }
const removeData = (e?: any) => { const removeData = (e?: any) => {
const selectRow = [e] || tableRef.value.getSelectionRows(); const selectRow = [e] || tableRef.value.getSelectionRows();
tableRemoveRow({data: selectRow}, (res: boolean) => { tableRemoveRow({data: selectRow}, (res: boolean) => {
if (res) { if (res) {
const ids: any = []; const ids: any = [];
selectRow.forEach((row: any) => { selectRow.forEach((row: any) => {
ids.push(row.roleId); ids.push(row.roleId);
}) })
roleApi.deleteById(ids).then((res: any) => { roleApi.deleteById(ids).then((res: any) => {
if (res.code == 0) { if (res.code == 0) {
ElMessage.success("删除成功"); ElMessage.success("删除成功");
init(); init();
} else { } else {
ElMessage.error(res.msg ? res.msg : "删除失败"); ElMessage.error(res.msg ? res.msg : "删除失败");
} }
}) })
} }
}) })
} }
const empower = (e: any) => { const empower = (e: any) => {
setTimeout(() => { setTimeout(() => {
empowerDialogRef.value.open(e) empowerDialogRef.value.open(e)
}) })
} }
const editData = (e: any) => { const editData = (e: any) => {
isFormDialog.value = true isFormDialog.value = true
formDialogTitle.value = '修改' formDialogTitle.value = '修改'
setTimeout(() => { setTimeout(() => {
RoleFormRef.value.resetData(JSON.parse(JSON.stringify(e))) RoleFormRef.value.resetData(JSON.parse(JSON.stringify(e)))
}, 0) }, 0)
} }
const tableRowClick = (row: any) => { const tableRowClick = (row: any) => {
tableRef.value.toggleRowSelection(row) tableRef.value.toggleRowSelection(row)
} }
const paginationChange = (page: number, s: number) => { const paginationChange = (page: number, s: number) => {
current = page current = page
size = s size = s
getRoleList() getRoleList()
} }
const importSuccessEvent = () => { const importSuccessEvent = () => {
init(); init();
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
:deep(.el-table__body) { :deep(.el-table__body) {
.cell { .cell {
max-height: 49px; max-height: 49px;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.cell-content { .cell-content {
max-height: 49px; max-height: 49px;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
} }
</style> </style>

View File

@ -49,9 +49,10 @@ defineExpose({
close, close,
}) })
function open(e: number) { function open(i: number) {
patientInfo.value = remoteWsStore.remoteTasks[e] patientInfo.value = remoteWsStore.remoteTasks[i];
dialogVisible.value = true patientInfo.value.date = new Date();
dialogVisible.value = true;
} }
function close() { function close() {

View File

@ -138,7 +138,7 @@ onUnmounted(() => {
remoteWsStore.unsubscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date); remoteWsStore.unsubscribeVital(remoteItem.value.patient, remoteItem.value.patientId, remoteItem.value.date);
}) })
function showData(i: number) { function showData(i: any) {
const lastTaskIndex = remoteWsStore.currentTaskIndex; const lastTaskIndex = remoteWsStore.currentTaskIndex;
const lastTask: any = remoteWsStore.remoteTasks[lastTaskIndex]; const lastTask: any = remoteWsStore.remoteTasks[lastTaskIndex];
if (lastTask) { if (lastTask) {

View File

@ -130,7 +130,7 @@
:disabled="tableDataStore[scope.$index].speed === scope.row.speed">确定--> :disabled="tableDataStore[scope.$index].speed === scope.row.speed">确定-->
<el-button size="small" color="#006080" @click="tableItemConfirm(scope, varTableData)">确定 <el-button size="small" color="#006080" @click="tableItemConfirm(scope, varTableData)">确定
</el-button> </el-button>
<el-button size="small" color="#006080" @click="tableItemCancel(scope, varTableData)">取消 <el-button size="small" color="#006080" @click="tableItemCancel(scope)">取消
</el-button> </el-button>
</div> </div>
</template> </template>
@ -163,7 +163,7 @@
</el-button> </el-button>
<el-button size="small" color="#006080" @click="tableItemConfirm(scope, fixedTableData)">确定 <el-button size="small" color="#006080" @click="tableItemConfirm(scope, fixedTableData)">确定
</el-button> </el-button>
<el-button size="small" color="#006080" @click="tableItemCancel(scope, fixedTableData)">取消 <el-button size="small" color="#006080" @click="tableItemCancel(scope)">取消
</el-button> </el-button>
</div> </div>
</template> </template>
@ -203,7 +203,7 @@ import imgHeart from '@/assets/imgs/heart.png';
import imgLungAlarm from '@/assets/imgs/lung_alarm.png'; import imgLungAlarm from '@/assets/imgs/lung_alarm.png';
import imgHeartAlarm from '@/assets/imgs/heart_alarm.png'; import imgHeartAlarm from '@/assets/imgs/heart_alarm.png';
import {useRemoteWsStore} from "@/stores/remote-ws-store"; import {useRemoteWsStore} from "@/stores/remote-ws-store";
import {useLoginStore} from "@/stores/user-info-store"; import {useUserStore} from "@/stores/user-info-store";
import {getPatientInfo} from "@/api/patient"; import {getPatientInfo} from "@/api/patient";
@ -222,7 +222,7 @@ const medicineCustom: any[] = [
] ]
const remoteWsStore = useRemoteWsStore() const remoteWsStore = useRemoteWsStore()
const currentRemote = ref(remoteWsStore.remoteTasks[remoteWsStore.currentTaskIndex]) const currentRemote = ref(remoteWsStore.remoteTasks[remoteWsStore.currentTaskIndex])
const userInfo = useLoginStore() const userInfo = useUserStore()
const chartDom1 = ref(), const chartDom1 = ref(),
chartDom2 = ref(), chartDom2 = ref(),
@ -237,7 +237,7 @@ const isPatientDialog = ref(false)
const database = ref('') const database = ref('')
const databaseOptions = ref([] as { value: string, label: string }[]) const databaseOptions = ref([] as { value: string, label: string }[])
const messageSum = ref(10) const messageSum = ref(10)
const userName = ref(userInfo.login.name) const userName = ref(userInfo.userInfo.name)
const setDatabaseDialog = ref(false); const setDatabaseDialog = ref(false);
const featureTable = ref([] as any[]); const featureTable = ref([] as any[]);
let chartNowData = reactive({ID: 0}); let chartNowData = reactive({ID: 0});
@ -546,7 +546,7 @@ const tableItemCancel = (e: any) => {
} }
function startAI() { function startAI() {
const params = { const params: any = {
name: currentRemote.value.patient, name: currentRemote.value.patient,
id: currentRemote.value.patientId, id: currentRemote.value.patientId,
date: currentRemote.value.date, date: currentRemote.value.date,

View File

@ -1,180 +1,277 @@
<template> <template>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="100" :disabled="type === 'view'" style="padding: 20px;"> <el-form ref="formRef" :model="formData" :rules="rules" label-width="100" :disabled="type === 'view'"
<el-row> style="padding: 20px;">
<el-col :span="12"> <el-row>
<el-form-item label="医院名称" prop="name"> <el-col :span="12">
<el-input v-model="formData.name" placeholder="请输入医院名称" :disabled="type === 'edit'"></el-input> <el-form-item label="医院名称" prop="name">
</el-form-item> <el-input v-model="formData.name" placeholder="请输入医院名称" :disabled="type === 'edit'"></el-input>
</el-col> </el-form-item>
<el-col :span="12"> </el-col>
<el-form-item label="编码" prop="code"> <el-col :span="12">
<el-input v-model="formData.code" placeholder="请输入编码"></el-input> <el-form-item label="编码" prop="code">
</el-form-item> <el-input v-model="formData.code" placeholder="请输入编码"></el-input>
</el-col> </el-form-item>
</el-row> </el-col>
<el-row> </el-row>
<el-col :span="12"> <el-row>
<el-form-item label="开始时间" prop="startTime"> <el-col :span="12">
<el-date-picker v-model="formData.startTime" type="datetime" format="YYYY-MM-DD HH:mm" placeholder="请输入开始时间" /> <el-form-item label="开始时间" prop="startTime">
</el-form-item> <el-date-picker v-model="formData.startTime" type="datetime" format="YYYY-MM-DD HH:mm"
</el-col> placeholder="请输入开始时间"/>
<el-col :span="12"> </el-form-item>
<el-form-item label="结束时间" prop="endTime"> </el-col>
<el-date-picker v-model="formData.endTime" type="datetime" format="YYYY-MM-DD HH:mm" placeholder="请输入结束时间" /> <el-col :span="12">
</el-form-item> <el-form-item label="结束时间" prop="endTime">
</el-col> <el-date-picker v-model="formData.endTime" type="datetime" format="YYYY-MM-DD HH:mm"
</el-row> placeholder="请输入结束时间"/>
<el-row> </el-form-item>
<el-col :span="12"> </el-col>
<el-form-item label="域名" prop="DNS"> </el-row>
<el-input v-model="formData.DNS" placeholder="请输入域名"></el-input> <el-row>
</el-form-item> <el-col :span="12">
</el-col> <el-form-item label="域名" prop="domain">
<el-col :span="12"> <el-input v-model="formData.domain" placeholder="请输入域名"></el-input>
<el-form-item label="状态" prop="state"> </el-form-item>
<el-radio-group v-model="formData.state"> </el-col>
<el-radio label="正常" border>正常</el-radio> <el-col :span="12">
<el-radio label="冻结" border>冻结</el-radio> <el-form-item label="状态" prop="status">
</el-radio-group> <el-radio-group v-model="formData.status">
</el-form-item> <el-radio value="0">正常</el-radio>
</el-col> <el-radio value="1" border>冻结</el-radio>
</el-row> </el-radio-group>
<el-divider border-style="dashed" /> </el-form-item>
<h3 class="main-color f20" style="margin: 10px 0 20px 0;">高级管理员</h3> </el-col>
<el-row> </el-row>
<el-col :span="12"> <el-row>
<el-form-item label="用户名" prop="admin.name"> <el-col>
<el-select v-model="formData.admin.name" filterable placeholder="请输入选择姓名" <el-form-item label="所在城市" prop="selectedOptions">
remote :remote-method="remoteSearchName" @change="selectNameChange"> <el-cascader
<el-option v-for="(item, index) in userOption" :key="'name-' + index" size="large"
:label="item.code" :value="item.code" /> :options="provinceAndCityData"
</el-select> v-model="formData.selectedOptions">
</el-form-item> </el-cascader>
</el-col> </el-form-item>
<el-col :span="12"> </el-col>
<el-form-item label="电话" prop="admin.phone"> </el-row>
<el-input v-model="formData.admin.phone" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="姓名" prop="admin.name">
<el-input v-model="formData.admin.name" disabled></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
</el-col> <el-divider border-style="dashed"/>
</el-row>
<div style="position: absolute;bottom: 50px;right: 50px;" v-if="type !== 'view'"> <div v-if="props.type != 'add'">
<el-button class="f18" @click="close">取消</el-button> <h3 class="main-color f20" style="margin: 10px 0 20px 0;">高级管理员</h3>
<el-button class="f18" type="primary" @click="saveData">确认</el-button> <el-row>
</div> <el-col :span="12">
</el-form> <el-form-item label="用户" prop="manager.id">
<el-select v-model="manager.id" filterable placeholder="请输入选择姓名"
remote :remote-method="remoteSearchName">
<el-option v-for="(item, index) in userOption" :key="'name-' + item.id"
:label="item.name" :value="item.id" @click="selectNameChange(item)"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="电话" prop="manager.phone">
<el-input v-model="manager.phone" disabled></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<!-- <el-col :span="12">
<el-form-item label="姓名" prop="manager.name">
<el-input v-model="manager.name" disabled></el-input>
</el-form-item>
</el-col>-->
<el-col :span="12">
</el-col>
</el-row>
</div>
<div style="position: absolute;bottom: 50px;right: 50px;" v-if="type != 'view'">
<el-button class="f18" @click="close">取消</el-button>
<el-button class="f18" type="primary" @click="saveData">确认</el-button>
</div>
</el-form>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, reactive, ref} from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import {ElMessage, ElMessageBox} from 'element-plus'
import { getusers } from '@/static-data/core' import * as hospitalApi from "@/api/hospital";
import {dateFormater} from "@/utils/date-util";
import * as userApi from "@/api/user";
import {
provinceAndCityData,
pcTextArr,
regionData,
pcaTextArr,
codeToText,
} from "element-china-area-data";
const emit = defineEmits(['close']) const emit = defineEmits(['close'])
const props = defineProps({ const props = defineProps({
type: String type: String
}) })
const users = getusers()
const rules = reactive({ const rules = reactive({
name: [ name: [
{ required: true, message: '请输入医院名称', trigger: ['blur', 'change'] }, {required: true, message: '请输入医院名称', trigger: ['blur', 'change']},
], ],
selectedOptions: [
{required: true, message: '请选择地区', trigger: ['blur', 'change']},
]
}) })
const formRef = ref() const formRef = ref()
const formData = ref({ const formData = ref({
name: '', name: '',
code: '', code: '',
admin: { domain: '',
userName: '', startTime: '',
name: '', endTime: '',
phone: '', selectedOptions: [],
}, status: 0
DNS: '', } as any)
startTime: '', const manager = ref({
endTime: '', id: "",
state: '' name: "",
phone: ""
} as any) } as any)
const userOption = ref([] as any) const userOption = ref([] as any)
let userList: any = []
onMounted(() => { onMounted(() => {
resetData() resetData()
}) })
defineExpose({ defineExpose({
formData, resetData
resetData,
}) })
function close() { function close() {
emit('close') emit('close')
} }
function resetData() {
formRef.value.resetFields() async function resetData(form?: any) {
formData.value = { formRef.value.resetFields()
name: '', if (form) {
code: '', manager.value = {
admin: { id: "",
userName: '', name: '',
name: '', phone: '',
phone: '',
},
DNS: '',
startTime: '',
endTime: '',
state: ''
} }
await getUserList(form.id);
getHospitalAdmin(form.id);
form.selectedOptions = [form.province, form.city]
formData.value = form;
} else {
formData.value = {
name: '',
code: '',
domain: '',
startTime: '',
endTime: '',
status: 0,
selectedOptions: []
}
manager.value = {
id: "",
name: '',
phone: '',
}
}
} }
const remoteSearchName = (e: any) => { const remoteSearchName = (e: any) => {
if (e) { if (e) {
userOption.value = users.filter((o: any) => o.name.indexOf(e) !== -1) userOption.value = userList.filter((user: any) => user.name.indexOf(e) != -1)
} }
} }
const selectNameChange = (e: any) => { const selectNameChange = (e: any) => {
manager.value.phone = e.phone;
manager.value.name = e.name;
} }
const saveData = async () => { const saveData = () => {
await formRef.value.validate((valid: any, fields: any) => { console.log(formData.value)
if (valid) { ElMessageBox.confirm(
ElMessage.success('保存成功!') "是否保存",
close() {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
draggable: true
}
).then(() => {
formRef.value.validate(async (valid: any, fields: any) => {
if (valid) {
const form = Object.assign({}, formData.value);
form.startTime = dateFormater("yyyy-MM-dd hh:mm:ss", form.startTime)
form.endTime = dateFormater("yyyy-MM-dd hh:mm:ss", form.endTime)
form.province = form.selectedOptions[0];
form.city = form.selectedOptions[1];
if (props.type == "edit") {
const hosRes: any = await hospitalApi.updateHospital(form)
const manRes: any = await hospitalApi.saveHospitalManager(form.id, manager.value.id)
if ((hosRes.code == 0 && hosRes.data) || (manRes.code == 0 && manRes.data)) {
ElMessage.success("更新成功")
close();
} else {
ElMessage.error("更新失败")
}
} else { } else {
// console.log('error submit!', fields) hospitalApi.saveHospital(form).then((res: any) => {
if (res.code == 0) {
ElMessage.success('保存成功!');
close();
} else {
ElMessage.error(res.msg ? res.msg : "保存失败");
}
});
} }
}
}) })
}).catch(() => {
})
}
function getHospitalAdmin(hospitalId: string) {
hospitalApi.getHospitalManager(hospitalId).then((res: any) => {
if (res.code == 0 && res.data.length > 0) {
manager.value = res.data[0];
}
})
}
async function getUserList(hospitalId: string) {
const res: any = await userApi.getUserListByHospital(hospitalId)
if (res.code == 0) {
userOption.value = res.data;
userOption.value.unshift({
id: "",
name: '无',
phone: '',
})
userList = userOption.value;
}
} }
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
:deep(.el-form-item) { :deep(.el-form-item) {
.el-form-item__label { .el-form-item__label {
display: block; display: block;
text-align: justify; text-align: justify;
text-align-last: justify; text-align-last: justify;
padding: 0 10px 0 20px; padding: 0 10px 0 20px;
&:before { &:before {
display: none; display: none;
}
} }
}
.el-radio-group { .el-radio-group {
width: 100%; width: 100%;
justify-content: space-between; justify-content: space-between;
.el-radio {
margin: 0; .el-radio {
} margin: 0;
} }
}
} }
</style> </style>

View File

@ -1,71 +1,76 @@
<template> <template>
<div class="table-page"> <div class="table-page">
<div class="search-part" v-show="isSearch"> <div class="search-part" v-show="isSearch">
<div class="search-cell"> <div class="search-cell">
<span class="label">医院名称</span> <span class="label">医院名称</span>
<el-input v-model="queryParams.userName" placeholder="请输入医院名称"></el-input> <el-input v-model="queryParams" placeholder="请输入医院名称"></el-input>
</div> </div>
<el-button type="primary" icon="Search" @click="queryData(queryParams)">查询</el-button> <el-button type="primary" icon="Search" @click="search">查询</el-button>
<el-button icon="Refresh" @click="queryParams = {}">重置</el-button> <el-button icon="Refresh" @click="resetSearch">重置</el-button>
</div>
<div class="button-part" style="justify-content: space-between;">
<div>
<el-button type="primary" icon="FirstAidKit" @click="addData">新增</el-button>
<el-button icon="Delete" @click="removeData()">删除</el-button>
</div>
<TableAbility @searchBtn="isSearch = !isSearch" @refreshBtn="queryData({})"
@downloadBtn="exportData('医生数据', tableData)"></TableAbility>
</div>
<div class="table-part">
<el-table ref="tableRef" v-loading="loading" :data="tableData" height="100%" border show-overflow-tooltip
@row-click="tableRowClick">
<el-table-column type="selection" width="55" />
<el-table-column type="index" label="#" width="55" align="center" />
<el-table-column property="name" label="医院名称" width="200" align="center" />
<el-table-column property="code" label="编码" width="60" align="center" />
<el-table-column label="高级管理员" width="200" align="center">
<template #default="scope">{{ scope.row.admin?.name }}</template>
</el-table-column>
<el-table-column property="DNS" label="域名" width="200" align="center" />
<el-table-column label="开始时间" width="200" align="center">
<template #default="scope">{{ dateFormater('yyyy-MM-dd HH:mm', scope.row.startTime) }}</template>
</el-table-column>
<el-table-column label="结束时间" width="200" align="center">
<template #default="scope">{{ dateFormater('yyyy-MM-dd HH:mm', scope.row.endTime) }}</template>
</el-table-column>
<el-table-column property="state" label="状态" width="60" align="center" />
<el-table-column label="操作" align="center">
<template #default="scope">
<span @click.stop>
<el-button link icon="View" @click="viewData(scope.row)">医院信息</el-button>
<el-button link icon="EditPen" @click="editData(scope.row)">修改</el-button>
<el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button>
</span>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-part">
<CommonPagination :total="100" @paginationChange="paginationChange" />
</div>
</div> </div>
<el-drawer v-model="isFormDialog" size="660px"> <div class="button-part" style="justify-content: space-between;">
<template #header> <div>
<h3 class="main-color f20" style="padding: 20px 20px 0 20px;">{{ formDialogTitle }}</h3> <el-button type="primary" icon="FirstAidKit" @click="addData">新增</el-button>
</template> <el-button icon="Delete" @click="removeData()">删除</el-button>
<HospitalForm ref="hospitalFormRef" </div>
:type="formDialogTitle === '添加' ? 'add' : formDialogTitle === '修改' ? 'edit' : 'view'" <TableAbility @searchBtn="isSearch = !isSearch" @refreshBtn="refresh"
@close="isFormDialog = false" /> @downloadBtn="exportData('医生数据', tableData)"></TableAbility>
</el-drawer> </div>
<div class="table-part">
<el-table ref="tableRef" v-loading="loading" :data="tableData" height="100%" border show-overflow-tooltip
@row-click="tableRowClick">
<el-table-column type="selection" width="55"/>
<el-table-column type="index" label="#" width="55" align="center"/>
<el-table-column property="name" label="医院名称" width="200" align="center"/>
<el-table-column property="code" label="编码" width="60" align="center"/>
<el-table-column label="高级管理员" width="200" align="center">
<template #default="scope">{{ scope.row.admin?.name }}</template>
</el-table-column>
<el-table-column property="domain" label="域名" width="200" align="center"/>
<el-table-column label="开始时间" width="200" align="center">
<template #default="scope">{{ dateFormater('yyyy-MM-dd HH:mm', scope.row.startTime) }}</template>
</el-table-column>
<el-table-column label="结束时间" width="200" align="center">
<template #default="scope">{{ dateFormater('yyyy-MM-dd HH:mm', scope.row.endTime) }}</template>
</el-table-column>
<el-table-column label="状态" width="60" align="center">
<template #default="scope">
{{ scope.row.status == 1 ? "锁定" : "正常" }}
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<div @click.stop>
<el-button link icon="View" @click="viewData(scope.row)">医院信息</el-button>
<el-button link icon="EditPen" @click="editData(scope.row)">修改</el-button>
<el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-part">
<CommonPagination :total="total" @paginationChange="paginationChange"/>
</div>
</div>
<el-drawer v-model="isFormDialog" size="660px">
<template #header>
<h3 class="main-color f20" style="padding: 20px 20px 0 20px;">{{ formDialogTitle }}</h3>
</template>
<HospitalForm ref="hospitalFormRef"
:type="formDialogTitle === '添加' ? 'add' : formDialogTitle === '修改' ? 'edit' : 'view'"
@close="isFormDialog = false"/>
</el-drawer>
</template> </template>
<script lang='ts' setup> <script lang='ts' setup>
import { onMounted, reactive, ref, toRefs, watch } from 'vue' import {onMounted, ref} from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import {exportData, tableRemoveRow} from '@/utils/table-util'
import { tableRemoveRow, exportData } from '@/utils/table-util'
import CommonPagination from '@/components/common-pagination.vue' import CommonPagination from '@/components/common-pagination.vue'
import HospitalForm from './form/hospital-form.vue' import HospitalForm from './form/hospital-form.vue'
import { dateFormater } from '@/utils/date-util' import {dateFormater} from '@/utils/date-util'
import * as hospitalApi from "@/api/hospital";
import {ElMessage, ElMessageBox} from "element-plus";
const tableRef = ref() const tableRef = ref()
const hospitalFormRef = ref() const hospitalFormRef = ref()
@ -73,71 +78,93 @@ const isSearch = ref(true)
const loading = ref(true) const loading = ref(true)
const isFormDialog = ref(false) const isFormDialog = ref(false)
const formDialogTitle = ref('') const formDialogTitle = ref('')
const queryParams = ref({ const queryParams = ref()
userName: ''
} as any)
const tableData = ref([] as any) const tableData = ref([] as any)
let current = 0;
let size = 10;
const total = ref(0);
queryData({ name: '测试' }) onMounted(() => {
init();
})
function queryData(e: any) { function init() {
loading.value = true loading.value = true
tableData.value = [] current = 0;
setTimeout(() => { total.value = 0;
while (tableData.value.length < 10) { getList();
tableData.value.push({ loading.value = false
name: e.name || '测试',
code: '',
admin: {
userName: 'admin',
name: '管理员',
phone: '12345678',
},
DNS: '***.****.***',
startTime: new Date(),
endTime: new Date(),
state: '正常'
})
}
loading.value = false
}, 200);
} }
function getList() {
hospitalApi.getHospitalPage(current, size, queryParams.value).then((res: any) => {
if (res.code == 0) {
tableData.value = res.data.list;
total.value = res.data.total;
}
})
}
function refresh() {
init();
}
function search() {
init();
}
function resetSearch() {
queryParams.value = "";
init();
}
const addData = () => { const addData = () => {
isFormDialog.value = true isFormDialog.value = true
formDialogTitle.value = '添加' formDialogTitle.value = '添加'
setTimeout(() => { setTimeout(() => {
hospitalFormRef.value.resetData() hospitalFormRef.value.resetData()
}, 0) }, 0)
} }
const removeData = (e?: any) => { const removeData = (e?: any) => {
const selectRow = e || tableRef.value.getSelectionRows() const selectRow = e ? [e] : tableRef.value.getSelectionRows()
tableRemoveRow({ data: selectRow }, (res: boolean) => {
if (res) { tableRemoveRow({data: selectRow}, (res: boolean) => {
// console.log('', selectRow) if (res) {
const ids: string[] = [];
selectRow.forEach((row: any) => {
ids.push(row.id);
})
hospitalApi.deleteHospitalByIds(ids.join(",")).then((res: any) => {
if (res.code == 0 && res.data) {
ElMessage.success("删除成功")
} else {
ElMessage.error(res.msg ? res.msg : "删除失败")
} }
}) })
}
})
} }
const viewData = (e: any) => { const viewData = (e: any) => {
isFormDialog.value = true isFormDialog.value = true
formDialogTitle.value = '医院信息' formDialogTitle.value = '医院信息'
setTimeout(() => { setTimeout(() => {
hospitalFormRef.value.resetData() hospitalFormRef.value.resetData(JSON.parse(JSON.stringify(e)))
hospitalFormRef.value.formData = JSON.parse(JSON.stringify(e)) }, 0)
}, 0)
} }
const editData = (e: any) => { const editData = (e: any) => {
isFormDialog.value = true isFormDialog.value = true
formDialogTitle.value = '修改' formDialogTitle.value = '修改'
setTimeout(() => { setTimeout(() => {
hospitalFormRef.value.resetData() hospitalFormRef.value.resetData(JSON.parse(JSON.stringify(e)))
hospitalFormRef.value.formData = JSON.parse(JSON.stringify(e)) }, 0)
}, 0)
} }
const tableRowClick = (row: any) => { const tableRowClick = (row: any) => {
tableRef.value.toggleRowSelection(row) tableRef.value.toggleRowSelection(row)
} }
const paginationChange = (page: number, size: number) => { const paginationChange = (page: number, s: number) => {
current = page;
size = s;
getList();
} }
</script> </script>