修改完成55%

This commit is contained in:
2026-07-15 08:31:21 +08:00
parent 8c98936da5
commit 241a7af54c
98 changed files with 3269 additions and 782 deletions
+112 -47
View File
@@ -1,16 +1,52 @@
<!-- 页面编号G-10用途管理员入谱申请审核 -->
<!-- 页面编号G-10用途管理员入谱申请审核与空/失败状态 -->
<template>
<view class="page-shell applications-page">
<PageHeader title="入谱审核" action="审核说明" @action="showHelp" />
<view class="audit-tip"><text>{{ loadError || '通过前请核实申请人的亲属关系;审核结果会通过通知告知对方。' }}</text></view>
<view class="application-list">
<view v-for="item in applications" :key="item.id" class="application-card paper-card">
<view class="application-top"><view><text class="applicant-name">{{ item.name }}</text><text class="applicant-phone">{{ item.phone }}</text></view><text class="applicant-time">{{ item.appliedAt }}</text></view>
<text class="relation-copy">{{ item.relation }}</text>
<view v-if="item.status === 'PENDING'" class="audit-actions"><button class="reject-button" @click="audit(item, false)">拒绝</button><button class="approve-button" @click="audit(item, true)">通过</button></view>
<text v-else class="audit-status">{{ item.status === 'APPROVED' ? '已通过' : '已拒绝' }}</text>
<view class="review-page">
<image class="review-page__paper" src="/static/assets/foundation/opaque/page-paper.jpg" mode="aspectFill" />
<image class="review-page__footer" src="/static/assets/foundation/transparent/footer-mountain-bamboo.png" mode="widthFix" />
<view class="review-page__header"><PageHeader title="入谱审核" action="说明" @action="showHelp" /></view>
<view class="review-content" :class="{
'review-state--list': reviewState === 'list',
'review-state--empty': reviewState === 'empty',
'review-state--error': reviewState === 'error'
}">
<view class="review-intro">
<text>核实亲属关系后再决定</text>
<text>审核结果会通过消息告知申请人</text>
<image src="/static/assets/modules/genealogy/transparent/section-divider.png" mode="scaleToFill" />
</view>
<template v-if="reviewState === 'list'">
<view v-for="item in applications" :key="item.id" class="application-card">
<image class="application-card__skin" src="/static/assets/modules/genealogy/opaque/application-record-card.png" mode="scaleToFill" />
<view class="application-card__body">
<text class="application-card__name">{{ item.name }}</text>
<text class="application-card__phone">{{ item.phone }}</text>
<text class="application-card__time">{{ item.appliedAt }}</text>
<text class="application-card__relation">{{ item.relation }}</text>
<view v-if="item.status === 'PENDING'" class="review-actions">
<view class="review-action" @click="confirmAudit(item, false)">
<image src="/static/assets/foundation/opaque/a01-secondary-button.png" mode="scaleToFill" /><text>拒绝</text>
</view>
<view class="review-action" @click="confirmAudit(item, true)">
<image src="/static/assets/foundation/opaque/a01-primary-button.png" mode="scaleToFill" /><text>通过</text>
</view>
</view>
<text v-else class="application-card__status">{{ item.status === 'APPROVED' ? '已通过' : '已拒绝' }}</text>
</view>
</view>
</template>
<view v-else class="review-state-card">
<image src="/static/assets/modules/genealogy/opaque/application-status-card.png" mode="scaleToFill" />
<view class="review-state-card__copy">
<text>{{ reviewState === 'empty' ? '暂无待审核申请' : '审核列表暂时无法读取' }}</text>
<text>{{ reviewState === 'empty' ? '新的入谱申请会在这里出现,并同步发送消息提醒。' : errorMessage || '请检查网络或家谱权限后重试。' }}</text>
</view>
</view>
<view v-if="reviewState === 'error'" class="review-page__retry" @click="loadApplications({ genealogyId })">
<image src="/static/assets/foundation/opaque/a01-primary-button.png" mode="scaleToFill" /><text>重新查看</text>
</view>
<view v-if="!applications.length && !loadError" class="empty-copy">暂无待审核申请</view>
</view>
</view>
</template>
@@ -19,50 +55,79 @@
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import PageHeader from '@/components/PageHeader.vue'
import { appApi } from '@/utils/api.js'
import { genealogyContext } from '@/utils/genealogy-context.js'
const applications = ref([])
const reviewSamples = [
{ id: 1, name: '汤志成', phone: '139****6421', relation: '自述为汤正华堂侄 · 祖居洛阳', appliedAt: '今天 10:24', status: 'PENDING' },
{ id: 2, name: '汤雨薇', phone: '136****2798', relation: '自述为汤正国之女 · 已补充长辈姓名', appliedAt: '昨天 18:02', status: 'PENDING' }
]
const genealogyId = ref('')
const loadError = ref('')
const reviewState = ref('loading')
const errorMessage = ref('')
onLoad(async (query) => {
genealogyId.value = query.genealogyId || genealogyContext.getCurrentGenealogyId()
if (!genealogyId.value) { loadError.value = '未找到当前家谱,请从家谱总览进入。'; return }
const loadApplications = (query = {}) => {
reviewState.value = 'loading'
errorMessage.value = ''
genealogyId.value = query.genealogyId?.value || query.genealogyId || genealogyId.value || genealogyContext.getCurrentGenealogyId()
if (query.state === 'empty') { reviewState.value = 'empty'; return }
if (query.state === 'error') { reviewState.value = 'error'; return }
if (!genealogyId.value) {
errorMessage.value = '没有找到当前家谱,请从家谱总览进入。'
reviewState.value = 'error'
return
}
genealogyContext.setCurrentGenealogyId(genealogyId.value)
try {
applications.value = await appApi.getPendingApplications(genealogyId.value)
} catch (error) {
loadError.value = error.message || '审核列表加载失败。'
}
})
const audit = async (item, approved) => {
try {
await appApi.auditApplication(genealogyId.value, item.id, approved)
item.status = approved ? 'APPROVED' : 'REJECTED'
uni.showToast({ title: approved ? '已通过申请' : '已拒绝申请', icon: 'none' })
} catch (error) {
uni.showToast({ title: error.message || '审核失败,请稍后重试', icon: 'none' })
}
applications.value = reviewSamples.map((item) => ({ ...item }))
reviewState.value = 'list'
}
const showHelp = () => uni.showModal({ title: '审核说明', content: '仅确认与本家谱存在真实亲属关系的申请,避免错误入谱。', showCancel: false })
onLoad(loadApplications)
const confirmAudit = (item, approved) => {
uni.showModal({
title: approved ? '确认通过申请?' : '确认拒绝申请?',
content: approved ? '通过后,申请人将成为本家谱成员。' : '拒绝后,申请人会收到审核结果。',
confirmText: approved ? '确认通过' : '确认拒绝',
success: ({ confirm }) => {
if (!confirm) return
item.status = approved ? 'APPROVED' : 'REJECTED'
uni.showToast({ title: approved ? '已通过申请' : '已拒绝申请', icon: 'none' })
}
})
}
const showHelp = () => uni.showModal({ title: '审核说明', content: '请核对申请人的姓名、亲属关系和补充说明,仅确认与本家谱存在真实关系的申请。', showCancel: false })
</script>
<style scoped lang="scss">
.applications-page { padding-bottom: 36rpx; }
.audit-tip { margin: 26rpx 28rpx 0; padding: 24rpx; border-left: 5rpx solid $brand-red; background: #efe3cd; color: $ink-muted; font-size: 24rpx; line-height: 1.6; }
.application-list { display: flex; flex-direction: column; gap: 20rpx; margin: 24rpx 28rpx; }
.application-card { padding: 28rpx; }
.application-top { display: flex; justify-content: space-between; }
.applicant-name { color: $ink; font-size: 32rpx; font-weight: 700; }
.applicant-phone { margin-left: 16rpx; color: $ink-muted; font-size: 22rpx; }
.applicant-time { color: #a39583; font-size: 21rpx; }
.relation-copy { display: block; margin-top: 16rpx; color: $ink-muted; font-size: 25rpx; }
.audit-actions { display: flex; justify-content: flex-end; gap: 16rpx; margin-top: 24rpx; }
.audit-actions button { min-width: 128rpx; min-height: 64rpx; margin: 0; border-radius: 8rpx; font-size: 24rpx; }
.reject-button { border: 1rpx solid $gold-soft; background: #fffaf0; color: $ink-muted; }
.approve-button { border: 1rpx solid $brand-red; background: $brand-red; color: #fff9ed; }
.audit-status { display: block; margin-top: 24rpx; color: $brand-red; font-size: 24rpx; text-align: right; }
.empty-copy { padding: 80rpx 0; color: $ink-muted; font-size: 26rpx; text-align: center; }
.review-page { position: relative; min-height: 100vh; overflow: hidden; background: $paper; }
.review-page__paper { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; opacity: .98; pointer-events: none; }
.review-page__footer { position: absolute; right: 0; bottom: 0; left: 0; z-index: 1; width: 100%; opacity: .13; pointer-events: none; }
.review-page__header { position: relative; z-index: 3; }
.review-content { position: relative; z-index: 2; padding: 24rpx 24rpx 60rpx; }
.review-intro { position: relative; margin: 0 8rpx 24rpx; padding-bottom: 22rpx; }
.review-intro text { display: block; }
.review-intro text:first-child { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 29rpx; font-weight: 700; }
.review-intro text:nth-child(2) { margin-top: 8rpx; color: $ink-muted; font-size: 21rpx; }
.review-intro image { position: absolute; right: 0; bottom: 0; left: 0; width: 100%; height: 14rpx; }
.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% 12% 8.5%; }
.application-card__name { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 30rpx; font-weight: 700; }
.application-card__phone { margin-left: 14rpx; color: $ink-muted; font-size: 20rpx; }
.application-card__time { position: absolute; top: 3rpx; right: 0; color: #998873; font-size: 20rpx; }
.application-card__relation { display: block; max-width: 58%; margin-top: 15rpx; color: $ink-muted; font-size: 22rpx; }
.review-actions { position: absolute; right: 0; bottom: 0; display: flex; gap: 12rpx; }
.review-action { position: relative; width: 128rpx; height: 60rpx; }
.review-action image { position: absolute; inset: 0; width: 100%; height: 100%; }
.review-action text { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; height: 100%; color: $ink; font-size: 22rpx; font-weight: 700; }
.review-action:last-child text { color: #fff9ed; }
.application-card__status { position: absolute; right: 3%; bottom: 10%; color: $brand-red; font-size: 24rpx; font-weight: 700; }
.review-state-card { position: relative; width: 100%; height: calc((100vw - 24px) * .34286); min-height: 228rpx; margin-top: 70rpx; }
.review-state-card > image { position: absolute; inset: 0; width: 100%; height: 100%; }
.review-state-card__copy { position: absolute; inset: 22% 12%; display: flex; flex-direction: column; justify-content: center; text-align: center; }
.review-state-card__copy text:first-child { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 31rpx; font-weight: 700; }
.review-state-card__copy text:last-child { margin-top: 15rpx; color: $ink-muted; font-size: 22rpx; line-height: 1.6; }
.review-page__retry { position: relative; width: 420rpx; height: 82rpx; margin: 32rpx auto 0; }
.review-page__retry image { position: absolute; inset: 0; width: 100%; height: 100%; }
.review-page__retry 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>