RightPanel.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. <template>
  2. <div class="right-Panel-container">
  3. <div class="title-container">
  4. <span class="title-text">当日重点关注:发热门诊病历99例</span>
  5. </div>
  6. <div class="top-chart-container">
  7. <div class="chart-left-container">
  8. <titleContent>本市发热腹综情况</titleContent>
  9. <div class="charts-box" id="leftChartId" ref="leftChartId"></div>
  10. </div>
  11. <div class="chart-right-container">
  12. <titleContent>发热门诊、呼综情况</titleContent>
  13. <div class="charts-box" id="rightChartId" ref="rightChartId"></div>
  14. </div>
  15. </div>
  16. <template v-if="!mapStore.currentToolSelectArray.includes('Bidding')">
  17. <div class="title-box">
  18. <titleContent>发热门诊病例分区</titleContent>
  19. </div>
  20. <div class="partition-box">
  21. <div
  22. class="partition-card"
  23. v-for="(key, index) in Object.keys(partitionData)"
  24. :key="index + key + ''"
  25. :class="{ activeCard: mapStore.selectPartKey == key }"
  26. @click="handleSelect(key)"
  27. >
  28. <div class="title">{{ key }}</div>
  29. <template v-for="(childKey, index1) in Object.keys(partitionData[key])" :key="index1">
  30. <template v-if="childKey == 'infection'">
  31. <div class="text-box">
  32. <span>传染病</span>
  33. <span class="num">{{ partitionData[key][childKey][0].num }}</span>
  34. </div>
  35. </template>
  36. <template v-else-if="childKey == 'fever'">
  37. <div class="text-box">
  38. <span>发热</span> <span class="num">{{ partitionData[key][childKey][0].num }}</span>
  39. </div>
  40. </template>
  41. <template v-else-if="childKey == 'fuzong'">
  42. <div class="text-box text-box-border">
  43. <span>腹综</span>
  44. <span class="num">{{ getSum(partitionData[key][childKey]) }}</span>
  45. </div>
  46. <div
  47. class="text-box text-child-box"
  48. v-for="(item, index2) in partitionData[key][childKey]"
  49. :key="index2"
  50. >
  51. <span>{{ item.type }}</span>
  52. <span class="num">{{ partitionData[key][childKey][index2].num }}</span>
  53. </div>
  54. </template>
  55. <template v-else-if="childKey == 'cold'">
  56. <div class="text-box">
  57. <span>感冒</span>
  58. <span class="num">{{ getSum(partitionData[key][childKey]) }}</span>
  59. </div>
  60. <div
  61. class="text-box text-child-box"
  62. v-for="(item, index2) in partitionData[key][childKey]"
  63. :key="index2"
  64. >
  65. <span>{{ item.type }}</span>
  66. <span class="num">{{ partitionData[key][childKey][index2].num }}</span>
  67. </div>
  68. </template>
  69. </template>
  70. </div>
  71. </div>
  72. </template>
  73. <template v-else>
  74. <div class="title-box">
  75. <titleContent>病例列表</titleContent>
  76. </div>
  77. <div class="table-container">
  78. <el-table
  79. :data="mapStore.currentAllPointList"
  80. @row-click="handleView"
  81. @row-dblclick="handleDbView"
  82. >
  83. <el-table-column show-overflow-tooltip align="left" label="" prop="" width="15">
  84. <template #default="scope">
  85. <div
  86. v-if="scope.row.ty == '无轨迹'"
  87. class="point-box"
  88. style="background: rgba(255, 127, 0, 0.4)"
  89. ></div>
  90. <div
  91. v-if="scope.row.ty == '有轨迹'"
  92. class="point-box"
  93. style="background: rgba(0, 128, 255, 0.4)"
  94. ></div>
  95. <div
  96. v-if="scope.row.ty == '无坐标'"
  97. class="point-box"
  98. style="background: rgba(248, 152, 152, 0.4)"
  99. ></div>
  100. </template>
  101. </el-table-column>
  102. <el-table-column label="序号" align="center" type="index" width="50" />
  103. <el-table-column
  104. show-overflow-tooltip
  105. align="center"
  106. label="病例编号"
  107. prop="blbh"
  108. min-width="60"
  109. >
  110. <template #default="scope">
  111. <div @click="clickBlbh(scope)" style="color: #1257bc">{{ scope.row.blbh }}</div>
  112. </template>
  113. </el-table-column>
  114. <el-table-column show-overflow-tooltip label="疾病名称" prop="type" min-width="60">
  115. <template #default="scope">
  116. <span v-if="scope.row.type == 1">传染病</span>
  117. <span v-if="scope.row.type == 2">发热</span>
  118. <span v-if="scope.row.type == 3">腹综</span>
  119. <span v-if="scope.row.type == 4">感冒</span>
  120. </template>
  121. </el-table-column>
  122. <el-table-column show-overflow-tooltip label="流调情况" prop="ty" min-width="60">
  123. </el-table-column>
  124. <!-- <el-table-column fixed="right" label="操作" min-width="40">
  125. <template #default="scoped">
  126. <el-button class="option-button" @click="handleView(scoped)" type="text"
  127. >查看</el-button
  128. >
  129. </template>
  130. </el-table-column> -->
  131. </el-table>
  132. </div>
  133. </template>
  134. </div>
  135. </template>
  136. <script setup>
  137. import { watch, onMounted, ref } from 'vue';
  138. import titleContent from './TitleContent.vue';
  139. import * as echarts from 'echarts';
  140. import {
  141. getDataByArea,
  142. getHistogramData,
  143. getTrajectorPointOnPeople,
  144. getTrajectorPointOnPeopleById,
  145. getCaseDetailsByBh,
  146. getAllSaDian
  147. } from '@/service/api/mapRequest';
  148. import { stackRightOptions, stackLeftOptions } from '@/utils/chartsOptions.js';
  149. import { useMapStore } from '@/stores/mapStore.js';
  150. import { useDrawPointStore } from '@/stores/drawPointManage.js';
  151. import {
  152. addPoint,
  153. gotoPosition,
  154. regionZone,
  155. closePoint,
  156. fullExtent
  157. } from '@/utils/map/mapOperation.js';
  158. const partitionData = ref({});
  159. const mapStore = useMapStore();
  160. const drawPointStore = useDrawPointStore();
  161. const leftChartId = ref('');
  162. const rightChartId = ref('');
  163. //初始化echarts图
  164. const initChart = (chartDom, option) => {
  165. const myChart = echarts.init(chartDom);
  166. option && myChart.setOption(option);
  167. };
  168. const getBarData = async () => {
  169. try {
  170. const res = await getHistogramData();
  171. if (res.code == 200) {
  172. const data = res?.data || [];
  173. const dateArr = Object.keys(data);
  174. const data1 = dateArr.map((item) => {
  175. return { date: item, num: 0 };
  176. });
  177. const data2 = dateArr.map((item) => {
  178. return { date: item, num: 0 };
  179. });
  180. const data3 = dateArr.map((item) => {
  181. return { date: item, num: 0 };
  182. });
  183. const data4 = dateArr.map((item) => {
  184. return { date: item, num: 0 };
  185. });
  186. Object.values(data).forEach((item) => {
  187. item.forEach((element) => {
  188. if (element.type == '1') {
  189. data1.forEach((data) => {
  190. if (element.month == data.date) {
  191. data.num = element.num;
  192. }
  193. });
  194. } else if (element.type == '2') {
  195. data2.forEach((data) => {
  196. if (element.month == data.date) {
  197. data.num = element.num;
  198. }
  199. });
  200. } else if (element.type == '3') {
  201. data3.forEach((data) => {
  202. if (element.month == data.date) {
  203. data.num = element.num;
  204. }
  205. });
  206. } else if (element.type == '4') {
  207. data4.forEach((data) => {
  208. if (element.month == data.date) {
  209. data.num = element.num;
  210. }
  211. });
  212. }
  213. });
  214. });
  215. const yAxisData = {
  216. data1: Object.values(data1).map((item) => item.num),
  217. data2: Object.values(data2).map((item) => item.num),
  218. data3: Object.values(data3).map((item) => item.num),
  219. data4: Object.values(data4).map((item) => item.num)
  220. };
  221. const line = yAxisData.data1.map((item, index) => {
  222. return (
  223. (item + yAxisData.data2[index] + yAxisData.data3[index] + yAxisData.data4[index]) / 4
  224. );
  225. });
  226. yAxisData.line = line;
  227. initChart(rightChartId.value, stackRightOptions(dateArr, yAxisData));
  228. initChart(leftChartId.value, stackLeftOptions(dateArr, yAxisData));
  229. }
  230. } catch (error) {
  231. console.log(error);
  232. }
  233. };
  234. const clickBlbh = async (scope) => {
  235. try {
  236. const row = scope.row;
  237. const res = await getCaseDetailsByBh({
  238. bh: row.blbh,
  239. type: row.type
  240. });
  241. if (res.code == 200) {
  242. } else {
  243. console.log('获取病例详情数据错误');
  244. }
  245. } catch (error) {
  246. console.log(error);
  247. }
  248. };
  249. const handleView = (row) => {
  250. if (row?.x && row?.y) {
  251. let color = row.ty == '有轨迹' ? 'rgba(0, 128, 255, 0.8)' : 'rgba(255, 127, 0, 0.8)';
  252. let borderColor = row.ty == '有轨迹' ? 'rgba(0, 128, 255, 1)' : 'rgba(255, 127, 0, 1)';
  253. addPoint([row], 'clickView', {
  254. color: color,
  255. borderColor: borderColor
  256. });
  257. }
  258. };
  259. const selectPartKey = ref('');
  260. //选择区
  261. const handleSelect = (key) => {
  262. closePoint('cityLine');
  263. if (mapStore.selectPartKey == key) {
  264. mapStore.selectPartKey = '';
  265. fullExtent();
  266. return;
  267. }
  268. mapStore.selectPartKey = key;
  269. if (key == '浦东新区') {
  270. regionZone('浦东新区');
  271. } else {
  272. regionZone(key);
  273. }
  274. };
  275. const handleDbView = async (row) => {
  276. try {
  277. if (row?.x && row?.y) {
  278. let color = row.ty == '有轨迹' ? 'rgba(0, 128, 255, 0.8)' : 'rgba(255, 127, 0, 0.8)';
  279. gotoPosition(row, color);
  280. }
  281. //有轨迹就有id,无轨迹无id,此时将编号作为id
  282. if (row?.id) {
  283. const res = await getTrajectorPointOnPeopleById({
  284. id: row?.id
  285. });
  286. if (res.code == 200) {
  287. drawPointStore.currentSelectName = row.name;
  288. drawPointStore.currentSelectId = row.id;
  289. drawPointStore.currentSelectCode = row.code;
  290. drawPointStore.currentDrawPointList = res.data || [];
  291. drawPointStore.openBiddingTable = true;
  292. } else {
  293. console.log('获取病例轨迹数据错误');
  294. }
  295. } else {
  296. drawPointStore.currentSelectName = row.name;
  297. drawPointStore.currentSelectId = row.blbh;
  298. drawPointStore.currentSelectCode = row.blbh;
  299. drawPointStore.currentDrawPointList = [];
  300. drawPointStore.openBiddingTable = true;
  301. }
  302. } catch (error) {
  303. console.log(error);
  304. }
  305. };
  306. //分区看板
  307. const getLeftChartData = async () => {
  308. try {
  309. const res = await getDataByArea();
  310. if (res.code == 200 && res.data) {
  311. //重塑数据结构
  312. Object.keys(res.data).forEach((key) => {
  313. if (res.data && res.data[key]) {
  314. res.data[key].forEach((item) => {
  315. if (!partitionData.value[key]) {
  316. partitionData.value[key] = {};
  317. }
  318. let keyName;
  319. if (item.diseaseType == '1') {
  320. //传染病
  321. keyName = 'infection';
  322. } else if (item.diseaseType == '2') {
  323. //发热
  324. keyName = 'fever';
  325. } else if (item.diseaseType == '3') {
  326. //腹宗
  327. keyName = 'fuzong';
  328. } else if (item.diseaseType == '4') {
  329. //感冒
  330. keyName = 'cold';
  331. }
  332. if (keyName) {
  333. if (!partitionData.value[key][keyName]) {
  334. partitionData.value[key][keyName] = [];
  335. }
  336. partitionData.value[key][keyName].push(item);
  337. }
  338. });
  339. }
  340. });
  341. console.log(partitionData.value);
  342. } else {
  343. console.log(res.msg || 'getDataByArea:error');
  344. }
  345. } catch (error) {
  346. console.log(error);
  347. }
  348. };
  349. //求和
  350. const getSum = (numArr) => {
  351. return numArr
  352. .map((item) => item.num)
  353. .reduce((pre, next) => {
  354. return pre + next;
  355. });
  356. };
  357. const getAllPoint = async () => {
  358. try {
  359. const res = await getAllSaDian();
  360. if (res.code == 200) {
  361. let arr = [];
  362. Object.keys(res.data).forEach((key) => {
  363. if (key == '有轨迹') {
  364. arr = [...res.data[key], ...arr];
  365. } else {
  366. arr = [...arr, ...res.data[key]];
  367. }
  368. });
  369. mapStore.currentAllPointList = arr;
  370. } else {
  371. throw 'getTrajectorPointOnPeople:error';
  372. }
  373. } catch (error) {
  374. console.log(error);
  375. }
  376. };
  377. onMounted(() => {
  378. getLeftChartData();
  379. getBarData();
  380. getAllPoint();
  381. });
  382. </script>
  383. <style lang="scss" scoped>
  384. .right-Panel-container {
  385. .title-container {
  386. background-image: url('@/assets/image/message-bg.png');
  387. margin-top: 67px;
  388. display: flex;
  389. justify-content: flex-start;
  390. align-items: center;
  391. background-size: 100% 100%;
  392. width: 703px;
  393. height: 50px;
  394. .title-text {
  395. font-weight: bold;
  396. font-size: 18px;
  397. color: #ffffff;
  398. line-height: 29px;
  399. padding-left: 15px;
  400. }
  401. }
  402. .top-chart-container {
  403. display: flex;
  404. justify-content: space-between;
  405. padding-top: 36px;
  406. .chart-left-container,
  407. .chart-right-container {
  408. width: calc(50% - 30px);
  409. .charts-box {
  410. width: 100%;
  411. height: 175px;
  412. margin-top: 30px;
  413. }
  414. }
  415. }
  416. .title-box {
  417. width: calc(50% - 10px);
  418. margin-top: 20px;
  419. }
  420. .partition-box {
  421. display: flex;
  422. justify-content: flex-start;
  423. align-content: flex-start;
  424. flex-wrap: wrap;
  425. width: 100%;
  426. height: 621px;
  427. overflow-y: auto;
  428. padding-top: 29px;
  429. gap: 24px;
  430. scrollbar-width: none;
  431. .partition-card {
  432. width: 162px;
  433. background-image: url('@/assets/image/normal-bg.png');
  434. background-repeat: no-repeat;
  435. background-size: 100% 60px;
  436. margin-bottom: 5%;
  437. .title {
  438. font-family: Microsoft YaHei;
  439. font-weight: 400;
  440. font-size: 16px;
  441. color: #0080ff;
  442. line-height: 32px;
  443. font-style: italic;
  444. padding-left: 14px;
  445. position: relative;
  446. top: -13px;
  447. }
  448. .text-box {
  449. color: #585858;
  450. display: flex;
  451. justify-content: space-between;
  452. font-size: 14px;
  453. padding: 5px 5px 0 9px;
  454. .num {
  455. color: #0080ff;
  456. font-size: 16px;
  457. }
  458. }
  459. .text-box-border {
  460. border-bottom: 1px solid #0080ff;
  461. }
  462. .text-child-box {
  463. padding-left: 20px;
  464. }
  465. }
  466. .activeCard {
  467. background-image: url('@/assets/image/red-bg.png');
  468. .title {
  469. color: rgb(253, 1, 0);
  470. }
  471. .text-box {
  472. .num {
  473. color: rgb(253, 1, 0);
  474. }
  475. }
  476. .text-box-border {
  477. border-bottom: 1px solid rgb(253, 1, 0);
  478. }
  479. }
  480. }
  481. .table-container {
  482. width: 100%;
  483. height: 600px;
  484. background: rgba(0, 0, 0, 0);
  485. box-shadow: 0px 4px 5px #cccccc;
  486. margin-top: 25px;
  487. overflow: hidden;
  488. .option-button {
  489. width: 30px;
  490. }
  491. :deep(.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell) {
  492. background-color: rgba(90, 172, 255, 0.2);
  493. color: #1257bc;
  494. }
  495. .top-box {
  496. display: flex;
  497. justify-content: flex-start;
  498. padding-right: 20px;
  499. span {
  500. margin-right: 10px;
  501. }
  502. .add-box {
  503. width: 40px;
  504. height: 30px;
  505. margin-left: auto;
  506. }
  507. }
  508. :deep(.el-table) {
  509. height: calc(100% - 30px);
  510. background: rgba(0, 0, 0, 0);
  511. .cell {
  512. padding: 0;
  513. }
  514. .el-table__cell {
  515. padding: 5px 3px;
  516. }
  517. .el-button + .el-button {
  518. margin-left: 5px;
  519. }
  520. tr,
  521. td {
  522. background-color: unset;
  523. }
  524. th {
  525. background-color: rgba(90, 172, 255, 0.5);
  526. color: #ffffff;
  527. }
  528. }
  529. .table-row-head,
  530. .table-row-box {
  531. display: flex;
  532. justify-content: space-evenly;
  533. align-items: center;
  534. height: 25px;
  535. font-size: 14px;
  536. .table-td {
  537. flex: 1;
  538. text-align: center;
  539. }
  540. }
  541. // .table-row-head {
  542. // background-color: #dde2eb;
  543. // }
  544. .table-row-box {
  545. }
  546. }
  547. }
  548. .point-box {
  549. width: 20px;
  550. height: 20px;
  551. border-radius: 50px;
  552. }
  553. </style>
  554. <style lang="scss">
  555. .bigSize {
  556. .right-Panel-container {
  557. .title-container {
  558. .title-text {
  559. font-size: 22px;
  560. }
  561. }
  562. .partition-box {
  563. scrollbar-width: none;
  564. .partition-card {
  565. .title {
  566. font-size: 20px;
  567. }
  568. .text-box {
  569. font-size: 18px;
  570. .num {
  571. font-size: 20px;
  572. }
  573. }
  574. }
  575. }
  576. .table-container {
  577. .table-row-head,
  578. .table-row-box {
  579. font-size: 18px;
  580. }
  581. .el-table {
  582. .cell {
  583. font-size: 16px;
  584. }
  585. }
  586. }
  587. }
  588. }
  589. .veryBigSize {
  590. .right-Panel-container {
  591. .title-container {
  592. .title-text {
  593. font-size: 25px;
  594. }
  595. }
  596. .partition-box {
  597. scrollbar-width: none;
  598. .partition-card {
  599. .title {
  600. font-size: 24px;
  601. }
  602. .text-box {
  603. font-size: 22px;
  604. .num {
  605. font-size: 24px;
  606. }
  607. }
  608. }
  609. }
  610. .table-container {
  611. .table-row-head,
  612. .table-row-box {
  613. font-size: 22px;
  614. }
  615. .el-table {
  616. .cell {
  617. font-size: 20px;
  618. }
  619. }
  620. }
  621. }
  622. }
  623. </style>