完成图片管理功能
This commit is contained in:
parent
e12c22f92a
commit
9b0298c3bd
@ -22,7 +22,7 @@
|
|||||||
{{ formatDateTime(record.create_time) }}
|
{{ formatDateTime(record.create_time) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'action'">
|
<template v-if="column.key === 'action'">
|
||||||
<a @click="handleManageImages(record)">管理图片</a>
|
<a-button type="link" @click="handleManageImages(record)">管理图片</a-button>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
@ -38,55 +38,6 @@
|
|||||||
<div id="map-container" style="height: 500px;"></div>
|
<div id="map-container" style="height: 500px;"></div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
<!-- 图片管理弹窗 -->
|
|
||||||
<a-modal
|
|
||||||
v-model:visible="imageModalVisible"
|
|
||||||
title="图片管理"
|
|
||||||
width="800px"
|
|
||||||
@ok="handleSaveImages"
|
|
||||||
@cancel="handleCancelImages"
|
|
||||||
:confirmLoading="imagesSaving"
|
|
||||||
>
|
|
||||||
<div class="image-uploader">
|
|
||||||
<a-upload
|
|
||||||
v-model:fileList="fileList"
|
|
||||||
:customRequest="handleUpload"
|
|
||||||
list-type="picture-card"
|
|
||||||
:multiple="true"
|
|
||||||
@preview="handlePreview"
|
|
||||||
@remove="handleRemove"
|
|
||||||
accept="image/*"
|
|
||||||
>
|
|
||||||
<template #uploadButton>
|
|
||||||
<div>
|
|
||||||
<plus-outlined />
|
|
||||||
<div style="margin-top: 8px">上传图片</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-upload>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 图片排序列表 -->
|
|
||||||
<div class="image-list">
|
|
||||||
<draggable
|
|
||||||
v-model="fileList"
|
|
||||||
item-key="uid"
|
|
||||||
ghost-class="ghost"
|
|
||||||
@end="handleDragEnd"
|
|
||||||
handle=".image-item"
|
|
||||||
>
|
|
||||||
<template #item="{ element }">
|
|
||||||
<div class="image-item">
|
|
||||||
<img :src="element.url" :alt="element.name" />
|
|
||||||
<div class="image-actions">
|
|
||||||
<delete-outlined @click="handleRemove(element)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</draggable>
|
|
||||||
</div>
|
|
||||||
</a-modal>
|
|
||||||
|
|
||||||
<!-- 添加商家模态框 -->
|
<!-- 添加商家模态框 -->
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="addModalVisible"
|
v-model:visible="addModalVisible"
|
||||||
@ -168,13 +119,42 @@
|
|||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
|
<!-- 添加图片管理模态框 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="imageModalVisible"
|
||||||
|
title="商家图片管理"
|
||||||
|
width="800px"
|
||||||
|
@ok="handleSaveImages"
|
||||||
|
@cancel="handleCancelImages"
|
||||||
|
:confirmLoading="imagesSaving"
|
||||||
|
okText="保存"
|
||||||
|
>
|
||||||
|
<div class="image-wall">
|
||||||
|
<a-upload
|
||||||
|
v-model:fileList="fileList"
|
||||||
|
:customRequest="handleUpload"
|
||||||
|
list-type="picture-card"
|
||||||
|
:multiple="true"
|
||||||
|
@preview="handlePreview"
|
||||||
|
@remove="handleRemove"
|
||||||
|
accept="image/*"
|
||||||
|
>
|
||||||
|
<div v-if="fileList.length < 8">
|
||||||
|
<plus-outlined />
|
||||||
|
<div style="margin-top: 8px">上传图片</div>
|
||||||
|
</div>
|
||||||
|
</a-upload>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
<!-- 图片预览模态框 -->
|
<!-- 图片预览模态框 -->
|
||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="previewVisible"
|
:visible="previewVisible"
|
||||||
:title="previewTitle"
|
:title="previewTitle"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
|
@cancel="handlePreviewCancel"
|
||||||
>
|
>
|
||||||
<img :src="previewImage" style="width: 100%" />
|
<img :alt="previewTitle" style="width: 100%" :src="previewImage" />
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</page-container>
|
</page-container>
|
||||||
@ -182,26 +162,24 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, ref, onMounted, nextTick } from 'vue'
|
import { defineComponent, ref, onMounted, nextTick } from 'vue'
|
||||||
import { message } from 'ant-design-vue'
|
import { message, Upload, Modal } from 'ant-design-vue'
|
||||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import PageContainer from '@/components/PageContainer.vue'
|
import PageContainer from '@/components/PageContainer.vue'
|
||||||
import { loadAMap, createMap, createAutoComplete, createGeocoder } from '@/utils/amap.js'
|
import { loadAMap, createMap, createAutoComplete, createGeocoder } from '@/utils/amap.js'
|
||||||
import draggable from 'vuedraggable'
|
|
||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
import { PlusOutlined } from '@ant-design/icons-vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
PageContainer,
|
PageContainer,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
DeleteOutlined,
|
AUpload: Upload,
|
||||||
draggable
|
AModal: Modal
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const tableData = ref([])
|
const tableData = ref([])
|
||||||
const mapVisible = ref(false)
|
const mapVisible = ref(false)
|
||||||
const imageModalVisible = ref(false)
|
|
||||||
const currentMap = ref(null)
|
const currentMap = ref(null)
|
||||||
const currentMarker = ref(null)
|
const currentMarker = ref(null)
|
||||||
|
|
||||||
@ -260,8 +238,9 @@ export default defineComponent({
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
width: 100,
|
width: 120,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
fixed: 'right'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -338,116 +317,6 @@ export default defineComponent({
|
|||||||
mapVisible.value = false
|
mapVisible.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图片管理相关
|
|
||||||
const imagesSaving = ref(false)
|
|
||||||
const currentMerchant = ref(null)
|
|
||||||
const fileList = ref([])
|
|
||||||
const previewVisible = ref(false)
|
|
||||||
const previewImage = ref('')
|
|
||||||
const previewTitle = ref('')
|
|
||||||
|
|
||||||
// 打开图片管理弹窗
|
|
||||||
const handleManageImages = (record) => {
|
|
||||||
currentMerchant.value = record
|
|
||||||
imageModalVisible.value = true
|
|
||||||
|
|
||||||
// 加载商家现有图片
|
|
||||||
if (record.images && record.images.length > 0) {
|
|
||||||
fileList.value = record.images.map((item, index) => ({
|
|
||||||
uid: `-${index}`,
|
|
||||||
name: item.image_url.substring(item.image_url.lastIndexOf('/') + 1),
|
|
||||||
status: 'done',
|
|
||||||
url: item.image_url,
|
|
||||||
sort: item.sort
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
fileList.value = []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理图片上传
|
|
||||||
const handleUpload = async ({ file, onSuccess, onError }) => {
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('files', file)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await request.post('/api/upload/images', formData)
|
|
||||||
if (res.data && res.data.urls) {
|
|
||||||
res.data.urls.forEach((url, index) => {
|
|
||||||
fileList.value.push({
|
|
||||||
uid: `new-${Date.now()}-${index}`,
|
|
||||||
name: url.substring(url.lastIndexOf('/') + 1),
|
|
||||||
status: 'done',
|
|
||||||
url: url,
|
|
||||||
sort: fileList.value.length
|
|
||||||
})
|
|
||||||
})
|
|
||||||
onSuccess()
|
|
||||||
message.success('上传成功')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('上传图片失败:', error)
|
|
||||||
onError()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存图片列表
|
|
||||||
const handleSaveImages = async () => {
|
|
||||||
try {
|
|
||||||
imagesSaving.value = true
|
|
||||||
const images = fileList.value.map((file, index) => ({
|
|
||||||
image_url: file.url,
|
|
||||||
sort: index
|
|
||||||
}))
|
|
||||||
|
|
||||||
await request.put(`/api/merchant/${currentMerchant.value.id}`, { images })
|
|
||||||
message.success('保存成功')
|
|
||||||
imageModalVisible.value = false
|
|
||||||
fetchData()
|
|
||||||
} catch (error) {
|
|
||||||
console.error('保存图片失败:', error)
|
|
||||||
} finally {
|
|
||||||
imagesSaving.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消图片管理
|
|
||||||
const handleCancelImages = () => {
|
|
||||||
fileList.value = []
|
|
||||||
imageModalVisible.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拖拽结束后更新排序
|
|
||||||
const handleDragEnd = () => {
|
|
||||||
// 排序已经通过 v-model 自动更新了 fileList
|
|
||||||
}
|
|
||||||
|
|
||||||
// 图片预览
|
|
||||||
const handlePreview = (file) => {
|
|
||||||
previewImage.value = file.url || file.preview
|
|
||||||
previewVisible.value = true
|
|
||||||
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移除图片
|
|
||||||
const handleRemove = async (file) => {
|
|
||||||
try {
|
|
||||||
const images = fileList.value
|
|
||||||
.filter(f => f.uid !== file.uid)
|
|
||||||
.map((f, index) => ({
|
|
||||||
image_url: f.url,
|
|
||||||
sort: index
|
|
||||||
}))
|
|
||||||
|
|
||||||
await request.put(`/api/merchant/${currentMerchant.value.id}`, { images })
|
|
||||||
message.success('删除成功')
|
|
||||||
fileList.value = fileList.value.filter(f => f.uid !== file.uid)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('删除图片失败:', error)
|
|
||||||
message.error('删除失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加商家相关
|
// 添加商家相关
|
||||||
const addModalVisible = ref(false)
|
const addModalVisible = ref(false)
|
||||||
const confirmLoading = ref(false)
|
const confirmLoading = ref(false)
|
||||||
@ -619,6 +488,137 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 图片管理相关
|
||||||
|
const imageModalVisible = ref(false)
|
||||||
|
const imagesSaving = ref(false)
|
||||||
|
const currentMerchant = ref(null)
|
||||||
|
const fileList = ref([])
|
||||||
|
const previewVisible = ref(false)
|
||||||
|
const previewImage = ref('')
|
||||||
|
const previewTitle = ref('')
|
||||||
|
|
||||||
|
// 打开图片管理
|
||||||
|
const handleManageImages = (record) => {
|
||||||
|
currentMerchant.value = record
|
||||||
|
imageModalVisible.value = true
|
||||||
|
|
||||||
|
// 加载商家现有图片
|
||||||
|
if (record.images && record.images.length > 0) {
|
||||||
|
fileList.value = record.images.map((item, index) => ({
|
||||||
|
uid: `-${index}`,
|
||||||
|
name: item.image_url.substring(item.image_url.lastIndexOf('/') + 1),
|
||||||
|
status: 'done',
|
||||||
|
url: item.image_url,
|
||||||
|
image_url: item.image_url,
|
||||||
|
sort: item.sort
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
fileList.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理图片上传
|
||||||
|
const handleUpload = async ({ file, onSuccess, onError, onProgress }) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('files', file)
|
||||||
|
|
||||||
|
try {
|
||||||
|
onProgress({ percent: 50 })
|
||||||
|
const res = await request.post('/api/upload/images', formData, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.code === 200 && res.data && res.data.urls && res.data.urls.length > 0) {
|
||||||
|
const url = res.data.urls[0]
|
||||||
|
const fileInfo = {
|
||||||
|
uid: `new-${Date.now()}`,
|
||||||
|
name: url.substring(url.lastIndexOf('/') + 1),
|
||||||
|
status: 'done',
|
||||||
|
response: res.data, // 保存完整的响应数据
|
||||||
|
url: url, // 用于预览显示
|
||||||
|
sort: fileList.value.length
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只更新本地文件列表,不保存到服务器
|
||||||
|
fileList.value = [...fileList.value, fileInfo]
|
||||||
|
onSuccess(res.data) // 传入完整的响应数据
|
||||||
|
message.success('上传成功')
|
||||||
|
} else {
|
||||||
|
throw new Error('上传失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('上传图片失败:', error)
|
||||||
|
onError()
|
||||||
|
message.error('上传失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 图片预览
|
||||||
|
const handlePreview = async (file) => {
|
||||||
|
previewImage.value = file.url || file.preview
|
||||||
|
previewVisible.value = true
|
||||||
|
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭预览
|
||||||
|
const handlePreviewCancel = () => {
|
||||||
|
previewVisible.value = false
|
||||||
|
previewTitle.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除图片
|
||||||
|
const handleRemove = async (file) => {
|
||||||
|
// 只从本地文件列表中移除,不更新服务器
|
||||||
|
fileList.value = fileList.value.filter(f => f.uid !== file.uid)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存图片列表
|
||||||
|
const handleSaveImages = async () => {
|
||||||
|
try {
|
||||||
|
imagesSaving.value = true
|
||||||
|
|
||||||
|
// 构造符合接口要求的数据格式
|
||||||
|
const data = {
|
||||||
|
images: fileList.value.map((file, index) => {
|
||||||
|
// 获取图片 URL 的优先级:
|
||||||
|
// 1. 如果是新上传的图片,从 response.urls[0] 获取
|
||||||
|
// 2. 如果是已有的图片,使用 url 字段
|
||||||
|
const imageUrl = file.response?.urls?.[0] || file.url
|
||||||
|
return {
|
||||||
|
image_url: imageUrl,
|
||||||
|
sort: index
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印检查数据
|
||||||
|
console.log('Saving data:', data)
|
||||||
|
|
||||||
|
const res = await request.put(`/api/merchant/${currentMerchant.value.id}`, data)
|
||||||
|
if (res.code === 200) {
|
||||||
|
message.success('保存成功')
|
||||||
|
imageModalVisible.value = false
|
||||||
|
fetchData()
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message || '保存失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
message.error(error.message || '保存失败')
|
||||||
|
} finally {
|
||||||
|
imagesSaving.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消图片管理
|
||||||
|
const handleCancelImages = () => {
|
||||||
|
fileList.value = []
|
||||||
|
imageModalVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchData()
|
fetchData()
|
||||||
})
|
})
|
||||||
@ -629,12 +629,10 @@ export default defineComponent({
|
|||||||
tableData,
|
tableData,
|
||||||
pagination,
|
pagination,
|
||||||
mapVisible,
|
mapVisible,
|
||||||
imageModalVisible,
|
|
||||||
handleTableChange,
|
handleTableChange,
|
||||||
showMap,
|
showMap,
|
||||||
closeMap,
|
closeMap,
|
||||||
formatDateTime,
|
formatDateTime,
|
||||||
handleManageImages,
|
|
||||||
addModalVisible,
|
addModalVisible,
|
||||||
confirmLoading,
|
confirmLoading,
|
||||||
formRef,
|
formRef,
|
||||||
@ -643,22 +641,24 @@ export default defineComponent({
|
|||||||
searchAddress,
|
searchAddress,
|
||||||
searchOptions,
|
searchOptions,
|
||||||
searchLoading,
|
searchLoading,
|
||||||
|
showAddModal,
|
||||||
|
handleSearch,
|
||||||
|
handleSelect,
|
||||||
|
handleAdd,
|
||||||
|
handleCancel,
|
||||||
|
imageModalVisible,
|
||||||
|
imagesSaving,
|
||||||
fileList,
|
fileList,
|
||||||
previewVisible,
|
previewVisible,
|
||||||
previewImage,
|
previewImage,
|
||||||
previewTitle,
|
previewTitle,
|
||||||
showAddModal,
|
handleManageImages,
|
||||||
handleSearch,
|
|
||||||
handleSelect,
|
|
||||||
handleUpload,
|
handleUpload,
|
||||||
handlePreview,
|
handlePreview,
|
||||||
|
handlePreviewCancel,
|
||||||
handleRemove,
|
handleRemove,
|
||||||
handleAdd,
|
|
||||||
handleCancel,
|
|
||||||
imagesSaving,
|
|
||||||
handleSaveImages,
|
handleSaveImages,
|
||||||
handleCancelImages,
|
handleCancelImages
|
||||||
handleDragEnd
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -690,49 +690,25 @@ export default defineComponent({
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-upload-list-picture-card-container) {
|
.image-wall {
|
||||||
width: 104px;
|
padding: 24px;
|
||||||
height: 104px;
|
background: #fafafa;
|
||||||
margin: 0 8px 8px 0;
|
border-radius: 2px;
|
||||||
|
min-height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-upload.ant-upload-select-picture-card) {
|
:deep(.ant-upload-select-picture-card) {
|
||||||
width: 104px;
|
width: 104px !important;
|
||||||
height: 104px;
|
height: 104px !important;
|
||||||
margin: 0 8px 8px 0;
|
margin: 0 8px 8px 0;
|
||||||
}
|
|
||||||
|
|
||||||
.image-uploader {
|
|
||||||
padding: 20px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ant-upload.ant-upload-select-picture-card) {
|
|
||||||
width: 104px;
|
|
||||||
height: 104px;
|
|
||||||
margin: 0 8px 8px 0;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: #fafafa;
|
|
||||||
border: 1px dashed #d9d9d9;
|
border: 1px dashed #d9d9d9;
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: pointer;
|
||||||
transition: border-color 0.3s;
|
transition: border-color 0.3s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: #1890ff;
|
border-color: #1890ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
> div {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.anticon {
|
|
||||||
font-size: 24px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-upload-list-picture-card-container) {
|
:deep(.ant-upload-list-picture-card-container) {
|
||||||
@ -741,70 +717,17 @@ export default defineComponent({
|
|||||||
margin: 0 8px 8px 0;
|
margin: 0 8px 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-upload.ant-upload-select-picture-card) {
|
|
||||||
width: 104px;
|
|
||||||
height: 104px;
|
|
||||||
margin: 0 8px 8px 0;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ant-upload-list-picture-card .ant-upload-list-item) {
|
:deep(.ant-upload-list-picture-card .ant-upload-list-item) {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-upload.ant-upload-select-picture-card:hover) {
|
:deep(.ant-upload-select-picture-card i) {
|
||||||
border-color: #1890ff;
|
font-size: 32px;
|
||||||
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-list {
|
:deep(.ant-upload-select-picture-card .ant-upload-text) {
|
||||||
margin-top: 20px;
|
margin-top: 8px;
|
||||||
display: grid;
|
color: #666;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
|
||||||
gap: 16px;
|
|
||||||
padding: 16px;
|
|
||||||
background: #fafafa;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-item {
|
|
||||||
position: relative;
|
|
||||||
width: 120px;
|
|
||||||
height: 120px;
|
|
||||||
border: 1px solid #d9d9d9;
|
|
||||||
border-radius: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
cursor: move;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-item img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-actions {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
padding: 4px;
|
|
||||||
background: rgba(0, 0, 0, 0.45);
|
|
||||||
border-bottom-left-radius: 4px;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-item:hover .image-actions {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.image-actions .anticon {
|
|
||||||
color: #fff;
|
|
||||||
font-size: 16px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ghost {
|
|
||||||
opacity: 0.5;
|
|
||||||
background: #c8ebfb;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user