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 0000000..798d702 Binary files /dev/null and b/WebVue/public/images/logo-512.png differ 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 @@