2025-11-18 09:36:58 +08:00
using Common ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Http ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.IdentityModel.Tokens ;
using MySql.Data.MySqlClient ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Linq ;
using System.Net.Http ;
using System.Text.Json ;
using System.Threading.Tasks ;
using System.Web ;
namespace WxCheckApi.Controllers
{
[Route("api/[controller] / [ action ] ")]
[ApiController]
public class CheckController : ControllerBase
{
private readonly MySqlConnection _connection ;
private readonly HttpClient _httpClient ;
private readonly IConfiguration _configuration ;
public CheckController ( MySqlConnection connection , IHttpClientFactory httpClientFactory , IConfiguration configuration )
{
_connection = connection ;
_httpClient = httpClientFactory . CreateClient ( ) ;
_configuration = configuration ;
}
// 将经纬度转换为地址信息
public async Task < string > ConvertCoordinatesToAddress ( string longitude , string latitude )
{
try
{
// 使用高德地图API进行逆地理编码
string apiKey = _configuration [ "AmapApi:ApiKey" ] ? ? "4d5cb7818664ada68ae5f68783b8bd4c" ;
string url = $"https://restapi.amap.com/v3/geocode/regeo?output=json&location={longitude},{latitude}&key={apiKey}&radius=1000&extensions=all" ;
var response = await _httpClient . GetStringAsync ( url ) ;
var jsonDoc = JsonDocument . Parse ( response ) ;
var root = jsonDoc . RootElement ;
if ( root . GetProperty ( "status" ) . GetString ( ) = = "1" & & root . TryGetProperty ( "regeocode" , out var regeocodeElement ) & & regeocodeElement . ValueKind ! = JsonValueKind . Null )
{
if ( regeocodeElement . TryGetProperty ( "formatted_address" , out var formatted_address ) )
{
return formatted_address . ToString ( ) ;
}
if ( regeocodeElement . TryGetProperty ( "addressComponent" , out var addressComponent ) )
{
string province = addressComponent . TryGetProperty ( "province" , out var provinceElement ) & & provinceElement . ValueKind = = JsonValueKind . String ? provinceElement . GetString ( ) : "" ;
string city = addressComponent . TryGetProperty ( "city" , out var cityElement ) & & cityElement . ValueKind = = JsonValueKind . String ? cityElement . GetString ( ) : "" ;
string district = addressComponent . TryGetProperty ( "district" , out var districtElement ) & & districtElement . ValueKind = = JsonValueKind . String ? districtElement . GetString ( ) : "" ;
string township = addressComponent . TryGetProperty ( "township" , out var townshipElement ) & & townshipElement . ValueKind = = JsonValueKind . String ? townshipElement . GetString ( ) : "" ;
// 获取街道和门牌号信息
string street = "" ;
string streetNumber = "" ;
double distance = 0 ;
// 方法1: 从addressComponent获取街道信息
if ( addressComponent . TryGetProperty ( "streetNumber" , out var streetNumberElement ) & & streetNumberElement . ValueKind = = JsonValueKind . Object )
{
street = streetNumberElement . TryGetProperty ( "street" , out var streetElement ) & & streetElement . ValueKind = = JsonValueKind . String ? streetElement . GetString ( ) : "" ;
streetNumber = streetNumberElement . TryGetProperty ( "number" , out var numberElement ) & & numberElement . ValueKind = = JsonValueKind . String ? numberElement . GetString ( ) : "" ;
// 获取距离信息
if ( streetNumberElement . TryGetProperty ( "distance" , out var distanceElement ) & & distanceElement . ValueKind = = JsonValueKind . String )
{
double . TryParse ( distanceElement . GetString ( ) , out distance ) ;
}
}
// 方法2: 如果方法1没有获取到街道信息, 尝试从aoi信息中获取
if ( string . IsNullOrEmpty ( street ) & & regeocodeElement . TryGetProperty ( "aois" , out var aoisElement ) & & aoisElement . ValueKind = = JsonValueKind . Array )
{
var aoisArray = aoisElement . EnumerateArray ( ) ;
foreach ( var aoi in aoisArray )
{
if ( aoi . TryGetProperty ( "name" , out var aoiNameElement ) & & aoiNameElement . ValueKind = = JsonValueKind . String )
{
street = aoiNameElement . GetString ( ) ;
break ; // 取第一个AOI作为街道信息
}
}
}
// 方法3: 如果前两种方法都没有获取到街道信息, 尝试从pois信息中获取
if ( string . IsNullOrEmpty ( street ) & & regeocodeElement . TryGetProperty ( "pois" , out var poisElement ) & & poisElement . ValueKind = = JsonValueKind . Array )
{
var poisArray = poisElement . EnumerateArray ( ) ;
foreach ( var poi in poisArray )
{
if ( poi . TryGetProperty ( "name" , out var poiNameElement ) & & poiNameElement . ValueKind = = JsonValueKind . String )
{
street = poiNameElement . GetString ( ) ;
break ; // 取第一个POI作为街道信息
}
}
}
// 方法4: 如果以上方法都没有获取到街道信息, 尝试从formatted_address中解析
if ( string . IsNullOrEmpty ( street ) & & regeocodeElement . TryGetProperty ( "formatted_address" , out var formattedAddressElement ) & & formattedAddressElement . ValueKind = = JsonValueKind . String )
{
string formattedAddress = formattedAddressElement . GetString ( ) ;
// 尝试从格式化地址中提取街道信息
// 格式化地址通常格式为:省 市 区 街道 具体地址
// 使用字符串数组作为分隔符
string [ ] separators = { " " , "省" , "市" , "区" , "县" , "镇" , "街道" , "路" , "巷" , "号" } ;
var addressParts = formattedAddress . Split ( separators , StringSplitOptions . RemoveEmptyEntries ) ;
// 查找可能包含街道信息的部分
for ( int i = 0 ; i < addressParts . Length ; i + + )
{
var part = addressParts [ i ] ;
// 如果部分包含"路"、"街"、"巷"等关键词,可能是街道信息
if ( part . Contains ( "路" ) | | part . Contains ( "街" ) | | part . Contains ( "巷" ) | | part . Contains ( "道" ) )
{
street = part ;
// 如果下一个部分存在且不是区县名称,可能是门牌号
if ( i + 1 < addressParts . Length & &
! addressParts [ i + 1 ] . Contains ( "区" ) & &
! addressParts [ i + 1 ] . Contains ( "县" ) )
{
streetNumber = addressParts [ i + 1 ] ;
}
break ;
}
}
}
// 方法5: 如果仍然没有获取到街道信息, 尝试从nearestRoad信息中获取
if ( string . IsNullOrEmpty ( street ) & & regeocodeElement . TryGetProperty ( "streetNumber" , out var nearestStreetElement ) & &
nearestStreetElement . ValueKind = = JsonValueKind . Object )
{
if ( nearestStreetElement . TryGetProperty ( "street" , out var nearestStreetNameElement ) & & nearestStreetNameElement . ValueKind = = JsonValueKind . String )
{
street = nearestStreetNameElement . GetString ( ) ;
}
}
// 构建详细地址字符串
string address = "" ;
if ( ! string . IsNullOrEmpty ( province ) )
{
address + = province ;
}
if ( ! string . IsNullOrEmpty ( city ) & & city ! = province )
{
address + = " " + city ;
}
if ( ! string . IsNullOrEmpty ( district ) )
{
address + = " " + district ;
}
if ( ! string . IsNullOrEmpty ( township ) )
{
address + = " " + township ;
}
if ( ! string . IsNullOrEmpty ( street ) )
{
address + = " " + street ;
}
if ( ! string . IsNullOrEmpty ( streetNumber ) )
{
address + = " " + streetNumber ;
}
// 如果有距离信息,添加到地址后面
if ( distance > 0 )
{
address + = $" {distance:F1}米" ;
}
if ( string . IsNullOrEmpty ( address ) )
{
return "未获取到位置信息(高德返回值为空) " + latitude + "," + longitude ;
}
return address . Trim ( ) ;
}
}
return latitude + "," + longitude ; ; // 如果API调用失败, 返回原始值
}
catch ( Exception )
{
return latitude + "," + longitude ; ; // 如果发生异常,返回原始值
}
}
[HttpPost]
public async Task < IActionResult > CheckAddress ( [ FromBody ] CheckAddressRequest request )
{
try
{
if ( _connection . State ! = ConnectionState . Open )
{
await _connection . OpenAsync ( ) ;
}
// 从数据库查询经纬度信息
string latitude = "" ;
string longitude = "" ;
2025-12-11 11:06:11 +08:00
using ( MySqlCommand cmd = new MySqlCommand ( "SELECT Latitude, Longitude FROM xcx_conversation WHERE Guid = @Guid AND IsDeleted = 0" , _connection ) )
2025-11-18 09:36:58 +08:00
{
2025-12-11 11:06:11 +08:00
cmd . Parameters . AddWithValue ( "@Guid" , request . Guid ) ;
2025-11-18 09:36:58 +08:00
using ( var reader = await cmd . ExecuteReaderAsync ( ) )
{
if ( await reader . ReadAsync ( ) )
{
latitude = reader . IsDBNull ( 0 ) ? "" : reader . GetString ( 0 ) ;
longitude = reader . IsDBNull ( 1 ) ? "" : reader . GetString ( 1 ) ;
}
else
{
return NotFound ( new { success = false , message = "记录不存在或已被删除" } ) ;
}
}
}
// 转换经纬度为地址
var address = await ConvertCoordinatesToAddress ( longitude , latitude ) ;
// 更新数据库中的UserLocation字段
2025-12-11 11:06:11 +08:00
using ( MySqlCommand cmd = new MySqlCommand ( "UPDATE xcx_conversation SET UserLocation = @UserLocation WHERE Guid = @Guid AND IsDeleted = 0" , _connection ) )
2025-11-18 09:36:58 +08:00
{
2025-12-11 11:06:11 +08:00
cmd . Parameters . AddWithValue ( "@Guid" , request . Guid ) ;
2025-11-18 09:36:58 +08:00
cmd . Parameters . AddWithValue ( "@UserLocation" , address ) ;
int rowsAffected = await cmd . ExecuteNonQueryAsync ( ) ;
if ( rowsAffected = = 0 )
{
return NotFound ( new { success = false , message = "记录不存在或已被删除" } ) ;
}
}
return Ok ( new { success = true , message = "地址更新成功" , address = address } ) ;
}
catch ( Exception ex )
{
return StatusCode ( 500 , new { success = false , message = "更新失败" , error = ex . Message } ) ;
}
finally
{
if ( _connection . State = = ConnectionState . Open )
{
await _connection . CloseAsync ( ) ;
}
}
}
// 添加会话记录
[HttpPost]
public async Task < IActionResult > AddConversation ( [ FromBody ] ConversationRequest request )
{
2025-12-11 11:06:11 +08:00
DateTime nowtime = DateTime . Now ;
2025-11-18 09:36:58 +08:00
try
{
if ( _connection . State ! = ConnectionState . Open )
{
await _connection . OpenAsync ( ) ;
}
// 解析经纬度并转换为地址
string address = "" ;
string latitude = "" ;
string longitude = "" ;
// 否则尝试从UserLocation字段解析
if ( ! string . IsNullOrEmpty ( request . UserLocation ) )
{
string [ ] parts = request . UserLocation . Split ( ',' ) ;
if ( parts . Length = = 2 )
{
if ( double . TryParse ( parts [ 0 ] , out double lat ) & & double . TryParse ( parts [ 1 ] , out double lng ) )
{
longitude = lng . ToString ( ) ;
latitude = lat . ToString ( ) ;
address = "" ; // await ConvertCoordinatesToAddress(latitude, longitude);
}
}
}
2025-12-11 11:06:11 +08:00
// 生成GUID
string conversationGuid = string . IsNullOrEmpty ( request . Guid ) ? Guid . NewGuid ( ) . ToString ( "N" ) : request . Guid ;
2025-11-18 09:36:58 +08:00
long conversationId = 0 ;
2025-12-11 11:06:11 +08:00
using ( MySqlCommand cmd = new MySqlCommand ( "INSERT INTO xcx_conversation (UserKey, ConversationContent, SendMethod, UserLocation, Latitude, Longitude, RecordTime, RecordTimeUTCStamp, IsDeleted, CreateTime, MessageType, Guid, SpeakingTime) VALUES (@UserKey, @ConversationContent, @SendMethod, @UserLocation, @Latitude, @Longitude, @RecordTime, @RecordTimeUTCStamp, @IsDeleted, @CreateTime, @MessageType, @Guid, @SpeakingTime); SELECT LAST_INSERT_ID();" , _connection ) )
2025-11-18 09:36:58 +08:00
{
cmd . Parameters . AddWithValue ( "@UserKey" , request . UserKey ) ;
cmd . Parameters . AddWithValue ( "@MessageType" , request . MessageType ) ;
cmd . Parameters . AddWithValue ( "@ConversationContent" , request . ConversationContent ) ;
cmd . Parameters . AddWithValue ( "@SendMethod" , request . SendMethod ) ;
cmd . Parameters . AddWithValue ( "@UserLocation" , address ) ;
cmd . Parameters . AddWithValue ( "@Latitude" , latitude ) ;
cmd . Parameters . AddWithValue ( "@Longitude" , longitude ) ;
2025-12-11 11:06:11 +08:00
cmd . Parameters . AddWithValue ( "@RecordTime" , nowtime ) ;
cmd . Parameters . AddWithValue ( "@CreateTime" , nowtime ) ;
2025-11-18 09:36:58 +08:00
cmd . Parameters . AddWithValue ( "@RecordTimeUTCStamp" , DateTimeOffset . UtcNow . ToUnixTimeMilliseconds ( ) ) ;
cmd . Parameters . AddWithValue ( "@IsDeleted" , 0 ) ;
2025-12-11 11:06:11 +08:00
cmd . Parameters . AddWithValue ( "@Guid" , conversationGuid ) ;
cmd . Parameters . AddWithValue ( "@SpeakingTime" , request . SpeakingTime ) ;
2025-11-18 09:36:58 +08:00
object result = await cmd . ExecuteScalarAsync ( ) ;
conversationId = Convert . ToInt64 ( result ) ;
}
// 查询刚插入的记录,并左连接用户表
if ( conversationId > 0 )
{
2025-12-11 11:06:11 +08:00
string query = @ "SELECT convs.Id, convs.Guid, convs.UserKey, convs.ConversationContent, convs.SendMethod,
2025-11-18 09:36:58 +08:00
convs . UserLocation , convs . Latitude , convs . Longitude , convs . RecordTime ,
2025-12-11 11:06:11 +08:00
convs . RecordTimeUTCStamp , convs . IsDeleted , convs . CreateTime , convs . MessageType , convs . SpeakingTime ,
2025-11-18 09:36:58 +08:00
users . UserName , users . WeChatName , users . PhoneNumber , users . AvatarUrl
FROM xcx_conversation AS convs
LEFT JOIN xcx_users AS users ON convs . UserKey = users . UserKey
2025-12-11 11:06:11 +08:00
WHERE convs . Guid = @Guid ";
2025-11-18 09:36:58 +08:00
using ( MySqlCommand cmd = new MySqlCommand ( query , _connection ) )
{
2025-12-11 11:06:11 +08:00
cmd . Parameters . AddWithValue ( "@Guid" , conversationGuid ) ;
2025-11-18 09:36:58 +08:00
using ( var reader = await cmd . ExecuteReaderAsync ( ) )
{
if ( await reader . ReadAsync ( ) )
{
// 构建要发送到Redis的数据
var messageData = new Dictionary < string , string >
{
["Id"] = reader . GetInt64 ( 0 ) . ToString ( ) ,
2025-12-11 11:06:11 +08:00
["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 ) . ToString ( "yyyy-MM-dd HH:mm:ss" ) ,
["RecordTimeUTCStamp"] = reader . GetInt64 ( 9 ) . ToString ( ) ,
["IsDeleted"] = reader . GetBoolean ( 10 ) . ToString ( ) ,
["CreateTime"] = reader . GetDateTime ( 11 ) . ToString ( "yyyy-MM-dd HH:mm:ss" ) ,
["MessageType"] = reader . GetInt32 ( 12 ) . ToString ( ) ,
["SpeakingTime"] = reader . IsDBNull ( 13 ) ? "" : reader . GetInt32 ( 13 ) . ToString ( ) ,
["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 )
2025-11-18 09:36:58 +08:00
} ;
// 发送到Redis Stream
try
{
// 确保Stream和Group存在
CSRedisCacheHelper . XGroupCreate ( "xcx_msg" , "xcx_group" , "0" ) ;
// 将Dictionary转换为params (string, string)[]格式
var fieldValues = messageData . SelectMany ( kvp = > new ( string , string ) [ ] { ( kvp . Key , kvp . Value ) } ) . ToArray ( ) ;
// 添加消息到Stream
string messageId = CSRedisCacheHelper . XAdd ( "xcx_msg" , fieldValues ) ;
// 记录日志(可选)
System . Diagnostics . Debug . WriteLine ( $"消息已发送到Redis Stream: {messageId}" ) ;
}
catch ( Exception ex )
{
// 记录错误但不影响主流程
System . Diagnostics . Debug . WriteLine ( $"发送到Redis Stream失败: {ex.Message}" ) ;
}
}
}
}
}
2025-12-11 11:06:11 +08:00
return Ok ( new { success = true , message = "收到!" , conversationGuid , receivedTime = nowtime . ToString ( "yyyy-MM-dd HH:mm:ss" ) } ) ;
2025-11-18 09:36:58 +08:00
}
catch ( Exception ex )
{
return StatusCode ( 500 , new { success = false , message = "发送失败" , error = ex . Message } ) ;
}
finally
{
if ( _connection . State = = ConnectionState . Open )
{
await _connection . CloseAsync ( ) ;
}
}
}
// 根据UserKey查询会话记录
[HttpPost]
public async Task < IActionResult > GetConversations ( [ FromBody ] UserKeyRequest request )
{
try
{
if ( _connection . State ! = ConnectionState . Open )
{
await _connection . OpenAsync ( ) ;
}
List < ConversationResponse > conversations = new List < ConversationResponse > ( ) ;
// 构建查询SQL, 根据MessageType参数决定是否添加过滤条件
2025-12-11 11:06:11 +08:00
string query = "SELECT Id, Guid, UserKey, ConversationContent, SendMethod, UserLocation, Latitude, Longitude, RecordTime, RecordTimeUTCStamp, IsDeleted, CreateTime, MessageType, SpeakingTime FROM xcx_conversation WHERE UserKey = @UserKey AND IsDeleted = 0" ;
2025-11-18 09:36:58 +08:00
if ( request . MessageType = = 1 )
{
query + = " AND MessageType = @MessageType" ;
}
query + = " ORDER BY RecordTimeUTCStamp DESC" ;
using ( MySqlCommand cmd = new MySqlCommand ( query , _connection ) )
{
cmd . Parameters . AddWithValue ( "@UserKey" , request . UserKey ) ;
using ( var reader = await cmd . ExecuteReaderAsync ( ) )
{
while ( await reader . ReadAsync ( ) )
{
conversations . Add ( new ConversationResponse
{
Id = reader . GetInt64 ( 0 ) ,
2025-12-11 11:06:11 +08:00
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 )
2025-11-18 09:36:58 +08:00
} ) ;
}
}
}
return Ok ( new { success = true , data = conversations . OrderBy ( z = > z . RecordTimeUTCStamp ) } ) ;
}
catch ( Exception ex )
{
return StatusCode ( 500 , new { success = false , message = "查询失败" , error = ex . Message } ) ;
}
finally
{
if ( _connection . State = = ConnectionState . Open )
{
await _connection . CloseAsync ( ) ;
}
}
}
// 更新会话记录
[HttpPost]
public async Task < IActionResult > UpdateConversation ( [ FromBody ] UpdateConversationRequest request )
{
try
{
if ( _connection . State ! = ConnectionState . Open )
{
await _connection . OpenAsync ( ) ;
}
2025-12-11 11:06:11 +08:00
DateTime nowtime = DateTime . Now ;
using ( MySqlCommand cmd = new MySqlCommand ( "UPDATE xcx_conversation SET ConversationContent = @ConversationContent, SendMethod = @SendMethod, UserLocation = @UserLocation, MessageType = @MessageType, RecordTime = @RecordTime WHERE Guid = @Guid AND UserKey = @UserKey" , _connection ) )
2025-11-18 09:36:58 +08:00
{
2025-12-11 11:06:11 +08:00
cmd . Parameters . AddWithValue ( "@Guid" , request . Guid ) ;
2025-11-18 09:36:58 +08:00
cmd . Parameters . AddWithValue ( "@UserKey" , request . UserKey ) ;
cmd . Parameters . AddWithValue ( "@ConversationContent" , request . ConversationContent ) ;
cmd . Parameters . AddWithValue ( "@SendMethod" , request . SendMethod ) ;
cmd . Parameters . AddWithValue ( "@UserLocation" , request . UserLocation ? ? "" ) ;
cmd . Parameters . AddWithValue ( "@MessageType" , request . MessageType ) ;
2025-12-11 11:06:11 +08:00
cmd . Parameters . AddWithValue ( "@RecordTime" , nowtime ) ;
2025-11-18 09:36:58 +08:00
int rowsAffected = await cmd . ExecuteNonQueryAsync ( ) ;
if ( rowsAffected = = 0 )
{
return NotFound ( new { success = false , message = "记录不存在或无权限修改" } ) ;
}
}
2025-12-11 11:06:11 +08:00
return Ok ( new { success = true , message = "更新成功" , receivedTime = nowtime . ToString ( "yyyy-MM-dd HH:mm:ss" ) } ) ;
2025-11-18 09:36:58 +08:00
}
catch ( Exception ex )
{
return StatusCode ( 500 , new { success = false , message = "更新失败" , error = ex . Message } ) ;
}
finally
{
if ( _connection . State = = ConnectionState . Open )
{
await _connection . CloseAsync ( ) ;
}
}
}
// 软删除会话记录
[HttpPost]
public async Task < IActionResult > DeleteConversation ( [ FromBody ] DeleteConversationRequest request )
{
try
{
if ( _connection . State ! = ConnectionState . Open )
{
await _connection . OpenAsync ( ) ;
}
2025-12-11 11:06:11 +08:00
using ( MySqlCommand cmd = new MySqlCommand ( "UPDATE xcx_conversation SET IsDeleted = 1 WHERE Guid = @Guid AND UserKey = @UserKey AND IsDeleted = 0" , _connection ) )
2025-11-18 09:36:58 +08:00
{
2025-12-11 11:06:11 +08:00
cmd . Parameters . AddWithValue ( "@Guid" , request . Guid ) ;
2025-11-18 09:36:58 +08:00
cmd . Parameters . AddWithValue ( "@UserKey" , request . UserKey ) ;
int rowsAffected = await cmd . ExecuteNonQueryAsync ( ) ;
if ( rowsAffected = = 0 )
{
return NotFound ( new { success = false , message = "记录不存在或已被删除" } ) ;
}
}
return Ok ( new { success = true , message = "删除成功" } ) ;
}
catch ( Exception ex )
{
return StatusCode ( 500 , new { success = false , message = "删除失败" , error = ex . Message } ) ;
}
finally
{
if ( _connection . State = = ConnectionState . Open )
{
await _connection . CloseAsync ( ) ;
}
}
}
2025-12-11 11:06:11 +08:00
// 根据GUID查询会话记录( 不考虑IsDeleted状态)
[HttpPost]
public async Task < IActionResult > GetConversationByGuid ( [ FromBody ] GetConversationByGuidRequest request )
{
try
{
if ( _connection . State ! = ConnectionState . Open )
{
await _connection . OpenAsync ( ) ;
}
// 查询记录, 不考虑IsDeleted状态
string query = @ "SELECT Id, Guid, UserKey, ConversationContent, SendMethod, UserLocation,
Latitude , Longitude , RecordTime , RecordTimeUTCStamp , IsDeleted , CreateTime , MessageType , SpeakingTime
FROM xcx_conversation
WHERE Guid = @Guid ";
using ( MySqlCommand cmd = new MySqlCommand ( query , _connection ) )
{
cmd . Parameters . AddWithValue ( "@Guid" , request . Guid ) ;
using ( var reader = await cmd . ExecuteReaderAsync ( ) )
{
if ( await reader . ReadAsync ( ) )
{
var conversation = new ConversationResponse
{
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 )
} ;
return Ok ( new { success = true , message = "查询成功" , data = conversation } ) ;
}
else
{
return NotFound ( new { success = false , message = "未找到该记录" } ) ;
}
}
}
}
catch ( Exception ex )
{
return StatusCode ( 500 , new { success = false , message = "查询失败" , error = ex . Message } ) ;
}
finally
{
if ( _connection . State = = ConnectionState . Open )
{
await _connection . CloseAsync ( ) ;
}
}
}
2025-11-18 09:36:58 +08:00
// 分页查询会话记录
[HttpPost]
public async Task < IActionResult > GetConversationsByPage ( [ FromBody ] PaginationRequest request )
{
try
{
if ( _connection . State ! = ConnectionState . Open )
{
await _connection . OpenAsync ( ) ;
}
// 验证并设置默认值
if ( request . Page < 1 ) request . Page = 1 ;
if ( request . PageSize < 1 | | request . PageSize > 100 ) request . PageSize = 10 ;
int offset = ( request . Page - 1 ) * request . PageSize ;
List < ConversationResponse > conversations = new List < ConversationResponse > ( ) ;
// 构建分页查询SQL, 根据MessageType参数决定是否添加过滤条件
2025-12-11 11:06:11 +08:00
string query = @ "SELECT Id, Guid, UserKey, ConversationContent, SendMethod, UserLocation, Latitude, Longitude, RecordTime, RecordTimeUTCStamp, IsDeleted, CreateTime, MessageType, SpeakingTime
2025-11-18 09:36:58 +08:00
FROM xcx_conversation
WHERE UserKey = @UserKey AND IsDeleted = 0 ";
if ( request . MessageType = = 1 )
{
query + = " AND MessageType = @MessageType" ;
}
query + = " ORDER BY RecordTimeUTCStamp DESC LIMIT @Offset, @Limit" ;
using ( MySqlCommand cmd = new MySqlCommand ( query , _connection ) )
{
cmd . Parameters . AddWithValue ( "@UserKey" , request . UserKey ) ;
if ( request . MessageType = = 1 )
{
cmd . Parameters . AddWithValue ( "@MessageType" , request . MessageType ) ;
}
cmd . Parameters . AddWithValue ( "@Offset" , offset ) ;
cmd . Parameters . AddWithValue ( "@Limit" , request . PageSize ) ;
using ( var reader = await cmd . ExecuteReaderAsync ( ) )
{
while ( await reader . ReadAsync ( ) )
{
conversations . Add ( new ConversationResponse
{
Id = reader . GetInt64 ( 0 ) ,
2025-12-11 11:06:11 +08:00
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 )
2025-11-18 09:36:58 +08:00
} ) ;
}
}
}
// 查询总数, 根据MessageType参数决定是否添加过滤条件
int totalCount = 0 ;
string countQuery = "SELECT COUNT(*) FROM xcx_conversation WHERE UserKey = @UserKey AND IsDeleted = 0" ;
if ( request . MessageType = = 1 )
{
countQuery + = " AND MessageType = @MessageType" ;
}
using ( MySqlCommand countCmd = new MySqlCommand ( countQuery , _connection ) )
{
countCmd . Parameters . AddWithValue ( "@UserKey" , request . UserKey ) ;
if ( request . MessageType = = 1 )
{
countCmd . Parameters . AddWithValue ( "@MessageType" , request . MessageType ) ;
}
totalCount = Convert . ToInt32 ( await countCmd . ExecuteScalarAsync ( ) ) ;
}
int totalPages = ( int ) Math . Ceiling ( ( double ) totalCount / request . PageSize ) ;
return Ok ( new {
success = true ,
data = new {
conversations = conversations . OrderBy ( z = > z . RecordTimeUTCStamp ) ,
totalCount = totalCount ,
page = request . Page ,
pageSize = request . PageSize ,
totalPages = totalPages
}
} ) ;
}
catch ( Exception ex )
{
return StatusCode ( 500 , new { success = false , message = "查询失败" , error = ex . Message } ) ;
}
finally
{
if ( _connection . State = = ConnectionState . Open )
{
await _connection . CloseAsync ( ) ;
}
}
}
// 从Redis Stream读取消息
[HttpPost]
public async Task < IActionResult > ReadMessageFromRedis ( [ FromBody ] RedisMessageRequest request )
{
try
{
// 确保Stream和Group存在
CSRedisCacheHelper . XGroupCreate ( "xcx_msg" , "xcx_group" , "0" ) ;
// 从Redis Stream读取消息
string groupName = request . GroupName ? ? "xcx_group" ;
string consumerName = request . ConsumerName ? ? "consumer_" + DateTime . Now . Ticks ;
string messages = CSRedisCacheHelper . XReadGroup ( "xcx_msg" , groupName , consumerName , request . Count ? ? 1 ) ;
if ( string . IsNullOrEmpty ( messages ) )
{
return Ok ( new { success = true , message = "没有新消息" , data = new List < string > ( ) } ) ;
}
// 解析消息
var messageList = new List < object > ( ) ;
try
{
var messageEntries = System . Text . Json . JsonSerializer . Deserialize < List < Dictionary < string , object > > > ( messages ) ;
if ( messageEntries ! = null )
{
foreach ( var entry in messageEntries )
{
if ( entry . TryGetValue ( "Id" , out var id ) & &
entry . TryGetValue ( "Values" , out var values ) )
{
var messageData = new Dictionary < string , string > ( ) ;
// 如果Values是JsonElement, 需要进一步解析
if ( values is JsonElement valuesElement & & valuesElement . ValueKind = = JsonValueKind . Object )
{
foreach ( var property in valuesElement . EnumerateObject ( ) )
{
messageData [ property . Name ] = property . Value . GetString ( ) ? ? "" ;
}
}
else if ( values is Dictionary < string , string > valuesDict )
{
messageData = valuesDict ;
}
messageData [ "MessageId" ] = id . ToString ( ) ;
messageList . Add ( messageData ) ;
}
}
}
}
catch ( Exception parseEx )
{
// 如果解析失败,尝试直接返回原始消息
System . Diagnostics . Debug . WriteLine ( $"解析消息失败: {parseEx.Message}" ) ;
messageList . Add ( new { RawMessage = messages } ) ;
}
return Ok ( new { success = true , message = "成功读取消息" , data = messageList } ) ;
}
catch ( Exception ex )
{
return StatusCode ( 500 , new { success = false , message = "读取消息失败" , error = ex . Message } ) ;
}
}
}
// 请求和响应模型
public class ConversationRequest
{
public string UserKey { get ; set ; }
public string ConversationContent { get ; set ; }
public string SendMethod { get ; set ; }
public string UserLocation { get ; set ; }
public double Latitude { get ; set ; }
public double Longitude { get ; set ; }
public int MessageType { get ; set ; } = 1 ; // 1:公有, 2:私有
2025-12-11 11:06:11 +08:00
public string? Guid { get ; set ; } // 会话唯一标识
public int? SpeakingTime { get ; set ; } // 对话时长
2025-11-18 09:36:58 +08:00
}
public class UserKeyRequest
{
public string UserKey { get ; set ; }
public int MessageType { get ; set ; } = 0 ; // 0:不判断消息类型, 1:公有, 2:私有
}
public class PaginationRequest
{
public string UserKey { get ; set ; }
public int Page { get ; set ; } = 1 ; // 默认第一页
public int PageSize { get ; set ; } = 10 ; // 默认每页10条
public int MessageType { get ; set ; } = 0 ; // 0:不判断消息类型, 1:公有, 2:私有
}
public class UpdateConversationRequest
{
2025-12-11 11:06:11 +08:00
public long? Id { get ; set ; }
public string Guid { get ; set ; } // 会话唯一标识
2025-11-18 09:36:58 +08:00
public string UserKey { get ; set ; }
public string ConversationContent { get ; set ; }
public string SendMethod { get ; set ; }
public string UserLocation { get ; set ; }
public int MessageType { get ; set ; } = 0 ;
2025-12-11 11:06:11 +08:00
public int? SpeakingTime { get ; set ; }
2025-11-18 09:36:58 +08:00
}
public class DeleteConversationRequest
{
2025-12-11 11:06:11 +08:00
public long? Id { get ; set ; }
public string Guid { get ; set ; } // 会话唯一标识
2025-11-18 09:36:58 +08:00
public string UserKey { get ; set ; }
}
public class CheckAddressRequest
{
2025-12-11 11:06:11 +08:00
public long? Id { get ; set ; }
public string Guid { get ; set ; } // 会话唯一标识
}
public class GetConversationByGuidRequest
{
public long? Id { get ; set ; }
public string Guid { get ; set ; } // 会话唯一标识
2025-11-18 09:36:58 +08:00
}
public class ConversationResponse
{
public long Id { get ; set ; }
2025-12-11 11:06:11 +08:00
public string Guid { get ; set ; } // 会话唯一标识
2025-11-18 09:36:58 +08:00
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 ; } // 1:公有消息, 2:私有消息
2025-12-11 11:06:11 +08:00
public int? SpeakingTime { get ; set ; }
2025-11-18 09:36:58 +08:00
}
public class RedisMessageRequest
{
public string GroupName { get ; set ; } = "xcx_group" ;
public string ConsumerName { get ; set ; }
public int? Count { get ; set ; } = 1 ;
}
}