3 Commits 08d03cfbe0 ... 6074180a1a

Autor SHA1 Mensagem Data
  IlhamTahir 6074180a1a feat: 调整个人信息页面 1 ano atrás
  IlhamTahir bde886d9e6 feat: 喂养计划 1 ano atrás
  IlhamTahir 6dfcc0076a feat: 完成喂养计划,宠物信息填充 1 ano atrás
41 arquivos alterados com 521 adições e 794 exclusões
  1. 1 0
      package.json
  2. 4 1
      pages.config.ts
  3. 3 0
      pnpm-lock.yaml
  4. 6 0
      src/api/user.ts
  5. 0 632
      src/auto-imports.d.ts
  6. 5 0
      src/components.d.ts
  7. 32 0
      src/components/Cell.vue
  8. 13 0
      src/components/CellGroup.vue
  9. 24 0
      src/components/PickerDate.vue
  10. 38 0
      src/components/PickerItem.vue
  11. 58 0
      src/components/PopupInput.vue
  12. 20 1
      src/components/TabBar.vue
  13. 15 1
      src/main.ts
  14. 3 0
      src/model/pet-manual.ts
  15. 47 3
      src/model/pet.ts
  16. 5 0
      src/model/user.ts
  17. 6 4
      src/pages.json
  18. 19 34
      src/pages/feed-calculator/components/FeedQuestionnaire.vue
  19. 0 0
      src/pages/feed-calculator/components/FeedSlogan.vue
  20. 0 1
      src/pages/feed-calculator/components/FeedStart.vue
  21. 18 23
      src/pages/feed-calculator/index.vue
  22. 1 1
      src/pages/feed-plan/index.vue
  23. 34 18
      src/pages/me/index.vue
  24. 13 17
      src/pages/setting/index.vue
  25. 28 33
      src/pages/start-filing/index.vue
  26. 2 22
      src/pages/userInfo/index.vue
  27. 3 0
      src/static/icons/right.svg
  28. 3 0
      src/static/image/body-type/extremely-obese.svg
  29. 3 0
      src/static/image/body-type/extremely-thin.svg
  30. 3 0
      src/static/image/body-type/ideal.svg
  31. 3 0
      src/static/image/body-type/obese.svg
  32. 3 0
      src/static/image/body-type/overweight.svg
  33. 3 0
      src/static/image/body-type/thin.svg
  34. 3 0
      src/static/image/body-type/underweight.svg
  35. 3 0
      src/static/image/body-type/very-thin.svg
  36. 0 0
      src/static/image/pet-parameters/avatar.png
  37. 23 1
      src/stores/app.ts
  38. 69 0
      src/stores/feeding-plan.ts
  39. 1 1
      src/uni-pages.d.ts
  40. 3 0
      tailwind.config.ts
  41. 3 1
      tsconfig.json

+ 1 - 0
package.json

@@ -66,6 +66,7 @@
     "pinia": "^2.2.6",
     "pinia-plugin-persistedstate": "^4.1.3",
     "vue": "~3.4.38",
