chore: OXC Formatter

This commit is contained in:
skytek_xinliang
2026-08-13 15:41:12 +08:00
parent 5377b872d8
commit 8f5fa15d3a
40 changed files with 2392 additions and 3009 deletions
+212 -198
View File
@@ -1,365 +1,377 @@
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { login as apiLogin } from '@/api/auth'
import { defineStore } from "pinia";
import { computed, ref } from "vue";
import { login as apiLogin } from "@/api/auth";
/** 後端尚未完成前保持 true,改為 false 才會實際呼叫登入 API */
const USE_MOCK = import.meta.env.VITE_USE_MOCK !== 'false'
const USE_MOCK = import.meta.env.VITE_USE_MOCK !== "false";
export interface UserProfile {
name: string
birthday: string
gender: string
height: number
weight: number
phone: string
email: string
emergencyContact: string
emergencyPhone: string
consent: boolean
name: string;
birthday: string;
gender: string;
height: number;
weight: number;
phone: string;
email: string;
emergencyContact: string;
emergencyPhone: string;
consent: boolean;
}
export interface SelfAssessment {
exerciseFrequency: string
painLevel: string
hasFalls: boolean
chronicDiseases: string[]
wantedImprovements: string[]
scoreLevel: string
completed: boolean
exerciseFrequency: string;
painLevel: string;
hasFalls: boolean;
chronicDiseases: string[];
wantedImprovements: string[];
scoreLevel: string;
completed: boolean;
}
export interface Appointment {
id: string
title: string
date: string
time: string
location: string
status: '未報名' | '已報名' | '已報到'
slots: number
organizer: string
items: string[]
id: string;
title: string;
date: string;
time: string;
location: string;
status: "未報名" | "已報名" | "已報到";
slots: number;
organizer: string;
items: string[];
}
export interface MeasurementStation {
name: string
completed: boolean
time?: string
values: Record<string, any>
name: string;
completed: boolean;
time?: string;
values: Record<string, any>;
}
function createDefaultUserProfile (): UserProfile {
function createDefaultUserProfile(): UserProfile {
return {
name: '林大明',
birthday: '1961-08-15',
gender: '男',
name: "林大明",
birthday: "1961-08-15",
gender: "男",
height: 168,
weight: 65,
phone: '0912-345-678',
email: 'jianguo.lin@email.com',
emergencyContact: '林小明 (長子)',
emergencyPhone: '0987-654-321',
phone: "0912-345-678",
email: "jianguo.lin@email.com",
emergencyContact: "林小明 (長子)",
emergencyPhone: "0987-654-321",
consent: true,
}
};
}
function createDefaultSelfAssessment (): SelfAssessment {
function createDefaultSelfAssessment(): SelfAssessment {
return {
exerciseFrequency: '1-2',
painLevel: '輕微',
exerciseFrequency: "1-2",
painLevel: "輕微",
hasFalls: false,
chronicDiseases: ['高血壓'],
wantedImprovements: ['肌力', '平衡'],
scoreLevel: '需追蹤',
chronicDiseases: ["高血壓"],
wantedImprovements: ["肌力", "平衡"],
scoreLevel: "需追蹤",
completed: true,
}
};
}
function createDefaultAppointments (): Appointment[] {
function createDefaultAppointments(): Appointment[] {
const measurementItems = [
'血壓',
'體脂',
'握力',
'5次坐站',
'30秒椅子坐立',
'原地抬膝踏步',
'手臂屈舉',
'抓背測驗',
'坐姿體前彎',
'2.44米繞物',
'開眼單足立',
]
const location = '信義區運動中心 3 樓多功能教室'
const organizer = '臺北市政府體育局'
"血壓",
"體脂",
"握力",
"5次坐站",
"30秒椅子坐立",
"原地抬膝踏步",
"手臂屈舉",
"抓背測驗",
"坐姿體前彎",
"2.44米繞物",
"開眼單足立",
];
const location = "信義區運動中心 3 樓多功能教室";
const organizer = "臺北市政府體育局";
return [
{
id: 'apt-01',
title: '銀髮活力公益普測 A 時段',
date: '2026-07-04',
time: '09:00 - 10:00',
id: "apt-01",
title: "銀髮活力公益普測 A 時段",
date: "2026-07-04",
time: "09:00 - 10:00",
location,
status: '已報名',
status: "已報名",
slots: 12,
organizer,
items: measurementItems,
},
{
id: 'apt-02',
title: '銀髮活力公益普測 B 時段',
date: '2026-07-04',
time: '10:30 - 11:30',
id: "apt-02",
title: "銀髮活力公益普測 B 時段",
date: "2026-07-04",
time: "10:30 - 11:30",
location,
status: '已報到',
status: "已報到",
slots: 5,
organizer,
items: measurementItems,
},
{
id: 'apt-03',
title: '銀髮活力公益普測 C 時段',
date: '2026-07-04',
time: '13:30 - 14:30',
id: "apt-03",
title: "銀髮活力公益普測 C 時段",
date: "2026-07-04",
time: "13:30 - 14:30",
location,
status: '未報名',
status: "未報名",
slots: 45,
organizer,
items: measurementItems,
},
]
];
}
function createDefaultMeasurements (): Record<string, MeasurementStation> {
function createDefaultMeasurements(): Record<string, MeasurementStation> {
return {
BloodPressure: {
name: '血壓量測',
name: "血壓量測",
completed: true,
time: '2026-06-18 15:00',
time: "2026-06-18 15:00",
values: { systolic: 132, diastolic: 84, heartRate: 72 },
},
BodyFat: {
name: '體組成分析',
name: "體組成分析",
completed: true,
time: '2026-06-18 15:05',
time: "2026-06-18 15:05",
values: { bmi: 23, bodyFatPct: 24.5 },
},
GripStrength: {
name: '左右握力',
name: "左右握力",
completed: false,
values: { leftHand: 0, rightHand: 0 },
},
Sit5x: {
name: '5次坐站測試',
name: "5次坐站測試",
completed: false,
values: { durationSeconds: 0 },
},
Sit30s: {
name: '30秒椅子坐立',
name: "30秒椅子坐立",
completed: false,
values: { count: 0 },
},
StepTest: {
name: '2分鐘原地抬膝踏步',
name: "2分鐘原地抬膝踏步",
completed: false,
values: { count: 0 },
},
ArmTest: {
name: '30秒肱二頭肌手臂屈舉',
name: "30秒肱二頭肌手臂屈舉",
completed: false,
values: { count: 0 },
},
BackTest: {
name: '抓背測驗(柔軟度)',
name: "抓背測驗(柔軟度)",
completed: false,
values: { leftDistanceCm: 0, rightDistanceCm: 0 },
},
SitReachTest: {
name: '坐姿體前彎(柔軟度)',
name: "坐姿體前彎(柔軟度)",
completed: false,
values: { distanceCm: 0 },
},
UpGo8ft: {
name: '2.44公尺起立繞物(敏捷)',
name: "2.44公尺起立繞物(敏捷)",
completed: false,
values: { durationSeconds: 0 },
},
OneLegTest: {
name: '開眼單足立(平衡)',
name: "開眼單足立(平衡)",
completed: false,
values: { leftSeconds: 0, rightSeconds: 0 },
},
}
};
}
function createDefaultRadarData () {
function createDefaultRadarData() {
return {
strength: 65,
balance: 60,
flexibility: 55,
agility: 70,
cardio: 62,
}
};
}
export const useAppStore = defineStore('app', () => {
const isLoggedIn = ref(false)
export const useAppStore = defineStore("app", () => {
const isLoggedIn = ref(false);
/** 登入取得的使用者識別碼,課程建議等 API 需要此值查詢 */
const userID = ref('')
const userProfile = ref<UserProfile>(createDefaultUserProfile())
const selfAssessment = ref<SelfAssessment>(createDefaultSelfAssessment())
const appointments = ref<Appointment[]>(createDefaultAppointments())
const measurements = ref<Record<string, MeasurementStation>>(createDefaultMeasurements())
const healthScore = ref(72)
const radarData = ref(createDefaultRadarData())
const isReportGenerated = ref(false)
const userID = ref("");
const userProfile = ref<UserProfile>(createDefaultUserProfile());
const selfAssessment = ref<SelfAssessment>(createDefaultSelfAssessment());
const appointments = ref<Appointment[]>(createDefaultAppointments());
const measurements = ref<Record<string, MeasurementStation>>(
createDefaultMeasurements(),
);
const healthScore = ref(72);
const radarData = ref(createDefaultRadarData());
const isReportGenerated = ref(false);
const completedStationsCount = computed(() => {
return Object.values(measurements.value).filter(station => station.completed).length
})
return Object.values(measurements.value).filter(
(station) => station.completed,
).length;
});
const totalStationsCount = computed(() => {
return Object.keys(measurements.value).length
})
return Object.keys(measurements.value).length;
});
const progressPercent = computed((): number => {
const keys = Object.keys(measurements.value)
const keys = Object.keys(measurements.value);
if (keys.length === 0) {
return 0
return 0;
}
const done = Object.values(measurements.value).filter(station => station.completed).length
return Math.round((done / keys.length) * 100)
})
const done = Object.values(measurements.value).filter(
(station) => station.completed,
).length;
return Math.round((done / keys.length) * 100);
});
/** 手機門號登入;後端未完成時走模擬資料,完成後設 VITE_USE_MOCK=false 改打真實 API */
async function login (phone: string) {
async function login(phone: string) {
if (USE_MOCK) {
isLoggedIn.value = true
userID.value = 'MOCK-USER'
userProfile.value.phone = phone
return
isLoggedIn.value = true;
userID.value = "MOCK-USER";
userProfile.value.phone = phone;
return;
}
const response = await apiLogin(phone)
const response = await apiLogin(phone);
isLoggedIn.value = true
userID.value = response.userID
userProfile.value.phone = response.phone
userProfile.value.name = response.userName
isLoggedIn.value = true;
userID.value = response.userID;
userProfile.value.phone = response.phone;
userProfile.value.name = response.userName;
}
function logout () {
isLoggedIn.value = false
userID.value = ''
function logout() {
isLoggedIn.value = false;
userID.value = "";
}
function updateProfile (profile: Partial<UserProfile>) {
userProfile.value = { ...userProfile.value, ...profile }
function updateProfile(profile: Partial<UserProfile>) {
userProfile.value = { ...userProfile.value, ...profile };
}
function submitSelfAssessment (answers: Partial<SelfAssessment>) {
function submitSelfAssessment(answers: Partial<SelfAssessment>) {
selfAssessment.value = {
...selfAssessment.value,
...answers,
completed: true,
}
};
let level = '低風險'
if (answers.exerciseFrequency === '0' || answers.hasFalls === true) {
level = '需追蹤'
let level = "低風險";
if (answers.exerciseFrequency === "0" || answers.hasFalls === true) {
level = "需追蹤";
}
if (
answers.painLevel === '中度'
|| answers.painLevel === '重度'
|| (answers.chronicDiseases && answers.chronicDiseases.length >= 2)
answers.painLevel === "中度" ||
answers.painLevel === "重度" ||
(answers.chronicDiseases && answers.chronicDiseases.length >= 2)
) {
level = '建議諮詢'
level = "建議諮詢";
}
selfAssessment.value.scoreLevel = level
selfAssessment.value.scoreLevel = level;
}
function registerAppointment (appointmentId: string) {
const appointment = appointments.value.find(item => item.id === appointmentId)
function registerAppointment(appointmentId: string) {
const appointment = appointments.value.find(
(item) => item.id === appointmentId,
);
if (!appointment) {
return
return;
}
appointment.status = '已報名'
appointment.slots -= 1
appointment.status = "已報名";
appointment.slots -= 1;
}
function cancelAppointment (appointmentId: string) {
const appointment = appointments.value.find(item => item.id === appointmentId)
function cancelAppointment(appointmentId: string) {
const appointment = appointments.value.find(
(item) => item.id === appointmentId,
);
if (!appointment) {
return
return;
}
appointment.status = '未報名'
appointment.slots += 1
appointment.status = "未報名";
appointment.slots += 1;
}
function checkinAppointment (appointmentId: string) {
const appointment = appointments.value.find(item => item.id === appointmentId)
function checkinAppointment(appointmentId: string) {
const appointment = appointments.value.find(
(item) => item.id === appointmentId,
);
if (!appointment) {
return
return;
}
appointment.status = '已報到'
appointment.status = "已報到";
}
function saveMeasurement (code: string, values: Record<string, any>) {
const measurement = measurements.value[code]
function saveMeasurement(code: string, values: Record<string, any>) {
const measurement = measurements.value[code];
if (!measurement) {
return
return;
}
const now = new Date()
const timeStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`
const now = new Date();
const timeStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")} ${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;
measurement.values = { ...values }
measurement.completed = true
measurement.time = timeStr
measurement.values = { ...values };
measurement.completed = true;
measurement.time = timeStr;
}
function generateFinalReport () {
const currentMeasurements = measurements.value
function generateFinalReport() {
const currentMeasurements = measurements.value;
let strScore = 65
let strScore = 65;
if (currentMeasurements.GripStrength.completed) {
const avgGrip
= ((currentMeasurements.GripStrength.values.leftHand || 0)
+ (currentMeasurements.GripStrength.values.rightHand || 0))
/ 2
const limit = userProfile.value.gender === '男' ? 30 : 20
strScore = Math.min(95, Math.max(50, Math.round((avgGrip / limit) * 75)))
const avgGrip =
((currentMeasurements.GripStrength.values.leftHand || 0) +
(currentMeasurements.GripStrength.values.rightHand || 0)) /
2;
const limit = userProfile.value.gender === "男" ? 30 : 20;
strScore = Math.min(95, Math.max(50, Math.round((avgGrip / limit) * 75)));
}
let balScore = 60
let balScore = 60;
if (currentMeasurements.OneLegTest.completed) {
const maxSec = Math.max(
currentMeasurements.OneLegTest.values.leftSeconds || 0,
currentMeasurements.OneLegTest.values.rightSeconds || 0,
)
balScore = Math.min(98, Math.max(40, Math.round((maxSec / 30) * 90)))
);
balScore = Math.min(98, Math.max(40, Math.round((maxSec / 30) * 90)));
}
let flexScore = 55
let flexScore = 55;
if (currentMeasurements.SitReachTest.completed) {
const dist = currentMeasurements.SitReachTest.values.distanceCm || 0
flexScore = Math.min(95, Math.max(45, 60 + dist * 1.5))
const dist = currentMeasurements.SitReachTest.values.distanceCm || 0;
flexScore = Math.min(95, Math.max(45, 60 + dist * 1.5));
}
let agiScore = 70
let agiScore = 70;
if (currentMeasurements.UpGo8ft.completed) {
const sec = currentMeasurements.UpGo8ft.values.durationSeconds || 10
agiScore = Math.min(95, Math.max(40, Math.round(100 - sec * 5)))
const sec = currentMeasurements.UpGo8ft.values.durationSeconds || 10;
agiScore = Math.min(95, Math.max(40, Math.round(100 - sec * 5)));
}
let cardScore = 62
let cardScore = 62;
if (currentMeasurements.StepTest.completed) {
const count = currentMeasurements.StepTest.values.count || 60
cardScore = Math.min(95, Math.max(45, Math.round((count / 80) * 80)))
const count = currentMeasurements.StepTest.values.count || 60;
cardScore = Math.min(95, Math.max(45, Math.round((count / 80) * 80)));
}
radarData.value = {
@@ -368,27 +380,29 @@ export const useAppStore = defineStore('app', () => {
flexibility: flexScore,
agility: agiScore,
cardio: cardScore,
}
};
const avg = Math.round((strScore + balScore + flexScore + agiScore + cardScore) / 5)
healthScore.value = Math.min(100, avg + 5)
isReportGenerated.value = true
const avg = Math.round(
(strScore + balScore + flexScore + agiScore + cardScore) / 5,
);
healthScore.value = Math.min(100, avg + 5);
isReportGenerated.value = true;
}
function resetMeasurements () {
function resetMeasurements() {
for (const [key, measurement] of Object.entries(measurements.value)) {
if (key !== 'BloodPressure' && key !== 'BodyFat') {
measurement.completed = false
if (key !== "BloodPressure" && key !== "BodyFat") {
measurement.completed = false;
for (const valueKey of Object.keys(measurement.values)) {
measurement.values[valueKey] = 0
measurement.values[valueKey] = 0;
}
}
}
isReportGenerated.value = false
healthScore.value = 72
radarData.value = createDefaultRadarData()
isReportGenerated.value = false;
healthScore.value = 72;
radarData.value = createDefaultRadarData();
}
return {
@@ -414,5 +428,5 @@ export const useAppStore = defineStore('app', () => {
saveMeasurement,
generateFinalReport,
resetMeasurements,
}
})
};
});