This commit is contained in:
2026-07-26 23:14:54 +08:00
parent 344981c6d5
commit a49affbcf2
10 changed files with 770 additions and 166 deletions

View File

@@ -75,7 +75,12 @@
:certification-data="certificationData"
:submit-time="manualReviewSubmitTime"
:company-name="enterpriseForm.companyName"
@refresh="getCertificationDetails"
@refresh="() => getCertificationDetails({ silent: true })"
/>
<PlatformSelect
v-if="currentStep === 'platform_select'"
@selected="handlePlatformSelected"
/>
<EnterpriseVerify
@@ -88,7 +93,7 @@
<div v-if="currentStep === 'contract_sign'">
<ContractPreview
v-if="certificationData?.status === 'enterprise_verified'"
:contract-url="stepMeta.ContractURL"
:contract-url="stepMeta.contract_url || stepMeta.ContractURL"
:loading="contractSignLoading"
@start-sign="handleStartContractSign"
/>
@@ -145,7 +150,9 @@ import ContractSign from './components/ContractSign.vue'
import EnterpriseInfo from './components/EnterpriseInfo.vue'
import EnterpriseVerify from './components/EnterpriseVerify.vue'
import ManualReviewPending from './components/ManualReviewPending.vue'
import PlatformSelect from './components/PlatformSelect.vue'
const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
const certificationSteps = [
{
@@ -160,6 +167,12 @@ const certificationSteps = [
description: '等待管理员审核企业信息',
icon: ClockIcon,
},
{
key: 'platform_select',
title: '选择平台',
description: '选择签署平台(法大大)',
icon: DocumentTextIcon,
},
{
key: 'enterprise_verify',
title: '企业认证',
@@ -224,6 +237,86 @@ const devCurrentStep = ref('enterprise_info')
// 合同签署加载状态
const contractSignLoading = ref(false)
// 合同签署状态轮询:进入 contract_applied 后定时拉详情,触发后端 checkAndUpdateSignStatus
let signPollTimer = null
const SIGN_POLL_INTERVAL = 5000
const signPolling = ref(false)
const autoSelectingPlatform = ref(false)
const stopSignStatusPolling = () => {
if (signPollTimer) {
clearTimeout(signPollTimer)
signPollTimer = null
}
signPolling.value = false
}
const startSignStatusPolling = () => {
if (signPollTimer) return
signPolling.value = true
const tick = async () => {
const status = certificationData.value?.status
if (status !== 'contract_applied') {
stopSignStatusPolling()
return
}
try {
const res = await certificationApi.getCertificationDetails()
if (res?.data) {
certificationData.value = res.data
stepMeta.value = res.data?.metadata || {}
const newStatus = res.data?.status
if (
newStatus === 'contract_signed' ||
newStatus === 'completed' ||
newStatus === 'contract_rejected' ||
newStatus === 'contract_expired'
) {
stopSignStatusPolling()
await setCurrentStepByStatus()
return
}
}
} catch (e) {
console.warn('合同签署状态轮询失败:', e)
}
if (signPolling.value) {
signPollTimer = setTimeout(tick, SIGN_POLL_INTERVAL)
}
}
signPollTimer = setTimeout(tick, SIGN_POLL_INTERVAL)
}
// 仅当可见平台为 1 个时可静默 select否则展示 PlatformSelect
async function maybeGoPlatformSelectOrAuto() {
const meta = certificationData.value?.metadata || {}
if (!meta.need_select_platform) return false
const platforms = meta.available_platforms || []
if (platforms.length <= 1 && meta.auto_select_platform && !autoSelectingPlatform.value) {
autoSelectingPlatform.value = true
try {
const res = await certificationApi.selectSignPlatform({
sign_platform: meta.auto_select_platform,
})
if (res?.data) {
certificationData.value = res.data
stepMeta.value = res.data.metadata || {}
}
await getCertificationDetails({ silent: true })
return true
} catch (e) {
ElMessage.error(e?.message || '选择签署平台失败')
} finally {
autoSelectingPlatform.value = false
}
}
currentStep.value = 'platform_select'
return true
}
// 只补 enterprise_verify 所需 auth_url不改动原有页面展示数据结构
// 轮询策略:最多 5 秒,每秒 1 次(最多 5 次)
const pollAuthUrlOnly = async (maxTries = 5) => {
@@ -282,6 +375,19 @@ const handleEnterpriseSubmit = async (payload) => {
}
}
const handlePlatformSelected = async (data) => {
if (data) {
certificationData.value = data
stepMeta.value = data.metadata || {}
}
await getCertificationDetails()
if (stepMeta.value?.auth_url) {
currentStep.value = 'enterprise_verify'
} else if (certificationData.value) {
await setCurrentStepByStatus()
}
}
const handleEnterpriseVerifySubmit = async () => {
try {
ElMessage.success('企业认证成功')
@@ -294,10 +400,23 @@ const handleEnterpriseVerifySubmit = async () => {
const handleStartContractSign = async () => {
try {
contractSignLoading.value = true
// 调用后端接口,发起合同签署
await certificationApi.applyContract()
const res = await certificationApi.applyContract()
const embedUrl = res?.data?.contract_sign_url
if (embedUrl) {
stepMeta.value = {
...(stepMeta.value || {}),
contract_sign_url: embedUrl,
contract_sign_short_url: res?.data?.contract_sign_short_url || '',
}
}
ElMessage.success('合同签署流程已启动')
await getCertificationDetails()
if (embedUrl) {
stepMeta.value = {
...(stepMeta.value || {}),
contract_sign_url: embedUrl,
}
}
} catch (error) {
ElMessage.error(error?.message || '发起签署失败,请稍后重试')
} finally {
@@ -357,10 +476,11 @@ const goToProfile = () => {
router.push('/profile')
}
// 获取认证详情
const getCertificationDetails = async () => {
// 获取认证详情silent=true 时不展示全页 loading用于人工审核/平台轮询)
const getCertificationDetails = async (opts = {}) => {
const silent = opts?.silent === true
try {
loading.value = true
if (!silent) loading.value = true
const res = await certificationApi.getCertificationDetails()
certificationData.value = res.data
console.log('s', res)
@@ -393,9 +513,14 @@ const getCertificationDetails = async () => {
// 步骤特定元数据
stepMeta.value = res.data?.metadata || {}
await setCurrentStepByStatus()
return true
} catch (error) {
console.error('获取认证详情失败:', error)
ElMessage.error('获取认证详情失败')
if (certificationData.value) {
await setCurrentStepByStatus()
}
return false
} finally {
loading.value = false
}
@@ -416,20 +541,46 @@ const setCurrentStepByStatus = async () => {
currentStep.value = 'enterprise_info'
break
case 'info_pending_review':
currentStep.value = 'manual_review'
if (certificationData.value?.metadata?.need_select_platform) {
if (await maybeGoPlatformSelectOrAuto()) return
} else {
currentStep.value = 'manual_review'
}
break
case 'info_submitted':
currentStep.value = 'enterprise_verify'
if (
!certificationData.value?.metadata?.auth_url &&
certificationData.value?.metadata?.need_select_platform
) {
if (await maybeGoPlatformSelectOrAuto()) return
} else {
currentStep.value = 'enterprise_verify'
}
break
case 'enterprise_verified':
if (
!certificationData.value?.metadata?.esign_flow_id &&
!certificationData.value?.metadata?.sign_task_ready
) {
if (await maybeGoPlatformSelectOrAuto()) return
currentStep.value = 'platform_select'
} else {
currentStep.value = 'contract_sign'
}
break
case 'contract_applied':
currentStep.value = 'contract_sign'
startSignStatusPolling()
break
case 'contract_rejected':
case 'contract_expired':
currentStep.value = 'contract_sign'
stopSignStatusPolling()
break
case 'contract_signed':
case 'completed':
currentStep.value = 'completed'
stopSignStatusPolling()
// 认证完成时重新获取用户信息
if (previousStatus !== 'completed') {
try {
@@ -530,12 +681,35 @@ async function handleIframeMessage(event) {
// 初始化
onMounted(() => {
// 若法大大等第三方在 iframe 内回跳到本页,立即顶层打开入驻页
if (window.top && window.top !== window.self) {
const target = `${window.location.origin}/profile/certification${window.location.search || ''}`
window.top.location.href = target
return
}
window.addEventListener('message', handleIframeMessage)
getCertificationDetails()
getCertificationDetails().then(async () => {
if (route.query?.signCallback) {
try {
await certificationApi.confirmSign()
await getCertificationDetails()
} catch (e) {
console.warn('签署回调确认失败,将轮询状态', e)
pollCertificationDetails(8)
}
}
})
const q = route.query || {}
if (q.authResult || q.openCorpId || q.clientCorpId) {
pollCertificationDetails(8)
}
})
onBeforeUnmount(() => {
window.removeEventListener('message', handleIframeMessage)
stopSignStatusPolling()
})
</script>