263 lines
12 KiB
Vue
263 lines
12 KiB
Vue
<template>
|
|
<div class="app-container">
|
|
<el-alert
|
|
title="门禁授权管理规范:门禁授权受学员报到确认、住宿安排及排课计划自动驱动。根据当前安全策略,在线密码凭证待业务侧安全交付方案确认(密文脱敏),系统不持久化亦不展示任何密码明文、Token或密钥。"
|
|
type="info"
|
|
:closable="false"
|
|
show-icon
|
|
style="margin-bottom: 16px;"
|
|
/>
|
|
|
|
<el-form v-show="showSearch" ref="queryForm" :model="queryParams" size="small" :inline="true" label-width="80px">
|
|
<el-form-item label="学员学号" prop="studentId">
|
|
<el-input
|
|
v-model="queryParams.studentId"
|
|
placeholder="请输入学员学号"
|
|
clearable
|
|
@keyup.enter.native="handleQuery"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="宿舍楼栋" prop="dormBuilding">
|
|
<el-input
|
|
v-model="queryParams.dormBuilding"
|
|
placeholder="请输入楼栋"
|
|
clearable
|
|
@keyup.enter.native="handleQuery"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="房间号" prop="dormRoom">
|
|
<el-input
|
|
v-model="queryParams.dormRoom"
|
|
placeholder="请输入房间号"
|
|
clearable
|
|
@keyup.enter.native="handleQuery"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item label="授权状态" prop="authStatus">
|
|
<el-select v-model="queryParams.authStatus" placeholder="全部状态" clearable>
|
|
<el-option label="待授权 (PENDING_GRANT)" value="PENDING_GRANT" />
|
|
<el-option label="授权中 (GRANTING)" value="GRANTING" />
|
|
<el-option label="生效中 (ACTIVE)" value="ACTIVE" />
|
|
<el-option label="待注销 (PENDING_REVOKE)" value="PENDING_REVOKE" />
|
|
<el-option label="注销中 (REVOKING)" value="REVOKING" />
|
|
<el-option label="已注销 (REVOKED)" value="REVOKED" />
|
|
<el-option label="异常 (ERROR)" value="ERROR" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<el-row :gutter="10" class="mb8">
|
|
<right-toolbar :show-search.sync="showSearch" @queryTable="getList" />
|
|
</el-row>
|
|
|
|
<el-table v-loading="loading" :data="authList">
|
|
<el-table-column label="授权ID" align="center" prop="authId" width="80" />
|
|
<el-table-column label="报名ID" align="center" prop="enrollmentId" width="90">
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.enrollmentId || '-' }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="学员姓名" align="center" width="110">
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.studentName || scope.row.studentId || '-' }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="学员学号" align="center" prop="studentId" width="120" />
|
|
<el-table-column label="宿舍安排" align="center" min-width="130">
|
|
<template slot-scope="scope">
|
|
<span>{{ scope.row.dormBuilding || '' }} {{ scope.row.dormRoom || '' }} ({{ scope.row.bedNo || '-' }}床)</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="业务授权状态" align="center" width="140">
|
|
<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 === '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 === 'ERROR'" type="danger" size="small">异常 (ERROR)</el-tag>
|
|
<el-tag v-else size="small">{{ scope.row.authStatus || 'UNKNOWN' }}</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="凭据类型" align="center" width="130">
|
|
<template slot-scope="scope">
|
|
<el-tag size="mini" type="info">{{ scope.row.credentialType || 'ONLINE_PASSWORD' }}</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="安全凭据状态" align="center" min-width="160">
|
|
<template slot-scope="{ row }">
|
|
<el-tag size="mini" type="warning">{{ row.authStatus ? '凭证待业务侧安全交付方案确认' : '待确认' }}</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="权限生效时间" align="center" min-width="150">
|
|
<template slot-scope="scope">
|
|
<span v-if="scope.row.authStart">{{ parseTime(scope.row.authStart, '{y}-{m}-{d} {h}:{i}') }}</span>
|
|
<el-tag v-else size="mini" type="info">WAITING_FOR_PREREQUISITE</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="权限失效时间" align="center" min-width="150">
|
|
<template slot-scope="scope">
|
|
<span v-if="scope.row.authEnd">{{ parseTime(scope.row.authEnd, '{y}-{m}-{d} {h}:{i}') }}</span>
|
|
<el-tag v-else size="mini" type="info">WAITING_FOR_PREREQUISITE</el-tag>
|
|
</template>
|
|
</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="160" class-name="small-padding fixed-width">
|
|
<template slot-scope="scope">
|
|
<el-button
|
|
v-hasPermi="['train:access:query']"
|
|
size="mini"
|
|
type="text"
|
|
icon="el-icon-document"
|
|
@click="handleOperationHistory(scope.row)"
|
|
>操作流水</el-button>
|
|
<el-button
|
|
v-hasPermi="['train:access:reconcile']"
|
|
size="mini"
|
|
type="text"
|
|
icon="el-icon-refresh"
|
|
@click="handleManualReconcile(scope.row)"
|
|
>手动对账</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
|
|
<pagination
|
|
v-show="total>0"
|
|
:total="total"
|
|
:page.sync="queryParams.pageNum"
|
|
:limit.sync="queryParams.pageSize"
|
|
@pagination="getList"
|
|
/>
|
|
|
|
<!-- 外部操作流水历史对话框 -->
|
|
<el-dialog title="外部设备操作流水 (External Operation History)" :visible.sync="operationOpen" width="850px" append-to-body>
|
|
<el-alert
|
|
title="安全提示:操作流水记录了系统向外部门禁/门锁发起的调度记录,已执行全链路敏感信息脱敏(无明文密码、无AppSecret、无Token)。"
|
|
type="info"
|
|
:closable="false"
|
|
show-icon
|
|
style="margin-bottom: 15px;"
|
|
/>
|
|
<el-table v-loading="operationLoading" :data="operationList" size="small" border empty-text="当前暂无外部操作流水记录">
|
|
<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-else size="mini">{{ scope.row.operationType }}</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="执行状态" prop="operationStatus" width="100" 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 size="mini">{{ scope.row.operationStatus }}</el-tag>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="尝试次数" prop="attemptCount" width="80" align="center" />
|
|
<el-table-column label="请求时间" align="center" width="150">
|
|
<template slot-scope="scope">
|
|
<span>{{ parseTime(scope.row.requestedAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="完成时间" align="center" width="150">
|
|
<template slot-scope="scope">
|
|
<span>{{ parseTime(scope.row.completedAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column label="外部流水引用" prop="externalOperationRef" align="center" min-width="120" :show-overflow-tooltip="true" />
|
|
<el-table-column label="错误说明" prop="sanitizedErrorMessage" align="center" min-width="120" :show-overflow-tooltip="true">
|
|
<template slot-scope="scope">
|
|
<span style="color: #F56C6C;">{{ scope.row.sanitizedErrorMessage || '-' }}</span>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="operationOpen = false">关 闭</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { listAuth, getOperationHistory, manualReconcile } from '@/api/train/access'
|
|
|
|
export default {
|
|
name: 'Auth',
|
|
data() {
|
|
return {
|
|
loading: true,
|
|
showSearch: true,
|
|
total: 0,
|
|
authList: [],
|
|
queryParams: {
|
|
pageNum: 1,
|
|
pageSize: 10,
|
|
studentId: null,
|
|
dormBuilding: null,
|
|
dormRoom: null,
|
|
authStatus: null
|
|
},
|
|
operationOpen: false,
|
|
operationLoading: false,
|
|
operationList: []
|
|
}
|
|
},
|
|
created() {
|
|
this.getList()
|
|
},
|
|
methods: {
|
|
getList() {
|
|
this.loading = true
|
|
listAuth(this.queryParams).then(response => {
|
|
this.authList = response.rows || []
|
|
this.total = response.total || 0
|
|
this.loading = false
|
|
}).catch(() => {
|
|
this.loading = false
|
|
})
|
|
},
|
|
handleQuery() {
|
|
this.queryParams.pageNum = 1
|
|
this.getList()
|
|
},
|
|
resetQuery() {
|
|
this.resetForm('queryForm')
|
|
this.handleQuery()
|
|
},
|
|
handleOperationHistory(row) {
|
|
this.operationOpen = true
|
|
this.operationLoading = true
|
|
getOperationHistory(row.authId).then(res => {
|
|
this.operationList = res.data || []
|
|
this.operationLoading = false
|
|
}).catch(() => {
|
|
this.operationLoading = false
|
|
})
|
|
},
|
|
handleManualReconcile(row) {
|
|
if (!row.enrollmentId) {
|
|
this.$modal.msgError('当前授权记录未关联报名信息,无法执行对账')
|
|
return
|
|
}
|
|
this.$modal.confirm(
|
|
'确认对报名编号 [' + row.enrollmentId + '] 执行门禁对账?系统将严格遵循业务前置校验规则。'
|
|
).then(() => {
|
|
return manualReconcile(row.enrollmentId)
|
|
}).then(res => {
|
|
this.$modal.msgSuccess(res.msg || '对账执行成功')
|
|
this.getList()
|
|
}).catch(() => {})
|
|
}
|
|
}
|
|
}
|
|
</script>
|