mirror of https://github.com/halo-dev/halo
refactor: attachment selection modal (halo-dev/console#420)
* refactor: attachment selection modal Signed-off-by: Ryan Wang <i@ryanc.cc> * feat: support view attachment detail Signed-off-by: Ryan Wang <i@ryanc.cc> * chore: remove AttachmentSelectDrawer.vue Signed-off-by: Ryan Wang <i@ryanc.cc> * chore: remove AttachmentDrawer.vue Signed-off-by: Ryan Wang <i@ryanc.cc> * perf: add selected icon Signed-off-by: Ryan Wang <i@ryanc.cc> * perf: add search form Signed-off-by: Ryan Wang <i@ryanc.cc> * perf: support upload file Signed-off-by: Ryan Wang <i@ryanc.cc> * refactor: attachment selection modal Signed-off-by: Ryan Wang <i@ryanc.cc>pull/3445/head
parent
867f78aa4a
commit
727a4d6db4
|
@ -108,52 +108,14 @@
|
|||
<script>
|
||||
import { mixin, mixinDevice } from '@/mixins/mixin.js'
|
||||
import apiClient from '@/utils/api-client'
|
||||
|
||||
const attachmentType = {
|
||||
LOCAL: {
|
||||
type: 'LOCAL',
|
||||
text: '本地'
|
||||
},
|
||||
SMMS: {
|
||||
type: 'SMMS',
|
||||
text: 'SM.MS'
|
||||
},
|
||||
UPOSS: {
|
||||
type: 'UPOSS',
|
||||
text: '又拍云'
|
||||
},
|
||||
QINIUOSS: {
|
||||
type: 'QINIUOSS',
|
||||
text: '七牛云'
|
||||
},
|
||||
ALIOSS: {
|
||||
type: 'ALIOSS',
|
||||
text: '阿里云'
|
||||
},
|
||||
BAIDUBOS: {
|
||||
type: 'BAIDUBOS',
|
||||
text: '百度云'
|
||||
},
|
||||
TENCENTCOS: {
|
||||
type: 'TENCENTCOS',
|
||||
text: '腾讯云'
|
||||
},
|
||||
HUAWEIOBS: {
|
||||
type: 'HUAWEIOBS',
|
||||
text: '华为云'
|
||||
},
|
||||
MINIO: {
|
||||
type: 'MINIO',
|
||||
text: 'MinIO'
|
||||
}
|
||||
}
|
||||
import { attachmentTypes } from '@/core/constant'
|
||||
|
||||
export default {
|
||||
name: 'AttachmentDetailModal',
|
||||
mixins: [mixin, mixinDevice],
|
||||
filters: {
|
||||
typeText(type) {
|
||||
return type ? attachmentType[type].text : ''
|
||||
return type ? attachmentTypes[type].text : ''
|
||||
}
|
||||
},
|
||||
props: {
|
|
@ -1,169 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<a-drawer
|
||||
:afterVisibleChange="handleAfterVisibleChanged"
|
||||
:title="title"
|
||||
:visible="visible"
|
||||
:width="isMobile() ? '100%' : drawerWidth"
|
||||
closable
|
||||
destroyOnClose
|
||||
@close="onClose"
|
||||
>
|
||||
<a-row align="middle" type="flex">
|
||||
<a-input-search v-model="queryParam.keyword" enterButton placeholder="搜索" @search="handleQuery()" />
|
||||
</a-row>
|
||||
<a-divider />
|
||||
<a-row align="middle" type="flex">
|
||||
<a-col :span="24">
|
||||
<a-spin :spinning="loading" class="attachments-group">
|
||||
<a-empty v-if="attachments.length === 0" />
|
||||
<div
|
||||
v-for="(item, index) in attachments"
|
||||
v-else
|
||||
:key="index"
|
||||
class="attach-item attachments-group-item"
|
||||
@click="handleSelectAttachment(item)"
|
||||
>
|
||||
<span v-if="!handleJudgeMediaType(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-spin>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider />
|
||||
<div class="page-wrapper">
|
||||
<a-pagination
|
||||
:current="pagination.page"
|
||||
:defaultPageSize="pagination.size"
|
||||
:total="pagination.total"
|
||||
showLessItems
|
||||
@change="handlePaginationChange"
|
||||
></a-pagination>
|
||||
</div>
|
||||
<a-divider class="divider-transparent" />
|
||||
<div class="bottom-control">
|
||||
<a-space>
|
||||
<a-button v-if="isChooseAvatar" type="dashed" @click="handleSelectGravatar">使用 Gravatar</a-button>
|
||||
<a-button type="primary" @click="handleShowUploadModal">上传附件</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</a-drawer>
|
||||
|
||||
<AttachmentUploadModal :visible.sync="uploadVisible" @close="onUploadClose" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mixin, mixinDevice } from '@/mixins/mixin.js'
|
||||
import apiClient from '@/utils/api-client'
|
||||
|
||||
export default {
|
||||
name: 'AttachmentSelectDrawer',
|
||||
mixins: [mixin, mixinDevice],
|
||||
model: {
|
||||
prop: 'visible',
|
||||
event: 'close'
|
||||
},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
drawerWidth: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 480
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '选择附件'
|
||||
},
|
||||
isChooseAvatar: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uploadVisible: false,
|
||||
loading: true,
|
||||
pagination: {
|
||||
page: 1,
|
||||
size: 12,
|
||||
sort: null,
|
||||
total: 1
|
||||
},
|
||||
queryParam: {
|
||||
page: 0,
|
||||
size: 12,
|
||||
sort: null,
|
||||
keyword: null
|
||||
},
|
||||
attachments: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleShowUploadModal() {
|
||||
this.uploadVisible = true
|
||||
},
|
||||
handleListAttachments() {
|
||||
this.loading = true
|
||||
this.queryParam.page = this.pagination.page - 1
|
||||
this.queryParam.size = this.pagination.size
|
||||
this.queryParam.sort = this.pagination.sort
|
||||
apiClient.attachment
|
||||
.list(this.queryParam)
|
||||
.then(response => {
|
||||
this.attachments = response.data.content
|
||||
this.pagination.total = response.data.total
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.handlePaginationChange(1, this.pagination.size)
|
||||
},
|
||||
handleSelectAttachment(item) {
|
||||
this.$emit('listenToSelect', item)
|
||||
},
|
||||
handleSelectGravatar() {
|
||||
this.$emit('listenToSelectGravatar')
|
||||
},
|
||||
handlePaginationChange(page, pageSize) {
|
||||
this.pagination.page = page
|
||||
this.pagination.size = pageSize
|
||||
this.handleListAttachments()
|
||||
},
|
||||
onUploadClose() {
|
||||
this.handlePaginationChange(1, this.pagination.size)
|
||||
},
|
||||
handleAfterVisibleChanged(visible) {
|
||||
if (visible) {
|
||||
this.handleListAttachments()
|
||||
}
|
||||
},
|
||||
handleJudgeMediaType(attachment) {
|
||||
const mediaType = attachment.mediaType
|
||||
// 判断文件类型
|
||||
if (mediaType) {
|
||||
const prefix = mediaType.split('/')[0]
|
||||
|
||||
return prefix === 'image'
|
||||
}
|
||||
return false
|
||||
},
|
||||
onClose() {
|
||||
this.$emit('close', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,461 @@
|
|||
<template>
|
||||
<a-modal v-model="modalVisible" :afterClose="onAfterClose" :title="title" :width="1024" destroyOnClose>
|
||||
<div class="table-page-search-wrapper">
|
||||
<a-form layout="inline">
|
||||
<a-row :gutter="24">
|
||||
<a-col :md="6" :sm="24">
|
||||
<a-form-item label="关键词:">
|
||||
<a-input v-model="list.params.keyword" @keyup.enter="handleSearch()" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="6" :sm="24">
|
||||
<a-form-item label="存储位置:">
|
||||
<a-select
|
||||
v-model="list.params.attachmentType"
|
||||
:loading="types.loading"
|
||||
allowClear
|
||||
@change="handleSearch()"
|
||||
>
|
||||
<a-select-option v-for="item in types.data" :key="item" :value="item">
|
||||
{{ item | typeText }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="6" :sm="24">
|
||||
<a-form-item label="文件类型:">
|
||||
<a-select
|
||||
v-model="list.params.mediaType"
|
||||
:loading="mediaTypes.loading"
|
||||
allowClear
|
||||
@change="handleSearch()"
|
||||
>
|
||||
<a-select-option v-for="(item, index) in mediaTypes.data" :key="index" :value="item">
|
||||
{{ item }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :md="6" :sm="24">
|
||||
<span class="table-page-search-submitButtons">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleSearch()">查询</a-button>
|
||||
<a-button @click="handleResetParam(), handleListAttachments()">重置</a-button>
|
||||
</a-space>
|
||||
</span>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</div>
|
||||
|
||||
<div class="mb-0 table-operator">
|
||||
<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"
|
||||
>
|
||||
<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"
|
||||
/>
|
||||
</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>
|
||||
|
||||
<div class="page-wrapper"></div>
|
||||
|
||||
<div class="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">
|
||||
<a-tab-pane key="markdown" tab="Markdown">
|
||||
<div class="text-slate-400" v-html="markdownSyntaxList.join('<br />')"></div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="html" force-render tab="HTML">
|
||||
<div class="text-slate-400">
|
||||
<span v-for="(item, index) in htmlSyntaxList" :key="index" class="text-slate-400">
|
||||
{{ item }}<br />
|
||||
</span>
|
||||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<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">
|
||||
已选择 {{ list.selected.length }} 项
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</a-popover>
|
||||
|
||||
<div class="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"
|
||||
showLessItems
|
||||
showSizeChanger
|
||||
@change="handlePageChange"
|
||||
@showSizeChange="handlePageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template slot="footer">
|
||||
<a-button @click="modalVisible = false">取消</a-button>
|
||||
<a-button type="primary" :disabled="!list.selected.length" @click="handleConfirm">确定</a-button>
|
||||
</template>
|
||||
|
||||
<AttachmentUploadModal :visible.sync="upload.visible" @close="handleSearch" />
|
||||
|
||||
<AttachmentDetailModal :attachment="list.current" :visible.sync="detailVisible" @delete="handleListAttachments()">
|
||||
<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">
|
||||
{{ list.selected.findIndex(item => item.id === list.current.id) > -1 ? '取消选择' : '选择' }}
|
||||
</a-button>
|
||||
</template>
|
||||
</AttachmentDetailModal>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script>
|
||||
import apiClient from '@/utils/api-client'
|
||||
import { attachmentTypes } from '@/core/constant'
|
||||
|
||||
export default {
|
||||
name: 'AttachmentSelectModal',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '选择附件'
|
||||
},
|
||||
multiSelect: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: {
|
||||
data: [],
|
||||
total: 0,
|
||||
hasNext: false,
|
||||
hasPrevious: false,
|
||||
loading: false,
|
||||
params: {
|
||||
page: 0,
|
||||
size: 12,
|
||||
keyword: undefined,
|
||||
mediaType: undefined,
|
||||
attachmentType: undefined
|
||||
},
|
||||
selected: [],
|
||||
current: {}
|
||||
},
|
||||
|
||||
mediaTypes: {
|
||||
data: [],
|
||||
loading: false
|
||||
},
|
||||
|
||||
types: {
|
||||
data: [],
|
||||
loading: false
|
||||
},
|
||||
|
||||
upload: {
|
||||
visible: false
|
||||
},
|
||||
|
||||
detailVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
modalVisible: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('update:visible', value)
|
||||
}
|
||||
},
|
||||
pagination() {
|
||||
return {
|
||||
page: this.list.params.page + 1,
|
||||
size: this.list.params.size,
|
||||
total: this.list.total
|
||||
}
|
||||
},
|
||||
selectPreviousButtonDisabled() {
|
||||
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.current.id)
|
||||
return index === this.list.data.length - 1 && !this.list.hasNext
|
||||
},
|
||||
isImage() {
|
||||
return function (attachment) {
|
||||
if (!attachment || !attachment.mediaType) {
|
||||
return false
|
||||
}
|
||||
return attachment.mediaType.startsWith('image')
|
||||
}
|
||||
},
|
||||
isItemSelect() {
|
||||
return function (attachment) {
|
||||
return this.list.selected.findIndex(item => item.id === attachment.id) > -1
|
||||
}
|
||||
},
|
||||
markdownSyntaxList() {
|
||||
if (!this.list.selected.length) {
|
||||
return []
|
||||
}
|
||||
return this.list.selected.map(item => {
|
||||
return `![${item.name}](${encodeURI(item.path)})`
|
||||
})
|
||||
},
|
||||
htmlSyntaxList() {
|
||||
if (!this.list.selected.length) {
|
||||
return []
|
||||
}
|
||||
return this.list.selected.map(item => {
|
||||
return `<img src="${encodeURI(item.path)}" alt="${item.name}">`
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modalVisible(value) {
|
||||
if (value) {
|
||||
this.handleListAttachments()
|
||||
this.handleListMediaTypes()
|
||||
this.handleListTypes()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* List attachments
|
||||
*/
|
||||
async handleListAttachments() {
|
||||
try {
|
||||
this.list.loading = true
|
||||
|
||||
const response = await apiClient.attachment.list(this.list.params)
|
||||
|
||||
this.list.data = response.data.content
|
||||
this.list.total = response.data.total
|
||||
this.list.hasNext = response.data.hasNext
|
||||
this.list.hasPrevious = response.data.hasPrevious
|
||||
} catch (error) {
|
||||
this.$log.error(error)
|
||||
} finally {
|
||||
this.list.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* List attachment media types
|
||||
*/
|
||||
async handleListMediaTypes() {
|
||||
try {
|
||||
this.mediaTypes.loading = true
|
||||
|
||||
const response = await apiClient.attachment.listMediaTypes()
|
||||
|
||||
this.mediaTypes.data = response.data
|
||||
} catch (error) {
|
||||
this.$log.error(error)
|
||||
} finally {
|
||||
this.mediaTypes.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* List attachment upload types
|
||||
*/
|
||||
async handleListTypes() {
|
||||
try {
|
||||
this.types.loading = true
|
||||
|
||||
const response = await apiClient.attachment.listTypes()
|
||||
|
||||
this.types.data = response.data
|
||||
} catch (error) {
|
||||
this.$log.error(error)
|
||||
} finally {
|
||||
this.types.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle page change
|
||||
*/
|
||||
handlePageChange(page = 1) {
|
||||
this.list.params.page = page - 1
|
||||
this.handleListAttachments()
|
||||
},
|
||||
|
||||
/**
|
||||
* Search attachments
|
||||
*/
|
||||
handleSearch() {
|
||||
this.handlePageChange(1)
|
||||
},
|
||||
|
||||
/**
|
||||
* Reset search params
|
||||
*/
|
||||
handleResetParam() {
|
||||
this.list.params = {
|
||||
page: 0,
|
||||
size: 12,
|
||||
keyword: undefined,
|
||||
mediaType: undefined,
|
||||
attachmentType: undefined
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle page size change
|
||||
*/
|
||||
handlePageSizeChange(current, size) {
|
||||
this.$log.debug(`Current: ${current}, PageSize: ${size}`)
|
||||
this.list.params.page = 0
|
||||
this.list.params.size = size
|
||||
this.handleListAttachments()
|
||||
},
|
||||
|
||||
handleItemClick(attachment) {
|
||||
// single select
|
||||
if (!this.multiSelect) {
|
||||
this.$emit('confirm', {
|
||||
raw: [attachment],
|
||||
markdown: [`![${attachment.name}](${encodeURI(attachment.path)})`],
|
||||
html: [`<img src="${encodeURI(attachment.path)}" alt="${attachment.name}">`]
|
||||
})
|
||||
this.modalVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
const isSelect = this.list.selected.findIndex(item => item.id === attachment.id) > -1
|
||||
isSelect ? 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)
|
||||
},
|
||||
|
||||
handleConfirm() {
|
||||
this.$emit('confirm', {
|
||||
raw: this.list.selected,
|
||||
markdown: this.markdownSyntaxList,
|
||||
html: this.htmlSyntaxList
|
||||
})
|
||||
this.modalVisible = false
|
||||
},
|
||||
|
||||
handleOpenDetail(attachment) {
|
||||
this.list.current = attachment
|
||||
this.detailVisible = true
|
||||
},
|
||||
|
||||
/**
|
||||
* Select previous attachment
|
||||
*/
|
||||
async handleSelectPrevious() {
|
||||
const index = this.list.data.findIndex(item => item.id === this.list.current.id)
|
||||
if (index > 0) {
|
||||
this.list.current = this.list.data[index - 1]
|
||||
return
|
||||
}
|
||||
if (index === 0 && this.list.hasPrevious) {
|
||||
this.list.params.page--
|
||||
await this.handleListAttachments()
|
||||
|
||||
this.list.current = this.list.data[this.list.data.length - 1]
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Select next attachment
|
||||
*/
|
||||
async handleSelectNext() {
|
||||
const index = this.list.data.findIndex(item => item.id === this.list.current.id)
|
||||
if (index < this.list.data.length - 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.current = this.list.data[0]
|
||||
}
|
||||
},
|
||||
|
||||
onAfterClose() {
|
||||
this.handleResetParam()
|
||||
this.list.selected = []
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
typeText(type) {
|
||||
return attachmentTypes[type].text
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,11 +1,15 @@
|
|||
<template>
|
||||
<div>
|
||||
<a-input :defaultValue="defaultValue" :placeholder="placeholder" :value="value" @change="onInputChange">
|
||||
<a slot="addonAfter" href="javascript:void(0);" @click="attachmentDrawerVisible = true">
|
||||
<a slot="addonAfter" href="javascript:void(0);" @click="attachmentModalVisible = true">
|
||||
<a-icon type="picture" />
|
||||
</a>
|
||||
</a-input>
|
||||
<AttachmentSelectDrawer v-model="attachmentDrawerVisible" :title="title" @listenToSelect="handleSelectAttachment" />
|
||||
<AttachmentSelectModal
|
||||
:multiSelect="false"
|
||||
:visible.sync="attachmentModalVisible"
|
||||
@confirm="handleSelectAttachment"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
@ -31,16 +35,17 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
attachmentDrawerVisible: false
|
||||
attachmentModalVisible: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onInputChange(e) {
|
||||
this.$emit('input', e.target.value)
|
||||
},
|
||||
handleSelectAttachment(data) {
|
||||
this.$emit('input', encodeURI(data.path))
|
||||
this.attachmentDrawerVisible = false
|
||||
handleSelectAttachment({ raw }) {
|
||||
if (raw.length) {
|
||||
this.$emit('input', encodeURI(raw[0].path))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,9 @@ import Vue from 'vue'
|
|||
import Ellipsis from '@/components/Ellipsis'
|
||||
import FooterToolbar from '@/components/FooterToolbar'
|
||||
import FilePondUpload from '@/components/Upload/FilePondUpload'
|
||||
import AttachmentSelectDrawer from './Attachment/AttachmentSelectDrawer'
|
||||
import AttachmentUploadModal from './Attachment/AttachmentUploadModal'
|
||||
import AttachmentSelectModal from './Attachment/AttachmentSelectModal'
|
||||
import AttachmentDetailModal from './Attachment/AttachmentDetailModal'
|
||||
import ReactiveButton from './Button/ReactiveButton'
|
||||
import PostTag from './Post/PostTag'
|
||||
import AttachmentInput from './Input/AttachmentInput'
|
||||
|
@ -13,8 +14,9 @@ const _components = {
|
|||
Ellipsis,
|
||||
FooterToolbar,
|
||||
FilePondUpload,
|
||||
AttachmentSelectDrawer,
|
||||
AttachmentUploadModal,
|
||||
AttachmentSelectModal,
|
||||
AttachmentDetailModal,
|
||||
ReactiveButton,
|
||||
PostTag,
|
||||
AttachmentInput
|
||||
|
|
|
@ -56,3 +56,42 @@ export const actionLogTypes = {
|
|||
text: '登录验证'
|
||||
}
|
||||
}
|
||||
|
||||
export const attachmentTypes = {
|
||||
LOCAL: {
|
||||
type: 'LOCAL',
|
||||
text: '本地'
|
||||
},
|
||||
SMMS: {
|
||||
type: 'SMMS',
|
||||
text: 'SM.MS'
|
||||
},
|
||||
UPOSS: {
|
||||
type: 'UPOSS',
|
||||
text: '又拍云'
|
||||
},
|
||||
QINIUOSS: {
|
||||
type: 'QINIUOSS',
|
||||
text: '七牛云'
|
||||
},
|
||||
ALIOSS: {
|
||||
type: 'ALIOSS',
|
||||
text: '阿里云'
|
||||
},
|
||||
BAIDUBOS: {
|
||||
type: 'BAIDUBOS',
|
||||
text: '百度云'
|
||||
},
|
||||
TENCENTCOS: {
|
||||
type: 'TENCENTCOS',
|
||||
text: '腾讯云'
|
||||
},
|
||||
HUAWEIOBS: {
|
||||
type: 'HUAWEIOBS',
|
||||
text: '华为云'
|
||||
},
|
||||
MINIO: {
|
||||
type: 'MINIO',
|
||||
text: 'MinIO'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -818,7 +818,7 @@ body {
|
|||
.attachments-group {
|
||||
&-item {
|
||||
padding: 0;
|
||||
height: 140px;
|
||||
height: 130px;
|
||||
|
||||
&-img {
|
||||
display: block;
|
||||
|
|
|
@ -92,8 +92,12 @@
|
|||
loading="lazy"
|
||||
/>
|
||||
</div>
|
||||
<a-card-meta class="p-3">
|
||||
<ellipsis slot="description" :length="isMobile() ? 12 : 16" tooltip>{{ item.name }}</ellipsis>
|
||||
<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"
|
||||
|
@ -140,58 +144,18 @@
|
|||
<script>
|
||||
import { mixin, mixinDevice } from '@/mixins/mixin.js'
|
||||
import { PageView } from '@/layouts'
|
||||
import AttachmentDetailModal from './components/AttachmentDetailModal.vue'
|
||||
import apiClient from '@/utils/api-client'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
const attachmentType = {
|
||||
LOCAL: {
|
||||
type: 'LOCAL',
|
||||
text: '本地'
|
||||
},
|
||||
SMMS: {
|
||||
type: 'SMMS',
|
||||
text: 'SM.MS'
|
||||
},
|
||||
UPOSS: {
|
||||
type: 'UPOSS',
|
||||
text: '又拍云'
|
||||
},
|
||||
QINIUOSS: {
|
||||
type: 'QINIUOSS',
|
||||
text: '七牛云'
|
||||
},
|
||||
ALIOSS: {
|
||||
type: 'ALIOSS',
|
||||
text: '阿里云'
|
||||
},
|
||||
BAIDUBOS: {
|
||||
type: 'BAIDUBOS',
|
||||
text: '百度云'
|
||||
},
|
||||
TENCENTCOS: {
|
||||
type: 'TENCENTCOS',
|
||||
text: '腾讯云'
|
||||
},
|
||||
HUAWEIOBS: {
|
||||
type: 'HUAWEIOBS',
|
||||
text: '华为云'
|
||||
},
|
||||
MINIO: {
|
||||
type: 'MINIO',
|
||||
text: 'MinIO'
|
||||
}
|
||||
}
|
||||
import { attachmentTypes } from '@/core/constant'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PageView,
|
||||
AttachmentDetailModal
|
||||
PageView
|
||||
},
|
||||
mixins: [mixin, mixinDevice],
|
||||
filters: {
|
||||
typeText(type) {
|
||||
return attachmentType[type].text
|
||||
return attachmentTypes[type].text
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
|
|
@ -1,250 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<a-drawer
|
||||
:afterVisibleChange="handleAfterVisibleChanged"
|
||||
:visible="visible"
|
||||
:width="isMobile() ? '100%' : '480'"
|
||||
closable
|
||||
destroyOnClose
|
||||
title="附件库"
|
||||
@close="onClose"
|
||||
>
|
||||
<a-row align="middle" type="flex">
|
||||
<a-input-search v-model="queryParam.keyword" enterButton placeholder="搜索附件" @search="handleQuery()" />
|
||||
</a-row>
|
||||
<a-divider />
|
||||
<a-row align="middle" type="flex">
|
||||
<a-col :span="24">
|
||||
<a-spin :spinning="loading" class="attachments-group">
|
||||
<a-empty v-if="formattedDatas.length === 0" />
|
||||
<div
|
||||
v-for="(item, index) in formattedDatas"
|
||||
v-else
|
||||
:key="index"
|
||||
class="attach-item attachments-group-item"
|
||||
@click="handleShowDetailDrawer(item)"
|
||||
@contextmenu.prevent="handleContextMenu($event, item)"
|
||||
>
|
||||
<span v-if="!handleJudgeMediaType(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-spin>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-divider />
|
||||
<div class="page-wrapper">
|
||||
<a-pagination
|
||||
:current="pagination.page"
|
||||
:defaultPageSize="pagination.size"
|
||||
:total="pagination.total"
|
||||
showLessItems
|
||||
@change="handlePaginationChange"
|
||||
></a-pagination>
|
||||
</div>
|
||||
|
||||
<!-- <AttachmentDetailDrawer
|
||||
v-model="detailVisible"
|
||||
v-if="selectedAttachment"
|
||||
:attachment="selectedAttachment"
|
||||
@delete="handleListAttachments"
|
||||
/> -->
|
||||
<a-divider class="divider-transparent" />
|
||||
<div class="bottom-control">
|
||||
<a-button type="primary" @click="uploadVisible = true">上传附件</a-button>
|
||||
</div>
|
||||
</a-drawer>
|
||||
|
||||
<AttachmentUploadModal :visible.sync="uploadVisible" @close="onUploadClose" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mixin, mixinDevice } from '@/mixins/mixin.js'
|
||||
// import AttachmentDetailDrawer from './AttachmentDetailDrawer'
|
||||
import apiClient from '@/utils/api-client'
|
||||
|
||||
export default {
|
||||
name: 'AttachmentDrawer',
|
||||
mixins: [mixin, mixinDevice],
|
||||
components: {
|
||||
// AttachmentDetailDrawer
|
||||
},
|
||||
model: {
|
||||
prop: 'visible',
|
||||
event: 'close'
|
||||
},
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
attachmentType: {
|
||||
LOCAL: {
|
||||
type: 'LOCAL',
|
||||
text: '本地'
|
||||
},
|
||||
SMMS: {
|
||||
type: 'SMMS',
|
||||
text: 'SM.MS'
|
||||
},
|
||||
UPOSS: {
|
||||
type: 'UPOSS',
|
||||
text: '又拍云'
|
||||
},
|
||||
QINIUOSS: {
|
||||
type: 'QINIUOSS',
|
||||
text: '七牛云'
|
||||
},
|
||||
ALIOSS: {
|
||||
type: 'ALIOSS',
|
||||
text: '阿里云'
|
||||
},
|
||||
BAIDUBOS: {
|
||||
type: 'BAIDUBOS',
|
||||
text: '百度云'
|
||||
},
|
||||
TENCENTCOS: {
|
||||
type: 'TENCENTCOS',
|
||||
text: '腾讯云'
|
||||
},
|
||||
HUAWEIOBS: {
|
||||
type: 'HUAWEIOBS',
|
||||
text: '华为云'
|
||||
},
|
||||
MINIO: {
|
||||
type: 'MINIO',
|
||||
text: 'MinIO'
|
||||
}
|
||||
},
|
||||
detailVisible: false,
|
||||
attachmentDrawerVisible: false,
|
||||
uploadVisible: false,
|
||||
loading: true,
|
||||
pagination: {
|
||||
page: 1,
|
||||
size: 12,
|
||||
sort: null,
|
||||
total: 1
|
||||
},
|
||||
queryParam: {
|
||||
page: 0,
|
||||
size: 12,
|
||||
sort: null,
|
||||
keyword: null
|
||||
},
|
||||
attachments: [],
|
||||
selectedAttachment: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
formattedDatas() {
|
||||
return this.attachments.map(attachment => {
|
||||
attachment.typeProperty = this.attachmentType[attachment.type]
|
||||
return attachment
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleShowDetailDrawer(attachment) {
|
||||
this.selectedAttachment = attachment
|
||||
this.$log.debug('Show detail of', attachment)
|
||||
this.detailVisible = true
|
||||
},
|
||||
handleContextMenu(event, item) {
|
||||
this.$contextmenu({
|
||||
items: [
|
||||
{
|
||||
label: '复制图片链接',
|
||||
onClick: () => {
|
||||
const text = `${encodeURI(item.path)}`
|
||||
this.$copyText(text)
|
||||
.then(message => {
|
||||
this.$log.debug('copy', message)
|
||||
this.$message.success('复制成功!')
|
||||
})
|
||||
.catch(err => {
|
||||
this.$log.debug('copy.err', err)
|
||||
this.$message.error('复制失败!')
|
||||
})
|
||||
},
|
||||
divided: true
|
||||
},
|
||||
{
|
||||
label: '复制 Markdown 格式链接',
|
||||
onClick: () => {
|
||||
const text = `![${item.name}](${encodeURI(item.path)})`
|
||||
this.$copyText(text)
|
||||
.then(message => {
|
||||
this.$log.debug('copy', message)
|
||||
this.$message.success('复制成功!')
|
||||
})
|
||||
.catch(err => {
|
||||
this.$log.debug('copy.err', err)
|
||||
this.$message.error('复制失败!')
|
||||
})
|
||||
}
|
||||
}
|
||||
],
|
||||
event,
|
||||
zIndex: 1001,
|
||||
minWidth: 210
|
||||
})
|
||||
return false
|
||||
},
|
||||
handleListAttachments() {
|
||||
this.loading = true
|
||||
this.queryParam.page = this.pagination.page - 1
|
||||
this.queryParam.size = this.pagination.size
|
||||
this.queryParam.sort = this.pagination.sort
|
||||
apiClient.attachment
|
||||
.list(this.queryParam)
|
||||
.then(response => {
|
||||
this.attachments = response.data.content
|
||||
this.pagination.total = response.data.total
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleQuery() {
|
||||
this.handlePaginationChange(1, this.pagination.size)
|
||||
},
|
||||
handlePaginationChange(page, pageSize) {
|
||||
this.pagination.page = page
|
||||
this.pagination.size = pageSize
|
||||
this.handleListAttachments()
|
||||
},
|
||||
onUploadClose() {
|
||||
this.handlePaginationChange(1, this.pagination.size)
|
||||
},
|
||||
handleAfterVisibleChanged(visible) {
|
||||
if (visible) {
|
||||
this.handleListAttachments()
|
||||
}
|
||||
},
|
||||
handleJudgeMediaType(attachment) {
|
||||
const mediaType = attachment.mediaType
|
||||
// 判断文件类型
|
||||
if (mediaType) {
|
||||
const prefix = mediaType.split('/')[0]
|
||||
|
||||
return prefix === 'image'
|
||||
}
|
||||
// 没有获取到文件返回false
|
||||
return false
|
||||
},
|
||||
onClose() {
|
||||
this.$emit('close', false)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -122,10 +122,10 @@
|
|||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<AttachmentSelectDrawer
|
||||
v-model="attachmentDrawerVisible"
|
||||
title="选择附件"
|
||||
@listenToSelect="handleSelectAttachment"
|
||||
<AttachmentSelectModal
|
||||
:multiSelect="false"
|
||||
:visible.sync="attachmentSelectVisible"
|
||||
@confirm="handleSelectAttachment"
|
||||
/>
|
||||
|
||||
<footer-tool-bar v-if="themeConfigurations.length > 0" class="w-full">
|
||||
|
@ -167,7 +167,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
attachmentDrawerVisible: false,
|
||||
attachmentSelectVisible: false,
|
||||
themeConfigurations: [],
|
||||
themeSettings: [],
|
||||
settingLoading: true,
|
||||
|
@ -251,12 +251,14 @@ export default {
|
|||
},
|
||||
handleShowSelectAttachment(field) {
|
||||
this.selectedField = field
|
||||
this.attachmentDrawerVisible = true
|
||||
this.attachmentSelectVisible = true
|
||||
},
|
||||
handleSelectAttachment(data) {
|
||||
this.$set(this.themeSettings, this.selectedField, encodeURI(data.path))
|
||||
handleSelectAttachment({ raw }) {
|
||||
if (raw.length) {
|
||||
this.$set(this.themeSettings, this.selectedField, encodeURI(raw[0].path))
|
||||
}
|
||||
// this.themeSettings[this.selectedField] = encodeURI(data.path)
|
||||
this.attachmentDrawerVisible = false
|
||||
this.attachmentSelectVisible = false
|
||||
},
|
||||
handleAfterVisibleChanged(visible) {
|
||||
if (visible) {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
></ReactiveButton>
|
||||
<a-button :loading="previewSaving" @click="handlePreview">预览</a-button>
|
||||
<a-button type="primary" @click="postSettingVisible = true">发布</a-button>
|
||||
<a-button type="dashed" @click="attachmentDrawerVisible = true">附件库</a-button>
|
||||
<a-button type="dashed" @click="attachmentSelectVisible = true">附件库</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-row :gutter="12">
|
||||
|
@ -39,31 +39,31 @@
|
|||
@onUpdate="onUpdateFromSetting"
|
||||
/>
|
||||
|
||||
<AttachmentDrawer v-model="attachmentDrawerVisible" />
|
||||
<AttachmentSelectModal :visible.sync="attachmentSelectVisible" @confirm="handleSelectAttachment" />
|
||||
</page-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mixin, mixinDevice, mixinPostEdit } from '@/mixins/mixin.js'
|
||||
import { datetimeFormat } from '@/utils/datetime'
|
||||
|
||||
// components
|
||||
import PostSettingModal from './components/PostSettingModal'
|
||||
import AttachmentDrawer from '../attachment/components/AttachmentDrawer'
|
||||
import MarkdownEditor from '@/components/Editor/MarkdownEditor'
|
||||
import { PageView } from '@/layouts'
|
||||
|
||||
// libs
|
||||
import { mixin, mixinDevice, mixinPostEdit } from '@/mixins/mixin.js'
|
||||
import { datetimeFormat } from '@/utils/datetime'
|
||||
import apiClient from '@/utils/api-client'
|
||||
|
||||
export default {
|
||||
mixins: [mixin, mixinDevice, mixinPostEdit],
|
||||
components: {
|
||||
PostSettingModal,
|
||||
AttachmentDrawer,
|
||||
MarkdownEditor,
|
||||
PageView
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
attachmentDrawerVisible: false,
|
||||
attachmentSelectVisible: false,
|
||||
postSettingVisible: false,
|
||||
postToStage: {},
|
||||
contentChanges: 0,
|
||||
|
@ -84,18 +84,11 @@ export default {
|
|||
})
|
||||
},
|
||||
destroyed() {
|
||||
if (this.attachmentDrawerVisible) {
|
||||
this.attachmentDrawerVisible = false
|
||||
}
|
||||
if (window.onbeforeunload) {
|
||||
window.onbeforeunload = null
|
||||
}
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
if (this.attachmentDrawerVisible) {
|
||||
this.attachmentDrawerVisible = false
|
||||
}
|
||||
|
||||
if (this.contentChanges <= 1) {
|
||||
next()
|
||||
} else {
|
||||
|
@ -219,6 +212,13 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
handleSelectAttachment({ markdown }) {
|
||||
this.$set(
|
||||
this.postToStage,
|
||||
'originalContent',
|
||||
(this.postToStage.originalContent || '') + '\n' + markdown.join(`\n`)
|
||||
)
|
||||
},
|
||||
handleRestoreSavedStatus() {
|
||||
this.contentChanges = 0
|
||||
},
|
||||
|
|
|
@ -144,10 +144,10 @@
|
|||
@click="handleCreateOrUpdate()"
|
||||
></ReactiveButton>
|
||||
</template>
|
||||
<AttachmentSelectDrawer
|
||||
v-model="attachmentSelectVisible"
|
||||
:drawerWidth="480"
|
||||
@listenToSelect="handleSelectPostThumb"
|
||||
<AttachmentSelectModal
|
||||
:multiSelect="false"
|
||||
:visible.sync="attachmentSelectVisible"
|
||||
@confirm="handleSelectPostThumbnail"
|
||||
/>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
@ -374,8 +374,10 @@ export default {
|
|||
* Select post thumbnail
|
||||
* @param data
|
||||
*/
|
||||
handleSelectPostThumb(data) {
|
||||
this.form.model.thumbnail = encodeURI(data.path)
|
||||
handleSelectPostThumbnail({ raw }) {
|
||||
if (raw.length) {
|
||||
this.form.model.thumbnail = encodeURI(raw[0].path)
|
||||
}
|
||||
this.attachmentSelectVisible = false
|
||||
},
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
></ReactiveButton>
|
||||
<a-button :loading="previewSaving" @click="handlePreview">预览</a-button>
|
||||
<a-button type="primary" @click="sheetSettingVisible = true">发布</a-button>
|
||||
<a-button type="dashed" @click="attachmentDrawerVisible = true">附件库</a-button>
|
||||
<a-button type="dashed" @click="attachmentSelectVisible = true">附件库</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
<a-row :gutter="12">
|
||||
|
@ -40,7 +40,7 @@
|
|||
@onUpdate="onUpdateFromSetting"
|
||||
/>
|
||||
|
||||
<AttachmentDrawer v-model="attachmentDrawerVisible" />
|
||||
<AttachmentSelectModal :visible.sync="attachmentSelectVisible" @confirm="handleSelectAttachment" />
|
||||
</page-view>
|
||||
</template>
|
||||
|
||||
|
@ -49,21 +49,19 @@ import { mixin, mixinDevice, mixinPostEdit } from '@/mixins/mixin.js'
|
|||
import { datetimeFormat } from '@/utils/datetime'
|
||||
import { PageView } from '@/layouts'
|
||||
import SheetSettingModal from './components/SheetSettingModal'
|
||||
import AttachmentDrawer from '../attachment/components/AttachmentDrawer'
|
||||
import MarkdownEditor from '@/components/Editor/MarkdownEditor'
|
||||
import apiClient from '@/utils/api-client'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PageView,
|
||||
AttachmentDrawer,
|
||||
SheetSettingModal,
|
||||
MarkdownEditor
|
||||
},
|
||||
mixins: [mixin, mixinDevice, mixinPostEdit],
|
||||
data() {
|
||||
return {
|
||||
attachmentDrawerVisible: false,
|
||||
attachmentSelectVisible: false,
|
||||
sheetSettingVisible: false,
|
||||
sheetToStage: {},
|
||||
contentChanges: 0,
|
||||
|
@ -85,23 +83,11 @@ export default {
|
|||
})
|
||||
},
|
||||
destroyed: function () {
|
||||
if (this.sheetSettingVisible) {
|
||||
this.sheetSettingVisible = false
|
||||
}
|
||||
if (this.attachmentDrawerVisible) {
|
||||
this.attachmentDrawerVisible = false
|
||||
}
|
||||
if (window.onbeforeunload) {
|
||||
window.onbeforeunload = null
|
||||
}
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
if (this.sheetSettingVisible) {
|
||||
this.sheetSettingVisible = false
|
||||
}
|
||||
if (this.attachmentDrawerVisible) {
|
||||
this.attachmentDrawerVisible = false
|
||||
}
|
||||
if (this.contentChanges <= 1) {
|
||||
next()
|
||||
} else {
|
||||
|
@ -221,6 +207,13 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
handleSelectAttachment({ markdown }) {
|
||||
this.$set(
|
||||
this.sheetToStage,
|
||||
'originalContent',
|
||||
(this.sheetToStage.originalContent || '') + '\n' + markdown.join(`\n`)
|
||||
)
|
||||
},
|
||||
handleRestoreSavedStatus() {
|
||||
this.contentChanges = 0
|
||||
},
|
||||
|
|
|
@ -94,8 +94,8 @@
|
|||
</div>
|
||||
<a-divider class="divider-transparent" />
|
||||
</div>
|
||||
<AttachmentSelectDrawer v-model="thumbDrawerVisible" :drawerWidth="480" @listenToSelect="handleSelectSheetThumb" />
|
||||
|
||||
<AttachmentSelectModal :multiSelect="false" :visible.sync="thumbDrawerVisible" @confirm="handleSelectSheetThumb" />
|
||||
<a-drawer
|
||||
:visible="advancedVisible"
|
||||
:width="isMobile() ? '100%' : '480'"
|
||||
|
@ -311,8 +311,10 @@ export default {
|
|||
this.customTplsLoading = false
|
||||
})
|
||||
},
|
||||
handleSelectSheetThumb(data) {
|
||||
this.selectedSheet.thumbnail = encodeURI(data.path)
|
||||
handleSelectSheetThumb({ raw }) {
|
||||
if (raw.length) {
|
||||
this.selectedSheet.thumbnail = encodeURI(raw[0].path)
|
||||
}
|
||||
this.thumbDrawerVisible = false
|
||||
},
|
||||
handlePublishClick() {
|
||||
|
|
|
@ -132,10 +132,10 @@
|
|||
@click="handleCreateOrUpdate()"
|
||||
></ReactiveButton>
|
||||
</template>
|
||||
<AttachmentSelectDrawer
|
||||
v-model="attachmentSelectVisible"
|
||||
:drawerWidth="480"
|
||||
@listenToSelect="handleSelectSheetThumb"
|
||||
<AttachmentSelectModal
|
||||
:multiSelect="false"
|
||||
:visible.sync="attachmentSelectVisible"
|
||||
@confirm="handleSelectSheetThumbnail"
|
||||
/>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
@ -326,8 +326,10 @@ export default {
|
|||
* Select sheet thumbnail
|
||||
* @param data
|
||||
*/
|
||||
handleSelectSheetThumb(data) {
|
||||
this.form.model.thumbnail = encodeURI(data.path)
|
||||
handleSelectSheetThumbnail({ raw }) {
|
||||
if (raw.length) {
|
||||
this.form.model.thumbnail = encodeURI(raw[0].path)
|
||||
}
|
||||
this.attachmentSelectVisible = false
|
||||
},
|
||||
/**
|
||||
|
|
|
@ -135,7 +135,7 @@
|
|||
</a-tooltip>
|
||||
</template>
|
||||
<template slot="footer">
|
||||
<a-button type="dashed" @click="attachmentDrawer.visible = true">附件库</a-button>
|
||||
<a-button type="dashed" @click="attachmentSelect.visible = true">附件库</a-button>
|
||||
<ReactiveButton
|
||||
:errored="form.saveErrored"
|
||||
:loading="form.saving"
|
||||
|
@ -170,7 +170,7 @@
|
|||
@close="onJournalCommentsDrawerClose"
|
||||
/>
|
||||
|
||||
<AttachmentDrawer v-model="attachmentDrawer.visible" />
|
||||
<AttachmentSelectModal :visible.sync="attachmentSelect.visible" @confirm="handleSelectAttachment" />
|
||||
</page-view>
|
||||
</template>
|
||||
|
||||
|
@ -178,7 +178,6 @@
|
|||
// components
|
||||
import { PageView } from '@/layouts'
|
||||
import TargetCommentDrawer from '../../comment/components/TargetCommentDrawer'
|
||||
import AttachmentDrawer from '../../attachment/components/AttachmentDrawer'
|
||||
|
||||
// libs
|
||||
import { mixin, mixinDevice } from '@/mixins/mixin.js'
|
||||
|
@ -187,7 +186,7 @@ import apiClient from '@/utils/api-client'
|
|||
|
||||
export default {
|
||||
mixins: [mixin, mixinDevice],
|
||||
components: { PageView, TargetCommentDrawer, AttachmentDrawer },
|
||||
components: { PageView, TargetCommentDrawer },
|
||||
data() {
|
||||
return {
|
||||
list: {
|
||||
|
@ -224,7 +223,7 @@ export default {
|
|||
journalCommentDrawer: {
|
||||
visible: false
|
||||
},
|
||||
attachmentDrawer: {
|
||||
attachmentSelect: {
|
||||
visible: false
|
||||
},
|
||||
optionModal: {
|
||||
|
@ -377,6 +376,9 @@ export default {
|
|||
this.handleListOptions()
|
||||
this.refreshOptionsCache()
|
||||
})
|
||||
},
|
||||
handleSelectAttachment({ markdown }) {
|
||||
this.$set(this.form.model, 'sourceContent', (this.form.model.sourceContent || '') + '\n' + markdown.join('\n'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
:src="form.model.url || '/images/placeholder.jpg'"
|
||||
class="w-full cursor-pointer"
|
||||
style="border-radius: 4px"
|
||||
@click="attachmentSelectDrawer.visible = true"
|
||||
@click="attachmentSelectModal.visible = true"
|
||||
/>
|
||||
</div>
|
||||
<a-input v-model="form.model.url" placeholder="点击封面图选择图片,或者输入外部链接" />
|
||||
|
@ -161,11 +161,10 @@
|
|||
</a-popconfirm>
|
||||
</a-space>
|
||||
</div>
|
||||
|
||||
<AttachmentSelectDrawer
|
||||
v-model="attachmentSelectDrawer.visible"
|
||||
:drawerWidth="480"
|
||||
@listenToSelect="handleAttachmentSelected"
|
||||
<AttachmentSelectModal
|
||||
:multiSelect="false"
|
||||
:visible.sync="attachmentSelectModal.visible"
|
||||
@confirm="handleAttachmentSelected"
|
||||
/>
|
||||
</a-drawer>
|
||||
</page-view>
|
||||
|
@ -215,7 +214,7 @@ export default {
|
|||
deleteErrored: false
|
||||
},
|
||||
|
||||
attachmentSelectDrawer: {
|
||||
attachmentSelectModal: {
|
||||
visible: false
|
||||
},
|
||||
|
||||
|
@ -347,10 +346,12 @@ export default {
|
|||
this.handleListPhotoTeams()
|
||||
}
|
||||
},
|
||||
handleAttachmentSelected(data) {
|
||||
this.form.model.url = encodeURI(data.path)
|
||||
this.form.model.thumbnail = encodeURI(data.thumbPath)
|
||||
this.attachmentSelectDrawer.visible = false
|
||||
handleAttachmentSelected({ raw }) {
|
||||
if (raw.length) {
|
||||
this.form.model.url = encodeURI(raw[0].path)
|
||||
this.form.model.thumbnail = encodeURI(raw[0].thumbPath)
|
||||
}
|
||||
this.attachmentSelectModal.visible = false
|
||||
},
|
||||
handleResetParam() {
|
||||
this.list.queryParam.keyword = null
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
</a-form-model-item>
|
||||
<a-form-model-item label="存储位置:">
|
||||
<a-select v-model="options.attachment_type">
|
||||
<a-select-option v-for="item in Object.keys(attachmentType)" :key="item" :value="item">
|
||||
{{ attachmentType[item].text }}
|
||||
<a-select-option v-for="item in Object.keys(attachmentTypes)" :key="item" :value="item">
|
||||
{{ attachmentTypes[item].text }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
|
@ -272,6 +272,8 @@
|
|||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { attachmentTypes } from '@/core/constant'
|
||||
|
||||
const tencentCosRegions = [
|
||||
{
|
||||
text: '北京一区',
|
||||
|
@ -324,44 +326,6 @@ const qiniuOssZones = [
|
|||
value: 'as0'
|
||||
}
|
||||
]
|
||||
const attachmentType = {
|
||||
LOCAL: {
|
||||
type: 'LOCAL',
|
||||
text: '本地'
|
||||
},
|
||||
SMMS: {
|
||||
type: 'SMMS',
|
||||
text: 'SM.MS'
|
||||
},
|
||||
UPOSS: {
|
||||
type: 'UPOSS',
|
||||
text: '又拍云'
|
||||
},
|
||||
QINIUOSS: {
|
||||
type: 'QINIUOSS',
|
||||
text: '七牛云'
|
||||
},
|
||||
ALIOSS: {
|
||||
type: 'ALIOSS',
|
||||
text: '阿里云'
|
||||
},
|
||||
BAIDUBOS: {
|
||||
type: 'BAIDUBOS',
|
||||
text: '百度云'
|
||||
},
|
||||
TENCENTCOS: {
|
||||
type: 'TENCENTCOS',
|
||||
text: '腾讯云'
|
||||
},
|
||||
HUAWEIOBS: {
|
||||
type: 'HUAWEIOBS',
|
||||
text: '华为云'
|
||||
},
|
||||
MINIO: {
|
||||
type: 'MINIO',
|
||||
text: 'MinIO'
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'AttachmentTab',
|
||||
props: {
|
||||
|
@ -380,7 +344,6 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
attachmentType,
|
||||
wrapperCol: {
|
||||
xl: { span: 8 },
|
||||
lg: { span: 8 },
|
||||
|
@ -389,6 +352,7 @@ export default {
|
|||
},
|
||||
tencentCosRegions,
|
||||
qiniuOssZones,
|
||||
attachmentTypes,
|
||||
rules: {}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
:size="104"
|
||||
:src="userForm.model.avatar || '//cn.gravatar.com/avatar/?s=256&d=mm'"
|
||||
class="cursor-pointer"
|
||||
@click="attachmentDrawer.visible = true"
|
||||
@click="attachmentSelect.visible = true"
|
||||
/>
|
||||
</a-tooltip>
|
||||
<div class="mt-4 mb-1 text-xl font-medium leading-5" style="color: rgba(0, 0, 0, 0.85)">
|
||||
|
@ -52,15 +52,15 @@
|
|||
<a-tab-pane key="1">
|
||||
<span slot="tab"> <a-icon type="idcard" />基本资料 </span>
|
||||
<a-form-model
|
||||
ref="userForm"
|
||||
:model="userForm.model"
|
||||
:rules="userForm.rules"
|
||||
:wrapperCol="{
|
||||
xl: { span: 15 },
|
||||
lg: { span: 15 },
|
||||
sm: { span: 15 },
|
||||
xs: { span: 24 }
|
||||
}"
|
||||
ref="userForm"
|
||||
:model="userForm.model"
|
||||
:rules="userForm.rules"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-model-item label="用户名:" prop="username">
|
||||
|
@ -92,15 +92,15 @@
|
|||
<a-tab-pane key="2">
|
||||
<span slot="tab"> <a-icon type="lock" />密码 </span>
|
||||
<a-form-model
|
||||
ref="passwordForm"
|
||||
:model="passwordForm.model"
|
||||
:rules="passwordForm.rules"
|
||||
:wrapperCol="{
|
||||
xl: { span: 15 },
|
||||
lg: { span: 15 },
|
||||
sm: { span: 15 },
|
||||
xs: { span: 24 }
|
||||
}"
|
||||
ref="passwordForm"
|
||||
:model="passwordForm.model"
|
||||
:rules="passwordForm.rules"
|
||||
layout="vertical"
|
||||
>
|
||||
<a-form-model-item label="原密码:" prop="oldPassword">
|
||||
|
@ -196,14 +196,6 @@
|
|||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<AttachmentSelectDrawer
|
||||
v-model="attachmentDrawer.visible"
|
||||
isChooseAvatar
|
||||
title="选择头像"
|
||||
@listenToSelect="handleSelectAvatar"
|
||||
@listenToSelectGravatar="handleSelectGravatar"
|
||||
/>
|
||||
|
||||
<a-modal
|
||||
:centered="true"
|
||||
:closable="false"
|
||||
|
@ -216,7 +208,7 @@
|
|||
icon="safety-certificate"
|
||||
>
|
||||
<template slot="footer">
|
||||
<a-button key="back" @click="handleCloseMFAuthModal"> 取消 </a-button>
|
||||
<a-button key="back" @click="handleCloseMFAuthModal"> 取消</a-button>
|
||||
<ReactiveButton
|
||||
key="submit"
|
||||
:errored="mfaParam.errored"
|
||||
|
@ -250,6 +242,13 @@
|
|||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
|
||||
<AttachmentSelectModal
|
||||
:multiSelect="false"
|
||||
:visible.sync="attachmentSelect.visible"
|
||||
title="选择头像"
|
||||
@confirm="handleSelectAvatar"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -268,7 +267,7 @@ export default {
|
|||
}
|
||||
}
|
||||
return {
|
||||
attachmentDrawer: {
|
||||
attachmentSelect: {
|
||||
visible: false
|
||||
},
|
||||
userForm: {
|
||||
|
@ -432,14 +431,16 @@ export default {
|
|||
this.userForm.errored = false
|
||||
}
|
||||
},
|
||||
handleSelectAvatar(data) {
|
||||
this.userForm.model.avatar = encodeURI(data.path)
|
||||
this.attachmentDrawer.visible = false
|
||||
handleSelectAvatar({ raw }) {
|
||||
if (raw.length) {
|
||||
this.userForm.model.avatar = encodeURI(raw[0].path)
|
||||
}
|
||||
this.attachmentSelect.visible = false
|
||||
},
|
||||
handleSelectGravatar() {
|
||||
this.userForm.model.avatar =
|
||||
'//cn.gravatar.com/avatar/' + new MD5().update(this.userForm.model.email).digest('hex') + '&d=mm'
|
||||
this.attachmentDrawer.visible = false
|
||||
this.attachmentSelect.visible = false
|
||||
},
|
||||
handleMFASwitch(useMFAuth) {
|
||||
this.mfaParam.switch.loading = true
|
||||
|
|
Loading…
Reference in New Issue