feat 生日券功能,自动上传消费数据,提醒访客到期

This commit is contained in:
2025-12-09 11:35:05 +08:00
parent 323eb367d0
commit c1462a03dc
60 changed files with 1451 additions and 409 deletions

View File

@@ -1,8 +1,10 @@
using Dlhis.Basic.Api;
using Dlhis.Canteen.Order.Repository;
using Dlhis.Canteen.Order.Request;
using Dlhis.Canteen.Order.Response;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Entities.Voucher;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
@@ -22,64 +24,78 @@ public class BirthdayConsumeHandler : IConsumeHandler
private readonly IDbContext _dbContext;
private readonly IOrderCommonHandler _orderCommonHandler;
private readonly IOrderRepository _orderRepository;
private readonly IFactorySettingApi _factorySettingApi;
public BirthdayConsumeHandler(IDbContext dbContext,
IOrderCommonHandler orderCommonHandler,
IOrderRepository orderRepository)
IOrderRepository orderRepository,
IFactorySettingApi factorySettingApi)
{
_dbContext = dbContext;
_orderCommonHandler = orderCommonHandler;
_orderRepository = orderRepository;
_factorySettingApi = factorySettingApi;
}
public async Task<DefaultApiResult<OrderResultResponse>> ConsumeAsync(OrderAddRequest request, GainfoEntity gainfo)
{
var msg = string.Empty;
var ticketNo = request.UserUniqueNo;
var qrCode = request.UserUniqueNo;
var exists = await _dbContext.Queryable<TicketEntity>()
.Where(x => x.Type == TicketEnumType.Birthday)
.Where(x => x.QrCode == ticketNo)
.AnyAsync();
exists.ThrowIfFalse("生日券无效");
var voucherQrCode = await _dbContext.Queryable<VoucherQrCodeEntity>()
.LeftJoin<VoucherUserInfoEntity>((x, u) => x.VoucherNo == u.VoucherNo)
.Where(x => x.QrCode == qrCode)
.Select((x, u) => new
{
x.VoucherNo,
u.UserCode,
u.Factory
})
.SingleAsync();
voucherQrCode.ThrowIfNull("生日券无效");
try
{
var checkData = await _orderCommonHandler.PreCheckAsync(request.DeviceUniqueNo, request.CostDateTime!.Value);
var isSupermarket = await _dbContext.Queryable<BusinessPlaceEntity>()
var businessPlace = await _dbContext.Queryable<BusinessPlaceEntity>()
.Where(x => x.Code == checkData.BusinessPlaceCode)
.Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket)
//.Select(x => x.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket)
.SingleAsync();
businessPlace.ThrowIfNull("营业点不存在");
var isSupermarket = businessPlace.Catalog == CanteenBusinessPlaceCatalogEnumType.Supermarket;
isSupermarket.ThrowIfFalse("请在超市消费");
var allowFactories = await _factorySettingApi.GetEnableUseBirthdayVoucherFactoriesAsync(voucherQrCode.Factory);
allowFactories.Contains(businessPlace.TenantId).ThrowIfFalse($"该厂区({businessPlace.TenantId})不可使用此生日券");
var order = await _orderRepository.CreateDeviceConsumeOrderAsync(checkData, request.Adapt<ConsumeRequest>(), gainfo);
await _orderCommonHandler.TryConsumeAsync(order.Id, async () =>
{
await CommonHelper.RetryAsync(async () =>
{
var ticket = await _dbContext.Queryable<TicketEntity>()
.Where(x => x.Type == TicketEnumType.Birthday)
.Where(x => x.QrCode == ticketNo)
var voucher = await _dbContext.Queryable<VoucherEntity>()
.Where(x => x.Type == VoucherEnumType.Birthday)
.Where(x => x.No == voucherQrCode.VoucherNo)
.SingleAsync();
//金额+-
ticket.Balance += order.Amount;
(ticket.Balance < 0).ThrowIfTrue("余额不足,无法消费");
voucher.Balance += order.Amount;
(voucher.Balance < 0).ThrowIfTrue("余额不足,无法消费");
await _dbContext.Updateable<TicketEntity>()
.SetColumns(x => x.Balance == ticket.Balance)
await _dbContext.Updateable<VoucherEntity>()
.SetColumns(x => x.Balance == voucher.Balance)
.SetColumns(x => x.Version == x.Version + 1)
.SetColumns(x => x.ModifiedTime == DateTime.Now)
.Where(x => x.QrCode == ticketNo && x.Version == ticket.Version) //必须与查询时的version一致
.Where(x => x.No == voucher.No && x.Version == voucher.Version) //必须与查询时的version一致
.ExecuteCommandThrowVersionAsync();
//写入记录
var balanceRecord = order.Adapt<BalanceRecordEntity>();
balanceRecord.Remark = $"{ticket.QrCode}(生日券消费)";
balanceRecord.Remark = $"{voucher.No}(生日券消费)";
await _dbContext.InsertAsync(balanceRecord);
}, 5);
});
}
@@ -87,14 +103,15 @@ public class BirthdayConsumeHandler : IConsumeHandler
{
msg = ex.Message;
}
//获取餐券余额
var data = await _dbContext.Queryable<TicketEntity>()
.LeftJoin<GainfoEntity>((x, ga) => x.UserCode == ga.Code)
.Where(x => x.Type == TicketEnumType.Birthday && x.QrCode == ticketNo)
.Select((x, ga) => new OrderResultResponse
var data = await _dbContext.Queryable<VoucherEntity>()
.LeftJoin<VoucherUserInfoEntity>((x, u) => x.No == u.VoucherNo)
.LeftJoin<GainfoEntity>((x, u, ga) => u.UserCode == ga.Code)
.Where(x => x.Type == VoucherEnumType.Birthday && x.No == voucherQrCode.VoucherNo)
.Select((x, u, ga) => new OrderResultResponse
{
UserCode = x.UserCode,
UserCode = u.UserCode,
UserName = ga.Name,
CurrentBalance = x.Balance
})

View File

@@ -3,6 +3,7 @@ using Dlhis.Canteen.Order.Request;
using Dlhis.Canteen.Order.Response;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;

View File

@@ -8,6 +8,7 @@ using Dlhis.Entity.Device.Enums;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using Microsoft.Extensions.Primitives;
namespace Dlhis.Canteen.Order.Services.ConsumeHandlers;
@@ -40,7 +41,8 @@ public class OrderCommonHandler : IOrderCommonHandler
{
try
{
if (_httpContextAccessor.HttpContext!.Request.Headers.TryGetValue("X-Requested-DeviceIp", out var ip))
StringValues ip = "";
if (_httpContextAccessor.HttpContext?.Request.Headers.TryGetValue("X-Requested-DeviceIp", out ip) == true)
{
var device = await _dbContext.Queryable<DeviceEntity>().Where(x => x.UniqueNo == deviceNo).SingleAsync();
device.ConnectionInfo = new

View File

@@ -6,6 +6,7 @@ using Dlhis.Canteen.Setting.Services;
using Dlhis.Constants;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
using Dlhis.Entity.Canteen.Enums;
using Dlhis.Entity.Device;
using Dlhis.Entity.Device.Entities;

View File

@@ -6,6 +6,8 @@ using Dlhis.Canteen.Setting.Services;
using Dlhis.Constants;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
using Dlhis.Entity.Canteen.Entities.Voucher;
using Dlhis.Entity.Canteen.Enums;
using Dlhis.Entity.Device;
using Dlhis.Entity.Device.Entities;
@@ -160,27 +162,35 @@ public class OrderService : IOrderService
switch (flag)
{
case QrCodeConstants.User:
{
gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo);
await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo);
}
{
gainfo = await GetUserByQrCodeAsync(request.UserUniqueNo);
await CheckPermissionAsync(gainfo.Code, request.DeviceUniqueNo);
}
break;
case QrCodeConstants.EMealVoucher:
{
request.Source = BalanceRecordSourceEnumType.EMealVoucher;
var eMealVoucherQrCode = await _dbContext.Queryable<EMealVoucherDetailQrCodeEntity>().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync();
eMealVoucherQrCode.ThrowIfNull("无法识别");
var code = eMealVoucherQrCode.OriginData.Split(':')[2];
gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == code).SingleAsync();
}
{
request.Source = BalanceRecordSourceEnumType.EMealVoucher;
var eMealVoucherQrCode = await _dbContext.Queryable<EMealVoucherDetailQrCodeEntity>().Where(x => x.QrCode == request.UserUniqueNo).SingleAsync();
eMealVoucherQrCode.ThrowIfNull("无法识别");
var code = eMealVoucherQrCode.OriginData.Split(':')[2];
gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == code).SingleAsync();
}
break;
case QrCodeConstants.Birthday:
{
request.Source = BalanceRecordSourceEnumType.Birthday;
var ticket = await _dbContext.Queryable<TicketEntity>().Where(x => x.Type == TicketEnumType.Birthday).Where(x => x.QrCode == request.UserUniqueNo).SingleAsync();
ticket.ThrowIfNull("无法识别");
gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == ticket.UserCode).SingleAsync();
}
{
request.Source = BalanceRecordSourceEnumType.Birthday;
var qrcode = await _dbContext.Queryable<VoucherQrCodeEntity>()
.Where(x => x.QrCode == request.UserUniqueNo)
.SingleAsync();
qrcode.ThrowIfNull("券码无法识别");
var vourcher = await _dbContext.Queryable<VoucherUserInfoEntity>()
.Where(x => x.VoucherNo == qrcode.VoucherNo)
.SingleAsync();
gainfo = await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == vourcher.UserCode).SingleAsync();
}
break;
default: throw new UserFriendlyException($"无法识别{request.UserUniqueNo}");
@@ -201,7 +211,7 @@ public class OrderService : IOrderService
//在线
if (!request.IsOffline)
{
gainfo.ThrowIfNull("无法识别");
gainfo.ThrowIfNull("无法识别人员信息");
}
else
{
@@ -213,6 +223,7 @@ public class OrderService : IOrderService
.FirstAsync();
}
gainfo.ThrowIfNull("无法识别人员信息");
return gainfo;
}
@@ -292,7 +303,9 @@ public class OrderService : IOrderService
.Where(x => x.DeviceUniqueNo == request.DeviceUniqueNo && x.BusinessPlaceCode.HasValue)
.Select((x, b, bs) => new
{
b.Code, bs.ShiftCode, Factory = b.TenantId
b.Code,
bs.ShiftCode,
Factory = b.TenantId
})
.SingleAsync();
@@ -485,7 +498,7 @@ public class OrderService : IOrderService
return await _dbContext.Queryable<GainfoEntity>().Where(x => x.Code == gainfoQrCode.UserCode).SingleAsync();
}
/// <summary>
/// 检查是否能够进行离线消费,处理hpt重复提交
/// </summary>

