YzTableV3.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. <script setup lang="ts">
  2. import {stringIsBlank} from "../../../../../../utils/blank-utils";
  3. import {
  4. associateOrders,
  5. clearAssociate, drugManual,
  6. tempYzData, yiZhuData, yzMitt,
  7. yzSize,
  8. yzType
  9. } from "../../../../../../views/hospitalization/zhu-yuan-yi-sheng/public-js/zhu-yuan-yi-sheng";
  10. import {ref, h, reactive, onMounted, nextTick} from 'vue'
  11. import {VxeTableInstance, VxeTablePropTypes} from 'vxe-table'
  12. import {nullToEmpty} from '../../../../../../utils/public'
  13. import {getFormatDatetime} from '../../../../../../utils/date'
  14. import {getServerDateApi} from '../../../../../../api/public-api'
  15. import XEUtils from "xe-utils";
  16. import {updateOrderInstruction} from '../../../../../../api/zhu-yuan-yi-sheng/yi-zhu-lu-ru'
  17. import sleep from "../../../../../../utils/sleep";
  18. const {height} = defineProps({
  19. height: [Number, null]
  20. })
  21. const tableRef = ref<VxeTableInstance>(null)
  22. const toggleAllCheckboxEvent = () => {
  23. const $table = tableRef.value
  24. if ($table) {
  25. $table.toggleAllCheckboxRow()
  26. }
  27. }
  28. const toggleCheckboxEvent = (row) => {
  29. const $table = tableRef.value
  30. if ($table) {
  31. $table.toggleCheckboxRow(row)
  32. }
  33. }
  34. interface MenuClick {
  35. $event: Event,
  36. row: yzType,
  37. menu: { code: string, name: string, disabled?: boolean },
  38. column: any
  39. }
  40. // 鼠标右键配置文件
  41. const menuConfig = reactive<VxeTablePropTypes.MenuConfig>({
  42. body: {
  43. options: [
  44. [
  45. {code: 'fee', name: '医嘱费用'}
  46. ],
  47. [
  48. {code: 'copy', name: '复制', prefixIcon: 'vxe-icon-copy'}
  49. ],
  50. [
  51. {code: 'paste', name: '粘贴', prefixIcon: 'vxe-icon-paste'}
  52. ],
  53. [
  54. {code: 'relevancy', name: '关联'}
  55. ],
  56. [
  57. {code: 'exitTheAssociation', name: '退出关联'}
  58. ],
  59. [
  60. {code: 'instructions', name: '说明书'}
  61. ],
  62. ],
  63. },
  64. visibleMethod({options, column}) {
  65. options.forEach(list => {
  66. list.forEach((item) => {
  67. item.disabled = !column;
  68. if (item.code === 'paste') {
  69. item.disabled = !yzMitt.emit('allowReplication')
  70. }
  71. })
  72. })
  73. return true
  74. }
  75. })
  76. // 鼠标右键执行的函数
  77. const rightFunc = {
  78. "fee": (data: yzType) => {
  79. yzMitt.emit('queryFeeByOrderNo', data)
  80. },
  81. "copy": (data: yzType) => {
  82. yzMitt.emit('copy', data.actOrderNo, data.frequCode)
  83. },
  84. "paste": (data: yzType) => {
  85. yzMitt.emit('paste')
  86. },
  87. "relevancy": (data: yzType) => {
  88. yzMitt.emit('clickAssociate', data)
  89. },
  90. "exitTheAssociation": (data: yzType) => {
  91. clearAssociate()
  92. },
  93. "instructions": (data: yzType) => {
  94. if (data.groupNo !== '00') {
  95. drugManual.value.open(data.orderCode, data.serial);
  96. }
  97. },
  98. }
  99. // 触发鼠标右键的时间
  100. const tableRightClick = (val: MenuClick) => {
  101. let {row, menu} = val
  102. try {
  103. rightFunc[menu.code](row)
  104. } catch {
  105. }
  106. }
  107. const twinkleList = ref({})
  108. const rowClassName = ({row, rowIndex}) => {
  109. let data = row as yzType
  110. if (typeof twinkleList.value[data.actOrderNo] !== 'undefined') {
  111. sleep(3000).then(() => {
  112. delete twinkleList.value[data.actOrderNo]
  113. })
  114. return 'animation_hzfirst'
  115. } else if (typeof twinkleList.value[data.parentNo] !== 'undefined') {
  116. return 'animation_hzfirst'
  117. }
  118. // 父级
  119. if (data.associationFlag) {
  120. return 'parent_level'
  121. }
  122. // 子级
  123. if (associateOrders.value.actOrderNo === data.actOrderNo) {
  124. return 'child_level'
  125. }
  126. if (data.actOrderNo === yiZhuData.value.actOrderNo) {
  127. return 'activation'
  128. }
  129. }
  130. const setDefaultStopTime = async (val) => {
  131. let {row} = val
  132. if (showEndTime(row)) {
  133. row.endTimeTemp = getFormatDatetime(await getServerDateApi(), 'YYYY-MM-DDTHH:mm')
  134. await tableRef.value.setCheckboxRow(row, true)
  135. }
  136. }
  137. const endTimeChange = (val, row) => {
  138. if (XEUtils.isEmpty(val)) {
  139. tableRef.value.setCheckboxRow(row, false)
  140. } else {
  141. tableRef.value.setCheckboxRow(row, true)
  142. }
  143. }
  144. const cancelStopTime = (row) => {
  145. if (row.parentNo) return
  146. row.endTimeTemp = ''
  147. tableRef.value.setCheckboxRow(row, false)
  148. }
  149. const instructionEnter = (row: yzType) => {
  150. updateOrderInstruction(row.actOrderNo, row.instruction)
  151. }
  152. function getYiZhuFlag(val) {
  153. if (stringIsBlank(val)) {
  154. return val
  155. }
  156. switch (val) {
  157. case '1':
  158. return h('span', {style: {color: '#05ff00'}}, 'R') // (<span style="color: #05ff00">R</span>)
  159. case '2':
  160. return h('span', {style: {color: '#0000fb'}}, 'Q')//(<span style="color: #0000fb">Q</span>)
  161. case '3':
  162. return h('span', {style: {color: '#ff07f3'}}, 'Z')// (<span style="color: #ff07f3">Z</span>)
  163. case '4':
  164. return h('span', {style: {color: '#ff07f3'}}, 'Z')// (<span style="color: #ff07f3">Z</span>)
  165. case '5':
  166. return h('span', {style: {color: 'red'}}, 'T')// (<span style="color: red">T</span>)
  167. case '-1':
  168. return h('span', {style: {color: '#00ffe0'}}, 'D') // (<span style="color: #00ffe0">D</span>)
  169. default:
  170. return 'warning'
  171. }
  172. }
  173. const timeFomat = (val) => {
  174. return getFormatDatetime(val, 'YY-MM-DD HH:mm')
  175. }
  176. const showEndTime = (data: yzType) => {
  177. return stringIsBlank(data.endTime) && stringIsBlank(data.parentNo) && data.frequCode !== 'ONCE';
  178. }
  179. const rowClick = ({row}) => {
  180. yzMitt.emit('rowClick', row)
  181. }
  182. const endDateStyle = (item) => {
  183. if (item.endTimeTemp && tableRef.value.isCheckedByCheckboxRow(item)) {
  184. return {
  185. width: '140px',
  186. color: 'white',
  187. backgroundColor: 'red',
  188. border: 0,
  189. }
  190. } else {
  191. return {
  192. width: '140px',
  193. border: 0,
  194. }
  195. }
  196. }
  197. onMounted(() => {
  198. yzMitt.on('tableScroll', (val) => {
  199. tableRef.value.scrollTo(0, val)
  200. })
  201. yzMitt.on('clearSelected', () => {
  202. tableRef.value.clearSelected()
  203. })
  204. yzMitt.on('scrollEndAndTwinkle', async (val) => {
  205. let endRow = tempYzData.value[tempYzData.value.length - 1]
  206. twinkleList.value = val;
  207. await nextTick()
  208. // 滚动到最后一行
  209. await tableRef.value.scrollToRow(endRow, 'actOrderNo')
  210. })
  211. yzMitt.on('setOrderNoTwinkle', async (val: yzType) => {
  212. twinkleList.value[val] = true;
  213. let endRow = tempYzData.value[tempYzData.value.length - 1]
  214. // await nextTick()
  215. console.log(val)
  216. await tableRef.value.scrollToRow(endRow)
  217. })
  218. yzMitt.on('getSelectedData', () => {
  219. return tableRef.value.getCheckboxRecords(true)
  220. })
  221. })
  222. </script>
  223. <template>
  224. <div style="width: max-content; height: max-content">
  225. <vxe-table :height="yzSize.h - height - 35"
  226. border
  227. :style="{width:yzSize.w + 'px' }"
  228. :menu-config="menuConfig"
  229. @menu-click="tableRightClick"
  230. @cell-dblclick="setDefaultStopTime"
  231. @cell-click="rowClick"
  232. :scroll-x="{gt: 40,enabled: false}"
  233. :scroll-y="{gt: 0,enabled: true}"
  234. :column-config="{resizable: true}"
  235. :row-config="{height: 24, isHover: true}"
  236. class="vxe-padding_zero vxe-header-max_content hl-style vxe-scroll_15"
  237. header-row-class-name="padding_zero"
  238. show-header-overflow
  239. show-overflow
  240. :row-class-name="rowClassName"
  241. ref="tableRef"
  242. :data="tempYzData">
  243. <vxe-column type="checkbox" width="20">
  244. <template #header="{ checked, indeterminate }">
  245. <span class="custom-checkbox" @click.stop="toggleAllCheckboxEvent">
  246. <i v-if="indeterminate" class="vxe-icon-square-minus-fill"></i>
  247. <i v-else-if="checked" class="vxe-icon-square-checked-fill"></i>
  248. <i v-else class="vxe-icon-checkbox-unchecked"></i>
  249. </span>
  250. </template>
  251. <template #checkbox="{ row, checked, indeterminate }">
  252. <span class="custom-checkbox" @click.stop="toggleCheckboxEvent(row)">
  253. <i v-if="indeterminate" class="vxe-icon-square-minus-fill"></i>
  254. <i v-else-if="checked" class="vxe-icon-square-checked-fill"></i>
  255. <i v-else class="vxe-icon-checkbox-unchecked"></i>
  256. </span>
  257. </template>
  258. </vxe-column>
  259. <vxe-column type="seq" width="30"/>
  260. <vxe-column field="orderGroup" title="组" width="20"></vxe-column>
  261. <vxe-column field="statusFlag" width="20">
  262. <template #default="scope">
  263. <component :is="getYiZhuFlag(scope.row.statusFlag)"/>
  264. </template>
  265. </vxe-column>
  266. <vxe-column field="actOrderNo" title="医嘱号" width="70"/>
  267. <vxe-column field="orderName" title="医嘱名称" width="225"/>
  268. <vxe-column field="dose" title="剂量" width="65">
  269. <template #default="{row}">
  270. {{ nullToEmpty(row.dose) + ' ' + nullToEmpty(row.doseUnitName) }}
  271. </template>
  272. </vxe-column>
  273. <vxe-column field="frequCode" title="频率" width="75"/>
  274. <vxe-column field="supplyCodeName" title="给药方式" width="60"/>
  275. <vxe-column field="startTime" title="开始时间" width="100">
  276. <template #default="{row}">
  277. {{ timeFomat(row.startTime) }}
  278. </template>
  279. </vxe-column>
  280. <vxe-column field="endTime" title="结束时间" width="140">
  281. <template #default="scope">
  282. <input v-if="showEndTime(scope.row)"
  283. type='datetime-local'
  284. @click.stop.prevent
  285. @change="endTimeChange(scope.row.endTimeTemp, scope.row)"
  286. @contextmenu.stop.prevent="cancelStopTime(scope.row)"
  287. :style="endDateStyle(scope.row)"
  288. v-model="scope.row.endTimeTemp"/>
  289. <span v-else>{{ timeFomat(scope.row.endTime) }}</span>
  290. </template>
  291. </vxe-column>
  292. <vxe-column field="emergencyFlag" title="紧急" width="30">
  293. <template #default="{row}">
  294. {{ row.emergencyFlag === '1' ? '√' : '' }}
  295. </template>
  296. </vxe-column>
  297. <vxe-column field="ybSelfFlag" title="自费" width="30">
  298. <template #default="{row}">
  299. {{ row.ybSelfFlag === '1' ? '√' : '' }}
  300. </template>
  301. </vxe-column>
  302. <vxe-column field="physicianName" title="医生" width="65"/>
  303. <vxe-column field="selfBuyName" title="费用标志" width="60"/>
  304. <vxe-column field="execUnitName" title="执行科室" width="80"/>
  305. <vxe-column field="drugQuan" title="领量" width="30">
  306. <template #default="{row}">
  307. {{ nullToEmpty(row.drugQuan) + nullToEmpty(row.miniUnitName) }}
  308. </template>
  309. </vxe-column>
  310. <vxe-column field="groupNoName" title="药房" width="91"/>
  311. <vxe-column field="serial" title="序号" width="35"/>
  312. <vxe-column field="instruction" title="嘱托" width="180">
  313. <template #default="scope">
  314. <input v-if="scope.row.statusFlag === '1' || scope.row.statusFlag === '2' "
  315. :title="scope.row.instruction"
  316. v-model="scope.row.instruction"
  317. :maxlength="50"
  318. @keydown.enter="instructionEnter(scope.row)"
  319. />
  320. <span v-else>{{ scope.row.instruction }}</span>
  321. </template>
  322. </vxe-column>
  323. <vxe-column field="right" title="操作" width="100" fixed="right">
  324. <template #default="scope">
  325. <div class="yz_button">
  326. <div class="toVoid">作废</div>
  327. <div class="delete">删除</div>
  328. </div>
  329. </template>
  330. </vxe-column>
  331. </vxe-table>
  332. </div>
  333. </template>
  334. <style lang="scss">
  335. .new_order {
  336. position: relative;
  337. &:before {
  338. position: absolute;
  339. right: -6px;
  340. font-size: 15px;
  341. top: -5px;
  342. content: "*";
  343. color: red;
  344. }
  345. }
  346. @keyframes hzfirst {
  347. from {
  348. background-color: #95d475
  349. }
  350. to {
  351. background-color: white;
  352. }
  353. }
  354. .yz_button {
  355. width: 100%;
  356. cursor: pointer;
  357. padding: 0 5px;
  358. display: flex;
  359. justify-content: space-between;
  360. div {
  361. width: max-content;
  362. margin: 0 5px;
  363. }
  364. .toVoid {
  365. color: #E6A23C;
  366. background-color: inherit;
  367. }
  368. .delete {
  369. color: #F56C6C;
  370. background-color: inherit;
  371. }
  372. }
  373. .animation_hzfirst {
  374. td {
  375. animation: hzfirst 1s linear infinite
  376. }
  377. }
  378. .activation {
  379. background-color: #5376e7cc !important;
  380. color: white;
  381. }
  382. .parent_level {
  383. background-color: red;
  384. color: white;
  385. }
  386. .child_level {
  387. background-color: rgba(3, 255, 15);
  388. color: black;
  389. }
  390. </style>