shinnosuke
2026-08-06 79ae06e6b4172d90df77b0e49ad3ab12ba63cd45
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { auditUpgradeApplication, getUpgradeApplicationDetail } from '../api/admin'
import type { UpgradeApplication, UpgradeApplicationHonor } from '../types/admin'
 
const route = useRoute()
const router = useRouter()
const detail = ref<UpgradeApplication>()
const loading = ref(false)
const processing = ref(false)
const pending = computed(() => detail.value?.status === '待审核')
 
function text(value: unknown) {
  return value === undefined || value === null || value === '' ? '-' : String(value)
}
function formatDate(value: unknown) {
  return typeof value === 'string' ? value.replace('T', ' ').slice(0, 19) : text(value)
}
function imageUrl(honor: UpgradeApplicationHonor) {
  const url = honor.proofUrl || honor.proofFileUrl || honor.proofFileId
  return typeof url === 'string' ? url : ''
}
function resolveImageUrl(url: string) {
  if (!url || /^https?:\/\//i.test(url)) return url
  const base = import.meta.env.VITE_API_BASE_URL || ''
  return base ? `${base.replace(/\/$/, '')}${url}` : url
}
 
async function load() {
  loading.value = true
  try {
    detail.value = await getUpgradeApplicationDetail(String(route.params.id))
  } finally {
    loading.value = false
  }
}
 
async function approve() {
  if (!detail.value) return
  await ElMessageBox.confirm('确认通过该升级申请?通过后将更新持卡人等级。', '审核通过', { type: 'warning' })
  await process('已通过')
}
 
async function reject() {
  if (!detail.value) return
  const result = await ElMessageBox.prompt('请输入驳回原因', '审核不通过', { inputValidator: value => !!value.trim(), inputErrorMessage: '请输入驳回原因' })
  await process('已驳回', result.value)
}
 
async function process(status: string, remark = '') {
  if (!detail.value) return
  processing.value = true
  try {
    detail.value = await auditUpgradeApplication(detail.value.id, status, remark)
    ElMessage.success(status === '已通过' ? '升级申请已通过' : '升级申请已驳回')
  } finally {
    processing.value = false
  }
}
 
onMounted(load)
</script>
 
<template>
  <div v-loading="loading" class="upgrade-application-detail-page">
    <div class="detail-toolbar"><el-button @click="router.back">返回</el-button><span>升级申请详情</span></div>
    <section v-if="detail" class="upgrade-detail-panel">
      <h3>持卡人信息</h3>
      <div class="upgrade-detail-grid">
        <div>持卡人姓名:<strong>{{ text(detail.talentName) }}</strong></div>
        <div>身份证号:<strong>{{ text(detail.talentIdCardNo) }}</strong></div>
        <div>联系方式:<strong>{{ text(detail.talentMobile) }}</strong></div>
        <div>人才等级:<strong>{{ text(detail.currentLevel) }}</strong></div>
        <div>人才卡号:<strong>{{ text(detail.talentCardNo) }}</strong></div>
      </div>
    </section>
    <section v-if="detail" class="upgrade-detail-panel">
      <h3>申请详情</h3>
      <div class="upgrade-detail-grid">
        <div>申请编号:<strong>{{ text(detail.applicationNo) }}</strong></div>
        <div>申请等级:<strong>{{ text(detail.targetLevel) }}</strong></div>
        <div>申请时间:<strong>{{ formatDate(detail.applyTime) }}</strong></div>
        <div class="full-line">申请理由:<strong>{{ text(detail.applyReason) }}</strong></div>
      </div>
      <div v-for="honor in (detail.honors || [])" :key="honor.id" class="honor-block">
        <div>新获得的荣誉称号/大奖项:<strong>{{ text(honor.honorName) }}</strong></div>
        <div>获得时间:<strong>{{ text(honor.obtainedDate) }}</strong></div>
        <div class="honor-images">
          <el-image
            v-if="imageUrl(honor)"
            :src="resolveImageUrl(imageUrl(honor))"
            :preview-src-list="[resolveImageUrl(imageUrl(honor))]"
            preview-teleported
            fit="cover"
            class="honor-image"
            alt="荣誉材料"
          />
          <span v-else>暂无材料图片</span>
        </div>
      </div>
    </section>
    <section v-if="detail" class="upgrade-detail-actions">
      <template v-if="pending">
        <el-button type="primary" :loading="processing" @click="approve">处理</el-button>
        <el-button type="danger" :loading="processing" @click="reject">审核不通过</el-button>
      </template>
      <span v-else>审核结果:{{ text(detail.status) }}<template v-if="detail.auditRemark">({{ detail.auditRemark }})</template></span>
    </section>
  </div>
</template>
 
<style scoped>
.upgrade-application-detail-page { padding: 20px; }
.detail-toolbar { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; font-size: 18px; font-weight: 600; }
.upgrade-detail-panel { padding: 18px 20px; margin-bottom: 14px; background: #fff; border: 1px solid #ebeef5; }
.upgrade-detail-panel h3 { margin: 0 0 16px; font-size: 16px; }
.upgrade-detail-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px 36px; padding: 18px; background: #f5f6f8; color: #606266; }
.upgrade-detail-grid strong { color: #303133; font-weight: 500; }
.full-line { grid-column: 1 / -1; }
.honor-block { margin-top: 14px; padding: 16px; background: #f5f6f8; color: #606266; }
.honor-images { display: flex; gap: 20px; min-height: 130px; margin-top: 14px; }
.honor-image { width: 150px; height: 110px; background: #e9eaec; cursor: zoom-in; }
.honor-images span { display: flex; align-items: center; justify-content: center; width: 150px; height: 110px; color: #909399; background: #e9eaec; }
.upgrade-detail-actions { display: flex; align-items: center; gap: 12px; padding: 18px 0; }
@media (max-width: 800px) { .upgrade-detail-grid { grid-template-columns: 1fr; } .full-line { grid-column: auto; } }
</style>