feat: 最後量測時間

This commit is contained in:
skytek_xinliang
2026-09-16 09:29:54 +08:00
parent 56dfb84890
commit 057bd335d6
4 changed files with 33 additions and 5 deletions
@@ -1,16 +1,16 @@
import type {
GeneratePhysicalFitnessResponse,
PhysicalFitnessItem,
PhysicalFitnessResponse,
} from "./types";
import { api } from "./client";
/** 取得指定使用者的 11 項最新體適能測驗成績。 */
export function fetchPhysicalFitness(
userID: string,
): Promise<PhysicalFitnessItem[]> {
): Promise<PhysicalFitnessResponse> {
return api
.get(`v1/physical-fitness/${encodeURIComponent(userID)}`)
.json<PhysicalFitnessItem[]>();
.json<PhysicalFitnessResponse>();
}
/** 產生指定使用者的體適能評級。 */
+6
View File
@@ -12,6 +12,12 @@ export interface PhysicalFitnessItem {
fitnessScore: string | null;
}
/** PhysicalFitnessController 回傳的最新體適能測驗資料。 */
export interface PhysicalFitnessResponse {
results: PhysicalFitnessItem[];
ReceivedAt: string | null;
}
/** PhysicalFitnessController 產生評級的回應。 */
export interface GeneratePhysicalFitnessResponse {
message: string;
@@ -19,7 +19,7 @@
</div>
</v-card-title>
<v-card-subtitle> 顯示目前帳號各測驗項目的最新成績。 </v-card-subtitle>
<v-card-subtitle> 最後量測時間:{{ formattedReceivedAt }} </v-card-subtitle>
<v-card-text>
<v-progress-linear
@@ -86,6 +86,7 @@ const props = defineProps<{
error: string;
items: PhysicalFitnessItem[];
loading: boolean;
receivedAt: string | null;
}>();
defineEmits<{
@@ -125,6 +126,22 @@ const displayItems = computed(() =>
const completedCount = computed(
() => displayItems.value.filter((item) => item.fitnessScore !== null).length,
);
const formattedReceivedAt = computed(() => {
if (!props.receivedAt) {
return "無資料";
}
const receivedAt = new Date(props.receivedAt);
if (Number.isNaN(receivedAt.getTime())) {
return "無資料";
}
return new Intl.DateTimeFormat("zh-TW", {
dateStyle: "medium",
timeStyle: "short",
}).format(receivedAt);
});
</script>
<style scoped>
+6 -1
View File
@@ -143,6 +143,7 @@
:error="physicalFitnessError"
:items="physicalFitnessItems"
:loading="physicalFitnessLoading"
:received-at="physicalFitnessReceivedAt"
@refresh="loadPhysicalFitness"
/>
@@ -424,6 +425,7 @@ const generatePhysicalFitnessLoading = ref(false);
const generateResult = ref("");
const generateError = ref("");
const physicalFitnessItems = ref<PhysicalFitnessItem[]>([]);
const physicalFitnessReceivedAt = ref<string | null>(null);
const physicalFitnessLoading = ref(false);
const physicalFitnessError = ref("");
const redirectingToLogin = ref(false);
@@ -507,6 +509,7 @@ function getRequiredUserID(): string | null {
async function loadPhysicalFitness() {
if (!store.isLoggedIn) {
physicalFitnessItems.value = [];
physicalFitnessReceivedAt.value = null;
physicalFitnessError.value = "";
return;
}
@@ -520,7 +523,9 @@ async function loadPhysicalFitness() {
physicalFitnessError.value = "";
try {
physicalFitnessItems.value = await fetchPhysicalFitness(userID);
const physicalFitnessResponse = await fetchPhysicalFitness(userID);
physicalFitnessItems.value = physicalFitnessResponse.results;
physicalFitnessReceivedAt.value = physicalFitnessResponse.ReceivedAt;
updateTodayTimeString();
} catch (error) {
physicalFitnessError.value = getApiErrorMessage(