Эх сурвалжийг харах

修改 App 标题显示方式

cc12458 7 сар өмнө
parent
commit
a1c9d67842

+ 7 - 15
src/App.vue

@@ -3,20 +3,12 @@ const title = import.meta.env.SIX_APP_TITLE;
 const theme = ref<'light' | 'dark'>('dark');
 </script>
 <template>
-  <van-config-provider class="page-container" :theme>
-    <router-view class="page-header" name="header"></router-view>
-    <router-view class="page-content"></router-view>
-    <router-view class="page-footer" name="footer"></router-view>
+  <van-config-provider :theme>
+    <router-view class="page-container" v-slot="{ Component }">
+      <keep-alive>
+        <component :is="Component" />
+      </keep-alive>
+    </router-view>
   </van-config-provider>
 </template>
-<style scoped lang="scss">
-.page {
-  &-header, &-footer {
-    flex: none;
-  }
-
-  &-content {
-    flex: auto;
-  }
-}
-</style>
+<style scoped lang="scss"></style>

+ 0 - 33
src/hooks/useTitle.ts

@@ -1,33 +0,0 @@
-import { useRouteMeta }                        from '@/router/hooks/useRouteMeta';
-import { defaultDocument, tryOnBeforeUnmount } from '@vueuse/core';
-import type { Ref }                            from 'vue';
-
-
-let title: Ref<string>;
-
-
-export function useTitle() {
-  const defaultValue = import.meta.env.SIX_APP_TITLE;
-
-  title ??= useRouteMeta('title', defaultValue);
-
-  function format(t: string) {
-    const template = t === defaultValue ? '%s' : `%s | ${ import.meta.env.SIX_APP_TITLE }`;
-    return toValue(template).replace(/%s/g, t);
-  }
-
-
-  const handle = watch(
-    title,
-    (t, o) => {
-      if ( t !== o && defaultDocument ) {
-        defaultDocument.title = format(typeof t === 'string' ? t : '');
-      }
-    },
-    { immediate: true },
-  );
-
-  tryOnBeforeUnmount(handle);
-
-  return title;
-}

+ 37 - 29
src/modules/camera/camera.page.vue

@@ -1,5 +1,4 @@
 <script setup lang="ts">
-import { useTitle }                         from '@/hooks/useTitle';
 import { Dialog, Toast }                    from '@/platform';
 import { saveFileMethod, uploadFileMethod } from '@/request/api/camera.api';
 import { useVisitor }                       from '@/stores';
@@ -12,7 +11,6 @@ import Camera                               from './camera.vue';
 let audio: HTMLAudioElement | void;
 
 const router = useRouter();
-const title = useTitle();
 const visitor = useVisitor();
 
 const { form: dataset, loading: submitting, send: submit } = useForm(data => saveFileMethod(data), {
@@ -46,7 +44,6 @@ watch([ step, snapshot ], ([ step, snapshot ], old, onCleanup) => {
            .then(() => audio!.play());
     }
   }
-  title.value = config.value.title;
 });
 
 const cameraRef = useTemplateRef<InstanceType<typeof Camera>>('camera');
@@ -100,34 +97,45 @@ tryOnUnmounted(() => {
 });
 </script>
 <template>
-  <div class="flex flex-col">
-    <header class="flex flex-col justify-center px-24">
-      <div class="text-3xl text-center">{{ config?.label }}</div>
-      <div class="mt-8 text-lg text-center tracking-wider leading-10">{{ config?.description }}</div>
-    </header>
-    <main class="flex justify-center items-center">
-      <Camera ref="camera" v-bind="config?.video" @loaded="step = 1;">
-        <template #shade="{scale}">
-          <component :is="config?.shade" :scale="scale"></component>
-        </template>
-      </Camera>
-      <div v-if="config?.example" class="size-40 absolute -top-8 right-2 cursor-pointer hover:text-primary">
-        <img class="size-full object-scale-down" :src="config?.example" alt="示例" />
-      </div>
-    </main>
-    <footer class="flex flex-col justify-center items-center">
-      <div v-if="snapshot" class="flex justify-evenly w-full cursor-pointer">
-        <div class="">
-          <img class="h-20" src="@/assets/images/button-cancel.png" alt="重拍" @click="handle()" /></div>
-        <div class="cursor-pointer">
-          <img class="h-20" src="@/assets/images/button-confirm.png" alt="确认" @click="next()" />
+  <div>
+    <div class="page-header flex py-4 px-4">
+      <div class="grow shrink-0 h-full min-w-16"></div>
+      <div class="grow-[3] shrink mx-2 flex flex-col justify-center overflow-hidden">
+        <div class="font-bold text-3xl text-nowrap text-center tracking-wide overflow-ellipsis overflow-hidden">
+          {{ config?.title }}
         </div>
       </div>
