using NCC.Common;
using NCC.Common.Configuration;
using NCC.Common.Core.Manager;
using NCC.Common.Enum;
using NCC.Common.Extension;
using NCC.Common.Filter;
using NCC.Common.Helper;
using NCC.Common.Model.NPOI;
using NCC.Dependency;
using NCC.DynamicApiController;
using NCC.FriendlyException;
using NCC.Extend.Interfaces.Zlgl;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using NCC.Extend.Entitys;
using NCC.Extend.Entitys.Dto.Zlgl;
using NCC.System.Entitys.System;
using Yitter.IdGenerator;
using NCC.DataEncryption;
using NCC.JsonSerialization;
using NCC.System.Entitys.Model.Permission.User;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
namespace NCC.Extend.Zlgl
{
///
/// 资料管理服务
///
[ApiDescriptionSettings(Tag = "Extend",Name = "Zlgl", Order = 200)]
[Route("api/Extend/[controller]")]
public class ZlglService : IZlglService, IDynamicApiController, ITransient
{
private readonly ISqlSugarRepository _zlglRepository;
private readonly SqlSugarScope _db;
private readonly IUserManager _userManager;
///
/// 初始化一个类型的新实例
///
public ZlglService(
ISqlSugarRepository zlglRepository,
IUserManager userManager)
{
_zlglRepository = zlglRepository;
_db = _zlglRepository.Context;
_userManager = userManager;
}
///
/// 获取资料管理
///
/// 参数
///
[HttpGet("{id}")]
public async Task GetInfo(string id)
{
var entity = await _db.Queryable().FirstAsync(p => p.Id == id);
var output = entity.Adapt();
return output;
}
///
/// 获取资料管理列表
///
/// 请求参数
///
[HttpGet("")]
public async Task GetList([FromQuery] ZlglListQueryInput input)
{
var sidx = input.sidx == null ? "id" : input.sidx;
List queryFbsj = input.fbsj != null ? input.fbsj.Split(',').ToObeject>() : null;
DateTime? startFbsj = queryFbsj != null ? Ext.GetDateTime(queryFbsj.First()) : null;
DateTime? endFbsj = queryFbsj != null ? Ext.GetDateTime(queryFbsj.Last()) : null;
List queryCcrq = input.ccrq != null ? input.ccrq.Split(',').ToObeject>() : null;
DateTime? startCcrq = queryCcrq != null ? Ext.GetDateTime(queryCcrq.First()) : null;
DateTime? endCcrq = queryCcrq != null ? Ext.GetDateTime(queryCcrq.Last()) : null;
var data = await _db.Queryable()
.WhereIF(!string.IsNullOrEmpty(input.zlm), p => p.Zlm.Contains(input.zlm))
.WhereIF(!string.IsNullOrEmpty(input.sbbh), p => p.Sbbh.Contains(input.sbbh))
.WhereIF(!string.IsNullOrEmpty(input.gg), p => p.Gg.Contains(input.gg))
.WhereIF(!string.IsNullOrEmpty(input.fl), p => p.Fl.Equals(input.fl))
.WhereIF(queryFbsj != null, p => p.Fbsj >= new DateTime(startFbsj.ToDate().Year, startFbsj.ToDate().Month, startFbsj.ToDate().Day, 0, 0, 0))
.WhereIF(queryFbsj != null, p => p.Fbsj <= new DateTime(endFbsj.ToDate().Year, endFbsj.ToDate().Month, endFbsj.ToDate().Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.bh), p => p.Bh.Contains(input.bh))
.WhereIF(!string.IsNullOrEmpty(input.ccbh), p => p.Ccbh.Contains(input.ccbh))
.WhereIF(queryCcrq != null, p => p.Ccrq >= new DateTime(startCcrq.ToDate().Year, startCcrq.ToDate().Month, startCcrq.ToDate().Day, 0, 0, 0))
.WhereIF(queryCcrq != null, p => p.Ccrq <= new DateTime(endCcrq.ToDate().Year, endCcrq.ToDate().Month, endCcrq.ToDate().Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.th), p => p.Th.Contains(input.th))
.Select(it=> new ZlglListOutput
{
id = it.Id,
zlm=it.Zlm,
sbbh=it.Sbbh,
gg=it.Gg,
fl=it.Fl,
fl1 = SqlFunc.Subqueryable().Where(x => x.Id == it.Fl).Select(x => x.FullName),
fbsj=it.Fbsj,
bh=it.Bh,
ccbh=it.Ccbh,
ccrq=it.Ccrq,
th=it.Th,
fj1 = it.Fj1,
fj2 = it.Fj2,
jszl = it.Jszl,
zlzl = it.Zlzl,
qtzl = it.Qtzl,
xctp = it.Xctp,
sbwhry = it.Sbwhry
}).MergeTable().OrderBy(sidx+" "+input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
return PageResult.SqlSugarPageResult(data);
}
///
/// 新建资料管理
///
/// 参数
///
[HttpPost("")]
public async Task Create([FromBody] ZlglCrInput input)
{
var userInfo = await _userManager.GetUserInfo();
var entity = input.Adapt();
entity.Id = YitIdHelper.NextId().ToString();
var isOk = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000);
}
///
/// 更新资料管理
///
/// 主键
/// 参数
///
[HttpPut("{id}")]
public async Task Update(string id, [FromBody] ZlglUpInput input)
{
var entity = input.Adapt();
entity.Id = id; // 确保设置主键
// 显式指定要更新的列,确保 sbwhry 字段被更新(包括 null 值也要更新)
var isOk = await _db.Updateable(entity)
.Where(it => it.Id == id)
.UpdateColumns(it => new {
it.Zlm, it.Sbbh, it.Gg, it.Fl, it.Fbsj, it.Bh, it.Ccbh, it.Ccrq,
it.Sbjs, it.Fj1, it.Fj2, it.Jszl, it.Zlzl, it.Qtzl, it.Xctp, it.Th, it.Sbwhry
})
.ExecuteCommandAsync();
if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1001);
}
///
/// 删除资料管理
///
///
[HttpDelete("{id}")]
public async Task Delete(string id)
{
var entity = await _db.Queryable().FirstAsync(p => p.Id == id);
_ = entity ?? throw NCCException.Oh(ErrorCode.COM1005);
var isOk = await _db.Deleteable().Where(d => d.Id == id).ExecuteCommandAsync();
if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1002);
}
///
/// 根据关键词模糊搜索资料管理(分页)
///
///
/// 根据关键词在所有字段中进行模糊匹配搜索,支持搜索的字段包括:编号、资料名、设备编号、规格、编号、出厂编号、图号、设备维护人员、分类
///
/// 搜索关键词,将在所有字符串字段中进行模糊匹配
/// 当前页码,默认值为1
/// 每页数量,默认值为20
/// 返回分页的资料管理列表
[HttpGet("Actions/SearchByKeyword")]
public async Task SearchByKeyword([FromQuery] string keyword, [FromQuery] int currentPage = 1, [FromQuery] int pageSize = 20)
{
if (string.IsNullOrEmpty(keyword))
{
return PageResult.SqlSugarPageResult(new SqlSugarPagedList
{
list = new List(),
pagination = new PagedModel
{
PageIndex = currentPage,
PageSize = pageSize,
Total = 0
}
});
}
var data = await _db.Queryable()
.Where(p => p.Id.Contains(keyword)
|| (p.Zlm != null && p.Zlm.Contains(keyword))
|| (p.Sbbh != null && p.Sbbh.Contains(keyword))
|| (p.Gg != null && p.Gg.Contains(keyword))
|| (p.Bh != null && p.Bh.Contains(keyword))
|| (p.Ccbh != null && p.Ccbh.Contains(keyword))
|| (p.Th != null && p.Th.Contains(keyword))
|| (p.Sbwhry != null && p.Sbwhry.Contains(keyword))
|| (p.Fl != null && p.Fl.Contains(keyword)))
.Select(it => new ZlglListOutput
{
id = it.Id,
zlm = it.Zlm,
sbbh = it.Sbbh,
gg = it.Gg,
fl = it.Fl,
fl1 = SqlFunc.Subqueryable().Where(x => x.Id == it.Fl).Select(x => x.FullName),
fbsj = it.Fbsj,
bh = it.Bh,
ccbh = it.Ccbh,
ccrq = it.Ccrq,
th = it.Th,
jszl = it.Jszl,
zlzl = it.Zlzl,
qtzl = it.Qtzl,
xctp = it.Xctp,
sbwhry = it.Sbwhry
}).MergeTable().OrderBy("id desc").ToPagedListAsync(currentPage, pageSize);
return PageResult.SqlSugarPageResult(data);
}
///
/// 根据关键词模糊搜索资料管理(不分页)
///
///
/// 根据关键词在所有字段中进行模糊匹配搜索,支持搜索的字段包括:编号、资料名、设备编号、规格、编号、出厂编号、图号、设备维护人员、分类
///
/// 搜索关键词,将在所有字符串字段中进行模糊匹配
/// 返回所有匹配的资料管理列表(不分页)
[HttpGet("Actions/SearchByKeywordNoPaging")]
public async Task SearchByKeywordNoPaging([FromQuery] string keyword)
{
if (string.IsNullOrEmpty(keyword))
{
return new List();
}
var data = await _db.Queryable()
.Where(p => p.Id.Contains(keyword)
|| (p.Zlm != null && p.Zlm.Contains(keyword))
|| (p.Sbbh != null && p.Sbbh.Contains(keyword))
|| (p.Gg != null && p.Gg.Contains(keyword))
|| (p.Bh != null && p.Bh.Contains(keyword))
|| (p.Ccbh != null && p.Ccbh.Contains(keyword))
|| (p.Th != null && p.Th.Contains(keyword))
|| (p.Sbwhry != null && p.Sbwhry.Contains(keyword))
|| (p.Fl != null && p.Fl.Contains(keyword)))
.Select(it => new ZlglListOutput
{
id = it.Id,
zlm = it.Zlm,
sbbh = it.Sbbh,
gg = it.Gg,
fl = it.Fl,
fl1 = SqlFunc.Subqueryable().Where(x => x.Id == it.Fl).Select(x => x.FullName),
fbsj = it.Fbsj,
bh = it.Bh,
ccbh = it.Ccbh,
ccrq = it.Ccrq,
th = it.Th,
jszl = it.Jszl,
zlzl = it.Zlzl,
qtzl = it.Qtzl,
xctp = it.Xctp,
sbwhry = it.Sbwhry
}).MergeTable().OrderBy("id desc").ToListAsync();
return data;
}
///
/// 资料管理简单搜索(仅匹配资料名称、资产编码、所属设备、关联产品)
///
/// 请求参数
///
[HttpGet("SimpleSearch")]
public async Task GetSimpleSearchList([FromQuery] ZlglSimpleSearchInput input)
{
var sidx = input.sidx == null ? "id" : input.sidx;
var query = _db.Queryable();
// 只有当searchKey不为空时才应用搜索条件
if (!string.IsNullOrEmpty(input.searchKey))
{
var searchKey = input.searchKey.Trim();
// 使用 EXISTS 子查询来匹配关联产品名称,避免先查询所有产品ID
// 注意:参数名必须与 Select 中的参数名一致,都使用 it
query = query.Where(it =>
(it.Zlm != null && it.Zlm.Contains(searchKey)) ||
(it.Sbbh != null && it.Sbbh.Contains(searchKey)) || // 资产编码
(it.Sbjs != null && it.Sbjs.Contains(searchKey)) ||
SqlFunc.Subqueryable().Where(x => x.Id == it.Fl && x.Cpmc != null && x.Cpmc.Contains(searchKey)).Any());
}
// 关联产品筛选
if (!string.IsNullOrEmpty(input.fl))
{
query = query.Where(it => it.Fl.Equals(input.fl));
}
// 客户权限:仅显示该客户在“我的设备”中已有设备关联产品的资料(传入 sskhbh 时生效;管理员不传则看全部)
// 使用与 KhsbPermissionHelper 一致的 sskhbh 扩展逻辑:当前用户可看 [userId, 所属组织, 上级组织] 下的设备
if (!string.IsNullOrEmpty(input.sskhbh))
{
var allowedSskhbhIds = await KhsbPermissionHelper.GetUserAllowedSskhbhIdsAsync(_userManager, _db);
if (allowedSskhbhIds == null)
{
// 管理员:不限制客户
}
else if (allowedSskhbhIds.Count == 0)
{
query = query.Where(it => false);
}
else
{
// 获取该用户可查看的设备所关联的产品ID:优先 Khsb.Fl,其次通过 Khsb.Dysbbh=cpgl.Cpid 关联
var productIdsFromFl = await _db.Queryable()
.Where(k => k.Sskhbh != null && allowedSskhbhIds.Contains(k.Sskhbh))
.Where(k => k.Fl != null && k.Fl != "")
.Select(k => k.Fl)
.Distinct()
.ToListAsync();
var productIdsFromDysbbh = await _db.Queryable()
.InnerJoin((k, c) => k.Dysbbh != null && k.Dysbbh != "" && k.Dysbbh == c.Cpid)
.Where((k, c) => k.Sskhbh != null && allowedSskhbhIds.Contains(k.Sskhbh))
.Select((k, c) => c.Id)
.Distinct()
.ToListAsync();
var allowedProductIds = (productIdsFromFl ?? new List())
.Union(productIdsFromDysbbh ?? new List())
.Distinct()
.ToList();
if (allowedProductIds == null || allowedProductIds.Count == 0)
query = query.Where(it => false);
else
query = query.Where(it => it.Fl != null && allowedProductIds.Contains(it.Fl));
}
}
var data = await query
.Select(it => new ZlglListOutput
{
id = it.Id,
zlm = it.Zlm,
sbbh = it.Sbbh,
gg = it.Gg,
fl = it.Fl,
fl1 = SqlFunc.Subqueryable().Where(x => x.Id == it.Fl).Select(x => x.Cpmc), // 关联产品名称
fbsj = it.Fbsj,
bh = it.Bh,
ccbh = it.Ccbh,
ccrq = it.Ccrq,
th = it.Th,
jszl = it.Jszl,
zlzl = it.Zlzl,
qtzl = it.Qtzl,
xctp = it.Xctp,
sbwhry = it.Sbwhry
}).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
return PageResult.SqlSugarPageResult(data);
}
#region 导入导出与模板
///
/// 获取资料管理列表(不分页,用于导出)
///
[HttpGet("GetNoPagingList")]
public async Task> GetNoPagingList([FromQuery] ZlglListQueryInput input)
{
var sidx = input.sidx == null ? "id" : input.sidx;
List queryFbsj = input.fbsj != null ? input.fbsj.Split(',').ToObeject>() : null;
DateTime? startFbsj = queryFbsj != null ? Ext.GetDateTime(queryFbsj.First()) : null;
DateTime? endFbsj = queryFbsj != null ? Ext.GetDateTime(queryFbsj.Last()) : null;
List queryCcrq = input.ccrq != null ? input.ccrq.Split(',').ToObeject>() : null;
DateTime? startCcrq = queryCcrq != null ? Ext.GetDateTime(queryCcrq.First()) : null;
DateTime? endCcrq = queryCcrq != null ? Ext.GetDateTime(queryCcrq.Last()) : null;
var data = await _db.Queryable()
.WhereIF(!string.IsNullOrEmpty(input.zlm), p => p.Zlm.Contains(input.zlm))
.WhereIF(!string.IsNullOrEmpty(input.sbbh), p => p.Sbbh.Contains(input.sbbh))
.WhereIF(!string.IsNullOrEmpty(input.gg), p => p.Gg.Contains(input.gg))
.WhereIF(!string.IsNullOrEmpty(input.fl), p => p.Fl.Equals(input.fl))
.WhereIF(queryFbsj != null, p => p.Fbsj >= new DateTime(startFbsj.ToDate().Year, startFbsj.ToDate().Month, startFbsj.ToDate().Day, 0, 0, 0))
.WhereIF(queryFbsj != null, p => p.Fbsj <= new DateTime(endFbsj.ToDate().Year, endFbsj.ToDate().Month, endFbsj.ToDate().Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.bh), p => p.Bh.Contains(input.bh))
.WhereIF(!string.IsNullOrEmpty(input.ccbh), p => p.Ccbh.Contains(input.ccbh))
.WhereIF(queryCcrq != null, p => p.Ccrq >= new DateTime(startCcrq.ToDate().Year, startCcrq.ToDate().Month, startCcrq.ToDate().Day, 0, 0, 0))
.WhereIF(queryCcrq != null, p => p.Ccrq <= new DateTime(endCcrq.ToDate().Year, endCcrq.ToDate().Month, endCcrq.ToDate().Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.th), p => p.Th.Contains(input.th))
.Select(it => new ZlglListOutput
{
id = it.Id,
zlm = it.Zlm,
sbbh = it.Sbbh,
gg = it.Gg,
fl = it.Fl,
fbsj = it.Fbsj,
bh = it.Bh,
ccbh = it.Ccbh,
ccrq = it.Ccrq,
th = it.Th,
fj1 = it.Fj1,
fj2 = it.Fj2,
jszl = it.Jszl,
zlzl = it.Zlzl,
qtzl = it.Qtzl,
xctp = it.Xctp,
sbwhry = it.Sbwhry
}).MergeTable().OrderBy(sidx + " " + input.sort).ToListAsync();
return data;
}
///
/// 导出资料管理(传 ids 按 id 导出,否则按当前查询条件导出;关联产品解析为产品名称)
///
[HttpGet("Actions/Export")]
public async Task Export([FromQuery] ZlglListQueryInput input)
{
var exportData = new List();
if (!string.IsNullOrEmpty(input.ids))
{
var idList = input.ids.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)).ToList();
if (idList.Count > 0)
{
var list = await _db.Queryable()
.Where(p => idList.Contains(p.Id))
.Select(it => new ZlglListOutput
{
id = it.Id,
zlm = it.Zlm,
sbbh = it.Sbbh,
gg = it.Gg,
fl = it.Fl,
fbsj = it.Fbsj,
bh = it.Bh,
ccbh = it.Ccbh,
ccrq = it.Ccrq,
th = it.Th,
fj1 = it.Fj1,
fj2 = it.Fj2,
jszl = it.Jszl,
zlzl = it.Zlzl,
qtzl = it.Qtzl,
xctp = it.Xctp,
sbwhry = it.Sbwhry
}).ToListAsync();
exportData = list;
}
}
else
{
exportData = await GetNoPagingList(input);
}
// 关联产品 fl 解析为产品名称(cpgl.Cpmc)
var flIds = exportData.Where(x => !string.IsNullOrEmpty(x.fl)).Select(x => x.fl).Distinct().ToList();
var cpglDict = flIds.Count > 0
? (await _db.Queryable().Where(c => flIds.Contains(c.Id)).Select(c => new { c.Id, c.Cpmc }).ToListAsync()).ToDictionary(c => c.Id, c => c.Cpmc ?? "")
: new Dictionary();
// 设备维护人员 sbwhry 为逗号分隔的 ID,导出时解析为姓名,多人用分号隔开
var sbwhryIds = new List();
foreach (var row in exportData)
{
if (!string.IsNullOrEmpty(row.sbwhry))
sbwhryIds.AddRange(row.sbwhry.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)));
}
sbwhryIds = sbwhryIds.Distinct().ToList();
var sbwhryDict = sbwhryIds.Count > 0
? (await _db.Queryable().Where(s => sbwhryIds.Contains(s.Id)).Select(s => new { s.Id, s.Xm }).ToListAsync()).ToDictionary(s => s.Id, s => s.Xm ?? "")
: new Dictionary();
foreach (var row in exportData)
{
if (!string.IsNullOrEmpty(row.fl) && cpglDict.TryGetValue(row.fl, out var cpmc))
row.fl1 = cpmc;
if (!string.IsNullOrEmpty(row.sbwhry))
{
var names = row.sbwhry.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(id => id.Trim())
.Where(id => !string.IsNullOrEmpty(id))
.Select(id => sbwhryDict.TryGetValue(id, out var xm) ? xm : id)
.Where(n => !string.IsNullOrEmpty(n));
row.sbwhry = string.Join(";", names);
}
}
var excelconfig = new ExcelConfig
{
FileName = "资料管理.xls",
HeadFont = "微软雅黑",
HeadPoint = 10,
IsAllSizeColumn = true,
ColumnModel = new List
{
new ExcelColumnModel { Column = "id", ExcelColumn = "id" },
new ExcelColumnModel { Column = "zlm", ExcelColumn = "资料名称" },
new ExcelColumnModel { Column = "sbbh", ExcelColumn = "设备编号" },
new ExcelColumnModel { Column = "gg", ExcelColumn = "规格" },
new ExcelColumnModel { Column = "fl1", ExcelColumn = "关联产品" },
new ExcelColumnModel { Column = "fbsj", ExcelColumn = "发布时间" },
new ExcelColumnModel { Column = "bh", ExcelColumn = "编号" },
new ExcelColumnModel { Column = "ccbh", ExcelColumn = "出厂编号" },
new ExcelColumnModel { Column = "ccrq", ExcelColumn = "出厂日期" },
new ExcelColumnModel { Column = "th", ExcelColumn = "设备图号" },
new ExcelColumnModel { Column = "sbwhry", ExcelColumn = "设备维护人员" }
}
};
var addPath = FileVariable.TemporaryFilePath + excelconfig.FileName;
ExcelExportHelper.Export(exportData, excelconfig, addPath);
var fileName = _userManager.UserId + "|" + addPath + "|xls";
return new { name = excelconfig.FileName, url = "/api/File/Download?encryption=" + DESCEncryption.Encrypt(fileName, "NCC") };
}
///
/// 模板下载(关联产品来自 cpgl:选产品编号后关联产品名称列公式带出)
///
[HttpGet("TemplateDownload")]
public async Task TemplateDownload()
{
var user = await _userManager.GetUserInfo();
string userId = user.userId;
string name = "资料管理导入模板.xlsx";
string addFilePath = FileVariable.TemporaryFilePath + name;
var fileds = GetFiledMaps();
var headersToWrite = new List();
int 关联产品ColIndex = -1, 关联产品名称ColIndex = -1;
int colIndex = 0;
foreach (var kv in fileds)
{
headersToWrite.Add(kv.Key);
if (kv.Value == "fl") 关联产品ColIndex = colIndex;
else if (kv.Value == "fl1") 关联产品名称ColIndex = colIndex;
colIndex++;
}
var cpglList = await _db.Queryable()
.Where(c => c.Cpid != null && c.Cpid != "")
.Select(c => new { c.Cpid, c.Cpmc })
.ToListAsync();
var cpidList = cpglList.Select(c => (c.Cpid ?? "").Trim()).Where(s => !string.IsNullOrEmpty(s)).ToList();
const int maxListLen = 250;
var cpidDropdown = new List();
var len = 0;
foreach (var s in cpidList)
{
if (len + (len > 0 ? 1 : 0) + s.Length > maxListLen) break;
len += (len > 0 ? 1 : 0) + s.Length;
cpidDropdown.Add(s);
}
var workbook = new XSSFWorkbook();
try
{
const string cpglSheetName = "ZlglCpgl";
var sheet = workbook.CreateSheet("sheet1");
var headerRow = sheet.CreateRow(0);
for (int i = 0; i < headersToWrite.Count; i++)
headerRow.CreateCell(i).SetCellValue(headersToWrite[i]);
if (关联产品ColIndex >= 0 && cpidDropdown.Count > 0)
{
var helper = sheet.GetDataValidationHelper();
var constraint = helper.CreateExplicitListConstraint(cpidDropdown.ToArray());
var range = new CellRangeAddressList(1, 9999, 关联产品ColIndex, 关联产品ColIndex);
var validation = helper.CreateValidation(constraint, range);
validation.SuppressDropDownArrow = false;
validation.ShowPromptBox = true;
validation.EmptyCellAllowed = true;
sheet.AddValidationData(validation);
}
if (关联产品名称ColIndex >= 0 && 关联产品ColIndex >= 0)
{
string idColLetter = ColIndexToLetter(关联产品ColIndex);
for (int r = 1; r <= 500; r++)
{
int excelRow = r + 1;
var row = sheet.CreateRow(r);
for (int c = 0; c < headersToWrite.Count; c++)
row.CreateCell(c);
var nameCell = row.GetCell(关联产品名称ColIndex);
nameCell.SetCellFormula($"IF({idColLetter}{excelRow}=\"\",\"\",VLOOKUP({idColLetter}{excelRow},{cpglSheetName}!A:B,2,0))");
}
}
var cpglSheet = workbook.CreateSheet(cpglSheetName);
cpglSheet.CreateRow(0).CreateCell(0).SetCellValue("关联产品");
cpglSheet.GetRow(0).CreateCell(1).SetCellValue("关联产品名称");
for (int i = 0; i < cpglList.Count; i++)
{
var prow = cpglSheet.CreateRow(i + 1);
prow.CreateCell(0).SetCellValue(cpglList[i].Cpid ?? "");
prow.CreateCell(1).SetCellValue(cpglList[i].Cpmc ?? "");
}
using (var fs = new FileStream(addFilePath, FileMode.Create, FileAccess.Write))
workbook.Write(fs);
}
finally
{
workbook?.Close();
}
return new { name = name, url = "/api/File/Download?encryption=" + DESCEncryption.Encrypt(userId + "|" + name, "NCC") };
}
///
/// 导入预览
///
[HttpGet("ImportPreview")]
public dynamic ImportPreview(string fileName, string orgId = "")
{
return new
{
dataRow = ExcelImportHelper.ImportPreview(fileName, GetFiledMaps(orgId)),
fileds = GetFiledMaps(orgId)
};
}
///
/// 模板/导入字段映射(模板不含 id,导出列单独配置且含 id)
///
public Dictionary GetFiledMaps(string orgId = "")
{
var fileds = new Dictionary
{
{ "资料名称", "zlm" },
{ "设备编号", "sbbh" },
{ "规格", "gg" },
{ "关联产品", "fl" },
{ "关联产品名称", "fl1" },
{ "发布时间", "fbsj" },
{ "编号", "bh" },
{ "出厂编号", "ccbh" },
{ "出厂日期", "ccrq" },
{ "设备图号", "th" },
{ "设备维护人员", "sbwhry" }
};
return fileds;
}
///
/// 导入数据
///
[HttpPost("ImportData")]
public async Task ImportData([FromBody] ImportDataDto input)
{
var user = new UserInfo();
await Scoped.Create(async (_, scope) =>
{
var services = scope.ServiceProvider;
var _userManager = App.GetService(services);
user = await _userManager.GetUserInfo();
});
var output = new ImportDataOutput();
foreach (var item in input.list)
{
try
{
var obj = item.ToJson().ToJToken();
var settings = new JsonSerializerSettings { DateFormatString = "yyyy-MM-dd HH:mm:ss" };
ZlglEntity entity;
try
{
entity = obj.ToObject();
}
catch
{
entity = JsonConvert.DeserializeObject(obj.ToJson().ReplaceRegex("日", "日 ").ReplaceRegex("点", ":").ReplaceRegex("分", ":00"), settings);
}
// 关联产品:Excel 填产品编号 cpid,解析为 cpgl.Id 存 fl
var 关联产品Str = (obj["关联产品"] ?? obj["fl"])?.ToString()?.Trim();
if (关联产品Str.IsNotEmptyOrNull())
{
var cp = (await _db.Queryable().Where(c => c.Cpid == 关联产品Str).ToListAsync()).FirstOrDefault();
if (cp == null)
{
AddFailWithError(output, item, "关联产品", "未找到该产品编号,请从下拉选择");
output.fnum++;
continue;
}
entity.Fl = cp.Id;
}
// 设备维护人员:Excel 填 张三 或 张三;李四,按姓名查 sbwhry 表得到 Id,逗号分隔保存
var 人员Str = (obj["设备维护人员"] ?? obj["sbwhry"])?.ToString()?.Trim();
if (人员Str.IsNotEmptyOrNull())
{
var names = 人员Str.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(n => n.Trim()).Where(n => !string.IsNullOrEmpty(n)).ToList();
var ids = new List();
bool 人员解析失败 = false;
foreach (var name in names)
{
var sb = (await _db.Queryable().Where(s => s.Xm == name).ToListAsync()).FirstOrDefault();
if (sb == null)
{
AddFailWithError(output, item, "设备维护人员", "未找到人员:" + name);
output.fnum++;
人员解析失败 = true;
break;
}
ids.Add(sb.Id);
}
if (人员解析失败) continue;
entity.Sbwhry = string.Join(",", ids);
}
entity.Id = YitIdHelper.NextId().ToString();
if (input.itemStr.IsNotEmptyOrNull() && entity.Fl.IsNullOrEmpty())
entity.Fl = input.itemStr;
var isOk = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
if (isOk < 1)
{
AddFailWithError(output, item, "数据", "新增失败");
output.fnum++;
}
else
output.snum++;
}
catch (Exception ex)
{
AddFailWithError(output, item, "数据", ex.Message);
output.fnum++;
}
}
// 与故障查询一致:resultType 0 表示全部成功,1 表示有失败(前端据此展示成功/失败块及失败列表)
if (output.snum == input.list.Count)
output.resultType = 0;
else
output.resultType = 1;
return output;
}
private static void AddFailWithError(ImportDataOutput output, object item, string errorField, string errorMessage)
{
try
{
var jobj = (item is JObject jo) ? jo : JObject.Parse(item.ToJson());
jobj["_errorField"] = errorField ?? "";
jobj["_errorMessage"] = errorMessage ?? "";
output.failResult.Add(jobj);
}
catch
{
output.failResult.Add(item);
}
}
private static string ColIndexToLetter(int colIndex)
{
int n = colIndex;
string result = "";
while (n >= 0)
{
result = (char)('A' + (n % 26)) + result;
n = n / 26 - 1;
}
return result;
}
#endregion
}
}