Files
xj-screen/src/views/indexSun.vue
T
weixin c7abcf1f67 update
1.新需求2025.9.19新需求:
去掉"健康监测"副屏, 修改后健康终端报警点击查看详情弹出告警记录分页列表;
去掉【体检人数统计】【体检数据】【健康打卡数据】,增加【心血管监测】模块功能,【心血管监测】功能将原心血管监测大屏上的内容整理并移动到急救服务平台大屏中;
员工求助时,地图中推荐两个医院、两个健康小屋、两个AED坐标信息,并按距离排序,体现距离远近顺序;
地图中油田医院、健康小屋等各个图例,显示总数信息;
救护车坐标信息维护,并在大屏上标记;
右上角"增加【救助信息】板块, 当出现应急弹窗后或从今日应急选中应急事件 , 该板块需展示应急事件的相关信息(开发中);
2025-09-24 20:53:28 +08:00

732 lines
25 KiB
Vue

<template>
<div class="sun-screen-box">
<login-out-button out-url="login" />
<div class="sun-screen-title">
<div class="sun-title-left">
{{ dateInfo?.day }} {{ dateInfo?.times }}<span style="margin-left: 10px">{{ rightDate }}</span>
</div>
<div class="sun-title-center">{{ getCenterInfo.screenTitle || '健康服务中心' }}</div>
<div class="sun-title-right">
<a-button class="top-right-button" @click="toOther">健康监测大屏</a-button>
</div>
</div>
<div class="sun-body-content">
<div class="sun-body-left">
<div class="sun-body-left-one">
<OneL @handle-click="handleOneLeftClick" :center-id="centerId" :bKey="`one-l-${count}`" />
</div>
<div class="sun-body-left-two">
<twoL @handle-view="handleTwoLClick" :center-id="centerId" :bKey="`two-l-${count}`" />
</div>
<div class="sun-body-left-three">
<three-left-new :bKey="`three-l-n-${count}`" :center-id="centerId" />
<!-- <threeL />-->
<!-- <threeNewL :bKey="`three-l-${count}`" :center-id="centerId" />-->
</div>
<!-- <div class="sun-body-left-four" style="margin-bottom: 0">-->
<!-- <threeR @handle-click="handleThreeRClick" :center-id="centerId" :bKey="`four-l-${count}`" />-->
<!-- </div>-->
</div>
<div class="sun-body-center">
<CenterMap
ref="centerMapRef"
:showHospitalList="showHospitalList"
:hospitalList="hospitalList"
@clear-hospital-list="clearHospitalList"
:show-rest-b="showRestB"
@handle-detail="handleCenterMapClick"
:show-map-bottom="showMapBottom"
@show-rest-b="
() => {
userData = {};
showRestB = false;
showMapBottom = false;
}
"
/>
</div>
<div class="sun-body-right">
<div class="sun-body-right-one">
<one-right-new :user-data="userData" @handle-view="handleOneRightView" @handle-archives="handleArchives" />
</div>
<div class="sun-body-right-two">
<oneR
@handle-view="handleOneRClick"
@show-reset="
() => {
showRestB = true;
}
"
:bKey="`one-r-${count}`"
/>
</div>
<div class="sun-body-right-three">
<two-new-r :center-id="centerId" :bKey="`two-n-r-${count}`" @handle-view="handleTwoNewRClick" />
</div>
</div>
</div>
</div>
<PhoneDialog ref="phoneDialogRef" :title="phoneDialogTitle" :useForm="true" :setting="setting" :phoneType="phoneType" />
<!-- 健康监测弹窗 -->
<EmployeeDialog ref="employeeDialogRef" :record="socketData" />
<!-- 应急、120弹窗 -->
<EmergencyDialog ref="emergencyDialogRef" :record="socketData1" @confirm-help="confirmHelp" />
<IndexModal
ref="indexModalRef"
:api="modalApi"
:api-params="apiParams"
:title="indexModalTitle"
:useForm="true"
:column="indexColumn"
:firstForm="firstFormOne"
:need-dept="needDept"
:twoROnly="twoROnly"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'cz'">
<a-button type="link" @click="forHelp(record)">救助信息</a-button>
</template>
</template>
</IndexModal>
</template>
<script setup lang="ts">
import OneL from '/@/views/indexSun/oneL.vue';
import twoL from '/@/views/indexSun/twoL.vue';
import oneR from '/@/views/indexSun/oneR.vue';
import CenterMap from '/@/views/indexSun/centerMap.vue';
import { ServerDetailType } from '/@/components/body-d-left/bodyLeftHooks.ts';
import {
centerMapColumns,
centerMapFromList,
columns,
fromLists,
infoContentSpecial,
oneRNewColumns,
threeRModalColumns,
threeRModalFromList,
towRcolumns,
twoRform,
twoRNewColumns,
twoRNewForm,
} from '/@/views/indexSun/indexSun.ts';
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import PhoneDialog from '/@/views/components/phoneDialog/phoneDialog.vue';
import { DataType, getSettings } from '/@/utils/settings.ts';
import IndexModal from '/@/views/indexSun/indexModal.vue';
import LoginOutButton from '/@/views/components/loginOutButton.vue';
import router from '/@/router';
import { getAuthCache } from '/@/utils/auth.ts';
import { basicPath, useSocket, emergencyPath } from '/@/utils/socket.ts';
import { Map } from '/@/assets/mapUtils/map.ts';
import EmployeeDialog from '/@/views/components/employeeDialog.vue';
import EmergencyDialog from '/@/views/components/emergencyDialog.vue';
import { handleSocketUrl, startTime } from '/@/utils/utils.ts';
import { useUserStore } from '/@/store/modules/user.ts';
const { getCenterInfo, setCount } = useUserStore();
import {
healthArchivesApi,
nearResourcesApi,
oneLApi,
roomDetailApi,
threeRModalApi,
todayEmergencyListApi,
twoLModalApi,
twoRModal1Api,
twoRModal2Api,
twoRModal3Api,
twoRNApi,
} from '/@/views/indexSun/indexSun.api.ts';
import dayjs from 'dayjs';
import ThreeLeftNew from '/@/views/indexSun/threeLeftNew.vue';
import OneRightNew from '/@/views/indexSun/oneRightNew.vue';
import TwoNewR from '/@/views/indexSun/twoNewR.vue';
//0:处置 1:处理 2:呼入 3:全部
const phoneType = ref('');
const phoneDialogTitle = ref('呼入电话');
const phoneDialogRef = ref();
const indexModalRef = ref();
const indexModalTitle = ref();
const indexColumn: any = ref([]);
const setting = getSettings(DataType.xian);
const firstFormOne = ref();
const centerId = ref();
const apiParams = ref();
const modalApi = ref();
const needDept = ref(false);
const twoROnly = ref();
const showRestB = ref(false);
const dateInfo = ref<object>({});
const rightDate = ref<string>('');
const count = ref<number>(0);
const qhInterval = ref();
const cInterval = ref();
const initDate = ref(startTime);
const showMapBottom = ref(false);
const userData = ref<object>({});
const centerMapRef = ref();
onMounted(() => {
getTime();
qhInterval.value = setInterval(() => {
getTime();
}, 1000);
cInterval.value = setInterval(
() => {
count.value++;
},
5 * 60 * 1000
);
rightDate.value = '累计运行时间:' + (dayjs().diff(dayjs(initDate.value), 'days') + 1) + ' 天';
const centerInfo = getAuthCache('centerInfo');
centerId.value = centerInfo.id;
document.title = centerInfo.screenTitle || '健康服务中心';
});
const getTime = () => {
dateInfo.value = {
day: dayjs().format('YYYY年MM月DD日'),
times: dayjs().format('HH:mm:ss'),
};
};
watch(
() => dateInfo.value.day,
() => {
rightDate.value = '累计运行时间:' + (dayjs().diff(dayjs(initDate.value), 'days') + 1) + ' 天';
}
);
async function forHelp(record: any) {
showMapBottom.value = false;
indexModalRef.value.closeDialog();
record['lat'] = record?.latitude;
record['lon'] = record?.longitude;
if (record['lat']) {
let list: any = [];
const res: any = await nearResourcesApi({ longitude: record?.lon, latitude: record?.lat });
if (res.code === 200) {
list = res.result || [];
}
record['hospitalList'] = list.map((item: any) => {
item['latitude'] = item['lat'];
item['longitude'] = item['lon'];
return item;
});
} else {
centerMapRef.value.resetMap();
showRestB.value = false;
userData.value = record;
}
confirmHelp(record);
}
function toOther() {
window.open('http://aygc.jy.pc.iosp.ydpt.tech/envShow/envFullscreen', '_blank');
}
function handleOneLeftClick(item: any) {
const { name, key } = item;
//呼入电话
//受理电话
if (key == 'alerdyreceive' || key == 'gross') {
phoneType.value = (ServerDetailType as any)[key];
indexModalTitle.value = name;
firstFormOne.value = fromLists[0];
indexColumn.value = columns[0];
modalApi.value = oneLApi;
needDept.value = false;
apiParams.value = {
phoneType: key == 'gross' ? 0 : 1,
centerId: centerId.value,
};
twoROnly.value = '';
nextTick(() => {
indexModalRef.value.openDialog();
});
}
}
function handleTwoLClick() {
indexModalTitle.value = '主诉分类详情';
indexColumn.value = columns[1];
firstFormOne.value = fromLists[1];
twoROnly.value = '';
modalApi.value = twoLModalApi;
needDept.value = true;
nextTick(() => {
indexModalRef.value.openDialog();
});
}
function handleOneRClick() {
router.push({
path: '/indexSon',
});
}
// 健康监测工具报警
let socketUrl = handleSocketUrl(basicPath, getCenterInfo?.id);
const { socketData, setSocketData, closeSocket } = useSocket(socketUrl);
const employeeDialogRef = ref();
function employeeDialogOpen() {
setSocketData1({
userId: '1942871719583739905',
phone: '15129287781',
realName: '连龙刚',
lon: 108.94734,
lat: 34.218951,
sex: 2,
age: 37,
orgCode: 'A01A01A02',
orgName: '硬件部',
departCode: 'A01A01',
departName: '软硬件开发部',
type: '0',
centerId: '1940693902422519809',
popType: 1,
queue: null,
noticeId: null,
careLiaisonName: '周飞飞',
careLiaisonPhone: '18800001111',
lifeguardName: '李林林',
lifeguardPhone: '15511110000',
});
emergencyDialogRef.value.openDialog();
}
setTimeout(() => {
// employeeDialogOpen();
// openEmergencyOpen();
// yunZOpen();
}, 5000);
watch(socketData, (nVal) => {
if (nVal) {
nextTick(() => {
setCount();
setSocketData(nVal);
employeeDialogRef.value.openDialog();
});
}
});
//应急求助、120弹窗
let socketUrl1 = handleSocketUrl(emergencyPath, getCenterInfo?.id);
const { socketData: socketData1, setSocketData: setSocketData1, closeSocket: closeSocket1 } = useSocket(socketUrl1, false);
const emergencyDialogRef = ref(); //紧急求助
watch(socketData1, (nVal) => {
if (nVal) {
setCount();
setSocketData1(nVal);
emergencyDialogRef.value.openDialog();
}
});
const hospitalList = ref([]); //医院列表
const showHospitalList = ref(false);
async function confirmHelp(data: any) {
if (!data.lon) return (showMapBottom.value = true);
Map.removeOverlayGroup();
hospitalList.value = data.hospitalList;
// showHospitalList.value = true;
//用户的坐标信息
let point = [data.lon, data.lat];
// if (data.hospitalList && data.hospitalList.length > 0) {
// try {
const a = ((await getHospitalList(data.hospitalList, point)) as any) || [];
hospitalList.value = a.sort((a: any, b: any) => a.distance - b.distance);
// showHospitalList.value = true;
// } catch (error) {
// console.log('获取医院列表时出错:', error);
// }
// } else {
// console.log('没有医院list');
// }
// showMapBottom.value = true;
const arr = await Map.createOverlay1(
[...hospitalList.value, { latitude: data.lat, longitude: data.lon }],
{
content: (val) => {
return `<div style="
width: 21px;
height: 44px;
position: absolute;
left: -20px;
top: -20px;" title="${val?.name}">
</div>`;
},
},
async (val) => {
if (val.type == '3') {
Map.createInfoModal({ option: val, content: infoContentSpecial(val) });
} else if (val.type == '4') {
Map.createInfoModal({ option: val, content: infoContentSpecial(val) });
} else {
Map.createInfoModal({ option: val, content: infoContentSpecial(val) });
}
Map.clearNaviLine();
Map.createNaviLine([val.lon, val.lat], [data.lon, data.lat]);
// const viewBtn = document.getElementById(val.id);
// viewBtn.onclick = () => {
// handleClcikDetail(val);
// };
('');
},
true,
'1'
);
Map.getAddressByPoint(point)
.then((res) => {
const option = {
lon: data.lon,
lat: data.lat,
position: point,
name: data.realName,
address: res,
sex: data.sex,
};
Map.createEmergencyMarker(option);
Map.map.setFitView([...arr, Map.emergencyMarker], false, [180, 180, 180, 180]);
})
.catch((err) => {});
userData.value = data;
}
async function getHospitalList(hospitalList, userLocation) {
const hospitalPromises = hospitalList.map(async (item) => {
item.distance = getDistance(userLocation, [item.lon, item.lat]);
let t = '';
let r = '';
if (item.distance > 2000) {
const { time, routeList } = await getDriveTime(userLocation, [item.lon, item.lat]);
t = time;
r = routeList;
} else {
const { time, routeList } = await getWalkingTime(userLocation, [item.lon, item.lat]);
t = time;
r = routeList;
}
item.driveTime = t;
item.routeList = r;
item.userLocation = userLocation;
return item; // 返回更新后的医院条目
});
return Promise.all(hospitalPromises);
}
function getDistance(userLocation, destination) {
const value = Map.getDistance(userLocation, destination);
// return value > 1000 ? (value / 1000).toFixed(2) + 'km' : parseInt(value) + 'm';
return value;
}
async function getDriveTime(userLocation, destination) {
let { time, steps } = await Map.getDriveTime(userLocation, destination);
let h,
m,
s = 0;
if (time <= 60) {
return {
time: `${s}秒`,
routeList: steps,
};
}
if (time > 60 && time < 3600) {
m = Math.floor(time / 60);
return {
time: `${m}分`,
routeList: steps,
};
}
if (time >= 3600) {
h = Math.floor(time / 3600);
m = Math.floor((time - h * 3600) / 60);
return {
time: `${h}小时${m}分`,
routeList: steps,
};
}
}
async function getWalkingTime(userLocation, destination) {
let { time, steps } = await Map.getWalkingTime(userLocation, destination);
let h,
m,
s = 0;
if (time <= 60) {
return {
time: `${s}秒`,
routeList: steps,
};
}
if (time > 60 && time < 3600) {
m = Math.floor(time / 60);
return {
time: `${m}分`,
routeList: steps,
};
}
if (time >= 3600) {
h = Math.floor(time / 3600);
m = Math.floor((time - h * 3600) / 60);
return {
time: `${h}小时${m}分`,
routeList: steps,
};
}
}
function clearHospitalList() {
hospitalList.value = [];
showHospitalList.value = false;
}
onUnmounted(() => {
if (qhInterval.value) clearInterval(qhInterval.value);
if (cInterval.value) clearInterval(cInterval.value);
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeSocket();
closeSocket1(); //西安云坐席
};
});
function handleThreeRClick(type) {
const textArr = ['心血管异常人员列表', '脑血管异常人员列表', '冠状CT异常人员列表'];
indexModalTitle.value = textArr[type - 1];
indexColumn.value = threeRModalColumns;
modalApi.value = threeRModalApi;
twoROnly.value = '';
apiParams.value = { queryType: type };
needDept.value = false;
firstFormOne.value = threeRModalFromList;
nextTick(() => {
indexModalRef.value.openDialog();
});
}
function handleTwoRClick(data) {
const textArr = ['健康打卡减重数据', '健康打卡减血糖数据', '健康打卡血压数据'];
indexModalTitle.value = textArr[data.type - 1];
indexColumn.value = towRcolumns[data.type - 1];
needDept.value = false;
twoROnly.value = data;
const apiArr = [twoRModal1Api, twoRModal2Api, twoRModal3Api];
const params = {
inputDateBegin: '',
inputDateEnd: '',
abFlag: data.normal == 2 ? '1' : '2',
};
if (data.date == 1) {
params.inputDateBegin = dayjs().format('YYYY-MM-DD');
params.inputDateEnd = dayjs().format('YYYY-MM-DD');
} else {
params.inputDateBegin = dayjs().startOf('month').format('YYYY-MM-DD');
params.inputDateEnd = dayjs().format('YYYY-MM-DD');
}
apiParams.value = params;
modalApi.value = apiArr[data.type - 1];
firstFormOne.value = twoRform(data.normal == 2 ? '1' : '');
nextTick(() => {
indexModalRef.value.openDialog();
});
}
function handleTwoNewRClick() {
indexColumn.value = twoRNewColumns;
firstFormOne.value = twoRNewForm;
const params = {
centerId: centerId.value,
};
indexModalTitle.value = '重点关爱趋势预警';
modalApi.value = twoRNApi;
apiParams.value = params;
nextTick(() => {
indexModalRef.value.openDialog();
});
}
function handleOneRightView() {
indexColumn.value = oneRNewColumns;
firstFormOne.value = [];
const params = {
centerId: centerId.value,
startDate: '2000-01-01',
endDate: '2025-09-25',
};
indexModalTitle.value = '今日应急';
modalApi.value = todayEmergencyListApi;
apiParams.value = params;
nextTick(() => {
indexModalRef.value.openDialog();
});
}
function handleArchives(userId: string) {
indexColumn.value = oneRNewColumns;
firstFormOne.value = [];
const params = {
userId: userId,
};
indexModalTitle.value = '今日应急';
modalApi.value = healthArchivesApi;
apiParams.value = params;
nextTick(() => {
indexModalRef.value.openDialog();
});
}
function handleCenterMapClick(res: any) {
indexColumn.value = centerMapColumns;
firstFormOne.value = centerMapFromList;
const params = {
healthRoomId: res.id,
};
indexModalTitle.value = '健康小屋详情';
modalApi.value = roomDetailApi;
apiParams.value = params;
nextTick(() => {
indexModalRef.value.openDialog();
});
}
</script>
<style lang="less" scoped>
.sun-screen-box {
height: 100vh;
letter-spacing: 2px;
background: url('/@/assets/indexSun/bigBg.png') no-repeat;
background-size: 100% 100%;
.sun-screen-title {
height: 80px;
background: url('/@/assets/indexSun/bg.png') no-repeat;
background-size: 100% 100%;
display: flex;
font-size: 20px;
color: #fff;
text-align: center;
.sun-title-left {
text-align: left;
flex: 1;
line-height: 60px;
padding-left: 15px;
}
.sun-title-right {
flex: 1;
text-align: right;
line-height: 50px;
padding-right: 30px;
}
.sun-title-center {
flex: 1;
font-size: 50px;
line-height: 80px;
letter-spacing: 10px;
text-shadow: 2px 2px 5px rgba(118, 141, 219, 0.53);
font-weight: bold;
}
}
.sun-body-content {
height: calc(100% - 80px);
padding: 10px 20px;
display: flex;
justify-content: space-between;
.sun-body-left,
.sun-body-right {
height: 100%;
width: 22%;
display: flex;
flex-direction: column;
//justify-content: space-between;
}
.sun-body-center {
flex: 1;
margin: 0 10px;
height: 100%;
display: flex;
flex-direction: column;
}
.sun-body-left {
> div {
margin-bottom: 10px;
border: 1px solid #00ccff;
border-radius: 14px;
.one-l-box,
.two-l-box,
.three-l-box,
.three-r-box,
.three-new-l {
height: 100%;
}
}
.sun-body-left-one {
height: 20%;
}
.sun-body-left-two {
flex: 1;
}
.sun-body-left-three {
//height: 45%;
}
//.sun-body-left-four {
// height: 18%;
//}
}
.sun-body-right {
//display: flex;
//flex-direction: column;
> div {
border: 1px solid #00ccff;
border-radius: 14px;
overflow: hidden;
overflow: hidden;
&:not(:last-child) {
margin-bottom: 10px;
}
.one-r-box,
.two-r-box,
.three-r-box {
height: 100%;
}
}
.sun-body-right-one {
}
.sun-body-right-two {
flex: 1;
}
.sun-body-right-three {
flex: 1;
}
}
}
}
.top-right-button {
color: #ffffff;
font-weight: bold;
font-size: 18px;
width: 160px;
height: 40px;
background: radial-gradient(ellipse at center, #082147 0%, #08254c 55%, #085faa 100%);
border-radius: 8px;
border: 1px solid #55d3ff;
}
:deep(.amap-info-close) {
top: 15px;
right: 15px;
}
</style>