-      <div v-else-if="step" class="h-min text-center cursor-pointer hover:text-primary" @click="handle()">
-        <button class="size-28 border-8 rounded-full hover:border-primary"></button>
-        <div class="mt-8 text-3xl">点击拍照</div>
-      </div>
-    </footer>
+      <div class="grow shrink-0 h-full min-w-16"></div>
+    </div>
+    <div class="page-content flex flex-col">
+      <header class="flex flex-col justify-center px-24">
+        <div class="text-3xl text-center">{{ config?.label }}</div>
+        <div class="mt-8 text-lg text-center tracking-wider leading-10">{{ config?.description }}</div>
+      </header>
+      <main class="flex justify-center items-center">
+        <Camera ref="camera" v-bind="config?.video" @loaded="step = 1;">
+          <template #shade="{scale}">
+            <component :is="config?.shade" :scale="scale"></component>
+          </template>
+        </Camera>
+        <div v-if="config?.example" class="size-40 absolute -top-8 right-2 cursor-pointer hover:text-primary">
+          <img class="size-full object-scale-down" :src="config?.example" alt="示例" />
+        </div>
+      </main>
+      <footer class="flex flex-col justify-center items-center">
+        <div v-if="snapshot" class="flex justify-evenly w-full cursor-pointer">
+          <div class="">
+            <img class="h-20" src="@/assets/images/button-cancel.png" alt="重拍" @click="handle()" /></div>
+          <div class="cursor-pointer">
+            <img class="h-20" src="@/assets/images/button-confirm.png" alt="确认" @click="next()" />
+          </div>
+        </div>
+        <div v-else-if="step" class="h-min text-center cursor-pointer hover:text-primary" @click="handle()">
+          <button class="size-28 border-8 rounded-full hover:border-primary"></button>
+          <div class="mt-8 text-3xl">点击拍照</div>
+        </div>
+      </footer>
+    </div>
   </div>
 </template>
 <style scoped lang="scss">

+ 27 - 16
src/modules/questionnaire/page.vue

@@ -62,23 +62,34 @@ load();
 </script>
 <template>
   <div>
-    <template v-if="data.length">
-      <div v-if="showTitle" class="my-8 text-2xl text-primary text-center">
-        <div>为了更全面地评估您的健康状况</div>
-        <div>还需要您回答6-9个问题,耗时2-3分钟</div>
+    <div class="page-header flex py-4 px-4">
+      <div class="grow shrink-0 h-full min-w-16"></div>
+      <div class="grow-[3] shrink mx-2 flex flex-col justify-center overflow-hidden">
+        <div class="font-bold text-3xl text-nowrap text-center tracking-wide overflow-ellipsis overflow-hidden">
+          问卷
+        </div>
       </div>
-      <div class="m-6" v-for="item in data" :key="item.id">
-        <div class="text-2xl" :class="{ required: item.required }">{{ item.label }}</div>
-        <TierSelectField
-          v-if="item.name === 'select'"
-          v-model:options="item.options"
-          :multiple="item.multiple"
-          :disabled="loading"
-        />
-      </div>
-      <van-button class="decorate" block :loading @click="handle()">提交</van-button>
-    </template>
-    <van-toast v-else-if="first" :show="loading" type="loading" message="加载中" />
+      <div class="grow shrink-0 h-full min-w-16"></div>
+    </div>
+    <div class="page-content">
+      <template v-if="data.length">
+        <div v-if="showTitle" class="my-8 text-2xl text-primary text-center">
+          <div>为了更全面地评估您的健康状况</div>
+          <div>还需要您回答6-9个问题,耗时2-3分钟</div>
+        </div>
+        <div class="m-6" v-for="item in data" :key="item.id">
+          <div class="text-2xl" :class="{ required: item.required }">{{ item.label }}</div>
+          <TierSelectField
+            v-if="item.name === 'select'"
+            v-model:options="item.options"
+            :multiple="item.multiple"
+            :disabled="loading"
+          />
+        </div>
+        <van-button class="decorate" block :loading @click="handle()">提交</van-button>
+      </template>
+      <van-toast v-else-if="first" :show="loading" type="loading" message="加载中" />
+    </div>
   </div>
 </template>
 <style scoped lang="scss">

