WholeProcessPlatform/frontend-sjgl/src/components/OperationLogModal/index.vue
2026-08-20 16:58:14 +08:00

294 lines
6.7 KiB
Vue

<template>
<a-modal
v-model:open="visible"
title="操作日志"
width="90vw"
:footer="null"
@cancel="handleCancel"
>
<!-- 搜索区域 -->
<BasicSearch
ref="basicSearchRef"
:searchList="searchList"
:initial-values="initSearchData"
:zhujianfujian="'fu'"
@finish="onSearchFinish"
@reset="onReset"
/>
<!-- 表格 -->
<BasicTable
ref="tableRef"
:enableEllipsis="true"
:scrollX="tableScrollX"
:scrollY="500"
:columns="columns"
:list-url="getOperationLogList"
:transform-data="customTransform"
>
<template #action="{ record }">
<a-button
type="link"
class="text-[#2f6b98]"
size="small"
@click="handleDetail(record)"
>
查看详情
</a-button>
</template>
</BasicTable>
<!-- 查看详情 Modal -->
<a-modal
v-model:open="detailVisible"
title="操作日志详情"
width="800px"
:footer="null"
>
<a-spin :spinning="detailLoading">
<div style="max-height: 50vh; overflow-y: auto">
<a-descriptions bordered :column="1" size="small">
<a-descriptions-item
v-for="item in diffList"
:key="item.field"
:label="item.label"
>
<template v-if="item.operationType === '01'">
<span style="color: #52c41a">{{ item.newValue }}</span>
</template>
<template v-else-if="item.operationType === '03'">
<span style="color: #ff4d4f">{{ item.oldValue }}</span>
</template>
<template v-else>
<span style="color: #ff4d4f">{{ item.oldValue }}</span>
<span style="margin: 0 8px">→</span>
<span style="color: #52c41a">{{ item.newValue }}</span>
</template>
</a-descriptions-item>
</a-descriptions>
</div>
</a-spin>
</a-modal>
</a-modal>
</template>
<script setup lang="ts">
import { ref, computed, watch, nextTick } from "vue";
import dayjs from "dayjs";
import BasicSearch from "@/components/BasicSearch/index.vue";
import BasicTable from "@/components/BasicTable/index.vue";
import { getOperationLogList, getDetailByMainId } from "@/api/DataQueryMenuModule";
import { useDraggable } from "@/utils/drag";
defineOptions({ name: "OperationLogModal" });
const props = withDefaults(
defineProps<{
open: boolean;
tableName: string;
recordNameTitle?: string;
}>(),
{
recordNameTitle: "电站",
}
);
const emit = defineEmits(["update:open"]);
const visible = computed({
get: () => props.open,
set: (val) => emit("update:open", val),
});
useDraggable(visible, { boundary: true, resetOnOpen: true });
const basicSearchRef = ref();
const tableRef = ref();
const initSearchData = { rvcd: 'all' };
// 搜索列表配置
const searchList: any = [
{
type: "waterStation",
name: "rvcd",
label: "流域",
placeholder: "请输入流域",
fieldProps: { allowClear: true },
options: [],
},
{
type: "Input",
name: "operator",
label: "修改人",
placeholder: "请输入修改人",
fieldProps: { allowClear: true },
},
{
type: "RangePicker",
name: "operateTime",
label: "修改时间",
fieldProps: {
allowClear: true,
valueFormat: "YYYY-MM-DD",
},
},
];
// 表格列配置
const columns = computed<any[]>(() => [
{
key: "recordName",
title: props.recordNameTitle,
dataIndex: "recordName",
visible: true,
width: 120,
ellipsis: true,
},
{
key: "operator",
title: "修改人",
dataIndex: "operator",
visible: true,
width: 120,
},
{
key: "operateTime",
title: "修改时间",
dataIndex: "operateTime",
visible: true,
width: 160,
sort: true,
},
{
key: "source",
title: "来源依据",
dataIndex: "source",
visible: true,
ellipsis: true,
},
{
key: "remark",
title: "备注",
dataIndex: "remark",
visible: true,
ellipsis: true,
},
{
key: "action",
title: "操作",
dataIndex: "action",
fixed: "right",
width: 120,
},
]);
const tableScrollX = computed(() =>
Math.max(
columns.value.reduce(
(sum: number, col: any) => sum + (col.width || 180),
0
),
600
)
);
const buildSearchParams = (values: any) => {
return {
logic: "and",
filters: [
values.rstcd
? {
field: "recordId",
operator: "eq",
dataType: "string",
value: values.rstcd,
}
: null,
values.operator
? {
field: "operator",
operator: "contains",
dataType: "string",
value: values.operator,
}
: null,
values.operateTime?.[0]
? {
field: "operateTime",
operator: "gte",
dataType: "date",
value: values.operateTime[0],
}
: null,
values.operateTime?.[1]
? {
field: "operateTime",
operator: "lte",
dataType: "date",
value: values.operateTime[1],
}
: null,
{
field: "tableName",
operator: "eq",
dataType: "string",
value: props.tableName,
},
].filter(Boolean),
};
};
const onSearchFinish = (values: any) => {
const params = buildSearchParams(values);
tableRef.value.getList(params);
};
const onReset = () => {
tableRef.value?.getList(buildSearchParams({}));
};
const handleDetail = async (record: any) => {
detailVisible.value = true;
detailLoading.value = true;
try {
const res = await getDetailByMainId({ mainId: record.id });
const data = res?.data || [];
diffList.value = data.map((item: any) => ({
field: item.fieldCode,
label: item.fieldMeaning,
operationType: record.operationType,
oldValue: item.oldValueName || item.oldValueCode || '-',
newValue: item.newValueName || item.newValueCode ||'-'
}));
} finally {
detailLoading.value = false;
}
};
const detailVisible = ref(false);
const detailLoading = ref(false);
const diffList = ref<{ field: string; label: string; operationType: string; oldValue: string; newValue: string }[]>([]);
const handleCancel = () => {
visible.value = false;
};
const customTransform = (res: any) => {
return {
records: res?.data?.records || [],
total: res?.data?.total || 0
};
};
watch(
() => props.open,
(val) => {
if (val) {
nextTick(() => {
tableRef.value?.getList(buildSearchParams({}));
});
}
}
);
</script>
<style scoped lang="less"></style>