alcohol.page.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <script setup lang="ts">
  2. import { Notify } from '@/platform';
  3. import { tryOnBeforeMount, tryOnUnmounted, useCountdown } from '@vueuse/core';
  4. import { getAlcoholReportMethod } from '@/request/api';
  5. import type { Flow, FlowRoute } from '@/request/model';
  6. import { getRoutePath, useRouteNext } from '@/computable/useRouteNext';
  7. import { useRouteMeta } from '@/router/hooks/useRouteMeta';
  8. import NavHomeSelect from '@/assets/images/nav-home.select.png?url';
  9. import alcohol_0 from '@/assets/images/alcohol-0.png?url';
  10. import alcohol_1 from '@/assets/images/alcohol-1.png?url';
  11. const router = useRouter();
  12. const actionText = computed(() => `获取健康调理方案`);
  13. /* 倒计时完成动作 */
  14. const done = shallowRef<Flow>();
  15. /* 下一动作可选 */
  16. const next = shallowRef<Flow>();
  17. const title = useRouteMeta('title');
  18. const { handle, flow, loading } = useRouteNext({
  19. onSuccess(flow) { return load(flow); },
  20. onError(error) { Notify.warning(error.message); },
  21. });
  22. const { remaining, start, stop } = useCountdown(5, {
  23. onComplete() { replace(done.value!); },
  24. immediate: false,
  25. });
  26. const countdown = computed(() => remaining.value.toString().padStart(2, '0'));
  27. tryOnBeforeMount(() => handle());
  28. tryOnUnmounted(() => stop());
  29. const report = ref<Awaited<ReturnType<typeof getAlcoholReportMethod>>>();
  30. const tips = '建议您每日饮酒';
  31. const description = computed(() => report.value?.alcohol?.description
  32. ?.replace?.(new RegExp(`^${tips}`), '')
  33. ?.replace?.(/(\S)\s*(或)/g, '$1\n$2')
  34. ?.replace?.(/(\{[^}]*})/g, "\n$1\n")
  35. ?.replace?.(/(\[[^\]]*])/g, "\n$1\n")
  36. ?.replace?.(/(\([^)]*\))/g, "\n$1\n")
  37. ?.replace?.(/(([^)]*))/g, "\n$1\n")
  38. ?.replace?.(/([((\[][^))\]]*\))/g, "\n$1\n")
  39. ?? ''
  40. );
  41. async function load(flow: FlowRoute) {
  42. stop();
  43. report.value = await getAlcoholReportMethod();
  44. done.value = flow.next.optional ? { title: '返回首页', route: '/screen' } : flow.next;
  45. next.value = flow.next.optional ? flow.next : void 0;
  46. start(report.value?.alcohol?.description ? 60 : 5);
  47. }
  48. const replace = (flow: Flow) => router.push({ path: getRoutePath(flow), replace: true });
  49. </script>
  50. <template>
  51. <div>
  52. <div class="page-header flex py-4 px-4">
  53. <div class="grow shrink-0 h-full min-w-16"></div>
  54. <div class="grow-[3] shrink mx-2 flex flex-col justify-center overflow-hidden">
  55. <div class="font-bold text-3xl text-nowrap text-center tracking-wide overflow-ellipsis overflow-hidden">
  56. {{ flow?.value.title ?? title }}
  57. </div>
  58. </div>
  59. <div class="grow shrink-0 h-full min-w-16 flex items-center justify-end overflow-hidden">
  60. <router-link :to="{ path: '/screen' }" replace>
  61. <img class="size-8 object-scale-down" :src="NavHomeSelect" alt="返回首页" />
  62. </router-link>
  63. </div>
  64. </div>
  65. <div class="page-content flex flex-col">
  66. <van-toast v-if="loading" show type="loading" message="加载中" />
  67. <template v-else>
  68. <header>
  69. <div class="my-6 text-primary text-2xl text-center" v-if="report?.date">报告日期:{{ report.date }}</div>
  70. </header>
  71. <main class="flex flex-col justify-evenly">
  72. <div class="report-wrapper" v-if="report">
  73. <div class="card m-6 text-lg" v-if="report.alcohol?.condition">
  74. <div v-if="title" class="card__title mb-3 text-primary text-2xl font-bold">您的情况为</div>
  75. <div class="card__content">
  76. <div class="text-center text-4xl font-bold pre" style="letter-spacing: 4px">
  77. {{ report.alcohol?.condition }}
  78. </div>
  79. </div>
  80. </div>
  81. <div class="card m-6 text-lg">
  82. <div v-if="title" class="card__title mb-3 text-primary text-2xl">{{ tips }}</div>
  83. <div class="card__content">
  84. <div class="flex items-center justify-center min-h-32" v-if="report.alcohol?.description">
  85. <div class="text-center text-5xl font-semibold whitespace-pre" style="letter-spacing: 4px; line-height: 1.25em">
  86. {{ description }}
  87. </div>
  88. <img v-if="report.alcohol?.volume?.length" class="image-container object-scale-down" :src="alcohol_1" alt="可饮酒" />
  89. </div>
  90. <van-empty v-else :image="alcohol_0" image-size="160" description="暂无建议" />
  91. </div>
  92. </div>
  93. </div>
  94. </main>
  95. <footer class="flex flex-col justify-center items-center gap-4">
  96. <van-button v-if="next" class="decorate !text-xl" @click="replace(next)">
  97. {{ next.title ?? actionText }}
  98. </van-button>
  99. <van-button v-if="done" class="decorate !text-xl !text-primary-400" @click="replace(done)">
  100. {{ done.title ?? actionText }}
  101. <template v-if="remaining">({{ countdown }}s)</template>
  102. </van-button>
  103. </footer>
  104. </template>
  105. </div>
  106. </div>
  107. </template>
  108. <style scoped lang="scss">
  109. header {
  110. flex: 1 1 10%;
  111. }
  112. footer {
  113. flex: 1 1 30%;
  114. }
  115. main {
  116. position: relative;
  117. flex: 1 1 50%;
  118. }
  119. .image-container {
  120. width: 30vw;
  121. height: 30vw;
  122. max-width: 216px;
  123. max-height: 216px;
  124. }
  125. .card__content {
  126. --van-empty-description-color: #fff;
  127. --van-empty-description-margin-top: 36px;
  128. --van-empty-description-font-size: 18px;
  129. }
  130. </style>
  131. <style scoped lang="scss">
  132. .report-wrapper .card {
  133. padding: 24px;
  134. border-radius: 24px;
  135. box-shadow: inset 0 0 80px 0 #34a76b60;
  136. }
  137. </style>