refactor: post list component code optimization (#445)

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/446/head^2
Ryan Wang 2022-02-21 13:59:10 +08:00 committed by GitHub
parent 4c886bf512
commit 3ec0cbba66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 216 additions and 200 deletions

View File

@ -95,3 +95,30 @@ export const attachmentTypes = {
text: 'MinIO'
}
}
export const postStatuses = {
PUBLISHED: {
value: 'PUBLISHED',
color: 'green',
status: 'success',
text: '已发布'
},
DRAFT: {
value: 'DRAFT',
color: 'yellow',
status: 'warning',
text: '草稿'
},
RECYCLE: {
value: 'RECYCLE',
color: 'red',
status: 'error',
text: '回收站'
},
INTIMATE: {
value: 'INTIMATE',
color: 'blue',
status: 'success',
text: '私密'
}
}

View File

@ -12,8 +12,8 @@
<a-col :md="6" :sm="24">
<a-form-item label="文章状态:">
<a-select v-model="list.params.status" allowClear placeholder="请选择文章状态" @change="handleQuery()">
<a-select-option v-for="status in Object.keys(postStatus)" :key="status" :value="status">
{{ postStatus[status].text }}
<a-select-option v-for="status in Object.keys(postStatuses)" :key="status" :value="status">
{{ postStatuses[status].text }}
</a-select-option>
</a-select>
</a-form-item>
@ -51,32 +51,34 @@
<a-button icon="plus" type="primary">写文章</a-button>
</router-link>
<a-dropdown v-show="list.params.status != null && list.params.status !== '' && !isMobile()">
<a-menu slot="overlay">
<a-menu-item
v-if="['DRAFT', 'RECYCLE'].includes(list.params.status)"
key="1"
@click="handleEditStatusMore(postStatus.PUBLISHED.value)"
>
发布
</a-menu-item>
<a-menu-item
v-if="['PUBLISHED', 'DRAFT', 'INTIMATE'].includes(list.params.status)"
key="2"
@click="handleEditStatusMore(postStatus.RECYCLE.value)"
>
移到回收站
</a-menu-item>
<a-menu-item
v-if="['RECYCLE', 'PUBLISHED', 'INTIMATE'].includes(list.params.status)"
key="3"
@click="handleEditStatusMore(postStatus.DRAFT.value)"
>
草稿
</a-menu-item>
<a-menu-item v-if="['RECYCLE', 'DRAFT'].includes(list.params.status)" key="4" @click="handleDeleteMore">
永久删除
</a-menu-item>
</a-menu>
<template #overlay>
<a-menu>
<a-menu-item
v-if="['DRAFT', 'RECYCLE'].includes(list.params.status)"
key="1"
@click="handleEditStatusMore(postStatuses.PUBLISHED.value)"
>
发布
</a-menu-item>
<a-menu-item
v-if="['PUBLISHED', 'DRAFT', 'INTIMATE'].includes(list.params.status)"
key="2"
@click="handleEditStatusMore(postStatuses.RECYCLE.value)"
>
移到回收站
</a-menu-item>
<a-menu-item
v-if="['RECYCLE', 'PUBLISHED', 'INTIMATE'].includes(list.params.status)"
key="3"
@click="handleEditStatusMore(postStatuses.DRAFT.value)"
>
草稿
</a-menu-item>
<a-menu-item v-if="['RECYCLE', 'DRAFT'].includes(list.params.status)" key="4" @click="handleDeleteMore">
永久删除
</a-menu-item>
</a-menu>
</template>
<a-button class="ml-2">
批量操作
<a-icon type="down" />
@ -87,138 +89,153 @@
<!-- Mobile -->
<a-list
v-if="isMobile()"
:dataSource="formattedPosts"
:dataSource="list.data"
:loading="list.loading"
:pagination="false"
itemLayout="vertical"
size="large"
>
<a-list-item :key="index" slot="renderItem" slot-scope="item, index">
<template slot="actions">
<span>
<a-icon type="eye" />
{{ item.visits }}
</span>
<span @click="handleShowPostComments(item)">
<a-icon type="message" />
{{ item.commentCount }}
</span>
<a-dropdown :trigger="['click']" placement="topLeft">
<template #renderItem="item, index">
<a-list-item :key="index">
<template #actions>
<span>
<a-icon type="bars" />
<a-icon type="eye" />
{{ item.visits }}
</span>
<a-menu slot="overlay">
<a-menu-item
v-if="['PUBLISHED', 'DRAFT', 'INTIMATE'].includes(item.status)"
@click="handleEditClick(item)"
>
编辑
</a-menu-item>
<a-menu-item v-else-if="item.status === 'RECYCLE'">
<a-popconfirm
:title="'你确定要发布【' + item.title + '】文章?'"
cancelText="取消"
okText="确定"
@confirm="handleEditStatusClick(item.id, 'PUBLISHED')"
>
还原
</a-popconfirm>
</a-menu-item>
<a-menu-item v-if="['PUBLISHED', 'DRAFT', 'INTIMATE'].includes(item.status)">
<a-popconfirm
:title="'你确定要将【' + item.title + '】文章移到回收站?'"
cancelText="取消"
okText="确定"
@confirm="handleEditStatusClick(item.id, 'RECYCLE')"
>
回收站
</a-popconfirm>
</a-menu-item>
<a-menu-item v-else-if="item.status === 'RECYCLE'">
<a-popconfirm
:title="'你确定要永久删除【' + item.title + '】文章?'"
cancelText="取消"
okText="确定"
@confirm="handleDeleteClick(item.id)"
>
删除
</a-popconfirm>
</a-menu-item>
<a-menu-item @click="handleShowPostSettings(item)"></a-menu-item>
</a-menu>
</a-dropdown>
</template>
<template slot="extra">
<span>
<a-badge :status="item.statusProperty.status" :text="item.statusProperty.text" />
</span>
</template>
<a-list-item-meta>
<template slot="description">
{{ item.createTime | moment }}
<span @click="handleShowPostComments(item)">
<a-icon type="message" />
{{ item.commentCount }}
</span>
<a-dropdown :trigger="['click']" placement="topLeft">
<span>
<a-icon type="bars" />
</span>
<template #overlay>
<a-menu>
<a-menu-item
v-if="['PUBLISHED', 'DRAFT', 'INTIMATE'].includes(item.status)"
@click="handleEditClick(item)"
>
编辑
</a-menu-item>
<a-menu-item v-else-if="item.status === 'RECYCLE'">
<a-popconfirm
:title="'你确定要发布【' + item.title + '】文章?'"
cancelText="取消"
okText="确定"
@confirm="handleEditStatusClick(item.id, 'PUBLISHED')"
>
还原
</a-popconfirm>
</a-menu-item>
<a-menu-item v-if="['PUBLISHED', 'DRAFT', 'INTIMATE'].includes(item.status)">
<a-popconfirm
:title="'你确定要将【' + item.title + '】文章移到回收站?'"
cancelText="取消"
okText="确定"
@confirm="handleEditStatusClick(item.id, 'RECYCLE')"
>
回收站
</a-popconfirm>
</a-menu-item>
<a-menu-item v-else-if="item.status === 'RECYCLE'">
<a-popconfirm
:title="'你确定要永久删除【' + item.title + '】文章?'"
cancelText="取消"
okText="确定"
@confirm="handleDeleteClick(item.id)"
>
删除
</a-popconfirm>
</a-menu-item>
<a-menu-item @click="handleShowPostSettings(item)"></a-menu-item>
</a-menu>
</template>
</a-dropdown>
</template>
<template #title>
<div
style="
max-width: 300px;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
>
<a-icon
v-if="item.topPriority !== 0"
style="margin-right: 3px"
theme="twoTone"
twoToneColor="red"
type="pushpin"
/>
<a-tooltip
v-if="['PUBLISHED', 'INTIMATE'].includes(item.status)"
:title="'点击访问【' + item.title + '】'"
placement="top"
<template #extra>
<a-badge :status="postStatuses[item.status].status" :text="item.status | statusText" />
</template>
<a-list-item-meta>
<template #description>
{{ item.createTime | moment }}
</template>
<template #title>
<div
style="
max-width: 300px;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
"
>
<a :href="item.fullPath" class="no-underline" target="_blank">
{{ item.title }}
</a>
</a-tooltip>
<a-tooltip
v-else-if="item.status === 'DRAFT'"
:title="'点击预览【' + item.title + '】'"
placement="top"
>
<a-button class="!p-0" type="link" @click="handlePreview(item.id)">
<a-icon
v-if="item.topPriority !== 0"
style="margin-right: 3px"
theme="twoTone"
twoToneColor="red"
type="pushpin"
/>
<a-tooltip v-if="item.inProgress" placement="top" title="当前有内容已保存,但还未发布。">
<a-icon
class="cursor-pointer"
style="margin-right: 3px"
theme="twoTone"
twoToneColor="#52c41a"
type="info-circle"
/>
</a-tooltip>
<a-tooltip
v-if="['PUBLISHED', 'INTIMATE'].includes(item.status)"
:title="'点击访问【' + item.title + '】'"
placement="top"
>
<a :href="item.fullPath" class="no-underline" target="_blank">
{{ item.title }}
</a>
</a-tooltip>
<a-tooltip
v-else-if="item.status === 'DRAFT'"
:title="'点击预览【' + item.title + '】'"
placement="top"
>
<a class="no-underline" href="javascript:void(0);" @click="handlePreview(item.id)">
{{ item.title }}
</a>
</a-tooltip>
<a-button v-else class="!p-0" disabled type="link">
{{ item.title }}
</a-button>
</a-tooltip>
<a-button v-else class="!p-0" disabled type="link">
{{ item.title }}
</a-button>
</div>
</template>
</a-list-item-meta>
<span> {{ item.summary }}... </span>
<br />
<br />
<a-tag
v-for="(category, categoryIndex) in item.categories"
:key="'category_' + categoryIndex"
color="blue"
style="margin-bottom: 8px"
@click="handleSelectCategory(category)"
>{{ category.name }}
</a-tag>
<br />
<post-tag v-for="(tag, tagIndex) in item.tags" :key="tagIndex" :tag="tag" style="margin-bottom: 8px" />
</a-list-item>
</div>
</template>
</a-list-item-meta>
<div v-if="item.summary" class="mb-3 block">
<span> {{ item.summary }}... </span>
</div>
<div class="block">
<a-tag
v-for="(category, categoryIndex) in item.categories"
:key="'category_' + categoryIndex"
color="blue"
style="margin-bottom: 8px"
@click="handleSelectCategory(category)"
>{{ category.name }}
</a-tag>
</div>
<post-tag v-for="(tag, tagIndex) in item.tags" :key="tagIndex" :tag="tag" style="margin-bottom: 8px" />
</a-list-item>
</template>
</a-list>
<!-- Desktop -->
<a-table
v-else
:columns="columns"
:dataSource="formattedPosts"
:dataSource="list.data"
:loading="list.loading"
:pagination="false"
:rowKey="post => post.id"
@ -264,13 +281,14 @@
{{ text }}
</a-button>
</template>
<span slot="status" slot-scope="statusProperty">
<a-badge :status="statusProperty.status" :text="statusProperty.text" />
</span>
<span slot="categories" slot-scope="categoriesOfPost">
<template #status="status">
<a-badge :status="postStatuses[status].status" :text="status | statusText" />
</template>
<template #categories="categories">
<a-tag
v-for="(category, index) in categoriesOfPost"
v-for="(category, index) in categories"
:key="index"
color="blue"
style="margin-bottom: 8px; cursor: pointer"
@ -278,52 +296,50 @@
>
{{ category.name }}
</a-tag>
</span>
</template>
<template #tags="tags">
<post-tag v-for="(tag, index) in tags" :key="index" :tag="tag" style="margin-bottom: 8px" />
</template>
<span
slot="commentCount"
slot-scope="text, record"
style="cursor: pointer"
@click="handleShowPostComments(record)"
>
<template #commentCount="text, record">
<a-badge
:count="record.commentCount"
:numberStyle="{ backgroundColor: '#f38181' }"
:overflowCount="999"
:showZero="true"
class="cursor-pointer"
@click="handleShowPostComments(record)"
/>
</span>
</template>
<span slot="visits" slot-scope="visits">
<template #visits="visits">
<a-badge
:count="visits"
:numberStyle="{ backgroundColor: '#00e0ff' }"
:overflowCount="9999"
:showZero="true"
class="cursor-pointer"
/>
</span>
</template>
<span slot="createTime" slot-scope="createTime">
<template #createTime="createTime">
<a-tooltip placement="top">
<template slot="title">
<template #title>
{{ createTime | moment }}
</template>
{{ createTime | timeAgo }}
</a-tooltip>
</span>
</template>
<span slot="action" slot-scope="text, post">
<template #action="text, post">
<a-button
v-if="['PUBLISHED', 'DRAFT', 'INTIMATE'].includes(post.status)"
class="!p-0"
type="link"
@click="handleEditClick(post)"
>编辑</a-button
>
>编辑
</a-button>
<a-popconfirm
v-else-if="post.status === 'RECYCLE'"
:title="'你确定要发布【' + post.title + '】文章?'"
@ -359,7 +375,7 @@
<a-divider type="vertical" />
<a-button class="!p-0" type="link" @click="handleShowPostSettings(post)"></a-button>
</span>
</template>
</a-table>
<div class="page-wrapper">
<a-pagination
@ -407,6 +423,7 @@ import { PageView } from '@/layouts'
import PostSettingModal from './components/PostSettingModal.vue'
import TargetCommentDrawer from '../comment/components/TargetCommentDrawer'
import apiClient from '@/utils/api-client'
import { postStatuses } from '@/core/constant'
const columns = [
{
@ -418,8 +435,7 @@ const columns = [
},
{
title: '状态',
className: 'status',
dataIndex: 'statusProperty',
dataIndex: 'status',
width: '100px',
scopedSlots: { customRender: 'status' }
},
@ -457,32 +473,6 @@ const columns = [
scopedSlots: { customRender: 'action' }
}
]
const postStatus = {
PUBLISHED: {
value: 'PUBLISHED',
color: 'green',
status: 'success',
text: '已发布'
},
DRAFT: {
value: 'DRAFT',
color: 'yellow',
status: 'warning',
text: '草稿'
},
RECYCLE: {
value: 'RECYCLE',
color: 'red',
status: 'error',
text: '回收站'
},
INTIMATE: {
value: 'INTIMATE',
color: 'blue',
status: 'success',
text: '私密'
}
}
export default {
name: 'PostList',
components: {
@ -493,8 +483,8 @@ export default {
mixins: [mixin, mixinDevice],
data() {
return {
postStatus,
columns,
postStatuses,
list: {
data: [],
loading: false,
@ -523,12 +513,6 @@ export default {
}
},
computed: {
formattedPosts() {
return this.list.data.map(post => {
post.statusProperty = this.postStatus[post.status]
return post
})
},
pagination() {
return {
page: this.list.params.page + 1,
@ -799,6 +783,11 @@ export default {
this.postSettingLoading = false
}
}
},
filters: {
statusText(type) {
return type ? postStatuses[type].text : ''
}
}
}
</script>