View File

@@ -1,50 +0,0 @@
using Dlhis.Canteen.Tickets.Request;
using Dlhis.Canteen.Tickets.Response;
using Dlhis.Canteen.Tickets.Services;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.Utils.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Dlhis.Canteen.Tickets.Controllers;
/// <summary>
/// 券
/// </summary>
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class TicketsController : ControllerBase
{
private readonly INamedResolver _namedResolver;
public TicketsController(INamedResolver namedResolver)
{
_namedResolver = namedResolver;
}
/// <summary>
/// 获取分页数据(按券类型)
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("page")]
public async Task<Pagination<TicketPageResponse>> GetPageAsync(TicketPageRequest request)
{
return await _namedResolver.GetService<ITicketService>(request.Type.ToString()).GetPageAsync(request);
}
/// <summary>
/// 创建券
/// </summary>
/// <param name="type">券类型,需要后端支持</param>
[AllowAnonymous]
[HttpPost("{type:required}/create")]
public async Task CreateAsync(string type)
{
var srv = _namedResolver.GetService<ITicketService>(type);
srv.ThrowIfNull("不支持的券类型");
await srv.CreateAsync();
}
}

View File

@@ -1,19 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Canteen.Tickets.Request;
public class TicketPageRequest : PageDto
{
/// <summary>
/// 类型
/// </summary>
[EnumDataType(typeof(TicketEnumType))]
public TicketEnumType Type { get; set; }
/// <summary>
/// 工号
/// </summary>
public string UserCode { get; set; }
}

