From 816209fc352ef4d61bc311a1e931948f82b5aef8 Mon Sep 17 00:00:00 2001 From: owen Date: Sun, 13 Sep 2026 19:01:48 +0800 Subject: [PATCH] ow --- .../DmsFileService.auto.cs | 128 +- .../FamilyGroupService.auto.cs | 13 +- .../FamilyPersonService.auto.cs | 6 + .../FamilyTreeService.auto.cs | 46 + .../PublishPhotoService.auto.cs | 2 +- .../PublishVideoService.auto.cs | 4 +- .../CloudBuilder.Master.csproj | 3 + .../Data/FamilyPersonDisplayData.cs | 2 + .../Service/IDmsFileService.auto.cs | 5 +- .../Master/DmsFileRequest.auto.cs | 4 + .../Policy/FileTypePolicy.cs | 38 +- .../Policy/ServiceSettingsPolicy.cs | 45 +- .../Master/DmsFileController.auto.cs | 22 + .../CloudBuilder.Web.Entry/appsettings.json | 7 +- .../components/basic/DmsFileEnquiryHelp.vue | 405 +++++ WebVue/src/components/basic/DragModal.vue | 26 +- WebVue/src/components/basic/FileUpload.vue | 236 +++ .../src/components/basic/OperatorStation.vue | 38 +- .../basic/OperatorStationDelete.vue | 19 +- .../basic/OperatorStationFamily.vue | 19 +- WebVue/src/components/basic/SearchCard.vue | 864 +++++++++ WebVue/src/components/basic/Toolbar.vue | 50 +- .../master/AncestryTreeChartModal.vue | 100 +- .../master/FamilyTreeChartModal.vue | 111 +- WebVue/src/md/fileUpload.md | 259 +++ WebVue/src/service/master/dmsFileService.ts | 9 + WebVue/src/styles/ft-mobile.less | 488 ++++++ .../src/views/master/DmsFileDeleteEnquiry.vue | 115 +- WebVue/src/views/master/DmsFileEnquiry.vue | 132 +- .../src/views/master/FamilyGroupOperation.vue | 401 ++--- WebVue/src/views/master/FamilyGroupShare.vue | 118 +- .../views/master/FamilyPersonOperation.vue | 168 +- .../views/master/OrgDmsFileDeleteEnquiry.vue | 912 ---------- WebVue/src/views/master/OrgDmsFileEnquiry.vue | 1539 ----------------- .../src/views/master/OrgFamilyGroupShare.vue | 1274 -------------- WebVue/src/views/security/GroupOperation.vue | 71 +- .../components/GroupPermissionActions.vue | 72 + 37 files changed, 3236 insertions(+), 4515 deletions(-) create mode 100644 WebVue/src/components/basic/DmsFileEnquiryHelp.vue create mode 100644 WebVue/src/components/basic/FileUpload.vue create mode 100644 WebVue/src/components/basic/SearchCard.vue create mode 100644 WebVue/src/md/fileUpload.md create mode 100644 WebVue/src/styles/ft-mobile.less delete mode 100644 WebVue/src/views/master/OrgDmsFileDeleteEnquiry.vue delete mode 100644 WebVue/src/views/master/OrgDmsFileEnquiry.vue delete mode 100644 WebVue/src/views/master/OrgFamilyGroupShare.vue create mode 100644 WebVue/src/views/security/components/GroupPermissionActions.vue diff --git a/CloudBuilder/CloudBuilder.Master.Service/DmsFileService.auto.cs b/CloudBuilder/CloudBuilder.Master.Service/DmsFileService.auto.cs index 4956ea4..4c5a5b7 100644 --- a/CloudBuilder/CloudBuilder.Master.Service/DmsFileService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master.Service/DmsFileService.auto.cs @@ -82,7 +82,7 @@ namespace CloudBuilder.Master.Service var webRootPath = service.Configuration[ServiceSettingsPolicy.RequestPath]; var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory]; - var scale = service.Configuration[ServiceSettingsPolicy.DmsFileScaleDirectory].Replace(phy, ""); + var scale = ServiceSettingsPolicy.GetDmsFileScaleDirectory(service).Replace(phy, ""); List prvs = new List(); //bool isAttached = Debugger.IsAttached; foreach (var item in list) @@ -150,7 +150,7 @@ namespace CloudBuilder.Master.Service var webRootPath = service.Configuration[ServiceSettingsPolicy.RequestPath]; var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory]; - var scale = service.Configuration[ServiceSettingsPolicy.DmsFileScaleDirectory].Replace(phy, ""); + var scale = ServiceSettingsPolicy.GetDmsFileScaleDirectory(service).Replace(phy, ""); List prvs = new List(); //bool isAttached = Debugger.IsAttached; foreach (var item in list) @@ -215,7 +215,7 @@ namespace CloudBuilder.Master.Service var webRootPath = service.Configuration[ServiceSettingsPolicy.RequestPath]; var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory]; - var scale = service.Configuration[ServiceSettingsPolicy.DmsFileScaleDirectory].Replace(phy, ""); + var scale = ServiceSettingsPolicy.GetDmsFileScaleDirectory(service).Replace(phy, ""); foreach (var item in list) { @@ -314,7 +314,7 @@ namespace CloudBuilder.Master.Service var webRootPath = service.Configuration[ServiceSettingsPolicy.RequestPath]; var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory]; - var scale = service.Configuration[ServiceSettingsPolicy.DmsFileScaleDirectory].Replace(phy, ""); + var scale = ServiceSettingsPolicy.GetDmsFileScaleDirectory(service).Replace(phy, ""); foreach (var item in list) @@ -1140,7 +1140,109 @@ namespace CloudBuilder.Master.Service string filePath = null; if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("FilePath")) filePath = httpContextAccessor.HttpContext.Request.Headers["FilePath"].ToString(); - dmsFile = PackUploadFile(file, filePath); + PackUploadFile(file, filePath); + break; + } + } + } + + + public void PackUploadFile(IFormFile file, string folderName) + { + var uploadFileRootPath = ServiceSettingsPolicy.GetUploadFileDirectory(service); + + //文件后缀 + var fileExtension = Path.GetExtension(file.Name.Replace(" ", "")).ToLower();//获取文件格式,拓展名 + if (string.IsNullOrEmpty(fileExtension)) fileExtension = "ext"; + + var filePath = Path.Combine(folderName, fileExtension.Replace(".", ""), ""); + + //创建存储文件夹 + if (!Directory.Exists(Path.Combine(uploadFileRootPath, filePath))) + { + Directory.CreateDirectory(Path.Combine(uploadFileRootPath, filePath)); + } + //判断文件大小 + var fileSize = file.Length; + if (fileSize > 1024 * 1024 * 100) //100M TODO:(1mb=1024X1024b) + { + return; + } + //保存的文件名称 + string fullName = Path.Combine(uploadFileRootPath, filePath, file.FileName); + if (File.Exists(fullName)) File.Delete(fullName); + //文件保存 + using (var fs = System.IO.File.Create(fullName)) + { + file.CopyTo(fs); + fs.Flush(); + } + //FileName上传Uid:xxxx-1-1.xxx + string[] fns = file.FileName.Split('-'); + //如果上传的不是最后一个分片 + if (fns[fns.Length - 2] != fns[fns.Length - 1].Split('.')[0]) + { + return; + } + else + { + string backupRootPath = ServiceSettingsPolicy.GetBackupFileDirectory(service); + string backupFileName = Path.Combine(backupRootPath, filePath, file.FileName); + if (!Directory.Exists(Path.Combine(backupRootPath, filePath))) + { + Directory.CreateDirectory(Path.Combine(backupRootPath, filePath)); + } + + if (fns[fns.Length - 1].Split('.')[0] == "1") + { + if (File.Exists(backupFileName)) File.Delete(backupFileName); + File.Copy(fullName, backupFileName, true); + } + else//合并文件 + { + List all = new List(); + List fileNames = new List(); + //文件分片从1开始 + for (int i = 1; i <= Convert.ToInt32(fns[fns.Length - 1].Split('.')[0]); i++) + { + fns[fns.Length - 2] = i.ToString(); + + fileNames.Add(Path.Combine(uploadFileRootPath, filePath, fns.ToDelimiteredList('-'))); + } + + if (File.Exists(backupFileName)) File.Delete(backupFileName); + + using (FileStream outputFile = File.Create(backupFileName)) // 创建输出文件流 + { + foreach (string fileName in fileNames) + { + byte[] buffer = File.ReadAllBytes(fileName); // 读取每个文件内容到字节数组 + outputFile.Write(buffer, 0, buffer.Length); // 将字节数组写入输出文件流 + } + } + } + } + } + + + [PermissionOperate(name: MasterPermissionPolicy.DmsFile, operate: Operate.Insert)] + [UnitOfWork] + public void UploadDmsFile() + { + //采用分片上传文件(以及后面分片下载) + DmsFileEntity dmsFile = null; + + var files = httpContextAccessor.HttpContext.Request.Form.Files; + + var currentDate = DateTime.Now; + if (files.Any()) + { + foreach (var file in files) + { + string filePath = null; + if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey("FilePath")) + filePath = httpContextAccessor.HttpContext.Request.Headers["FilePath"].ToString(); + dmsFile = PackUploadDmsFile(file, filePath); break; } } @@ -1151,9 +1253,9 @@ namespace CloudBuilder.Master.Service } } - public DmsFileEntity PackUploadFile(IFormFile file, string folderName) + public DmsFileEntity PackUploadDmsFile(IFormFile file, string folderName) { - var webRootPath = service.Configuration[ServiceSettingsPolicy.DmsFileUploadDirectory]; + var webRootPath = ServiceSettingsPolicy.GetDmsFileUploadDirectory(service); DmsFileEntity dmsFile = new DmsFileEntity(); dmsFile.OrgFileName = file.Name.Replace(" ", ""); dmsFile.FilePath = folderName; @@ -1199,7 +1301,7 @@ namespace CloudBuilder.Master.Service dmsFile.OrderKey = file.FileName; dmsFile.FileName = file.FileName; dmsFile.FileSize = Convert.ToInt32(fileSize / 1024); - var backupRootPath = service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory]; + var backupRootPath = ServiceSettingsPolicy.GetDmsFileBackupDirectory(service); string backupName = Path.Combine(backupRootPath, filePath, dmsFile.FileName); if (!Directory.Exists(Path.Combine(backupRootPath, filePath))) { @@ -1225,7 +1327,7 @@ namespace CloudBuilder.Master.Service fileNames.Add(Path.Combine(webRootPath, filePath, fns.ToDelimiteredList('-'))); } dmsFile.FileName = Path.GetFileName(fullName); - var backupRootPath = service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory]; + var backupRootPath = ServiceSettingsPolicy.GetDmsFileBackupDirectory(service); fullName = Path.Combine(backupRootPath, filePath, dmsFile.FileName); if (!Directory.Exists(Path.Combine(backupRootPath, filePath))) @@ -1328,7 +1430,7 @@ namespace CloudBuilder.Master.Service // 仅修改这一行,替换硬编码反斜杠字符串拼接 var filePath = Path.Combine(service.UserId, fileExtension.Replace(".", ""), ""); // 这里同步改成Path.Combine,不要直接+字符串拼接 - string saveName = Path.Combine(service.Configuration[ServiceSettingsPolicy.DmsFileScaleDirectory], filePath, dmsFile.OrderKey); + string saveName = Path.Combine(ServiceSettingsPolicy.GetDmsFileScaleDirectory(service), filePath, dmsFile.OrderKey); if (!Directory.Exists(Path.GetDirectoryName(saveName))) { @@ -1518,7 +1620,7 @@ namespace CloudBuilder.Master.Service [PermissionOperate(name: MasterPermissionPolicy.DmsFile, operate: Operate.Find)] public dynamic DownloadFilePreview(DmsFileEntity dmsFile) { - var webRootPath = service.Configuration[ServiceSettingsPolicy.DmsFileScaleDirectory]; + var webRootPath = ServiceSettingsPolicy.GetDmsFileScaleDirectory(service); var fileExtension = Path.GetExtension(dmsFile.OrderKey); var filePath = Path.Combine(dmsFile.CreatedBy, fileExtension.Replace(".", ""), ""); @@ -1538,7 +1640,7 @@ namespace CloudBuilder.Master.Service [PermissionOperate(name: MasterPermissionPolicy.DmsFile, operate: Operate.Find)] public dynamic DownloadFileCombine(string fileName) { - var webRootPath = service.Configuration[ServiceSettingsPolicy.DmsFileUploadDirectory]; + var webRootPath = ServiceSettingsPolicy.GetDmsFileUploadDirectory(service); var fileExtension = Path.GetExtension(fileName); var filePath = Path.Combine(service.UserId, fileExtension.Replace(".", ""), ""); @@ -1615,7 +1717,7 @@ namespace CloudBuilder.Master.Service { IRepository repositoryFolderMap = repository.GetRepository>(); - return repositoryFolderMap.DetachedEntities.Where(x => x.FolderNameSon == folderName).Count(); + return repositoryFolderMap.DetachedEntities.Where(x => x.FolderNameParent == folderName).Count(); } [PermissionOperate(name: MasterPermissionPolicy.DmsFile, operate: Operate.Find)] diff --git a/CloudBuilder/CloudBuilder.Master.Service/FamilyGroupService.auto.cs b/CloudBuilder/CloudBuilder.Master.Service/FamilyGroupService.auto.cs index 58d27fa..657d8bd 100644 --- a/CloudBuilder/CloudBuilder.Master.Service/FamilyGroupService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master.Service/FamilyGroupService.auto.cs @@ -425,6 +425,8 @@ namespace CloudBuilder.Master.Service if (familyGroupFolders == null || familyGroupFolders.Length == 0) return; + List manages = new List(); + FamilyGroupPermissionEntity familyGroupPermission; foreach (FamilyGroupFolderEntity dto in familyGroupFolders) { //原来不存在的插入 @@ -445,7 +447,15 @@ namespace CloudBuilder.Master.Service repositoryFamilyGroupFolder.InsertNow(familyGroupFolderEntity); dto.FolderName = familyGroupFolderEntity.FolderName; + + + familyGroupPermission = new FamilyGroupPermissionEntity(); + familyGroupPermission.FamilyName = familyName; + familyGroupPermission.FolderName = dto.FolderName; + familyGroupPermission.UserName = service.UserId; + manages.Add(familyGroupPermission); } + InsertFamilyGroupPermission(manages.ToArray()); } @@ -559,8 +569,9 @@ namespace CloudBuilder.Master.Service repository.UpdateNow(familyGroup); - SaveFamilyGroupFolders(familyGroup.FamilyName, data.FamilyGroupFolders); + //因为SavePermissions要在SaveFamilyGroupFolders之前,因为SaveFamilyGroupFolders要插入管理员的权限 SavePermissions(familyGroup.FamilyName, data.FamilyGroupPermissions); + SaveFamilyGroupFolders(familyGroup.FamilyName, data.FamilyGroupFolders); SaveFamilyGroupManagers(familyGroup.FamilyName, data.FamilyGroupManagers); //创建群根目录 diff --git a/CloudBuilder/CloudBuilder.Master.Service/FamilyPersonService.auto.cs b/CloudBuilder/CloudBuilder.Master.Service/FamilyPersonService.auto.cs index a1e52ba..f14e3c2 100644 --- a/CloudBuilder/CloudBuilder.Master.Service/FamilyPersonService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master.Service/FamilyPersonService.auto.cs @@ -17,6 +17,9 @@ namespace CloudBuilder.Master.Service { public class FamilyPersonService : IFamilyPersonService { + /// 头像上传目录,与前端 FileUpload 的 file-path 保持一致 + private const string AVATAR_FOLDER_NAME = "FamilyPersonAvatar"; + private readonly IApplicationService service; private IRepository repository; @@ -43,6 +46,9 @@ namespace CloudBuilder.Master.Service if (fp == null) return data; data.FamilyPerson = new FamilyPersonDisplayData(fp); + // AvatarFilename 保存的是文件名(如 xxxx-3-3.jpg),AvatarUrl 才是带路径的访问地址 + + data.FamilyPerson.AvatarUrl = FileTypePolicy.PackAvatarUrl(service, AVATAR_FOLDER_NAME, data.FamilyPerson.AvatarFilename); return data; } diff --git a/CloudBuilder/CloudBuilder.Master.Service/FamilyTreeService.auto.cs b/CloudBuilder/CloudBuilder.Master.Service/FamilyTreeService.auto.cs index 79f30eb..9c772cf 100644 --- a/CloudBuilder/CloudBuilder.Master.Service/FamilyTreeService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master.Service/FamilyTreeService.auto.cs @@ -8,6 +8,7 @@ using CloudBuilder.Master.Policy; using CloudBuilder.Master.SearchCriteria; using CloudBuilder.Security.Data; using CloudBuilder.Security.Entity; +using CloudBuilder.Security.Policy; using CloudBuilder.Security.Service; using CloudBuilder.Security.Utility; using Microsoft.AspNetCore.Authorization; @@ -18,6 +19,9 @@ namespace CloudBuilder.Master.Service { public class FamilyTreeService : IFamilyTreeService { + /// 头像上传目录,与前端 FileUpload 的 file-path 保持一致 + private const string AVATAR_FOLDER_NAME = "FamilyPersonAvatar"; + private readonly IApplicationService service; private IRepository repository; @@ -27,6 +31,23 @@ namespace CloudBuilder.Master.Service repository = service.GetRepository>(); } + /// 把 AvatarFilename 拼装成可访问的 AvatarUrl,供谱系图卡片显示头像 + private void FillAvatarUrl(FamilyPersonDisplayData person) + { + if (person == null) return; + person.AvatarUrl = FileTypePolicy.PackAvatarUrl(service, AVATAR_FOLDER_NAME, person.AvatarFilename); + } + + /// 批量填充头像访问地址 + private void FillAvatarUrl(FamilyPersonDisplayData[] persons) + { + if (persons == null || persons.Length == 0) return; + foreach (FamilyPersonDisplayData person in persons) + { + FillAvatarUrl(person); + } + } + [PermissionOperate(name: MasterPermissionPolicy.FamilyTree, operate: Operate.Find)] public FamilyTreeData FindAllByTreeId(string treeId) { @@ -46,6 +67,8 @@ namespace CloudBuilder.Master.Service data.CurrentPerson.FamilyPerson = new FamilyPersonDisplayData(repositoryFamilyPerson.DetachedEntities.Where(x => x.PersonId == currentPerson).FirstOrDefault()!); + FillAvatarUrl(data.CurrentPerson.FamilyPerson); + data.FamilyTree.AncestorPersonGenealogyName = data.CurrentPerson.FamilyPerson.GenealogyName; IRepository repositoryChildrenMap = repository.GetRepository>(); @@ -72,6 +95,7 @@ namespace CloudBuilder.Master.Service if (families != null && families.Length > 0) { data.CurrentPerson.FamilyTreePersons = families.Select(x => new FamilyPersonDisplayData(x)).ToArray(); + FillAvatarUrl(data.CurrentPerson.FamilyTreePersons); } return data; @@ -116,6 +140,8 @@ namespace CloudBuilder.Master.Service data.CurrentPerson.FamilyPerson = new FamilyPersonDisplayData(repositoryFamilyPerson.DetachedEntities.Where(x => x.PersonId == personId).FirstOrDefault()!); } + FillAvatarUrl(data.CurrentPerson.FamilyPerson); + IRepository repositoryChildrenMap = repository.GetRepository>(); IRepository repositorySpouseMap = repository.GetRepository>(); @@ -125,6 +151,26 @@ namespace CloudBuilder.Master.Service //data.CurrentPerson.FamilyTreeParentMaps = repositoryChildrenMap.GetRepository>().DetachedEntities.Where(x => x.ChildrenId == key).OrderBy(x => x.Orderby).ToArray(); data.CurrentPerson.FamilyTreeChildrenMaps = repositoryChildrenMap.GetRepository>().DetachedEntities.Where(x => x.PersonId == currentPerson).OrderBy(x => x.Orderby).ToArray(); + // 补充当前人员及其配偶、子女的人员信息(含头像地址),供谱系图卡片显示头像 + List ps = new List(); + if (!string.IsNullOrEmpty(currentPerson)) ps.Add(currentPerson); + if (data.CurrentPerson.FamilyTreeSpouseMaps != null) + { + ps.AddRange(data.CurrentPerson.FamilyTreeSpouseMaps.Select(x => x.SpouseId).ToArray()); + } + if (data.CurrentPerson.FamilyTreeChildrenMaps != null) + { + ps.AddRange(data.CurrentPerson.FamilyTreeChildrenMaps.Select(x => x.ChildrenId).ToArray()); + } + + ps = ps.Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + FamilyPersonEntity[] families = repositoryFamilyPerson.DetachedEntities.Where(x => ps.AsQueryable().Contains(x.PersonId)).ToArray(); + if (families != null && families.Length > 0) + { + data.CurrentPerson.FamilyTreePersons = families.Select(x => new FamilyPersonDisplayData(x)).ToArray(); + FillAvatarUrl(data.CurrentPerson.FamilyTreePersons); + } + return data; } diff --git a/CloudBuilder/CloudBuilder.Master.Service/PublishPhotoService.auto.cs b/CloudBuilder/CloudBuilder.Master.Service/PublishPhotoService.auto.cs index 21fc548..7ca38f3 100644 --- a/CloudBuilder/CloudBuilder.Master.Service/PublishPhotoService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master.Service/PublishPhotoService.auto.cs @@ -421,7 +421,7 @@ namespace CloudBuilder.Master.Service var webRootPath = service.Configuration[ServiceSettingsPolicy.RequestPath]; var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory]; - var backup = service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory].Replace(phy, "").Substring(1); + var backup = ServiceSettingsPolicy.GetDmsFileBackupDirectory(service).Replace(phy, "").Substring(1); var fileExtension = Path.GetExtension(dmsFile.OrderKey); var filePathRel = Path.Combine(webRootPath.Substring(1), backup, dmsFile.CreatedBy, fileExtension.Replace(".", ""), ""); diff --git a/CloudBuilder/CloudBuilder.Master.Service/PublishVideoService.auto.cs b/CloudBuilder/CloudBuilder.Master.Service/PublishVideoService.auto.cs index d4c657e..d317fde 100644 --- a/CloudBuilder/CloudBuilder.Master.Service/PublishVideoService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master.Service/PublishVideoService.auto.cs @@ -78,7 +78,7 @@ namespace CloudBuilder.Master.Service { var webRootPath = service.Configuration[ServiceSettingsPolicy.RequestPath]; var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory]; - var scale = service.Configuration[ServiceSettingsPolicy.DmsFileScaleDirectory].Replace(phy, ""); + var scale = ServiceSettingsPolicy.GetDmsFileScaleDirectory(service).Replace(phy, ""); IRepository repositoryDmsFile = repository.GetRepository>(); @@ -86,7 +86,7 @@ namespace CloudBuilder.Master.Service { if (!string.IsNullOrEmpty(item.Url) && FileTypePolicy.GetType(item.Url!) == FileTypePolicy.VIDEO) { - var upload = service.Configuration[ServiceSettingsPolicy.DmsFileUploadDirectory].Replace(phy, ""); + var upload = ServiceSettingsPolicy.GetDmsFileUploadDirectory(service).Replace(phy, ""); var filePathRel = Path.Combine(upload, item.CreatedBy, "m3u8", ""); var filePath = filePathRel.Replace(Path.DirectorySeparatorChar, '/'); diff --git a/CloudBuilder/CloudBuilder.Master/CloudBuilder.Master.csproj b/CloudBuilder/CloudBuilder.Master/CloudBuilder.Master.csproj index 8ac84af..e4a1eaf 100644 --- a/CloudBuilder/CloudBuilder.Master/CloudBuilder.Master.csproj +++ b/CloudBuilder/CloudBuilder.Master/CloudBuilder.Master.csproj @@ -39,6 +39,9 @@ ..\CloudBuilder.Core\bin\Debug\net8.0\CloudBuilder.Core.dll + + ..\CloudBuilder.Security\bin\Debug\net8.0\CloudBuilder.Security.dll + diff --git a/CloudBuilder/CloudBuilder.Master/Data/FamilyPersonDisplayData.cs b/CloudBuilder/CloudBuilder.Master/Data/FamilyPersonDisplayData.cs index f2ec103..be21db3 100644 --- a/CloudBuilder/CloudBuilder.Master/Data/FamilyPersonDisplayData.cs +++ b/CloudBuilder/CloudBuilder.Master/Data/FamilyPersonDisplayData.cs @@ -23,5 +23,7 @@ namespace CloudBuilder.Master.Data { CopyFrom(entity); } + + public string? AvatarUrl { get; set; } } } diff --git a/CloudBuilder/CloudBuilder.Master/Service/IDmsFileService.auto.cs b/CloudBuilder/CloudBuilder.Master/Service/IDmsFileService.auto.cs index 9e26e95..236413c 100644 --- a/CloudBuilder/CloudBuilder.Master/Service/IDmsFileService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master/Service/IDmsFileService.auto.cs @@ -8,13 +8,11 @@ using Microsoft.AspNetCore.Http; namespace CloudBuilder.Master.Service { - public interface IDmsFileService :IServiceBase + public interface IDmsFileService : IServiceBase { DmsFileResultData FindBySearchCriteria(DmsFileSearchCriteria tc); dynamic PrintBySearchCriteria(DmsFileSearchCriteria tc); - DmsFileEntity PackUploadFile(IFormFile file, string folderName); - DmsFileEntity CreateDmsFile(DmsFileEntity dmsFile); string CreateDmsFolder(DmsFileEntity dmsFile); void RestoreDmsFile(long fileId); @@ -33,6 +31,7 @@ namespace CloudBuilder.Master.Service SelectOption[] FindDmsFolderDeleteLogs(); DmsFolderData FindDmsFolderData(); void UploadFile(); + void UploadDmsFile(); string FindM3u8Path(long fileId); diff --git a/CloudBuilder/CloudBuilder.Request/Master/DmsFileRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Master/DmsFileRequest.auto.cs index 6ebdabe..cc38f81 100644 --- a/CloudBuilder/CloudBuilder.Request/Master/DmsFileRequest.auto.cs +++ b/CloudBuilder/CloudBuilder.Request/Master/DmsFileRequest.auto.cs @@ -107,6 +107,10 @@ return Task.Run(() => serviceRequest.PostAsJsonAsync ("/DmsFile { Task.Run(() => serviceRequest.PostAsync("/DmsFile/UploadFile")).GetAwaiter().GetResult(); } + public void UploadDmsFile() + { + Task.Run(() => serviceRequest.PostAsync("/DmsFile/UploadDmsFile")).GetAwaiter().GetResult(); } + public string FindM3u8Path(Int64 fileId) { return Task.Run(() => serviceRequest.PostAsJsonAsync("/DmsFile/FindM3u8Path?fileId=" + fileId.ToString())).GetAwaiter().GetResult(); } diff --git a/CloudBuilder/CloudBuilder.Security/Policy/FileTypePolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/FileTypePolicy.cs index a8c0db3..c2d713d 100644 --- a/CloudBuilder/CloudBuilder.Security/Policy/FileTypePolicy.cs +++ b/CloudBuilder/CloudBuilder.Security/Policy/FileTypePolicy.cs @@ -2,7 +2,9 @@ using CloudBuilder.Core.DependencyInjection.Form; using CloudBuilder.Core.DependencyInjection.Policy; using CloudBuilder.Core.DependencyInjection.Request; +using CloudBuilder.Core.Extensions; using CloudBuilder.Core.Policy; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; @@ -85,7 +87,7 @@ namespace CloudBuilder.Security.Policy { if (transcodeIndc == YesNoPolicy.YES) { - var backup = (service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory] ?? "").Replace(phy ?? "", ""); + var backup = (ServiceSettingsPolicy.GetDmsFileBackupDirectory(service) ?? "").Replace(phy ?? "", ""); var filePathRel = Path.Combine(backup, createdBy, fileExtension.Replace(".", ""), ""); var filePath = filePathRel.Replace(Path.DirectorySeparatorChar, '/') + "/"; @@ -93,7 +95,7 @@ namespace CloudBuilder.Security.Policy } else { - var scale = (service.Configuration[ServiceSettingsPolicy.DmsFileScaleDirectory] ?? "").Replace(phy ?? "", ""); + var scale = (ServiceSettingsPolicy.GetDmsFileScaleDirectory(service) ?? "").Replace(phy ?? "", ""); var filePathRel = Path.Combine(scale, createdBy, fileExtension.Replace(".", ""), ""); var filePath = filePathRel.Replace(Path.DirectorySeparatorChar, '/') + "/"; url = service.Configuration[AppsettingsPolicy.ApplicationUrl] + webRootPath + filePath + orderKey; @@ -101,7 +103,7 @@ namespace CloudBuilder.Security.Policy } else if (GetType(orderKey!) == AUDIO) { - var backup = (service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory] ?? "").Replace(phy ?? "", ""); + var backup = (ServiceSettingsPolicy.GetDmsFileBackupDirectory(service) ?? "").Replace(phy ?? "", ""); var filePathRel = Path.Combine(backup, createdBy, fileExtension.Replace(".", ""), ""); var filePath = filePathRel.Replace(Path.DirectorySeparatorChar, '/') + "/"; url = service.Configuration[AppsettingsPolicy.ApplicationUrl] + webRootPath + filePath + orderKey; @@ -110,14 +112,14 @@ namespace CloudBuilder.Security.Policy { if (transcodeIndc == YesNoPolicy.YES) { - var upload = (service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory] ?? "").Replace(phy ?? "", ""); + var upload = (ServiceSettingsPolicy.GetDmsFileBackupDirectory(service) ?? "").Replace(phy ?? "", ""); var filePathRel = Path.Combine(upload, createdBy, fileExtension.Replace(".", ""), ""); var filePath = filePathRel.Replace(Path.DirectorySeparatorChar, '/') + "/"; url = service.Configuration[AppsettingsPolicy.ApplicationUrl] + webRootPath + filePath + Path.GetFileNameWithoutExtension(orderKey) + ".png"; } else { - var backup = (service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory] ?? "").Replace(phy ?? "", ""); + var backup = (ServiceSettingsPolicy.GetDmsFileBackupDirectory(service) ?? "").Replace(phy ?? "", ""); var filePathRel = Path.Combine(backup, createdBy, fileExtension.Replace(".", ""), ""); var filePath = filePathRel.Replace(Path.DirectorySeparatorChar, '/') + "/"; url = service.Configuration[AppsettingsPolicy.ApplicationUrl] + webRootPath + filePath + orderKey; @@ -125,7 +127,7 @@ namespace CloudBuilder.Security.Policy } else if (GetType(orderKey!) == LYRIC) { - var upload = service.Configuration[ServiceSettingsPolicy.DmsFileUploadDirectory].Replace(phy, ""); + var upload = ServiceSettingsPolicy.GetDmsFileBackupDirectory(service).Replace(phy, ""); var filePathRel = Path.Combine(upload, createdBy, fileExtension.Replace(".", ""), ""); var filePath = filePathRel.Replace(Path.DirectorySeparatorChar, '/') + "/"; url = service.Configuration[AppsettingsPolicy.ApplicationUrl] + webRootPath + filePath + orderKey; @@ -136,7 +138,7 @@ namespace CloudBuilder.Security.Policy { var webRootPath = service.Configuration[ServiceSettingsPolicy.RequestPath] ?? ""; var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory] ?? ""; - var upload = (service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory] ?? "").Replace(phy ?? "", ""); + var upload = (ServiceSettingsPolicy.GetDmsFileBackupDirectory(service) ?? "").Replace(phy ?? "", ""); var fileExtension = Path.GetExtension(orderKey);//获取文件格式,拓展名 // 使用Path.Combine拼接路径,再将系统分隔符转为URL标准正斜杠 @@ -148,10 +150,30 @@ namespace CloudBuilder.Security.Policy public static string PackFilePath(IApplicationService service, string createdBy, string orderKey) { - var backup = service.Configuration[ServiceSettingsPolicy.DmsFileBackupDirectory]!; + var backup = ServiceSettingsPolicy.GetDmsFileBackupDirectory(service)!; var fileExtension = Path.GetExtension(orderKey).Replace(".", "");//获取文件格式,拓展名 return Path.Combine(backup, createdBy, fileExtension, orderKey); } + + /// + /// 拼装头像访问地址。分片上传合并后的文件在备份目录:{BackupFileDirectory}/{folderName}/{扩展名}/{文件名} + /// + public static string PackAvatarUrl(IApplicationService service, string folderName, string fileName) + { + if (string.IsNullOrEmpty(fileName)) return null; + + var webRootPath = service.Configuration[ServiceSettingsPolicy.RequestPath] ?? ""; + var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory] ?? ""; + + var fileExtension = (Path.GetExtension(fileName) ?? "").Replace(".", "").ToLower();//获取文件格式,拓展名 + if (string.IsNullOrEmpty(fileExtension)) fileExtension = "ext"; + + var backup = (ServiceSettingsPolicy.GetBackupFileDirectory(service) ?? "").Replace(phy ?? "", ""); + + var filePathRel = Path.Combine(backup, folderName ?? "", fileExtension, ""); + var filePath = filePathRel.Replace(Path.DirectorySeparatorChar, '/') + "/"; + return service.Configuration[AppsettingsPolicy.ApplicationUrl] + webRootPath + filePath + fileName; + } } } diff --git a/CloudBuilder/CloudBuilder.Security/Policy/ServiceSettingsPolicy.cs b/CloudBuilder/CloudBuilder.Security/Policy/ServiceSettingsPolicy.cs index 0c17b92..34d3413 100644 --- a/CloudBuilder/CloudBuilder.Security/Policy/ServiceSettingsPolicy.cs +++ b/CloudBuilder/CloudBuilder.Security/Policy/ServiceSettingsPolicy.cs @@ -1,4 +1,5 @@ -using System; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,10 +10,13 @@ namespace CloudBuilder.Security.Policy { public class ServiceSettingsPolicy { - public const string DmsFileScaleDirectory = "FileServiceSettings:DmsFileScaleDirectory"; public const string PhysicalFileDirectory = "FileServiceSettings:PhysicalFileDirectory"; - public const string DmsFileUploadDirectory = "FileServiceSettings:DmsFileUploadDirectory"; - public const string DmsFileBackupDirectory = "FileServiceSettings:DmsFileBackupDirectory"; + public const string ScaleFileDirectory = "FileServiceSettings:ScaleFileDirectory"; + public const string BackupFileDirectory = "FileServiceSettings:BackupFileDirectory"; + public const string UploadFileDirectory = "FileServiceSettings:UploadFileDirectory"; + + public const string DmsFileDirectory = "FileServiceSettings:DmsFileDirectory"; + public const string RequestPath = "FileServiceSettings:RequestPath"; public const string ExcelOutputDirectory = "FileServiceSettings:ExcelOutputDirectory"; @@ -20,5 +24,38 @@ namespace CloudBuilder.Security.Policy public const string FfmpegPictrue = "Ffmpeg:Pictrue"; public const string FfmpegArguments = "Ffmpeg:Arguments"; + public static string GetPhysicalFileDirectory(IApplicationService service) + { + return service.Configuration[PhysicalFileDirectory]; + } + public static string GetUploadFileDirectory(IApplicationService service) + { + return service.Configuration[UploadFileDirectory]; + } + + public static string GetBackupFileDirectory(IApplicationService service) + { + return service.Configuration[BackupFileDirectory]; + } + + public static string GetScaleFileDirectory(IApplicationService service) + { + return service.Configuration[ScaleFileDirectory]; + } + + public static string GetDmsFileScaleDirectory(IApplicationService service) + { + return Path.Combine(service.Configuration[ScaleFileDirectory], service.Configuration[DmsFileDirectory]); + } + + public static string GetDmsFileBackupDirectory(IApplicationService service) + { + return Path.Combine(service.Configuration[BackupFileDirectory], service.Configuration[DmsFileDirectory]); + } + + public static string GetDmsFileUploadDirectory(IApplicationService service) + { + return Path.Combine(service.Configuration[UploadFileDirectory], service.Configuration[DmsFileDirectory]); + } } } diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Master/DmsFileController.auto.cs b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Master/DmsFileController.auto.cs index 981ead4..83e5e62 100644 --- a/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Master/DmsFileController.auto.cs +++ b/CloudBuilder/CloudBuilder.Web.Entry/Controllers/Master/DmsFileController.auto.cs @@ -442,6 +442,28 @@ this.dmsFileService= dmsFileService; dmsFileService.UploadFile(); + return string.Empty; + } + catch (ValidatedException vex) + { + return vex; + } + catch (Exception ex) + { + return new ServiceErrorException(ex); + } + } + + [PermissionOperate(name: "DmsFile", operate: "Insert")] + [HttpPost] + [UnitOfWork] + public dynamic UploadDmsFile() + { + try + { + + dmsFileService.UploadDmsFile(); + return string.Empty; } catch (ValidatedException vex) diff --git a/CloudBuilder/CloudBuilder.Web.Entry/appsettings.json b/CloudBuilder/CloudBuilder.Web.Entry/appsettings.json index e4e9ec1..7e977d9 100644 --- a/CloudBuilder/CloudBuilder.Web.Entry/appsettings.json +++ b/CloudBuilder/CloudBuilder.Web.Entry/appsettings.json @@ -56,10 +56,11 @@ }, "FileServiceSettings": { "PhysicalFileDirectory": "D:\\Net8\\FileServer", + "UploadFileDirectory": "D:\\Net8\\FileServer\\Upload", + "BackupFileDirectory": "D:\\Net8\\FileServer\\Backup", + "ScaleFileDirectory": "D:\\Net8\\FileServer\\Backup", "RequestPath": "/FileServer", //如果是IIS反向代理来的,那么要在本地给这个文件添加IUSR,IIS_IUSRS权限 - "DmsFileUploadDirectory": "D:\\Net8\\FileServer\\Upload\\DmsFile", //上传文件目录,有可能是分片文件,仅当临时文件使用 - "DmsFileBackupDirectory": "D:\\Net8\\FileServer\\Backup\\DmsFile", //这个是备份目录,也是完整文件目录,原文件目录 - "DmsFileScaleDirectory": "D:\\Net8\\FileServer\\Scale\\DmsFile", //这个是压缩图片或者视频目录 + "DmsFileDirectory": "DmsFile", "ExcelOutputDirectory": "D:\\Net8\\FileServer\\Output" }, "Ffmpeg": { diff --git a/WebVue/src/components/basic/DmsFileEnquiryHelp.vue b/WebVue/src/components/basic/DmsFileEnquiryHelp.vue new file mode 100644 index 0000000..254de42 --- /dev/null +++ b/WebVue/src/components/basic/DmsFileEnquiryHelp.vue @@ -0,0 +1,405 @@ + + + + + diff --git a/WebVue/src/components/basic/DragModal.vue b/WebVue/src/components/basic/DragModal.vue index ba2f9fa..fd926dd 100644 --- a/WebVue/src/components/basic/DragModal.vue +++ b/WebVue/src/components/basic/DragModal.vue @@ -2,12 +2,12 @@
@@ -38,7 +38,7 @@ + + diff --git a/WebVue/src/components/basic/OperatorStation.vue b/WebVue/src/components/basic/OperatorStation.vue index c54951f..28fd752 100644 --- a/WebVue/src/components/basic/OperatorStation.vue +++ b/WebVue/src/components/basic/OperatorStation.vue @@ -84,11 +84,9 @@ -
- - -
+ + + diff --git a/WebVue/src/components/basic/Toolbar.vue b/WebVue/src/components/basic/Toolbar.vue index a15adde..e3dcdbc 100644 --- a/WebVue/src/components/basic/Toolbar.vue +++ b/WebVue/src/components/basic/Toolbar.vue @@ -139,16 +139,56 @@ - +
+ +
+ + + +
+
+ + + + + + + + +``` + +### 2. 使用内置按钮 + +```vue + +``` + +### 3. 自定义触发元素(头像上传场景) + +点击头像即上传,并可在遮罩上显示进度百分比。`file-path="FamilyPersonAvatar"` 指定头像保存目录,`success` 里用**最后一个分片的文件名**作为头像文件名(如 `690340e5-7c65-49e4-8d31-3528daf10bc4-3-3.jpg`)。 + +```vue + + + +``` + +### 4. 直接上传一个已有的 File 对象 + +```ts +// 例如从拖拽 / 剪贴板获取的 File +const [file] = e.dataTransfer.files; +await fileUploadRef.value?.upload(file); +``` + +--- + +## 八、注意事项 + +1. **头像等场景的返回值**:`success` 里的 `response` 是**最后一个分片请求的响应体**,不一定是最终文件的 URL。若后端返回的是合并状态而非地址,用 `fileName`(最后一个分片文件名,`uid-total-total.扩展名`)配合 `path` 作为文件标识去查询/拼接最终地址;`fileName` 也是 DMS 记录该文件的 `OrderKey`。 +2. **`FilePath` 为空**:表示上传到 DMS 根目录。如果后端要求必须有目录,请通过 `file-path` 或 `resolve-file-path` 显式指定。 +3. **`headers` 覆盖规则**:`Authorization`、`Content-Type`、`FilePath` 会被组件强制覆盖,不要通过 `headers` 传这三个键。 +4. **`disabled` 的作用范围**:只拦截用户交互(`trigger()`),不拦截 `upload(file)`;如需完全禁止,请在调用前自行判断。 +5. **分片合并延时**:DMS 在收到最后一个分片后需要时间合并,建议 `success` 后延迟刷新列表(见示例 1)。 +6. **多选**:`multiple` 为 `true` 时,所选文件会逐个进入上传流程,但受 `uploading` 标记限制,实际仍是一个接一个串行执行。 diff --git a/WebVue/src/service/master/dmsFileService.ts b/WebVue/src/service/master/dmsFileService.ts index fad702b..bab396a 100644 --- a/WebVue/src/service/master/dmsFileService.ts +++ b/WebVue/src/service/master/dmsFileService.ts @@ -218,6 +218,15 @@ class DmsFileService{ ) }; + async UploadDmsFile() { + return request( + { + url: "/DmsFile/UploadDmsFile", + method: "post", + } + ) + }; + async FindM3u8Path(data: number) { return request( { diff --git a/WebVue/src/styles/ft-mobile.less b/WebVue/src/styles/ft-mobile.less new file mode 100644 index 0000000..448bba3 --- /dev/null +++ b/WebVue/src/styles/ft-mobile.less @@ -0,0 +1,488 @@ +/* ==================== Operation 页面移动端样式(与 FamilyTreeOperation 保持一致) ==================== + * 使用方式:主内容容器加 class="page-main ft-page",只读态再加 ft-readonly + *
+ * 结构:ft-hero(顶部信息卡) / ft-card + ft-card-title + ft-grid + ft-field(字段卡) + * ft-list + ft-item(列表卡) / ft-detail-*(图片明细卡) + */ + +.page-main.ft-page { + padding: 12px 12px 96px 12px; + -webkit-overflow-scrolling: touch; +} + +/* 顶部信息卡 */ +.page-main.ft-page .ft-hero { + display: flex; + align-items: center; + gap: 12px; + padding: 14px; + margin-bottom: 12px; + border: 1px solid #e8f1ff; + border-radius: 14px; + background: linear-gradient(135deg, #f2f8ff 0%, #ffffff 70%); + box-shadow: 0 2px 10px rgba(22, 119, 255, 0.06); +} + +.page-main.ft-page .ft-hero-icon { + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: center; + width: 52px; + height: 52px; + border-radius: 14px; + color: #fff; + font-size: 24px; + background: linear-gradient(135deg, #1677ff 0%, #69b1ff 100%); + box-shadow: 0 2px 8px rgba(22, 119, 255, 0.28); +} + +.page-main.ft-page .ft-hero-main { + flex: 1 1 auto; + min-width: 0; +} + +.page-main.ft-page .ft-hero-name { + font-size: 18px; + font-weight: 600; + line-height: 1.35; + color: #1f2329; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.page-main.ft-page .ft-hero-meta { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-top: 6px; +} + +.page-main.ft-page .ft-chip { + display: inline-block; + padding: 1px 10px; + border-radius: 10px; + background: rgba(22, 119, 255, 0.08); + color: #1677ff; + font-size: 12px; + line-height: 18px; +} + +/* 分组卡片 */ +.page-main.ft-page .ft-card { + padding: 12px 14px 14px; + margin-bottom: 12px; + border: 1px solid #eef0f4; + border-radius: 14px; + background: #fff; + box-shadow: 0 1px 6px rgba(0, 0, 0, 0.04); +} + +.page-main.ft-page .ft-card-title { + display: flex; + align-items: center; + gap: 8px; + padding-bottom: 10px; + font-size: 14px; + font-weight: 600; + color: #1f2329; +} + +.page-main.ft-page .ft-card-title::before { + content: ""; + width: 3px; + height: 14px; + border-radius: 2px; + background: #1677ff; +} + +/* 字段栅格:手机单列,宽屏自动多列 */ +.page-main.ft-page .ft-grid { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 10px 16px; +} + +@media (min-width: 576px) { + .page-main.ft-page .ft-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (min-width: 1200px) { + .page-main.ft-page .ft-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +.page-main.ft-page .ft-field { + min-width: 0; +} + +.page-main.ft-page .ft-field-full { + grid-column: 1 / -1; +} + +.page-main.ft-page .ft-label { + margin-bottom: 4px; + font-size: 13px; + line-height: 20px; + color: #646a73; +} + +.page-main.ft-page .ft-required { + margin-left: 2px; + color: #ff4d4f; +} + +.page-main.ft-page .ft-check { + display: flex; + align-items: center; + min-height: 40px; + font-size: 14px; + color: #1f2329; +} + +.page-main.ft-page .ft-inline { + display: flex; + align-items: center; + gap: 6px; +} + +.page-main.ft-page .ft-inline .ft-inline-main { + flex: 1 1 auto; + min-width: 0; +} + +.page-main.ft-page .ft-inline .ft-inline-btn { + flex: 0 0 auto; +} + +.page-main.ft-page .ft-full-btn { + width: 100%; +} + +/* 控件外观 */ +.page-main.ft-page .ant-input, +.page-main.ft-page .ant-input-affix-wrapper, +.page-main.ft-page .ant-select-selector, +.page-main.ft-page .ant-picker, +.page-main.ft-page .ant-input-number { + border-radius: 10px !important; +} + +.page-main.ft-page .ant-collapse-content-box { + padding: 0 !important; +} + +/* 查看态:弱化边框与底色,像纯文本一样易读 */ +.page-main.ft-page.ft-readonly .ant-input, +.page-main.ft-page.ft-readonly textarea.ant-input, +.page-main.ft-page.ft-readonly .ant-input-affix-wrapper, +.page-main.ft-page.ft-readonly .ant-select-selector, +.page-main.ft-page.ft-readonly .ant-picker { + border-color: #f0f1f3; + background: #fafbfc; + color: #1f2329; + box-shadow: none; +} + +.page-main.ft-page.ft-readonly .ant-input[readonly], +.page-main.ft-page.ft-readonly .ant-input[disabled] { + color: #1f2329; + cursor: default; +} + +.page-main.ft-page.ft-readonly .ant-select-disabled .ant-select-selector { + color: #1f2329; +} + +.page-main.ft-page.ft-readonly .ant-select-disabled .ant-select-arrow, +.page-main.ft-page.ft-readonly .ant-picker-disabled .ant-picker-suffix { + display: none; +} + +/* 折叠面板去边框 */ +.page-main.ft-page .ft-collapse { + border: none; + background: transparent; +} + +.page-main.ft-page .ft-collapse > .ant-collapse-item { + border-bottom: none; +} + +.page-main.ft-page .ft-collapse .ant-collapse-header { + padding: 8px 0 !important; + font-size: 14px; + font-weight: 600; + color: #1f2329; +} + +.page-main.ft-page .ft-collapse .ant-collapse-content-box { + padding: 0 0 4px 0 !important; +} + +/* ==================== 列表卡(成员 / 目录 / 群组明细) ==================== */ +.page-main.ft-page .ft-list { + display: flex; + flex-direction: column; + gap: 10px; +} + +.page-main.ft-page .ft-item { + overflow: hidden; + border: 1px solid #eef0f4; + border-radius: 12px; + background: #fff; + transition: + border-color 0.2s, + box-shadow 0.2s; +} + +.page-main.ft-page .ft-item-selected { + border-color: #1677ff; + box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.12); +} + +.page-main.ft-page .ft-item-head { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 12px; + border-bottom: 1px solid #eef0f4; + background: #f7f9fc; +} + +.page-main.ft-page .ft-item-head-plain { + border-bottom: none; + background: transparent; +} + +.page-main.ft-page .ft-item-index { + flex: 0 0 auto; + display: flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + border-radius: 50%; + background: #e8f1ff; + color: #1677ff; + font-size: 12px; + font-weight: 600; +} + +.page-main.ft-page .ft-item-title { + flex: 1 1 auto; + min-width: 0; + display: flex; + align-items: center; + gap: 6px; +} + +.page-main.ft-page .ft-item-name { + overflow: hidden; + font-size: 15px; + font-weight: 600; + color: #1f2329; + white-space: nowrap; + text-overflow: ellipsis; +} + +.page-main.ft-page .ft-item-link { + color: #1677ff; + cursor: pointer; +} + +.page-main.ft-page .ft-item-tag { + flex: 0 0 auto; + margin: 0; + border-radius: 8px; + border-color: #d6e4ff; + background: #f0f5ff; + color: #1677ff; +} + +.page-main.ft-page .ft-item-actions { + flex: 0 0 auto; + display: flex; + align-items: center; + gap: 12px; +} + +.page-main.ft-page .ft-action { + font-size: 22px; + line-height: 1; + cursor: pointer; +} + +.page-main.ft-page .ft-action-delete { + color: #ff4d4f; +} + +.page-main.ft-page .ft-item-body { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 10px 14px; + padding: 12px; +} + +@media (min-width: 576px) { + .page-main.ft-page .ft-item-body { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (min-width: 1200px) { + .page-main.ft-page .ft-item-body { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +.page-main.ft-page .ft-item-field { + min-width: 0; +} + +.page-main.ft-page .ft-item-label { + display: block; + margin-bottom: 4px; + font-size: 12px; + color: #8a919f; +} + +.page-main.ft-page .ft-item-text { + display: block; + min-height: 22px; + font-size: 14px; + color: #1f2329; + word-break: break-all; +} + +.page-main.ft-page .ft-empty { + padding: 20px 0; + border: 1px dashed #e5e8ef; + border-radius: 12px; + background: #fafbfc; + text-align: center; + font-size: 13px; + color: #8a919f; +} + +.page-main.ft-page .ft-add-btn { + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + height: 42px; + border-radius: 12px; + border-style: dashed; + color: #1677ff; +} + +/* ==================== 图片明细卡 ==================== */ +.page-main.ft-page .ft-detail-list { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 12px; +} + +@media (min-width: 576px) { + .page-main.ft-page .ft-detail-list { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (min-width: 1200px) { + .page-main.ft-page .ft-detail-list { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +.page-main.ft-page .ft-detail { + overflow: hidden; + border: 1px solid #eef0f4; + border-radius: 12px; + background: #fff; + transition: + border-color 0.2s, + box-shadow 0.2s; +} + +.page-main.ft-page .ft-detail-selected { + border-color: #1677ff; + box-shadow: 0 0 0 2px rgba(22, 119, 255, 0.12); +} + +.page-main.ft-page .ft-detail-cover, +.page-main.ft-page .ft-detail-cover img { + display: block; + width: 100%; + height: 180px; + object-fit: cover; + background: #f2f4f8; +} + +.page-main.ft-page .ft-detail-main { + padding: 10px 12px; +} + +.page-main.ft-page .ft-detail-title { + font-size: 15px; + font-weight: 600; + color: #1f2329; + word-break: break-all; +} + +.page-main.ft-page .ft-detail-sub { + margin-top: 4px; + font-size: 13px; + color: #8a919f; + word-break: break-all; +} + +.page-main.ft-page .ft-detail-actions { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 18px; + padding: 8px 12px; + border-top: 1px solid #eef0f4; + background: #fafbfc; +} + +.page-main.ft-page .ft-detail-actions > span { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 13px; + color: #1677ff; + cursor: pointer; +} + +.page-main.ft-page .ft-detail-actions > span.ft-action-danger { + color: #ff4d4f; +} + +/* ==================== 手机端 ==================== */ +@media (max-width: 575px) { + .page-main.ft-page { + padding-left: 10px; + padding-right: 10px; + } + + /* 16px 字号可避免 iOS 聚焦输入框时页面被自动放大 */ + .page-main.ft-page .ant-input, + .page-main.ft-page .ant-input-affix-wrapper, + .page-main.ft-page .ant-select-selector, + .page-main.ft-page .ant-select-selection-item, + .page-main.ft-page .ant-select-selection-placeholder, + .page-main.ft-page .ant-picker { + font-size: 16px; + } + + .page-main.ft-page .ft-item-body { + grid-template-columns: minmax(0, 1fr); + } +} diff --git a/WebVue/src/views/master/DmsFileDeleteEnquiry.vue b/WebVue/src/views/master/DmsFileDeleteEnquiry.vue index ffd758c..b0ae11b 100644 --- a/WebVue/src/views/master/DmsFileDeleteEnquiry.vue +++ b/WebVue/src/views/master/DmsFileDeleteEnquiry.vue @@ -4,9 +4,9 @@ - (""); -const fileList = ref([]); -const uploadUrl = ref(WebSitePolicy.WebApiRoot + "DmsFile/UploadFile"); -if (process.env.NODE_ENV === "development") { - uploadUrl.value = WebSitePolicy.WebApiRootDev + "/DmsFile/UploadFile"; -} else { - uploadUrl.value = WebSitePolicy.WebApiRoot + "/DmsFile/UploadFile"; -} - const currFilePath = ref(""); -const headers = ref({ - Authorization: useLoginProfileStore().getToken(), - "Content-Type": "multipart/form-data", - FilePath: currFilePath.value, -}); - const bindOptions = ref([]); const datas = ref([]); const pagingParams = ref({ pageSize: 999999, page: 1 }); @@ -288,97 +269,6 @@ onMounted(async () => { onSearchByFilePath(rootPath.value); }); -const beforeUpload: UploadProps["beforeUpload"] = async (file) => { - if (!file || typeof file.size !== "number") { - return false; - } - loading.value = true; - fileList.value = [...(fileList.value || []), file]; - const chunks = splitFile(file); - - let bindOption: BindOption = bindOptions.value.filter( - (x) => x.BindValue == DmsFileUploadDeleteLogViewDisplayData.DB_FILE_PATH, - )[0]; - currFilePath.value = headers.value.FilePath = bindOption.Value; - let i = 1; - let fileSize = file.size; - let uid: string = uuidv4(); - spinTip.value = "上传中(1/" + chunks.length + ")..."; - await uploadChunk(chunks, file.name, uid, i); - - spinTip.value = "加载中..."; - return false; -}; - -const uploadChunk = async ( - chunks: any, - fileName: string, - uid: string, - index: number, -) => { - const formData = new FormData(); - - const fileExtension = fileName.split(".").pop(); - formData.append( - fileName, - chunks[index - 1], - uid + - "-" + - index.toString() + - "-" + - chunks.length.toString() + - "." + - fileExtension, - ); - - if (process.env.NODE_ENV === "development") { - axios.defaults.baseURL = WebSitePolicy.WebApiRootDev; - axios.defaults.withCredentials = true; - } else { - axios.defaults.baseURL = WebSitePolicy.WebApiRoot; - } - try { - let response = await axios.create().request({ - url: "/DmsFile/UploadFile", - method: "post", - data: formData, - headers: headers.value, - }); - - if (response.status == 200 && index < chunks.length) { - spinTip.value = "上传中(" + (index + 1) + "/" + chunks.length + ")..."; - await uploadChunk(chunks, fileName, uid, index + 1); - } else if (index == chunks.length) { - let sec: number = 2500; - if (index > 25) sec = index * 100; - spinTip.value = "加载中..."; - setTimeout(function () { - onReSearch(); - }, sec); - } - } catch (error) { - loading.value = false; - spinTip.value = "加载中..."; - } -}; - -const CHUNK_SIZE = 1024 * 1024; - -const splitFile = (file: any) => { - const chunks: Blob[] = []; - if (!file || typeof file.size !== "number" || typeof file.slice !== "function") { - return chunks; - } - let start = 0; - while (start < file.size) { - const end = Math.min(start + CHUNK_SIZE, file.size); - const chunk = file.slice(start, end); - chunks.push(chunk); - start += CHUNK_SIZE; - } - return chunks; -}; - const onSelectChange = (selected: DmsFileUploadDeleteLogViewDisplayData[]) => { keys.value = selected; }; @@ -617,7 +507,6 @@ const onSearchByFilePath = async (fvalue: string) => { ); previousFilePath.value = unref(currFilePath.value); currFilePath.value = fvalue; - headers.value.FilePath = fvalue; isSearched.value = true; if (currentSearchCriteria.value && fvalue && fvalue.length > 0) { currentSearchCriteria.value.Filter = []; diff --git a/WebVue/src/views/master/DmsFileEnquiry.vue b/WebVue/src/views/master/DmsFileEnquiry.vue index ae1e105..fd1a6e9 100644 --- a/WebVue/src/views/master/DmsFileEnquiry.vue +++ b/WebVue/src/views/master/DmsFileEnquiry.vue @@ -5,11 +5,13 @@ @refresh="onReSearch" @search="onSearchByName" @breadcrumb-click="onBreadcrumbClick" /> + :can-amend="canAmend" :can-delete="canDelete" :can-view="canView" + :resolve-file-path="resolveUploadFilePath" @create-folder="onCreate" @upload-start="onUploadStart" + @upload-progress="onUploadProgress" @upload-success="onUploadSuccess" @upload-error="onUploadError" + @download="onDownloadSelected" @share="onShareSelected" @publish="onPublishSelected" + @view-preview="onViewPreviewSelected" @play-video="onUrlVideoPlayItem" @play-audio="onPlayAudioItem" + @pause-audio="onPauseAudio" @continue-audio="onContinueAudio" @preview="onPreviewSelected" + @rename="onAmendSelected" @move="onMoveSelected" @delete="onDeleteSelected" /> @@ -68,10 +70,8 @@ import { notification } from "ant-design-vue"; import { SearchCriteriaResultData } from "@/data/auto/searchCriteriaResultData"; import dmsFolder from "./DmsFolderModal.vue"; import { useLoginProfileStore } from "@/store/modules/loginProfile"; -import type { UploadProps } from "ant-design-vue"; import { WebSitePolicy } from "@/policy/custom/webSitePolicy"; import { orderBy } from "lodash-es"; -import axios from "axios"; import VideoPlay from "./PlayVideo.vue"; import { Howl } from "howler"; import { PublishVideoEntity } from "@/data/auto/publishVideoEntity"; @@ -79,7 +79,6 @@ import publishVideoService from "@/service/master/publishVideoService"; import { useWindowSize } from "@vueuse/core"; import fileTypePolicy from "@/policy/custom/fileTypePolicy"; import { PublishAudioEntity } from "@/data/auto/publishAudioEntity"; -import { v4 as uuidv4 } from "uuid"; import { FamilyFolderFavoriteViewEntity } from "@/data/auto/familyFolderFavoriteViewEntity"; import { DmsFileEntity } from "@/data/auto/dmsFileEntity"; import { PublishData } from "@/data/auto/publishData"; @@ -113,12 +112,11 @@ const route = useRoute(); const router = useRouter(); const previousFilePath = ref(""); -const fileList = ref([]); -const uploadUrl = ref(WebSitePolicy.WebApiRoot + "DmsFile/UploadFile"); +const uploadUrl = ref(WebSitePolicy.WebApiRoot + "DmsFile/UploadDmsFile"); if (process.env.NODE_ENV === "development") { - uploadUrl.value = WebSitePolicy.WebApiRootDev + "/DmsFile/UploadFile"; + uploadUrl.value = WebSitePolicy.WebApiRootDev + "/DmsFile/UploadDmsFile"; } else { - uploadUrl.value = WebSitePolicy.WebApiRoot + "/DmsFile/UploadFile"; + uploadUrl.value = WebSitePolicy.WebApiRoot + "/DmsFile/UploadDmsFile"; } const currFilePath = ref(""); @@ -276,99 +274,35 @@ onMounted(async () => { onSearchByFilePath(rootPath.value); }); -const beforeUpload: UploadProps["beforeUpload"] = async (file) => { - if (!file || typeof file.size !== "number") { - return false; - } - loading.value = true; - fileList.value = [...(fileList.value || []), file]; - const chunks = splitFile(file); - - let bindOption: BindOption = bindOptions.value.filter( +/** 解析上传目标文件夹(DMS 当前路径) */ +const resolveUploadFilePath = () => { + const bindOption = bindOptions.value.filter( (x) => x.BindValue == DmsFileUploadViewDisplayData.DB_FILE_PATH, )[0]; - currFilePath.value = headers.value.FilePath = bindOption.Value; - let i = 1; - let fileSize = file.size; - let uid: string = uuidv4(); - spinTip.value = "上传中(1/" + chunks.length + ")..."; - await uploadChunk(chunks, file.name, uid, i); + return bindOption?.Value || currFilePath.value; +}; +const onUploadStart = () => { + loading.value = true; +}; + +const onUploadProgress = (payload: { text?: string }) => { + spinTip.value = payload?.text || "上传中..."; +}; + +const onUploadSuccess = (payload: { total?: number }) => { + const total = payload?.total ?? 1; + let sec = 2500; + if (total > 25) sec = total * 100; spinTip.value = "加载中..."; - return false; + setTimeout(() => { + onReSearch(); + }, sec); }; -const uploadChunk = async ( - chunks: any, - fileName: string, - uid: string, - index: number, -) => { - const formData = new FormData(); - - const fileExtension = fileName.split(".").pop(); - formData.append( - fileName, - chunks[index - 1], - uid + - "-" + - index.toString() + - "-" + - chunks.length.toString() + - "." + - fileExtension, - ); - - if (process.env.NODE_ENV === "development") { - axios.defaults.baseURL = WebSitePolicy.WebApiRootDev; - axios.defaults.withCredentials = true; - } else { - axios.defaults.baseURL = WebSitePolicy.WebApiRoot; - } - try { - let response = await axios.create().request({ - url: "/DmsFile/UploadFile", - method: "post", - data: formData, - headers: headers.value, - }); - - if (response.status == 200 && index < chunks.length) { - spinTip.value = "上传中(" + (index + 1) + "/" + chunks.length + ")..."; - await uploadChunk(chunks, fileName, uid, index + 1); - } else if (index == chunks.length) { - let sec: number = 2500; - if (index > 25) sec = index * 100; - spinTip.value = "加载中..."; - setTimeout(function () { - onReSearch(); - }, sec); - } - } catch (error) { - loading.value = false; - spinTip.value = "加载中..."; - } -}; - -const CHUNK_SIZE = 1 * 1024 * 1024; - -const splitFile = (file: any) => { - const chunks: Blob[] = []; - if ( - !file || - typeof file.size !== "number" || - typeof file.slice !== "function" - ) { - return chunks; - } - let start = 0; - while (start < file.size) { - const end = Math.min(start + CHUNK_SIZE, file.size); - const chunk = file.slice(start, end); - chunks.push(chunk); - start += CHUNK_SIZE; - } - return chunks; +const onUploadError = () => { + loading.value = false; + spinTip.value = "加载中..."; }; const onSelectChange = (selected: DmsFileUploadViewDisplayData[]) => { diff --git a/WebVue/src/views/master/FamilyGroupOperation.vue b/WebVue/src/views/master/FamilyGroupOperation.vue index bc0cdb1..1c50b68 100644 --- a/WebVue/src/views/master/FamilyGroupOperation.vue +++ b/WebVue/src/views/master/FamilyGroupOperation.vue @@ -7,64 +7,33 @@
- + " />
- +
- 查询 - 重置 - 新增 + 查询 + 重置 + 新增
-
+
@@ -90,57 +59,33 @@
群组代码
- +
群组名称*
- +
群组描述
- +
公开设置
- +
加入申请
- +
@@ -151,11 +96,7 @@
-
+
{{ index + 1 }}
@@ -164,66 +105,38 @@
- - + +
目录名称 - +
备注 - + {{ record.Notice || "-" }}
-
+
暂无共享目录
- + 新增共享目录
@@ -235,11 +148,8 @@
-
+
{{ index + 1 }}
@@ -249,28 +159,19 @@ }}
-
- - +
+ +
@@ -280,13 +181,10 @@
-
+
暂无待审核成员
@@ -299,11 +197,8 @@
-
+
{{ index + 1 }}
@@ -314,36 +209,27 @@
- +
群组管理员 - + 管理员
-
+
暂无正式成员
@@ -355,13 +241,8 @@
-
+
{{ index + 1 }}
@@ -374,16 +255,13 @@
- +
@@ -401,13 +279,10 @@
-
+
暂无目录权限
@@ -422,59 +297,23 @@
- - 取消 + + 取消 - 取消 - 保存 + 取消 + 保存 - 修改 - - 解散 + 修改 + + 解散 @@ -484,29 +323,13 @@
- - + + - - + + @@ -782,7 +605,6 @@ onMounted(() => { canDelete.value = pContext.canDelete(route.meta.permission as string); canCreate.value = pContext.canCreate(route.meta.permission as string); computResultTableHeight(); - if (familyName.value && familyName.value.trim().length > 0) { onSearch(); } @@ -961,7 +783,7 @@ const shareFamilyGroupPermission = (folderName: string) => { }; const deleteFamilyGroupFolder = (key: number, folderName: string) => { - if (key > 0) { + if (folderName && folderName.length > 0) { dmsFileService.FindDmsFolderMapByFolderName(folderName).then((count) => { if (count > 0) { notification.info({ @@ -969,12 +791,33 @@ const deleteFamilyGroupFolder = (key: number, folderName: string) => { description: "【群组中心】请先删除共享目录下的内容再删除该目录.", placement: "topRight", }); + + return; + } + else { + data.value.FamilyGroupFolders = data.value.FamilyGroupFolders.filter( + (item) => item.FolderId !== key, + ); + + data.value.FamilyGroupPermissions = data.value.FamilyGroupPermissions.filter( + (item) => + !( + item.FolderName == folderName + ), + ); } }); } else { data.value.FamilyGroupFolders = data.value.FamilyGroupFolders.filter( (item) => item.FolderId !== key, ); + + data.value.FamilyGroupPermissions = data.value.FamilyGroupPermissions.filter( + (item) => + !( + item.FolderName == folderName + ), + ); } }; diff --git a/WebVue/src/views/master/FamilyGroupShare.vue b/WebVue/src/views/master/FamilyGroupShare.vue index f8a8735..e5595fb 100644 --- a/WebVue/src/views/master/FamilyGroupShare.vue +++ b/WebVue/src/views/master/FamilyGroupShare.vue @@ -4,9 +4,9 @@ - (""); -const fileList = ref([]); -const uploadUrl = ref(WebSitePolicy.WebApiRoot + "DmsFile/UploadFile"); -if (process.env.NODE_ENV === "development") { - uploadUrl.value = WebSitePolicy.WebApiRootDev + "/DmsFile/UploadFile"; -} else { - uploadUrl.value = WebSitePolicy.WebApiRoot + "/DmsFile/UploadFile"; -} - const currFilePath = ref(""); -const headers = ref({ - Authorization: useLoginProfileStore().getToken(), - "Content-Type": "multipart/form-data", - FilePath: currFilePath.value, -}); - const bindOptions = ref([]); const datas = ref([]); const pagingParams = ref({ pageSize: 999999, page: 1 }); @@ -288,101 +269,6 @@ onMounted(async () => { onSearchByFilePath(rootPath.value); }); -const beforeUpload: UploadProps["beforeUpload"] = async (file) => { - if (!file || typeof file.size !== "number") { - return false; - } - loading.value = true; - fileList.value = [...(fileList.value || []), file]; - const chunks = splitFile(file); - - let bindOption: BindOption = bindOptions.value.filter( - (x) => x.BindValue == FamilyDmsFileViewDisplayData.DB_FILE_PATH, - )[0]; - currFilePath.value = headers.value.FilePath = bindOption.Value; - let i = 1; - let fileSize = file.size; - let uid: string = uuidv4(); - spinTip.value = "上传中(1/" + chunks.length + ")..."; - await uploadChunk(chunks, file.name, uid, i); - - spinTip.value = "加载中..."; - return false; -}; - -const uploadChunk = async ( - chunks: any, - fileName: string, - uid: string, - index: number, -) => { - const formData = new FormData(); - - const fileExtension = fileName.split(".").pop(); - formData.append( - fileName, - chunks[index - 1], - uid + - "-" + - index.toString() + - "-" + - chunks.length.toString() + - "." + - fileExtension, - ); - - if (process.env.NODE_ENV === "development") { - axios.defaults.baseURL = WebSitePolicy.WebApiRootDev; - axios.defaults.withCredentials = true; - } else { - axios.defaults.baseURL = WebSitePolicy.WebApiRoot; - } - try { - let response = await axios.create().request({ - url: "/DmsFile/UploadFile", - method: "post", - data: formData, - headers: headers.value, - }); - - if (response.status == 200 && index < chunks.length) { - spinTip.value = "上传中(" + (index + 1) + "/" + chunks.length + ")..."; - await uploadChunk(chunks, fileName, uid, index + 1); - } else if (index == chunks.length) { - let sec: number = 2500; - if (index > 25) sec = index * 100; - spinTip.value = "加载中..."; - setTimeout(function () { - onReSearch(); - }, sec); - } - } catch (error) { - loading.value = false; - spinTip.value = "加载中..."; - } -}; - -const CHUNK_SIZE = 1024 * 1024; - -const splitFile = (file: any) => { - const chunks: Blob[] = []; - if ( - !file || - typeof file.size !== "number" || - typeof file.slice !== "function" - ) { - return chunks; - } - let start = 0; - while (start < file.size) { - const end = Math.min(start + CHUNK_SIZE, file.size); - const chunk = file.slice(start, end); - chunks.push(chunk); - start += CHUNK_SIZE; - } - return chunks; -}; - const onSelectChange = (selected: FamilyDmsFileViewDisplayData[]) => { keys.value = selected; }; diff --git a/WebVue/src/views/master/FamilyPersonOperation.vue b/WebVue/src/views/master/FamilyPersonOperation.vue index c9be0e4..3e24ecd 100644 --- a/WebVue/src/views/master/FamilyPersonOperation.vue +++ b/WebVue/src/views/master/FamilyPersonOperation.vue @@ -66,15 +66,31 @@ >
- - - +
+ + + +
+ {{ avatarUploadPercent }}% + +
+
+
{{ @@ -89,11 +105,14 @@
清除头像
@@ -499,7 +518,17 @@ diff --git a/WebVue/src/views/master/OrgDmsFileEnquiry.vue b/WebVue/src/views/master/OrgDmsFileEnquiry.vue deleted file mode 100644 index 4cec503..0000000 --- a/WebVue/src/views/master/OrgDmsFileEnquiry.vue +++ /dev/null @@ -1,1539 +0,0 @@ - - - - - diff --git a/WebVue/src/views/master/OrgFamilyGroupShare.vue b/WebVue/src/views/master/OrgFamilyGroupShare.vue deleted file mode 100644 index c3352bc..0000000 --- a/WebVue/src/views/master/OrgFamilyGroupShare.vue +++ /dev/null @@ -1,1274 +0,0 @@ - - - - diff --git a/WebVue/src/views/security/GroupOperation.vue b/WebVue/src/views/security/GroupOperation.vue index b5ec987..ec8c1cd 100644 --- a/WebVue/src/views/security/GroupOperation.vue +++ b/WebVue/src/views/security/GroupOperation.vue @@ -91,7 +91,7 @@ @click="deletePermission(record.PermissionName)" />
-
+
中文名称 {{ record.PermissionDescription || "-" }} @@ -104,30 +104,7 @@ {{ record.Dependent || "-" }}
-
- 查看 -
- -
-
-
- 新增 -
- -
-
-
- 修改 -
- -
-
-
- 删除 -
- -
-
+
-
+
扩展名称 {{ record.Dependent || "-" }} @@ -164,30 +141,7 @@ 扩展子项目中文 {{ record.DependentDetailDescription || "-" }}
-
- 查看 -
- -
-
-
- 新增 -
- -
-
-
- 修改 -
- -
-
-
- 删除 -
- -
-
+
{ bottom: 8px; border-top: 1px solid silver; } + +/* 权限明细:查看/新增/修改/删除 四个操作无论屏幕大小都保持在同一行 */ +.page-main.ft-page .ft-item-body .ft-perm-actions { + grid-column: 1 / -1; +} + +@media (min-width: 1200px) { + .page-main.ft-page .ft-item-body.permission-row { + /* 大屏:中文名称 / 扩展名称 / 权限操作 同一行 */ + grid-template-columns: 1.1fr 1.1fr 1.8fr; + } + + .page-main.ft-page .ft-item-body .ft-perm-actions { + grid-column: auto; + } +} \ No newline at end of file diff --git a/WebVue/src/views/security/components/GroupPermissionActions.vue b/WebVue/src/views/security/components/GroupPermissionActions.vue new file mode 100644 index 0000000..8d1b2b0 --- /dev/null +++ b/WebVue/src/views/security/components/GroupPermissionActions.vue @@ -0,0 +1,72 @@ + + + + +