Review changes batch 6 of 6
This commit is contained in:
@@ -2,50 +2,117 @@
|
||||
<template>
|
||||
<view class="join-page">
|
||||
<GenealogyPageBackground />
|
||||
<view class="join-page__header"><PageHeader :title="sourceContract.headerTitle" /></view>
|
||||
<view class="join-page__header"
|
||||
><PageHeader :title="sourceContract.headerTitle"
|
||||
/></view>
|
||||
|
||||
<view class="join-panel" :class="{
|
||||
'join-state--form': joinState === 'form',
|
||||
'join-state--success': joinState === 'success',
|
||||
'join-state--error': joinState === 'error'
|
||||
}">
|
||||
<image class="join-panel__skin" src="/static/assets/modules/genealogy/opaque/g03-create-flow-panel.png" mode="scaleToFill" />
|
||||
<view
|
||||
class="join-panel"
|
||||
:class="{
|
||||
'join-state--form': joinState === 'form',
|
||||
'join-state--success': joinState === 'success',
|
||||
'join-state--error': joinState === 'error',
|
||||
}"
|
||||
>
|
||||
<image
|
||||
class="join-panel__skin"
|
||||
src="/static/assets/modules/genealogy/transparent/g01-empty-panel-frame.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
|
||||
<view v-if="joinState === 'form'" class="join-form">
|
||||
<text class="join-form__eyebrow">{{ sourceContract.eyebrow }}</text>
|
||||
<text class="join-form__title">{{ sourceContract.formTitle }} {{ genealogyName }}</text>
|
||||
<text class="join-form__title"
|
||||
>{{ sourceContract.formTitle }} {{ genealogyName }}</text
|
||||
>
|
||||
<text class="join-form__copy">{{ sourceContract.formCopy }}</text>
|
||||
|
||||
<view class="join-field">
|
||||
<image src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" />
|
||||
<text>真实姓名</text><input v-model="form.realName" placeholder="请输入真实姓名" placeholder-class="join-placeholder" @input="clearFieldError('realName')" />
|
||||
<image
|
||||
src="/static/assets/modules/genealogy/transparent/g-form-field-frame.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<text>真实姓名</text
|
||||
><input
|
||||
v-model="form.realName"
|
||||
placeholder="请输入真实姓名"
|
||||
placeholder-class="join-placeholder"
|
||||
@input="clearFieldError('realName')"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="fieldErrors.realName" class="join-field-error">{{ fieldErrors.realName }}</text>
|
||||
<text v-if="fieldErrors.realName" class="join-field-error">{{
|
||||
fieldErrors.realName
|
||||
}}</text>
|
||||
<view class="join-field">
|
||||
<image src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" />
|
||||
<text>与家谱关系</text><input v-model="form.relation" placeholder="例如:汤正华堂侄" placeholder-class="join-placeholder" @input="clearFieldError('relation')" />
|
||||
<image
|
||||
src="/static/assets/modules/genealogy/transparent/g-form-field-frame.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<text>与家谱关系</text
|
||||
><input
|
||||
v-model="form.relation"
|
||||
placeholder="例如:汤正华堂侄"
|
||||
placeholder-class="join-placeholder"
|
||||
@input="clearFieldError('relation')"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="fieldErrors.relation" class="join-field-error">{{ fieldErrors.relation }}</text>
|
||||
<text class="relation-help">请以家谱中一位已知长辈为参照,例如:汤正华堂侄</text>
|
||||
<text v-if="fieldErrors.relation" class="join-field-error">{{
|
||||
fieldErrors.relation
|
||||
}}</text>
|
||||
<text class="relation-help"
|
||||
>请以家谱中一位已知长辈为参照,例如:汤正华堂侄</text
|
||||
>
|
||||
<view class="join-field join-field--message">
|
||||
<image src="/static/assets/modules/genealogy/opaque/g06-search-input-wide.png" mode="scaleToFill" />
|
||||
<text>{{ sourceContract.thirdFieldLabel }}</text><textarea v-model="form.message" maxlength="80" :placeholder="sourceContract.thirdFieldPlaceholder" placeholder-class="join-placeholder" />
|
||||
<image
|
||||
src="/static/assets/modules/genealogy/transparent/g-form-field-frame.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<text>{{ sourceContract.thirdFieldLabel }}</text
|
||||
><textarea
|
||||
v-model="form.message"
|
||||
maxlength="80"
|
||||
:placeholder="sourceContract.thirdFieldPlaceholder"
|
||||
placeholder-class="join-placeholder"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<text class="join-form__note">{{ sourceContract.note }}</text>
|
||||
<view class="join-action" @click="submitJoin">
|
||||
<image src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png" mode="aspectFit" />
|
||||
<text>{{ isSubmitting ? sourceContract.submittingLabel : sourceContract.submitLabel }}</text>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text>{{
|
||||
isSubmitting
|
||||
? sourceContract.submittingLabel
|
||||
: sourceContract.submitLabel
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="join-result">
|
||||
<text class="join-result__eyebrow">{{ joinState === 'success' ? sourceContract.successEyebrow : sourceContract.errorEyebrow }}</text>
|
||||
<text class="join-result__title">{{ joinState === 'success' ? sourceContract.successTitle : sourceContract.errorTitle }}</text>
|
||||
<text class="join-result__eyebrow">{{
|
||||
joinState === "success"
|
||||
? sourceContract.successEyebrow
|
||||
: sourceContract.errorEyebrow
|
||||
}}</text>
|
||||
<text class="join-result__title">{{
|
||||
joinState === "success"
|
||||
? sourceContract.successTitle
|
||||
: sourceContract.errorTitle
|
||||
}}</text>
|
||||
<text class="join-result__copy">{{ resultCopy }}</text>
|
||||
<view class="join-action" @click="joinState === 'success' ? completeFlow() : retryForm()">
|
||||
<image src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png" mode="aspectFit" />
|
||||
<text>{{ joinState === 'success' ? sourceContract.nextLabel : '重新填写' }}</text>
|
||||
<view
|
||||
class="join-action"
|
||||
@click="joinState === 'success' ? completeFlow() : retryForm()"
|
||||
>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text>{{
|
||||
joinState === "success" ? sourceContract.nextLabel : "重新填写"
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -53,121 +120,280 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import GenealogyPageBackground from '@/components/GenealogyPageBackground.vue'
|
||||
import PageHeader from '@/components/PageHeader.vue'
|
||||
import { computed, reactive, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
|
||||
const genealogyId = ref('')
|
||||
const source = ref('search')
|
||||
const genealogyName = ref('这部家谱')
|
||||
const genealogyId = ref("");
|
||||
const source = ref("search");
|
||||
const genealogyName = ref("这部家谱");
|
||||
const genealogyPreview = {
|
||||
'1001': '汤氏家谱',
|
||||
'1002': '汝南汤氏家谱'
|
||||
}
|
||||
const joinState = ref('form')
|
||||
const isSubmitting = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const form = reactive({ realName: '', relation: '', message: '' })
|
||||
const fieldErrors = reactive({ realName: '', relation: '' })
|
||||
const sourceContract = computed(() => source.value === 'invite' ? {
|
||||
headerTitle: '确认关系并加入',
|
||||
eyebrow: '邀请码直接加入',
|
||||
formTitle: '确认加入',
|
||||
formCopy: '请填写真实身份和亲属关系;提交后直接加入,无需等待管理员审核。',
|
||||
thirdFieldLabel: '补充信息',
|
||||
thirdFieldPlaceholder: '选填:补充祖居地、长辈姓名等信息',
|
||||
note: '邀请码来源提交后直接加入,无需等待审核。',
|
||||
submitLabel: '确认加入',
|
||||
submittingLabel: '正在加入…',
|
||||
successEyebrow: '已加入家谱',
|
||||
successTitle: '关系信息已提交',
|
||||
errorEyebrow: '加入未完成',
|
||||
errorTitle: '暂时无法加入家谱',
|
||||
nextLabel: '返回我的家谱',
|
||||
successCopy: `已直接加入“${genealogyName.value}”,无需等待审核;返回后将刷新并选中这部家谱。`
|
||||
} : {
|
||||
headerTitle: '申请加入家谱',
|
||||
eyebrow: '公开家谱入谱申请',
|
||||
formTitle: '申请加入',
|
||||
formCopy: '请填写真实身份和亲属关系,管理员审核后会通过消息告知结果。',
|
||||
thirdFieldLabel: '申请说明',
|
||||
thirdFieldPlaceholder: '补充祖居地、长辈姓名等核验信息',
|
||||
note: '提交后可在“我的申请”中查看审核进度。',
|
||||
submitLabel: '提交申请',
|
||||
submittingLabel: '正在提交…',
|
||||
successEyebrow: '申请已送达',
|
||||
successTitle: '等待管理员核实亲属关系',
|
||||
errorEyebrow: '申请未提交',
|
||||
errorTitle: '暂时无法提交申请',
|
||||
nextLabel: '查看我的申请',
|
||||
successCopy: `“${genealogyName.value}”的管理员会在核实后给出结果,请留意消息中心。`
|
||||
})
|
||||
const resultCopy = computed(() => joinState.value === 'success'
|
||||
? sourceContract.value.successCopy
|
||||
: errorMessage.value || '请检查网络后重新填写;未成功提交的内容不会进入审核列表。')
|
||||
1001: "汤氏家谱",
|
||||
1002: "汝南汤氏家谱",
|
||||
};
|
||||
const joinState = ref("form");
|
||||
const isSubmitting = ref(false);
|
||||
const errorMessage = ref("");
|
||||
const form = reactive({ realName: "", relation: "", message: "" });
|
||||
const fieldErrors = reactive({ realName: "", relation: "" });
|
||||
const sourceContract = computed(() =>
|
||||
source.value === "invite"
|
||||
? {
|
||||
headerTitle: "确认关系并加入",
|
||||
eyebrow: "邀请码直接加入",
|
||||
formTitle: "确认加入",
|
||||
formCopy:
|
||||
"请填写真实身份和亲属关系;提交后直接加入,无需等待管理员审核。",
|
||||
thirdFieldLabel: "补充信息",
|
||||
thirdFieldPlaceholder: "选填:补充祖居地、长辈姓名等信息",
|
||||
note: "邀请码来源提交后直接加入,无需等待审核。",
|
||||
submitLabel: "确认加入",
|
||||
submittingLabel: "正在加入…",
|
||||
successEyebrow: "已加入家谱",
|
||||
successTitle: "关系信息已提交",
|
||||
errorEyebrow: "加入未完成",
|
||||
errorTitle: "暂时无法加入家谱",
|
||||
nextLabel: "返回我的家谱",
|
||||
successCopy: `已直接加入“${genealogyName.value}”,无需等待审核;返回后将刷新并选中这部家谱。`,
|
||||
}
|
||||
: {
|
||||
headerTitle: "申请加入家谱",
|
||||
eyebrow: "公开家谱入谱申请",
|
||||
formTitle: "申请加入",
|
||||
formCopy: "请填写真实身份和亲属关系,管理员审核后会通过消息告知结果。",
|
||||
thirdFieldLabel: "申请说明",
|
||||
thirdFieldPlaceholder: "补充祖居地、长辈姓名等核验信息",
|
||||
note: "提交后可在“我的申请”中查看审核进度。",
|
||||
submitLabel: "提交申请",
|
||||
submittingLabel: "正在提交…",
|
||||
successEyebrow: "申请已送达",
|
||||
successTitle: "等待管理员核实亲属关系",
|
||||
errorEyebrow: "申请未提交",
|
||||
errorTitle: "暂时无法提交申请",
|
||||
nextLabel: "查看我的申请",
|
||||
successCopy: `“${genealogyName.value}”的管理员会在核实后给出结果,请留意消息中心。`,
|
||||
},
|
||||
);
|
||||
const resultCopy = computed(() =>
|
||||
joinState.value === "success"
|
||||
? sourceContract.value.successCopy
|
||||
: errorMessage.value ||
|
||||
"请检查网络后重新填写;未成功提交的内容不会进入审核列表。",
|
||||
);
|
||||
|
||||
onLoad((query) => {
|
||||
genealogyId.value = query.genealogyId || ''
|
||||
source.value = query.source === 'invite' ? 'invite' : 'search'
|
||||
if (query.state === 'success') {
|
||||
joinState.value = 'success'
|
||||
return
|
||||
genealogyId.value = query.genealogyId || "";
|
||||
source.value = query.source === "invite" ? "invite" : "search";
|
||||
if (query.state === "success") {
|
||||
joinState.value = "success";
|
||||
return;
|
||||
}
|
||||
if (!genealogyId.value) {
|
||||
errorMessage.value = '没有找到要申请加入的家谱,请先返回公开家谱检索。'
|
||||
joinState.value = 'error'
|
||||
return
|
||||
errorMessage.value = "没有找到要申请加入的家谱,请先返回公开家谱检索。";
|
||||
joinState.value = "error";
|
||||
return;
|
||||
}
|
||||
genealogyName.value = genealogyPreview[genealogyId.value] || '这部家谱'
|
||||
})
|
||||
genealogyName.value = genealogyPreview[genealogyId.value] || "这部家谱";
|
||||
});
|
||||
|
||||
const submitJoin = () => {
|
||||
if (isSubmitting.value) return
|
||||
fieldErrors.realName = form.realName.trim() ? '' : '请填写真实姓名'
|
||||
fieldErrors.relation = form.relation.trim() ? '' : '请填写与家谱的关系'
|
||||
if (fieldErrors.realName || fieldErrors.relation) return
|
||||
isSubmitting.value = true
|
||||
if (isSubmitting.value) return;
|
||||
fieldErrors.realName = form.realName.trim() ? "" : "请填写真实姓名";
|
||||
fieldErrors.relation = form.relation.trim() ? "" : "请填写与家谱的关系";
|
||||
if (fieldErrors.realName || fieldErrors.relation) return;
|
||||
isSubmitting.value = true;
|
||||
setTimeout(() => {
|
||||
joinState.value = form.realName.trim() === '失败' ? 'error' : 'success'
|
||||
if (joinState.value === 'error') errorMessage.value = source.value === 'invite' ? '邀请码加入暂未完成,请稍后重试。' : '申请暂未提交,请稍后重试。'
|
||||
isSubmitting.value = false
|
||||
}, 280)
|
||||
}
|
||||
const clearFieldError = (field) => { fieldErrors[field] = '' }
|
||||
const retryForm = () => { joinState.value = 'form'; errorMessage.value = '' }
|
||||
const toMyApplications = () => uni.redirectTo({ url: '/pages/genealogy/g09-my-applications' })
|
||||
const toMyGenealogies = () => uni.reLaunch({ url: `/pages/genealogy/g01-my-genealogies?genealogyId=${genealogyId.value}` })
|
||||
const completeFlow = () => source.value === 'invite' ? toMyGenealogies() : toMyApplications()
|
||||
joinState.value = form.realName.trim() === "失败" ? "error" : "success";
|
||||
if (joinState.value === "error")
|
||||
errorMessage.value =
|
||||
source.value === "invite"
|
||||
? "邀请码加入暂未完成,请稍后重试。"
|
||||
: "申请暂未提交,请稍后重试。";
|
||||
isSubmitting.value = false;
|
||||
}, 280);
|
||||
};
|
||||
const clearFieldError = (field) => {
|
||||
fieldErrors[field] = "";
|
||||
};
|
||||
const retryForm = () => {
|
||||
joinState.value = "form";
|
||||
errorMessage.value = "";
|
||||
};
|
||||
const toMyApplications = () =>
|
||||
uni.redirectTo({ url: "/pages/genealogy/g09-my-applications" });
|
||||
const toMyGenealogies = () =>
|
||||
uni.reLaunch({
|
||||
url: `/pages/genealogy/g01-my-genealogies?genealogyId=${genealogyId.value}`,
|
||||
});
|
||||
const completeFlow = () =>
|
||||
source.value === "invite" ? toMyGenealogies() : toMyApplications();
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.join-page { position: relative; min-height: 100vh; overflow-x: hidden; background: $paper; }
|
||||
.join-page__header { position: relative; z-index: 3; }
|
||||
.join-panel { position: relative; z-index: 2; width: calc(100% - 32rpx); height: min(590px, calc((100vw - 16px) * 1.337)); margin: 22rpx auto 0; }
|
||||
.join-panel__skin { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.join-form { position: absolute; inset: 8.5% 8%; }
|
||||
.join-form__eyebrow, .join-result__eyebrow { display: block; color: $brand-red; font-size: 23rpx; letter-spacing: 3rpx; }
|
||||
.join-form__title, .join-result__title { display: block; margin-top: 12rpx; color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 36rpx; font-weight: 700; }
|
||||
.join-form__copy, .join-result__copy { display: block; margin-top: 12rpx; color: $ink-muted; font-size: 22rpx; line-height: 1.6; }
|
||||
.join-field { position: relative; height: 92rpx; margin-top: 18rpx; }
|
||||
.join-field > image { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.join-field > text { position: absolute; top: 31rpx; left: 24rpx; z-index: 1; color: $ink; font-size: 23rpx; font-weight: 700; }
|
||||
.join-field input, .join-field textarea { position: absolute; top: 0; right: 20rpx; bottom: 0; left: 170rpx; z-index: 1; height: 92rpx; color: $ink; font-size: 23rpx; line-height: 92rpx; }
|
||||
.join-field textarea { box-sizing: border-box; padding-top: 26rpx; line-height: 1.5; }
|
||||
.join-placeholder { color: #a79884; }
|
||||
.join-field-error { display: block; margin-top: 3rpx; color: $brand-red; font-size: 20rpx; text-align: right; }
|
||||
.relation-help { display: block; margin-top: 5rpx; color: #8e7b67; font-size: 19rpx; line-height: 29rpx; }
|
||||
.join-form__note { display: block; margin-top: 18rpx; color: $ink-muted; font-size: 21rpx; text-align: center; }
|
||||
.join-action { position: relative; width: 100%; height: 82rpx; margin-top: 20rpx; }
|
||||
.join-action image { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.join-action text { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; height: 100%; color: #fff9ed; font-size: 27rpx; font-weight: 700; letter-spacing: 3rpx; }
|
||||
.join-result { position: absolute; top: 28%; right: 12%; left: 12%; text-align: center; }
|
||||
.join-result__eyebrow { text-align: center; }
|
||||
.join-result__copy { margin-top: 22rpx; }
|
||||
.join-result .join-action { width: 420rpx; max-width: 100%; margin: 34rpx auto 0; }
|
||||
.join-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
background: $paper;
|
||||
}
|
||||
.join-page__header {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
.join-panel {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
width: calc(100% - 32rpx);
|
||||
height: min(590px, calc((100vw - 16px) * 1.337));
|
||||
margin: 22rpx auto 0;
|
||||
}
|
||||
.join-panel__skin {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.join-form {
|
||||
position: absolute;
|
||||
inset: 8.5% 8%;
|
||||
}
|
||||
.join-form__eyebrow,
|
||||
.join-result__eyebrow {
|
||||
display: block;
|
||||
color: $brand-red;
|
||||
font-size: 23rpx;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.join-form__title,
|
||||
.join-result__title {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
color: $ink;
|
||||
font-family: "STKaiti", "KaiTi", serif;
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.join-form__copy,
|
||||
.join-result__copy {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.join-field {
|
||||
position: relative;
|
||||
height: 92rpx;
|
||||
margin-top: 18rpx;
|
||||
}
|
||||
.join-field > image {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.join-field > text {
|
||||
position: absolute;
|
||||
top: 31rpx;
|
||||
left: 24rpx;
|
||||
z-index: 1;
|
||||
color: $ink;
|
||||
font-size: 23rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.join-field input,
|
||||
.join-field textarea {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 20rpx;
|
||||
bottom: 0;
|
||||
left: 170rpx;
|
||||
z-index: 1;
|
||||
height: 92rpx;
|
||||
color: $ink;
|
||||
font-size: 23rpx;
|
||||
line-height: 92rpx;
|
||||
}
|
||||
.join-field textarea {
|
||||
box-sizing: border-box;
|
||||
padding-top: 26rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.join-placeholder {
|
||||
color: #a79884;
|
||||
}
|
||||
.join-field-error {
|
||||
display: block;
|
||||
margin-top: 3rpx;
|
||||
color: $brand-red;
|
||||
font-size: 24rpx;
|
||||
line-height: 34rpx;
|
||||
text-align: right;
|
||||
}
|
||||
.relation-help {
|
||||
display: block;
|
||||
margin-top: 5rpx;
|
||||
color: #8e7b67;
|
||||
font-size: 19rpx;
|
||||
line-height: 29rpx;
|
||||
}
|
||||
.join-form__note {
|
||||
display: block;
|
||||
margin-top: 18rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 21rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.join-action {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 82rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
.join-action image {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.join-action text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #fff9ed;
|
||||
font-size: 27rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
.join-result {
|
||||
position: absolute;
|
||||
top: 28%;
|
||||
right: 12%;
|
||||
left: 12%;
|
||||
text-align: center;
|
||||
}
|
||||
.join-result__eyebrow {
|
||||
text-align: center;
|
||||
}
|
||||
.join-result__copy {
|
||||
margin-top: 22rpx;
|
||||
}
|
||||
.join-result .join-action {
|
||||
width: 420rpx;
|
||||
max-width: 100%;
|
||||
margin: 34rpx auto 0;
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
.join-panel { width: calc(100% - 48rpx); }
|
||||
.join-form { right: 9%; left: 9%; }
|
||||
.join-panel {
|
||||
width: calc(100% - 48rpx);
|
||||
}
|
||||
.join-form {
|
||||
right: 9%;
|
||||
left: 9%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,47 +2,94 @@
|
||||
<template>
|
||||
<view class="application-page">
|
||||
<GenealogyPageBackground />
|
||||
<view class="application-page__header"><PageHeader title="我的申请" /></view>
|
||||
<view class="application-page__header"
|
||||
><PageHeader title="我的申请"
|
||||
/></view>
|
||||
|
||||
<view class="application-content" :class="{
|
||||
'application-state--list': applicationState === 'list',
|
||||
'application-state--empty': applicationState === 'empty',
|
||||
'application-state--error': applicationState === 'error'
|
||||
}">
|
||||
<view
|
||||
class="application-content"
|
||||
:class="{
|
||||
'application-state--list': applicationState === 'list',
|
||||
'application-state--empty': applicationState === 'empty',
|
||||
'application-state--error': applicationState === 'error',
|
||||
}"
|
||||
>
|
||||
<template v-if="applicationState === 'list'">
|
||||
<view class="application-intro">
|
||||
<text>入谱申请进度</text><text>审核结果会同步到消息中心</text>
|
||||
</view>
|
||||
<view v-for="item in applications" :key="item.id" class="application-card">
|
||||
<image class="application-card__skin" src="/static/assets/modules/genealogy/opaque/application-status-card.png" mode="scaleToFill" />
|
||||
<view
|
||||
v-for="item in applications"
|
||||
:key="item.id"
|
||||
class="application-card"
|
||||
>
|
||||
<image
|
||||
class="application-card__skin"
|
||||
src="/static/assets/modules/genealogy/transparent/list-slip-frame.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<view class="application-card__body">
|
||||
<text class="application-card__name">{{ item.genealogyName }}</text>
|
||||
<text class="application-card__time">{{ item.appliedAt }}</text>
|
||||
<text class="application-card__relation">{{ item.relation }}</text>
|
||||
<text class="application-card__status" :class="`application-card__status--${item.status.toLowerCase()}`">{{ statusLabel(item.status) }}</text>
|
||||
<text class="application-card__hint">{{ statusHint(item.status) }}</text>
|
||||
<view v-if="actionFor(item)" class="application-card__action" @click="handleApplicationAction(item)">{{ actionFor(item) }}</view>
|
||||
<text
|
||||
class="application-card__status"
|
||||
:class="`application-card__status--${item.status.toLowerCase()}`"
|
||||
>{{ statusLabel(item.status) }}</text
|
||||
>
|
||||
<text class="application-card__hint">{{
|
||||
statusHint(item.status)
|
||||
}}</text>
|
||||
<view
|
||||
v-if="actionFor(item)"
|
||||
class="application-card__action"
|
||||
@click="handleApplicationAction(item)"
|
||||
>{{ actionFor(item) }}</view
|
||||
>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<AppLoading
|
||||
v-else-if="applicationState === 'loading'"
|
||||
text="正在整理申请记录"
|
||||
description="请稍候,正在同步审核状态。"
|
||||
/>
|
||||
<view v-else class="application-state-card">
|
||||
<image src="/static/assets/modules/genealogy/opaque/application-status-card.png" mode="scaleToFill" />
|
||||
<image
|
||||
src="/static/assets/modules/genealogy/transparent/list-slip-frame.png"
|
||||
mode="scaleToFill"
|
||||
/>
|
||||
<view class="application-state-card__copy">
|
||||
<text>{{ stateTitle }}</text>
|
||||
<text>{{ stateCopy }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="applicationState !== 'list'" class="application-page__action" @click="applicationState === 'error' ? loadApplications({}) : toSearch()">
|
||||
<image src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png" mode="aspectFit" />
|
||||
<text>{{ applicationState === 'error' ? '重新查看' : '查找公开家谱' }}</text>
|
||||
<view
|
||||
v-if="applicationState !== 'list' && applicationState !== 'loading'"
|
||||
class="application-page__action"
|
||||
@click="
|
||||
applicationState === 'error' ? loadApplications({}) : toSearch()
|
||||
"
|
||||
>
|
||||
<image
|
||||
src="/static/assets/foundation/transparent/a01-scroll-primary-v3.png"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<text>{{
|
||||
applicationState === "error" ? "重新查看" : "查找公开家谱"
|
||||
}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<AppDialog
|
||||
:visible="!!withdrawTarget"
|
||||
title="撤回加入申请"
|
||||
:message="withdrawTarget ? `确认撤回对“${withdrawTarget.genealogyName}”的申请?撤回后如需加入,可重新提交。` : ''"
|
||||
:message="
|
||||
withdrawTarget
|
||||
? `确认撤回对“${withdrawTarget.genealogyName}”的申请?撤回后如需加入,可重新提交。`
|
||||
: ''
|
||||
"
|
||||
confirm-text="确认撤回"
|
||||
cancel-text="暂不撤回"
|
||||
show-cancel
|
||||
@@ -54,89 +101,282 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import AppDialog from '@/components/AppDialog.vue'
|
||||
import GenealogyPageBackground from '@/components/GenealogyPageBackground.vue'
|
||||
import PageHeader from '@/components/PageHeader.vue'
|
||||
import { computed, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import AppDialog from "@/components/AppDialog.vue";
|
||||
import AppLoading from "@/components/AppLoading.vue";
|
||||
import GenealogyPageBackground from "@/components/GenealogyPageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
|
||||
const applications = ref([])
|
||||
const applicationState = ref('loading')
|
||||
const errorMessage = ref('')
|
||||
const withdrawTarget = ref(null)
|
||||
const applications = ref([]);
|
||||
const applicationState = ref("loading");
|
||||
const errorMessage = ref("");
|
||||
const withdrawTarget = ref(null);
|
||||
const applicationSamples = [
|
||||
{ id: 1, genealogyId: 1001, genealogyName: '汤氏家谱', relation: '自述为汤正华堂侄', appliedAt: '今天 10:24', status: 'PENDING' },
|
||||
{ id: 2, genealogyId: 1002, genealogyName: '汝南汤氏家谱', relation: '祖居河南汝南', appliedAt: '昨天 18:02', status: 'APPROVED' },
|
||||
{ id: 3, genealogyId: 1003, genealogyName: '清河汤氏家谱', relation: '补充材料不足', appliedAt: '7月12日 09:18', status: 'REJECTED' }
|
||||
]
|
||||
{
|
||||
id: 1,
|
||||
genealogyId: 1001,
|
||||
genealogyName: "汤氏家谱",
|
||||
relation: "自述为汤正华堂侄",
|
||||
appliedAt: "今天 10:24",
|
||||
status: "PENDING",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
genealogyId: 1002,
|
||||
genealogyName: "汝南汤氏家谱",
|
||||
relation: "祖居河南汝南",
|
||||
appliedAt: "昨天 18:02",
|
||||
status: "APPROVED",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
genealogyId: 1003,
|
||||
genealogyName: "清河汤氏家谱",
|
||||
relation: "补充材料不足",
|
||||
appliedAt: "7月12日 09:18",
|
||||
status: "REJECTED",
|
||||
},
|
||||
];
|
||||
|
||||
const statusLabel = (status) => ({
|
||||
'PENDING': '审核中',
|
||||
'APPROVED': '已通过',
|
||||
'REJECTED': '未通过',
|
||||
'WITHDRAWN': '已撤回'
|
||||
}[status] || '状态未知')
|
||||
const statusLabel = (status) =>
|
||||
({
|
||||
PENDING: "审核中",
|
||||
APPROVED: "已通过",
|
||||
REJECTED: "未通过",
|
||||
WITHDRAWN: "已撤回",
|
||||
})[status] || "状态未知";
|
||||
|
||||
const statusHint = (status) => ({
|
||||
PENDING: '管理员尚未处理,可在审核前撤回',
|
||||
APPROVED: '申请已通过,可进入这部家谱',
|
||||
REJECTED: '请修改关系说明后重新提交',
|
||||
WITHDRAWN: '申请已撤回,不再进入管理员审核'
|
||||
}[status] || '')
|
||||
const statusHint = (status) =>
|
||||
({
|
||||
PENDING: "管理员尚未处理,可在审核前撤回",
|
||||
APPROVED: "申请已通过,可进入这部家谱",
|
||||
REJECTED: "请修改关系说明后重新提交",
|
||||
WITHDRAWN: "申请已撤回,不再进入管理员审核",
|
||||
})[status] || "";
|
||||
|
||||
const actionFor = (item) => ({ PENDING: '撤回申请', APPROVED: '进入家谱', REJECTED: '修改后重新提交' }[item.status] || '')
|
||||
const stateTitle = computed(() => applicationState.value === 'empty' ? '还没有入谱申请' : applicationState.value === 'loading' ? '正在整理申请记录' : '申请记录暂时无法读取')
|
||||
const stateCopy = computed(() => applicationState.value === 'empty' ? '从家谱搜索提交的申请会显示在这里;邀请码直接加入不进入本页。' : applicationState.value === 'loading' ? '请稍候,正在同步审核状态。' : errorMessage.value || '请检查网络后重新查看。')
|
||||
const actionFor = (item) =>
|
||||
({ PENDING: "撤回申请", APPROVED: "进入家谱", REJECTED: "修改后重新提交" })[
|
||||
item.status
|
||||
] || "";
|
||||
const stateTitle = computed(() =>
|
||||
applicationState.value === "empty"
|
||||
? "还没有入谱申请"
|
||||
: applicationState.value === "loading"
|
||||
? "正在整理申请记录"
|
||||
: "申请记录暂时无法读取",
|
||||
);
|
||||
const stateCopy = computed(() =>
|
||||
applicationState.value === "empty"
|
||||
? "从家谱搜索提交的申请会显示在这里;邀请码直接加入不进入本页。"
|
||||
: applicationState.value === "loading"
|
||||
? "请稍候,正在同步审核状态。"
|
||||
: errorMessage.value || "请检查网络后重新查看。",
|
||||
);
|
||||
|
||||
const loadApplications = (query = {}) => {
|
||||
applicationState.value = 'loading'
|
||||
errorMessage.value = ''
|
||||
if (query.state === 'empty') { applicationState.value = 'empty'; return }
|
||||
if (query.state === 'error') { applicationState.value = 'error'; return }
|
||||
if (query.state === 'loading') { applicationState.value = 'loading'; return }
|
||||
applications.value = applicationSamples.map((item) => ({ ...item }))
|
||||
applicationState.value = 'list'
|
||||
}
|
||||
applicationState.value = "loading";
|
||||
errorMessage.value = "";
|
||||
if (query.state === "empty") {
|
||||
applicationState.value = "empty";
|
||||
return;
|
||||
}
|
||||
if (query.state === "error") {
|
||||
applicationState.value = "error";
|
||||
return;
|
||||
}
|
||||
if (query.state === "loading") {
|
||||
applicationState.value = "loading";
|
||||
return;
|
||||
}
|
||||
applications.value = applicationSamples.map((item) => ({ ...item }));
|
||||
applicationState.value = "list";
|
||||
};
|
||||
|
||||
onLoad(loadApplications)
|
||||
onLoad(loadApplications);
|
||||
const handleApplicationAction = (item) => {
|
||||
if (item.status === 'APPROVED') return uni.navigateTo({ url: `/pages/genealogy/g05-genealogy-overview?genealogyId=${item.genealogyId}` })
|
||||
if (item.status === 'REJECTED') return uni.navigateTo({ url: `/pages/genealogy/g08-join-application?source=search&previous=rejected&genealogyId=${item.genealogyId}` })
|
||||
if (item.status === 'PENDING') withdrawTarget.value = item
|
||||
}
|
||||
const cancelWithdraw = () => { withdrawTarget.value = null }
|
||||
if (item.status === "APPROVED")
|
||||
return uni.navigateTo({
|
||||
url: `/pages/genealogy/g05-genealogy-overview?genealogyId=${item.genealogyId}`,
|
||||
});
|
||||
if (item.status === "REJECTED")
|
||||
return uni.navigateTo({
|
||||
url: `/pages/genealogy/g08-join-application?source=search&previous=rejected&genealogyId=${item.genealogyId}`,
|
||||
});
|
||||
if (item.status === "PENDING") withdrawTarget.value = item;
|
||||
};
|
||||
const cancelWithdraw = () => {
|
||||
withdrawTarget.value = null;
|
||||
};
|
||||
const confirmWithdraw = () => {
|
||||
const target = applications.value.find((item) => item.id === withdrawTarget.value?.id)
|
||||
if (target) target.status = 'WITHDRAWN'
|
||||
cancelWithdraw()
|
||||
}
|
||||
const toSearch = () => uni.navigateTo({ url: '/pages/genealogy/g06-search-genealogies' })
|
||||
const target = applications.value.find(
|
||||
(item) => item.id === withdrawTarget.value?.id,
|
||||
);
|
||||
if (target) target.status = "WITHDRAWN";
|
||||
cancelWithdraw();
|
||||
};
|
||||
const toSearch = () =>
|
||||
uni.navigateTo({ url: "/pages/genealogy/g06-search-genealogies" });
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.application-page { position: relative; min-height: 100vh; overflow-x: hidden; background: $paper; }
|
||||
.application-page__header { position: relative; z-index: 3; }
|
||||
.application-content { position: relative; z-index: 2; padding: 28rpx 24rpx 60rpx; }
|
||||
.application-intro { display: flex; align-items: baseline; justify-content: space-between; margin: 0 8rpx 20rpx; }
|
||||
.application-intro text:first-child { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 31rpx; font-weight: 700; }
|
||||
.application-intro text:last-child { color: $ink-muted; font-size: 21rpx; }
|
||||
.application-card { position: relative; width: 100%; height: calc((100vw - 24px) * .34286); min-height: 228rpx; max-height: 282rpx; margin-bottom: 18rpx; }
|
||||
.application-card__skin { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.application-card__body { position: absolute; inset: 18% 7% 14% 8.5%; }
|
||||
.application-card__name { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 30rpx; font-weight: 700; }
|
||||
.application-card__time { position: absolute; top: 3rpx; right: 0; color: #998873; font-size: 20rpx; }
|
||||
.application-card__relation { display: block; max-width: 70%; margin-top: 14rpx; color: $ink-muted; font-size: 22rpx; }
|
||||
.application-card__status { position: absolute; right: 3%; bottom: 38%; color: $brand-red; font-size: 23rpx; font-weight: 700; }
|
||||
.application-card__status--approved { color: #537368; }
|
||||
.application-card__status--rejected { color: #7e6f62; }
|
||||
.application-card__hint { position: absolute; bottom: 5%; left: 0; max-width: 62%; color: #8d7c67; font-size: 20rpx; }
|
||||
.application-card__action { position: absolute; right: 2%; bottom: 2%; z-index: 2; display: flex; min-height: 54rpx; align-items: center; color: $brand-red; font-size: 21rpx; font-weight: 700; }
|
||||
.application-state-card { position: relative; width: 100%; height: calc((100vw - 24px) * .34286); min-height: 228rpx; margin-top: 80rpx; }
|
||||
.application-state-card > image { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.application-state-card__copy { position: absolute; inset: 22% 12%; display: flex; flex-direction: column; justify-content: center; text-align: center; }
|
||||
.application-state-card__copy text:first-child { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 31rpx; font-weight: 700; }
|
||||
.application-state-card__copy text:last-child { margin-top: 16rpx; color: $ink-muted; font-size: 22rpx; line-height: 1.6; }
|
||||
.application-page__action { position: relative; width: 420rpx; height: 82rpx; margin: 34rpx auto 0; }
|
||||
.application-page__action image { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.application-page__action text { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; height: 100%; color: #fff9ed; font-size: 26rpx; font-weight: 700; }
|
||||
.application-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
overflow-x: hidden;
|
||||
background: $paper;
|
||||
}
|
||||
.application-page__header {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
.application-content {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: 28rpx 24rpx 60rpx;
|
||||
}
|
||||
.application-intro {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
margin: 0 8rpx 20rpx;
|
||||
}
|
||||
.application-intro text:first-child {
|
||||
color: $ink;
|
||||
font-family: "STKaiti", "KaiTi", serif;
|
||||
font-size: 31rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.application-intro text:last-child {
|
||||
color: $ink-muted;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.application-card {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc((100vw - 24px) * 0.34286);
|
||||
min-height: 228rpx;
|
||||
max-height: 282rpx;
|
||||
margin-bottom: 18rpx;
|
||||
}
|
||||
.application-card__skin {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.application-card__body {
|
||||
position: absolute;
|
||||
inset: 18% 7% 14% 8.5%;
|
||||
}
|
||||
.application-card__name {
|
||||
color: $ink;
|
||||
font-family: "STKaiti", "KaiTi", serif;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.application-card__time {
|
||||
position: absolute;
|
||||
top: 3rpx;
|
||||
right: 0;
|
||||
color: #998873;
|
||||
font-size: 23rpx;
|
||||
}
|
||||
.application-card__relation {
|
||||
display: block;
|
||||
max-width: 70%;
|
||||
margin-top: 14rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.application-card__status {
|
||||
position: absolute;
|
||||
right: 3%;
|
||||
bottom: 38%;
|
||||
color: $brand-red;
|
||||
font-size: 25rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.application-card__status--approved {
|
||||
color: #537368;
|
||||
}
|
||||
.application-card__status--rejected {
|
||||
color: #7e6f62;
|
||||
}
|
||||
.application-card__hint {
|
||||
position: absolute;
|
||||
bottom: 5%;
|
||||
left: 0;
|
||||
max-width: 62%;
|
||||
color: #766653;
|
||||
font-size: 23rpx;
|
||||
}
|
||||
.application-card__action {
|
||||
position: absolute;
|
||||
right: 2%;
|
||||
bottom: 2%;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
min-height: 54rpx;
|
||||
align-items: center;
|
||||
color: $brand-red;
|
||||
font-size: 23rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.application-state-card {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc((100vw - 24px) * 0.34286);
|
||||
min-height: 228rpx;
|
||||
margin-top: 80rpx;
|
||||
}
|
||||
.application-state-card > image {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.application-state-card__copy {
|
||||
position: absolute;
|
||||
inset: 22% 12%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
.application-state-card__copy text:first-child {
|
||||
color: $ink;
|
||||
font-family: "STKaiti", "KaiTi", serif;
|
||||
font-size: 31rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.application-state-card__copy text:last-child {
|
||||
margin-top: 16rpx;
|
||||
color: $ink-muted;
|
||||
font-size: 24rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.application-page__action {
|
||||
position: relative;
|
||||
width: 420rpx;
|
||||
height: 82rpx;
|
||||
margin: 34rpx auto 0;
|
||||
}
|
||||
.application-page__action image {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.application-page__action text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #fff9ed;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user