DocumentExe.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <!-- 单据执行 -->
  2. <template>
  3. <view class="content-wrap">
  4. <view class="exe-item">
  5. <view class="exe-item-top">
  6. <text class="clo6">要求执行日期</text>
  7. <uni-datetime-picker
  8. class="item-right"
  9. type="date"
  10. :hide-second="true"
  11. :model-value="exeDate"
  12. @change="(e) => onConfirm(e)"
  13. :border="false"
  14. />
  15. </view>
  16. <view class="exe-item-bottom">
  17. <view class="scroll-container">
  18. <van-space size="8">
  19. <van-badge
  20. v-for="(item, index) in exeTypes"
  21. :key="index"
  22. :dot="item.dot">
  23. <van-button
  24. class="badge-btn"
  25. :type="item.type"
  26. @click="handleButtonClick(item, index)"
  27. >{{ item.label }}</van-button>
  28. </van-badge>
  29. </van-space>
  30. </view>
  31. </view>
  32. </view>
  33. <!-- 新增滚动容器 -->
  34. <view class="table-scroll-container">
  35. <view
  36. v-if="tableData.length > 0"
  37. class="exe-item flex"
  38. v-for="(item, index) in tableData"
  39. :key="index">
  40. <view class="exe-left">
  41. <van-checkbox
  42. shape="square"
  43. v-model="item.checked"></van-checkbox>
  44. </view>
  45. <view class="exe-right">
  46. <view
  47. class="exe-item-top"
  48. v-for="(medical, index) in item.exeMedications"
  49. :key="index">
  50. <text class="item-name"> {{ medical.name }}</text>
  51. <view
  52. v-if="index == 0"
  53. class="item-right-li mini">
  54. {{ item.exeDateTime }}
  55. </view>
  56. <view class="tag-container">
  57. <view class="top-btns" v-for="(type, index) in medical.useArr">
  58. <uni-tag :inverted="index === 0 || index === 5 ? false : true" :text="type.label" :type="type.type" />
  59. </view>
  60. </view>
  61. </view>
  62. <view class="exe-item-time-view">
  63. <van-space class="exe-item-time" >
  64. <view v-for="(time, index) in item.exeTimes">
  65. <uni-tag :text="time.time" size="mini" type="primary"
  66. :inverted="time.state == 'disabled'"/>
  67. </view>
  68. </van-space>
  69. <view
  70. class="item-right-li mini"
  71. @tap="showDetail(item)">
  72. {{item.showNum}}
  73. <van-icon name="arrow" />
  74. </view>
  75. </view>
  76. </view>
  77. </view>
  78. <!-- 暂无数据组件:默认样式 -->
  79. <no-data v-if="tableData.length === 0"></no-data>
  80. </view>
  81. <view class="bottom-btns">
  82. <van-button
  83. class="bottom-btn"
  84. plain
  85. type="default"
  86. @tap="selectAll"
  87. >全选</van-button>
  88. <van-button
  89. class="bottom-btn"
  90. type="primary"
  91. @tap="exeConfirm"
  92. >执行</van-button>
  93. </view>
  94. <DetailList
  95. :visibleDetail="visibleDetail"
  96. :close="() => (visibleDetail = false)"
  97. :detailData="detailData" />
  98. </view>
  99. </template>
  100. <script setup>
  101. // 原有脚本逻辑保持不变
  102. import { ref, watch, onMounted, nextTick } from 'vue';
  103. import { onLoad, onShow } from '@dcloudio/uni-app';
  104. import { $http } from '../../../config/https';
  105. import NoData from './NoData.vue';
  106. import Util from '../../../utils/util.js';
  107. import DetailList from './DetailList.vue';
  108. const props = defineProps({
  109. activeTab: {type: Number,default: 0},
  110. patNo:{type: String ,default: ''},
  111. });
  112. const userData = ref(uni.getStorageSync('userData') || {});
  113. const visibleDetail = ref(false); // 详情显示
  114. const detailData = ref('');
  115. const exeDate = ref(''); // 执行日期
  116. // 执行类型
  117. const exeTypes = ref([]);
  118. //当前选中的类型
  119. const exeTypesItem = ref('');
  120. // 执行列表数据
  121. const tableData = ref([]);
  122. onShow(() => {
  123. });
  124. const formatDateTime = () => {
  125. const date = new Date();
  126. return `${date.getFullYear()}-${(date.getMonth()+1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
  127. };
  128. // 处理接口数据的方法
  129. const handleSheetData = (sheetList) => {
  130. if (!Array.isArray(sheetList)) return [];
  131. return sheetList.map((item, index) => {
  132. return {
  133. // 去除descripts中的*、制表符、空格等多余字符
  134. label: item.descripts?.replace(/[\t*]/g, '').trim() || '',
  135. // 选中为primary,默认不选中
  136. type: index === 0 ? 'primary' : 'default',
  137. // 红点
  138. dot: false,
  139. // code
  140. code: item.code
  141. };
  142. });
  143. };
  144. //初始化
  145. const initData = () =>{
  146. let exeDateNow = formatDateTime();
  147. exeDate.value = exeDateNow;
  148. $http.post('urlDeault',this, {
  149. code: '04220024',
  150. data: {
  151. params: [{
  152. "hospID": userData.value.hospID,
  153. "locID": userData.value.locID,
  154. "stDate": exeDate.value,
  155. "stTime": "00:00:00",
  156. "endDate": exeDate.value,
  157. "endTime": "23:59:59",
  158. "patients": [props.patNo]
  159. }]
  160. },
  161. success: function(res) {
  162. if (+res.errorCode === 0) {
  163. exeTypes.value = handleSheetData(res.result.sheet);
  164. exeTypesItem.value = exeTypes.value[0].code;
  165. getPatYZInfo();
  166. }
  167. },
  168. });
  169. }
  170. //获取医嘱列表数据
  171. const getPatYZInfo = () => {
  172. $http.post('urlDeault',this, {
  173. code: '04220025',
  174. data: {
  175. params: [{
  176. "hospID": userData.value.hospID,
  177. "sheetCode": exeTypesItem.value || "QBYZ",
  178. "locID": userData.value.locID,
  179. "stDate": exeDate.value,
  180. "stTime": "00:00:00",
  181. "endDate": exeDate.value,
  182. "endTime": "23:59:59",
  183. "patients": [props.patNo]
  184. }]
  185. },
  186. success: function(res) {
  187. if (+res.errorCode === 0) {
  188. // 执行转换
  189. const transformedData = transformOrderData(res.result.order);
  190. tableData.value = transformedData;
  191. }
  192. },
  193. });
  194. }
  195. /**
  196. * 处理医嘱数据,转换为指定格式的数组
  197. * @param {Array} originalData 原始医嘱数据数组
  198. * @returns {Array} 转换后的格式化数组
  199. */
  200. const transformOrderData =(originalData)=> {
  201. // 定义type可选值,用于随机分配
  202. const typeOptions = ['primary', 'warning', 'default', 'success','error'];
  203. // 处理空数据情况
  204. if (!Array.isArray(originalData) || originalData.length === 0) {
  205. return [];
  206. }
  207. // 封装单个item转换为exeMedications项的逻辑(复用)
  208. const getMedicationItem = (item) => {
  209. return {
  210. name: item.medDesc || '', // 赋值medDesc
  211. useArr: (item.ordText || '')
  212. .split('^') // 按^拆分
  213. // .filter(part => part.trim() !== '') // 过滤空值
  214. .map((part,index) => ({
  215. label: part.trim(),
  216. type: index === 5 ? 'warning' : 'primary'
  217. }))
  218. };
  219. };
  220. // 遍历原始数据进行转换
  221. return originalData.map(item => {
  222. // 1. 计算已执行数量和总数量,生成showNum
  223. const totalExecCount = Array.isArray(item.execInfos) ? item.execInfos.length : 0;
  224. const executedCount = Array.isArray(item.execInfos)
  225. ? item.execInfos.filter(exec => exec.statusDesc === '已执行').length
  226. : 0;
  227. const showNum = `${executedCount}/${totalExecCount}`;
  228. // 2. 处理exeMedications:先加当前item,再加children里的所有item
  229. const exeMedications = [];
  230. // 先添加当前item的medication
  231. exeMedications.push(getMedicationItem(item));
  232. // 再添加children数组中的所有item(判断children存在且为数组)
  233. if (Array.isArray(item.children) && item.children.length > 0) {
  234. item.children.forEach(child => {
  235. exeMedications.push(getMedicationItem(child));
  236. });
  237. }
  238. // 3. 处理exeTimes:过滤未执行的execInfos,提取时间并设置state
  239. const unExecutedInfos = Array.isArray(item.execInfos)
  240. ? item.execInfos.filter(exec => exec.statusDesc === '未执行')
  241. : [];
  242. const exeTimes = unExecutedInfos.map((execInfo, index) => {
  243. // 提取execSttTime中的时间部分(如"12-15 15:02" -> "15:02")
  244. const time = (execInfo.execSttTime || '').split(' ')[1] || '';
  245. return {
  246. time,
  247. // 第一个元素state为空,其余为disabled
  248. state: index === 0 ? '' : 'disabled'
  249. };
  250. });
  251. // 4. 组装最终对象
  252. return {
  253. checked: true, // 默认选中,可根据需求调整
  254. exeDateTime: item.execTime || '', // execTime赋值给exeDateTime
  255. showNum,
  256. exeMedications,
  257. exeTimes,
  258. execInfos: item.execInfos,
  259. startDeteTime: item.ordStartDateTime.slice(5, 16),
  260. endDeteTime: item.ordStopDateTime.slice(5, 16),
  261. ordID: item.ordID
  262. };
  263. });
  264. }
  265. //不同医嘱类型点击事件
  266. const handleButtonClick = (item, index) => {
  267. if(item.type === 'primary'){
  268. exeTypes.value[index].type = 'default';
  269. exeTypesItem.value = '';
  270. getPatYZInfo();
  271. }else{
  272. exeTypes.value.forEach((itm, idx) => itm.type = idx === index ? 'primary' : 'default');
  273. exeTypesItem.value = item.code;
  274. getPatYZInfo();
  275. }
  276. };
  277. watch(
  278. () => props.activeTab,
  279. (newVal) => {
  280. if (newVal != 0) return;
  281. initData();
  282. },
  283. { immediate: true, deep: true },
  284. );
  285. // 确定选择日期
  286. const onConfirm = (value) => {
  287. exeDate.value = value;
  288. exeTypes.value.map(item => {
  289. if(item.type === "primary"){
  290. // 选择日期后刷新数据
  291. exeTypesItem.value = item.code;
  292. getPatYZInfo();
  293. }
  294. })
  295. };
  296. // 全选
  297. const selectAll = () => {
  298. const allChecked = tableData.value.every((item) => item.checked);
  299. tableData.value.forEach((item) => {
  300. item.checked = !allChecked;
  301. });
  302. };
  303. // 执行
  304. const exeConfirm = () => {
  305. const selectedItems = tableData.value.filter((item) => item.checked);
  306. if (selectedItems.length === 0) {
  307. uni.showToast({
  308. title: '请至少选择一项进行执行',
  309. icon: 'none',
  310. });
  311. return;
  312. }
  313. const idArr = selectedItems.map(item => item.execInfos[0].execID);
  314. $http.post('urlDeault',this, {
  315. code: '04220026',
  316. data: {
  317. params: [{
  318. "hospID": userData.value.hospID,
  319. "locID": userData.value.locID,
  320. "userID": userData.value.userID,
  321. "code": "F",
  322. "ordIDs": idArr
  323. }]
  324. },
  325. success: function(res) {
  326. if (+res.errorCode === 0) {
  327. uni.showToast({
  328. title: '执行成功',
  329. icon: 'success',
  330. });
  331. getPatYZInfo();
  332. }
  333. }
  334. });
  335. };
  336. // 查看详情
  337. const showDetail = (data) => {
  338. visibleDetail.value = true;
  339. detailData.value = data;
  340. };
  341. </script>
  342. <style scoped>
  343. @import url(../common.css);
  344. </style>