View File

@@ -1,6 +0,0 @@
namespace Dlhis.Canteen.Tickets.Services;
public interface IBirthdayTicketService : ITicketService
{
}

View File

@@ -1,24 +0,0 @@
using Dlhis.Canteen.Tickets.Request;
using Dlhis.Canteen.Tickets.Response;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Canteen.Tickets.Services;
/// <summary>
/// 券
/// </summary>
public interface ITicketService : IScopeDependency
{
/// <summary>
/// 分页数据
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
Task<Pagination<TicketPageResponse>> GetPageAsync(TicketPageRequest request);
/// <summary>
/// 创建
/// </summary>
/// <returns></returns>
Task CreateAsync();
}

View File

@@ -1,65 +0,0 @@
using System.Text;
using Dlhis.Constants;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.DataAccess.Entity;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using SqlSugar;
namespace Dlhis.Canteen.Tickets.Services.Implements;
[Service(nameof(TicketEnumType.Birthday))]
public class BirthdayTicketService : BaseTicketService, IBirthdayTicketService
{
/// <inheritdoc />
public BirthdayTicketService(IDbContext dbContext) : base(dbContext)
{
}
/// <inheritdoc />
public override async Task CreateAsync()
{
await DbContext.IgnoreAsync<ITenantId>(async () =>
{
var today = DateTime.Today;
var userCodes = await DbContext.Queryable<GainfoEntity>()
.Where(x => SqlFunc.DateIsSame(SqlFunc.ToDate(x.Birthday), today, DateType.Day))
.Select(x => new { x.Code, x.Factory })
.ToListAsync();
const decimal amount = 30;
var todayStr = today.ToString("yyyy-MM-dd");
foreach (var item in userCodes)
{
var qrCode = GetQrCode(item.Code + todayStr);
if (!await DbContext.Queryable<TicketEntity>().Where(x => x.Type == TicketEnumType.Birthday && x.UserCode == item.Code && x.QrCode == qrCode).AnyAsync())
{
await DbContext.InsertAsync(new TicketEntity
{
Type = TicketEnumType.Birthday,
UserCode = item.Code,
OriginalBalance = amount,
Balance = amount,
QrCode = qrCode,
Remark = todayStr + "生日券",
TenantId = item.Factory
});
}
}
});
}
private static string GetQrCode(string data)
{
var qrCode = QrCodeConstants.Birthday + data.ToArray().Select(x =>
{
var b = Encoding.ASCII.GetBytes(x.ToString());
int i = b[0];
return Convert.ToString(i);
}).Join(string.Empty);
return qrCode;
}
}

View File

@@ -1,32 +0,0 @@
using Dlhis.Canteen.Tickets.Request;
using Dlhis.Canteen.Tickets.Response;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
namespace Dlhis.Canteen.Tickets.Services.Implements;
public abstract class BaseTicketService : ITicketService
{
protected IDbContext DbContext { get; set; }
protected BaseTicketService(IDbContext dbContext)
{
DbContext = dbContext;
}
public async Task<Pagination<TicketPageResponse>> GetPageAsync(TicketPageRequest request)
{
return await DbContext.Queryable<TicketEntity>()
.LeftJoin<GainfoEntity>((x, ga) => x.UserCode == ga.Code)
.Where(x => x.Type == request.Type)
.WhereIF(request.UserCode.IsPresent(), x => x.UserCode == request.UserCode)
.Select((x, ga) => new TicketPageResponse { UserName = ga.Name }, true)
.ToPageListAsync(request);
}
public abstract Task CreateAsync();
}

View File

@@ -1,14 +1,14 @@
using Dlhis.Canteen.EMealVoucher.Request;
using Dlhis.Canteen.EMealVoucher.Response;
using Dlhis.Canteen.EMealVoucher.Services;
using Dlhis.Canteen.Order.Request;
using Dlhis.Canteen.Order.Response;
using Dlhis.Canteen.Voucher.Requests;
using Dlhis.Canteen.Voucher.Response;
using Dlhis.Canteen.Voucher.Services;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Dlhis.Canteen.EMealVoucher.Controllers;
namespace Dlhis.Canteen.Voucher.Controllers;
[Authorize]
[Route("api/[controller]")]

View File

