fix: 完善活动公告,修复图片生成参考图无法放大问题。
This commit is contained in:
@@ -11,6 +11,21 @@ const isLoadingData = ref(false);
|
||||
|
||||
const activeTab = ref('activity');
|
||||
|
||||
// 图片预览相关状态
|
||||
const isImageViewerVisible = ref(false);
|
||||
const currentPreviewUrl = ref('');
|
||||
|
||||
// 打开图片预览
|
||||
function openImagePreview(url: string) {
|
||||
currentPreviewUrl.value = url;
|
||||
isImageViewerVisible.value = true;
|
||||
}
|
||||
|
||||
// 关闭图片预览
|
||||
function closeImagePreview() {
|
||||
isImageViewerVisible.value = false;
|
||||
}
|
||||
|
||||
// 窗口宽度响应式状态
|
||||
const windowWidth = ref(typeof window !== 'undefined' ? window.innerWidth : 1920);
|
||||
|
||||
@@ -123,9 +138,18 @@ watch(isDialogVisible, async (newValue) => {
|
||||
:key="index"
|
||||
class="activity-item"
|
||||
>
|
||||
<!-- 活动图片 -->
|
||||
<div v-if="activity.imageUrl" class="activity-image-wrapper">
|
||||
<!-- 活动图片 - 浮动在右上方 -->
|
||||
<div v-if="activity.imageUrl" class="activity-image-wrapper" @click="openImagePreview(activity.imageUrl)">
|
||||
<img :src="activity.imageUrl" :alt="activity.title" class="activity-image">
|
||||
<!-- 放大图标提示 -->
|
||||
<div class="zoom-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
||||
<line x1="11" y1="8" x2="11" y2="14"></line>
|
||||
<line x1="8" y1="11" x2="14" y2="11"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<!-- 图片上的状态标签 -->
|
||||
<div class="activity-status-badge">
|
||||
<el-tag
|
||||
@@ -233,6 +257,16 @@ watch(isDialogVisible, async (newValue) => {
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 图片预览组件 -->
|
||||
<teleport to="body">
|
||||
<el-image-viewer
|
||||
v-if="isImageViewerVisible"
|
||||
:url-list="[currentPreviewUrl]"
|
||||
:initial-index="0"
|
||||
@close="closeImagePreview"
|
||||
/>
|
||||
</teleport>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
@@ -489,15 +523,22 @@ watch(isDialogVisible, async (newValue) => {
|
||||
|
||||
.activity-item {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
overflow: visible;
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
border: 2px solid transparent;
|
||||
background-clip: padding-box;
|
||||
|
||||
// 清除浮动,确保父容器高度正确
|
||||
&::after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@@ -525,9 +566,8 @@ watch(isDialogVisible, async (newValue) => {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.activity-image {
|
||||
transform: scale(1.1);
|
||||
filter: brightness(1.05);
|
||||
.activity-image-wrapper {
|
||||
box-shadow: 0 8px 24px rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
|
||||
.detail-link {
|
||||
@@ -545,10 +585,31 @@ watch(isDialogVisible, async (newValue) => {
|
||||
|
||||
.activity-image-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
float: right;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
margin-left: 16px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%);
|
||||
shape-outside: inset(0);
|
||||
transition: box-shadow 0.3s;
|
||||
cursor: pointer;
|
||||
z-index: 1; // 确保在内容之上
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
&:hover .activity-image {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
&:hover .zoom-icon {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
@@ -560,6 +621,7 @@ watch(isDialogVisible, async (newValue) => {
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
|
||||
z-index: 1;
|
||||
animation: shine 3s infinite;
|
||||
pointer-events: none; // 确保不拦截鼠标事件
|
||||
}
|
||||
|
||||
&::after {
|
||||
@@ -587,22 +649,22 @@ watch(isDialogVisible, async (newValue) => {
|
||||
.activity-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-fit: contain; // 等比例缩放,完整显示图片,不裁剪
|
||||
transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.activity-status-badge {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
z-index: 2;
|
||||
animation: fadeInScale 0.5s ease-out 0.3s both;
|
||||
|
||||
:deep(.el-tag) {
|
||||
border-radius: 20px;
|
||||
padding: 7px 18px;
|
||||
border-radius: 16px;
|
||||
padding: 5px 14px;
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
font-size: 11px;
|
||||
border: none;
|
||||
backdrop-filter: blur(12px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||
@@ -648,24 +710,52 @@ watch(isDialogVisible, async (newValue) => {
|
||||
}
|
||||
}
|
||||
|
||||
.zoom-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) scale(0.8);
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
backdrop-filter: blur(8px);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
pointer-events: none; // 不拦截鼠标事件,让父容器接收hover
|
||||
z-index: 10; // 提高层级,确保在状态标签之上
|
||||
|
||||
svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: #fff;
|
||||
stroke-width: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.activity-body {
|
||||
padding: 20px;
|
||||
// 内容会自动环绕浮动的图片
|
||||
position: relative;
|
||||
z-index: 0; // 确保在浮动图片之下
|
||||
}
|
||||
|
||||
.activity-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.activity-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: #1a1a1a;
|
||||
flex: 1;
|
||||
line-height: 1.4;
|
||||
line-height: 1.3;
|
||||
background: linear-gradient(135deg, #1a1a1a 0%, #4a5568 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
@@ -679,23 +769,23 @@ watch(isDialogVisible, async (newValue) => {
|
||||
|
||||
.activity-content-list {
|
||||
padding: 0;
|
||||
margin: 0 0 16px 0;
|
||||
margin: 0 0 12px 0;
|
||||
color: #4a5568;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
|
||||
.content-line {
|
||||
margin: 8px 0;
|
||||
padding-left: 18px;
|
||||
margin: 6px 0;
|
||||
padding-left: 16px;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 11px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
top: 9px;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 50%;
|
||||
}
|
||||
@@ -715,8 +805,9 @@ watch(isDialogVisible, async (newValue) => {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding-top: 16px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px dashed #e8e9eb;
|
||||
clear: both; // 清除浮动,始终在新行显示,占满100%宽度
|
||||
}
|
||||
|
||||
.activity-time-range {
|
||||
@@ -727,7 +818,7 @@ watch(isDialogVisible, async (newValue) => {
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
color: #718096;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -735,19 +826,19 @@ watch(isDialogVisible, async (newValue) => {
|
||||
|
||||
&:first-child::before {
|
||||
content: '🕐';
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 18px;
|
||||
gap: 6px;
|
||||
padding: 8px 16px;
|
||||
background: linear-gradient(135deg, #f0f1f3 0%, #e8eaed 100%);
|
||||
color: #667eea;
|
||||
border-radius: 24px;
|
||||
font-size: 13px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
@@ -1095,16 +1186,27 @@ watch(isDialogVisible, async (newValue) => {
|
||||
|
||||
.activity-item {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.activity-image-wrapper {
|
||||
height: 180px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.activity-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.activity-image-wrapper {
|
||||
float: none;
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
min-height: 180px;
|
||||
margin: 0 0 16px 0;
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.activity-status-badge {
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.activity-header {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -1183,7 +1285,18 @@ watch(isDialogVisible, async (newValue) => {
|
||||
|
||||
.activity-content {
|
||||
.activity-image-wrapper {
|
||||
float: none;
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
|
||||
.activity-item {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.activity-body {
|
||||
padding: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@ const generating = ref(false);
|
||||
const currentTaskId = ref('');
|
||||
const currentTask = ref<TaskStatusResponse | null>(null);
|
||||
const showViewer = ref(false);
|
||||
const referenceImageViewerVisible = ref(false);
|
||||
const referenceImagePreviewUrl = ref('');
|
||||
let pollTimer: any = null;
|
||||
let debounceTimer: any = null;
|
||||
|
||||
@@ -130,6 +132,17 @@ function handleRemove(file: UploadFile) {
|
||||
fileList.value.splice(index, 1);
|
||||
}
|
||||
|
||||
function handlePreview(file: UploadFile) {
|
||||
if (file.url) {
|
||||
referenceImagePreviewUrl.value = file.url;
|
||||
referenceImageViewerVisible.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
function closeReferenceImageViewer() {
|
||||
referenceImageViewerVisible.value = false;
|
||||
}
|
||||
|
||||
// Handle paste event for reference images
|
||||
function handlePaste(event: ClipboardEvent) {
|
||||
const items = event.clipboardData?.items;
|
||||
@@ -510,6 +523,7 @@ onUnmounted(() => {
|
||||
:limit="2"
|
||||
:on-change="handleFileChange"
|
||||
:on-remove="handleRemove"
|
||||
:on-preview="handlePreview"
|
||||
accept=".jpg,.jpeg,.png,.bmp,.webp"
|
||||
:class="{ 'hide-upload-btn': fileList.length >= 2 }"
|
||||
>
|
||||
@@ -644,6 +658,15 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 参考图预览组件 -->
|
||||
<teleport to="body">
|
||||
<el-image-viewer
|
||||
v-if="referenceImageViewerVisible && referenceImagePreviewUrl"
|
||||
:url-list="[referenceImagePreviewUrl]"
|
||||
@close="closeReferenceImageViewer"
|
||||
/>
|
||||
</teleport>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user