+ 126 - 115
src/modules/report/report.page.vue

@@ -29,138 +29,149 @@ const { loading: uploading, send: upload } = useRequest(() => updateReportMethod
 });
 </script>
 <template>
-  <div class="flex flex-col overflow-hidden">
-    <van-skeleton class="flex-auto" title :row="3" :loading>
-      <div class="flex-auto x-6 overflow-y-auto">
-        <div class="my-6 text-primary text-2xl text-center">报告日期:{{ data.date }}</div>
-        <div class="card my-6 text-lg">
-          <div class="card__title text-primary text-3xl font-bold"></div>
-          <div class="card__content flex">
-            <div class="flex-auto">
-              <div class="flex items-center my-2">
-                <span class="text-primary">结果显示您是:</span>
-                <van-button class="decorate !text-primary-400">{{ data[ '结果' ] }}</van-button>
+  <div>
+    <div class="page-header flex py-4 px-4">
+      <div class="grow shrink-0 h-full min-w-16"></div>
+      <div class="grow-[3] shrink mx-2 flex flex-col justify-center overflow-hidden">
+        <div class="font-bold text-3xl text-nowrap text-center tracking-wide overflow-ellipsis overflow-hidden">
+          健康分析报告
+        </div>
+      </div>
+      <div class="grow shrink-0 h-full min-w-16"></div>
+    </div>
+    <div class="page-content flex flex-col overflow-hidden">
+      <van-skeleton class="flex-auto" title :row="3" :loading>
+        <div class="flex-auto overflow-y-auto">
+          <div class="my-6 text-primary text-2xl text-center">报告日期:{{ data.date }}</div>
+          <div class="card m-6 text-lg">
+            <div class="card__title text-primary text-3xl font-bold"></div>
+            <div class="card__content flex">
+              <div class="flex-auto">
+                <div class="flex items-center my-2">
+                  <span class="text-primary">结果显示您是:</span>
+                  <van-button class="decorate !text-primary-400">{{ data[ '结果' ] }}</van-button>
+                </div>
+                <div class="flex items-center my-2" v-if="data[ '程度' ]">
+                  <span class="text-grey">程度:</span>
+                  <span class="px-4 py-2 rounded-lg border border-primary-400 text-primary">{{ data[ '程度' ] }}</span>
+                </div>
+                <div class="my-2 text-grey" v-if="data[ '表现' ]">表现:{{ data[ '表现' ] }}</div>
+                <div class="my-2 text-grey" v-if="data[ '体质' ]">体质:{{ data[ '体质' ] }}</div>
               </div>
-              <div class="flex items-center my-2" v-if="data[ '程度' ]">
-                <span class="text-grey">程度:</span>
-                <span class="px-4 py-2 rounded-lg border border-primary-400 text-primary">{{ data[ '程度' ] }}</span>
+              <div class="flex-none size-48 ml-4">
+                <img class="size-full object-cover" src="@/assets/images/report-cover.png" alt="封面">
               </div>
-              <div class="my-2 text-grey" v-if="data[ '表现' ]">表现:{{ data[ '表现' ] }}</div>
-              <div class="my-2 text-grey" v-if="data[ '体质' ]">体质:{{ data[ '体质' ] }}</div>
-            </div>
-            <div class="flex-none size-48 ml-4">
-              <img class="size-full object-cover" src="@/assets/images/report-cover.png" alt="封面">
             </div>
           </div>
