|
|
@@ -0,0 +1,389 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import {
|
|
|
+ type PlusColumn,
|
|
|
+ type OptionsRow,
|
|
|
+ PlusPage,
|
|
|
+ PlusDialog,
|
|
|
+ PlusDescriptions,
|
|
|
+ PlusPageInstance,
|
|
|
+ useTable
|
|
|
+} from "plus-pro-components";
|
|
|
+import { computed, reactive, ref, toRefs } from "vue";
|
|
|
+import {
|
|
|
+ cleanSystemOperlog,
|
|
|
+ deleteSystemOperlog,
|
|
|
+ getSystemOperlogList
|
|
|
+} from "@/api/system/operlog";
|
|
|
+import { useDict, useDictValue } from "@/utils/dict";
|
|
|
+import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
+
|
|
|
+defineOptions({
|
|
|
+ name: "Operlog"
|
|
|
+});
|
|
|
+
|
|
|
+const { sys_common_status, sys_oper_type } = useDict(
|
|
|
+ "sys_common_status",
|
|
|
+ "sys_oper_type"
|
|
|
+);
|
|
|
+
|
|
|
+const plusPageInstance = ref<PlusPageInstance | null>(null);
|
|
|
+
|
|
|
+const getList = async (query: Record<string, any>) => {
|
|
|
+ let res = await getSystemOperlogList(query);
|
|
|
+ return {
|
|
|
+ data: res.rows,
|
|
|
+ total: res.total
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+// 重新请求列表接口
|
|
|
+const refresh = () => {
|
|
|
+ plusPageInstance.value?.getList();
|
|
|
+};
|
|
|
+
|
|
|
+const tableConfig: PlusColumn[] = [
|
|
|
+ {
|
|
|
+ label: "日志编号",
|
|
|
+ prop: "operId",
|
|
|
+ valueType: "input",
|
|
|
+ hideInSearch: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "系统模块",
|
|
|
+ prop: "title",
|
|
|
+ valueType: "input"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作类型",
|
|
|
+ prop: "businessType",
|
|
|
+ valueType: "tag",
|
|
|
+ options: computed(() => sys_oper_type.value),
|
|
|
+ fieldProps: value => {
|
|
|
+ return {
|
|
|
+ type: sys_oper_type.value.find(item => item.value === value + "")?.class
|
|
|
+ };
|
|
|
+ },
|
|
|
+ formatter: (value, { column }) => {
|
|
|
+ return (column.options as OptionsRow[])?.find(
|
|
|
+ item => item.value === value + ""
|
|
|
+ )?.label;
|
|
|
+ },
|
|
|
+ hideInSearch: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作类型",
|
|
|
+ prop: "bussinessType",
|
|
|
+ valueType: "select",
|
|
|
+ options: computed(() => sys_oper_type.value),
|
|
|
+ hideInTable: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "请求方式",
|
|
|
+ prop: "requestMethod",
|
|
|
+ valueType: "input"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作人员",
|
|
|
+ prop: "operName",
|
|
|
+ valueType: "input"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作地址",
|
|
|
+ prop: "operIp",
|
|
|
+ valueType: "input",
|
|
|
+ hideInSearch: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作状态",
|
|
|
+ prop: "status",
|
|
|
+ valueType: "tag",
|
|
|
+ options: computed(() => sys_common_status.value),
|
|
|
+ fieldProps: value => {
|
|
|
+ return {
|
|
|
+ type: sys_common_status.value.find(item => item.value === value + "")
|
|
|
+ ?.class
|
|
|
+ };
|
|
|
+ },
|
|
|
+ formatter: (value, { column }) => {
|
|
|
+ return (column.options as OptionsRow[])?.find(
|
|
|
+ item => item.value === value + ""
|
|
|
+ )?.label;
|
|
|
+ },
|
|
|
+ hideInSearch: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作状态",
|
|
|
+ prop: "status",
|
|
|
+ valueType: "select",
|
|
|
+ options: computed(() => sys_common_status.value),
|
|
|
+ hideInTable: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作时间",
|
|
|
+ prop: "operTime",
|
|
|
+ valueType: "date-picker",
|
|
|
+ fieldProps: {
|
|
|
+ type: "datetime",
|
|
|
+ rangeSeparator: "至",
|
|
|
+ startPlaceholder: "开始时间",
|
|
|
+ endPlaceholder: "结束时间",
|
|
|
+ valueFormat: "YYYY-MM-DD HH:mm:ss"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "消耗时间",
|
|
|
+ prop: "costTime",
|
|
|
+ valueType: "input",
|
|
|
+ hideInSearch: true,
|
|
|
+ formatter: value => value + "毫秒"
|
|
|
+ }
|
|
|
+];
|
|
|
+
|
|
|
+const { buttons } = useTable();
|
|
|
+
|
|
|
+buttons.value = [
|
|
|
+ {
|
|
|
+ // 修改
|
|
|
+ text: "详细",
|
|
|
+ code: "edit",
|
|
|
+ // props v0.1.16 版本新增函数类型
|
|
|
+ props: {
|
|
|
+ type: "primary"
|
|
|
+ },
|
|
|
+ onClick(params) {
|
|
|
+ form.value = params.row;
|
|
|
+ state.isCreate = false;
|
|
|
+ state.dialogVisible = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+];
|
|
|
+
|
|
|
+const multipleSelection = ref([]);
|
|
|
+
|
|
|
+const handleSelectionChange = (val: string[]) => {
|
|
|
+ multipleSelection.value = val;
|
|
|
+};
|
|
|
+
|
|
|
+const handleDelete = () => {
|
|
|
+ // 删除前确认
|
|
|
+ ElMessageBox.confirm("是否确认删除选中数据?", "删除确认", {
|
|
|
+ confirmButtonText: "确认",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning",
|
|
|
+ draggable: true
|
|
|
+ })
|
|
|
+ .then(async () => {
|
|
|
+ try {
|
|
|
+ let operIds = multipleSelection.value.map(
|
|
|
+ item => item.operId
|
|
|
+ ) as string[];
|
|
|
+ let res = await deleteSystemOperlog(operIds.join(","));
|
|
|
+ if (res.code === 200) {
|
|
|
+ ElMessage.success("删除成功");
|
|
|
+ refresh();
|
|
|
+ multipleSelection.value = [];
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.msg);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ ElMessage.error("删除失败");
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ // 取消删除
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleClear = () => {
|
|
|
+ // 清空前确认
|
|
|
+ ElMessageBox.confirm("是否确认清空所有操作日志?", "清空确认", {
|
|
|
+ confirmButtonText: "确认",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning",
|
|
|
+ draggable: true
|
|
|
+ })
|
|
|
+ .then(async () => {
|
|
|
+ try {
|
|
|
+ let res = await cleanSystemOperlog();
|
|
|
+ if (res.code === 200) {
|
|
|
+ ElMessage.success("清空成功");
|
|
|
+ refresh();
|
|
|
+ multipleSelection.value = [];
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.msg);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ ElMessage.error("清空失败");
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ // 取消清空
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+interface State {
|
|
|
+ dialogVisible: boolean;
|
|
|
+ detailsVisible: boolean;
|
|
|
+ confirmLoading: boolean;
|
|
|
+ selectedIds: number[];
|
|
|
+ isCreate: boolean;
|
|
|
+ form: Record<string, any>;
|
|
|
+ rules: Record<string, any>;
|
|
|
+}
|
|
|
+
|
|
|
+const state = reactive<State>({
|
|
|
+ dialogVisible: false,
|
|
|
+ detailsVisible: false,
|
|
|
+ confirmLoading: false,
|
|
|
+ selectedIds: [],
|
|
|
+ isCreate: true,
|
|
|
+ form: {},
|
|
|
+ rules: {
|
|
|
+ sysName: [{ required: true, message: "请输入系统名称", trigger: "blur" }],
|
|
|
+ sysCode: [{ required: true, message: "请输入系统编码", trigger: "blur" }]
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const columns: PlusColumn[] = [
|
|
|
+ {
|
|
|
+ label: "操作模块",
|
|
|
+ prop: "sysName",
|
|
|
+ formatter: () => {
|
|
|
+ return `${form.value.title}/${useDictValue("sys_oper_type", form.value.businessType)}`;
|
|
|
+ },
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 12
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "请求地址",
|
|
|
+ prop: "operUrl",
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 12
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "登录信息",
|
|
|
+ prop: "operIp",
|
|
|
+ formatter: () => {
|
|
|
+ return `${form.value.operName}/${form.value.operIp}`;
|
|
|
+ },
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 12
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "请求方式",
|
|
|
+ prop: "requestMethod",
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 12
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作方法",
|
|
|
+ prop: "method",
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 24
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作参数",
|
|
|
+ prop: "operParam",
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 24,
|
|
|
+ className: "break-all"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "返回参数",
|
|
|
+ prop: "jsonResult",
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 24
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作状态",
|
|
|
+ prop: "status",
|
|
|
+ formatter: () => {
|
|
|
+ return useDictValue("sys_common_status", form.value.status);
|
|
|
+ },
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 8
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "消耗时间",
|
|
|
+ prop: "costTime",
|
|
|
+ formatter: () => {
|
|
|
+ return `${form.value.costTime}毫秒`;
|
|
|
+ },
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 8
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: "操作时间",
|
|
|
+ prop: "operTime",
|
|
|
+ descriptionsItemProps: {
|
|
|
+ span: 8
|
|
|
+ }
|
|
|
+ }
|
|
|
+];
|
|
|
+
|
|
|
+const { form, dialogVisible } = toRefs(state);
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <PlusPage
|
|
|
+ ref="plusPageInstance"
|
|
|
+ :columns="tableConfig"
|
|
|
+ :request="getList"
|
|
|
+ :pageInfoMap="{ page: 'pageNum', pageSize: 'pageSize' }"
|
|
|
+ :table="{
|
|
|
+ actionBar: { buttons, type: 'link', width: 140 },
|
|
|
+ adaptive: { offsetBottom: 50 },
|
|
|
+ isSelection: true,
|
|
|
+ onSelectionChange: handleSelectionChange,
|
|
|
+ rowKey: 'operId'
|
|
|
+ }"
|
|
|
+ :search="{
|
|
|
+ showNumber: 3
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <template #table-title>
|
|
|
+ <el-row class="button-row">
|
|
|
+ <el-button
|
|
|
+ size="default"
|
|
|
+ :disabled="multipleSelection.length === 0"
|
|
|
+ type="danger"
|
|
|
+ @click="handleDelete"
|
|
|
+ >
|
|
|
+ 删除
|
|
|
+ </el-button>
|
|
|
+ <el-button size="default" type="danger" @click="handleClear">
|
|
|
+ 清空日志
|
|
|
+ </el-button>
|
|
|
+ </el-row>
|
|
|
+ </template>
|
|
|
+ </PlusPage>
|
|
|
+ <!-- 弹窗编辑 -->
|
|
|
+ <PlusDialog
|
|
|
+ v-model="dialogVisible"
|
|
|
+ :title="'操作日志详细'"
|
|
|
+ width="800"
|
|
|
+ :has-footer="false"
|
|
|
+ >
|
|
|
+ <PlusDescriptions
|
|
|
+ size="large"
|
|
|
+ :column="24"
|
|
|
+ :columns="columns"
|
|
|
+ :data="form"
|
|
|
+ :border="true"
|
|
|
+ label-width="90px"
|
|
|
+ />
|
|
|
+ </PlusDialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped lang="scss"></style>
|