home.ts 29 KB

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