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,7 +1,15 @@
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 => {
@ -16,3 +24,99 @@ export const getHospitalList = () => {
}) })
}) })
} }
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

@ -19,7 +19,7 @@ export function getMenuTree(menuName?: string, parent?: string, type?: string) {
.then((res) => { .then((res) => {
resolve(res.data); resolve(res.data);
}).catch(err => { }).catch(err => {
reject(err); resolve(err);
}) })
}) })
} }
@ -39,7 +39,7 @@ export function saveMenu(menu: any) {
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);
}) })
}) })
} }
@ -47,9 +47,9 @@ export function saveMenu(menu: any) {
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);
}) })
}) })
} }

View File

@ -35,7 +35,7 @@ export function deleteByIds(ids: string[]) {
}) })
} }
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,

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)

View File

@ -1,8 +1,9 @@
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),
@ -13,78 +14,24 @@ const router = createRouter({
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
// 普通用户
const commonUser = [
'/login',
'/home',
'/patients-manage',
'/patients-manage/patients-manage',
'/patients-manage/surgery-info'
]
// 中级管理员
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() next()
return return
} }
/*if (!isLogin) next('/login') //
else */ const b = await isViewRoute(to);
if (!isViewRoute()) { if (!b) {
ElMessage.error('无权访问!') ElMessage.error('无权访问!')
next(from.fullPath) next(from.fullPath)
} else next() } 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));
} }
@ -97,4 +44,20 @@ function parseQuery(query: any) {
} }
} }
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,14 +1,16 @@
export const constantRoute=[ export const constantRoute = [
{
{ path: '/:pathMatch(.*)*', name: 'not-found', redirect: '/login' }, path: '/404',
name: "404",
component: () => import('@/views/404/404.vue')
},
{ {
path: '/login', path: '/login',
name: '登录', name: '登录',
component: () => import('@/views/login/login.vue'), component: () => import('@/views/login/login.vue'),
}, },
{ {
path: '/', path: '/page',
redirect: '/login',
component: () => import('@/views/index.vue'), component: () => import('@/views/index.vue'),
children: [ children: [
{ {
@ -123,6 +125,11 @@ export const constantRoute=[
path: '/logs-manage/logs-manage', path: '/logs-manage/logs-manage',
name: '日志管理', name: '日志管理',
component: () => import('@/views/logs-manage/logs-manage.vue'), 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

@ -108,3 +108,27 @@ export function getDays(date: any, days: number) {
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

@ -5,15 +5,15 @@
<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;">
@ -21,7 +21,7 @@
</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>
@ -44,7 +44,7 @@
<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>
@ -55,13 +55,46 @@
</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> </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,36 +103,71 @@ 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>
@ -227,4 +295,16 @@ function getTodoCount() {
} }
} }
} }
.message-drawer-box {
.body {
margin-bottom: 20px;
}
.footer {
position: fixed;
bottom: 6px;
background: white;
}
}
}</style> }</style>

View File

@ -2,9 +2,14 @@
<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>
<el-date-picker v-model="currentMonth" format="YYYY年MM月" type="month" :editable="false" :clearable="false"
@change="getData"/>
<el-icon @click="getData(downMonth)">
<ArrowRight/>
</el-icon>
</div> </div>
</div> </div>
<div ref="chartDom" class="chart-dom"></div> <div ref="chartDom" class="chart-dom"></div>
@ -13,9 +18,10 @@
</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,13 +31,13 @@ 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();
@ -55,11 +61,11 @@ function initChart(chartData: any) {
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: {
@ -67,11 +73,11 @@ function initChart(chartData: any) {
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',
@ -108,28 +114,34 @@ 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
for (let i = 0; i < days; i++) { const start = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth(), 1)
xData.push((i < 9 ? '0' : '') + (i + 1)) const end = new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 0)
data.push(Math.ceil(Math.random() * 10)) medicineApi.getSurgeryCount(dateFormater("yyyy-MM-dd", start), dateFormater("yyyy-MM-dd", end)).then(res => {
num += data[i] if (res.code == 0) {
} 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 { .date-btn {
position: absolute; position: absolute;
height: 50px; height: 50px;
@ -139,20 +151,25 @@ const getData = (date: any) => {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
z-index: 1; z-index: 1;
.btn-box { .btn-box {
height: 30px; height: 30px;
display: flex; display: flex;
align-items: center; align-items: center;
color: $text2-color; color: $text2-color;
&>:deep(.el-date-editor) {
& > :deep(.el-date-editor) {
font-size: 14px; font-size: 14px;
.el-input__wrapper { .el-input__wrapper {
box-shadow: none; box-shadow: none;
padding: 0; padding: 0;
.el-input__prefix, .el-input__prefix,
.el-input__suffix { .el-input__suffix {
display: none; display: none;
} }
.el-input__inner { .el-input__inner {
cursor: pointer; cursor: pointer;
width: 100px; width: 100px;
@ -161,15 +178,18 @@ const getData = (date: any) => {
} }
} }
} }
.el-icon { .el-icon {
cursor: pointer; cursor: pointer;
} }
} }
} }
.chart-dom { .chart-dom {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.total-mini { .total-mini {
position: absolute; position: absolute;
top: 0; top: 0;
@ -179,5 +199,5 @@ const getData = (date: any) => {
font-size: 14px; font-size: 14px;
padding: 3px 8px; padding: 3px 8px;
} }
} }
</style> </style>

View File

@ -3,11 +3,12 @@
<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"
@change="getData"/>
<el-icon @click="getData(downMonth)"> <el-icon @click="getData(downMonth)">
<ArrowRight /> <ArrowRight/>
</el-icon> </el-icon>
</div> </div>
</div> </div>
@ -19,9 +20,11 @@
</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()
@ -86,15 +89,27 @@ 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) => {
pieData.value.push({value: Math.ceil(Math.random() * 10), name: item, itemStyle: { const start = dateFormater("yyyy-MM-dd", new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth(), 1))
color: color[index] const end = dateFormater("yyyy-MM-dd", new Date(currentMonth.value.getFullYear(), currentMonth.value.getMonth() + 1, 0))
}}) medicineApi.getSurgeryTypeProportion(start, end).then(res => {
if (res.code == 0) {
res.data.forEach((item: any, i: number) => {
const c = generateRandomColor()
color.push(c)
pieData.value.push({
value: item.count,
name: item._id,
itemStyle: {
color: c
}
}) })
initChart({ data: pieData.value, color }) })
}
initChart({data: pieData.value, color})
});
} }
</script> </script>
@ -122,15 +137,18 @@ const getData = (date: any) => {
align-items: center; align-items: center;
color: $text2-color; color: $text2-color;
&>:deep(.el-date-editor) { & > :deep(.el-date-editor) {
font-size: 14px; font-size: 14px;
.el-input__wrapper { .el-input__wrapper {
box-shadow: none; box-shadow: none;
padding: 0; padding: 0;
.el-input__prefix, .el-input__prefix,
.el-input__suffix { .el-input__suffix {
display: none; display: none;
} }
.el-input__inner { .el-input__inner {
cursor: pointer; cursor: pointer;
width: 100px; width: 100px;
@ -163,6 +181,7 @@ const getData = (date: any) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
.total-item { .total-item {
padding: 5px 0; padding: 5px 0;
} }

View File

@ -3,12 +3,12 @@
<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>
@ -17,9 +17,10 @@
</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()
@ -33,6 +34,7 @@ onMounted(() => {
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();
@ -67,11 +69,11 @@ function initChart(chartData: any) {
name: '日期', name: '日期',
show: true, show: true,
type: 'category', type: 'category',
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, color: '#909399', formatter: (value: any) => getCurrentDate(value) }, axisLabel: {show: true, color: '#909399', formatter: (value: any) => getCurrentDate(value)},
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: {
@ -79,11 +81,11 @@ function initChart(chartData: any) {
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: [{
name: chartData.dataName[0], name: chartData.dataName[0],
@ -124,20 +126,29 @@ function initChart(chartData: any) {
chart.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>
@ -165,7 +176,7 @@ const getData = (date: any) => {
align-items: center; align-items: center;
color: $text2-color; color: $text2-color;
&>:deep(.el-date-editor) { & > :deep(.el-date-editor) {
font-size: 14px; font-size: 14px;
.el-input__wrapper { .el-input__wrapper {

View File

@ -3,11 +3,12 @@
<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"
@change="getData"/>
<el-icon @click="getData(downMonth)"> <el-icon @click="getData(downMonth)">
<ArrowRight /> <ArrowRight/>
</el-icon> </el-icon>
</div> </div>
</div> </div>
@ -17,9 +18,10 @@
</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()
@ -55,11 +57,11 @@ function initChart(chartData: any) {
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: {
@ -67,11 +69,11 @@ function initChart(chartData: any) {
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',
@ -108,17 +110,23 @@ 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>
@ -147,15 +155,18 @@ const getData = (date: any) => {
align-items: center; align-items: center;
color: $text2-color; color: $text2-color;
&>:deep(.el-date-editor) { & > :deep(.el-date-editor) {
font-size: 14px; font-size: 14px;
.el-input__wrapper { .el-input__wrapper {
box-shadow: none; box-shadow: none;
padding: 0; padding: 0;
.el-input__prefix, .el-input__prefix,
.el-input__suffix { .el-input__suffix {
display: none; display: none;
} }
.el-input__inner { .el-input__inner {
cursor: pointer; cursor: pointer;
width: 100px; width: 100px;

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> <el-button text @click="userStore.showHomeMsg=true">
<el-badge is-dot> <el-badge is-dot>
<el-icon> <el-icon>
<Bell/> <Bell/>
@ -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

@ -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) {
@ -314,11 +301,10 @@ const sendCode = () => {
} }
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;
// //
@ -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,14 +339,19 @@ 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.push('/home') router.removeRoute("root");
router.addRoute({
name: "root",
path: "/",
redirect: "/home"
})
router.replace('/home')
} }
}) })
} }
@ -371,9 +363,9 @@ function sliderClose() {
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,7 +1,7 @@
<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>
<div class="content-box"> <div class="content-box">
<!-- <div class="header-box"> <!-- <div class="header-box">
@ -9,7 +9,7 @@
</div> --> </div> -->
<div class="main-box"> <div class="main-box">
<div class="background-block"> <div class="background-block">
<RouterView /> <RouterView/>
</div> </div>
</div> </div>
</div> </div>
@ -17,14 +17,15 @@
</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()
@ -62,6 +63,7 @@ const selectMenu = (e: MenuItem) => {
// height: calc(100% - 50px); // height: calc(100% - 50px);
height: 100%; height: 100%;
padding: 10px; padding: 10px;
.background-block { .background-block {
width: 100%; width: 100%;
height: 100%; height: 100%;

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,33 +1,44 @@
<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-form-item label="上级菜单">
<el-radio label="0" border>菜单</el-radio> <span>{{ formData.parentName }}</span>
<el-radio label="1" border v-if="formData.parentId != -1">按钮</el-radio> </el-form-item>
<el-form-item label="类型" v-if="type === 'edit'">
<span>{{ formData.menuType == 0 ? "菜单" : "按钮" }}</span>
</el-form-item>
<el-form-item label="类型" prop="type" v-else>
<el-radio-group v-model="formData.menuType">
<el-radio value="0" border>菜单</el-radio>
<el-radio value="1" border v-if="formData.parentId != -1">按钮</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </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-form-item label="菜单名称" prop="name">
<el-input v-model="formData.name" placeholder="请输入菜单名称"></el-input> <el-input v-model="formData.name" placeholder="请输入菜单名称"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="图标" prop="icon"> <el-form-item label="图标" prop="icon">
<i :class="formData.icon" style="font-size: 26px;margin: 0 10px;"></i> <i :class="formData.icon" style="font-size: 26px;margin: 0 10px;"></i>
<el-button @click="isIconDialog = true">选择图标</el-button> <el-button @click="isIconDialog = true">选择图标</el-button>
</el-form-item> </el-form-item>
<el-form-item label="路由" prop="route"> <el-form-item label="路由" prop="route">
<el-input v-model="formData.path" placeholder="请输入路由"></el-input> <el-input v-model="formData.path" placeholder="请输入路由"></el-input>
</el-form-item> </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-form-item label="排序" prop="order">
<el-input class="number-input" v-model="formData.sortOrder" <el-input class="number-input" v-model="formData.sortOrder"
type="number" input-style="text-align: center;" type="number" input-style="text-align: center;"
@change="numberInputChange"> @change="numberInputChange">
<template #prepend> <template #prepend>
<el-button text icon="Minus" :disabled="formData.sortOrder <= 1" <el-button text icon="Minus" :disabled="formData.sortOrder <= 0"
@click="formData.sortOrder--"/> @click="formData.sortOrder--"/>
</template> </template>
<template #append> <template #append>
@ -35,10 +46,11 @@
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item label="是否显示" prop="visible"> <el-form-item label="是否显示" prop="visible">
<el-radio-group v-model="formData.visible"> <el-radio-group v-model="formData.visible">
<el-radio label="1" border></el-radio> <el-radio value="1" border></el-radio>
<el-radio label="0" border></el-radio> <el-radio value="0" border></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
@ -104,7 +116,8 @@ function resetData(menu?: any, form?: any) {
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 {
@ -116,15 +129,16 @@ function resetData(menu?: any, form?: any) {
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) => {

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

@ -19,16 +19,22 @@
<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 property="menuType" label="类型" width="180" align="center"/> <el-table-column label="类型" width="180" align="center">
<template #default="scope">
<span>{{ scope.row.menuType == 0 ? "菜单" : "按钮" }}</span>
</template>
</el-table-column>
<el-table-column property="sortOrder" label="排序" width="80" align="center"/>
<el-table-column label="操作" align="center"> <el-table-column label="操作" align="center">
<template #default="scope"> <template #default="scope">
<div @click.stop> <div @click.stop>
<el-button link icon="EditPen" @click="addData(scope.row)">新建下级</el-button> <el-button link icon="EditPen" v-if="scope.row.menuType == 0" @click="addData(scope.row)">
新建下级
</el-button>
<el-button link icon="EditPen" @click="editData(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> <el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button>
</div> </div>
@ -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)
@ -84,7 +89,7 @@ function resetSearch() {
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);
}) })
} }

View File

@ -27,17 +27,10 @@
<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
trigger="hover"
:content="scope.row.menu"
>
<template #reference>
<div class="cell-content"> <div class="cell-content">
{{ scope.row.menu }} {{ scope.row.menu }}
</div> </div>
</template> </template>
</el-popover>
</template>
</el-table-column> </el-table-column>
<el-table-column label="创建时间" width="220" align="center"> <el-table-column label="创建时间" width="220" align="center">
<template #default="scope">{{ scope.row.createTime }}</template> <template #default="scope">{{ scope.row.createTime }}</template>

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,5 +1,6 @@
<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'"
style="padding: 20px;">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="医院名称" prop="name"> <el-form-item label="医院名称" prop="name">
@ -15,60 +16,76 @@
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="开始时间" prop="startTime"> <el-form-item label="开始时间" prop="startTime">
<el-date-picker v-model="formData.startTime" type="datetime" format="YYYY-MM-DD HH:mm" placeholder="请输入开始时间" /> <el-date-picker v-model="formData.startTime" type="datetime" format="YYYY-MM-DD HH:mm"
placeholder="请输入开始时间"/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="结束时间" prop="endTime"> <el-form-item label="结束时间" prop="endTime">
<el-date-picker v-model="formData.endTime" type="datetime" format="YYYY-MM-DD HH:mm" placeholder="请输入结束时间" /> <el-date-picker v-model="formData.endTime" type="datetime" format="YYYY-MM-DD HH:mm"
placeholder="请输入结束时间"/>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="域名" prop="DNS"> <el-form-item label="域名" prop="domain">
<el-input v-model="formData.DNS" placeholder="请输入域名"></el-input> <el-input v-model="formData.domain" placeholder="请输入域名"></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="状态" prop="state"> <el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.state"> <el-radio-group v-model="formData.status">
<el-radio label="正常" border>正常</el-radio> <el-radio value="0">正常</el-radio>
<el-radio label="冻结" border>冻结</el-radio> <el-radio value="1" border>冻结</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-divider border-style="dashed" /> <el-row>
<el-col>
<el-form-item label="所在城市" prop="selectedOptions">
<el-cascader
size="large"
:options="provinceAndCityData"
v-model="formData.selectedOptions">
</el-cascader>
</el-form-item>
</el-col>
</el-row>
<el-divider border-style="dashed"/>
<div v-if="props.type != 'add'">
<h3 class="main-color f20" style="margin: 10px 0 20px 0;">高级管理员</h3> <h3 class="main-color f20" style="margin: 10px 0 20px 0;">高级管理员</h3>
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="用户名" prop="admin.name"> <el-form-item label="用户" prop="manager.id">
<el-select v-model="formData.admin.name" filterable placeholder="请输入选择姓名" <el-select v-model="manager.id" filterable placeholder="请输入选择姓名"
remote :remote-method="remoteSearchName" @change="selectNameChange"> remote :remote-method="remoteSearchName">
<el-option v-for="(item, index) in userOption" :key="'name-' + index" <el-option v-for="(item, index) in userOption" :key="'name-' + item.id"
:label="item.code" :value="item.code" /> :label="item.name" :value="item.id" @click="selectNameChange(item)"/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="电话" prop="admin.phone"> <el-form-item label="电话" prop="manager.phone">
<el-input v-model="formData.admin.phone" disabled></el-input> <el-input v-model="manager.phone" disabled></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row> <el-row>
<el-col :span="12"> <!-- <el-col :span="12">
<el-form-item label="姓名" prop="admin.name"> <el-form-item label="姓名" prop="manager.name">
<el-input v-model="formData.admin.name" disabled></el-input> <el-input v-model="manager.name" disabled></el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>-->
<el-col :span="12"> <el-col :span="12">
</el-col> </el-col>
</el-row> </el-row>
</div>
<div style="position: absolute;bottom: 50px;right: 50px;" v-if="type !== 'view'"> <div style="position: absolute;bottom: 50px;right: 50px;" v-if="type != 'view'">
<el-button class="f18" @click="close">取消</el-button> <el-button class="f18" @click="close">取消</el-button>
<el-button class="f18" type="primary" @click="saveData">确认</el-button> <el-button class="f18" type="primary" @click="saveData">确认</el-button>
</div> </div>
@ -76,83 +93,162 @@
</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: '',
name: '',
phone: '',
},
DNS: '',
startTime: '', startTime: '',
endTime: '', endTime: '',
state: '' selectedOptions: [],
status: 0
} as any)
const manager = ref({
id: "",
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() {
async function resetData(form?: any) {
formRef.value.resetFields() formRef.value.resetFields()
if (form) {
manager.value = {
id: "",
name: '',
phone: '',
}
await getUserList(form.id);
getHospitalAdmin(form.id);
form.selectedOptions = [form.province, form.city]
formData.value = form;
} else {
formData.value = { formData.value = {
name: '', name: '',
code: '', code: '',
admin: { domain: '',
userName: '',
name: '',
phone: '',
},
DNS: '',
startTime: '', startTime: '',
endTime: '', endTime: '',
state: '' 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)
ElMessageBox.confirm(
"是否保存",
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
draggable: true
}
).then(() => {
formRef.value.validate(async (valid: any, fields: any) => {
if (valid) { if (valid) {
ElMessage.success('保存成功!') const form = Object.assign({}, formData.value);
close() 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 { } else {
// console.log('error submit!', fields) ElMessage.error("更新失败")
}
} else {
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>
@ -172,6 +268,7 @@ const saveData = async () => {
.el-radio-group { .el-radio-group {
width: 100%; width: 100%;
justify-content: space-between; justify-content: space-between;
.el-radio { .el-radio {
margin: 0; margin: 0;
} }

View File

@ -3,50 +3,54 @@
<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>
<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="Delete" @click="removeData()">删除</el-button> <el-button icon="Delete" @click="removeData()">删除</el-button>
</div> </div>
<TableAbility @searchBtn="isSearch = !isSearch" @refreshBtn="queryData({})" <TableAbility @searchBtn="isSearch = !isSearch" @refreshBtn="refresh"
@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="name" label="医院名称" width="200" 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 property="code" label="编码" width="60" align="center"/>
<el-table-column label="高级管理员" width="200" align="center"> <el-table-column label="高级管理员" width="200" align="center">
<template #default="scope">{{ scope.row.admin?.name }}</template> <template #default="scope">{{ scope.row.admin?.name }}</template>
</el-table-column> </el-table-column>
<el-table-column property="DNS" label="域名" width="200" align="center" /> <el-table-column property="domain" label="域名" width="200" align="center"/>
<el-table-column 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> <template #default="scope">{{ dateFormater('yyyy-MM-dd HH:mm', scope.row.startTime) }}</template>
</el-table-column> </el-table-column>
<el-table-column label="结束时间" width="200" align="center"> <el-table-column label="结束时间" width="200" align="center">
<template #default="scope">{{ dateFormater('yyyy-MM-dd HH:mm', scope.row.endTime) }}</template> <template #default="scope">{{ dateFormater('yyyy-MM-dd HH:mm', scope.row.endTime) }}</template>
</el-table-column> </el-table-column>
<el-table-column property="state" label="状态" width="60" align="center" /> <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"> <el-table-column label="操作" align="center">
<template #default="scope"> <template #default="scope">
<span @click.stop> <div @click.stop>
<el-button link icon="View" @click="viewData(scope.row)">医院信息</el-button> <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="EditPen" @click="editData(scope.row)">修改</el-button>
<el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button> <el-button link icon="Delete" @click="removeData(scope.row)">删除</el-button>
</span> </div>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<div class="pagination-part"> <div class="pagination-part">
<CommonPagination :total="100" @paginationChange="paginationChange" /> <CommonPagination :total="total" @paginationChange="paginationChange"/>
</div> </div>
</div> </div>
<el-drawer v-model="isFormDialog" size="660px"> <el-drawer v-model="isFormDialog" size="660px">
@ -55,17 +59,18 @@
</template> </template>
<HospitalForm ref="hospitalFormRef" <HospitalForm ref="hospitalFormRef"
:type="formDialogTitle === '添加' ? 'add' : formDialogTitle === '修改' ? 'edit' : 'view'" :type="formDialogTitle === '添加' ? 'add' : formDialogTitle === '修改' ? 'edit' : 'view'"
@close="isFormDialog = false" /> @close="isFormDialog = false"/>
</el-drawer> </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,35 +78,46 @@ 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({
name: e.name || '测试',
code: '',
admin: {
userName: 'admin',
name: '管理员',
phone: '12345678',
},
DNS: '***.****.***',
startTime: new Date(),
endTime: new Date(),
state: '正常'
})
}
loading.value = false 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 = '添加'
@ -110,10 +126,21 @@ const addData = () => {
}, 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) => {
tableRemoveRow({data: selectRow}, (res: boolean) => {
if (res) { if (res) {
// console.log('', selectRow) 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 : "删除失败")
}
})
} }
}) })
} }
@ -121,23 +148,23 @@ 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>