feat: 最後量測時間
This commit is contained in:
@@ -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>();
|
||||
}
|
||||
|
||||
/** 產生指定使用者的體適能評級。 */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user