Files
jiapuapp/pages/family/f07-album-list.vue
T
2026-07-24 07:56:33 +08:00

105 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.
<!-- 页面编号F-07用途相册入口列表 DTO 缺失时不展示本地相册 -->
<template>
<view class="album-list-page">
<ModulePageBackground module="family" />
<view class="album-list-header"><PageHeader title="家族相册" :action="hasValidContext ? '新建' : ''" custom-back @back="requestBack" @action="openCreateDialog" /></view>
<view class="album-list-content">
<view class="album-state-card">
<text>{{ stateCopy.title }}</text>
<text>{{ stateCopy.copy }}</text>
<AppButton block :label="stateCopy.action" @click="handleStateAction" />
</view>
</view>
<AppDialog :visible="dialogVisible" eyebrow="新建相册" title="为家人整理一段影像" message="仅提交已声明的相册名称;封面、排序和状态没有可用 owner,不会猜测提交。" :confirm-text="isSubmitting ? '正在提交' : '提交相册'" cancel-text="取消" show-cancel :close-on-mask="false" @confirm="submitAlbum" @cancel="closeCreateDialog">
<view class="album-dialog-field">
<text>相册名称</text>
<input v-model="albumNameDraft" maxlength="30" placeholder="例如:春节团圆" @input="submitError = ''" />
<text v-if="submitError">{{ submitError }}</text>
</view>
</AppDialog>
</view>
</template>
<script setup>
import { computed, onUnmounted, ref } from "vue";
import { onBackPress, onLoad } from "@dcloudio/uni-app";
import AppButton from "@/components/AppButton.vue";
import AppDialog from "@/components/AppDialog.vue";
import ModulePageBackground from "@/components/ModulePageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
import { appApi, createRequestController, isRequestCancelled } from "@/utils/api.js";
import { goBack, handleBackPress, runBackGuard } from "@/utils/navigation.js";
const genealogyId = ref("");
const hasValidContext = ref(false);
const dialogVisible = ref(false);
const albumNameDraft = ref("");
const submitError = ref("");
const isSubmitting = ref(false);
const created = ref(false);
const requestController = createRequestController();
const stateCopy = computed(() => !hasValidContext.value
? { title: "相册入口无效", copy: "没有取得有效家谱标识,页面不会展示其他家谱相册。", action: "返回上一页" }
: created.value
? { title: "相册已提交服务端", copy: "服务端已返回成功信封;相册列表仍没有条目 DTO,页面不会生成本地相册卡片。", action: "新建相册" }
: { title: "相册列表待后端字段合同", copy: "列表响应没有声明相册 ID、封面、名称、照片数、描述或更新时间字段;页面已停止展示本地相册。", action: "新建相册" },
);
onLoad((query) => {
genealogyId.value = String(query?.genealogyId || "");
hasValidContext.value = /^[1-9]\d*$/.test(genealogyId.value);
});
const openCreateDialog = () => {
if (!hasValidContext.value || isSubmitting.value) return;
albumNameDraft.value = "";
submitError.value = "";
dialogVisible.value = true;
};
const closeCreateDialog = () => {
if (!isSubmitting.value) dialogVisible.value = false;
};
const submitAlbum = async () => {
if (isSubmitting.value) return;
const albumName = albumNameDraft.value.trim();
if (!albumName) {
submitError.value = "请填写相册名称";
return;
}
isSubmitting.value = true;
submitError.value = "";
try {
await appApi.createAlbum(genealogyId.value, { albumName }, { requestController });
dialogVisible.value = false;
created.value = true;
} catch (error) {
if (!isRequestCancelled(error)) submitError.value = error?.message || "相册提交失败,请稍后重试。";
} finally {
isSubmitting.value = false;
}
};
const requestBack = () => runBackGuard({
transientOpen: dialogVisible.value,
submitting: isSubmitting.value,
"close-transient": closeCreateDialog,
"block-submitting": () => true,
});
const handleStateAction = () => hasValidContext.value ? openCreateDialog() : goBack();
onBackPress((event) => handleBackPress(event, requestBack));
onUnmounted(() => requestController.abort());
</script>
<style scoped lang="scss">
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
.album-list-page { display: flex; min-height: 100vh; flex-direction: column; background: $paper; }
.album-list-header, .album-list-content { z-index: 1; }
.album-list-content { padding: 18rpx 24rpx 72rpx; }
.album-state-card { @include adaptive.adaptive-family-content; width: 100%; min-height: 340rpx; margin-top: 30rpx; padding: 78rpx 52rpx 50rpx; text-align: center; }
.album-state-card > text { display: block; }
.album-state-card > text:first-child { color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 35rpx; font-weight: 700; }
.album-state-card > text:nth-child(2) { margin-top: 18rpx; color: $ink-muted; font-size: 24rpx; line-height: 1.65; }
.album-state-card .app-button { margin-top: 28rpx; }
.album-dialog-field { width: 100%; margin: 24rpx 0; text-align: left; }
.album-dialog-field > text:first-child { display: block; color: $ink; font-size: 23rpx; font-weight: 700; }
.album-dialog-field input { @include adaptive.adaptive-family-field; width: 100%; min-height: 76rpx; margin-top: 10rpx; padding: 0 22rpx; color: $ink; font-size: 24rpx; }
.album-dialog-field > text:last-child { display: block; margin-top: 8rpx; color: $brand-red; font-size: 21rpx; }
</style>