This commit is contained in:
2024-06-20 19:12:13 +08:00
parent 12f0406a48
commit 4a6e6f4ac4
22 changed files with 509 additions and 204 deletions

View File

@@ -0,0 +1,25 @@
import { request } from "@/api/request"
export default {
/**
* 分页查询操作日志
* @returns 操作日志分页结果
*/
getLoginLogs(params = { pageSize: 10, page: 1 }) {
return request({
url: `/system/log/loginLogsList`,
method: "get",
params
})
},
/**
* 操作日志删除
* @returns 后台返回的删除信息
*/
loginLogsDelete(params = { day: 7 }) {
return request({
url: `/system/log/loginLogsDel`,
method: "get",
params
})
}
}

View File

@@ -0,0 +1,25 @@
import { request } from "@/api/request"
export default {
/**
* 分页查询操作日志
* @returns 操作日志分页结果
*/
getOperations(params = { pageSize: 10, page: 1 }) {
return request({
url: `/system/log/operationsPagination`,
method: "get",
params
})
},
/**
* 操作日志删除
* @returns 后台返回的删除信息
*/
operationsDelete(params = { day: 7 }) {
return request({
url: `/system/log/operationsDel`,
method: "get",
params
})
}
}

View File

@@ -123,5 +123,16 @@ export default {
method: "get",
params
})
},
/**
* 改变用户启用/停用状态
* @returns
*/
changeUserStatus(params = {}) {
return request({
url: "system/user/change_status",
method: "get",
params
})
}
}

View File

@@ -142,7 +142,6 @@ const initConfig = reactive({
cleanStyles(element)
removeUnwantedSpansAndMore(element)
removeCommentNodes(element)
console.log(element)
})
// 将处理后的fragment转换回HTML字符串
args.content = doc.body.innerHTML

View File

@@ -3,7 +3,7 @@
<template v-if="!Component">
<Empty class="full-empty" />
</template>
<transition name="ma-fade" mode="out-in" appear>
<transition name="ma-slide-down" mode="out-in" appear>
<!-- 这里主要在路由定义是否缓存页面 -->
<component :is="Component" v-if="route.meta.ignoreCache" :key="route.fullPath" />
<keep-alive v-else :include="cacheList">

View File

@@ -42,4 +42,4 @@ app.config.globalProperties.$url = import.meta.env.VITE_APP_BASE
app.mount("#app")
// 无用的东西:下面就打印一个东西
tool.capsule("ChengduTestManagePlant", `v${packageJson.version} debug`)
tool.capsule("TestManagePlant", `v${packageJson.version} debug`)

View File

@@ -1,12 +1,18 @@
import { setRouteEmitter } from "@/utils/route-listener"
import setupUserLoginInfoGuard from "./userLoginInfo"
import setupPermissionGuard from "@/router/guard/permisstion"
// 导入设置title的工具
import { setRouteTitle } from "@/utils/title"
function setupPageGuard(router) {
router.beforeEach(async (to) => {
// 发出路由改变的事件
setRouteEmitter(to)
})
// 设置站点document.title
router.afterEach((to, from) => {
setRouteTitle(to.meta.title)
})
}
export default function createRouteGuard(router) {

View File

@@ -8,7 +8,8 @@ const DASHBOARD = {
requiresAuth: true,
icon: "icon-home",
order: 99,
locale: "首页"
locale: "首页",
title: "首页"
},
children: [
{
@@ -19,7 +20,8 @@ const DASHBOARD = {
requiresAuth: true,
roles: ["*"],
locale: "工作台",
icon: "icon-dashboard"
icon: "icon-dashboard",
title: "工作台"
}
},
{
@@ -30,7 +32,8 @@ const DASHBOARD = {
requiresAuth: true,
roles: ["*"],
locale: "用户中心",
icon: "icon-user"
icon: "icon-user",
title: "用户中心"
}
},
{
@@ -41,9 +44,10 @@ const DASHBOARD = {
requiresAuth: true,
roles: ["*"],
locale: "用户管理",
icon: "icon-user-group"
icon: "icon-user-group",
title: "用户管理"
}
},
}
]
}

View File

@@ -8,7 +8,8 @@ const DATAMANAGE = {
requiresAuth: true,
icon: "icon-storage",
order: 99,
locale: "数据管理"
locale: "数据管理",
title: "数据管理"
},
children: [
{
@@ -19,7 +20,8 @@ const DATAMANAGE = {
requiresAuth: true,
roles: ["*"],
locale: "字典管理",
icon: "icon-book"
icon: "icon-book",
title: "字典管理"
}
},
{
@@ -30,7 +32,8 @@ const DATAMANAGE = {
requiresAuth: true,
roles: ["*"],
locale: "项目联系信息",
icon: "icon-phone"
icon: "icon-phone",
title: "项目联系信息"
}
},
{
@@ -41,7 +44,8 @@ const DATAMANAGE = {
requiresAuth: true,
roles: ["*"],
locale: "缩略语",
icon: "icon-scissor"
icon: "icon-scissor",
title: "缩略语"
}
}
]

