更新操作日志和登录日志的数据隔离

This commit is contained in:
2026-09-04 23:57:08 +08:00
parent 20be7f4817
commit 3d53f03246
8 changed files with 1053 additions and 934 deletions
@@ -46,7 +46,7 @@
</div> </div>
<el-table :data="pagedRows" v-loading="loading" stripe> <el-table :data="pagedRows" v-loading="loading" stripe>
<el-table-column prop="id" label="ID" width="70" align="center" /> <!--<el-table-column prop="id" label="ID" width="70" align="center" />-->
<el-table-column prop="position_code" label="职位编码" width="150" /> <el-table-column prop="position_code" label="职位编码" width="150" />
<el-table-column prop="position_name" label="职位名称" min-width="140" /> <el-table-column prop="position_name" label="职位名称" min-width="140" />
<el-table-column label="所属部门" min-width="150"> <el-table-column label="所属部门" min-width="150">
@@ -1,301 +1,328 @@
<template> <template>
<el-form <el-form
ref="normalFormRef" ref="normalFormRef"
:model="formData" :model="formData"
:rules="normalRules" :rules="normalRules"
label-width="120px" label-width="120px"
style="max-width: 600px" style="max-width: 600px"
> >
<el-form-item label="站点名称" prop="sitename"> <el-form-item label="站点名称" prop="sitename">
<el-input v-model="sitename" placeholder="请输入站点名称" /> <el-input v-model="sitename" placeholder="请输入站点名称" />
</el-form-item> </el-form-item>
<el-form-item label="站点Logo" prop="logo"> <el-form-item label="站点Logo" prop="logo">
<el-upload <el-upload
class="logo-uploader" class="logo-uploader"
:show-file-list="false" :show-file-list="false"
:auto-upload="false" :auto-upload="false"
:on-change="handleLogoChange" :on-change="handleLogoChange"
> >
<img <img
v-if="logo" v-if="logo"
:src="getPreviewUrl(logo)" :src="getPreviewUrl(logo)"
class="logo-image" class="logo-image"
/> />
<el-icon v-else class="logo-uploader-icon"><Plus /></el-icon> <el-icon v-else class="logo-uploader-icon"><Plus /></el-icon>
</el-upload> </el-upload>
</el-form-item> </el-form-item>
<el-form-item label="站点Logo-浅色" prop="logow"> <el-form-item label="站点Logo-浅色" prop="logow">
<el-upload <el-upload
class="logo-uploader" class="logo-uploader"
:show-file-list="false" :show-file-list="false"
:auto-upload="false" :auto-upload="false"
:on-change="handleLogowChange" :on-change="handleLogowChange"
> >
<img <img
v-if="logow" v-if="logow"
:src="getPreviewUrl(logow)" :src="getPreviewUrl(logow)"
class="logo-image darkbg" class="logo-image darkbg"
/> />
<el-icon v-else class="logo-uploader-icon"><Plus /></el-icon> <el-icon v-else class="logo-uploader-icon"><Plus /></el-icon>
</el-upload> </el-upload>
</el-form-item> </el-form-item>
<el-form-item label="站点图标" prop="ico"> <el-form-item label="站点图标" prop="ico">
<el-upload <el-upload
class="logo-uploader" class="logo-uploader"
:show-file-list="false" :show-file-list="false"
:auto-upload="false" :auto-upload="false"
:on-change="handleIconChange" :on-change="handleIconChange"
> >
<img <img
v-if="ico" v-if="ico"
:src="getPreviewUrl(ico)" :src="getPreviewUrl(ico)"
class="logo-image" class="logo-image"
/> />
<el-icon v-else class="logo-uploader-icon"><Plus /></el-icon> <el-icon v-else class="logo-uploader-icon"><Plus /></el-icon>
</el-upload> </el-upload>
<div class="form-tip">请上传ico格式文件</div> <div class="form-tip">请上传ico格式文件</div>
</el-form-item> </el-form-item>
<el-form-item label="企业名称" prop="companyname"> <el-form-item label="企业名称" prop="companyname">
<el-input v-model="companyname" placeholder="请输入企业名称" /> <el-input v-model="companyname" placeholder="请输入企业名称" />
</el-form-item> </el-form-item>
<el-form-item label="企业介绍" prop="companyintroduction"> <el-form-item label="企业简称" prop="company_short_name">
<el-input v-model="companyintroduction" type="textarea" rows="5" placeholder="请输入企业介绍" /> <el-input v-model="companyShortName" placeholder="请输入企业简称" />
</el-form-item> </el-form-item>
<el-form-item label="站点简介" prop="description"> <el-form-item label="企业英文名称" prop="company_english_name">
<el-input v-model="description" placeholder="请输入站点简介" /> <el-input v-model="companyEnglishName" placeholder="请输入企业英文名称" />
</el-form-item> </el-form-item>
<el-form-item label="版权信息" prop="copyright"> <el-form-item label="企业英文简称" prop="company_english_short_name">
<el-input v-model="copyright" placeholder="如:© 2026 公司名称" /> <el-input v-model="companyEnglishShortName" placeholder="请输入企业英文简称" />
</el-form-item> </el-form-item>
<el-form-item label="备案号 " prop="icp"> <el-form-item label="企业介绍" prop="companyintroduction">
<el-input v-model="icp" placeholder="如:苏ICP备20260000号" /> <el-input v-model="companyintroduction" type="textarea" rows="5" placeholder="请输入企业介绍" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item label="站点简介" prop="description">
<el-button type="primary" @click="handleSaveNormalInfos" <el-input v-model="description" placeholder="请输入站点简介" />
>保存设置</el-button </el-form-item>
> <el-form-item label="版权信息" prop="copyright">
<el-button @click="resetnormalForm">重置</el-button> <el-input v-model="copyright" placeholder="如:© 2026 公司名称" />
</el-form-item> </el-form-item>
</el-form> <el-form-item label="备案号 " prop="icp">
</template> <el-input v-model="icp" placeholder="如:苏ICP备20260000号" />
</el-form-item>
<script setup lang="ts"> <el-form-item>
import { ref, onMounted } from "vue"; <el-button type="primary" @click="handleSaveNormalInfos"
import { ElMessage } from "element-plus"; >保存设置</el-button
import { Plus } from "@element-plus/icons-vue"; >
import type { FormInstance, FormRules, UploadFile } from "element-plus"; <el-button @click="resetnormalForm">重置</el-button>
import { getNormalInfos, saveNormalInfos } from "@/api/sitesettings"; </el-form-item>
import { uploadFile } from "@/api/file"; </el-form>
import { useAuthStore } from "@/stores/auth"; </template>
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL; <script setup lang="ts">
const authStore = useAuthStore(); import { ref, onMounted } from "vue";
import { ElMessage } from "element-plus";
const normalFormRef = ref<FormInstance>(); import { Plus } from "@element-plus/icons-vue";
import type { FormInstance, FormRules, UploadFile } from "element-plus";
const sitename = ref(""); import { getNormalInfos, saveNormalInfos } from "@/api/sitesettings";
const companyname = ref(""); import { uploadFile } from "@/api/file";
const companyintroduction = ref(""); import { useAuthStore } from "@/stores/auth";
const logo = ref("");
const logow = ref(""); const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
const description = ref(""); const authStore = useAuthStore();
const copyright = ref("");
const icp = ref(""); const normalFormRef = ref<FormInstance>();
const ico = ref("");
const sitename = ref("");
const formData = { const companyname = ref("");
sitename, const companyShortName = ref("");
companyname, const companyEnglishName = ref("");
companyintroduction, const companyEnglishShortName = ref("");
logo, const companyintroduction = ref("");
logow, const logo = ref("");
ico, const logow = ref("");
description, const description = ref("");
copyright, const copyright = ref("");
icp, const icp = ref("");
}; const ico = ref("");
const normalRules: FormRules = { const formData = {
sitename: [{ required: true, message: "请输入站点名称", trigger: "blur" }], sitename,
}; companyname,
companyShortName,
const getPreviewUrl = (url: string) => { companyEnglishName,
const value = String(url || "").trim().replace(/\\/g, "/"); companyEnglishShortName,
if (!value) return ""; companyintroduction,
if (/^(https?:\/\/|\/\/|data:|blob:)/i.test(value)) { logo,
return value; logow,
} ico,
description,
const base = String(API_BASE_URL || "").replace(/\/+$/, ""); copyright,
const path = value.startsWith("/") ? value : `/${value}`; icp,
return `${base}${path}`; };
};
const normalRules: FormRules = {
//调用基础数据 sitename: [{ required: true, message: "请输入站点名称", trigger: "blur" }],
const initNormalInfos = async () => { };
const res = await getNormalInfos(authStore.user.tid);
if (res.code === 200 && res.data) { const getPreviewUrl = (url: string) => {
const data = res.data; const value = String(url || "").trim().replace(/\\/g, "/");
sitename.value = data.sitename || ""; if (!value) return "";
companyintroduction.value = data.companyintroduction || ""; if (/^(https?:\/\/|\/\/|data:|blob:)/i.test(value)) {
logo.value = data.logo || ""; return value;
logow.value = data.logow || ""; }
ico.value = data.ico || "";
description.value = data.description || ""; const base = String(API_BASE_URL || "").replace(/\/+$/, "");
copyright.value = data.copyright || ""; const path = value.startsWith("/") ? value : `/${value}`;
icp.value = data.icp || ""; return `${base}${path}`;
companyname.value = data.companyname || ""; };
}
}; //调用基础数据
const initNormalInfos = async () => {
const handleLogoChange = (file: UploadFile) => { const res = await getNormalInfos(authStore.user.tid);
const uploadFormData = new FormData(); if (res.code === 200 && res.data) {
uploadFormData.append("file", file.raw); const data = res.data;
uploadFormData.append("cate", "site"); sitename.value = data.sitename || "";
companyintroduction.value = data.companyintroduction || "";
uploadFile(uploadFormData).then((uploadRes) => { logo.value = data.logo || "";
if ( logow.value = data.logow || "";
(uploadRes.code === 200 || uploadRes.code === 201) && ico.value = data.ico || "";
uploadRes.data && description.value = data.description || "";
uploadRes.data.url copyright.value = data.copyright || "";
) { icp.value = data.icp || "";
logo.value = uploadRes.data.url.replace(/\\/g, "/"); companyname.value = data.companyname || "";
} else { companyShortName.value = data.company_short_name || "";
ElMessage.error(uploadRes.msg || "上传失败"); companyEnglishName.value = data.company_english_name || "";
} companyEnglishShortName.value = data.company_english_short_name || "";
}); }
}; };
const handleLogowChange = (file: UploadFile) => { const handleLogoChange = (file: UploadFile) => {
const uploadFormData = new FormData(); const uploadFormData = new FormData();
uploadFormData.append("file", file.raw); uploadFormData.append("file", file.raw);
uploadFormData.append("cate", "site"); uploadFormData.append("cate", "site");
uploadFile(uploadFormData).then((uploadRes) => { uploadFile(uploadFormData).then((uploadRes) => {
if ( if (
(uploadRes.code === 200 || uploadRes.code === 201) && (uploadRes.code === 200 || uploadRes.code === 201) &&
uploadRes.data && uploadRes.data &&
uploadRes.data.url uploadRes.data.url
) { ) {
logow.value = uploadRes.data.url.replace(/\\/g, "/"); logo.value = uploadRes.data.url.replace(/\\/g, "/");
} else { } else {
ElMessage.error(uploadRes.msg || "上传失败"); ElMessage.error(uploadRes.msg || "上传失败");
} }
}); });
}; };
const handleSaveNormalInfos = async () => { const handleLogowChange = (file: UploadFile) => {
if (!normalFormRef.value) return; const uploadFormData = new FormData();
await normalFormRef.value.validate(async (valid) => { uploadFormData.append("file", file.raw);
if (valid) { uploadFormData.append("cate", "site");
const data = {
tid: authStore.user.tid, uploadFile(uploadFormData).then((uploadRes) => {
sitename: sitename.value, if (
companyintroduction: companyintroduction.value, (uploadRes.code === 200 || uploadRes.code === 201) &&
logo: logo.value, uploadRes.data &&
logow: logow.value, uploadRes.data.url
ico: ico.value, ) {
description: description.value, logow.value = uploadRes.data.url.replace(/\\/g, "/");
companyname: companyname.value, } else {
copyright: copyright.value, ElMessage.error(uploadRes.msg || "上传失败");
icp: icp.value, }
}; });
const res = await saveNormalInfos(data); };
if (res.code === 200) {
ElMessage.success("保存成功"); const handleSaveNormalInfos = async () => {
} else { if (!normalFormRef.value) return;
ElMessage.error(res.msg || "保存失败"); await normalFormRef.value.validate(async (valid) => {
} if (valid) {
} const data = {
}); tid: authStore.user.tid,
}; sitename: sitename.value,
companyintroduction: companyintroduction.value,
const handleIconChange = (file: UploadFile) => { logo: logo.value,
const uploadFormData = new FormData(); logow: logow.value,
uploadFormData.append("file", file.raw); ico: ico.value,
uploadFormData.append("cate", "site"); description: description.value,
companyname: companyname.value,
uploadFile(uploadFormData).then((uploadRes) => { company_short_name: companyShortName.value,
if ((uploadRes.code === 200 || uploadRes.code === 201) && uploadRes.data?.url) { company_english_name: companyEnglishName.value,
ico.value = uploadRes.data.url.replace(/\\/g, "/"); company_english_short_name: companyEnglishShortName.value,
} else { copyright: copyright.value,
ElMessage.error(uploadRes.msg || "上传失败"); icp: icp.value,
} };
}); const res = await saveNormalInfos(data);
}; if (res.code === 200) {
ElMessage.success("保存成功");
const resetnormalForm = () => { } else {
sitename.value = ""; ElMessage.error(res.msg || "保存失败");
companyname.value = ""; }
companyintroduction.value = ""; }
logo.value = ""; });
logow.value = ""; };
ico.value = "";
description.value = ""; const handleIconChange = (file: UploadFile) => {
copyright.value = ""; const uploadFormData = new FormData();
icp.value = ""; uploadFormData.append("file", file.raw);
}; uploadFormData.append("cate", "site");
defineExpose({ uploadFile(uploadFormData).then((uploadRes) => {
sitename, if ((uploadRes.code === 200 || uploadRes.code === 201) && uploadRes.data?.url) {
companyname, ico.value = uploadRes.data.url.replace(/\\/g, "/");
companyintroduction, } else {
logo, ElMessage.error(uploadRes.msg || "上传失败");
logow, }
ico, });
description, };
copyright,
icp, const resetnormalForm = () => {
}); sitename.value = "";
companyname.value = "";
// 初始化基础数据 companyShortName.value = "";
onMounted(() => { companyEnglishName.value = "";
initNormalInfos(); companyEnglishShortName.value = "";
}); companyintroduction.value = "";
</script> logo.value = "";
logow.value = "";
<style lang="less" scoped> ico.value = "";
.darkbg { description.value = "";
background-color: #efefef; copyright.value = "";
} icp.value = "";
};
.form-tip{
margin-left: 20px; defineExpose({
color: #999; sitename,
font-size: 12px; companyname,
margin-top: 5px; companyShortName,
} companyEnglishName,
companyEnglishShortName,
.logo-uploader { companyintroduction,
:deep(.el-upload) { logo,
border: 1px dashed #d9d9d9; logow,
border-radius: 6px; ico,
cursor: pointer; description,
position: relative; copyright,
overflow: hidden; icp,
transition: all 0.3s; });
&:hover { // 初始化基础数据
border-color: #3973ff; onMounted(() => {
} initNormalInfos();
} });
</script>
.logo-uploader-icon {
font-size: 28px; <style lang="less" scoped>
color: #8c939d; .darkbg {
width: 100px; background-color: #efefef;
height: 100px; }
text-align: center;
display: flex; .form-tip{
align-items: center; margin-left: 20px;
justify-content: center; color: #999;
} font-size: 12px;
margin-top: 5px;
.logo-image { }
width: 100px;
height: 100px; .logo-uploader {
object-fit: contain; :deep(.el-upload) {
display: block; border: 1px dashed #d9d9d9;
} border-radius: 6px;
} cursor: pointer;
</style> position: relative;
overflow: hidden;
transition: all 0.3s;
&:hover {
border-color: #3973ff;
}
}
.logo-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 100px;
height: 100px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.logo-image {
width: 100px;
height: 100px;
object-fit: contain;
display: block;
}
}
</style>
+2 -2
View File
@@ -80,8 +80,8 @@
v-loading="loading" v-loading="loading"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column type="selection" width="55" align="center" /> <!--<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="id" label="ID" width="60" align="center" /> <el-table-column prop="id" label="ID" width="60" align="center" />-->
<el-table-column <el-table-column
prop="user_name" prop="user_name"
label="用户姓名" label="用户姓名"
@@ -67,8 +67,8 @@
v-loading="loading" v-loading="loading"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column type="selection" width="55" align="center" /> <!--<el-table-column type="selection" width="55" align="center" />-->
<el-table-column prop="id" label="ID" width="60" align="center" /> <!--<el-table-column prop="id" label="ID" width="60" align="center" />-->
<el-table-column <el-table-column
prop="user_name" prop="user_name"
label="用户姓名" label="用户姓名"
+54 -15
View File
@@ -2,11 +2,13 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"fmt"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"server/models" "server/models"
"server/pkg/jwtutil"
"github.com/beego/beego/v2/client/orm" "github.com/beego/beego/v2/client/orm"
beego "github.com/beego/beego/v2/server/web" beego "github.com/beego/beego/v2/server/web"
@@ -17,6 +19,40 @@ type BackendErpContactController struct {
beego.Controller beego.Controller
} }
// contactClaims 从请求头解析登录态 JWT,返回后端用户 Claims
func (c *BackendErpContactController) contactClaims() (*jwtutil.Claims, error) {
auth := c.Ctx.Request.Header.Get("Authorization")
if auth == "" {
return nil, fmt.Errorf("未登录")
}
parts := strings.SplitN(auth, " ", 2)
if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") {
return nil, fmt.Errorf("认证信息格式错误")
}
claims, err := jwtutil.ParseToken(parts[1])
if err != nil {
return nil, fmt.Errorf("无效的token")
}
if claims.UserType != "backend" {
return nil, fmt.Errorf("无权访问")
}
return claims, nil
}
// contactTenantID 获取当前请求的租户ID:优先使用登录态 JWT 中的租户,
// 仅当显式传入 tid 参数时才以参数为准(兼容管理端等显式指定场景)。
func (c *BackendErpContactController) contactTenantID() (uint64, error) {
claims, err := c.contactClaims()
if err != nil {
return 0, err
}
tid := uint64(claims.TenantId)
if v, e := c.GetInt64("tid"); e == nil && v > 0 {
tid = uint64(v)
}
return tid, nil
}
type erpContactDTO struct { type erpContactDTO struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
Tid uint64 `json:"tid"` Tid uint64 `json:"tid"`
@@ -46,7 +82,11 @@ type erpContactDTO struct {
// List 获取通讯录列表(支持分页、搜索、按组织筛选) // List 获取通讯录列表(支持分页、搜索、按组织筛选)
// GET /backend/erp/contact/list // GET /backend/erp/contact/list
func (c *BackendErpContactController) List() { func (c *BackendErpContactController) List() {
tid, _ := c.GetInt64("tid") tid, err := c.contactTenantID()
if err != nil {
c.contactJsonError(401, "未登录或无权访问")
return
}
page, _ := c.GetInt("page", 1) page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("page_size", 20) pageSize, _ := c.GetInt("page_size", 20)
keyword := strings.TrimSpace(c.GetString("keyword")) keyword := strings.TrimSpace(c.GetString("keyword"))
@@ -62,10 +102,8 @@ func (c *BackendErpContactController) List() {
qs := models.Orm.QueryTable(new(models.BackendErpContact)). qs := models.Orm.QueryTable(new(models.BackendErpContact)).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
Exclude("status", 0) Exclude("status", 0).
if tid > 0 { Filter("tid", tid)
qs = qs.Filter("tid", tid)
}
if orgID > 0 { if orgID > 0 {
qs = qs.Filter("org_id", orgID) qs = qs.Filter("org_id", orgID)
} }
@@ -398,17 +436,19 @@ func (c *BackendErpContactController) SyncAllContacts() {
// GetContactOrgTree 获取通讯录组织树(带各部门联系人数量) // GetContactOrgTree 获取通讯录组织树(带各部门联系人数量)
// GET /backend/erp/contact/orgTree // GET /backend/erp/contact/orgTree
func (c *BackendErpContactController) GetContactOrgTree() { func (c *BackendErpContactController) GetContactOrgTree() {
tid, _ := c.GetInt64("tid") tid, err := c.contactTenantID()
if err != nil {
c.contactJsonError(401, "未登录或无权访问")
return
}
qs := models.Orm.QueryTable(new(models.BackendOrganization)). qs := models.Orm.QueryTable(new(models.BackendOrganization)).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
Exclude("status", 0) Exclude("status", 0).
if tid > 0 { Filter("tid", tid)
qs = qs.Filter("tid", tid)
}
var orgs []models.BackendOrganization var orgs []models.BackendOrganization
_, err := qs.OrderBy("sort", "id").All(&orgs) _, err = qs.OrderBy("sort", "id").All(&orgs)
if err != nil { if err != nil {
c.contactJsonError(500, "查询组织架构失败: "+err.Error()) c.contactJsonError(500, "查询组织架构失败: "+err.Error())
return return
@@ -418,10 +458,8 @@ func (c *BackendErpContactController) GetContactOrgTree() {
cqs := models.Orm.QueryTable(new(models.BackendErpContact)). cqs := models.Orm.QueryTable(new(models.BackendErpContact)).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
Exclude("status", 0). Exclude("status", 0).
Filter("contact_type", 1) Filter("contact_type", 1).
if tid > 0 { Filter("tid", tid)
cqs = cqs.Filter("tid", tid)
}
type orgCount struct { type orgCount struct {
OrgID uint64 `orm:"column(org_id)"` OrgID uint64 `orm:"column(org_id)"`
@@ -437,6 +475,7 @@ func (c *BackendErpContactController) GetContactOrgTree() {
for _, org := range orgs { for _, org := range orgs {
cnt, _ := models.Orm.QueryTable(new(models.BackendErpContact)). cnt, _ := models.Orm.QueryTable(new(models.BackendErpContact)).
Filter("org_id", org.ID). Filter("org_id", org.ID).
Filter("tid", tid).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
Exclude("status", 0). Exclude("status", 0).
Filter("contact_type", 1). Filter("contact_type", 1).
+34 -6
View File
@@ -48,10 +48,13 @@ func (c *BackendOperationLogController) jsonErr(httpStatus, bizCode int, msg str
// List GET /backend/operationLogs?page=1&pageSize=20&keyword=&module=&action=&status=&startTime=&endTime= // List GET /backend/operationLogs?page=1&pageSize=20&keyword=&module=&action=&status=&startTime=&endTime=
func (c *BackendOperationLogController) List() { func (c *BackendOperationLogController) List() {
if _, err := c.backendClaims(); err != nil { claims, err := c.backendClaims()
if err != nil {
c.jsonErr(401, 401, err.Error()) c.jsonErr(401, 401, err.Error())
return return
} }
uid := uint64(claims.UserID)
tid := uint64(claims.TenantId)
page, _ := c.GetInt("page", 1) page, _ := c.GetInt("page", 1)
pageSize, _ := c.GetInt("pageSize", 20) pageSize, _ := c.GetInt("pageSize", 20)
@@ -72,7 +75,10 @@ func (c *BackendOperationLogController) List() {
startTimeStr := strings.TrimSpace(c.GetString("startTime")) startTimeStr := strings.TrimSpace(c.GetString("startTime"))
endTimeStr := strings.TrimSpace(c.GetString("endTime")) endTimeStr := strings.TrimSpace(c.GetString("endTime"))
qs := models.Orm.QueryTable(new(models.SystemOperationLog)).Filter("delete_time__isnull", true) qs := models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("delete_time__isnull", true).
Filter("tid", tid).
Filter("user_id", uid)
// 条件拼装 // 条件拼装
cond := orm.NewCondition() cond := orm.NewCondition()
@@ -174,10 +180,13 @@ func (c *BackendOperationLogController) List() {
// Detail GET /backend/operationLogs/:id // Detail GET /backend/operationLogs/:id
func (c *BackendOperationLogController) Detail() { func (c *BackendOperationLogController) Detail() {
if _, err := c.backendClaims(); err != nil { claims, err := c.backendClaims()
if err != nil {
c.jsonErr(401, 401, err.Error()) c.jsonErr(401, 401, err.Error())
return return
} }
uid := uint64(claims.UserID)
tid := uint64(claims.TenantId)
idStr := c.Ctx.Input.Param(":id") idStr := c.Ctx.Input.Param(":id")
id, err := strconv.ParseUint(idStr, 10, 64) id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil || id == 0 { if err != nil || id == 0 {
@@ -187,6 +196,8 @@ func (c *BackendOperationLogController) Detail() {
var row models.SystemOperationLog var row models.SystemOperationLog
err = models.Orm.QueryTable(new(models.SystemOperationLog)). err = models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("id", id). Filter("id", id).
Filter("tid", tid).
Filter("user_id", uid).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
One(&row) One(&row)
if err != nil { if err != nil {
@@ -219,10 +230,13 @@ func (c *BackendOperationLogController) Detail() {
// Delete DELETE /backend/operationLogs/:id // Delete DELETE /backend/operationLogs/:id
func (c *BackendOperationLogController) Delete() { func (c *BackendOperationLogController) Delete() {
if _, err := c.backendClaims(); err != nil { claims, err := c.backendClaims()
if err != nil {
c.jsonErr(401, 401, err.Error()) c.jsonErr(401, 401, err.Error())
return return
} }
uid := uint64(claims.UserID)
tid := uint64(claims.TenantId)
idStr := c.Ctx.Input.Param(":id") idStr := c.Ctx.Input.Param(":id")
id, err := strconv.ParseUint(idStr, 10, 64) id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil || id == 0 { if err != nil || id == 0 {
@@ -232,6 +246,8 @@ func (c *BackendOperationLogController) Delete() {
now := time.Now() now := time.Now()
n, err := models.Orm.QueryTable(new(models.SystemOperationLog)). n, err := models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("id", id). Filter("id", id).
Filter("tid", tid).
Filter("user_id", uid).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
Update(map[string]interface{}{"delete_time": now}) Update(map[string]interface{}{"delete_time": now})
if err != nil { if err != nil {
@@ -252,10 +268,13 @@ type backendBatchDeletePayload struct {
// BatchDelete POST /backend/operationLogs/batchDelete // BatchDelete POST /backend/operationLogs/batchDelete
func (c *BackendOperationLogController) BatchDelete() { func (c *BackendOperationLogController) BatchDelete() {
if _, err := c.backendClaims(); err != nil { claims, err := c.backendClaims()
if err != nil {
c.jsonErr(401, 401, err.Error()) c.jsonErr(401, 401, err.Error())
return return
} }
uid := uint64(claims.UserID)
tid := uint64(claims.TenantId)
raw, err := io.ReadAll(c.Ctx.Request.Body) raw, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil { if err != nil {
c.jsonErr(400, 400, "参数错误") c.jsonErr(400, 400, "参数错误")
@@ -273,6 +292,8 @@ func (c *BackendOperationLogController) BatchDelete() {
now := time.Now() now := time.Now()
_, err = models.Orm.QueryTable(new(models.SystemOperationLog)). _, err = models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("id__in", p.IDs). Filter("id__in", p.IDs).
Filter("tid", tid).
Filter("user_id", uid).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
Update(map[string]interface{}{"delete_time": now}) Update(map[string]interface{}{"delete_time": now})
if err != nil { if err != nil {
@@ -286,14 +307,19 @@ func (c *BackendOperationLogController) BatchDelete() {
// Statistics GET /backend/operationLogs/statistics // Statistics GET /backend/operationLogs/statistics
// 供前端筛选项:modules/actions // 供前端筛选项:modules/actions
func (c *BackendOperationLogController) Statistics() { func (c *BackendOperationLogController) Statistics() {
if _, err := c.backendClaims(); err != nil { claims, err := c.backendClaims()
if err != nil {
c.jsonErr(401, 401, err.Error()) c.jsonErr(401, 401, err.Error())
return return
} }
uid := uint64(claims.UserID)
tid := uint64(claims.TenantId)
var moduleRows []models.SystemOperationLog var moduleRows []models.SystemOperationLog
_, _ = models.Orm.QueryTable(new(models.SystemOperationLog)). _, _ = models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
Filter("tid", tid).
Filter("user_id", uid).
Filter("module__isnull", false). Filter("module__isnull", false).
Limit(1000). Limit(1000).
All(&moduleRows, "Module") All(&moduleRows, "Module")
@@ -312,6 +338,8 @@ func (c *BackendOperationLogController) Statistics() {
var actionRows []models.SystemOperationLog var actionRows []models.SystemOperationLog
_, _ = models.Orm.QueryTable(new(models.SystemOperationLog)). _, _ = models.Orm.QueryTable(new(models.SystemOperationLog)).
Filter("delete_time__isnull", true). Filter("delete_time__isnull", true).
Filter("tid", tid).
Filter("user_id", uid).
Filter("action__isnull", false). Filter("action__isnull", false).
Limit(1000). Limit(1000).
All(&actionRows, "Action") All(&actionRows, "Action")
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.