Files
F8WebAI/backend/AgriculturalPlatform.Api/Controllers/FarmersController.cs
T
fanhongcai c377421a3e 新增农户功能升级:身份证OCR/OSS上传、头像采集、同名村检测、Region热度排序及表单体验优化
- Region 表新增热度列,热门省份优先显示
- 区县下拉按地级市分组、已录区县优先、支持全省搜索
- 组选择内置一组至二十组
- 银行卡号独立行+粗体预览,开户行独立行
- 新增农户类型:农户/个体户/合作社/经营集体/公司
- 身份证正反面支持高拍仪/摄像头OCR与手机扫码上传,附件存本地/OSS
- 新增农户头像采集组件(摄像头/本地上传),预留人脸识别收购扩展
- 同名村弹窗提醒(防选错乡镇)
- 编辑窗体禁止遮罩/Esc误关,整体加宽适配高频操作
- 修复二维码局域网手机无法访问(监听0.0.0.0、局域网IP识别、Vite代理兜底)
2026-08-13 16:07:35 +08:00

149 lines
6.6 KiB
C#

using AgriculturalPlatform.Api.Data;
using AgriculturalPlatform.Api.Dtos;
using AgriculturalPlatform.Api.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace AgriculturalPlatform.Api.Controllers;
[ApiController]
[Route("api/farmers")]
[Authorize]
public class FarmersController(AppDbContext db) : ControllerBase
{
/// <summary>农户列表(分页/关键字/地区筛选)</summary>
[HttpGet]
public async Task<ActionResult<PagedResult<FarmerDto>>> List(
string? status, string? province, string? county, string? township, string? village,
[FromQuery] int page = 1, [FromQuery] int pageSize = 20, [FromQuery] string? keyword = null)
{
var query = db.Farmers.AsQueryable();
if (!string.IsNullOrWhiteSpace(status) && Enum.TryParse<FarmerStatus>(status, out var fs))
query = query.Where(f => f.Status == fs);
if (!string.IsNullOrWhiteSpace(province))
query = query.Where(f => f.Province == province);
if (!string.IsNullOrWhiteSpace(county))
query = query.Where(f => f.County == county);
if (!string.IsNullOrWhiteSpace(township))
query = query.Where(f => f.Township == township);
if (!string.IsNullOrWhiteSpace(village))
query = query.Where(f => f.Village == village);
if (!string.IsNullOrWhiteSpace(keyword))
query = query.Where(f => f.Name.Contains(keyword)
|| f.Phone.Contains(keyword)
|| f.IdCard.Contains(keyword)
|| f.Village.Contains(keyword)
|| f.Province.Contains(keyword)
|| f.County.Contains(keyword)
|| f.Township.Contains(keyword)
|| f.GroupName.Contains(keyword));
var total = await query.CountAsync();
var items = await query.OrderByDescending(f => f.Id)
.Skip((page - 1) * pageSize).Take(pageSize)
.ToListAsync();
return Ok(new PagedResult<FarmerDto>(items.ToDtos(), total));
}
/// <summary>全部农户(下拉选择用)</summary>
[HttpGet("all")]
public async Task<ActionResult> All(string? keyword, int limit = 50)
{
var query = db.Farmers.Where(f => f.Status == FarmerStatus.Active).AsQueryable();
if (!string.IsNullOrWhiteSpace(keyword))
query = query.Where(f => f.Name.Contains(keyword) || f.Phone.Contains(keyword) || f.IdCard.Contains(keyword));
var items = await query.OrderByDescending(f => f.Id).Take(limit)
.Select(f => new { f.Id, f.Name, f.Phone, f.Province, f.County, f.Township, f.Village, f.GroupName, f.IdCard }).ToListAsync();
return Ok(items);
}
/// <summary>农户详情(含交易统计)</summary>
[HttpGet("{id:int}")]
public async Task<ActionResult> Get(int id)
{
var farmer = await db.Farmers.FindAsync(id);
if (farmer is null) return NotFound();
var totalAmount = await db.PurchaseOrders
.Where(p => p.FarmerId == id && p.Status == PurchaseStatus.Completed)
.SumAsync(p => (decimal?)p.Amount) ?? 0;
var orderCount = await db.PurchaseOrders
.CountAsync(p => p.FarmerId == id && p.Status == PurchaseStatus.Completed);
var paidAmount = await db.PaymentRecords
.Where(p => p.FarmerId == id && p.Status == PayStatus.Success)
.SumAsync(p => (decimal?)p.Amount) ?? 0;
var dto = farmer.ToDto();
return Ok(new { farmer = dto, totalAmount, orderCount, paidAmount });
}
/// <summary>新增农户</summary>
[HttpPost]
public async Task<ActionResult<FarmerDto>> Create(FarmerSaveRequest req)
{
if (await db.Farmers.AnyAsync(f => f.IdCard == req.IdCard))
return BadRequest(new { message = "该身份证号已存在" });
if (!Enum.TryParse<FarmerStatus>(req.Status, out var status)) status = FarmerStatus.Active;
var farmer = new Farmer
{
Name = req.Name, IdCard = req.IdCard, Gender = req.Gender, FarmerType = req.FarmerType,
Phone = req.Phone,
Province = req.Province, County = req.County, Township = req.Township,
Village = req.Village, GroupName = req.GroupName,
Address = req.Address,
BankName = req.BankName, BankAccount = req.BankAccount,
IdCardFrontUrl = req.IdCardFrontUrl, IdCardBackUrl = req.IdCardBackUrl,
AvatarUrl = req.AvatarUrl,
CreditScore = req.CreditScore, Status = status, Notes = req.Notes
};
db.Farmers.Add(farmer);
await db.SaveChangesAsync();
return Ok(farmer.ToDto());
}
/// <summary>修改农户</summary>
[HttpPut("{id:int}")]
public async Task<ActionResult<FarmerDto>> Update(int id, FarmerSaveRequest req)
{
var farmer = await db.Farmers.FindAsync(id);
if (farmer is null) return NotFound();
if (req.IdCard != farmer.IdCard && await db.Farmers.AnyAsync(f => f.IdCard == req.IdCard))
return BadRequest(new { message = "该身份证号已存在" });
farmer.Name = req.Name; farmer.IdCard = req.IdCard; farmer.Gender = req.Gender;
farmer.FarmerType = req.FarmerType;
farmer.Phone = req.Phone;
farmer.Province = req.Province; farmer.County = req.County;
farmer.Township = req.Township; farmer.Village = req.Village;
farmer.GroupName = req.GroupName;
farmer.Address = req.Address;
farmer.BankName = req.BankName; farmer.BankAccount = req.BankAccount;
farmer.IdCardFrontUrl = req.IdCardFrontUrl; farmer.IdCardBackUrl = req.IdCardBackUrl;
farmer.AvatarUrl = req.AvatarUrl;
farmer.CreditScore = req.CreditScore; farmer.Notes = req.Notes;
if (Enum.TryParse<FarmerStatus>(req.Status, out var status)) farmer.Status = status;
farmer.UpdatedAt = DateTime.Now;
await db.SaveChangesAsync();
return Ok(farmer.ToDto());
}
/// <summary>删除农户(存在收购记录时禁止删除,仅冻结)</summary>
[HttpDelete("{id:int}")]
public async Task<IActionResult> Delete(int id)
{
var farmer = await db.Farmers.FindAsync(id);
if (farmer is null) return NotFound();
if (await db.PurchaseOrders.AnyAsync(p => p.FarmerId == id))
{
farmer.Status = FarmerStatus.Frozen;
await db.SaveChangesAsync();
return Ok(new { message = "该农户已有收购记录,已将其状态置为冻结" });
}
db.Farmers.Remove(farmer);
await db.SaveChangesAsync();
return Ok(new { message = "删除成功" });
}
}