-        </div>
-        <div class="card my-6 text-lg">
-          <div class="card__title mb-3 text-primary text-2xl font-bold">体质分析</div>
-          <div class="card__content">
-            <PhysiqueChart
-              :dataset="data['体质图表']"
-              v-model:snapshot="data.constitutionGroupImg" @update:snapshot="upload()"
-            />
-            <div class="my-2 text-primary" v-if="data[ '体质描述' ]">{{ data[ '体质描述' ] }}</div>
-            <table class="mt-8 mb-2 w-full table-auto border border-collapse  border-primary">
-              <thead>
-              <tr>
-                <th class="border border-primary min-w-[140px]"
-                    v-for="(value, i) in data.descriptionsTable.column" :key="i"
-                    v-html="value"
-                ></th>
-              </tr>
-              </thead>
-              <tbody>
-              <tr v-for="item in data.descriptionsTable?.data" :key="item[0]">
-                <td class="py-4 px-2 border border-primary min-w-[140px]"
-                    :class="{'text-grey': i, 'text-primary': !i}"
-                    v-for="(value, i) in item" :key="i"
-                    v-html="value"
-                ></td>
-              </tr>
-              </tbody>
-            </table>
-          </div>
-        </div>
-        <div class="card my-6 text-lg">
-          <div class="card__title mb-3 text-primary text-2xl font-bold">舌象分析</div>
-          <div class="card__content">
-            <table class="mt-8 mb-2 w-full table-auto border border-collapse  border-primary">
-              <thead>
-              <tr>
-                <th class="py-4 px-2 text-primary border border-primary"
-                    v-for="(value, i) in data.tongueTable.column" :key="i"
-                    v-html="value"
-                >
-                </th>
-              </tr>
-              </thead>
-              <tbody>
-              <tr v-for="item in data.tongueTable?.data" :key="item[0]">
-                <td class="py-4 px-2 border border-primary text-center text-grey"
-                    v-for="(value, i) in item" :key="i"
-                    v-html="value"
-                ></td>
-              </tr>
-              </tbody>
-            </table>
+          <div class="card m-6 text-lg">
+            <div class="card__title mb-3 text-primary text-2xl font-bold">体质分析</div>
+            <div class="card__content">
+              <PhysiqueChart
+                :dataset="data['体质图表']"
+                v-model:snapshot="data.constitutionGroupImg" @update:snapshot="upload()"
+              />
+              <div class="my-2 text-primary" v-if="data[ '体质描述' ]">{{ data[ '体质描述' ] }}</div>
+              <table class="mt-8 mb-2 w-full table-auto border border-collapse  border-primary">
+                <thead>
+                <tr>
+                  <th class="border border-primary min-w-[140px]"
+                      v-for="(value, i) in data.descriptionsTable.column" :key="i"
+                      v-html="value"
+                  ></th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr v-for="item in data.descriptionsTable?.data" :key="item[0]">
+                  <td class="py-4 px-2 border border-primary min-w-[140px]"
+                      :class="{'text-grey': i, 'text-primary': !i}"
+                      v-for="(value, i) in item" :key="i"
+                      v-html="value"
+                  ></td>
+                </tr>
+                </tbody>
+              </table>
+            </div>
           </div>
-        </div>
-        <div class="grid grid-rows-1 grid-cols-2 gap-8 my-6">
-          <div class="card text-lg" v-for="item in data.tongueException">
-            <div class="card__title mb-3 text-primary text-2xl font-bold">{{ item.title }}</div>
+          <div class="card m-6 text-lg">
+            <div class="card__title mb-3 text-primary text-2xl font-bold">舌象分析</div>
             <div class="card__content">
-              <div class="flex my-6 justify-center">
-                <img class="flex-none w-2/4 object-scale-down" :src="item.cover" alt="舌象">
-                <div class="flex-none ml-8">
-                  <div class="my-2 px-4 py-2 rounded-lg border border-primary-400 text-primary"
-                       v-for="value in item.tags" :key="value"
-                  >{{ value }}
+              <table class="mt-8 mb-2 w-full table-auto border border-collapse  border-primary">
+                <thead>
+                <tr>
+                  <th class="py-4 px-2 text-primary border border-primary"
+                      v-for="(value, i) in data.tongueTable.column" :key="i"
+                      v-html="value"
+                  >
+                  </th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr v-for="item in data.tongueTable?.data" :key="item[0]">
+                  <td class="py-4 px-2 border border-primary text-center text-grey"
+                      v-for="(value, i) in item" :key="i"
+                      v-html="value"
+                  ></td>
+                </tr>
+                </tbody>
+              </table>
+            </div>
+          </div>
+          <div class="grid grid-rows-1 grid-cols-2 gap-8 m-6">
+            <div class="card text-lg" v-for="item in data.tongueException">
+              <div class="card__title mb-3 text-primary text-2xl font-bold">{{ item.title }}</div>
+              <div class="card__content">
+                <div class="flex my-6 justify-center">
+                  <img class="flex-none w-2/4 object-scale-down" :src="item.cover" alt="舌象">
+                  <div class="flex-none ml-8">
+                    <div class="my-2 px-4 py-2 rounded-lg border border-primary-400 text-primary"
+                         v-for="value in item.tags" :key="value"
+                    >{{ value }}
+                    </div>
                   </div>
                 </div>
+                <div class="my-2 text-grey" v-for="value in item.descriptions" :key="value">{{ value }}</div>
               </div>
-              <div class="my-2 text-grey" v-for="value in item.descriptions" :key="value">{{ value }}</div>
             </div>
           </div>
