新增农户功能升级:身份证OCR/OSS上传、头像采集、同名村检测、Region热度排序及表单体验优化
- Region 表新增热度列,热门省份优先显示 - 区县下拉按地级市分组、已录区县优先、支持全省搜索 - 组选择内置一组至二十组 - 银行卡号独立行+粗体预览,开户行独立行 - 新增农户类型:农户/个体户/合作社/经营集体/公司 - 身份证正反面支持高拍仪/摄像头OCR与手机扫码上传,附件存本地/OSS - 新增农户头像采集组件(摄像头/本地上传),预留人脸识别收购扩展 - 同名村弹窗提醒(防选错乡镇) - 编辑窗体禁止遮罩/Esc误关,整体加宽适配高频操作 - 修复二维码局域网手机无法访问(监听0.0.0.0、局域网IP识别、Vite代理兜底)
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
using System.Text;
|
||||
using System.Text.Json.Serialization;
|
||||
using AgriculturalPlatform.Api.Data;
|
||||
using AgriculturalPlatform.Api.Services;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Http.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// ---------- 注册 GBK 等编码(天气 IP 定位接口使用) ----------
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
|
||||
// ---------- 在线 MySQL 数据库 ----------
|
||||
var connectionString = builder.Configuration.GetConnectionString("Default")
|
||||
?? throw new InvalidOperationException("未配置数据库连接字符串 ConnectionStrings:Default");
|
||||
|
||||
var serverVersion = new MySqlServerVersion(new Version(
|
||||
builder.Configuration.GetValue("MySql:Major", 8),
|
||||
builder.Configuration.GetValue("MySql:Minor", 0),
|
||||
builder.Configuration.GetValue("MySql:Build", 36)));
|
||||
|
||||
builder.Services.AddDbContext<AppDbContext>(options =>
|
||||
options.UseMySql(connectionString, serverVersion, mysql =>
|
||||
{
|
||||
mysql.EnableRetryOnFailure(3);
|
||||
mysql.CommandTimeout(30);
|
||||
}));
|
||||
|
||||
// ---------- JWT 认证 ----------
|
||||
var jwtKey = builder.Configuration["Jwt:Key"] ?? "AgriculturalPlatform-Default-Jwt-Secret-Key-2026!";
|
||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = builder.Configuration["Jwt:Issuer"] ?? "AgriculturalPlatform",
|
||||
ValidAudience = builder.Configuration["Jwt:Audience"] ?? "AgriculturalPlatform.Client",
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey))
|
||||
};
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnMessageReceived = ctx =>
|
||||
{
|
||||
// 兼容前端直接携带 token 的查询参数方式
|
||||
if (string.IsNullOrEmpty(ctx.Token)
|
||||
&& ctx.Request.Query.TryGetValue("access_token", out var token))
|
||||
{
|
||||
ctx.Token = token;
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
builder.Services.AddAuthorization();
|
||||
|
||||
// ---------- JSON:枚举序列化为字符串、中文不被转义 ----------
|
||||
builder.Services.Configure<JsonOptions>(o =>
|
||||
{
|
||||
o.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
|
||||
o.SerializerOptions.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;
|
||||
});
|
||||
|
||||
// ---------- 业务服务 ----------
|
||||
builder.Services.AddSingleton<JwtService>();
|
||||
builder.Services.AddScoped<CurrentUserService>();
|
||||
builder.Services.AddScoped<DataScopeService>();
|
||||
builder.Services.AddScoped<NumberGenerator>();
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
// ---------- 附件存储(本地为准,OSS 配置好后切换) ----------
|
||||
builder.Services.AddSingleton<LocalFileStorage>();
|
||||
builder.Services.AddSingleton<OssFileStorage>();
|
||||
builder.Services.AddSingleton<IFileStorage>(sp =>
|
||||
sp.GetRequiredService<IConfiguration>().GetValue("Storage:UseOss", false)
|
||||
? sp.GetRequiredService<OssFileStorage>()
|
||||
: sp.GetRequiredService<LocalFileStorage>());
|
||||
|
||||
// ---------- OCR 识别(默认占位,接入阿里云/百度 OCR 时替换实现) ----------
|
||||
builder.Services.AddSingleton<IOcrService, DisabledOcrService>();
|
||||
|
||||
// ---------- 手机传图上传会话 ----------
|
||||
builder.Services.AddSingleton<MobileUploadSessionStore>();
|
||||
|
||||
// ---------- 天气服务(调用第三方天气接口) ----------
|
||||
builder.Services.AddHttpClient("weather");
|
||||
|
||||
// ---------- 前端(Vue 开发服务器)跨域 ----------
|
||||
var frontendUrl = builder.Configuration["FrontendUrl"] ?? "http://localhost:5173";
|
||||
builder.Services.AddCors(o => o.AddPolicy("frontend", p =>
|
||||
p.WithOrigins(frontendUrl.Split(';')).AllowAnyHeader().AllowAnyMethod().AllowCredentials()));
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// ---------- 初始化数据库(自动建库建表 + 种子数据) ----------
|
||||
try
|
||||
{
|
||||
using var scope = app.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
db.Database.EnsureCreated();
|
||||
await SchemaMigrator.EnsureColumnsAsync(db);
|
||||
await SchemaMigrator.EnsureRegionsTableAsync(db);
|
||||
DbSeeder.Seed(db);
|
||||
app.Logger.LogInformation("数据库初始化完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
app.Logger.LogError(ex, "数据库初始化失败,请检查 ConnectionStrings:Default 配置");
|
||||
}
|
||||
|
||||
app.UseCors("frontend");
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
// 附件与手机上传页面(wwwroot)
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.MapOpenApi();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
Reference in New Issue
Block a user