Skip to content

Commit

Permalink
优化管理页面
Browse files Browse the repository at this point in the history
  • Loading branch information
jianyun8023 committed Aug 18, 2024
1 parent 0cd4a68 commit ec0b41c
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 50 deletions.
19 changes: 14 additions & 5 deletions app/calibre-pages/src/components/BookCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,20 @@ import {useRouter} from 'vue-router';
import {Book} from '@/types/book'
const props = defineProps<{
book: Book;
more_info: boolean;
proxy_image: boolean;
}>();
const props = defineProps({
book: {
type: Object as () => Book,
required: true
},
more_info: {
type: Boolean,
required: true
},
proxy_image: {
type: Boolean,
default: false
}
});
const router = useRouter();
Expand Down
1 change: 1 addition & 0 deletions app/calibre-pages/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
Expand Down
3 changes: 3 additions & 0 deletions app/calibre-pages/src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Setting from '../views/Setting.vue'
import Detail from '../views/Detail.vue'
import BatchMeta from '../views/BatchMeta.vue'
import ReadBook from '../views/ReadBook.vue'
import Publisher from '../views/Publisher.vue'


const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
Expand All @@ -17,6 +19,7 @@ const router = createRouter({
{path: '/metadata/manager', component: BatchMeta},
{path: '/detail/:id', component: Detail, props: true},
{path: '/read/:id', component: ReadBook, props: true},
{path: '/publisher', component: Publisher},
]
})

Expand Down
12 changes: 6 additions & 6 deletions app/calibre-pages/src/styles/element/index.scss
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
$colors: (
'primary': (
'base': #003261
'base': #35D0BA
),
'success': (
'base': #21ba45
'base': #F8C43A
),
'warning': (
'base': #f2711c
'base': #C93D1B
),
'danger': (
'base': #db2828
'base': #043210
),
'error': (
'base': #db2828
'base': #04322E
),
'info': (
'base': #42b8dd
'base': #0D7C66
)
)
);
27 changes: 27 additions & 0 deletions app/calibre-pages/src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// src/utils/utils.ts
import { ElNotification } from 'element-plus'
import { h } from 'vue'

export function formatFileSize(size: number): string {
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB'
return (size / 1024 / 1024).toFixed(2) + ' MB'
}