-        </div>
-        <div class="card my-6 text-lg" v-if="data.faceAnalysis?.['结果']">
-          <div class="card__title mb-3 text-primary text-2xl font-bold">面象分析</div>
-          <div class="card__content flex">
-            <div class="flex-auto text-grey mt-6">{{ data.faceAnalysis?.[ '结果' ] }}</div>
-            <div class="flex-none w-2/4 max-h-96 ml-4">
-              <img class="size-full object-scale-down" :src="data.faceAnalysis?.['面象']" alt="面象">
+          <div class="card m-6 text-lg" v-if="data.faceAnalysis?.['结果']">
+            <div class="card__title mb-3 text-primary text-2xl font-bold">面象分析</div>
+            <div class="card__content flex">
+              <div class="flex-auto text-grey mt-6">{{ data.faceAnalysis?.[ '结果' ] }}</div>
+              <div class="flex-none w-2/4 max-h-96 ml-4">
+                <img class="size-full object-scale-down" :src="data.faceAnalysis?.['面象']" alt="面象">
+              </div>
             </div>
           </div>
-        </div>
-        <div class="card my-6 text-lg" v-if="data['中医证素']?.length">
-          <div class="card__title mb-3 text-primary text-2xl font-bold">中医证素</div>
-          <div class="card__content">
-            <SyndromeChart
-              :dataset="data['中医证素']"
-              v-model:snapshot="data.factorItemRadarImg" @update:snapshot="upload()"
-            />
-            <table class="mt-8 mb-2 w-full table-auto border border-collapse  border-primary">
-              <tbody>
-              <tr v-for="item in data['中医证素']" :key="item.label">
-                <td class="py-4 px-2 border border-primary text-primary text-center" v-html="item.label"></td>
-                <td class="py-4 px-2 border border-primary text-grey" v-html="item.value"></td>
-              </tr>
-              </tbody>
-            </table>
+          <div class="card m-6 text-lg" v-if="data['中医证素']?.length">
+            <div class="card__title mb-3 text-primary text-2xl font-bold">中医证素</div>
+            <div class="card__content">
+              <SyndromeChart
+                :dataset="data['中医证素']"
+                v-model:snapshot="data.factorItemRadarImg" @update:snapshot="upload()"
+              />
+              <table class="mt-8 mb-2 w-full table-auto border border-collapse  border-primary">
+                <tbody>
+                <tr v-for="item in data['中医证素']" :key="item.label">
+                  <td class="py-4 px-2 border border-primary text-primary text-center" v-html="item.label"></td>
+                  <td class="py-4 px-2 border border-primary text-grey" v-html="item.value"></td>
+                </tr>
+                </tbody>
+              </table>
+            </div>
           </div>
-        </div>
-        <div class="card my-6 text-lg" v-if="data['中医证型']?.length">
-          <div class="card__title mb-3 text-primary text-2xl font-bold">中医证型</div>
-          <div class="card__content">
-            <div class="my-6 text-grey" v-for="item in data['中医证型']" :key="item.label">
-              <div class="my-2 text-primary" v-html="item.label"></div>
-              <div style="text-indent: 2em;" v-html="item.value"></div>
+          <div class="card m-6 text-lg" v-if="data['中医证型']?.length">
+            <div class="card__title mb-3 text-primary text-2xl font-bold">中医证型</div>
+            <div class="card__content">
+              <div class="my-6 text-grey" v-for="item in data['中医证型']" :key="item.label">
+                <div class="my-2 text-primary" v-html="item.label"></div>
+                <div style="text-indent: 2em;" v-html="item.value"></div>
+              </div>
             </div>
           </div>
         </div>
-      </div>
-    </van-skeleton>
-    <NavBar class="flex-none"></NavBar>
+      </van-skeleton>
+      <NavBar class="flex-none"></NavBar>
+    </div>
   </div>
 </template>
 <style scoped lang="scss">

+ 28 - 17
src/modules/report/scheme.page.vue

@@ -15,27 +15,38 @@ const { data, loading } = useWatcher(() => getReportSchemeMethod(id.value), [ id
 });
 </script>
 <template>
