Commit d2cba459 by ningjihai

操作日志

parent 45f5ce61
......@@ -219,13 +219,6 @@ const toggleStatus = (row) => {
脱敏策略管理
</template>
<template #buttons>
<!-- <el-button
icon="Plus"
type="primary"
@click="handleAdd"
>
新增策略
</el-button> -->
</template>
</PageTitle>
......
<script setup lang="ts" name="QueryForm">
import { computed,ref,watch } from 'vue'
import type { FormInstance } from 'element-plus'
import PageWrapperSearch from '@/components/search/PageWrapperSearch.vue'
import {
Plus
} from '@element-plus/icons-vue'
import { color } from 'echarts'
// import { useDict } from '@/utils/dict'
// import { listDept } from '@/api/system/dept'// 部门
// const { approve_status, invoice_status} = useDict('approve_status', 'invoice_status')
const emit = defineEmits(['update:modelValue', 'query', 'reset','handleAdd'])
const invoice_status_filter = ref([])
const employeesList = ref([])
const props = defineProps<{
modelValue: any
}>()
const queryForm = computed({
get() {
return props.modelValue
},
set(val: any) {
console.log('query computed', val)
emit('update:modelValue', val)
}
})
// 搜索
function onSearch() {
emit('query')
}
// 重置
function onReset(formRef: FormInstance) {
queryForm.value.useridentifier = ''
queryForm.value.username = ''
queryForm.value.note = ''
emit('reset', formRef)
}
function handleAdd() {
emit('handleAdd')
}
</script>
<template>
<!-- el-form -->
<page-wrapper-search
:model="queryForm"
:extraButtons="[
{
text: '新增',
icon: Plus,
color: 'rgba(0, 189, 207, 1)',
type: 'success',
class: 'btn-fff',
onClick: handleAdd
}
]"
@search="onSearch"
@reset="onReset">
<el-form-item label="唯一标识:">
<el-input v-model="queryForm.useridentifier" clearable placeholder="请输入唯一标识"></el-input>
</el-form-item>
<el-form-item label="用户名:">
<el-input v-model="queryForm.username" clearable placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="备注:">
<el-input v-model="queryForm.note" clearable placeholder="请输入备注"></el-input>
</el-form-item>
</page-wrapper-search>
<!-- <page-wrapper-search
:model="queryForm"
:extraButtons="[
{
text: '导出',
icon: Edit,
type: 'success',
onClick: handleExport
},
{
text: '打印',
type: 'warning',
onClick: handlePrint
}
]"
@search="onSearch"
@reset="onReset">
<el-form-item label="项目名称" prop="proName">
<el-input
v-model="queryForm.proName"
placeholder="请输入项目名称"
clearable
/>
</el-form-item>
<el-form-item label="备注" prop="note">
<el-input
v-model="queryForm.note"
placeholder="请输入备注"
clearable
/>
</el-form-item>
</page-wrapper-search> -->
</template>
<style scoped lang="scss">
:deep(.btn-fff){
span{
color: #fff;
}
}
</style>
<script setup lang="ts" name="QueryForm">
import { computed,ref,watch } from 'vue'
import type { FormInstance } from 'element-plus'
import PageWrapperSearch from '@/components/search/PageWrapperSearch.vue'
import {
Plus
} from '@element-plus/icons-vue'
import { color } from 'echarts'
// import { useDict } from '@/utils/dict'
// import { listDept } from '@/api/system/dept'// 部门
// const { approve_status, invoice_status} = useDict('approve_status', 'invoice_status')
const emit = defineEmits(['update:modelValue', 'query', 'reset','handleAdd'])
const invoice_status_filter = ref([])
const employeesList = ref([])
const props = defineProps<{
modelValue: any
}>()
const queryForm = computed({
get() {
return props.modelValue
},
set(val: any) {
console.log('query computed', val)
emit('update:modelValue', val)
}
})
// 搜索
function onSearch() {
emit('query')
}
// 重置
function onReset(formRef: FormInstance) {
queryForm.value.useridentifier = ''
queryForm.value.username = ''
queryForm.value.note = ''
emit('reset', formRef)
}
function handleAdd() {
emit('handleAdd')
}
</script>
<template>
<!-- el-form -->
<page-wrapper-search
:model="queryForm"
:extraButtons="[
{
text: '新增',
icon: Plus,
color: 'rgba(0, 189, 207, 1)',
type: 'success',
class: 'btn-fff',
onClick: handleAdd
}
]"
@search="onSearch"
@reset="onReset">
<el-form-item label="唯一标识:">
<el-input v-model="queryForm.useridentifier" clearable placeholder="请输入唯一标识"></el-input>
</el-form-item>
<el-form-item label="用户名:">
<el-input v-model="queryForm.username" clearable placeholder="请输入用户名"></el-input>
</el-form-item>
<el-form-item label="备注:">
<el-input v-model="queryForm.note" clearable placeholder="请输入备注"></el-input>
</el-form-item>
</page-wrapper-search>
<!-- <page-wrapper-search
:model="queryForm"
:extraButtons="[
{
text: '导出',
icon: Edit,
type: 'success',
onClick: handleExport
},
{
text: '打印',
type: 'warning',
onClick: handlePrint
}
]"
@search="onSearch"
@reset="onReset">
<el-form-item label="项目名称" prop="proName">
<el-input
v-model="queryForm.proName"
placeholder="请输入项目名称"
clearable
/>
</el-form-item>
<el-form-item label="备注" prop="note">
<el-input
v-model="queryForm.note"
placeholder="请输入备注"
clearable
/>
</el-form-item>
</page-wrapper-search> -->
</template>
<style scoped lang="scss">
:deep(.btn-fff){
span{
color: #fff;
}
}
</style>
<script setup lang="ts" name="QueryForm">
import { computed,ref,onMounted } from 'vue'
import type { FormInstance } from 'element-plus'
import PageWrapperSearch from '@/components/search/PageWrapperSearch.vue'
import {
Download
} from '@element-plus/icons-vue'
import { color } from 'echarts'
import { query, checkEnc, queryMenuTreeAndUserlist, getOpeExcel} from '@/api/logSet/operationLog.js'
import timeRangeOptions from '@/constants/timeRangeOptions.js'
// const { approve_status, invoice_status} = useDict('approve_status', 'invoice_status')
const emit = defineEmits(['update:modelValue', 'query', 'reset','handleAdd'])
const invoice_status_filter = ref([])
const employeesList = ref([])
const props = defineProps<{
modelValue: any
}>()
const queryForm = computed({
get() {
return props.modelValue
},
set(val: any) {
console.log('query computed', val)
emit('update:modelValue', val)
}
})
// 搜索
function onSearch() {
emit('query')
}
// 重置
function onReset(formRef: FormInstance) {
queryForm.value.user = undefined
queryForm.value.range = 0
queryForm.value.module = undefined
emit('reset', formRef)
}
function handleAdd() {
emit('handleAdd')
}
const userOptions:any = ref([])
const moduleTreeOptions:any = ref([])
onMounted(async () => {
try {
const response = await queryMenuTreeAndUserlist({type: "global"})
console.log('queryMenuTreeAndUserlist',response);
userOptions.value = response.data.userlist.map(user => ({
id: user.id,
realname: user.realname
}))
moduleTreeOptions.value = response.data.menulist.map(menu => ({
value: menu.id,
label: menu.text,
children: menu.children ? menu.children.map(child => ({
value: child.id,
label: child.text
})) : null
}))
} catch (error) {
console.error('Failed to fetch user and module data:', error)
}
})
</script>
<template>
<!-- el-form -->
<page-wrapper-search
:model="queryForm"
:extraButtons="[
{
text: '导出',
icon: Download,
color: 'rgba(0, 189, 207, 1)',
type: 'success',
class: 'btn-fff',
onClick: handleAdd
}
]"
@search="onSearch"
@reset="onReset">
<el-form-item label="用户" prop="user">
<el-select
v-model="queryForm.user"
placeholder="请选择"
clearable
style="width: 200px"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.realname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="时间" prop="range">
<el-select
v-model="queryForm.range"
placeholder="请选择时间"
style="width: 200px"
>
<el-option
v-for="item in timeRangeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="操作模块" prop="module">
<el-cascader
v-model="queryForm.module"
:options="moduleTreeOptions"
:props="{
checkStrictly: false,
value: 'value',
label: 'label',
emitPath: false,
leaf: true
}"
clearable
style="width: 200px"
placeholder="请选择"
/>
</el-form-item>
</page-wrapper-search>
</template>
<style scoped lang="scss">
:deep(.btn-fff){
span{
color: #fff;
}
}
</style>
<template>
<div class="app-container">
<div class="page-title">
<el-icon class="title-icon"><Document /></el-icon>
<span>操作日志</span>
</div>
<div class="search-box">
<el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form-item label="用户" prop="user">
<el-select
v-model="queryParams.user"
placeholder="请选择"
clearable
style="width: 200px"
>
<el-option
v-for="item in userOptions"
:key="item.id"
:label="item.realname"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="时间" prop="range">
<el-select
v-model="queryParams.range"
placeholder="请选择时间"
style="width: 200px"
>
<el-option
v-for="item in timeRangeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="操作模块" prop="module">
<el-cascader
v-model="queryParams.module"
:options="moduleTreeOptions"
:props="{
checkStrictly: false,
value: 'value',
label: 'label',
emitPath: false,
leaf: true
}"
clearable
style="width: 200px"
placeholder="请选择"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="Download" @click="handleExport">导出</el-button>
<!-- <el-button type="primary" @click="handleCheck">数据完整性校验</el-button> -->
</el-form-item>
</el-form>
</div>
<el-table
v-loading="loading"
:data="logList"
border
style="width: 100%"
>
<el-table-column prop="user" label="用户" width="200" align="left" />
<el-table-column prop="operationtime" label="时间" align="left" width="180" />
<el-table-column prop="operationObject" label="模块编号" align="left" width="120" />
<el-table-column prop="module" label="操作模块" align="left" width="150" />
<el-table-column prop="logmessage" label="操作信息" align="left" show-overflow-tooltip />
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.page"
v-model:limit="queryParams.rows"
@pagination="getList"
/>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { Document } from '@element-plus/icons-vue'
import { query, checkEnc, queryMenuTreeAndUserlist, getOpeExcel} from '@/api/logSet/operationLog.js'
import { ElMessageBox, ElMessage } from 'element-plus'
import timeRangeOptions from '@/constants/timeRangeOptions.js'
const loading = ref(true)
const total = ref(0)
const logList = ref([])
const queryParams = reactive({
page: 1,
rows: 10,
user: undefined,
range: '0',
module: undefined
})
const userOptions = ref([
// { id: 'admin', realname: 'admin' },
// { id: 'system', realname: 'system' },
// { id: 'test', realname: 'test' }
])
<script setup lang="ts" name="projectManageIndex">
import { ref } from 'vue'
import list from './list.vue'
const moduleTreeOptions = ref([])
const getList = async () => {
loading.value = true
try {
const response = await query(queryParams)
logList.value = response.data.list || []
total.value = response.data.total || 0
} catch (error) {
console.error('Failed to fetch log list:', error)
} finally {
loading.value = false
}
const widget = {
list: list
}
const handleQuery = () => {
queryParams.page = 1
getList()
}
const page = ref('list')
const params = ref({})
const handleExport = async () => {
ElMessageBox.confirm('是否确认导出所有操作日志数据?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
try {
const response = await getOpeExcel(queryParams)
const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = '操作日志.xls'
link.click()
URL.revokeObjectURL(link.href)
ElMessage.success('导出成功')
} catch (error) {
console.error('Failed to export operation logs:', error)
ElMessage.error('导出出错')
}
})
.catch(() => {
ElMessage.info('导出已取消')
})
function onChangePage(val: string, param?: any) {
page.value = val
params.value = param ?? {}
}
const handleCheck = async () => {
try {
const response = await checkEnc(queryParams)
if (response.success) {
window.$modal.msgSuccess('数据完整性校验完成')
} else {
window.$modal.msgError('数据完整性校验失败')
}
} catch (error) {
console.error('Failed to perform data integrity check:', error)
window.$modal.msgError('数据完整性校验出错')
}
}
onMounted(async () => {
try {
const response = await queryMenuTreeAndUserlist({type: "global"})
console.log('queryMenuTreeAndUserlist',response);
userOptions.value = response.data.userlist.map(user => ({
id: user.id,
realname: user.realname
}))
moduleTreeOptions.value = response.data.menulist.map(menu => ({
value: menu.id,
label: menu.text,
children: menu.children ? menu.children.map(child => ({
value: child.id,
label: child.text
})) : null
}))
} catch (error) {
console.error('Failed to fetch user and module data:', error)
}
getList()
})
</script>
<style lang="scss" scoped>
.app-container {
padding: 20px;
.page-title {
display: flex;
align-items: center;
margin-bottom: 20px;
font-size: 16px;
font-weight: bold;
.title-icon {
margin-right: 8px;
font-size: 20px;
color: #409EFF;
}
}
.search-box {
margin-bottom: 20px;
background-color: #fff;
padding: 20px;
border-radius: 4px;
text-align: left;
:deep(.el-form) {
justify-content: flex-start;
}
:deep(.el-form--inline .el-form-item) {
margin-right: 20px;
}
}
.el-table {
margin-top: 20px;
}
:deep(.el-table) {
text-align: left;
}
:deep(.el-cascader) {
width: 100%;
}
}
</style>
<template>
<component :is="widget[page]" v-bind="params" @page="onChangePage" />
</template>
<template>
<div class="app-container scroller">
<PageTitle>
<template #title>
<div style="display: flex;align-items: center;">
<el-icon class="title-icon"><Document /></el-icon>
<span style="margin-left: 8px;">操作日志</span>
</div>
</template>
</PageTitle>
<div class="app-container__body">
<query-form
ref="QueryFormRef"
v-model="queryParams"
@query="handleQuery"
@reset="onReset"
@handleAdd="handleExport"
/>
<div style="flex: 1;">
<el-table
v-loading="loading"
:data="logList"
stripe
height="100%"
style="width: 100%"
>
<el-table-column prop="user" label="用户" width="200" align="left" />
<el-table-column prop="operationtime" label="时间" align="left" width="180" />
<el-table-column prop="operationObject" label="模块编号" align="left" width="120" />
<el-table-column prop="module" label="操作模块" align="left" width="150" />
<el-table-column prop="logmessage" label="操作信息" align="left" show-overflow-tooltip />
</el-table>
</div>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.page"
v-model:limit="queryParams.rows"
@pagination="getList"
/>
</div>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { Document } from '@element-plus/icons-vue'
import { query, checkEnc, queryMenuTreeAndUserlist, getOpeExcel} from '@/api/logSet/operationLog.js'
import { ElMessageBox, ElMessage } from 'element-plus'
import timeRangeOptions from '@/constants/timeRangeOptions.js'
import QueryForm from './QueryForm.vue'
const loading = ref(true)
const logList = ref([])
// const queryParams = reactive({
// page: 1,
// rows: 10,
// user: undefined,
// range: '0',
// module: undefined
// })
const data = reactive({
queryParams: {
page: 1,
rows: 10,
user: undefined,
range: '0',
module: undefined
}
})
const total = ref(0)
// 表格数据
const { queryParams } = toRefs(data)
const userOptions = ref([
// { id: 'admin', realname: 'admin' },
// { id: 'system', realname: 'system' },
// { id: 'test', realname: 'test' }
])
const moduleTreeOptions = ref([])
const getList = async () => {
loading.value = true
try {
const response = await query(queryParams.value)
logList.value = response.data.list || []
total.value = response.data.total || 0
} catch (error) {
console.error('Failed to fetch log list:', error)
} finally {
loading.value = false
}
}
const onReset = (formQuery) =>{
console.log('onReset')
formQuery.resetFields()
handleQuery()
}
const handleQuery = () => {
queryParams.value.page = 1
getList()
}
const handleExport = async () => {
ElMessageBox.confirm('是否确认导出所有操作日志数据?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(async () => {
try {
const response = await getOpeExcel(queryParams.value)
const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = '操作日志.xls'
link.click()
URL.revokeObjectURL(link.href)
ElMessage.success('导出成功')
} catch (error) {
console.error('Failed to export operation logs:', error)
ElMessage.error('导出出错')
}
})
.catch(() => {
ElMessage.info('导出已取消')
})
}
const handleCheck = async () => {
try {
const response = await checkEnc(queryParams.value)
if (response.success) {
window.$modal.msgSuccess('数据完整性校验完成')
} else {
window.$modal.msgError('数据完整性校验失败')
}
} catch (error) {
console.error('Failed to perform data integrity check:', error)
window.$modal.msgError('数据完整性校验出错')
}
}
onMounted(async () => {
try {
const response = await queryMenuTreeAndUserlist({type: "global"})
console.log('queryMenuTreeAndUserlist',response);
userOptions.value = response.data.userlist.map(user => ({
id: user.id,
realname: user.realname
}))
moduleTreeOptions.value = response.data.menulist.map(menu => ({
value: menu.id,
label: menu.text,
children: menu.children ? menu.children.map(child => ({
value: child.id,
label: child.text
})) : null
}))
} catch (error) {
console.error('Failed to fetch user and module data:', error)
}
getList()
})
</script>
<style lang="scss" scoped>
// .app-container {
// padding: 20px;
// .page-title {
// display: flex;
// align-items: center;
// margin-bottom: 20px;
// font-size: 16px;
// font-weight: bold;
// .title-icon {
// margin-right: 8px;
// font-size: 20px;
// color: #409EFF;
// }
// }
// .search-box {
// margin-bottom: 20px;
// background-color: #fff;
// padding: 20px;
// border-radius: 4px;
// text-align: left;
// :deep(.el-form) {
// justify-content: flex-start;
// }
// :deep(.el-form--inline .el-form-item) {
// margin-right: 20px;
// }
// }
// .el-table {
// margin-top: 20px;
// }
// :deep(.el-table) {
// text-align: left;
// }
// :deep(.el-cascader) {
// width: 100%;
// }
// }
</style>
......@@ -91,10 +91,7 @@
</el-table-column>
</el-table>
</div>
<pagination
v-show="total > 0"
:total="total"
......@@ -104,52 +101,7 @@
/>
</div>
<!-- 用户列表 -->
<!-- <div class="user-list">
<div class="user-grid">
<div v-for="(user, index) in userList" :key="index" class="user-card">
<div class="card-left-bar"></div>
<div class="user-info">
<div class="info">
<div class="name">{{ user.username }}</div>
<div class="username">
<el-icon><User /></el-icon>
用户名 {{ user.username }}
</div>
<div class="note">
<el-icon><Edit /></el-icon>
备注 {{ user.note }}
</div>
</div>
<div class="avatar">
<el-avatar :size="80" icon="UserFilled" style="background: #f6f8fa; color: #d3d8e0;" />
</div>
</div>
<div class="card-divider"></div>
<div class="card-bottom">
<div>
<el-icon><Clock /></el-icon>
{{ user.createtime || '' }}
</div>
<el-icon class="lock"><Lock /></el-icon>
</div>
<div class="hover-mask">
<div class="operation-buttons">
<div class="operation-btn" @click="handleDelete(user)">
<el-icon><Delete /></el-icon>
<span>删除</span>
</div>
<div class="operation-btn" @click="handleEdit(user)">
<el-icon><FolderOpened /></el-icon>
<span>编辑</span>
</div>
</div>
</div>
</div>
</div>
</div> -->
<!-- 分页 -->
<!-- 编辑弹窗 -->
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论