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