signInList.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. <template>
  2. <view class="container">
  3. <view class="content">
  4. <view class="userInfoTopFixe">
  5. <userInfo :userInfo="currentUser" :type="withoutCard ? 'member' : 'card'" bgClass="bgLinGra"></userInfo>
  6. </view>
  7. <view class="main_box">
  8. <view v-if="appoint.length == 0" class="noData">
  9. <noData :value="noDataValue"></noData>
  10. </view>
  11. <view class="item_list" v-for="(item, index) in appoint" :key="index">
  12. <view class="header_time border_bottom">
  13. <text>{{ item.regDate }} {{ item.week }}</text>
  14. <text class="colorCustom border boderColorCustom"
  15. v-if="item.regFlag == '1' && (item.reservationStatus == '1' || item.reservationStatus == '2')"
  16. @click="withdrawNumber(item)">取消订单</text>
  17. </view>
  18. <view class="main_centent border_bottom">
  19. <view class="record_info">
  20. <text>预约科室</text>
  21. <text>{{ item.deptName }}</text>
  22. </view>
  23. <view class="record_info">
  24. <text>预约医生</text>
  25. <text>{{ item.doctorName || "--" }}</text>
  26. </view>
  27. <view class="record_info">
  28. <text>就诊时间</text>
  29. <text> {{ item.timeSliceName }} {{ item.commendTime }} {{ item.sqNo }}号</text>
  30. </view>
  31. <view class="record_info">
  32. <text>就诊类型</text>
  33. <text v-if="item.sourceType == '006'">视频问诊</text>
  34. <text v-else>普通问诊</text>
  35. </view>
  36. <view class="record_info">
  37. <text>就诊位置</text>
  38. <text>{{ item.workPlace || "--" }}</text>
  39. </view>
  40. <view class="record_info">
  41. <text>就诊人</text>
  42. <text>{{ item.name }}</text>
  43. </view>
  44. <view class="record_info" v-if="!withoutCard">
  45. <text>就诊卡号</text>
  46. <text v-if="item.cardNo">{{ item.cardNo }}</text>
  47. <text v-else>暂无</text>
  48. </view>
  49. </view>
  50. <view class="footer_btn">
  51. <text :class="item.reservationStatus == 1 ? 'backgroundCustom' : item.reservationStatus == 2 ? 'backgroundCustom_F08' : 'backgroundCustom_D9'"
  52. @click="checkIn(item)">{{ item.reservationText }}</text>
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. </view>
  58. </template>
  59. <script setup lang="ts">
  60. import { ref, onUnmounted } from 'vue';
  61. import { onLoad, onHide } from '@dcloudio/uni-app';
  62. import { common } from '@/utils';
  63. import icon from '@/utils/icon';
  64. import { hisYyWaterList_V2, orderCancel } from '@/pagesPatient/service/record';
  65. import { regSignForHis } from '@/pagesPatient/service/yygh';
  66. const app = getApp();
  67. const iconUrl = ref(icon);
  68. const noDataValue = ref("暂无符合可签到条件的预约记录");
  69. const appoint = ref<any[]>([]);
  70. const serviceType = ref("");
  71. const pageConfig = ref<any>({});
  72. const currentUser = ref<any>({});
  73. const withoutCard = ref(false);
  74. const lat = ref<number | null>(null);
  75. const lng = ref<number | null>(null);
  76. let timer: any = null;
  77. onLoad((options: any) => {
  78. let config = common.deepCopy(app.globalData.config.pageConfiguration.signInList_config);
  79. let user = app.globalData.currentUser;
  80. pageConfig.value = config;
  81. currentUser.value = user;
  82. serviceType.value = options.serviceType || '';
  83. withoutCard.value = app.globalData.withoutCard;
  84. // 获取用户位置信息
  85. getUserLocation();
  86. // 获取预约记录
  87. queryYySignListForHis();
  88. });
  89. onHide(() => {
  90. if (timer) clearInterval(timer);
  91. });
  92. onUnmounted(() => {
  93. if (timer) clearInterval(timer);
  94. });
  95. const getUserLocation = () => {
  96. uni.getLocation({
  97. type: 'gcj02',
  98. success: (res) => {
  99. lat.value = res.latitude;
  100. lng.value = res.longitude;
  101. },
  102. fail: (err) => {
  103. console.error('获取位置失败', err);
  104. }
  105. });
  106. };
  107. const refresh = () => {
  108. queryYySignListForHis();
  109. };
  110. const queryYySignListForHis = async () => {
  111. let user = currentUser.value;
  112. let reqData = {
  113. memberId: user.memberId || '',
  114. cardEncryptionStore: user.encryptionStore || '',
  115. memberEncryptionStore: user.baseMemberEncryptionStore || '',
  116. startTime: common.newDay(),
  117. endTime: common.afterFewDays(1),
  118. hosId: app.globalData.districtId || app.globalData.hosId
  119. };
  120. let resp = await hisYyWaterList_V2(reqData);
  121. if (common.isNotEmpty(resp)) {
  122. let list = resp.filter((item: any) => item.regFlag == 1 && item.signState == 0);
  123. appoint.value = list;
  124. interval(list);
  125. if (timer) clearInterval(timer);
  126. timer = setInterval(() => {
  127. interval(list);
  128. }, 1000);
  129. } else {
  130. appoint.value = [];
  131. }
  132. };
  133. const interval = (list: any[]) => {
  134. // 获取当前时间
  135. let now = Date.now();
  136. //就诊前多久可签到
  137. let differenceBefore = pageConfig.value.allowedSignBefore * 60 * 1000;
  138. //允许超时多久还可签到
  139. let differenceEnd = pageConfig.value.allowedSignAfter * 60 * 1000;
  140. list.forEach(item => {
  141. /**就诊时间 */
  142. // common.iosTime might not be needed if date format is standard, but keeping it safe
  143. let dateStr = `${item.regDate} ${item.commendTime.split('-')[0]}`;
  144. // Replace - with / for iOS compatibility if common.iosTime is not available or handled differently
  145. let registertimes = new Date(dateStr.replace(/-/g, '/')).getTime();
  146. let times = registertimes - now;
  147. if (registertimes - now > differenceBefore) {
  148. /**未到时间 减去提前可签到时间毫秒数 */
  149. times = registertimes - now - differenceBefore;
  150. }
  151. let days = Math.floor(times / (24 * 60 * 60 * 1000));
  152. let hours = Math.floor(times % (24 * 60 * 60 * 1000) / (60 * 60 * 1000));
  153. let mins = common.formatNumber(Math.floor(times % (24 * 60 * 60 * 1000) % (60 * 60 * 1000) / (60 * 1000)));
  154. let secs = common.formatNumber(Math.floor(times % (24 * 60 * 60 * 1000) % (60 * 60 * 1000) % (60 * 1000) / 1000));
  155. // reservationStatus: 0:过期 1:可签到 3:时间未到 2:即将超时
  156. if (registertimes - now > differenceBefore) {
  157. /**未到时间 */
  158. let tips = days > 0 ? `${days}天` : hours > 0 ? `${hours}小时` : `${mins}分${secs}秒`;
  159. item.reservationStatus = 3;
  160. item.reservationText = `时间未到,${tips}后可签到`;
  161. } else if (registertimes - now <= differenceBefore && registertimes - now >= 0) {
  162. item.reservationStatus = 1;
  163. item.reservationText = '就诊签到';
  164. } else if (now - registertimes > 0 && now - registertimes <= differenceEnd) {
  165. /**由于超时分值是负数所以要负数转正数*/
  166. let tips = hours > 0 ? `${hours}小时` : `${common.formatNumber(Number(mins) * -1)}分${common.formatNumber(Number(secs)* -1)}秒`;
  167. item.reservationStatus = 2;
  168. item.reservationText = `已超过签到时间 ${tips}`;
  169. } else if (now - registertimes > differenceEnd) {
  170. item.reservationStatus = 0;
  171. item.reservationText = '已过期';
  172. }
  173. });
  174. list.sort(compare);
  175. appoint.value = [...list]; // Trigger reactivity
  176. };
  177. const compare = (orderInfo1: any, orderInfo2: any) => {
  178. var registerdate1 = orderInfo1.regDate + " " + orderInfo1.commendTime + ":00";
  179. var registerdateStr1 = registerdate1.replace(/-/g, "/");
  180. let registerdateTime1 = new Date(registerdateStr1).getTime();
  181. var registerdate2 = orderInfo2.regDate + " " + orderInfo2.commendTime + ":00";
  182. var registerdateStr2 = registerdate2.replace(/-/g, "/");
  183. let registerdateTime2 = new Date(registerdateStr2).getTime();
  184. if (registerdateTime1 > registerdateTime2) {
  185. if (orderInfo2.reservationStatus == 0 && orderInfo1.reservationStatus > 0) {
  186. return -1;
  187. }
  188. return 1;
  189. } else if (registerdateTime1 < registerdateTime2) {
  190. if (orderInfo1.reservationStatus == 0 && orderInfo2.reservationStatus > 0) {
  191. return 1;
  192. }
  193. return -1;
  194. }
  195. return 0;
  196. };
  197. const withdrawNumber = (item: any) => {
  198. let user = currentUser.value;
  199. common.showModal("您正在进行退号操作,为了避免误操作带来的不必要损失,系统需要您再次确认", async () => {
  200. let orderCancelData = {
  201. ...item,
  202. MemberStore: {
  203. cardEncryptionStore: user.encryptionStore || '',
  204. baseMemberEncryptionStore: user.baseMemberEncryptionStore
  205. },
  206. Store: {
  207. cardEncryptionStore: user.encryptionStore || '',
  208. baseMemberEncryptionStore: user.baseMemberEncryptionStore
  209. }
  210. };
  211. let resp = await orderCancel(orderCancelData, 0);
  212. if (!common.isEmpty(resp)) {
  213. if (timer) clearInterval(timer);
  214. /**取消成功 */
  215. common.showModal(`退号成功`, () => {
  216. queryYySignListForHis();
  217. }, {
  218. confirmText: '好的'
  219. });
  220. }
  221. }, {
  222. title: "温馨提示",
  223. cancelText: "取消"
  224. });
  225. };
  226. const checkIn = (item: any) => {
  227. // 判断当前时间未到
  228. if (item.reservationStatus !== 1 && item.reservationStatus !== 2) return;
  229. // 获取医院信息
  230. let hospitalInfo = app.globalData.hospitalInfo;
  231. if (common.isNotEmpty(hospitalInfo)) {
  232. let hosLat = hospitalInfo.Wd;
  233. let hosLng = hospitalInfo.Jd;
  234. if (common.isEmpty(hosLat) || common.isEmpty(hosLng)) {
  235. common.showToast("没有找到医院位置信息,无法线上签到。");
  236. return;
  237. }
  238. uni.getLocation({
  239. type: 'gcj02',
  240. success: async (res) => {
  241. // Use common.getDistance or implement it if missing. Assuming common has it based on original code.
  242. let distance = common.getDistance(res.latitude, res.longitude, hosLat, hosLng);
  243. if (distance > pageConfig.value.signDistance) {
  244. common.showModal(`距离医院${pageConfig.value.signDistance}公里内才可以进行在线签到,当前距离医院${distance}公里无法进行在线签到`);
  245. return;
  246. }
  247. // 判断可以无卡预约 跳转选卡页面进行校验签到
  248. if (withoutCard.value) {
  249. let queryBeanStr = encodeURIComponent(JSON.stringify(item));
  250. common.goToUrl(`/pagesPatient/st1/business/signIn/signInDetails/signInDetails?queryBean=${queryBeanStr}`);
  251. } else {
  252. let user = currentUser.value;
  253. let querData = {
  254. CardNo: user.cardNo,
  255. CardType: user.cardType,
  256. MemberId: user.memberId,
  257. OrderId: "",
  258. ChannelId: item.channelId,
  259. DeptName: item.deptName,
  260. DoctorCode: item.doctorCode,
  261. HisOrderId: item.hisOrderId,
  262. IdCardId: "",
  263. QueueNo: item.sqNo,
  264. RegisterDate: item.regDate,
  265. SourceType: "",
  266. UserName: item.name,
  267. //后端表示原因,在此用于区分是否走星网
  268. Reason: pageConfig.value.signReason,
  269. Store: {
  270. baseMemberEncryptionStore: user.baseMemberEncryptionStore,
  271. cardEncryptionStore: user.encryptionStore || ''
  272. }
  273. };
  274. let resp = await regSignForHis(querData);
  275. if (!common.isEmpty(resp)) {
  276. let queryBeanStr = JSON.stringify({
  277. ...resp[0]
  278. });
  279. console.log(queryBeanStr);
  280. common.goToUrl(`/pagesPatient/st1/business/pay/payState/payState?pageType=signIn&queryBean=${queryBeanStr}`);
  281. }
  282. }
  283. },
  284. fail: (err) => {
  285. common.showModal('请授权获取位置信息以进行签到');
  286. }
  287. });
  288. }
  289. };
  290. </script>
  291. <style scoped>
  292. .noData {
  293. width: 100%;
  294. padding-top: 0 !important;
  295. position: absolute;
  296. top: 50%;
  297. margin-top: -100upx;
  298. }
  299. .main_box {
  300. padding-top: 190upx;
  301. }
  302. .item_list {
  303. background: white;
  304. margin: 30upx;
  305. box-sizing: border-box;
  306. border-radius: 24upx;
  307. }
  308. .header_time {
  309. height: 100upx;
  310. padding: 36upx;
  311. box-sizing: border-box;
  312. display: flex;
  313. flex-direction: row;
  314. justify-content: space-between;
  315. align-items: center;
  316. }
  317. .header_time text:nth-child(1) {
  318. line-height: 32upx;
  319. font-size: 32upx;
  320. color: #333;
  321. }
  322. .header_time text:nth-child(2) {
  323. display: inline-block;
  324. width: 168upx;
  325. line-height: 56upx;
  326. text-align: center;
  327. font-size: 28upx;
  328. position: relative;
  329. }
  330. .main_centent {
  331. padding: 36upx;
  332. box-sizing: border-box;
  333. }
  334. .record_info {
  335. margin-bottom: 36upx;
  336. display: flex;
  337. flex-direction: row;
  338. justify-content: space-between;
  339. align-items: center;
  340. }
  341. .record_info:last-child {
  342. margin-bottom: 0 !important;
  343. }
  344. .record_info text:nth-child(1) {
  345. width: 26%;
  346. display: inline-block;
  347. font-size: 30upx;
  348. color: #666;
  349. }
  350. .record_info text:nth-child(2) {
  351. width: 74%;
  352. display: inline-block;
  353. font-size: 30upx;
  354. color: #333;
  355. }
  356. .footer_btn {
  357. padding: 30upx;
  358. }
  359. .footer_btn text {
  360. display: inline-block;
  361. width: 100%;
  362. line-height: 98upx;
  363. text-align: center;
  364. border-radius: 50upx;
  365. color: white;
  366. font-size: 36upx;
  367. position: relative;
  368. z-index: 0;
  369. }
  370. </style>