40 lines
4.5 KiB
Vue
40 lines
4.5 KiB
Vue
<template>
|
|
<view class="ritual-list-page">
|
|
<ModulePageBackground module="records" />
|
|
<view class="page-header"><PageHeader title="礼仪活动" :action="valid ? '新建' : ''" custom-back @back="returnToFamily" @action="createCeremony" /></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="loadCeremonies" /></view>
|
|
<view v-else-if="state === 'empty'" class="state-card"><text>还没有礼仪活动</text><AppButton block label="新建礼仪活动" @click="createCeremony" /></view>
|
|
<view v-else class="ceremony-list"><view v-for="item in ceremonies" :key="item.id" class="ceremony-card" @click="openCeremony(item)"><view><text>{{ item.title }}</text><text>{{ item.type }}{{ item.time ? ` · ${item.time}` : '' }}</text><text v-if="item.description">{{ item.description }}</text></view><text>{{ item.giftCount }} 笔献礼</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 ceremonies = ref([]); const state = ref("loading"); const controller = createRequestController(); let active = true;
|
|
const valid = computed(() => /^[1-9]\d*$/.test(genealogyId.value));
|
|
const loadCeremonies = async () => { if (!valid.value) return; controller.abort(); state.value = "loading"; try { const rows = await appApi.getCeremonies(genealogyId.value, { requestController: controller }); if (!active) return; ceremonies.value = rows.map((item) => ({ id: String(item.ceremonyId), title: String(item.ceremonyTitle || "未命名活动"), type: String(item.ceremonyType || ""), time: String(item.ceremonyTime || ""), description: String(item.ceremonyDesc || ""), giftCount: Number.isSafeInteger(item.giftCount) ? item.giftCount : 0 })).filter((item) => /^[1-9]\d*$/.test(item.id)); state.value = ceremonies.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 createCeremony = () => valid.value ? openPage("R07", { genealogyId: genealogyId.value, mode: "create" }, "R05") : Promise.resolve(false);
|
|
const openCeremony = (item) => openPage("R06", { genealogyId: genealogyId.value, ceremonyId: item.id }, "R05");
|
|
onLoad((query) => { genealogyId.value = String(query?.genealogyId || ""); if (valid.value) loadCeremonies(); });
|
|
onShow(() => { if (valid.value && state.value !== "loading") loadCeremonies(); });
|
|
onUnload(() => { active = false; controller.abort(); });
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
|
|
.ritual-list-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,.ceremony-card{@include adaptive.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:28rpx}.state-card .app-button{width:100%;margin-top:24rpx}.ceremony-list{display:flex;flex-direction:column;gap:16rpx}.ceremony-card{display:flex;min-height:138rpx;align-items:center;justify-content:space-between;gap:18rpx;padding:28rpx 32rpx}.ceremony-card>view{min-width:0;flex:1}.ceremony-card text{display:block}.ceremony-card>view text:first-child{color:$ink;font-family:STKaiti,KaiTi,serif;font-size:30rpx;font-weight:700;overflow-wrap:anywhere}.ceremony-card>view text:not(:first-child){margin-top:7rpx;color:$ink-muted;font-size:21rpx;line-height:1.45;overflow-wrap:anywhere}.ceremony-card>text{flex:0 0 auto;color:$brand-red;font-size:21rpx}
|
|
</style>
|