ChronicDiseaseQuestionnaire.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. <template>
  2. <el-row :gutter="5" style="height: 100%;">
  3. <el-col :span="8" style="height: auto;">
  4. <PageLayer>
  5. <template #main class="hd-cl">
  6. <el-row :gutter="5">
  7. <el-descriptions :column="2" border style="width:100%;">
  8. <el-descriptions-item label="门诊号" width="15%">
  9. {{ crmEmrPatientVo.hisMzNo }}
  10. </el-descriptions-item>
  11. <el-descriptions-item label="住院号" width="15%">
  12. {{ crmEmrPatientVo.hisZyNo }}
  13. </el-descriptions-item>
  14. </el-descriptions>
  15. </el-row>
  16. <el-row :gutter="5">
  17. <el-descriptions :column="1" border style="width:100%;">
  18. <el-descriptions-item label="证件号" width="30%">
  19. {{ crmEmrPatientVo.socialNo }}
  20. </el-descriptions-item>
  21. </el-descriptions>
  22. </el-row>
  23. <el-row :gutter="5">
  24. <el-descriptions :column="1" border style="width:100%;">
  25. <el-descriptions-item label="慢病类型" width="30%">
  26. {{
  27. crmEmrPatientVo.chronicDiseaseName.substring(0,
  28. crmEmrPatientVo.chronicDiseaseName.lastIndexOf(","))
  29. }}
  30. </el-descriptions-item>
  31. </el-descriptions>
  32. </el-row>
  33. <el-row :gutter="5">
  34. <el-descriptions :column="2" border style="width:100%;">
  35. <el-descriptions-item label="姓名" width="15%">
  36. {{ crmEmrPatientVo.pName }}
  37. </el-descriptions-item>
  38. <el-descriptions-item label="病人来源" width="15%">
  39. {{ crmEmrPatientVo.ptName }}
  40. </el-descriptions-item>
  41. </el-descriptions>
  42. </el-row>
  43. <el-row :gutter="5">
  44. <el-descriptions :column="2" border style="width:100%;">
  45. <el-descriptions-item label="性别" width="15%">
  46. {{ crmEmrPatientVo.sexValue }}
  47. </el-descriptions-item>
  48. <el-descriptions-item label="年龄" width="15%">
  49. {{ crmEmrPatientVo.age === null ? '' : crmEmrPatientVo.age + '岁' }}
  50. </el-descriptions-item>
  51. </el-descriptions>
  52. </el-row>
  53. <el-row :gutter="5" style="padding-top: 5px;">
  54. <el-tabs type="border-card" v-model="tabType" class="small_tabs" @tab-click="queryCrmEmdrData"
  55. style="width:100%;">
  56. <el-tab-pane label="慢病模板" name="0">
  57. <el-table :data="emrTemplateData" @row-click="rowClick">
  58. <el-table-column type="index" label="序号" width="50"></el-table-column>
  59. <el-table-column label="名称" prop="name"></el-table-column>
  60. </el-table>
  61. </el-tab-pane>
  62. <el-tab-pane label="历史模板" name="3">
  63. <el-input v-model="filterText" placeholder="搜索" style="width: 100%;">
  64. <template #prepend>关键字</template>
  65. </el-input>
  66. <el-tree style="width: 100%;" ref="treeRef" class="filter-tree" :data="treeData"
  67. :props="defaultProps" @node-click="handleNodeClick" node-key="id" highlight-current
  68. default-expand-all :filter-node-method="filterNode"/>
  69. </el-tab-pane>
  70. </el-tabs>
  71. </el-row>
  72. </template>
  73. </PageLayer>
  74. </el-col>
  75. <el-col :span="16" style="height: auto;">
  76. <PageLayer>
  77. <template #header class="hd-cl">
  78. <el-input v-model="textCode" placeholder="请输入证件号/门诊号/住院号" style="width: 320px;">
  79. <template #prepend>关键字</template>
  80. </el-input>
  81. <el-button type="primary" icon="Search" @click="selectCrmPatientMiByCode" style="margin-left: 10px">查询
  82. </el-button>
  83. <el-button type="success" @click="saveData">保存</el-button>
  84. <el-button icon="Printer" type="primary" @click="handlePrint"> 打印</el-button>
  85. </template>
  86. <template #main>
  87. <div ref="emrDivRef" style="width: 100% ; height: 100%">
  88. </div>
  89. </template>
  90. </PageLayer>
  91. </el-col>
  92. </el-row>
  93. </template>
  94. <script setup lang="ts">
  95. import {onMounted, ref, nextTick, watch, onActivated, onUnmounted} from "vue";
  96. import PageLayer from '@/layout/PageLayer.vue'
  97. import {clone} from '@/utils/clone'
  98. import {useEmrInit, UseEmrInitReturn} from "@/utils/emr/emr-init-v2";
  99. import {
  100. getCrmEmrModel,
  101. queryCrmEmrTree,
  102. queryCrmPatientInfoByCode,
  103. saveCrmEmrModel
  104. } from "@/api/chronic-disease/chronic-disease-questionnaire";
  105. import {userInfoStore} from "@/utils/store-public";
  106. import {ElMessageBox, ElTree, ElMessage} from 'element-plus'
  107. import {stringIsBlank} from "@/utils/blank-utils";
  108. import {getServerDateApi, getUuid} from "@/api/public-api";
  109. import router from "@/router";
  110. import {useCompRef} from "@/utils/useCompRef";
  111. import {onDeactivated} from "@vue/runtime-core";
  112. import {xcMessage} from "@/utils/xiaochan-element-plus";
  113. const textCode = ref('')
  114. const tabType = ref('0')
  115. const emrEvent = {
  116. 'contextUpdate': (evt, contextMap, component, context) => {
  117. const element = component.getAttribute('element')
  118. if (element) {
  119. console.log(element.name)
  120. }
  121. }
  122. }
  123. export interface Property {
  124. editorVersion?: string;
  125. creator?: string;
  126. modifyTime?: string;
  127. createTime?: string;
  128. modifier?: string;
  129. reviewer?: string;
  130. reviewTime?: string;
  131. }
  132. export interface Version {
  133. name?: string;
  134. properties?: Property;
  135. }
  136. export interface emrTemplateType {
  137. documentId?: string,
  138. parent?: string;
  139. code?: string;
  140. versions?: Version[];
  141. sortNumber?: number;
  142. name?: string;
  143. description?: string;
  144. _id?: string;
  145. type?: string;
  146. labels?: string[];
  147. }
  148. const emrTemplateData = ref<emrTemplateType[]>()
  149. const emrTemplateEditData = ref<emrTemplateType[]>()
  150. const emrDivRef = ref<HTMLDivElement>()
  151. let editor: UseEmrInitReturn;
  152. const selectionStatus = ref(false)
  153. const categoryCode = ref<string>('')
  154. const mzEmrName = ref<string>('')
  155. const parent = ref<string>('')
  156. const rowClick = async (row: emrTemplateType) => {
  157. selectionStatus.value = true
  158. categoryCode.value = row.code as string
  159. mzEmrName.value = row.name as string
  160. parent.value = row.parent as string
  161. if (tabType.value == '0') {
  162. await editor.loadAndSetDocument({
  163. categoryId: row._id,
  164. categoryCode: row.code,
  165. })
  166. } else {
  167. await editor.loadAndSetDocument({
  168. documentId: row.documentId
  169. })
  170. }
  171. editor.editor.setEditorMode('form')
  172. }
  173. const saveData = () => {
  174. const validator = editor.editor.getValidator();
  175. const valid = validator.valid(true);
  176. if (valid) {
  177. xcMessage.error('请检查必填项或者填写值是否正确!')
  178. return
  179. }
  180. if (!((tabType.value == '0' || tabType.value == '2') && selectionStatus.value)) {
  181. return ElMessage.error('请选择数据,只有慢病模板才能保存!')
  182. }
  183. ElMessageBox.confirm('请确认是否保存', {
  184. cancelButtonText: '取消',
  185. confirmButtonText: '确定',
  186. })
  187. .then(() => {
  188. clickSaveData()
  189. })
  190. .catch(() => {
  191. })
  192. }
  193. const clickSaveData = async () => {
  194. // 解析 id
  195. let id = await analysisIframeSrcSearch()
  196. let data: any = {
  197. pId: crmEmrPatientVo.value.pId,
  198. pType: crmEmrPatientVo.value.pType,
  199. emrDocumentId: id,
  200. emrCategoryCode: categoryCode.value,
  201. visitTimes: crmEmrPatientVo.value.visitTimes,
  202. emrName: mzEmrName.value,
  203. name: mzEmrName.value,
  204. parent: parent.value,
  205. inputId: crmEmrPatientVo.value.userIdCode,
  206. inputDept: crmEmrPatientVo.value.deptCode,
  207. documentData: null
  208. }
  209. let newDate = await getServerDateApi();
  210. const document = editor.editor.getDocument();
  211. document.properties.categoryCode = data.emrCategoryCode
  212. document.properties.patientId = data.pId + "-" + data.visitTimes;
  213. document._id = data.emrDocumentId
  214. data.documentData = document
  215. if (document.properties.creator) {
  216. document.properties.modifier = crmEmrPatientVo.value.userIdCode
  217. document.properties.modifierId = crmEmrPatientVo.value.userName
  218. document.properties.modifyTime = newDate
  219. } else {
  220. document.properties.creator = crmEmrPatientVo.value.userIdCode
  221. document.properties.creatorId = crmEmrPatientVo.value.userName
  222. document.properties.createTime = newDate
  223. }
  224. saveCrmEmrModel(data).then((res: any) => {
  225. selectCrmPatientMiByCode()
  226. queryCrmEmdrData(null, null)
  227. })
  228. }
  229. const analysisIframeSrcSearch = async () => {
  230. let id = getId()
  231. let temp: string
  232. if (stringIsBlank(id)) {
  233. // 这个是 唯一 id 调用服务的雪花算法
  234. temp = await getUuid()
  235. } else {
  236. temp = id
  237. }
  238. return temp
  239. }
  240. const getId = () => {
  241. if (editor) {
  242. return editor.editor.documentData._id
  243. }
  244. return null
  245. }
  246. const appContext = () => {
  247. return {
  248. endpoints: {
  249. app: "/bdp/dataservice/api",
  250. his: import.meta.env.VITE_BASE_URL,
  251. },
  252. input: {
  253. user: userInfoStore.value.code,
  254. name: userInfoStore.value.name
  255. },
  256. login: {
  257. token: userInfoStore.value.token,
  258. user: {
  259. id: userInfoStore.value.code,
  260. name: userInfoStore.value.name
  261. }
  262. },
  263. data: {
  264. '姓名': crmEmrPatientVo.value.pName,
  265. '性别': [{code: crmEmrPatientVo.value.sex, name: crmEmrPatientVo.value.sexValue}],
  266. '年龄': crmEmrPatientVo.value.age,
  267. '电话号码': crmEmrPatientVo.value.relTel,
  268. '住址': crmEmrPatientVo.value.detailAdress,
  269. '身份证号码': crmEmrPatientVo.value.socialNo,
  270. '家属电话': crmEmrPatientVo.value.relNameTel,
  271. '首次建卡时间': crmEmrPatientVo.value.createDate,
  272. '随访医生': [{code: crmEmrPatientVo.value.userIdCode, name: crmEmrPatientVo.value.userName}],
  273. }
  274. }
  275. }
  276. const handlePrint = () => {
  277. editor.editor.execute("print", {
  278. value: {
  279. showPreview: false,
  280. }
  281. })
  282. }
  283. const crmEmrPatientVo = ref<any>({
  284. pId: '',
  285. pType: '',
  286. hisMzNo: '',
  287. hisZyNo: '',
  288. visitTimes: null,
  289. userIdCode: '',
  290. userName: '',
  291. deptCode: '',
  292. deptName: '',
  293. pName: '',
  294. sex: '',
  295. sexValue: '',
  296. age: null,
  297. relTel: '',
  298. socialNo: '',
  299. relNameTel: '',
  300. chronicDiseaseName: '',
  301. detailAdress: '',
  302. createDate: '',
  303. ptName: '',
  304. type: null,
  305. })
  306. const treeData = ref<Tree[]>()
  307. const selectCrmPatientMiByCode = () => {
  308. queryCrmPatientInfoByCode(textCode.value).then((res: any) => {
  309. crmEmrPatientVo.value = res
  310. router.push({
  311. name: 'chronicDiseaseQuestionnaire',
  312. query: {
  313. id: textCode.value
  314. }
  315. })
  316. })
  317. }
  318. const queryCrmEmdrData = async (tab: any, event: any) => {
  319. tabType.value = tab === null ? '0' : tab.props.name
  320. let type = Number.parseInt(tabType.value)
  321. selectionStatus.value = false
  322. if (type == 0) {
  323. await getCrmEmrModel().then((res: any) => {
  324. let tem = [] as Array<emrTemplateType>
  325. if (res) {
  326. for (let i = 0; i < res.length; i++) {
  327. if (res[i].parent != null) {
  328. tem.push(res[i])
  329. }
  330. }
  331. }
  332. emrTemplateData.value = tem
  333. })
  334. } else {
  335. crmEmrPatientVo.value['type'] = type
  336. queryCrmEmrTree(crmEmrPatientVo.value).then((res: any) => {
  337. treeData.value = res
  338. })
  339. }
  340. }
  341. interface Tree {
  342. [key: string]: any
  343. }
  344. const filterText = ref('')
  345. const treeRef = useCompRef(ElTree)
  346. const defaultProps = {
  347. children: 'children',
  348. label: 'name',
  349. }
  350. watch(filterText, (val) => {
  351. treeRef.value!.filter(val)
  352. })
  353. const filterNode = (value: string, data: Tree) => {
  354. if (!value) return true
  355. return data.name.includes(value)
  356. }
  357. const handleNodeClick = (node: any, object: any, event: any) => {
  358. selectionStatus.value = true
  359. editor.editor.setEditorMode('readonly')
  360. editor.loadAndSetDocument({
  361. documentId: node.emrDocumentId
  362. })
  363. }
  364. let tempDocument = null
  365. onDeactivated(() => {
  366. tempDocument = editor.editor.getDocument()
  367. })
  368. onActivated(async () => {
  369. const id = router.currentRoute.value.query.id as string
  370. if (id) {
  371. if (textCode.value !== id) {
  372. tempDocument = null
  373. }
  374. textCode.value = id
  375. selectCrmPatientMiByCode()
  376. }
  377. await nextTick()
  378. useEmrInit(emrDivRef.value, {appContext, event: emrEvent}).then((res: any) => {
  379. editor = res
  380. if (tempDocument) {
  381. editor.editor.setDocument(tempDocument)
  382. tempDocument = null
  383. }
  384. })
  385. })
  386. onMounted(async () => {
  387. await queryCrmEmdrData(null, null)
  388. })
  389. </script>