-  <div class="flex flex-col overflow-hidden">
-    <!--{{ data }}-->
-    <van-skeleton class="flex-auto" title :row="3" :loading>
-      <div class="flex-auto px-6 overflow-y-auto">
-        <div class="card my-6 text-lg" v-for="item in data.children" :key="item.id">
-          <div class="card__title mb-3 text-primary text-2xl font-bold">{{ item.title }}</div>
-          <div class="card__content">
-            <div class="my-4" v-for="card in item.children" :key="card.id">
-              <div class="text-xl text-center text-primary">{{ card.title }}</div>
-              <SchemeMedia :media="card.media"></SchemeMedia>
-              <div v-if="card.description">{{ card.description }}</div>
-              <div v-for="(item,index) in card.descriptions ">
-                <span class="text-primary">【{{ item.title }}】</span>
-                <span v-html="item.description"></span>
+  <div>
+    <div class="page-header flex py-4 px-4">
+      <div class="grow shrink-0 h-full min-w-16"></div>
+      <div class="grow-[3] shrink mx-2 flex flex-col justify-center overflow-hidden">
+        <div class="font-bold text-3xl text-nowrap text-center tracking-wide overflow-ellipsis overflow-hidden">
+          调理方案
+        </div>
+      </div>
+      <div class="grow shrink-0 h-full min-w-16"></div>
+    </div>
+    <div class="page-content flex flex-col overflow-hidden">
+      <!--{{ data }}-->
+      <van-skeleton class="flex-auto" title :row="3" :loading>
+        <div class="flex-auto px-6 overflow-y-auto">
+          <div class="card my-6 text-lg" v-for="item in data.children" :key="item.id">
+            <div class="card__title mb-3 text-primary text-2xl font-bold">{{ item.title }}</div>
+            <div class="card__content">
+              <div class="my-4" v-for="card in item.children" :key="card.id">
+                <div class="text-xl text-center text-primary">{{ card.title }}</div>
+                <SchemeMedia :media="card.media"></SchemeMedia>
+                <div v-if="card.description">{{ card.description }}</div>
+                <div v-for="(item,index) in card.descriptions ">
+                  <span class="text-primary">【{{ item.title }}】</span>
+                  <span v-html="item.description"></span>
+                </div>
               </div>
             </div>
           </div>
         </div>
-      </div>
-    </van-skeleton>
-    <NavBar class="flex-none"></NavBar>
+      </van-skeleton>
+      <NavBar class="flex-none"></NavBar>
+    </div>
   </div>
 </template>
 <style scoped lang="scss">

+ 64 - 53
src/pages/register.page.vue

@@ -206,60 +206,71 @@ const { send: handle } = useRequest(
   });
 </script>
 <template>
-  <div class="p-6">
-    <van-form class="register-form" ref="register-form" colon required="auto"
-              scroll-to-error scroll-to-error-position="center"
-              @submit="onSubmitHandle()"
-    >
-      <van-cell-group :border="false">
-        <template v-for="field in fields" :key="field.name">
-          <van-field v-model="modelRef[field.name]" :name="field.name" :id="field.name"
-                     :rules="field.rules" v-bind="field.control"
-                     :class="{'no-border': field.control?.border === false}"
-                     :focused="field.keyboard?.show" @focus="field.keyboard && (field.keyboard.show = true)"
-                     @blur="field.keyboard && (field.keyboard.show = false)"
-                     :readonly="field.control.readonly" @click="field.keyboard && (field.keyboard.show = true)"
+  <div>
+    <div class="page-header flex py-4 px-4">
+      <div class="grow shrink-0 h-full min-w-16"></div>
+      <div class="grow-[3] shrink mx-2 flex flex-col justify-center overflow-hidden">
+        <div class="font-bold text-3xl text-nowrap text-center tracking-wide overflow-ellipsis overflow-hidden">
+          建档
+        </div>
+      </div>
+      <div class="grow shrink-0 h-full min-w-16"></div>
+    </div>
+    <div class="page-content p-6">
+      <van-form class="register-form" ref="register-form" colon required="auto"
+                scroll-to-error scroll-to-error-position="center"
+                @submit="onSubmitHandle()"
+      >
+        <van-cell-group :border="false">
+          <template v-for="field in fields" :key="field.name">
+            <van-field v-model="modelRef[field.name]" :name="field.name" :id="field.name"
+                       :rules="field.rules" v-bind="field.control"
+                       :class="{'no-border': field.control?.border === false}"
+                       :focused="field.keyboard?.show" @focus="field.keyboard && (field.keyboard.show = true)"
+                       @blur="field.keyboard && (field.keyboard.show = false)"
+                       :readonly="field.control.readonly" @click="field.keyboard && (field.keyboard.show = true)"
+            >
+              <template #input v-if="field.component?.name === 'radio'">
+                <van-radio-group v-model="modelRef[field.name]" direction="horizontal" shape="dot">
+                  <van-radio v-for="option in field.component?.options" :key="option.value" :name="option.value">
+                    {{ option.label }}
+                  </van-radio>
+                </van-radio-group>
+              </template>
+              <template #input v-else-if="field.component?.name === 'code'">
+                <van-password-input
+                  style="width: 100%;"
+                  v-model:value="modelRef[field.name]" v-bind="(field.component as any)!.props"
+                  :focused="field.keyboard?.show" @focus="field.keyboard && (field.keyboard.show = true)"
+                />
+              </template>
+              <template #button>
+                <div class="text-primary cursor-pointer">
+                  <template v-if="field.component?.name === 'code'">
+                    <div class="text-primary cursor-pointer" @click="getCaptchaHandle()">
+                      {{ captchaLoading ? '发送中...' : countdown > 0 ? `${ countdown }后可重发` : '获取验证码' }}
+                    </div>
+                  </template>
+                  <template v-else>{{ field.suffix }}</template>
+                </div>
+              </template>
+            </van-field>
+            <van-number-keyboard
+              v-if="field.keyboard"
+              v-model="modelRef[field.name]"
+              v-bind="field.keyboard" :maxlength="field.control.maxlength"
+              @blur="field.keyboard.show = false; onKeyboardBlur(field)"
+            />
+          </template>
+        </van-cell-group>
+      </van-form>
+      <div class="m-4">
+        <div class="m-auto size-16 cursor-pointer">
+          <van-loading v-if="submitting" type="spinner" size="64" color="#38ff6e" />
+          <img v-else class="size-full"
+               src="@/assets/images/next-step.svg" alt="提交" @click="formRef?.submit()"
           >
