Merge branch 'main' of http://blv-rd.tech:3001/Boonlive_RD_Web/Wx_WxCheck_Prod
This commit is contained in:
26
.amazonq/prompts/openspec-apply.md
Normal file
26
.amazonq/prompts/openspec-apply.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
description: Implement an approved OpenSpec change and keep tasks in sync.
|
||||
---
|
||||
|
||||
The user wants to apply the following change. Use the openspec instructions to implement the approved change.
|
||||
|
||||
<ChangeId>
|
||||
$ARGUMENTS
|
||||
</ChangeId>
|
||||
<!-- OPENSPEC:START -->
|
||||
**Guardrails**
|
||||
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
|
||||
- Keep changes tightly scoped to the requested outcome.
|
||||
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
|
||||
|
||||
**Steps**
|
||||
Track these steps as TODOs and complete them one by one.
|
||||
1. Read `changes/<id>/proposal.md`, `design.md` (if present), and `tasks.md` to confirm scope and acceptance criteria.
|
||||
2. Work through tasks sequentially, keeping edits minimal and focused on the requested change.
|
||||
3. Confirm completion before updating statuses—make sure every item in `tasks.md` is finished.
|
||||
4. Update the checklist after all work is done so each task is marked `- [x]` and reflects reality.
|
||||
5. Reference `openspec list` or `openspec show <item>` when additional context is required.
|
||||
|
||||
**Reference**
|
||||
- Use `openspec show <id> --json --deltas-only` if you need additional context from the proposal while implementing.
|
||||
<!-- OPENSPEC:END -->
|
||||
30
.amazonq/prompts/openspec-archive.md
Normal file
30
.amazonq/prompts/openspec-archive.md
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
description: Archive a deployed OpenSpec change and update specs.
|
||||
---
|
||||
|
||||
The user wants to archive the following deployed change. Use the openspec instructions to archive the change and update specs.
|
||||
|
||||
<ChangeId>
|
||||
$ARGUMENTS
|
||||
</ChangeId>
|
||||
<!-- OPENSPEC:START -->
|
||||
**Guardrails**
|
||||
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
|
||||
- Keep changes tightly scoped to the requested outcome.
|
||||
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
|
||||
|
||||
**Steps**
|
||||
1. Determine the change ID to archive:
|
||||
- If this prompt already includes a specific change ID (for example inside a `<ChangeId>` block populated by slash-command arguments), use that value after trimming whitespace.
|
||||
- If the conversation references a change loosely (for example by title or summary), run `openspec list` to surface likely IDs, share the relevant candidates, and confirm which one the user intends.
|
||||
- Otherwise, review the conversation, run `openspec list`, and ask the user which change to archive; wait for a confirmed change ID before proceeding.
|
||||
- If you still cannot identify a single change ID, stop and tell the user you cannot archive anything yet.
|
||||
2. Validate the change ID by running `openspec list` (or `openspec show <id>`) and stop if the change is missing, already archived, or otherwise not ready to archive.
|
||||
3. Run `openspec archive <id> --yes` so the CLI moves the change and applies spec updates without prompts (use `--skip-specs` only for tooling-only work).
|
||||
4. Review the command output to confirm the target specs were updated and the change landed in `changes/archive/`.
|
||||
5. Validate with `openspec validate --strict` and inspect with `openspec show <id>` if anything looks off.
|
||||
|
||||
**Reference**
|
||||
- Use `openspec list` to confirm change IDs before archiving.
|
||||
- Inspect refreshed specs with `openspec list --specs` and address any validation issues before handing off.
|
||||
<!-- OPENSPEC:END -->
|
||||
31
.amazonq/prompts/openspec-proposal.md
Normal file
31
.amazonq/prompts/openspec-proposal.md
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
description: Scaffold a new OpenSpec change and validate strictly.
|
||||
---
|
||||
|
||||
The user has requested the following change proposal. Use the openspec instructions to create their change proposal.
|
||||
|
||||
<UserRequest>
|
||||
$ARGUMENTS
|
||||
</UserRequest>
|
||||
<!-- OPENSPEC:START -->
|
||||
**Guardrails**
|
||||
- Favor straightforward, minimal implementations first and add complexity only when it is requested or clearly required.
|
||||
- Keep changes tightly scoped to the requested outcome.
|
||||
- Refer to `openspec/AGENTS.md` (located inside the `openspec/` directory—run `ls openspec` or `openspec update` if you don't see it) if you need additional OpenSpec conventions or clarifications.
|
||||
- Identify any vague or ambiguous details and ask the necessary follow-up questions before editing files.
|
||||
- Do not write any code during the proposal stage. Only create design documents (proposal.md, tasks.md, design.md, and spec deltas). Implementation happens in the apply stage after approval.
|
||||
|
||||
**Steps**
|
||||
1. Review `openspec/project.md`, run `openspec list` and `openspec list --specs`, and inspect related code or docs (e.g., via `rg`/`ls`) to ground the proposal in current behaviour; note any gaps that require clarification.
|
||||
2. Choose a unique verb-led `change-id` and scaffold `proposal.md`, `tasks.md`, and `design.md` (when needed) under `openspec/changes/<id>/`.
|
||||
3. Map the change into concrete capabilities or requirements, breaking multi-scope efforts into distinct spec deltas with clear relationships and sequencing.
|
||||
4. Capture architectural reasoning in `design.md` when the solution spans multiple systems, introduces new patterns, or demands trade-off discussion before committing to specs.
|
||||
5. Draft spec deltas in `changes/<id>/specs/<capability>/spec.md` (one folder per capability) using `## ADDED|MODIFIED|REMOVED Requirements` with at least one `#### Scenario:` per requirement and cross-reference related capabilities when relevant.
|
||||
6. Draft `tasks.md` as an ordered list of small, verifiable work items that deliver user-visible progress, include validation (tests, tooling), and highlight dependencies or parallelizable work.
|
||||
7. Validate with `openspec validate <id> --strict` and resolve every issue before sharing the proposal.
|
||||
|
||||
**Reference**
|
||||
- Use `openspec show <id> --json --deltas-only` or `openspec show <spec> --type spec` to inspect details when validation fails.
|
||||
- Search existing requirements with `rg -n "Requirement:|Scenario:" openspec/specs` before writing new ones.
|
||||
- Explore the codebase with `rg <keyword>`, `ls`, or direct file reads so proposals align with current implementation realities.
|
||||
<!-- OPENSPEC:END -->
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,3 +3,7 @@
|
||||
/WxCheckApi/.vs
|
||||
/WxCheckApi/*.user
|
||||
/.vscode
|
||||
WxCheckMvc/obj
|
||||
WxCheckMvc/.vs
|
||||
WxCheckMvc/bin
|
||||
node_modules
|
||||
|
||||
93
.trae/documents/会话管理和用户管理页面优化.md
Normal file
93
.trae/documents/会话管理和用户管理页面优化.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# 会话管理和用户管理页面优化
|
||||
|
||||
## 1. 优化conversations模块的发送方式显示
|
||||
|
||||
### 实现方案
|
||||
- 修改 `ConversationList.vue` 中的发送方式列,将其重构为tag标签形式
|
||||
- 当 `sendMethod` 为文字类型时,显示success样式的tag标签,内容为"text"
|
||||
- 当 `sendMethod` 为语音类型时,显示默认样式的tag标签,内容为"voice"
|
||||
|
||||
### 代码修改点
|
||||
- `src/views/ConversationList.vue:98-104`:修改发送方式列的实现,添加tag标签模板
|
||||
|
||||
## 2. 实现手机号脱敏与时间格式化功能
|
||||
|
||||
### 实现方案
|
||||
- 创建工具函数处理手机号脱敏和时间格式化
|
||||
- 实现手机号自动脱敏,默认隐藏中间4-8位数字
|
||||
- 添加点击交互,支持显示/隐藏完整手机号
|
||||
- 实现时间格式转换,将时间数据中的"T"字符替换为空格
|
||||
|
||||
### 代码修改点
|
||||
- 创建 `src/utils/formatters.js`:添加手机号脱敏和时间格式化工具函数
|
||||
- `src/views/ConversationList.vue`:应用手机号脱敏和时间格式化
|
||||
- `src/views/UserList.vue`:应用手机号脱敏和时间格式化
|
||||
|
||||
## 3. 重构表格组件与实现无限滚动分页
|
||||
|
||||
### 实现方案
|
||||
- 将现有el-table组件包装在el-scrollbar中,实现滚动加载
|
||||
- 修改 `fetchConversations` 方法,添加分页参数
|
||||
- 实现滚动到底部自动加载下一页数据
|
||||
- 添加加载状态提示,避免重复请求
|
||||
- 设置固定分页大小为20条/页
|
||||
|
||||
### 代码修改点
|
||||
- `src/views/ConversationList.vue`:
|
||||
- 添加el-scrollbar组件包装el-table
|
||||
- 修改fetchConversations方法,添加分页逻辑
|
||||
- 实现滚动加载功能
|
||||
- 移除传统分页控件
|
||||
|
||||
## 4. 优化用户管理页面
|
||||
|
||||
### 实现方案
|
||||
- 移除UserList页面的分页控件及相关逻辑
|
||||
- 调整表格配置,不分页加载所有用户数据
|
||||
- 应用时间格式转换,将时间数据中的"T"字符替换为空格
|
||||
|
||||
### 代码修改点
|
||||
- `src/views/UserList.vue`:
|
||||
- 移除分页控件和相关数据
|
||||
- 修改fetchUsers方法,移除分页逻辑
|
||||
- 应用时间格式化
|
||||
|
||||
## 5. 文档记录
|
||||
|
||||
### 实现方案
|
||||
- 在openspec目录下创建详细的修改记录文档
|
||||
- 记录修改内容、原因及影响范围
|
||||
|
||||
### 代码修改点
|
||||
- 创建 `openspec/changes/optimize-conversation-user-management/` 目录
|
||||
- 创建 `proposal.md`:描述问题和解决方案
|
||||
- 创建 `tasks.md`:列出具体实现任务
|
||||
- 创建 `implementation.md`:详细记录技术实现和最佳实践
|
||||
|
||||
## 实现顺序
|
||||
|
||||
1. 创建工具函数文件 `src/utils/formatters.js`
|
||||
2. 优化ConversationList.vue的发送方式显示
|
||||
3. 实现手机号脱敏与时间格式化功能
|
||||
4. 重构表格组件与实现无限滚动分页
|
||||
5. 优化用户管理页面
|
||||
6. 创建修改记录文档
|
||||
|
||||
## 预期效果
|
||||
|
||||
- 会话记录页面:
|
||||
- 发送方式以tag标签形式显示
|
||||
- 手机号自动脱敏,支持点击显示/隐藏完整号码
|
||||
- 时间格式统一为"YYYY-MM-DD HH:mm:ss"
|
||||
- 表格实现无限滚动加载,提升用户体验
|
||||
|
||||
- 用户管理页面:
|
||||
- 移除分页控件,加载所有用户数据
|
||||
- 时间格式统一为"YYYY-MM-DD HH:mm:ss"
|
||||
- 手机号自动脱敏,支持点击显示/隐藏完整号码
|
||||
|
||||
- 代码质量:
|
||||
- 工具函数复用性高
|
||||
- 代码结构清晰,易于维护
|
||||
- 符合openspec开发规范
|
||||
- 详细的修改记录文档
|
||||
106
.trae/documents/后台管理网站开发计划.md
Normal file
106
.trae/documents/后台管理网站开发计划.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# 后台管理网站开发计划
|
||||
|
||||
## 1. 项目初始化
|
||||
|
||||
* 初始化Vue 3.x + Element Plus + Vite项目
|
||||
|
||||
* 配置项目目录结构
|
||||
|
||||
* 安装必要依赖:vue-router、Pinia、axios
|
||||
|
||||
## 2. 项目基础配置
|
||||
|
||||
* 创建路由配置文件:`src/router/index.js`
|
||||
|
||||
* 创建Pinia状态管理:`src/store/index.js`、`src/store/auth.js`、`src/store/theme.js`
|
||||
|
||||
* 配置axios拦截器:`src/utils/request.js`
|
||||
|
||||
* 创建全局样式文件:`src/styles/main.scss`、`src/styles/variables.scss`、`src/styles/responsive.scss`
|
||||
|
||||
## 3. 登录功能实现
|
||||
|
||||
* 创建登录页面:`src/views/Login.vue`
|
||||
|
||||
* 实现登录验证逻辑(固定账号密码:Admin/Admin)
|
||||
|
||||
* 实现登录状态管理
|
||||
|
||||
* 配置路由守卫,保护受保护页面
|
||||
|
||||
## 4. 主题切换功能
|
||||
|
||||
* 创建主题切换组件:`src/components/ThemeSwitcher.vue`
|
||||
|
||||
* 实现深色/浅色模式切换逻辑
|
||||
|
||||
* 实现主题状态持久化(localStorage)
|
||||
|
||||
## 5. 响应式布局和菜单
|
||||
|
||||
* 创建布局组件:`src/components/Layout/Layout.vue`、`src/components/Layout/Sidebar.vue`、`src/components/Layout/Header.vue`
|
||||
|
||||
* 实现侧边栏菜单(桌面/平板端)
|
||||
|
||||
* 实现抽屉式菜单(手机端)
|
||||
|
||||
* 实现响应式布局适配
|
||||
|
||||
## 6. 会话记录管理页面
|
||||
|
||||
* 创建会话记录管理页面:`src/views/ConversationList.vue`
|
||||
|
||||
* 实现会话记录查询功能
|
||||
|
||||
* 实现多条件筛选功能(时间范围、用户、消息类型、部门)
|
||||
|
||||
* 实现会话记录表格展示
|
||||
|
||||
## 7. 用户管理页面
|
||||
|
||||
* 创建用户管理页面:`src/views/UserList.vue`
|
||||
|
||||
* 实现用户列表查询功能
|
||||
|
||||
* 实现用户表格展示
|
||||
|
||||
## 8. 首页实现
|
||||
|
||||
* 创建首页:`src/views/Home.vue`
|
||||
|
||||
* 实现系统概览和统计信息展示
|
||||
|
||||
## 9. 测试和优化
|
||||
|
||||
* 测试所有功能模块
|
||||
|
||||
* 优化响应式布局
|
||||
|
||||
* 优化页面性能
|
||||
|
||||
* 完善错误处理
|
||||
|
||||
## 10. 文档更新
|
||||
|
||||
* 更新项目文档
|
||||
|
||||
* 记录开发过程中的变更
|
||||
|
||||
## 技术规范遵循
|
||||
|
||||
* 使用Vue 3.x Composition API和`<script setup>`语法
|
||||
|
||||
* 遵循Element Plus组件库规范
|
||||
|
||||
* 实现响应式设计,优先适配手机宽度
|
||||
|
||||
* 采用模块化设计思路
|
||||
|
||||
* 严格遵循openspec文档中规定的API接口和数据模型
|
||||
|
||||
## 变更记录要求
|
||||
|
||||
* 所有代码修改、功能调整或配置变更均需在changes文档中进行详细记录
|
||||
|
||||
* 记录内容包括:变更时间、变更人、变更模块、变更类型(新增/修改/删除)、变更具体内容、关联需求ID及变更原因
|
||||
|
||||
18
AGENTS.md
Normal file
18
AGENTS.md
Normal file
@@ -0,0 +1,18 @@
|
||||
<!-- OPENSPEC:START -->
|
||||
# OpenSpec Instructions
|
||||
|
||||
These instructions are for AI assistants working in this project.
|
||||
|
||||
Always open `@/openspec/AGENTS.md` when the request:
|
||||
- Mentions planning or proposals (words like proposal, spec, change, plan)
|
||||
- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
|
||||
- Sounds ambiguous and you need the authoritative spec before coding
|
||||
|
||||
Use `@/openspec/AGENTS.md` to learn:
|
||||
- How to create and apply change proposals
|
||||
- Spec format and conventions
|
||||
- Project structure and guidelines
|
||||
|
||||
Keep this managed block so 'openspec update' can refresh the instructions.
|
||||
|
||||
<!-- OPENSPEC:END -->
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "9.0.10",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
35
WxCheckApi/.vscode/launch.json
vendored
35
WxCheckApi/.vscode/launch.json
vendored
@@ -1,35 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// 使用 IntelliSense 找出 C# 调试存在哪些属性
|
||||
// 将悬停用于现有属性的说明
|
||||
// 有关详细信息,请访问 https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md。
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// 如果已更改目标框架,请确保更新程序路径。
|
||||
"program": "${workspaceFolder}/bin/Debug/net8.0/WxCheckApi.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}",
|
||||
"stopAtEntry": false,
|
||||
// 启用在启动 ASP.NET Core 时启动 Web 浏览器。有关详细信息: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
||||
41
WxCheckApi/.vscode/tasks.json
vendored
41
WxCheckApi/.vscode/tasks.json
vendored
@@ -1,41 +0,0 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/WxCheckApi.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/WxCheckApi.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/WxCheckApi.csproj"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,766 +0,0 @@
|
||||
# 微信小程序:语音信息打卡 API 接口文档
|
||||
|
||||
本文档详细描述了WxCheck项目中Login控制器和Check控制器的所有API接口,包括接口功能、请求参数、响应格式以及调用示例。
|
||||
|
||||
## 基础信息
|
||||
|
||||
- **API基础路径**:`https://wx-xcx-check.blv-oa.com:4433/api/[controller]/[action]`
|
||||
- **请求方式**:POST
|
||||
|
||||
## 统一响应格式
|
||||
|
||||
所有接口返回以下统一格式的JSON响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true/false,
|
||||
"message": "操作结果描述",
|
||||
"data": {...}, // 可选,返回的具体数据
|
||||
"error": "错误信息" // 可选,错误时返回
|
||||
}
|
||||
```
|
||||
|
||||
## 1. Login控制器接口
|
||||
|
||||
### 1.1 用户注册接口
|
||||
|
||||
#### 接口描述
|
||||
用户信息更新功能,根据传入的UserKey更新用户的UserName、WeChatName和PhoneNumber信息。
|
||||
|
||||
#### 接口路径
|
||||
`/api/Login/Register`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| UserName | string | 否 | 用户名(可以为空) |
|
||||
| UserKey | string | 是 | 用户唯一标识键 |
|
||||
| WeChatName | string | 否 | 微信名称 |
|
||||
| PhoneNumber | string | 否 | 电话号码 |
|
||||
| AvatarUrl | string | 否 | 头像地址 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"UserName": "张三",
|
||||
"UserKey": "openid_from_wechat",
|
||||
"WeChatName": "张三的微信",
|
||||
"PhoneNumber": "13800138000",
|
||||
"AvatarUrl": "https://example.com/avatar.jpg"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"Id": 1,
|
||||
"UserName": "张三",
|
||||
"UserKey": "openid_from_wechat",
|
||||
"WeChatName": "张三的微信",
|
||||
"PhoneNumber": "13800138000",
|
||||
"AvatarUrl": "https://example.com/avatar.jpg",
|
||||
"FirstLoginTime": "2023-10-31T10:00:00",
|
||||
"IsDisabled": false,
|
||||
"CreateTime": "2023-10-31T10:00:00",
|
||||
"UpdateTime": "2023-10-31T15:30:00",
|
||||
"Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "用户不存在"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "更新用户信息失败",
|
||||
"error": "数据库连接错误"
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 用户登录接口
|
||||
|
||||
#### 接口描述
|
||||
用户登录功能,将微信小程序code转换为OpenID并验证用户身份。如果用户不存在,则自动创建新用户记录。无论用户是否存在,都返回完整的用户信息和Token。
|
||||
|
||||
#### 接口路径
|
||||
`/api/Login/Login`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| Code | string | 是 | 微信小程序登录凭证code,用于获取OpenID |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"Code": "wx_login_code_here"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应(已存在用户):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"Id": 1,
|
||||
"UserName": "张三",
|
||||
"UserKey": "openid_from_wechat",
|
||||
"WeChatName": "张三的微信",
|
||||
"PhoneNumber": "13800138000",
|
||||
"AvatarUrl": "https://example.com/avatar.jpg",
|
||||
"FirstLoginTime": "2023-10-31T10:00:00",
|
||||
"IsDisabled": false,
|
||||
"CreateTime": "2023-10-31T10:00:00",
|
||||
"UpdateTime": "2023-10-31T10:00:00",
|
||||
"Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**成功响应(新用户自动注册):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"Id": 2,
|
||||
"UserName": "",
|
||||
"UserKey": "new_openid_from_wechat",
|
||||
"WeChatName": "",
|
||||
"PhoneNumber": "",
|
||||
"AvatarUrl": "",
|
||||
"FirstLoginTime": "2023-10-31T16:00:00",
|
||||
"IsDisabled": false,
|
||||
"CreateTime": "2023-10-31T16:00:00",
|
||||
"UpdateTime": "2023-10-31T16:00:00",
|
||||
"Token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "用户已被禁用"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "获取微信OpenID失败",
|
||||
"error": "微信API调用失败"
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Check控制器接口
|
||||
|
||||
### 2.1 检查地址接口
|
||||
|
||||
#### 接口描述
|
||||
根据会话记录的GUID查询经纬度信息,并转换为详细地址更新到数据库中。
|
||||
|
||||
#### 接口路径
|
||||
`/api/Check/CheckAddress`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| Guid | string | 是 | 会话唯一标识 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"Guid": "会话唯一标识"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "地址更新成功",
|
||||
"address": "北京市海淀区中关村南大街5号"
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "记录不存在或已被删除"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "更新失败",
|
||||
"error": "数据库操作错误"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 添加会话记录接口
|
||||
|
||||
#### 接口描述
|
||||
添加新的会话记录到系统中。
|
||||
|
||||
#### 接口路径
|
||||
`/api/Check/AddConversation`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| UserKey | string | 是 | 用户唯一标识键 |
|
||||
| ConversationContent | string | 是 | 会话内容 |
|
||||
| SendMethod | string | 是 | 发送方式 |
|
||||
| UserLocation | string | 否 | 用户定位信息(经纬度格式:"纬度,经度") |
|
||||
| MessageType | int | 否 | 1:公有消息,2:私有消息 |
|
||||
| Guid | string | 否 | 会话唯一标识(不提供则系统自动生成) |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"UserKey": "user_123456",
|
||||
"ConversationContent": "这是一条测试消息",
|
||||
"SendMethod": "文本",
|
||||
"UserLocation": "39.9087,116.3975",
|
||||
"MessageType": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "收到!",
|
||||
"conversationGuid": "会话唯一标识",
|
||||
"receivedTime": "2023-10-31 10:05:00"
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "发送失败",
|
||||
"error": "数据库操作错误"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 查询会话记录接口
|
||||
|
||||
#### 接口描述
|
||||
根据用户唯一标识键查询该用户的所有会话记录。
|
||||
|
||||
#### 接口路径
|
||||
`https://wx-xcx-check.blv-oa.com/api/Check/GetConversations`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| UserKey | string | 是 | 用户唯一标识键 |
|
||||
| MessageType | int | 否 | 0:不判断消息类型(默认),1:只返回公有消息,2:只返回私有消息 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"UserKey": "user_123456",
|
||||
"MessageType": 0
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": [
|
||||
{
|
||||
"Id": 1,
|
||||
"Guid": "会话唯一标识",
|
||||
"UserKey": "user_123456",
|
||||
"ConversationContent": "这是一条测试消息",
|
||||
"SendMethod": "文本",
|
||||
"UserLocation": "北京市海淀区",
|
||||
"Latitude": "39.9087",
|
||||
"Longitude": "116.3975",
|
||||
"RecordTime": "2023-10-31T10:05:00",
|
||||
"RecordTimeUTCStamp": 1698732300000,
|
||||
"IsDeleted": false,
|
||||
"CreateTime": "2023-10-31T10:05:00",
|
||||
"MessageType": 1
|
||||
},
|
||||
{
|
||||
"Id": 2,
|
||||
"Guid": "会话唯一标识",
|
||||
"UserKey": "user_123456",
|
||||
"ConversationContent": "这是第二条测试消息",
|
||||
"SendMethod": "图片",
|
||||
"UserLocation": "北京市朝阳区",
|
||||
"Latitude": "39.9180",
|
||||
"Longitude": "116.4272",
|
||||
"RecordTime": "2023-10-31T10:06:00",
|
||||
"RecordTimeUTCStamp": 1698732360000,
|
||||
"IsDeleted": false,
|
||||
"CreateTime": "2023-10-31T10:06:00",
|
||||
"MessageType": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "查询失败",
|
||||
"error": "数据库连接错误"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 分页查询会话记录接口
|
||||
|
||||
#### 接口描述
|
||||
分页查询用户的会话记录,每页默认10条,按时间戳从**最新到最旧**排序,支持根据消息类型进行过滤。
|
||||
|
||||
#### 接口路径
|
||||
`https://wx-xcx-check.blv-oa.com:4433/api/Check/GetConversationsByPage`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| UserKey | string | 是 | 用户唯一标识键 |
|
||||
| Page | int | 否 | 页码,默认为1,小于1时自动设为1 |
|
||||
| PageSize | int | 否 | 每页数量,默认为10,最大100,小于1时自动设为10 |
|
||||
| MessageType | int | 否 | 0:不判断消息类型(默认),1:只返回公有消息,2:只返回私有消息 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"UserKey": "user_123456",
|
||||
"Page": 1,
|
||||
"PageSize": 10,
|
||||
"MessageType": 0
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"conversations": [
|
||||
{
|
||||
"Id": 1,
|
||||
"Guid": "会话唯一标识",
|
||||
"UserKey": "user_123456",
|
||||
"ConversationContent": "这是一条测试消息",
|
||||
"SendMethod": "文本",
|
||||
"UserLocation": "北京市海淀区",
|
||||
"Latitude": "39.9087",
|
||||
"Longitude": "116.3975",
|
||||
"RecordTime": "2023-10-31T10:00:00",
|
||||
"RecordTimeUTCStamp": 1698727200000,
|
||||
"IsDeleted": false,
|
||||
"CreateTime": "2023-10-31T10:00:00",
|
||||
"MessageType": 1
|
||||
},
|
||||
{
|
||||
"Id": 2,
|
||||
"Guid": "会话唯一标识",
|
||||
"UserKey": "user_123456",
|
||||
"ConversationContent": "这是一条私有消息",
|
||||
"SendMethod": "文本",
|
||||
"UserLocation": "北京市朝阳区",
|
||||
"Latitude": "39.9180",
|
||||
"Longitude": "116.4272",
|
||||
"RecordTime": "2023-10-31T09:55:00",
|
||||
"RecordTimeUTCStamp": 1698724500000,
|
||||
"IsDeleted": false,
|
||||
"CreateTime": "2023-10-31T09:55:00",
|
||||
"MessageType": 2
|
||||
}
|
||||
],
|
||||
"totalCount": 25,
|
||||
"page": 1,
|
||||
"pageSize": 10,
|
||||
"totalPages": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "查询失败",
|
||||
"error": "数据库操作错误"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 根据GUID查询会话记录接口
|
||||
|
||||
#### 接口描述
|
||||
根据会话唯一标识(GUID)查询会话记录详情,不考虑IsDeleted状态。
|
||||
|
||||
#### 接口路径
|
||||
`/api/Check/GetConversationByGuid`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| Guid | string | 是 | 会话唯一标识 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"Guid": "会话唯一标识"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"Id": 1,
|
||||
"Guid": "会话唯一标识",
|
||||
"UserKey": "user_123456",
|
||||
"ConversationContent": "这是一条测试消息",
|
||||
"SendMethod": "文本",
|
||||
"UserLocation": "北京市海淀区",
|
||||
"Latitude": "39.9087",
|
||||
"Longitude": "116.3975",
|
||||
"RecordTime": "2023-10-31T10:05:00",
|
||||
"RecordTimeUTCStamp": 1698732300000,
|
||||
"IsDeleted": false,
|
||||
"CreateTime": "2023-10-31T10:05:00",
|
||||
"MessageType": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "未找到该记录"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "查询失败",
|
||||
"error": "数据库操作错误"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 更新会话记录接口
|
||||
|
||||
#### 接口描述
|
||||
更新指定GUID的会话记录,需要验证UserKey的权限。每次更新时,RecordTime会自动更新为当前时间。
|
||||
|
||||
#### 接口路径
|
||||
`/api/Check/UpdateConversation`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| Guid | string | 是 | 会话唯一标识 |
|
||||
| UserKey | string | 是 | 用户唯一标识键(用于权限验证) |
|
||||
| ConversationContent | string | 是 | 新的会话内容 |
|
||||
| SendMethod | string | 是 | 新的发送方式 |
|
||||
| UserLocation | string | 否 | 新的用户定位信息 |
|
||||
| MessageType | int | 否 | 1:公有消息,2:私有消息 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"Guid": "会话唯一标识",
|
||||
"UserKey": "user_123456",
|
||||
"ConversationContent": "更新后的会话内容",
|
||||
"SendMethod": "文本",
|
||||
"UserLocation": "北京市西城区",
|
||||
"MessageType": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "更新成功",
|
||||
"receivedTime": "2023-10-31 10:10:00"
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "记录不存在或无权限修改"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "更新失败",
|
||||
"error": "数据库操作错误"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.7 删除会话记录接口
|
||||
|
||||
#### 接口描述
|
||||
软删除会话记录(将IsDeleted标记为1),需要验证UserKey的权限。
|
||||
|
||||
#### 接口路径
|
||||
`/api/Check/DeleteConversation`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| Guid | string | 是 | 会话唯一标识 |
|
||||
| UserKey | string | 是 | 用户唯一标识键(用于权限验证) |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"Guid": "会话唯一标识",
|
||||
"UserKey": "user_123456"
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "删除成功"
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "记录不存在或已被删除"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "删除失败",
|
||||
"error": "数据库操作错误"
|
||||
}
|
||||
```
|
||||
|
||||
### 2.8 从Redis Stream读取消息接口
|
||||
|
||||
#### 接口描述
|
||||
从Redis Stream读取新的会话消息。
|
||||
|
||||
#### 接口路径
|
||||
`/api/Check/ReadMessageFromRedis`
|
||||
|
||||
#### 请求参数
|
||||
|
||||
| 参数名 | 类型 | 必填 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| GroupName | string | 否 | 消费组名称,默认:xcx_group |
|
||||
| ConsumerName | string | 否 | 消费者名称,默认:consumer_时间戳 |
|
||||
| Count | int | 否 | 读取消息数量,默认:1 |
|
||||
|
||||
#### 请求示例
|
||||
|
||||
```json
|
||||
{
|
||||
"GroupName": "xcx_group",
|
||||
"ConsumerName": "consumer_1",
|
||||
"Count": 5
|
||||
}
|
||||
```
|
||||
|
||||
#### 响应示例
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "成功读取消息",
|
||||
"data": [
|
||||
{
|
||||
"MessageId": "1635739200000-0",
|
||||
"Id": "1",
|
||||
"Guid": "会话唯一标识",
|
||||
"UserKey": "user_123456",
|
||||
"ConversationContent": "测试消息",
|
||||
"SendMethod": "文本",
|
||||
"UserLocation": "北京市海淀区",
|
||||
"Latitude": "39.9087",
|
||||
"Longitude": "116.3975",
|
||||
"RecordTime": "2023-10-31T10:00:00",
|
||||
"RecordTimeUTCStamp": "1698727200000",
|
||||
"IsDeleted": "false",
|
||||
"CreateTime": "2023-10-31T10:00:00",
|
||||
"MessageType": "1",
|
||||
"UserName": "张三",
|
||||
"WeChatName": "张三的微信",
|
||||
"PhoneNumber": "13800138000",
|
||||
"AvatarUrl": "https://example.com/avatar.jpg"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "读取消息失败",
|
||||
"error": "Redis操作错误"
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 接口调用说明
|
||||
|
||||
### 3.1 HTTP客户端调用示例(JavaScript)
|
||||
|
||||
```javascript
|
||||
// 封装API请求函数
|
||||
async function callApi(endpoint, data) {
|
||||
try {
|
||||
const response = await fetch(`http://your-api-domain/api${endpoint}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('API调用失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 用户信息更新示例
|
||||
async function updateUser() {
|
||||
const result = await callApi('/Login/Register', {
|
||||
UserName: '张三',
|
||||
UserKey: 'openid_from_wechat',
|
||||
WeChatName: '张三的微信',
|
||||
PhoneNumber: '13800138000'
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log('用户信息更新成功');
|
||||
} else {
|
||||
console.log('用户信息更新失败:', result.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 用户登录示例
|
||||
async function loginUser() {
|
||||
const result = await callApi('/Login/Login', {
|
||||
Code: 'wx_login_code_here'
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log('登录成功,用户信息:', result.data);
|
||||
// 保存用户信息和Token到本地存储
|
||||
localStorage.setItem('userInfo', JSON.stringify(result.data));
|
||||
localStorage.setItem('token', result.data.Token);
|
||||
} else {
|
||||
console.log('登录失败:', result.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加会话示例
|
||||
async function addConversation() {
|
||||
const result = await callApi('/Check/AddConversation', {
|
||||
UserKey: 'user_123456',
|
||||
ConversationContent: '测试会话内容',
|
||||
SendMethod: '文本',
|
||||
UserLocation: '北京',
|
||||
MessageType: 0
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log('会话添加成功');
|
||||
} else {
|
||||
console.log('会话添加失败:', result.message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 常见错误处理
|
||||
|
||||
1. **数据库连接错误**:检查数据库服务是否正常运行,连接字符串是否正确
|
||||
2. **权限验证失败**:确保提供的UserKey与操作资源匹配
|
||||
3. **记录不存在**:在更新或删除前确认记录ID和UserKey的正确性
|
||||
4. **网络错误**:检查API服务是否正常运行,网络连接是否稳定
|
||||
|
||||
## 4. 安全注意事项
|
||||
|
||||
1. **参数验证**:所有接口都应在前端进行基本的数据格式验证
|
||||
2. **UserKey保护**:UserKey作为用户身份标识,应妥善保护,避免泄露
|
||||
3. **错误信息处理**:生产环境中应避免返回详细的错误信息,防止信息泄露
|
||||
4. **请求频率限制**:建议在生产环境中对API接口实施请求频率限制,防止滥用
|
||||
|
||||
## 5. 接口维护信息
|
||||
|
||||
- **最后更新时间**:2023-11-01
|
||||
- **维护人员**:系统管理员
|
||||
- **版本号**:v1.2.0
|
||||
@@ -1,199 +0,0 @@
|
||||
using CSRedis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static CSRedis.CSRedisClient;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
/// <summary>
|
||||
/// Redis缓存辅助类
|
||||
/// </summary>
|
||||
public class CSRedisCacheHelper
|
||||
{
|
||||
public static CSRedisClient? redis;
|
||||
public static CSRedisClient? redis14;
|
||||
public static CSRedisClient? redis15;
|
||||
|
||||
private const string ip = "127.0.0.1";
|
||||
//private const string port = "6379";
|
||||
private const string port = "6800";
|
||||
static CSRedisCacheHelper()
|
||||
{
|
||||
var redisHostStr = string.Format("{0}:{1}", ip, port);
|
||||
if (!string.IsNullOrEmpty(redisHostStr))
|
||||
{
|
||||
redis = new CSRedisClient(redisHostStr + ",password=,defaultDatabase=0");
|
||||
redis15 = new CSRedisClient(redisHostStr + ",password=,defaultDatabase=15");
|
||||
var DingYueMsg = ("CellCorelDRAWUser", new Action<SubscribeMessageEventArgs>(async (args) =>
|
||||
{
|
||||
string body = args.Body;
|
||||
}));
|
||||
|
||||
CSRedisCacheHelper.redis.Subscribe(DingYueMsg);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加缓存
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
public static void Set<T>(string key, T value, int ExpireTime)
|
||||
{
|
||||
redis?.Set(key, value, ExpireTime * 60);
|
||||
}
|
||||
|
||||
public static T Get<T>(string key)
|
||||
{
|
||||
return redis.Get<T>(key);
|
||||
}
|
||||
|
||||
public static void Forever<T>(string key, T value)
|
||||
{
|
||||
redis.Set(key, value, -1);
|
||||
}
|
||||
public static void Del(string key)
|
||||
{
|
||||
redis.Del(key);
|
||||
}
|
||||
public static void ListPush<T>(string key, T value)
|
||||
{
|
||||
redis.LPush(key, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否存在
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public static bool Contains(string key)
|
||||
{
|
||||
bool result = redis.Exists(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string? XAdd(string key, params (string, string)[] fieldValues)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = redis.XAdd(key, fieldValues);
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"XAdd error: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static string? XReadGroup(string key, string group, string consumer, int count = 1, string id = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
id = id ?? ">";
|
||||
var result = redis.XReadGroup(group, consumer, count, 0, (key, id));
|
||||
|
||||
if (result != null && result.Length > 0)
|
||||
{
|
||||
// 处理消息
|
||||
var messages = new List<Dictionary<string, object>>();
|
||||
|
||||
foreach (var streamResult in result)
|
||||
{
|
||||
foreach (var entry in streamResult.data)
|
||||
{
|
||||
var message = new Dictionary<string, object>
|
||||
{
|
||||
["Id"] = entry.id,
|
||||
["Values"] = entry.items
|
||||
};
|
||||
|
||||
messages.Add(message);
|
||||
|
||||
// 确认消息已处理
|
||||
redis.XAck(key, group, entry.id);
|
||||
}
|
||||
}
|
||||
|
||||
return System.Text.Json.JsonSerializer.Serialize(messages);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"XReadGroup error: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static (string key, (string id, string items)[] data)[] XReadGroup(string group, string consumer, long count, long block, params (string key, string id)[] streams)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = redis.XReadGroup(group, consumer, count, block, streams);
|
||||
|
||||
if (result != null && result.Length > 0)
|
||||
{
|
||||
// 处理消息并确认已处理
|
||||
var processedResults = new List<(string key, (string id, string items)[] data)>();
|
||||
|
||||
foreach (var streamResult in result)
|
||||
{
|
||||
var messages = new List<(string id, string items)>();
|
||||
|
||||
foreach (var entry in streamResult.data)
|
||||
{
|
||||
// 确认消息已处理
|
||||
redis.XAck(streamResult.key, group, entry.id);
|
||||
|
||||
// entry是一个元组 (string id, string[] items)
|
||||
// 我们需要将string[] items转换为string items
|
||||
var itemsArray = entry.items;
|
||||
var itemsString = string.Join(",", itemsArray);
|
||||
messages.Add((entry.id, itemsString));
|
||||
}
|
||||
|
||||
processedResults.Add((streamResult.key, messages.ToArray()));
|
||||
}
|
||||
|
||||
return processedResults.ToArray();
|
||||
}
|
||||
|
||||
return Array.Empty<(string key, (string id, string items)[] data)>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"XReadGroup error: {ex.Message}");
|
||||
return Array.Empty<(string key, (string id, string items)[] data)>();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool XGroupCreate(string key, string group, string id = "0")
|
||||
{
|
||||
try
|
||||
{
|
||||
redis.XGroupCreate(key, group, id, true);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布消息
|
||||
/// </summary>
|
||||
/// <param name="Topic"></param>
|
||||
/// <param name="Payload"></param>
|
||||
public static void Publish(string Topic, string Payload)
|
||||
{
|
||||
CSRedisCacheHelper.redis.PublishNoneMessageId(Topic, Payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,869 +0,0 @@
|
||||
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 = "";
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace WxCheckApi.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class WeatherForecastController : ControllerBase
|
||||
{
|
||||
private static readonly string[] Summaries = new[]
|
||||
{
|
||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
||||
};
|
||||
|
||||
private readonly ILogger<WeatherForecastController> _logger;
|
||||
|
||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IEnumerable<WeatherForecast> Get()
|
||||
{
|
||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.Text;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddControllers();
|
||||
|
||||
// 添加HttpClientFactory
|
||||
builder.Services.AddHttpClient();
|
||||
|
||||
// 添加数据库连接
|
||||
builder.Services.AddScoped<MySqlConnection>(sp => {
|
||||
var connectionString = builder.Configuration.GetConnectionString("MySQLConnection");
|
||||
return new MySqlConnection(connectionString);
|
||||
});
|
||||
|
||||
builder.Services.AddAuthorization();
|
||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(option =>
|
||||
{
|
||||
string DefaultKey = "B,EZipeApY3cNj3~4RP0UMR=H>9x8.1!E85wmZ]]py2d$Y?5";
|
||||
var sec = Encoding.UTF8.GetBytes(builder.Configuration["JWT:SecretKey"] ?? DefaultKey);
|
||||
|
||||
option.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = builder.Configuration["JwT:Issuer"],
|
||||
ValidAudience = builder.Configuration["JwT:Audience"],
|
||||
IssuerSigningKey = new SymmetricSecurityKey(sec)
|
||||
};
|
||||
|
||||
option.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = context =>
|
||||
{
|
||||
var token = context.Request.Headers["token"].FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
// 如果没有找到 token 头部,则继续检查 Authorization 头部
|
||||
token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
}
|
||||
// 如果找到了 token,则将其设置到 HttpContext 中
|
||||
if (!string.IsNullOrEmpty(token))
|
||||
{
|
||||
context.Token = token;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
app.UseAuthentication(); // 添加认证中间件
|
||||
app.UseAuthorization(); // 使用授权中间件
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<DeleteExistingFiles>true</DeleteExistingFiles>
|
||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||
<PublishProvider>FileSystem</PublishProvider>
|
||||
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
|
||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<ProjectGuid>e545c738-a21b-71f3-9fb9-a68d8018822d</ProjectGuid>
|
||||
<SelfContained>false</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<_PublishTargetUrl>E:\Project\WxCheck\WxCheckApi\bin\Release\net8.0\publish\</_PublishTargetUrl>
|
||||
<History>True|2025-11-08T01:48:12.8385703Z||;True|2025-11-07T15:09:26.3902793+08:00||;True|2025-11-07T11:51:31.5643958+08:00||;True|2025-11-07T11:50:44.2146653+08:00||;True|2025-11-04T14:29:55.7628000+08:00||;False|2025-11-04T14:29:50.0660192+08:00||;True|2025-11-04T14:20:52.6380538+08:00||;True|2025-11-04T10:14:31.0406197+08:00||;True|2025-11-04T10:01:51.9971474+08:00||;True|2025-11-04T09:53:16.2195499+08:00||;True|2025-11-04T09:45:30.2430508+08:00||;True|2025-11-04T08:52:40.6424728+08:00||;True|2025-11-03T21:04:36.1464303+08:00||;True|2025-11-03T20:46:33.3635634+08:00||;True|2025-11-03T20:45:29.5368625+08:00||;True|2025-11-03T20:42:14.5975957+08:00||;True|2025-11-03T20:40:43.0062117+08:00||;True|2025-11-03T20:16:38.4711929+08:00||;True|2025-11-03T20:14:42.8936169+08:00||;True|2025-11-03T19:35:15.7051947+08:00||;True|2025-11-03T19:01:58.6546141+08:00||;True|2025-11-03T17:59:30.0861681+08:00||;True|2025-11-03T16:15:01.5245126+08:00||;True|2025-11-03T16:06:34.1178642+08:00||;True|2025-10-31T17:30:06.3039818+08:00||;True|2025-10-31T16:20:12.7490590+08:00||;True|2025-10-31T15:10:14.4751645+08:00||;</History>
|
||||
<LastFailureDetails />
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<DeleteExistingFiles>true</DeleteExistingFiles>
|
||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
|
||||
<LastUsedPlatform>Any CPU</LastUsedPlatform>
|
||||
<PublishProvider>FileSystem</PublishProvider>
|
||||
<PublishUrl>bin\Release\net8.0\publish\</PublishUrl>
|
||||
<WebPublishMethod>FileSystem</WebPublishMethod>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
<SiteUrlToLaunchAfterPublish />
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<ProjectGuid>e545c738-a21b-71f3-9fb9-a68d8018822d</ProjectGuid>
|
||||
<SelfContained>false</SelfContained>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<_PublishTargetUrl>E:\Project_Class\WX_XCX\WxCheck_Wx_Prod\WxCheckApi\bin\Release\net8.0\publish\</_PublishTargetUrl>
|
||||
<History>True|2025-12-05T03:46:42.6952752Z||;True|2025-12-03T17:28:08.6000818+08:00||;True|2025-12-03T15:36:17.3153352+08:00||;True|2025-12-03T15:34:35.0408800+08:00||;True|2025-12-03T15:32:13.7754473+08:00||;True|2025-12-03T15:23:43.3405041+08:00||;True|2025-12-03T11:08:15.0823391+08:00||;True|2025-12-03T11:04:29.8829020+08:00||;True|2025-12-03T11:00:07.4056298+08:00||;True|2025-12-03T10:56:38.5220608+08:00||;True|2025-12-03T10:51:59.6142114+08:00||;</History>
|
||||
<LastFailureDetails />
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:6041",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "weatherforecast",
|
||||
"applicationUrl": "http://localhost:5065",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "weatherforecast",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
namespace WxCheckApi
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string? Summary { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CSRedisCore" Version="3.8.806" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.21" />
|
||||
<PackageReference Include="MySql.Data" Version="8.4.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,6 +0,0 @@
|
||||
@WxCheckApi_HostAddress = http://localhost:5065
|
||||
|
||||
GET {{WxCheckApi_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
@@ -1,4 +0,0 @@
|
||||
<Solution>
|
||||
<Project Path="../WxCheckMvc/WxCheckMvc.csproj" Id="5f5aee53-ea7f-4a13-a039-d664f136a7f8" />
|
||||
<Project Path="WxCheckApi.csproj" />
|
||||
</Solution>
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"JwT": {
|
||||
"SecretKey": "1%猜U36eraIYI?3s9dI}46an不Nn>P]3)$9:dCnS5=ajAu%8B5]15hF到20T20QBD]Mt9}2z76jO#Glg&0yDy7k-2zVdt&Z5ur>=l)QF2^1&Dq04m76U2P9wvlWf",
|
||||
"Issuer": "微信小程序token",
|
||||
"Audience": "W*u93xxp*08DnW@%6}5Tjh6bE?;hW"
|
||||
},
|
||||
"WeChat": {
|
||||
"AppId": "wx42e9add0f91af98b",
|
||||
"AppSecret": "5620f00b40297efaf3d197d61ae184d6"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"MySQLConnection": "Server=47.119.147.104;Database=wx_xcx_check;user id=root;password=hbfjW6A_eob;port=3307;"
|
||||
},
|
||||
"AmapApi": {
|
||||
"ApiKey": "4d5cb7818664ada68ae5f68783b8bd4c"
|
||||
}
|
||||
|
||||
}
|
||||
325
WxCheckMvc/Controllers/AdminController.cs
Normal file
325
WxCheckMvc/Controllers/AdminController.cs
Normal file
@@ -0,0 +1,325 @@
|
||||
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<IActionResult> QueryConversations([FromBody] ConversationQueryRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_connection.State != ConnectionState.Open)
|
||||
{
|
||||
await _connection.OpenAsync();
|
||||
}
|
||||
|
||||
List<ConversationQueryResponse> 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<MySqlParameter>();
|
||||
|
||||
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<IActionResult> QueryUsers()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_connection.State != ConnectionState.Open)
|
||||
{
|
||||
await _connection.OpenAsync();
|
||||
}
|
||||
|
||||
List<UserQueryResponse> 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<IActionResult> 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; }
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ namespace WxCheckMvc.Controllers
|
||||
}
|
||||
|
||||
string updateSql = "UPDATE xcx_users SET AvatarUrl = @AvatarUrl, UpdateTime = NOW() WHERE UserKey = @UserKey";
|
||||
using (MySqlCommand cmd = new MySqlCommand(updateSql, _connection))
|
||||
using (MySqlCommand cmd = new(updateSql, _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@AvatarUrl", fullUrl);
|
||||
cmd.Parameters.AddWithValue("@UserKey", userKey);
|
||||
@@ -212,13 +212,13 @@ namespace WxCheckMvc.Controllers
|
||||
{
|
||||
var part = addressParts[i];
|
||||
// 如果部分包含"路"、"街"、"巷"等关键词,可能是街道信息
|
||||
if (part.Contains("路") || part.Contains("街") || part.Contains("巷") || part.Contains("道"))
|
||||
if (part.Contains('路') || part.Contains('街') || part.Contains('巷') || part.Contains('道'))
|
||||
{
|
||||
street = part;
|
||||
// 如果下一个部分存在且不是区县名称,可能是门牌号
|
||||
if (i + 1 < addressParts.Length &&
|
||||
!addressParts[i + 1].Contains("区") &&
|
||||
!addressParts[i + 1].Contains("县"))
|
||||
!addressParts[i + 1].Contains('区') &&
|
||||
!addressParts[i + 1].Contains('县'))
|
||||
{
|
||||
streetNumber = addressParts[i + 1];
|
||||
}
|
||||
@@ -299,7 +299,7 @@ namespace WxCheckMvc.Controllers
|
||||
string latitude = "";
|
||||
string longitude = "";
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT Latitude, Longitude FROM xcx_conversation WHERE Guid = @Guid AND IsDeleted = 0", _connection))
|
||||
using (MySqlCommand cmd = new("SELECT Latitude, Longitude FROM xcx_conversation WHERE Guid = @Guid AND IsDeleted = 0", _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", request.Guid);
|
||||
|
||||
@@ -321,7 +321,7 @@ namespace WxCheckMvc.Controllers
|
||||
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))
|
||||
using (MySqlCommand cmd = new("UPDATE xcx_conversation SET UserLocation = @UserLocation WHERE Guid = @Guid AND IsDeleted = 0", _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", request.Guid);
|
||||
cmd.Parameters.AddWithValue("@UserLocation", address);
|
||||
@@ -334,7 +334,7 @@ namespace WxCheckMvc.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(new { success = true, message = "地址更新成功", address = address });
|
||||
return Ok(new { success = true, message = "地址更新成功", address });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -383,7 +383,7 @@ namespace WxCheckMvc.Controllers
|
||||
// 生成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))
|
||||
using (MySqlCommand cmd = new("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);
|
||||
@@ -414,7 +414,7 @@ namespace WxCheckMvc.Controllers
|
||||
LEFT JOIN xcx_users AS users ON convs.UserKey = users.UserKey
|
||||
WHERE convs.Guid = @Guid";
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand(query, _connection))
|
||||
using (MySqlCommand cmd = new(query, _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", conversationGuid);
|
||||
using (var reader = await cmd.ExecuteReaderAsync())
|
||||
@@ -495,7 +495,7 @@ namespace WxCheckMvc.Controllers
|
||||
await _connection.OpenAsync();
|
||||
}
|
||||
|
||||
List<ConversationResponse> conversations = new List<ConversationResponse>();
|
||||
List<ConversationResponse> conversations = [];
|
||||
|
||||
// 构建查询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";
|
||||
@@ -505,7 +505,7 @@ namespace WxCheckMvc.Controllers
|
||||
}
|
||||
query += " ORDER BY RecordTimeUTCStamp DESC";
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand(query, _connection))
|
||||
using (MySqlCommand cmd = new(query, _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@UserKey", request.UserKey);
|
||||
|
||||
@@ -561,13 +561,13 @@ namespace WxCheckMvc.Controllers
|
||||
}
|
||||
|
||||
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))
|
||||
using (MySqlCommand cmd = new("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("@UserLocation", "");//request.UserLocation ?? "");
|
||||
cmd.Parameters.AddWithValue("@MessageType", request.MessageType);
|
||||
cmd.Parameters.AddWithValue("@RecordTime", nowtime);
|
||||
|
||||
@@ -605,7 +605,7 @@ namespace WxCheckMvc.Controllers
|
||||
await _connection.OpenAsync();
|
||||
}
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand("UPDATE xcx_conversation SET IsDeleted = 1 WHERE Guid = @Guid AND UserKey = @UserKey AND IsDeleted = 0", _connection))
|
||||
using (MySqlCommand cmd = new("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);
|
||||
@@ -649,7 +649,7 @@ namespace WxCheckMvc.Controllers
|
||||
FROM xcx_conversation
|
||||
WHERE Guid = @Guid";
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand(query, _connection))
|
||||
using (MySqlCommand cmd = new(query, _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@Guid", request.Guid);
|
||||
|
||||
@@ -714,7 +714,7 @@ namespace WxCheckMvc.Controllers
|
||||
|
||||
int offset = (request.Page - 1) * request.PageSize;
|
||||
|
||||
List<ConversationResponse> conversations = new List<ConversationResponse>();
|
||||
List<ConversationResponse> conversations = [];
|
||||
|
||||
// 构建分页查询SQL,根据MessageType参数决定是否添加过滤条件
|
||||
string query = @"SELECT Id, Guid, UserKey, ConversationContent, SendMethod, UserLocation, Latitude, Longitude, RecordTime, RecordTimeUTCStamp, IsDeleted, CreateTime, MessageType, SpeakingTime
|
||||
@@ -726,7 +726,7 @@ namespace WxCheckMvc.Controllers
|
||||
}
|
||||
query += " ORDER BY RecordTimeUTCStamp DESC LIMIT @Offset, @Limit";
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand(query, _connection))
|
||||
using (MySqlCommand cmd = new(query, _connection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@UserKey", request.UserKey);
|
||||
if (request.MessageType == 1)
|
||||
@@ -769,7 +769,7 @@ namespace WxCheckMvc.Controllers
|
||||
countQuery += " AND MessageType = @MessageType";
|
||||
}
|
||||
|
||||
using (MySqlCommand countCmd = new MySqlCommand(countQuery, _connection))
|
||||
using (MySqlCommand countCmd = new(countQuery, _connection))
|
||||
{
|
||||
countCmd.Parameters.AddWithValue("@UserKey", request.UserKey);
|
||||
if (request.MessageType == 1)
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
|
||||
@@ -110,7 +111,10 @@ namespace WxCheckMvc.Controllers
|
||||
{
|
||||
await _connection.OpenAsync();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(request.UserKey))
|
||||
{
|
||||
return BadRequest(new { success = false, message = "UserKey不能为空" });
|
||||
}
|
||||
// 检查用户是否存在
|
||||
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))
|
||||
@@ -142,6 +146,31 @@ namespace WxCheckMvc.Controllers
|
||||
return NotFound(new { success = false, message = "用户不存在" });
|
||||
}
|
||||
|
||||
// 在验证之前,先对 UserName 和 PhoneNumber 去除空格和标点符号
|
||||
string cleanedUserName = request.UserName ?? string.Empty;
|
||||
string cleanedPhoneNumber = request.PhoneNumber ?? string.Empty;
|
||||
|
||||
// PhoneNumber 只保留数字
|
||||
cleanedPhoneNumber = Regex.Replace(cleanedPhoneNumber, "\\D", "");
|
||||
// UserName 去除标点、符号和空白(保留所有字母/汉字/罕见字形以及数字)
|
||||
cleanedUserName = Regex.Replace(cleanedUserName, @"[\p{P}\p{S}\s]+", "").Trim();
|
||||
|
||||
// 验证 UserName 不为空
|
||||
if (string.IsNullOrEmpty(cleanedUserName))
|
||||
{
|
||||
return BadRequest(new { success = false, message = "用户名不能为空或仅包含非法字符" });
|
||||
}
|
||||
|
||||
// 验证 PhoneNumber 是否为合法手机号(以 1 开头,共 11 位数字)
|
||||
if (!Regex.IsMatch(cleanedPhoneNumber, "^1\\d{10}$"))
|
||||
{
|
||||
return BadRequest(new { success = false, message = "手机号格式错误" });
|
||||
}
|
||||
|
||||
// 将清理后的值写回 request,确保更新数据库时使用清理后的值
|
||||
request.UserName = cleanedUserName;
|
||||
request.PhoneNumber = cleanedPhoneNumber;
|
||||
|
||||
// 更新用户信息
|
||||
using (MySqlCommand cmd = new MySqlCommand("UPDATE xcx_users SET UserName = @UserName, WeChatName = @WeChatName, PhoneNumber = @PhoneNumber, AvatarUrl = @AvatarUrl, UpdateTime = NOW() WHERE UserKey = @UserKey", _connection))
|
||||
{
|
||||
@@ -237,6 +266,15 @@ namespace WxCheckMvc.Controllers
|
||||
await insertCmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 用户已存在:更新最后一次接口调用时间
|
||||
using (MySqlCommand updateCmd = new MySqlCommand("UPDATE xcx_users SET UpdateTime = NOW() WHERE UserKey = @UserKey", _connection))
|
||||
{
|
||||
updateCmd.Parameters.AddWithValue("@UserKey", openId);
|
||||
await updateCmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
@@ -296,7 +334,7 @@ namespace WxCheckMvc.Controllers
|
||||
public class RegisterRequest
|
||||
{
|
||||
public string UserName { get; set; }
|
||||
public string UserKey { get; set; } // 改为直接传入UserKey
|
||||
public string UserKey { get; set; }
|
||||
public string WeChatName { get; set; }
|
||||
public string PhoneNumber { get; set; }
|
||||
public string AvatarUrl { get; set; }
|
||||
|
||||
@@ -10,7 +10,17 @@ builder.Services.AddControllersWithViews();
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>HttpClientFactory
|
||||
builder.Services.AddHttpClient();
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy(name: "KuaYu",
|
||||
policy =>
|
||||
{
|
||||
policy
|
||||
.AllowAnyOrigin()
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod();
|
||||
});
|
||||
});
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݿ<EFBFBD><DDBF><EFBFBD><EFBFBD><EFBFBD>
|
||||
builder.Services.AddScoped<MySqlConnection>(sp => {
|
||||
var connectionString = builder.Configuration.GetConnectionString("MySQLConnection");
|
||||
@@ -68,7 +78,7 @@ if (!app.Environment.IsDevelopment())
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseCors("KuaYu");
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<_PublishTargetUrl>E:\Project_Class\WX_XCX\WxCheck_Wx_Prod\WxCheckMvc\bin\Release\net8.0\publish\</_PublishTargetUrl>
|
||||
<History>True|2025-12-05T10:56:51.7439135Z||;True|2025-12-05T17:44:11.4130698+08:00||;</History>
|
||||
<_PublishTargetUrl>E:\Project_Class\WX_XCX\Wx_WxCheck_Prod\WxCheckMvc\bin\Release\net8.0\publish\</_PublishTargetUrl>
|
||||
<History>True|2025-12-25T06:00:56.3451051Z||;True|2025-12-24T20:05:02.2999541+08:00||;True|2025-12-24T16:33:44.2108439+08:00||;True|2025-12-24T15:32:13.8037439+08:00||;True|2025-12-12T11:09:28.8147447+08:00||;True|2025-12-11T17:04:53.2856075+08:00||;True|2025-12-11T17:04:22.0809574+08:00||;True|2025-12-05T18:56:51.7439135+08:00||;True|2025-12-05T17:44:11.4130698+08:00||;</History>
|
||||
<LastFailureDetails />
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -2,6 +2,6 @@
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ActiveDebugProfile>https</ActiveDebugProfile>
|
||||
<NameOfLastUsedPublishProfile>E:\Project_Class\WX_XCX\WxCheck_Wx_Prod\WxCheckMvc\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
|
||||
<NameOfLastUsedPublishProfile>E:\Project_Class\WX_XCX\Wx_WxCheck_Prod\WxCheckMvc\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,489 +0,0 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v8.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v8.0": {
|
||||
"WxCheckMvc/1.0.0": {
|
||||
"dependencies": {
|
||||
"CSRedisCore": "3.8.807",
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer": "8.0.22",
|
||||
"MySql.Data": "8.4.0"
|
||||
},
|
||||
"runtime": {
|
||||
"WxCheckMvc.dll": {}
|
||||
}
|
||||
},
|
||||
"BouncyCastle.Cryptography/2.2.1": {
|
||||
"runtime": {
|
||||
"lib/net6.0/BouncyCastle.Cryptography.dll": {
|
||||
"assemblyVersion": "2.0.0.0",
|
||||
"fileVersion": "2.2.1.47552"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CSRedisCore/3.8.807": {
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": "13.0.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/CSRedisCore.dll": {
|
||||
"assemblyVersion": "3.8.807.0",
|
||||
"fileVersion": "3.8.807.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Google.Protobuf/3.25.1": {
|
||||
"runtime": {
|
||||
"lib/net5.0/Google.Protobuf.dll": {
|
||||
"assemblyVersion": "3.25.1.0",
|
||||
"fileVersion": "3.25.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"K4os.Compression.LZ4/1.3.5": {
|
||||
"runtime": {
|
||||
"lib/net6.0/K4os.Compression.LZ4.dll": {
|
||||
"assemblyVersion": "1.3.5.0",
|
||||
"fileVersion": "1.3.5.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"K4os.Compression.LZ4.Streams/1.3.5": {
|
||||
"dependencies": {
|
||||
"K4os.Compression.LZ4": "1.3.5",
|
||||
"K4os.Hash.xxHash": "1.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net6.0/K4os.Compression.LZ4.Streams.dll": {
|
||||
"assemblyVersion": "1.3.5.0",
|
||||
"fileVersion": "1.3.5.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"K4os.Hash.xxHash/1.0.8": {
|
||||
"runtime": {
|
||||
"lib/net6.0/K4os.Hash.xxHash.dll": {
|
||||
"assemblyVersion": "1.0.8.0",
|
||||
"fileVersion": "1.0.8.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer/8.0.22": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll": {
|
||||
"assemblyVersion": "8.0.22.0",
|
||||
"fileVersion": "8.0.2225.52808"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Abstractions/7.1.2": {
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Abstractions.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.JsonWebTokens/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Tokens": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.JsonWebTokens.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Logging/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Abstractions": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Logging.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Protocols/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Logging": "7.1.2",
|
||||
"Microsoft.IdentityModel.Tokens": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Protocols.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Protocols.OpenIdConnect/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Protocols": "7.1.2",
|
||||
"System.IdentityModel.Tokens.Jwt": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Tokens/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Logging": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Tokens.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents/4.7.0": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll": {
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/win/lib/netcoreapp3.0/Microsoft.Win32.SystemEvents.dll": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MySql.Data/8.4.0": {
|
||||
"dependencies": {
|
||||
"BouncyCastle.Cryptography": "2.2.1",
|
||||
"Google.Protobuf": "3.25.1",
|
||||
"K4os.Compression.LZ4.Streams": "1.3.5",
|
||||
"System.Configuration.ConfigurationManager": "4.4.1",
|
||||
"System.Security.Permissions": "4.7.0",
|
||||
"ZstdSharp.Port": "0.7.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/MySql.Data.dll": {
|
||||
"assemblyVersion": "8.4.0.0",
|
||||
"fileVersion": "8.4.0.0"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/win-x64/native/comerr64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
},
|
||||
"runtimes/win-x64/native/gssapi64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
},
|
||||
"runtimes/win-x64/native/k5sprt64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
},
|
||||
"runtimes/win-x64/native/krb5_64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
},
|
||||
"runtimes/win-x64/native/krbcc64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||
"assemblyVersion": "13.0.0.0",
|
||||
"fileVersion": "13.0.1.25517"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Configuration.ConfigurationManager/4.4.1": {
|
||||
"dependencies": {
|
||||
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/System.Configuration.ConfigurationManager.dll": {
|
||||
"assemblyVersion": "4.0.0.0",
|
||||
"fileVersion": "4.6.25921.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Drawing.Common/4.7.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Win32.SystemEvents": "4.7.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/System.Drawing.Common.dll": {
|
||||
"assemblyVersion": "4.0.0.1",
|
||||
"fileVersion": "4.6.26919.2"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/unix/lib/netcoreapp3.0/System.Drawing.Common.dll": {
|
||||
"rid": "unix",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
},
|
||||
"runtimes/win/lib/netcoreapp3.0/System.Drawing.Common.dll": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.IdentityModel.Tokens.Jwt/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.JsonWebTokens": "7.1.2",
|
||||
"Microsoft.IdentityModel.Tokens": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/System.IdentityModel.Tokens.Jwt.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData/4.4.0": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": {
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.6.25519.3"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/win/lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.6.25519.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Security.Permissions/4.7.0": {
|
||||
"dependencies": {
|
||||
"System.Windows.Extensions": "4.7.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netcoreapp3.0/System.Security.Permissions.dll": {
|
||||
"assemblyVersion": "4.0.3.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Windows.Extensions/4.7.0": {
|
||||
"dependencies": {
|
||||
"System.Drawing.Common": "4.7.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netcoreapp3.0/System.Windows.Extensions.dll": {
|
||||
"assemblyVersion": "4.0.1.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/win/lib/netcoreapp3.0/System.Windows.Extensions.dll": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.1.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ZstdSharp.Port/0.7.1": {
|
||||
"runtime": {
|
||||
"lib/net7.0/ZstdSharp.dll": {
|
||||
"assemblyVersion": "0.7.1.0",
|
||||
"fileVersion": "0.7.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"WxCheckMvc/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"BouncyCastle.Cryptography/2.2.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-A6Zr52zVqJKt18ZBsTnX0qhG0kwIQftVAjLmszmkiR/trSp8H+xj1gUOzk7XHwaKgyREMSV1v9XaKrBUeIOdvQ==",
|
||||
"path": "bouncycastle.cryptography/2.2.1",
|
||||
"hashPath": "bouncycastle.cryptography.2.2.1.nupkg.sha512"
|
||||
},
|
||||
"CSRedisCore/3.8.807": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-fu0ZGIRdq1q0dZR+ecJxajfdLiRNWBR+UKx9Ob43rSwPQT/9duIJ8DLThkDjlx/0CHtX8oktv3rYAHS/mIy8bw==",
|
||||
"path": "csrediscore/3.8.807",
|
||||
"hashPath": "csrediscore.3.8.807.nupkg.sha512"
|
||||
},
|
||||
"Google.Protobuf/3.25.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Sw9bq4hOD+AaS3RrnmP5IT25cyZ/T1qpM0e8+G+23Nojhv7+ScJFPEAQo1m4EFQWhXoI4FRZDrK+wjHCPw9yxg==",
|
||||
"path": "google.protobuf/3.25.1",
|
||||
"hashPath": "google.protobuf.3.25.1.nupkg.sha512"
|
||||
},
|
||||
"K4os.Compression.LZ4/1.3.5": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-TS4mqlT0X1OlnvOGNfl02QdVUhuqgWuCnn7UxupIa7C9Pb6qlQ5yZA2sPhRh0OSmVULaQU64KV4wJuu//UyVQQ==",
|
||||
"path": "k4os.compression.lz4/1.3.5",
|
||||
"hashPath": "k4os.compression.lz4.1.3.5.nupkg.sha512"
|
||||
},
|
||||
"K4os.Compression.LZ4.Streams/1.3.5": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-M0NufZI8ym3mm6F6HMSPz1jw7TJGdY74fjAtbIXATmnAva/8xLz50eQZJI9tf9mMeHUaFDg76N1BmEh8GR5zeA==",
|
||||
"path": "k4os.compression.lz4.streams/1.3.5",
|
||||
"hashPath": "k4os.compression.lz4.streams.1.3.5.nupkg.sha512"
|
||||
},
|
||||
"K4os.Hash.xxHash/1.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Wp2F7BamQ2Q/7Hk834nV9vRQapgcr8kgv9Jvfm8J3D0IhDqZMMl+a2yxUq5ltJitvXvQfB8W6K4F4fCbw/P6YQ==",
|
||||
"path": "k4os.hash.xxhash/1.0.8",
|
||||
"hashPath": "k4os.hash.xxhash.1.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer/8.0.22": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3lqhBK+t4u8Ajl2je5UC9jCoDI+8zLz/YBVjwxQKfFF9NyzACf4QQmlmKnpH/LdkVSxCjLwvJ1ko4k0EAgy8cg==",
|
||||
"path": "microsoft.aspnetcore.authentication.jwtbearer/8.0.22",
|
||||
"hashPath": "microsoft.aspnetcore.authentication.jwtbearer.8.0.22.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Abstractions/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-33eTIA2uO/L9utJjZWbKsMSVsQf7F8vtd6q5mQX7ZJzNvCpci5fleD6AeANGlbbb7WX7XKxq9+Dkb5e3GNDrmQ==",
|
||||
"path": "microsoft.identitymodel.abstractions/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.abstractions.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.JsonWebTokens/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-cloLGeZolXbCJhJBc5OC05uhrdhdPL6MWHuVUnkkUvPDeK7HkwThBaLZ1XjBQVk9YhxXE2OvHXnKi0PLleXxDg==",
|
||||
"path": "microsoft.identitymodel.jsonwebtokens/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.jsonwebtokens.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Logging/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-YCxBt2EeJP8fcXk9desChkWI+0vFqFLvBwrz5hBMsoh0KJE6BC66DnzkdzkJNqMltLromc52dkdT206jJ38cTw==",
|
||||
"path": "microsoft.identitymodel.logging/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.logging.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Protocols/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-SydLwMRFx6EHPWJ+N6+MVaoArN1Htt92b935O3RUWPY1yUF63zEjvd3lBu79eWdZUwedP8TN2I5V9T3nackvIQ==",
|
||||
"path": "microsoft.identitymodel.protocols/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.protocols.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Protocols.OpenIdConnect/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-6lHQoLXhnMQ42mGrfDkzbIOR3rzKM1W1tgTeMPLgLCqwwGw0d96xFi/UiX/fYsu7d6cD5MJiL3+4HuI8VU+sVQ==",
|
||||
"path": "microsoft.identitymodel.protocols.openidconnect/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.protocols.openidconnect.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Tokens/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-oICJMqr3aNEDZOwnH5SK49bR6Z4aX0zEAnOLuhloumOSuqnNq+GWBdQyrgILnlcT5xj09xKCP/7Y7gJYB+ls/g==",
|
||||
"path": "microsoft.identitymodel.tokens/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.tokens.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-mtVirZr++rq+XCDITMUdnETD59XoeMxSpLRIII7JRI6Yj0LEDiO1pPn0ktlnIj12Ix8bfvQqQDMMIF9wC98oCA==",
|
||||
"path": "microsoft.win32.systemevents/4.7.0",
|
||||
"hashPath": "microsoft.win32.systemevents.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"MySql.Data/8.4.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-NA273x7ybutfGwGbF2cd8rLVM5t7AkZCzRHr/+tGms1FeMlfl+LgfjHXcb5qN1QxFpeNQQKZ+vqZw8v/S8gUiA==",
|
||||
"path": "mysql.data/8.4.0",
|
||||
"hashPath": "mysql.data.8.4.0.nupkg.sha512"
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||
"path": "newtonsoft.json/13.0.1",
|
||||
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Configuration.ConfigurationManager/4.4.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-jz3TWKMAeuDEyrPCK5Jyt4bzQcmzUIMcY9Ud6PkElFxTfnsihV+9N/UCqvxe1z5gc7jMYAnj7V1COMS9QKIuHQ==",
|
||||
"path": "system.configuration.configurationmanager/4.4.1",
|
||||
"hashPath": "system.configuration.configurationmanager.4.4.1.nupkg.sha512"
|
||||
},
|
||||
"System.Drawing.Common/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-v+XbyYHaZjDfn0ENmJEV1VYLgGgCTx1gnfOBcppowbpOAriglYgGCvFCPr2EEZyBvXlpxbEsTwkOlInl107ahA==",
|
||||
"path": "system.drawing.common/4.7.0",
|
||||
"hashPath": "system.drawing.common.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"System.IdentityModel.Tokens.Jwt/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Thhbe1peAmtSBFaV/ohtykXiZSOkx59Da44hvtWfIMFofDA3M3LaVyjstACf2rKGn4dEDR2cUpRAZ0Xs/zB+7Q==",
|
||||
"path": "system.identitymodel.tokens.jwt/7.1.2",
|
||||
"hashPath": "system.identitymodel.tokens.jwt.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData/4.4.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==",
|
||||
"path": "system.security.cryptography.protecteddata/4.4.0",
|
||||
"hashPath": "system.security.cryptography.protecteddata.4.4.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Permissions/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-dkOV6YYVBnYRa15/yv004eCGRBVADXw8qRbbNiCn/XpdJSUXkkUeIvdvFHkvnko4CdKMqG8yRHC4ox83LSlMsQ==",
|
||||
"path": "system.security.permissions/4.7.0",
|
||||
"hashPath": "system.security.permissions.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"System.Windows.Extensions/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-CeWTdRNfRaSh0pm2gDTJFwVaXfTq6Xwv/sA887iwPTneW7oMtMlpvDIO+U60+3GWTB7Aom6oQwv5VZVUhQRdPQ==",
|
||||
"path": "system.windows.extensions/4.7.0",
|
||||
"hashPath": "system.windows.extensions.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"ZstdSharp.Port/0.7.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Idgg+mJEyAujqDPzA3APy9dNoyw0YQcNA65GgYjktDRtJ+nvx/hv+J+m6Eax3JJMGEYGy04oc5YNP6ZvQ3Y1vQ==",
|
||||
"path": "zstdsharp.port/0.7.1",
|
||||
"hashPath": "zstdsharp.port.0.7.1.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"runtimeOptions": {
|
||||
"tfm": "net8.0",
|
||||
"frameworks": [
|
||||
{
|
||||
"name": "Microsoft.NETCore.App",
|
||||
"version": "8.0.0"
|
||||
},
|
||||
{
|
||||
"name": "Microsoft.AspNetCore.App",
|
||||
"version": "8.0.0"
|
||||
}
|
||||
],
|
||||
"configProperties": {
|
||||
"System.GC.Server": true,
|
||||
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,489 +0,0 @@
|
||||
{
|
||||
"runtimeTarget": {
|
||||
"name": ".NETCoreApp,Version=v8.0",
|
||||
"signature": ""
|
||||
},
|
||||
"compilationOptions": {},
|
||||
"targets": {
|
||||
".NETCoreApp,Version=v8.0": {
|
||||
"WxCheckMvc/1.0.0": {
|
||||
"dependencies": {
|
||||
"CSRedisCore": "3.8.807",
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer": "8.0.22",
|
||||
"MySql.Data": "8.4.0"
|
||||
},
|
||||
"runtime": {
|
||||
"WxCheckMvc.dll": {}
|
||||
}
|
||||
},
|
||||
"BouncyCastle.Cryptography/2.2.1": {
|
||||
"runtime": {
|
||||
"lib/net6.0/BouncyCastle.Cryptography.dll": {
|
||||
"assemblyVersion": "2.0.0.0",
|
||||
"fileVersion": "2.2.1.47552"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CSRedisCore/3.8.807": {
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": "13.0.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/CSRedisCore.dll": {
|
||||
"assemblyVersion": "3.8.807.0",
|
||||
"fileVersion": "3.8.807.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Google.Protobuf/3.25.1": {
|
||||
"runtime": {
|
||||
"lib/net5.0/Google.Protobuf.dll": {
|
||||
"assemblyVersion": "3.25.1.0",
|
||||
"fileVersion": "3.25.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"K4os.Compression.LZ4/1.3.5": {
|
||||
"runtime": {
|
||||
"lib/net6.0/K4os.Compression.LZ4.dll": {
|
||||
"assemblyVersion": "1.3.5.0",
|
||||
"fileVersion": "1.3.5.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"K4os.Compression.LZ4.Streams/1.3.5": {
|
||||
"dependencies": {
|
||||
"K4os.Compression.LZ4": "1.3.5",
|
||||
"K4os.Hash.xxHash": "1.0.8"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net6.0/K4os.Compression.LZ4.Streams.dll": {
|
||||
"assemblyVersion": "1.3.5.0",
|
||||
"fileVersion": "1.3.5.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"K4os.Hash.xxHash/1.0.8": {
|
||||
"runtime": {
|
||||
"lib/net6.0/K4os.Hash.xxHash.dll": {
|
||||
"assemblyVersion": "1.0.8.0",
|
||||
"fileVersion": "1.0.8.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer/8.0.22": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll": {
|
||||
"assemblyVersion": "8.0.22.0",
|
||||
"fileVersion": "8.0.2225.52808"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Abstractions/7.1.2": {
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Abstractions.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.JsonWebTokens/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Tokens": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.JsonWebTokens.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Logging/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Abstractions": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Logging.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Protocols/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Logging": "7.1.2",
|
||||
"Microsoft.IdentityModel.Tokens": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Protocols.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Protocols.OpenIdConnect/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Protocols": "7.1.2",
|
||||
"System.IdentityModel.Tokens.Jwt": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.IdentityModel.Tokens/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.Logging": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/Microsoft.IdentityModel.Tokens.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents/4.7.0": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll": {
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/win/lib/netcoreapp3.0/Microsoft.Win32.SystemEvents.dll": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MySql.Data/8.4.0": {
|
||||
"dependencies": {
|
||||
"BouncyCastle.Cryptography": "2.2.1",
|
||||
"Google.Protobuf": "3.25.1",
|
||||
"K4os.Compression.LZ4.Streams": "1.3.5",
|
||||
"System.Configuration.ConfigurationManager": "4.4.1",
|
||||
"System.Security.Permissions": "4.7.0",
|
||||
"ZstdSharp.Port": "0.7.1"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/MySql.Data.dll": {
|
||||
"assemblyVersion": "8.4.0.0",
|
||||
"fileVersion": "8.4.0.0"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/win-x64/native/comerr64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
},
|
||||
"runtimes/win-x64/native/gssapi64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
},
|
||||
"runtimes/win-x64/native/k5sprt64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
},
|
||||
"runtimes/win-x64/native/krb5_64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
},
|
||||
"runtimes/win-x64/native/krbcc64.dll": {
|
||||
"rid": "win-x64",
|
||||
"assetType": "native",
|
||||
"fileVersion": "4.1.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/Newtonsoft.Json.dll": {
|
||||
"assemblyVersion": "13.0.0.0",
|
||||
"fileVersion": "13.0.1.25517"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Configuration.ConfigurationManager/4.4.1": {
|
||||
"dependencies": {
|
||||
"System.Security.Cryptography.ProtectedData": "4.4.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/System.Configuration.ConfigurationManager.dll": {
|
||||
"assemblyVersion": "4.0.0.0",
|
||||
"fileVersion": "4.6.25921.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Drawing.Common/4.7.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.Win32.SystemEvents": "4.7.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/System.Drawing.Common.dll": {
|
||||
"assemblyVersion": "4.0.0.1",
|
||||
"fileVersion": "4.6.26919.2"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/unix/lib/netcoreapp3.0/System.Drawing.Common.dll": {
|
||||
"rid": "unix",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
},
|
||||
"runtimes/win/lib/netcoreapp3.0/System.Drawing.Common.dll": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.IdentityModel.Tokens.Jwt/7.1.2": {
|
||||
"dependencies": {
|
||||
"Microsoft.IdentityModel.JsonWebTokens": "7.1.2",
|
||||
"Microsoft.IdentityModel.Tokens": "7.1.2"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/net8.0/System.IdentityModel.Tokens.Jwt.dll": {
|
||||
"assemblyVersion": "7.1.2.0",
|
||||
"fileVersion": "7.1.2.41121"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData/4.4.0": {
|
||||
"runtime": {
|
||||
"lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": {
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.6.25519.3"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/win/lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.2.0",
|
||||
"fileVersion": "4.6.25519.3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Security.Permissions/4.7.0": {
|
||||
"dependencies": {
|
||||
"System.Windows.Extensions": "4.7.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netcoreapp3.0/System.Security.Permissions.dll": {
|
||||
"assemblyVersion": "4.0.3.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
}
|
||||
},
|
||||
"System.Windows.Extensions/4.7.0": {
|
||||
"dependencies": {
|
||||
"System.Drawing.Common": "4.7.0"
|
||||
},
|
||||
"runtime": {
|
||||
"lib/netcoreapp3.0/System.Windows.Extensions.dll": {
|
||||
"assemblyVersion": "4.0.1.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
},
|
||||
"runtimeTargets": {
|
||||
"runtimes/win/lib/netcoreapp3.0/System.Windows.Extensions.dll": {
|
||||
"rid": "win",
|
||||
"assetType": "runtime",
|
||||
"assemblyVersion": "4.0.1.0",
|
||||
"fileVersion": "4.700.19.56404"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ZstdSharp.Port/0.7.1": {
|
||||
"runtime": {
|
||||
"lib/net7.0/ZstdSharp.dll": {
|
||||
"assemblyVersion": "0.7.1.0",
|
||||
"fileVersion": "0.7.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"WxCheckMvc/1.0.0": {
|
||||
"type": "project",
|
||||
"serviceable": false,
|
||||
"sha512": ""
|
||||
},
|
||||
"BouncyCastle.Cryptography/2.2.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-A6Zr52zVqJKt18ZBsTnX0qhG0kwIQftVAjLmszmkiR/trSp8H+xj1gUOzk7XHwaKgyREMSV1v9XaKrBUeIOdvQ==",
|
||||
"path": "bouncycastle.cryptography/2.2.1",
|
||||
"hashPath": "bouncycastle.cryptography.2.2.1.nupkg.sha512"
|
||||
},
|
||||
"CSRedisCore/3.8.807": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-fu0ZGIRdq1q0dZR+ecJxajfdLiRNWBR+UKx9Ob43rSwPQT/9duIJ8DLThkDjlx/0CHtX8oktv3rYAHS/mIy8bw==",
|
||||
"path": "csrediscore/3.8.807",
|
||||
"hashPath": "csrediscore.3.8.807.nupkg.sha512"
|
||||
},
|
||||
"Google.Protobuf/3.25.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Sw9bq4hOD+AaS3RrnmP5IT25cyZ/T1qpM0e8+G+23Nojhv7+ScJFPEAQo1m4EFQWhXoI4FRZDrK+wjHCPw9yxg==",
|
||||
"path": "google.protobuf/3.25.1",
|
||||
"hashPath": "google.protobuf.3.25.1.nupkg.sha512"
|
||||
},
|
||||
"K4os.Compression.LZ4/1.3.5": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-TS4mqlT0X1OlnvOGNfl02QdVUhuqgWuCnn7UxupIa7C9Pb6qlQ5yZA2sPhRh0OSmVULaQU64KV4wJuu//UyVQQ==",
|
||||
"path": "k4os.compression.lz4/1.3.5",
|
||||
"hashPath": "k4os.compression.lz4.1.3.5.nupkg.sha512"
|
||||
},
|
||||
"K4os.Compression.LZ4.Streams/1.3.5": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-M0NufZI8ym3mm6F6HMSPz1jw7TJGdY74fjAtbIXATmnAva/8xLz50eQZJI9tf9mMeHUaFDg76N1BmEh8GR5zeA==",
|
||||
"path": "k4os.compression.lz4.streams/1.3.5",
|
||||
"hashPath": "k4os.compression.lz4.streams.1.3.5.nupkg.sha512"
|
||||
},
|
||||
"K4os.Hash.xxHash/1.0.8": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Wp2F7BamQ2Q/7Hk834nV9vRQapgcr8kgv9Jvfm8J3D0IhDqZMMl+a2yxUq5ltJitvXvQfB8W6K4F4fCbw/P6YQ==",
|
||||
"path": "k4os.hash.xxhash/1.0.8",
|
||||
"hashPath": "k4os.hash.xxhash.1.0.8.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer/8.0.22": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-3lqhBK+t4u8Ajl2je5UC9jCoDI+8zLz/YBVjwxQKfFF9NyzACf4QQmlmKnpH/LdkVSxCjLwvJ1ko4k0EAgy8cg==",
|
||||
"path": "microsoft.aspnetcore.authentication.jwtbearer/8.0.22",
|
||||
"hashPath": "microsoft.aspnetcore.authentication.jwtbearer.8.0.22.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Abstractions/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-33eTIA2uO/L9utJjZWbKsMSVsQf7F8vtd6q5mQX7ZJzNvCpci5fleD6AeANGlbbb7WX7XKxq9+Dkb5e3GNDrmQ==",
|
||||
"path": "microsoft.identitymodel.abstractions/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.abstractions.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.JsonWebTokens/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-cloLGeZolXbCJhJBc5OC05uhrdhdPL6MWHuVUnkkUvPDeK7HkwThBaLZ1XjBQVk9YhxXE2OvHXnKi0PLleXxDg==",
|
||||
"path": "microsoft.identitymodel.jsonwebtokens/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.jsonwebtokens.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Logging/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-YCxBt2EeJP8fcXk9desChkWI+0vFqFLvBwrz5hBMsoh0KJE6BC66DnzkdzkJNqMltLromc52dkdT206jJ38cTw==",
|
||||
"path": "microsoft.identitymodel.logging/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.logging.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Protocols/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-SydLwMRFx6EHPWJ+N6+MVaoArN1Htt92b935O3RUWPY1yUF63zEjvd3lBu79eWdZUwedP8TN2I5V9T3nackvIQ==",
|
||||
"path": "microsoft.identitymodel.protocols/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.protocols.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Protocols.OpenIdConnect/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-6lHQoLXhnMQ42mGrfDkzbIOR3rzKM1W1tgTeMPLgLCqwwGw0d96xFi/UiX/fYsu7d6cD5MJiL3+4HuI8VU+sVQ==",
|
||||
"path": "microsoft.identitymodel.protocols.openidconnect/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.protocols.openidconnect.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.IdentityModel.Tokens/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-oICJMqr3aNEDZOwnH5SK49bR6Z4aX0zEAnOLuhloumOSuqnNq+GWBdQyrgILnlcT5xj09xKCP/7Y7gJYB+ls/g==",
|
||||
"path": "microsoft.identitymodel.tokens/7.1.2",
|
||||
"hashPath": "microsoft.identitymodel.tokens.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-mtVirZr++rq+XCDITMUdnETD59XoeMxSpLRIII7JRI6Yj0LEDiO1pPn0ktlnIj12Ix8bfvQqQDMMIF9wC98oCA==",
|
||||
"path": "microsoft.win32.systemevents/4.7.0",
|
||||
"hashPath": "microsoft.win32.systemevents.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"MySql.Data/8.4.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-NA273x7ybutfGwGbF2cd8rLVM5t7AkZCzRHr/+tGms1FeMlfl+LgfjHXcb5qN1QxFpeNQQKZ+vqZw8v/S8gUiA==",
|
||||
"path": "mysql.data/8.4.0",
|
||||
"hashPath": "mysql.data.8.4.0.nupkg.sha512"
|
||||
},
|
||||
"Newtonsoft.Json/13.0.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==",
|
||||
"path": "newtonsoft.json/13.0.1",
|
||||
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
|
||||
},
|
||||
"System.Configuration.ConfigurationManager/4.4.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-jz3TWKMAeuDEyrPCK5Jyt4bzQcmzUIMcY9Ud6PkElFxTfnsihV+9N/UCqvxe1z5gc7jMYAnj7V1COMS9QKIuHQ==",
|
||||
"path": "system.configuration.configurationmanager/4.4.1",
|
||||
"hashPath": "system.configuration.configurationmanager.4.4.1.nupkg.sha512"
|
||||
},
|
||||
"System.Drawing.Common/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-v+XbyYHaZjDfn0ENmJEV1VYLgGgCTx1gnfOBcppowbpOAriglYgGCvFCPr2EEZyBvXlpxbEsTwkOlInl107ahA==",
|
||||
"path": "system.drawing.common/4.7.0",
|
||||
"hashPath": "system.drawing.common.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"System.IdentityModel.Tokens.Jwt/7.1.2": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Thhbe1peAmtSBFaV/ohtykXiZSOkx59Da44hvtWfIMFofDA3M3LaVyjstACf2rKGn4dEDR2cUpRAZ0Xs/zB+7Q==",
|
||||
"path": "system.identitymodel.tokens.jwt/7.1.2",
|
||||
"hashPath": "system.identitymodel.tokens.jwt.7.1.2.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Cryptography.ProtectedData/4.4.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog==",
|
||||
"path": "system.security.cryptography.protecteddata/4.4.0",
|
||||
"hashPath": "system.security.cryptography.protecteddata.4.4.0.nupkg.sha512"
|
||||
},
|
||||
"System.Security.Permissions/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-dkOV6YYVBnYRa15/yv004eCGRBVADXw8qRbbNiCn/XpdJSUXkkUeIvdvFHkvnko4CdKMqG8yRHC4ox83LSlMsQ==",
|
||||
"path": "system.security.permissions/4.7.0",
|
||||
"hashPath": "system.security.permissions.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"System.Windows.Extensions/4.7.0": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-CeWTdRNfRaSh0pm2gDTJFwVaXfTq6Xwv/sA887iwPTneW7oMtMlpvDIO+U60+3GWTB7Aom6oQwv5VZVUhQRdPQ==",
|
||||
"path": "system.windows.extensions/4.7.0",
|
||||
"hashPath": "system.windows.extensions.4.7.0.nupkg.sha512"
|
||||
},
|
||||
"ZstdSharp.Port/0.7.1": {
|
||||
"type": "package",
|
||||
"serviceable": true,
|
||||
"sha512": "sha512-Idgg+mJEyAujqDPzA3APy9dNoyw0YQcNA65GgYjktDRtJ+nvx/hv+J+m6Eax3JJMGEYGy04oc5YNP6ZvQ3Y1vQ==",
|
||||
"path": "zstdsharp.port/0.7.1",
|
||||
"hashPath": "zstdsharp.port.0.7.1.nupkg.sha512"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user