Merge remote-tracking branch 'origin/dev/0.9_cockpit' into dev/0.9_cockpit

This commit is contained in:
George 2026-09-15 09:11:18 +08:00
commit 8412b62996
31 changed files with 474 additions and 17 deletions

View File

@ -72,7 +72,7 @@ services:
logging: logging:
driver: "json-file" driver: "json-file"
options: options:
max-size: "10m" max-size: "50m"
max-file: "2" max-file: "2"
ports: ports:
- 8080:8080 - 8080:8080

View File

@ -0,0 +1,88 @@
package com.fastbee.web.task;
import com.fastbee.iot.service.IAlertLogService;
import com.fastbee.iot.service.IEventLogService;
import com.fastbee.notify.service.INotifyLogService;
import com.fastbee.quartz.service.ISysJobLogService;
import com.fastbee.system.service.ISysLogininforService;
import com.fastbee.system.service.ISysOperLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 日志清理定时任务
*
* @author fastbee
*/
@Component("logCleanTask")
public class LogCleanTask {
private static final Logger log = LoggerFactory.getLogger(LogCleanTask.class);
@Autowired
private IEventLogService eventLogService;
@Autowired
private ISysOperLogService operLogService;
@Autowired
private ISysLogininforService logininforService;
@Autowired
private IAlertLogService alertLogService;
@Autowired
private ISysJobLogService jobLogService;
@Autowired
private INotifyLogService notifyLogService;
// 之后还有清理的表往下写
/**
* 清理日志(默认清理15天前)
*/
public void cleanLogs() {
cleanLogs(15);
}
/**
* 清理日志
*
* @param days 保留天数
*/
public void cleanLogs(int days) {
log.info("========== 开始清理日志数据,保留最近 {} 天的记录 ==========", days);
try {
// 清理 IoT 事件日志
eventLogService.cleanEventLog(days);
//log.info("已清理 iot_event_log 表 {} 天前的数据", days);
// 清理系统操作日志
operLogService.cleanOperLog(days);
//log.info("已清理 sys_oper_log 表 {} 天前的数据", days);
// 清理登录日志
logininforService.cleanLogininfor(days);
//log.info("已清理 sys_logininfor 表 {} 天前的数据", days);
// 清理设备告警日志
alertLogService.cleanAlertLog(days);
//log.info("已清理 iot_alert_log 表 {} 天前的数据", days);
// 清理定时任务日志
jobLogService.cleanJobLog(days);
//log.info("已清理 sys_job_log 表 {} 天前的数据", days);
// 清理通知日志
notifyLogService.cleanNotifyLog(days);
//log.info("已清理 notify_log 表 {} 天前的数据", days);
log.info("========== 日志清理任务执行完成 ==========");
} catch (Exception e) {
log.error("日志清理任务执行失败", e);
throw e;
}
}
}

View File

@ -58,4 +58,12 @@ public interface NotifyLogMapper {
* @return 结果 * @return 结果
*/ */
public int deleteNotifyLogByIds(Long[] ids); public int deleteNotifyLogByIds(Long[] ids);
/**
* 删除指定天数前的通知日志
*
* @param days 保留天数
* @return 删除记录数
*/
public int deleteNotifyLogBeforeDays(int days);
} }

View File

@ -58,4 +58,11 @@ public interface INotifyLogService {
* @return 结果 * @return 结果
*/ */
public int deleteNotifyLogById(Long id); public int deleteNotifyLogById(Long id);
/**
* 清理通知日志
*
* @param days 保留天数
*/
public void cleanNotifyLog(int days);
} }

View File

@ -132,4 +132,14 @@ public class NotifyLogServiceImpl implements INotifyLogService {
public int deleteNotifyLogById(Long id) { public int deleteNotifyLogById(Long id) {
return notifyLogMapper.deleteNotifyLogById(id); return notifyLogMapper.deleteNotifyLogById(id);
} }
/**
* 清理通知日志
*
* @param days 保留天数
*/
@Override
public void cleanNotifyLog(int days) {
notifyLogMapper.deleteNotifyLogBeforeDays(days);
}
} }

View File