-            <template #input v-if="field.component?.name === 'radio'">
-              <van-radio-group v-model="modelRef[field.name]" direction="horizontal" shape="dot">
-                <van-radio v-for="option in field.component?.options" :key="option.value" :name="option.value">
-                  {{ option.label }}
-                </van-radio>
-              </van-radio-group>
-            </template>
-            <template #input v-else-if="field.component?.name === 'code'">
-              <van-password-input
-                style="width: 100%;"
-                v-model:value="modelRef[field.name]" v-bind="(field.component as any)!.props"
-                :focused="field.keyboard?.show" @focus="field.keyboard && (field.keyboard.show = true)"
-              />
-            </template>
-            <template #button>
-              <div class="text-primary cursor-pointer">
-                <template v-if="field.component?.name === 'code'">
-                  <div class="text-primary cursor-pointer" @click="getCaptchaHandle()">
-                    {{ captchaLoading ? '发送中...' : countdown > 0 ? `${ countdown }后可重发` : '获取验证码' }}
-                  </div>
-                </template>
-                <template v-else>{{ field.suffix }}</template>
-              </div>
-            </template>
-          </van-field>
-          <van-number-keyboard
-            v-if="field.keyboard"
-            v-model="modelRef[field.name]"
-            v-bind="field.keyboard" :maxlength="field.control.maxlength"
-            @blur="field.keyboard.show = false; onKeyboardBlur(field)"
-          />
-        </template>
-      </van-cell-group>
-    </van-form>
-    <div class="m-4">
-      <div class="m-auto size-16 cursor-pointer">
-        <van-loading v-if="submitting" type="spinner" size="64" color="#38ff6e" />
-        <img v-else class="size-full"
-             src="@/assets/images/next-step.svg" alt="提交" @click="formRef?.submit()"
-        >
+        </div>
       </div>
     </div>
   </div>

+ 1 - 1
src/request/api/account.api.ts

