home.ts 30 KB

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