初始化小程序端
This commit is contained in:
960
WxCheckMvc/Controllers/CheckController.cs
Normal file
960
WxCheckMvc/Controllers/CheckController.cs
Normal file
@@ -0,0 +1,960 @@
|
||||
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;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using System.IO;
|
||||
|
||||
namespace WxCheckMvc.Controllers
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class CheckController : ControllerBase
|
||||
{
|
||||
private readonly MySqlConnection _connection;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
|
||||
public CheckController(MySqlConnection connection, IHttpClientFactory httpClientFactory, IConfiguration configuration, IWebHostEnvironment environment)
|
||||
{
|
||||
_connection = connection;
|
||||
_httpClient = httpClientFactory.CreateClient();
|
||||
_configuration = configuration;
|
||||
_environment = environment;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> UploadFile(IFormFile file, [FromForm] string rootPathType, [FromForm] string userKey)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (file == null || file.Length == 0)
|
||||
{
|
||||
return BadRequest(new { success = false, message = "请选择文件" });
|
||||
}
|
||||
|
||||
// 1. 确定保存路径
|
||||
// 默认使用 Avatar,如果传入了 rootPathType 则使用传入值
|
||||
string folderName = "Avatar";
|
||||
if (!string.IsNullOrWhiteSpace(rootPathType))
|
||||
{
|
||||
// 安全检查:只允许字母、数字、下划线,防止路径遍历
|
||||
if (rootPathType.Any(c => !char.IsLetterOrDigit(c) && c != '_'))
|
||||
{
|
||||
return BadRequest(new { success = false, message = "rootPathType 包含非法字符,只允许字母、数字和下划线" });
|
||||
}
|
||||
folderName = rootPathType;
|
||||
}
|
||||
|
||||
string webRootPath = _environment.WebRootPath;
|
||||
string uploadDir = Path.Combine(webRootPath, folderName);
|
||||
|
||||
// 如果文件夹不存在,则创建
|
||||
if (!Directory.Exists(uploadDir))
|
||||
{
|
||||
Directory.CreateDirectory(uploadDir);
|
||||
}
|
||||
|
||||
// 2. 生成唯一文件名并保存
|
||||
string fileExtension = Path.GetExtension(file.FileName);
|
||||
string newFileName = Guid.NewGuid().ToString("N") + fileExtension;
|
||||
string filePath = Path.Combine(uploadDir, newFileName);
|
||||
|
||||
using (var stream = new FileStream(filePath, FileMode.Create))
|
||||
{
|
||||
await file.CopyToAsync(stream);
|
||||
}
|
||||
|
||||
// 构建返回URL
|
||||
string relativePath = $"/{folderName}/{newFileName}";
|
||||
string fullUrl = $"{Request.Scheme}://{Request.Host}{relativePath}";
|
||||
|
||||
// 3. 如果提供了 UserKey,更新数据库中的 AvatarUrl
|
||||
if (!string.IsNullOrWhiteSpace(userKey))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_connection.State != ConnectionState.Open)
|
||||
{
|
||||
await _connection.OpenAsync();
|
||||
}
|
||||
|
||||
string updateSql = "UPDATE xcx_users SET AvatarUrl = @AvatarUrl, UpdateTime = NOW() WHERE UserKey = @UserKey";
|
||||
using (MySqlCommand cmd = new MySqlCommand(updateSql, _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@AvatarUrl", fullUrl);
|
||||
cmd.Parameters.AddWithValue("@UserKey", userKey);
|
||||
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_connection.State == ConnectionState.Open)
|
||||
{
|
||||
await _connection.CloseAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(new { success = true, message = "上传成功", url = fullUrl, path = relativePath });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 确保连接关闭
|
||||
if (_connection.State == ConnectionState.Open)
|
||||
{
|
||||
await _connection.CloseAsync();
|
||||
}
|
||||
return StatusCode(500, new { success = false, message = "上传失败", error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// 将经纬度转换为地址信息
|
||||
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 = "";
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT Latitude, Longitude FROM xcx_conversation WHERE Guid = @Guid AND IsDeleted = 0", _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", request.Guid);
|
||||
|
||||
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字段
|
||||
using (MySqlCommand cmd = new MySqlCommand("UPDATE xcx_conversation SET UserLocation = @UserLocation WHERE Guid = @Guid AND IsDeleted = 0", _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", request.Guid);
|
||||
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)
|
||||
{
|
||||
DateTime nowtime = DateTime.Now;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 生成GUID
|
||||
string conversationGuid = string.IsNullOrEmpty(request.Guid) ? Guid.NewGuid().ToString("N") : request.Guid;
|
||||
long conversationId = 0;
|
||||
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))
|
||||
{
|
||||
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);
|
||||
cmd.Parameters.AddWithValue("@RecordTime", nowtime);
|
||||
cmd.Parameters.AddWithValue("@CreateTime", nowtime);
|
||||
cmd.Parameters.AddWithValue("@RecordTimeUTCStamp", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds());
|
||||
cmd.Parameters.AddWithValue("@IsDeleted", 0);
|
||||
cmd.Parameters.AddWithValue("@Guid", conversationGuid);
|
||||
cmd.Parameters.AddWithValue("@SpeakingTime", request.SpeakingTime);
|
||||
|
||||
object result = await cmd.ExecuteScalarAsync();
|
||||
conversationId = Convert.ToInt64(result);
|
||||
}
|
||||
|
||||
// 查询刚插入的记录,并左连接用户表
|
||||
if (conversationId > 0)
|
||||
{
|
||||
string query = @"SELECT convs.Id, convs.Guid, convs.UserKey, convs.ConversationContent, convs.SendMethod,
|
||||
convs.UserLocation, convs.Latitude, convs.Longitude, convs.RecordTime,
|
||||
convs.RecordTimeUTCStamp, convs.IsDeleted, convs.CreateTime, convs.MessageType, convs.SpeakingTime,
|
||||
users.UserName, users.WeChatName, users.PhoneNumber, users.AvatarUrl
|
||||
FROM xcx_conversation AS convs
|
||||
LEFT JOIN xcx_users AS users ON convs.UserKey = users.UserKey
|
||||
WHERE convs.Guid = @Guid";
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand(query, _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", conversationGuid);
|
||||
using (var reader = await cmd.ExecuteReaderAsync())
|
||||
{
|
||||
if (await reader.ReadAsync())
|
||||
{
|
||||
// 构建要发送到Redis的数据
|
||||
var messageData = new Dictionary<string, string>
|
||||
{
|
||||
["Id"] = reader.GetInt64(0).ToString(),
|
||||
["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)
|
||||
};
|
||||
|
||||
// 发送到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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(new { success = true, message = "收到!", conversationGuid, receivedTime = nowtime.ToString("yyyy-MM-dd HH:mm:ss") });
|
||||
}
|
||||
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参数决定是否添加过滤条件
|
||||
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";
|
||||
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),
|
||||
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, 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();
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", request.Guid);
|
||||
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);
|
||||
cmd.Parameters.AddWithValue("@RecordTime", nowtime);
|
||||
|
||||
int rowsAffected = await cmd.ExecuteNonQueryAsync();
|
||||
|
||||
if (rowsAffected == 0)
|
||||
{
|
||||
return NotFound(new { success = false, message = "记录不存在或无权限修改" });
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(new { success = true, message = "更新成功" , receivedTime = nowtime.ToString("yyyy-MM-dd HH:mm:ss") });
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand("UPDATE xcx_conversation SET IsDeleted = 1 WHERE Guid = @Guid AND UserKey = @UserKey AND IsDeleted = 0", _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", request.Guid);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 根据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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 分页查询会话记录
|
||||
[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参数决定是否添加过滤条件
|
||||
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";
|
||||
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),
|
||||
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)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询总数,根据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:私有
|
||||
public string? Guid { get; set; } // 会话唯一标识
|
||||
public int? SpeakingTime { get; set; } // 对话时长
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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 int MessageType { get; set; } = 0;
|
||||
public int? SpeakingTime { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteConversationRequest
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
public string Guid { get; set; } // 会话唯一标识
|
||||
public string UserKey { get; set; }
|
||||
}
|
||||
public class CheckAddressRequest
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
public string Guid { get; set; } // 会话唯一标识
|
||||
}
|
||||
public class GetConversationByGuidRequest
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
public string Guid { get; set; } // 会话唯一标识
|
||||
}
|
||||
|
||||
public class ConversationResponse
|
||||
{
|
||||
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; } // 1:公有消息,2:私有消息
|
||||
public int? SpeakingTime { get; set; }
|
||||
}
|
||||
|
||||
public class RedisMessageRequest
|
||||
{
|
||||
public string GroupName { get; set; } = "xcx_group";
|
||||
public string ConsumerName { get; set; }
|
||||
public int? Count { get; set; } = 1;
|
||||
}
|
||||
}
|
||||
32
WxCheckMvc/Controllers/HomeController.cs
Normal file
32
WxCheckMvc/Controllers/HomeController.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Diagnostics;
|
||||
using WxCheckMvc.Models;
|
||||
|
||||
namespace WxCheckMvc.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
private readonly ILogger<HomeController> _logger;
|
||||
|
||||
public HomeController(ILogger<HomeController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Privacy()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
}
|
||||
}
|
||||
324
WxCheckMvc/Controllers/LoginController.cs
Normal file
324
WxCheckMvc/Controllers/LoginController.cs
Normal file
@@ -0,0 +1,324 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace WxCheckMvc.Controllers
|
||||
{
|
||||
[Route("api/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class LoginController : ControllerBase
|
||||
{
|
||||
private readonly MySqlConnection _connection;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
public IConfiguration? configuration { get; set; }
|
||||
|
||||
public LoginController(MySqlConnection connection, IHttpClientFactory httpClientFactory, IConfiguration? configuration)
|
||||
{
|
||||
_connection = connection;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
// 获取微信小程序OpenID
|
||||
private async Task<string> GetWxOpenIdAsync(string code)
|
||||
{
|
||||
try
|
||||
{
|
||||
var appId = configuration["WeChat:AppId"];
|
||||
var appSecret = configuration["WeChat:AppSecret"];
|
||||
|
||||
if (string.IsNullOrEmpty(appId) || string.IsNullOrEmpty(appSecret))
|
||||
{
|
||||
throw new Exception("微信小程序配置缺失");
|
||||
}
|
||||
|
||||
var httpClient = _httpClientFactory.CreateClient();
|
||||
var url = $"https://api.weixin.qq.com/sns/jscode2session?appid={appId}&secret={appSecret}&js_code={code}&grant_type=authorization_code";
|
||||
|
||||
var response = await httpClient.GetAsync(url);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
var jsonDocument = JsonDocument.Parse(responseContent);
|
||||
|
||||
if (jsonDocument.RootElement.TryGetProperty("openid", out var openidElement))
|
||||
{
|
||||
return openidElement.GetString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果有错误信息,抛出异常
|
||||
if (jsonDocument.RootElement.TryGetProperty("errcode", out var errcodeElement) &&
|
||||
jsonDocument.RootElement.TryGetProperty("errmsg", out var errmsgElement))
|
||||
{
|
||||
throw new Exception($"获取OpenID失败: {errcodeElement.GetInt32()} - {errmsgElement.GetString()}");
|
||||
}
|
||||
throw new Exception("获取OpenID失败: 响应中未包含openid");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception($"获取微信OpenID时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private string GetToken(string entity)
|
||||
{
|
||||
string TokenString;
|
||||
var claims = new Claim[]
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()),
|
||||
new Claim(ClaimTypes.Name, entity)
|
||||
};
|
||||
|
||||
var secretByte = Encoding.UTF8.GetBytes(configuration["JwT:SecretKey"]);
|
||||
var signingKey = new SymmetricSecurityKey(secretByte);
|
||||
var a = SecurityAlgorithms.HmacSha256;
|
||||
|
||||
var signingCredentials = new SigningCredentials(signingKey, a);
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: configuration["JwT:Issuer"],
|
||||
audience: configuration["JwT:Audience"],//接收
|
||||
claims: claims,//存放的用户信息
|
||||
notBefore: DateTime.UtcNow,//发布时间
|
||||
expires: DateTime.UtcNow.AddMonths(12),
|
||||
signingCredentials: signingCredentials
|
||||
//有效期设置为1天signingCredentials //数字名
|
||||
);
|
||||
TokenString = new JwtSecurityTokenHandler().WriteToken(token);
|
||||
return TokenString;
|
||||
}
|
||||
|
||||
// 用户注册接口
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Register([FromBody] RegisterRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_connection.State != ConnectionState.Open)
|
||||
{
|
||||
await _connection.OpenAsync();
|
||||
}
|
||||
|
||||
// 检查用户是否存在
|
||||
UserResponse user = null;
|
||||
using (MySqlCommand checkCmd = new MySqlCommand("SELECT Id, UserName, UserKey, WeChatName, PhoneNumber, AvatarUrl, FirstLoginTime, IsDisabled, CreateTime, UpdateTime FROM xcx_users WHERE UserKey = @UserKey", _connection))
|
||||
{
|
||||
checkCmd.Parameters.AddWithValue("@UserKey", request.UserKey);
|
||||
using (var reader = await checkCmd.ExecuteReaderAsync())
|
||||
{
|
||||
if (await reader.ReadAsync())
|
||||
{
|
||||
user = new UserResponse
|
||||
{
|
||||
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),
|
||||
AvatarUrl = reader.IsDBNull(5) ? "" : reader.GetString(5),
|
||||
FirstLoginTime = reader.GetDateTime(6),
|
||||
IsDisabled = reader.GetBoolean(7),
|
||||
CreateTime = reader.GetDateTime(8),
|
||||
UpdateTime = reader.GetDateTime(9)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound(new { success = false, message = "用户不存在" });
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
using (MySqlCommand cmd = new MySqlCommand("UPDATE xcx_users SET UserName = @UserName, WeChatName = @WeChatName, PhoneNumber = @PhoneNumber, AvatarUrl = @AvatarUrl, UpdateTime = NOW() WHERE UserKey = @UserKey", _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@UserName", request.UserName ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@WeChatName", request.WeChatName ?? "");
|
||||
cmd.Parameters.AddWithValue("@PhoneNumber", request.PhoneNumber ?? "");
|
||||
cmd.Parameters.AddWithValue("@AvatarUrl", request.AvatarUrl ?? (object)DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@UserKey", request.UserKey);
|
||||
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
|
||||
// 获取更新后的用户信息
|
||||
UserResponse updatedUser = null;
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT Id, UserName, UserKey, WeChatName, PhoneNumber, AvatarUrl, FirstLoginTime, IsDisabled, CreateTime, UpdateTime FROM xcx_users WHERE UserKey = @UserKey", _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@UserKey", request.UserKey);
|
||||
using (var reader = await cmd.ExecuteReaderAsync())
|
||||
{
|
||||
if (await reader.ReadAsync())
|
||||
{
|
||||
updatedUser = new UserResponse
|
||||
{
|
||||
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),
|
||||
AvatarUrl = reader.IsDBNull(5) ? "" : reader.GetString(5),
|
||||
FirstLoginTime = reader.GetDateTime(6),
|
||||
IsDisabled = reader.GetBoolean(7),
|
||||
CreateTime = reader.GetDateTime(8),
|
||||
UpdateTime = reader.GetDateTime(9),
|
||||
Token = GetToken(request.UserKey)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(new { success = true, data = updatedUser });
|
||||
}
|
||||
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> Login([FromBody] LoginRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
string openId;
|
||||
try
|
||||
{
|
||||
openId = await GetWxOpenIdAsync(request.Code);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new { success = false, message = "获取微信OpenID失败", error = ex.Message });
|
||||
}
|
||||
|
||||
if (_connection.State != ConnectionState.Open)
|
||||
{
|
||||
await _connection.OpenAsync();
|
||||
}
|
||||
|
||||
UserResponse user = null;
|
||||
|
||||
// 检查用户是否存在
|
||||
using (MySqlCommand checkCmd = new MySqlCommand("SELECT COUNT(1) FROM xcx_users WHERE UserKey = @UserKey", _connection))
|
||||
{
|
||||
checkCmd.Parameters.AddWithValue("@UserKey", openId);
|
||||
int count = Convert.ToInt32(await checkCmd.ExecuteScalarAsync());
|
||||
|
||||
// 如果用户不存在,则注册新用户
|
||||
if (count == 0)
|
||||
{
|
||||
using (MySqlCommand insertCmd = new MySqlCommand("INSERT INTO xcx_users (UserKey, FirstLoginTime, IsDisabled, CreateTime, UpdateTime) VALUES (@UserKey, @FirstLoginTime, @IsDisabled, NOW(), NOW())", _connection))
|
||||
{
|
||||
insertCmd.Parameters.AddWithValue("@UserKey", openId);
|
||||
insertCmd.Parameters.AddWithValue("@FirstLoginTime", DateTime.Now);
|
||||
insertCmd.Parameters.AddWithValue("@IsDisabled", 0); // 默认启用
|
||||
|
||||
await insertCmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT Id, UserName, UserKey, WeChatName, PhoneNumber, AvatarUrl, FirstLoginTime, IsDisabled, CreateTime, UpdateTime FROM xcx_users WHERE UserKey = @UserKey", _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@UserKey", openId);
|
||||
|
||||
using (var reader = await cmd.ExecuteReaderAsync())
|
||||
{
|
||||
if (await reader.ReadAsync())
|
||||
{
|
||||
user = new UserResponse
|
||||
{
|
||||
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),
|
||||
AvatarUrl = reader.IsDBNull(5) ? "" : reader.GetString(5),
|
||||
FirstLoginTime = reader.GetDateTime(6),
|
||||
IsDisabled = reader.GetBoolean(7),
|
||||
CreateTime = reader.GetDateTime(8),
|
||||
UpdateTime = reader.GetDateTime(9),
|
||||
Token = GetToken(openId)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound(new { success = false, message = "用户不存在" });
|
||||
}
|
||||
|
||||
if (user.IsDisabled)
|
||||
{
|
||||
return Ok(new { success = false, message = "用户已被禁用" });
|
||||
}
|
||||
|
||||
return Ok(new { success = true, data = user });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return StatusCode(500, new { success = false, message = "登录失败", error = ex.Message });
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_connection.State == ConnectionState.Open)
|
||||
{
|
||||
await _connection.CloseAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 请求和响应模型
|
||||
public class RegisterRequest
|
||||
{
|
||||
public string UserName { get; set; }
|
||||
public string UserKey { get; set; } // 改为直接传入UserKey
|
||||
public string WeChatName { get; set; }
|
||||
public string PhoneNumber { get; set; }
|
||||
public string AvatarUrl { get; set; }
|
||||
}
|
||||
|
||||
public class LoginRequest
|
||||
{
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
public class UserResponse
|
||||
{
|
||||
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 string AvatarUrl { get; set; }
|
||||
public DateTime FirstLoginTime { get; set; }
|
||||
public bool IsDisabled { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
public string Token { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user