修复前端:按真实门禁状态展示下发与注销结果

This commit is contained in:
wangzhibiao committed 2026-09-21 14:57:46 +08:00
1 parent 1c46efbcad
commit a12b2e3543
2 files changed
+126 -22

No files matched your search

+8
View File
@@ -82,3 +82,11 @@ export function revokeAuth(authId) {
method: 'post'
})
}
// 获取门禁系统能力配置状态(只读脱敏)
export function getCapabilities() {
return request({
url: '/train/access/capabilities',
method: 'get'
})
}
+118 -22
View File
@@ -1,6 +1,15 @@
<template>
<div class="app-container">
<el-alert
v-if="!dmsCapabilities.dmsEnabled"
title="系统提示:门禁系统当前处于未启用(DMS Disabled)状态,门禁凭据在线下发已暂停。根据安全策略,系统不会发起外部门禁操作。"
type="warning"
:closable="false"
show-icon
style="margin-bottom: 16px;"
/>
<el-alert
v-else
title="门禁授权管理规范:门禁授权受学员报到确认、住宿安排及排课计划自动驱动。根据当前安全策略,在线密码凭证待业务侧安全交付方案确认(密文脱敏),系统不持久化亦不展示任何密码明文、Token或密钥。"
type="info"
:closable="false"
@@ -41,6 +50,7 @@
<el-option label="待注销 (PENDING_REVOKE)" value="PENDING_REVOKE" />
<el-option label="注销中 (REVOKING)" value="REVOKING" />
<el-option label="已注销 (REVOKED)" value="REVOKED" />
<el-option label="外部结果不确定 (AMBIGUOUS)" value="AMBIGUOUS" />
<el-option label="异常 (ERROR)" value="ERROR" />
</el-select>
</el-form-item>
@@ -78,14 +88,15 @@
<span>{{ scope.row.dormBuilding || '' }} {{ scope.row.dormRoom || '' }} ({{ scope.row.bedNo || '-' }}床)</span>
</template>
</el-table-column>
<el-table-column label="业务授权状态" align="center" width="140">
<el-table-column label="业务授权状态" align="center" width="150">
<template slot-scope="scope">
<el-tag v-if="scope.row.authStatus === 'ACTIVE'" type="success" effect="dark" size="small">生效中 (ACTIVE)</el-tag>
<el-tag v-else-if="scope.row.authStatus === 'PENDING_GRANT'" type="info" size="small">待授权 (PENDING_GRANT)</el-tag>
<el-tag v-else-if="scope.row.authStatus === 'GRANTING'" type="warning" size="small">授权中 (GRANTING)</el-tag>
<el-tag v-else-if="scope.row.authStatus === 'PENDING_REVOKE'" type="warning" size="small">待注销 (PENDING_REVOKE)</el-tag>
<el-tag v-else-if="scope.row.authStatus === 'PENDING_REVOKE'" type="warning" size="small">等待DMS/待注销</el-tag>
<el-tag v-else-if="scope.row.authStatus === 'REVOKING'" type="warning" size="small">注销中 (REVOKING)</el-tag>
<el-tag v-else-if="scope.row.authStatus === 'REVOKED'" type="info" size="small">已注销 (REVOKED)</el-tag>
<el-tag v-else-if="scope.row.authStatus === 'AMBIGUOUS'" type="danger" effect="dark" size="small">外部不确定 (AMBIGUOUS)</el-tag>
<el-tag v-else-if="scope.row.authStatus === 'ERROR'" type="danger" size="small">异常 (ERROR)</el-tag>
<el-tag v-else size="small">{{ scope.row.authStatus || 'UNKNOWN' }}</el-tag>
</template>
@@ -114,7 +125,7 @@
</el-table-column>
<el-table-column label="重试次数" align="center" prop="retryCount" width="80" />
<el-table-column label="异常说明" align="center" prop="lastError" :show-overflow-tooltip="true" min-width="120" />
<el-table-column label="管理操作" align="center" width="280" class-name="small-padding fixed-width">
<el-table-column label="管理操作" align="center" width="300" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
v-hasPermi="['train:access:query']"
@@ -130,11 +141,39 @@
icon="el-icon-refresh"
@click="handleManualReconcile(scope.row)"
>手动对账</el-button>
<span v-if="scope.row.authStatus === 'PENDING_GRANT' || scope.row.authStatus === 'ERROR'">
<el-tooltip v-if="!scope.row.studentPhone" content="缺手机号,暂无法下发门禁" placement="top">
<span style="display: inline-block; margin-left: 10px;">
<!-- AMBIGUOUS 危险阻断状态:禁止直接重发,要求人工对账 -->
<span v-if="scope.row.authStatus === 'AMBIGUOUS'">
<el-tooltip content="外部执行结果不确定,禁止直接下发,请先人工核对厂商凭据" placement="top">
<span style="display: inline-block; margin-left: 8px;">
<el-button
v-hasPermi="['train:access:manage']"
size="mini"
type="text"
icon="el-icon-warning"
style="color: #F56C6C;"
disabled
>不确定需核对</el-button>
</span>
</el-tooltip>
</span>
<!-- 待授权/异常重发状态 -->
<span v-else-if="scope.row.authStatus === 'PENDING_GRANT' || scope.row.authStatus === 'ERROR'">
<el-tooltip v-if="!dmsCapabilities.dmsEnabled" content="DMS未启用,当前无法下发门禁凭据" placement="top">
<span style="display: inline-block; margin-left: 8px;">
<el-button
v-hasPermi="['train:access:credential']"
size="mini"
type="text"
icon="el-icon-key"
disabled
>下发门禁凭据</el-button>
</span>
</el-tooltip>
<el-tooltip v-else-if="!scope.row.studentPhone" content="缺手机号,暂无法下发门禁" placement="top">
<span style="display: inline-block; margin-left: 8px;">
<el-button
v-hasPermi="['train:access:credential']"
size="mini"
type="text"
icon="el-icon-key"
@@ -144,21 +183,23 @@
</el-tooltip>
<el-button
v-else
v-hasPermi="['train:access:manage']"
v-hasPermi="['train:access:credential']"
size="mini"
type="text"
icon="el-icon-key"
style="color: #409EFF;"
style="color: #409EFF; margin-left: 8px;"
@click="handleIssue(scope.row)"
>下发门禁凭据</el-button>
</span>
<!-- 注销操作 -->
<el-button
v-if="scope.row.authStatus === 'ACTIVE' || scope.row.authStatus === 'GRANTING' || scope.row.authStatus === 'PENDING_REVOKE'"
v-hasPermi="['train:access:manage']"
v-hasPermi="['train:access:credential']"
size="mini"
type="text"
icon="el-icon-circle-close"
style="color: #E6A23C;"
style="color: #E6A23C; margin-left: 8px;"
@click="handleRevoke(scope.row)"
>注销授权</el-button>
</template>
@@ -186,16 +227,17 @@
<el-table-column label="流水ID" prop="operationId" width="80" align="center" />
<el-table-column label="操作类型" prop="operationType" width="140" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.operationType === 'GRANT_PASSCODE'" type="success" size="mini">下发密码 (GRANT)</el-tag>
<el-tag v-else-if="scope.row.operationType === 'REVOKE_PASSCODE'" type="danger" size="mini">注销密码 (REVOKE)</el-tag>
<el-tag v-if="scope.row.operationType === 'GRANT' || scope.row.operationType === 'GRANT_PASSCODE'" type="success" size="mini">下发密码 (GRANT)</el-tag>
<el-tag v-else-if="scope.row.operationType === 'REVOKE' || scope.row.operationType === 'REVOKE_PASSCODE'" type="danger" size="mini">注销密码 (REVOKE)</el-tag>
<el-tag v-else size="mini">{{ scope.row.operationType }}</el-tag>
</template>
</el-table-column>
<el-table-column label="执行状态" prop="operationStatus" width="100" align="center">
<el-table-column label="执行状态" prop="operationStatus" width="110" align="center">
<template slot-scope="scope">
<el-tag v-if="scope.row.operationStatus === 'SUCCESS'" type="success" size="mini">成功</el-tag>
<el-tag v-else-if="scope.row.operationStatus === 'FAILED'" type="danger" size="mini">失败</el-tag>
<el-tag v-else-if="scope.row.operationStatus === 'RUNNING'" type="warning" size="mini">运行中</el-tag>
<el-tag v-else-if="scope.row.operationStatus === 'DISPATCHING'" type="warning" size="mini">派发中</el-tag>
<el-tag v-else-if="scope.row.operationStatus === 'AMBIGUOUS'" type="danger" effect="dark" size="mini">不确定</el-tag>
<el-tag v-else size="mini">{{ scope.row.operationStatus }}</el-tag>
</template>
</el-table-column>
@@ -258,7 +300,7 @@
</template>
<script>
import { listAuth, getOperationHistory, manualReconcile, issueAuth, revokeAuth } from '@/api/train/access'
import { listAuth, getOperationHistory, manualReconcile, issueAuth, revokeAuth, getCapabilities } from '@/api/train/access'
export default {
name: 'Auth',
@@ -281,13 +323,26 @@ export default {
operationList: [],
oneTimeDialogOpen: false,
oneTimeCredential: null,
maskedMode: true
maskedMode: true,
dmsCapabilities: {
dmsEnabled: true,
manualIssueAvailable: true,
manualRevokeAvailable: true
}
}
},
created() {
this.fetchCapabilities()
this.getList()
},
methods: {
fetchCapabilities() {
getCapabilities().then(res => {
if (res.data) {
this.dmsCapabilities = res.data
}
}).catch(() => {})
},
getList() {
this.loading = true
listAuth(this.queryParams).then(response => {
@@ -348,14 +403,38 @@ export default {
this.$modal.confirm(`确认向学员【${row.studentName || row.studentId}】下发门禁凭据?`).then(() => {
return issueAuth(row.authId)
}).then(res => {
this.$modal.msgSuccess(res.msg || '凭据已提交下发,设备确认后生效。')
const data = res.data || {}
const decision = data.decision || data.status || ''
const msg = res.msg || data.message || ''
if (decision === 'DISPATCHED' || data.status === 'ACTIVE' || data.status === 'GRANTING') {
this.$modal.msgSuccess(msg || '凭据已提交下发,设备确认后生效')
} else if (decision === 'WAITING_FOR_DMS' || msg.includes('DMS当前未启用')) {
this.$modal.msgWarning(msg || 'DMS当前未启用,未执行门禁下发')
} else if (decision === 'MISSING_STUDENT_PHONE') {
this.$modal.msgWarning(msg || '缺少学员手机号,未下发门禁')
} else if (decision === 'INVALID_VALIDITY_WINDOW') {
this.$modal.msgWarning(msg || '授权起止时间无效,未下发门禁')
} else if (decision === 'AMBIGUOUS_EXTERNAL_MUTATION' || decision === 'AMBIGUOUS') {
this.$modal.msgError(msg || '上一次下发结果无法确认,禁止重复下发,请先核对厂商侧凭据')
} else if (decision === 'FAILED' || !res.data) {
this.$modal.msgError(msg || '凭据下发失败')
} else {
this.$modal.msgInfo(msg || '凭据处理完成')
}
this.getList()
if (res.data && res.data.oneTimePlaintextCredential) {
this.oneTimeCredential = res.data.oneTimePlaintextCredential
if (data.oneTimePlaintextCredential) {
this.oneTimeCredential = data.oneTimePlaintextCredential
this.maskedMode = false
this.oneTimeDialogOpen = true
}
}).catch(() => {})
}).catch(err => {
const errMsg = err && (err.message || err.msg) ? (err.message || err.msg) : ''
if (errMsg.includes('无法确认') || errMsg.includes('AMBIGUOUS')) {
this.$modal.msgError('上一次下发结果无法确认,禁止重复下发,请先核对厂商侧凭据')
}
})
},
handleRevoke(row) {
const studentDesc = row.studentName ? `${row.studentName} (${row.studentId || row.enrollmentId})` : (row.studentId || `报名ID:${row.enrollmentId}`)
@@ -363,7 +442,24 @@ export default {
this.$modal.confirm(`确定要注销学员【${studentDesc}】在宿舍【${dormDesc}】的门禁授权(授权ID: ${row.authId})吗?注销后该学员将无法通行该门禁。`).then(() => {
return revokeAuth(row.authId)
}).then(res => {
this.$modal.msgSuccess(res.msg || '注销操作已提交')
const data = res.data || {}
const status = data.authStatus || data.status || ''
const decision = data.decision || ''
const msg = res.msg || data.message || ''
if (status === 'REVOKED') {
this.$modal.msgSuccess(msg || '门禁注销成功')
} else if (status === 'PENDING_REVOKE' || decision === 'WAITING_FOR_DMS') {
this.$modal.msgWarning(msg || '已建立注销队列,等待DMS处理')
} else if (status === 'REVOKING' || decision === 'DISPATCHED') {
this.$modal.msgInfo(msg || '注销指令已提交,设备确认后生效')
} else if (status === 'AMBIGUOUS') {
this.$modal.msgError(msg || '外部注销结果不确定,请人工核对')
} else if (status === 'ERROR') {
this.$modal.msgError(msg || '注销操作失败')
} else {
this.$modal.msgInfo(msg || '注销请求已提交')
}
this.getList()
}).catch(() => {})
}