@ -138,4 +138,9 @@
#{id} #{id}
</foreach> </foreach>
</delete> </delete>
<delete id="deleteNotifyLogBeforeDays">
DELETE FROM notify_log
WHERE create_time &lt; DATE_SUB(NOW(), INTERVAL #{days} DAY)
</delete>
</mapper> </mapper>

View File

@ -0,0 +1,96 @@
package com.fastbee.controller.system;
import com.fastbee.common.annotation.Log;
import com.fastbee.common.core.controller.BaseController;
import com.fastbee.common.core.domain.AjaxResult;
import com.fastbee.common.enums.BusinessType;
import com.fastbee.iot.service.IAlertLogService;
import com.fastbee.iot.service.IEventLogService;
import com.fastbee.notify.service.INotifyLogService;
import com.fastbee.quartz.service.ISysJobLogService;
import com.fastbee.system.service.ISysLogininforService;
import com.fastbee.system.service.ISysOperLogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 日志清理Controller
*
* @author fastbee
*/
@Api(tags = "系统管理:日志清理")
@RestController
@RequestMapping("/system/log")
public class LogCleanController extends BaseController {
@Autowired
private IEventLogService eventLogService;
@Autowired
private ISysOperLogService operLogService;
@Autowired
private ISysLogininforService logininforService;
@Autowired
private IAlertLogService alertLogService;
@Autowired
private ISysJobLogService jobLogService;
@Autowired
private INotifyLogService notifyLogService;
/**
* 清理日志数据
*
* @param days 保留天数,默认15天
* @return 清理结果
*/
@ApiOperation("清理日志数据")
@PreAuthorize("@ss.hasRole('admin')")
@Log(title = "日志清理", businessType = BusinessType.CLEAN)
@PostMapping("/clean")
public AjaxResult cleanLogs(
@ApiParam("保留天数,默认15天")
@RequestParam(value = "days", defaultValue = "15") Integer days) {
try {
logger.info("手动触发日志清理,保留最近 {} 天的记录", days);
if (days < 1) {
return error("保留天数必须大于等于1天");
}
// 清理 IoT 事件日志
eventLogService.cleanEventLog(days);
// 清理系统操作日志
operLogService.cleanOperLog(days);
// 清理登录日志
logininforService.cleanLogininfor(days);
// 清理设备告警日志
alertLogService.cleanAlertLog(days);
// 清理定时任务日志
jobLogService.cleanJobLog(days);
// 清理通知日志
notifyLogService.cleanNotifyLog(days);
logger.info("日志清理完成,保留最近 {} 天的记录", days);
return success(String.format("日志清理完成,已删除 %d 天前的历史数据", days));
} catch (Exception e) {
logger.error("日志清理失败", e);
return error("日志清理失败:" + e.getMessage());
}
}
}

View File

@ -254,20 +254,19 @@ public class ToolController extends BaseController {
} }
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace();
log.error("发生错误:{}", ex.getMessage(), ex); log.error("发生错误:{}", ex.getMessage(), ex);
} }
} }
@ApiOperation("mqtt钩子处理") @ApiOperation("mqtt钩子处理")
@PostMapping("/mqtt/webhookv5") @PostMapping("/mqtt/webhookv5")
public void webHookProcessv5(@RequestBody JSONObject json) { public void webHookProcessV5(@RequestBody JSONObject json) {
try { try {
String clientid = json.getString("clientid"); String clientid = json.getString("clientid");
String event = json.getString("event"); String event = json.getString("event");
String peername = json.getString("peername"); // 类似 127.0.0.1:8812 String peername = json.getString("peername"); // 类似 127.0.0.1:8812
String ipAddress = peername; String ipAddress = peername;
if (peername.indexOf(":") != -1) { if (peername.contains(":")) {
ipAddress = peername.substring(0, peername.indexOf(":")); ipAddress = peername.substring(0, peername.indexOf(":"));
} }
log.info("webhook:{},clientid:{},peername:{}", event, clientid, peername); log.info("webhook:{},clientid:{},peername:{}", event, clientid, peername);
@ -310,18 +309,17 @@ public class ToolController extends BaseController {
// 影子模式,发布属性和功能 // 影子模式,发布属性和功能
if (device.getIsShadow() == 1) { if (device.getIsShadow() == 1) {
ThingsModelShadow shadow = deviceService.getDeviceShadowThingsModel(device); ThingsModelShadow shadow = deviceService.getDeviceShadowThingsModel(device);
if (shadow.getProperties().size() > 0) { if (!shadow.getProperties().isEmpty()) {
messagePublish.publishProperty(device.getProductId(), device.getSerialNumber(), shadow.getProperties(), 3); messagePublish.publishProperty(device.getProductId(), device.getSerialNumber(), shadow.getProperties(), 3);
} }
if (shadow.getFunctions().size() > 0) { if (!shadow.getFunctions().isEmpty()) {
messagePublish.publishFunction(device.getProductId(), device.getSerialNumber(), shadow.getFunctions(), 3); messagePublish.publishFunction(device.getProductId(), device.getSerialNumber(), shadow.getFunctions(), 3);
} }
} }
} }
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); log.error("发生错误:{}", ex.getMessage());
log.error("发生错误:" + ex.getMessage());
} }
} }

