添加商家页面实现。
This commit is contained in:
parent
9b6e38edce
commit
e12c22f92a
23
package-lock.json
generated
23
package-lock.json
generated
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "dm-admin",
|
"name": "beefast-admin",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "dm-admin",
|
"name": "beefast-admin",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ant-design-vue": "^3.2.20",
|
"ant-design-vue": "^3.2.20",
|
||||||
@ -13,6 +13,7 @@
|
|||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
|
"vuedraggable": "^4.1.0",
|
||||||
"vuex": "^4.0.2"
|
"vuex": "^4.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -7694,6 +7695,12 @@
|
|||||||
"websocket-driver": "^0.7.4"
|
"websocket-driver": "^0.7.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sortablejs": {
|
||||||
|
"version": "1.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz",
|
||||||
|
"integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
@ -8490,6 +8497,18 @@
|
|||||||
"vue": "^3.0.0"
|
"vue": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vuedraggable": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"sortablejs": "1.14.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vuex": {
|
"node_modules/vuex": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
|
"vuedraggable": "^4.1.0",
|
||||||
"vuex": "^4.0.2"
|
"vuex": "^4.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@ -3,7 +3,10 @@ import { message } from 'ant-design-vue'
|
|||||||
|
|
||||||
const request = axios.create({
|
const request = axios.create({
|
||||||
baseURL: 'http://127.0.0.1:8000',
|
baseURL: 'http://127.0.0.1:8000',
|
||||||
timeout: 5000
|
timeout: 5000,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 请求拦截器
|
// 请求拦截器
|
||||||
@ -13,6 +16,12 @@ request.interceptors.request.use(
|
|||||||
if (token) {
|
if (token) {
|
||||||
config.headers.authorization = `Bearer ${token}`
|
config.headers.authorization = `Bearer ${token}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理文件上传
|
||||||
|
if (config.data instanceof FormData) {
|
||||||
|
delete config.headers['Content-Type']
|
||||||
|
}
|
||||||
|
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
@ -23,7 +32,13 @@ request.interceptors.request.use(
|
|||||||
// 响应拦截器
|
// 响应拦截器
|
||||||
request.interceptors.response.use(
|
request.interceptors.response.use(
|
||||||
response => {
|
response => {
|
||||||
return response.data
|
const res = response.data
|
||||||
|
if (res.code === 200) {
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
|
message.error(res.message || '请求失败')
|
||||||
|
return Promise.reject(new Error(res.message || '请求失败'))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
message.error(error.response?.data?.message || '请求失败')
|
message.error(error.response?.data?.message || '请求失败')
|
||||||
|
|||||||
@ -42,10 +42,49 @@
|
|||||||
<a-modal
|
<a-modal
|
||||||
v-model:visible="imageModalVisible"
|
v-model:visible="imageModalVisible"
|
||||||
title="图片管理"
|
title="图片管理"
|
||||||
:footer="null"
|
|
||||||
width="800px"
|
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>
|
||||||
|
|
||||||
<!-- 添加商家模态框 -->
|
<!-- 添加商家模态框 -->
|
||||||
@ -126,22 +165,6 @@
|
|||||||
/>
|
/>
|
||||||
</a-input-group>
|
</a-input-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
||||||
<a-form-item label="商家图片" name="images">
|
|
||||||
<a-upload
|
|
||||||
v-model:fileList="fileList"
|
|
||||||
:customRequest="handleUpload"
|
|
||||||
list-type="picture-card"
|
|
||||||
:multiple="true"
|
|
||||||
@preview="handlePreview"
|
|
||||||
@remove="handleRemove"
|
|
||||||
>
|
|
||||||
<div v-if="fileList.length < 8">
|
|
||||||
<plus-outlined />
|
|
||||||
<div style="margin-top: 8px">上传</div>
|
|
||||||
</div>
|
|
||||||
</a-upload>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
|
||||||
@ -160,15 +183,19 @@
|
|||||||
<script>
|
<script>
|
||||||
import { defineComponent, ref, onMounted, nextTick } from 'vue'
|
import { defineComponent, ref, onMounted, nextTick } from 'vue'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import { PlusOutlined } from '@ant-design/icons-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'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
PageContainer,
|
PageContainer,
|
||||||
PlusOutlined
|
PlusOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
draggable
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@ -253,18 +280,13 @@ export default defineComponent({
|
|||||||
limit: pagination.value.pageSize
|
limit: pagination.value.pageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await fetch('/api/merchant?' + new URLSearchParams(params))
|
const res = await request.get('/api/merchant', { params })
|
||||||
const result = await res.json()
|
if (res.data) {
|
||||||
|
tableData.value = res.data.items || []
|
||||||
if (result.code === 200) {
|
pagination.value.total = res.data.total || 0
|
||||||
tableData.value = result.data
|
|
||||||
pagination.value.total = result.total || result.data.length
|
|
||||||
} else {
|
|
||||||
message.error(result.message || '获取数据失败')
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取商家列表失败:', error)
|
console.error('获取商家列表失败:', error)
|
||||||
message.error('获取数据失败')
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
@ -284,10 +306,10 @@ export default defineComponent({
|
|||||||
await nextTick()
|
await nextTick()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const AMap = await initAMap()
|
await loadAMap()
|
||||||
|
|
||||||
if (!currentMap.value) {
|
if (!currentMap.value) {
|
||||||
currentMap.value = new AMap.Map('map-container', {
|
currentMap.value = createMap('map-container', {
|
||||||
zoom: 15,
|
zoom: 15,
|
||||||
viewMode: '3D'
|
viewMode: '3D'
|
||||||
})
|
})
|
||||||
@ -297,15 +319,14 @@ export default defineComponent({
|
|||||||
currentMap.value.setCenter(position)
|
currentMap.value.setCenter(position)
|
||||||
|
|
||||||
if (currentMarker.value) {
|
if (currentMarker.value) {
|
||||||
currentMap.value.remove(currentMarker.value)
|
currentMarker.value.remove()
|
||||||
}
|
}
|
||||||
|
|
||||||
currentMarker.value = new AMap.Marker({
|
currentMarker.value = new window.AMap.Marker({
|
||||||
position,
|
position,
|
||||||
|
map: currentMap.value,
|
||||||
title: record.name
|
title: record.name
|
||||||
})
|
})
|
||||||
currentMap.value.add(currentMarker.value)
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载地图失败:', error)
|
console.error('加载地图失败:', error)
|
||||||
message.error('加载地图失败')
|
message.error('加载地图失败')
|
||||||
@ -317,10 +338,114 @@ 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) => {
|
const handleManageImages = (record) => {
|
||||||
|
currentMerchant.value = record
|
||||||
imageModalVisible.value = true
|
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('删除失败')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加商家相关
|
// 添加商家相关
|
||||||
@ -332,10 +457,6 @@ export default defineComponent({
|
|||||||
const searchLoading = ref(false)
|
const searchLoading = ref(false)
|
||||||
const addMap = ref(null)
|
const addMap = ref(null)
|
||||||
const addMarker = ref(null)
|
const addMarker = ref(null)
|
||||||
const fileList = ref([])
|
|
||||||
const previewVisible = ref(false)
|
|
||||||
const previewImage = ref('')
|
|
||||||
const previewTitle = ref('')
|
|
||||||
|
|
||||||
const formState = ref({
|
const formState = ref({
|
||||||
name: '',
|
name: '',
|
||||||
@ -343,8 +464,7 @@ export default defineComponent({
|
|||||||
address: '',
|
address: '',
|
||||||
longitude: null,
|
longitude: null,
|
||||||
latitude: null,
|
latitude: null,
|
||||||
phone: '',
|
phone: ''
|
||||||
images: []
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
@ -472,72 +592,17 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理图片上传
|
|
||||||
const handleUpload = async ({ file, onSuccess, onError }) => {
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('files', file)
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch('/api/upload/images', {
|
|
||||||
method: 'POST',
|
|
||||||
body: formData
|
|
||||||
})
|
|
||||||
const result = await response.json()
|
|
||||||
|
|
||||||
if (result.code === 200) {
|
|
||||||
const imageUrl = result.data[0] // 假设返回的是图片URL数组
|
|
||||||
formState.value.images.push(imageUrl)
|
|
||||||
onSuccess(result)
|
|
||||||
} else {
|
|
||||||
onError()
|
|
||||||
message.error('上传失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('上传图片失败:', error)
|
|
||||||
onError()
|
|
||||||
message.error('上传失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 图片预览
|
|
||||||
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 = (file) => {
|
|
||||||
const index = formState.value.images.indexOf(file.url)
|
|
||||||
if (index > -1) {
|
|
||||||
formState.value.images.splice(index, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交表单
|
// 提交表单
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
formRef.value.validate().then(async () => {
|
formRef.value.validate().then(async () => {
|
||||||
try {
|
try {
|
||||||
confirmLoading.value = true
|
confirmLoading.value = true
|
||||||
const res = await fetch('/api/merchant', {
|
await request.post('/api/merchant', formState.value)
|
||||||
method: 'POST',
|
message.success('添加成功')
|
||||||
headers: {
|
addModalVisible.value = false
|
||||||
'Content-Type': 'application/json'
|
fetchData()
|
||||||
},
|
|
||||||
body: JSON.stringify(formState.value)
|
|
||||||
})
|
|
||||||
const result = await res.json()
|
|
||||||
|
|
||||||
if (result.code === 200) {
|
|
||||||
message.success('添加成功')
|
|
||||||
addModalVisible.value = false
|
|
||||||
fetchData() // 刷新列表
|
|
||||||
} else {
|
|
||||||
message.error(result.message || '添加失败')
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('添加商家失败:', error)
|
console.error('添加商家失败:', error)
|
||||||
message.error('添加失败')
|
|
||||||
} finally {
|
} finally {
|
||||||
confirmLoading.value = false
|
confirmLoading.value = false
|
||||||
}
|
}
|
||||||
@ -547,8 +612,6 @@ export default defineComponent({
|
|||||||
// 取消添加
|
// 取消添加
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
fileList.value = []
|
|
||||||
formState.value.images = []
|
|
||||||
addModalVisible.value = false
|
addModalVisible.value = false
|
||||||
if (addMarker.value) {
|
if (addMarker.value) {
|
||||||
addMarker.value.setMap(null)
|
addMarker.value.setMap(null)
|
||||||
@ -591,7 +654,11 @@ export default defineComponent({
|
|||||||
handlePreview,
|
handlePreview,
|
||||||
handleRemove,
|
handleRemove,
|
||||||
handleAdd,
|
handleAdd,
|
||||||
handleCancel
|
handleCancel,
|
||||||
|
imagesSaving,
|
||||||
|
handleSaveImages,
|
||||||
|
handleCancelImages,
|
||||||
|
handleDragEnd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -634,4 +701,110 @@ export default defineComponent({
|
|||||||
height: 104px;
|
height: 104px;
|
||||||
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;
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
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) {
|
||||||
|
width: 104px;
|
||||||
|
height: 104px;
|
||||||
|
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) {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-upload.ant-upload-select-picture-card:hover) {
|
||||||
|
border-color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-list {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: grid;
|
||||||
|
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