@@ -7,7 +7,7 @@ export type FieldKey = 'cardno' | 'phone' | 'code' | 'name' | 'sex' | 'height' |
 
 
 export function getCaptchaMethod(mobile: string) {
-  return HTTP.Get(`/fdhb-tablet/sms/sendVerCode`, {
+  return HTTP.Get<string>(`/fdhb-tablet/sms/sendVerCode`, {
     params: { phone: mobile },
   });
 }

+ 7 - 17
src/router/index.ts

@@ -7,23 +7,13 @@ const router = createRouter({
     {
       path: '/screen', component: () => import('@/pages/screen.page.vue'),
     },
-    {
-      path: '/',
-      children: [
-        { path: 'register', component: () => import('@/pages/register.page.vue'), meta: { title: '建档' } },
-        { path: 'camera', component: () => import('@/modules/camera/camera.page.vue'), meta: { title: '拍摄' } },
-        { path: 'camera/result', component: () => import('@/modules/camera/camera-result.page.vue'), meta: { title: '拍摄完成' } },
-        { path: 'questionnaire', component: () => import('@/modules/questionnaire/page.vue'), meta: { title: '问卷' } },
-        { path: 'report/:id/scheme', component: () => import('@/modules/report/scheme.page.vue'), meta: { title: '调理方案' } },
-        { path: 'report/:id', component: () => import('@/modules/report/report.page.vue'), meta: { title: '健康分析报告' } },
-        { path: '', redirect: '/screen' },
-      ],
-      components: {
-        header: () => import('@/widgets/header.widget.vue'),
-        // footer: () => import('@/widgets/footer.widget.vue'),
-        default: () => import('@/views/page.view.vue'),
-      },
-    },
+    { path: '/register', component: () => import('@/pages/register.page.vue'), meta: { title: '建档' } },
+    { path: '/camera', component: () => import('@/modules/camera/camera.page.vue'), meta: { title: '拍摄' } },
+    { path: '/camera/result', component: () => import('@/modules/camera/camera-result.page.vue'), meta: { title: '拍摄完成' } },
+    { path: '/questionnaire', component: () => import('@/modules/questionnaire/page.vue'), meta: { title: '问卷' } },
+    { path: '/report/:id/scheme', component: () => import('@/modules/report/scheme.page.vue'), meta: { title: '调理方案' } },
+    { path: '/report/:id', component: () => import('@/modules/report/report.page.vue'), meta: { title: '健康分析报告' } },
+    { path: '/', redirect: '/screen' },
   ],
 });
 

+ 15 - 5
src/themes/index.scss

@@ -4,13 +4,23 @@
 
 @import "./vant";
 
-.page-container {
-  display: flex;
-  flex-direction: column;
-  height: 100vh;
+.page {
+  &-container {
+    display: flex;
+    flex-direction: column;
+    height: 100vh;
+  }
+
+  &-header, &-footer {
+    flex: none;
+  }
+
+  &-content {
+    flex: auto;
+  }
 }
 
 :root:root {
-  --primary-color: #34A76B;
+  --primary-color: #34a76b;
   --primary-color-hover: #38ff6e;
 }

+ 0 - 23
src/tools/camera.tool.ts

@@ -1,23 +0,0 @@
-interface Size {
-  width?: number;
-  height?: number;
-  aspectRatio?: number;
-}
-
-
-export async function getMediaStream(constraints?: MediaTrackConstraints & Size) {
-  const stream = await navigator.mediaDevices.getUserMedia({ video: constraints ?? true });
-  if ( constraints?.width != null && constraints?.height != null ) {
-    // 修正宽高
-    const track = stream.getVideoTracks()[ 0 ];
-    const { width: CW = 1, height: CH = 1, aspectRatio: CAR = CW / CH, ..._constraints } = constraints;
-    const { width: SW = 1, height: SH = 1, aspectRatio: SAR = SW / SH } = track.getSettings();
-    if ( SAR > CAR || (
-      CW === SH && CH === SW
-    ) ) {
-      await track.applyConstraints({ ..._constraints, height: CW, width: CH });
-    }
-  }
-  return stream;
-}
-

+ 0 - 11
src/views/page.view.vue

@@ -1,11 +0,0 @@
-<script setup lang="ts">
-</script>
-<template>
-  <router-view v-slot="{ Component }">
-    <keep-alive>
-      <component :is="Component" />
-    </keep-alive>
-  </router-view>
-</template>
-<style scoped lang="scss">
-</style>

+ 0 - 7
src/widgets/footer.widget.vue

@@ -1,7 +0,0 @@
-<script setup lang="ts">
-</script>
-<template>
-  <div></div>
-</template>
-<style scoped lang="scss">
-</style>

+ 0 - 17
src/widgets/header.widget.vue

@@ -1,17 +0,0 @@
-<script setup lang="ts">
-import { useTitle } from '@/hooks/useTitle';
-
-const title = useTitle();
-</script>
-<template>
-  <div class="flex py-4 px-4">
-    <div class="grow shrink-0 h-full min-w-16"></div>
-    <div class="grow-[3] shrink mx-2 flex flex-col justify-center overflow-hidden">
-      <div class="font-bold text-3xl text-nowrap text-center tracking-wide overflow-ellipsis overflow-hidden">
-        {{ title }}
-      </div>
-    </div>
-    <div class="grow shrink-0 h-full min-w-16"></div>
-  </div>
-</template>
-<style scoped lang="scss"></style>