完善系统参数配置和数据字典管理模块
This commit is contained in:
@@ -1,12 +1,227 @@
|
||||
using Model;
|
||||
using Model.Dto.Asset;
|
||||
using Model.Entity.Asset;
|
||||
using ORM;
|
||||
using QRCoder;
|
||||
using Service.Interface;
|
||||
using SqlSugar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Service.Implement
|
||||
{
|
||||
/// <summary>
|
||||
/// 二维码 服务实现
|
||||
/// 设备二维码 服务实现
|
||||
/// 扫码直达 URL 约定:{baseUrl}/asset/ledger/equipment?id={equipmentId}
|
||||
/// baseUrl 由 Controller 从 HTTP 请求(scheme://host)传入;如需固定域名可改为读 sys_param 的 site_base_url
|
||||
/// </summary>
|
||||
public class QrCodeService : IQrCodeService
|
||||
{
|
||||
// TODO: 实现 二维码 相关方法
|
||||
public async Task<Result<QrCodeDto>> GenerateAsync(long equipmentId, string baseUrl)
|
||||
{
|
||||
if (equipmentId <= 0) return Result<QrCodeDto>.Error("设备Id无效");
|
||||
try
|
||||
{
|
||||
var entity = await LoadEquipmentAsync(equipmentId);
|
||||
if (entity == null) return Result<QrCodeDto>.Error("设备不存在或已被删除");
|
||||
|
||||
var url = BuildQrUrl(baseUrl, equipmentId);
|
||||
if (string.IsNullOrEmpty(entity.QrCodeUrl))
|
||||
{
|
||||
await SqlSugarContext.DbContext.Updateable<EquipmentEntity>()
|
||||
.SetColumns(x => x.QrCodeUrl == url)
|
||||
.Where(x => x.Id == equipmentId).ExecuteCommandAsync();
|
||||
entity.QrCodeUrl = url;
|
||||
}
|
||||
return Result<QrCodeDto>.Success(ToDto(entity));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<QrCodeDto>.Error("生成二维码失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<byte[]>> GenerateImageAsync(long equipmentId, string baseUrl)
|
||||
{
|
||||
if (equipmentId <= 0) return Result<byte[]>.Error("设备Id无效");
|
||||
try
|
||||
{
|
||||
var entity = await LoadEquipmentAsync(equipmentId);
|
||||
if (entity == null) return Result<byte[]>.Error("设备不存在或已被删除");
|
||||
|
||||
var url = string.IsNullOrEmpty(entity.QrCodeUrl) ? BuildQrUrl(baseUrl, equipmentId) : entity.QrCodeUrl;
|
||||
if (string.IsNullOrEmpty(entity.QrCodeUrl))
|
||||
{
|
||||
await SqlSugarContext.DbContext.Updateable<EquipmentEntity>()
|
||||
.SetColumns(x => x.QrCodeUrl == url)
|
||||
.Where(x => x.Id == equipmentId).ExecuteCommandAsync();
|
||||
entity.QrCodeUrl = url;
|
||||
}
|
||||
|
||||
var png = EncodePng(url);
|
||||
return Result<byte[]>.Success(png);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<byte[]>.Error("生成二维码图片失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<List<QrCodeBatchResultDto>>> BatchGenerateAsync(long[] equipmentIds, string baseUrl)
|
||||
{
|
||||
if (equipmentIds == null || equipmentIds.Length == 0)
|
||||
return Result<List<QrCodeBatchResultDto>>.Error("设备Id列表不能为空");
|
||||
var results = new List<QrCodeBatchResultDto>();
|
||||
foreach (var id in equipmentIds.Distinct())
|
||||
{
|
||||
var r = await GenerateAsync(id, baseUrl);
|
||||
results.Add(new QrCodeBatchResultDto
|
||||
{
|
||||
EquipmentId = id.ToString(),
|
||||
EquipmentCode = r.Data?.EquipmentCode,
|
||||
EquipmentName = r.Data?.EquipmentName,
|
||||
QrCodeUrl = r.Data?.QrCodeUrl,
|
||||
Success = r.IsSuccess,
|
||||
Message = r.IsSuccess ? "成功" : r.Msg
|
||||
});
|
||||
}
|
||||
return Result<List<QrCodeBatchResultDto>>.Success(results);
|
||||
}
|
||||
|
||||
public async Task<Result<List<QrCodeDto>>> GetListPagedAsync(int pageIndex, int pageSize, RefAsync<int> total, string? keyword = null, bool qrOnly = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
var list = await SqlSugarContext.DbContext.Queryable<EquipmentEntity>()
|
||||
.Where(x => x.IsDel == 0)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(keyword), x => x.Code!.Contains(keyword!) || x.Name!.Contains(keyword!))
|
||||
.WhereIF(qrOnly, x => x.QrCodeUrl != null && x.QrCodeUrl != "")
|
||||
.OrderBy(x => x.Code)
|
||||
.ToPageListAsync(pageIndex, pageSize, total);
|
||||
return Result<List<QrCodeDto>>.Success(list.Select(ToDto).ToList());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<List<QrCodeDto>>.Error("查询二维码列表失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result<string>> GetPrintHtmlAsync(long equipmentId, string baseUrl)
|
||||
{
|
||||
if (equipmentId <= 0) return Result<string>.Error("设备Id无效");
|
||||
try
|
||||
{
|
||||
var entity = await LoadEquipmentAsync(equipmentId);
|
||||
if (entity == null) return Result<string>.Error("设备不存在或已被删除");
|
||||
|
||||
var url = string.IsNullOrEmpty(entity.QrCodeUrl) ? BuildQrUrl(baseUrl, equipmentId) : entity.QrCodeUrl;
|
||||
var png = EncodePng(url);
|
||||
var base64 = Convert.ToBase64String(png);
|
||||
|
||||
var html = BuildPrintHtml(entity, url, base64);
|
||||
return Result<string>.Success(html);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<string>.Error("生成打印页失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result> BindRfidAsync(long equipmentId, string rfidCode)
|
||||
{
|
||||
if (equipmentId <= 0) return Result.Error("设备Id无效");
|
||||
if (string.IsNullOrWhiteSpace(rfidCode)) return Result.Error("RFID 编号不能为空");
|
||||
try
|
||||
{
|
||||
var exists = await SqlSugarContext.DbContext.Queryable<EquipmentEntity>()
|
||||
.Where(x => x.Id == equipmentId && x.IsDel == 0).AnyAsync();
|
||||
if (!exists) return Result.Error("设备不存在或已被删除");
|
||||
|
||||
await SqlSugarContext.DbContext.Updateable<EquipmentEntity>()
|
||||
.SetColumns(x => x.RfidCode == rfidCode)
|
||||
.Where(x => x.Id == equipmentId).ExecuteCommandAsync();
|
||||
return Result.Success();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result.Error("绑定 RFID 失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 私有工具 ====================
|
||||
|
||||
private static async Task<EquipmentEntity?> LoadEquipmentAsync(long id)
|
||||
=> await SqlSugarContext.DbContext.Queryable<EquipmentEntity>()
|
||||
.Where(x => x.Id == id && x.IsDel == 0).FirstAsync();
|
||||
|
||||
private static QrCodeDto ToDto(EquipmentEntity e) => new()
|
||||
{
|
||||
EquipmentId = e.Id.ToString(),
|
||||
EquipmentCode = e.Code,
|
||||
EquipmentName = e.Name,
|
||||
Location = e.Location,
|
||||
QrCode = e.QrCode,
|
||||
QrCodeUrl = e.QrCodeUrl,
|
||||
RfidCode = e.RfidCode
|
||||
};
|
||||
|
||||
private static string BuildQrUrl(string baseUrl, long equipmentId)
|
||||
{
|
||||
var b = (baseUrl ?? string.Empty).TrimEnd('/');
|
||||
return $"{b}/asset/ledger/equipment?id={equipmentId}";
|
||||
}
|
||||
|
||||
private static byte[] EncodePng(string content)
|
||||
{
|
||||
using var gen = new QRCodeGenerator();
|
||||
var data = gen.CreateQrCode(content, QRCodeGenerator.ECCLevel.Q);
|
||||
var png = new PngByteQRCode(data);
|
||||
return png.GetGraphic(20); // 20 px per module,便于扫描识别
|
||||
}
|
||||
|
||||
private static string BuildPrintHtml(EquipmentEntity e, string url, string base64)
|
||||
{
|
||||
// 简单 A4 打印模板:左侧二维码,右侧设备信息;浏览器 window.print() 即可
|
||||
var safe = (string? s) => System.Net.WebUtility.HtmlEncode(s ?? string.Empty);
|
||||
return $@"<!DOCTYPE html>
|
||||
<html lang='zh-CN'>
|
||||
<head>
|
||||
<meta charset='utf-8' />
|
||||
<title>设备二维码 - {safe(e.Name)}</title>
|
||||
<style>
|
||||
@page {{ size: A4; margin: 12mm; }}
|
||||
body {{ font-family: 'Microsoft YaHei', sans-serif; color: #303133; }}
|
||||
.label {{ border:1px solid #303133; border-radius:6px; padding:16px; display:flex; gap:24px; align-items:center; max-width:480px; }}
|
||||
.qr img {{ width: 220px; height: 220px; }}
|
||||
.info dl {{ margin:0; }}
|
||||
.info dt {{ font-size:13px; color:#909399; margin-top:8px; }}
|
||||
.info dd {{ font-size:16px; margin:4px 0 0 0; font-weight:600; }}
|
||||
.info h2 {{ margin:0 0 8px 0; font-size:20px; }}
|
||||
.url {{ margin-top:12px; font-size:12px; color:#909399; word-break:break-all; }}
|
||||
.actions {{ margin-top:16px; }}
|
||||
.actions button {{ padding:6px 16px; font-size:14px; cursor:pointer; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='label'>
|
||||
<div class='qr'><img src='data:image/png;base64,{base64}' alt='QR' /></div>
|
||||
<div class='info'>
|
||||
<h2>{safe(e.Name)}</h2>
|
||||
<dl>
|
||||
<dt>设备编号</dt><dd>{safe(e.Code)}</dd>
|
||||
<dt>二维码编号</dt><dd>{safe(e.QrCode)}</dd>
|
||||
<dt>存放位置</dt><dd>{safe(e.Location)}</dd>
|
||||
<dt>责任人</dt><dd>{safe(e.ResponsiblePerson)}</dd>
|
||||
</dl>
|
||||
<div class='url'>{safe(url)}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='actions'><button onclick='window.print()'>打印</button></div>
|
||||
<script>window.onload=function(){{setTimeout(function(){{window.print();}},300);}};</script>
|
||||
</body>
|
||||
</html>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user