View File

@@ -8,18 +8,44 @@ const TESTMANAGE = {
requiresAuth: true,
icon: "icon-desktop",
order: 1,
locale: "监控"
locale: "日志监控",
title: "日志监控"
},
children: [
{
path: "operationLog",
name: "OperationLog",
name: "operationLog",
component: () => import("@/views/monitor/operationLog/index.vue"),
meta: {
requiresAuth: true,
roles: ["*"],
locale: "操作日志",
icon: "icon-robot"
locale: "数据操作日志",
icon: "icon-file",
title: "数据操作日志"
}
},
{
path: "operations",
name: "operations",
component: () => import("@/views/monitor/operations/index.vue"),
meta: {
requiresAuth: true,
roles: ["*"],
locale: "接口操作日志",
icon: "icon-file",
title: "接口操作日志"
}
},
{
path: "loginLog",
name: "loginLog",
component: () => import("@/views/monitor/loginLog/index.vue"),
meta: {
requiresAuth: true,
roles: ["*"],
locale: "登录日志",
icon: "icon-file",
title: "登录日志"
}
}
]

View File

@@ -8,7 +8,8 @@ const TESTMANAGE = {
requiresAuth: true,
icon: "icon-apps",
order: 98,
locale: "测试管理"
locale: "测试管理",
title: "测试管理"
},
children: [
{
@@ -19,7 +20,8 @@ const TESTMANAGE = {
requiresAuth: true,
roles: ["*"],
locale: "项目管理",
icon: "icon-folder"
icon: "icon-folder",
title: "项目管理"
}
},
// 二级路由(非三级路由,但是想办法把左侧菜单删除)
@@ -34,7 +36,8 @@ const TESTMANAGE = {
icon: "icon-folder",
hideInMenu: true,
ignoreCache: false,
noAffix: true
noAffix: true,
title: "项目看板"
}
}
]

16
cdTMP/src/utils/title.js Normal file
View File

@@ -0,0 +1,16 @@
let routeTitle = ""
let siteTitle = "测试管理平台"
function setTitle() {
if (routeTitle) {
document.title = routeTitle + " - " + siteTitle
return
} else {
document.title = siteTitle
}
}
export function setRouteTitle(title) {
routeTitle = title
setTitle()
}

View File

