From adcf94df4abcea610a2f35cc09690930fdcf7ff1 Mon Sep 17 00:00:00 2001 From: owen Date: Tue, 22 Sep 2026 23:09:11 +0800 Subject: [PATCH] ow --- .../PublishPhotoService.auto.cs | 56 +++++---- .../Data/PublishPhotoData.cs | 2 +- .../Data/PublishPhotoDetailDisplayData.cs | 27 ++++ .../Service/IPublishPhotoService.auto.cs | 4 +- .../Master/PublishPhotoRequest.auto.cs | 8 +- .../CloudBuilder.Web.Entry.csproj.user | 2 +- .../FolderProfile3.pubxml.user | 2 +- .../FolderProfile4.pubxml.user | 2 +- WebVue/index.html | 23 +++- WebVue/public/images/logo-512.png | Bin 0 -> 12175 bytes .../src/components/basic/PhotoSlidePlayer.vue | 115 +++++++++++++++--- WebVue/src/main.ts | 14 +++ WebVue/src/router/index.ts | 12 +- .../src/service/master/publishPhotoService.ts | 6 +- WebVue/src/styles/main.css | 23 ++++ WebVue/src/views/master/Preview.vue | 51 +++++--- WebVue/src/views/master/PreviewVideo.vue | 24 ---- 17 files changed, 274 insertions(+), 97 deletions(-) create mode 100644 CloudBuilder/CloudBuilder.Master/Data/PublishPhotoDetailDisplayData.cs create mode 100644 WebVue/public/images/logo-512.png diff --git a/CloudBuilder/CloudBuilder.Master.Service/PublishPhotoService.auto.cs b/CloudBuilder/CloudBuilder.Master.Service/PublishPhotoService.auto.cs index 7ca38f3..ddf9bc6 100644 --- a/CloudBuilder/CloudBuilder.Master.Service/PublishPhotoService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master.Service/PublishPhotoService.auto.cs @@ -1,19 +1,21 @@  -using CloudBuilder.Core.DatabaseAccessor.Entity; -using Microsoft.AspNetCore.Authorization; using CloudBuilder.Core.DatabaseAccessor; +using CloudBuilder.Core.DatabaseAccessor.Entity; +using CloudBuilder.Core.Extensions; +using CloudBuilder.Core.Policy; +using CloudBuilder.Core.Service; +using CloudBuilder.Master.Data; using CloudBuilder.Master.Entity; using CloudBuilder.Master.Policy; using CloudBuilder.Master.SearchCriteria; -using CloudBuilder.Master.Data; -using CloudBuilder.Core.Service; -using System.Diagnostics; -using CloudBuilder.Security.Service; -using Microsoft.Extensions.DependencyInjection; using CloudBuilder.Security.Entity; -using CloudBuilder.Security.Utility; using CloudBuilder.Security.Policy; -using CloudBuilder.Core.Policy; +using CloudBuilder.Security.Service; +using CloudBuilder.Security.Utility; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http.HttpResults; +using Microsoft.Extensions.DependencyInjection; +using System.Diagnostics; namespace CloudBuilder.Master.Service { public class PublishPhotoService : IPublishPhotoService @@ -73,13 +75,14 @@ namespace CloudBuilder.Master.Service data.PublishPhoto = publish; IRepository repositoryPublishPhotoDetail = repository.GetRepository>(); - data.Details = repositoryPublishPhotoDetail.DetachedEntities.Where(x => x.PublishName == publish.PublishName).OrderBy(x => x.OrderBy).ToArray(); + data.Details = repositoryPublishPhotoDetail.DetachedEntities.Where(x => x.PublishName == publish.PublishName).OrderBy(x => x.OrderBy).Select(x => new PublishPhotoDetailDisplayData(x)).ToArray(); bool isAttached = Debugger.IsAttached; if (data.Details != null || data.Details.Length > 0) foreach (var item in data.Details) { + item.FormattedPic = PackImageScareFileName(isAttached, item.FileName); item.FileName = PackImageFileName(isAttached, item.FileName); } @@ -87,10 +90,20 @@ namespace CloudBuilder.Master.Service return data; } - private string PackImageFileName(bool isAttached,string fileName) + private string PackImageScareFileName(bool isAttached, string fileName) { - return (isAttached ? service.Configuration[AppsettingsPolicy.ApplicationUrl] : "") - + fileName?.Replace("\\", "/"); + var phy = service.Configuration[ServiceSettingsPolicy.PhysicalFileDirectory] ?? ""; + var backup = (ServiceSettingsPolicy.GetDmsFileBackupDirectory(service) ?? "").Replace(phy ?? "", ""); + var scale = (ServiceSettingsPolicy.GetDmsFileScaleDirectory(service) ?? "").Replace(phy ?? "", ""); + + return (isAttached ? service.Configuration[AppsettingsPolicy.ApplicationUrl] : "") + + fileName?.Replace("\\", "/").Replace(backup.Replace("\\", "/"), scale.Replace("\\", "/")); + } + + private string PackImageFileName(bool isAttached, string fileName) + { + return (isAttached ? service.Configuration[AppsettingsPolicy.ApplicationUrl] : "") + + fileName?.Replace("\\", "/"); } [PermissionOperate(name: MasterPermissionPolicy.PublishPhoto, operate: Operate.Find)] @@ -336,9 +349,9 @@ namespace CloudBuilder.Master.Service } [AllowAnonymous] - public PublishPhotoDetailEntity[] FindPublishPhotoDetailByPublishName(string publishName) + public PublishPhotoDetailDisplayData[] FindPublishPhotoDetailByPublishName(string publishName) { - List publishPhotoDetails = new List(); + List publishPhotoDetails = new List(); if (string.IsNullOrEmpty(publishName)) return publishPhotoDetails.ToArray(); IRepository repositoryPublishPhoto = repository.GetRepository>(); @@ -348,7 +361,7 @@ namespace CloudBuilder.Master.Service return publishPhotoDetails.ToArray(); IRepository repositoryPublishPhotoDetail = repository.GetRepository>(); - PublishPhotoDetailEntity[] dtls = repositoryPublishPhotoDetail.DetachedEntities.Where(x => x.PublishName == publishName).OrderBy(x => x.OrderBy).ToArray(); + PublishPhotoDetailDisplayData[] dtls = repositoryPublishPhotoDetail.DetachedEntities.Where(x => x.PublishName == publishName).OrderBy(x => x.OrderBy).Select(x => new PublishPhotoDetailDisplayData(x)).ToArray(); if (dtls == null || dtls.Length == 0) return publishPhotoDetails.ToArray(); @@ -356,7 +369,7 @@ namespace CloudBuilder.Master.Service foreach (var item in dtls) { if (item.FileName.ToLower().StartsWith("http")) continue; - + item.FormattedPic = PackImageScareFileName(isAttached, item.FileName); item.FileName = PackImageFileName(isAttached, item.FileName); } @@ -364,16 +377,16 @@ namespace CloudBuilder.Master.Service } [AllowAnonymous] - public PublishPhotoDetailEntity[] FindPublishPhotoDetail() + public PublishPhotoDetailDisplayData[] FindPublishPhotoDetail() { PublishPhotoEntity publishPhoto = repository.DetachedEntities.Where(x => x.OwnerName == service.UserId && x.DefaultIndc == YesNoPolicy.YES).FirstOrDefault(); - List publishPhotoDetails = new List(); + List publishPhotoDetails = new List(); if (publishPhoto == null) return publishPhotoDetails.ToArray(); IRepository repositoryPublishPhotoDetail = repository.GetRepository>(); - PublishPhotoDetailEntity[] dtls = repositoryPublishPhotoDetail.DetachedEntities.Where(x => x.PublishName == publishPhoto.PublishName).OrderBy(x => x.OrderBy).ToArray(); + PublishPhotoDetailDisplayData[] dtls = repositoryPublishPhotoDetail.DetachedEntities.Where(x => x.PublishName == publishPhoto.PublishName).OrderBy(x => x.OrderBy).Select(x => new PublishPhotoDetailDisplayData(x)).ToArray(); if (dtls == null || dtls.Length == 0) return dtls; @@ -382,6 +395,7 @@ namespace CloudBuilder.Master.Service { if (item.FileName.ToLower().StartsWith("http")) continue; + item.FormattedPic = PackImageScareFileName(isAttached, item.FileName); item.FileName = (isAttached ? service.Configuration[AppsettingsPolicy.ApplicationUrl] : "") + item.FileName; } @@ -425,7 +439,7 @@ namespace CloudBuilder.Master.Service var fileExtension = Path.GetExtension(dmsFile.OrderKey); var filePathRel = Path.Combine(webRootPath.Substring(1), backup, dmsFile.CreatedBy, fileExtension.Replace(".", ""), ""); - var filePath = '/'+filePathRel.Replace(Path.DirectorySeparatorChar, '/'); + var filePath = '/' + filePathRel.Replace(Path.DirectorySeparatorChar, '/'); string path = Path.Combine(filePath, dmsFile.OrderKey); diff --git a/CloudBuilder/CloudBuilder.Master/Data/PublishPhotoData.cs b/CloudBuilder/CloudBuilder.Master/Data/PublishPhotoData.cs index 6d56558..6353a7f 100644 --- a/CloudBuilder/CloudBuilder.Master/Data/PublishPhotoData.cs +++ b/CloudBuilder/CloudBuilder.Master/Data/PublishPhotoData.cs @@ -13,7 +13,7 @@ namespace CloudBuilder.Master.Data { public PublishPhotoEntity? PublishPhoto { get; set; } - public PublishPhotoDetailEntity[]? Details { get; set; } + public PublishPhotoDetailDisplayData[]? Details { get; set; } public PublishPhotoFamilyGroupDisplayData[]? FamilyGroups { get; set; } } diff --git a/CloudBuilder/CloudBuilder.Master/Data/PublishPhotoDetailDisplayData.cs b/CloudBuilder/CloudBuilder.Master/Data/PublishPhotoDetailDisplayData.cs new file mode 100644 index 0000000..279eec7 --- /dev/null +++ b/CloudBuilder/CloudBuilder.Master/Data/PublishPhotoDetailDisplayData.cs @@ -0,0 +1,27 @@ +using CloudBuilder.Core.Authorization; +using CloudBuilder.Master.Entity; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CloudBuilder.Master.Data +{ + [NotMapped] + [TypeScript] + public class PublishPhotoDetailDisplayData : PublishPhotoDetailEntity + { + public PublishPhotoDetailDisplayData() + { + } + + public PublishPhotoDetailDisplayData(PublishPhotoDetailEntity entity) + { + CopyFrom(entity); + } + + public string? FormattedPic { get; set; } + } +} \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Master/Service/IPublishPhotoService.auto.cs b/CloudBuilder/CloudBuilder.Master/Service/IPublishPhotoService.auto.cs index d17a4a2..a5c56ef 100644 --- a/CloudBuilder/CloudBuilder.Master/Service/IPublishPhotoService.auto.cs +++ b/CloudBuilder/CloudBuilder.Master/Service/IPublishPhotoService.auto.cs @@ -15,7 +15,7 @@ namespace CloudBuilder.Master.Service void InsertPublishPhotoDetail(PublishData publishData); void InsertPublishPhotoDetailByFamilyGroup(PublishData publishData); - PublishPhotoDetailEntity[] FindPublishPhotoDetail(); - PublishPhotoDetailEntity[] FindPublishPhotoDetailByPublishName(string publishName); + PublishPhotoDetailDisplayData[] FindPublishPhotoDetail(); + PublishPhotoDetailDisplayData[] FindPublishPhotoDetailByPublishName(string publishName); } } diff --git a/CloudBuilder/CloudBuilder.Request/Master/PublishPhotoRequest.auto.cs b/CloudBuilder/CloudBuilder.Request/Master/PublishPhotoRequest.auto.cs index a4ff868..13c3f46 100644 --- a/CloudBuilder/CloudBuilder.Request/Master/PublishPhotoRequest.auto.cs +++ b/CloudBuilder/CloudBuilder.Request/Master/PublishPhotoRequest.auto.cs @@ -47,13 +47,13 @@ return Task.Run(() => serviceRequest.PostAsJsonAsync serviceRequest.PostAsync("/PublishPhoto/Delete?key=" + key.ToString())).GetAwaiter().GetResult(); } - public PublishPhotoDetailEntity[] FindPublishPhotoDetailByPublishName(string publishName) + public PublishPhotoDetailDisplayData[] FindPublishPhotoDetailByPublishName(string publishName) { -return Task.Run(() => serviceRequest.PostAsJsonAsync("/PublishPhoto/FindPublishPhotoDetailByPublishName?publishName=" + publishName.ToString())).GetAwaiter().GetResult(); } +return Task.Run(() => serviceRequest.PostAsJsonAsync("/PublishPhoto/FindPublishPhotoDetailByPublishName?publishName=" + publishName.ToString())).GetAwaiter().GetResult(); } - public PublishPhotoDetailEntity[] FindPublishPhotoDetail() + public PublishPhotoDetailDisplayData[] FindPublishPhotoDetail() { -return Task.Run(() => serviceRequest.PostAsJsonAsync ("/PublishPhoto/FindPublishPhotoDetail")).GetAwaiter().GetResult(); } +return Task.Run(() => serviceRequest.PostAsJsonAsync ("/PublishPhoto/FindPublishPhotoDetail")).GetAwaiter().GetResult(); } public void InsertPublishPhotoDetail(PublishData publishData) { diff --git a/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj.user b/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj.user index d91626f..7b23cd1 100644 --- a/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj.user +++ b/CloudBuilder/CloudBuilder.Web.Entry/CloudBuilder.Web.Entry.csproj.user @@ -1,7 +1,7 @@  - D:\Docker\CloudBuilder\CloudBuilder.Web.Entry\Properties\PublishProfiles\FolderProfile4.pubxml + D:\Docker\CloudBuilder\CloudBuilder.Web.Entry\Properties\PublishProfiles\FolderProfile3.pubxml http diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user index 4e020af..0f0ba45 100644 --- a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile3.pubxml.user @@ -3,7 +3,7 @@ <_PublishTargetUrl>C:\inetpub\wwwroot\dockwebapi2 - True|2026-09-22T03:19:19.6087109Z||;True|2026-09-22T11:09:24.9165065+08:00||;True|2026-09-21T22:40:07.1232044+08:00||;True|2026-09-21T22:35:06.9446571+08:00||;True|2026-09-21T22:27:42.1146825+08:00||;False|2026-09-21T22:27:17.6066573+08:00||;True|2026-09-21T21:01:22.8888913+08:00||;True|2026-09-21T19:15:03.4753747+08:00||;True|2026-09-21T18:08:30.0866986+08:00||;True|2026-09-21T16:51:19.8137872+08:00||;True|2026-09-21T16:30:01.0950896+08:00||;True|2026-09-21T15:09:00.2326737+08:00||;True|2026-09-21T14:47:09.6120256+08:00||;True|2026-09-21T14:16:35.3194409+08:00||;True|2026-09-21T13:54:58.2829712+08:00||;True|2026-09-21T13:36:45.3134499+08:00||;True|2026-09-19T09:48:52.0085130+08:00||;False|2026-09-19T09:47:56.1658214+08:00||;True|2026-09-17T18:50:15.9493380+08:00||;True|2026-09-17T18:11:11.5364547+08:00||;True|2026-09-17T18:07:27.7830758+08:00||;True|2026-09-17T17:58:16.5798560+08:00||;True|2026-09-17T15:37:30.9025614+08:00||;True|2026-09-17T15:25:46.9116292+08:00||;True|2026-09-17T15:05:18.6592403+08:00||;True|2026-09-17T14:57:28.7997437+08:00||;True|2026-09-17T14:36:00.6339386+08:00||;True|2026-09-17T13:56:43.2376873+08:00||;True|2026-09-16T13:56:51.8724546+08:00||;True|2026-09-15T20:44:46.6559899+08:00||;True|2026-09-13T19:02:59.5654245+08:00||;True|2026-09-10T09:14:56.2914193+08:00||;True|2026-09-09T16:40:16.6461154+08:00||;True|2026-09-08T13:55:23.1502435+08:00||;True|2026-09-08T08:04:53.4279263+08:00||;True|2026-09-07T08:48:17.4682304+08:00||;True|2026-09-04T14:39:08.7878670+08:00||;True|2026-09-04T14:35:48.2937877+08:00||;True|2026-09-04T11:45:16.1372876+08:00||;True|2026-09-04T11:42:59.9356436+08:00||;True|2026-09-03T16:05:52.5270232+08:00||;True|2026-09-03T14:52:56.8559144+08:00||;True|2026-09-02T11:08:23.8720038+08:00||;True|2026-09-02T10:58:16.8081797+08:00||;True|2026-08-26T13:34:12.3805892+08:00||;True|2026-08-25T08:31:30.7787234+08:00||;True|2026-08-20T13:10:46.4725468+08:00||;True|2026-08-20T13:10:28.3142576+08:00||;True|2026-08-19T16:10:27.3362887+08:00||;True|2026-08-19T16:01:12.6234971+08:00||;True|2026-08-19T15:42:46.6576265+08:00||;True|2026-08-19T13:39:59.9363522+08:00||;True|2026-08-19T13:36:53.0379313+08:00||;True|2026-08-19T13:31:36.0841398+08:00||;True|2026-08-19T11:44:37.5319626+08:00||;True|2026-08-19T09:36:45.6000047+08:00||;True|2026-08-19T09:34:36.8468631+08:00||;True|2026-08-19T08:35:41.2202300+08:00||;True|2026-08-18T16:20:59.0170916+08:00||; + True|2026-09-22T15:03:13.6509491Z||;True|2026-09-22T16:07:15.9177123+08:00||;True|2026-09-22T11:19:19.6087109+08:00||;True|2026-09-22T11:09:24.9165065+08:00||;True|2026-09-21T22:40:07.1232044+08:00||;True|2026-09-21T22:35:06.9446571+08:00||;True|2026-09-21T22:27:42.1146825+08:00||;False|2026-09-21T22:27:17.6066573+08:00||;True|2026-09-21T21:01:22.8888913+08:00||;True|2026-09-21T19:15:03.4753747+08:00||;True|2026-09-21T18:08:30.0866986+08:00||;True|2026-09-21T16:51:19.8137872+08:00||;True|2026-09-21T16:30:01.0950896+08:00||;True|2026-09-21T15:09:00.2326737+08:00||;True|2026-09-21T14:47:09.6120256+08:00||;True|2026-09-21T14:16:35.3194409+08:00||;True|2026-09-21T13:54:58.2829712+08:00||;True|2026-09-21T13:36:45.3134499+08:00||;True|2026-09-19T09:48:52.0085130+08:00||;False|2026-09-19T09:47:56.1658214+08:00||;True|2026-09-17T18:50:15.9493380+08:00||;True|2026-09-17T18:11:11.5364547+08:00||;True|2026-09-17T18:07:27.7830758+08:00||;True|2026-09-17T17:58:16.5798560+08:00||;True|2026-09-17T15:37:30.9025614+08:00||;True|2026-09-17T15:25:46.9116292+08:00||;True|2026-09-17T15:05:18.6592403+08:00||;True|2026-09-17T14:57:28.7997437+08:00||;True|2026-09-17T14:36:00.6339386+08:00||;True|2026-09-17T13:56:43.2376873+08:00||;True|2026-09-16T13:56:51.8724546+08:00||;True|2026-09-15T20:44:46.6559899+08:00||;True|2026-09-13T19:02:59.5654245+08:00||;True|2026-09-10T09:14:56.2914193+08:00||;True|2026-09-09T16:40:16.6461154+08:00||;True|2026-09-08T13:55:23.1502435+08:00||;True|2026-09-08T08:04:53.4279263+08:00||;True|2026-09-07T08:48:17.4682304+08:00||;True|2026-09-04T14:39:08.7878670+08:00||;True|2026-09-04T14:35:48.2937877+08:00||;True|2026-09-04T11:45:16.1372876+08:00||;True|2026-09-04T11:42:59.9356436+08:00||;True|2026-09-03T16:05:52.5270232+08:00||;True|2026-09-03T14:52:56.8559144+08:00||;True|2026-09-02T11:08:23.8720038+08:00||;True|2026-09-02T10:58:16.8081797+08:00||;True|2026-08-26T13:34:12.3805892+08:00||;True|2026-08-25T08:31:30.7787234+08:00||;True|2026-08-20T13:10:46.4725468+08:00||;True|2026-08-20T13:10:28.3142576+08:00||;True|2026-08-19T16:10:27.3362887+08:00||;True|2026-08-19T16:01:12.6234971+08:00||;True|2026-08-19T15:42:46.6576265+08:00||;True|2026-08-19T13:39:59.9363522+08:00||;True|2026-08-19T13:36:53.0379313+08:00||;True|2026-08-19T13:31:36.0841398+08:00||;True|2026-08-19T11:44:37.5319626+08:00||;True|2026-08-19T09:36:45.6000047+08:00||;True|2026-08-19T09:34:36.8468631+08:00||;True|2026-08-19T08:35:41.2202300+08:00||;True|2026-08-18T16:20:59.0170916+08:00||; \ No newline at end of file diff --git a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile4.pubxml.user b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile4.pubxml.user index 9c073e2..2b73062 100644 --- a/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile4.pubxml.user +++ b/CloudBuilder/CloudBuilder.Web.Entry/Properties/PublishProfiles/FolderProfile4.pubxml.user @@ -3,7 +3,7 @@ <_PublishTargetUrl>C:\inetpub\wwwroot\windows - True|2026-09-22T07:18:53.4935889Z||;True|2026-09-22T11:24:43.8593406+08:00||;True|2026-09-19T09:55:09.0653660+08:00||;True|2026-09-19T09:53:13.8933944+08:00||; + True|2026-09-22T15:02:08.0902556Z||;True|2026-09-22T16:47:49.2530282+08:00||;True|2026-09-22T15:18:53.4935889+08:00||;True|2026-09-22T11:24:43.8593406+08:00||;True|2026-09-19T09:55:09.0653660+08:00||;True|2026-09-19T09:53:13.8933944+08:00||; \ No newline at end of file diff --git a/WebVue/index.html b/WebVue/index.html index 1a5ca5d..0836d45 100644 --- a/WebVue/index.html +++ b/WebVue/index.html @@ -1,10 +1,27 @@ - + - + + + + + + - + 有家相册 + + + + + + +
diff --git a/WebVue/public/images/logo-512.png b/WebVue/public/images/logo-512.png new file mode 100644 index 0000000000000000000000000000000000000000..798d70237a4b8a2bfc00b6f4d7ddd8335ec20092 GIT binary patch literal 12175 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 E0OTN&g8%>k literal 0 HcmV?d00001 diff --git a/WebVue/src/components/basic/PhotoSlidePlayer.vue b/WebVue/src/components/basic/PhotoSlidePlayer.vue index 5e91440..8fae887 100644 --- a/WebVue/src/components/basic/PhotoSlidePlayer.vue +++ b/WebVue/src/components/basic/PhotoSlidePlayer.vue @@ -1,9 +1,10 @@ @@ -187,20 +202,24 @@ import { ref, computed, watch, onMounted, onBeforeUnmount } from "vue"; import { Image as AImage, message } from "ant-design-vue"; import { request } from "@/utils/request"; +import { useVModel } from "@vueuse/core"; import { DownOutlined, DownloadOutlined, CloseOutlined, PictureOutlined, EllipsisOutlined, ThunderboltOutlined, RetweetOutlined, SwapOutlined, StepBackwardFilled, StepForwardFilled, CaretRightFilled, PauseOutlined, UnorderedListOutlined, + EyeOutlined, EyeInvisibleOutlined, } from "@ant-design/icons-vue"; /** 一张图片 */ export interface PhotoSlideItem { - /** 原图地址 */ + /** 展示地址(舞台幻灯片 + 列表缩略图):一般给缩略图,轮播加载更快 */ url: string; - /** 缩略图地址(列表用,缺省用原图) */ + /** 缩略图地址(列表用,缺省用 url) */ thumb?: string; /** 名称(下载文件名) */ name?: string; + /** 原图地址:精看与下载用它,缺省退回 url */ + full?: string; } const props = withDefaults( @@ -208,10 +227,15 @@ const props = withDefaults( items?: PhotoSlideItem[]; /** 每张停留秒数 */ interval?: number; + /** 底部控制区是否显示(页面可用它做「整页全屏」) */ + controls?: boolean; }>(), - { items: () => [], interval: 5 } + { items: () => [], interval: 5, controls: true } ); -const emit = defineEmits<{ (e: "close"): void }>(); +const emit = defineEmits<{ + (e: "close"): void; + (e: "update:controls", visible: boolean): void; +}>(); /* ---------------- 基础状态 ---------------- */ const items = computed(() => props.items || []); @@ -225,12 +249,30 @@ const showList = ref(false); const menu = ref<"" | "effect" | "more">(""); const downloaded = ref(false); +/** + * 底部控制区是否显示:由功能图标行的眼睛图标切换。 + * 收起后舞台吃掉这部分空间,图片最大化;父组件可用 v-model:controls 拿到这个状态 + * 去做整页全屏(例如 Preview.vue 藏掉 layout 顶部的两条栏)。 + * + * passive: true 是关键:不传的话 useVModel 直接读写 props, + * 父组件没绑 v-model:controls 时内部改了值只会 emit 出去、props 不变, + * 按钮就"点了没反应"(与 VideoPlayer 一致)。 + */ +const controlsVisible = useVModel(props, "controls", emit, { passive: true }); + +const toggleControls = () => { + menu.value = ""; // 顺手收起可能打开的弹层(特效 / 更多) + controlsVisible.value = !controlsVisible.value; +}; + /** 舞台元素与像素尺寸:圆形格子的直径按舞台短边换算,避免非正方舞台被压成椭圆 */ const stageEl = ref(null); const stageSize = ref({ w: 0, h: 0 }); let stageRo: ResizeObserver | null = null; const current = computed(() => items.value[index.value] ?? null); +/** 精看与下载用原图(full),没单独给就退回展示地址 */ +const currentFull = computed(() => current.value?.full || current.value?.url || ""); const modeTitle = computed( () => ({ list: "顺序循环", random: "随机播放", once: "播完停止" }[mode.value]) ); @@ -789,15 +831,30 @@ const picVisible = ref(false); const setPicVisible = (v: boolean) => { picVisible.value = v; }; -/** 单击舞台:播放中先暂停(原来的行为);已经暂停则打开精看,效果同 DmsFileEnquiry 的单图精看 */ +/** + * 单击舞台:播放中先暂停(原来的行为);已经暂停则打开精看,效果同 DmsFileEnquiry 的单图精看。 + * + * 页内全屏(控制区已收起)时只切暂停/播放:那会儿没有控制条, + * 再叠一层大图预览会盖住整屏、也没有恢复入口,容易把人"困住"。 + */ const onStageClick = () => { if (!items.value.length) return; + if (!controlsVisible.value) { + toggle(); + return; + } if (isPlaying.value) { toggle(); return; } setPicVisible(true); }; + +/** 舞台提示:页内全屏时没有"看大图",文案跟着变,免得点了跟说好的不一样 */ +const stageTitle = computed(() => { + if (!controlsVisible.value) return isPlaying.value ? "单击暂停" : "单击播放"; + return isPlaying.value ? "单击暂停" : "单击看大图"; +}); const playAt = (i: number) => { index.value = i; elapsed.value = 0; @@ -848,13 +905,15 @@ const onDownload = async () => { if (!it || downloading.value) return; downloading.value = true; try { + // 下载要原图,不是舞台上那张缩略图 + const url = currentFull.value; const res = await request({ - url: it.url, + url, method: "get", responseType: "arraybuffer", }); const blobUrl = window.URL.createObjectURL(new Blob([res])); - const ext = (it.url.match(/\.(\w{2,5})(?:\?|#|$)/) || [])[1] || "jpg"; + const ext = (url.match(/\.(\w{2,5})(?:\?|#|$)/) || [])[1] || "jpg"; const a = document.createElement("a"); a.href = blobUrl; a.download = `${it.name || "image"}.${ext}`; @@ -963,11 +1022,37 @@ onBeforeUnmount(() => { cursor: pointer; } -/* 暂停后单击就是精看,光标跟着变 */ -.psp-stage.is-paused { +/* 暂停后单击就是精看,光标跟着变; + 页内全屏(.is-immersive)时单击是继续播放,不给放大镜光标,免得误导 */ +.psp-stage.is-paused:not(.is-immersive) { cursor: zoom-in; } +/* 控制区收起后的恢复入口(整页用法没有弹窗右上角按钮) */ +.psp-restore { + position: absolute; + top: 14px; + right: 14px; + z-index: 30; + display: flex; + align-items: center; + justify-content: center; + width: 34px; + height: 34px; + font-size: 18px; + color: #fff; + background: rgba(0, 0, 0, .38); + border: 0; + border-radius: 10px; + cursor: pointer; + opacity: .55; + transition: opacity .2s; +} + +.psp-restore:hover { + opacity: 1; +} + .psp-img { position: absolute; inset: 0; diff --git a/WebVue/src/main.ts b/WebVue/src/main.ts index 9d4ced2..827e58f 100644 --- a/WebVue/src/main.ts +++ b/WebVue/src/main.ts @@ -35,9 +35,23 @@ async function setupApp() { // 初始化 i18n await setupI18n(app); + setupShareImage(); + app.mount("#app"); } +/** + * 分享卡片(微信收藏/转发等)的缩略图要求绝对地址,相对路径会被忽略, + * 这里按当前域名把 index.html 里的 og:image 补全。 + */ +function setupShareImage() { + const meta = document.querySelector('meta[property="og:image"]'); + const content = meta?.getAttribute("content"); + if (meta && content && !/^https?:\/\//i.test(content)) { + meta.setAttribute("content", new URL(content, location.origin).href); + } +} + setupPlugins(); setupApp(); diff --git a/WebVue/src/router/index.ts b/WebVue/src/router/index.ts index c7d1c1d..2b18b62 100644 --- a/WebVue/src/router/index.ts +++ b/WebVue/src/router/index.ts @@ -110,7 +110,9 @@ export async function setupRouter(app: App) { ), props: true, meta: { - title: "首页", + // 这个 title 会被 App.vue 写进 document.title, + // 微信「收藏 / 分享」卡片的第一行取的就是它,所以用品牌名而不是"首页" + title: "有家相册", }, }); router.addRoute({ @@ -129,17 +131,19 @@ export async function setupRouter(app: App) { name: "dashboard", component: () => import("../layout/home.vue"), meta: { - title: "首页", + // 这里不要用 description:App.vue 会优先把 meta.description 写进 document.title, + // 而微信「收藏 / 转发」卡片的第一行取的就是 document.title,必须是品牌名, + // 否则分享出去显示的是"欢迎页" + title: "有家相册", role: "*", - description: "欢迎页", }, children: [ { path: "", name: "dashboardWelcome", meta: { + title: "有家相册", role: "*", - description: "欢迎页", }, component: () => import("../views/dashboard.vue"), }, diff --git a/WebVue/src/service/master/publishPhotoService.ts b/WebVue/src/service/master/publishPhotoService.ts index 5a4a13f..fdf0469 100644 --- a/WebVue/src/service/master/publishPhotoService.ts +++ b/WebVue/src/service/master/publishPhotoService.ts @@ -3,7 +3,7 @@ import { request,download } from "@/utils/request"; import type { PublishPhotoData } from "@/data/auto/publishPhotoData"; import type { PublishPhotoSearchCriteria } from "@/data/auto/publishPhotoSearchCriteria"; import type { PublishPhotoResultData } from "@/data/auto/publishPhotoResultData"; - import type { PublishPhotoDetailEntity } from "@/data/auto/publishPhotoDetailEntity"; + import type { PublishPhotoDetailDisplayData } from "@/data/auto/publishPhotoDetailDisplayData"; import type { PublishData } from "@/data/auto/publishData"; class PublishPhotoService{ @@ -70,7 +70,7 @@ class PublishPhotoService{ }; async FindPublishPhotoDetailByPublishName(data: string) { - return request( + return request( { url: "/PublishPhoto/FindPublishPhotoDetailByPublishName?publishName="+data, method: "post", @@ -80,7 +80,7 @@ class PublishPhotoService{ }; async FindPublishPhotoDetail() { - return request( + return request( { url: "/PublishPhoto/FindPublishPhotoDetail", method: "post", diff --git a/WebVue/src/styles/main.css b/WebVue/src/styles/main.css index dfbeaff..6377efa 100644 --- a/WebVue/src/styles/main.css +++ b/WebVue/src/styles/main.css @@ -23,4 +23,27 @@ select[readonly]:not([disabled])+.dropdown-toggle.custom-selectpicker, input[type=checkbox][readonly]:not([disabled]), input[type=radio][readonly]:not([disabled]) { background-color: #f3f3f3 !important; +} + +/* 页面级「整页全屏」(沉浸看片/看图): + body 上有 .pv-fullscreen 时才生效,该 class 由影视厅 PreviewVideo.vue、 + 图片预览 Preview.vue 在收起控制区时临时挂上,离开页面立即移除,所以不会影响其它页面。 + 1. 藏掉 layout 顶部两条栏(标题栏 + 页面头); + 2. 内容区与页面容器撑到整屏,去掉原有的 8px 内边距,做到真正的全屏铺满。 + 容器高度是行内样式(bsInfo.height - 120)、Preview 还用了负外边距,只能用 !important 覆盖。 */ +body.pv-fullscreen .layout-header, +body.pv-fullscreen .layout-page-header { + display: none !important; +} + +body.pv-fullscreen .layout-content-view { + height: 100vh !important; + padding: 0 !important; +} + +body.pv-fullscreen .pv-page { + width: 100% !important; + height: 100vh !important; + padding: 0 !important; + margin: 0 !important; } \ No newline at end of file diff --git a/WebVue/src/views/master/Preview.vue b/WebVue/src/views/master/Preview.vue index 42b9053..6873265 100644 --- a/WebVue/src/views/master/Preview.vue +++ b/WebVue/src/views/master/Preview.vue @@ -1,14 +1,14 @@