feat: 增加时间处理

master
xjs 2026-08-06 13:59:08 +08:00
parent 5033284258
commit 861bdb5195
3 changed files with 75 additions and 95 deletions

View File

@ -1,10 +1,13 @@
// 通用格式化 / 校验纯函数(无状态,供 composable 与页面复用)。 // 通用格式化 / 校验纯函数(无状态,供 composable 与页面复用)。
/** Date → `YYYY-MM-DD` */ /** Date → `YYYY-MM-DD` */
export const formatDate = (date: Date): string => { export const formatDate = (date: Date | string): string => {
const year = date.getFullYear(); const transformedDate = typeof date === "string" ? new Date(date) : date;
const month = String(date.getMonth() + 1).padStart(2, "0"); if (Number.isNaN(transformedDate.getTime())) return "";
const day = String(date.getDate()).padStart(2, "0");
const year = transformedDate.getFullYear();
const month = String(transformedDate.getMonth() + 1).padStart(2, "0");
const day = String(transformedDate.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
}; };

View File

@ -32,7 +32,7 @@
<div class="flex items-center gap-8"> <div class="flex items-center gap-8">
<span class="min-w-0 truncate text-[4rem] font-600 leading-none text-[#000]">{{ item.studentName || "-" }}</span> <span class="min-w-0 truncate text-[4rem] font-600 leading-none text-[#000]">{{ item.studentName || "-" }}</span>
<span class="shrink-0 rounded-2 bg-[#E7F2FF] px-4 py-3 text-[2.5rem] leading-none text-[#1580FF]"> <span class="shrink-0 rounded-2 bg-[#E7F2FF] px-4 py-3 text-[2.5rem] leading-none text-[#1580FF]">
签到:{{ formatCheckinTime(item.checkinTime) }} 签到:{{ formatDate(item.checkinTime) }}
</span> </span>
<span <span
v-if="activeTab === 'available' && item.waitingMinutes > 0" v-if="activeTab === 'available' && item.waitingMinutes > 0"
@ -90,6 +90,7 @@
import "vant/es/tabs/style"; import "vant/es/tabs/style";
import type { ReceptionTaskDTO } from "@/api/reception"; import type { ReceptionTaskDTO } from "@/api/reception";
import { useReceptionTasks, type ReceptionTaskTab } from "@/composables/useReceptionTasks"; import { useReceptionTasks, type ReceptionTaskTab } from "@/composables/useReceptionTasks";
import { formatDate } from "@/utils/format";
const tabs: ReadonlyArray<{ label: string; value: ReceptionTaskTab }> = [ const tabs: ReadonlyArray<{ label: string; value: ReceptionTaskTab }> = [
{ label: "待接待", value: "available" }, { label: "待接待", value: "available" },
@ -99,10 +100,7 @@
const router = useRouter(); const router = useRouter();
const { activeTab, tasks, loading, finished, error, claimingTaskId, showEmpty, emptyText, loadNextPage, claimTask } = useReceptionTasks(20); const { activeTab, tasks, loading, finished, error, claimingTaskId, showEmpty, emptyText, loadNextPage, claimTask } = useReceptionTasks(20);
const formatCheckinTime = (value: string): string => {
const normalized = value.replace("T", " ");
return normalized.length >= 16 ? normalized.slice(5, 16) : normalized || "-";
};
const formatDateOnly = (value: string): string => value.split(/[T ]/, 1)[0] || "-"; const formatDateOnly = (value: string): string => value.split(/[T ]/, 1)[0] || "-";

View File

@ -1,49 +1,27 @@
<template> <template>
<main class="invitation-data min-h-full bg-[#F5F5F5]"> <main class="invitation-data min-h-full bg-[#F5F5F5]">
<div class="sticky top-0 z-10 bg-white"> <div class="sticky top-0 z-10 bg-white">
<VanSearch <VanSearch v-model="searchKeyword" class="invitation-data__search" background="#fff" placeholder="请输入学生姓名"
v-model="searchKeyword" autocomplete="off" enterkeyhint="search" clearable @search="submitSearch" @clear="clearSearch" />
class="invitation-data__search"
background="#fff"
placeholder="请输入学生姓名"
autocomplete="off"
enterkeyhint="search"
clearable
@search="submitSearch"
@clear="clearSearch" />
<VanTabs <VanTabs v-model:active="activeFilter" class="invitation-data__tabs" line-width="24px" line-height="2px"
v-model:active="activeFilter" :swipe-threshold="6" color="#1580ff" title-active-color="#000" title-inactive-color="#999">
class="invitation-data__tabs"
line-width="24px"
line-height="2px"
:swipe-threshold="6"
color="#1580ff"
title-active-color="#000"
title-inactive-color="#999">
<VanTab v-for="tab in tabs" :key="tab.value" :name="tab.value" :title="tab.label" /> <VanTab v-for="tab in tabs" :key="tab.value" :name="tab.value" :title="tab.label" />
</VanTabs> </VanTabs>
</div> </div>
<VanList <VanList v-model:loading="loading" :finished="finished" :error="error"
v-model:loading="loading" :finished-text="records.length ? '没有更多了' : ''" error-text="加载失败,点击重试" @load="loadNextPage"
:finished="finished"
:error="error"
:finished-text="records.length ? '没有更多了' : ''"
error-text="加载失败,点击重试"
@load="loadNextPage"
@update:error="(value: boolean) => (error = value)"> @update:error="(value: boolean) => (error = value)">
<VanEmpty <VanEmpty v-if="showEmpty" class="my-auto mt-40"
v-if="showEmpty" image="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/inviteReception/icon_zanwu.png" :image-size="[186, 144]"
class="my-auto mt-40"
image="https://lw-zk.oss-cn-hangzhou.aliyuncs.com/inviteReception/icon_zanwu.png"
:image-size="[186, 144]"
description="暂无数据" /> description="暂无数据" />
<div v-else class="flex flex-col gap-12 px-15 py-15"> <div v-else class="flex flex-col gap-12 px-15 py-15">
<article v-for="record in records" :key="record.id" class="rounded-8 bg-white p-15"> <article v-for="record in records" :key="record.id" class="rounded-8 bg-white p-15">
<div class="flex items-center justify-between gap-10"> <div class="flex items-center justify-between gap-10">
<h2 class="min-w-0 flex-1 truncate text-[4rem] font-600 leading-none text-[#000]">{{ record.studentName }}</h2> <h2 class="min-w-0 flex-1 truncate text-[4rem] font-600 leading-none text-[#000]">{{ record.studentName }}
</h2>
<span class="shrink-0 text-[3.25rem] leading-none" :style="{ color: getStatusColor(record.statusName) }"> <span class="shrink-0 text-[3.25rem] leading-none" :style="{ color: getStatusColor(record.statusName) }">
{{ record.statusName }} {{ record.statusName }}
</span> </span>
@ -52,7 +30,7 @@
<div class="mt-15 flex flex-col gap-8 text-[3.25rem] text-[#333]"> <div class="mt-15 flex flex-col gap-8 text-[3.25rem] text-[#333]">
<p class="m-0"> <p class="m-0">
<span class="text-[#666]">预约:</span> <span class="text-[#666]">预约:</span>
{{ record.visitDate }} {{ formatDate(record.visitDate) }}
</p> </p>
<p v-if="record.graduateSchoolName" class="m-0"> <p v-if="record.graduateSchoolName" class="m-0">
<span class="text-[#666]">院校:</span> <span class="text-[#666]">院校:</span>
@ -70,70 +48,71 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Empty as VanEmpty, List as VanList, Search as VanSearch, Tab as VanTab, Tabs as VanTabs } from "vant"; import { Empty as VanEmpty, List as VanList, Search as VanSearch, Tab as VanTab, Tabs as VanTabs } from "vant";
import "vant/es/empty/style"; import "vant/es/empty/style";
import "vant/es/list/style"; import "vant/es/list/style";
import "vant/es/search/style"; import "vant/es/search/style";
import "vant/es/tab/style"; import "vant/es/tab/style";
import "vant/es/tabs/style"; import "vant/es/tabs/style";
import type { InvitationPageFilter } from "@/api/admission"; import type { InvitationPageFilter } from "@/api/admission";
import { useTeacherInvitationData } from "@/composables/useTeacherInvitationData"; import { useTeacherInvitationData } from "@/composables/useTeacherInvitationData";
import { formatDate } from "@/utils/format"
const tabs: ReadonlyArray<{ label: string; value: InvitationPageFilter }> = [ const tabs: ReadonlyArray<{ label: string; value: InvitationPageFilter }> = [
{ label: "全部邀约", value: "all" }, { label: "全部邀约", value: "all" },
{ label: "待到访", value: "pending" }, { label: "待到访", value: "pending" },
{ label: "已到访", value: "arrived" }, { label: "已到访", value: "arrived" },
{ label: "未到访", value: "noShow" }, { label: "未到访", value: "noShow" },
{ label: "已缴费", value: "paid" }, { label: "已缴费", value: "paid" },
]; ];
const { searchKeyword, activeFilter, records, loading, finished, error, showEmpty, loadNextPage, submitSearch, clearSearch } = useTeacherInvitationData(20); const { searchKeyword, activeFilter, records, loading, finished, error, showEmpty, loadNextPage, submitSearch, clearSearch } = useTeacherInvitationData(20);
const statusColors: Readonly<Record<string, string>> = { const statusColors: Readonly<Record<string, string>> = {
待到访: "#06C764", 待到访: "#06C764",
已到访: "#1580FF", 已到访: "#1580FF",
已完成: "#1580FF", 已完成: "#1580FF",
未到访: "#969696", 未到访: "#969696",
}; };
const getStatusColor = (statusName: string): string => statusColors[statusName] ?? "#666666"; const getStatusColor = (statusName: string): string => statusColors[statusName] ?? "#666666";
</script> </script>
<style scoped> <style scoped>
:global(.invitation-data) { :global(.invitation-data) {
--van-search-padding: 4px 15px 0; --van-search-padding: 4px 15px 0;
--van-search-content-background: #f3f4f8; --van-search-content-background: #f3f4f8;
--van-search-input-height: 38px; --van-search-input-height: 38px;
--van-tab-font-size: 15px; --van-tab-font-size: 15px;
} }
:global(.invitation-data .van-search__content) { :global(.invitation-data .van-search__content) {
border-radius: 81px; border-radius: 81px;
--van-field-placeholder-text-color: #c0c4cc; --van-field-placeholder-text-color: #c0c4cc;
--van-padding-sm: 15px; --van-padding-sm: 15px;
} }
:global(.invitation-data .van-field__left-icon) { :global(.invitation-data .van-field__left-icon) {
--van-field-icon-size: 14px; --van-field-icon-size: 14px;
--van-padding-base: 5px; --van-padding-base: 5px;
line-height: 1; line-height: 1;
} }
:global(.invitation-data .van-tabs--line .van-tabs__wrap) { :global(.invitation-data .van-tabs--line .van-tabs__wrap) {
--van-tabs-line-height: 38px; --van-tabs-line-height: 38px;
} }
:deep(.van-tab) { :deep(.van-tab) {
--van-tab-font-size: 15px; --van-tab-font-size: 15px;
--van-font-bold: 400; --van-font-bold: 400;
} }
:deep(.van-tab--active) { :deep(.van-tab--active) {
--van-tab-font-size: 16px; --van-tab-font-size: 16px;
--van-font-bold: 500; --van-font-bold: 500;
} }
:deep(.van-empty) { :deep(.van-empty) {
--van-empty-padding: 50% 0; --van-empty-padding: 50% 0;
} }
</style> </style>