home.ts 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. import PageContainerBehavior from "../../core/behavior/page-container.behavior";
  2. import I18nBehavior from "../../i18n/behavior";
  3. import {
  4. DraggableSheetBehavior,
  5. getDraggableSheetContext,
  6. } from "../../core/behavior/draggableSheet.behavior";
  7. import { login } from "../../lib/logic";
  8. import { useRouteQuery } from "../../utils/route-query";
  9. import { appUpdate } from "../../lib/wx/update";
  10. import { addPatientOnlineRecordClockIn } from "./request";
  11. import { Get } from "../../lib/request/method";
  12. const { shared, Easing, timing } = wx.worklet;
  13. const offset = shared(0);
  14. const menus = ["shareAppMessage", "shareTimeline"];
  15. // pages/home/home.ts
  16. import {
  17. getPatients,
  18. healthReportMethod,
  19. healthIndexMethod,
  20. getSolarTerms,
  21. getShortScienceList,
  22. getPatientDescription,
  23. getNotDealLists,
  24. getCareList,
  25. } from "./request";
  26. import { toCertificationPage, toChats } from "./router";
  27. import { Post } from "../../lib/request/method";
  28. // import { useLocation } from "../../lib/use/use-location";
  29. Page({
  30. data: {
  31. i18n: {
  32. common: { title: '生活助理', zy: '' },
  33. home: { analysis: '评估', consult: '聊天', __showRecord__: false, __showDisplay__: false },
  34. report: { title: '报告' },
  35. healthTeach: { title: '' },
  36. },
  37. NoteTitle: "",
  38. isShowComplete: true,
  39. careList: [],
  40. displayList: [] as {
  41. id: number;
  42. conditioningProgramType: string;
  43. operateBy?: string;
  44. operateTime: string;
  45. frequencyType: string; // 频次类型
  46. frequencyMeasure: string; // 总用量
  47. arrangeDate: string; // 下一次开始日期
  48. finishCount: number; // 完成量
  49. conditioningProgramName: string; // 调养计划名称
  50. conditioningProgramSupplierName: string; // 调养计划供应商名称
  51. expanded: boolean;
  52. }[],
  53. allExpanded: false,
  54. fixedHeight: "370rpx",
  55. tabbarValue: "/pages/home/home",
  56. tabbarHidden: false,
  57. pageHeight: "100vh", // 默认值
  58. popupList: [] as AnyArray,
  59. isShowPopup: false,
  60. isCompleting: false, // 防止重复点击标志
  61. patients: [] as (App.Patient.Model & { isDefault: "Y" | "N" })[],
  62. patient: null as App.Patient.Model | null,
  63. patientDescription: "",
  64. healthId: "",
  65. healthReport: { data: null, message: "", loading: true },
  66. healthIndex: { data: [], message: "" },
  67. position: {} as AnyObject,
  68. location: {} as AnyObject,
  69. solarTerms: {} as AnyObject,
  70. sheet: false,
  71. scienceList: [] as AnyArray,
  72. leftColumnList: [] as AnyArray,
  73. rightColumnList: [] as AnyArray,
  74. scienceListPage: 1,
  75. scienceListSize: 10,
  76. scienceListTotal: 0,
  77. scienceListLoading: false,
  78. scienceListHasMore: true,
  79. refreshing: false,
  80. _loaded: false,
  81. statusList: [] as AnyArray,
  82. switchType: "",
  83. carouselLoading: {} as Record<string | number, boolean>,
  84. carouselMediaList: [] as Array<{
  85. type: "image" | "video";
  86. src: string;
  87. }>,
  88. // 是否在咨询中
  89. isConsulting: false,
  90. // 是否有新消息
  91. hasNewMessage: false,
  92. },
  93. behaviors: [
  94. I18nBehavior,
  95. PageContainerBehavior,
  96. DraggableSheetBehavior(".draggable-sheet-wrapper"),
  97. ],
  98. async getCareLists() {
  99. const currentExpandedStates = this.data.displayList.map((item: any) => ({
  100. id: item.id,
  101. expanded: item.expanded,
  102. }));
  103. const res = await getCareList();
  104. if (res && res.length > 0) {
  105. res.forEach((item: any) => {
  106. item.carouselMediaList = [];
  107. // 添加photo
  108. if (item.photo) {
  109. item.carouselMediaList.push({
  110. type: "image",
  111. src: item.photo,
  112. });
  113. }
  114. // 添加itemImgFirst
  115. if (item?.itemImgFirst) {
  116. item.carouselMediaList.push({
  117. type: "image",
  118. src: item.itemImgFirst,
  119. });
  120. }
  121. // 添加itemVideoFirst
  122. if (item?.itemVideoFirst) {
  123. item.carouselMediaList.push({
  124. type: "video",
  125. src: item.itemVideoFirst,
  126. });
  127. }
  128. });
  129. // 先设置 careList
  130. this.setData({
  131. careList: res,
  132. });
  133. await this.updateDisplayList(currentExpandedStates);
  134. setTimeout(() => {
  135. res.forEach((item: any, index: number) => {
  136. if (item.carouselMediaList && item.carouselMediaList.length > 0) {
  137. this.setData({
  138. [`careList[${index}].carouselMediaList`]: [
  139. ...item.carouselMediaList,
  140. ],
  141. });
  142. // 同时更新 displayList
  143. const displayIndex = this.data.displayList.findIndex(
  144. (displayItem: any) => displayItem.id === item.id
  145. );
  146. if (displayIndex !== -1) {
  147. this.setData({
  148. [`displayList[${displayIndex}].carouselMediaList`]: [
  149. ...item.carouselMediaList,
  150. ],
  151. });
  152. }
  153. }
  154. });
  155. }, 100);
  156. }
  157. },
  158. async onLoad(options) {
  159. appUpdate();
  160. const query = useRouteQuery(options.scene!);
  161. if (query.ys) wx.setStorageSync("doctorId", query.ys);
  162. if (options.scene) wx.setStorageSync("scene", options.scene);
  163. this.initFabAnimated();
  164. if (options.switchType) {
  165. this.setData({
  166. switchType: options.switchType,
  167. });
  168. }
  169. },
  170. async onShow() {
  171. wx.showShareMenu({ withShareTicket: true, menus }).then();
  172. await this.load();
  173. // 如果是从一体机扫码进来的 有switchType值就直接跳转到注册页面
  174. if (
  175. this.data.switchType &&
  176. ((this.data.patient as any)?.isPerfectInfo ?? true)
  177. ) {
  178. wx.navigateTo({
  179. url: "/module/user/pages/user-certification/user-certification?type=home",
  180. });
  181. }
  182. // 检查咨询状态
  183. this.checkConsultationStatus();
  184. // 如果用户没有手机号每次进入页面都提示 点击跳到注册页补充
  185. // todo 要先判断用户有没有手机号 isPerfectInfo是true 就出来弹窗提示用户
  186. // if ((this.data.patient as any)?.isPerfectInfo ?? true) {
  187. // wx.showModal({
  188. // title: "提示",
  189. // content: "手机号为空,请补充",
  190. // success: (res) => {
  191. // if (res.confirm) {
  192. // wx.navigateTo({
  193. // url: "/module/user/pages/user-certification/user-certification?type=home",
  194. // });
  195. // }
  196. // },
  197. // });
  198. // }
  199. },
  200. onHide() {
  201. wx.hideShareMenu({ menus }).then();
  202. offset.value = timing(
  203. 0,
  204. { duration: 100, easing: (<any>Easing).linear },
  205. () => {
  206. "worklet";
  207. }
  208. );
  209. },
  210. onShareAppMessage(_opts): WechatMiniprogram.Page.ICustomShareContent {
  211. return {
  212. title: `健康为基,从容赏生活之美`,
  213. imageUrl: `https://wx.hzliuzhi.com/media/healthManager/wx/share.jpg`,
  214. path: `/pages/home/home`,
  215. };
  216. },
  217. onShareTimeline() {
  218. return {
  219. title: `健康为基,从容赏生活之美`,
  220. };
  221. },
  222. async updateDisplayList(
  223. preserveExpandedStates?: Array<{
  224. id: number;
  225. expanded: boolean;
  226. }>
  227. ) {
  228. const { careList, allExpanded } = this.data;
  229. let newDisplayList: any[] =
  230. allExpanded || careList.length <= 4 ? careList : careList.slice(0, 4);
  231. // 如果有保存的展开状态,则恢复它们
  232. if (preserveExpandedStates && preserveExpandedStates.length > 0) {
  233. newDisplayList = newDisplayList.map((item: any) => {
  234. const savedState = preserveExpandedStates.find(
  235. (state) => state.id === item.id
  236. );
  237. if (savedState) {
  238. return {
  239. ...item,
  240. expanded: savedState.expanded,
  241. };
  242. }
  243. return item;
  244. });
  245. }
  246. this.setData({
  247. displayList: newDisplayList,
  248. });
  249. },
  250. toggleAll() {
  251. this.setData(
  252. { allExpanded: !this.data.allExpanded },
  253. this.updateDisplayList
  254. );
  255. },
  256. toggleItem(e: any) {
  257. const index = e.currentTarget.dataset.index;
  258. const key = `displayList[${index}].expanded`;
  259. this.setData({ [key]: !this.data.displayList[index].expanded });
  260. },
  261. // 核销记录
  262. onRecord(e: any) {
  263. const id = e.currentTarget.dataset.id;
  264. if (id) {
  265. wx.navigateTo({
  266. url: `/module/care/pages/care/verifyRecord?id=${id}`,
  267. });
  268. } else {
  269. wx.showToast({
  270. title: "暂无核销记录",
  271. icon: "none",
  272. });
  273. }
  274. },
  275. // 去预约
  276. onAppointment(e: any) {
  277. const id = e.currentTarget.dataset.id;
  278. if (id) {
  279. wx.navigateTo({
  280. url: `/module/care/pages/offlineTreatment/offlineTreatment?id=${id}`,
  281. });
  282. }
  283. },
  284. // 长按复制机构名称
  285. onCopyInstitutionName(e: any) {
  286. const name = e.currentTarget.dataset.name;
  287. if (name) {
  288. wx.setClipboardData({
  289. data: name,
  290. success: () => wx.showToast({ title: "已复制", icon: "none" }),
  291. });
  292. }
  293. },
  294. onClose() {
  295. this.setData({
  296. isShowPopup: false,
  297. });
  298. },
  299. // 打卡
  300. pushCard(e: any) {
  301. const id = e.currentTarget.dataset.id;
  302. wx.navigateTo({
  303. url: `/module/article/pages/punch-card/punch-card?id=${id}`,
  304. });
  305. },
  306. calculatePageHeight() {
  307. const systemInfo = wx.getSystemInfoSync();
  308. const windowHeight = systemInfo.windowHeight; // 屏幕可用高度
  309. // 获取 tabbar 高度
  310. const query = wx.createSelectorQuery();
  311. query
  312. .select(".t-tabbar")
  313. .boundingClientRect((rect) => {
  314. if (rect) {
  315. const tabbarHeight = rect.height;
  316. const contentHeight = windowHeight - tabbarHeight;
  317. this.setData({
  318. pageHeight: `${contentHeight}px`,
  319. });
  320. }
  321. })
  322. .exec();
  323. },
  324. getNotDealList() {
  325. getNotDealLists().then((res) => {
  326. if (res.length > 0) {
  327. this.setData({
  328. popupList: res,
  329. isShowPopup: true,
  330. NoteTitle: res[0].title,
  331. });
  332. } else {
  333. this.setData({
  334. popupList: [],
  335. isShowPopup: false,
  336. NoteTitle: "",
  337. });
  338. }
  339. });
  340. },
  341. showFollowPopup() {
  342. this.getNotDealList();
  343. },
  344. onVisibleChange(e: { detail: { visible: any } }) {
  345. this.setData({
  346. isShowPopup: e.detail.visible,
  347. });
  348. },
  349. async goComplete(e: {
  350. currentTarget: { dataset: { page: string; id: number; title: string } };
  351. }) {
  352. if (this.data.isCompleting) {
  353. return;
  354. }
  355. this.setData({ isCompleting: true });
  356. try {
  357. const { title } = e.currentTarget.dataset;
  358. let page = e.currentTarget.dataset.page;
  359. let id = e.currentTarget.dataset.id;
  360. if (page === "/module/chats/pages/index/index") {
  361. if (title === "健康评估") {
  362. wx.setStorageSync("isAnalysis", 4);
  363. toChats("questionnaire", 2);
  364. } else {
  365. wx.setStorageSync("isAnalysis", 2);
  366. wx.setStorageSync("workId", id);
  367. wx.navigateTo({
  368. url: `${page}?component=questionnaire&messageType=1&id=${id}`,
  369. });
  370. }
  371. } else if (page === "/module/article/pages/science-info/science-info") {
  372. try {
  373. const res = await Get(`/psarticle/clickPsaNotice`, {
  374. params: { noticeSendRecordId: id },
  375. });
  376. const url = res?.data;
  377. const item = {
  378. url,
  379. };
  380. wx.navigateTo({
  381. url: `${page}`,
  382. }).then((res) => {
  383. res.eventChannel.emit("load", item);
  384. });
  385. } catch (error) {
  386. console.log(error);
  387. }
  388. } else {
  389. const status = 'pending';
  390. // 随访
  391. wx.navigateTo({ url: `${page}?id=${id}&status=${status}` });
  392. }
  393. } finally {
  394. setTimeout(() => {
  395. this.setData({ isCompleting: false });
  396. }, 500);
  397. }
  398. },
  399. // 随访评估报告已出
  400. goSeeFollowReport() {
  401. wx.navigateTo({ url: "/module/follow/pages/evaluation/report" });
  402. },
  403. async load(forceLogin = false) {
  404. try {
  405. await login(forceLogin);
  406. wx.showLoading({ title: "加载中" });
  407. const { patient } = await getPatients(/*this.data.patientId*/);
  408. // if (!patient) await toCertificationPage();
  409. if (!patient) {
  410. /*if (wx.getStorageSync("doctorId")) {
  411. toCertificationPage();
  412. }*/
  413. this.setData({
  414. "healthReport.loading": false,
  415. isShowComplete: true,
  416. });
  417. } else {
  418. this.setData({ patient });
  419. this.observerPatient(patient);
  420. }
  421. wx.hideLoading();
  422. } catch (error: any) {
  423. await wx
  424. .showModal({
  425. title: `加载失败`,
  426. content: `${error?.errMsg ?? error?.message ?? ""}`,
  427. showCancel: false,
  428. confirmText: `重新加载`,
  429. })
  430. .catch(() => { });
  431. await this.load(true);
  432. return;
  433. }
  434. // 加载健康宣教的文章
  435. this.loadScienceList(true);
  436. if (!this.data._loaded) {
  437. getSolarTerms()
  438. .then((solarTerms) => {
  439. this.setData({ solarTerms });
  440. })
  441. .catch(() => { });
  442. this.setData({ _loaded: true });
  443. }
  444. },
  445. async _getHealthReport() {
  446. wx.showLoading({ title: "加载中" });
  447. this.setData({ "healthReport.loading": true });
  448. try {
  449. const data = await healthReportMethod();
  450. if (!data) {
  451. this.setData({
  452. isShowComplete: true,
  453. });
  454. } else {
  455. this.setData({
  456. isShowComplete: false,
  457. });
  458. }
  459. this.setData({
  460. "healthReport.data": data,
  461. "healthReport.loading": false,
  462. healthId: data?.healthAnalysisReportId,
  463. });
  464. let arr2 = [
  465. [
  466. {
  467. title: "健康状态",
  468. value: data?.willillStateName ? `${data?.willillStateName}` : "",
  469. },
  470. {
  471. title: "程度",
  472. value: data?.willillDegreeName ? `${data?.willillDegreeName}` : "",
  473. },
  474. {
  475. title: "表现",
  476. value: data?.willillFunctionName
  477. ? `${data?.willillFunctionName}`
  478. : "",
  479. },
  480. ],
  481. [
  482. {
  483. title: "中医证素",
  484. value: data?.factorItemSummary ? `${data?.factorItemSummary}` : "",
  485. },
  486. ],
  487. [
  488. {
  489. title: "体质",
  490. value: data?.constitutionGroupName
  491. ? `${data?.constitutionGroupName}`
  492. : "",
  493. },
  494. ],
  495. ];
  496. this.setData({
  497. statusList: arr2,
  498. });
  499. } catch (error: any) {
  500. wx.showToast({
  501. title: error.errMsg || "加载失败",
  502. icon: "none",
  503. });
  504. this.setData({
  505. "healthReport.data": [],
  506. "healthReport.loading": false,
  507. "healthReport.message": error.errMsg,
  508. healthId: "",
  509. });
  510. }
  511. wx.hideLoading();
  512. },
  513. async _getAbnormalHealthIndex() {
  514. this.setData({ "healthIndex.loading": true });
  515. try {
  516. const data = await healthIndexMethod();
  517. this.setData({
  518. "healthIndex.data": data
  519. .map((item: AnyObject) => item.abnormalDesc)
  520. .filter(Boolean),
  521. "healthIndex.loading": false,
  522. });
  523. } catch (error: any) {
  524. this.setData({
  525. "healthIndex.data": [],
  526. "healthIndex.loading": false,
  527. "healthIndex.message": error.errMsg,
  528. });
  529. }
  530. },
  531. onBodyModel(event: WechatMiniprogram.TouchEvent) {
  532. if (event.detail?.position === "LB") {
  533. this.toReportPage();
  534. } else if (event.detail?.position === "item0") {
  535. const report = this.data.healthReport.data as unknown as AnyObject;
  536. this.setData({
  537. position: {
  538. LT: [
  539. "willillState",
  540. "willillDegree",
  541. "willillSocial",
  542. "willillFunction",
  543. ]
  544. .map((key) => {
  545. const title = report[`${key}Name`];
  546. const description = report[`${key}Description`];
  547. return title || description ? { title, description } : null;
  548. })
  549. .filter(Boolean),
  550. },
  551. });
  552. this.showDraggableSheet();
  553. } else if (event.detail?.position === "item2") {
  554. const report = this.data.healthReport.data as unknown as AnyObject;
  555. const get = (key: string) => ({ [key]: report[key] });
  556. this.setData({
  557. position: {
  558. RT: {
  559. ...get("constitutionGroupName"),
  560. ...get("constitutionGroupDefinition"),
  561. ...get("faceImg"),
  562. ...get("faceAnalysisResult"),
  563. ...get("tongueAnalysisResult"),
  564. ...get("upImg"),
  565. ...get("downImg"),
  566. },
  567. },
  568. });
  569. this.showDraggableSheet();
  570. } else if (event.detail?.position === "item1") {
  571. const report = this.data.healthReport.data as unknown as AnyObject;
  572. const get = (key: string) => ({ [key]: report[key] });
  573. this.setData({
  574. position: {
  575. RB: {
  576. ...get("diagnoseSyndromeSummary"),
  577. ...get("diagnoseSyndromes"),
  578. ...get("factorItemSummary"),
  579. ...get("factorItems"),
  580. },
  581. },
  582. });
  583. this.showDraggableSheet();
  584. } else if (event.detail?.position === "CT") {
  585. this.setData({
  586. position: {
  587. CT: this.data.healthIndex.data.map(
  588. (item, index) => `${index + 1}、${item}`
  589. ),
  590. },
  591. });
  592. this.showDraggableSheet();
  593. }
  594. },
  595. tabValue() {
  596. this.setData({
  597. position: {
  598. CT: this.data.healthIndex.data.map(
  599. (item, index) => `${index + 1}、${item}`
  600. ),
  601. },
  602. });
  603. this.showDraggableSheet();
  604. },
  605. initFabAnimated() {
  606. (<any>this).applyAnimatedStyle(".fab-wrapper", () => {
  607. "worklet";
  608. return { right: `${Math.min(offset.value, 36) - 36}px` };
  609. });
  610. (<any>this).applyAnimatedStyle(".fab-1", () => {
  611. "worklet";
  612. return { transform: `translateY(${-offset.value}px)` };
  613. });
  614. (<any>this).applyAnimatedStyle(".fab-2", () => {
  615. "worklet";
  616. return {
  617. transform: `translateX(${-offset.value}px) translateY(${-offset.value / 2
  618. }px)`,
  619. };
  620. });
  621. (<any>this).applyAnimatedStyle(".fab-3", () => {
  622. "worklet";
  623. return {
  624. transform: `translateX(${-offset.value}px) translateY(${offset.value / 2
  625. }px)`,
  626. };
  627. });
  628. (<any>this).applyAnimatedStyle(".fab-4", () => {
  629. "worklet";
  630. return { transform: `translateY(${offset.value}px)` };
  631. });
  632. },
  633. onFabTap() {
  634. const value = Math.abs(offset.value - 72);
  635. offset.value = timing(
  636. value,
  637. { duration: 500, easing: (<any>Easing).linear },
  638. () => {
  639. "worklet";
  640. if (offset.value > 0) offset.value = 72;
  641. }
  642. );
  643. },
  644. async toChatsPage() {
  645. if (!this.data.patient?.patientId) {
  646. try {
  647. await this.load();
  648. } catch (error: any) {
  649. wx.showModal({
  650. title: "出错了",
  651. content: error?.errMsg ?? error?.message ?? "错误,请重试",
  652. showCancel: false,
  653. });
  654. return;
  655. }
  656. }
  657. const page = "/module/chats/pages/index/index";
  658. wx.navigateTo({
  659. url: `${page}?component=guide&isShowGuide=true`,
  660. });
  661. wx.setStorageSync("isAnalysis", 3);
  662. },
  663. toSciencePage() {
  664. wx.navigateTo({ url: `/module/article/pages/science-list/science-list` });
  665. },
  666. async toReportPage() {
  667. // const { patient } = await getPatients(/*this.data.patientId*/);
  668. if (!this.data.patient) await toCertificationPage();
  669. else {
  670. const id = this.data.healthId;
  671. if (id)
  672. wx.navigateTo({ url: `/module/health/pages/report/report?id=${id}` });
  673. else wx.showToast({ title: "暂无分析报告", icon: "none" });
  674. }
  675. },
  676. onDraggableSizeUpdate(e: any) {
  677. "worklet";
  678. if (e.pixels < 1) {
  679. wx.worklet.runOnJS(this.hideDraggableSheet.bind(this))();
  680. }
  681. },
  682. showDraggableSheet() {
  683. getDraggableSheetContext.call(this).scrollTo({
  684. size: 0.5,
  685. pixels: 600,
  686. animated: true,
  687. duration: 300,
  688. easingFunction: "ease",
  689. });
  690. this.setData({ sheet: true });
  691. },
  692. hideDraggableSheet(event?: any) {
  693. if (event) {
  694. getDraggableSheetContext.call(this).scrollTo({
  695. size: 0,
  696. animated: true,
  697. duration: 300,
  698. easingFunction: "ease",
  699. });
  700. }
  701. this.setData({ position: {}, sheet: false });
  702. },
  703. async loadScienceList(reset = false) {
  704. if (this.data.scienceListLoading) {
  705. return;
  706. }
  707. if (!reset && !this.data.scienceListHasMore) {
  708. return;
  709. }
  710. if (reset) {
  711. this.setData({
  712. scienceListPage: 1,
  713. scienceListHasMore: true,
  714. scienceList: [],
  715. leftColumnList: [],
  716. rightColumnList: [],
  717. });
  718. }
  719. this.setData({ scienceListLoading: true });
  720. try {
  721. const page = reset ? 1 : this.data.scienceListPage;
  722. const {
  723. data,
  724. total,
  725. page: currentPage,
  726. } = await getShortScienceList(page, this.data.scienceListSize);
  727. const newList = reset ? data : [...this.data.scienceList, ...data];
  728. const hasMore = newList.length < total;
  729. this.setData({
  730. scienceList: newList,
  731. scienceListTotal: total,
  732. scienceListPage: currentPage + 1,
  733. scienceListHasMore: hasMore,
  734. scienceListLoading: false,
  735. });
  736. this.distributeCardsToColumns(newList, reset);
  737. } catch (error) {
  738. this.setData({ scienceListLoading: false });
  739. wx.showToast({
  740. title: "加载失败,请重试",
  741. icon: "none",
  742. });
  743. }
  744. },
  745. // 下拉刷新
  746. async onRefreshScienceList() {
  747. this.setData({ refreshing: true });
  748. await this.loadScienceList(true);
  749. this.setData({ refreshing: false });
  750. },
  751. // 上拉加载更多
  752. onLoadMoreScienceList() {
  753. if (this.data.scienceListHasMore && !this.data.scienceListLoading) {
  754. this.loadScienceList(false);
  755. }
  756. },
  757. // 将卡片分配到两列,实现瀑布流布局
  758. distributeCardsToColumns(list: AnyArray, reset = false) {
  759. // 如果是重置,使用空数组;否则过滤出新增的卡片
  760. const itemsToDistribute = reset
  761. ? list
  762. : list.filter(
  763. (item: any) =>
  764. !this.data.leftColumnList.some(
  765. (existing: any) => existing.id === item.id
  766. ) &&
  767. !this.data.rightColumnList.some(
  768. (existing: any) => existing.id === item.id
  769. )
  770. );
  771. if (itemsToDistribute.length === 0) return;
  772. // 计算当前两列的高度(重置时两列已为空,高度为0)
  773. let leftHeight = reset
  774. ? 0
  775. : this.data.leftColumnList.reduce(
  776. (sum: number, item: any) => sum + this.estimateCardHeight(item),
  777. 0
  778. );
  779. let rightHeight = reset
  780. ? 0
  781. : this.data.rightColumnList.reduce(
  782. (sum: number, item: any) => sum + this.estimateCardHeight(item),
  783. 0
  784. );
  785. const leftColumn = reset ? [] : [...this.data.leftColumnList];
  786. const rightColumn = reset ? [] : [...this.data.rightColumnList];
  787. itemsToDistribute.forEach((item: any) => {
  788. const estimatedHeight = this.estimateCardHeight(item);
  789. if (leftHeight <= rightHeight) {
  790. leftColumn.push(item);
  791. leftHeight += estimatedHeight;
  792. } else {
  793. rightColumn.push(item);
  794. rightHeight += estimatedHeight;
  795. }
  796. });
  797. this.setData({
  798. leftColumnList: leftColumn,
  799. rightColumnList: rightColumn,
  800. });
  801. },
  802. estimateCardHeight(item: any): number {
  803. let height = 0;
  804. if (item.briefImg) {
  805. const imgMinHeight = 120;
  806. const imgMaxHeight = 260;
  807. const imgHeightRange = imgMaxHeight - imgMinHeight;
  808. const idHash = item.id
  809. ? String(item.id)
  810. .split("")
  811. .reduce((acc: number, char: string) => acc + char.charCodeAt(0), 0)
  812. : 0;
  813. const imgHeight = imgMinHeight + (idHash % imgHeightRange);
  814. height += imgHeight;
  815. }
  816. const title = item.title || "";
  817. const titleLength = title.length;
  818. const charsPerLine = 12;
  819. const titleLines = Math.min(Math.ceil(titleLength / charsPerLine), 3);
  820. const titleHeight = titleLines * 24;
  821. const contentPadding = 24;
  822. const metaHeight = 40;
  823. height += titleHeight + contentPadding + metaHeight;
  824. height += 12;
  825. height += 4;
  826. if (!item.briefImg) {
  827. const minContentHeight =
  828. titleHeight + contentPadding + metaHeight + 12 + 4;
  829. if (height < minContentHeight) {
  830. height = minContentHeight;
  831. }
  832. }
  833. return Math.round(height);
  834. },
  835. observerPatient(model: { patientId: string; sex: "0" | "1" }) {
  836. wx.setStorageSync("patientId", model.patientId);
  837. this._getHealthReport();
  838. this._getAbnormalHealthIndex();
  839. const patientIcon = { 0: "gender-male", 1: "gender-female" }[model.sex];
  840. const patientIconColor = { 0: "#0f40f5", 1: "#E560B3" }[model.sex];
  841. this.setData({ patientIcon, patientIconColor });
  842. getPatientDescription(model).then((patientDescription) => {
  843. this.setData({ patientDescription });
  844. });
  845. // 获取未处理随访列表
  846. this.getNotDealList();
  847. // 获取调养计划
  848. this.getCareLists();
  849. },
  850. // 没有健康分析去做健康分析
  851. goHealthAnalyze() {
  852. wx.redirectTo({
  853. url: `/module/chats/pages/index/index?component=guide&isShowGuide=true`,
  854. });
  855. wx.setStorageSync("showGuideActive", 1);
  856. wx.setStorageSync("isAnalysis", 3);
  857. },
  858. // 检查咨询状态
  859. async checkConsultationStatus() {
  860. //获取正在咨询中的咨询id
  861. const res = await Post("/consultManage/getConsultIng");
  862. const isConsulting = !!res.data?.id;
  863. const hasNewMessage = res.data?.patientUnreadCount > 0;
  864. // 是否有新消息
  865. this.setData({ hasNewMessage });
  866. if (isConsulting) {
  867. // 保存咨询id,标记咨询未结束
  868. wx.setStorageSync("consultId", res.data);
  869. wx.setStorageSync("consultEnded", false);
  870. this.setData({
  871. isConsulting: true,
  872. });
  873. } else {
  874. // 没有咨询,清理相关数据
  875. wx.setStorageSync("consultEnded", true);
  876. wx.removeStorageSync("consultId");
  877. this.setData({
  878. isConsulting: false,
  879. hasNewMessage: false,
  880. });
  881. }
  882. },
  883. // 跳转到咨询页面
  884. goToConsultation() {
  885. // 跳转之后 未读的消息变为已读 就没有最新消息了 不显示绿点
  886. this.setData({ hasNewMessage: false });
  887. // 跳转到咨询页面,显示 message-consult 组件
  888. wx.navigateTo({
  889. url: `/module/chats/pages/index/index?component=questionnaire&messageType=3`,
  890. });
  891. wx.setStorageSync("isAnalysis", 5);
  892. },
  893. async isGoPunchcard(e: any) {
  894. const { id, signintime } = e.currentTarget.dataset;
  895. // 已经打卡了
  896. if (signintime) {
  897. // 已打卡 跳转到打卡页面
  898. wx.navigateTo({
  899. url: `/module/article/pages/punch-card/punch-card?id=${id}`,
  900. });
  901. } else {
  902. // 打卡
  903. const cardId = e.currentTarget.dataset.id;
  904. await addPatientOnlineRecordClockIn(cardId);
  905. wx.showToast({
  906. title: "打卡成功",
  907. icon: "success",
  908. duration: 1500,
  909. });
  910. await this.refreshCareListsWithState();
  911. }
  912. },
  913. async refreshCareListsWithState() {
  914. // 保存当前的展开状态
  915. const currentExpandedStates = this.data.displayList.map((item: any) => ({
  916. id: item.id,
  917. expanded: item.expanded,
  918. carouselMediaList: item.carouselMediaList,
  919. }));
  920. // 获取新数据
  921. const res = await getCareList();
  922. if (res && res.length > 0) {
  923. res.forEach((item: any) => {
  924. const oldItem = currentExpandedStates.find(
  925. (state) => state.id === item.id
  926. );
  927. if (oldItem && oldItem.carouselMediaList) {
  928. item.carouselMediaList = oldItem.carouselMediaList;
  929. } else {
  930. item.carouselMediaList = [];
  931. // 添加photo
  932. if (item.photo) {
  933. item.carouselMediaList.push({
  934. type: "image",
  935. src: item.photo,
  936. });
  937. }
  938. // 添加itemImgFirst
  939. if (item?.itemImgFirst) {
  940. item.carouselMediaList.push({
  941. type: "image",
  942. src: item.itemImgFirst,
  943. });
  944. }
  945. // 添加itemVideoFirst
  946. if (item?.itemVideoFirst) {
  947. item.carouselMediaList.push({
  948. type: "video",
  949. src: item.itemVideoFirst,
  950. });
  951. }
  952. }
  953. });
  954. // 更新 careList
  955. this.setData({
  956. careList: res,
  957. });
  958. // 更新 displayList 并恢复展开状态
  959. const { allExpanded } = this.data;
  960. let newDisplayList: any[] =
  961. allExpanded || res.length <= 4 ? res : res.slice(0, 4);
  962. // 恢复展开状态
  963. newDisplayList = newDisplayList.map((item: any) => {
  964. const savedState = currentExpandedStates.find(
  965. (state) => state.id === item.id
  966. );
  967. if (savedState) {
  968. return {
  969. ...item,
  970. expanded: savedState.expanded,
  971. carouselMediaList:
  972. savedState.carouselMediaList || item.carouselMediaList,
  973. };
  974. }
  975. return item;
  976. });
  977. this.setData({
  978. displayList: newDisplayList,
  979. });
  980. }
  981. },
  982. /**
  983. * 轮播组件进入/退出全屏时,隐藏/显示底部 tabbar,防止遮挡视频进度条
  984. */
  985. onCarouselFullscreenChange(e: { detail?: { fullScreen?: boolean } }) {
  986. const fullScreen = !!e.detail?.fullScreen;
  987. this.setData({
  988. tabbarHidden: fullScreen,
  989. });
  990. },
  991. });