Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Y
yd-csf
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xingmin
yd-csf
Commits
4bf8eaf1
Commit
4bf8eaf1
authored
Aug 03, 2026
by
jianan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
操作日志1
parent
dd86ab31
Show whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
1344 additions
and
8 deletions
+1344
-8
yd-csf-api/src/main/java/com/yd/csf/api/controller/AuditLogController.java
+75
-0
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditContext.java
+47
-0
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditContextHolder.java
+23
-0
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditHelper.java
+225
-0
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditService.java
+136
-0
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditTemplate.java
+72
-0
yd-csf-service/src/main/java/com/yd/csf/service/audit/FieldLabelResolver.java
+64
-0
yd-csf-service/src/main/java/com/yd/csf/service/component/CommissionAsyncService.java
+125
-3
yd-csf-service/src/main/java/com/yd/csf/service/dao/AuditLogDataChangeMapper.java
+15
-0
yd-csf-service/src/main/java/com/yd/csf/service/dao/AuditLogDataSnapshotMapper.java
+15
-0
yd-csf-service/src/main/java/com/yd/csf/service/dao/AuditLogMapper.java
+15
-0
yd-csf-service/src/main/java/com/yd/csf/service/model/Commission.java
+2
-0
yd-csf-service/src/main/java/com/yd/csf/service/model/CommissionExpected.java
+2
-0
yd-csf-service/src/main/java/com/yd/csf/service/model/ExpectedFortune.java
+2
-0
yd-csf-service/src/main/java/com/yd/csf/service/model/Fortune.java
+2
-0
yd-csf-service/src/main/java/com/yd/csf/service/model/SysOperDataChange.java
+72
-0
yd-csf-service/src/main/java/com/yd/csf/service/model/SysOperDataSnapshot.java
+52
-0
yd-csf-service/src/main/java/com/yd/csf/service/model/SysOperLog.java
+112
-0
yd-csf-service/src/main/java/com/yd/csf/service/service/AuditLogDataChangeService.java
+13
-0
yd-csf-service/src/main/java/com/yd/csf/service/service/AuditLogDataSnapshotService.java
+13
-0
yd-csf-service/src/main/java/com/yd/csf/service/service/AuditLogService.java
+13
-0
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/AuditLogDataChangeServiceImpl.java
+25
-0
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/AuditLogDataSnapshotServiceImpl.java
+25
-0
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/AuditLogServiceImpl.java
+25
-0
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/CommissionServiceImpl.java
+51
-5
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/FortuneServiceImpl.java
+39
-0
yd-csf-service/src/main/resources/mappers/AuditLogDataChangeMapper.xml
+26
-0
yd-csf-service/src/main/resources/mappers/AuditLogDataSnapshotMapper.xml
+22
-0
yd-csf-service/src/main/resources/mappers/AuditLogMapper.xml
+36
-0
No files found.
yd-csf-api/src/main/java/com/yd/csf/api/controller/AuditLogController.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
api
.
controller
;
import
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper
;
import
com.baomidou.mybatisplus.extension.plugins.pagination.Page
;
import
com.yd.common.result.Result
;
import
com.yd.csf.api.dto.AuditLogQueryRequest
;
import
com.yd.csf.service.model.SysOperDataChange
;
import
com.yd.csf.service.model.SysOperDataSnapshot
;
import
com.yd.csf.service.model.SysOperLog
;
import
com.yd.csf.service.service.AuditLogDataChangeService
;
import
com.yd.csf.service.service.AuditLogDataSnapshotService
;
import
com.yd.csf.service.service.AuditLogService
;
import
io.swagger.v3.oas.annotations.Operation
;
import
io.swagger.v3.oas.annotations.tags.Tag
;
import
lombok.RequiredArgsConstructor
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.web.bind.annotation.*
;
import
javax.annotation.Resource
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
@RestController
@RequestMapping
(
"/auditlog"
)
@Tag
(
name
=
"审计日志"
)
@RequiredArgsConstructor
public
class
AuditLogController
{
@Resource
private
AuditLogService
operLogService
;
@Resource
private
AuditLogDataSnapshotService
snapshotService
;
@Resource
private
AuditLogDataChangeService
changeService
;
@PostMapping
(
"/log/page"
)
@Operation
(
summary
=
"操作日志分页查询"
)
public
Result
<
Page
<
SysOperLog
>>
page
(
@RequestBody
AuditLogQueryRequest
request
)
{
LambdaQueryWrapper
<
SysOperLog
>
wrapper
=
new
LambdaQueryWrapper
<
SysOperLog
>()
.
eq
(
StringUtils
.
isNotBlank
(
request
.
getModule
()),
SysOperLog:
:
getModule
,
request
.
getModule
())
.
eq
(
StringUtils
.
isNotBlank
(
request
.
getOperName
()),
SysOperLog:
:
getOperName
,
request
.
getOperName
())
.
eq
(
request
.
getStatus
()
!=
null
,
SysOperLog:
:
getStatus
,
request
.
getStatus
())
.
ge
(
StringUtils
.
isNotBlank
(
request
.
getStartTime
()),
SysOperLog:
:
getOperTime
,
request
.
getStartTime
())
.
le
(
StringUtils
.
isNotBlank
(
request
.
getEndTime
()),
SysOperLog:
:
getOperTime
,
request
.
getEndTime
())
.
orderByDesc
(
SysOperLog:
:
getOperTime
);
Page
<
SysOperLog
>
page
=
operLogService
.
page
(
new
Page
<>(
request
.
getPageNo
(),
request
.
getPageSize
()),
wrapper
);
return
Result
.
success
(
page
);
}
@GetMapping
(
"/log/detail"
)
@Operation
(
summary
=
"审计详情查询"
)
public
Result
<
Map
<
String
,
Object
>>
detail
(
@RequestParam
String
requestId
)
{
if
(
StringUtils
.
isBlank
(
requestId
))
{
return
Result
.
success
(
null
);
}
SysOperLog
operLog
=
operLogService
.
getOne
(
new
LambdaQueryWrapper
<
SysOperLog
>().
eq
(
SysOperLog:
:
getRequestId
,
requestId
));
List
<
SysOperDataSnapshot
>
snapshots
=
snapshotService
.
list
(
new
LambdaQueryWrapper
<
SysOperDataSnapshot
>().
eq
(
SysOperDataSnapshot:
:
getRequestId
,
requestId
));
List
<
SysOperDataChange
>
changes
=
changeService
.
list
(
new
LambdaQueryWrapper
<
SysOperDataChange
>().
eq
(
SysOperDataChange:
:
getRequestId
,
requestId
));
Map
<
String
,
Object
>
result
=
new
HashMap
<>();
result
.
put
(
"operLog"
,
operLog
);
result
.
put
(
"snapshots"
,
snapshots
);
result
.
put
(
"changes"
,
changes
);
return
Result
.
success
(
result
);
}
}
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditContext.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
audit
;
import
lombok.Data
;
import
lombok.experimental.Accessors
;
import
java.util.Date
;
@Data
@Accessors
(
chain
=
true
)
public
class
AuditContext
{
private
String
requestId
;
private
String
module
;
private
Integer
businessType
;
private
String
method
;
private
String
content
;
private
Long
businessId
;
private
Integer
operationType
;
private
Long
userId
;
private
String
operName
;
private
String
deptName
;
private
String
operUrl
;
private
String
operIp
;
private
String
operLocation
;
private
String
operParam
;
private
String
jsonResult
;
private
Integer
status
;
private
String
errorMsg
;
private
Date
operTime
;
}
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditContextHolder.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
audit
;
public
class
AuditContextHolder
{
private
static
final
ThreadLocal
<
AuditContext
>
CONTEXT
=
new
ThreadLocal
<>();
public
static
void
set
(
AuditContext
context
)
{
CONTEXT
.
set
(
context
);
}
public
static
AuditContext
get
()
{
return
CONTEXT
.
get
();
}
public
static
String
getRequestId
()
{
AuditContext
ctx
=
CONTEXT
.
get
();
return
ctx
!=
null
?
ctx
.
getRequestId
()
:
null
;
}
public
static
void
clear
()
{
CONTEXT
.
remove
();
}
}
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditHelper.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
audit
;
import
cn.hutool.core.collection.CollUtil
;
import
com.google.gson.ExclusionStrategy
;
import
com.google.gson.FieldAttributes
;
import
com.google.gson.Gson
;
import
com.google.gson.GsonBuilder
;
import
com.yd.csf.service.annotation.Auditable
;
import
com.yd.csf.service.model.SysOperDataChange
;
import
com.yd.csf.service.model.SysOperDataSnapshot
;
import
com.yd.csf.service.service.AuditLogDataChangeService
;
import
com.yd.csf.service.service.AuditLogDataSnapshotService
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Component
;
import
java.lang.reflect.Field
;
import
java.util.*
;
@Slf4j
@Component
@RequiredArgsConstructor
public
class
AuditHelper
{
private
final
AuditLogDataSnapshotService
snapshotService
;
private
final
AuditLogDataChangeService
changeService
;
private
final
FieldLabelResolver
fieldLabelResolver
;
private
static
final
Set
<
String
>
EXCLUDED_FIELDS
=
new
HashSet
<>(
Arrays
.
asList
(
"id"
,
"createTime"
,
"updateTime"
,
"creatorId"
,
"creatorName"
,
"updaterId"
,
"updaterName"
,
"isDeleted"
,
"serialVersionUID"
));
private
static
final
Gson
GSON
=
new
GsonBuilder
()
.
addSerializationExclusionStrategy
(
new
ExclusionStrategy
()
{
@Override
public
boolean
shouldSkipField
(
FieldAttributes
f
)
{
return
EXCLUDED_FIELDS
.
contains
(
f
.
getName
());
}
@Override
public
boolean
shouldSkipClass
(
Class
<?>
clazz
)
{
return
false
;
}
})
.
create
();
/**
* 记录数据变更。
*
* @param tableName 表名
* @param beforeMap 变更前的数据,key 为主键值,value 为实体对象(INSERT 时为 null)
* @param afterMap 变更后的数据,key 为主键值,value 为实体对象(DELETE 时为 null)
* @param ctx 审计上下文
*/
public
void
record
(
String
tableName
,
Map
<
String
,
?>
beforeMap
,
Map
<
String
,
?>
afterMap
,
AuditContext
ctx
)
{
if
(
beforeMap
==
null
&&
afterMap
==
null
)
{
return
;
}
Class
<?>
entityClass
=
getEntityClass
(
beforeMap
,
afterMap
);
if
(
entityClass
==
null
)
{
log
.
warn
(
"无法确定实体类型,跳过审计记录: table={}"
,
tableName
);
return
;
}
Auditable
auditable
=
entityClass
.
getAnnotation
(
Auditable
.
class
);
if
(
auditable
==
null
)
{
throw
new
IllegalArgumentException
(
"实体类 "
+
entityClass
.
getName
()
+
" 缺少 @Auditable 注解"
);
}
List
<
Field
>
diffFields
=
getDiffFields
(
entityClass
);
Set
<
String
>
allIds
=
new
LinkedHashSet
<>();
if
(
beforeMap
!=
null
)
allIds
.
addAll
(
beforeMap
.
keySet
());
if
(
afterMap
!=
null
)
allIds
.
addAll
(
afterMap
.
keySet
());
List
<
SysOperDataSnapshot
>
snapshots
=
new
ArrayList
<>();
List
<
SysOperDataChange
>
changes
=
new
ArrayList
<>();
Date
now
=
new
Date
();
for
(
String
recordId
:
allIds
)
{
Object
before
=
beforeMap
!=
null
?
beforeMap
.
get
(
recordId
)
:
null
;
Object
after
=
afterMap
!=
null
?
afterMap
.
get
(
recordId
)
:
null
;
String
beforeJson
=
before
!=
null
?
GSON
.
toJson
(
before
)
:
null
;
String
afterJson
=
after
!=
null
?
GSON
.
toJson
(
after
)
:
null
;
boolean
isInsert
=
before
==
null
&&
after
!=
null
;
boolean
isDelete
=
before
!=
null
&&
after
==
null
;
String
changeType
=
isInsert
?
"ADD"
:
(
isDelete
?
"DELETE"
:
"MODIFY"
);
SysOperDataSnapshot
snapshot
=
new
SysOperDataSnapshot
();
snapshot
.
setRequestId
(
ctx
.
getRequestId
());
snapshot
.
setTableName
(
tableName
);
snapshot
.
setRecordId
(
recordId
);
snapshot
.
setBeforeJson
(
beforeJson
);
snapshot
.
setAfterJson
(
afterJson
);
snapshot
.
setCreateTime
(
now
);
snapshots
.
add
(
snapshot
);
if
(!
isInsert
&&
!
isDelete
&&
before
!=
null
&&
after
!=
null
)
{
for
(
Field
field
:
diffFields
)
{
try
{
field
.
setAccessible
(
true
);
Object
oldVal
=
field
.
get
(
before
);
Object
newVal
=
field
.
get
(
after
);
if
(!
Objects
.
equals
(
oldVal
,
newVal
))
{
SysOperDataChange
change
=
new
SysOperDataChange
();
change
.
setRequestId
(
ctx
.
getRequestId
());
change
.
setTableName
(
tableName
);
change
.
setRecordId
(
recordId
);
change
.
setFieldName
(
field
.
getName
());
change
.
setFieldComment
(
fieldLabelResolver
.
resolve
(
field
,
tableName
));
change
.
setOldValue
(
oldVal
!=
null
?
oldVal
.
toString
()
:
null
);
change
.
setNewValue
(
newVal
!=
null
?
newVal
.
toString
()
:
null
);
change
.
setChangeType
(
"MODIFY"
);
change
.
setCreateTime
(
now
);
changes
.
add
(
change
);
}
}
catch
(
IllegalAccessException
e
)
{
log
.
debug
(
"跳过无法访问的字段: {}"
,
field
.
getName
());
}
}
}
}
if
(
CollUtil
.
isNotEmpty
(
snapshots
))
{
snapshotService
.
saveBatch
(
snapshots
);
}
if
(
CollUtil
.
isNotEmpty
(
changes
))
{
changeService
.
saveBatch
(
changes
);
}
}
private
Class
<?>
getEntityClass
(
Map
<
String
,
?>
beforeMap
,
Map
<
String
,
?>
afterMap
)
{
if
(
beforeMap
!=
null
)
{
for
(
Object
v
:
beforeMap
.
values
())
{
if
(
v
!=
null
)
return
v
.
getClass
();
}
}
if
(
afterMap
!=
null
)
{
for
(
Object
v
:
afterMap
.
values
())
{
if
(
v
!=
null
)
return
v
.
getClass
();
}
}
return
null
;
}
private
List
<
Field
>
getDiffFields
(
Class
<?>
entityClass
)
{
List
<
Field
>
fields
=
new
ArrayList
<>();
Class
<?>
current
=
entityClass
;
while
(
current
!=
null
&&
current
!=
Object
.
class
)
{
for
(
Field
field
:
current
.
getDeclaredFields
())
{
if
(!
EXCLUDED_FIELDS
.
contains
(
field
.
getName
())
&&
!
java
.
lang
.
reflect
.
Modifier
.
isStatic
(
field
.
getModifiers
()))
{
fields
.
add
(
field
);
}
}
current
=
current
.
getSuperclass
();
}
return
fields
;
}
/**
* 对实体列表做深拷贝快照。
* 使用 Gson 序列化→反序列化做深拷贝,自动从 @Auditable.idField 读取 Map key。
*
* @param entities 实体列表,null 或空列表返回空 Map
* @param <T> 实体类型
* @return Map<业务ID, 深拷贝后的实体>
* @throws IllegalArgumentException 如果实体类缺少 @Auditable 注解
*/
@SuppressWarnings
(
"unchecked"
)
public
<
T
>
Map
<
String
,
T
>
snapshot
(
List
<
T
>
entities
)
{
if
(
CollUtil
.
isEmpty
(
entities
))
{
return
Collections
.
emptyMap
();
}
T
first
=
entities
.
get
(
0
);
if
(
first
==
null
)
{
return
Collections
.
emptyMap
();
}
Class
<?>
entityClass
=
first
.
getClass
();
Auditable
auditable
=
entityClass
.
getAnnotation
(
Auditable
.
class
);
if
(
auditable
==
null
)
{
throw
new
IllegalArgumentException
(
"实体类 "
+
entityClass
.
getName
()
+
" 缺少 @Auditable 注解"
);
}
String
idFieldName
=
auditable
.
idField
();
Map
<
String
,
T
>
result
=
new
LinkedHashMap
<>();
for
(
T
entity
:
entities
)
{
try
{
Field
idField
=
findField
(
entityClass
,
idFieldName
);
if
(
idField
==
null
)
{
throw
new
RuntimeException
(
"实体类 "
+
entityClass
.
getName
()
+
" 中没有字段: "
+
idFieldName
);
}
idField
.
setAccessible
(
true
);
Object
idValue
=
idField
.
get
(
entity
);
if
(
idValue
==
null
)
{
log
.
warn
(
"实体 idField={} 值为 null,跳过: {}"
,
idFieldName
,
entity
);
continue
;
}
T
copy
=
(
T
)
GSON
.
fromJson
(
GSON
.
toJson
(
entity
),
entityClass
);
result
.
put
(
idValue
.
toString
(),
copy
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
"无法读取字段 "
+
idFieldName
,
e
);
}
}
return
result
;
}
private
Field
findField
(
Class
<?>
clazz
,
String
fieldName
)
{
Class
<?>
current
=
clazz
;
while
(
current
!=
null
&&
current
!=
Object
.
class
)
{
try
{
return
current
.
getDeclaredField
(
fieldName
);
}
catch
(
NoSuchFieldException
e
)
{
current
=
current
.
getSuperclass
();
}
}
return
null
;
}
}
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditService.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
audit
;
import
com.yd.auth.core.dto.AuthUserDto
;
import
com.yd.auth.core.utils.SecurityUtil
;
import
com.yd.csf.service.model.SysOperLog
;
import
com.yd.csf.service.service.AuditLogService
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Component
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.Date
;
import
java.util.UUID
;
@Slf4j
@Component
@RequiredArgsConstructor
public
class
AuditService
{
private
final
AuditLogService
operLogService
;
/**
* 开始审计,创建新的审计上下文。
*
* @param module 业务模块
* @param businessType 业务类型
* @param content 操作描述
* @return requestId
*/
public
String
begin
(
String
module
,
Integer
businessType
,
String
content
)
{
String
requestId
=
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
);
AuditContext
ctx
=
new
AuditContext
();
ctx
.
setRequestId
(
requestId
);
ctx
.
setModule
(
module
);
ctx
.
setBusinessType
(
businessType
);
ctx
.
setContent
(
content
);
ctx
.
setOperTime
(
new
Date
());
fillRequestInfo
(
ctx
);
fillOperatorInfo
(
ctx
);
AuditContextHolder
.
set
(
ctx
);
return
requestId
;
}
/**
* 使用已有 requestId 恢复审计上下文(用于异步回调)。
*/
public
void
begin
(
String
requestId
)
{
AuditContext
ctx
=
new
AuditContext
();
ctx
.
setRequestId
(
requestId
);
ctx
.
setOperTime
(
new
Date
());
AuditContextHolder
.
set
(
ctx
);
}
/**
* 标记操作成功,写入 sys_oper_log。
*/
public
void
success
(
String
requestId
)
{
AuditContext
ctx
=
AuditContextHolder
.
get
();
if
(
ctx
==
null
)
{
return
;
}
SysOperLog
log
=
buildOperLog
(
ctx
);
log
.
setStatus
(
0
);
operLogService
.
save
(
log
);
}
/**
* 标记操作失败,写入 sys_oper_log。
*/
public
void
fail
(
String
requestId
,
String
errorMsg
)
{
AuditContext
ctx
=
AuditContextHolder
.
get
();
if
(
ctx
==
null
)
{
return
;
}
SysOperLog
log
=
buildOperLog
(
ctx
);
log
.
setStatus
(
1
);
log
.
setErrorMsg
(
errorMsg
);
operLogService
.
save
(
log
);
}
/**
* 关闭审计,清理 ThreadLocal。
*/
public
void
close
(
String
requestId
)
{
AuditContextHolder
.
clear
();
}
private
void
fillRequestInfo
(
AuditContext
ctx
)
{
try
{
ServletRequestAttributes
attrs
=
(
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
();
if
(
attrs
!=
null
)
{
HttpServletRequest
request
=
attrs
.
getRequest
();
ctx
.
setOperUrl
(
request
.
getRequestURI
());
ctx
.
setOperIp
(
request
.
getRemoteAddr
());
}
}
catch
(
Exception
e
)
{
log
.
debug
(
"获取请求信息失败: {}"
,
e
.
getMessage
());
}
}
private
void
fillOperatorInfo
(
AuditContext
ctx
)
{
try
{
AuthUserDto
user
=
SecurityUtil
.
getCurrentLoginUser
();
ctx
.
setUserId
(
user
.
getId
());
ctx
.
setOperName
(
user
.
getUsername
());
}
catch
(
Exception
e
)
{
log
.
debug
(
"获取操作人信息失败: {}"
,
e
.
getMessage
());
}
}
private
SysOperLog
buildOperLog
(
AuditContext
ctx
)
{
SysOperLog
log
=
new
SysOperLog
();
log
.
setRequestId
(
ctx
.
getRequestId
());
log
.
setModule
(
ctx
.
getModule
());
log
.
setBusinessType
(
ctx
.
getBusinessType
());
log
.
setMethod
(
ctx
.
getMethod
());
log
.
setContent
(
ctx
.
getContent
());
log
.
setBusinessId
(
ctx
.
getBusinessId
());
log
.
setOperationType
(
ctx
.
getOperationType
());
log
.
setUserId
(
ctx
.
getUserId
());
log
.
setOperName
(
ctx
.
getOperName
());
log
.
setDeptName
(
ctx
.
getDeptName
());
log
.
setOperUrl
(
ctx
.
getOperUrl
());
log
.
setOperIp
(
ctx
.
getOperIp
());
log
.
setOperLocation
(
ctx
.
getOperLocation
());
log
.
setOperParam
(
ctx
.
getOperParam
());
log
.
setJsonResult
(
ctx
.
getJsonResult
());
log
.
setOperTime
(
ctx
.
getOperTime
());
return
log
;
}
}
yd-csf-service/src/main/java/com/yd/csf/service/audit/AuditTemplate.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
audit
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.stereotype.Component
;
/**
* 审计生命周期编排器。
* 封装 begin → action → success/fail → close 的固定模板,调用方只需编写业务逻辑。
*
* <pre>{@code
* // INSERT 场景
* return auditTemplate.execute("来佣管理", 1, "导入入账记录", ctx -> {
* saveBatch(list);
* auditHelper.record("commission", null, toMap(list), ctx);
* return true;
* });
*
* // UPDATE 场景
* return auditTemplate.execute("应付款管理", 2, "生成可出账", ctx -> {
* Map<String, ExpectedFortune> before = auditHelper.snapshot(list);
* // ... 业务变更 ...
* Map<String, ExpectedFortune> after = auditHelper.snapshot(list);
* auditHelper.record("expected_fortune", before, after, ctx);
* return true;
* });
* }</pre>
*
* @author Zhang Jianan
*/
@Component
@RequiredArgsConstructor
public
class
AuditTemplate
{
private
final
AuditService
auditService
;
/**
* 执行带审计的操作。
* 自动处理 begin → success → close(正常路径)或 begin → fail → close(异常路径)。
* 异常会原样重新抛出,不改变异常传播链。
*
* @param module 业务模块名称
* @param businessType 业务类型
* @param content 操作描述
* @param action 业务逻辑,接收 AuditContext,返回结果
* @param <T> 返回值类型
* @return action 的返回值
*/
public
<
T
>
T
execute
(
String
module
,
Integer
businessType
,
String
content
,
AuditAction
<
T
>
action
)
{
String
requestId
=
auditService
.
begin
(
module
,
businessType
,
content
);
try
{
T
result
=
action
.
apply
(
AuditContextHolder
.
get
());
auditService
.
success
(
requestId
);
return
result
;
}
catch
(
Exception
e
)
{
auditService
.
fail
(
requestId
,
e
.
getMessage
());
throw
(
RuntimeException
)
e
;
}
finally
{
auditService
.
close
(
requestId
);
}
}
/**
* 审计操作函数式接口。
*
* @param <T> 返回值类型
*/
@FunctionalInterface
public
interface
AuditAction
<
T
>
{
T
apply
(
AuditContext
ctx
);
}
}
yd-csf-service/src/main/java/com/yd/csf/service/audit/FieldLabelResolver.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
audit
;
import
com.yd.csf.service.annotation.AuditField
;
import
lombok.RequiredArgsConstructor
;
import
org.springframework.jdbc.core.JdbcTemplate
;
import
org.springframework.stereotype.Component
;
import
java.lang.reflect.Field
;
import
java.util.Arrays
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
@Component
@RequiredArgsConstructor
public
class
FieldLabelResolver
{
private
final
JdbcTemplate
jdbcTemplate
;
private
final
Map
<
String
,
String
>
cache
=
new
ConcurrentHashMap
<>();
private
static
final
String
SQL
=
"SELECT COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?"
;
/**
* 获取字段中文名,优先级:
* 1. @AuditField.label
* 2. information_schema.COLUMNS.COLUMN_COMMENT
* 3. field 名本身
*/
public
String
resolve
(
Field
field
,
String
tableName
)
{
AuditField
auditField
=
field
.
getAnnotation
(
AuditField
.
class
);
if
(
auditField
!=
null
&&
!
auditField
.
label
().
isEmpty
())
{
return
auditField
.
label
();
}
String
columnName
=
camelToUnderscore
(
field
.
getName
());
String
cacheKey
=
tableName
+
"."
+
columnName
;
String
comment
=
cache
.
computeIfAbsent
(
cacheKey
,
k
->
{
try
{
return
jdbcTemplate
.
queryForObject
(
SQL
,
String
.
class
,
tableName
,
columnName
);
}
catch
(
Exception
e
)
{
return
null
;
}
});
if
(
comment
!=
null
&&
!
comment
.
isEmpty
())
{
return
comment
;
}
return
field
.
getName
();
}
private
String
camelToUnderscore
(
String
camel
)
{
StringBuilder
sb
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
camel
.
length
();
i
++)
{
char
c
=
camel
.
charAt
(
i
);
if
(
Character
.
isUpperCase
(
c
))
{
sb
.
append
(
'_'
).
append
(
Character
.
toLowerCase
(
c
));
}
else
{
sb
.
append
(
c
);
}
}
return
sb
.
toString
();
}
}
yd-csf-service/src/main/java/com/yd/csf/service/component/CommissionAsyncService.java
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
component
;
import
cn.hutool.core.collection.CollUtil
;
import
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
;
import
com.yd.auth.core.dto.AuthUserDto
;
import
com.yd.auth.core.utils.SecurityUtil
;
import
com.yd.common.enums.ResultCode
;
import
com.yd.common.exception.BusinessException
;
import
com.yd.csf.service.audit.AuditContextHolder
;
import
com.yd.csf.service.audit.AuditHelper
;
import
com.yd.csf.service.audit.AuditService
;
import
com.yd.csf.service.enums.CommissionExpectedStatusEnum
;
import
com.yd.csf.service.enums.CommissionStatusEnum
;
import
com.yd.csf.service.model.Commission
;
...
...
@@ -24,9 +28,7 @@ import org.springframework.transaction.annotation.Transactional;
import
javax.annotation.Resource
;
import
java.math.BigDecimal
;
import
java.math.RoundingMode
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.*
;
import
java.util.function.Function
;
import
java.util.stream.Collectors
;
...
...
@@ -39,10 +41,24 @@ public class CommissionAsyncService {
private
CommissionService
commissionService
;
@Resource
private
CommissionCompareRecordService
commissionCompareRecordService
;
@Resource
private
AuditService
auditService
;
@Resource
private
AuditHelper
auditHelper
;
// @Async("commonAsyncExecutor")
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
public
void
commissionCompareBatch
(
List
<
Commission
>
entities
)
{
// 保留旧签名兼容(无审计)
commissionCompareBatch
(
entities
,
null
);
}
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
public
void
commissionCompareBatch
(
List
<
Commission
>
entities
,
String
requestId
)
{
if
(
requestId
!=
null
)
{
auditService
.
begin
(
requestId
);
}
try
{
// 根据是否关联保单号,来区分比对方式
List
<
Commission
>
hasPolicyNoList
=
new
ArrayList
<>();
List
<
Commission
>
noPolicyNoList
=
new
ArrayList
<>();
...
...
@@ -53,12 +69,118 @@ public class CommissionAsyncService {
hasPolicyNoList
.
add
(
entity
);
}
}
// 审计:收集将被修改的记录ID,拍快照
Set
<
String
>
commissionBizIds
=
new
HashSet
<>();
Set
<
String
>
expectedBizIds
=
new
HashSet
<>();
collectAffectedIds
(
hasPolicyNoList
,
noPolicyNoList
,
commissionBizIds
,
expectedBizIds
);
Map
<
String
,
Commission
>
commissionBefore
=
queryCommissionsByBizIds
(
commissionBizIds
);
Map
<
String
,
CommissionExpected
>
expectedBefore
=
queryExpectedByBizIds
(
expectedBizIds
);
// 执行比对
if
(
CollectionUtils
.
isNotEmpty
(
hasPolicyNoList
))
{
normalBatch
(
hasPolicyNoList
);
}
if
(
CollectionUtils
.
isNotEmpty
(
noPolicyNoList
))
{
noPolicyNoBatch
(
noPolicyNoList
);
}
// 审计:记录变更(不写 oper_log,主事务已写)
if
(
requestId
!=
null
)
{
Map
<
String
,
Commission
>
commissionAfter
=
queryCommissionsByBizIds
(
commissionBizIds
);
Map
<
String
,
CommissionExpected
>
expectedAfter
=
queryExpectedByBizIds
(
expectedBizIds
);
if
(
CollUtil
.
isNotEmpty
(
commissionBefore
)
&&
CollUtil
.
isNotEmpty
(
commissionAfter
))
{
auditHelper
.
record
(
"commission"
,
commissionBefore
,
commissionAfter
,
AuditContextHolder
.
get
());
}
if
(
CollUtil
.
isNotEmpty
(
expectedBefore
)
&&
CollUtil
.
isNotEmpty
(
expectedAfter
))
{
auditHelper
.
record
(
"commission_expected"
,
expectedBefore
,
expectedAfter
,
AuditContextHolder
.
get
());
}
}
}
catch
(
Exception
e
)
{
throw
e
;
}
finally
{
if
(
requestId
!=
null
)
{
auditService
.
close
(
requestId
);
}
}
}
/**
* 收集比对过程中会被修改的 commission 和 commission_expected 记录ID。
*/
private
void
collectAffectedIds
(
List
<
Commission
>
hasPolicyNoList
,
List
<
Commission
>
noPolicyNoList
,
Set
<
String
>
commissionBizIds
,
Set
<
String
>
expectedBizIds
)
{
// 新插入的 commission
for
(
Commission
entity
:
hasPolicyNoList
)
{
if
(
entity
.
getCommissionBizId
()
!=
null
)
{
commissionBizIds
.
add
(
entity
.
getCommissionBizId
());
}
}
for
(
Commission
entity
:
noPolicyNoList
)
{
if
(
entity
.
getCommissionBizId
()
!=
null
)
{
commissionBizIds
.
add
(
entity
.
getCommissionBizId
());
}
}
// normalBatch: 查询同一 expectedBizId 下的所有已存在 commission
if
(
CollectionUtils
.
isNotEmpty
(
hasPolicyNoList
))
{
List
<
String
>
commissionExpectedBizIdList
=
hasPolicyNoList
.
stream
()
.
map
(
Commission:
:
getCommissionExpectedBizId
)
.
filter
(
StringUtils:
:
isNotBlank
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
if
(
CollectionUtils
.
isNotEmpty
(
commissionExpectedBizIdList
))
{
List
<
Commission
>
existing
=
commissionService
.
lambdaQuery
()
.
in
(
Commission:
:
getCommissionExpectedBizId
,
commissionExpectedBizIdList
)
.
list
();
existing
.
forEach
(
c
->
{
if
(
c
.
getCommissionBizId
()
!=
null
)
{
commissionBizIds
.
add
(
c
.
getCommissionBizId
());
}
});
expectedBizIds
.
addAll
(
commissionExpectedBizIdList
);
}
}
// noPolicyNoBatch: 查询同一 receivableNo 的 commissionExpected
if
(
CollectionUtils
.
isNotEmpty
(
noPolicyNoList
))
{
List
<
String
>
receivableNoList
=
noPolicyNoList
.
stream
()
.
map
(
Commission:
:
getReceivableNo
)
.
filter
(
StringUtils:
:
isNotBlank
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
if
(
CollectionUtils
.
isNotEmpty
(
receivableNoList
))
{
List
<
CommissionExpected
>
expectedList
=
commissionExpectedService
.
lambdaQuery
()
.
in
(
CommissionExpected:
:
getReceivableNo
,
receivableNoList
)
.
list
();
expectedList
.
forEach
(
e
->
{
if
(
e
.
getCommissionExpectedBizId
()
!=
null
)
{
expectedBizIds
.
add
(
e
.
getCommissionExpectedBizId
());
}
});
}
}
}
private
Map
<
String
,
Commission
>
queryCommissionsByBizIds
(
Set
<
String
>
bizIds
)
{
if
(
CollectionUtils
.
isEmpty
(
bizIds
))
{
return
Collections
.
emptyMap
();
}
List
<
Commission
>
list
=
commissionService
.
lambdaQuery
()
.
in
(
Commission:
:
getCommissionBizId
,
new
ArrayList
<>(
bizIds
))
.
list
();
return
list
.
stream
().
collect
(
Collectors
.
toMap
(
Commission:
:
getCommissionBizId
,
Function
.
identity
()));
}
private
Map
<
String
,
CommissionExpected
>
queryExpectedByBizIds
(
Set
<
String
>
bizIds
)
{
if
(
CollectionUtils
.
isEmpty
(
bizIds
))
{
return
Collections
.
emptyMap
();
}
List
<
CommissionExpected
>
list
=
commissionExpectedService
.
lambdaQuery
()
.
in
(
CommissionExpected:
:
getCommissionExpectedBizId
,
new
ArrayList
<>(
bizIds
))
.
list
();
return
list
.
stream
().
collect
(
Collectors
.
toMap
(
CommissionExpected:
:
getCommissionExpectedBizId
,
Function
.
identity
()));
}
/**
...
...
yd-csf-service/src/main/java/com/yd/csf/service/dao/AuditLogDataChangeMapper.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
dao
;
import
com.yd.csf.service.model.SysOperDataChange
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_data_change】的数据库操作Mapper
* @createDate 2026-07-30 14:46:28
* @Entity generator.domain.SysOperDataChange
*/
public
interface
AuditLogDataChangeMapper
extends
BaseMapper
<
SysOperDataChange
>
{
}
\ No newline at end of file
yd-csf-service/src/main/java/com/yd/csf/service/dao/AuditLogDataSnapshotMapper.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
dao
;
import
com.yd.csf.service.model.SysOperDataSnapshot
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_data_snapshot】的数据库操作Mapper
* @createDate 2026-07-30 14:46:24
* @Entity generator.domain.SysOperDataSnapshot
*/
public
interface
AuditLogDataSnapshotMapper
extends
BaseMapper
<
SysOperDataSnapshot
>
{
}
\ No newline at end of file
yd-csf-service/src/main/java/com/yd/csf/service/dao/AuditLogMapper.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
dao
;
import
com.yd.csf.service.model.SysOperLog
;
import
com.baomidou.mybatisplus.core.mapper.BaseMapper
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_log】的数据库操作Mapper
* @createDate 2026-07-30 14:45:38
* @Entity generator.domain.SysOperLog
*/
public
interface
AuditLogMapper
extends
BaseMapper
<
SysOperLog
>
{
}
\ No newline at end of file
yd-csf-service/src/main/java/com/yd/csf/service/model/Commission.java
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
model
;
import
com.baomidou.mybatisplus.annotation.*
;
import
com.yd.csf.service.annotation.Auditable
;
import
lombok.Data
;
import
java.io.Serializable
;
...
...
@@ -13,6 +14,7 @@ import java.util.Date;
* @TableName commission
*/
@TableName
(
value
=
"commission"
)
@Auditable
(
table
=
"commission"
,
idField
=
"commissionBizId"
)
@Data
public
class
Commission
implements
Serializable
{
/**
...
...
yd-csf-service/src/main/java/com/yd/csf/service/model/CommissionExpected.java
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
model
;
import
com.baomidou.mybatisplus.annotation.*
;
import
com.yd.csf.service.annotation.Auditable
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Data
;
...
...
@@ -14,6 +15,7 @@ import java.util.Date;
* @TableName commission_expected
*/
@TableName
(
value
=
"commission_expected"
)
@Auditable
(
table
=
"commission_expected"
,
idField
=
"commissionExpectedBizId"
)
@Data
public
class
CommissionExpected
implements
Serializable
{
/**
...
...
yd-csf-service/src/main/java/com/yd/csf/service/model/ExpectedFortune.java
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
model
;
import
com.baomidou.mybatisplus.annotation.*
;
import
com.yd.csf.service.annotation.Auditable
;
import
lombok.Getter
;
import
lombok.Setter
;
...
...
@@ -20,6 +21,7 @@ import java.time.LocalDateTime;
@Getter
@Setter
@TableName
(
"expected_fortune"
)
@Auditable
(
table
=
"expected_fortune"
,
idField
=
"expectedFortuneBizId"
)
public
class
ExpectedFortune
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L
;
...
...
yd-csf-service/src/main/java/com/yd/csf/service/model/Fortune.java
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
model
;
import
com.baomidou.mybatisplus.annotation.*
;
import
com.yd.csf.service.annotation.Auditable
;
import
java.math.BigDecimal
;
import
java.time.LocalDate
;
...
...
@@ -14,6 +15,7 @@ import lombok.Data;
* @TableName fortune
*/
@TableName
(
value
=
"fortune"
)
@Auditable
(
table
=
"fortune"
,
idField
=
"fortuneBizId"
)
@Data
public
class
Fortune
{
/**
...
...
yd-csf-service/src/main/java/com/yd/csf/service/model/SysOperDataChange.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
model
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
java.util.Date
;
import
lombok.Data
;
/**
*
* @TableName sys_oper_data_change
*/
@TableName
(
value
=
"sys_oper_data_change"
)
@Data
public
class
SysOperDataChange
{
/**
*
*/
@TableId
(
type
=
IdType
.
AUTO
)
private
Long
id
;
/**
*
*/
private
String
requestId
;
/**
* 关联 sys_oper_log.id(MP拦截器路径不设置,由request_id关联)
*/
private
Long
operLogId
;
/**
* 表名
*/
private
String
tableName
;
/**
* 记录主键
*/
private
String
recordId
;
/**
* 字段名
*/
private
String
fieldName
;
/**
* 字段中文名
*/
private
String
fieldComment
;
/**
* 变更前值
*/
private
String
oldValue
;
/**
* 变更后值
*/
private
String
newValue
;
/**
* ADD/MODIFY/DELETE
*/
private
String
changeType
;
/**
*
*/
private
Date
createTime
;
}
\ No newline at end of file
yd-csf-service/src/main/java/com/yd/csf/service/model/SysOperDataSnapshot.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
model
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
java.util.Date
;
import
lombok.Data
;
/**
*
* @TableName sys_oper_data_snapshot
*/
@TableName
(
value
=
"sys_oper_data_snapshot"
)
@Data
public
class
SysOperDataSnapshot
{
/**
*
*/
@TableId
(
type
=
IdType
.
AUTO
)
private
Long
id
;
/**
*
*/
private
String
requestId
;
/**
* 表名
*/
private
String
tableName
;
/**
* 记录主键
*/
private
String
recordId
;
/**
* 变更前完整快照
*/
private
String
beforeJson
;
/**
* 变更后完整快照
*/
private
String
afterJson
;
/**
*
*/
private
Date
createTime
;
}
\ No newline at end of file
yd-csf-service/src/main/java/com/yd/csf/service/model/SysOperLog.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
model
;
import
com.baomidou.mybatisplus.annotation.IdType
;
import
com.baomidou.mybatisplus.annotation.TableId
;
import
com.baomidou.mybatisplus.annotation.TableName
;
import
java.util.Date
;
import
lombok.Data
;
/**
*
* @TableName sys_oper_log
*/
@TableName
(
value
=
"sys_oper_log"
)
@Data
public
class
SysOperLog
{
/**
* 日志主键
*/
@TableId
(
type
=
IdType
.
AUTO
)
private
Long
id
;
/**
*
*/
private
String
requestId
;
/**
* 业务模块
*/
private
String
module
;
/**
* 业务类型 0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据
*/
private
Integer
businessType
;
/**
* 方法名称
*/
private
String
method
;
/**
* 日志内容
*/
private
String
content
;
/**
* 业务数据ID
*/
private
Long
businessId
;
/**
* 操作类型(0其它 1新增 2修改 3删除)
*/
private
Integer
operationType
;
/**
* 操作人ID
*/
private
Long
userId
;
/**
* 操作人员
*/
private
String
operName
;
/**
* 部门名称
*/
private
String
deptName
;
/**
* 请求URL
*/
private
String
operUrl
;
/**
* 主机地址
*/
private
String
operIp
;
/**
* 操作地点
*/
private
String
operLocation
;
/**
* 请求参数
*/
private
String
operParam
;
/**
* 返回参数
*/
private
String
jsonResult
;
/**
* 0成功 1失败
*/
private
Integer
status
;
/**
* 错误消息
*/
private
String
errorMsg
;
/**
* 操作时间
*/
private
Date
operTime
;
}
\ No newline at end of file
yd-csf-service/src/main/java/com/yd/csf/service/service/AuditLogDataChangeService.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
service
;
import
com.yd.csf.service.model.SysOperDataChange
;
import
com.baomidou.mybatisplus.extension.service.IService
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_data_change】的数据库操作Service
* @createDate 2026-07-30 14:46:28
*/
public
interface
AuditLogDataChangeService
extends
IService
<
SysOperDataChange
>
{
}
yd-csf-service/src/main/java/com/yd/csf/service/service/AuditLogDataSnapshotService.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
service
;
import
com.yd.csf.service.model.SysOperDataSnapshot
;
import
com.baomidou.mybatisplus.extension.service.IService
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_data_snapshot】的数据库操作Service
* @createDate 2026-07-30 14:46:24
*/
public
interface
AuditLogDataSnapshotService
extends
IService
<
SysOperDataSnapshot
>
{
}
yd-csf-service/src/main/java/com/yd/csf/service/service/AuditLogService.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
service
;
import
com.yd.csf.service.model.SysOperLog
;
import
com.baomidou.mybatisplus.extension.service.IService
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_log】的数据库操作Service
* @createDate 2026-07-30 14:45:38
*/
public
interface
AuditLogService
extends
IService
<
SysOperLog
>
{
}
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/AuditLogDataChangeServiceImpl.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
service
.
impl
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.yd.csf.service.model.SysOperDataChange
;
import
com.yd.csf.service.service.AuditLogDataChangeService
;
import
com.yd.csf.service.dao.AuditLogDataChangeMapper
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_data_change】的数据库操作Service实现
* @createDate 2026-07-30 14:46:28
*/
@Service
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
public
class
AuditLogDataChangeServiceImpl
extends
ServiceImpl
<
AuditLogDataChangeMapper
,
SysOperDataChange
>
implements
AuditLogDataChangeService
{
}
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/AuditLogDataSnapshotServiceImpl.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
service
.
impl
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.yd.csf.service.model.SysOperDataSnapshot
;
import
com.yd.csf.service.service.AuditLogDataSnapshotService
;
import
com.yd.csf.service.dao.AuditLogDataSnapshotMapper
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_data_snapshot】的数据库操作Service实现
* @createDate 2026-07-30 14:46:24
*/
@Service
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
public
class
AuditLogDataSnapshotServiceImpl
extends
ServiceImpl
<
AuditLogDataSnapshotMapper
,
SysOperDataSnapshot
>
implements
AuditLogDataSnapshotService
{
}
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/AuditLogServiceImpl.java
0 → 100644
View file @
4bf8eaf1
package
com
.
yd
.
csf
.
service
.
service
.
impl
;
import
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl
;
import
com.yd.csf.service.model.SysOperLog
;
import
com.yd.csf.service.service.AuditLogService
;
import
com.yd.csf.service.dao.AuditLogMapper
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Propagation
;
import
org.springframework.transaction.annotation.Transactional
;
/**
* @author Zhang Jianan
* @description 针对表【sys_oper_log】的数据库操作Service实现
* @createDate 2026-07-30 14:45:38
*/
@Service
@Transactional
(
propagation
=
Propagation
.
REQUIRES_NEW
)
public
class
AuditLogServiceImpl
extends
ServiceImpl
<
AuditLogMapper
,
SysOperLog
>
implements
AuditLogService
{
}
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/CommissionServiceImpl.java
View file @
4bf8eaf1
...
...
@@ -24,6 +24,10 @@ import com.yd.csf.service.enums.CommissionStatusEnum;
import
com.yd.csf.service.enums.FortuneStatusEnum
;
import
com.yd.csf.service.model.*
;
import
com.yd.csf.service.service.*
;
import
com.yd.csf.service.audit.AuditContextHolder
;
import
com.yd.csf.service.audit.AuditHelper
;
import
com.yd.csf.service.audit.AuditService
;
import
com.yd.csf.service.audit.AuditTemplate
;
import
com.yd.csf.service.dao.CommissionMapper
;
import
com.yd.csf.service.vo.CommissionStatisticsVO
;
import
com.yd.csf.service.vo.CommissionVO
;
...
...
@@ -85,6 +89,12 @@ public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commiss
private
ApiInsuranceReconciliationCompanyFeignClient
apiInsuranceReconciliationCompanyFeignClient
;
@Resource
private
PolicyPolicyholderService
policyPolicyholderService
;
@Resource
private
AuditService
auditService
;
@Resource
private
AuditHelper
auditHelper
;
@Resource
private
AuditTemplate
auditTemplate
;
@Override
...
...
@@ -608,6 +618,7 @@ public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commiss
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
Boolean
generateFortune
(
GenerateFortuneRequest
generateFortuneRequest
)
{
return
auditTemplate
.
execute
(
"应付款管理"
,
2
,
"生成可出账记录"
,
ctx
->
{
List
<
String
>
commissionBizIdList
=
generateFortuneRequest
.
getCommissionBizIdList
();
List
<
Commission
>
commissions
=
this
.
lambdaQuery
().
in
(
Commission:
:
getCommissionBizId
,
commissionBizIdList
).
list
();
...
...
@@ -708,13 +719,40 @@ public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commiss
// 2.5 根据保单号、期数查询入账检核汇率
Map
<
String
,
BigDecimal
>
exchangeRateMap
=
this
.
queryCommissionExchangeRateMap
(
commissions
);
// 审计:深拷贝预计发佣记录变更前快照
Map
<
String
,
ExpectedFortune
>
beforeExpectedFortuneMap
=
auditHelper
.
snapshot
(
filteredExpectedFortuneList2
);
// 3. 构建实际的初始发佣记录(使用入账检核汇率)
List
<
Fortune
>
newFortuneList
=
buildNewFortunes
(
filteredExpectedFortuneList2
,
commissions
,
exchangeRateMap
,
reconciliationYearMonth
);
// 4. 保存发佣记录
saveNewFortunes
(
newFortuneList
);
// 审计:fortune DELETE
if
(
CollUtil
.
isNotEmpty
(
deleteList
))
{
Map
<
String
,
Fortune
>
deleteMap
=
deleteList
.
stream
()
.
collect
(
Collectors
.
toMap
(
Fortune:
:
getFortuneBizId
,
Function
.
identity
()));
auditHelper
.
record
(
"fortune"
,
deleteMap
,
null
,
ctx
);
}
// 审计:fortune INSERT
Map
<
String
,
Fortune
>
insertMap
=
newFortuneList
.
stream
()
.
collect
(
Collectors
.
toMap
(
Fortune:
:
getFortuneBizId
,
Function
.
identity
()));
auditHelper
.
record
(
"fortune"
,
null
,
insertMap
,
ctx
);
// 审计:expected_fortune UPDATE(重新查询 after 状态后 diff)
List
<
String
>
efBizIds
=
new
ArrayList
<>(
beforeExpectedFortuneMap
.
keySet
());
if
(
CollUtil
.
isNotEmpty
(
efBizIds
))
{
Map
<
String
,
ExpectedFortune
>
afterExpectedFortuneMap
=
iExpectedFortuneService
.
lambdaQuery
()
.
in
(
ExpectedFortune:
:
getExpectedFortuneBizId
,
efBizIds
)
.
list
().
stream
()
.
collect
(
Collectors
.
toMap
(
ExpectedFortune:
:
getExpectedFortuneBizId
,
Function
.
identity
()));
auditHelper
.
record
(
"expected_fortune"
,
beforeExpectedFortuneMap
,
afterExpectedFortuneMap
,
ctx
);
}
return
true
;
});
}
private
Map
<
String
,
BigDecimal
>
queryCommissionExchangeRateMap
(
List
<
Commission
>
commissions
)
{
...
...
@@ -991,6 +1029,8 @@ public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commiss
if
(
CollectionUtils
.
isEmpty
(
customerAddRequestList
))
{
throw
new
BusinessException
(
ResultCode
.
PARAMS_ERROR
.
getCode
(),
"入账数据不能为空"
);
}
return
auditTemplate
.
execute
(
"来佣管理"
,
1
,
"导入入账记录"
,
ctx
->
{
validateAddCommissionBatch
(
customerAddRequestList
);
Set
<
String
>
policyNoSet
=
customerAddRequestList
.
stream
()
...
...
@@ -1057,23 +1097,29 @@ public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commiss
// 1. 先保存主数据
saveOrUpdateBatch
(
commissionList
);
// 审计:commission INSERT
if
(
CollUtil
.
isNotEmpty
(
commissionList
))
{
Map
<
String
,
Commission
>
insertMap
=
commissionList
.
stream
()
.
collect
(
Collectors
.
toMap
(
Commission:
:
getCommissionBizId
,
Function
.
identity
()));
auditHelper
.
record
(
"commission"
,
null
,
insertMap
,
ctx
);
}
// 2. 事务提交后执行比对
TransactionSynchronizationManager
.
registerSynchronization
(
new
TransactionSynchronization
()
{
@Override
public
void
afterCommit
()
{
try
{
// 这里会开启新事务执行更新
commissionAsyncService
.
commissionCompareBatch
(
commissionList
);
commissionAsyncService
.
commissionCompareBatch
(
commissionList
,
ctx
.
getRequestId
());
}
catch
(
Exception
e
)
{
log
.
error
(
"比对更新失败"
,
e
);
// 可以发送告警或记录失败任务
}
}
}
);
return
commissionList
;
});
}
private
CommissionExpected
getCommissionExpectedBizIdBatch
(
CommissionAddRequest
request
,
Set
<
String
>
policyNoSet
,
Commission
commission
)
{
...
...
@@ -1311,8 +1357,8 @@ public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commiss
@Override
public
Long
queryCount
(
String
commissionExpectedBizId
)
{
return
this
.
baseMapper
.
selectCount
(
new
LambdaQueryWrapper
<
Commission
>()
.
eq
(
Commission:
:
getCommissionExpectedBizId
,
commissionExpectedBizId
)
.
eq
(
Commission:
:
getIsDeleted
,
0
)
.
eq
(
Commission:
:
getCommissionExpectedBizId
,
commissionExpectedBizId
)
.
eq
(
Commission:
:
getIsDeleted
,
0
)
);
}
...
...
yd-csf-service/src/main/java/com/yd/csf/service/service/impl/FortuneServiceImpl.java
View file @
4bf8eaf1
...
...
@@ -18,6 +18,11 @@ import com.yd.common.exception.BusinessException;
import
com.yd.common.result.Result
;
import
com.yd.common.utils.RandomStringGenerator
;
import
com.yd.common.utils.RedisUtil
;
import
com.yd.csf.service.audit.AuditContextHolder
;
import
com.yd.csf.service.audit.AuditHelper
;
import
com.yd.csf.service.audit.AuditService
;
import
com.yd.csf.service.audit.AuditTemplate
;
import
com.yd.csf.service.audit.AuditContext
;
import
com.yd.csf.service.dto.*
;
import
com.yd.csf.service.enums.FortuneStatusEnum
;
import
com.yd.csf.service.model.*
;
...
...
@@ -75,6 +80,12 @@ public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
private
ApiExchangeRateFeignClient
apiExchangeRateFeignClient
;
@Resource
private
IAgentAccumulatedFycService
iAgentAccumulatedFycService
;
@Resource
private
AuditService
auditService
;
@Resource
private
AuditHelper
auditHelper
;
@Resource
private
AuditTemplate
auditTemplate
;
@Override
public
Wrapper
<
Fortune
>
getQueryWrapper
(
FortuneQueryRequest
fortuneQueryRequest
)
{
...
...
@@ -767,6 +778,11 @@ public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
return
false
;
}
return
auditTemplate
.
execute
(
"出账管理"
,
1
,
"批量新增出账记录"
,
ctx
->
doAddFortuneBatch
(
fortuneAddRequestList
,
ctx
));
}
private
Boolean
doAddFortuneBatch
(
List
<
FortuneAddRequest
>
fortuneAddRequestList
,
AuditContext
ctx
)
{
Set
<
String
>
policyNoSet
=
fortuneAddRequestList
.
stream
()
.
map
(
FortuneAddRequest:
:
getPolicyNo
)
.
filter
(
StringUtils:
:
isNotBlank
).
collect
(
Collectors
.
toSet
());
...
...
@@ -810,6 +826,8 @@ public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
String
realName
=
currentLoginUser
.
getRealName
();
List
<
Fortune
>
fortuneList
=
new
ArrayList
<>();
// 收集自动创建的 ExpectedFortune bizId
List
<
String
>
createdExpectedBizIds
=
new
ArrayList
<>();
for
(
FortuneAddRequest
fortuneAddRequest
:
fortuneAddRequestList
)
{
// 校验参数
...
...
@@ -845,6 +863,8 @@ public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
.
update
();
// 关联应付款编号
fortune
.
setPayableNo
(
payableNo
);
// 记录自动创建的 expectedFortune
createdExpectedBizIds
.
add
(
expectedFortune
.
getExpectedFortuneBizId
());
}
else
{
// 如果有预计出账记录,提示去应付款管理页面修改金额,而不是在出账页面新增
throw
new
BusinessException
(
ResultCode
.
FAIL
.
getCode
(),
fortuneAddRequest
.
getFortuneName
()
+
" 已存在应付记录,请在应付款管理页面修改金额"
);
...
...
@@ -888,6 +908,25 @@ public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
}
this
.
saveBatch
(
fortuneList
);
// 审计:fortune INSERT
if
(
CollUtil
.
isNotEmpty
(
fortuneList
))
{
Map
<
String
,
Fortune
>
insertMap
=
fortuneList
.
stream
()
.
collect
(
Collectors
.
toMap
(
Fortune:
:
getFortuneBizId
,
Function
.
identity
()));
auditHelper
.
record
(
"fortune"
,
null
,
insertMap
,
ctx
);
}
// 审计:expected_fortune INSERT(自动创建时)
if
(
CollUtil
.
isNotEmpty
(
createdExpectedBizIds
))
{
List
<
ExpectedFortune
>
createdList
=
expectedFortuneService
.
lambdaQuery
()
.
in
(
ExpectedFortune:
:
getExpectedFortuneBizId
,
createdExpectedBizIds
)
.
list
();
if
(
CollUtil
.
isNotEmpty
(
createdList
))
{
Map
<
String
,
ExpectedFortune
>
efInsertMap
=
createdList
.
stream
()
.
collect
(
Collectors
.
toMap
(
ExpectedFortune:
:
getExpectedFortuneBizId
,
Function
.
identity
()));
auditHelper
.
record
(
"expected_fortune"
,
null
,
efInsertMap
,
ctx
);
}
}
return
true
;
}
...
...
yd-csf-service/src/main/resources/mappers/AuditLogDataChangeMapper.xml
0 → 100644
View file @
4bf8eaf1
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.yd.csf.service.dao.AuditLogDataChangeMapper"
>
<resultMap
id=
"BaseResultMap"
type=
"com.yd.csf.service.model.SysOperDataChange"
>
<id
property=
"id"
column=
"id"
/>
<result
property=
"requestId"
column=
"request_id"
/>
<result
property=
"operLogId"
column=
"oper_log_id"
/>
<result
property=
"tableName"
column=
"table_name"
/>
<result
property=
"recordId"
column=
"record_id"
/>
<result
property=
"fieldName"
column=
"field_name"
/>
<result
property=
"fieldComment"
column=
"field_comment"
/>
<result
property=
"oldValue"
column=
"old_value"
/>
<result
property=
"newValue"
column=
"new_value"
/>
<result
property=
"changeType"
column=
"change_type"
/>
<result
property=
"createTime"
column=
"create_time"
/>
</resultMap>
<sql
id=
"Base_Column_List"
>
id
,request_id,oper_log_id,table_name,record_id,field_name,
field_comment,old_value,new_value,change_type,create_time
</sql>
</mapper>
yd-csf-service/src/main/resources/mappers/AuditLogDataSnapshotMapper.xml
0 → 100644
View file @
4bf8eaf1
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.yd.csf.service.dao.AuditLogDataSnapshotMapper"
>
<resultMap
id=
"BaseResultMap"
type=
"com.yd.csf.service.model.SysOperDataSnapshot"
>
<id
property=
"id"
column=
"id"
/>
<result
property=
"requestId"
column=
"request_id"
/>
<result
property=
"tableName"
column=
"table_name"
/>
<result
property=
"recordId"
column=
"record_id"
/>
<result
property=
"beforeJson"
column=
"before_json"
/>
<result
property=
"afterJson"
column=
"after_json"
/>
<result
property=
"createTime"
column=
"create_time"
/>
</resultMap>
<sql
id=
"Base_Column_List"
>
id
,request_id,table_name,record_id,before_json,after_json,
create_time
</sql>
</mapper>
yd-csf-service/src/main/resources/mappers/AuditLogMapper.xml
0 → 100644
View file @
4bf8eaf1
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.yd.csf.service.dao.AuditLogMapper"
>
<resultMap
id=
"BaseResultMap"
type=
"com.yd.csf.service.model.SysOperLog"
>
<id
property=
"id"
column=
"id"
/>
<result
property=
"requestId"
column=
"request_id"
/>
<result
property=
"module"
column=
"module"
/>
<result
property=
"businessType"
column=
"business_type"
/>
<result
property=
"method"
column=
"method"
/>
<result
property=
"content"
column=
"content"
/>
<result
property=
"businessId"
column=
"business_id"
/>
<result
property=
"operationType"
column=
"operation_type"
/>
<result
property=
"userId"
column=
"user_id"
/>
<result
property=
"operName"
column=
"oper_name"
/>
<result
property=
"deptName"
column=
"dept_name"
/>
<result
property=
"operUrl"
column=
"oper_url"
/>
<result
property=
"operIp"
column=
"oper_ip"
/>
<result
property=
"operLocation"
column=
"oper_location"
/>
<result
property=
"operParam"
column=
"oper_param"
/>
<result
property=
"jsonResult"
column=
"json_result"
/>
<result
property=
"status"
column=
"status"
/>
<result
property=
"errorMsg"
column=
"error_msg"
/>
<result
property=
"operTime"
column=
"oper_time"
/>
</resultMap>
<sql
id=
"Base_Column_List"
>
id
,request_id,module,business_type,method,content,
business_id,operation_type,user_id,oper_name,dept_name,
oper_url,oper_ip,oper_location,oper_param,json_result,
status,error_msg,oper_time
</sql>
</mapper>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment