This commit is contained in:
zk
2023-12-19 14:26:27 +08:00
parent cf29ea07c1
commit e732938a34
25 changed files with 2218 additions and 80 deletions
+13
View File
@@ -0,0 +1,13 @@
import { get } from '/@/api/request.ts';
enum Api {
code = '/sys/dictItem/list',
}
export const getCodeInfo = (params: any) =>
get(Api.code, {
pageNo: 1,
pageSize: 999,
dictId: '1722171687208849409',
...params,
});
+6
View File
@@ -3,7 +3,9 @@ import { getAppEnvConfig } from '../utils/env.ts';
import { useUserStore } from '/@/store/modules/user.ts';
import { getAuthCache } from '/@/utils/auth.ts';
import { TOKEN_KEY } from '/@/enum/cacheEnum.ts';
import { useMessage } from '/@/hooks/web/useMessage.ts';
const { createMessage, createErrorModal } = useMessage();
const { VITE_GLOB_API_URL } = getAppEnvConfig();
const userStore = useUserStore();
const { token } = userStore;
@@ -21,6 +23,10 @@ const service = axios.create({
responseInterceptorsCatch(error: any) {
const { response, code, message, config } = error || {};
const errorMessageMode = config?.requestOptions?.errorMessageMode || 'none';
if (errorMessageMode === 'message') {
createMessage.error(message);
}
return Promise.reject(error);
},
});
export const get = (url, params = {}) => {
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

+22 -20
View File
@@ -27,26 +27,28 @@ export const Map = {
* @param option 地图配置
*/
initMap({ el, option }: InitMap) {
AMapLoader.load({
key: '4bbcb216b889f2d612cbed05ae6979c8', // 申请好的Web端开发者Key,首次调用 load 时必填
// version: '1.4.15', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: mapPlugin, // 需要使用的的插件列表,如比例尺'AMap.Scale'等
}).then((res) => {
AMap = res;
const { zoom, center, mapStyle } = { ...defaultOption, ...option };
//基本地图加载
this.map = new AMap.Map(el, {
resizeEnable: true,
center: center,
zoom: zoom,
mapStyle: 'amap://styles/darkblue',
version: '2.0',
});
// 异步同时加载多个插件
new AMap.plugin(mapPlugin, () => {
this.drawInnerLine();
this.drawOutLine();
return new Promise((resolve) => {
AMapLoader.load({
key: '4bbcb216b889f2d612cbed05ae6979c8', // 申请好的Web端开发者Key,首次调用 load 时必填
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: mapPlugin, // 需要使用的的插件列表,如比例尺'AMap.Scale'等
}).then((res) => {
AMap = res;
const { zoom, center, mapStyle } = { ...defaultOption, ...option };
//基本地图加载
this.map = new AMap.Map(el, {
resizeEnable: true,
center: center,
zoom: zoom,
mapStyle: 'amap://styles/darkblue',
version: '2.0',
});
// 异步同时加载多个插件
new AMap.plugin(mapPlugin, () => {
this.drawInnerLine();
this.drawOutLine();
});
resolve();
});
});
} /**
+29 -2
View File
@@ -1,7 +1,34 @@
import type { App } from 'vue';
import { Form, Input, Button, Radio, Modal, Table, Select, Cascader, Spin, ConfigProvider } from 'ant-design-vue';
import {
Form,
Input,
Button,
Radio,
RadioGroup,
RadioButton,
DatePicker,
Modal,
Table,
Select,
Cascader,
Spin,
ConfigProvider,
} from 'ant-design-vue';
import dataV from '@iamzzg/data-view/dist/vue3/datav.map.vue.esm';
export default function registerGlobComp(app: App) {
app.use(dataV).use(Button).use(Form).use(Input).use(Radio).use(Modal).use(Table).use(Select).use(Cascader).use(Spin).use(ConfigProvider);
app.use(dataV)
.use(Button)
.use(Form)
.use(Input)
.use(Radio)
.use(RadioGroup)
.use(RadioButton)
.use(DatePicker)
.use(Modal)
.use(Table)
.use(Select)
.use(Cascader)
.use(Spin)
.use(ConfigProvider);
}
+7 -11
View File
@@ -143,19 +143,15 @@
});
onMounted(() => {
console.log('reload');
initMap();
getMapData(tabList[0].type);
Map.map && Map.map.on('moveend', setLevel);
Map.map && Map.map.on('zoomend', setLevel);
$bus.on('alerdyreceive', (val) => {
footerData.value = val;
Map.initMap({ el: 'mapContainer' }).then(() => {
getMapData(tabList[0].type);
Map.map && Map.map.on('moveend', setLevel);
Map.map && Map.map.on('zoomend', setLevel);
$bus.on('alerdyreceive', (val) => {
footerData.value = val;
});
});
});
function initMap() {
Map.initMap({ el: 'mapContainer' });
}
const routeList = ref([]);
const showRoutePanel = ref(false);
const panelTitle = ref();
@@ -0,0 +1,32 @@
<template>
<div>
<div style="text-align: center" v-if="props.showRadio">
<a-radio-group v-model:value="paramsDate" button-style="solid" @change="changeParamsDate">
<a-radio-button value="0">今日</a-radio-button>
<a-radio-button value="1">近7日</a-radio-button>
<a-radio-button value="2">近14日</a-radio-button>
</a-radio-group>
</div>
<all-look-item :info-data="props.infoData" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import AllLookItem from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/componets/allLookItem.vue';
import { propTypes } from '/@/utils/propTypes';
const props = defineProps({
infoData: propTypes.object.def({}),
showRadio: propTypes.bool.def(true),
});
const emit = defineEmits(['changeParamsDate']);
const paramsDate = ref('0');
function changeParamsDate(v) {
emit('changeParamsDate', v.target.value);
}
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,283 @@
<template>
<div style="display: flex; margin-top: 20px">
<div style="width: calc(70% - 20px); border: 1px solid #ededed; padding: 20px">
<div style="display: flex; align-items: center; padding: 10px 0; justify-content: flex-start">
<img src="../../../../../../assets/images/allLook/heart_rate.png" alt="" />
心率
</div>
<div style="display: flex">
<div style="display: flex; width: 45%" class="border-d">
<div class="label-d">
<div>心率最大值</div>
<div>心率最小值</div>
<div>心率平均值</div>
</div>
<div class="value-d">
<div>{{ getNum(props.infoData?.heartRateStat?.max) }}/分钟</div>
<div>{{ getNum(props.infoData?.heartRateStat?.min) }}/分钟</div>
<div>{{ getNum(props.infoData?.heartRateStat?.avg) }}/分钟</div>
</div>
</div>
<div style="display: flex; width: 45%; margin-left: 10%">
<div class="label-d">
<div>静息心率最大值</div>
<div>静息心率最小值</div>
<div>静息心率平均值</div>
</div>
<div class="value-d">
<div>{{ getNum(props.infoData?.heartRateStat?.silenceMax) }}/分钟</div>
<div>{{ getNum(props.infoData?.heartRateStat?.silenceMin) }}/分钟</div>
<div>{{ getNum(props.infoData?.heartRateStat?.silenceAvg) }}/分钟</div>
</div>
</div>
</div>
</div>
<div style="width: 30%; margin-left: 20px; border: 1px solid #ededed; padding: 20px">
<div style="display: flex; align-items: center; padding: 10px 0; justify-content: flex-start">
<img src="../../../../../../assets/images/allLook/blood_oxygen.png" alt="" />
血氧
</div>
<div style="display: flex">
<div style="display: flex; width: 100%">
<div class="label-d">
<div>血氧最大值</div>
<div>血氧最小值</div>
<div>血氧平均值</div>
</div>
<div class="value-d">
<div>{{ getNum(props.infoData?.bloodOxygenAllStat?.max) }}%</div>
<div>{{ getNum(props.infoData?.bloodOxygenAllStat?.min) }}%</div>
<div>{{ getNum(props.infoData?.bloodOxygenAllStat?.avg) }}%</div>
</div>
</div>
</div>
</div>
</div>
<div style="display: flex; margin-top: 20px">
<div style="width: calc(70% - 20px); border: 1px solid #ededed; padding: 20px">
<div style="display: flex; align-items: center; padding: 10px 0; justify-content: flex-start">
<img src="../../../../../../assets/images/allLook/sleep.png" alt="" />
睡眠
</div>
<div style="display: flex">
<div style="display: flex; width: 45%" class="border-d">
<div class="label-d">
<div>夜间睡眠次数</div>
<div>夜间睡眠最长时长</div>
<div>夜间睡眠最短时长</div>
<div>夜间睡眠总时长</div>
</div>
<div class="value-d">
<div>{{ getNum(props.infoData?.sleepStat?.num) }}</div>
<div>{{ getTime(getNum(props.infoData?.sleepStat?.timeMax)) }}</div>
<div>{{ getTime(getNum(props.infoData?.sleepStat?.timeMin)) }}</div>
<div>{{ getTime(getNum(props.infoData?.sleepStat?.timeTotal)) }}</div>
</div>
</div>
<div style="display: flex; width: 45%; margin-left: 10%">
<div class="label-d">
<div>零星小睡次数</div>
<div>零星睡眠最长时长</div>
<div>零星小睡最短时长</div>
<div>零星睡眠总时长</div>
</div>
<div class="value-d">
<div>{{ getNum(props.infoData?.sleepStat?.napNum) }}</div>
<div>{{ getTime(getNum(props.infoData?.sleepStat?.napTimeMax)) }}</div>
<div>{{ getTime(getNum(props.infoData?.sleepStat?.napTimeMin)) }}</div>
<div>{{ getTime(getNum(props.infoData?.sleepStat?.napTimeTotal)) }}</div>
</div>
</div>
</div>
</div>
<div style="width: 30%; margin-left: 20px; border: 1px solid #ededed; padding: 20px">
<div style="display: flex; align-items: center; padding: 10px 0; justify-content: flex-start">
<img src="../../../../../../assets/images/allLook/pressure.png" alt="" />
压力
</div>
<div style="display: flex">
<div style="display: flex; width: 100%">
<div class="label-d">
<div>压力最大值</div>
<div>压力最小值</div>
<div>压力平均值</div>
<div style="opacity: 0">血氧平均值</div>
</div>
<div class="value-d">
<div>{{ getNum(props.infoData?.stressStat?.max) }}</div>
<div>{{ getNum(props.infoData?.stressStat?.min) }}</div>
<div>{{ getNum(props.infoData?.stressStat?.avg) }}</div>
<div style="opacity: 0">88</div>
</div>
</div>
</div>
</div>
</div>
<div style="display: flex; margin-top: 20px">
<div style="width: 100%; border: 1px solid #ededed">
<div style="display: flex; align-items: center; padding: 30px 20px 10px; justify-content: flex-start">
<img src="../../../../../../assets/images/allLook/motion.png" alt="" />
运动
</div>
<div style="display: flex; justify-content: space-between">
<div style="width: calc(70% - 20px); padding: 0 20px 20px">
<div style="display: flex">
<div style="display: flex; width: 45%" class="border-d">
<div class="label-d">
<div>运动最大距离</div>
<div>运动最小距离</div>
<div>运动总距离</div>
<div>运动距离有效次数</div>
</div>
<div class="value-d">
<div>{{ getK(getNum(props.infoData?.exerciseStat?.distanceMax)) }}</div>
<div>{{ getK(getNum(props.infoData?.exerciseStat?.distanceMin)) }}</div>
<div>{{ getK(getNum(props.infoData?.exerciseStat?.distanceTotal)) }}</div>
<div>{{ getNum(props.infoData?.exerciseStat?.distanceValidNum) }}</div>
</div>
</div>
<div style="display: flex; width: 45%; margin-left: 10%" class="border-d-d">
<div class="label-d">
<div>最大卡路里</div>
<div>最小卡路里</div>
<div>总卡路里</div>
<div>卡路里有效次数</div>
</div>
<div class="value-d">
<div>{{ getC(getNum(props.infoData?.exerciseStat?.kcalMax)) }}</div>
<div>{{ getC(getNum(props.infoData?.exerciseStat?.kcalMin)) }}</div>
<div>{{ getC(getNum(props.infoData?.exerciseStat?.kcalTotal)) }}</div>
<div>{{ getNum(props.infoData?.exerciseStat?.kcalValidNum) }}</div>
</div>
</div>
</div>
</div>
<div style="width: 30%; margin-left: 20px; padding: 0 20px 20px">
<div style="display: flex">
<div style="display: flex; width: 100%">
<div class="label-d">
<div>运动最大时长</div>
<div>运动最小时长</div>
<div>运动总时长</div>
<div>运动有效次数</div>
</div>
<div class="value-d">
<div>{{ getTime(getNum(props.infoData?.exerciseStat?.timeMax)) }}</div>
<div>{{ getTime(getNum(props.infoData?.exerciseStat?.timeMin)) }}</div>
<div>{{ getTime(getNum(props.infoData?.exerciseStat?.timeTotal)) }}</div>
<div>{{ getNum(props.infoData?.exerciseStat?.timeValidNum) }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="display: flex; margin-top: 20px">
<div style="width: calc(70% - 20px); border: 1px solid #ededed; padding: 20px">
<div style="display: flex; align-items: center; padding: 10px 0; justify-content: flex-start">
<img src="../../../../../../assets/images/allLook/temperature.png" alt="" />
体温
</div>
<div style="display: flex">
<div style="display: flex; width: 45%" class="border-d">
<div class="label-d">
<div>体温最大值</div>
<div>体温最小值</div>
<div>体温平均值</div>
</div>
<div class="value-d">
<div>{{ getNum(props.infoData?.bodyTempOverviewStat?.max) }}</div>
<div>{{ getNum(props.infoData?.bodyTempOverviewStat?.min) }}</div>
<div>{{ getNum(props.infoData?.bodyTempOverviewStat?.avg) }}</div>
</div>
</div>
<div style="display: flex; width: 45%; margin-left: 10%">
<div class="label-d">
<div>体表温度最大值</div>
<div>体表温度最小值</div>
<div>体表温度平均值</div>
</div>
<div class="value-d">
<div>{{ getNum(props.infoData?.bodyTempOverviewStat?.skinMax) }}</div>
<div>{{ getNum(props.infoData?.bodyTempOverviewStat?.skinMin) }}</div>
<div>{{ getNum(props.infoData?.bodyTempOverviewStat?.skinAvg) }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { propTypes } from '/@/utils/propTypes';
const props = defineProps({
infoData: propTypes.object.def({}),
});
function getTime(time) {
if (time < 60) {
return `0 时 ${time}`;
}
return `${(time - (time % 60)) / 60}${time % 60}`;
}
function getC(c) {
return c === 0 ? 0 + '(千卡)' : parseFloat(c / 1000).toFixed(3) + '(千卡)';
}
function getK(k) {
return k === 0 ? 0 + 'km' : parseFloat(k / 1000).toFixed(3) + 'km';
}
function getNum(num) {
if (num) {
return num;
}
return 0;
}
</script>
<style scoped lang="less">
img {
width: 30px;
height: 30px;
margin-right: 5px;
}
.label-d {
width: 50%;
}
.value-d {
width: 50%;
text-align: center;
}
.border-d {
position: relative;
&:after {
content: '';
height: 90%;
width: 1px;
position: absolute;
right: 0;
top: 5%;
background-color: #d3d3d3;
}
}
.border-d-d {
position: relative;
&:after {
content: '';
height: 90%;
width: 1px;
position: absolute;
right: -20px;
top: 5%;
background-color: #d3d3d3;
}
}
.label-d,
.value-d {
div {
padding: 5px 0;
}
}
</style>
@@ -0,0 +1,197 @@
<template>
<public-title @change-v="changeV" @changeShowStatus="changeShowStatus" :keyType="keyType" :user-id="userId" />
<div style="display: flex; justify-content: center" v-if="status">
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ maxInfo }}</span>
<span style="color: #aa9db6">%</span>
</div>
<div style="color: #aa9db6">最高血氧</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ minInfo }}</span>
<span style="color: #aa9db6">%</span>
</div>
<div style="color: #aa9db6">最低血氧</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px">{{ middleInfo }}</span>
<span style="color: #aa9db6">%</span>
</div>
<div style="color: #aa9db6">平均血氧</div>
</div>
</div>
<div v-if="status" ref="chartRef" style="min-height: 300px; width: 100%"></div>
<BasicTable v-else @register="registerTable" />
</template>
<script setup lang="ts">
import PublicTitle from '/@/components/secondaryScreen/secondMap/components/userInfoModal/publicTitle.vue';
import { nextTick, onMounted, ref } from 'vue';
import * as echarts from 'echarts';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import {
queryBloodOxygenStatisticsApi,
queryBloodOxygenStatisticsPageApi,
} from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.api';
import { propTypes } from '/@/utils/propTypes';
import dayjs from 'dayjs';
import { message } from 'ant-design-vue';
import { bloodOxygenColumns } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.data';
const type = ref(1);
const status = ref<boolean>(true);
const value = ref(dayjs(new Date()).format('YYYY-MM-DD'));
const maxInfo = ref();
const middleInfo = ref();
const minInfo = ref();
const props = defineProps({
userId: propTypes.string.def(''),
keyType: propTypes.string.def('2'),
});
let echart = null;
const { tableContext } = useListPage({
tableProps: {
api: queryBloodOxygenStatisticsPageApi,
columns: bloodOxygenColumns,
beforeFetch: (params) => {
let p = getParams();
for (const pKey in p) {
params[pKey] = p[pKey];
}
return params;
},
canResize: false,
showTableSetting: false,
rowSelection: false,
useSearchForm: false,
showActionColumn: false,
},
});
const [registerTable, { reload }, {}] = tableContext;
function changeV(j: any) {
type.value = j.type;
value.value = j.value;
initF();
}
function initF() {
if (status.value) {
echart && echart.clear();
initEchart('0');
} else {
reload();
}
}
function changeShowStatus(s: boolean) {
status.value = s;
if (s) {
nextTick(() => {
initEchart('0');
});
} else {
reload();
}
}
const chartRef = ref();
/**
* @type 传入 type = '1' 则不需要要渲染图表
* */
async function initEchart(type) {
try {
const { code, result, message: msg } = await queryBloodOxygenStatisticsApi(getParams());
if (code === 200) {
let xArr = [];
let yArr = [];
maxInfo.value = result.maxValue ? result.maxValue : '/';
middleInfo.value = result.avgValue ? result.avgValue : '/';
minInfo.value = result.minValue ? result.minValue : '/';
if (type === '1') return;
result.viewDataList.map((item) => {
xArr.push(item.date);
yArr.push(item.value ? item.value : 0);
});
echart = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: 'axis',
},
xAxis: {
type: 'category',
boundaryGap: true,
data: xArr,
},
grid: {
top: 30,
left: 60,
right: 60,
bottom: 40,
},
yAxis: {
type: 'value',
},
series: [
{
data: yArr,
type: 'line',
lineStyle: {
color: '#5894ff',
},
areaStyle: {
color: '#5894ff',
opacity: 0.15,
},
},
],
};
echart.setOption(option);
window.addEventListener('resize', () => {
echart.resize();
});
} else {
message.warn(msg);
}
} catch {}
}
function getParams() {
let params = {
flag: type.value,
userId: props.userId,
};
switch (type.value) {
case 1:
params['dateDay'] = value.value;
break;
case 2:
params['dateWeekStart'] = value.value.substring(0, value.value.indexOf('~') - 1);
params['dateWeekEnd'] = value.value.substring(value.value.indexOf('~') + 2);
break;
case 3:
params['dateMonth'] = value.value;
break;
case 4:
params['dateYear'] = value.value;
break;
}
return params;
}
onMounted(() => {
initEchart('0');
});
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,197 @@
<template>
<public-title @change-v="changeV" @changeShowStatus="changeShowStatus" :keyType="keyType" :user-id="userId" />
<div style="display: flex; justify-content: center" v-if="status">
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ maxInfo }}</span>
<span style="color: #aa9db6">/分钟</span>
</div>
<div style="color: #aa9db6">最高心率</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ minInfo }}</span>
<span style="color: #aa9db6">/分钟</span>
</div>
<div style="color: #aa9db6">最低心率</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px">{{ middleInfo }}</span>
<span style="color: #aa9db6">/分钟</span>
</div>
<div style="color: #aa9db6">平均心率</div>
</div>
</div>
<div v-if="status" ref="chartRef" style="min-height: 300px; width: 100%"></div>
<BasicTable v-else @register="registerTable" />
</template>
<script setup lang="ts">
import PublicTitle from '/@/components/secondaryScreen/secondMap/components/userInfoModal/publicTitle.vue';
import { nextTick, onMounted, ref } from 'vue';
import * as echarts from 'echarts';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import {
queryHeartRateStatisticsApi,
queryHeartRateStatisticsPageApi,
} from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.api';
import { propTypes } from '/@/utils/propTypes';
import dayjs from 'dayjs';
import { message } from 'ant-design-vue';
import { heartRateColumns } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.data';
const type = ref(1);
const status = ref<boolean>(true);
const value = ref(dayjs(new Date()).format('YYYY-MM-DD'));
const maxInfo = ref();
const middleInfo = ref();
const minInfo = ref();
const props = defineProps({
userId: propTypes.string.def(''),
keyType: propTypes.string.def('1'),
});
let echart = null;
const { tableContext } = useListPage({
tableProps: {
api: queryHeartRateStatisticsPageApi,
columns: heartRateColumns,
beforeFetch: (params) => {
let p = getParams();
for (const pKey in p) {
params[pKey] = p[pKey];
}
return params;
},
canResize: false,
showTableSetting: false,
rowSelection: false,
useSearchForm: false,
showActionColumn: false,
},
});
const [registerTable, { reload }, {}] = tableContext;
function changeV(j: any) {
type.value = j.type;
value.value = j.value;
initF();
}
function initF() {
if (status.value) {
echart && echart.clear();
initEchart('0');
} else {
reload();
}
}
function changeShowStatus(s: boolean) {
status.value = s;
if (s) {
nextTick(() => {
initEchart('0');
});
} else {
reload();
}
}
const chartRef = ref();
/**
* @type 传入 type = '1' 则不需要要渲染图表
* */
async function initEchart(type) {
try {
const { code, result, message: msg } = await queryHeartRateStatisticsApi(getParams());
if (code === 200) {
let xArr = [];
let yArr = [];
maxInfo.value = result.maxValue ? result.maxValue : '/';
middleInfo.value = result.avgValue ? result.avgValue : '/';
minInfo.value = result.minValue ? result.minValue : '/';
if (type === '1') return;
result.viewDataList.map((item) => {
xArr.push(item.date);
yArr.push(item.value ? item.value : 0);
});
echart = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: 'axis',
},
xAxis: {
type: 'category',
boundaryGap: true,
data: xArr,
},
grid: {
top: 30,
left: 60,
right: 60,
bottom: 40,
},
yAxis: {
type: 'value',
},
series: [
{
data: yArr,
type: 'line',
lineStyle: {
color: '#5894ff',
},
areaStyle: {
color: '#5894ff',
opacity: 0.15,
},
},
],
};
echart.setOption(option);
window.addEventListener('resize', () => {
echart.resize();
});
} else {
message.warn(msg);
}
} catch {}
}
function getParams() {
let params = {
flag: type.value,
userId: props.userId,
};
switch (type.value) {
case 1:
params['dateDay'] = value.value;
break;
case 2:
params['dateWeekStart'] = value.value.substring(0, value.value.indexOf('~') - 1);
params['dateWeekEnd'] = value.value.substring(value.value.indexOf('~') + 2);
break;
case 3:
params['dateMonth'] = value.value;
break;
case 4:
params['dateYear'] = value.value;
break;
}
return params;
}
onMounted(() => {
initEchart('0');
});
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,123 @@
<template>
<public-title
:show-list="false"
@change-v="changeV"
@change-show-status="changeShowStatus"
@change-m="changeMotion"
:keyType="keyType"
:user-id="userId"
/>
<!-- <div style="display: flex; justify-content: center">-->
<!-- <div style="width: 15%; text-align: center">-->
<!-- <div>-->
<!-- <span style="font-size: 25px"> {{ maxInfo > 1000 ? (maxInfo / 1000).toFixed(2) : maxInfo }}</span>-->
<!-- <span style="color: #aa9db6">{{ maxInfo > 1000 ? 'km' : 'm' }}</span>-->
<!-- </div>-->
<!-- <div style="color: #aa9db6">总运动距离</div>-->
<!-- </div>-->
<!-- <div style="width: 15%; text-align: center">-->
<!-- <div>-->
<!-- <span style="font-size: 25px"> {{ minInfo > 1000 ? (minInfo / 1000).toFixed(2) : minInfo }}</span>-->
<!-- <span style="color: #aa9db6">{{ minInfo > 1000 ? '千卡' : '卡' }}</span>-->
<!-- </div>-->
<!-- <div style="color: #aa9db6">总卡路里</div>-->
<!-- </div>-->
<!-- </div>-->
<BasicTable @register="registerTable" />
</template>
<script setup lang="ts">
import PublicTitle from '/@/components/secondaryScreen/secondMap/components/userInfoModal/publicTitle.vue';
import { ref } from 'vue';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { queryExercisePageApi } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.api';
import { propTypes } from '/@/utils/propTypes';
import dayjs from 'dayjs';
import { motionColumns } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.data';
const type = ref(1);
const status = ref<boolean>(true);
const value = ref(dayjs(new Date()).format('YYYY-MM-DD'));
const maxInfo = ref();
const minInfo = ref();
const motionType = ref();
const props = defineProps({
userId: propTypes.string.def(''),
keyType: propTypes.string.def('6'),
});
const { tableContext } = useListPage({
tableProps: {
api: queryExercisePageApi,
columns: motionColumns,
beforeFetch: (params) => {
let p = getParams();
for (const pKey in p) {
params[pKey] = p[pKey];
}
return params;
},
canResize: false,
afterFetch: async () => {
let res = getRawDataSource();
maxInfo.value = res.totalDistance;
minInfo.value = res.totalKcal;
setPagination({
total: res.page.total,
current: res.page.current,
pageSize: res.page.size,
});
return res.page.records;
},
showTableSetting: false,
rowSelection: false,
useSearchForm: false,
showActionColumn: false,
},
});
const [registerTable, { reload, getDataSource, getRawDataSource, setPagination, getPaginationRef }, {}] = tableContext;
function changeV(j: any) {
type.value = j.type;
value.value = j.value;
reload();
}
function changeShowStatus(s: boolean) {
status.value = s;
reload();
}
function changeMotion(s: string) {
motionType.value = s;
reload();
}
function getParams() {
let params = {
flag: type.value,
userId: props.userId,
type: motionType.value,
};
switch (type.value) {
case 1:
params['dateDay'] = value.value;
break;
case 2:
params['dateWeekStart'] = value.value.substring(0, value.value.indexOf('~') - 1);
params['dateWeekEnd'] = value.value.substring(value.value.indexOf('~') + 2);
break;
case 3:
params['dateMonth'] = value.value;
break;
case 4:
params['dateYear'] = value.value;
break;
}
return params;
}
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,194 @@
<template>
<public-title @change-v="changeV" @changeShowStatus="changeShowStatus" :keyType="keyType" :user-id="userId" />
<div style="display: flex; justify-content: center" v-if="status">
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ maxInfo }}</span>
</div>
<div style="color: #aa9db6">最高压力</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ minInfo }}</span>
</div>
<div style="color: #aa9db6">最低压力</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px">{{ middleInfo }}</span>
</div>
<div style="color: #aa9db6">平均压力</div>
</div>
</div>
<div v-if="status" ref="chartRef" style="min-height: 300px; width: 100%"></div>
<BasicTable v-else @register="registerTable" />
</template>
<script setup lang="ts">
import PublicTitle from '/@/components/secondaryScreen/secondMap/components/userInfoModal/publicTitle.vue';
import { nextTick, onMounted, ref } from 'vue';
import * as echarts from 'echarts';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import {
queryStressStatisticsApi,
queryStressStatisticsPageApi,
} from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.api';
import { propTypes } from '/@/utils/propTypes';
import dayjs from 'dayjs';
import { message } from 'ant-design-vue';
import { pressureColumns } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.data';
const type = ref(1);
const status = ref<boolean>(true);
const value = ref(dayjs(new Date()).format('YYYY-MM-DD'));
const maxInfo = ref();
const middleInfo = ref();
const minInfo = ref();
const props = defineProps({
userId: propTypes.string.def(''),
keyType: propTypes.string.def('2'),
});
let echart = null;
const { tableContext } = useListPage({
tableProps: {
api: queryStressStatisticsPageApi,
columns: pressureColumns,
beforeFetch: (params) => {
let p = getParams();
for (const pKey in p) {
params[pKey] = p[pKey];
}
return params;
},
canResize: false,
showTableSetting: false,
rowSelection: false,
useSearchForm: false,
showActionColumn: false,
},
});
const [registerTable, { reload, getPaginationRef }, {}] = tableContext;
function changeV(j: any) {
type.value = j.type;
value.value = j.value;
initF();
}
function initF() {
if (status.value) {
echart && echart.clear();
initEchart('0');
} else {
reload();
}
}
function changeShowStatus(s: boolean) {
status.value = s;
if (s) {
nextTick(() => {
initEchart('0');
});
} else {
reload();
}
}
const chartRef = ref();
/**
* @type 传入 type = '1' 则不需要要渲染图表
* */
async function initEchart(type) {
try {
const { code, result, message: msg } = await queryStressStatisticsApi(getParams());
if (code === 200) {
let xArr = [];
let yArr = [];
maxInfo.value = result.maxValue ? result.maxValue : '/';
middleInfo.value = result.avgValue ? result.avgValue : '/';
minInfo.value = result.minValue ? result.minValue : '/';
if (type === '1') return;
result.viewDataList.map((item) => {
xArr.push(item.date);
yArr.push(item.value ? item.value : 0);
});
echart = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: 'axis',
},
xAxis: {
type: 'category',
boundaryGap: true,
data: xArr,
},
grid: {
top: 30,
left: 60,
right: 60,
bottom: 40,
},
yAxis: {
type: 'value',
},
series: [
{
data: yArr,
type: 'line',
lineStyle: {
color: '#5894ff',
},
areaStyle: {
color: '#5894ff',
opacity: 0.15,
},
},
],
};
echart.setOption(option);
window.addEventListener('resize', () => {
echart.resize();
});
} else {
message.warn(msg);
}
} catch {}
}
function getParams() {
let params = {
flag: type.value,
userId: props.userId,
};
switch (type.value) {
case 1:
params['dateDay'] = value.value;
break;
case 2:
params['dateWeekStart'] = value.value.substring(0, value.value.indexOf('~') - 1);
params['dateWeekEnd'] = value.value.substring(value.value.indexOf('~') + 2);
break;
case 3:
params['dateMonth'] = value.value;
break;
case 4:
params['dateYear'] = value.value;
break;
}
return params;
}
onMounted(() => {
initEchart('0');
});
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,240 @@
<template>
<div style="display: flex; align-items: center; justify-content: center; position: relative" :style="{ minHeight: props.showList ? '30px' : '' }">
<a-radio-group v-model:value="active" button-style="solid" @change="changeType" v-if="showStatus && props.showList">
<a-radio-button v-if="props.showOne" :value="1"></a-radio-button>
<a-radio-button :value="2"></a-radio-button>
<a-radio-button :value="3"></a-radio-button>
<a-radio-button :value="4"></a-radio-button>
</a-radio-group>
<div v-if="props.showList" class="right-d" @click="changeShowStatus">
<img :src="showStatus ? listImg : chartImg" alt="" />
{{ showStatus ? '列表展示' : '图表展示' }}
</div>
</div>
<div
style="display: flex; justify-content: center; margin-top: 20px; align-items: center; position: relative"
:style="{ minHeight: props.showList ? '' : '30px' }"
>
<div style="position: absolute; left: 10px; display: flex; align-items: center" v-if="!props.showList">
锻炼类型
<JDictSelectTag
v-model:value="motionType"
style="min-width: 140px"
placeholder="请选择锻炼类型"
dictCode="watch_exercise_type"
@change="changeSelect"
/>
</div>
<div style="display: flex; font-size: 20px" v-if="showStatus && props.showList">
<span style="margin: 0 0 0 5px; cursor: pointer" @click="changeDate('0')">&lt;</span>
<div style="position: relative">
<a-date-picker
ref="datePicker"
v-model:value="dateInfo"
:disabledDate="(current) => current > new Date()"
:format="rType()"
:picker="getP()"
@change="changeValue"
style="opacity: 0; z-index: 99; position: absolute; top: 0; left: 0"
>
<template #dateRender="{ current }">
<div class="ant-picker-cell-inner" :class="[getBg(current) ? 'bgc' : '']">
{{ current.date() }}
</div>
</template>
</a-date-picker>
<div style="z-index: 1; min-width: 150px; text-align: center">{{ getDateFormat(dateInfo) }}</div>
</div>
<span style="margin: 0 0 5px 5px; cursor: pointer" @click="changeDate('1')">&gt;</span>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import chartImg from '/@/assets/images/chart.png';
import listImg from '/@/assets/images/list.png';
import dayjs from 'dayjs';
import { propTypes } from '/@/utils/propTypes';
import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
import { userDataDayByYearApi } from '/@/components/secondaryScreen/secondMap/secondMapApi.ts';
const props = defineProps({
showOne: propTypes.bool.def(true),
showList: propTypes.bool.def(true),
keyType: propTypes.string.def(''),
userId: propTypes.string.def(''),
});
const emit = defineEmits(['changeV', 'changeShowStatus', 'changeM']);
const active = ref(props.showOne ? 1 : 2);
const showStatus = ref(true);
const dateInfo = ref(dayjs());
const motionType = ref();
const dateFormat = 'YYYY-MM-DD';
const weekFormat = 'YYYY-MM-DD';
const monthFormat = 'YYYY-MM';
let searchYear = dayjs().format('YYYY');
const infoData = ref([]);
const customWeekStartEndFormat = (value) =>
`${dayjs(value).startOf('week').format(weekFormat)} ~ ${dayjs(value).endOf('week').format(weekFormat)}`;
function getInfoByDayOrMonth() {
let params = {
userId: props.userId,
type: props.keyType,
year: searchYear,
};
userDataDayByYearApi(params)
.then((res) => {
infoData.value = res.month;
})
.catch(() => {});
}
getInfoByDayOrMonth();
function getBg(c) {
for (let i = 0; i < infoData.value.length; i++) {
if (infoData.value[i].month === dayjs(c).format('MM') * 1) {
if (active.value === 3) {
return true;
} else {
for (let j = 0; j < infoData.value[i].day.length; j++) {
if (dayjs(c).format('DD') * 1 === infoData.value[i].day[j]) {
return true;
}
}
}
}
}
return false;
}
function rType() {
switch (active.value) {
case 1:
return dateFormat;
case 2:
return customWeekStartEndFormat(dateInfo.value);
case 3:
return monthFormat;
case 4:
return 'YYYY';
}
return '';
}
function getP() {
switch (active.value) {
case 2:
return 'week';
case 3:
return 'month';
case 4:
return 'year';
}
return '';
}
function changeShowStatus() {
showStatus.value = !showStatus.value;
emit('changeShowStatus', showStatus.value);
}
function changeType() {
emit('changeV', { type: active.value, value: getDateFormat(dateInfo.value) });
}
function changeValue() {
if (searchYear !== dayjs(dateInfo.value).format('YYYY')) {
searchYear = dayjs(dateInfo.value).format('YYYY');
getInfoByDayOrMonth();
}
emit('changeV', { type: active.value, value: getDateFormat(dateInfo.value) });
}
function changeSelect() {
emit('changeM', motionType.value);
}
function getDateFormat(v) {
return active.value === 2 ? customWeekStartEndFormat(v) : dayjs(v).format(rType());
}
function weekNext(x, data) {
let d = dayjs(getDateFormat(data).substring(getDateFormat(data).indexOf('~') + 2));
return x.diff(d, 'day') < 0;
}
function changeDate(type) {
const x = dayjs(dateInfo.value);
if (searchYear !== dayjs(x).format('YYYY')) {
searchYear = dayjs(x).format('YYYY');
getInfoByDayOrMonth();
}
const y = dayjs();
if (
type === '1' &&
((active.value === 1 && x.diff(y, 'day') === 0) ||
(active.value === 2 && weekNext(y, dateInfo.value)) ||
(active.value === 3 && x.diff(y, 'month') === 0) ||
(active.value === 4 && x.diff(y, 'year') === 0))
)
return;
switch (active.value) {
case 1:
type === '0' ? (dateInfo.value = dayjs(dateInfo.value).subtract(1, 'day')) : (dateInfo.value = dayjs(dateInfo.value).add(1, 'day'));
break;
case 2:
type === '0' ? (dateInfo.value = dayjs(dateInfo.value).subtract(1, 'week')) : (dateInfo.value = dayjs(dateInfo.value).add(1, 'week'));
break;
case 3:
type === '0'
? (dateInfo.value = dayjs(dateInfo.value).subtract(1, 'month'))
: (dateInfo.value = dayjs(dateInfo.value).add(1, 'month'));
break;
case 4:
type === '0' ? (dateInfo.value = dayjs(dateInfo.value).subtract(1, 'year')) : (dateInfo.value = dayjs(dateInfo.value).add(1, 'year'));
break;
}
changeValue();
}
</script>
<style scoped lang="less">
.ant-radio-button-wrapper {
padding: 0 30px;
}
.right-d {
position: absolute;
border: 1px solid #e6e6e6;
right: 20px;
border-radius: 50px;
padding: 3px 20px 3px 30px;
display: flex;
align-items: center;
cursor: pointer;
color: #5087ec;
}
img {
width: 20px;
height: 20px;
margin-right: 10px;
}
:deep(.ant-select) {
min-width: 140px;
}
.bgc {
border: 1px solid #1890ff;
border-radius: 50px;
}
</style>
@@ -0,0 +1,242 @@
<template>
<public-title @change-v="changeV" @changeShowStatus="changeShowStatus" :keyType="keyType" :user-id="userId" />
<div style="display: flex; justify-content: center" v-if="status">
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ maxInfo }}</span>
</div>
<div style="color: #aa9db6">最高睡眠时长</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ minInfo }}</span>
</div>
<div style="color: #aa9db6">最低睡眠时长</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px">{{ middleInfo }}</span>
</div>
<div style="color: #aa9db6">平均睡眠时长</div>
</div>
</div>
<div v-if="status && !isEmpty" ref="chartRef" style="min-height: 300px; width: 100%"></div>
<template v-if="status && isEmpty">
<div style="min-height: 300px; width: 100%; display: flex; align-items: center; justify-content: center">
<a-empty />
</div>
</template>
<BasicTable v-if="!status" @register="registerTable" />
</template>
<script setup lang="ts">
import PublicTitle from '/@/components/secondaryScreen/secondMap/components/userInfoModal/publicTitle.vue';
import { nextTick, onMounted, ref } from 'vue';
import * as echarts from 'echarts';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { querySleepStatisticsApi, querySleepStatisticsPageApi } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.api';
import { propTypes } from '/@/utils/propTypes';
import dayjs from 'dayjs';
import { message } from 'ant-design-vue';
import { sleepColumns } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.data';
const type = ref(1);
const status = ref<boolean>(true);
const value = ref(dayjs(new Date()).format('YYYY-MM-DD'));
const maxInfo = ref();
const middleInfo = ref();
const minInfo = ref();
const isEmpty = ref(false);
const props = defineProps({
userId: propTypes.string.def(''),
keyType: propTypes.string.def('4'),
});
let echart = null;
const { tableContext } = useListPage({
tableProps: {
api: querySleepStatisticsPageApi,
columns: sleepColumns,
beforeFetch: (params) => {
let p = getParams();
for (const pKey in p) {
params[pKey] = p[pKey];
}
return params;
},
canResize: false,
showTableSetting: false,
rowSelection: false,
useSearchForm: false,
showActionColumn: false,
},
});
const [registerTable, { reload }, {}] = tableContext;
function changeV(j: any) {
type.value = j.type;
value.value = j.value;
isEmpty.value = false;
initF();
}
function initF() {
if (status.value) {
echart && echart.clear();
initEchart('0');
} else {
reload();
}
}
function changeShowStatus(s: boolean) {
status.value = s;
if (s) {
nextTick(() => {
initEchart('0');
});
} else {
reload();
}
}
const chartRef = ref();
/**
* @type 传入 type = '1' 则不需要要渲染图表
* */
async function initEchart(t) {
try {
const { code, result, message: msg } = await querySleepStatisticsApi(getParams());
if (code === 200) {
isEmpty.value = result.viewDataList.length === 0;
let xArr = [];
let yArr = [];
let yArr1 = [];
maxInfo.value = result.maxValue ? result.maxValue : '/';
middleInfo.value = result.avgValue ? result.avgValue : '/';
minInfo.value = result.minValue ? result.minValue : '/';
if (t === '1') return;
type.value === 1 &&
result.viewDataList.map((item) => {
xArr.push(item.date);
yArr.push(item.value === 1 ? 1 : 0);
yArr1.push(item.value === 2 ? 1 : 0);
});
type.value !== 1 &&
result.viewDataList.map((item) => {
xArr.push(item.date);
yArr.push(item.value);
yArr1.push(item.value1);
});
echart = echarts.init(chartRef.value);
const option = {
title: {},
legend: {},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
formatter: function (params) {
let tar1 = params[1];
let tar = params[0];
// let tar = params[1];
// return (tar1.value > 0 ? '短睡' : '长睡') + '<br/>' + tar.seriesName + ' : ' + tar.value;
let str = '';
if (type.value === 1) {
str = tar1.value > 0 ? '长睡' : '短睡';
} else {
str = '短睡' + ' : ' + (tar.value ? tar.value : 0) + '<br/>' + '长睡' + ' : ' + (tar1.value ? tar1.value : 0);
}
return str;
},
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'category',
splitLine: { show: false },
data: xArr,
},
yAxis: {
show: false,
},
series: [
{
name: '长睡',
type: 'bar',
barMaxWidth: '20px',
itemStyle: {
borderColor: '#5087ec',
borderWidth: 0,
color: '#5087ec',
},
// emphasis: {
// itemStyle: {
// borderColor: '#68bbc4',
// color: '#68bbc4',
// },
// },
data: yArr,
},
{
name: '短睡',
barMaxWidth: '20px',
itemStyle: {
borderColor: '#85d0dc',
borderWidth: 0,
color: '#85d0dc',
},
type: 'bar',
data: yArr1,
},
],
};
echart.setOption(option);
window.addEventListener('resize', () => {
echart.resize();
});
} else {
isEmpty.value = true;
message.warn(msg);
}
} catch {}
}
function getParams() {
let params = {
flag: type.value,
userId: props.userId,
};
switch (type.value) {
case 1:
params['dateDay'] = value.value;
break;
case 2:
params['dateWeekStart'] = value.value.substring(0, value.value.indexOf('~') - 1);
params['dateWeekEnd'] = value.value.substring(value.value.indexOf('~') + 2);
break;
case 3:
params['dateMonth'] = value.value;
break;
case 4:
params['dateYear'] = value.value;
break;
}
return params;
}
onMounted(() => {
initEchart('0');
});
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,199 @@
<template>
<public-title :show-one="false" @change-v="changeV" @change-show-status="changeShowStatus" :keyType="keyType" :user-id="userId" />
<div style="display: flex; justify-content: center" v-if="status">
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ maxInfo }}</span>
</div>
<div style="color: #aa9db6">总步数</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ minInfo }}</span>
<span style="color: #aa9db6">m</span>
</div>
<div style="color: #aa9db6">总距离</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px">{{ middleInfo }}</span>
<span style="color: #aa9db6"></span>
</div>
<div style="color: #aa9db6">总卡路里</div>
</div>
</div>
<div v-if="status" ref="chartRef" style="min-height: 300px; width: 100%"></div>
<BasicTable v-else @register="registerTable" />
</template>
<script setup lang="ts">
import PublicTitle from '/@/components/secondaryScreen/secondMap/components/userInfoModal/publicTitle.vue';
import { nextTick, onMounted, ref } from 'vue';
import * as echarts from 'echarts';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import { queryStepStatisticsApi, queryStepStatisticsPageApi } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.api';
import { propTypes } from '/@/utils/propTypes';
import dayjs from 'dayjs';
import { message } from 'ant-design-vue';
import { stepNumberColumns } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.data';
const type = ref(2);
const status = ref<boolean>(true);
const value = ref(customWeekStartEndFormat(dayjs()));
const maxInfo = ref();
const middleInfo = ref();
const minInfo = ref();
function customWeekStartEndFormat(value) {
return `${dayjs(value).startOf('week').format('YYYY-MM-DD')} ~ ${dayjs(value).endOf('week').format('YYYY-MM-DD')}`;
}
const props = defineProps({
userId: propTypes.string.def(''),
keyType: propTypes.string.def('7'),
});
let echart = null;
const { tableContext } = useListPage({
tableProps: {
api: queryStepStatisticsPageApi,
columns: stepNumberColumns,
beforeFetch: (params) => {
let p = getParams();
for (const pKey in p) {
params[pKey] = p[pKey];
}
return params;
},
canResize: false,
showTableSetting: false,
rowSelection: false,
useSearchForm: false,
showActionColumn: false,
},
});
const [registerTable, { reload }, {}] = tableContext;
function changeV(j: any) {
type.value = j.type;
value.value = j.value;
initF();
}
function initF() {
if (status.value) {
echart && echart.clear();
initEchart('0');
} else {
reload();
}
}
function changeShowStatus(s: boolean) {
status.value = s;
if (s) {
nextTick(() => {
initEchart('0');
});
} else {
reload();
}
}
const chartRef = ref();
/**
* @type 传入 type = '1' 则不需要要渲染图表
* */
async function initEchart(type) {
try {
const { code, result, message: msg } = await queryStepStatisticsApi(getParams());
if (code === 200) {
let xArr = [];
let yArr = [];
maxInfo.value = result.total ? result.total : '/';
middleInfo.value = result.total1 ? result.total1 : '/';
minInfo.value = result.total2 ? result.total2 : '/';
if (type === '1') return;
result.viewDataList.map((item) => {
xArr.push(item.date);
yArr.push(item.value ? item.value : 0);
});
echart = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: 'axis',
},
legend: {},
xAxis: {
type: 'category',
boundaryGap: true,
data: xArr,
},
grid: {
top: 30,
left: 60,
right: 60,
bottom: 40,
},
yAxis: {
type: 'value',
},
series: [
{
name: '步数',
data: yArr,
type: 'bar',
lineStyle: {
color: '#5894ff',
},
areaStyle: {
color: '#5894ff',
opacity: 0.15,
},
},
],
};
echart.setOption(option);
window.addEventListener('resize', () => {
echart.resize();
});
} else {
message.warn(msg);
}
} catch {}
}
function getParams() {
let params = {
flag: type.value,
userId: props.userId,
};
switch (type.value) {
case 1:
params['dateDay'] = value.value;
break;
case 2:
params['dateWeekStart'] = value.value.substring(0, value.value.indexOf('~') - 1);
params['dateWeekEnd'] = value.value.substring(value.value.indexOf('~') + 2);
break;
case 3:
params['dateMonth'] = value.value;
break;
case 4:
params['dateYear'] = value.value;
break;
}
return params;
}
onMounted(() => {
initEchart('0');
});
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,215 @@
<template>
<public-title @change-v="changeV" @changeShowStatus="changeShowStatus" :keyType="keyType" :user-id="userId" />
<div style="display: flex; justify-content: center" v-if="status">
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ maxInfo }}</span>
<span style="color: #aa9db6"></span>
</div>
<div style="color: #aa9db6">最高体温</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px"> {{ minInfo }}</span>
<span style="color: #aa9db6"></span>
</div>
<div style="color: #aa9db6">最低体温</div>
</div>
<div style="width: 15%; text-align: center">
<div>
<span style="font-size: 25px">{{ middleInfo }}</span>
<span style="color: #aa9db6"></span>
</div>
<div style="color: #aa9db6">平均体温</div>
</div>
</div>
<div v-if="status" ref="chartRef" style="min-height: 300px; width: 100%"></div>
<BasicTable v-else @register="registerTable" />
</template>
<script setup lang="ts">
import PublicTitle from '/@/components/secondaryScreen/secondMap/components/userInfoModal/publicTitle.vue';
import { nextTick, onMounted, ref } from 'vue';
import * as echarts from 'echarts';
import BasicTable from '/@/components/Table/src/BasicTable.vue';
import { useListPage } from '/@/hooks/system/useListPage';
import {
queryBodyTemperatureStatApi,
queryBodyTemperatureStatPageApi,
} from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.api';
import { propTypes } from '/@/utils/propTypes';
import dayjs from 'dayjs';
import { message } from 'ant-design-vue';
import { temperatureColumns } from '/@/views/healthMonitor/healMonitorManage/monitorToll/userInfo/userInfo.data';
const type = ref(1);
const status = ref<boolean>(true);
const value = ref(dayjs(new Date()).format('YYYY-MM-DD'));
const maxInfo = ref();
const middleInfo = ref();
const minInfo = ref();
const props = defineProps({
userId: propTypes.string.def(''),
keyType: propTypes.string.def('5'),
});
let echart = null;
const { tableContext } = useListPage({
tableProps: {
api: queryBodyTemperatureStatPageApi,
columns: temperatureColumns,
beforeFetch: (params) => {
let p = getParams();
for (const pKey in p) {
params[pKey] = p[pKey];
}
return params;
},
canResize: false,
showTableSetting: false,
rowSelection: false,
useSearchForm: false,
showActionColumn: false,
},
});
const [registerTable, { reload }, {}] = tableContext;
function changeV(j: any) {
type.value = j.type;
value.value = j.value;
initF();
}
function initF() {
if (status.value) {
echart && echart.clear();
initEchart('0');
} else {
reload();
}
}
function changeShowStatus(s: boolean) {
status.value = s;
if (s) {
nextTick(() => {
initEchart('0');
});
} else {
reload();
}
}
const chartRef = ref();
/**
* @type 传入 type = '1' 则不需要要渲染图表
* */
async function initEchart(type) {
try {
const { code, result, message: msg } = await queryBodyTemperatureStatApi(getParams());
if (code === 200) {
let xArr = [];
let yArr = [];
let yArr1 = [];
maxInfo.value = result.maxValue ? result.maxValue : '/';
middleInfo.value = result.avgValue ? result.avgValue : '/';
minInfo.value = result.minValue ? result.minValue : '/';
if (type === '1') return;
result.viewDataList.map((item) => {
xArr.push(item.date);
yArr.push(item.value ? item.value : 0);
yArr1.push(item.value2 ? item.value2 : 0);
});
echart = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: 'axis',
// axisPointer: {
// type: 'cross',
// crossStyle: {
// color: '#999',
// },
// },
},
xAxis: [
{
type: 'category',
data: xArr,
},
],
yAxis: [
{
type: 'value',
name: '温度',
// axisLabel: {
// formatter: '{value} ml',
// },
},
],
series: [
{
name: '体温',
type: 'bar',
tooltip: {
valueFormatter: function (value) {
return value + ' ℃';
},
},
data: yArr,
},
{
name: '体表温度',
type: 'bar',
tooltip: {
valueFormatter: function (value) {
return value + ' ℃';
},
},
data: yArr1,
},
],
};
echart.setOption(option);
window.addEventListener('resize', () => {
echart.resize();
});
} else {
message.warn(msg);
}
} catch {}
}
function getParams() {
let params = {
flag: type.value,
userId: props.userId,
};
switch (type.value) {
case 1:
params['dateDay'] = value.value;
break;
case 2:
params['dateWeekStart'] = value.value.substring(0, value.value.indexOf('~') - 1);
params['dateWeekEnd'] = value.value.substring(value.value.indexOf('~') + 2);
break;
case 3:
params['dateMonth'] = value.value;
break;
case 4:
params['dateYear'] = value.value;
break;
}
return params;
}
onMounted(() => {
initEchart('0');
});
</script>
<style scoped lang="less"></style>
@@ -0,0 +1,108 @@
<template>
<Dialog :openVis="visible" width="70%" title="健康终端报警列表" @close="closeModal">
<div style="display: flex">
<div style="width: 23%; padding: 0 20px 20px">
<div style="margin-bottom: 10px; font-weight: bold"> 用户名称{{ infoData.username }}</div>
<div style="margin-bottom: 10px; font-weight: bold"> 工具编码{{ infoData.watchNo }}</div>
<div style="margin-bottom: 10px; font-weight: bold"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{ infoData.unit }} </div>
<div style="margin-bottom: 10px; font-weight: bold"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{ infoData.department }} </div>
<div style="margin-bottom: 10px; font-weight: bold"> 绑定日期{{ infoData.bindDate }}</div>
</div>
<div style="position: absolute; top: 5%; left: 20%; height: 90%; border-right: 1px solid #e6e6e6"></div>
<div style="width: 77%">
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="0" tab="总览" />
<a-tab-pane key="1" tab="心率" />
<a-tab-pane key="2" tab="血氧" />
<a-tab-pane key="4" tab="睡眠" />
<a-tab-pane key="3" tab="压力" />
<a-tab-pane key="6" tab="锻炼" />
<a-tab-pane key="7" tab="步数" />
<a-tab-pane key="5" tab="体温" />
</a-tabs>
<div style="height: 60vh; overflow: auto">
<all-look
@change-params-date="changeParamsDate"
v-if="activeKey === '0'"
:info-data="info"
:userId="infoData.userid"
class="tabs-d"
/>
<heart-rate v-if="activeKey === '1'" :userId="infoData.userid" class="tabs-d" :keyType="activeKey" />
<blood-oxygen v-if="activeKey === '2'" :userId="infoData.userid" class="tabs-d" :keyType="activeKey" />
<pressure v-if="activeKey === '3'" :userId="infoData.userid" class="tabs-d" :keyType="activeKey" />
<sleep v-if="activeKey === '4'" :userId="infoData.userid" class="tabs-d" :keyType="activeKey" />
<temperature v-if="activeKey === '5'" :userId="infoData.userid" class="tabs-d" :keyType="activeKey" />
<motion v-if="activeKey === '6'" :userId="infoData.userid" class="tabs-d" :keyType="activeKey" />
<step-number v-if="activeKey === '7'" :userId="infoData.userid" class="tabs-d" :keyType="activeKey" />
</div>
</div>
</div>
</Dialog>
</template>
<script setup lang="ts">
import Dialog from '/@/components/dialog/Dialog.vue';
import { ref } from 'vue';
import AllLook from '/@/components/secondaryScreen/secondMap/components/userInfoModal/allLook.vue';
import HeartRate from '/@/components/secondaryScreen/secondMap/components/userInfoModal/heartRate.vue';
import BloodOxygen from '/@/components/secondaryScreen/secondMap/components/userInfoModal/bloodOxygen.vue';
import Pressure from '/@/components/secondaryScreen/secondMap/components/userInfoModal/pressure.vue';
import Sleep from '/@/components/secondaryScreen/secondMap/components/userInfoModal/sleep.vue';
import Temperature from '/@/components/secondaryScreen/secondMap/components/userInfoModal/temperature.vue';
import Motion from '/@/components/secondaryScreen/secondMap/components/userInfoModal/motion.vue';
import StepNumber from '/@/components/secondaryScreen/secondMap/components/userInfoModal/stepNumber.vue';
import { queryAllStatisticsApi } from '/@/components/secondaryScreen/secondMap/secondMapApi.ts';
const visible = ref(false);
async function openModal(data) {
visible.value = true;
activeKey.value = '0';
paramsDate.value = '0';
info.value = {};
infoData.value = data.record;
await getInfo();
}
function closeModal() {
visible.value = false;
}
const activeKey = ref('0');
const infoData = ref({});
const paramsDate = ref('0');
const info = ref({});
async function changeParamsDate(v) {
paramsDate.value = v;
await getInfo();
}
async function getInfo() {
await queryAllStatisticsApi({ type: paramsDate.value, userId: infoData.value.userid }).then((res) => {
info.value = res;
});
}
</script>
<style scoped lang="less">
:deep(.ant-tabs-nav-wrap) {
justify-content: center;
}
:deep(.ant-tabs-top > .ant-tabs-nav::before, .ant-tabs-top > div > .ant-tabs-nav::before) {
display: none;
}
:deep(.ant-tabs-tab + .ant-tabs-tab) {
margin-left: calc(100% / 14);
}
:deep(.ant-tabs-nav-list) {
width: 100%;
justify-content: center;
}
.tabs-d {
padding: 20px;
}
</style>
@@ -1,23 +1,32 @@
<template>
<Dialog :openVis="visible" width="65%" title="健康终端报警列表" @close="closeModal">
<template #container>
<div class="dialog-con">
<a-table
class="ant-table-striped"
:dataSource="dataSource"
:columns="columns"
:scroll="{ y: '56vh' }"
:pagination="paginationProp"
:rowClassName="(record, index) => (index % 2 === 1 ? 'table-default' : 'table-striped')"
>
</a-table>
</div>
</template>
</Dialog>
<div>
<Dialog :openVis="visible" width="70%" title="健康终端报警列表" @close="closeModal">
<template #container>
<div class="dialog-con">
<a-table
class="ant-table-striped"
:dataSource="dataSource"
:columns="columns"
:scroll="{ y: '56vh' }"
:pagination="paginationProp"
:rowClassName="(record, index) => (index % 2 === 1 ? 'table-default' : 'table-striped')"
>
<!-- <template #bodyCell="{ column, record }">-->
<!-- <template v-if="column.key === 'operation'">-->
<!-- <span class="detail-data" @click="openUserInfoModal(record)">详细数据</span>-->
<!-- </template>-->
<!-- </template>-->
</a-table>
</div>
</template>
</Dialog>
<!-- <UserInfoModal ref="userInfoModal"></UserInfoModal>-->
</div>
</template>
<script setup lang="ts">
import Dialog from '/@/components/dialog/Dialog.vue';
import { ref } from 'vue';
// import UserInfoModal from '/@/components/secondaryScreen/secondMap/components/userInfoModal/userInfoModal.vue';
import { columns } from '/@/components/secondaryScreen/secondMap/secondMapHooks.ts';
import { getUserListByDeptId } from '/@/components/secondaryScreen/secondMap/secondMapApi.ts';
//分页相关
@@ -64,6 +73,13 @@
}
}
const userInfoModal = ref();
function openUserInfoModal(item) {
console.log(item);
// UserInfoModal.value.openModal(item.extData?.deptId);
}
defineExpose({
openModal,
closeModal,
@@ -76,6 +92,12 @@
min-height: 500px;
}
.detail-data {
display: block;
color: #33afff;
cursor: pointer;
}
:deep(.ant-table-thead > tr > th) {
color: #fff !important;
background: rgba(35, 132, 221, 0.5) !important;
@@ -91,7 +113,7 @@
:deep(.ant-table) {
color: #fff;
background-color: transparent;
pointer-events: none;
//pointer-events: none;
}
:deep(.ant-table-tbody > tr > td) {
@@ -54,8 +54,10 @@
function init() {
let mapContainer = document.querySelector('.mapSecondMap');
mapContainer && Map.initMap({ el: 'mapSecondMap' });
getMapList();
mapContainer &&
Map.initMap({ el: 'mapSecondMap' }).then(() => {
getMapList();
});
}
const watchDialogRef = ref();
@@ -4,6 +4,9 @@ export enum Api {
footerStatistic = '/health-watch/watch/deptStatisticData/listByorgCode',
mapListApi = '/health-watch/watch/watchDevice/getMapList',
getUserListByDeptId = '/health-watch/watch/watchDevice/getUserListByDeptId',
queryAllStatistics = '/health-watch/watch/watchData/queryAllStatistics',
// 获取是否有数据
userDataDayByYear = '/health-watch/watch/watchData/userDataDayByYear',
}
/**
@@ -12,4 +15,6 @@ export enum Api {
*/
export const footerApi = (params) => get(Api.footerStatistic, params);
export const mapListApi = (params) => get(Api.mapListApi, params);
export const getUserListByDeptId = (params) => get(Api.getUserListByDeptId, params);
export const getUserListByDeptId = (params) => get(Api.getUserListByDeptId, params);
export const queryAllStatisticsApi = (params) => get(Api.queryAllStatistics, params);
export const userDataDayByYearApi = (params) => get(Api.userDataDayByYear, params);
@@ -303,4 +303,12 @@ export const columns = [
align: 'center',
key: 'workout',
},
// {
// title: '操作',
// dataIndex: 'operation',
// align: 'center',
// key: 'operation',
// fixed: 'right',
// width: 80,
// },
];
+34
View File
@@ -0,0 +1,34 @@
import { CSSProperties, VNodeChild } from 'vue';
import { createTypes, VueTypeValidableDef, VueTypesInterface } from 'vue-types';
export type VueNode = VNodeChild | JSX.Element;
type PropTypes = VueTypesInterface & {
readonly style: VueTypeValidableDef<CSSProperties>;
readonly VNodeChild: VueTypeValidableDef<VueNode>;
// readonly trueBool: VueTypeValidableDef<boolean>;
};
const propTypes = createTypes({
func: undefined,
bool: undefined,
string: undefined,
number: undefined,
object: undefined,
integer: undefined,
}) as PropTypes;
propTypes.extend([
{
name: 'style',
getter: true,
type: [String, Object],
default: undefined,
},
{
name: 'VNodeChild',
getter: true,
type: undefined,
},
]);
export { propTypes };
+7 -18
View File
@@ -1,32 +1,21 @@
<!--健康监测工具-->
<template>
<Dialog :openVis="visible" width="30%" :title="title" @close="closeDialog" :maskClosable="false">
<template #container>
<div class="police-con">
<div class="sub-text">有一个员工健康监测发生异常</div>
<div class="con-item">
<span>异常事件</span>
<span>{{ userInfo?.eventType_dictText }}</span>
</div>
<div class="sub-text">有一个员工刚刚发起应急求助,请马上处理!</div>
<div class="con-item">
<span>姓名</span>
<span>{{ userInfo?.realName }}</span>
</div>
<div class="con-item">
<span>年龄</span>
<span>{{ userInfo?.age }}</span>
</div>
<div class="con-item">
<span>二级单位</span>
<span>{{ userInfo?.orgName }}</span>
</div>
<div class="con-item">
<span>手机号码</span>
<span>{{ userInfo?.phone }}</span>
</div>
<div class="con-item">
<span>发生时间</span>
<span>{{ userInfo?.warnTime }}</span>
</div>
<div class="con-item">
<span>发生地点</span>
<span>{{ userInfo?.address }}</span>
</div>
</div>
</template>
</Dialog>
@@ -46,7 +35,7 @@
userInfo.value = nVal;
}
);
const { visible, title, closeDialog, openDialog } = useDialog({ title: '健康监测工具报警' });
const { visible, title, closeDialog, openDialog } = useDialog({ title: '应急求助' });
defineExpose({
openDialog,
+1
View File
@@ -1,3 +1,4 @@
<!--应急求助-->
<template>
<Dialog :openVis="visible" width="30%" :title="title" @close="closeDialog" :maskClosable="false">
<template #container>
+13 -10
View File
@@ -9,20 +9,20 @@
</div>
<div class="body-d">
<div class="body-d-left">
<one-l />
<two-l />
<three-l />
<one-l :key="refreshState" />
<two-l :key="refreshState" />
<three-l :key="refreshState" />
</div>
<div class="body-d-middle">
<china-map />
</div>
<div class="body-d-right">
<one-r />
<two-r />
<three-r />
<one-r :key="refreshState" />
<two-r :key="refreshState" />
<three-r :key="refreshState" />
</div>
</div>
<div class="bottom-d" @click="test"></div>
<div class="bottom-d"></div>
<EmployeeDialog ref="employeeDialogRef" :record="socketData" />
<EmergencyDialog ref="emergencyDialogRef" :record="emergencyData" />
</div>
@@ -40,7 +40,10 @@
import EmergencyDialog from '/@/views/components/emergencyDialog.vue';
import { useTopTime } from '/@/utils/utils.ts';
import { basicPath, emergencyPath, useSocket } from '/@/utils/socket.ts';
import { useRefresh } from '/@/hooks/autoRefresh';
import { DEFAULT_TIME } from '/@/hooks/autoRefresh/pageRefreshTime.ts';
const { refreshState } = useRefresh(DEFAULT_TIME);
const dayTimeO = ref();
const dayTimeT = ref();
const interval = ref(1);
@@ -113,8 +116,8 @@
phone: '15229020494',
};
nextTick(() => {
setSocketData(nVal);
employeeDialogRef.value.openDialog();
setEmergencyData(nVal);
emergencyDialogRef.value.openDialog();
});
}
</script>
@@ -200,4 +203,4 @@
background: url('../assets/images/bottom-b.png') no-repeat;
background-size: 100% 100%;
}
</style>
</style>