Compare commits
4 Commits
51f04d7528
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a7cd16848c | |||
| 33dc672440 | |||
| 7c2f828222 | |||
| d3dde79474 |
@@ -43,6 +43,7 @@
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-if="!isMobile"
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
stripe
|
||||
@@ -76,6 +77,31 @@
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div v-else v-loading="loading" class="mobile-list">
|
||||
<div v-if="list.length" class="mobile-card-list">
|
||||
<article v-for="row in list" :key="row.id" class="mobile-card">
|
||||
<div class="mobile-card-header">
|
||||
<div class="mobile-company">{{ row.company_name || '-' }}</div>
|
||||
<el-tag :type="statusTagType(row)" size="small">
|
||||
{{ certificationStatusDisplay(row?.certification_status) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="mobile-card-info"><span>提交时间:</span>{{ formatDate(row.submit_at) }}</div>
|
||||
<div class="mobile-card-info"><span>法人:</span>{{ row.legal_person_name || '-' }}</div>
|
||||
<div class="mobile-card-info"><span>手机号:</span>{{ row.legal_person_phone || '-' }}</div>
|
||||
<div class="mobile-card-info"><span>统一代码:</span>{{ row.unified_social_code || '-' }}</div>
|
||||
<div class="mobile-card-actions">
|
||||
<el-button type="primary" plain size="small" @click="openDetail(row.id)">查看详情</el-button>
|
||||
<template v-if="canShowApproveReject(row)">
|
||||
<el-button type="success" plain size="small" @click="handleApprove(row)">通过</el-button>
|
||||
<el-button type="danger" plain size="small" @click="handleReject(row)">拒绝</el-button>
|
||||
</template>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<el-empty v-else description="暂无数据" />
|
||||
</div>
|
||||
|
||||
<div class="pagination-wrap">
|
||||
<el-pagination
|
||||
v-model:current-page="page"
|
||||
@@ -92,7 +118,7 @@
|
||||
<el-drawer
|
||||
v-model="drawerVisible"
|
||||
title="企业信息详情"
|
||||
size="560"
|
||||
:size="isMobile ? '100%' : '560px'"
|
||||
direction="rtl"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
@@ -200,7 +226,7 @@
|
||||
</el-drawer>
|
||||
|
||||
<!-- 通过弹窗 -->
|
||||
<el-dialog v-model="approveDialogVisible" title="审核通过" width="400px">
|
||||
<el-dialog v-model="approveDialogVisible" title="审核通过" :width="isMobile ? '92%' : '400px'">
|
||||
<el-form label-width="80">
|
||||
<el-form-item label="审核备注">
|
||||
<el-input v-model="approveRemark" type="textarea" :rows="3" placeholder="选填" />
|
||||
@@ -213,7 +239,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 拒绝弹窗 -->
|
||||
<el-dialog v-model="rejectDialogVisible" title="审核拒绝" width="400px">
|
||||
<el-dialog v-model="rejectDialogVisible" title="审核拒绝" :width="isMobile ? '92%' : '400px'">
|
||||
<el-form label-width="80">
|
||||
<el-form-item label="拒绝原因" required>
|
||||
<el-input v-model="rejectRemark" type="textarea" :rows="3" placeholder="必填" />
|
||||
@@ -250,6 +276,12 @@ const rejectRemark = ref('')
|
||||
const actionLoading = ref(false)
|
||||
const pendingRecordId = ref('')
|
||||
const pendingUserId = ref('')
|
||||
const isMobile = ref(false)
|
||||
|
||||
function updateMobileState() {
|
||||
if (typeof window === 'undefined') return
|
||||
isMobile.value = window.innerWidth <= 768
|
||||
}
|
||||
|
||||
function formatDate(val) {
|
||||
if (!val) return '-'
|
||||
@@ -297,9 +329,14 @@ function statusTagType(row) {
|
||||
return m[status] || 'info'
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否展示通过/拒绝:须当前认证为待审核,且本条提交记录为「校验通过」(verified)。
|
||||
* 历史失败记录 (failed) 与认证状态无关字段共用同一 certification_status,否则会误显按钮。
|
||||
*/
|
||||
function canShowApproveReject(row) {
|
||||
if (!row) return false
|
||||
return row.certification_status === 'info_pending_review'
|
||||
if (row.certification_status !== 'info_pending_review') return false
|
||||
return row.status === 'verified'
|
||||
}
|
||||
|
||||
// 判断是否可作为图片展示(含七牛云等无扩展名的 CDN URL)
|
||||
@@ -448,8 +485,14 @@ async function confirmReject() {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
updateMobileState()
|
||||
window.addEventListener('resize', updateMobileState)
|
||||
loadList()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', updateMobileState)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -472,6 +515,8 @@ onMounted(() => {
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@@ -480,6 +525,48 @@ onMounted(() => {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.mobile-list {
|
||||
min-height: 200px;
|
||||
}
|
||||
.mobile-card-list {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
.mobile-card {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
padding: 12px;
|
||||
background: #fff;
|
||||
}
|
||||
.mobile-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.mobile-company {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
word-break: break-word;
|
||||
}
|
||||
.mobile-card-info {
|
||||
color: #475569;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 4px;
|
||||
word-break: break-all;
|
||||
}
|
||||
.mobile-card-info span {
|
||||
color: #64748b;
|
||||
}
|
||||
.mobile-card-actions {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.drawer-title {
|
||||
margin-right: 12px;
|
||||
}
|
||||
@@ -579,4 +666,37 @@ onMounted(() => {
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.certification-reviews-page {
|
||||
padding: 12px;
|
||||
}
|
||||
.page-title {
|
||||
font-size: 18px;
|
||||
}
|
||||
.page-subtitle {
|
||||
font-size: 13px;
|
||||
}
|
||||
.toolbar > * {
|
||||
width: 100% !important;
|
||||
}
|
||||
.pagination-wrap {
|
||||
justify-content: center;
|
||||
}
|
||||
.detail-content {
|
||||
padding-right: 0;
|
||||
}
|
||||
.drawer-actions {
|
||||
gap: 6px;
|
||||
}
|
||||
.detail-dl {
|
||||
grid-template-columns: 88px 1fr;
|
||||
gap: 6px 10px;
|
||||
}
|
||||
.image-link {
|
||||
width: 88px;
|
||||
height: 88px;
|
||||
line-height: 88px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -119,9 +119,9 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 暂时隐藏:办公场地图片上传 -->
|
||||
<!-- <el-row :gutter="16" class="mb-4">
|
||||
<el-row :gutter="16" class="mb-4">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="办公场地照片">
|
||||
<el-form-item label="办公场地照片" prop="officePlaceImageURLs">
|
||||
<div class="text-xs mb-1 text-blue-500">
|
||||
请在非 IE 浏览器下上传大小不超过 1M 的图片,最多 10 张,需体现门楣 LOGO、办公设备与工作人员。
|
||||
</div>
|
||||
@@ -146,7 +146,7 @@
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row> -->
|
||||
</el-row>
|
||||
|
||||
|
||||
<el-row :gutter="16" class="mb-4">
|
||||
@@ -201,7 +201,7 @@
|
||||
|
||||
|
||||
<!-- 暂时隐藏:授权代表信息(姓名、身份证号、手机号、授权代表身份证) -->
|
||||
<!-- <h3 class="section-title">授权代表信息</h3>
|
||||
<h3 class="section-title">授权代表信息</h3>
|
||||
<p class="section-desc">授权代表信息用于证明该人员已获得企业授权,请确保姓名、身份证号、手机号及身份证正反面照片真实有效。</p>
|
||||
|
||||
<el-row :gutter="16" class="mb-4">
|
||||
@@ -278,10 +278,10 @@
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row> -->
|
||||
</el-row>
|
||||
|
||||
<!-- 暂时隐藏:应用场景说明、应用场景附件 -->
|
||||
<!-- <h3 class="section-title">应用场景填写</h3>
|
||||
<h3 class="section-title">应用场景填写</h3>
|
||||
<p class="section-desc">请描述您调用接口的具体业务场景</p>
|
||||
|
||||
<el-row :gutter="16" class="mb-4">
|
||||
@@ -303,7 +303,7 @@
|
||||
<el-row :gutter="16" class="mb-4">
|
||||
<el-col :span="24">
|
||||
|
||||
<el-form-item label="应用场景附件">
|
||||
<el-form-item label="应用场景附件" prop="scenarioAttachmentURLs">
|
||||
<div class="text-xs mb-1 text-blue-500">
|
||||
请在非 IE 浏览器下上传大小不超过 1M 的图片,最多 10 张后台应用截图。
|
||||
</div>
|
||||
@@ -328,7 +328,7 @@
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row> -->
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
@@ -493,6 +493,24 @@ const validatePhone = (rule, value, callback) => {
|
||||
callback()
|
||||
}
|
||||
|
||||
// 数组字段必填验证(至少上传/选择一项)
|
||||
const validateRequiredArray = (message) => (rule, value, callback) => {
|
||||
if (!Array.isArray(value) || value.length === 0) {
|
||||
callback(new Error(message))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
// 授权代表身份证要求:正反面都必须上传
|
||||
const validateAuthorizedRepIDImages = (rule, value, callback) => {
|
||||
if (!Array.isArray(value) || value.length < 2) {
|
||||
callback(new Error('请上传授权代表身份证正反面图片'))
|
||||
return
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
||||
// 表单验证规则
|
||||
const enterpriseRules = {
|
||||
companyName: [
|
||||
@@ -527,26 +545,32 @@ const enterpriseRules = {
|
||||
businessLicenseImageURL: [
|
||||
{ required: true, message: '请上传营业执照图片', trigger: 'change' }
|
||||
],
|
||||
officePlaceImageURLs: [
|
||||
{ validator: validateRequiredArray('请上传办公场地照片'), trigger: 'change' }
|
||||
],
|
||||
// 暂时隐藏的表单项,校验已关闭,恢复显示时请还原
|
||||
// apiUsage: [
|
||||
// { required: true, message: '请填写接口用途', trigger: 'blur' },
|
||||
// { min: 5, max: 500, message: '接口用途长度应在5-500个字符之间', trigger: 'blur' }
|
||||
// ],
|
||||
// authorizedRepName: [
|
||||
// { required: true, message: '请输入授权代表姓名', trigger: 'blur' },
|
||||
// { min: 2, max: 20, message: '授权代表姓名长度应在2-20个字符之间', trigger: 'blur' }
|
||||
// ],
|
||||
// authorizedRepID: [
|
||||
// { required: true, message: '请输入授权代表身份证号', trigger: 'blur' },
|
||||
// { validator: validateIDCard, trigger: 'blur' }
|
||||
// ],
|
||||
// authorizedRepPhone: [
|
||||
// { required: true, message: '请输入授权代表手机号', trigger: 'blur' },
|
||||
// { validator: validatePhone, trigger: 'blur' }
|
||||
// ],
|
||||
// authorizedRepIDImageURLs: [
|
||||
// { required: true, message: '请上传授权代表身份证正反面图片', trigger: 'change' }
|
||||
// ]
|
||||
apiUsage: [
|
||||
{ required: true, message: '请填写接口用途', trigger: 'blur' },
|
||||
{ min: 5, max: 500, message: '接口用途长度应在5-500个字符之间', trigger: 'blur' }
|
||||
],
|
||||
scenarioAttachmentURLs: [
|
||||
{ validator: validateRequiredArray('请上传应用场景附件'), trigger: 'change' }
|
||||
],
|
||||
authorizedRepName: [
|
||||
{ required: true, message: '请输入授权代表姓名', trigger: 'blur' },
|
||||
{ min: 2, max: 20, message: '授权代表姓名长度应在2-20个字符之间', trigger: 'blur' }
|
||||
],
|
||||
authorizedRepID: [
|
||||
{ required: true, message: '请输入授权代表身份证号', trigger: 'blur' },
|
||||
{ validator: validateIDCard, trigger: 'blur' }
|
||||
],
|
||||
authorizedRepPhone: [
|
||||
{ required: true, message: '请输入授权代表手机号', trigger: 'blur' },
|
||||
{ validator: validatePhone, trigger: 'blur' }
|
||||
],
|
||||
authorizedRepIDImageURLs: [
|
||||
{ validator: validateAuthorizedRepIDImages, trigger: 'change' }
|
||||
]
|
||||
}
|
||||
|
||||
// 监听props变化
|
||||
@@ -698,10 +722,10 @@ const syncFormUrlsAndCheckReady = () => {
|
||||
const hasUnfinished = (list) => list.some((f) => f.raw && !f.response?.url)
|
||||
if (hasUploading(businessLicenseFileList.value) || hasUnfinished(businessLicenseFileList.value)) return false
|
||||
// 以下上传项已暂时隐藏,不再参与“未上传完成”的拦截
|
||||
// if (hasUploading(officePlaceFileList.value) || hasUnfinished(officePlaceFileList.value)) return false
|
||||
// if (hasUploading(scenarioFileList.value) || hasUnfinished(scenarioFileList.value)) return false
|
||||
// if (hasUploading(authorizedRepIDFrontFileList.value) || hasUnfinished(authorizedRepIDFrontFileList.value)) return false
|
||||
// if (hasUploading(authorizedRepIDBackFileList.value) || hasUnfinished(authorizedRepIDBackFileList.value)) return false
|
||||
if (hasUploading(officePlaceFileList.value) || hasUnfinished(officePlaceFileList.value)) return false
|
||||
if (hasUploading(scenarioFileList.value) || hasUnfinished(scenarioFileList.value)) return false
|
||||
if (hasUploading(authorizedRepIDFrontFileList.value) || hasUnfinished(authorizedRepIDFrontFileList.value)) return false
|
||||
if (hasUploading(authorizedRepIDBackFileList.value) || hasUnfinished(authorizedRepIDBackFileList.value)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -798,6 +822,7 @@ const updateAuthorizedRepIDImageURLs = () => {
|
||||
if (frontUrl) urls.push(frontUrl)
|
||||
if (backUrl) urls.push(backUrl)
|
||||
form.value.authorizedRepIDImageURLs = urls
|
||||
enterpriseFormRef.value?.validateField('authorizedRepIDImageURLs')
|
||||
}
|
||||
|
||||
// 办公场地图片变更:选择即上传
|
||||
@@ -807,11 +832,13 @@ const handleOfficePlaceChange = async (file, fileList) => {
|
||||
await uploadFileOnceSelected(file)
|
||||
}
|
||||
form.value.officePlaceImageURLs = extractUrls(fileList)
|
||||
enterpriseFormRef.value?.validateField('officePlaceImageURLs')
|
||||
}
|
||||
|
||||
const handleOfficePlaceRemove = (file, fileList) => {
|
||||
officePlaceFileList.value = fileList
|
||||
form.value.officePlaceImageURLs = extractUrls(fileList)
|
||||
enterpriseFormRef.value?.validateField('officePlaceImageURLs')
|
||||
}
|
||||
|
||||
// 应用场景附件图片变更:选择即上传
|
||||
@@ -821,11 +848,13 @@ const handleScenarioChange = async (file, fileList) => {
|
||||
await uploadFileOnceSelected(file)
|
||||
}
|
||||
form.value.scenarioAttachmentURLs = extractUrls(fileList)
|
||||
enterpriseFormRef.value?.validateField('scenarioAttachmentURLs')
|
||||
}
|
||||
|
||||
const handleScenarioRemove = (file, fileList) => {
|
||||
scenarioFileList.value = fileList
|
||||
form.value.scenarioAttachmentURLs = extractUrls(fileList)
|
||||
enterpriseFormRef.value?.validateField('scenarioAttachmentURLs')
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
|
||||
@@ -68,14 +68,13 @@
|
||||
@submit="handleEnterpriseSubmit"
|
||||
/>
|
||||
|
||||
<!-- 暂时隐藏:第二步人工审核 -->
|
||||
<!-- <ManualReviewPending
|
||||
<ManualReviewPending
|
||||
v-if="currentStep === 'manual_review'"
|
||||
:certification-data="certificationData"
|
||||
:submit-time="manualReviewSubmitTime"
|
||||
:company-name="enterpriseForm.companyName"
|
||||
@refresh="getCertificationDetails"
|
||||
/> -->
|
||||
/>
|
||||
|
||||
<EnterpriseVerify
|
||||
v-if="currentStep === 'enterprise_verify'"
|
||||
@@ -146,7 +145,6 @@ import EnterpriseVerify from './components/EnterpriseVerify.vue'
|
||||
import ManualReviewPending from './components/ManualReviewPending.vue'
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
// 认证步骤配置(暂时隐藏第二步「人工审核」,恢复时取消注释 manual_review 并还原 setCurrentStepByStatus 中 info_pending_review 分支)
|
||||
const certificationSteps = [
|
||||
{
|
||||
key: 'enterprise_info',
|
||||
@@ -154,12 +152,12 @@ const certificationSteps = [
|
||||
description: '填写企业基本信息和法人信息',
|
||||
icon: BuildingOfficeIcon,
|
||||
},
|
||||
// {
|
||||
// key: 'manual_review',
|
||||
// title: '人工审核',
|
||||
// description: '等待管理员审核企业信息',
|
||||
// icon: ClockIcon,
|
||||
// },
|
||||
{
|
||||
key: 'manual_review',
|
||||
title: '人工审核',
|
||||
description: '等待管理员审核企业信息',
|
||||
icon: ClockIcon,
|
||||
},
|
||||
{
|
||||
key: 'enterprise_verify',
|
||||
title: '企业认证',
|
||||
@@ -416,8 +414,7 @@ const setCurrentStepByStatus = async () => {
|
||||
currentStep.value = 'enterprise_info'
|
||||
break
|
||||
case 'info_pending_review':
|
||||
// 暂时跳过人工审核展示,直接进入企业认证步骤
|
||||
currentStep.value = 'enterprise_verify'
|
||||
currentStep.value = 'manual_review'
|
||||
break
|
||||
case 'info_submitted':
|
||||
currentStep.value = 'enterprise_verify'
|
||||
|
||||
Reference in New Issue
Block a user