创建源表
CREATE TABLE `api_log` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(20) DEFAULT NULL COMMENT '用户名',
`ip` varchar(45) DEFAULT NULL COMMENT '登录IP地址',
`ip_location` varchar(255) DEFAULT NULL COMMENT 'IP所属地',
`os` varchar(50) DEFAULT NULL COMMENT '操作系统',
`browser` varchar(50) DEFAULT NULL COMMENT '浏览器',
`status` smallint(6) DEFAULT '1' COMMENT '登录状态 (1成功 2失败)',
`message` varchar(50) DEFAULT NULL COMMENT '提示消息',
`login_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '登录时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`created_by` int(11) DEFAULT NULL COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8 COMMENT='登录日志表';
新增日志
//按年月分表 通过redis存储 防止每次插入都需要去扫描数据库
public function apiLog():Response
{
// 获取当前年月
$tableName = 'api_log_' . date('Ym');
//每月第一次创建删除一次
if(!\support\Redis::get($tableName)){
$prefix = 'api_log_';
$expireDate = date('Ym', strtotime('-1 year'));
//清理一年前的旧表
\support\think\Db::query("DROP TABLE IF EXISTS ".$prefix . $expireDate);
//清理一年前及更早的旧表
// 查询所有分表
$tables = \support\think\Db::query("SHOW TABLES LIKE '{$prefix}%'");
foreach ($tables as $t) {
$table = reset($t); // 获取表名
// 提取年月后缀
$suffix = str_replace($prefix, '', $table);
// 如果年月 <= 过期年月,则删除
if (ctype_digit($suffix) && $suffix <= $expireDate) {
\support\think\Db::query("DROP TABLE IF EXISTS {$table}");
}
}
//保存31天自动销毁
\support\Redis::set($tableName,1, 60 * 60 * 24 * 31);
// 确保表存在(没有则创建)
\support\think\Db::query("CREATE TABLE IF NOT EXISTS {$tableName} LIKE api_log");
}
// 插入数据
\support\think\Db::table($tableName)->insert([
'username'=>'日志插入'
]);
return success();
}
日志查询带分页
public function apiLogList(\support\Request $request): Response
{
$rows = $request->post('rows');
$page = $request->post('page');
$starttime = $request->post('starttime');
$endtime = $request->post('endtime');
$tables = $this->getTableNames($starttime, $endtime);
$baseQuery = "SELECT id,username FROM %s WHERE status='004001'";
$unionQueries = array_map(
fn($table) => sprintf($baseQuery, $table),
$tables
);
// 构建 UNION ALL 查询
$unionSql = implode(' UNION ALL ', $unionQueries);
// 总数查询
$count = \support\think\Db::query("SELECT COUNT(*) as total_count FROM ({$unionSql}) as combined_tables");
// 分页查询
$offset = ($page - 1) * $rows;
$list = \support\think\Db::query("{$unionSql} ORDER BY cts DESC LIMIT {$offset}, {$rows}");
return success(data:$list,count: $count);
}
/**
* 根据时间范围生成表名数组
*/
private function getTableNames($starttime, $endtime){
$startDate = new DateTime($starttime);
$endDate = new DateTime($endtime);
$tableList = \support\think\Db::query('SHOW TABLES');
$tables = [];
$current = (clone $startDate)->modify('first day of this month');
$endMonth = (clone $endDate)->modify('first day of this month');
while($current <= $endMonth){
$tableName = 'api_log_' . $current->format('Ym');
// 检查表是否存在(可选)
if(in_array($tableName,$tableList)){
$tables[] = $tableName;
}
// 下一个月
$current->modify('+1 month');
}
return $tables;
}