export function copyToClipboard(text: string): void {
navigator.clipboard
.writeText(text)
.then(() => {
ElNotification({
title: 'ID copied ' + text,
message: h('i', { style: 'color: teal' }, 'ID copied to clipboard'),
type: 'success'
})
})
.catch((err) => {
ElNotification({
title: 'ID copied ' + text,
message: h('i', { style: 'color: red' }, 'Oops, Could not copy text.'),
type: 'error'
})
})
}
187 changes: 176 additions & 11 deletions app/calibre-pages/src/views/BatchMeta.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,143 @@
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55"/>
<el-table-column type="expand">
<template #default="props">
<el-row>
<el-col :span="6">
<el-image
style="width: 89%; height: 100%"
:src="props.row.cover"
fit="cover"
/>
</el-col>
<el-col :span="18">
<el-descriptions :title="props.row.title" :column="1" size="large" border>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon>
<Box/>
</el-icon>
ID
</div>
</template>
<el-button text bg @click="copyToClipboard(props.row.id)">{{ props.row.id }}📋</el-button>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon>
<user/>
</el-icon>
Authors
</div>
</template>
<el-tag
class="tag-spacing"
v-for="item in props.row.authors"
:key="item"
effect="dark"
>
{{ item }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon>
<Discount/>
</el-icon>
Publisher
</div>
</template>
<span>{{ props.row.publisher }}</span>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon class="el-icon">
<Key/>
</el-icon>
ISBN
</div>
</template>
{{ props.row.isbn }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon>
<Timer/>
</el-icon>
Published Date
</div>
</template>
<span class="tag-spacing">{{ new Date(props.row.pubdate).toLocaleDateString() }}</span>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon>
<Trophy/>
</el-icon>
Rating
</div>
</template>
<el-rate
:value="props.row.rating / 2"
@input="(val: number) => (props.row.rating = val * 2)"
show-score
text-color="#ff9900"
:max="5"
allow-half
:score-template="`${props.row.rating}分`"
>
</el-rate>
</el-descriptions-item>
<el-descriptions-item v-if="props.row.tags && props.row.tags.length">
<template #label>
<div class="cell-item">
<el-icon>
<CollectionTag/>
</el-icon>
Tags
</div>
</template>
<el-tag v-for="item in props.row.tags" :key="item" effect="dark" round>
{{ item }}
</el-tag>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon>
<Document/>
</el-icon>
File Size
</div>
</template>
{{ formatFileSize(props.row.size) }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
</template>
</el-table-column>
<el-table-column prop="id" label="ID" width="100"/>
<el-table-column prop="title" label="标题" width="180"/>
<el-table-column prop="authors" label="作者" width="180"/>
<el-table-column prop="isbn" label="ISBN"/>
<el-table-column prop="publisher" label="出版社"/>
<el-table-column label="标题" width="200">
<template #default="scope">
<div style="display: flex; align-items: center">
<el-icon @click="goToSearch(scope.row)">
<Search/>
</el-icon>
<span style="margin-left: 10px">{{ scope.row.title }}</span>
</div>
</template>
</el-table-column>
<el-table-column v-if="filterType !== 'author'" prop="authors" label="作者" width="180"/>
<el-table-column v-if="filterType !== 'isbn'" prop="isbn" label="ISBN"/>
<el-table-column v-if="filterType !== 'publisher'" prop="publisher" label="出版社"/>
<el-table-column
prop="pubdate"
label="出版日期"
Expand All @@ -79,6 +211,9 @@
</el-table-column>
<el-table-column fixed="right" label="Operations" min-width="120">
<template #default="scope">
<el-button color="#626aef" :xs="24" @click="previewBook(scope.row)">
预览
</el-button>
<el-button
link
type="primary"
Expand All @@ -100,6 +235,7 @@
<el-button link :icon="Delete" size="small" :xs="24" class="delete-button">删除</el-button>
</template>
</el-popconfirm>

</template>
</el-table-column>
</el-table>
Expand All @@ -108,6 +244,11 @@
<el-button @click="exclusionPackage">排除套装</el-button>
<el-button @click="clearSelection">清除选择</el-button>
<el-button @click="updateMetaData">更新书籍元数据</el-button>
<el-popconfirm title="确定删除?" @confirm="batchDelete">
<template #reference>
<el-button :xs="24" class="delete-button">删除</el-button>
</template>
</el-popconfirm>
</div>
</el-row>
<el-row class="mt-4" justify="center">
Expand Down Expand Up @@ -170,25 +311,32 @@

<MetadataEdit :book="editBook" :dialogEditVisible="dialogEditVisible"
@dialogEditVisible="dialogEditVisible = $event"/>
<PreviewBook :book="editBook" :dialog-preview-visible="dialogPreviewVisible"
@dialog-preview-visible="dialogPreviewVisible = $event"/>
</template>

<script lang="ts">
import {Book, mapMetaBookToBook, MetaBook} from '@/types/book'
import BookCard from '@/components/BookCard.vue'
import {ElButton, ElCol, ElInput, ElNotification, ElRow, ElTable} from 'element-plus'
import MetadataEdit from "@/components/MetadataEdit.vue";
import {Delete} from "@element-plus/icons-vue";
import {Delete, Menu, Search} from "@element-plus/icons-vue";
import {h} from "vue";
import MetadataSearch from "@/components/MetadataSearch.vue";
import PreviewBook from "@/components/PreviewBook.vue";
import {copyToClipboard, formatFileSize} from "@/utils/utils";
export default {
name: 'BatchMeta',
computed: {
Menu() {
return Menu
},
Delete() {
return Delete
}
},
components: {MetadataSearch, MetadataEdit, ElInput, ElButton, ElRow, ElCol, BookCard},
components: {Search, PreviewBook, MetadataSearch, MetadataEdit, ElInput, ElButton, ElRow, ElCol, BookCard},
data() {
return {
filterType: 'publisher' as string,
Expand All @@ -211,6 +359,7 @@ export default {
allPublishers: [] as string[],
dialogSearchVisible: false,
dialogEditVisible: false,
dialogPreviewVisible: false,
editBook: {} as Book
}
},
Expand Down Expand Up @@ -244,6 +393,8 @@ export default {
this.allPublishers = publishers.data
},
mapMetaBookToBook,
formatFileSize,
copyToClipboard,
async fetchBooks() {
if (this.filterType === 'publisher') {
this.filter[0] = 'publisher = "' + this.keyword + '"'
Expand Down Expand Up @@ -273,7 +424,7 @@ export default {
async querySearch(queryString: string, cb: (arg0: string[]) => void) {
if (this.filterType === 'publisher') {
const results = queryString ? this.allPublishers.filter(this.createFilter(queryString)) : []
const results = queryString ? this.allPublishers.filter(this.createFilter(queryString)) : this.allPublishers
console.log(results)
cb(results)
} else {
Expand Down Expand Up @@ -359,7 +510,6 @@ export default {
message: book.title,
type: 'success'
})
this.$router.back()
} else {
ElNotification({
title: '删除书籍失败',
Expand All @@ -382,21 +532,36 @@ export default {
// metadataEdit.book.value = book
this.dialogSearchVisible = true
},
previewBook(book: Book) {
// console.log(book)
// updateBook(book, this.editBook)
this.editBook = book
// metadataEdit.book.value = book
this.dialogPreviewVisible = true
},
toggleSelection() {
this.books.forEach((row) => {
if (row.isbn) {
;(this.$refs.multipleTable as any).toggleRowSelection(row, true)
}
})
},
goToSearch(book: Book) {
const {href} = this.$router.resolve({
path: '/search',
query: {
q: book.title
}
});
window.open(href, "_blank");
},
handleSelectionChange(val: Book[]) {
console.log(val)
this.multipleSelection = val
},
async batchDelete() {
for (const book of this.multipleSelection) {
}
await Promise.all(this.multipleSelection.map(book => this.deleteBook(book)));
await this.fetchBooks();
},
async updateMetaData() {
this.metaUpdateDialogVisible = true
Expand Down
Loading

0 comments on commit ec0b41c

Please sign in to comment.