14 lines
5.8 KiB
Vue
14 lines
5.8 KiB
Vue
<!-- 页面编号:R-11;用途:功德记录创建。列表 DTO 缺失时不展示 fixture。 -->
|
||
<template>
|
||
<view class="merit-page"><ModulePageBackground module="records" /><view class="page-header"><PageHeader title="功德记录" custom-back @back="requestBack" /></view><view class="page-content"><view v-if="state === 'form'" class="form-card"><text>新建功德记录</text><text class="form-copy">列表没有展示 DTO;本页仅提交已声明的捐赠人、标题、类型、金额、时间和内容,不猜测状态或排序。</text><view v-for="field in fields" :key="field.key" class="field"><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.key === 'amount' ? 'digit' : 'text'" :placeholder="`请输入${field.label}`" @input="error = ''" /></view><text v-if="error" class="error">{{ error }}</text><AppButton block :disabled="submitting" :label="submitting ? '正在提交' : '提交功德记录'" @click="submit" /></view><view v-else class="state-card"><text>{{ result.title }}</text><text>{{ result.copy }}</text><AppButton block :label="result.action" @click="resultAction" /></view></view><AppDialog :visible="discardVisible" title="放弃功德记录?" message="尚未提交的内容将被清除。" confirm-text="放弃并返回" cancel-text="继续填写" show-cancel :close-on-mask="false" @confirm="confirmDiscard" @cancel="cancelDiscard" /></view>
|
||
</template>
|
||
<script setup>
|
||
import { computed,onUnmounted,reactive,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 { createDiscardConfirmation } from "@/utils/discard-confirmation.js"; import { goBack,handleBackPress,returnTo,runBackGuard } from "@/utils/navigation.js";
|
||
const genealogyId=ref("");const state=ref("form");const submitting=ref(false);const error=ref("");const discardVisible=ref(false);const form=reactive({donor:"",title:"",type:"",amount:"",time:"",content:""});const fields=[{key:"donor",label:"捐赠人"},{key:"title",label:"功德标题"},{key:"type",label:"功德类型"},{key:"amount",label:"金额"},{key:"time",label:"记录时间"},{key:"content",label:"记录内容"}];const controller=createRequestController();const valid=computed(()=>/^[1-9]\d*$/.test(genealogyId.value));const dirty=computed(()=>Object.values(form).some((value)=>value.trim()));const result=computed(()=>state.value==="success"?{title:"功德记录已提交服务端",copy:"服务端已返回成功信封;列表仍缺条目 DTO,不生成本地功德记录。",action:"返回功德记录"}:{title:"功德记录入口无效",copy:"没有取得有效家谱标识。",action:"返回上一页"});const confirmation=createDiscardConfirmation((visible)=>{discardVisible.value=visible;});const confirmDiscard=confirmation.confirm;const cancelDiscard=confirmation.cancel;
|
||
onLoad((query)=>{genealogyId.value=String(query?.genealogyId||"");if(!valid.value)state.value="invalid";});const submit=async()=>{if(submitting.value||!valid.value)return;const donorName=form.donor.trim();const meritTitle=form.title.trim();const amountText=form.amount.trim();if(!donorName||!meritTitle){error.value=!donorName?"请填写捐赠人":"请填写功德标题";return;}if(amountText&&!Number.isFinite(Number(amountText))){error.value="金额必须是数字";return;}submitting.value=true;error.value="";try{await appApi.createMeritRecord(genealogyId.value,{donorName,meritTitle,meritType:form.type,meritContent:form.content,meritTime:form.time,...(amountText?{amount:Number(amountText)}:{})},{requestController:controller});Object.keys(form).forEach((key)=>{form[key]="";});state.value="success";}catch(cause){if(!isRequestCancelled(cause))error.value=cause?.message||"功德记录提交失败,请稍后重试。";}finally{submitting.value=false;}};const requestBack=()=>runBackGuard({transientOpen:discardVisible.value,dirty:dirty.value,submitting:submitting.value,"close-transient":cancelDiscard,"block-submitting":()=>true,"confirm-discard":confirmation.request});const resultAction=()=>state.value==="success"?returnTo("R11",{genealogyId:genealogyId.value}):goBack();onBackPress((event)=>handleBackPress(event,requestBack));onUnmounted(()=>{controller.abort();confirmation.dispose();});
|
||
</script>
|
||
<style scoped lang="scss">
|
||
@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{box-sizing:border-box;padding:46rpx;@include adaptive.adaptive-records-content}.form-card>text:first-child,.state-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}.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-card .app-button{margin-top:20rpx}.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;line-height:1.65}.state-card .app-button{margin-top:28rpx}
|
||
</style>
|