View File

@ -61,4 +61,12 @@ public interface SysJobLogMapper {
* 清空任务日志 * 清空任务日志
*/ */
public void cleanJobLog(); public void cleanJobLog();
/**
* 删除指定天数前的任务日志
*
* @param days 保留天数
* @return 删除记录数
*/
public int deleteJobLogBeforeDays(int days);
} }

View File

@ -53,4 +53,11 @@ public interface ISysJobLogService {
* 清空任务日志 * 清空任务日志
*/ */
public void cleanJobLog(); public void cleanJobLog();
/**
* 清理指定天数前的任务日志
*
* @param days 保留天数
*/
public void cleanJobLog(int days);
} }

View File

@ -78,4 +78,14 @@ public class SysJobLogServiceImpl implements ISysJobLogService {
public void cleanJobLog() { public void cleanJobLog() {
jobLogMapper.cleanJobLog(); jobLogMapper.cleanJobLog();
} }
/**
* 清理指定天数前的任务日志
*
* @param days 保留天数
*/
@Override
public void cleanJobLog(int days) {
jobLogMapper.deleteJobLogBeforeDays(days);
}
} }

View File

@ -77,6 +77,11 @@
truncate table sys_job_log truncate table sys_job_log
</update> </update>
<delete id="deleteJobLogBeforeDays">
DELETE FROM sys_job_log
WHERE create_time &lt; DATE_SUB(NOW(), INTERVAL #{days} DAY)
</delete>
<insert id="insertJobLog" parameterType="SysJobLog"> <insert id="insertJobLog" parameterType="SysJobLog">
insert into sys_job_log( insert into sys_job_log(
<if test="jobLogId != null and jobLogId != 0">job_log_id,</if> <if test="jobLogId != null and jobLogId != 0">job_log_id,</if>

View File

@ -115,4 +115,12 @@ public interface AlertLogMapper {
* @return com.fastbee.iot.model.AlertCountVO * @return com.fastbee.iot.model.AlertCountVO
*/ */
List<AlertCountVO> countAlertLevel(DataCenterParam dataCenterParam); List<AlertCountVO> countAlertLevel(DataCenterParam dataCenterParam);
/**
* 删除指定天数前的告警日志
*
* @param days 保留天数
* @return 删除记录数
*/
int deleteAlertLogBeforeDays(@Param("days") int days);
} }

View File

@ -25,4 +25,12 @@ public interface EventLogMapper extends BaseMapperX<EventLog> {
Long selectEventLogCount(@Param("userId") Long userId); Long selectEventLogCount(@Param("userId") Long userId);
/**
* 删除指定天数前的日志
*
* @param days 保留天数
* @return 删除记录数
*/
int deleteEventLogBeforeDays(@Param("days") int days);
} }

View File

@ -107,4 +107,11 @@ public interface IAlertLogService {
* @return com.fastbee.iot.model.AlertCountVO * @return com.fastbee.iot.model.AlertCountVO
*/ */
List<AlertCountVO> countAlertLevel(DataCenterParam dataCenterParam); List<AlertCountVO> countAlertLevel(DataCenterParam dataCenterParam);
/**
* 清理告警日志
*
* @param days 保留天数
*/
void cleanAlertLog(int days);
} }

