验收20%

This commit is contained in:
2026-07-16 07:42:07 +08:00
parent 0dec90ffdd
commit cb25317412
108 changed files with 6477 additions and 1308 deletions
+71 -17
View File
@@ -8,7 +8,8 @@
<view class="review-content" :class="{
'review-state--list': reviewState === 'list',
'review-state--empty': reviewState === 'empty',
'review-state--error': reviewState === 'error'
'review-state--error': reviewState === 'error',
'review-state--no-permission': reviewState === 'no-permission'
}">
<view class="review-intro">
<text>核实亲属关系后再决定</text>
@@ -40,20 +41,46 @@
<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>
<text>{{ stateTitle }}</text>
<text>{{ stateCopy }}</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>
<view v-if="confirmation || helpVisible" class="review-dialog-layer" @click="closeDialog">
<view class="review-dialog" @click.stop>
<image class="review-dialog__skin" src="/static/assets/modules/genealogy/opaque/application-status-card.png" mode="scaleToFill" />
<view class="review-dialog__content">
<template v-if="helpVisible">
<text class="review-dialog__title">审核说明</text>
<text class="review-dialog__copy">请核对申请人的姓名亲属关系和补充说明仅确认与本家谱存在真实关系的申请</text>
<view class="review-dialog__single" @click="closeDialog">我知道了</view>
</template>
<template v-else>
<text class="review-dialog__title">{{ confirmation.approved ? '确认通过申请?' : '确认拒绝申请?' }}</text>
<text class="review-dialog__copy">{{ confirmation.approved ? '通过后,申请人将成为本家谱成员。' : '拒绝后,申请人会收到审核结果,并可修改后重新申请。' }}</text>
<view class="review-dialog__actions">
<view class="review-dialog__action" @click="closeDialog">取消</view>
<view class="review-dialog__action review-dialog__action--primary" @click="applyAudit">{{ confirmation.approved ? '确认通过' : '确认拒绝' }}</view>
</view>
</template>
</view>
</view>
</view>
<view v-if="feedbackVisible" class="review-feedback">
<image src="/static/assets/foundation/opaque/a01-secondary-button.png" mode="scaleToFill" />
<text>{{ feedbackMessage }}</text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { computed, ref } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
import PageHeader from '@/components/PageHeader.vue'
import { genealogyContext } from '@/utils/genealogy-context.js'
@@ -65,6 +92,14 @@ const reviewSamples = [
const genealogyId = ref('')
const reviewState = ref('loading')
const errorMessage = ref('')
const confirmation = ref(null)
const helpVisible = ref(false)
const feedbackVisible = ref(false)
const feedbackMessage = ref('')
let feedbackTimer = null
onUnload(() => { if (feedbackTimer) clearTimeout(feedbackTimer) })
const stateTitle = computed(() => reviewState.value === 'empty' ? '暂无待审核申请' : reviewState.value === 'no-permission' ? '当前账号无审核权限' : '审核列表暂时无法读取')
const stateCopy = computed(() => reviewState.value === 'empty' ? '新的入谱申请会在这里出现,并同步发送消息提醒。' : reviewState.value === 'no-permission' ? '只有家谱所有者或具备审核权限的管理员可以处理申请。' : errorMessage.value || '请检查网络或家谱权限后重试。')
const loadApplications = (query = {}) => {
reviewState.value = 'loading'
@@ -72,6 +107,7 @@ const loadApplications = (query = {}) => {
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 (query.state === 'no-permission') { reviewState.value = 'no-permission'; return }
if (!genealogyId.value) {
errorMessage.value = '没有找到当前家谱,请从家谱总览进入。'
reviewState.value = 'error'
@@ -84,22 +120,27 @@ const loadApplications = (query = {}) => {
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' })
}
})
confirmation.value = { item, approved }
}
const showHelp = () => uni.showModal({ title: '审核说明', content: '请核对申请人的姓名、亲属关系和补充说明,仅确认与本家谱存在真实关系的申请。', showCancel: false })
const closeDialog = () => { confirmation.value = null; helpVisible.value = false }
const showFeedback = (message) => {
feedbackMessage.value = message
feedbackVisible.value = true
if (feedbackTimer) clearTimeout(feedbackTimer)
feedbackTimer = setTimeout(() => { feedbackVisible.value = false; feedbackTimer = null }, 1800)
}
const applyAudit = () => {
const current = confirmation.value
if (!current) return
current.item.status = current.approved ? 'APPROVED' : 'REJECTED'
closeDialog()
showFeedback(current.approved ? '已通过申请' : '已拒绝申请')
}
const showHelp = () => { helpVisible.value = true }
</script>
<style scoped lang="scss">
.review-page { position: relative; min-height: 100vh; overflow: hidden; background: $paper; }
.review-page { position: relative; min-height: 100vh; overflow-x: 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; }
@@ -130,4 +171,17 @@ const showHelp = () => uni.showModal({ title: '审核说明', content: '请核
.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; }
.review-dialog-layer { position: fixed; z-index: 30; inset: 0; display: flex; align-items: center; justify-content: center; box-sizing: border-box; padding: 42rpx; background: rgba(34, 20, 12, .58); }
.review-dialog { position: relative; width: 100%; max-width: 660rpx; min-height: 410rpx; }
.review-dialog__skin { position: absolute; inset: 0; width: 100%; height: 100%; }
.review-dialog__content { position: relative; z-index: 1; display: flex; min-height: 410rpx; flex-direction: column; align-items: center; box-sizing: border-box; padding: 72rpx 60rpx 42rpx; text-align: center; }
.review-dialog__title { color: $ink; font-family: 'STKaiti', 'KaiTi', serif; font-size: 36rpx; font-weight: 700; }
.review-dialog__copy { margin-top: 24rpx; color: $ink-muted; font-size: 23rpx; line-height: 38rpx; }
.review-dialog__actions { display: flex; width: 100%; margin-top: auto; border-top: 1rpx solid rgba(181, 138, 75, .42); }
.review-dialog__action { display: flex; flex: 1; min-height: 74rpx; align-items: center; justify-content: center; color: $ink-muted; font-size: 23rpx; }
.review-dialog__action--primary { border-left: 1rpx solid rgba(181, 138, 75, .42); color: $brand-red; font-weight: 700; }
.review-dialog__single { display: flex; min-height: 76rpx; align-items: center; margin-top: auto; color: $brand-red; font-size: 24rpx; font-weight: 700; }
.review-feedback { position: fixed; z-index: 40; top: 140rpx; left: 50%; display: flex; min-width: 250rpx; min-height: 76rpx; align-items: center; justify-content: center; padding: 0 36rpx; transform: translateX(-50%); }
.review-feedback image { position: absolute; inset: 0; width: 100%; height: 100%; }
.review-feedback text { position: relative; z-index: 1; color: $ink; font-size: 23rpx; }
</style>