diff --git a/src/api/index.js b/src/api/index.js
index 2abe03b..2f4b01e 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -208,11 +208,13 @@ export const certificationApi = {
// 管理员代用户完成认证(暂不关联合同)
adminCompleteWithoutContract: (data) => request.post('/certifications/admin/complete-without-contract', data),
- // 管理端企业审核:列表、详情、通过、拒绝
+ // 管理端企业审核:列表(按状态机 certification_status 筛选)、详情、通过、拒绝、按用户变更状态
adminListSubmitRecords: (params) => request.get('/certifications/admin/submit-records', { params }),
adminGetSubmitRecord: (id) => request.get(`/certifications/admin/submit-records/${id}`),
adminApproveSubmitRecord: (id, data) => request.post(`/certifications/admin/submit-records/${id}/approve`, data || {}),
- adminRejectSubmitRecord: (id, data) => request.post(`/certifications/admin/submit-records/${id}/reject`, data)
+ adminRejectSubmitRecord: (id, data) => request.post(`/certifications/admin/submit-records/${id}/reject`, data),
+ // 管理端按用户变更认证状态(以状态机为准:info_submitted=通过 / info_rejected=拒绝)
+ adminTransitionCertificationStatus: (data) => request.post('/certifications/admin/transition-status', data)
}
// API相关接口
diff --git a/src/pages/admin/certification-reviews/index.vue b/src/pages/admin/certification-reviews/index.vue
index 794c8ff..8898bc9 100644
--- a/src/pages/admin/certification-reviews/index.vue
+++ b/src/pages/admin/certification-reviews/index.vue
@@ -8,15 +8,15 @@
-
- {{ detail.company_name }}
- {{ detail.unified_social_code }}
- {{ detail.legal_person_name }}
- {{ detail.legal_person_id }}
- {{ detail.legal_person_phone }}
- {{ detail.enterprise_address }}
- {{ (detail.authorized_rep_name ?? detail.authorizedRepName) || '-' }}
- {{ (detail.authorized_rep_id ?? detail.authorizedRepId) || '-' }}
- {{ (detail.authorized_rep_phone ?? detail.authorizedRepPhone) || '-' }}
- {{ detail.api_usage || '-' }}
- {{ formatDate(detail.submit_at) }}
-
-
- {{ reviewStatusDisplay(detail) }}
-
-
-
- {{ detail.manual_review_remark }}
-
-
- {{ detail.failure_reason }}
-
-
+
+ 基本信息
+
+ - 企业名称
+ - {{ detail.company_name }}
+ - 统一社会信用代码
+ - {{ detail.unified_social_code }}
+ - 法人姓名
+ - {{ detail.legal_person_name }}
+ - 法人身份证号
+ - {{ detail.legal_person_id }}
+ - 法人手机号
+ - {{ detail.legal_person_phone }}
+ - 企业地址
+ - {{ detail.enterprise_address || '-' }}
+ - 提交时间
+ - {{ formatDate(detail.submit_at) }}
+ - 认证状态
+ -
+
+ {{ certificationStatusDisplay(detail?.certification_status) }}
+
+
+
+ - 失败原因
+ - {{ detail.failure_reason }}
+
+
+
+
+
+ 授权代表
+
+ - 姓名
+ - {{ (detail.authorized_rep_name ?? detail.authorizedRepName) || '-' }}
+ - 身份证号
+ - {{ (detail.authorized_rep_id ?? detail.authorizedRepId) || '-' }}
+ - 手机号
+ - {{ (detail.authorized_rep_phone ?? detail.authorizedRepPhone) || '-' }}
+
+
+
+
+ 应用场景说明
+ {{ detail.api_usage || '无' }}
+
营业执照
@@ -227,6 +249,7 @@ const approveRemark = ref('')
const rejectRemark = ref('')
const actionLoading = ref(false)
const pendingRecordId = ref('')
+const pendingUserId = ref('')
function formatDate(val) {
if (!val) return '-'
@@ -238,31 +261,45 @@ function formatDate(val) {
}
}
-// 已完成企业认证的状态:展示「已审核」,不再展示通过/拒绝
-const ENTERPRISE_VERIFIED_STATUSES = ['enterprise_verified', 'contract_applied', 'contract_signed', 'contract_rejected', 'contract_expired', 'completed']
-
-function isEnterpriseVerified(certificationStatus) {
- if (!certificationStatus) return false
- return ENTERPRISE_VERIFIED_STATUSES.includes(certificationStatus)
+// 以状态机为准:认证状态展示与是否可操作(全流程口径)
+const CERTIFICATION_STATUS_LABELS = {
+ pending: '待认证',
+ info_pending_review: '待审核',
+ info_submitted: '已通过',
+ info_rejected: '已拒绝',
+ enterprise_verified: '已企业认证',
+ contract_applied: '已申请合同',
+ contract_signed: '已签署合同',
+ contract_rejected: '合同拒签',
+ contract_expired: '合同超时',
+ completed: '已完成'
}
-function reviewStatusDisplay(row) {
- if (isEnterpriseVerified(row?.certification_status)) return '已审核'
- const m = { pending: '待审核', approved: '已通过', rejected: '已拒绝' }
- return m[row?.manual_review_status] || row?.manual_review_status || '-'
+function certificationStatusDisplay(certificationStatus) {
+ if (!certificationStatus) return '-'
+ return CERTIFICATION_STATUS_LABELS[certificationStatus] || certificationStatus
}
function statusTagType(row) {
- if (isEnterpriseVerified(row?.certification_status)) return 'info'
- const m = { pending: 'warning', approved: 'success', rejected: 'danger' }
- return m[row?.manual_review_status] || 'info'
+ const status = row?.certification_status
+ const m = {
+ pending: 'info',
+ info_pending_review: 'warning',
+ info_submitted: 'success',
+ info_rejected: 'danger',
+ enterprise_verified: 'success',
+ contract_applied: 'info',
+ contract_signed: 'success',
+ contract_rejected: 'danger',
+ contract_expired: 'warning',
+ completed: 'success'
+ }
+ return m[status] || 'info'
}
function canShowApproveReject(row) {
if (!row) return false
- if (row.manual_review_status !== 'pending') return false
- if (isEnterpriseVerified(row.certification_status)) return false
- return true
+ return row.certification_status === 'info_pending_review'
}
// 判断是否可作为图片展示(含七牛云等无扩展名的 CDN URL)
@@ -309,7 +346,7 @@ async function loadList() {
const res = await certificationApi.adminListSubmitRecords({
page: page.value,
page_size: pageSize.value,
- manual_review_status: filterStatus.value || undefined,
+ certification_status: filterStatus.value || undefined,
company_name: filterCompanyName.value || undefined,
legal_person_phone: filterLegalPersonPhone.value || undefined,
legal_person_name: filterLegalPersonName.value || undefined
@@ -336,6 +373,7 @@ async function openDetail(id) {
function handleApprove(row) {
pendingRecordId.value = row.id
+ pendingUserId.value = row.user_id
approveRemark.value = ''
approveDialogVisible.value = true
}
@@ -343,19 +381,26 @@ function handleApprove(row) {
function approveFromDrawer() {
if (!detail.value?.id) return
pendingRecordId.value = detail.value.id
+ pendingUserId.value = detail.value.user_id
approveRemark.value = ''
approveDialogVisible.value = true
}
async function confirmApprove() {
- if (!pendingRecordId.value) return
+ if (!pendingUserId.value) return
actionLoading.value = true
try {
- await certificationApi.adminApproveSubmitRecord(pendingRecordId.value, { remark: approveRemark.value })
+ await certificationApi.adminTransitionCertificationStatus({
+ user_id: pendingUserId.value,
+ target_status: 'info_submitted',
+ remark: approveRemark.value || ''
+ })
ElMessage.success('已通过')
approveDialogVisible.value = false
drawerVisible.value = false
detail.value = null
+ pendingRecordId.value = ''
+ pendingUserId.value = ''
loadList()
} catch (e) {
ElMessage.error(e?.message || '操作失败')
@@ -366,6 +411,7 @@ async function confirmApprove() {
function handleReject(row) {
pendingRecordId.value = row.id
+ pendingUserId.value = row.user_id
rejectRemark.value = ''
rejectDialogVisible.value = true
}
@@ -373,19 +419,26 @@ function handleReject(row) {
function rejectFromDrawer() {
if (!detail.value?.id) return
pendingRecordId.value = detail.value.id
+ pendingUserId.value = detail.value.user_id
rejectRemark.value = ''
rejectDialogVisible.value = true
}
async function confirmReject() {
- if (!pendingRecordId.value || !rejectRemark.value?.trim()) return
+ if (!pendingUserId.value || !rejectRemark.value?.trim()) return
actionLoading.value = true
try {
- await certificationApi.adminRejectSubmitRecord(pendingRecordId.value, { remark: rejectRemark.value.trim() })
+ await certificationApi.adminTransitionCertificationStatus({
+ user_id: pendingUserId.value,
+ target_status: 'info_rejected',
+ remark: rejectRemark.value.trim()
+ })
ElMessage.success('已拒绝')
rejectDialogVisible.value = false
drawerVisible.value = false
detail.value = null
+ pendingRecordId.value = ''
+ pendingUserId.value = ''
loadList()
} catch (e) {
ElMessage.error(e?.message || '操作失败')
@@ -436,15 +489,73 @@ onMounted(() => {
align-items: center;
}
.detail-content {
- padding-right: 8px;
+ padding-right: 12px;
+ max-height: calc(100vh - 60px);
+ overflow-y: auto;
+}
+.detail-section {
+ margin-bottom: 20px;
+}
+.detail-section-title {
+ font-size: 13px;
+ font-weight: 600;
+ color: #475569;
+ margin: 0 0 10px;
+ padding-bottom: 6px;
+ border-bottom: 1px solid #e2e8f0;
+}
+.detail-dl {
+ display: grid;
+ grid-template-columns: 110px 1fr;
+ gap: 8px 16px;
+ margin: 0;
+ font-size: 13px;
+}
+.detail-dl dt {
+ margin: 0;
+ color: #64748b;
+ font-weight: 500;
+ line-height: 1.5;
+}
+.detail-dl dd {
+ margin: 0;
+ color: #1e293b;
+ line-height: 1.5;
+ word-break: break-word;
+}
+.detail-mono {
+ font-family: ui-monospace, monospace;
+ font-size: 12px;
+}
+.detail-long {
+ white-space: pre-wrap;
+ word-break: break-word;
+}
+.detail-long-block {
+ font-size: 13px;
+ line-height: 1.6;
+ color: #334155;
+ white-space: pre-wrap;
+ word-break: break-word;
+ padding: 12px;
+ background: #f8fafc;
+ border-radius: 8px;
+ border: 1px solid #e2e8f0;
+ max-height: 160px;
+ overflow-y: auto;
+}
+.detail-error {
+ color: #dc2626;
}
.image-section {
margin-top: 20px;
}
.image-section h4 {
- font-size: 14px;
+ font-size: 13px;
+ font-weight: 600;
color: #475569;
margin: 0 0 8px;
+ padding-bottom: 4px;
}
.image-list {
display: flex;