| | |
| | | <template> |
| | | <div> |
| | | <div class="page-head"> |
| | | <div class="page-title">运维日志</div> |
| | | <div class="page-subtitle">展示管理后台写操作记录</div> |
| | | </div> |
| | | |
| | | <el-table :data="rows" v-loading="loading" stripe> |
| | | <el-table-column prop="id" label="任务ID" width="100" /> |
| | | <el-table-column prop="nodeCode" label="节点" width="200" /> |
| | | <el-table-column prop="taskStatus" label="状态" width="120" /> |
| | | <el-table-column label="操作" width="200"> |
| | | <el-table-column prop="opTime" label="操作时间" min-width="180" /> |
| | | <el-table-column prop="operatorName" label="操作人" min-width="120" /> |
| | | <el-table-column prop="module" label="模块" min-width="120" /> |
| | | <el-table-column prop="action" label="动作" min-width="140" /> |
| | | <el-table-column prop="resourceType" label="资源类型" min-width="140" show-overflow-tooltip /> |
| | | <el-table-column prop="resourceId" label="资源标识" min-width="220" show-overflow-tooltip /> |
| | | <el-table-column prop="traceId" label="TraceId" min-width="220" show-overflow-tooltip /> |
| | | <el-table-column label="详情" min-width="280"> |
| | | <template #default="{ row }"> |
| | | <div class="table-ops"> |
| | | <el-button v-permission="'approvals:action'" size="small" type="success" link @click="act(row, true)">同意</el-button> |
| | | <el-button v-permission="'approvals:action'" size="small" type="danger" link @click="act(row, false)">拒绝</el-button> |
| | | </div> |
| | | <span class="detail-text">{{ row.detailJson || "—" }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div class="pager"> |
| | | <el-pagination |
| | | background |
| | | layout="total, prev, pager, next" |
| | | :current-page="page" |
| | | :page-size="size" |
| | | :total="total" |
| | | @current-change="handlePageChange" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { onMounted, ref } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import { ElMessage } from "element-plus"; |
| | | import http from "../api/http"; |
| | | |
| | | type OpLogRow = { |
| | | id: number; |
| | | opTime?: string; |
| | | operatorName?: string; |
| | | module?: string; |
| | | action?: string; |
| | | resourceType?: string; |
| | | resourceId?: string; |
| | | traceId?: string; |
| | | detailJson?: string; |
| | | }; |
| | | |
| | | const loading = ref(false); |
| | | const rows = ref<Record<string, unknown>[]>([]); |
| | | const rows = ref<OpLogRow[]>([]); |
| | | const page = ref(1); |
| | | const size = ref(10); |
| | | const total = ref(0); |
| | | |
| | | async function load() { |
| | | loading.value = true; |
| | | try { |
| | | const { data } = await http.get("/approvals/todo", { params: { page: 1, size: 50 } }); |
| | | const { data } = await http.get("/op-logs", { |
| | | params: { |
| | | page: page.value, |
| | | size: size.value, |
| | | sourceType: "ADMIN", |
| | | }, |
| | | }); |
| | | rows.value = data.result || []; |
| | | total.value = data.total || 0; |
| | | } catch (e: unknown) { |
| | | ElMessage.error(e instanceof Error ? e.message : "加载失败"); |
| | | } finally { |
| | |
| | | } |
| | | } |
| | | |
| | | async function act(row: Record<string, unknown>, approve: boolean) { |
| | | let comment = ""; |
| | | if (!approve) { |
| | | const { value } = await ElMessageBox.prompt("拒绝原因", "审批", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | }); |
| | | comment = value || ""; |
| | | } |
| | | try { |
| | | await http.post("/approvals/action", { |
| | | taskId: row.id, |
| | | taskUuid: row.uuid, |
| | | approve, |
| | | comment, |
| | | }); |
| | | ElMessage.success("已处理"); |
| | | load(); |
| | | } catch (e: unknown) { |
| | | ElMessage.error(e instanceof Error ? e.message : "操作失败"); |
| | | } |
| | | function handlePageChange(nextPage: number) { |
| | | page.value = nextPage; |
| | | load(); |
| | | } |
| | | |
| | | onMounted(load); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .page-head { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .page-title { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #1f2937; |
| | | } |
| | | |
| | | .page-subtitle { |
| | | margin-top: 4px; |
| | | font-size: 13px; |
| | | color: #6b7280; |
| | | } |
| | | |
| | | .pager { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 16px; |
| | | } |
| | | |
| | | .detail-text { |
| | | display: inline-block; |
| | | max-width: 100%; |
| | | color: #4b5563; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | </style> |