修复前端:按真实门禁状态展示下发与注销结果
This commit is contained in:
1 parent
1c46efbcad
commit
a12b2e3543
2 files changed
+126
-22
No files matched your search
@@ -82,3 +82,11 @@ export function revokeAuth(authId) {
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取门禁系统能力配置状态(只读脱敏)
|
||||
export function getCapabilities() {
|
||||
return request({
|
||||
url: '/train/access/capabilities',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
@@ -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(() => {})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user