@@ -0,0 +1,33 @@
using Dlhis.Canteen.Voucher.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Dlhis.Canteen.Voucher.Controllers;
/// <summary>
/// 券二维码服务
/// </summary>
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class VoucherQrCodesController : ControllerBase
{
private readonly IVoucherQrCodeService _voucherQrCodeService;
public VoucherQrCodesController(IVoucherQrCodeService voucherQrCodeService)
{
_voucherQrCodeService = voucherQrCodeService;
}
/// <summary>
/// 获取二维码
/// </summary>
/// <param name="voucherNo">券码</param>
/// <param name="isNeedRefresh">true:请求刷新</param>
/// <returns></returns>
[HttpGet]
public async Task<string> GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false)
{
return await _voucherQrCodeService.GetQrCodeAsync(voucherNo, isNeedRefresh);
}
}

View File

@@ -0,0 +1,107 @@
using Dlhis.Basic.Vouchers.Request;
using Dlhis.Canteen.Order.Request;
using Dlhis.Canteen.Order.Response;
using Dlhis.Canteen.Tickets.Request;
using Dlhis.Canteen.Tickets.Services;
using Dlhis.Canteen.Voucher.Requests;
using Dlhis.Canteen.Voucher.Response;
using Dlhis.Constants;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.Authentication.Abstractions;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Aop;
using Kurisu.AspNetCore.Utils.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Dlhis.Canteen.Voucher.Controllers;
/// <summary>
/// 券
/// </summary>
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class VouchersController : ControllerBase
{
private readonly INamedResolver _namedResolver;
private readonly ICurrentUser _currentUser;
public VouchersController(INamedResolver namedResolver, ICurrentUser currentUser)
{
_namedResolver = namedResolver;
_currentUser = currentUser;
}
/// <summary>
/// 获取分页数据(按券类型)
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("page")]
public async Task<Pagination<VoucherPageResponse>> GetPageAsync([FromQuery] VoucherPageRequest request)
{
return await _namedResolver.GetService<IVoucherService>(request.Type.ToString() + "VoucherService").GetPageAsync(request);
}
/// <summary>
/// 获取我的分页数据(按券类型)(H5)
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("my")]
public async Task<Pagination<VoucherPageResponse>> GetMyPageAsync([FromQuery] VoucherPageRequest request)
{
var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode);
request.UserCode = userCode;
return await _namedResolver.GetService<IVoucherService>(request.Type.ToString()).GetPageAsync(request);
}
/// <summary>
/// 创建生日券
/// </summary>
/// <returns></returns>
[AllowAnonymous]
[HttpPost("birthday/create")]
public async Task CreateBirthdayVoucherAsync(VoucherByBirthdayRequest request)
{
var srv = _namedResolver.GetService<IVoucherService>(VoucherEnumType.Birthday.ToString() + "VoucherService");
srv.ThrowIfNull("不支持的券类型");
await srv.CreateAsync(new Dictionary<string, object>
{
["userCodes"] = request.UserCodes,
["begin"] = request.Begin,
["end"] = request.End,
["remark"] = request.Remark
});
}
/// <summary>
/// 餐券消费分页
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("balance/page")]
[IgnoreTenant]
public async Task<Pagination<VoucherBalancePageResponse>> GetVoucherBalancePageAsync([FromQuery] VoucherBalancePageRequest request)
{
var srv = _namedResolver.GetService<IVoucherService>(request.Type.ToString() + "VoucherService");
return await srv.GetVoucherBalancePageAsync(request);
}
/// <summary>
/// 我的餐券消费分页(H5)
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("balance/my/page")]
[IgnoreTenant]
public async Task<Pagination<VoucherBalancePageResponse>> GetMyVoucherBalancePageAsync([FromQuery] VoucherBalancePageRequest request)
{
var srv = _namedResolver.GetService<IVoucherService>(request.Type.ToString());
return await srv.GetVoucherBalancePageAsync(request);
}
}

View File

