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,
|
"Version": 1,
|
||||||
"WorkspaceRootPath": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\",
|
"WorkspaceRootPath": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\",
|
||||||
"Documents": [
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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": [
|
"DocumentGroups": [
|
||||||
{
|
{
|
||||||
"DockedWidth": 200,
|
"DockedWidth": 200,
|
||||||
"SelectedChildIndex": 7,
|
"SelectedChildIndex": 4,
|
||||||
"Children": [
|
"Children": [
|
||||||
{
|
{
|
||||||
"$type": "Bookmark",
|
"$type": "Bookmark",
|
||||||
|
|
@ -67,19 +71,32 @@
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 2,
|
"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",
|
"Title": "PayController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||||
"ViewState": "AgIAAB8AAAAAAAAAAAAAwAAAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAACIAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:35:53.369Z",
|
"WhenOpened": "2026-01-03T06:35:53.369Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 3,
|
"DocumentIndex": 5,
|
||||||
"Title": "CouponController.cs",
|
"Title": "CouponController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||||
|
|
@ -92,46 +109,46 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 1,
|
"DocumentIndex": 0,
|
||||||
"Title": "ConfigController.cs",
|
"Title": "ConfigController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||||
"ViewState": "AgIAAEcAAAAAAAAAAAAAAFIAAAAcAAAAAAAAAA==",
|
"ViewState": "AgIAAIcAAAAAAAAAAADwv6QAAABOAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:15:47.201Z",
|
"WhenOpened": "2026-01-03T06:15:47.201Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 5,
|
"DocumentIndex": 7,
|
||||||
"Title": "AuthController.cs",
|
"Title": "AuthController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||||
"ViewState": "AgIAAGYAAAAAAAAAAAAuwPcAAAAWAAAAAAAAAA==",
|
"ViewState": "AgIAAGYAAAAAAAAAAAAuwCUBAAAWAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:07:38.674Z",
|
"WhenOpened": "2026-01-03T06:07:38.674Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 4,
|
"DocumentIndex": 6,
|
||||||
"Title": "CollectionController.cs",
|
"Title": "CollectionController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||||
"ViewState": "AgIAAL0AAAAAAAAAAAAAAM0AAAAUAAAAAAAAAA==",
|
"ViewState": "AgIAAA0BAAAAAAAAAAAAAEkBAAAUAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:07:37.824Z",
|
"WhenOpened": "2026-01-03T06:07:37.824Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 6,
|
"DocumentIndex": 8,
|
||||||
"Title": "appsettings.json",
|
"Title": "appsettings.json",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\appsettings.json",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\appsettings.json",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\appsettings.json",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\appsettings.json",
|
||||||
|
|
@ -144,33 +161,33 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 0,
|
"DocumentIndex": 3,
|
||||||
"Title": "GoodsController.cs",
|
"Title": "GoodsController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||||
"ViewState": "AgIAACgAAAAAAAAAAAAuwFMAAABUAAAAAAAAAA==",
|
"ViewState": "AgIAAD0AAAAAAAAAAAAAAFkAAAAIAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T05:07:08.788Z",
|
"WhenOpened": "2026-01-03T05:07:08.788Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 8,
|
"DocumentIndex": 1,
|
||||||
"Title": "HoneyBoxDbContext.cs",
|
"Title": "HoneyBoxDbContext.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||||
"RelativeToolTip": "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|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-02T06:46:26.809Z",
|
"WhenOpened": "2026-01-02T06:46:26.809Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 7,
|
"DocumentIndex": 9,
|
||||||
"Title": "Program.cs",
|
"Title": "Program.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Program.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Program.cs",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Program.cs",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Program.cs",
|
||||||
|
|
@ -183,7 +200,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 9,
|
"DocumentIndex": 10,
|
||||||
"Title": "ApiResponse.cs",
|
"Title": "ApiResponse.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
||||||
|
|
@ -195,7 +212,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 10,
|
"DocumentIndex": 11,
|
||||||
"Title": "PrizeModels.cs",
|
"Title": "PrizeModels.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
||||||
|
|
@ -207,7 +224,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 11,
|
"DocumentIndex": 12,
|
||||||
"Title": "T_Task.cs",
|
"Title": "T_Task.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Entities\\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",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Entities\\T_Task.cs",
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,6 @@
|
||||||
"Version": 1,
|
"Version": 1,
|
||||||
"WorkspaceRootPath": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\",
|
"WorkspaceRootPath": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\",
|
||||||
"Documents": [
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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}",
|
"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}"
|
"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": [
|
"DocumentGroups": [
|
||||||
{
|
{
|
||||||
"DockedWidth": 200,
|
"DockedWidth": 200,
|
||||||
"SelectedChildIndex": 7,
|
"SelectedChildIndex": 5,
|
||||||
"Children": [
|
"Children": [
|
||||||
{
|
{
|
||||||
"$type": "Bookmark",
|
"$type": "Bookmark",
|
||||||
|
|
@ -66,72 +78,111 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$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",
|
"Title": "PayController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\PayController.cs",
|
||||||
"ViewState": "AgIAAB8AAAAAAAAAAAAAwAAAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAACIAAAAAAAAAAAAAwAAAAAAAAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:35:53.369Z",
|
"WhenOpened": "2026-01-03T06:35:53.369Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 3,
|
"DocumentIndex": 0,
|
||||||
"Title": "CouponController.cs",
|
"Title": "CouponController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CouponController.cs",
|
||||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
|
"ViewState": "AgIAADEBAAAAAAAAAAAAAEQAAAA3AAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:35:48.625Z",
|
"WhenOpened": "2026-01-03T06:35:48.625Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 1,
|
"DocumentIndex": 5,
|
||||||
"Title": "ConfigController.cs",
|
"Title": "ConfigController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\ConfigController.cs",
|
||||||
"ViewState": "AgIAAEcAAAAAAAAAAAAAAFIAAAAcAAAAAAAAAA==",
|
"ViewState": "AgIAAJsAAAAAAAAAAADwv7QAAAANAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:15:47.201Z",
|
"WhenOpened": "2026-01-03T06:15:47.201Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 5,
|
"DocumentIndex": 2,
|
||||||
"Title": "AuthController.cs",
|
"Title": "AuthController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\AuthController.cs",
|
||||||
"ViewState": "AgIAAGYAAAAAAAAAAAAuwPcAAAAWAAAAAAAAAA==",
|
"ViewState": "AgIAAC4BAAAAAAAAAAAuwCUBAAAWAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:07:38.674Z",
|
"WhenOpened": "2026-01-03T06:07:38.674Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 4,
|
"DocumentIndex": 1,
|
||||||
"Title": "CollectionController.cs",
|
"Title": "CollectionController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\CollectionController.cs",
|
||||||
"ViewState": "AgIAAL0AAAAAAAAAAAAAAM0AAAAUAAAAAAAAAA==",
|
"ViewState": "AgIAAFMBAAAAAAAAAADwvyABAAAZAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T06:07:37.824Z",
|
"WhenOpened": "2026-01-03T06:07:37.824Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 6,
|
"DocumentIndex": 10,
|
||||||
"Title": "appsettings.json",
|
"Title": "appsettings.json",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\appsettings.json",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\appsettings.json",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\appsettings.json",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\appsettings.json",
|
||||||
|
|
@ -144,33 +195,33 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 0,
|
"DocumentIndex": 8,
|
||||||
"Title": "GoodsController.cs",
|
"Title": "GoodsController.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||||
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
"RelativeToolTip": "src\\HoneyBox.Api\\Controllers\\GoodsController.cs",
|
||||||
"ViewState": "AgIAADQAAAAAAAAAAAAAAF0AAAAMAAAAAAAAAA==",
|
"ViewState": "AgIAAD0AAAAAAAAAAAAAAFkAAAAIAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-03T05:07:08.788Z",
|
"WhenOpened": "2026-01-03T05:07:08.788Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 8,
|
"DocumentIndex": 6,
|
||||||
"Title": "HoneyBoxDbContext.cs",
|
"Title": "HoneyBoxDbContext.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||||
"RelativeDocumentMoniker": "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",
|
"ToolTip": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Data\\HoneyBoxDbContext.cs",
|
||||||
"RelativeToolTip": "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|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-01-02T06:46:26.809Z",
|
"WhenOpened": "2026-01-02T06:46:26.809Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 7,
|
"DocumentIndex": 11,
|
||||||
"Title": "Program.cs",
|
"Title": "Program.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Program.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Api\\Program.cs",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Program.cs",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Api\\Program.cs",
|
||||||
|
|
@ -183,7 +234,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 9,
|
"DocumentIndex": 12,
|
||||||
"Title": "ApiResponse.cs",
|
"Title": "ApiResponse.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Base\\ApiResponse.cs",
|
||||||
|
|
@ -195,7 +246,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 10,
|
"DocumentIndex": 13,
|
||||||
"Title": "PrizeModels.cs",
|
"Title": "PrizeModels.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
||||||
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Models\\Prize\\PrizeModels.cs",
|
||||||
|
|
@ -207,7 +258,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 11,
|
"DocumentIndex": 14,
|
||||||
"Title": "T_Task.cs",
|
"Title": "T_Task.cs",
|
||||||
"DocumentMoniker": "D:\\outsource\\HaniBlindBox\\server\\C#\\HoneyBox\\src\\HoneyBox.Model\\Entities\\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",
|
"RelativeDocumentMoniker": "src\\HoneyBox.Model\\Entities\\T_Task.cs",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using HoneyBox.Core.Interfaces;
|
using HoneyBox.Core.Interfaces;
|
||||||
using HoneyBox.Model.Base;
|
using HoneyBox.Model.Base;
|
||||||
using HoneyBox.Model.Models.Config;
|
using HoneyBox.Model.Models.Config;
|
||||||
|
using HoneyBox.Model.Models.FloatBall;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace HoneyBox.Api.Controllers;
|
namespace HoneyBox.Api.Controllers;
|
||||||
|
|
@ -9,20 +11,23 @@ namespace HoneyBox.Api.Controllers;
|
||||||
/// 配置控制器 - 处理系统配置和平台配置
|
/// 配置控制器 - 处理系统配置和平台配置
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// 提供系统配置、商品类型、平台配置等功能
|
/// 提供系统配置、商品类型、平台配置、悬浮球配置等功能
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api")]
|
[Route("api")]
|
||||||
public class ConfigController : ControllerBase
|
public class ConfigController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
|
private readonly IFloatBallService _floatBallService;
|
||||||
private readonly ILogger<ConfigController> _logger;
|
private readonly ILogger<ConfigController> _logger;
|
||||||
|
|
||||||
public ConfigController(
|
public ConfigController(
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
|
IFloatBallService floatBallService,
|
||||||
ILogger<ConfigController> logger)
|
ILogger<ConfigController> logger)
|
||||||
{
|
{
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
|
_floatBallService = floatBallService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,9 +165,9 @@ public class ConfigController : ControllerBase
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="request">请求参数</param>
|
/// <param name="request">请求参数</param>
|
||||||
/// <returns>单页内容数据</returns>
|
/// <returns>单页内容数据</returns>
|
||||||
[HttpPost("danye")]
|
[HttpGet("danye")]
|
||||||
[ProducesResponseType(typeof(ApiResponse<DanyeContentDto>), StatusCodes.Status200OK)]
|
[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
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -184,4 +189,32 @@ public class ConfigController : ControllerBase
|
||||||
return ApiResponse<DanyeContentDto>.Fail("获取单页内容失败");
|
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.Core.Interfaces;
|
||||||
using HoneyBox.Model.Base;
|
using HoneyBox.Model.Base;
|
||||||
using HoneyBox.Model.Models;
|
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);
|
return new ConfigService(dbContext, logger, redisService);
|
||||||
}).As<IConfigService>().InstancePerLifetimeScope();
|
}).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<Reward> Rewards { get; set; }
|
||||||
|
|
||||||
|
public virtual DbSet<FloatBallConfig> FloatBallConfigs { get; set; }
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
// Connection string is configured in Program.cs via dependency injection
|
// Connection string is configured in Program.cs via dependency injection
|
||||||
|
|
@ -2974,6 +2976,97 @@ public partial class HoneyBoxDbContext : DbContext
|
||||||
.HasColumnName("updated_at");
|
.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);
|
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