照片墙&图片资源库
This commit is contained in:
parent
c751f26122
commit
8dd1916a3d
@ -11,6 +11,8 @@ import Statistics from './views/system/Statistics.vue'
|
||||
|
||||
import Music from './views/api/Music.vue'
|
||||
import Hitokoto from './views/api/Hitokoto.vue'
|
||||
import PhotoWall from './views/api/PhotoWall.vue'
|
||||
import SourceImage from './views/api/SourceImage.vue'
|
||||
import SqlReplace from './views/tool/SqlReplace.vue'
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
@ -25,7 +27,8 @@ const routes: Array<RouteRecordRaw> = [
|
||||
|
||||
{ path: '/api/music', name: 'Music', component: Music },
|
||||
{ path: '/api/hitokoto', name: 'Hitokoto', component: Hitokoto },
|
||||
|
||||
{ path: '/api/photoWall', name: 'PhotoWall', component: PhotoWall },
|
||||
{ path: '/api/sourceImage', name: 'SourceImage', component: SourceImage },
|
||||
{ path: '/tool/sqlReplace', name: 'SqlReplace', component: SqlReplace },
|
||||
]}
|
||||
]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form inline :model="search" @submit.prevent>
|
||||
<el-form inline :model="search">
|
||||
<el-form-item label="内容">
|
||||
<el-input size="small" v-model="search.content" />
|
||||
</el-form-item>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-form inline :model="search" @submit.prevent>
|
||||
<el-form inline :model="search">
|
||||
<el-form-item label="名称">
|
||||
<el-input size="small" v-model="search.name" />
|
||||
</el-form-item>
|
||||
|
||||
173
src/views/api/PhotoWall.vue
Normal file
173
src/views/api/PhotoWall.vue
Normal file
@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert type="info" show-icon :closable="false" >
|
||||
<template #title>上传要求</template>
|
||||
图片格式为{{allowUploadExt.join('、')}},文件大小不超过10MB。
|
||||
</el-alert>
|
||||
<el-form inline :model="search">
|
||||
<el-form-item label="文件名">
|
||||
<el-input size="small" v-model="search.name" />
|
||||
</el-form-item>
|
||||
<el-form-item label="宽度" >
|
||||
<el-input size="small" v-model="search.widthMin" type="number" style="vertical-align: middle;" >
|
||||
<template #prepend>≥</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input size="small" v-model="search.widthMax" type="number" style="vertical-align: middle;" >
|
||||
<template #prepend>≤</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="高度" >
|
||||
<el-input size="small" v-model="search.heightMin" type="number" style="vertical-align: middle;" >
|
||||
<template #prepend>≥</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input size="small" v-model="search.heightMax" type="number" style="vertical-align: middle;" >
|
||||
<template #prepend>≤</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="btn-container">
|
||||
<el-upload
|
||||
action="/api/photowall/upload"
|
||||
accept="image/jpeg,image/png"
|
||||
name="image"
|
||||
:headers="uploadHeaders"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="uploadSuccess"
|
||||
:on-error="uploadError"
|
||||
auto-upload
|
||||
:show-file-list="false"
|
||||
style="display: inline-block;margin-right: 10px;">
|
||||
<el-button size="small" type="primary" icon="el-icon-upload" :loading="isUploading">上传图片</el-button>
|
||||
</el-upload>
|
||||
<el-button size="small" type="danger" @click="deleteAll">删除</el-button>
|
||||
<div class="search-btn">
|
||||
<el-button type="primary" @click="loadDataBase(true)" size="small" icon="el-icon-search">搜索</el-button>
|
||||
<el-button @click="reset" size="small" icon="el-icon-refresh-right">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-container">
|
||||
<el-table :data="photowallData" v-loading="loading" stripe height="520" @selection-change="dataSelect">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="name" label="文件名" />
|
||||
<el-table-column prop="md5" label="md5" width="300" />
|
||||
<el-table-column prop="thumbnail" label="缩略图" />
|
||||
<el-table-column prop="width" label="宽度" width="70" />
|
||||
<el-table-column prop="height" label="高度" width="70" />
|
||||
<el-table-column label="操作" width="100" >
|
||||
<template #default="scope">
|
||||
<el-button size="mini" plain @click="preview(scope.row)">预览</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="page-container">
|
||||
<el-pagination background
|
||||
:page-sizes="$store.state.pageSizeOpts"
|
||||
:layout="$store.state.pageLayout"
|
||||
:total="total"
|
||||
@size-change="pageSizeChange"
|
||||
@current-change="pageChange">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Options } from 'vue-class-component'
|
||||
import { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElAlert, ElUpload, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import { MsgResult, Page } from '../../model/common.dto'
|
||||
import BaseList from '../../model/baselist'
|
||||
import PhotoWallModel from '../../model/api/photowall'
|
||||
import { h } from 'vue'
|
||||
|
||||
let selectedData: string[] = []
|
||||
@Options({
|
||||
name: 'PhotoWall',
|
||||
components: { ElButton, ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElPagination, ElAlert, ElUpload }
|
||||
})
|
||||
export default class PhotoWall extends BaseList<PhotoWallPage> {
|
||||
uploadHeaders = {token: localStorage.getItem('login_token')}
|
||||
search = new PhotoWallPage()
|
||||
allowUploadExt = ['jpg','jpeg','png']
|
||||
photowallData = []
|
||||
isUploading: boolean = false
|
||||
async loadData() {
|
||||
this.loading = true
|
||||
const { data } = await this.$http.get<PhotoWallPage, AxiosResponse<any>>('/api/photowall/list', {params:this.search})
|
||||
selectedData = []
|
||||
this.loading = false
|
||||
this.total = data.total
|
||||
this.photowallData = data.data
|
||||
}
|
||||
deleteAll() {
|
||||
if(!selectedData || !selectedData.length) {
|
||||
ElMessage.warning('请选择要删除的数据')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(`是否确认删除选中的${selectedData.length}条数据?`, '确认删除', {type: 'warning'}).then(async () => {
|
||||
await this.$http.delete('/api/photowall/delete', {params:{_ids: selectedData}})
|
||||
ElMessage.success('删除成功')
|
||||
this.loadData()
|
||||
}).catch(() => {})
|
||||
}
|
||||
dataSelect(selection: PhotoWallModel[]) {
|
||||
selectedData = selection.map(item => item._id)
|
||||
}
|
||||
beforeUpload(file: File): boolean {
|
||||
if(file.size > 10 << 20) {
|
||||
ElMessage.warning('文件大小超过10MB')
|
||||
return false
|
||||
}
|
||||
this.isUploading = true
|
||||
return true
|
||||
}
|
||||
uploadSuccess(response: MsgResult) {
|
||||
if(response.status) {
|
||||
ElMessage.success(response.message)
|
||||
this.loadData()
|
||||
} else {
|
||||
ElMessage.warning(response.message)
|
||||
}
|
||||
this.isUploading = false
|
||||
}
|
||||
uploadError(error: Error) {
|
||||
this.isUploading = false
|
||||
ElMessage.error(error.message)
|
||||
}
|
||||
async preview(row: PhotoWallModel) {
|
||||
const previewHeight = Math.floor(row.height * (500 / row.width))
|
||||
const pictureCdn = (await this.$http.get('/api/common/config/picture_cdn')).data
|
||||
ElMessageBox({
|
||||
title: '图片预览',
|
||||
message: h('img', { style: `width:500px;height:${previewHeight}px;`, src: `${pictureCdn}/${row.name}` }, ''),
|
||||
showCancelButton: false,
|
||||
confirmButtonText: '关闭',
|
||||
customStyle: {width: '530px'}
|
||||
}).catch(() => {})
|
||||
}
|
||||
created() {
|
||||
this.loadData()
|
||||
}
|
||||
}
|
||||
|
||||
class PhotoWallPage extends Page {
|
||||
name?: string
|
||||
widthMin?: number = 0
|
||||
widthMax?: number = 0
|
||||
heightMin?: number = 0
|
||||
heightMax?: number = 0
|
||||
reset() {
|
||||
super.reset()
|
||||
this.name = undefined
|
||||
this.widthMin = 0
|
||||
this.widthMax = 0
|
||||
this.heightMin = 0
|
||||
this.heightMax = 0
|
||||
}
|
||||
}
|
||||
</script>
|
||||
180
src/views/api/SourceImage.vue
Normal file
180
src/views/api/SourceImage.vue
Normal file
@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert type="info" show-icon :closable="false" >
|
||||
<template #title>上传要求</template>
|
||||
图片格式为{{allowUploadExt.join('、')}},文件大小不超过10MB。
|
||||
</el-alert>
|
||||
<div class="btn-container" style="margin-top:10px;">
|
||||
<el-upload
|
||||
action="/api/source-image/upload"
|
||||
accept="image/jpeg,image/png,image/svg+xml,image/x-icon"
|
||||
name="image"
|
||||
:headers="uploadHeaders"
|
||||
:before-upload="beforeUpload"
|
||||
:on-success="uploadSuccess"
|
||||
:on-error="uploadError"
|
||||
auto-upload
|
||||
:show-file-list="false"
|
||||
style="display: inline-block;margin-right: 10px;">
|
||||
<el-button size="small" type="primary" icon="el-icon-upload" :loading="isUploading">上传图片</el-button>
|
||||
</el-upload>
|
||||
<el-button size="small" type="danger" @click="deleteAll">删除</el-button>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<el-table :data="sourceImageData" v-loading="loading" stripe height="520" @selection-change="dataSelect">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="hash" label="md5" width="300" />
|
||||
<el-table-column prop="size" label="文件大小" >
|
||||
<template #default="scope">
|
||||
{{ prettyBytes(scope.row.size) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="mime" label="MIME" />
|
||||
<el-table-column prop="label" label="标签" >
|
||||
<template #default="scope">
|
||||
<el-tag v-for="label in scope.row.label" :key="label" effect="plain">{{label}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="created_at" label="上传时间" >
|
||||
<template #default="scope">
|
||||
{{ datetimeFormat(scope.row.created_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" >
|
||||
<template #default="scope">
|
||||
<el-button size="mini" type="primary" plain @click="modifyTags(scope.row)">修改标签</el-button>
|
||||
<el-button size="mini" plain @click="preview(scope.row)">预览</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="page-container">
|
||||
<el-pagination background
|
||||
:page-sizes="$store.state.pageSizeOpts"
|
||||
:layout="$store.state.pageLayout"
|
||||
:total="total"
|
||||
@size-change="pageSizeChange"
|
||||
@current-change="pageChange">
|
||||
</el-pagination>
|
||||
</div>
|
||||
<el-dialog v-model="modifyModal" title="修改标签" width="630px" @closed="loadData">
|
||||
<el-transfer
|
||||
v-model="curModifyLabels"
|
||||
filterable
|
||||
:render-content="renderFunc"
|
||||
:titles="['可选标签', '已选标签']"
|
||||
:format="{
|
||||
noChecked: '${total}',
|
||||
hasChecked: '${checked}/${total}',
|
||||
}"
|
||||
@change="tarnsferChange"
|
||||
:data="labels"
|
||||
></el-transfer>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Options } from 'vue-class-component'
|
||||
import { ElButton, ElTable, ElTableColumn, ElPagination, ElAlert, ElUpload, ElTag, ElTransfer, ElDialog, ElMessage, ElMessageBox } from 'element-plus'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { MsgResult, Page } from '../../model/common.dto'
|
||||
import BaseList from '../../model/baselist'
|
||||
import { SourceImageModel, ImageLabel } from '../../model/api/source-image'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import { h } from 'vue'
|
||||
|
||||
let selectedData: string[] = []
|
||||
@Options({
|
||||
name: 'SourceImage',
|
||||
components: { ElButton, ElTable, ElTableColumn, ElPagination, ElAlert, ElUpload, ElTag, ElTransfer, ElDialog }
|
||||
})
|
||||
export default class SourceImage extends BaseList<Page> {
|
||||
prettyBytes = prettyBytes
|
||||
uploadHeaders = {token: localStorage.getItem('login_token')}
|
||||
search = new Page()
|
||||
allowUploadExt = ['jpg','jpeg','png','svg','ico']
|
||||
sourceImageData: SourceImageModel[] = []
|
||||
curModifyLabels: string[] = []
|
||||
labelList: ImageLabel[] = []
|
||||
curId: string | null = null
|
||||
modifyModal: boolean = false
|
||||
isUploading: boolean = false
|
||||
renderFunc(h: Function, option: any) {
|
||||
return h('span', null, option.label)
|
||||
}
|
||||
get labels() {
|
||||
return this.labelList.map(item => {
|
||||
return { key: item.name, label: item.name }
|
||||
})
|
||||
}
|
||||
async loadData(): Promise<void> {
|
||||
this.loading = true
|
||||
const { data } = await this.$http.get<Page, AxiosResponse<any>>('/api/source-image/list', {params:this.search})
|
||||
selectedData = []
|
||||
this.loading = false
|
||||
this.total = data.total
|
||||
this.sourceImageData = data.data
|
||||
}
|
||||
deleteAll(): void {
|
||||
if(!selectedData.length) {
|
||||
ElMessage.warning('请选择要删除的数据')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm(`是否确认删除选中的${selectedData.length}条数据?`, '确认删除', {type: 'warning'}).then(async () => {
|
||||
await this.$http.delete('/api/source-image/delete', {params:{_ids: selectedData}})
|
||||
ElMessage.success('删除成功')
|
||||
this.loadData()
|
||||
}).catch(() => {})
|
||||
}
|
||||
dataSelect(selection: SourceImageModel[]): void {
|
||||
selectedData = selection.map(item => item._id)
|
||||
}
|
||||
beforeUpload(file: File): boolean {
|
||||
if(file.size > 10 << 20) {
|
||||
ElMessage.warning('文件大小超过10MB')
|
||||
return false
|
||||
}
|
||||
this.isUploading = true
|
||||
return true
|
||||
}
|
||||
uploadSuccess(response: MsgResult): void {
|
||||
if(response.status) {
|
||||
ElMessage.success(response.message)
|
||||
this.loadData()
|
||||
} else {
|
||||
ElMessage.warning(response.message)
|
||||
}
|
||||
this.isUploading = false
|
||||
}
|
||||
uploadError(error: Error): void {
|
||||
this.isUploading = false
|
||||
ElMessage.error(error.message)
|
||||
}
|
||||
preview(row: SourceImageModel): void {
|
||||
ElMessageBox({
|
||||
title: '图片预览',
|
||||
message: h('img', { style: `width:500px`, src: `/api/common/randomBg?id=${row._id}` }, ''),
|
||||
showCancelButton: false,
|
||||
confirmButtonText: '关闭',
|
||||
customStyle: {width: '530px'}
|
||||
}).catch(() => {})
|
||||
}
|
||||
modifyTags(item: SourceImageModel): void {
|
||||
this.curModifyLabels.length = 0
|
||||
if(item.label) {
|
||||
this.curModifyLabels.push(...item.label)
|
||||
}
|
||||
this.curId = item._id
|
||||
this.modifyModal = true
|
||||
}
|
||||
async tarnsferChange(newTargetKeys: string[], direction: 'right' | 'left', moveKeys: string[]) {
|
||||
await this.$http.post('/api/source-image/updateLabel', {id: this.curId, labels: newTargetKeys})
|
||||
}
|
||||
created() {
|
||||
this.$http.get<never, AxiosResponse<any>>('/api/common/config/image_label').then(({data}) => {
|
||||
this.labelList.push(...data)
|
||||
this.loadData()
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="search-panel">
|
||||
<el-form inline :model="search" @submit.prevent>
|
||||
<el-form inline :model="search">
|
||||
<el-form-item label="标题">
|
||||
<el-input size="small" v-model="search.title" />
|
||||
</el-form-item>
|
||||
@ -176,7 +176,7 @@ export default class Article extends BaseList<ArticlePage> {
|
||||
dataSelect(selection: ArticleModel[]) {
|
||||
selectedData = selection.map(item => item._id)
|
||||
}
|
||||
beforeUpload(file: File) {
|
||||
beforeUpload(file: File): boolean {
|
||||
this.isUploading = true
|
||||
return true
|
||||
}
|
||||
@ -188,9 +188,9 @@ export default class Article extends BaseList<ArticlePage> {
|
||||
}
|
||||
this.isUploading = false
|
||||
}
|
||||
uploadError() {
|
||||
uploadError(error: Error) {
|
||||
this.isUploading = false
|
||||
ElMessage.error('上传失败')
|
||||
ElMessage.error(error.message)
|
||||
}
|
||||
readonly treeProps = {
|
||||
label: 'name',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user