@@ -1,13 +1,11 @@
<template>
<div class="block">
<div class="user-header rounded-sm text-center">
<div class="pt-3 mx-auto avatar-box">
<ma-upload rounded></ma-upload>
<div class="pt-6 mx-auto avatar-box top-box">
{{ userStore.name }}
</div>
<div>
<a-tag size="large" class="mt-3 rounded-full" color="#de53ff">
{{ userStore.role }}
</a-tag>
<a-tag size="large" class="mt-3 rounded-full" color="#de53ff"> 账号{{ userStore.username }} </a-tag>
</div>
</div>
<a-layout-content class="block lg:flex lg:justify-between">
@@ -41,9 +39,10 @@
v-for="(item, idx) in operationLogList"
:key="idx"
>
您于 {{ item.create_datetime }} 请求了 {{ item.request_path }}状态码{{
item.response_code
}}
您于 {{ item.create_datetime }} 请求了 {{ item.request_path }}<span
:class="{ nostatus: item.response_code === '200' ? false : true }"
>状态码{{ item.response_code }}</span
>
</a-timeline-item>
</a-timeline>
</a-tab-pane>
@@ -91,8 +90,14 @@ const operationLogList = computed(() => {
}
.user-header {
width: 100%;
height: 200px;
height: 150px;
background: url("@/assets/userBanner.jpg") no-repeat;
background-size: cover;
}
.nostatus {
color: red;
}
.top-box {
font-size: 2rem;
}
</style>

View File

@@ -22,9 +22,11 @@ import userApi from "@/api/system/user"
import user from "@/api/system/user"
import { Message } from "@arco-design/web-vue"
// 切换状态按钮
const changeStatus = (e, id) => {
console.log("当前值:", e)
console.log("当前ID", id)
const changeStatus = async (e, id) => {
const res = await userApi.changeUserStatus({ user_status: e, userId: id })
if (res.data) {
Message.success(res.data === "1" ? "启用成功" : "禁用成功")
}
}
// crud组件
const crudRef = ref()
@@ -67,6 +69,7 @@ const crudOptions = reactive({
viewType: "modal"
// isFull: true
},
operationColumnAlign: "center",
// 用户点击编辑/删除前的hook
beforeOpenEdit: (record) => {
if (record.id === 1) {
@@ -93,7 +96,7 @@ const crudColumns = reactive([
width: 80,
commonRules: [{ required: true, message: "名称必填" }]
},
{ title: "用户名", dataIndex: "username", search: true },
{ title: "用户名", dataIndex: "username", search: true, align: "center" },
{
title: "电话",
align: "center",

View File

@@ -23,7 +23,7 @@
</a>
</a-card>
<div class="mt-2">管理平台版本</div>
<a-tag class="mt-2" color="#0fc6c2">cdTestPlant V0.0.1</a-tag>
<a-tag class="mt-2" color="#0fc6c2">TestManagePlant V0.0.1</a-tag>
</div>
</div>
</template>

View File

@@ -25,11 +25,12 @@ const crudOptions = ref({
showIndex: false,
searchColNumber: 3,
tablePagination: false,
rowSelection: { showCheckedAll: true }
rowSelection: { showCheckedAll: true },
showTools: false
})
const crudColumns = ref([
{ title: "ID", dataIndex: "id", addDisplay: false, editDisplay: false, width: 50, hide: true },
{ title: "公司编号", align: "center", dataIndex: "key", search: true, width: 220 },
{ title: "公司编号", align: "center", dataIndex: "key", search: true, width: 220, formType: "input-number" },
{
title: "名称",
align: "center",
@@ -47,11 +48,11 @@ const crudColumns = ref([
commonRules: [{ required: true, message: "法人必填" }]
},
{
title:'地址',
align:'center',
dataIndex:'addr',
search:true,
width:200,
title: "地址",
align: "center",
dataIndex: "addr",
search: true,
width: 200,
commonRules: [{ required: true, message: "公司地址必填" }]
}
])

View File

@@ -0,0 +1,86 @@
<template>
<div class="ma-content-block lg:flex justify-between p-4">
<div class="lg:w-full w-full lg:ml-4 mt-5 lg:mt-0">
<ma-crud :options="crudOptions" :columns="crudColumns" ref="crudRef">
<template #create_datetime="{ record }">
{{ record.create_datetime.split(".")[0].replace("T", " ") }}
</template>
<template #tableBeforeButtons>
<a-button type="primary" status="warning" @click="handleDeleteLogButton">
<template #icon> <icon-delete /> </template>删除7天前数据
</a-button>
<a-button type="primary" status="danger" @click="handleDeleteAllLogButton">
<template #icon> <icon-delete /> </template>删除全部日志
</a-button>
</template>
<!-- 操作列 -->
<template #operationCell="{ record }">
<a-button size="mini" type="primary" status="success" @click="handleSee(record)"
><icon-eye
/></a-button>
</template>
</ma-crud>
</div>
</div>
</template>
<script setup>
import { ref } from "vue"
import logApi from "@/api/monitor/loginLog"
import { Message, Notification } from "@arco-design/web-vue"
const crudRef = ref({})
// 删除日志按钮事件处理函数
const handleDeleteLogButton = async () => {
const res = await logApi.loginLogsDelete({ day: 7 }) // 参数:{day:4}保留4天内的日志
Message.success(res.message)
}
const handleDeleteAllLogButton = async () => {
const res = await logApi.loginLogsDelete({ day: 0 }) // 0表示删除全部日志
crudRef.value.refresh()
Message.success(res.message)
}
// 点击操作:查看【思路打开编辑窗口】
const handleSee = (record) => {
crudRef.value.editAction(record)
// 设置表单标题
crudRef.value.crudFormRef.actionTitle = "详情"
}
// 设置api
async function editClick() {
Notification.error("该详情只能查看")
}
const crudOptions = ref({
api: logApi.getLoginLogs,
edit: { api: editClick, text: "查看操作日志信息", show: false },
showIndex: false,
showTools: false,
pageLayout: "fixed",
tablePagination: false,
operationColumn: true,
operationColumnAlign: "center",
bordered: { wrapper: true, cell: true },
isDbClickEdit: false,
formOption: {
viewType: "drawer",
width: 600
}
})
const crudColumns = ref([
{ title: "ID", dataIndex: "id", addDisplay: false, editDisplay: false, width: 50, hide: true },
{ title: "登录用户", dataIndex: "username", search: true, align: "center" },
{ title: "IP", dataIndex: "ip", align: "center" },
{ title: "客户端信息", width: 215, dataIndex: "agent", align: "center" },
{ title: "操作系统", dataIndex: "os", align: "center" },
{ title: "浏览器", width: 110, dataIndex: "browser", align: "center" },
{
title: "创建时间",
dataIndex: "create_datetime",
align: "center",
width: 150,
addDisplay: false,
editDisplay: false
}
])
</script>
<style lang="less" scoped></style>

View File

@@ -4,7 +4,7 @@
<!-- crud组件 -->
<ma-crud :options="crudOptions" :columns="crudColumns" ref="crudRef">
<template #create_datetime="{ record }">
{{ record.create_datetime.replace("T", " ") }}
{{ record.create_datetime.split(".")[0].replace("T", " ") }}
</template>
<template #tableBeforeButtons>
<a-button type="primary" status="warning" @click="handleDeleteLogButton"
@@ -29,9 +29,9 @@ const crudOptions = reactive({
api: operationApi.getOperationsLogs,
showIndex: false,
pageLayout: "fixed",
rowSelection: { showCheckedAll: true },
showTools: false,
tablePagination: false
tablePagination: false,
bordered: { wrapper: true, cell: true }
})
const crudColumns = reactive([
{ title: "ID", dataIndex: "id", addDisplay: false, editDisplay: false, width: 50, hide: true },

View File

@@ -0,0 +1,90 @@
<template>
<div class="ma-content-block lg:flex justify-between p-4">
<div class="lg:w-full w-full lg:ml-4 mt-5 lg:mt-0">
<ma-crud :options="crudOptions" :columns="crudColumns" ref="crudRef">
<template #create_datetime="{ record }">
{{ record.create_datetime.split(".")[0].replace("T", " ") }}
</template>
<template #tableBeforeButtons>
<a-button type="primary" status="warning" @click="handleDeleteLogButton">
<template #icon> <icon-delete /> </template>删除7天前数据
</a-button>
<a-button type="primary" status="danger" @click="handleDeleteAllLogButton">
<template #icon> <icon-delete /> </template>删除全部日志
</a-button>
</template>
<!-- 操作列 -->
<template #operationCell="{ record }">
<a-button size="mini" type="primary" status="success" @click="handleSee(record)"
><icon-eye
/></a-button>
</template>
</ma-crud>
</div>
</div>
</template>
<script setup>
import { ref } from "vue"
import logApi from "@/api/monitor/operations"
import { Message, Notification } from "@arco-design/web-vue"
const crudRef = ref({})
// 删除日志按钮事件处理函数
const handleDeleteLogButton = async () => {
const res = await logApi.operationsDelete({ day: 7 }) // 参数:{day:4}保留4天内的日志
Message.success(res.message)
}
const handleDeleteAllLogButton = async () => {
const res = await logApi.operationsDelete({ day: 0 }) // 0表示删除全部日志
crudRef.value.refresh()
Message.success(res.message)
}
// 点击操作:查看【思路打开编辑窗口】
const handleSee = (record) => {
crudRef.value.editAction(record)
// 设置表单标题
crudRef.value.crudFormRef.actionTitle = "详情"
}
// 设置api
async function editClick() {
Notification.error("该详情只能查看")
}
const crudOptions = ref({
api: logApi.getOperations,
edit: { api: editClick, text: "查看操作日志信息", show: false },
showIndex: false,
showTools: false,
pageLayout: "fixed",
tablePagination: false,
operationColumn: true,
operationColumnAlign: "center",
bordered: { wrapper: true, cell: true },
isDbClickEdit: false,
formOption: {
viewType: "drawer",
width: 600
}
})
const crudColumns = ref([
{ title: "ID", dataIndex: "id", addDisplay: false, editDisplay: false, width: 50, hide: true },
{ title: "操作用户", dataIndex: "request_username", search: true, align: "center" },
{ title: "请求方式", dataIndex: "request_method", align: "center" },
{ title: "IP", dataIndex: "request_ip", align: "center" },
{ title: "浏览器", dataIndex: "request_browser", align: "center" },
{ title: "响应状态码", dataIndex: "response_code", align: "center" },
{ title: "操作系统", dataIndex: "request_os", align: "center" },
{
title: "创建时间",
dataIndex: "create_datetime",
align: "center",
width: 150,
addDisplay: false,
editDisplay: false
},
{ title: "请求地址", dataIndex: "request_path", hide: true },
{ title: "请求参数", dataIndex: "request_body", hide: true, formType: "textarea" },
{ title: "返回信息", dataIndex: "json_result", hide: true, formType: "textarea" }
])
</script>
<style lang="less" scoped></style>