123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- <template>
- <a-list :grid="{ gutter: 20, column: 3 }" :data-source="current">
- <template
- #renderItem="{
- item,
- index
- }: {
- item: string | typeof addMarked,
- index: number
- }"
- >
- <a-list-item class="scene-item">
- <div v-if="item === addMarked" class="add-album">
- <a-upload
- v-model:file-list="albumFile"
- name="file"
- accept=".png,.jpg,.jpeg"
- :show-upload-list="false"
- action="https://v4-test.4dkankan.com/takelook/upload/file"
- :multiple="true"
- :before-upload="handleBeforeUpload"
- @change="handleABlumChange"
- >
- <div class="add-item-icon">
- <a-button shape="circle" class="button" type="primary">
- <plus-outlined class="add-room-icon" />
- </a-button>
- </div>
- </a-upload>
- </div>
- <div v-else class="scene-sign">
- <a-image v-if="item" :src="item" />
- <span class="delete-scene" @click="deleteAblum(index)">
- <close-outlined class="delete-scene-icon" />
- </span>
- </div>
- </a-list-item>
- </template>
- </a-list>
- </template>
- <script lang="ts" setup>
- import { computed, ref, watch, unref } from 'vue'
- import { Modal, message } from 'ant-design-vue'
- import type { UploadChangeParam } from 'ant-design-vue'
- import { useI18n } from '@/hook/useI18n'
- import { watchEffect } from 'vue'
- export interface FileItem {
- uid: string
- response:
- | {
- ok?: number
- data: string
- }
- | undefined
- name?: string
- status?: string
- url?: string
- type?: string
- size?: number
- originFileObj?: any
- }
- const { t } = useI18n()
- defineOptions<{ name: 'RoomSceneList' }>()
- const props = defineProps<{ data: string[] }>()
- const addMarked = Symbol('add-album')
- const albumFile = ref<any[]>([])
- const albumFileExist = ref<any[]>([])
- const current = computed(() => [addMarked, ...albumFileExist.value])
- const deleteAblum = (index: number) => {
- console.log('index', index)
- if (index - 1 > -1) {
- albumFileExist.value.splice(index - 1, 1)
- }
- const syncData = albumFileExist.value.length ? albumFileExist.value : []
- emit('syncList', syncData)
- }
- const emit = defineEmits(['syncList'])
- watchEffect(() => {
- if (props.data?.length) {
- albumFileExist.value = props.data
- }
- })
- const handleABlumChange = (info: UploadChangeParam) => {
- if (info.file.status === 'done') {
- const { code, data } = info.file.response
- if (code === 0) {
- albumFileExist.value.push(data)
- }
- const syncData = albumFileExist.value.length ? albumFileExist.value : []
- emit('syncList', syncData)
- } else if (info.file.status === 'error') {
- message.error(`${info.file.name} file upload failed.`)
- }
- }
- const handleBeforeUpload = (file: any) => {
- const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
- if (!isJpgOrPng) {
- message.error('You can only upload JPG file!')
- }
- const isLt5M = file.size / 1024 / 1024 < 5
- if (!isLt5M) {
- message.error('Image must smaller than 5MB!')
- }
- return isJpgOrPng && isLt5M
- }
- </script>
- <style lang="scss" scoped>
- .add-album {
- border: 1px solid #ebedf0;
- border-radius: 4px;
- height: 100%;
- width: 100%;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- .button {
- width: 40px;
- height: 40px;
- line-height: 34px;
- background: linear-gradient(144deg, #00aefb 0%, #0076f6 100%);
- }
- .add-room-icon {
- font-size: 18px;
- }
- }
- .scene-sign {
- height: 100%;
- border-radius: 4px;
- overflow: hidden;
- position: relative;
- img {
- width: 100%;
- height: 100%;
- display: block;
- object-fit: cover;
- }
- .title {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- height: 24px;
- background: rgba(0, 0, 0, 0.5);
- padding: 5px;
- font-size: 12px;
- color: #fff;
- margin: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .delete-scene {
- z-index: 2;
- position: absolute;
- right: 0;
- top: 0;
- width: 52px;
- height: 52px;
- background-color: rgba(0, 0, 0, 0.5);
- color: #fa5555;
- font-size: 14px;
- border-radius: 50%;
- display: flex;
- align-items: flex-end;
- transform: translate(100%, -100%);
- transition: all 0.3s ease;
- opacity: 0;
- cursor: pointer;
- .delete-scene-icon {
- padding: 10px;
- }
- }
- &:hover .delete-scene {
- transform: translate(50%, -50%);
- opacity: 1;
- }
- .status-cover {
- z-index: 1;
- position: absolute;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- display: flex;
- align-items: center;
- justify-content: center;
- p {
- color: #fff;
- }
- }
- }
- </style>
- <style>
- .scene-item {
- height: 120px;
- }
- </style>
|