feat:增加运动健康模块
This commit is contained in:
@@ -1,49 +0,0 @@
|
|||||||
import { cloudService } from './index'
|
|
||||||
import { IBudgetInfo } from '@/types/budget'
|
|
||||||
|
|
||||||
export const addBudgetApi = (budget: IBudgetInfo): Promise<any> =>
|
|
||||||
cloudService({
|
|
||||||
url: '/home-api/budget',
|
|
||||||
method: 'post',
|
|
||||||
data: budget
|
|
||||||
})
|
|
||||||
|
|
||||||
export const updateBudgetApi = (id: number, budget: IBudgetInfo): Promise<any> =>
|
|
||||||
cloudService({
|
|
||||||
url: `/home-api/budget/${id}`,
|
|
||||||
method: 'put',
|
|
||||||
data: budget
|
|
||||||
})
|
|
||||||
|
|
||||||
export const deleteBudgetApi = (id: number): Promise<any> =>
|
|
||||||
cloudService({
|
|
||||||
url: `/home-api/budget/${id}`,
|
|
||||||
method: 'DELETE'
|
|
||||||
})
|
|
||||||
|
|
||||||
export const queryBudgetApi = (category: string): Promise<any> =>
|
|
||||||
cloudService({
|
|
||||||
url: '/home-api/budget',
|
|
||||||
method: 'get',
|
|
||||||
params: { category }
|
|
||||||
})
|
|
||||||
|
|
||||||
export const queryBudgetCategory = (): Promise<any> =>
|
|
||||||
cloudService({
|
|
||||||
url: '/home-api/budget/category',
|
|
||||||
method: 'get'
|
|
||||||
})
|
|
||||||
|
|
||||||
export const queryBudgetRankStats = (category: string): Promise<any> =>
|
|
||||||
cloudService({
|
|
||||||
url: '/home-api/budget/stats/rank',
|
|
||||||
method: 'get',
|
|
||||||
params: { category }
|
|
||||||
})
|
|
||||||
|
|
||||||
export const queryBudgetProjectStats = (category: string): Promise<any> =>
|
|
||||||
cloudService({
|
|
||||||
url: '/home-api/budget/stats/project',
|
|
||||||
method: 'get',
|
|
||||||
params: { category }
|
|
||||||
})
|
|
||||||
29
src/apis/exercise.ts
Normal file
29
src/apis/exercise.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { cloudService } from './index'
|
||||||
|
import { IExercise } from '@/types/health'
|
||||||
|
|
||||||
|
export const addExerciseApi = (exercise: IExercise): Promise<boolean> =>
|
||||||
|
cloudService({
|
||||||
|
url: '/home-api/exercise',
|
||||||
|
method: 'post',
|
||||||
|
data: exercise
|
||||||
|
})
|
||||||
|
|
||||||
|
export const updateExerciseApi = (id: number, exercise: IExercise): Promise<boolean> =>
|
||||||
|
cloudService({
|
||||||
|
url: `/home-api/exercise/${id}`,
|
||||||
|
method: 'put',
|
||||||
|
data: exercise
|
||||||
|
})
|
||||||
|
|
||||||
|
export const deleteExerciseApi = (id: number): Promise<boolean> =>
|
||||||
|
cloudService({
|
||||||
|
url: `/home-api/exercise/${id}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
|
||||||
|
export const queryExerciseApi = (query: IExerciseQuery): Promise<IExercise[]> =>
|
||||||
|
cloudService({
|
||||||
|
url: '/home-api/exercise',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { cloudService } from './index'
|
import { cloudService } from './index'
|
||||||
import { IPassword, IQueryPassword } from '@/types/password'
|
import { IPassword, IPasswordQuery } from '@/types/password'
|
||||||
|
|
||||||
export const addPasswordApi = (password: IPassword): Promise<boolean> =>
|
export const addPasswordApi = (password: IPassword): Promise<boolean> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
@@ -21,7 +21,7 @@ export const deletePasswordApi = (id: number): Promise<boolean> =>
|
|||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
|
|
||||||
export const queryPasswordApi = (query: IQueryPassword): Promise<IPassword[]> =>
|
export const queryPasswordApi = (query: IPasswordQuery): Promise<IPassword[]> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: '/home-api/password',
|
url: '/home-api/password',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { cloudService } from './index'
|
import { cloudService } from './index'
|
||||||
import { IProduct, IQueryProduct } from '@/types/product.ts'
|
import { IProduct, IProductQuery } from '@/types/product.ts'
|
||||||
|
|
||||||
export const addProductApi = (product: IProduct): Promise<boolean> =>
|
export const addProductApi = (product: IProduct): Promise<boolean> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
@@ -27,7 +27,7 @@ export const queryProductApi = (id: number): Promise<IProduct> =>
|
|||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
|
|
||||||
export const queryProductListApi = (query: IQueryProduct): Promise<IProduct[]> =>
|
export const queryProductListApi = (query: IProductQuery): Promise<IProduct[]> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: '/home-api/product',
|
url: '/home-api/product',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
|||||||
29
src/apis/weight.ts
Normal file
29
src/apis/weight.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { cloudService } from './index'
|
||||||
|
import { IWeight } from '@/types/health'
|
||||||
|
|
||||||
|
export const addWeightApi = (weight: IWeight): Promise<boolean> =>
|
||||||
|
cloudService({
|
||||||
|
url: '/home-api/weight',
|
||||||
|
method: 'post',
|
||||||
|
data: weight
|
||||||
|
})
|
||||||
|
|
||||||
|
export const updateWeightApi = (id: number, weight: IWeight): Promise<boolean> =>
|
||||||
|
cloudService({
|
||||||
|
url: `/home-api/weight/${id}`,
|
||||||
|
method: 'put',
|
||||||
|
data: weight
|
||||||
|
})
|
||||||
|
|
||||||
|
export const deleteWeightApi = (id: number): Promise<boolean> =>
|
||||||
|
cloudService({
|
||||||
|
url: `/home-api/weight/${id}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
|
||||||
|
export const queryWeightApi = (query: IWeightQuery): Promise<IWeight[]> =>
|
||||||
|
cloudService({
|
||||||
|
url: '/home-api/weight',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
100
src/components/Health/HealthForm.vue
Normal file
100
src/components/Health/HealthForm.vue
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<el-form :model="healthStore.currentHealth" class="health-form card-item">
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<i class="fa-regular fa-calendar-check"></i>
|
||||||
|
<span>日期</span>
|
||||||
|
</template>
|
||||||
|
<el-date-picker v-model="healthStore.currentHealth.date"
|
||||||
|
type="date" :disabled="true"
|
||||||
|
style="width: 150px;"/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<i class="fa-solid fa-person-running"></i>
|
||||||
|
<span>运动项目</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-select v-model="healthStore.currentHealth.project"
|
||||||
|
placeholder="请选择运行项目" style="width: 150px;">
|
||||||
|
<el-option v-for="(item, index) in projectList" :key="index"
|
||||||
|
:label="item" :value="item"/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<i class="fa-solid fa-clock"></i>
|
||||||
|
<span>运动时长</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-input-number v-model="healthStore.currentHealth.duration"
|
||||||
|
style="width: 120px;"></el-input-number>
|
||||||
|
|
||||||
|
<span style="margin-left: 5px;">分钟</span>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<template #label>
|
||||||
|
<i class="fa-solid fa-weight-scale"></i>
|
||||||
|
<span>体重</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-input-number v-model="healthStore.currentHealth.value"
|
||||||
|
style="width: 120px;"></el-input-number>
|
||||||
|
|
||||||
|
<span style="margin-left: 5px;">千克</span>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item style="align-self: center;">
|
||||||
|
<el-button type="primary" @click="onSubmit"
|
||||||
|
:disabled="isBeforeDate(formatDate(new Date()), healthStore.selectDate)">
|
||||||
|
确认
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useHealthStore } from '@/store/health'
|
||||||
|
import { formatDate, isBeforeDate } from 'vue3-common/utils/dateUtil'
|
||||||
|
|
||||||
|
const healthStore = useHealthStore()
|
||||||
|
|
||||||
|
const projectList = ['羽毛球', '乒乓球', '跑步', '其他']
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
// await periodStore.updatePeriodDay()
|
||||||
|
// periodStore.currentPeriodDay = periodStore.getPeriodDay(periodStore.selectDate)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.health-form {
|
||||||
|
padding: 10px;
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.el-form-item__label {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 20px 1fr;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #DE3163;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item__content {
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
43
src/components/Health/HealthLegend.vue
Normal file
43
src/components/Health/HealthLegend.vue
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<div class="health-legend card-item">
|
||||||
|
<div class="legend-item">
|
||||||
|
<div class="small-circle weight"></div>
|
||||||
|
<span>体重</span>
|
||||||
|
</div>
|
||||||
|
<div class="legend-item">
|
||||||
|
<div class="small-circle exercise"></div>
|
||||||
|
<span>运动</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.health-legend {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
.legend-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
.small-circle {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.weight {
|
||||||
|
background-color: #DC2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exercise {
|
||||||
|
background-color: #16A34A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -43,6 +43,12 @@
|
|||||||
<span>记录</span>
|
<span>记录</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
|
<router-link v-if="path.includes('health')" to="/health/calendar"
|
||||||
|
@click="routerClick()" class="item">
|
||||||
|
<i class="fa-solid fa-calendar-days"></i>
|
||||||
|
<span>记录</span>
|
||||||
|
</router-link>
|
||||||
|
|
||||||
<router-link v-if="path.includes('plan')" to="/plan/calendar"
|
<router-link v-if="path.includes('plan')" to="/plan/calendar"
|
||||||
@click="routerClick()" class="item">
|
@click="routerClick()" class="item">
|
||||||
<i class="fa-solid fa-calendar-days"></i>
|
<i class="fa-solid fa-calendar-days"></i>
|
||||||
|
|||||||
130
src/store/health.ts
Normal file
130
src/store/health.ts
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import type { IHandleApi } from 'vue3-common/types'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import {
|
||||||
|
addExerciseApi,
|
||||||
|
deleteExerciseApi,
|
||||||
|
queryExerciseApi,
|
||||||
|
updateExerciseApi
|
||||||
|
} from '@/apis/exercise'
|
||||||
|
import { addWeightApi, deleteWeightApi, queryWeightApi, updateWeightApi } from '@/apis/weight'
|
||||||
|
import { IExercise, IExerciseQuery, IHealth, IWeight } from '@/types/health'
|
||||||
|
|
||||||
|
export const useHealthStore = defineStore('health', {
|
||||||
|
state: () => ({
|
||||||
|
weightRecordList: [] as IWeight[],
|
||||||
|
exerciseRecordList: [] as IExercise[],
|
||||||
|
queryInfo: {
|
||||||
|
startDate: '',
|
||||||
|
endDate: ''
|
||||||
|
} as IExerciseQuery,
|
||||||
|
weightApiType: 'ADD' as IHandleApi,
|
||||||
|
exerciseApiType: 'ADD' as IHandleApi,
|
||||||
|
currentExercise: {
|
||||||
|
project: '',
|
||||||
|
duration: 0,
|
||||||
|
date: ''
|
||||||
|
} as IExercise,
|
||||||
|
currentHealth: {
|
||||||
|
project: '',
|
||||||
|
duration: 0,
|
||||||
|
value: 0,
|
||||||
|
date: ''
|
||||||
|
} as IHealth,
|
||||||
|
currentWeight: {
|
||||||
|
value: '',
|
||||||
|
date: ''
|
||||||
|
} as IWeight,
|
||||||
|
selectDate: '',
|
||||||
|
isScrollEnd: false,
|
||||||
|
isRefresh: false
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
async queryExerciseRecordList() {
|
||||||
|
this.exerciseRecordList = await queryExerciseApi(this.queryInfo)
|
||||||
|
},
|
||||||
|
async queryWeightRecordList() {
|
||||||
|
this.weightRecordList = await queryWeightApi(this.queryInfo)
|
||||||
|
},
|
||||||
|
async handleExerciseApi(exercise: IExercise) {
|
||||||
|
switch (this.exerciseApiType) {
|
||||||
|
case 'ADD':
|
||||||
|
await addExerciseApi(exercise)
|
||||||
|
ElMessage.success('新增锻炼记录成功')
|
||||||
|
break
|
||||||
|
case 'UPDATE':
|
||||||
|
await updateExerciseApi(exercise.id as number, exercise)
|
||||||
|
ElMessage.success('更新锻炼记录成功')
|
||||||
|
break
|
||||||
|
case 'DELETE':
|
||||||
|
await deleteExerciseApi(exercise.id as number)
|
||||||
|
ElMessage.success('删除锻炼记录成功')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
await this.refreshInfo()
|
||||||
|
},
|
||||||
|
async handleWeightApi(weight: IWeight) {
|
||||||
|
switch (this.weightApiType) {
|
||||||
|
case 'ADD':
|
||||||
|
await addWeightApi(weight)
|
||||||
|
ElMessage.success('新增体重记录成功')
|
||||||
|
break
|
||||||
|
case 'UPDATE':
|
||||||
|
await updateWeightApi(weight.id as number, weight)
|
||||||
|
ElMessage.success('更新体重记录成功')
|
||||||
|
break
|
||||||
|
case 'DELETE':
|
||||||
|
await deleteWeightApi(weight.id as number)
|
||||||
|
ElMessage.success('删除体重记录成功')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
await this.refreshInfo()
|
||||||
|
},
|
||||||
|
getHealthDay(date: string): IHealth {
|
||||||
|
const exercise = this.exerciseRecordList.find((item) => item.date === date)
|
||||||
|
const weight = this.weightRecordList.find((item) => item.date === date)
|
||||||
|
this.currentHealth = this.getEmptyHealth()
|
||||||
|
|
||||||
|
if (exercise) {
|
||||||
|
this.currentHealth.project = exercise.project
|
||||||
|
this.currentHealth.duration = exercise.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weight) {
|
||||||
|
this.currentHealth.value = weight.value
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentHealth.date = date
|
||||||
|
},
|
||||||
|
async refreshInfo() {
|
||||||
|
await this.queryExerciseRecordList()
|
||||||
|
await this.queryWeightRecordList()
|
||||||
|
this.isRefresh = !this.isRefresh
|
||||||
|
},
|
||||||
|
getEmptyExercise(): IExercise {
|
||||||
|
return {
|
||||||
|
project: '',
|
||||||
|
duration: 0,
|
||||||
|
date: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getEmptyWeight(): IWeight {
|
||||||
|
return {
|
||||||
|
value: 0,
|
||||||
|
date: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getEmptyHealth(): IHealth {
|
||||||
|
return {
|
||||||
|
date: '',
|
||||||
|
duration: 0,
|
||||||
|
project: '',
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import type { IHandleApi } from 'vue3-common/types'
|
import type { IHandleApi } from 'vue3-common/types'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { IPassword, IQueryPassword } from '@/types/password.ts'
|
import { IPassword, IPasswordQuery } from '@/types/password.ts'
|
||||||
import {
|
import {
|
||||||
addPasswordApi,
|
addPasswordApi,
|
||||||
deletePasswordApi,
|
deletePasswordApi,
|
||||||
@@ -15,7 +15,7 @@ export const usePasswordStore = defineStore('password', {
|
|||||||
queryInfo: {
|
queryInfo: {
|
||||||
category: '',
|
category: '',
|
||||||
owner: '哥哥'
|
owner: '哥哥'
|
||||||
} as IQueryPassword,
|
} as IPasswordQuery,
|
||||||
passwordApiType: 'ADD' as IHandleApi,
|
passwordApiType: 'ADD' as IHandleApi,
|
||||||
categoryList: [] as string[],
|
categoryList: [] as string[],
|
||||||
currentPassword: {
|
currentPassword: {
|
||||||
|
|||||||
@@ -82,4 +82,4 @@ span, input {
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "//at.alicdn.com/t/c/font_4793264_6bh098pu52x.css";
|
@import "//at.alicdn.com/t/c/font_4793264_jis1w9io0s8.css";
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
export type IBillType = 'expensive' | 'income' | ''
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 账单记录
|
* 账单记录
|
||||||
*/
|
*/
|
||||||
@@ -70,5 +72,3 @@ export interface IBillSummaryStats {
|
|||||||
balance: number;
|
balance: number;
|
||||||
rate: number;
|
rate: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IBillType = 'expensive' | 'income' | ''
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
/**
|
|
||||||
* 预算信息
|
|
||||||
*/
|
|
||||||
export interface IBudgetInfo {
|
|
||||||
id?: number;
|
|
||||||
/**
|
|
||||||
* 预算类别
|
|
||||||
*/
|
|
||||||
category: string;
|
|
||||||
/**
|
|
||||||
* 预算项目
|
|
||||||
*/
|
|
||||||
project: string;
|
|
||||||
/**
|
|
||||||
* 预算内容
|
|
||||||
*/
|
|
||||||
content: string;
|
|
||||||
/**
|
|
||||||
* 预算供应商
|
|
||||||
*/
|
|
||||||
vendor: string;
|
|
||||||
/**
|
|
||||||
* 预算支出
|
|
||||||
*/
|
|
||||||
budget: number;
|
|
||||||
/**
|
|
||||||
* 实际支出
|
|
||||||
*/
|
|
||||||
actual: number;
|
|
||||||
/**
|
|
||||||
* 支付时间
|
|
||||||
*/
|
|
||||||
payTime: string;
|
|
||||||
/**
|
|
||||||
* 备注
|
|
||||||
*/
|
|
||||||
remake: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IBudgetQuery {
|
|
||||||
category: string;
|
|
||||||
}
|
|
||||||
@@ -1,38 +1,3 @@
|
|||||||
/**
|
|
||||||
* 菜谱信息
|
|
||||||
*/
|
|
||||||
export interface IFoodRecipe {
|
|
||||||
id?: number;
|
|
||||||
/**
|
|
||||||
* 美食名称
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
/**
|
|
||||||
* 美食菜系
|
|
||||||
*/
|
|
||||||
category: string;
|
|
||||||
/**
|
|
||||||
* 推荐指数
|
|
||||||
*/
|
|
||||||
recommendRate: number;
|
|
||||||
/**
|
|
||||||
* 备注
|
|
||||||
*/
|
|
||||||
remark: string;
|
|
||||||
/**
|
|
||||||
* 食材
|
|
||||||
*/
|
|
||||||
materialList: IFoodMaterial[];
|
|
||||||
/**
|
|
||||||
* 步骤
|
|
||||||
*/
|
|
||||||
stepList: IFoodStep[];
|
|
||||||
/**
|
|
||||||
* 成果
|
|
||||||
*/
|
|
||||||
recordList: IFoodRecord[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 食材信息
|
* 食材信息
|
||||||
*/
|
*/
|
||||||
@@ -72,6 +37,41 @@ export interface IFoodStats {
|
|||||||
workCount: number;
|
workCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜谱信息
|
||||||
|
*/
|
||||||
|
export interface IFoodRecipe {
|
||||||
|
id?: number;
|
||||||
|
/**
|
||||||
|
* 美食名称
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
/**
|
||||||
|
* 美食菜系
|
||||||
|
*/
|
||||||
|
category: string;
|
||||||
|
/**
|
||||||
|
* 推荐指数
|
||||||
|
*/
|
||||||
|
recommendRate: number;
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
remark: string;
|
||||||
|
/**
|
||||||
|
* 食材
|
||||||
|
*/
|
||||||
|
materialList: IFoodMaterial[];
|
||||||
|
/**
|
||||||
|
* 步骤
|
||||||
|
*/
|
||||||
|
stepList: IFoodStep[];
|
||||||
|
/**
|
||||||
|
* 成果
|
||||||
|
*/
|
||||||
|
recordList: IFoodRecord[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface IFoodQuery {
|
export interface IFoodQuery {
|
||||||
category: string;
|
category: string;
|
||||||
}
|
}
|
||||||
|
|||||||
30
src/types/health.ts
Normal file
30
src/types/health.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
export interface IHealth {
|
||||||
|
id?: number;
|
||||||
|
sportProject: string;
|
||||||
|
sportDuration: number;
|
||||||
|
weight: number;
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IExercise {
|
||||||
|
id?: number;
|
||||||
|
project: string;
|
||||||
|
duration: number;
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHealthQuery {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IWeight {
|
||||||
|
id?: number;
|
||||||
|
value: number;
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IWeightQuery {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ export interface IPassword {
|
|||||||
remark: string;
|
remark: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQueryPassword {
|
export interface IPasswordQuery {
|
||||||
category: string;
|
category: string;
|
||||||
owner: string;
|
owner: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export interface IProduct {
|
|||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQueryProduct {
|
export interface IProductQuery {
|
||||||
category: string;
|
category: string;
|
||||||
order: string;
|
order: string;
|
||||||
}
|
}
|
||||||
|
|||||||
84
src/views/health/calendar.vue
Normal file
84
src/views/health/calendar.vue
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mobile-health-view common-mobile-view">
|
||||||
|
<v-calendar ref="calendarRef" :attributes='dailyInfo.attrs'
|
||||||
|
@dayclick="dateClick" @did-move="changeMonthClick"
|
||||||
|
:is-dark="appStore.isDark"
|
||||||
|
class="health-calendar card-item"/>
|
||||||
|
<health-legend />
|
||||||
|
|
||||||
|
<health-form />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import HealthLegend from '@/components/Health/HealthLegend.vue'
|
||||||
|
import HealthForm from '@/components/Health/HealthForm.vue'
|
||||||
|
import { CalendarDay } from 'v-calendar/dist/types/src/utils/page'
|
||||||
|
import { formatDate, getStartEndDate } from 'vue3-common/utils/dateUtil'
|
||||||
|
import { onMounted, reactive } from 'vue'
|
||||||
|
import { useHealthStore } from '@/store/health'
|
||||||
|
import { useAppStore } from '@/store/app.ts'
|
||||||
|
import { IExercise, IWeight } from '@/types/health'
|
||||||
|
|
||||||
|
const healthStore = useHealthStore()
|
||||||
|
const appStore = useAppStore()
|
||||||
|
|
||||||
|
const dailyInfo = reactive({
|
||||||
|
calendarDate: '',
|
||||||
|
attrs: [] as any[]
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const result = getStartEndDate(formatDate(new Date()), 'month')
|
||||||
|
healthStore.queryInfo = { startDate: result[0], endDate: result[1] }
|
||||||
|
|
||||||
|
await healthStore.refreshInfo()
|
||||||
|
updateRecordList()
|
||||||
|
healthStore.getHealthDay(formatDate(new Date()))
|
||||||
|
})
|
||||||
|
|
||||||
|
const updateRecordList = () => {
|
||||||
|
healthStore.weightRecordList.forEach((item: IWeight) => {
|
||||||
|
dailyInfo.attrs.push({
|
||||||
|
dot: 'red',
|
||||||
|
dates: item.date
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
healthStore.exerciseRecordList.forEach((item: IExercise) => {
|
||||||
|
dailyInfo.attrs.push({
|
||||||
|
dot: 'green',
|
||||||
|
dates: item.date
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateClick = (day: CalendarDay) => {
|
||||||
|
healthStore.selectDate = formatDate(day.date)
|
||||||
|
healthStore.getHealthDay(formatDate(day.date))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择月份事件
|
||||||
|
*/
|
||||||
|
const changeMonthClick = async (value) => {
|
||||||
|
const result = getStartEndDate(value[0].id, 'month')
|
||||||
|
healthStore.queryInfo = { startDate: result[0], endDate: result[1] }
|
||||||
|
|
||||||
|
await healthStore.refreshInfo()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.mobile-health-view {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1vh;
|
||||||
|
|
||||||
|
.health-calendar {
|
||||||
|
justify-self: center;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -36,6 +36,10 @@
|
|||||||
title="物品记录" sub-title="收纳生活琐碎"
|
title="物品记录" sub-title="收纳生活琐碎"
|
||||||
router="/product/list"/>
|
router="/product/list"/>
|
||||||
|
|
||||||
|
<module-card icon="iconfont icon-yundongjiankang" color="#FD644C"
|
||||||
|
title="运动健康" sub-title="乐享健康生活"
|
||||||
|
router="/health/calendar"/>
|
||||||
|
|
||||||
<module-card icon="iconfont icon-paiban" color="#9933FF"
|
<module-card icon="iconfont icon-paiban" color="#9933FF"
|
||||||
title="日程安排" sub-title="规划每日时光"
|
title="日程安排" sub-title="规划每日时光"
|
||||||
router="/plan/calendar"/>
|
router="/plan/calendar"/>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
|||||||
},
|
},
|
||||||
'/bill': {
|
'/bill': {
|
||||||
title: '收支记录',
|
title: '收支记录',
|
||||||
icon: 'home-bill',
|
icon: '',
|
||||||
order: 2,
|
order: 2,
|
||||||
redirect: '/bill/data'
|
redirect: '/bill/data'
|
||||||
},
|
},
|
||||||
@@ -51,7 +51,7 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
|||||||
},
|
},
|
||||||
'/travel': {
|
'/travel': {
|
||||||
title: '旅行记录',
|
title: '旅行记录',
|
||||||
icon: 'home-food',
|
icon: '',
|
||||||
order: 4,
|
order: 4,
|
||||||
redirect: '/travel/spot'
|
redirect: '/travel/spot'
|
||||||
},
|
},
|
||||||
@@ -75,6 +75,16 @@ export const mobileHomeMeta: IRouteMetaConfig = {
|
|||||||
title: '记录表单',
|
title: '记录表单',
|
||||||
icon: ''
|
icon: ''
|
||||||
},
|
},
|
||||||
|
'/health': {
|
||||||
|
title: '运动健康',
|
||||||
|
icon: '',
|
||||||
|
order: 4,
|
||||||
|
redirect: '/health/calendar'
|
||||||
|
},
|
||||||
|
'/health/calendar': {
|
||||||
|
title: '记录',
|
||||||
|
icon: ''
|
||||||
|
},
|
||||||
'/plan': {
|
'/plan': {
|
||||||
title: '时光日程',
|
title: '时光日程',
|
||||||
icon: 'home-calendar',
|
icon: 'home-calendar',
|
||||||
|
|||||||
Reference in New Issue
Block a user