yyghDeptList.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. <template>
  2. <view class="container" @click.stop="elementTracker">
  3. <view class="content">
  4. <view class="search">
  5. <view class="search_box">
  6. <input :class="isFocus ? 'search_input' : 'search_input_none'" placeholder="搜索科室或医生"
  7. :placeholder-class="isFocus ? 'placeholder' : 'placeholder_none'" :value="searchValue" data-type="focus"
  8. data-key="searchValue" @focus="focusFn" @input="setVal"></input>
  9. <image class="search_icon" :class="{ 'search_icon_none': isFocus }" :src="iconUrl.search"></image>
  10. <image class="remove_icon" v-if="isFocus" :src="iconUrl.cha" @click.stop="focusFn" data-type="blur"></image>
  11. <view v-if="isFocus" class="search_confirm backgroundCustom_F08"
  12. :class="{ 'search_confirm_active': isFocus }" @click="searchClick">搜索</view>
  13. </view>
  14. </view>
  15. <view class="search_con" @click="focusFn" data-type="blur" v-if="isFocus">
  16. <view class="search_con_inner" @click.stop="doNothing">
  17. <view class="search_con_list">
  18. <view class="search_con_list_inner">
  19. <view class="search_con_item border_top" v-for="(item, index) in searchList" :key="index"
  20. @click="deptClick(item, index, 'search')">
  21. {{ item.SearchType == '2' ? item.DoctorName + " " + item.DeptName : item.DeptName }}
  22. <image class="public_right_img" :src="iconUrl.icon_right"></image>
  23. </view>
  24. </view>
  25. </view>
  26. </view>
  27. </view>
  28. <view class="img_box displayFlexBetween">
  29. <view class="img_item displayFlexCol" @click="optionClick('ai')" v-if="pageConfig.aiMode && pageConfig.aiMode.showAi">
  30. <image class="img" :src="iconUrl.ai"></image>
  31. <view class="text">
  32. <view>AI智能导诊</view>
  33. <view style="font-size: 26upx;opacity: 0.6;margin-top: 20upx;">不懂挂哪个科室?</view>
  34. </view>
  35. </view>
  36. <view class="img_item displayFlexCol" @click="optionClick('history')">
  37. <image class="img" :src="iconUrl.doctor_history"></image>
  38. <view class="text">
  39. <view>查看历史医生</view>
  40. <view style="font-size: 26upx;opacity: 0.6;margin-top: 20upx;">预约看过的医生? </view>
  41. </view>
  42. </view>
  43. </view>
  44. </view>
  45. <view class="dept_list">
  46. <view class="dept_list_inner">
  47. <view class="dept_list_fir" :class="{ 'dept_list_fir_short': pageConfig.showDeptSec }">
  48. <view class="dept_item"
  49. :class="{ 'dept_item_active colorCustom': index == deptListFirIndex, 'toBoderRadio': index == deptListFirIndex - 1 }"
  50. v-for="(item, index) in deptListFir" :key="index" @click="deptClick(item, index, 'fir')">
  51. <view class="dept_item_inner" :class="{ 'border_bottom': !pageConfig.showDeptSec }">
  52. {{ item.DeptName }}
  53. </view>
  54. </view>
  55. </view>
  56. <view class="dept_list_sec" v-if="pageConfig.showDeptSec">
  57. <view class="dept_item border_bottom" v-for="(item, index) in deptListSec" :key="index"
  58. @click="deptClick(item, index, 'sec')">
  59. {{ item.DeptName }}
  60. </view>
  61. </view>
  62. </view>
  63. </view>
  64. <richTextModal :modalData="modalData" v-if="modalData.showModal" @cancel="modalCancel" @confirm="modalConfirm"
  65. @noData="modalNoData"></richTextModal>
  66. </view>
  67. </template>
  68. <script setup lang="ts">
  69. import { ref } from 'vue';
  70. import { onLoad, onShow } from '@dcloudio/uni-app';
  71. import { common, pagesPatientFn } from '@/utils';
  72. import icon from '@/utils/icon';
  73. import {
  74. queryClinicBaseDept,
  75. searchClinicDeptAndDoctor,
  76. queryDeptList_V2,
  77. queryDoctorList_V2
  78. } from '@/pagesPatient/service/yygh';
  79. import richTextModal from '@/pages/st1/components/richTextModal/richTextModal.vue';
  80. const app = getApp();
  81. const iconUrl = ref(icon);
  82. const isFocus = ref(false); // input是否获取焦点
  83. const searchValue = ref(''); // 搜索值
  84. const searchList = ref<any[]>([]); // 搜索结果
  85. const deptListFir = ref<any[]>([]); // 一级科室
  86. const deptListFirIndex = ref(-1); // 当前一级科室
  87. const deptListSec = ref<any[]>([]); // 二级科室
  88. const deptListSecIndex = ref(-1); // 当前二级科室
  89. const pageConfig = ref<any>({}); // 页面配置
  90. const serviceId = ref('');
  91. const queryData = ref<any>({
  92. HosId: '',
  93. ParentDeptCode: "",
  94. ServiceId: ""
  95. });
  96. const modalData = ref<any>({});
  97. onLoad((options: any) => {
  98. pageConfig.value = common.deepCopy(app.globalData.config.pageConfiguration.yyghDeptList_config);
  99. serviceId.value = options.serviceId || '';
  100. queryData.value.HosId = app.globalData.districtId || app.globalData.hosId;
  101. queryData.value.ServiceId = options.serviceId || '';
  102. main();
  103. });
  104. onShow(() => {
  105. });
  106. const main = async () => {
  107. let pConfig = pageConfig.value;
  108. // 获取一级科室
  109. let dListFir: any[] = [];
  110. let dListSec: any[] = [];
  111. let qData = queryData.value;
  112. let deptListFirResp = await queryClinicBaseDept(qData);
  113. if (!common.isEmpty(deptListFirResp)) {
  114. dListFir = deptListFirResp;
  115. if (pConfig.showDeptSec) {
  116. // 如果有二级科室 默认取第一个一级科室
  117. qData.ParentDeptCode = dListFir[0].DeptCode;
  118. let deptListSecResp = await queryClinicBaseDept(qData);
  119. if (!common.isEmpty(deptListSecResp)) {
  120. dListSec = deptListSecResp;
  121. }
  122. }
  123. }
  124. deptListFir.value = dListFir;
  125. deptListSec.value = dListSec;
  126. deptListFirIndex.value = pConfig.showDeptSec ? 0 : -1;
  127. modalData.value = pConfig.modalData;
  128. };
  129. /**
  130. * 科室点击
  131. */
  132. const deptClick = async (item: any, index: number, type: string) => {
  133. let pageType = "";
  134. let pConfig = pageConfig.value;
  135. if (type == 'fir') {
  136. // 如果点击一级科室
  137. deptListFirIndex.value = index;
  138. if (pConfig.showDeptSec) {
  139. // 如果医院有二级科室
  140. deptListSec.value = [];
  141. let qData = queryData.value;
  142. qData.ParentDeptCode = item.DeptCode;
  143. let resp = await queryClinicBaseDept(qData);
  144. if (!common.isEmpty(resp)) {
  145. deptListSec.value = resp;
  146. deptListSecIndex.value = -1;
  147. }
  148. } else {
  149. pageType = 'yyghDoctorList';
  150. }
  151. } else if (type == 'sec') {
  152. // 如果点击二级科室
  153. deptListSecIndex.value = index;
  154. pageType = 'yyghDoctorList';
  155. } else {
  156. // 搜索结果点击
  157. pageType = 'yyghDoctorList';
  158. if (item.SearchType == '2') {
  159. /**如果点击医生 跳转到挂号页面*/
  160. pageType = "yyghClinicMsg";
  161. }
  162. }
  163. // 模拟事件对象,用于 handleRouter
  164. let e = {
  165. currentTarget: {
  166. dataset: {
  167. item: item
  168. }
  169. }
  170. };
  171. // 判断如果不为空就是跳转
  172. if (common.isNotEmpty(pageType)) {
  173. // 判断等于跳转医生列表页 且有配置特殊科室续弹窗显示内容
  174. if (pageType == 'yyghDoctorList' && pConfig.deptShowMode && pConfig.deptShowMode[item.DeptCode]) {
  175. common.showModal(pConfig.deptShowMode[item.DeptCode], () => {
  176. pagesPatientFn.handleRouter(e, pageType, serviceId.value);
  177. });
  178. } else {
  179. pagesPatientFn.handleRouter(e, pageType, serviceId.value);
  180. }
  181. }
  182. };
  183. /**
  184. * 点击搜索
  185. */
  186. const searchClick = async () => {
  187. let pConfig = pageConfig.value;
  188. let sValue = searchValue.value;
  189. if (common.isEmpty(sValue)) {
  190. common.showModal('请输入搜索科室或医生');
  191. return;
  192. }
  193. let result: any[] = [];
  194. let qData = {
  195. HosId: app.globalData.districtId || app.globalData.hosId,
  196. SearchLike: sValue,
  197. ServiceId: serviceId.value,
  198. QueryLocal: "1",
  199. UseBaseInfo: true,
  200. ExcludeOneLv: pConfig.showDeptSec ? 1 : 0, // 是否过滤一级科室,
  201. };
  202. let resp = await searchClinicDeptAndDoctor(qData);
  203. if (!common.isEmpty(resp)) {
  204. result = resp;
  205. }
  206. searchList.value = result;
  207. };
  208. // 搜索科室 (Seems unused in original code but kept for completeness if needed)
  209. const queryDeptList = async (sValue: string) => {
  210. let qData = {
  211. dept: {
  212. hospitalId: app.globalData.districtId || app.globalData.hosId,
  213. deptNameOrPingyinLike: sValue,
  214. status: 1
  215. },
  216. deptdoctor: {
  217. doctorServiceGh: 1,
  218. displaystatus: 1,
  219. },
  220. doctor: {},
  221. };
  222. let resp: any = await queryDeptList_V2(qData);
  223. if (!common.isEmpty(resp)) {
  224. if (pageConfig.value.showDeptSec) {
  225. resp = resp.filter((item: any) => item.parientId != -1);
  226. }
  227. resp = common.changeObj(resp);
  228. return resp;
  229. }
  230. return [];
  231. };
  232. // 搜索医生 (Seems unused in original code but kept for completeness if needed)
  233. const queryDoctorList = async (sValue: string) => {
  234. let qData = {
  235. isQueryDeptList: "1", // "是否返回医生的科室列表",
  236. doctor: {
  237. doctorNameOrPingYinLike: sValue, // "拼音检索-模糊"
  238. status: 1
  239. },
  240. dept: {
  241. hospitalId: app.globalData.districtId || app.globalData.hosId,
  242. status: 1
  243. },
  244. deptdoctor: {
  245. doctorServiceGh: 1, // "是否开通挂号服务"
  246. displaystatus: "1" // "是否启用"
  247. }
  248. };
  249. let resp: any = await queryDoctorList_V2(qData);
  250. if (!common.isEmpty(resp)) {
  251. let doctorList: any[] = [];
  252. resp.map((item: any) => {
  253. item.searchType = '2'; // 医生数据做一个标识
  254. item.deptList.map((ele: any) => { // 方向把当前医生所有的坐诊科室排列出来
  255. doctorList.push({ ...ele, ...item });
  256. });
  257. });
  258. doctorList = common.changeObj(doctorList);
  259. return doctorList;
  260. }
  261. return [];
  262. };
  263. /**
  264. * 输入框聚焦
  265. */
  266. const focusFn = (e: any) => {
  267. let type = e.currentTarget.dataset.type;
  268. isFocus.value = type == 'focus' ? true : !isFocus.value;
  269. if (type != 'focus') {
  270. // Blur or other action, maybe clear search value?
  271. // Original logic: searchValue: type == 'focus' ? this.data.searchValue : '',
  272. searchValue.value = '';
  273. searchList.value = [];
  274. }
  275. };
  276. /**
  277. * 输入值获取
  278. */
  279. const setVal = (e: any) => {
  280. // let key = e.currentTarget.dataset.key; // unused in ref
  281. let value = e.detail.value;
  282. searchValue.value = value;
  283. };
  284. /**
  285. * 空函数 阻止搜索结果点击冒泡
  286. */
  287. const doNothing = () => {
  288. };
  289. /**
  290. * ai导诊 历史医生点击
  291. */
  292. const optionClick = (type: string) => {
  293. if (type == 'ai') {
  294. // 点击ai导诊
  295. // 跳转密影 根目录加公众号appid
  296. uni.navigateToMiniProgram({
  297. appId: pageConfig.value.aiMode.appId,
  298. // appid=: 需要自行对接配置相应医院的公众号appId
  299. path: pageConfig.value.aiMode.path
  300. });
  301. } else {
  302. // 点击历史医生
  303. common.goToUrl('/pagesPatient/st1/business/yygh/yyghHistoryDoctor/yyghHistoryDoctor');
  304. }
  305. };
  306. // 就诊须知弹窗关闭
  307. const modalCancel = () => {
  308. common.navigateBack(1);
  309. };
  310. const modalConfirm = () => {
  311. modalData.value.showModal = false;
  312. };
  313. const modalNoData = () => {
  314. common.navigateBack(1);
  315. };
  316. const elementTracker = () => {
  317. // Placeholder for elementTracker if needed
  318. };
  319. </script>
  320. <style scoped>
  321. @import "@/pagesPatient/st1/static/css/search.css";
  322. .content {
  323. padding-top: 110upx;
  324. position: relative;
  325. z-index: 10;
  326. }
  327. .search_con {
  328. width: 100%;
  329. position: fixed;
  330. height: 100%;
  331. background-color: rgba(0, 0, 0, 0.6);
  332. top: 0;
  333. left: 0;
  334. z-index: 1;
  335. overflow: auto;
  336. -webkit-overflow-scrolling: touch;
  337. }
  338. .search_con_inner {
  339. width: 100%;
  340. background-color: #fff;
  341. padding: 0 0 10upx 30upx;
  342. }
  343. .search_con_list {
  344. overflow: auto;
  345. padding-top: 110upx;
  346. -webkit-overflow-scrolling: touch;
  347. }
  348. .search_con_list_inner {
  349. width: 100%;
  350. display: inline-block;
  351. margin-top: -1px;
  352. }
  353. .search_con_item {
  354. font-size: 32upx;
  355. padding: 36upx 0;
  356. color: #222326;
  357. }
  358. .public_right_img {
  359. right: 30upx;
  360. }
  361. /* =============== */
  362. .img_box {
  363. width: 100%;
  364. flex-wrap: wrap;
  365. justify-content: space-between;
  366. align-items: center;
  367. padding: 10upx 30upx 30upx;
  368. background-color: #fff;
  369. }
  370. .img_item {
  371. width: 333upx;
  372. height: 160upx;
  373. position: relative;
  374. align-items: flex-start;
  375. padding: 0 30upx;
  376. }
  377. .img_item .img {
  378. position: absolute;
  379. top: 0;
  380. left: 0;
  381. }
  382. .img_item .text {
  383. position: relative;
  384. font-size: 32upx;
  385. font-family: PingFang SC;
  386. font-weight: 800;
  387. color: #FFFFFF;
  388. }
  389. /* =============== */
  390. .dept_list {
  391. width: 100%;
  392. position: absolute;
  393. top: 0;
  394. left: 0;
  395. width: 100%;
  396. height: 95%;
  397. padding: 330upx 30upx 0;
  398. }
  399. .dept_list_inner {
  400. display: flex;
  401. align-items: center;
  402. justify-content: space-between;
  403. overflow: hidden;
  404. border-radius: 24upx;
  405. height: 100%;
  406. }
  407. .dept_list_fir {
  408. height: 100%;
  409. overflow: auto;
  410. width: 100%;
  411. -webkit-overflow-scrolling: touch;
  412. background-color: #fff;
  413. }
  414. .dept_list_fir_short {
  415. max-width: 316upx;
  416. }
  417. .dept_list_fir_short .dept_item {
  418. background: #F7F7FC;
  419. }
  420. .dept_list_sec {
  421. height: 100%;
  422. overflow: auto;
  423. -webkit-overflow-scrolling: touch;
  424. width: 410upx;
  425. background-color: #fff;
  426. }
  427. .dept_list_sec .dept_item {
  428. text-indent: 30upx;
  429. display: flex;
  430. align-items: center;
  431. justify-content: start;
  432. padding: 34upx 0 34upx 30upx;
  433. line-height: 44upx;
  434. }
  435. .dept_item {
  436. font-size: 28upx;
  437. position: relative;
  438. color: #222326;
  439. padding-left: 30upx;
  440. padding-right: 30upx;
  441. }
  442. .dept_item_inner {
  443. padding: 34upx 0;
  444. line-height: 44upx;
  445. }
  446. .dept_item_active {
  447. font-size: 32upx;
  448. font-weight: bold;
  449. }
  450. .dept_list_fir_short .dept_item_active {
  451. background-color: #fff;
  452. }
  453. .dept_list_fir_short .dept_item_active+.dept_item {
  454. border-radius: 0 30upx 0 0;
  455. }
  456. .toBoderRadio {
  457. border-radius: 0 0 30upx 0;
  458. }
  459. </style>