Browse Source

refactor: attachment list layout (#580)

* refactor: attachment list layout

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

* chore: revert pnpm-locl.yaml

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/584/head
Ryan Wang 2 years ago committed by GitHub
parent
commit
b85a89bb41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      package.json
  2. 14
      pnpm-lock.yaml
  3. 111
      src/components/Attachment/AttachmentSelectModal.vue
  4. 75
      src/styles/global.less
  5. 118
      src/views/attachment/AttachmentList.vue
  6. 102
      src/views/sheet/independent/PhotoList.vue
  7. 2
      tailwind.config.js

1
package.json

@ -53,6 +53,7 @@
"@ant-design/colors": "3.2.2",
"@babel/core": "^7.17.9",
"@babel/eslint-parser": "^7.17.0",
"@tailwindcss/aspect-ratio": "^0.4.0",
"@vue/cli-plugin-babel": "~5.0.4",
"@vue/cli-plugin-eslint": "~5.0.4",
"@vue/cli-plugin-router": "~5.0.4",

14
pnpm-lock.yaml

@ -9,6 +9,7 @@ specifiers:
'@codemirror/lang-java': ^0.19.1
'@halo-dev/admin-api': ^1.0.0
'@halo-dev/editor': ^3.0.4
'@tailwindcss/aspect-ratio': ^0.4.0
'@vue/cli-plugin-babel': ~5.0.4
'@vue/cli-plugin-eslint': ~5.0.4
'@vue/cli-plugin-router': ~5.0.4
@ -85,6 +86,7 @@ devDependencies:
'@ant-design/colors': 3.2.2
'@babel/core': 7.17.9
'@babel/eslint-parser': 7.17.0_@babel+core@7.17.9+eslint@7.32.0
'@tailwindcss/aspect-ratio': 0.4.0_tailwindcss@3.0.23
'@vue/cli-plugin-babel': 5.0.4_1a7ab14a3c0306b5654c447f15269443
'@vue/cli-plugin-eslint': 5.0.4_6084a5b0c7b00dd6f5be6d9e72604c89
'@vue/cli-plugin-router': 5.0.4_@vue+cli-service@5.0.4
@ -446,6 +448,8 @@ packages:
resolution: {integrity: sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg==}
engines: {node: '>=6.0.0'}
hasBin: true
dependencies:
'@babel/types': 7.17.0
dev: true
/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.16.7_@babel+core@7.17.9:
@ -1824,6 +1828,14 @@ packages:
meaw: 5.0.0
dev: false
/@tailwindcss/aspect-ratio/0.4.0_tailwindcss@3.0.23:
resolution: {integrity: sha512-WJu0I4PpqNPuutpaA9zDUq2JXR+lorZ7PbLcKNLmb6GL9/HLfC7w3CRsMhJF4BbYd/lkY6CfXOvkYpuGnZfkpQ==}
peerDependencies:
tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1'
dependencies:
tailwindcss: 3.0.23
dev: true
/@trysound/sax/0.2.0:
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
engines: {node: '>=10.13.0'}
@ -5202,7 +5214,7 @@ packages:
dev: true
/image-size/0.5.5:
resolution: {integrity: sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=}
resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
engines: {node: '>=0.10.0'}
hasBin: true
requiresBuild: true

111
src/components/Attachment/AttachmentSelectModal.vue

@ -1,5 +1,5 @@
<template>
<a-modal v-model="modalVisible" :afterClose="onAfterClose" :title="title" :width="1024" destroyOnClose>
<a-modal v-model="modalVisible" :afterClose="onAfterClose" :title="title" :width="1280" destroyOnClose>
<div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row :gutter="24">
@ -48,63 +48,64 @@
</a-form>
</div>
<div class="mb-0 table-operator">
<div class="table-operator mb-0">
<a-button icon="cloud-upload" type="primary" @click="upload.visible = true">上传</a-button>
</div>
<a-divider />
<a-list
:dataSource="list.data"
:grid="{ gutter: 6, xs: 2, sm: 2, md: 4, lg: 6, xl: 6, xxl: 6 }"
:loading="list.loading"
class="attachments-group"
>
<template #renderItem="item, index">
<a-list-item
@mouseenter="$set(item, 'hover', true)"
@mouseleave="$set(item, 'hover', false)"
<a-spin :spinning="list.loading">
<div
class="grid grid-cols-2 gap-x-2 gap-y-3 sm:grid-cols-3 md:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10"
role="list"
>
<div
v-for="(attachment, index) in list.data"
:key="index"
@click="handleItemClick(item)"
:class="`${isItemSelect(attachment) ? 'border-blue-600' : 'border-slate-200'}`"
class="relative cursor-pointer overflow-hidden rounded-sm border-solid bg-white transition-all hover:shadow-sm"
@click="handleItemClick(attachment)"
@mouseenter="$set(attachment, 'hover', true)"
@mouseleave="$set(attachment, 'hover', false)"
>
<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="{ backgroundImage: `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 class="group aspect-w-10 aspect-h-7 block w-full overflow-hidden bg-white">
<img
v-if="isImage(attachment)"
:alt="attachment.name"
:src="attachment.thumbPath"
class="pointer-events-none overflow-hidden object-cover transition-opacity group-hover:opacity-70"
loading="lazy"
/>
<span v-else class="flex items-center justify-center text-2xl text-gray-600">
{{ attachment.suffix }}
</span>
</div>
</a-list-item>
</template>
</a-list>
<a-tooltip :title="attachment.name">
<span class="block truncate p-1.5 text-xs font-medium text-gray-500">
{{ attachment.name }}
</span>
</a-tooltip>
<a-icon
v-show="isItemSelect(attachment) && !attachment.hover"
:style="{ fontSize: '20px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-1 cursor-pointer font-bold transition-all"
theme="twoTone"
type="check-circle"
/>
<a-icon
v-show="attachment.hover"
:style="{ fontSize: '20px' }"
class="absolute top-1 right-1 cursor-pointer font-bold transition-all"
theme="twoTone"
type="profile"
@click.stop="handleOpenDetail(attachment)"
/>
</div>
</div>
</a-spin>
<div class="flex justify-between">
<div class="mt-4 flex justify-between">
<a-popover placement="right" title="预览" trigger="click">
<template slot="content">
<a-tabs v-if="list.selected.length" default-active-key="markdown" tab-position="left">
@ -122,7 +123,7 @@
<div v-else class="text-slate-400">未选择附件</div>
</template>
<a-tooltip placement="top" title="点击预览">
<div class="self-center text-slate-400 select-none cursor-pointer hover:text-blue-400 transition-all">
<div class="cursor-pointer select-none self-center text-slate-400 transition-all hover:text-blue-400">
已选择 {{ list.selected.length }}
</div>
</a-tooltip>
@ -132,7 +133,7 @@
<a-pagination
:current="pagination.page"
:defaultPageSize="pagination.size"
:pageSizeOptions="['12', '18', '24', '30', '36', '42']"
:pageSizeOptions="['40', '50', '100', '150', '200']"
:total="pagination.total"
class="pagination !mt-0"
showLessItems
@ -143,9 +144,9 @@
</div>
</div>
<template slot="footer">
<template #footer>
<a-button @click="modalVisible = false">取消</a-button>
<a-button type="primary" :disabled="!list.selected.length" @click="handleConfirm">确定</a-button>
<a-button :disabled="!list.selected.length" type="primary" @click="handleConfirm">确定</a-button>
</template>
<AttachmentUploadModal :visible.sync="upload.visible" @close="handleSearch" />
@ -154,7 +155,7 @@
<template #extraFooter>
<a-button :disabled="selectPreviousButtonDisabled" @click="handleSelectPrevious">上一项</a-button>
<a-button :disabled="selectNextButtonDisabled" @click="handleSelectNext">下一项</a-button>
<a-button @click="handleItemClick(list.current)" type="primary">
<a-button type="primary" @click="handleItemClick(list.current)">
{{ list.selected.findIndex(item => item.id === list.current.id) > -1 ? '取消选择' : '选择' }}
</a-button>
</template>
@ -191,7 +192,7 @@ export default {
loading: false,
params: {
page: 0,
size: 12,
size: 40,
keyword: undefined,
mediaType: undefined,
attachmentType: undefined
@ -356,7 +357,7 @@ export default {
handleResetParam() {
this.list.params = {
page: 0,
size: 12,
size: 40,
keyword: undefined,
mediaType: undefined,
attachmentType: undefined

75
src/styles/global.less

@ -648,44 +648,6 @@ body {
}
}
.attach-item {
width: 50%;
padding-bottom: 28%;
float: left;
}
.attach-thumb,
.photo-thumb {
width: 100%;
padding-bottom: 56%;
}
.attach-item,
.attach-thumb,
.photo-thumb {
margin: 0 auto;
position: relative;
overflow: hidden;
cursor: pointer;
img,
span {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
span {
display: flex;
font-size: 12px;
align-items: center;
justify-content: center;
color: #9b9ea0;
}
}
.analysis-card-container {
position: relative;
overflow: hidden;
@ -741,21 +703,6 @@ body {
}
}
.select-attachment-checkbox {
display: block;
width: 100%;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
z-index: 10;
.ant-checkbox {
margin-left: 4px;
}
}
.ant-list-item {
.ant-list-item-main,
.ant-list-item-meta-content,
@ -798,28 +745,6 @@ body {
top: 0;
}
// 附件图片样式
.attachments-group,
.photos-group {
&-item {
padding: 0;
height: 130px;
&-img {
display: block;
height: 100%;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
.attachments-group &-type {
font-size: 38px;
text-transform: capitalize;
}
}
}
.ant-affix {
z-index: 1000 !important;
}

118
src/views/attachment/AttachmentList.vue

@ -50,7 +50,7 @@
</a-row>
</a-form>
</div>
<div class="mb-0 table-operator">
<div class="table-operator mb-0">
<a-button icon="cloud-upload" type="primary" @click="upload.visible = true">上传</a-button>
<a-button v-show="list.selected.length" icon="check-circle" type="primary" @click="handleSelectAll">
全选
@ -63,67 +63,65 @@
</a-card>
</a-col>
<a-col :span="24">
<a-list
:dataSource="list.data"
:grid="{ gutter: 6, xs: 2, sm: 2, md: 4, lg: 6, xl: 6, xxl: 6 }"
:loading="list.loading"
class="attachments-group"
>
<template #renderItem="item, index">
<a-list-item
<a-spin :spinning="list.loading">
<div
class="grid grid-cols-2 gap-x-2 gap-y-3 sm:grid-cols-3 md:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10"
role="list"
>
<div
v-for="(attachment, index) in list.data"
:key="index"
@click="handleItemClick(item)"
@mouseenter="$set(item, 'hover', true)"
@mouseleave="$set(item, 'hover', false)"
@contextmenu.prevent="handleContextMenu($event, item)"
:class="`${isItemSelect(attachment) ? 'border-blue-600' : 'border-white'}`"
class="relative cursor-pointer overflow-hidden rounded-sm border-solid bg-white transition-all hover:shadow-sm"
@click="handleItemClick(attachment)"
@mouseenter="$set(attachment, 'hover', true)"
@mouseleave="$set(attachment, 'hover', false)"
@contextmenu.prevent="handleContextMenu($event, attachment)"
>
<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="{ backgroundImage: `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"
:style="{ fontSize: '18px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-2 font-bold cursor-pointer transition-all"
theme="twoTone"
type="plus-circle"
@click.stop="handleSelect(item)"
/>
<a-icon
v-show="isItemSelect(item)"
:style="{ fontSize: '18px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-2 font-bold cursor-pointer transition-all"
theme="twoTone"
type="check-circle"
/>
<a-icon
v-show="item.hover && list.selected.length > 0"
:style="{ fontSize: '18px' }"
class="absolute top-1 left-2 font-bold cursor-pointer transition-all"
theme="twoTone"
type="profile"
@click.stop="handleOpenDetail(item)"
<div class="group aspect-w-10 aspect-h-7 block w-full overflow-hidden bg-white">
<img
v-if="isImage(attachment)"
:alt="attachment.name"
:src="attachment.thumbPath"
class="pointer-events-none overflow-hidden object-cover transition-opacity group-hover:opacity-70"
loading="lazy"
/>
<span v-else class="flex items-center justify-center text-2xl text-gray-600">
{{ attachment.suffix }}
</span>
</div>
</a-list-item>
</template>
</a-list>
<a-tooltip :title="attachment.name">
<span class="block truncate p-1.5 text-xs font-medium text-gray-500">
{{ attachment.name }}
</span>
</a-tooltip>
<a-icon
v-show="!isItemSelect(attachment) && attachment.hover"
:style="{ fontSize: '20px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-1 cursor-pointer font-bold transition-all"
theme="twoTone"
type="plus-circle"
@click.stop="handleSelect(attachment)"
/>
<a-icon
v-show="isItemSelect(attachment)"
:style="{ fontSize: '20px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-1 cursor-pointer font-bold transition-all"
theme="twoTone"
type="check-circle"
/>
<a-icon
v-show="attachment.hover && list.selected.length > 0"
:style="{ fontSize: '20px' }"
class="absolute top-1 left-1 cursor-pointer font-bold transition-all"
theme="twoTone"
type="profile"
@click.stop="handleOpenDetail(attachment)"
/>
</div>
</div>
</a-spin>
</a-col>
</a-row>
@ -131,7 +129,7 @@
<a-pagination
:current="pagination.page"
:defaultPageSize="pagination.size"
:pageSizeOptions="['18', '36', '54', '72', '90', '108']"
:pageSizeOptions="['50', '100', '150', '200']"
:total="pagination.total"
class="pagination"
showLessItems
@ -183,7 +181,7 @@ export default {
hasPrevious: false,
params: {
page: 0,
size: 18,
size: 50,
keyword: undefined,
mediaType: undefined,
attachmentType: undefined

102
src/views/sheet/independent/PhotoList.vue

@ -31,7 +31,7 @@
</a-row>
</a-form>
</div>
<div class="mb-0 table-operator">
<div class="table-operator mb-0">
<a-dropdown>
<template #overlay>
<a-menu>
@ -58,60 +58,55 @@
</a-card>
</a-col>
<a-col :span="24">
<a-list
:dataSource="list.data"
:grid="{ gutter: 6, xs: 2, sm: 2, md: 4, lg: 6, xl: 6, xxl: 6 }"
:loading="list.loading"
class="photos-group"
>
<template #renderItem="item, index">
<a-list-item
<a-spin :spinning="list.loading">
<div
class="grid grid-cols-2 gap-x-2 gap-y-3 sm:grid-cols-3 md:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-10"
role="list"
>
<div
v-for="(photo, index) in list.data"
:key="index"
@click="handleItemClick(item)"
@mouseenter="$set(item, 'hover', true)"
@mouseleave="$set(item, 'hover', false)"
:class="`${isItemSelect(photo) ? 'border-blue-600' : 'border-white'}`"
class="relative cursor-pointer overflow-hidden rounded-sm border-solid bg-white transition-all hover:shadow-sm"
@click="handleItemClick(photo)"
@mouseenter="$set(photo, 'hover', true)"
@mouseleave="$set(photo, 'hover', false)"
>
<div
:class="`${isItemSelect(item) ? 'border-blue-600' : 'border-slate-200'}`"
class="border border-solid"
>
<div class="photo-thumb photos-group-item">
<span
:style="{ backgroundImage: `url('${item.thumbnail}')` }"
class="photos-group-item-img"
loading="lazy"
/>
</div>
<a-card-meta class="p-2 cursor-pointer">
<template #description>
<a-tooltip :title="item.name">
<div class="truncate">
<span class="mr-1">{{ item.name }}</span>
<span v-if="item.team" class="text-gray-500 text-xs">#{{ item.team }}</span>
</div>
</a-tooltip>
</template>
</a-card-meta>
<a-icon
v-show="!isItemSelect(item) && item.hover"
:style="{ fontSize: '18px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-2 font-bold cursor-pointer transition-all"
theme="twoTone"
type="plus-circle"
@click.stop="handleSelect(item)"
/>
<a-icon
v-show="isItemSelect(item)"
:style="{ fontSize: '18px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-2 font-bold cursor-pointer transition-all"
theme="twoTone"
type="check-circle"
<div class="group aspect-w-10 aspect-h-7 block w-full overflow-hidden bg-white">
<img
:alt="photo.name"
:src="photo.thumbnail"
class="pointer-events-none overflow-hidden object-cover transition-opacity group-hover:opacity-70"
loading="lazy"
/>
</div>
</a-list-item>
</template>
</a-list>
<a-tooltip :title="photo.name">
<div class="block truncate p-1.5 text-xs font-medium text-gray-500">
<span class="mr-1">
{{ photo.name }}
</span>
<span v-if="photo.team">#{{ photo.team }}</span>
</div>
</a-tooltip>
<a-icon
v-show="!isItemSelect(photo) && photo.hover"
:style="{ fontSize: '20px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-1 cursor-pointer font-bold transition-all"
theme="twoTone"
type="plus-circle"
@click.stop="handleSelect(photo)"
/>
<a-icon
v-show="isItemSelect(photo)"
:style="{ fontSize: '20px', color: 'rgb(37 99 235)' }"
class="absolute top-1 right-1 cursor-pointer font-bold transition-all"
theme="twoTone"
type="check-circle"
/>
</div>
</div>
</a-spin>
</a-col>
</a-row>
@ -119,8 +114,9 @@
<a-pagination
:current="pagination.page"
:defaultPageSize="pagination.size"
:pageSizeOptions="['18', '36', '54', '72', '90', '108']"
:pageSizeOptions="['50', '100', '150', '200']"
:total="pagination.total"
class="pagination"
showLessItems
showSizeChanger
@change="handlePageChange"
@ -203,7 +199,7 @@ export default {
loading: false,
params: {
page: 0,
size: 18,
size: 50,
sort: ['createTime,desc', 'id,asc'],
keyword: null,
team: undefined

2
tailwind.config.js

@ -6,5 +6,5 @@ module.exports = {
corePlugins: {
preflight: false
},
plugins: []
plugins: [require('@tailwindcss/aspect-ratio')]
}

Loading…
Cancel
Save