.NETAdmin/ZR.Admin.WebApi/Controllers/CommonController.cs
2025-08-21 19:48:25 +08:00

739 lines
29 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using MiniExcelLibs;
using ZR.Infrastructure.IPTools;
using ZR.Model.Business.Dto;
using ZR.Model.Business;
using ZR.Model.Dto;
using ZR.Model.System;
using ZR.ServiceCore.Resources;
using ZR.Service.Business.IBusinessService;
using ZR.Service.Business;
using System.Threading.Tasks;
using static SKIT.FlurlHttpClient.Wechat.Api.Models.CgibinExpressIntracityUpdateStoreRequest.Types;
using Aliyun.OSS.Model;
using System.IO.Compression;
using IOFile = System.IO.File;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp;
namespace ZR.Admin.WebApi.Controllers
{
/// <summary>
/// 公共模块
/// </summary>
[Route("[controller]/[action]")]
[ApiExplorerSettings(GroupName = "sys")]
public class CommonController : BaseController
{
private OptionsSetting OptionsSetting;
private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private IWebHostEnvironment WebHostEnvironment;
private ISysFileService SysFileService;
private readonly IStringLocalizer<SharedResource> _localizer;
public readonly ISysDeptService _deptService;
public readonly ISysDictDataService sysDictDataService;
/// <summary>
/// 工作记录接口
/// </summary>
private readonly ICamWorkrecordService _CamWorkrecordService;
/// <summary>
/// 工作人员记录接口
/// </summary>
private readonly ICamWorkerService _CamWorkerService;
/// <summary>
/// CommonController 构造函数
/// </summary>
/// <param name="stringLocalizer"></param>
/// <param name="options"></param>
/// <param name="webHostEnvironment"></param>
/// <param name="fileService"></param>
/// <param name="deptService"></param>
public CommonController(
IStringLocalizer<SharedResource> stringLocalizer,
IOptions<OptionsSetting> options,
IWebHostEnvironment webHostEnvironment,
ISysFileService fileService,
ISysDeptService deptService,
ISysDictDataService sysDictDataService,
ICamWorkrecordService _CamWorkrecordService,
ICamWorkerService camWorkerService)
{
WebHostEnvironment = webHostEnvironment;
SysFileService = fileService;
OptionsSetting = options.Value;
_localizer = stringLocalizer;
_deptService = deptService;
this.sysDictDataService = sysDictDataService;
this._CamWorkrecordService = _CamWorkrecordService;
_CamWorkerService = camWorkerService;
}
/// <summary>
/// home
/// </summary>
/// <returns></returns>
[Route("/")]
[HttpGet]
[AllowAnonymous]
public IActionResult Index()
{
var hello = _localizer["hello"].Value;
return Ok($"请求成功!=>" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
/// <summary>
/// 查询IP信息
/// </summary>
/// <returns></returns>
[Route("/ip")]
[HttpGet]
[AllowAnonymous]
public IActionResult IPInfo(string ip)
{
if (ip.IsEmpty()) return ToResponse(ResultCode.CUSTOM_ERROR, "IP异常");
var region = IpTool.GetRegion(ip);
return SUCCESS(region);
}
/// <summary>
/// 企业消息测试
/// </summary>
/// <param name="msg">要发送的消息</param>
/// <param name="toUser">要发送的人@all所有xxx单独发送对个人</param>
/// <returns></returns>
[Route("/sendMsg")]
[HttpGet]
[Log(Title = "企业消息测试")]
public IActionResult SendMsg(string msg, string toUser = "")
{
WxNoticeHelper.SendMsg("消息测试", msg, toUser, WxNoticeHelper.MsgType.markdown);
return SUCCESS(msg);
}
#region
/// <summary>
/// 存储文件
/// </summary>
/// <param name="uploadDto">自定义文件名</param>
/// <param name="file"></param>
/// <param name="storeType">上传类型1、保存到本地 2、保存到阿里云</param>
/// <returns></returns>
[HttpPost]
[ActionPermissionFilter(Permission = "common")]
public async Task<IActionResult> UploadFile([FromForm] UploadDto uploadDto, IFormFile file, StoreType storeType = StoreType.LOCAL)
{
if (file == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空");
SysFile sysfile = new();
IFormFile formFile = file;
string fileExt = Path.GetExtension(formFile.FileName);//文件后缀
double fileSize = Math.Round(formFile.Length / 1024.0, 2);//文件大小KB
if (OptionsSetting.Upload.NotAllowedExt.Contains(fileExt))
{
return ToResponse(ResultCode.CUSTOM_ERROR, "上传失败,未经允许上传类型");
}
if (uploadDto.FileNameType == 1)
{
uploadDto.FileName = Path.GetFileNameWithoutExtension(formFile.FileName);
}
else if (uploadDto.FileNameType == 3)
{
uploadDto.FileName = SysFileService.HashFileName();
}
switch (storeType)
{
case StoreType.LOCAL:
string savePath = Path.Combine(WebHostEnvironment.WebRootPath);
if (uploadDto.FileDir.IsEmpty())
{
uploadDto.FileDir = OptionsSetting.Upload.LocalSavePath;
}
sysfile = await SysFileService.SaveFileToLocal(savePath, uploadDto, HttpContext.GetName(), formFile);
break;
case StoreType.REMOTE:
break;
case StoreType.ALIYUN:
int AlimaxContentLength = OptionsSetting.ALIYUN_OSS.MaxSize;
if (OptionsSetting.ALIYUN_OSS.REGIONID.IsEmpty())
{
return ToResponse(ResultCode.CUSTOM_ERROR, "配置文件缺失");
}
if ((fileSize / 1024) > AlimaxContentLength)
{
return ToResponse(ResultCode.CUSTOM_ERROR, "上传文件过大,不能超过 " + AlimaxContentLength + " MB");
}
sysfile = new(formFile.FileName, uploadDto.FileName, fileExt, fileSize + "kb", uploadDto.FileDir, HttpContext.GetName())
{
StoreType = (int)StoreType.ALIYUN,
FileType = formFile.ContentType,
ClassifyType = uploadDto.ClassifyType,
CategoryId = uploadDto.CategoryId,
};
sysfile = await SysFileService.SaveFileToAliyun(sysfile, uploadDto, formFile);
if (sysfile.Id <= 0) { return ToResponse(ApiResult.Error("阿里云连接失败")); }
break;
case StoreType.TENCENT:
break;
case StoreType.QINIU:
break;
default:
break;
}
return SUCCESS(new
{
url = sysfile.AccessUrl,
fileName = sysfile.FileName,
fileId = sysfile.Id.ToString()
});
}
#endregion
/// <summary>
/// 下载文件
/// </summary>
/// <param name="path"></param>
/// <param name="fileId"></param>
/// <returns></returns>
[HttpGet]
[ActionPermissionFilter(Permission = "common")]
[Log(Title = "下载文件", IsSaveResponseData = false)]
public IActionResult DownloadFile(string? path, long fileId = 0)
{
var tempPath = path;
if (fileId > 0)
{
var fileInfo = SysFileService.GetById(fileId);
if (fileInfo != null)
{
tempPath = fileInfo.FileUrl;
}
}
string fullPath = tempPath;
//if (tempPath.StartsWith("/"))
//{
// fullPath = Path.Combine(WebHostEnvironment.WebRootPath, tempPath.ReplaceFirst("/", ""));
//}
string fileName = Path.GetFileName(fullPath);
return DownFile(fullPath, fileName);
}
/// <summary>
/// home
/// </summary>
/// <returns></returns>
[Route("/config")]
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> GetConfig()
{
var file = await SysFileService.AsQueryable().Where(x => x.ClassifyType == "watermark").FirstAsync();
var topDept = await _deptService.AsQueryable().Where(it => it.ParentId == 0 && it.DelFlag == 0 && it.Status == 0).FirstAsync();
List<string> deptList = new List<string>();
if (topDept != null)
{
var children = await _deptService.AsQueryable().Where(it => it.ParentId == topDept.DeptId && it.DelFlag == 0 && it.Status == 0).Select(it => it.DeptName).ToListAsync();
deptList = children;
}
var list = await sysDictDataService.AsQueryable().Where(it => it.DictType == "sys_construction_status" && it.Status == "0").Select(it => it.DictValue).ToListAsync();
return SUCCESS(new { logo = file?.AccessUrl ?? "", deptList, construction = list });
}
/// <summary>
/// 添加工作记录
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("/addworkrecord")]
[AllowAnonymous]
public async Task<IActionResult> AddCamWorkRecord([FromBody] CamRecordWorkDto parm)
{
if (parm.Workers == null || parm.Workers.Count == 0)
{
return ToResponse(ResultCode.PARAM_ERROR, "请选择工作人员");
}
if (string.IsNullOrEmpty(parm.Image) && !string.IsNullOrEmpty(parm.ImageUrl))
{
return ToResponse(ResultCode.PARAM_ERROR, "请上传图片");
}
//-当日所有照片
//- 当日根据【人名】分类的照片
//- 当日根据【工作内容】分类的照片
//- 当日根据【部门】分类的照片
var imageprx = ImageConverter.GetFileExtensionFromBase64(parm.Image);
var filePath = "/workfiles/" + parm.RecordTime?.ToString("yyyyMM/yyyyMMdd");
string savePath = Path.Combine(WebHostEnvironment.WebRootPath);
var path = savePath + filePath;
var images = ImageConverter.Base64ToImageBytes(parm.Image);
if (images.Length == 0)
{
return ToResponse(ResultCode.CUSTOM_ERROR, "图片上传失败");
}
if (parm.Id != null && parm.Id > 0)
{
if (parm.ImageUrl.IndexOf("http") == -1)
{
//删除之前的人员照片
var m = await _CamWorkrecordService.AsQueryable().Where(it => it.Id == parm.Id).FirstAsync();
var m_workers = await _CamWorkerService.AsQueryable().Where(it => it.WorkrecordId == parm.Id).ToListAsync();
if (m == null)
{
return ToResponse(ResultCode.PARAM_ERROR, "未找到该记录");
}
if (!string.IsNullOrEmpty(m.ImageUrl))
{
//m.ImageUrl http://localhost:8888/workfiles/202508/20250819/当日照片/1755617080_7078.jpg
var imagePath = m.ImageUrl.Substring(m.ImageUrl.IndexOf("workfiles"));
var fullImagePath = Path.Combine(WebHostEnvironment.WebRootPath, imagePath);
// 获取文件名
var fileName = Path.GetFileName(fullImagePath);
var directoryPath = Path.GetDirectoryName(fullImagePath);
// 删除当日照片
if (IOFile.Exists(fullImagePath))
{
IOFile.Delete(fullImagePath);
}
// 删除参与人员照片
var participantsPath = Path.Combine(WebHostEnvironment.WebRootPath, "workfiles", m.RecordTime?.ToString("yyyyMM/yyyyMMdd"), "参与人员");
if (Directory.Exists(participantsPath))
{
foreach (var workerDir in m_workers)
{
var workerImagePath = Path.Combine(participantsPath, workerDir.WorkerName, fileName);
if (IOFile.Exists(workerImagePath))
{
IOFile.Delete(workerImagePath);
}
}
}
// 删除工作内容照片
var jobContentPath = Path.Combine(WebHostEnvironment.WebRootPath, "workfiles", m.RecordTime?.ToString("yyyyMM/yyyyMMdd"), "工作内容", m.Content);
var jobContentImagePath = Path.Combine(jobContentPath, fileName);
if (IOFile.Exists(jobContentImagePath))
{
IOFile.Delete(jobContentImagePath);
}
// 删除部门照片
var departmentPath = Path.Combine(WebHostEnvironment.WebRootPath, "workfiles", m.RecordTime?.ToString("yyyyMM/yyyyMMdd"), "部门", m.DeptName);
var departmentImagePath = Path.Combine(departmentPath, fileName);
if (IOFile.Exists(departmentImagePath))
{
IOFile.Delete(departmentImagePath);
}
}
//删除施工人员数据
await _CamWorkerService.DeleteAsync(it => it.WorkrecordId == parm.Id);
}
}
int MaxSize = 300 * 1024; // 300KB = 307200 字节
// 如果图片大于300KB才压缩
if (images.Length > MaxSize)
{
images = CompressImage(images, 50); // 压缩质量 70
imageprx = ".jpg";
}
var imageName = ImageConverter.GenerateImageFileName(imageprx);
var participantsUrl = $"{path}/参与人员/";
var photosDay = $"{path}/当日照片/";
var jobContent = $"{path}/工作内容/";
var department = $"{path}/部门/";
//添加当日照片
if (!Directory.Exists(photosDay))
{
Directory.CreateDirectory(photosDay);
}
var photosDayFileName = $"{photosDay}/{imageName}";
using (var stream = new FileStream(photosDayFileName, FileMode.Create))
{
await stream.WriteAsync(images, 0, images.Length);
}
//添加当日根据【人名】分类的照片
foreach (var work in parm.Workers)
{
var participantsUrlFIleName = $"{participantsUrl}/{work}/";
if (!Directory.Exists(participantsUrlFIleName))
{
Directory.CreateDirectory(participantsUrlFIleName);
}
participantsUrlFIleName += imageName;
using (var stream = new FileStream(participantsUrlFIleName, FileMode.Create))
{
await stream.WriteAsync(images, 0, images.Length);
}
}
//添加当日根据【工作内容】分类的照片
var jobContentUrl = $"{jobContent}/{parm.Content}/";
if (!Directory.Exists(jobContentUrl))
{
Directory.CreateDirectory(jobContentUrl);
}
jobContentUrl += imageName;
using (var stream = new FileStream(jobContentUrl, FileMode.Create))
{
await stream.WriteAsync(images, 0, images.Length);
}
//添加当日根据【部门】分类的照片
var departmentUrl = $"{department}{parm.DeptName}/";
if (!Directory.Exists(departmentUrl))
{
Directory.CreateDirectory(departmentUrl);
}
departmentUrl += imageName;
using (var stream = new FileStream(departmentUrl, FileMode.Create))
{
await stream.WriteAsync(images, 0, images.Length);
}
var domainUrl = $"{OptionsSetting.Upload.UploadUrl}";
//备份一下本地
var modal = parm.Adapt<CamWorkrecord>().ToCreate(HttpContext);
modal.CreateTime = DateTime.Now;
modal.UpdateTime = DateTime.Now;
modal.ImageUrl = $"{domainUrl}{filePath}/当日照片/{imageName}";
if (parm.Id != null && parm.Id > 0)
{
//修改实体类
await _CamWorkrecordService.UpdateAsync(modal);
}
else
{
modal = await _CamWorkrecordService.Insertable(modal).ExecuteReturnEntityAsync();
}
var workid = modal.Id;
var workers = new List<CamWorker>();
foreach (var item in parm.Workers)
{
var worker = new CamWorker()
{
WorkrecordId = workid,
WorkerName = item,
CreateTime = DateTime.Now,
UpdateTime = DateTime.Now
};
workers.Add(worker);
}
_CamWorkerService.AsInsertable(workers).ExecuteCommand();
return SUCCESS(1);
}
/// <summary>
/// 删除工作记录
/// </summary>
/// <param name="id">工作记录ID</param>
/// <returns></returns>
[HttpPost]
[Route("/deleteworkrecord/{id}")]
[ActionPermissionFilter(Permission = "camworkrecord:delete")]
public async Task<IActionResult> DeleteCamWorkRecord(long id)
{
// 查询工作记录
var workRecord = await _CamWorkrecordService.AsQueryable().Where(it => it.Id == id).FirstAsync();
if (workRecord == null)
{
return ToResponse(ResultCode.PARAM_ERROR, "未找到该记录");
}
// 查询相关的工作人员
var workers = await _CamWorkerService.AsQueryable().Where(it => it.WorkrecordId == id).ToListAsync();
// 删除图片文件
if (!string.IsNullOrEmpty(workRecord.ImageUrl))
{
// 从URL中提取文件路径
var imagePath = workRecord.ImageUrl.Substring(workRecord.ImageUrl.IndexOf("workfiles"));
var fullImagePath = Path.Combine(WebHostEnvironment.WebRootPath, imagePath);
// 获取文件名
var fileName = Path.GetFileName(fullImagePath);
var directoryPath = Path.GetDirectoryName(fullImagePath);
// 删除当日照片
if (IOFile.Exists(fullImagePath))
{
IOFile.Delete(fullImagePath);
}
// 删除参与人员照片
var participantsPath = Path.Combine(WebHostEnvironment.WebRootPath, "workfiles", workRecord.RecordTime?.ToString("yyyyMM/yyyyMMdd"), "参与人员");
if (Directory.Exists(participantsPath))
{
foreach (var worker in workers)
{
var workerImagePath = Path.Combine(participantsPath, worker.WorkerName, fileName);
if (IOFile.Exists(workerImagePath))
{
IOFile.Delete(workerImagePath);
}
// 如果该工作人员的文件夹为空,则删除文件夹
var workerDir = Path.GetDirectoryName(workerImagePath);
if (Directory.Exists(workerDir) && !Directory.EnumerateFiles(workerDir).Any())
{
Directory.Delete(workerDir);
}
}
}
// 删除工作内容照片
var jobContentPath = Path.Combine(WebHostEnvironment.WebRootPath, "workfiles", workRecord.RecordTime?.ToString("yyyyMM/yyyyMMdd"), "工作内容", workRecord.Content);
var jobContentImagePath = Path.Combine(jobContentPath, fileName);
if (IOFile.Exists(jobContentImagePath))
{
IOFile.Delete(jobContentImagePath);
}
// 如果工作内容文件夹为空,则删除文件夹
if (Directory.Exists(jobContentPath) && !Directory.EnumerateFiles(jobContentPath).Any())
{
Directory.Delete(jobContentPath);
}
// 删除部门照片
var departmentPath = Path.Combine(WebHostEnvironment.WebRootPath, "workfiles", workRecord.RecordTime?.ToString("yyyyMM/yyyyMMdd"), "部门", workRecord.DeptName);
var departmentImagePath = Path.Combine(departmentPath, fileName);
if (IOFile.Exists(departmentImagePath))
{
IOFile.Delete(departmentImagePath);
}
// 如果部门文件夹为空,则删除文件夹
if (Directory.Exists(departmentPath) && !Directory.EnumerateFiles(departmentPath).Any())
{
Directory.Delete(departmentPath);
}
// 清理空文件夹
CleanEmptyDirectories(Path.Combine(WebHostEnvironment.WebRootPath, "workfiles", workRecord.RecordTime?.ToString("yyyyMM/yyyyMMdd")));
}
// 删除工作人员记录
await _CamWorkerService.DeleteAsync(it => it.WorkrecordId == id);
// 删除工作记录
await _CamWorkrecordService.DeleteAsync(it => it.Id == id);
return SUCCESS(1);
}
/// <summary>
/// 清理空文件夹
/// </summary>
/// <param name="directoryPath">目录路径</param>
private void CleanEmptyDirectories(string directoryPath)
{
if (!Directory.Exists(directoryPath))
return;
try
{
// 递归清理子目录
foreach (var subDir in Directory.GetDirectories(directoryPath))
{
CleanEmptyDirectories(subDir);
}
// 如果当前目录为空,则删除
if (!Directory.EnumerateFiles(directoryPath).Any() && !Directory.EnumerateDirectories(directoryPath).Any())
{
Directory.Delete(directoryPath);
}
}
catch (Exception ex)
{
// 记录日志但不抛出异常,避免影响主流程
logger.Error($"清理空文件夹失败: {directoryPath}, 错误: {ex.Message}");
}
}
[HttpGet]
[Route("/getDownloadZip")]
[AllowAnonymous]
public async Task<IActionResult> DownloadZip([FromQuery] string? yearMoney)
{
if (string.IsNullOrEmpty(yearMoney)|| yearMoney=="null")
{
yearMoney = DateTime.Now.ToString("yyyyMM");
}
if (yearMoney.IndexOf("-") > -1)
{
yearMoney = yearMoney.Replace("-", "");
}
var filePath = "/workfiles/" + yearMoney;
string savePath = Path.Combine(WebHostEnvironment.WebRootPath);
var path = savePath + filePath;
if (!Directory.Exists(path))
{
return ToResponse(ResultCode.FAIL, "无数据");
}
var outputPath = WebHostEnvironment.WebRootPath + "/workfiles/temp/";
if (!Directory.Exists(outputPath))
{
Directory.CreateDirectory(outputPath);
}
var zipReturnFileName = $"{outputPath}{yearMoney}.zip";
if (IOFile.Exists(zipReturnFileName))
{
IOFile.Delete(zipReturnFileName);
}
ZipFile.CreateFromDirectory(path, zipReturnFileName);
return DownFile(zipReturnFileName, $"{yearMoney}.zip");
}
public byte[] CompressImage(byte[] imageBytes, int quality)
{
using (var inputStream = new MemoryStream(imageBytes))
using (var image = Image.Load(inputStream))
{
var encoder = new JpegEncoder { Quality = quality };
using (var outputStream = new MemoryStream())
{
image.Save(outputStream, encoder);
return outputStream.ToArray();
}
}
}
/// <summary>
/// 获取workfiles文件夹大小信息
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("/getWorkfilesSize")]
[AllowAnonymous]
public IActionResult GetWorkfilesSize()
{
try
{
var workfilesPath = Path.Combine(WebHostEnvironment.WebRootPath, "workfiles");
if (!Directory.Exists(workfilesPath))
{
return ToResponse(ResultCode.FAIL, "workfiles文件夹不存在");
}
var result = new
{
TotalSize = GetDirectorySize(workfilesPath),
TotalSizeFormatted = FormatFileSize(GetDirectorySize(workfilesPath)),
DailyFolders = GetDailyFoldersSize(workfilesPath)
};
return SUCCESS(result);
}
catch (Exception ex)
{
logger.Error(ex, "获取workfiles文件夹大小信息失败");
return ToResponse(ResultCode.FAIL, "获取文件夹大小信息失败");
}
}
/// <summary>
/// 计算目录大小
/// </summary>
/// <param name="directoryPath">目录路径</param>
/// <returns>目录大小(字节)</returns>
private long GetDirectorySize(string directoryPath)
{
long size = 0;
try
{
var directory = new DirectoryInfo(directoryPath);
var files = directory.GetFiles("*", SearchOption.AllDirectories);
size = files.Sum(file => file.Length);
}
catch (Exception ex)
{
logger.Error(ex, $"计算目录大小失败: {directoryPath}");
}
return size;
}
/// <summary>
/// 格式化文件大小
/// </summary>
/// <param name="bytes">字节数</param>
/// <returns>格式化后的大小字符串</returns>
private string FormatFileSize(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double len = bytes;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:0.##} {sizes[order]}";
}
/// <summary>
/// 获取每日文件夹大小信息
/// </summary>
/// <param name="workfilesPath">workfiles路径</param>
/// <returns>每日文件夹大小信息列表</returns>
private List<object> GetDailyFoldersSize(string workfilesPath)
{
var dailyFolders = new List<object>();
try
{
var directory = new DirectoryInfo(workfilesPath);
var subDirectories = directory.GetDirectories();
foreach (var subDir in subDirectories)
{
var folderSize = GetDirectorySize(subDir.FullName);
var folderInfo = new
{
FolderName = subDir.Name,
Size = folderSize,
SizeFormatted = FormatFileSize(folderSize),
FileCount = subDir.GetFiles("*", SearchOption.AllDirectories).Length,
LastModified = subDir.LastWriteTime
};
dailyFolders.Add(folderInfo);
}
// 按文件夹名称排序(通常是日期格式)
dailyFolders = dailyFolders.OrderByDescending(x => ((dynamic)x).FolderName).ToList();
}
catch (Exception ex)
{
logger.Error(ex, "获取每日文件夹大小信息失败");
}
return dailyFolders;
}
}
}