Files
jiapuapp/pages/records/r03-gift-list.vue
T

193 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 页面编号R-03用途读取并展示当前家谱的亲友往来记录 -->
<template>
<view class="gift-page">
<ModulePageBackground module="records" />
<view class="page-header"
><PageHeader
title="贺礼簿"
:action="valid ? '新建' : ''"
custom-back
@back="returnToFamily"
@action="createRelative"
/></view>
<view class="page-content">
<view v-if="!valid" class="state-card"
><text>贺礼簿入口无效</text
><AppButton block label="返回上一页" @click="returnToFamily"
/></view>
<view v-else-if="state === 'loading'" class="state-card"
><AppLoading text="正在读取亲友往来"
/></view>
<view v-else-if="state === 'error'" class="state-card"
><text>暂时无法读取亲友往来</text
><AppButton
block
type="secondary"
label="重新加载"
@click="loadRecords"
/></view>
<view v-else-if="state === 'empty'" class="state-card"
><text>还没有亲友往来记录</text
><AppButton block label="新建往来记录" @click="createRelative"
/></view>
<view v-else class="record-list">
<view v-for="item in records" :key="item.id" class="record-card">
<view
><text>{{ item.name }}</text
><text
>{{ item.relation
}}{{ item.event ? ` · ${item.event}` : "" }}</text
><text v-if="item.time || item.content">{{
item.time || item.content
}}</text></view
>
<text v-if="item.amount">¥{{ item.amount }}</text>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { computed, ref } from "vue";
import { onLoad, onShow, onUnload } from "@dcloudio/uni-app";
import AppButton from "@/components/AppButton.vue";
import AppLoading from "@/components/AppLoading.vue";
import ModulePageBackground from "@/components/ModulePageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import {
appApi,
createRequestController,
isRequestCancelled,
} from "@/utils/api.js";
import { goBack, openPage, returnTo } from "@/utils/navigation.js";
const genealogyId = ref("");
const records = ref([]);
const state = ref("loading");
const controller = createRequestController();
let active = true;
const valid = computed(() => /^[1-9]\d*$/.test(genealogyId.value));
const loadRecords = async () => {
if (!valid.value) return;
controller.abort();
state.value = "loading";
try {
const rows = await appApi.getRelativeRecords(genealogyId.value, {
requestController: controller,
});
if (!active) return;
records.value = rows
.map((item) => ({
id: String(item.relativeId || ""),
name: String(item.relativeName || "未命名亲友"),
relation: String(item.relationName || ""),
event: String(item.eventName || ""),
time: String(item.eventTime || ""),
amount:
item.giftAmount == null || item.giftAmount === ""
? ""
: String(item.giftAmount),
content: String(item.recordContent || ""),
}))
.filter((item) => /^[1-9]\d*$/.test(item.id));
state.value = records.value.length ? "ready" : "empty";
} catch (error) {
if (!active || isRequestCancelled(error)) return;
state.value = "error";
}
};
const returnToFamily = () =>
valid.value ? returnTo("F01", { genealogyId: genealogyId.value }) : goBack();
const createRelative = () =>
valid.value
? openPage("R04", { genealogyId: genealogyId.value, mode: "create" }, "R03")
: Promise.resolve(false);
onLoad((query) => {
genealogyId.value = String(query?.genealogyId || "");
if (valid.value) loadRecords();
});
onShow(() => {
if (valid.value && state.value !== "loading") loadRecords();
});
onUnload(() => {
active = false;
controller.abort();
});
</script>
<style scoped lang="scss">
@import "../../styles/adaptive-frame-profiles.scss";
.gift-page {
display: flex;
min-height: 100vh;
flex-direction: column;
background: $paper;
}
.page-header,
.page-content {
z-index: 1;
}
.page-content {
padding: 18rpx 24rpx 72rpx;
}
.state-card,
.record-card {
@include adaptive-records-content;
}
.state-card {
display: flex;
min-height: 320rpx;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 42rpx;
text-align: center;
color: $ink;
font-size: clamp(16px, 28rpx, 20px);
}
.state-card .app-button {
width: 100%;
margin-top: 24rpx;
}
.record-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.record-card {
display: flex;
min-height: 138rpx;
align-items: center;
justify-content: space-between;
gap: 18rpx;
padding: 28rpx 32rpx;
}
.record-card > view {
min-width: 0;
flex: 1;
}
.record-card text {
display: block;
}
.record-card > view text:first-child {
color: $ink;
font-family: STKaiti, KaiTi, serif;
font-size: clamp(17px, 30rpx, 22px);
font-weight: 700;
overflow-wrap: anywhere;
}
.record-card > view text:not(:first-child) {
margin-top: 7rpx;
color: $ink-muted;
font-size: clamp(13px, 21rpx, 16px);
line-height: 1.45;
overflow-wrap: anywhere;
}
.record-card > text {
flex: 0 0 auto;
color: $brand-red;
font-size: clamp(14px, 22rpx, 17px);
}
</style>