@@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Canteen.EMealVoucher.Request;
namespace Dlhis.Canteen.Voucher.Requests;
public class EMealVoucherPageRequest : PageDto, IValidatableObject
{

View File

@@ -0,0 +1,19 @@
using System.ComponentModel.DataAnnotations;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Canteen.Voucher.Requests;
public class VoucherBalancePageRequest : PageDto
{
/// <summary>
/// 券类型 VoucherEnumType
/// </summary>
[EnumDataType(typeof(VoucherEnumType))]
public VoucherEnumType Type { get; set; }
public string UserCode { get; set; }
public DateTimePeriod SearchDateTimePeriod { get; set; }
}

View File

@@ -0,0 +1,28 @@

using System.ComponentModel.DataAnnotations;
namespace Dlhis.Basic.Vouchers.Request;
public class VoucherByBirthdayRequest
{
/// <summary>
/// 支持指定工号
/// </summary>
public List<string> UserCodes { get; set; }
/// <summary>
/// 开始范围
/// </summary>
public DateTime Begin { get; set; }
/// <summary>
/// 结束范围
/// </summary>
public DateTime End { get; set; }
/// <summary>
/// 备注
/// </summary>
[Required(ErrorMessage = "请填写备注")]
public string Remark { get; set; }
}

View File

@@ -0,0 +1,35 @@
using System.ComponentModel.DataAnnotations;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Canteen.Tickets.Request;
public class VoucherPageRequest : PageDto
{
/// <summary>
/// 类型 VoucherEnumType
/// </summary>
[EnumDataType(typeof(VoucherEnumType))]
public VoucherEnumType Type { get; set; }
/// <summary>
/// 工号
/// </summary>
public string UserCode { get; set; }
/// <summary>
/// 查询日期区间
/// </summary>
public DateTimePeriod SearchDateTimePeriod { get; set; }
/// <summary>
/// 一级部门
/// </summary>
public string DepartmentNoFirst { get; set; }
/// <summary>
/// 二级部门
/// </summary>
public string DepartmentNoSecond { get; set; }
}

View File

@@ -1,4 +1,4 @@
namespace Dlhis.Canteen.EMealVoucher.Response;
namespace Dlhis.Canteen.Voucher.Response;
public class EMealVoucherDetailResponse
{

View File

@@ -1,4 +1,4 @@
namespace Dlhis.Canteen.EMealVoucher.Response;
namespace Dlhis.Canteen.Voucher.Response;
public class EMealVoucherMyPageResponse
{

View File

@@ -3,7 +3,7 @@ using Kurisu.AspNetCore.Utils.Extensions;
using Mapster.Utils;
using Newtonsoft.Json;
namespace Dlhis.Canteen.EMealVoucher.Response;
namespace Dlhis.Canteen.Voucher.Response;
public class EMealVoucherPageResponse
{
@@ -65,7 +65,7 @@ public class EMealVoucherPageResponse
{
get
{
var a = CurrentShifts.ToObject<List<int>>().Select(x => ((ShiftEnumType)(x * 10))).ToList();
var a = CurrentShifts.ToObject<List<int>>().Select(x => (ShiftEnumType)(x * 10)).ToList();
return a.Select(x=>x.GetDescription()).ToList();
}
}

View File

@@ -0,0 +1,129 @@
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.Utils.Converters;
using Kurisu.AspNetCore.Utils.Extensions;
using Newtonsoft.Json;
namespace Dlhis.Canteen.Voucher.Response;
public class VoucherBalancePageResponse
{
public long Id { get; set; }
/// <summary>
/// 流水号
/// </summary>
public string No { get; set; }
/// <summary>
/// 档案号/QRCode
/// </summary>
public string UserNo { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 学工号
/// </summary>
public string UserCode { get; set; }
/// <summary>
/// 部门号
/// </summary>
public string DepartmentNo { get; set; }
/// <summary>
/// 部门
/// </summary>
public string DepartmentName { get; set; }
/// <summary>
/// 所属成本日期
/// </summary>
[JsonConverter(typeof(ToDateJsonConverter))]
public DateTime CostDate { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 来源
/// </summary>
public BalanceRecordSourceEnumType Source { get; set; }
/// <summary>
/// 消费识别来源
/// </summary>
public string SourceDesc => Source.GetDescription();
/// <summary>
/// 收入/支出
/// </summary>
public BalanceRecordTypeEnumType Type { get; set; }
public string TypeDesc => Type.GetDescription();
/// <summary>
/// 金额
/// </summary>
public decimal Amount { get; set; }
/// <summary>
/// 营业点
/// </summary>
public string BusinessPlaceName { get; set; }
/// <summary>
/// 餐次
/// </summary>
public ShiftEnumType? ShiftType { get; set; }
/// <summary>
/// 餐次
/// </summary>
public string ShiftTypeDesc => ShiftType?.GetDescription();
/// <summary>
/// 消费机器唯一信息
/// </summary>
public string DeviceInfo { get; set; }
/// <summary>
/// 成本中心
/// </summary>
public string CostId { get; set; }
/// <summary>
/// 消费者所在基地
/// </summary>
public string OriginTenantId { get; set; }
/// <summary>
/// 数据状态
/// </summary>
public BalanceRecordStatusEnumType Status { get; set; }
/// <summary>
/// 数据状态描述
/// </summary>
public string StatusDesc => Status.GetDescription();
/// <summary>
/// 记录产生时间
/// </summary>
public DateTime CostDateTime { get; set; }
/// <summary>
/// 厂区
/// </summary>
public string Factory { get; set; }
/// <summary>
/// 人事范围
/// </summary>
public string Werks { get; set; }
}

View File

@@ -1,13 +1,13 @@
using Dlhis.Entity.Canteen.Enums;
namespace Dlhis.Canteen.Tickets.Response;
namespace Dlhis.Canteen.Voucher.Response;
public class TicketPageResponse
public class VoucherPageResponse
{
/// <summary>
/// 券类型
/// </summary>
public TicketEnumType Type { get; set; }
public VoucherEnumType Type { get; set; }
/// <summary>
/// 工号
@@ -30,12 +30,27 @@ public class TicketPageResponse
public decimal Amount { get; set; }
/// <summary>
/// 消费码
/// 描述
/// </summary>
public string QrCode { get; set; }
public string Description { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
public string CostId { get; set; }
public string DepartmentNo { get; set; }
public string DepartmentName { get; set; }
public string DepartmentNoFirst { get; set; }
public string DepartmentNameFirst { get; set; }
public string DepartmentNoSecond { get; set; }
public string DepartmentNameSecond { get; set; }
public string Werks { get; set; }
public string Factory { get; set; }
}

View File

@@ -1,11 +1,11 @@
using Dlhis.Canteen.EMealVoucher.Request;
using Dlhis.Canteen.EMealVoucher.Response;
using Dlhis.Canteen.Order.Request;
using Dlhis.Canteen.Order.Response;
using Dlhis.Canteen.Voucher.Requests;
using Dlhis.Canteen.Voucher.Response;
using Kurisu.AspNetCore.DataAccess.Dto;
using Microsoft.AspNetCore.Mvc;
namespace Dlhis.Canteen.EMealVoucher.Services;
namespace Dlhis.Canteen.Voucher.Services;
public interface IEMealVoucherService : IScopeDependency
{

View File

@@ -0,0 +1,13 @@
namespace Dlhis.Canteen.Voucher.Services;
public interface IVoucherQrCodeService
{
/// <summary>
/// 获取二维码
/// </summary>
/// <param name="voucherNo"></param>
/// <param name="isNeedRefresh"></param>
/// <returns></returns>
Task<string> GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false);
}

View File

@@ -0,0 +1,28 @@
using Dlhis.Canteen.Tickets.Request;
using Dlhis.Canteen.Voucher.Requests;
using Dlhis.Canteen.Voucher.Response;
using Kurisu.AspNetCore.DataAccess.Dto;
namespace Dlhis.Canteen.Tickets.Services;
/// <summary>
/// 券
/// </summary>
public interface IVoucherService : IScopeDependency
{
/// <summary>
/// 分页数据
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
Task<Pagination<VoucherPageResponse>> GetPageAsync(VoucherPageRequest request);
/// <summary>
/// 创建
/// </summary>
/// <returns></returns>
Task CreateAsync(Dictionary<string, object> pairs);
Task<Pagination<VoucherBalancePageResponse>> GetVoucherBalancePageAsync(VoucherBalancePageRequest request);
}

View File

@@ -0,0 +1,83 @@
using Dlhis.Canteen.Tickets.Request;
using Dlhis.Canteen.Voucher.Requests;
using Dlhis.Canteen.Voucher.Response;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities.Voucher;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
namespace Dlhis.Canteen.Tickets.Services.Implements;
public abstract class BaseVoucherService : IVoucherService
{
protected IDbContext DbContext { get; set; }
protected BaseVoucherService(IDbContext dbContext)
{
DbContext = dbContext;
}
public async Task<Pagination<VoucherPageResponse>> GetPageAsync(VoucherPageRequest request)
{
var pagination = await DbContext.Queryable<VoucherEntity>()
.LeftJoin<VoucherUserInfoEntity>((x, u) => x.No == u.VoucherNo)
.LeftJoin<GainfoEntity>((x, u, ga) => u.UserCode == ga.Code)
.Where(x => x.Type == request.Type)
.WhereIF(request.UserCode.IsPresent(), (x, u, ga) => u.UserCode == request.UserCode)
.WhereIF(request.SearchDateTimePeriod.HasValue(),
(x, u, ga) => x.CreateTime >= request.SearchDateTimePeriod.Start &&
x.CreateTime <= request.SearchDateTimePeriod.End)
.WhereIF(request.DepartmentNoFirst.IsPresent(),
(x, u, ga) => u.DepartmentNoFirst == request.DepartmentNoFirst)
.WhereIF(request.DepartmentNoSecond.IsPresent(),
(x, u, ga) => u.DepartmentNoSecond == request.DepartmentNoSecond)
.OrderByDescending(x => x.ClaimDateTime)
.Select((x, u, ga) => new VoucherPageResponse
{
Type = x.Type,
UserCode = u.UserCode,
UserName = ga.Name,
OriginalAmount = x.OriginalBalance,
Amount = x.Balance,
Remark = x.Remark,
Description = x.Description,
CostId = u.CostId,
DepartmentNo = u.DepartmentNo,
DepartmentNoFirst = u.DepartmentNoFirst,
DepartmentNoSecond = u.DepartmentNoSecond,
Werks = u.Werks,
Factory = u.Factory
})
.ToPageListAsync(request);
var searchNos = pagination.Data.SelectMany(x =>
{
return new List<string>
{
x.DepartmentNo,
x.DepartmentNoFirst,
x.DepartmentNoSecond
};
}).Distinct().ToList();
var departments = await DbContext.Queryable<DepartmentEntity>().Where(x => searchNos.Contains(x.No)).ToListAsync();
pagination.Data.ForEach(x =>
{
x.DepartmentName = departments.FirstOrDefault(d => d.No == x.DepartmentNo)?.Name;
x.DepartmentNameFirst = departments.FirstOrDefault(d => d.No == x.DepartmentNoFirst)?.Name;
x.DepartmentNameSecond = departments.FirstOrDefault(d => d.No == x.DepartmentNoSecond)?.Name;
});
return pagination;
}
public abstract Task CreateAsync(Dictionary<string, object> pairs);
public abstract Task<Pagination<VoucherBalancePageResponse>> GetVoucherBalancePageAsync(VoucherBalancePageRequest request);
}

View File

@@ -0,0 +1,254 @@
using System.Collections.Generic;
using System.Text;
using Dlhis.Basic.Api;
using Dlhis.Canteen.Tickets.Services;
using Dlhis.Canteen.Tickets.Services.Implements;
using Dlhis.Canteen.Voucher.Requests;
using Dlhis.Canteen.Voucher.Response;
using Dlhis.Constants;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Basic.Enums;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Entities.Voucher;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.CustomClass;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.DataAccess.Entity;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using SqlSugar;
namespace Dlhis.Canteen.Voucher.Services.Implements;
[Service("BirthdayVoucherService")]
public class BirthdayVoucherService : BaseVoucherService, IVoucherService
{
private readonly IFactorySettingApi _factorySettingApi;
/// <inheritdoc />
public BirthdayVoucherService(IDbContext dbContext, IFactorySettingApi factorySettingApi) : base(dbContext)
{
_factorySettingApi = factorySettingApi;
}
/// <inheritdoc />
public override async Task CreateAsync(Dictionary<string, object> pairs)
{
var p = GetDateRange(pairs);
var remark = pairs != null && pairs.TryGetValue("remark", out var r) ? r?.ToString() : string.Empty;
var userCodes = pairs != null && pairs.TryGetValue("userCodes", out var c) ? c as List<string> : new List<string>();
//忽略tenant操作
await DbContext.IgnoreAsync<ITenantId>(async () =>
{
var gainfos = await GetGainfosAsync(userCodes, p.begin, p.end);
var departmentNos = gainfos.Select(g => g.DepartmentNo).Distinct().ToList();
var departmentInfos = await DbContext.Queryable<DepartmentEntity>()
.Where(x => departmentNos.Contains(x.No))
.ToListAsync();
foreach (var gainfo in gainfos.Where(x => x.Birthday.HasValue))
{
await DbContext.Client.Ado.BeginTranAsync();
try
{
var years = GetBirthdayYears(gainfo.Birthday.Value, p.begin, p.end);
foreach (var year in years)
{
await GenerateVoucherAsync(gainfo, departmentInfos, year, remark);
}
await DbContext.Client.Ado.CommitTranAsync();
}
catch (Exception)
{
await DbContext.Client.Ado.RollbackTranAsync();
}
}
});
}
private async Task GenerateVoucherAsync(GainfoEntity gainfo, List<DepartmentEntity> departments, int year, string remark)
{
//生日券金额固定100元
const decimal amount = 100;
var dayStr = year + "-" + gainfo.Birthday.Value.ToString("MM-dd");
//由数据类型+工号+生日组成唯一标识
var no = GenerateUniqueCode(VoucherEnumType.Birthday.ToString() + gainfo.Code + dayStr);
if (!await DbContext.Queryable<VoucherEntity>()
.Where(x => x.No == no)
.Where(x => x.Type == VoucherEnumType.Birthday)
.AnyAsync())
{
await DbContext.InsertAsync(new VoucherEntity
{
No = no,
Type = VoucherEnumType.Birthday,
ClaimDateTime = new DateTime(year, gainfo.Birthday.Value.Month, gainfo.Birthday.Value.Day),
OriginalBalance = amount,
Balance = amount,
Description = dayStr + "生日券",
Remark = remark,
CreatedBy = 1,
CreateTime = DateTime.Now,
ModifiedBy = 1,
ModifiedTime = DateTime.Now,
Version = 0
});
var department = departments.FirstOrDefault(x => x.No == gainfo.DepartmentNo);
await DbContext.InsertAsync(new VoucherUserInfoEntity
{
VoucherNo = no,
UserCode = gainfo.Code,
CostId = gainfo.CostId,
Werks = gainfo.Werks,
Factory = gainfo.Factory,
DepartmentNo = gainfo.DepartmentNo,
DepartmentNoFirst = department?.DepartmentNoFirst,
DepartmentNoSecond = department?.DepartmentNoSecond,
CreatedBy = 1,
CreateTime = DateTime.Now,
ModifiedBy = 1,
ModifiedTime = DateTime.Now
});
}
}
private (DateTime begin, DateTime end) GetDateRange(Dictionary<string, object> pairs)
{
var begin = DateTime.Today;
var end = begin;
if (pairs != null)
{
if (pairs.TryGetValue("begin", out var b))
{
if (b is DateTime bb)
{
begin = bb;
}
}
if (pairs.TryGetValue("end", out var e))
{
if (e is DateTime ee)
{
end = ee;
}
}
}
return (begin, end);
}
private async Task<List<GainfoEntity>> GetGainfosAsync(List<string> userCodes, DateTime begin, DateTime end)
{
var factries = await _factorySettingApi.GetEnableBirthdayVoucherFactoriesAsync();
var isToday = begin.Date == end.Date;
var beginMonth = begin.Month;
var endMonth = end.Month;
var overYear = endMonth < beginMonth;
//var limit = end.Date.AddHours(9);//9点入职
return await DbContext.Queryable<GainfoEntity>()
.WhereIF(userCodes.IsPresent(), x => userCodes.Contains(x.Code))
.Where(x => x.Type == GainfoUserTypeEnumType.Normal || x.Type == GainfoUserTypeEnumType.SecurityWhite)
.Where(x => x.Birthday.HasValue && !string.IsNullOrEmpty(x.CostId))
.WhereIF(isToday, x => SqlFunc.DateValue(x.Birthday.Value, DateType.Month) == begin.Month && SqlFunc.DateValue(x.Birthday.Value, DateType.Day) == begin.Day)
.WhereIF(!isToday && !overYear, x => SqlFunc.DateValue(x.Birthday.Value, DateType.Month) >= beginMonth && SqlFunc.DateValue(x.Birthday.Value, DateType.Month) <= endMonth)
.WhereIF(!isToday && overYear, x => SqlFunc.DateValue(x.Birthday.Value, DateType.Month) >= beginMonth || SqlFunc.DateValue(x.Birthday.Value, DateType.Month) <= endMonth)
.Where(x => factries.Contains(x.Factory))
.ToListAsync();
}
private static string GenerateUniqueCode(string data)
{
return QrCodeConstants.Birthday + data.ToArray().Select(x =>
{
var b = Encoding.ASCII.GetBytes(x.ToString());
int i = b[0];
return Convert.ToString(i);
}).Join(string.Empty);
}
/// <summary>
/// 计算给定生日在区间 [begin, end] 内出现的所有年份(可能为0、1或多个)。
/// - 对于每个候选年份构造安全的日期(处理 2/29 在非闰年的情况,退到当年最大天数)。
/// - 若区间内找不到匹配年份,则返回包含 begin.Year 的单元素列表作为兜底行为,保持向后兼容。
/// </summary>
private static List<int> GetBirthdayYears(DateTime birthday, DateTime begin, DateTime end)
{
var years = new List<int>();
// 扩展范围到 begin.Year-1 .. end.Year+1 以覆盖跨年边界的极端情况
var startYear = begin.Year - 1;
var endYear = end.Year + 1;
for (var y = startYear; y <= endYear; y++)
{
var candidate = SafeDate(y, birthday);
if (candidate >= begin && candidate <= end)
{
years.Add(candidate.Year);
}
}
// 去重并排序
years = years.Distinct().OrderBy(x => x).ToList();
return years;
static DateTime SafeDate(int year, DateTime bday)
{
var day = Math.Min(bday.Day, DateTime.DaysInMonth(year, bday.Month));
return new DateTime(year, bday.Month, day);
}
}
public override async Task<Pagination<VoucherBalancePageResponse>> GetVoucherBalancePageAsync(VoucherBalancePageRequest request)
{
return await DbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<BusinessPlaceEntity>((x, bPlace) => x.BusinessPlaceCode == bPlace.Code)
.LeftJoin<DepartmentEntity>((x, bPlace, department) => x.DepartmentNo == department.No)
.Where(x => x.UserCode == request.UserCode)
.WhereIF(request.SearchDateTimePeriod.HasValue(), x => x.CostDate >= request.SearchDateTimePeriod.Start && x.CostDate <= request.SearchDateTimePeriod.End) //成本日期
.Where(x => x.Status == BalanceRecordStatusEnumType.Valid && x.Type == BalanceRecordTypeEnumType.Out) //有效,消费数据
.Where(x => x.Source == BalanceRecordSourceEnumType.Birthday)
.Select((x, bPlace, department) => new VoucherBalancePageResponse
{
No = x.No,
UserNo = x.UserNo,
Name = x.Name,
UserCode = x.UserCode,
DepartmentNo = x.DepartmentNo,
DepartmentName = department.Name,
CostDate = x.CostDate,
Remark = x.Remark,
Source = x.Source,
Type = x.Type,
Amount = SqlFunc.Abs(x.Amount),
BusinessPlaceName = bPlace.Name,
ShiftType = x.ShiftType,
DeviceInfo = x.DeviceUniqueNo,
CostId = x.CostId,
OriginTenantId = x.OriginTenantId,
Status = x.Status,
CostDateTime = x.CostDateTime,
Factory = x.TenantId,
Werks = x.Werks
})
.ToPageListAsync(request);
}
}

View File

@@ -1,11 +1,12 @@
using System.Text;
using Dlhis.Canteen.EMealVoucher.Request;
using Dlhis.Canteen.EMealVoucher.Response;
using Dlhis.Canteen.Order.Request;
using Dlhis.Canteen.Order.Response;
using Dlhis.Canteen.Voucher.Requests;
using Dlhis.Canteen.Voucher.Response;
using Dlhis.Constants;
using Dlhis.Entity.Basic.Entity;
using Dlhis.Entity.Canteen.Entities;
using Dlhis.Entity.Canteen.Entities.EMealVoucher;
using Dlhis.Entity.Canteen.Enums;
using Kurisu.AspNetCore.Authentication.Abstractions;
using Kurisu.AspNetCore.CustomClass;
@@ -15,7 +16,7 @@ using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using SqlSugar;
namespace Dlhis.Canteen.EMealVoucher.Services.Implements;
namespace Dlhis.Canteen.Voucher.Services.Implements;
public class EMealVoucherService : IEMealVoucherService
{

View File

@@ -0,0 +1,75 @@

using System.Text;
using Dlhis.Constants;
using Dlhis.Entity.Canteen.Entities.Voucher;
using Kurisu.AspNetCore.Authentication.Abstractions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
namespace Dlhis.Canteen.Voucher.Services.Implements;
public class VoucherQrCodeService : IVoucherQrCodeService
{
private readonly IDbContext _dbContext;
private readonly ICurrentUser _currentUser;
public VoucherQrCodeService(IDbContext dbContext, ICurrentUser currentUser)
{
_dbContext = dbContext;
_currentUser = currentUser;
}
public async Task<string> GetQrCodeAsync(string voucherNo, bool isNeedRefresh = false)
{
var userCode = _currentUser.GetUserClaim(UserClaimConstants.JinkoCode);
if (!await _dbContext.Queryable<VoucherUserInfoEntity>().Where(x => x.VoucherNo == voucherNo && x.UserCode == userCode).AnyAsync())
{
true.ThrowIfTrue("非法的消费券");
}
var qrcodeInfo = await _dbContext.Queryable<VoucherQrCodeEntity>().SingleAsync(x => x.VoucherNo == voucherNo);
if (qrcodeInfo == null)
{
qrcodeInfo = new VoucherQrCodeEntity
{
VoucherNo = voucherNo,
QrCode = GenerateQrCode(voucherNo)
};
await _dbContext.InsertAsync(qrcodeInfo);
return qrcodeInfo.QrCode;
}
var now = DateTime.Now;
if (qrcodeInfo.ModifiedTime.AddMinutes(1) >= now && !isNeedRefresh)
{
return qrcodeInfo.QrCode;
}
qrcodeInfo.QrCode = GenerateQrCode(voucherNo);
await _dbContext.UpdateAsync(qrcodeInfo);
return qrcodeInfo.QrCode;
}
/// <summary>
/// qrCode生成
/// </summary>
/// <param name="voucherNo"></param>
/// <returns></returns>
private static string GenerateQrCode(string voucherNo)
{
var ts = DateTimeOffset.Now.ToUnixTimeMilliseconds();
return QrCodeConstants.Birthday + voucherNo.ToArray().Select(x =>
{
var b = Encoding.ASCII.GetBytes(x.ToString());
int i = b[0];
return Convert.ToString(i);
}).Join(string.Empty) + ts;
}
}