View File

@ -37,4 +37,11 @@ public interface IEventLogService extends IService<EventLog> {
*/ */
List<HistoryModel> listHistory(EventLog eventLog); List<HistoryModel> listHistory(EventLog eventLog);
/**
* 清理事件日志
*
* @param days 保留天数
*/
void cleanEventLog(int days);
} }

View File

@ -199,4 +199,14 @@ public class AlertLogServiceImpl implements IAlertLogService {
public List<AlertCountVO> countAlertLevel(DataCenterParam dataCenterParam) { public List<AlertCountVO> countAlertLevel(DataCenterParam dataCenterParam) {
return alertLogMapper.countAlertLevel(dataCenterParam); return alertLogMapper.countAlertLevel(dataCenterParam);
} }
/**
* 清理告警日志
*
* @param days 保留天数
*/
@Override
public void cleanAlertLog(int days) {
alertLogMapper.deleteAlertLogBeforeDays(days);
}
} }

View File

@ -210,7 +210,7 @@ public class DataRepairServiceImpl implements IDataRepairService {
public void executeDataRepair(String serialNumber, boolean isShadow, List<DeviceLog> currentLogs) { public void executeDataRepair(String serialNumber, boolean isShadow, List<DeviceLog> currentLogs) {
if (CollectionUtils.isEmpty(currentLogs) || isShadow) { if (CollectionUtils.isEmpty(currentLogs) || isShadow) {
log.debug("无数据或为影子模式,不执行数据修复: serialNumber={}, isShadow={}", serialNumber, isShadow); //log.debug("无数据或为影子模式,不执行数据修复: serialNumber={}, isShadow={}", serialNumber, isShadow);
return; return;
} }

View File

@ -648,8 +648,7 @@ public class DeviceServiceImpl implements IDeviceService {
*/ */
@Override @Override
@DSTransactional @DSTransactional
public List<ThingsModelSimpleItem> reportDeviceThingsModelValue(ThingsModelValuesInput input, int type, public List<ThingsModelSimpleItem> reportDeviceThingsModelValue(ThingsModelValuesInput input, int type, boolean isShadow) {
boolean isShadow) {
String serialNumber = input.getDeviceNumber(); String serialNumber = input.getDeviceNumber();
String key = RedisKeyBuilder.buildTSLVCacheKey(input.getProductId(), serialNumber); String key = RedisKeyBuilder.buildTSLVCacheKey(input.getProductId(), serialNumber);
Map<String, String> maps = new HashMap<>(); Map<String, String> maps = new HashMap<>();
@ -675,6 +674,9 @@ public class DeviceServiceImpl implements IDeviceService {
ThingsModelSimpleItem::getValue, ThingsModelSimpleItem::getValue,
(oldValue, newValue) -> oldValue)); (oldValue, newValue) -> oldValue));
} }
// 查询设备信息
Device device = this.selectDeviceBySerialNumber(serialNumber);
for (ThingsModelSimpleItem item : thingsModelValueRemarkItem) { for (ThingsModelSimpleItem item : thingsModelValueRemarkItem) {
String identity = item.getId(); String identity = item.getId();
if (identity.startsWith("array_")) { if (identity.startsWith("array_")) {
@ -746,11 +748,9 @@ public class DeviceServiceImpl implements IDeviceService {
valueItem.setId(identity); valueItem.setId(identity);
if (id.startsWith("array_")) { if (id.startsWith("array_")) {
// 查询是否有缓存,如果没有先进行缓存 // 查询是否有缓存,如果没有先进行缓存
if (!redisCache.containsKey(key)) { // if (!redisCache.containsKey(key)) {
Device device = this.selectDeviceBySerialNumber(serialNumber); // itslValueCache.addCacheDeviceStatus(input.getProductId(), serialNumber);
this.selectDeviceByDeviceId(device.getDeviceId()); // }
}
int index = Integer.parseInt(id.substring(6, 8)); int index = Integer.parseInt(id.substring(6, 8));
if (isShadow) { if (isShadow) {
String[] shadows = cacheIdentifier.getShadow().split(","); String[] shadows = cacheIdentifier.getShadow().split(",");
@ -791,7 +791,6 @@ public class DeviceServiceImpl implements IDeviceService {
/* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★ */ /* ★★★★★★★★★★★★★★★★★★★★★★ 存储数据 - 开始 ★★★★★★★★★★★★★★★★★★★★★★ */
ThingsModelType modelType = ThingsModelType.getType(thingModels.getType()); ThingsModelType modelType = ThingsModelType.getType(thingModels.getType());
Device device = this.selectDeviceBySerialNumber(serialNumber);
switch (modelType) { switch (modelType) {
case PROP: case PROP:
if (1 == thingModels.getIsHistory()) { if (1 == thingModels.getIsHistory()) {

View File

@ -64,4 +64,14 @@ public class EventLogServiceImpl extends ServiceImpl<EventLogMapper, EventLog> i
public List<HistoryModel> listHistory(EventLog eventLog) { public List<HistoryModel> listHistory(EventLog eventLog) {
return eventLogMapper.listHistory(eventLog); return eventLogMapper.listHistory(eventLog);
} }
/**
* 清理事件日志
*
* @param days 保留天数
*/
@Override
public void cleanEventLog(int days) {
eventLogMapper.deleteEventLogBeforeDays(days);
}
} }

View File

@ -274,4 +274,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
</delete> </delete>
<delete id="deleteAlertLogBeforeDays">
DELETE FROM iot_alert_log
WHERE create_time &lt; DATE_SUB(NOW(), INTERVAL #{days} DAY)
</delete>
</mapper> </mapper>

View File

@ -59,4 +59,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="userId != null and userId != 0"> and user_id = #{userId}</if> <if test="userId != null and userId != 0"> and user_id = #{userId}</if>
</where> </where>
</select> </select>
<delete id="deleteEventLogBeforeDays">
DELETE FROM iot_event_log
WHERE create_time &lt; DATE_SUB(NOW(), INTERVAL #{days} DAY)
</delete>
</mapper> </mapper>

View File

@ -41,4 +41,12 @@ public interface SysLogininforMapper {
public int cleanLogininfor(); public int cleanLogininfor();
public List<SysLogininfor> getUserCount(); public List<SysLogininfor> getUserCount();
/**
* 删除指定天数前的登录日志
*
* @param days 保留天数
* @return 删除记录数
*/
public int deleteLogininforBeforeDays(int days);
} }

View File

@ -45,4 +45,12 @@ public interface SysOperLogMapper {
* 清空操作日志 * 清空操作日志
*/ */
public void cleanOperLog(); public void cleanOperLog();
/**
* 删除指定天数前的操作日志
*
* @param days 保留天数
* @return 删除记录数
*/
public int deleteOperLogBeforeDays(int days);
} }

View File

@ -42,4 +42,11 @@ public interface ISysLogininforService {
* 统计一周内的登陆数据 * 统计一周内的登陆数据
*/ */
public List<SysLogininfor> getUserCount(); public List<SysLogininfor> getUserCount();
/**
* 清理指定天数前的登录日志
*
* @param days 保留天数
*/
public void cleanLogininfor(int days);
} }

View File

@ -45,4 +45,11 @@ public interface ISysOperLogService {
* 清空操作日志 * 清空操作日志
*/ */
public void cleanOperLog(); public void cleanOperLog();
/**
* 清理指定天数前的操作日志
*
* @param days 保留天数
*/
public void cleanOperLog(int days);
} }

View File

@ -63,4 +63,14 @@ public class SysLogininforServiceImpl implements ISysLogininforService {
public List<SysLogininfor> getUserCount() { public List<SysLogininfor> getUserCount() {
return logininforMapper.getUserCount(); return logininforMapper.getUserCount();
} }
/**
* 清理指定天数前的登录日志
*
* @param days 保留天数
*/
@Override
public void cleanLogininfor(int days) {
logininforMapper.deleteLogininforBeforeDays(days);
}
} }

View File

@ -68,4 +68,14 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
public void cleanOperLog() { public void cleanOperLog() {
operLogMapper.cleanOperLog(); operLogMapper.cleanOperLog();
} }
/**
* 清理指定天数前的操作日志
*
* @param days 保留天数
*/
@Override
public void cleanOperLog(int days) {
operLogMapper.deleteOperLogBeforeDays(days);
}
} }

View File

@ -76,4 +76,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) b on a.login_time = b.datetime; ) b on a.login_time = b.datetime;
</select> </select>
<delete id="deleteLogininforBeforeDays">
DELETE FROM sys_logininfor
WHERE login_time &lt; DATE_SUB(NOW(), INTERVAL #{days} DAY)
</delete>
</mapper> </mapper>

View File

@ -80,4 +80,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
truncate table sys_oper_log truncate table sys_oper_log
</update> </update>
<delete id="deleteOperLogBeforeDays">
DELETE FROM sys_oper_log
WHERE oper_time &lt; DATE_SUB(NOW(), INTERVAL #{days} DAY)
</delete>
</mapper> </mapper>

View File

@ -0,0 +1,96 @@
-- ============================================
-- 日志清理定时任务初始化 SQL
-- ============================================
-- 1. 插入定时任务记录到 sys_job 表
-- 说明:每天凌晨 0 点自动清理 15 天前的日志数据
-- 注意:LogCleanTask 类位于 fastbee-admin 模块的 com.fastbee.web.task 包下
INSERT INTO `sys_job` (
`job_name`,
`job_group`,
`invoke_target`,
`cron_expression`,
`misfire_policy`,
`concurrent`,
`status`,
`create_by`,
`create_time`,
`remark`
) VALUES (
'日志清理任务', -- 任务名称
'SYSTEM', -- 任务组名
'logCleanTask.cleanLogs()', -- 调用目标字符串
'0 0 0 * * ?', -- Cron 表达式:每天凌晨 00:00:00
'3', -- 错误策略:不触发立即执行
'1', -- 禁止并发执行
'0', -- 状态:正常
'admin', -- 创建者
NOW(), -- 创建时间
'每天凌晨0点自动清理15天前的日志数据(iot_event_log、sys_oper_log、sys_logininfor、iot_alert_log、sys_job_log、notify_log)'
);
-- ============================================
-- 清理的日志表说明
-- ============================================
-- 1. iot_event_log - IoT 事件日志
-- 2. sys_oper_log - 系统操作日志
-- 3. sys_logininfor - 登录日志
-- 4. iot_alert_log - 设备告警日志
-- 5. sys_job_log - 定时任务日志
-- 6. notify_log - 通知日志
--
-- 注意:iot_device_log 表(设备监测日志)不参与清理
-- 该表为核心数据,目前有 214 万条记录,需要数据迁移方案
-- 2. 可选:添加日志清理权限菜单(根据需要执行)
-- 如果需要在管理后台显示权限按钮,可以执行以下 SQL
/*
INSERT INTO `sys_menu` (
`menu_name`,
`parent_id`,
`order_num`,
`path`,
`component`,
`query`,
`is_frame`,
`is_cache`,
`menu_type`,
`visible`,
`status`,
`perms`,
`icon`,
`create_by`,
`create_time`,
`remark`
) VALUES (
'日志清理', -- 菜单名称
2, -- 父菜单ID(根据实际情况调整,2通常是系统管理)
99, -- 显示顺序
'', -- 路由地址
'', -- 组件路径
'', -- 路由参数
1, -- 不是外链
0, -- 不缓存
'F', -- 菜单类型:F=按钮
'0', -- 显示状态
'0', -- 菜单状态
'system:log:clean', -- 权限标识
'#', -- 图标
'admin', -- 创建者
NOW(), -- 创建时间
'日志清理按钮权限'
);
*/
-- ============================================
-- 验证定时任务是否创建成功
-- ============================================
-- SELECT * FROM sys_job WHERE job_name = '日志清理任务';
-- ============================================
-- 手动触发清理(可选)
-- ============================================
-- 如果需要立即清理历史数据,可以通过以下方式:
-- 方式1:通过管理后台 -> 系统监控 -> 定时任务 -> 点击"执行一次"
-- 方式2:调用 API 接口:POST /system/log/clean?days=30
-- 方式3:数据库执行:UPDATE sys_job SET status = '0' WHERE job_name = '日志清理任务';