Commit 5debbd47 by ruyun.zhang@suvalue.com

Merge branch 'feature/writeexcel' into develop

# Conflicts:
#	performance/Performance.Api/Controllers/TemplateController.cs
parents bc4ceecc 017c70ef
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc;
......@@ -15,16 +15,19 @@ namespace Performance.Api.Controllers
[Route("api/[controller]")]
public class TemplateController : Controller
{
private TemplateService templateService;
private readonly TemplateService templateService;
private readonly ExtractService extractService;
private HospitalService hospitalService;
private IHostingEnvironment evn;
private ClaimService claim;
public TemplateController(TemplateService templateService,
HospitalService hospitalService,
ExtractService extractService,
IHostingEnvironment evn,
ClaimService claim)
{
this.templateService = templateService;
this.extractService = extractService;
this.hospitalService = hospitalService;
this.evn = evn;
this.claim = claim;
......@@ -54,7 +57,7 @@ public ApiResponse Import([FromForm] IFormCollection form)
var name = FileHelper.GetFileNameNoExtension(file.FileName) + DateTime.Now.ToString("yyyyMMddHHmmssfff");
var ext = FileHelper.GetExtension(file.FileName);
var dpath = Path.Combine(evn.ContentRootPath, "FirstFiles", $"{hospitalid}");
var dpath = Path.Combine(evn.ContentRootPath, "Files", $"{hospitalid}", "first");
FileHelper.CreateDirectory(dpath);
var path = Path.Combine(dpath, $"{name}{ext}");
......@@ -79,5 +82,18 @@ public ApiResponse Import([FromForm] IFormCollection form)
}
return new ApiResponse(ResponseType.OK);
}
/// <summary>
/// 提取绩效数据
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[Route("extractdata")]
[HttpPost]
public ApiResponse ExtractData([FromBody]ApiRequest request)
{
var filePath = extractService.ExtractData(24);
return new ApiResponse(ResponseType.OK, "OK", filePath);
}
}
}
\ No newline at end of file
......@@ -65,10 +65,17 @@ public AutoMapperConfigs()
CreateMap<PerHeader, im_header>()
.ForMember(dest => dest.IsMerge, opt => opt.MapFrom(src => src.IsMerge ? 1 : 2));
CreateMap<PerData, im_data>()
.ForMember(dest => dest.IsFactor, opt => opt.MapFrom(src => src.IsFactor ? 1 : 2))
.ForMember(dest => dest.UnitType, opt => opt.MapFrom(src => src.UnitType == "医生组" ? 1 : (src.UnitType == "护理组" ? 2 : 0)));
CreateMap<im_header, PerHeader>()
.ForMember(dest => dest.IsMerge, opt => opt.MapFrom(src => src.IsMerge == 1 ? true : false));
CreateMap<im_data, PerData>()
.ForMember(dest => dest.IsFactor, opt => opt.MapFrom(src => src.IsFactor == 1 ? true : false))
.ForMember(dest => dest.UnitType, opt => opt.MapFrom(src => src.UnitType == 1 ? "医生组" : (src.UnitType == 2 ? "护理组" : "")));
CreateMap<PerDataEmployee, im_employee>();
CreateMap<im_employee, PerDataEmployee>();
......
......@@ -39,7 +39,7 @@ public class sys_hospitalconfig
/// <summary>
///
/// </summary>
public Nullable<int> DbUser { get; set; }
public string DbUser { get; set; }
/// <summary>
///
......
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;
namespace Performance.Repository
{
/// <summary>
/// 创建连接
/// </summary>
public class ConnectionBuilder
{
/// <summary>
/// 创建连接
/// </summary>
/// <param name="type"></param>
/// <param name="connectionString"></param>
/// <returns></returns>
public static IDbConnection Create(DatabaseType type, string connectionString)
{
switch (type)
{
case DatabaseType.MySql:
return new MySqlConnection(connectionString);
case DatabaseType.SqlServer:
return new SqlConnection(connectionString);
default:
throw new Exception($"nonsupport {DatabaseType.MySql}");
}
}
/// <summary>
/// 创建连接字符串
/// </summary>
/// <param name="type"></param>
/// <param name="ip"></param>
/// <param name="database"></param>
/// <param name="uid"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public static string GetConnectionString(DatabaseType type, string ip, string database, string uid, string pwd)
{
string connectionString = "";
switch (type)
{
case DatabaseType.MySql:
connectionString = $"Server={ip};Database={database};Uid={uid};Pwd={pwd};connection timeout=12000;pooling=true;charset=utf8;Convert Zero Datetime=True;port=3306;Allow User Variables=True;;";
break;
case DatabaseType.SqlServer:
connectionString = $"data source={ip};initial catalog={database};user id={uid};password={pwd};connection timeout=12000;";
break;
default:
throw new Exception($"nonsupport {DatabaseType.MySql}");
}
return connectionString;
}
/// <summary>
/// 创建连接
/// </summary>
/// <param name="type"></param>
/// <param name="ip"></param>
/// <param name="database"></param>
/// <param name="uid"></param>
/// <param name="pwd"></param>
/// <returns></returns>
public static IDbConnection Create(DatabaseType type, string ip, string database, string uid, string pwd)
{
string connectionString = GetConnectionString(type, ip, database, uid, pwd);
return Create(type, connectionString);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Performance.Repository
{
public enum DatabaseType
{
MySql,
SqlServer
}
}
//-----------------------------------------------------------------------
// <copyright file=" sys_extract.cs">
// * FileName: sys_extract.cs
// </copyright>
//-----------------------------------------------------------------------
using Dapper;
using Performance.EntityModels;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
namespace Performance.Repository
{
/// <summary>
/// sys_extract Repository
/// </summary>
public partial class PerforExtractRepository : PerforRepository<sys_extract>
{
public List<CustomExecute> ExecuteScript(IDbConnection connection, string sql, string param)
{
List<CustomExecute> result = new List<CustomExecute>();
using (connection)
{
var dataReader = connection.ExecuteReader(sql, param);
int row = 0;
while (dataReader.Read())
{
for (int i = 0; i < dataReader.FieldCount; i++)
{
var fileName = dataReader.GetName(i);
var @object = dataReader[fileName];
result.Add(new CustomExecute { RowNumber = row, ColumnName = fileName, Value = @object });
}
row++;
}
}
return result;
}
}
public class CustomExecute
{
public int RowNumber { get; set; }
public string ColumnName { get; set; }
public object Value { get; set; }
}
}
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Options;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Performance.Services
{
/// <summary>
/// 数据抽取服务
/// </summary>
public class ExtractService : IAutoInjection
{
private readonly IHostingEnvironment environment;
private readonly PerSheetService perSheetService;
private readonly PerHeaderService perHeaderService;
private readonly PerforPersheetRepository perforPersheetRepository;
private readonly PerforImheaderRepository perforImheaderRepository;
private readonly PerforImemployeeRepository perforImemployeeRepository;
private readonly PerforExtractRepository perforExtractRepository;
private readonly PerforPerfirstRepository perforPerfirstRepository;
private readonly PerforPerallotRepository perforPerallotRepository;
private readonly PerforHospitalconfigRepository perforHospitalconfigRepository;
public ExtractService(IHostingEnvironment environment,
PerSheetService perSheetService,
PerHeaderService perHeaderService,
PerforPersheetRepository perforPersheetRepository,
PerforImheaderRepository perforImheaderRepository,
PerforImemployeeRepository perforImemployeeRepository,
PerforExtractRepository perforExtractRepository,
PerforPerfirstRepository perforPerfirstRepository,
PerforPerallotRepository perforPerallotRepository,
PerforHospitalconfigRepository perforHospitalconfigRepository)
{
this.environment = environment;
this.perSheetService = perSheetService;
this.perHeaderService = perHeaderService;
this.perforPersheetRepository = perforPersheetRepository;
this.perforImheaderRepository = perforImheaderRepository;
this.perforImemployeeRepository = perforImemployeeRepository;
this.perforExtractRepository = perforExtractRepository;
this.perforPerfirstRepository = perforPerfirstRepository;
this.perforPerallotRepository = perforPerallotRepository;
this.perforHospitalconfigRepository = perforHospitalconfigRepository;
}
public string ExtractData(int hospitalId)
{
List<PerSheet> sheetList = new List<PerSheet>();
var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospitalId);
var configList = perforHospitalconfigRepository.GetEntities(t => t.HospitalId == hospitalId);
var first = perforPerfirstRepository.GetEntity(t => t.HospitalId == hospitalId);
if (configList == null || !configList.Any())
throw new PerformanceException($"暂不支持自动提取绩效数据");
var hospitalConfig = configList.First();
string originalPath = "";
//判断是否是首次
if ((allotList == null || !allotList.Any()) && first != null)
{
//首次 从excel中获取人员信息,SHEET页信息,列头信息
sheetList = GetFileData(first.Path);
originalPath = first.Path;
}
else
{
//非首次 从数据库中获取人员信息,SHEET页信息,列头信息
var allot = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First();
sheetList = GetRepositoryData(allot.ID);
originalPath = allot.Path;
}
var dpath = Path.Combine(environment.ContentRootPath, "Files", $"{hospitalId}", "autoextract");
FileHelper.CreateDirectory(dpath);
string path = Path.Combine(dpath, $"绩效数据{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.xlsx");
//根据SHEET页信息,列头信息,创建EXCEL文件
if (WriteExcel(path, originalPath, sheetList, hospitalConfig, hospitalId))
return dpath;
throw new PerformanceException("绩效数据提取失败");
}
/// <summary>
/// 向EXCEL中写入数据
/// 人员信息由EXCEL中提供,或从上次绩效中提供
/// SHEET页在SQL提取中出现时,执行SQL脚本获得结果向EXCEL中填充
/// 向EXCEL中填充数据,填充时值与列头必须匹配
/// </summary>
/// <param name="newpath"></param>
/// <param name="originalPath"></param>
/// <param name="sheetList"></param>
/// <param name="hospitalConfig"></param>
/// <param name="hospitalId"></param>
private bool WriteExcel(string newpath, string originalPath, List<PerSheet> sheetList, sys_hospitalconfig hospitalConfig, int hospitalId)
{
if (string.IsNullOrEmpty(originalPath))
throw new PerformanceException($"{originalPath}文件路径无效");
var scriptList = perforExtractRepository.GetEntities(t => t.HospitalId == hospitalId);
var connection = ConnectionBuilder.Create(DatabaseType.SqlServer, hospitalConfig.DbSource, hospitalConfig.DbName, hospitalConfig.DbUser, hospitalConfig.DbPassword);
//根据SHEET页信息,列头信息,创建EXCEL文件
IWorkbook workbook = new XSSFWorkbook(originalPath);
foreach (var sheet in sheetList)
{
var importSheet = workbook.GetSheet(sheet.SheetName);
if (importSheet == null) continue;
//var importSheet = workbook.CreateSheet(sheet.SheetName);
//创建列头
//foreach (var pointRow in sheet.PerHeader.Select(t => t.PointRow).Distinct().OrderBy(t => t))
//{
// var importRow = importSheet.CreateRow(pointRow);
// //写入单元格
// foreach (var perHeader in sheet.PerHeader.Where(t => t.PointRow == pointRow))
// {
// importRow.CreateCell(perHeader.PointCell).SetCellValue(perHeader.CellValue);
// //设置合并单元格
// if (perHeader.IsMerge)
// {
// var cellRange = new CellRangeAddress(perHeader.PointRow, perHeader.PointRow + perHeader.MergeRow, perHeader.PointCell, perHeader.PointCell + perHeader.MergeCell);
// importSheet.AddMergedRegion(cellRange);
// }
// }
//}
var maxHeaderRowNumber = sheet.PerHeader.Max(t => t.PointRow);
//清空数据行
for (int i = maxHeaderRowNumber + 1; i < importSheet.LastRowNum + 1; i++)
{
var importRow = importSheet.GetRow(i);
if (importRow != null)
importSheet.RemoveRow(importRow);
}
//填充人员信息
if (SheetType.Employee == sheet.SheetType && sheet.PerData != null && sheet.PerData.Any())
{
var dataList = sheet.PerData.ConvertAll(new Converter<IPerData, PerDataEmployee>(t => (PerDataEmployee)t));
for (int i = 0; i < dataList.Count; i++)
{
var importRow = importSheet.CreateRow(maxHeaderRowNumber + i + 1);
Dictionary<string, Func<PerDataEmployee, object>> keyValues = new Dictionary<string, Func<PerDataEmployee, object>>
{
{ "核算单元", (t) => t.AccountingUnit },
{ "医生姓名", (t) => t.DoctorName },
{ "职称", (t) => t.JobTitle },
{ "绩效基数核算参考对象", (t) => t.FitPeople },
{ "核算单元分类", (t) => t.AccountType },
{ "岗位系数", (t) => t.PostCoefficient },
{ "参加工作时间", (t) => t.WorkTime },
{ "考核得分率", (t) => t.ScoreAverageRate },
{ "出勤率", (t) => t.Attendance },
{ "核算单元医生数", (t) => t.PeopleNumber },
{ "工作量绩效", (t) => t.Workload },
{ "其他绩效", (t) => t.OthePerfor },
{ "医院奖罚", (t) => t.Punishment },
{ "调节系数", (t) => t.Adjust },
{ "发放系数", (t) => t.Grant },
};
foreach (var item in keyValues.Keys)
{
var headInfo = sheet.PerHeader.FirstOrDefault(t => t.CellValue == item);
if (headInfo != null)
{
var value = (keyValues[item].Invoke(dataList[i]) ?? "").ToString();
importRow.CreateCell(headInfo.PointCell).SetCellValue(value);
}
}
}
}
//SHEET页在SQL提取中出现时,执行SQL脚本获得结果向EXCEL中填充
else if (scriptList.Any(t => sheet.SheetName.Contains(t.SheetName)))
{
var script = scriptList.First(t => sheet.SheetName.Contains(t.SheetName));
if (!string.IsNullOrEmpty(script.ExecuteScript))
{
var dataList = perforExtractRepository.ExecuteScript(connection, script.ExecuteScript, null);
//创建数据行
foreach (var pointRow in dataList.Select(t => t.RowNumber).Distinct().OrderBy(t => t))
{
var importRow = importSheet.CreateRow(maxHeaderRowNumber + pointRow + 1);
//写入单元格
foreach (var data in dataList.Where(t => t.RowNumber == pointRow))
{
var headInfo = sheet.PerHeader.FirstOrDefault(t => t.CellValue == data.ColumnName);
if (headInfo != null)
{
importRow.CreateCell(headInfo.PointCell).SetCellValue(data.Value.ToString());
}
}
}
}
}
}
using (FileStream file = new FileStream(newpath, FileMode.Create))
workbook.Write(file);
return true;
}
/// <summary>
/// 从数据库中获取sheet及列头
/// </summary>
/// <param name="allotId"></param>
/// <returns></returns>
private List<PerSheet> GetRepositoryData(int allotId)
{
List<PerSheet> sheetList = new List<PerSheet>();
//获取最近一次绩效
var perSheetList = perforPersheetRepository.GetEntities(t => t.AllotID == allotId);
foreach (var sheet in perSheetList)
{
PerSheet perSheet = new PerSheet()
{
SheetName = sheet.SheetName,
SheetType = (SheetType)sheet.SheetType,
ModuleName = EnumHelper.GetDescription((SheetType)sheet.SheetType),
};
var perHeadList = perforImheaderRepository.GetEntities(t => t.SheetID == sheet.ID);
perSheet.PerHeader = AutoMapper.Mapper.Map<List<PerHeader>>(perHeadList);
if (SheetType.Employee == (SheetType)sheet.SheetType)
{
var employeeList = perforImemployeeRepository.GetEntities(t => t.AllotID == sheet.ID);
var perEmployeeList = AutoMapper.Mapper.Map<List<PerDataEmployee>>(employeeList);
perSheet.PerData = perEmployeeList.ConvertAll(new Converter<PerDataEmployee, IPerData>(m => m));
}
sheetList.Add(perSheet);
}
return sheetList;
}
/// <summary>
/// 获取sheet及列头
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private List<PerSheet> GetFileData(string path)
{
if (!FileHelper.IsExistFile(path))
throw new PerformanceException($"{path}文件不存在");
List<PerSheet> sheetList = new List<PerSheet>();
using (FileStream fs = new FileStream(path, FileMode.Open))
{
var version = FileHelper.GetExtension(path) == ".xlsx" ? ExcelVersion.xlsx : ExcelVersion.xls;
IWorkbook workbook = (version == ExcelVersion.xlsx) ? (IWorkbook)(new XSSFWorkbook(fs)) : (IWorkbook)(new HSSFWorkbook(fs));
for (int i = 0; i < workbook.NumberOfSheets; i++)
{
var sheet = workbook.GetSheetAt(i);
var sheetType = perSheetService.GetSheetType(sheet.SheetName);
if (SheetType.Unidentifiable != sheetType)
{
var sheetRead = PerSheetDataFactory.GetDataRead(sheetType);
var perHeader = perHeaderService.GetPerHeader(sheet, sheetRead.Point);
PerSheet perSheet = new PerSheet()
{
SheetName = sheet.SheetName,
SheetType = sheetType,
ModuleName = EnumHelper.GetDescription(sheetType),
PerHeader = perHeader
};
if (SheetType.Employee == sheetType)
{
var headerReverse = perHeaderService.GetPerHeaderReverse(perHeader);
perSheet.PerData = sheetRead.ReadData(sheet, headerReverse);
}
sheetList.Add(perSheet);
}
}
}
return sheetList;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment