Files
jiapuapp/pages/records/r04-gift-editor.vue
T
2026-07-21 07:53:08 +08:00

261 lines
7.4 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-04用途贺礼查看新增编辑保存与删除确认 -->
<template>
<view class="gift-editor-page" :class="editorClasses">
<ModulePageBackground module="records" />
<view class="page-header">
<PageHeader
:title="
mode === 'create'
? '新增贺礼'
: mode === 'view'
? '贺礼详情'
: '编辑贺礼'
"
:action="mode === 'view' ? '编辑' : ''"
@action="mode = 'edit'"
/>
</view>
<view v-if="editorState === 'loading'" class="page-loading">
<AppLoading
text="正在读取贺礼"
description="请稍候,正在整理这份礼仪记录。"
/>
</view>
<view v-else class="page-content">
<view v-if="editorState === 'success'" class="state-card">
<text>贺礼已保存</text>
<text>这份心意已加入家族贺礼簿</text>
<AppButton block label="返回贺礼簿" @click="backToGifts" />
</view>
<view v-else-if="mode === 'view'" class="detail-card">
<text>{{ giftForm.title }}</text>
<view v-for="item in detailRows" :key="item.label">
<text>{{ item.label }}</text>
<text>{{ item.value }}</text>
</view>
<AppButton block label="编辑贺礼" @click="mode = 'edit'" />
<AppButton
type="secondary"
block
label="删除记录"
@click="confirmDelete"
/>
</view>
<view v-else class="form-card">
<text>
{{ mode === "create" ? "记录一份家人心意" : "修改贺礼信息" }}
</text>
<view v-for="field in fields" :key="field.key" class="field-row">
<text>{{ field.label }}</text>
<input
v-model="giftForm[field.key]"
:placeholder="`请输入${field.label}`"
/>
<text v-if="giftErrors[field.key]">{{ giftErrors[field.key] }}</text>
</view>
<text v-if="editorState === 'error'" class="save-error">
保存失败请检查内容后重试
</text>
<AppButton
block
:disabled="editorState === 'saving'"
:label="editorState === 'saving' ? '正在保存' : '保存贺礼'"
@click="saveGift"
/>
<AppButton
v-if="mode === 'edit'"
type="secondary"
block
label="删除记录"
@click="confirmDelete"
/>
</view>
</view>
<AppDialog
:visible="deleteVisible"
eyebrow="删除确认"
title="删除这份贺礼?"
message="删除后将返回贺礼簿,本地演示记录不会继续显示。"
confirm-text="确认删除"
cancel-text="保留记录"
show-cancel
@confirm="deleteGift"
@cancel="deleteVisible = false"
/>
</view>
</template>
<script setup>
import { computed, onUnmounted, reactive, ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import AppButton from "@/components/AppButton.vue";
import AppDialog from "@/components/AppDialog.vue";
import AppLoading from "@/components/AppLoading.vue";
import ModulePageBackground from "@/components/ModulePageBackground.vue";
import PageHeader from "@/components/PageHeader.vue";
const records = [
{
id: "301",
title: "新春贺礼",
from: "汤文正一家",
date: "2024-02-10",
note: "新春团拜时赠予长辈的心意",
},
{
id: "302",
title: "寿宴礼单",
from: "汤淑华",
date: "2024-04-18",
note: "汤老先生八十寿辰",
},
];
const giftId = ref("");
const mode = ref("create");
const editorState = ref("ready");
const deleteVisible = ref(false);
const forceSaveFailure = ref(false);
const giftForm = reactive({ title: "", from: "", date: "", note: "" });
const giftErrors = reactive({ title: "", from: "", date: "" });
const fields = [
{ key: "title", label: "贺礼名称" },
{ key: "from", label: "赠送人" },
{ key: "date", label: "日期" },
{ key: "note", label: "备注" },
];
let saveTimer = null;
const editorClasses = computed(() => ({
"gift-editor-state--saving": editorState.value === "saving",
"gift-editor-state--error": editorState.value === "error",
}));
const detailRows = computed(() =>
fields
.slice(1)
.map((f) => ({ label: f.label, value: giftForm[f.key] || "未填写" })),
);
onLoad((query) => {
giftId.value = String(query.giftId || "");
mode.value = ["view", "edit"].includes(query.mode) ? query.mode : "create";
forceSaveFailure.value = query.saveResult === "error";
const selected = records.find((x) => x.id === giftId.value);
if (selected) Object.assign(giftForm, selected);
else if (mode.value !== "create") editorState.value = "error";
if (query.state === "loading") editorState.value = "loading";
});
const validateGift = () => {
giftErrors.title = giftForm.title.trim() ? "" : "请填写贺礼名称";
giftErrors.from = giftForm.from.trim() ? "" : "请填写赠送人";
giftErrors.date = giftForm.date.trim() ? "" : "请填写日期";
return !giftErrors.title && !giftErrors.from && !giftErrors.date;
};
const saveGift = () => {
if (editorState.value === "saving" || !validateGift()) return;
editorState.value = "saving";
saveTimer = setTimeout(() => {
editorState.value = forceSaveFailure.value ? "error" : "success";
forceSaveFailure.value = false;
}, 320);
};
const confirmDelete = () => {
deleteVisible.value = true;
};
const deleteGift = () => {
deleteVisible.value = false;
backToGifts();
};
const backToGifts = () =>
uni.redirectTo({ url: "/pages/records/r03-gift-list" });
onUnmounted(() => {
if (saveTimer) clearTimeout(saveTimer);
});
</script>
<style scoped lang="scss">
.gift-editor-page {
display: flex;
min-height: 100vh;
flex-direction: column;
background: $paper;
}
.page-header,
.page-loading,
.page-content {
z-index: 1;
}
.page-loading {
min-height: calc(100vh - 100rpx);
}
.page-content {
padding: 18rpx 24rpx 72rpx;
}
.form-card,
.detail-card,
.state-card {
box-sizing: border-box;
padding: 46rpx;
background: url("/static/assets/modules/records/transparent/module-content-frame.png")
center/100% 100% no-repeat;
}
.form-card > text:first-child,
.detail-card > text:first-child,
.state-card > text:first-child {
display: block;
color: $ink;
font-size: 34rpx;
font-weight: 700;
}
.field-row,
.detail-card > view {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
align-items: center;
gap: 12rpx 20rpx;
min-height: 82rpx;
margin-top: 14rpx;
padding: 14rpx 24rpx;
box-sizing: border-box;
background: url("/static/assets/modules/records/transparent/module-field-frame.png")
center/100% 100% no-repeat;
}
.field-row > text:first-child,
.detail-card > view > text:first-child {
color: $ink;
font-size: 23rpx;
font-weight: 700;
}
.field-row input,
.detail-card > view > text:last-child {
min-width: 0;
color: $ink;
font-size: 23rpx;
text-align: right;
}
.field-row > text:last-child {
grid-column: 1/-1;
color: $brand-red;
font-size: 20rpx;
text-align: right;
}
.form-card .app-button,
.detail-card .app-button {
margin-top: 18rpx;
}
.save-error {
display: block;
margin-top: 14rpx;
color: $brand-red;
font-size: 22rpx;
}
.state-card {
min-height: 340rpx;
padding-top: 80rpx;
text-align: center;
}
.state-card > text:nth-child(2) {
display: block;
margin-top: 18rpx;
color: $ink-muted;
font-size: 24rpx;
}
.state-card .app-button {
margin-top: 28rpx;
}
</style>