using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Yh.Platform.Abstractions; using YhCore.Common; using YhCore.Common.Config; using YhCore.Common.UserContext; using YhCore.Entity; using YhCore.Model.Dto; using YhCore.Service.Interfaces; namespace YhCore.WebApi.Controllers.Api.Common { /// /// 公共字典 / 文件(对应旧 Areas/Common/CommonController,路由 api/base)。 /// 字典部分 8 接口 + 文件部分 4 接口(FileDown / FilePreview / FileUpload / FileUploadImage)已落地; /// 旧 [NoAuth] 语义:无需用户上下文,schId 由前端传入或取当前用户。 /// [ApiController] [Route(ApiRoutes.ApiPath + "/base")] public class CommonController : ControllerBase { private readonly IDictionaryService _dict; private readonly IFileService _file; public CommonController(IDictionaryService dict, IFileService file) { _dict = dict; _file = file; } /// 获取指定字典数据(Type 1~10)。 [HttpGet("GetSysDic")] public async Task> GetSysDic([FromQuery] int type = 0) { var typeId = DictionaryTypeHelper.FromSysDicType(type); if (typeId == null) { throw new DException("参数错误"); } return await _dict.GetDictListAsync(typeId, SchSerID()); } /// 字典类别列表([NoAuth],排除部门)。 [HttpGet("GetDicTypeList")] public async Task> GetDicTypeList() => await _dict.GetDicTypeListAsync(); /// 字典列表管理(Type=0/DEPT 取全校;其他仅超管 bestsch)。 [HttpGet("GetDictMangeList")] public async Task> GetDictMangeList([FromQuery] string type) { var typeId = DictionaryTypeHelper.ResolveTypeId(type); if (typeId == null) { throw new DException("参数错误"); } if (DictionaryTypeHelper.IsDept(typeId)) { return await _dict.GetDictMangeListAsync("DEPT", SchSerID()); } //if (UserContextHolder.Current.() =1 ) //{ // throw new DException("非超管不得操作!"); //} return await _dict.GetDictMangeListAsync(typeId, ""); } /// 添加字典。 [HttpPost("AddDic")] public async Task AddDic([FromBody] Common_Dictionary model) { if (model == null) throw new DException("参数错误!"); var info = new Common_Dictionary { typeID = model.typeID, typeName = DictionaryTypeHelper.GetTypeName(model.typeID), Name = model.Name, Schserid = SchSerID() }; await _dict.AddDicAsync(info); } /// 更新字典。 [HttpPost("UpdateDic")] public async Task UpdateDic([FromBody] Common_Dictionary model) { if (model == null) throw new DException("参数有误!"); model.Schserid = SchSerID(); await _dict.UpdateDicAsync(model); } /// 编辑字典名称。 [HttpPost("EditDic")] public async Task EditDic([FromBody] Common_Dictionary model) { if (model == null) throw new DException("参数有误!"); model.Schserid = SchSerID(); await _dict.EditDicAsync(model); } /// 添加发文部门。 [HttpPost("AddDeptDic")] public async Task AddDeptDic([FromBody] Common_Dictionary model) { if (model == null) throw new DException("参数有误!"); var info = new Common_Dictionary { typeID = "DEPT", typeName = "部门类别", Name = model.Name, Schserid = SchSerID() }; await _dict.AddDicAsync(info); } /// 更新发文部门。 [HttpPost("UpdateDeptDic")] public async Task UpdateDeptDic([FromBody] Common_Dictionary model) { if (model == null) throw new DException("参数有误!"); model.Schserid = SchSerID(); await _dict.UpdateDicAsync(model); } #region 文件:下载 / 预览 / 上传 /// /// 公用下载文件(旧 FileDown,[NoAuth])。yl=true 且为图片/PDF 时重定向到文件 URL(webapp 预览), /// 否则物理文件下载。 /// [HttpGet("FileDown")] public async Task FileDown([FromQuery] int id, [FromQuery] bool yl = false) { if (id == 0) return Ok(); var file = await _file.GetEnclosureAsync(id); string[] previewArry = { ".jpg", ".gif", ".png", ".pdf", ".jpeg", ".bmp" }; if (yl) { // 旧 sch_weboa_url.Replace("notice/api", AppType + "/") + fileurl → 新 FileWebPath + fileurl string fileUrl = (Config.FileWebPath ?? "") + file.fileurl; string suffName = Path.GetExtension(fileUrl); if (previewArry.Any(x => x == suffName.ToLower())) return Redirect(fileUrl); } // WebHelper.DownFile:物理文件下载 string filePath = _file.MapPhysicalPath(file.fileurl); if (!System.IO.File.Exists(filePath)) return Content("请求的文件不存在!"); string contentType = GetContentType(filePath); string outputFileName = file.filename ?? "file"; return PhysicalFile(filePath, contentType, outputFileName); } /// /// 公用预览 office 文件(旧 FilePreview / CommonPreview,[NoAuth])。 /// type=1 → 返回可用预览 url(本地 .pdf 存在优先);type=2 → 重定向本地 pdf 或 officeapps.live.com; /// 其余 → 重定向替换后缀为 .pdf 的地址。跳转返回 RedirectResult(全局包装过滤器不拦截)。 /// [HttpGet("FilePreview")] public async Task FilePreview([FromQuery] int id, [FromQuery] string type = null) { if (id == 0) throw new DException("文件ID错误!"); var file = await _file.GetEnclosureAsync(id); // 公文另做处理 if (file.fileurl != null && file.fileurl.IndexOf("gw.") > -1) { string fileUrl = "http://" + file.fileurl; string suffName = Path.GetExtension(fileUrl); string newName = fileUrl.Remove(fileUrl.LastIndexOf(suffName, StringComparison.Ordinal), suffName.Length) + ".pdf"; return Redirect(newName); } string fileUrl2 = (Config.FileWebPath ?? "") + file.fileurl; string suffName2 = Path.GetExtension(fileUrl2); if (!string.IsNullOrEmpty(type)) { // 单独读取文件是否存在 string newFile = file.fileurl; string pdfFile = newFile.Remove(newFile.LastIndexOf(suffName2, StringComparison.Ordinal), suffName2.Length) + ".pdf"; string outFile = _file.MapPhysicalPath(pdfFile); if (type == "1") { if (System.IO.File.Exists(outFile)) return (Config.FileWebPath ?? "") + pdfFile; return fileUrl2; } if (type == "2") { string pdfUrl = string.Empty; if (System.IO.File.Exists(outFile)) pdfUrl = (Config.FileWebPath ?? "") + pdfFile; else pdfUrl = "https://view.officeapps.live.com/op/view.aspx?src=" + fileUrl2; return Redirect(pdfUrl); } return ""; } string newName2 = fileUrl2.Remove(fileUrl2.LastIndexOf(suffName2, StringComparison.Ordinal), suffName2.Length) + ".pdf"; return Redirect(newName2); } /// /// 公用附件上传(旧 FileUpload,[NoAuth])。 /// chunk 参数 → 分片保存返回 {code:1,type:"chunk",msg};fileName 参数 → 合并分片;否则单文件上传。 /// 落库 Common_UpFiles(TopicType=AppCode),返回 {fileurl,host,fileid,name,type}。 /// [HttpPost("FileUpload")] public async Task Upload() { string apptype = "docprint"; // 旧 WebHelper.AppType 固定 docprint string guid = Request.Form["guid"]; string chunk = Request.Form["chunk"]; string fileName = Request.Form["fileName"]; if (!string.IsNullOrEmpty(chunk)) { var chunkFile = Request.Form.Files.FirstOrDefault(f => f.Name == "file") ?? Request.Form.Files.FirstOrDefault(); await _file.SaveChunkAsync(guid, chunk, chunkFile); return new { code = 1, type = "chunk", msg = "分片上传成功!" }; } FileObj url; string errMsg = "上传失败!"; if (string.IsNullOrEmpty(fileName)) { url = await _file.SaveFileAsync(apptype, Request.Form.Files.FirstOrDefault()); } else { url = await _file.MergeSaveAsync(apptype, guid, fileName); } if (url == null) throw new DException(errMsg); // 旧 WebHelper.AppCode == "1102" ? "1002" : AppCode → docprint 固定 1003 int serid = await _file.SaveEnclosureAsync(url, DocPrintConstants.AppCode.ToString()); return new { fileurl = url.fileurl, host = url.host, fileid = serid, name = url.filename, type = url.filetype }; } /// 公用图片上传(旧 FileUploadImage,[NoAuth];多图,返回数组)。 [HttpPost("FileUploadImage")] public async Task UploadImg() { string apptype = "docprint"; var urlList = await _file.SaveFileImageAsync(apptype, Request.Form.Files); if (urlList.Count == 0) throw new DException("上传失败!"); var result = new List(); foreach (var item in urlList) { int serid = await _file.SaveEnclosureAsync(item, DocPrintConstants.AppCode.ToString()); result.Add(new { fileurl = item.fileurl, host = item.host, fileid = serid, name = item.filename, type = item.filetype }); } return result; } /// 按扩展名取 ContentType(替代旧 MimeMapping.GetMimeMapping)。 private static string GetContentType(string filePath) { string ext = Path.GetExtension(filePath).ToLower(); return ext switch { ".jpg" or ".jpeg" => "image/jpeg", ".gif" => "image/gif", ".png" => "image/png", ".bmp" => "image/bmp", ".pdf" => "application/pdf", ".txt" => "text/plain", ".doc" => "application/msword", ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".xls" => "application/vnd.ms-excel", ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".ppt" => "application/vnd.ms-powerpoint", ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".zip" => "application/zip", ".rar" => "application/x-rar-compressed", ".mp4" => "video/mp4", _ => "application/octet-stream", }; } #endregion private static string SchSerID() => UserContextHolder.Current.SchSerID; } }