refactor: refactoring the batch operation logic of attachment management (halo-dev/console#431)

* refactor: refactoring the batch operation logic of attachment management

Signed-off-by: Ryan Wang <i@ryanc.cc>

* feat: support select all

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/3445/head
Ryan Wang 2022-02-10 16:00:17 +08:00 committed by GitHub
parent a471f91c90
commit 10bf358e33
2 changed files with 155 additions and 156 deletions

View File

@ -60,52 +60,50 @@
:loading="list.loading"
class="attachments-group"
>
<a-list-item
@mouseenter="$set(item, 'hover', true)"
@mouseleave="$set(item, 'hover', false)"
:key="index"
slot="renderItem"
slot-scope="item, index"
@click="handleItemClick(item)"
>
<div :class="`${isItemSelect(item) ? 'border-blue-600' : 'border-slate-200'}`" class="border border-solid">
<div class="attach-thumb attachments-group-item">
<span v-if="!isImage(item)" class="attachments-group-item-type">{{ item.suffix }}</span>
<span
v-else
:style="`background-image:url(${item.thumbPath})`"
class="attachments-group-item-img"
loading="lazy"
<template #renderItem="item, index">
<a-list-item
@mouseenter="$set(item, 'hover', true)"
@mouseleave="$set(item, 'hover', false)"
:key="index"
@click="handleItemClick(item)"
>
<div :class="`${isItemSelect(item) ? 'border-blue-600' : 'border-slate-200'}`" class="border border-solid">
<div class="attach-thumb attachments-group-item">
<span v-if="!isImage(item)" class="attachments-group-item-type">{{ item.suffix }}</span>
<span
v-else
:style="`background-image:url(${item.thumbPath})`"
class="attachments-group-item-img"
loading="lazy"
/>
</div>
<a-card-meta class="p-2 cursor-pointer">
<template #description>
<a-tooltip :title="item.name">
<div class="truncate">{{ item.name }}</div>
</a-tooltip>
</template>
</a-card-meta>
<a-icon
v-show="isItemSelect(item) && !item.hover"
type="check-circle"
theme="twoTone"
class="absolute top-1 right-2 font-bold cursor-pointer transition-all"
:style="{ fontSize: '18px', color: 'rgb(37 99 235)' }"
/>
<a-icon
v-show="item.hover"
type="profile"
theme="twoTone"
class="absolute top-1 right-2 font-bold cursor-pointer transition-all"
@click.stop="handleOpenDetail(item)"
:style="{ fontSize: '18px' }"
/>
</div>
<a-card-meta class="p-2 cursor-pointer">
<template #description>
<a-tooltip :title="item.name">
<div class="truncate">{{ item.name }}</div>
</a-tooltip>
</template>
</a-card-meta>
<a-icon
v-show="isItemSelect(item) && !item.hover"
type="check-circle"
theme="twoTone"
class="absolute top-1 right-2 font-bold transition-all"
:style="{ fontSize: '18px', color: 'rgb(37 99 235)' }"
/>
<a-icon
v-show="item.hover"
type="profile"
theme="twoTone"
class="absolute top-1 right-2 font-bold cursor-pointer hover:text-blue-400 transition-all"
@click.stop="handleOpenDetail(item)"
:style="{ fontSize: '18px' }"
/>
</div>
</a-list-item>
</a-list-item>
</template>
</a-list>
<div class="page-wrapper"></div>
<div class="flex justify-between">
<a-popover placement="right" title="预览" trigger="click">
<template slot="content">
@ -130,13 +128,13 @@
</a-tooltip>
</a-popover>
<div class="flex justify-end self-center">
<div class="page-wrapper flex justify-end self-center">
<a-pagination
:current="pagination.page"
:defaultPageSize="pagination.size"
:pageSizeOptions="['12', '18', '24', '30', '36', '42']"
:total="pagination.total"
class="pagination"
class="pagination !mt-0"
showLessItems
showSizeChanger
@change="handlePageChange"

View File

@ -52,65 +52,81 @@
</div>
<div class="mb-0 table-operator">
<a-button icon="cloud-upload" type="primary" @click="upload.visible = true">上传</a-button>
<a-button v-show="!supportMultipleSelection" icon="select" @click="handleMultipleSelection">
批量操作
<a-button v-show="list.selected.length" icon="check-circle" type="primary" @click="handleSelectAll">
全选
</a-button>
<a-button
v-show="supportMultipleSelection"
icon="delete"
type="danger"
@click="handleDeleteAttachmentInBatch"
>
<a-button v-show="list.selected.length" icon="delete" type="danger" @click="handleDeleteAttachmentInBatch">
删除
</a-button>
<a-button v-show="supportMultipleSelection" icon="close" @click="handleCancelMultipleSelection">
取消
</a-button>
<a-button v-show="list.selected.length" icon="close" @click="list.selected = []"> </a-button>
</div>
</a-card>
</a-col>
<a-col :span="24">
<a-list
:dataSource="list.data"
:grid="{ gutter: 12, xs: 2, sm: 2, md: 4, lg: 6, xl: 6, xxl: 6 }"
:grid="{ gutter: 6, xs: 2, sm: 2, md: 4, lg: 6, xl: 6, xxl: 6 }"
:loading="list.loading"
class="attachments-group"
>
<a-list-item :key="index" slot="renderItem" slot-scope="item, index">
<a-card
:bodyStyle="{ padding: 0 }"
hoverable
@click="handleOpenDetail(item)"
<template #renderItem="item, index">
<a-list-item
@mouseenter="$set(item, 'hover', true)"
@mouseleave="$set(item, 'hover', false)"
:key="index"
@click="handleItemClick(item)"
@contextmenu.prevent="handleContextMenu($event, item)"
>
<div class="attach-thumb attachments-group-item">
<span v-if="!isImage(item)" class="attachments-group-item-type">{{ item.suffix }}</span>
<span
v-else
:style="`background-image:url(${item.thumbPath})`"
class="attachments-group-item-img"
loading="lazy"
<div
:class="`${isItemSelect(item) ? 'border-blue-600' : 'border-slate-200'}`"
class="border border-solid"
>
<div class="attach-thumb attachments-group-item">
<span v-if="!isImage(item)" class="attachments-group-item-type">{{ item.suffix }}</span>
<span
v-else
:style="`background-image:url(${item.thumbPath})`"
class="attachments-group-item-img"
loading="lazy"
/>
</div>
<a-card-meta class="p-2 cursor-pointer">
<template #description>
<a-tooltip :title="item.name">
<div class="truncate">{{ item.name }}</div>
</a-tooltip>
</template>
</a-card-meta>
<a-icon
v-show="!isItemSelect(item) && item.hover"
type="plus-circle"
theme="twoTone"
class="absolute top-1 right-2 font-bold cursor-pointer transition-all"
:style="{ fontSize: '18px', color: 'rgb(37 99 235)' }"
@click.stop="handleSelect(item)"
/>
<a-icon
v-show="isItemSelect(item)"
type="check-circle"
theme="twoTone"
class="absolute top-1 right-2 font-bold cursor-pointer transition-all"
:style="{ fontSize: '18px', color: 'rgb(37 99 235)' }"
/>
<a-icon
v-show="item.hover && list.selected.length > 0"
type="profile"
theme="twoTone"
class="absolute top-1 left-2 font-bold cursor-pointer transition-all"
@click.stop="handleOpenDetail(item)"
:style="{ fontSize: '18px' }"
/>
</div>
<a-card-meta class="p-2">
<template #description>
<a-tooltip :title="item.name">
<div class="truncate">{{ item.name }}</div>
</a-tooltip>
</template>
</a-card-meta>
<a-checkbox
v-show="supportMultipleSelection"
:checked="getCheckStatus(item.id)"
:style="getCheckStatus(item.id) ? selectedAttachmentStyle : ''"
class="select-attachment-checkbox"
@click="handleAttachmentSelectionChanged($event, item)"
></a-checkbox>
</a-card>
</a-list-item>
</a-list-item>
</template>
</a-list>
</a-col>
</a-row>
<div class="page-wrapper">
<a-pagination
:current="pagination.page"
@ -129,7 +145,7 @@
<AttachmentDetailModal
:addToPhoto="true"
:attachment="list.selected"
:attachment="list.current"
:visible.sync="detailVisible"
@delete="handleListAttachments()"
>
@ -145,7 +161,6 @@
import { mixin, mixinDevice } from '@/mixins/mixin.js'
import { PageView } from '@/layouts'
import apiClient from '@/utils/api-client'
import { mapGetters } from 'vuex'
import { attachmentTypes } from '@/core/constant'
export default {
@ -166,14 +181,15 @@ export default {
total: 0,
hasNext: false,
hasPrevious: false,
selected: {},
params: {
page: 0,
size: 18,
keyword: undefined,
mediaType: undefined,
attachmentType: undefined
}
},
selected: [],
current: {}
},
mediaTypes: {
@ -190,19 +206,10 @@ export default {
visible: false
},
detailVisible: false,
supportMultipleSelection: false,
selectedAttachmentCheckbox: {},
batchSelectedAttachments: []
detailVisible: false
}
},
computed: {
selectedAttachmentStyle() {
return {
border: `2px solid ${this.color()}`
}
},
isImage() {
return function (attachment) {
if (!attachment || !attachment.mediaType) {
@ -211,6 +218,11 @@ export default {
return attachment.mediaType.startsWith('image')
}
},
isItemSelect() {
return function (attachment) {
return this.list.selected.findIndex(item => item.id === attachment.id) > -1
}
},
pagination() {
return {
page: this.list.params.page + 1,
@ -219,11 +231,11 @@ export default {
}
},
selectPreviousButtonDisabled() {
const index = this.list.data.findIndex(attachment => attachment.id === this.list.selected.id)
const index = this.list.data.findIndex(attachment => attachment.id === this.list.current.id)
return index === 0 && !this.list.hasPrevious
},
selectNextButtonDisabled() {
const index = this.list.data.findIndex(attachment => attachment.id === this.list.selected.id)
const index = this.list.data.findIndex(attachment => attachment.id === this.list.current.id)
return index === this.list.data.length - 1 && !this.list.hasNext
}
},
@ -233,8 +245,6 @@ export default {
this.handleListTypes()
},
methods: {
...mapGetters(['color']),
/**
* List attachments
*/
@ -293,8 +303,28 @@ export default {
* Handle open attachment detail modal event
*/
handleOpenDetail(attachment) {
this.list.selected = attachment
this.detailVisible = !this.supportMultipleSelection
this.list.current = attachment
this.detailVisible = true
},
handleItemClick(attachment) {
if (this.list.selected.length <= 0) {
this.handleOpenDetail(attachment)
return
}
this.isItemSelect(attachment) ? this.handleUnselect(attachment) : this.handleSelect(attachment)
},
handleSelect(attachment) {
this.list.selected = [...this.list.selected, attachment]
},
handleUnselect(attachment) {
this.list.selected = this.list.selected.filter(item => item.id !== attachment.id)
},
handleSelectAll() {
this.list.selected = this.list.data
},
/**
@ -347,6 +377,7 @@ export default {
onOk: async () => {
await apiClient.attachment.delete(item.id)
await this.handleListAttachments()
this.handleUnselect(item)
}
})
}
@ -394,67 +425,37 @@ export default {
handleQuery() {
this.handlePageChange()
},
onUploadClose() {
this.handlePageChange()
this.handleListMediaTypes()
this.handleListTypes()
},
getCheckStatus(key) {
return this.selectedAttachmentCheckbox[key] || false
},
handleMultipleSelection() {
this.supportMultipleSelection = true
//
this.detailVisible = false
this.list.data.forEach(item => {
this.$set(this.selectedAttachmentCheckbox, item.id, false)
})
},
handleCancelMultipleSelection() {
this.supportMultipleSelection = false
this.detailVisible = false
this.batchSelectedAttachments = []
for (const key in this.selectedCheckbox) {
this.$set(this.selectedAttachmentCheckbox, key, false)
}
},
handleAttachmentSelectionChanged(e, item) {
const isChecked = e.target.checked || false
if (isChecked) {
this.$set(this.selectedAttachmentCheckbox, item.id, true)
this.batchSelectedAttachments.push(item.id)
} else {
this.$set(this.selectedAttachmentCheckbox, item.id, false)
// idid
const index = this.batchSelectedAttachments.indexOf(item.id)
this.batchSelectedAttachments.splice(index, 1)
}
},
/**
* Deletes selected attachments
*/
handleDeleteAttachmentInBatch() {
const that = this
if (this.batchSelectedAttachments.length <= 0) {
const _this = this
if (this.list.selected.length <= 0) {
this.$message.warn('你还未选择任何附件,请至少选择一个!')
return
}
this.$confirm({
title: '确定要批量删除选中的附件吗?',
title: '确定要批量删除选中的附件吗?',
content: '一旦删除不可恢复,请谨慎操作',
onOk() {
apiClient.attachment
.deleteInBatch(that.batchSelectedAttachments)
.then(() => {
that.handleCancelMultipleSelection()
that.$message.success('删除成功')
})
.finally(() => {
that.handleListAttachments()
})
},
onCancel() {}
async onOk() {
try {
const attachmentIds = _this.list.selected.map(attachment => attachment.id)
await apiClient.attachment.deleteInBatch(attachmentIds)
_this.list.selected = []
_this.$message.success('删除成功')
} catch (e) {
_this.$log.error('Failed to delete selected attachments', e)
} finally {
await _this.handleListAttachments()
}
}
})
},
@ -462,16 +463,16 @@ export default {
* Select previous attachment
*/
async handleSelectPrevious() {
const index = this.list.data.findIndex(item => item.id === this.list.selected.id)
const index = this.list.data.findIndex(item => item.id === this.list.current.id)
if (index > 0) {
this.list.selected = this.list.data[index - 1]
this.list.current = this.list.data[index - 1]
return
}
if (index === 0 && this.list.hasPrevious) {
this.list.params.page--
await this.handleListAttachments()
this.list.selected = this.list.data[this.list.data.length - 1]
this.list.current = this.list.data[this.list.data.length - 1]
}
},
@ -479,16 +480,16 @@ export default {
* Select next attachment
*/
async handleSelectNext() {
const index = this.list.data.findIndex(item => item.id === this.list.selected.id)
const index = this.list.data.findIndex(item => item.id === this.list.current.id)
if (index < this.list.data.length - 1) {
this.list.selected = this.list.data[index + 1]
this.list.current = this.list.data[index + 1]
return
}
if (index === this.list.data.length - 1 && this.list.hasNext) {
this.list.params.page++
await this.handleListAttachments()
this.list.selected = this.list.data[0]
this.list.current = this.list.data[0]
}
}
}