完成80%

This commit is contained in:
2026-07-27 06:50:07 +08:00
parent 8475bbd19a
commit 1eae3bbef4
63 changed files with 13664 additions and 280 deletions
+10 -6
View File
@@ -8,6 +8,8 @@
<text>新建功德记录</text>
<text class="form-copy">红色 * 为必填项其余内容可按需补充</text>
<view v-for="field in fields" :key="field.key" class="field"><text><text v-if="field.required" class="required-mark">*</text>{{ field.label }}</text><textarea v-if="field.key === 'content'" v-model="form[field.key]" auto-height :placeholder="`请输入${field.label}`" @input="error = ''" /><input v-else v-model="form[field.key]" :type="field.inputType || 'text'" :placeholder="field.placeholder || `请输入${field.label}`" @input="error = ''" /></view>
<view class="field field--picker"><text>记录日期</text><picker mode="date" :value="form.meritDate" @change="selectMeritDate"><view :class="{ placeholder: !form.meritDate }">{{ form.meritDate || '请选择' }}</view></picker></view>
<view class="field field--picker"><text>记录时间</text><picker mode="time" :value="form.meritClock" @change="selectMeritClock"><view :class="{ placeholder: !form.meritClock }">{{ form.meritClock || '请选择' }}</view></picker></view>
<text v-if="error" class="error">{{ error }}</text>
<view class="form-actions"><AppButton type="secondary" label="取消" @click="cancelCreate" /><AppButton :disabled="submitting" :label="submitting ? '正在提交' : '提交功德记录'" @click="submit" /></view>
</view>
@@ -45,13 +47,12 @@ const saveNotice = ref(false);
const submitting = ref(false);
const error = ref("");
const discardVisible = ref(false);
const form = reactive({ donor: "", title: "", type: "", amount: "", time: "", content: "", sortOrder: "" });
const form = reactive({ donor: "", title: "", type: "", amount: "", meritDate: "", meritClock: "", content: "", sortOrder: "" });
const fields = [
{ key: "donor", label: "捐赠人", required: true },
{ key: "title", label: "功德标题", required: true },
{ key: "type", label: "功德类型" },
{ key: "amount", inputType: "digit", label: "金额" },
{ key: "time", label: "记录时间" },
{ key: "content", label: "记录内容" },
{ key: "sortOrder", label: "排序值", inputType: "number", placeholder: "数值越小越靠前" },
];
@@ -59,12 +60,13 @@ const controller = createRequestController();
let active = true;
const valid = computed(() => /^[1-9]\d*$/.test(genealogyId.value));
const dirty = computed(() => Object.values(form).some((value) => String(value).trim()));
const meritTime = computed(() => form.meritDate ? `${form.meritDate} ${form.meritClock || "00:00"}:00` : "");
const totalAmount = computed(() => merits.value.reduce((total, item) => total + item.amount, 0).toFixed(2));
const confirmation = createDiscardConfirmation((visible) => { discardVisible.value = visible; });
const confirmDiscard = () => { confirmation.confirm(); resetForm(); view.value = "list"; };
const cancelDiscard = confirmation.cancel;
const resetForm = () => { Object.assign(form, { donor: "", title: "", type: "", amount: "", time: "", content: "", sortOrder: "" }); error.value = ""; };
const resetForm = () => { Object.assign(form, { donor: "", title: "", type: "", amount: "", meritDate: "", meritClock: "", content: "", sortOrder: "" }); error.value = ""; };
const loadMerits = async () => {
if (!valid.value) return;
controller.abort();
@@ -89,6 +91,8 @@ const loadMerits = async () => {
};
const openCreate = () => { if (!valid.value) return; saveNotice.value = false; resetForm(); view.value = "form"; };
const cancelCreate = () => { resetForm(); view.value = "list"; };
const selectMeritDate = (event) => { form.meritDate = event.detail.value || ""; error.value = ""; };
const selectMeritClock = (event) => { form.meritClock = event.detail.value || ""; error.value = ""; };
const submit = async () => {
if (submitting.value || !valid.value) return;
const donorName = form.donor.trim();
@@ -99,7 +103,7 @@ const submit = async () => {
submitting.value = true;
error.value = "";
try {
await appApi.createMeritRecord(genealogyId.value, { donorName, meritTitle, meritType: form.type, meritContent: form.content, meritTime: form.time, sortOrder: form.sortOrder, ...(amountText ? { amount: Number(amountText) } : {}) }, { requestController: controller });
await appApi.createMeritRecord(genealogyId.value, { donorName, meritTitle, meritType: form.type, meritContent: form.content, meritTime: meritTime.value, sortOrder: form.sortOrder, ...(amountText ? { amount: Number(amountText) } : {}) }, { requestController: controller });
resetForm();
view.value = "list";
saveNotice.value = true;
@@ -122,6 +126,6 @@ onUnmounted(() => { active = false; controller.abort(); confirmation.dispose();
@use "../../styles/adaptive-frame-profiles.scss" as adaptive;
.merit-page { display: flex; min-height: 100vh; flex-direction: column; background: $paper; }.page-header, .page-content { z-index: 1; }.page-content { padding: 18rpx 24rpx 72rpx; }
.form-card, .state-card, .merit-card { @include adaptive.adaptive-records-content; }.form-card { box-sizing: border-box; padding: 46rpx; }.form-card > text:first-child { display: block; color: $ink; font-size: 34rpx; font-weight: 700; }.form-copy { display: block; margin-top: 12rpx; color: $ink-muted; font-size: 22rpx; line-height: 1.55; }
.field { margin-top: 16rpx; }.field > text { display: block; margin: 0 8rpx 8rpx; color: $ink; font-size: 23rpx; font-weight: 700; }.required-mark { display: inline-block; margin-right: 4rpx; color: $brand-red; font-size: 26rpx; transform: translateY(-3rpx); }.field input, .field textarea { @include adaptive.adaptive-records-field; box-sizing: border-box; width: 100%; min-height: 76rpx; padding: 16rpx 22rpx; color: $ink; font-size: 23rpx; }.field textarea { min-height: 150rpx; }.error { display: block; margin-top: 12rpx; color: $brand-red; font-size: 22rpx; }
.form-actions { display: grid; grid-template-columns: 1fr 1.45fr; gap: 16rpx; margin-top: 20rpx; }.state-card { display: flex; min-height: 320rpx; flex-direction: column; align-items: center; justify-content: center; padding: 42rpx; color: $ink; font-size: 28rpx; text-align: center; }.state-card .app-button { width: 100%; margin-top: 24rpx; }.merit-list { display: flex; flex-direction: column; gap: 16rpx; }.save-notice { display: block; color: $brand-red; font-size: 22rpx; }.merit-summary { display: block; color: $ink-muted; font-size: 22rpx; }.merit-card { display: flex; min-height: 138rpx; align-items: center; justify-content: space-between; gap: 18rpx; padding: 28rpx 32rpx; }.merit-card > view { min-width: 0; flex: 1; }.merit-card text { display: block; }.merit-card > view text:first-child { color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 30rpx; font-weight: 700; overflow-wrap: anywhere; }.merit-card > view text:not(:first-child) { margin-top: 7rpx; color: $ink-muted; font-size: 21rpx; line-height: 1.45; overflow-wrap: anywhere; }.merit-card > text { flex: 0 0 auto; color: $brand-red; font-size: 22rpx; }
.field { margin-top: 16rpx; }.field > text { display: block; margin: 0 8rpx 8rpx; color: $ink; font-size: 23rpx; font-weight: 700; }.required-mark { display: inline-block; margin-right: 4rpx; color: $brand-red; font-size: 26rpx; transform: translateY(-3rpx); }.field input, .field textarea, .field--picker picker > view { @include adaptive.adaptive-records-field; box-sizing: border-box; width: 100%; min-height: 76rpx; padding: 16rpx 22rpx; color: $ink; font-size: 23rpx; }.field textarea { min-height: 150rpx; }.field--picker picker { display: block; }.field--picker .placeholder { color: $ink-muted; }.error { display: block; margin-top: 12rpx; color: $brand-red; font-size: 22rpx; }
.form-actions { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr); gap: 16rpx; margin-top: 20rpx; }.form-actions .app-button { width: 100%; min-width: 0; }.state-card { display: flex; min-height: 320rpx; flex-direction: column; align-items: center; justify-content: center; padding: 42rpx; color: $ink; font-size: 28rpx; text-align: center; }.state-card .app-button { width: 100%; margin-top: 24rpx; }.merit-list { display: flex; flex-direction: column; gap: 16rpx; }.save-notice { display: block; color: $brand-red; font-size: 22rpx; }.merit-summary { display: block; color: $ink-muted; font-size: 22rpx; }.merit-card { display: flex; min-height: 138rpx; align-items: center; justify-content: space-between; gap: 18rpx; padding: 28rpx 32rpx; }.merit-card > view { min-width: 0; flex: 1; }.merit-card text { display: block; }.merit-card > view text:first-child { color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 30rpx; font-weight: 700; overflow-wrap: anywhere; }.merit-card > view text:not(:first-child) { margin-top: 7rpx; color: $ink-muted; font-size: 21rpx; line-height: 1.45; overflow-wrap: anywhere; }.merit-card > text { flex: 0 0 auto; color: $brand-red; font-size: 22rpx; }
</style>