init
This commit is contained in:
Binary file not shown.
Binary file not shown.
49
backend/FateMaster.API/Controllers/Admin/PricesController.cs
Normal file
49
backend/FateMaster.API/Controllers/Admin/PricesController.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using FateMaster.API.Data;
|
||||
using FateMaster.API.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FateMaster.API.Controllers.Admin;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/admin/[controller]")]
|
||||
public class PricesController : ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
public PricesController(ApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有价格配置
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<PriceConfig>>> GetAll()
|
||||
{
|
||||
return await _context.PriceConfigs.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新价格配置
|
||||
/// </summary>
|
||||
[HttpPut("{id}")]
|
||||
public async Task<ActionResult> Update(int id, [FromBody] UpdatePriceRequest request)
|
||||
{
|
||||
var price = await _context.PriceConfigs.FindAsync(id);
|
||||
if (price == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
price.Price = request.Price;
|
||||
price.IsEnabled = request.IsEnabled;
|
||||
price.UpdatedAt = DateTime.UtcNow;
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
return Ok(price);
|
||||
}
|
||||
}
|
||||
|
||||
public record UpdatePriceRequest(decimal Price, bool IsEnabled);
|
||||
@@ -0,0 +1,87 @@
|
||||
using FateMaster.API.Data;
|
||||
using FateMaster.API.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FateMaster.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/admin/[controller]")]
|
||||
public class RecordsController : ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
public RecordsController(ApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取卜卦记录列表
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult> GetRecords(
|
||||
[FromQuery] int page = 1,
|
||||
[FromQuery] int pageSize = 20,
|
||||
[FromQuery] string? type = null,
|
||||
[FromQuery] string? paymentStatus = null)
|
||||
{
|
||||
var query = _context.DivinationRecords.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(type))
|
||||
{
|
||||
query = query.Where(r => r.Type == type);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(paymentStatus))
|
||||
{
|
||||
query = query.Where(r => r.PaymentStatus == paymentStatus);
|
||||
}
|
||||
|
||||
var total = await query.CountAsync();
|
||||
var records = await query
|
||||
.OrderByDescending(r => r.CreatedAt)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
data = records
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取统计数据
|
||||
/// </summary>
|
||||
[HttpGet("statistics")]
|
||||
public async Task<ActionResult> GetStatistics()
|
||||
{
|
||||
var total = await _context.DivinationRecords.CountAsync();
|
||||
var paidCount = await _context.DivinationRecords
|
||||
.CountAsync(r => r.PaymentStatus == "paid");
|
||||
var totalRevenue = await _context.DivinationRecords
|
||||
.Where(r => r.PaymentStatus == "paid")
|
||||
.SumAsync(r => r.Amount);
|
||||
|
||||
var typeStats = await _context.DivinationRecords
|
||||
.GroupBy(r => r.Type)
|
||||
.Select(g => new
|
||||
{
|
||||
Type = g.Key,
|
||||
Count = g.Count()
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
total,
|
||||
paidCount,
|
||||
totalRevenue,
|
||||
typeStats
|
||||
});
|
||||
}
|
||||
}
|
||||
88
backend/FateMaster.API/Controllers/DivinationController.cs
Normal file
88
backend/FateMaster.API/Controllers/DivinationController.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using FateMaster.API.Data;
|
||||
using FateMaster.API.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FateMaster.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class DivinationController : ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly ILogger<DivinationController> _logger;
|
||||
|
||||
public DivinationController(
|
||||
ApplicationDbContext context,
|
||||
ILogger<DivinationController> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取价格配置
|
||||
/// </summary>
|
||||
[HttpGet("prices")]
|
||||
public async Task<ActionResult<List<PriceConfig>>> GetPrices()
|
||||
{
|
||||
var prices = await _context.PriceConfigs
|
||||
.Where(p => p.IsEnabled)
|
||||
.ToListAsync();
|
||||
return Ok(prices);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提交卜卦请求
|
||||
/// </summary>
|
||||
[HttpPost("submit")]
|
||||
public async Task<ActionResult<DivinationRecord>> Submit([FromBody] SubmitRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var record = new DivinationRecord
|
||||
{
|
||||
Type = request.Type,
|
||||
InputData = request.InputData,
|
||||
PaymentStatus = "pending",
|
||||
PaymentMethod = request.PaymentMethod,
|
||||
Amount = request.Amount,
|
||||
ClientIp = HttpContext.Connection.RemoteIpAddress?.ToString(),
|
||||
Language = request.Language ?? "zh-CN"
|
||||
};
|
||||
|
||||
_context.DivinationRecords.Add(record);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return Ok(record);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error submitting divination request");
|
||||
return StatusCode(500, new { message = "提交失败" });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取卜卦结果
|
||||
/// </summary>
|
||||
[HttpGet("{id}")]
|
||||
public async Task<ActionResult<DivinationRecord>> GetResult(long id)
|
||||
{
|
||||
var record = await _context.DivinationRecords.FindAsync(id);
|
||||
if (record == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return Ok(record);
|
||||
}
|
||||
}
|
||||
|
||||
public record SubmitRequest(
|
||||
string Type,
|
||||
string InputData,
|
||||
string? PaymentMethod,
|
||||
decimal Amount,
|
||||
string? Language
|
||||
);
|
||||
47
backend/FateMaster.API/Data/ApplicationDbContext.cs
Normal file
47
backend/FateMaster.API/Data/ApplicationDbContext.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using FateMaster.API.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace FateMaster.API.Data;
|
||||
|
||||
public class ApplicationDbContext : DbContext
|
||||
{
|
||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public DbSet<DivinationRecord> DivinationRecords { get; set; }
|
||||
public DbSet<SystemConfig> SystemConfigs { get; set; }
|
||||
public DbSet<PriceConfig> PriceConfigs { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
// 配置索引
|
||||
modelBuilder.Entity<DivinationRecord>()
|
||||
.HasIndex(d => d.Type);
|
||||
|
||||
modelBuilder.Entity<DivinationRecord>()
|
||||
.HasIndex(d => d.PaymentStatus);
|
||||
|
||||
modelBuilder.Entity<DivinationRecord>()
|
||||
.HasIndex(d => d.CreatedAt);
|
||||
|
||||
modelBuilder.Entity<SystemConfig>()
|
||||
.HasIndex(s => s.ConfigKey)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<PriceConfig>()
|
||||
.HasIndex(p => p.ServiceType);
|
||||
|
||||
// 初始化数据
|
||||
modelBuilder.Entity<PriceConfig>().HasData(
|
||||
new PriceConfig { Id = 1, ServiceType = "bazi", Price = 99, Currency = "CNY" },
|
||||
new PriceConfig { Id = 2, ServiceType = "career", Price = 88, Currency = "CNY" },
|
||||
new PriceConfig { Id = 3, ServiceType = "marriage", Price = 88, Currency = "CNY" },
|
||||
new PriceConfig { Id = 4, ServiceType = "tarot", Price = 66, Currency = "CNY" },
|
||||
new PriceConfig { Id = 5, ServiceType = "zodiac", Price = 29, Currency = "CNY" }
|
||||
);
|
||||
}
|
||||
}
|
||||
19
backend/FateMaster.API/FateMaster.API.csproj
Normal file
19
backend/FateMaster.API/FateMaster.API.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
86
backend/FateMaster.API/Models/DivinationRecord.cs
Normal file
86
backend/FateMaster.API/Models/DivinationRecord.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace FateMaster.API.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 卜卦记录表
|
||||
/// </summary>
|
||||
public class DivinationRecord
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 卜卦类型: bazi, career, marriage, tarot, zodiac
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string Type { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 用户输入数据(JSON)
|
||||
/// </summary>
|
||||
[Required]
|
||||
[Column(TypeName = "json")]
|
||||
public string InputData { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 传统算法结果(JSON)
|
||||
/// </summary>
|
||||
[Column(TypeName = "json")]
|
||||
public string? TraditionalResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// AI解读结果
|
||||
/// </summary>
|
||||
[Column(TypeName = "text")]
|
||||
public string? AIInterpretation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付状态: pending, paid, failed
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(20)]
|
||||
public string PaymentStatus { get; set; } = "pending";
|
||||
|
||||
/// <summary>
|
||||
/// 支付方式: alipay, paypal, stripe
|
||||
/// </summary>
|
||||
[MaxLength(20)]
|
||||
public string? PaymentMethod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付金额
|
||||
/// </summary>
|
||||
[Column(TypeName = "decimal(10,2)")]
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付订单号
|
||||
/// </summary>
|
||||
[MaxLength(100)]
|
||||
public string? PaymentOrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户端IP
|
||||
/// </summary>
|
||||
[MaxLength(50)]
|
||||
public string? ClientIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 语言
|
||||
/// </summary>
|
||||
[MaxLength(10)]
|
||||
public string? Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
49
backend/FateMaster.API/Models/PriceConfig.cs
Normal file
49
backend/FateMaster.API/Models/PriceConfig.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace FateMaster.API.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 价格配置表
|
||||
/// </summary>
|
||||
public class PriceConfig
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务类型: bazi, career, marriage, tarot, zodiac
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string ServiceType { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 价格
|
||||
/// </summary>
|
||||
[Required]
|
||||
[Column(TypeName = "decimal(10,2)")]
|
||||
public decimal Price { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 货币: CNY, USD
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(10)]
|
||||
public string Currency { get; set; } = "CNY";
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
41
backend/FateMaster.API/Models/SystemConfig.cs
Normal file
41
backend/FateMaster.API/Models/SystemConfig.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace FateMaster.API.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 系统配置表
|
||||
/// </summary>
|
||||
public class SystemConfig
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 配置键
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(100)]
|
||||
public string ConfigKey { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 配置值
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string ConfigValue { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
[MaxLength(500)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
41
backend/FateMaster.API/Program.cs
Normal file
41
backend/FateMaster.API/Program.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using FateMaster.API.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
// Configure MySQL
|
||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
|
||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));
|
||||
|
||||
// Configure CORS
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowFrontend", policy =>
|
||||
{
|
||||
policy.WithOrigins("http://localhost:3000", "http://localhost:3001")
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()
|
||||
.AllowCredentials();
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
app.UseCors("AllowFrontend");
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
12
backend/FateMaster.API/Properties/launchSettings.json
Normal file
12
backend/FateMaster.API/Properties/launchSettings.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"profiles": {
|
||||
"FateMaster.API": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:63347;http://localhost:63348"
|
||||
}
|
||||
}
|
||||
}
|
||||
34
backend/FateMaster.API/appsettings.json
Normal file
34
backend/FateMaster.API/appsettings.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=localhost;Port=3306;Database=fatemaster;User=root;Password=your_password;"
|
||||
},
|
||||
"PaymentSettings": {
|
||||
"Alipay": {
|
||||
"AppId": "",
|
||||
"PrivateKey": "",
|
||||
"PublicKey": ""
|
||||
},
|
||||
"PayPal": {
|
||||
"ClientId": "",
|
||||
"ClientSecret": "",
|
||||
"Mode": "sandbox"
|
||||
},
|
||||
"Stripe": {
|
||||
"SecretKey": "",
|
||||
"PublishableKey": ""
|
||||
}
|
||||
},
|
||||
"AISettings": {
|
||||
"Provider": "OpenAI",
|
||||
"ApiKey": "",
|
||||
"Model": "gpt-4",
|
||||
"BaseUrl": "https://api.openai.com/v1"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user