using Microsoft.AspNetCore.Mvc; using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.Data; using System.Threading.Tasks; namespace WxCheckMvc.Controllers { [Route("api/[controller]/[action]")] [ApiController] public class AdminController : ControllerBase { private readonly MySqlConnection _connection; public AdminController(MySqlConnection connection) { _connection = connection; } [HttpPost] public async Task QueryConversations([FromBody] ConversationQueryRequest request) { try { if (_connection.State != ConnectionState.Open) { await _connection.OpenAsync(); } List conversations = []; string query = @"SELECT c.Id, c.Guid, c.UserKey, c.ConversationContent, c.SendMethod, c.UserLocation, c.Latitude, c.Longitude, c.RecordTime, c.RecordTimeUTCStamp, c.IsDeleted, c.CreateTime, c.MessageType, c.SpeakingTime, u.UserName, u.WeChatName, u.PhoneNumber, u.AvatarUrl, u.Department FROM xcx_conversation c LEFT JOIN xcx_users u ON c.UserKey = u.UserKey WHERE c.IsDeleted = 0"; var parameters = new List(); if (!string.IsNullOrEmpty(request.UserKey)) { query += " AND c.UserKey = @UserKey"; parameters.Add(new MySqlParameter("@UserKey", request.UserKey)); } if (request.MessageType.HasValue) { query += " AND c.MessageType = @MessageType"; parameters.Add(new MySqlParameter("@MessageType", request.MessageType.Value)); } if (request.StartTime.HasValue) { long startUtcStamp = new DateTimeOffset(request.StartTime.Value).ToUnixTimeMilliseconds(); query += " AND c.RecordTimeUTCStamp >= @StartTime"; parameters.Add(new MySqlParameter("@StartTime", startUtcStamp)); } if (request.EndTime.HasValue) { long endUtcStamp = new DateTimeOffset(request.EndTime.Value).ToUnixTimeMilliseconds(); query += " AND c.RecordTimeUTCStamp <= @EndTime"; parameters.Add(new MySqlParameter("@EndTime", endUtcStamp)); } if (!string.IsNullOrEmpty(request.Department)) { query += " AND u.Department = @Department"; parameters.Add(new MySqlParameter("@Department", request.Department)); } query += " ORDER BY c.RecordTimeUTCStamp DESC"; int offset = (request.Page - 1) * request.PageSize; query += " LIMIT @Limit OFFSET @Offset"; parameters.Add(new MySqlParameter("@Limit", request.PageSize)); parameters.Add(new MySqlParameter("@Offset", offset)); using (MySqlCommand cmd = new(query, _connection)) { cmd.Parameters.AddRange(parameters.ToArray()); using (var reader = await cmd.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { conversations.Add(new ConversationQueryResponse { Id = reader.GetInt64(0), Guid = reader.IsDBNull(1) ? "" : reader.GetString(1), UserKey = reader.GetString(2), ConversationContent = reader.GetString(3), SendMethod = reader.GetString(4), UserLocation = reader.IsDBNull(5) ? "" : reader.GetString(5), Latitude = reader.IsDBNull(6) ? "" : reader.GetString(6), Longitude = reader.IsDBNull(7) ? "" : reader.GetString(7), RecordTime = reader.GetDateTime(8), RecordTimeUTCStamp = reader.GetInt64(9), IsDeleted = reader.GetBoolean(10), CreateTime = reader.GetDateTime(11), MessageType = reader.GetInt32(12), SpeakingTime = reader.IsDBNull(13) ? null : reader.GetInt32(13), UserName = reader.IsDBNull(14) ? "" : reader.GetString(14), WeChatName = reader.IsDBNull(15) ? "" : reader.GetString(15), PhoneNumber = reader.IsDBNull(16) ? "" : reader.GetString(16), AvatarUrl = reader.IsDBNull(17) ? "" : reader.GetString(17), Department = reader.IsDBNull(18) ? "" : reader.GetString(18) }); } } } return Ok(new { success = true, data = conversations }); } catch (Exception ex) { return StatusCode(500, new { success = false, message = "查询失败", error = ex.Message }); } finally { if (_connection.State == ConnectionState.Open) { await _connection.CloseAsync(); } } } [HttpGet] public async Task QueryUsers() { try { if (_connection.State != ConnectionState.Open) { await _connection.OpenAsync(); } List users = []; string query = @"SELECT Id, UserName, UserKey, WeChatName, PhoneNumber, FirstLoginTime, IsDisabled, CreateTime, UpdateTime, AvatarUrl, Department FROM xcx_users WHERE PhoneNumber IS NOT NULL AND PhoneNumber != '' AND UserName IS NOT NULL AND UserName != '' AND UserKey IS NOT NULL AND UserKey != '' AND IsDisabled = 0 ORDER BY FirstLoginTime DESC"; using (MySqlCommand cmd = new(query, _connection)) { using (var reader = await cmd.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { users.Add(new UserQueryResponse { Id = reader.GetInt64(0), UserName = reader.IsDBNull(1) ? "" : reader.GetString(1), UserKey = reader.GetString(2), WeChatName = reader.IsDBNull(3) ? "" : reader.GetString(3), PhoneNumber = reader.IsDBNull(4) ? "" : reader.GetString(4), FirstLoginTime = reader.GetDateTime(5), IsDisabled = reader.GetBoolean(6), CreateTime = reader.GetDateTime(7), UpdateTime = reader.GetDateTime(8), AvatarUrl = reader.IsDBNull(9) ? "" : reader.GetString(9), Department = reader.IsDBNull(10) ? "" : reader.GetString(10) }); } } } return Ok(new { success = true, data = users }); } catch (Exception ex) { return StatusCode(500, new { success = false, message = "查询失败", error = ex.Message }); } finally { if (_connection.State == ConnectionState.Open) { await _connection.CloseAsync(); } } } [HttpGet] public async Task QueryStats() { try { if (_connection.State != ConnectionState.Open) { await _connection.OpenAsync(); } // 1) 活跃用户:最近 7 天登录(UpdateTime)且 UserKey/PhoneNumber 不为空 long activeUsers; using (MySqlCommand cmd = new(@" SELECT COUNT(1) FROM xcx_users WHERE UpdateTime >= DATE_SUB(NOW(), INTERVAL 7 DAY) AND UserKey IS NOT NULL AND UserKey <> '' AND PhoneNumber IS NOT NULL AND PhoneNumber <> ''", _connection)) { activeUsers = Convert.ToInt64(await cmd.ExecuteScalarAsync()); } // 2) 总会话记录数 long totalConversations; using (MySqlCommand cmd = new("SELECT COUNT(1) FROM xcx_conversation", _connection)) { totalConversations = Convert.ToInt64(await cmd.ExecuteScalarAsync()); } // 3) 今日新增会话记录(CreateTime 在今天内) long todayNewConversations; using (MySqlCommand cmd = new(@" SELECT COUNT(1) FROM xcx_conversation WHERE CreateTime >= CURDATE() AND CreateTime < DATE_ADD(CURDATE(), INTERVAL 1 DAY)", _connection)) { todayNewConversations = Convert.ToInt64(await cmd.ExecuteScalarAsync()); } // 4) 总用户数:UserKey/PhoneNumber 不为空 long totalUsers; using (MySqlCommand cmd = new(@" SELECT COUNT(1) FROM xcx_users WHERE UserKey IS NOT NULL AND UserKey <> '' AND PhoneNumber IS NOT NULL AND PhoneNumber <> ''", _connection)) { totalUsers = Convert.ToInt64(await cmd.ExecuteScalarAsync()); } var data = new AdminStatsResponse { ActiveUsers = activeUsers, TotalConversations = totalConversations, TodayNewConversations = todayNewConversations, TotalUsers = totalUsers }; return Ok(new { success = true, data }); } catch (Exception ex) { return StatusCode(500, new { success = false, message = "查询失败", error = ex.Message }); } finally { if (_connection.State == ConnectionState.Open) { await _connection.CloseAsync(); } } } } public class ConversationQueryRequest { public DateTime? StartTime { get; set; } public DateTime? EndTime { get; set; } public string UserKey { get; set; } public int? MessageType { get; set; } public string Department { get; set; } public int Page { get; set; } = 1; public int PageSize { get; set; } = 20; } public class ConversationQueryResponse { public long Id { get; set; } public string Guid { get; set; } public string UserKey { get; set; } public string ConversationContent { get; set; } public string SendMethod { get; set; } public string UserLocation { get; set; } public string Latitude { get; set; } public string Longitude { get; set; } public DateTime RecordTime { get; set; } public long RecordTimeUTCStamp { get; set; } public bool IsDeleted { get; set; } public DateTime CreateTime { get; set; } public int MessageType { get; set; } public int? SpeakingTime { get; set; } public string UserName { get; set; } public string WeChatName { get; set; } public string PhoneNumber { get; set; } public string AvatarUrl { get; set; } public string Department { get; set; } } public class UserQueryResponse { public long Id { get; set; } public string UserName { get; set; } public string UserKey { get; set; } public string WeChatName { get; set; } public string PhoneNumber { get; set; } public DateTime FirstLoginTime { get; set; } public bool IsDisabled { get; set; } public DateTime CreateTime { get; set; } public DateTime UpdateTime { get; set; } public string AvatarUrl { get; set; } public string Department { get; set; } } public class AdminStatsResponse { public long ActiveUsers { get; set; } public long TotalConversations { get; set; } public long TodayNewConversations { get; set; } public long TotalUsers { get; set; } } }