feat: 最後量測時間
This commit is contained in:
@@ -1,16 +1,16 @@
|
|||||||
import type {
|
import type {
|
||||||
GeneratePhysicalFitnessResponse,
|
GeneratePhysicalFitnessResponse,
|
||||||
PhysicalFitnessItem,
|
PhysicalFitnessResponse,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import { api } from "./client";
|
import { api } from "./client";
|
||||||
|
|
||||||
/** 取得指定使用者的 11 項最新體適能測驗成績。 */
|
/** 取得指定使用者的 11 項最新體適能測驗成績。 */
|
||||||
export function fetchPhysicalFitness(
|
export function fetchPhysicalFitness(
|
||||||
userID: string,
|
userID: string,
|
||||||
): Promise<PhysicalFitnessItem[]> {
|
): Promise<PhysicalFitnessResponse> {
|
||||||
return api
|
return api
|
||||||
.get(`v1/physical-fitness/${encodeURIComponent(userID)}`)
|
.get(`v1/physical-fitness/${encodeURIComponent(userID)}`)
|
||||||
.json<PhysicalFitnessItem[]>();
|
.json<PhysicalFitnessResponse>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 產生指定使用者的體適能評級。 */
|
/** 產生指定使用者的體適能評級。 */
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ export interface PhysicalFitnessItem {
|
|||||||
fitnessScore: string | null;
|
fitnessScore: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** PhysicalFitnessController 回傳的最新體適能測驗資料。 */
|
||||||
|
export interface PhysicalFitnessResponse {
|
||||||
|
results: PhysicalFitnessItem[];
|
||||||
|
ReceivedAt: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
/** PhysicalFitnessController 產生評級的回應。 */
|
/** PhysicalFitnessController 產生評級的回應。 */
|
||||||
export interface GeneratePhysicalFitnessResponse {
|
export interface GeneratePhysicalFitnessResponse {
|
||||||
message: string;
|
message: string;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-subtitle> 顯示目前帳號各測驗項目的最新成績。 </v-card-subtitle>
|
<v-card-subtitle> 最後量測時間:{{ formattedReceivedAt }} </v-card-subtitle>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-progress-linear
|
<v-progress-linear
|
||||||
@@ -86,6 +86,7 @@ const props = defineProps<{
|
|||||||
error: string;
|
error: string;
|
||||||
items: PhysicalFitnessItem[];
|
items: PhysicalFitnessItem[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
receivedAt: string | null;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
defineEmits<{
|
defineEmits<{
|
||||||
@@ -125,6 +126,22 @@ const displayItems = computed(() =>
|
|||||||
const completedCount = computed(
|
const completedCount = computed(
|
||||||
() => displayItems.value.filter((item) => item.fitnessScore !== null).length,
|
() => 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>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -143,6 +143,7 @@
|
|||||||
:error="physicalFitnessError"
|
:error="physicalFitnessError"
|
||||||
:items="physicalFitnessItems"
|
:items="physicalFitnessItems"
|
||||||
:loading="physicalFitnessLoading"
|
:loading="physicalFitnessLoading"
|
||||||
|
:received-at="physicalFitnessReceivedAt"
|
||||||
@refresh="loadPhysicalFitness"
|
@refresh="loadPhysicalFitness"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -424,6 +425,7 @@ const generatePhysicalFitnessLoading = ref(false);
|
|||||||
const generateResult = ref("");
|
const generateResult = ref("");
|
||||||
const generateError = ref("");
|
const generateError = ref("");
|
||||||
const physicalFitnessItems = ref<PhysicalFitnessItem[]>([]);
|
const physicalFitnessItems = ref<PhysicalFitnessItem[]>([]);
|
||||||
|
const physicalFitnessReceivedAt = ref<string | null>(null);
|
||||||
const physicalFitnessLoading = ref(false);
|
const physicalFitnessLoading = ref(false);
|
||||||
const physicalFitnessError = ref("");
|
const physicalFitnessError = ref("");
|
||||||
const redirectingToLogin = ref(false);
|
const redirectingToLogin = ref(false);
|
||||||
@@ -507,6 +509,7 @@ function getRequiredUserID(): string | null {
|
|||||||
async function loadPhysicalFitness() {
|
async function loadPhysicalFitness() {
|
||||||
if (!store.isLoggedIn) {
|
if (!store.isLoggedIn) {
|
||||||
physicalFitnessItems.value = [];
|
physicalFitnessItems.value = [];
|
||||||
|
physicalFitnessReceivedAt.value = null;
|
||||||
physicalFitnessError.value = "";
|
physicalFitnessError.value = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -520,7 +523,9 @@ async function loadPhysicalFitness() {
|
|||||||
physicalFitnessError.value = "";
|
physicalFitnessError.value = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
physicalFitnessItems.value = await fetchPhysicalFitness(userID);
|
const physicalFitnessResponse = await fetchPhysicalFitness(userID);
|
||||||
|
physicalFitnessItems.value = physicalFitnessResponse.results;
|
||||||
|
physicalFitnessReceivedAt.value = physicalFitnessResponse.ReceivedAt;
|
||||||
updateTodayTimeString();
|
updateTodayTimeString();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
physicalFitnessError.value = getApiErrorMessage(
|
physicalFitnessError.value = getApiErrorMessage(
|
||||||
|
|||||||
Reference in New Issue
Block a user