+    "vue-demi": "^0.14.10",
     "vue-i18n": "^9.14.1"
   },
   "devDependencies": {

+ 4 - 1
pages.config.ts

@@ -48,6 +48,9 @@ export default defineUniPages({
     {
       path: 'pages/setting/index',
       type: 'page',
+      style: {
+        navigationBarTitleText: '设置',
+      },
     },
     {
       path: 'pages/start-filing/index',
@@ -61,7 +64,7 @@ export default defineUniPages({
       type: 'page',
     },
     {
-      path: 'pages/feed-calculator/components/FeedFlogan',
+      path: 'pages/feed-calculator/components/FeedSlogan',
       type: 'page',
     },
     {

+ 3 - 0
pnpm-lock.yaml

@@ -71,6 +71,9 @@ importers:
       vue:
         specifier: ~3.4.38
         version: 3.4.38(typescript@5.5.4)
+      vue-demi:
+        specifier: ^0.14.10
+        version: 0.14.10(vue@3.4.38(typescript@5.5.4))
       vue-i18n:
         specifier: ^9.14.1
         version: 9.14.1(vue@3.4.38(typescript@5.5.4))

+ 6 - 0
src/api/user.ts

@@ -0,0 +1,6 @@
+import type { User } from '@/model/user'
+import httpClient from '@/api/httpClient'
+
+export function getCurrentUser() {
+  return httpClient.get<User>('/users/current')
+}

+ 0 - 632
src/auto-imports.d.ts

@@ -1,632 +0,0 @@
-/* eslint-disable */
-/* prettier-ignore */
-// @ts-nocheck
-// noinspection JSUnusedGlobalSymbols
-// Generated by unplugin-auto-import
-// biome-ignore lint: disable
-export {}
-declare global {
-  const EffectScope: typeof import('vue')['EffectScope']
-  const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
-  const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
-  const computed: typeof import('vue')['computed']
-  const computedAsync: typeof import('@vueuse/core')['computedAsync']
-  const computedEager: typeof import('@vueuse/core')['computedEager']
-  const computedInject: typeof import('@vueuse/core')['computedInject']
-  const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
-  const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
-  const controlledRef: typeof import('@vueuse/core')['controlledRef']
-  const createApp: typeof import('vue')['createApp']
-  const createEventHook: typeof import('@vueuse/core')['createEventHook']
-  const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
-  const createInjectionState: typeof import('@vueuse/core')['createInjectionState']
-  const createReactiveFn: typeof import('@vueuse/core')['createReactiveFn']
-  const createReusableTemplate: typeof import('@vueuse/core')['createReusableTemplate']
-  const createSharedComposable: typeof import('@vueuse/core')['createSharedComposable']
-  const createTemplatePromise: typeof import('@vueuse/core')['createTemplatePromise']
-  const createUnrefFn: typeof import('@vueuse/core')['createUnrefFn']
-  const customRef: typeof import('vue')['customRef']
-  const debouncedRef: typeof import('@vueuse/core')['debouncedRef']
-  const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
-  const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
-  const defineComponent: typeof import('vue')['defineComponent']
-  const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
-  const effectScope: typeof import('vue')['effectScope']
-  const extendRef: typeof import('@vueuse/core')['extendRef']
-  const getCurrentInstance: typeof import('vue')['getCurrentInstance']
-  const getCurrentScope: typeof import('vue')['getCurrentScope']
-  const h: typeof import('vue')['h']
-  const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
-  const inject: typeof import('vue')['inject']
-  const injectLocal: typeof import('@vueuse/core')['injectLocal']
-  const isDefined: typeof import('@vueuse/core')['isDefined']
-  const isProxy: typeof import('vue')['isProxy']
-  const isReactive: typeof import('vue')['isReactive']
-  const isReadonly: typeof import('vue')['isReadonly']
-  const isRef: typeof import('vue')['isRef']
-  const makeDestructurable: typeof import('@vueuse/core')['makeDestructurable']
-  const markRaw: typeof import('vue')['markRaw']
-  const nextTick: typeof import('vue')['nextTick']
-  const onActivated: typeof import('vue')['onActivated']
-  const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
-  const onBackPress: typeof import('@dcloudio/uni-app')['onBackPress']
-  const onBeforeMount: typeof import('vue')['onBeforeMount']
-  const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
-  const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
-  const onClickOutside: typeof import('@vueuse/core')['onClickOutside']
-  const onDeactivated: typeof import('vue')['onDeactivated']
-  const onError: typeof import('@dcloudio/uni-app')['onError']
-  const onErrorCaptured: typeof import('vue')['onErrorCaptured']
-  const onHide: typeof import('@dcloudio/uni-app')['onHide']
-  const onKeyStroke: typeof import('@vueuse/core')['onKeyStroke']
-  const onLaunch: typeof import('@dcloudio/uni-app')['onLaunch']
-  const onLoad: typeof import('@dcloudio/uni-app')['onLoad']
-  const onLongPress: typeof import('@vueuse/core')['onLongPress']
-  const onMounted: typeof import('vue')['onMounted']
-  const onNavigationBarButtonTap: typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']
-  const onNavigationBarSearchInputChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']
-  const onNavigationBarSearchInputClicked: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']
-  const onNavigationBarSearchInputConfirmed: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']
-  const onNavigationBarSearchInputFocusChanged: typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']
-  const onPageNotFound: typeof import('@dcloudio/uni-app')['onPageNotFound']
-  const onPageScroll: typeof import('@dcloudio/uni-app')['onPageScroll']
-  const onPullDownRefresh: typeof import('@dcloudio/uni-app')['onPullDownRefresh']
-  const onReachBottom: typeof import('@dcloudio/uni-app')['onReachBottom']
-  const onReady: typeof import('@dcloudio/uni-app')['onReady']
-  const onRenderTracked: typeof import('vue')['onRenderTracked']
-  const onRenderTriggered: typeof import('vue')['onRenderTriggered']
-  const onResize: typeof import('@dcloudio/uni-app')['onResize']
-  const onScopeDispose: typeof import('vue')['onScopeDispose']
-  const onServerPrefetch: typeof import('vue')['onServerPrefetch']
-  const onShareAppMessage: typeof import('@dcloudio/uni-app')['onShareAppMessage']
-  const onShareTimeline: typeof import('@dcloudio/uni-app')['onShareTimeline']
-  const onShow: typeof import('@dcloudio/uni-app')['onShow']
-  const onStartTyping: typeof import('@vueuse/core')['onStartTyping']
-  const onTabItemTap: typeof import('@dcloudio/uni-app')['onTabItemTap']
-  const onThemeChange: typeof import('@dcloudio/uni-app')['onThemeChange']
-  const onUnhandledRejection: typeof import('@dcloudio/uni-app')['onUnhandledRejection']
-  const onUnload: typeof import('@dcloudio/uni-app')['onUnload']
-  const onUnmounted: typeof import('vue')['onUnmounted']
-  const onUpdated: typeof import('vue')['onUpdated']
-  const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
-  const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
-  const provide: typeof import('vue')['provide']
-  const provideLocal: typeof import('@vueuse/core')['provideLocal']
-  const reactify: typeof import('@vueuse/core')['reactify']
-  const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
-  const reactive: typeof import('vue')['reactive']
-  const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
-  const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
-  const reactivePick: typeof import('@vueuse/core')['reactivePick']
-  const readonly: typeof import('vue')['readonly']
-  const ref: typeof import('vue')['ref']
-  const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
-  const refDebounced: typeof import('@vueuse/core')['refDebounced']
-  const refDefault: typeof import('@vueuse/core')['refDefault']
-  const refThrottled: typeof import('@vueuse/core')['refThrottled']
-  const refWithControl: typeof import('@vueuse/core')['refWithControl']
-  const resolveComponent: typeof import('vue')['resolveComponent']
-  const resolveRef: typeof import('@vueuse/core')['resolveRef']
-  const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
-  const shallowReactive: typeof import('vue')['shallowReactive']
-  const shallowReadonly: typeof import('vue')['shallowReadonly']
-  const shallowRef: typeof import('vue')['shallowRef']
-  const syncRef: typeof import('@vueuse/core')['syncRef']
-  const syncRefs: typeof import('@vueuse/core')['syncRefs']
-  const templateRef: typeof import('@vueuse/core')['templateRef']
-  const throttledRef: typeof import('@vueuse/core')['throttledRef']
-  const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
-  const toRaw: typeof import('vue')['toRaw']
-  const toReactive: typeof import('@vueuse/core')['toReactive']
-  const toRef: typeof import('vue')['toRef']
-  const toRefs: typeof import('vue')['toRefs']
-  const toValue: typeof import('vue')['toValue']
-  const triggerRef: typeof import('vue')['triggerRef']
-  const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
-  const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
-  const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
-  const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
-  const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
-  const unref: typeof import('vue')['unref']
-  const unrefElement: typeof import('@vueuse/core')['unrefElement']
-  const until: typeof import('@vueuse/core')['until']
-  const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
-  const useAnimate: typeof import('@vueuse/core')['useAnimate']
-  const useAppStore: typeof import('./stores/app')['useAppStore']
-  const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
-  const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
-  const useArrayFilter: typeof import('@vueuse/core')['useArrayFilter']
-  const useArrayFind: typeof import('@vueuse/core')['useArrayFind']
-  const useArrayFindIndex: typeof import('@vueuse/core')['useArrayFindIndex']
-  const useArrayFindLast: typeof import('@vueuse/core')['useArrayFindLast']
-  const useArrayIncludes: typeof import('@vueuse/core')['useArrayIncludes']
-  const useArrayJoin: typeof import('@vueuse/core')['useArrayJoin']
-  const useArrayMap: typeof import('@vueuse/core')['useArrayMap']
-  const useArrayReduce: typeof import('@vueuse/core')['useArrayReduce']
-  const useArraySome: typeof import('@vueuse/core')['useArraySome']
-  const useArrayUnique: typeof import('@vueuse/core')['useArrayUnique']
-  const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
-  const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
-  const useAttrs: typeof import('vue')['useAttrs']
-  const useBase64: typeof import('@vueuse/core')['useBase64']
-  const useBattery: typeof import('@vueuse/core')['useBattery']
-  const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
-  const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
-  const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
-  const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
-  const useCached: typeof import('@vueuse/core')['useCached']
-  const useClipboard: typeof import('@vueuse/core')['useClipboard']
-  const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems']
-  const useCloned: typeof import('@vueuse/core')['useCloned']
-  const useColorMode: typeof import('@vueuse/core')['useColorMode']
-  const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
-  const useCount: typeof import('./composables/useCount')['useCount']
-  const useCounter: typeof import('@vueuse/core')['useCounter']
-  const useCssModule: typeof import('vue')['useCssModule']
-  const useCssVar: typeof import('@vueuse/core')['useCssVar']
-  const useCssVars: typeof import('vue')['useCssVars']
-  const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
-  const useCycleList: typeof import('@vueuse/core')['useCycleList']
-  const useDark: typeof import('@vueuse/core')['useDark']
-  const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
-  const useDebounce: typeof import('@vueuse/core')['useDebounce']
-  const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']
-  const useDebouncedRefHistory: typeof import('@vueuse/core')['useDebouncedRefHistory']
-  const useDeviceMotion: typeof import('@vueuse/core')['useDeviceMotion']
-  const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
-  const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
-  const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
-  const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
-  const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
-  const useDraggable: typeof import('@vueuse/core')['useDraggable']
-  const useDropZone: typeof import('@vueuse/core')['useDropZone']
-  const useElementBounding: typeof import('@vueuse/core')['useElementBounding']
-  const useElementByPoint: typeof import('@vueuse/core')['useElementByPoint']
-  const useElementHover: typeof import('@vueuse/core')['useElementHover']
-  const useElementSize: typeof import('@vueuse/core')['useElementSize']
-  const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
-  const useEventBus: typeof import('@vueuse/core')['useEventBus']
-  const useEventListener: typeof import('@vueuse/core')['useEventListener']
-  const useEventSource: typeof import('@vueuse/core')['useEventSource']
-  const useEyeDropper: typeof import('@vueuse/core')['useEyeDropper']
-  const useFavicon: typeof import('@vueuse/core')['useFavicon']
-  const useFetch: typeof import('@vueuse/core')['useFetch']
-  const useFileDialog: typeof import('@vueuse/core')['useFileDialog']
-  const useFileSystemAccess: typeof import('@vueuse/core')['useFileSystemAccess']
-  const useFocus: typeof import('@vueuse/core')['useFocus']
-  const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
-  const useFps: typeof import('@vueuse/core')['useFps']
-  const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
-  const useGamepad: typeof import('@vueuse/core')['useGamepad']
-  const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
-  const useId: typeof import('vue')['useId']
-  const useIdle: typeof import('@vueuse/core')['useIdle']
-  const useImage: typeof import('@vueuse/core')['useImage']
-  const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
-  const useIntersectionObserver: typeof import('@vueuse/core')['useIntersectionObserver']
-  const useInterval: typeof import('@vueuse/core')['useInterval']
-  const useIntervalFn: typeof import('@vueuse/core')['useIntervalFn']
-  const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
-  const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
-  const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
-  const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
-  const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
-  const useMediaControls: typeof import('@vueuse/core')['useMediaControls']
-  const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
-  const useMemoize: typeof import('@vueuse/core')['useMemoize']
-  const useMemory: typeof import('@vueuse/core')['useMemory']
-  const useModel: typeof import('vue')['useModel']
-  const useMounted: typeof import('@vueuse/core')['useMounted']
-  const useMouse: typeof import('@vueuse/core')['useMouse']
-  const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
-  const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
-  const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
-  const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
-  const useNetwork: typeof import('@vueuse/core')['useNetwork']
-  const useNow: typeof import('@vueuse/core')['useNow']
-  const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
-  const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
-  const useOnline: typeof import('@vueuse/core')['useOnline']
-  const usePageLeave: typeof import('@vueuse/core')['usePageLeave']
-  const useParallax: typeof import('@vueuse/core')['useParallax']
-  const useParentElement: typeof import('@vueuse/core')['useParentElement']
-  const usePerformanceObserver: typeof import('@vueuse/core')['usePerformanceObserver']
-  const usePermission: typeof import('@vueuse/core')['usePermission']
-  const usePointer: typeof import('@vueuse/core')['usePointer']
-  const usePointerLock: typeof import('@vueuse/core')['usePointerLock']
-  const usePointerSwipe: typeof import('@vueuse/core')['usePointerSwipe']
-  const usePreferredColorScheme: typeof import('@vueuse/core')['usePreferredColorScheme']
-  const usePreferredContrast: typeof import('@vueuse/core')['usePreferredContrast']
-  const usePreferredDark: typeof import('@vueuse/core')['usePreferredDark']
-  const usePreferredLanguages: typeof import('@vueuse/core')['usePreferredLanguages']
-  const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
-  const usePrevious: typeof import('@vueuse/core')['usePrevious']
-  const useQuery: typeof import('./composables/useQuery')['useQuery']
-  const useRafFn: typeof import('@vueuse/core')['useRafFn']
-  const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
-  const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
-  const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
-  const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
-  const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
-  const useScroll: typeof import('@vueuse/core')['useScroll']
-  const useScrollLock: typeof import('@vueuse/core')['useScrollLock']
-  const useSessionStorage: typeof import('@vueuse/core')['useSessionStorage']
-  const useShare: typeof import('@vueuse/core')['useShare']
-  const useSlots: typeof import('vue')['useSlots']
-  const useSorted: typeof import('@vueuse/core')['useSorted']
-  const useSpeechRecognition: typeof import('@vueuse/core')['useSpeechRecognition']
-  const useSpeechSynthesis: typeof import('@vueuse/core')['useSpeechSynthesis']
-  const useStepper: typeof import('@vueuse/core')['useStepper']
-  const useStorage: typeof import('@vueuse/core')['useStorage']
-  const useStorageAsync: typeof import('@vueuse/core')['useStorageAsync']
-  const useStyleTag: typeof import('@vueuse/core')['useStyleTag']
-  const useSupported: typeof import('@vueuse/core')['useSupported']
-  const useSwipe: typeof import('@vueuse/core')['useSwipe']
-  const useTemplateRef: typeof import('vue')['useTemplateRef']
-  const useTemplateRefsList: typeof import('@vueuse/core')['useTemplateRefsList']
-  const useTextDirection: typeof import('@vueuse/core')['useTextDirection']
-  const useTextSelection: typeof import('@vueuse/core')['useTextSelection']
-  const useTextareaAutosize: typeof import('@vueuse/core')['useTextareaAutosize']
-  const useThrottle: typeof import('@vueuse/core')['useThrottle']
-  const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
-  const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
-  const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
-  const useTimeout: typeof import('@vueuse/core')['useTimeout']
-  const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
-  const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
-  const useTimestamp: typeof import('@vueuse/core')['useTimestamp']
-  const useTitle: typeof import('@vueuse/core')['useTitle']
-  const useToNumber: typeof import('@vueuse/core')['useToNumber']
-  const useToString: typeof import('@vueuse/core')['useToString']
-  const useToggle: typeof import('@vueuse/core')['useToggle']
-  const useTransition: typeof import('@vueuse/core')['useTransition']
-  const useUrlSearchParams: typeof import('@vueuse/core')['useUrlSearchParams']
-  const useUserMedia: typeof import('@vueuse/core')['useUserMedia']
-  const useVModel: typeof import('@vueuse/core')['useVModel']
-  const useVModels: typeof import('@vueuse/core')['useVModels']
-  const useVibrate: typeof import('@vueuse/core')['useVibrate']
-  const useVirtualList: typeof import('@vueuse/core')['useVirtualList']
-  const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
-  const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
-  const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
-  const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
-  const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
-  const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
-  const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
-  const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
-  const utils: typeof import('./utils/index')['default']
-  const watch: typeof import('vue')['watch']
-  const watchArray: typeof import('@vueuse/core')['watchArray']
-  const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
-  const watchDebounced: typeof import('@vueuse/core')['watchDebounced']
-  const watchDeep: typeof import('@vueuse/core')['watchDeep']
-  const watchEffect: typeof import('vue')['watchEffect']
-  const watchIgnorable: typeof import('@vueuse/core')['watchIgnorable']
-  const watchImmediate: typeof import('@vueuse/core')['watchImmediate']
-  const watchOnce: typeof import('@vueuse/core')['watchOnce']
-  const watchPausable: typeof import('@vueuse/core')['watchPausable']
-  const watchPostEffect: typeof import('vue')['watchPostEffect']
-  const watchSyncEffect: typeof import('vue')['watchSyncEffect']
-  const watchThrottled: typeof import('@vueuse/core')['watchThrottled']
-  const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
-  const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
-  const whenever: typeof import('@vueuse/core')['whenever']
-}
-// for type re-export
-declare global {
-  // @ts-ignore
-  export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
-  import('vue')
-}
-// for vue template auto import
-import { UnwrapRef } from 'vue'
-declare module 'vue' {
-  interface GlobalComponents {}
-  interface ComponentCustomProperties {
-    readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
-    readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
-    readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
-    readonly computed: UnwrapRef<typeof import('vue')['computed']>
-    readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']>
-    readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']>
-    readonly computedInject: UnwrapRef<typeof import('@vueuse/core')['computedInject']>
-    readonly computedWithControl: UnwrapRef<typeof import('@vueuse/core')['computedWithControl']>
-    readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']>
-    readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']>
-    readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
-    readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']>
-    readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']>
-    readonly createInjectionState: UnwrapRef<typeof import('@vueuse/core')['createInjectionState']>
-    readonly createReactiveFn: UnwrapRef<typeof import('@vueuse/core')['createReactiveFn']>
-    readonly createReusableTemplate: UnwrapRef<typeof import('@vueuse/core')['createReusableTemplate']>
-    readonly createSharedComposable: UnwrapRef<typeof import('@vueuse/core')['createSharedComposable']>
-    readonly createTemplatePromise: UnwrapRef<typeof import('@vueuse/core')['createTemplatePromise']>
-    readonly createUnrefFn: UnwrapRef<typeof import('@vueuse/core')['createUnrefFn']>
-    readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
-    readonly debouncedRef: UnwrapRef<typeof import('@vueuse/core')['debouncedRef']>
-    readonly debouncedWatch: UnwrapRef<typeof import('@vueuse/core')['debouncedWatch']>
-    readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
-    readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
-    readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
-    readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
-    readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']>
-    readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
-    readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
-    readonly h: UnwrapRef<typeof import('vue')['h']>
-    readonly ignorableWatch: UnwrapRef<typeof import('@vueuse/core')['ignorableWatch']>
-    readonly inject: UnwrapRef<typeof import('vue')['inject']>
-    readonly injectLocal: UnwrapRef<typeof import('@vueuse/core')['injectLocal']>
-    readonly isDefined: UnwrapRef<typeof import('@vueuse/core')['isDefined']>
-    readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
-    readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
-    readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
-    readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
-    readonly makeDestructurable: UnwrapRef<typeof import('@vueuse/core')['makeDestructurable']>
-    readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
-    readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
-    readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
-    readonly onAddToFavorites: UnwrapRef<typeof import('@dcloudio/uni-app')['onAddToFavorites']>
-    readonly onBackPress: UnwrapRef<typeof import('@dcloudio/uni-app')['onBackPress']>
-    readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
-    readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
-    readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
-    readonly onClickOutside: UnwrapRef<typeof import('@vueuse/core')['onClickOutside']>
-    readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
-    readonly onError: UnwrapRef<typeof import('@dcloudio/uni-app')['onError']>
-    readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
-    readonly onHide: UnwrapRef<typeof import('@dcloudio/uni-app')['onHide']>
-    readonly onKeyStroke: UnwrapRef<typeof import('@vueuse/core')['onKeyStroke']>
-    readonly onLaunch: UnwrapRef<typeof import('@dcloudio/uni-app')['onLaunch']>
-    readonly onLoad: UnwrapRef<typeof import('@dcloudio/uni-app')['onLoad']>
-    readonly onLongPress: UnwrapRef<typeof import('@vueuse/core')['onLongPress']>
-    readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
-    readonly onNavigationBarButtonTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarButtonTap']>
-    readonly onNavigationBarSearchInputChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputChanged']>
-    readonly onNavigationBarSearchInputClicked: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputClicked']>
-    readonly onNavigationBarSearchInputConfirmed: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputConfirmed']>
-    readonly onNavigationBarSearchInputFocusChanged: UnwrapRef<typeof import('@dcloudio/uni-app')['onNavigationBarSearchInputFocusChanged']>
-    readonly onPageNotFound: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageNotFound']>
-    readonly onPageScroll: UnwrapRef<typeof import('@dcloudio/uni-app')['onPageScroll']>
-    readonly onPullDownRefresh: UnwrapRef<typeof import('@dcloudio/uni-app')['onPullDownRefresh']>
-    readonly onReachBottom: UnwrapRef<typeof import('@dcloudio/uni-app')['onReachBottom']>
-    readonly onReady: UnwrapRef<typeof import('@dcloudio/uni-app')['onReady']>
-    readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
-    readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
-    readonly onResize: UnwrapRef<typeof import('@dcloudio/uni-app')['onResize']>
-    readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
-    readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
-    readonly onShareAppMessage: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareAppMessage']>
-    readonly onShareTimeline: UnwrapRef<typeof import('@dcloudio/uni-app')['onShareTimeline']>
-    readonly onShow: UnwrapRef<typeof import('@dcloudio/uni-app')['onShow']>
-    readonly onStartTyping: UnwrapRef<typeof import('@vueuse/core')['onStartTyping']>
-    readonly onTabItemTap: UnwrapRef<typeof import('@dcloudio/uni-app')['onTabItemTap']>
-    readonly onThemeChange: UnwrapRef<typeof import('@dcloudio/uni-app')['onThemeChange']>
-    readonly onUnhandledRejection: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnhandledRejection']>
-    readonly onUnload: UnwrapRef<typeof import('@dcloudio/uni-app')['onUnload']>
-    readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
-    readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
-    readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
-    readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
-    readonly provide: UnwrapRef<typeof import('vue')['provide']>
-    readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
-    readonly reactify: UnwrapRef<typeof import('@vueuse/core')['reactify']>
-    readonly reactifyObject: UnwrapRef<typeof import('@vueuse/core')['reactifyObject']>
-    readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
-    readonly reactiveComputed: UnwrapRef<typeof import('@vueuse/core')['reactiveComputed']>
-    readonly reactiveOmit: UnwrapRef<typeof import('@vueuse/core')['reactiveOmit']>
-    readonly reactivePick: UnwrapRef<typeof import('@vueuse/core')['reactivePick']>
-    readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
-    readonly ref: UnwrapRef<typeof import('vue')['ref']>
-    readonly refAutoReset: UnwrapRef<typeof import('@vueuse/core')['refAutoReset']>
-    readonly refDebounced: UnwrapRef<typeof import('@vueuse/core')['refDebounced']>
-    readonly refDefault: UnwrapRef<typeof import('@vueuse/core')['refDefault']>
-    readonly refThrottled: UnwrapRef<typeof import('@vueuse/core')['refThrottled']>
-    readonly refWithControl: UnwrapRef<typeof import('@vueuse/core')['refWithControl']>
-    readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
-    readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']>
-    readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']>
-    readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
-    readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
-    readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
-    readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
-    readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>
-    readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']>
-    readonly throttledRef: UnwrapRef<typeof import('@vueuse/core')['throttledRef']>
-    readonly throttledWatch: UnwrapRef<typeof import('@vueuse/core')['throttledWatch']>
-    readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
-    readonly toReactive: UnwrapRef<typeof import('@vueuse/core')['toReactive']>
-    readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
-    readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
-    readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
-    readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
-    readonly tryOnBeforeMount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeMount']>
-    readonly tryOnBeforeUnmount: UnwrapRef<typeof import('@vueuse/core')['tryOnBeforeUnmount']>
-    readonly tryOnMounted: UnwrapRef<typeof import('@vueuse/core')['tryOnMounted']>
-    readonly tryOnScopeDispose: UnwrapRef<typeof import('@vueuse/core')['tryOnScopeDispose']>
-    readonly tryOnUnmounted: UnwrapRef<typeof import('@vueuse/core')['tryOnUnmounted']>
-    readonly unref: UnwrapRef<typeof import('vue')['unref']>
-    readonly unrefElement: UnwrapRef<typeof import('@vueuse/core')['unrefElement']>
-    readonly until: UnwrapRef<typeof import('@vueuse/core')['until']>
-    readonly useActiveElement: UnwrapRef<typeof import('@vueuse/core')['useActiveElement']>
-    readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']>
-    readonly useAppStore: UnwrapRef<typeof import('./stores/app')['useAppStore']>
-    readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']>
-    readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']>
-    readonly useArrayFilter: UnwrapRef<typeof import('@vueuse/core')['useArrayFilter']>
-    readonly useArrayFind: UnwrapRef<typeof import('@vueuse/core')['useArrayFind']>
-    readonly useArrayFindIndex: UnwrapRef<typeof import('@vueuse/core')['useArrayFindIndex']>
-    readonly useArrayFindLast: UnwrapRef<typeof import('@vueuse/core')['useArrayFindLast']>
-    readonly useArrayIncludes: UnwrapRef<typeof import('@vueuse/core')['useArrayIncludes']>
-    readonly useArrayJoin: UnwrapRef<typeof import('@vueuse/core')['useArrayJoin']>
-    readonly useArrayMap: UnwrapRef<typeof import('@vueuse/core')['useArrayMap']>
-    readonly useArrayReduce: UnwrapRef<typeof import('@vueuse/core')['useArrayReduce']>
-    readonly useArraySome: UnwrapRef<typeof import('@vueuse/core')['useArraySome']>
-    readonly useArrayUnique: UnwrapRef<typeof import('@vueuse/core')['useArrayUnique']>
-    readonly useAsyncQueue: UnwrapRef<typeof import('@vueuse/core')['useAsyncQueue']>
-    readonly useAsyncState: UnwrapRef<typeof import('@vueuse/core')['useAsyncState']>
-    readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
-    readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']>
-    readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']>
-    readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']>
-    readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']>
-    readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']>
-    readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']>
-    readonly useCached: UnwrapRef<typeof import('@vueuse/core')['useCached']>
-    readonly useClipboard: UnwrapRef<typeof import('@vueuse/core')['useClipboard']>
-    readonly useClipboardItems: UnwrapRef<typeof import('@vueuse/core')['useClipboardItems']>
-    readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']>
-    readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']>
-    readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']>
-    readonly useCount: UnwrapRef<typeof import('./composables/useCount')['useCount']>
-    readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']>
-    readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
-    readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']>
-    readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
-    readonly useCurrentElement: UnwrapRef<typeof import('@vueuse/core')['useCurrentElement']>
-    readonly useCycleList: UnwrapRef<typeof import('@vueuse/core')['useCycleList']>
-    readonly useDark: UnwrapRef<typeof import('@vueuse/core')['useDark']>
-    readonly useDateFormat: UnwrapRef<typeof import('@vueuse/core')['useDateFormat']>
-    readonly useDebounce: UnwrapRef<typeof import('@vueuse/core')['useDebounce']>
-    readonly useDebounceFn: UnwrapRef<typeof import('@vueuse/core')['useDebounceFn']>
-    readonly useDebouncedRefHistory: UnwrapRef<typeof import('@vueuse/core')['useDebouncedRefHistory']>
-    readonly useDeviceMotion: UnwrapRef<typeof import('@vueuse/core')['useDeviceMotion']>
-    readonly useDeviceOrientation: UnwrapRef<typeof import('@vueuse/core')['useDeviceOrientation']>
-    readonly useDevicePixelRatio: UnwrapRef<typeof import('@vueuse/core')['useDevicePixelRatio']>
-    readonly useDevicesList: UnwrapRef<typeof import('@vueuse/core')['useDevicesList']>
-    readonly useDisplayMedia: UnwrapRef<typeof import('@vueuse/core')['useDisplayMedia']>
-    readonly useDocumentVisibility: UnwrapRef<typeof import('@vueuse/core')['useDocumentVisibility']>
-    readonly useDraggable: UnwrapRef<typeof import('@vueuse/core')['useDraggable']>
-    readonly useDropZone: UnwrapRef<typeof import('@vueuse/core')['useDropZone']>
-    readonly useElementBounding: UnwrapRef<typeof import('@vueuse/core')['useElementBounding']>
-    readonly useElementByPoint: UnwrapRef<typeof import('@vueuse/core')['useElementByPoint']>
-    readonly useElementHover: UnwrapRef<typeof import('@vueuse/core')['useElementHover']>
-    readonly useElementSize: UnwrapRef<typeof import('@vueuse/core')['useElementSize']>
-    readonly useElementVisibility: UnwrapRef<typeof import('@vueuse/core')['useElementVisibility']>
-    readonly useEventBus: UnwrapRef<typeof import('@vueuse/core')['useEventBus']>
-    readonly useEventListener: UnwrapRef<typeof import('@vueuse/core')['useEventListener']>
-    readonly useEventSource: UnwrapRef<typeof import('@vueuse/core')['useEventSource']>
-    readonly useEyeDropper: UnwrapRef<typeof import('@vueuse/core')['useEyeDropper']>
-    readonly useFavicon: UnwrapRef<typeof import('@vueuse/core')['useFavicon']>
-    readonly useFetch: UnwrapRef<typeof import('@vueuse/core')['useFetch']>
-    readonly useFileDialog: UnwrapRef<typeof import('@vueuse/core')['useFileDialog']>
-    readonly useFileSystemAccess: UnwrapRef<typeof import('@vueuse/core')['useFileSystemAccess']>
-    readonly useFocus: UnwrapRef<typeof import('@vueuse/core')['useFocus']>
-    readonly useFocusWithin: UnwrapRef<typeof import('@vueuse/core')['useFocusWithin']>
-    readonly useFps: UnwrapRef<typeof import('@vueuse/core')['useFps']>
-    readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']>
-    readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']>
-    readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']>
-    readonly useId: UnwrapRef<typeof import('vue')['useId']>
-    readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
-    readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
-    readonly useInfiniteScroll: UnwrapRef<typeof import('@vueuse/core')['useInfiniteScroll']>
-    readonly useIntersectionObserver: UnwrapRef<typeof import('@vueuse/core')['useIntersectionObserver']>
-    readonly useInterval: UnwrapRef<typeof import('@vueuse/core')['useInterval']>
-    readonly useIntervalFn: UnwrapRef<typeof import('@vueuse/core')['useIntervalFn']>
-    readonly useKeyModifier: UnwrapRef<typeof import('@vueuse/core')['useKeyModifier']>
-    readonly useLastChanged: UnwrapRef<typeof import('@vueuse/core')['useLastChanged']>
-    readonly useLocalStorage: UnwrapRef<typeof import('@vueuse/core')['useLocalStorage']>
-    readonly useMagicKeys: UnwrapRef<typeof import('@vueuse/core')['useMagicKeys']>
-    readonly useManualRefHistory: UnwrapRef<typeof import('@vueuse/core')['useManualRefHistory']>
-    readonly useMediaControls: UnwrapRef<typeof import('@vueuse/core')['useMediaControls']>
-    readonly useMediaQuery: UnwrapRef<typeof import('@vueuse/core')['useMediaQuery']>
-    readonly useMemoize: UnwrapRef<typeof import('@vueuse/core')['useMemoize']>
-    readonly useMemory: UnwrapRef<typeof import('@vueuse/core')['useMemory']>
-    readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
-    readonly useMounted: UnwrapRef<typeof import('@vueuse/core')['useMounted']>
-    readonly useMouse: UnwrapRef<typeof import('@vueuse/core')['useMouse']>
-    readonly useMouseInElement: UnwrapRef<typeof import('@vueuse/core')['useMouseInElement']>
-    readonly useMousePressed: UnwrapRef<typeof import('@vueuse/core')['useMousePressed']>
-    readonly useMutationObserver: UnwrapRef<typeof import('@vueuse/core')['useMutationObserver']>
-    readonly useNavigatorLanguage: UnwrapRef<typeof import('@vueuse/core')['useNavigatorLanguage']>
-    readonly useNetwork: UnwrapRef<typeof import('@vueuse/core')['useNetwork']>
-    readonly useNow: UnwrapRef<typeof import('@vueuse/core')['useNow']>
-    readonly useObjectUrl: UnwrapRef<typeof import('@vueuse/core')['useObjectUrl']>
-    readonly useOffsetPagination: UnwrapRef<typeof import('@vueuse/core')['useOffsetPagination']>
-    readonly useOnline: UnwrapRef<typeof import('@vueuse/core')['useOnline']>
-    readonly usePageLeave: UnwrapRef<typeof import('@vueuse/core')['usePageLeave']>
-    readonly useParallax: UnwrapRef<typeof import('@vueuse/core')['useParallax']>
-    readonly useParentElement: UnwrapRef<typeof import('@vueuse/core')['useParentElement']>
-    readonly usePerformanceObserver: UnwrapRef<typeof import('@vueuse/core')['usePerformanceObserver']>
-    readonly usePermission: UnwrapRef<typeof import('@vueuse/core')['usePermission']>
-    readonly usePointer: UnwrapRef<typeof import('@vueuse/core')['usePointer']>
-    readonly usePointerLock: UnwrapRef<typeof import('@vueuse/core')['usePointerLock']>
-    readonly usePointerSwipe: UnwrapRef<typeof import('@vueuse/core')['usePointerSwipe']>
-    readonly usePreferredColorScheme: UnwrapRef<typeof import('@vueuse/core')['usePreferredColorScheme']>
-    readonly usePreferredContrast: UnwrapRef<typeof import('@vueuse/core')['usePreferredContrast']>
-    readonly usePreferredDark: UnwrapRef<typeof import('@vueuse/core')['usePreferredDark']>
-    readonly usePreferredLanguages: UnwrapRef<typeof import('@vueuse/core')['usePreferredLanguages']>
-    readonly usePreferredReducedMotion: UnwrapRef<typeof import('@vueuse/core')['usePreferredReducedMotion']>
-    readonly usePrevious: UnwrapRef<typeof import('@vueuse/core')['usePrevious']>
-    readonly useQuery: UnwrapRef<typeof import('./composables/useQuery')['useQuery']>
-    readonly useRafFn: UnwrapRef<typeof import('@vueuse/core')['useRafFn']>
-    readonly useRefHistory: UnwrapRef<typeof import('@vueuse/core')['useRefHistory']>
-    readonly useResizeObserver: UnwrapRef<typeof import('@vueuse/core')['useResizeObserver']>
-    readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
-    readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
-    readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']>
-    readonly useScroll: UnwrapRef<typeof import('@vueuse/core')['useScroll']>
-    readonly useScrollLock: UnwrapRef<typeof import('@vueuse/core')['useScrollLock']>
-    readonly useSessionStorage: UnwrapRef<typeof import('@vueuse/core')['useSessionStorage']>
-    readonly useShare: UnwrapRef<typeof import('@vueuse/core')['useShare']>
-    readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
-    readonly useSorted: UnwrapRef<typeof import('@vueuse/core')['useSorted']>
-    readonly useSpeechRecognition: UnwrapRef<typeof import('@vueuse/core')['useSpeechRecognition']>
-    readonly useSpeechSynthesis: UnwrapRef<typeof import('@vueuse/core')['useSpeechSynthesis']>
-    readonly useStepper: UnwrapRef<typeof import('@vueuse/core')['useStepper']>
-    readonly useStorage: UnwrapRef<typeof import('@vueuse/core')['useStorage']>
-    readonly useStorageAsync: UnwrapRef<typeof import('@vueuse/core')['useStorageAsync']>
-    readonly useStyleTag: UnwrapRef<typeof import('@vueuse/core')['useStyleTag']>
-    readonly useSupported: UnwrapRef<typeof import('@vueuse/core')['useSupported']>
-    readonly useSwipe: UnwrapRef<typeof import('@vueuse/core')['useSwipe']>
-    readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
-    readonly useTemplateRefsList: UnwrapRef<typeof import('@vueuse/core')['useTemplateRefsList']>
-    readonly useTextDirection: UnwrapRef<typeof import('@vueuse/core')['useTextDirection']>
-    readonly useTextSelection: UnwrapRef<typeof import('@vueuse/core')['useTextSelection']>
-    readonly useTextareaAutosize: UnwrapRef<typeof import('@vueuse/core')['useTextareaAutosize']>
-    readonly useThrottle: UnwrapRef<typeof import('@vueuse/core')['useThrottle']>
-    readonly useThrottleFn: UnwrapRef<typeof import('@vueuse/core')['useThrottleFn']>
-    readonly useThrottledRefHistory: UnwrapRef<typeof import('@vueuse/core')['useThrottledRefHistory']>
-    readonly useTimeAgo: UnwrapRef<typeof import('@vueuse/core')['useTimeAgo']>
-    readonly useTimeout: UnwrapRef<typeof import('@vueuse/core')['useTimeout']>
-    readonly useTimeoutFn: UnwrapRef<typeof import('@vueuse/core')['useTimeoutFn']>
-    readonly useTimeoutPoll: UnwrapRef<typeof import('@vueuse/core')['useTimeoutPoll']>
-    readonly useTimestamp: UnwrapRef<typeof import('@vueuse/core')['useTimestamp']>
-    readonly useTitle: UnwrapRef<typeof import('@vueuse/core')['useTitle']>
-    readonly useToNumber: UnwrapRef<typeof import('@vueuse/core')['useToNumber']>
-    readonly useToString: UnwrapRef<typeof import('@vueuse/core')['useToString']>
-    readonly useToggle: UnwrapRef<typeof import('@vueuse/core')['useToggle']>
-    readonly useTransition: UnwrapRef<typeof import('@vueuse/core')['useTransition']>
-    readonly useUrlSearchParams: UnwrapRef<typeof import('@vueuse/core')['useUrlSearchParams']>
-    readonly useUserMedia: UnwrapRef<typeof import('@vueuse/core')['useUserMedia']>
-    readonly useVModel: UnwrapRef<typeof import('@vueuse/core')['useVModel']>
-    readonly useVModels: UnwrapRef<typeof import('@vueuse/core')['useVModels']>
-    readonly useVibrate: UnwrapRef<typeof import('@vueuse/core')['useVibrate']>
-    readonly useVirtualList: UnwrapRef<typeof import('@vueuse/core')['useVirtualList']>
-    readonly useWakeLock: UnwrapRef<typeof import('@vueuse/core')['useWakeLock']>
-    readonly useWebNotification: UnwrapRef<typeof import('@vueuse/core')['useWebNotification']>
-    readonly useWebSocket: UnwrapRef<typeof import('@vueuse/core')['useWebSocket']>
-    readonly useWebWorker: UnwrapRef<typeof import('@vueuse/core')['useWebWorker']>
-    readonly useWebWorkerFn: UnwrapRef<typeof import('@vueuse/core')['useWebWorkerFn']>
-    readonly useWindowFocus: UnwrapRef<typeof import('@vueuse/core')['useWindowFocus']>
-    readonly useWindowScroll: UnwrapRef<typeof import('@vueuse/core')['useWindowScroll']>
-    readonly useWindowSize: UnwrapRef<typeof import('@vueuse/core')['useWindowSize']>
-    readonly utils: UnwrapRef<typeof import('./utils/index')['default']>
-    readonly watch: UnwrapRef<typeof import('vue')['watch']>
-    readonly watchArray: UnwrapRef<typeof import('@vueuse/core')['watchArray']>
-    readonly watchAtMost: UnwrapRef<typeof import('@vueuse/core')['watchAtMost']>
-    readonly watchDebounced: UnwrapRef<typeof import('@vueuse/core')['watchDebounced']>
-    readonly watchDeep: UnwrapRef<typeof import('@vueuse/core')['watchDeep']>
-    readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
-    readonly watchIgnorable: UnwrapRef<typeof import('@vueuse/core')['watchIgnorable']>
-    readonly watchImmediate: UnwrapRef<typeof import('@vueuse/core')['watchImmediate']>
-    readonly watchOnce: UnwrapRef<typeof import('@vueuse/core')['watchOnce']>
-    readonly watchPausable: UnwrapRef<typeof import('@vueuse/core')['watchPausable']>
-    readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
-    readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
-    readonly watchThrottled: UnwrapRef<typeof import('@vueuse/core')['watchThrottled']>
-    readonly watchTriggerable: UnwrapRef<typeof import('@vueuse/core')['watchTriggerable']>
-    readonly watchWithFilter: UnwrapRef<typeof import('@vueuse/core')['watchWithFilter']>
-    readonly whenever: UnwrapRef<typeof import('@vueuse/core')['whenever']>
-  }
-}

+ 5 - 0
src/components.d.ts

@@ -7,6 +7,11 @@ export {}
 
 declare module 'vue' {
   export interface GlobalComponents {
+    Cell: typeof import('./components/Cell.vue')['default']
+    CellGroup: typeof import('./components/CellGroup.vue')['default']
+    PickerDate: typeof import('./components/PickerDate.vue')['default']
+    PickerItem: typeof import('./components/PickerItem.vue')['default']
+    PopupInput: typeof import('./components/PopupInput.vue')['default']
     TabBar: typeof import('./components/TabBar.vue')['default']
     TitleBar: typeof import('./components/TitleBar.vue')['default']
   }

+ 32 - 0
src/components/Cell.vue

@@ -0,0 +1,32 @@
+<script setup lang="ts">
+import right from '@/static/icons/right.svg'
+
+withDefaults(defineProps<{
+  title: string
+  border?: boolean
+}>(), {
+  border: false,
+})
+</script>
+
+<template>
+  <view
+    class="h-[56px] bg-[white] flex items-center p-4 justify-between" :class="{
+      'border-[#E5E5E5] border-b-[0.5px]': border,
+    }"
+  >
+    <view class="text-base">
+      {{ title }}
+    </view>
+    <view class="flex-1 flex justify-center items-center gap-3">
+      <view class="flex-1 flex justify-end">
+        <slot />
+      </view>
+      <image :src="right" class="w-[24px] h-[24px]" />
+    </view>
+  </view>
+</template>
+
+<style scoped>
+
+</style>

+ 13 - 0
src/components/CellGroup.vue

@@ -0,0 +1,13 @@
+<script setup lang="ts">
+
+</script>
+
+<template>
+  <view class="w-full bg-[#fff] shadow-cell-group rounded-3 overflow-hidden cell-group">
+    <slot />
+  </view>
+</template>
+
+<style scoped>
+
+</style>

+ 24 - 0
src/components/PickerDate.vue

@@ -0,0 +1,24 @@
+<script setup lang="ts">
+defineProps<{
+  modelValue: string
+}>()
+const emits = defineEmits<{
+  'update:modelValue': [string]
+}>()
+
+function bindDateChange(e: { detail: { value: string } }) {
+  emits('update:modelValue', e.detail.value)
+}
+</script>
+
+<template>
+  <picker mode="date" :value="modelValue" @change="bindDateChange">
+    <view class="">
+      {{ modelValue }}
+    </view>
+  </picker>
+</template>
+
+<style scoped>
+
+</style>

+ 38 - 0
src/components/PickerItem.vue

@@ -0,0 +1,38 @@
+<script setup lang="ts">
+export interface PickerItemOption {
+  label: string
+  value: string | number
+}
+const props = defineProps<{
+  modelValue: string | number
+  options: PickerItemOption[]
+}>()
+
+const emits = defineEmits<{
+  'update:modelValue': [string | number]
+}>()
+
+function bindPickerChange(e: { detail: { value: number | string } }) {
+  const currentIndex = e.detail.value as number
+  emits('update:modelValue', props.options[currentIndex].value)
+}
+
+const index = ref(0)
+
+watch(() => props.modelValue, (currentValue) => {
+  const currentIndex = props.options.findIndex(option => option.value === currentValue)
+  index.value = currentIndex === -1 ? 0 : currentIndex
+}, { immediate: true })
+</script>
+
+<template>
+  <picker :value="index" :range="options" range-key="label" @change="bindPickerChange">
+    <view>
+      {{ options[index].label }}
+    </view>
+  </picker>
+</template>
+
+<style scoped>
+
+</style>

+ 58 - 0
src/components/PopupInput.vue

@@ -0,0 +1,58 @@
+<script setup lang="ts">
+import type { UniPopupDialogInstance } from '@uni-helper/uni-types'
+import type { UniPopupInstance } from '@uni-helper/uni-ui-types'
+
+const props = withDefaults(defineProps<{
+  modelValue: string | number
+  placeholder?: string
+  suffix?: string
+}>(), {
+  placeholder: '请输入内容',
+})
+
+const emits = defineEmits<{
+  'update:modelValue': [string | number]
+}>()
+
+const uniPopupRef = ref<UniPopupInstance | null>(null)
+const uniPopupDialogRef = ref<UniPopupDialogInstance | null>(null)
+
+function dialogInputConfirm(value: any) {
+  if (value === '') {
+    uni.showToast({
+      title: props.placeholder,
+      icon: 'none',
+    })
+    return
+  }
+  emits('update:modelValue', value as (string | number))
+  if (uniPopupRef.value && uniPopupRef.value.close) {
+    uniPopupRef.value.close()
+  }
+}
+
+function handleClick() {
+  if (uniPopupRef.value && uniPopupRef.value.open) {
+    uniPopupRef.value.open()
+  }
+}
+</script>
+
+<template>
+  <view class="w-full" @click="handleClick">
+    {{ modelValue }}
+    <text v-if="suffix">
+      {{ suffix }}
+    </text>
+  </view>
+  <uni-popup ref="uniPopupRef" type="dialog">
+    <uni-popup-dialog
+      ref="uniPopupDialogRef" mode="input" title="输入内容" :value="modelValue" :placeholder="placeholder"
+      @confirm="dialogInputConfirm"
+    />
+  </uni-popup>
+</template>
+
+<style scoped>
+
+</style>

+ 20 - 1
src/components/TabBar.vue

@@ -35,10 +35,29 @@ function getCurrentPageUrl() {
 const selectedIndex = computed(() => {
   return tabList.value.findIndex(item => item.url === getCurrentPageUrl())
 })
+
+const height = ref<number>(0)
+
+const instance = getCurrentInstance()
+
+if (instance) {
+  const query = uni.createSelectorQuery().in(instance.proxy)
+  query.select('#tabBar').boundingClientRect((data) => {
+    if (data && !(Array.isArray(data))) {
+      height.value = data.height as number
+    }
+  }).exec()
+}
 </script>
 
 <template>
-  <view class="w-full p-1 fixed bottom-0 left-0 safe-area  border-t-[0.5px] border-[#E7E7E7] bg-[#fff]">
+  <view
+    class="w-full"
+    :style="{
+      height: `${height}px`,
+    }" t
+  />
+  <view id="tabBar" class="w-full p-1 fixed bottom-0 left-0 safe-area  border-t-[0.5px] border-[#E7E7E7] bg-[#fff]">
     <view class="w-full flex gap-2">
       <view v-for="(item, index) in tabList" :key="index" class="flex flex-col items-center justify-center w-1/4" @tap="handleTap(item)">
         <image :src="selectedIndex === index ? item.iconSelect : item.icon" class="w-8 h-8" />

+ 15 - 1
src/main.ts

@@ -1,14 +1,28 @@
 import { createPinia } from 'pinia'
+import { createPersistedState } from 'pinia-plugin-persistedstate'
 import { createSSRApp } from 'vue'
 import App from './App.vue'
 import './styles/tailwind.css'
 
 export function createApp() {
-  const pinia = createPinia()
   const app = createSSRApp(App)
+  const pinia = createPinia()
+  pinia.use(customStorage())
   app.use(pinia)
   return {
     app,
     pinia,
   }
 }
+function customStorage() {
+  return createPersistedState({
+    storage: {
+      getItem(key) {
+        return uni.getStorageSync(key)
+      },
+      setItem(key, value) {
+        uni.setStorageSync(key, value)
+      },
+    },
+  })
+}

+ 3 - 0
src/model/pet-manual.ts

@@ -1,4 +1,5 @@
 import type { Paging } from '@/model/base'
+import type { CreatePetRequest } from '@/model/pet'
 
 export interface CreateCarousalsRequest {
   imageUrl: string
@@ -35,6 +36,8 @@ export interface Recommends {
 }
 export interface PetCard {
   image?: string
+  key?: keyof CreatePetRequest
+  value?: any
   name: string
 }
 export interface StepInfo {

+ 47 - 3
src/model/pet.ts

@@ -1,8 +1,8 @@
-import type { TraceableModel } from '@/model/base'
+import type { BaseModel, TraceableModel } from '@/model/base'
 
 export interface Pet extends TraceableModel {
   birthday: string
-  bodyType: string
+  bodyType: PetBodyType
   gender: number
   isActive: boolean
   isLactation: boolean
@@ -10,10 +10,54 @@ export interface Pet extends TraceableModel {
   isSterilization: boolean
   name: string
   photo: string
-  type: string
+  type: PetType
   weight: number
 }
 
 export interface CreatePetRequest extends Omit<Pet, keyof TraceableModel> {
 
 }
+
+export enum PetType {
+  CAT = 'cat',
+  DOG = 'dog',
+}
+
+export enum PetBodyType {
+  // 极度消瘦
+  EXTREMELY_THIN = 'extremely-thin',
+  // 非常瘦
+  VERY_THIN = 'very-thin',
+  // 消瘦
+  THIN = 'thin',
+  // 偏轻
+  UNDERWEIGHT = 'underweight',
+  // 理想体重
+  IDEAL = 'ideal',
+  // 偏重
+  OVERWEIGHT = 'overweight',
+  // 肥胖
+  OBESE = 'obese',
+  // 极度肥胖
+  EXTREMELY_OBESE = 'extremely-obese',
+}
+
+export enum Gender {
+  MALE,
+  FEMALE,
+  UNKNOWN,
+}
+
+export enum FeedingGoal {
+  GAIN = 'gain',
+  LOSE = 'lose',
+  MAINTAIN = 'maintain',
+}
+
+export interface FeedingPlan extends BaseModel {
+  feedingGoal: FeedingGoal
+  targetWeight: number
+}
+
+export interface CreateFeedingPlanRequest extends Omit<FeedingPlan, keyof BaseModel> {
+}

+ 5 - 0
src/model/user.ts

@@ -4,6 +4,11 @@ export interface User extends TraceableModel {
   username: string
   locked: boolean
   enabled: boolean
+  age: number
+  avatar: null | string
+  address: null | string
+  occupation: null | string
+  trueName: null | string
 }
 
 export interface UserSearchFilter extends BaseFilterRequest {

+ 6 - 4
src/pages.json

@@ -45,7 +45,9 @@
     {
       "path": "pages/setting/index",
       "type": "page",
-      "style": {}
+      "style": {
+        "navigationBarTitleText": "设置"
+      }
     },
     {
       "path": "pages/start-filing/index",
@@ -60,17 +62,17 @@
       "style": {}
     },
     {
-      "path": "pages/feed-calculator/components/FeedFlogan",
+      "path": "pages/feed-calculator/components/FeedForm",
       "type": "page",
       "style": {}
     },
     {
-      "path": "pages/feed-calculator/components/FeedForm",
+      "path": "pages/feed-calculator/components/FeedQuestionnaire",
       "type": "page",
       "style": {}
     },
     {
-      "path": "pages/feed-calculator/components/FeedQuestionnaire",
+      "path": "pages/feed-calculator/components/FeedSlogan",
       "type": "page",
       "style": {}
     },

+ 19 - 34
src/pages/feed-calculator/components/FeedQuestionnaire.vue

@@ -1,10 +1,9 @@
 <script setup lang="ts">
 import type { FeedFormQuestions, PetCard, StepInfo, UserList } from '@/model/pet-manual'
-import FeedSlogan from '@/pages/feed-calculator/components/FeedFlogan.vue'
 import FeedForm from '@/pages/feed-calculator/components/FeedForm.vue'
+import FeedSlogan from '@/pages/feed-calculator/components/FeedSlogan.vue'
 import ProgressBar from '@/pages/feed-calculator/components/ProgressBar.vue'
-import avator from '@/static/image/pet-parameters/avator.png'
-import right from '@/static/image/pet-parameters/right.png'
+import avator from '@/static/image/pet-parameters/avatar.png'
 
 const props = defineProps<{
   list: FeedFormQuestions[]
@@ -51,18 +50,21 @@ function handlePrevious() {
     emits('back')
   }
 }
+
+const feedingPlanStore = useFeedingPlanStore()
+
 function handleAnswer(answer: PetCard) {
-  console.log(answer, '答案')
+  if (answer.key) {
+    feedingPlanStore.setPetValue(answer.key, answer.value)
+  }
   if (step.value === 2 || step.value === 7) {
     emits('step', step.value)
   }
   if (step.value === props.list.length - 1) {
-    console.log(123)
     isUserPage.value = true
   }
   if (step.value < props.list.length - 1 + addPage.value) {
     step.value += 1
-    console.log(step.value, 'step')
   }
 }
 </script>
@@ -77,41 +79,24 @@ function handleAnswer(answer: PetCard) {
         <image :src="avator" class="w-[64px] h-[64px] rounded-full" />
         <view class="mt-[5px] ">
           <text class="font-bold text-[16px] ">
-            {{ props.userList.username }}
+            {{ feedingPlanStore.pet.name }}
           </text>
           <view class="mt-[8px] flex gap-2">
-            <view v-for="(item, index) in props.userList.type" :key="index" class="text-[12px] text-[#999] bg-[#F3F3F3] rounded-[3px] py-[2px] px-[8px]">
-              {{ item }}
+            <view v-for="item in feedingPlanStore.petTags" :key="item.key" class="text-[12px] text-[#999] bg-[#F3F3F3] rounded-[3px] py-[2px] px-[8px]">
+              {{ item.value }}
             </view>
           </view>
         </view>
       </view>
     </view>
-    <view class="w-[calc(100% - 32px)] mx-[16px] h-[56px] bg-[white] rounded-t-3 mt-4 flex items-center card_border_bottom p-4 justify-between">
-      <view class="whitespace-nowrap">
-        喂养目标
-      </view>
-
-      <view class="flex justify-center items-center">
-        <picker :value="aimIndex" :range="aimList" @change="handleAimChange($event, 'aim')">
-          <view class="uni-input">
-            {{ aimList[aimIndex] }}
-          </view>
-        </picker>
-        <image :src="right" class="w-[24px] h-[24px]" />
-      </view>
-    </view>
-    <view class="w-[calc(100% - 32px)] mx-[16px] h-[56px] bg-[white] rounded-b-3 flex items-center p-4 justify-between">
-      <view>目标体重</view>
-      <view class="flex justify-center items-center">
-        <picker :value="weightIndex" :range="weightList" @change="handleAimChange($event, 'weight')">
-          <view class="uni-input">
-            {{ weightList[weightIndex] }}
-          </view>
-        </picker>
-        <image :src="right" class="w-[24px] h-[24px]" />
-      </view>
-    </view>
+    <CellGroup>
+      <Cell title="喂养目标" border>
+        <PickerItem v-model="feedingPlanStore.feedingPlan.feedingGoal" :options="feedingPlanStore.feedingGoalOptions" />
+      </Cell>
+      <Cell title="目标体重">
+        <PopupInput v-model="feedingPlanStore.feedingPlan.targetWeight" placeholder="请输入目标体重" />
+      </Cell>
+    </CellGroup>
     <view class="flex items-center justify-center">
       <button class="w-[176px] h-[47px] flex items-center justify-center bg-[#4545E5] border-none text-[white] rounded-3xl mt-[210px]">
         下一步

+ 0 - 0
src/pages/feed-calculator/components/FeedFlogan.vue → src/pages/feed-calculator/components/FeedSlogan.vue


+ 0 - 1
src/pages/feed-calculator/components/FeedStart.vue

@@ -1,6 +1,5 @@
 <script setup lang="ts">
 import type { StepInfo } from '@/model/pet-manual'
-import FeedFlogan from '@/pages/feed-calculator/components/FeedFlogan.vue'
 import FeedStep from '@/pages/feed-calculator/components/FeedStep.vue'
 import feedTitle from '@/static/image/feed-plan/feed-title.png'
 

+ 18 - 23
src/pages/feed-calculator/index.vue

@@ -1,17 +1,18 @@
 <script setup lang="ts">
 import type { FeedFormQuestions, UserList } from '@/model/pet-manual'
+import { PetBodyType } from '@/model/pet'
 import FeedQuestionnaire from '@/pages/feed-calculator/components/FeedQuestionnaire.vue'
 import FeedStart from '@/pages/feed-calculator/components/FeedStart.vue'
 import FeedStep from '@/pages/feed-calculator/components/FeedStep.vue'
-import avator from '@/static/image/pet-parameters/avator.png'
-import cat from '@/static/image/pet-parameters/cat.png'
-import dog from '@/static/image/pet-parameters/dog.png'
-import emaciatedCat from '@/static/image/pet-parameters/form/emaciated_cat.png'
-import idealWightCat from '@/static/image/pet-parameters/form/idealweight_cat.png'
-import overWeightCat from '@/static/image/pet-parameters/form/overweight_cat.png'
-import skinnyCat from '@/static/image/pet-parameters/form/skinny_cat.png'
-import thinCat from '@/static/image/pet-parameters/form/thin_cat.png'
-import underWeightCat from '@/static/image/pet-parameters/form/underweight_cat.png'
+import extremelyObese from '@/static/image/body-type/extremely-obese.svg'
+import extremelyThin from '@/static/image/body-type/extremely-thin.svg'
+import ideal from '@/static/image/body-type/ideal.svg'
+import obese from '@/static/image/body-type/obese.svg'
+import overWeight from '@/static/image/body-type/overweight.svg'
+import thin from '@/static/image/body-type/thin.svg'
+import underWeight from '@/static/image/body-type/underweight.svg'
+import veryThin from '@/static/image/body-type/very-thin.svg'
+import avatar from '@/static/image/pet-parameters/avatar.png'
 import ToolApi from '@/utils'
 
 interface StepInfo {
@@ -22,27 +23,21 @@ const titleName = ref<string>('喂养计算器')
 const safeHeight = ToolApi.getSafeHeight()
 const stage = ref<number>(0)
 const stepInfo = ref<StepInfo[]>([
-  { step: 1, title: '宠物基础信息' },
-  { step: 2, title: '身体状态信息' },
-  { step: 3, title: '计算喂养计划' },
+  { step: 1, title: '身体状态信息' },
+  { step: 2, title: '计算喂养计划' },
+  { step: 3, title: '完成统计' },
 ])
 const controlFormDisplay = ref({
   display1: true,
   display2: false,
   display3: false,
 })
-const feedFormQuestions = ref<FeedFormQuestions[]>([
-  { title: '您的动物是?', question: [{ image: cat, name: '猫猫' }, { image: dog, name: '狗狗' }], formType: 1 },
-  { title: '猫咪的性别?', question: [{ name: '男孩' }, { name: '女孩' }], formType: 2 },
-  { title: '猫咪的年龄区间?', question: [{ name: '0-4个月' }, { name: '5-12个月' }], formType: 2 },
-  { title: '猫咪是否活跃?', question: [{ name: '活跃' }, { name: '不活跃' }], formType: 2 },
-  { title: '猫咪是否怀孕?', question: [{ name: '怀孕' }, { name: '未怀孕' }], formType: 2 },
-  { title: '猫咪是否绝育?', question: [{ name: '绝育' }, { name: '未绝育' }], formType: 2 },
-  { title: '猫咪是否在哺乳?', question: [{ name: '哺乳中' }, { name: '未哺乳' }], formType: 2 },
-  { title: '请选择猫咪的体型', question: [{ image: emaciatedCat, name: '极度消廋' }, { image: skinnyCat, name: '非常廋' }, { image: thinCat, name: '消瘦' }, { image: underWeightCat, name: '体重偏低' }, { image: idealWightCat, name: '理想体重' }, { image: overWeightCat, name: '体重偏重' }], formType: 3 },
-])
+const feedFormQuestions = ref<FeedFormQuestions[]>(
+  [{ title: '猫咪是否活跃?', question: [{ name: '活跃', key: 'isActive', value: true }, { name: '不活跃', key: 'isActive', value: false }], formType: 2 }, { title: '猫咪是否怀孕?', question: [{ name: '怀孕', key: 'isPregnant', value: true }, { name: '未怀孕', key: 'isPregnant', value: false }], formType: 2 }, { title: '猫咪是否绝育?', question: [{ name: '绝育', key: 'isSterilization', value: true }, { name: '未绝育', key: 'isSterilization', value: false }], formType: 2 }, { title: '猫咪是否在哺乳?', question: [{ name: '哺乳中', key: 'isLactation', value: true }, { name: '未哺乳', key: 'isLactation', value: false }], formType: 2 }, { title: '请选择猫咪的体型', question:
+          [{ image: extremelyThin, name: '极度消廋', key: 'bodyType', value: PetBodyType.EXTREMELY_THIN }, { image: veryThin, name: '非常廋', key: 'bodyType', value: PetBodyType.VERY_THIN }, { image: thin, name: '消瘦', key: 'bodyType', value: PetBodyType.THIN }, { image: underWeight, name: '体重偏低', key: 'bodyType', value: PetBodyType.UNDERWEIGHT }, { image: ideal, name: '理想体重', key: 'bodyType', value: PetBodyType.IDEAL }, { image: overWeight, name: '体重偏重', key: 'bodyType', value: PetBodyType.OVERWEIGHT }, { image: obese, name: '肥胖', key: 'bodyType', value: PetBodyType.OBESE }, { image: extremelyObese, name: '极度肥胖', key: 'bodyType', value: PetBodyType.EXTREMELY_OBESE }], formType: 3 }],
+)
 const userList = ref<UserList>({
-  image: avator,
+  image: avatar,
   username: '子龙',
   type: ['年龄', '品种', '体重'],
 })

+ 1 - 1
src/pages/feed-plan/index.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { Pet } from '@/model/pet'
 import { getOwnPets } from '@/api/pet'
-import avatar from '@/static/image/pet-parameters/avator.png'
+import avatar from '@/static/image/pet-parameters/avatar.png'
 import addBtn from '@/static/image/pet-plan/add_btn.png'
 import card from '@/static/image/pet-plan/card.png'
 import editBtn from '@/static/image/pet-plan/edit.png'

+ 34 - 18
src/pages/me/index.vue

@@ -4,10 +4,9 @@ import avatar from '@/static/image/me/avatar.png'
 import consult from '@/static/image/me/consult.png'
 import coupon from '@/static/image/me/coupon.png'
 import memberShop from '@/static/image/me/memberShop.png'
-import ToolApi from '@/utils'
 
-const safeHeight = ToolApi.getSafeHeight()
-const titleName = ref<string>('我的')
+const appStore = useAppStore()
+
 const userInfo = ref<UserInfo>({
   age: 0,
   avatar,
@@ -36,10 +35,24 @@ const userModules = ref<UserModule>({
     path: '',
   },
 })
+
+onShow(appStore.fetchCurrentUser)
+
+function goToSetting() {
+  uni.navigateTo({
+    url: '/pages/setting/index',
+  })
+}
+
+function goUserInfo() {
+  uni.navigateTo({
+    url: '/pages/userInfo/index',
+  })
+}
 </script>
 
 <template>
-  <view class="w-full bg-[#F5F6F7]" :style="`height:calc(100vh - ${safeHeight}px)`">
+  <view class="w-full bg-[#F5F6F7] h-screen">
     <view class="me-container p-4 w-full">
       <view class="me-card bg-[#FFFFFF] h-[229px] flex flex-col justify-center items-center w-full rounded-xl">
         <view class="me-card-info flex flex-1 w-full border-b-1 border-[#E7E7E7] p-4 justify-between items-center">
@@ -48,16 +61,21 @@ const userModules = ref<UserModule>({
               <image :src="userInfo.avatar" alt="avatar" class="w-[64px] h-[64px] rounded-full" />
             </view>
             <view class="me-card-info-login-person flex flex-col justify-between h-[54px]">
-              <text class="text-[16px] font-bold ">
-                {{ userInfo.nickName }}
+              <text class="text-[16px] font-bold line-clamp-1">
+                <template v-if="appStore.user">
+                  {{ appStore.user.username }}
+                </template>
+                <span v-else @click="() => appStore.login()">
+                  请登录
+                </span>
               </text>
               <view class="h-[fit-content] text-[#999999] ">
-                <uni-tag :text="`${userInfo.isLogin ? (`${userInfo.age}岁`) : '年龄'}`" class="mr-2" />
-                <uni-tag :text="userInfo.memberType" />
+                <uni-tag :text="`${appStore.age ? (`${appStore.age}岁`) : '年龄'}`" class="mr-2" />
+                <uni-tag :text="appStore.memberType" />
               </view>
             </view>
           </view>
-          <view class="me-card-info-edit w-[20px] h-[20px]">
+          <view class="me-card-info-edit w-[20px] h-[20px] shrink-0" @tap="goUserInfo">
             <image src="@/static/image/me/edit.png" alt="edit" class="w-full h-full" />
           </view>
         </view>
@@ -66,7 +84,7 @@ const userModules = ref<UserModule>({
             v-for="item in userModules" :key="item.id"
             class="flex justify-between items-center flex-col me-card-item-module"
           >
-            <image :src="item.imgUrl" :alt="item.name" class="w-[48px] h-[48px]" />
+            <image :src="item.imgUrl" :alt="item.name" class="w-[48px] h-[48px] shrink-0" />
             <text class="text-[12px] text-[#000000]">
               {{ item.name }}
             </text>
@@ -74,14 +92,12 @@ const userModules = ref<UserModule>({
         </view>
       </view>
     </view>
-    <uni-card spacing="0" padding="0" :border="false">
-      <view class="uni-body">
-        <uni-list :border="false">
-          <uni-list-item title="关于我们" show-arrow class="border-b-1 border-[#E7E7E7]" />
-          <uni-list-item title="设置" show-arrow />
-        </uni-list>
-      </view>
-    </uni-card>
+    <view class="px-4">
+      <CellGroup>
+        <Cell title="关于我们" border />
+        <Cell title="设置" @tap="goToSetting" />
+      </CellGroup>
+    </view>
   </view>
 </template>
 

+ 13 - 17
src/pages/setting/index.vue

@@ -1,25 +1,21 @@
 <script setup lang="ts">
-import ToolFun from '@/utils'
 
-const titleName = ref<string>('设置')
-const safeHeight = ToolFun.getSafeHeight()
 </script>
 
 <template>
-  <TitleBar :title-name="titleName" />
-  <view class="flex flex-col bg-[#F5F6F7] overflow-y-auto" :style="`height:calc(100vh - ${safeHeight}px)`">
-    <uni-card>
-      <uni-list class="text-[16px] font-normal" :border="false">
-        <uni-list-item title="通用设置" />
-        <uni-list-item title="通知设置" />
-      </uni-list>
-    </uni-card>
-    <uni-card>
-      <uni-list class="mt-6 text-[16px] font-normal" :border="false">
-        <uni-list-item title="账号安全" />
-        <uni-list-item title="隐私" />
-      </uni-list>
-    </uni-card>
+  <view class="flex flex-col bg-[#F5F6F7] overflow-y-auto h-screen gap-4 pt-4">
+    <view class="px-4">
+      <CellGroup>
+        <Cell title="通用设置" border />
+        <Cell title="通知设置" />
+      </CellGroup>
+    </view>
+    <view class="px-4">
+      <CellGroup>
+        <Cell title="账号安全" border />
+        <Cell title="隐私" />
+      </CellGroup>
+    </view>
   </view>
 </template>
 

+ 28 - 33
src/pages/start-filing/index.vue

@@ -1,30 +1,18 @@
 <script setup lang="ts">
-import FeedFlogan from '@/pages/feed-calculator/components/FeedFlogan.vue'
-import right from '@/static/image/pet-parameters/right.png'
+import PickerItem from '@/components/PickerItem.vue'
+import FeedSlogan from '@/pages/feed-calculator/components/FeedSlogan.vue'
 import edit from '@/static/image/start-filing/edit.png'
+import { useFeedingPlanStore } from '@/stores/feeding-plan'
 import ToolApi from '@/utils'
 
-interface RecordList {
-  title: string
-  options: string[]
-  aimIndex: number
-}
-
 const safeHeight = ToolApi.getSafeHeight()
-const recordList = ref<RecordList[]>([
-  { title: '宠物名字', options: ['子龙'], aimIndex: 0 },
-  { title: '品种', options: ['好猫'], aimIndex: 0 },
-  { title: '性别', options: ['男孩'], aimIndex: 0 },
-  { title: '出生日期', options: ['2月2日'], aimIndex: 0 },
-  { title: '体重', options: ['2kg'], aimIndex: 0 },
-])
-const feedFloganBottom = ref<number>(13)
-function handleAimChange(e: CustomEvent, index: number) {
-  recordList.value[index].aimIndex = e.detail.value
-}
+
+const feedSloganBottom = ref<number>(13)
 function handleNext() {
   uni.navigateTo({ url: '/pages/feed-calculator/index' })
 }
+
+const { pet, petTypeOptions, genderOptions } = useFeedingPlanStore()
 </script>
 
 <template>
@@ -34,19 +22,26 @@ function handleNext() {
         <image :src="edit" class="w-[10px] h-[10px]" />
       </view>
     </view>
-    <view v-for="(item, index) in recordList" :key="index" :style="{ marginTop: index === 0 ? '28px' : index === 1 ? '16px' : '', borderRadius: index === 0 ? '12px' : index === 1 ? '12px 12px 0 0' : index === recordList.length - 1 ? '0 0 12px 12px' : '0px' }" class="w-[calc(100% - 32px)] mx-[16px] h-[56px] bg-[white] flex items-center card_border_bottom p-4 justify-between">
-      <view class="whitespace-nowrap">
-        {{ item.title }}
-      </view>
-
-      <view class="flex justify-center items-center">
-        <picker :value="item.aimIndex" :range="item.options" @change="handleAimChange($event, index)">
-          <view class="uni-input">
-            {{ item.options[item.aimIndex] }}
-          </view>
-        </picker>
-        <image :src="right" class="w-[24px] h-[24px]" />
-      </view>
+    <view class="w-full px-4 flex flex-col gap-4 mt-[28px]">
+      <CellGroup class="w-full bg-[#fff] shadow-cell-group rounded-3 overflow-hidden">
+        <Cell title="宠物名称">
+          <PopupInput v-model="pet.name" placeholder="请输入宠物名称" />
+        </Cell>
+      </CellGroup>
+      <CellGroup class="w-full bg-[#fff] shadow-cell-group rounded-3 overflow-hidden">
+        <Cell title="品种" border>
+          <PickerItem v-model="pet.type" :options="petTypeOptions" />
+        </Cell>
+        <Cell title="性别" border>
+          <PickerItem v-model="pet.gender" :options="genderOptions" />
+        </Cell>
+        <Cell title="出生日期" border>
+          <PickerDate v-model="pet.birthday" />
+        </Cell>
+        <Cell title="体重">
+          <PopupInput v-model="pet.weight" placeholder="请输入宠物体重" suffix="kg" />
+        </Cell>
+      </CellGroup>
     </view>
 
     <view class="flex items-center justify-center">
@@ -54,7 +49,7 @@ function handleNext() {
         下一题
       </button>
     </view>
-    <FeedFlogan :bottom="feedFloganBottom" />
+    <FeedSlogan :bottom="feedSloganBottom" />
   </view>
 </template>
 

+ 2 - 22
src/pages/userInfo/index.vue

@@ -2,15 +2,10 @@
 import avatar from '@/static/image/user-info/avatar.png'
 import component from '@/static/image/user-info/Component.png'
 import union from '@/static/image/user-info/union.png'
-import ToolFun from '@/utils'
-
-const titleName = ref<string>('个人信息')
-const safeHeight = ToolFun.getSafeHeight()
 </script>
 
 <template>
-  <TitleBar :title-name="titleName" />
-  <view class="flex flex-col bg-[#F5F6F7] overflow-y-auto" :style="`height:calc(100vh - ${safeHeight}px)`">
+  <view class="flex flex-col bg-[#F5F6F7] overflow-y-auto h-screen">
     <view class="flex justify-center items-center  p-[61px] w-full pb-[30px] ">
       <view class="relative h-[80px] w-[80px]">
         <image
@@ -49,20 +44,5 @@ const safeHeight = ToolFun.getSafeHeight()
 </template>
 
 <style  lang="scss" scoped>
-        :deep .uni-list-item{
-        height: 56px !important;
-      }
-      :deep .uni-list-item__content-title {
-        color: var(--text-icon-font-gy-190, rgba(0, 0, 0, 0.90)) !important;
-      font-size: 16px !important;
-      font-family: "PingFang SC" !important;
-      font-style: normal !important;
-      font-weight: 400 !important;
-     }
-     :deep .uni-list-item__extra-text{
-      color: var(--text-icon-font-gy-190, rgba(0, 0, 0, 0.90)) !important;
-      font-size: 16px !important;
-      font-style: normal !important;
-      font-weight: 400 !important;
-     }
+
 </style>

+ 3 - 0
src/static/icons/right.svg

@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+    <path fill-rule="evenodd" clip-rule="evenodd" d="M9.6907 18.6889L8.31184 17.31L13.6224 11.9994L8.31184 6.68887L9.6907 5.31001L16.3801 11.9994L9.6907 18.6889Z" fill="black" fill-opacity="0.4"/>
+</svg>

Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 0
src/static/image/body-type/extremely-obese.svg


Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 0
src/static/image/body-type/extremely-thin.svg


Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 0
src/static/image/body-type/ideal.svg


Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 0
src/static/image/body-type/obese.svg


Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 0
src/static/image/body-type/overweight.svg


Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 0
src/static/image/body-type/thin.svg


Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 0
src/static/image/body-type/underweight.svg


Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 0
src/static/image/body-type/very-thin.svg


+ 0 - 0
src/static/image/pet-parameters/avator.png → src/static/image/pet-parameters/avatar.png


+ 23 - 1
src/stores/app.ts

@@ -1,4 +1,6 @@
+import type { User } from '@/model/user'
 import { createToken } from '@/api/token'
+import { getCurrentUser } from '@/api/user'
 import { defineStore } from 'pinia'
 import { computed, ref } from 'vue'
 
@@ -6,7 +8,10 @@ export const useAppStore = defineStore(
   'app',
   () => {
     const token = ref('')
-
+    const user = ref<User | null>(null)
+    const fetchCurrentUser = async () => {
+      user.value = await getCurrentUser()
+    }
     const login = () => {
       uni.showLoading({ title: '登录中' })
       return new Promise<void>((resolve, reject) => {
@@ -15,6 +20,7 @@ export const useAppStore = defineStore(
           success: async (result) => {
             const data = await createToken(result.code)
             token.value = data.token
+            await fetchCurrentUser()
             uni.hideLoading()
             resolve()
           },
@@ -30,10 +36,26 @@ export const useAppStore = defineStore(
       return !!token.value
     })
 
+    const memberType = '会员'
+
+    const age = computed(() => {
+      if (!user.value) {
+        return 0
+      }
+      return user.value.age
+    })
+
     return {
       token,
       isLogin,
       login,
+      fetchCurrentUser,
+      user,
+      memberType,
+      age,
     }
   },
+  {
+    persist: true,
+  },
 )

+ 69 - 0
src/stores/feeding-plan.ts

@@ -0,0 +1,69 @@
+import {
+  type CreateFeedingPlanRequest,
+  type CreatePetRequest,
+  FeedingGoal,
+  Gender,
+  PetBodyType,
+  PetType,
+} from '@/model/pet'
+import { defineStore } from 'pinia'
+
+export const useFeedingPlanStore = defineStore('feeding-plan', () => {
+  const petTypeOptions = [
+    { value: PetType.CAT, label: '猫猫' },
+    { value: PetType.DOG, label: '狗狗' },
+  ]
+
+  const genderOptions = [
+    { value: Gender.MALE, label: '男孩' },
+    { value: Gender.FEMALE, label: '女孩' },
+  ]
+
+  const pet = ref <CreatePetRequest>({
+    birthday: new Date().toISOString().split('T')[0],
+    bodyType: PetBodyType.IDEAL,
+    gender: Gender.MALE,
+    isActive: false,
+    isLactation: false,
+    isPregnant: false,
+    isSterilization: false,
+    name: '子龙',
+    photo: '',
+    type: PetType.CAT,
+    weight: 0,
+  })
+
+  const petTags = computed(() => {
+    return [
+      { key: 'age', value: `${new Date().getFullYear() - new Date(pet.value.birthday).getFullYear()}岁` },
+      { key: 'type', value: pet.value.type === PetType.CAT ? '猫猫' : '狗狗' },
+      { key: 'weight', value: `${pet.value.weight}kg` },
+    ]
+  })
+
+  const feedingPlan = ref<CreateFeedingPlanRequest>({
+    feedingGoal: FeedingGoal.LOSE,
+    targetWeight: pet.value.weight - 1,
+  })
+
+  const feedingGoalOptions = [
+    { value: FeedingGoal.GAIN, label: '增肥' },
+    { value: FeedingGoal.LOSE, label: '减重' },
+    { value: FeedingGoal.MAINTAIN, label: '保持' },
+  ]
+
+  const setPetValue = (key: keyof CreatePetRequest, value: any) => {
+    // @ts-expect-error @ts-ignore
+    pet.value[key] = (value as CreatePetRequest[keyof CreatePetRequest])
+  }
+
+  return {
+    pet,
+    petTypeOptions,
+    genderOptions,
+    setPetValue,
+    petTags,
+    feedingPlan,
+    feedingGoalOptions,
+  }
+})

+ 1 - 1
src/uni-pages.d.ts

@@ -12,9 +12,9 @@ interface NavigateToOptions {
        "/pages/setting/index" |
        "/pages/start-filing/index" |
        "/pages/userInfo/index" |
-       "/pages/feed-calculator/components/FeedFlogan" |
        "/pages/feed-calculator/components/FeedForm" |
        "/pages/feed-calculator/components/FeedQuestionnaire" |
+       "/pages/feed-calculator/components/FeedSlogan" |
        "/pages/feed-calculator/components/FeedStart" |
        "/pages/feed-calculator/components/FeedStep" |
        "/pages/feed-calculator/components/ProgressBar" |

+ 3 - 0
tailwind.config.ts

@@ -17,6 +17,9 @@ const theme: Config['theme'] = {
     primary: '#4545E5',
     default: '#828282',
   },
+  boxShadow: {
+    'cell-group': '0px 4px 12px 0px rgba(0, 0, 0, 0.10)',
+  },
 }
 if (isMp || isQuickapp)
   theme.screens = {}

+ 3 - 1
tsconfig.json

@@ -10,7 +10,9 @@
       "@dcloudio/types",
       "@mini-types/alipay",
       "miniprogram-api-typings",
-      "@uni-helper/uni-types"
+      "@uni-helper/uni-types",
+      "@uni-helper/uni-app-types",
+      "@uni-helper/uni-ui-types"
     ],
     "sourceMap": true
   },

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff