21
This commit is contained in:
parent
68955dcd80
commit
43f8a88394
290
.kiro/specs/float-ball-migration/design.md
Normal file
290
.kiro/specs/float-ball-migration/design.md
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
# Design Document: Float Ball Migration
|
||||
|
||||
## Overview
|
||||
|
||||
本设计文档描述悬浮球功能从 PHP 后端迁移到 .NET 10 后端的技术方案。包括数据库表设计、数据迁移脚本、API 接口实现和 Entity Framework 配置。
|
||||
|
||||
悬浮球是首页显示的可点击浮动图标,支持两种交互方式:
|
||||
1. **展示图片** (type=1): 点击后弹出图片弹窗
|
||||
2. **跳转页面** (type=2): 点击后跳转到指定页面
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Frontend (UniApp) │
|
||||
│ FloatBall.vue Component │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ GET /api/getFloatBall
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ HoneyBox.Api Layer │
|
||||
│ ConfigController.cs │
|
||||
│ [AllowAnonymous] endpoint │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ HoneyBox.Core Layer │
|
||||
│ IFloatBallService.cs │
|
||||
│ FloatBallService.cs │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ HoneyBox.Model Layer │
|
||||
│ FloatBallConfig.cs (Entity) │
|
||||
│ FloatBallResponse.cs (DTO) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ SQL Server │
|
||||
│ float_ball_configs table │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Components and Interfaces
|
||||
|
||||
### 1. Database Table: float_ball_configs
|
||||
|
||||
```sql
|
||||
CREATE TABLE float_ball_configs (
|
||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
status TINYINT NOT NULL DEFAULT 0, -- 状态: 0关闭 1开启
|
||||
type TINYINT NOT NULL DEFAULT 1, -- 类型: 1展示图片 2跳转页面
|
||||
image NVARCHAR(255) NOT NULL DEFAULT '', -- 悬浮球图片URL
|
||||
link_url NVARCHAR(255) NOT NULL DEFAULT '', -- 跳转链接
|
||||
position_x NVARCHAR(30) NOT NULL DEFAULT '', -- X轴位置
|
||||
position_y NVARCHAR(30) NOT NULL DEFAULT '', -- Y轴位置
|
||||
width NVARCHAR(30) NOT NULL DEFAULT '', -- 宽度
|
||||
height NVARCHAR(30) NOT NULL DEFAULT '', -- 高度
|
||||
effect TINYINT NOT NULL DEFAULT 0, -- 特效: 0无 1缩放动画
|
||||
title NVARCHAR(255) NULL, -- 标题
|
||||
image_details NVARCHAR(255) NULL, -- 详情图片URL
|
||||
image_bj NVARCHAR(255) NULL, -- 背景图片URL
|
||||
image_details_x NVARCHAR(255) NULL, -- 详情图片X偏移
|
||||
image_details_y NVARCHAR(255) NULL, -- 详情图片Y偏移
|
||||
image_details_w NVARCHAR(255) NULL, -- 详情图片宽度
|
||||
image_details_h NVARCHAR(255) NULL, -- 详情图片高度
|
||||
created_at DATETIME2 NOT NULL DEFAULT GETDATE(),
|
||||
updated_at DATETIME2 NOT NULL DEFAULT GETDATE()
|
||||
);
|
||||
```
|
||||
|
||||
### 2. Entity Class: FloatBallConfig
|
||||
|
||||
```csharp
|
||||
namespace HoneyBox.Model.Entities;
|
||||
|
||||
public class FloatBallConfig
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public byte Status { get; set; }
|
||||
public byte Type { get; set; }
|
||||
public string Image { get; set; } = string.Empty;
|
||||
public string LinkUrl { get; set; } = string.Empty;
|
||||
public string PositionX { get; set; } = string.Empty;
|
||||
public string PositionY { get; set; } = string.Empty;
|
||||
public string Width { get; set; } = string.Empty;
|
||||
public string Height { get; set; } = string.Empty;
|
||||
public byte Effect { get; set; }
|
||||
public string? Title { get; set; }
|
||||
public string? ImageDetails { get; set; }
|
||||
public string? ImageBj { get; set; }
|
||||
public string? ImageDetailsX { get; set; }
|
||||
public string? ImageDetailsY { get; set; }
|
||||
public string? ImageDetailsW { get; set; }
|
||||
public string? ImageDetailsH { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Response DTO: FloatBallResponse
|
||||
|
||||
```csharp
|
||||
namespace HoneyBox.Model.Models.FloatBall;
|
||||
|
||||
public class FloatBallResponse
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public int Type { get; set; }
|
||||
public string Image { get; set; } = string.Empty;
|
||||
public string LinkUrl { get; set; } = string.Empty;
|
||||
public string PositionX { get; set; } = string.Empty;
|
||||
public string PositionY { get; set; } = string.Empty;
|
||||
public string Width { get; set; } = string.Empty;
|
||||
public string Height { get; set; } = string.Empty;
|
||||
public int Effect { get; set; }
|
||||
public string? Title { get; set; }
|
||||
public string? ImageDetails { get; set; }
|
||||
public string? ImageBj { get; set; }
|
||||
public string? ImageDetailsX { get; set; }
|
||||
public string? ImageDetailsY { get; set; }
|
||||
public string? ImageDetailsW { get; set; }
|
||||
public string? ImageDetailsH { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Service Interface: IFloatBallService
|
||||
|
||||
```csharp
|
||||
namespace HoneyBox.Core.Interfaces;
|
||||
|
||||
public interface IFloatBallService
|
||||
{
|
||||
Task<List<FloatBallResponse>> GetEnabledFloatBallsAsync();
|
||||
}
|
||||
```
|
||||
|
||||
### 5. API Endpoint
|
||||
|
||||
```
|
||||
GET /api/getFloatBall
|
||||
Authorization: None (AllowAnonymous)
|
||||
Response: ApiResponse<List<FloatBallResponse>>
|
||||
```
|
||||
|
||||
## Data Models
|
||||
|
||||
### MySQL Source Table Schema (float_ball_config)
|
||||
|
||||
| Column | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| id | int(11) | 主键ID |
|
||||
| status | tinyint(1) | 状态: 0关闭 1开启 |
|
||||
| type | tinyint(1) | 类型: 1展示图片 2跳转页面 |
|
||||
| image | varchar(255) | 悬浮球图片URL |
|
||||
| link_url | varchar(255) | 跳转链接 |
|
||||
| position_x | varchar(30) | X轴位置 (如: -0%, 10px) |
|
||||
| position_y | varchar(30) | Y轴位置 (如: 70vh, 21vh) |
|
||||
| width | varchar(30) | 宽度 (如: 150rpx, 52rpx) |
|
||||
| height | varchar(30) | 高度 (如: 165rpx, 120rpx) |
|
||||
| effect | tinyint(1) | 特效: 0无 1缩放动画 |
|
||||
| create_time | int(11) | 创建时间 (Unix时间戳) |
|
||||
| update_time | int(11) | 更新时间 (Unix时间戳) |
|
||||
| title | varchar(255) | 标题 |
|
||||
| image_details | varchar(255) | 详情图片URL |
|
||||
| image_bj | varchar(255) | 背景图片URL |
|
||||
| image_details_x | varchar(255) | 详情图片X偏移 |
|
||||
| image_details_y | varchar(255) | 详情图片Y偏移 |
|
||||
| image_details_w | varchar(255) | 详情图片宽度 |
|
||||
| image_details_h | varchar(255) | 详情图片高度 |
|
||||
|
||||
### Data Migration Mapping
|
||||
|
||||
| MySQL Column | SQL Server Column | Transformation |
|
||||
|--------------|-------------------|----------------|
|
||||
| id | id | 保持原值 (IDENTITY_INSERT ON) |
|
||||
| status | status | 直接映射 |
|
||||
| type | type | 直接映射 |
|
||||
| image | image | 直接映射 |
|
||||
| link_url | link_url | 直接映射 |
|
||||
| position_x | position_x | 直接映射 |
|
||||
| position_y | position_y | 直接映射 |
|
||||
| width | width | 直接映射 |
|
||||
| height | height | 直接映射 |
|
||||
| effect | effect | 直接映射 |
|
||||
| title | title | 直接映射 |
|
||||
| image_details | image_details | 直接映射 |
|
||||
| image_bj | image_bj | 直接映射 |
|
||||
| image_details_x | image_details_x | 直接映射 |
|
||||
| image_details_y | image_details_y | 直接映射 |
|
||||
| image_details_w | image_details_w | 直接映射 |
|
||||
| image_details_h | image_details_h | 直接映射 |
|
||||
| create_time | created_at | Unix时间戳 → DATETIME2 |
|
||||
| update_time | updated_at | Unix时间戳 → DATETIME2 |
|
||||
|
||||
## Correctness Properties
|
||||
|
||||
*A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
|
||||
|
||||
### Property 1: Data Migration Record Count Consistency
|
||||
|
||||
*For any* migration execution, the number of records in SQL Server `float_ball_configs` table after migration SHALL equal the number of records in MySQL `float_ball_config` table.
|
||||
|
||||
**Validates: Requirements 2.4**
|
||||
|
||||
### Property 2: Data Migration ID Preservation
|
||||
|
||||
*For any* record migrated from MySQL to SQL Server, the `id` value in the target table SHALL equal the `id` value in the source table.
|
||||
|
||||
**Validates: Requirements 2.3**
|
||||
|
||||
### Property 3: Timestamp Transformation Validity
|
||||
|
||||
*For any* Unix timestamp value from MySQL, the transformed DATETIME2 value in SQL Server SHALL represent the same point in time.
|
||||
|
||||
**Validates: Requirements 2.2**
|
||||
|
||||
### Property 4: API Returns Only Enabled Configurations
|
||||
|
||||
*For any* GET request to `/api/getFloatBall`, all returned configurations SHALL have status equal to 1 (enabled) in the database.
|
||||
|
||||
**Validates: Requirements 3.1, 3.2**
|
||||
|
||||
### Property 5: API Response Field Completeness
|
||||
|
||||
*For any* configuration returned by the API, the response SHALL contain all required fields (id, type, image, link_url, position_x, position_y, width, height, effect, title, image_details, image_bj, image_details_x, image_details_y, image_details_w, image_details_h) and SHALL NOT contain status, created_at, updated_at fields.
|
||||
|
||||
**Validates: Requirements 3.3, 3.4**
|
||||
|
||||
### Property 6: API Response Format Consistency
|
||||
|
||||
*For any* successful API response, the format SHALL be `{ "status": 1, "msg": "...", "data": [...] }` with status equal to 1.
|
||||
|
||||
**Validates: Requirements 5.1, 5.2**
|
||||
|
||||
### Property 7: Image URL Preservation
|
||||
|
||||
*For any* configuration with image URLs (image, image_details, image_bj), the API response SHALL return the URLs unchanged from the database values.
|
||||
|
||||
**Validates: Requirements 5.4**
|
||||
|
||||
### Property 8: Incremental Migration Idempotence
|
||||
|
||||
*For any* migration script execution, running the migration twice SHALL result in the same final state (no duplicate records).
|
||||
|
||||
**Validates: Requirements 2.5**
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Migration Script Errors
|
||||
|
||||
1. **Connection Failure**: Log error and exit with non-zero code
|
||||
2. **Single Record Insert Failure**: Log error, continue with remaining records
|
||||
3. **Batch Insert Failure**: Fall back to single record inserts
|
||||
|
||||
### API Errors
|
||||
|
||||
1. **Database Connection Error**: Return `{ "status": 0, "msg": "获取悬浮球配置失败", "data": null }`
|
||||
2. **Unexpected Exception**: Log error, return generic error message
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
|
||||
- Test FloatBallService.GetEnabledFloatBallsAsync() returns only enabled configs
|
||||
- Test response DTO mapping excludes status, created_at, updated_at
|
||||
- Test empty result when no enabled configs exist
|
||||
|
||||
### Property-Based Tests
|
||||
|
||||
使用 xUnit + FsCheck 进行属性测试:
|
||||
|
||||
1. **Property 1**: 验证迁移后记录数一致性
|
||||
2. **Property 4**: 验证 API 只返回启用的配置
|
||||
3. **Property 8**: 验证迁移脚本幂等性
|
||||
|
||||
### Integration Tests
|
||||
|
||||
- Test full API endpoint `/api/getFloatBall` returns correct format
|
||||
- Test migration script with test database
|
||||
|
||||
### Test Configuration
|
||||
|
||||
- Property tests: 最少 100 次迭代
|
||||
- 使用 FsCheck 生成随机测试数据
|
||||
- 标签格式: **Feature: float-ball-migration, Property {number}: {property_text}**
|
||||
73
.kiro/specs/float-ball-migration/requirements.md
Normal file
73
.kiro/specs/float-ball-migration/requirements.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Requirements Document
|
||||
|
||||
## Introduction
|
||||
|
||||
悬浮球功能迁移 - 将悬浮球配置管理功能从 PHP (ThinkPHP) 后端迁移到 .NET 10 后端。包括数据库表迁移、数据迁移和 API 接口迁移。悬浮球是首页显示的可点击浮动图标,支持展示图片弹窗或跳转页面两种交互方式。
|
||||
|
||||
## Glossary
|
||||
|
||||
- **Float_Ball_System**: 悬浮球系统,负责管理和展示首页悬浮球配置
|
||||
- **Float_Ball_Config**: 悬浮球配置实体,存储单个悬浮球的所有配置信息
|
||||
- **Float_Ball_Service**: 悬浮球业务服务,处理悬浮球相关的业务逻辑
|
||||
- **Migration_Script**: 数据迁移脚本,负责将 MySQL 数据迁移到 SQL Server
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement 1: 数据库表迁移
|
||||
|
||||
**User Story:** As a developer, I want to create the float_ball_configs table in SQL Server, so that the system can store float ball configuration data.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. THE Float_Ball_System SHALL create a `float_ball_configs` table in SQL Server with all required columns
|
||||
2. THE Float_Ball_System SHALL support the following columns: id, status, type, image, link_url, position_x, position_y, width, height, effect, title, image_details, image_bj, image_details_x, image_details_y, image_details_w, image_details_h, created_at, updated_at
|
||||
3. THE Float_Ball_System SHALL use appropriate SQL Server data types matching the original MySQL schema
|
||||
4. THE Float_Ball_System SHALL set id as primary key with auto-increment
|
||||
|
||||
### Requirement 2: 数据迁移
|
||||
|
||||
**User Story:** As a developer, I want to migrate existing float ball data from MySQL to SQL Server, so that the new system has all historical configurations.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. THE Migration_Script SHALL read all records from MySQL `float_ball_config` table
|
||||
2. THE Migration_Script SHALL transform Unix timestamps to SQL Server DATETIME2 format
|
||||
3. THE Migration_Script SHALL insert all records into SQL Server `float_ball_configs` table preserving original IDs
|
||||
4. THE Migration_Script SHALL verify record count consistency after migration
|
||||
5. THE Migration_Script SHALL support incremental migration (skip already migrated records)
|
||||
6. IF migration fails for a record, THEN THE Migration_Script SHALL log the error and continue with remaining records
|
||||
|
||||
### Requirement 3: 获取悬浮球配置接口
|
||||
|
||||
**User Story:** As a frontend developer, I want to call the getFloatBall API, so that I can display float balls on the homepage.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN a GET request is made to `/api/getFloatBall`, THE Float_Ball_System SHALL return all enabled float ball configurations
|
||||
2. THE Float_Ball_System SHALL only return configurations where status equals 1 (enabled)
|
||||
3. THE Float_Ball_System SHALL return the following fields for each configuration: id, type, image, link_url, position_x, position_y, width, height, effect, title, image_details, image_bj, image_details_x, image_details_y, image_details_w, image_details_h
|
||||
4. THE Float_Ball_System SHALL NOT return status, created_at, updated_at fields in the response
|
||||
5. THE Float_Ball_System SHALL return an empty array if no enabled configurations exist
|
||||
6. THE Float_Ball_System SHALL NOT require authentication for this endpoint
|
||||
|
||||
### Requirement 4: Entity Framework 实体配置
|
||||
|
||||
**User Story:** As a developer, I want to create the FloatBallConfig entity class, so that Entity Framework can map the database table correctly.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. THE Float_Ball_System SHALL create a `FloatBallConfig` entity class in HoneyBox.Model
|
||||
2. THE Float_Ball_System SHALL configure proper column mappings using Fluent API or Data Annotations
|
||||
3. THE Float_Ball_System SHALL register the entity in HoneyBoxDbContext
|
||||
4. THE Float_Ball_System SHALL support nullable fields for optional columns (title, image_details, image_bj, etc.)
|
||||
|
||||
### Requirement 5: 响应格式兼容性
|
||||
|
||||
**User Story:** As a frontend developer, I want the API response format to be compatible with the existing frontend, so that no frontend changes are required.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. THE Float_Ball_System SHALL return response in format: `{ "status": 1, "msg": "获取悬浮球配置成功", "data": [...] }`
|
||||
2. THE Float_Ball_System SHALL return status 1 for successful requests
|
||||
3. THE Float_Ball_System SHALL return status 0 for failed requests with error message
|
||||
4. WHEN returning image URLs, THE Float_Ball_System SHALL preserve the original URL format (already contains full CDN path)
|
||||
84
.kiro/specs/float-ball-migration/tasks.md
Normal file
84
.kiro/specs/float-ball-migration/tasks.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Implementation Plan: Float Ball Migration
|
||||
|
||||
## Overview
|
||||
|
||||
将悬浮球功能从 PHP 后端迁移到 .NET 10 后端,包括数据库表创建、数据迁移脚本和 API 接口实现。
|
||||
|
||||
## Tasks
|
||||
|
||||
- [x] 1. 创建数据库表和 Entity 配置
|
||||
- [x] 1.1 创建 SQL Server 表 `float_ball_configs`
|
||||
- 在 SQL Server 中执行建表语句
|
||||
- 包含所有必要字段和约束
|
||||
- _Requirements: 1.1, 1.2, 1.3, 1.4_
|
||||
|
||||
- [x] 1.2 创建 FloatBallConfig 实体类
|
||||
- 在 `HoneyBox.Model/Entities/` 目录创建 `FloatBallConfig.cs`
|
||||
- 定义所有属性和数据类型
|
||||
- _Requirements: 4.1, 4.4_
|
||||
|
||||
- [x] 1.3 配置 DbContext
|
||||
- 在 `HoneyBoxDbContext.cs` 中添加 `DbSet<FloatBallConfig>`
|
||||
- 配置 Fluent API 映射
|
||||
- _Requirements: 4.2, 4.3_
|
||||
|
||||
- [x] 2. 创建数据迁移脚本
|
||||
- [x] 2.1 创建 `migrate_float_ball.js` 迁移脚本
|
||||
- 参考 `migrate_coupons.js` 的模式
|
||||
- 实现 MySQL 到 SQL Server 的数据迁移
|
||||
- 支持增量迁移(跳过已迁移记录)
|
||||
- 包含错误处理和日志记录
|
||||
- _Requirements: 2.1, 2.2, 2.3, 2.5, 2.6_
|
||||
|
||||
- [x] 2.2 执行数据迁移并验证
|
||||
- 运行迁移脚本
|
||||
- 验证记录数一致性
|
||||
- _Requirements: 2.4_
|
||||
|
||||
- [x] 3. 实现 API 接口
|
||||
- [x] 3.1 创建 FloatBallResponse DTO
|
||||
- 在 `HoneyBox.Model/Models/FloatBall/` 目录创建响应模型
|
||||
- 排除 status, created_at, updated_at 字段
|
||||
- _Requirements: 3.3, 3.4_
|
||||
|
||||
- [x] 3.2 创建 IFloatBallService 接口和实现
|
||||
- 在 `HoneyBox.Core/Interfaces/` 创建接口
|
||||
- 在 `HoneyBox.Core/Services/` 创建实现
|
||||
- 实现 GetEnabledFloatBallsAsync 方法
|
||||
- _Requirements: 3.1, 3.2_
|
||||
|
||||
- [x] 3.3 创建 API 端点
|
||||
- 在 `ConfigController.cs` 或新建 `FloatBallController.cs` 添加端点
|
||||
- 实现 `GET /api/getFloatBall` 接口
|
||||
- 设置 `[AllowAnonymous]` 属性
|
||||
- _Requirements: 3.5, 3.6, 5.1, 5.2, 5.3_
|
||||
|
||||
- [x] 3.4 注册服务依赖
|
||||
- 在 Autofac 模块中注册 IFloatBallService
|
||||
- _Requirements: 4.3_
|
||||
|
||||
- [x] 4. Checkpoint - 验证功能
|
||||
- 确保所有代码编译通过
|
||||
- 测试 API 接口返回正确数据
|
||||
- 验证响应格式与 PHP 后端一致
|
||||
- 如有问题请询问用户
|
||||
|
||||
- [ ]* 5. 编写测试
|
||||
- [ ]* 5.1 编写单元测试
|
||||
- 测试 FloatBallService 只返回启用的配置
|
||||
- 测试空结果场景
|
||||
- **Property 4: API Returns Only Enabled Configurations**
|
||||
- **Validates: Requirements 3.1, 3.2**
|
||||
|
||||
- [ ]* 5.2 编写集成测试
|
||||
- 测试完整 API 端点
|
||||
- 验证响应格式
|
||||
- **Property 6: API Response Format Consistency**
|
||||
- **Validates: Requirements 5.1, 5.2**
|
||||
|
||||
## Notes
|
||||
|
||||
- 任务标记 `*` 为可选任务,可跳过以加快 MVP 开发
|
||||
- 每个任务引用具体需求以便追溯
|
||||
- 数据迁移脚本参考现有的 `migrate_coupons.js` 模式
|
||||
- API 端点无需认证,使用 `[AllowAnonymous]` 属性
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -2,14 +2,22 @@
|
|||
"Version": 1,
|
||||
"WorkspaceRootPath": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\goodscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\goodscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\configcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\configcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.model\\data\\honeyboxdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|solutionrelative:src\\honeybox.model\\data\\honeyboxdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.model\\entities\\useraddress.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|solutionrelative:src\\honeybox.model\\entities\\useraddress.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\goodscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\goodscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\paycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\paycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
|
|
@ -34,10 +42,6 @@
|
|||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.model\\data\\honeyboxdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|solutionrelative:src\\honeybox.model\\data\\honeyboxdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.model\\base\\apiresponse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|solutionrelative:src\\honeybox.model\\base\\apiresponse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
|
|
@ -58,7 +62,7 @@
|
|||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": 7,
|
||||
"SelectedChildIndex": 4,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
|
|
@ -67,19 +71,32 @@
|
|||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "UserAddress.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Entities\\UserAddress.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Entities\\UserAddress.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Entities\\UserAddress.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Model\\Entities\\UserAddress.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T09:17:05.325Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"Title": "PayController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||
"ViewState": "AgIAAB8AAAAAAAAAAAAAwAAAAAAAAAAAAAAAAA==",
|
||||
"ViewState": "AgIAACIAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:35:53.369Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"DocumentIndex": 5,
|
||||
"Title": "CouponController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||
|
|
@ -92,46 +109,46 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"DocumentIndex": 0,
|
||||
"Title": "ConfigController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||
"ViewState": "AgIAAEcAAAAAAAAAAAAAAFIAAAAcAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAIcAAAAAAAAAAADwv6QAAABOAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:15:47.201Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 5,
|
||||
"DocumentIndex": 7,
|
||||
"Title": "AuthController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||
"ViewState": "AgIAAGYAAAAAAAAAAAAuwPcAAAAWAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAGYAAAAAAAAAAAAuwCUBAAAWAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:07:38.674Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"DocumentIndex": 6,
|
||||
"Title": "CollectionController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||
"ViewState": "AgIAAL0AAAAAAAAAAAAAAM0AAAAUAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAA0BAAAAAAAAAAAAAEkBAAAUAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:07:37.824Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"DocumentIndex": 8,
|
||||
"Title": "appsettings.json",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\appsettings.json",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\appsettings.json",
|
||||
|
|
@ -144,33 +161,33 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"DocumentIndex": 3,
|
||||
"Title": "GoodsController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||
"ViewState": "AgIAACgAAAAAAAAAAAAuwFMAAABUAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAD0AAAAAAAAAAAAAAFkAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T05:07:08.788Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"DocumentIndex": 1,
|
||||
"Title": "HoneyBoxDbContext.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||
"ViewState": "AgIAADkAAAAAAAAAAAAcwEYAAAA+AAAAAAAAAA==",
|
||||
"ViewState": "AgIAAFUAAAAAAAAAAAAUwHAAAAAqAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-02T06:46:26.809Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"DocumentIndex": 9,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Program.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Program.cs",
|
||||
|
|
@ -183,7 +200,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"DocumentIndex": 10,
|
||||
"Title": "ApiResponse.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
||||
|
|
@ -195,7 +212,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 10,
|
||||
"DocumentIndex": 11,
|
||||
"Title": "PrizeModels.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
||||
|
|
@ -207,7 +224,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 11,
|
||||
"DocumentIndex": 12,
|
||||
"Title": "T_Task.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Entities\\T_Task.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Entities\\T_Task.cs",
|
||||
|
|
|
|||
|
|
@ -2,18 +2,6 @@
|
|||
"Version": 1,
|
||||
"WorkspaceRootPath": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\",
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\goodscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\goodscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\configcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\configcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\paycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\paycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\couponcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\couponcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
|
|
@ -26,6 +14,34 @@
|
|||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\authcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\authcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\addresscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\addresscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\redeemcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\redeemcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\configcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\configcontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.model\\data\\honeyboxdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|solutionrelative:src\\honeybox.model\\data\\honeyboxdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.model\\entities\\useraddress.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|solutionrelative:src\\honeybox.model\\entities\\useraddress.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\goodscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\goodscontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\controllers\\paycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\controllers\\paycontroller.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\appsettings.json||{90A6B3A7-C1A3-4009-A288-E2FF89E96FA0}"
|
||||
|
|
@ -34,10 +50,6 @@
|
|||
"AbsoluteMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.api\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{73C88F2C-A98A-4E84-A61C-02FBA69416A4}|src\\HoneyBox.Api\\HoneyBox.Api.csproj|solutionrelative:src\\honeybox.api\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.model\\data\\honeyboxdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|solutionrelative:src\\honeybox.model\\data\\honeyboxdbcontext.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|d:\\outsource\\haniblindbox\\server\\c#\\honeybox\\src\\honeybox.model\\base\\apiresponse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{B3732485-B324-43A2-AEB0-092AD84A1302}|src\\HoneyBox.Model\\HoneyBox.Model.csproj|solutionrelative:src\\honeybox.model\\base\\apiresponse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
|
|
@ -58,7 +70,7 @@
|
|||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": 7,
|
||||
"SelectedChildIndex": 5,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
|
|
@ -66,72 +78,111 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"DocumentIndex": 4,
|
||||
"Title": "RedeemController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\RedeemController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\RedeemController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\RedeemController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\RedeemController.cs",
|
||||
"ViewState": "AgIAAFIAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T11:40:46.393Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"Title": "AddressController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AddressController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\AddressController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AddressController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\AddressController.cs",
|
||||
"ViewState": "AgIAAGkAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T11:40:39.283Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"Title": "UserAddress.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Entities\\UserAddress.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Entities\\UserAddress.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Entities\\UserAddress.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Model\\Entities\\UserAddress.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAADwvwAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T09:17:05.325Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"Title": "PayController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||
"ViewState": "AgIAAB8AAAAAAAAAAAAAwAAAAAAAAAAAAAAAAA==",
|
||||
"ViewState": "AgIAACIAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:35:53.369Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"DocumentIndex": 0,
|
||||
"Title": "CouponController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"ViewState": "AgIAADEBAAAAAAAAAAAAAEQAAAA3AAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:35:48.625Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"DocumentIndex": 5,
|
||||
"Title": "ConfigController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||
"ViewState": "AgIAAEcAAAAAAAAAAAAAAFIAAAAcAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAJsAAAAAAAAAAADwv7QAAAANAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:15:47.201Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 5,
|
||||
"DocumentIndex": 2,
|
||||
"Title": "AuthController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||
"ViewState": "AgIAAGYAAAAAAAAAAAAuwPcAAAAWAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAC4BAAAAAAAAAAAuwCUBAAAWAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:07:38.674Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"DocumentIndex": 1,
|
||||
"Title": "CollectionController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||
"ViewState": "AgIAAL0AAAAAAAAAAAAAAM0AAAAUAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAFMBAAAAAAAAAADwvyABAAAZAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T06:07:37.824Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"DocumentIndex": 10,
|
||||
"Title": "appsettings.json",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\appsettings.json",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\appsettings.json",
|
||||
|
|
@ -144,33 +195,33 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"DocumentIndex": 8,
|
||||
"Title": "GoodsController.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||
"ViewState": "AgIAADQAAAAAAAAAAAAAAF0AAAAMAAAAAAAAAA==",
|
||||
"ViewState": "AgIAAD0AAAAAAAAAAAAAAFkAAAAIAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-03T05:07:08.788Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"DocumentIndex": 6,
|
||||
"Title": "HoneyBoxDbContext.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||
"RelativeToolTip": "src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||
"ViewState": "AgIAADkAAAAAAAAAAAAcwEYAAAA+AAAAAAAAAA==",
|
||||
"ViewState": "AgIAAFUAAAAAAAAAAAAUwHIAAAAqAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2026-01-02T06:46:26.809Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"DocumentIndex": 11,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Program.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Program.cs",
|
||||
|
|
@ -183,7 +234,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"DocumentIndex": 12,
|
||||
"Title": "ApiResponse.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
||||
|
|
@ -195,7 +246,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 10,
|
||||
"DocumentIndex": 13,
|
||||
"Title": "PrizeModels.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
||||
|
|
@ -207,7 +258,7 @@
|
|||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 11,
|
||||
"DocumentIndex": 14,
|
||||
"Title": "T_Task.cs",
|
||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Entities\\T_Task.cs",
|
||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Entities\\T_Task.cs",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using HoneyBox.Core.Interfaces;
|
||||
using HoneyBox.Model.Base;
|
||||
using HoneyBox.Model.Models.Config;
|
||||
using HoneyBox.Model.Models.FloatBall;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HoneyBox.Api.Controllers;
|
||||
|
|
@ -9,20 +11,23 @@ namespace HoneyBox.Api.Controllers;
|
|||
/// 配置控制器 - 处理系统配置和平台配置
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 提供系统配置、商品类型、平台配置等功能
|
||||
/// 提供系统配置、商品类型、平台配置、悬浮球配置等功能
|
||||
/// </remarks>
|
||||
[ApiController]
|
||||
[Route("api")]
|
||||
public class ConfigController : ControllerBase
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IFloatBallService _floatBallService;
|
||||
private readonly ILogger<ConfigController> _logger;
|
||||
|
||||
public ConfigController(
|
||||
IConfigService configService,
|
||||
IFloatBallService floatBallService,
|
||||
ILogger<ConfigController> logger)
|
||||
{
|
||||
_configService = configService;
|
||||
_floatBallService = floatBallService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
|
@ -160,9 +165,9 @@ public class ConfigController : ControllerBase
|
|||
/// </remarks>
|
||||
/// <param name="request">请求参数</param>
|
||||
/// <returns>单页内容数据</returns>
|
||||
[HttpPost("danye")]
|
||||
[HttpGet("danye")]
|
||||
[ProducesResponseType(typeof(ApiResponse<DanyeContentDto>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<DanyeContentDto>> GetDanyeContent([FromBody] DanyeRequest? request)
|
||||
public async Task<ApiResponse<DanyeContentDto>> GetDanyeContent([FromQuery] DanyeRequest? request)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -184,4 +189,32 @@ public class ConfigController : ControllerBase
|
|||
return ApiResponse<DanyeContentDto>.Fail("获取单页内容失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取悬浮球配置
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// GET /api/getFloatBall
|
||||
///
|
||||
/// 返回所有启用的悬浮球配置列表
|
||||
/// 支持未登录访问
|
||||
/// Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 5.1, 5.2, 5.3
|
||||
/// </remarks>
|
||||
/// <returns>悬浮球配置列表</returns>
|
||||
[HttpGet("getFloatBall")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(typeof(ApiResponse<List<FloatBallResponse>>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<List<FloatBallResponse>>> GetFloatBall()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _floatBallService.GetEnabledFloatBallsAsync();
|
||||
return ApiResponse<List<FloatBallResponse>>.Success(result, "获取悬浮球配置成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to get float ball configurations");
|
||||
return ApiResponse<List<FloatBallResponse>>.Fail("获取悬浮球配置失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Security.Claims;
|
||||
using System.Security.Claims;
|
||||
using HoneyBox.Core.Interfaces;
|
||||
using HoneyBox.Model.Base;
|
||||
using HoneyBox.Model.Models;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
using HoneyBox.Model.Models.FloatBall;
|
||||
|
||||
namespace HoneyBox.Core.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// 悬浮球服务接口
|
||||
/// </summary>
|
||||
public interface IFloatBallService
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取所有启用的悬浮球配置
|
||||
/// </summary>
|
||||
/// <returns>启用的悬浮球配置列表</returns>
|
||||
Task<List<FloatBallResponse>> GetEnabledFloatBallsAsync();
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
using HoneyBox.Core.Interfaces;
|
||||
using HoneyBox.Model.Data;
|
||||
using HoneyBox.Model.Models.FloatBall;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace HoneyBox.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 悬浮球服务实现
|
||||
/// </summary>
|
||||
public class FloatBallService : IFloatBallService
|
||||
{
|
||||
private readonly HoneyBoxDbContext _dbContext;
|
||||
private readonly ILogger<FloatBallService> _logger;
|
||||
|
||||
public FloatBallService(
|
||||
HoneyBoxDbContext dbContext,
|
||||
ILogger<FloatBallService> logger)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<List<FloatBallResponse>> GetEnabledFloatBallsAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var floatBalls = await _dbContext.FloatBallConfigs
|
||||
.Where(f => f.Status == 1)
|
||||
.Select(f => new FloatBallResponse
|
||||
{
|
||||
Id = f.Id,
|
||||
Type = f.Type,
|
||||
Image = f.Image,
|
||||
LinkUrl = f.LinkUrl,
|
||||
PositionX = f.PositionX,
|
||||
PositionY = f.PositionY,
|
||||
Width = f.Width,
|
||||
Height = f.Height,
|
||||
Effect = f.Effect,
|
||||
Title = f.Title,
|
||||
ImageDetails = f.ImageDetails,
|
||||
ImageBj = f.ImageBj,
|
||||
ImageDetailsX = f.ImageDetailsX,
|
||||
ImageDetailsY = f.ImageDetailsY,
|
||||
ImageDetailsW = f.ImageDetailsW,
|
||||
ImageDetailsH = f.ImageDetailsH
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return floatBalls;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to get enabled float ball configurations");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -277,6 +277,14 @@ public class ServiceModule : Module
|
|||
return new ConfigService(dbContext, logger, redisService);
|
||||
}).As<IConfigService>().InstancePerLifetimeScope();
|
||||
|
||||
// 注册悬浮球服务
|
||||
builder.Register(c =>
|
||||
{
|
||||
var dbContext = c.Resolve<HoneyBoxDbContext>();
|
||||
var logger = c.Resolve<ILogger<FloatBallService>>();
|
||||
return new FloatBallService(dbContext, logger);
|
||||
}).As<IFloatBallService>().InstancePerLifetimeScope();
|
||||
|
||||
// ========== 签到系统服务注册 ==========
|
||||
|
||||
// 注册签到服务
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ public partial class HoneyBoxDbContext : DbContext
|
|||
|
||||
public virtual DbSet<Reward> Rewards { get; set; }
|
||||
|
||||
public virtual DbSet<FloatBallConfig> FloatBallConfigs { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
// Connection string is configured in Program.cs via dependency injection
|
||||
|
|
@ -2974,6 +2976,97 @@ public partial class HoneyBoxDbContext : DbContext
|
|||
.HasColumnName("updated_at");
|
||||
});
|
||||
|
||||
modelBuilder.Entity<FloatBallConfig>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id).HasName("pk_float_ball_configs");
|
||||
|
||||
entity.ToTable("float_ball_configs", tb => tb.HasComment("悬浮球配置表,存储首页悬浮球配置信息"));
|
||||
|
||||
entity.HasIndex(e => e.Status, "ix_float_ball_configs_status");
|
||||
|
||||
entity.Property(e => e.Id)
|
||||
.HasComment("主键ID")
|
||||
.HasColumnName("id");
|
||||
entity.Property(e => e.Status)
|
||||
.HasDefaultValue((byte)0)
|
||||
.HasComment("状态: 0关闭 1开启")
|
||||
.HasColumnName("status");
|
||||
entity.Property(e => e.Type)
|
||||
.HasDefaultValue((byte)1)
|
||||
.HasComment("类型: 1展示图片 2跳转页面")
|
||||
.HasColumnName("type");
|
||||
entity.Property(e => e.Image)
|
||||
.HasMaxLength(255)
|
||||
.HasDefaultValue("")
|
||||
.HasComment("悬浮球图片URL")
|
||||
.HasColumnName("image");
|
||||
entity.Property(e => e.LinkUrl)
|
||||
.HasMaxLength(255)
|
||||
.HasDefaultValue("")
|
||||
.HasComment("跳转链接")
|
||||
.HasColumnName("link_url");
|
||||
entity.Property(e => e.PositionX)
|
||||
.HasMaxLength(30)
|
||||
.HasDefaultValue("")
|
||||
.HasComment("X轴位置")
|
||||
.HasColumnName("position_x");
|
||||
entity.Property(e => e.PositionY)
|
||||
.HasMaxLength(30)
|
||||
.HasDefaultValue("")
|
||||
.HasComment("Y轴位置")
|
||||
.HasColumnName("position_y");
|
||||
entity.Property(e => e.Width)
|
||||
.HasMaxLength(30)
|
||||
.HasDefaultValue("")
|
||||
.HasComment("宽度")
|
||||
.HasColumnName("width");
|
||||
entity.Property(e => e.Height)
|
||||
.HasMaxLength(30)
|
||||
.HasDefaultValue("")
|
||||
.HasComment("高度")
|
||||
.HasColumnName("height");
|
||||
entity.Property(e => e.Effect)
|
||||
.HasDefaultValue((byte)0)
|
||||
.HasComment("特效: 0无 1缩放动画")
|
||||
.HasColumnName("effect");
|
||||
entity.Property(e => e.Title)
|
||||
.HasMaxLength(255)
|
||||
.HasComment("标题")
|
||||
.HasColumnName("title");
|
||||
entity.Property(e => e.ImageDetails)
|
||||
.HasMaxLength(255)
|
||||
.HasComment("详情图片URL")
|
||||
.HasColumnName("image_details");
|
||||
entity.Property(e => e.ImageBj)
|
||||
.HasMaxLength(255)
|
||||
.HasComment("背景图片URL")
|
||||
.HasColumnName("image_bj");
|
||||
entity.Property(e => e.ImageDetailsX)
|
||||
.HasMaxLength(255)
|
||||
.HasComment("详情图片X偏移")
|
||||
.HasColumnName("image_details_x");
|
||||
entity.Property(e => e.ImageDetailsY)
|
||||
.HasMaxLength(255)
|
||||
.HasComment("详情图片Y偏移")
|
||||
.HasColumnName("image_details_y");
|
||||
entity.Property(e => e.ImageDetailsW)
|
||||
.HasMaxLength(255)
|
||||
.HasComment("详情图片宽度")
|
||||
.HasColumnName("image_details_w");
|
||||
entity.Property(e => e.ImageDetailsH)
|
||||
.HasMaxLength(255)
|
||||
.HasComment("详情图片高度")
|
||||
.HasColumnName("image_details_h");
|
||||
entity.Property(e => e.CreatedAt)
|
||||
.HasDefaultValueSql("(getdate())")
|
||||
.HasComment("创建时间")
|
||||
.HasColumnName("created_at");
|
||||
entity.Property(e => e.UpdatedAt)
|
||||
.HasDefaultValueSql("(getdate())")
|
||||
.HasComment("更新时间")
|
||||
.HasColumnName("updated_at");
|
||||
});
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
using System;
|
||||
|
||||
namespace HoneyBox.Model.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 悬浮球配置表,存储首页悬浮球配置信息
|
||||
/// </summary>
|
||||
public partial class FloatBallConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键ID
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态: 0关闭 1开启
|
||||
/// </summary>
|
||||
public byte Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类型: 1展示图片 2跳转页面
|
||||
/// </summary>
|
||||
public byte Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 悬浮球图片URL
|
||||
/// </summary>
|
||||
public string Image { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接
|
||||
/// </summary>
|
||||
public string LinkUrl { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// X轴位置
|
||||
/// </summary>
|
||||
public string PositionX { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Y轴位置
|
||||
/// </summary>
|
||||
public string PositionY { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 宽度
|
||||
/// </summary>
|
||||
public string Width { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 高度
|
||||
/// </summary>
|
||||
public string Height { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 特效: 0无 1缩放动画
|
||||
/// </summary>
|
||||
public byte Effect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片URL
|
||||
/// </summary>
|
||||
public string? ImageDetails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 背景图片URL
|
||||
/// </summary>
|
||||
public string? ImageBj { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片X偏移
|
||||
/// </summary>
|
||||
public string? ImageDetailsX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片Y偏移
|
||||
/// </summary>
|
||||
public string? ImageDetailsY { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片宽度
|
||||
/// </summary>
|
||||
public string? ImageDetailsW { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片高度
|
||||
/// </summary>
|
||||
public string? ImageDetailsH { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace HoneyBox.Model.Models.FloatBall;
|
||||
|
||||
/// <summary>
|
||||
/// 悬浮球配置响应DTO
|
||||
/// 排除 status, created_at, updated_at 字段
|
||||
/// </summary>
|
||||
public class FloatBallResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类型: 1展示图片 2跳转页面
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
public int Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 悬浮球图片URL
|
||||
/// </summary>
|
||||
[JsonPropertyName("image")]
|
||||
public string Image { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 跳转链接
|
||||
/// </summary>
|
||||
[JsonPropertyName("link_url")]
|
||||
public string LinkUrl { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// X轴位置
|
||||
/// </summary>
|
||||
[JsonPropertyName("position_x")]
|
||||
public string PositionX { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Y轴位置
|
||||
/// </summary>
|
||||
[JsonPropertyName("position_y")]
|
||||
public string PositionY { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 宽度
|
||||
/// </summary>
|
||||
[JsonPropertyName("width")]
|
||||
public string Width { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 高度
|
||||
/// </summary>
|
||||
[JsonPropertyName("height")]
|
||||
public string Height { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 特效: 0无 1缩放动画
|
||||
/// </summary>
|
||||
[JsonPropertyName("effect")]
|
||||
public int Effect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
[JsonPropertyName("title")]
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片URL
|
||||
/// </summary>
|
||||
[JsonPropertyName("image_details")]
|
||||
public string? ImageDetails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 背景图片URL
|
||||
/// </summary>
|
||||
[JsonPropertyName("image_bj")]
|
||||
public string? ImageBj { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片X偏移
|
||||
/// </summary>
|
||||
[JsonPropertyName("image_details_x")]
|
||||
public string? ImageDetailsX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片Y偏移
|
||||
/// </summary>
|
||||
[JsonPropertyName("image_details_y")]
|
||||
public string? ImageDetailsY { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片宽度
|
||||
/// </summary>
|
||||
[JsonPropertyName("image_details_w")]
|
||||
public string? ImageDetailsW { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 详情图片高度
|
||||
/// </summary>
|
||||
[JsonPropertyName("image_details_h")]
|
||||
public string? ImageDetailsH { get; set; }
|
||||
}
|
||||
267
server/scripts/migrate_float_ball.js
Normal file
267
server/scripts/migrate_float_ball.js
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/**
|
||||
* 悬浮球配置数据迁移脚本 - Node.js
|
||||
* Feature: float-ball-migration, Property 1: Data Migration Record Count Consistency
|
||||
* Feature: float-ball-migration, Property 2: Data Migration ID Preservation
|
||||
* Feature: float-ball-migration, Property 3: Timestamp Transformation Validity
|
||||
* Feature: float-ball-migration, Property 8: Incremental Migration Idempotence
|
||||
* Validates: Requirements 2.1, 2.2, 2.3, 2.5, 2.6
|
||||
*
|
||||
* 源表: MySQL float_ball_config
|
||||
* 目标表: SQL Server float_ball_configs
|
||||
*/
|
||||
|
||||
const mysql = require('mysql2/promise');
|
||||
const sql = require('mssql');
|
||||
|
||||
// MySQL 配置
|
||||
const mysqlConfig = {
|
||||
host: '192.168.195.16',
|
||||
port: 1887,
|
||||
user: 'root',
|
||||
password: 'Dbt@com@123',
|
||||
database: 'youdas',
|
||||
charset: 'utf8mb4'
|
||||
};
|
||||
|
||||
// SQL Server 配置
|
||||
const sqlServerConfig = {
|
||||
server: '192.168.195.15',
|
||||
port: 1433,
|
||||
user: 'sa',
|
||||
password: 'Dbt@com@123',
|
||||
database: 'honey_box',
|
||||
options: {
|
||||
encrypt: false,
|
||||
trustServerCertificate: true
|
||||
}
|
||||
};
|
||||
|
||||
// Unix时间戳转换为 SQL Server DATETIME2 格式
|
||||
function unixToDatetime(timestamp) {
|
||||
if (!timestamp || timestamp === 0) {
|
||||
return null;
|
||||
}
|
||||
const date = new Date(timestamp * 1000);
|
||||
return date.toISOString().slice(0, 23).replace('T', ' ');
|
||||
}
|
||||
|
||||
// 转义SQL字符串
|
||||
function escapeString(str) {
|
||||
if (str === null || str === undefined) return 'NULL';
|
||||
return "N'" + String(str).replace(/'/g, "''") + "'";
|
||||
}
|
||||
|
||||
// 格式化日期时间
|
||||
function formatDatetime(dt) {
|
||||
if (!dt) return 'NULL';
|
||||
return "'" + dt + "'";
|
||||
}
|
||||
|
||||
|
||||
// 获取已迁移的悬浮球配置ID列表
|
||||
async function getMigratedIds(pool) {
|
||||
const result = await pool.request().query('SELECT id FROM float_ball_configs');
|
||||
return new Set(result.recordset.map(r => r.id));
|
||||
}
|
||||
|
||||
// 批量插入悬浮球配置数据
|
||||
async function insertFloatBallsBatch(pool, floatBalls) {
|
||||
if (floatBalls.length === 0) return 0;
|
||||
|
||||
let insertedCount = 0;
|
||||
|
||||
// 构建批量插入SQL
|
||||
let sqlBatch = 'SET IDENTITY_INSERT float_ball_configs ON;\n';
|
||||
|
||||
for (const fb of floatBalls) {
|
||||
const createdAt = unixToDatetime(fb.create_time) || new Date().toISOString().slice(0, 23).replace('T', ' ');
|
||||
const updatedAt = unixToDatetime(fb.update_time) || createdAt;
|
||||
|
||||
sqlBatch += `
|
||||
INSERT INTO float_ball_configs (
|
||||
id, status, type, image, link_url, position_x, position_y, width, height, effect,
|
||||
title, image_details, image_bj, image_details_x, image_details_y, image_details_w, image_details_h,
|
||||
created_at, updated_at
|
||||
) VALUES (
|
||||
${fb.id},
|
||||
${fb.status || 0},
|
||||
${fb.type || 1},
|
||||
${escapeString(fb.image || '')},
|
||||
${escapeString(fb.link_url || '')},
|
||||
${escapeString(fb.position_x || '')},
|
||||
${escapeString(fb.position_y || '')},
|
||||
${escapeString(fb.width || '')},
|
||||
${escapeString(fb.height || '')},
|
||||
${fb.effect || 0},
|
||||
${escapeString(fb.title)},
|
||||
${escapeString(fb.image_details)},
|
||||
${escapeString(fb.image_bj)},
|
||||
${escapeString(fb.image_details_x)},
|
||||
${escapeString(fb.image_details_y)},
|
||||
${escapeString(fb.image_details_w)},
|
||||
${escapeString(fb.image_details_h)},
|
||||
${formatDatetime(createdAt)},
|
||||
${formatDatetime(updatedAt)}
|
||||
);
|
||||
`;
|
||||
}
|
||||
|
||||
sqlBatch += 'SET IDENTITY_INSERT float_ball_configs OFF;';
|
||||
|
||||
try {
|
||||
await pool.request().batch(sqlBatch);
|
||||
insertedCount = floatBalls.length;
|
||||
} catch (err) {
|
||||
console.error('批量插入失败:', err.message);
|
||||
// 如果批量失败,尝试逐条插入
|
||||
for (const fb of floatBalls) {
|
||||
try {
|
||||
const createdAt = unixToDatetime(fb.create_time) || new Date().toISOString().slice(0, 23).replace('T', ' ');
|
||||
const updatedAt = unixToDatetime(fb.update_time) || createdAt;
|
||||
|
||||
const singleSql = `
|
||||
SET IDENTITY_INSERT float_ball_configs ON;
|
||||
INSERT INTO float_ball_configs (
|
||||
id, status, type, image, link_url, position_x, position_y, width, height, effect,
|
||||
title, image_details, image_bj, image_details_x, image_details_y, image_details_w, image_details_h,
|
||||
created_at, updated_at
|
||||
) VALUES (
|
||||
${fb.id},
|
||||
${fb.status || 0},
|
||||
${fb.type || 1},
|
||||
${escapeString(fb.image || '')},
|
||||
${escapeString(fb.link_url || '')},
|
||||
${escapeString(fb.position_x || '')},
|
||||
${escapeString(fb.position_y || '')},
|
||||
${escapeString(fb.width || '')},
|
||||
${escapeString(fb.height || '')},
|
||||
${fb.effect || 0},
|
||||
${escapeString(fb.title)},
|
||||
${escapeString(fb.image_details)},
|
||||
${escapeString(fb.image_bj)},
|
||||
${escapeString(fb.image_details_x)},
|
||||
${escapeString(fb.image_details_y)},
|
||||
${escapeString(fb.image_details_w)},
|
||||
${escapeString(fb.image_details_h)},
|
||||
${formatDatetime(createdAt)},
|
||||
${formatDatetime(updatedAt)}
|
||||
);
|
||||
SET IDENTITY_INSERT float_ball_configs OFF;`;
|
||||
|
||||
await pool.request().batch(singleSql);
|
||||
insertedCount++;
|
||||
console.log(` ✓ 插入悬浮球配置 ${fb.id} 成功`);
|
||||
} catch (singleErr) {
|
||||
console.error(` ✗ 插入悬浮球配置 ${fb.id} 失败:`, singleErr.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return insertedCount;
|
||||
}
|
||||
|
||||
|
||||
async function main() {
|
||||
console.log('========================================');
|
||||
console.log('悬浮球配置数据迁移脚本 - Node.js');
|
||||
console.log('========================================\n');
|
||||
|
||||
let mysqlConn = null;
|
||||
let sqlPool = null;
|
||||
|
||||
try {
|
||||
// 连接 MySQL
|
||||
console.log('正在连接 MySQL...');
|
||||
mysqlConn = await mysql.createConnection(mysqlConfig);
|
||||
console.log('MySQL 连接成功\n');
|
||||
|
||||
// 连接 SQL Server
|
||||
console.log('正在连接 SQL Server...');
|
||||
sqlPool = await sql.connect(sqlServerConfig);
|
||||
console.log('SQL Server 连接成功\n');
|
||||
|
||||
// 获取已迁移的ID(支持增量迁移)
|
||||
console.log('正在获取已迁移的悬浮球配置ID...');
|
||||
const migratedIds = await getMigratedIds(sqlPool);
|
||||
console.log(`已迁移悬浮球配置数: ${migratedIds.size}\n`);
|
||||
|
||||
// 从 MySQL 获取所有悬浮球配置数据
|
||||
console.log('正在从 MySQL 读取悬浮球配置数据...');
|
||||
const [rows] = await mysqlConn.execute(`
|
||||
SELECT id, status, type, image, link_url, position_x, position_y, width, height, effect,
|
||||
create_time, update_time, title, image_details, image_bj,
|
||||
image_details_x, image_details_y, image_details_w, image_details_h
|
||||
FROM float_ball_config
|
||||
ORDER BY id
|
||||
`);
|
||||
console.log(`MySQL 悬浮球配置总数: ${rows.length}\n`);
|
||||
|
||||
// 过滤出未迁移的配置(增量迁移)
|
||||
const floatBallsToMigrate = rows.filter(fb => !migratedIds.has(fb.id));
|
||||
console.log(`待迁移悬浮球配置数: ${floatBallsToMigrate.length}\n`);
|
||||
|
||||
if (floatBallsToMigrate.length === 0) {
|
||||
console.log('所有悬浮球配置数据已迁移完成!');
|
||||
} else {
|
||||
// 批量迁移(每批50条)
|
||||
const batchSize = 50;
|
||||
let totalInserted = 0;
|
||||
|
||||
for (let i = 0; i < floatBallsToMigrate.length; i += batchSize) {
|
||||
const batch = floatBallsToMigrate.slice(i, i + batchSize);
|
||||
const inserted = await insertFloatBallsBatch(sqlPool, batch);
|
||||
totalInserted += inserted;
|
||||
console.log(`进度: ${Math.min(i + batchSize, floatBallsToMigrate.length)}/${floatBallsToMigrate.length} (本批插入: ${inserted})`);
|
||||
}
|
||||
|
||||
console.log(`\n迁移完成!共插入 ${totalInserted} 条记录`);
|
||||
}
|
||||
|
||||
// 验证迁移结果
|
||||
console.log('\n========================================');
|
||||
console.log('迁移结果验证');
|
||||
console.log('========================================');
|
||||
|
||||
const [mysqlCount] = await mysqlConn.execute('SELECT COUNT(*) as count FROM float_ball_config');
|
||||
const sqlResult = await sqlPool.request().query('SELECT COUNT(*) as count FROM float_ball_configs');
|
||||
|
||||
console.log(`MySQL float_ball_config 表记录数: ${mysqlCount[0].count}`);
|
||||
console.log(`SQL Server float_ball_configs 表记录数: ${sqlResult.recordset[0].count}`);
|
||||
|
||||
if (mysqlCount[0].count === sqlResult.recordset[0].count) {
|
||||
console.log('\n✅ 数据迁移完成,记录数一致!');
|
||||
} else {
|
||||
console.log(`\n⚠️ 记录数不一致,差异: ${mysqlCount[0].count - sqlResult.recordset[0].count}`);
|
||||
}
|
||||
|
||||
// 验证ID保留
|
||||
console.log('\n验证ID保留...');
|
||||
const [mysqlIds] = await mysqlConn.execute('SELECT id FROM float_ball_config ORDER BY id');
|
||||
const sqlIds = await sqlPool.request().query('SELECT id FROM float_ball_configs ORDER BY id');
|
||||
|
||||
const mysqlIdSet = new Set(mysqlIds.map(r => r.id));
|
||||
const sqlIdSet = new Set(sqlIds.recordset.map(r => r.id));
|
||||
|
||||
let idMismatch = false;
|
||||
for (const id of mysqlIdSet) {
|
||||
if (!sqlIdSet.has(id)) {
|
||||
console.log(` ⚠️ MySQL ID ${id} 未在 SQL Server 中找到`);
|
||||
idMismatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!idMismatch) {
|
||||
console.log('✅ 所有ID已正确保留!');
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('迁移过程中发生错误:', err);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
// 关闭连接
|
||||
if (mysqlConn) await mysqlConn.end();
|
||||
if (sqlPool) await sqlPool.close();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
Loading…
Reference in New Issue
Block a user