|
|
|
|
@ -14,19 +14,19 @@
|
|
|
|
|
<!-- 图书统计 -->
|
|
|
|
|
<div class="book-stats">
|
|
|
|
|
<div class="stat-card blue">
|
|
|
|
|
<div class="stat-number">1,247</div>
|
|
|
|
|
<div class="stat-number">{{ chartData.total || 0 }}</div>
|
|
|
|
|
<div class="stat-label">总图书数量</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="stat-card green">
|
|
|
|
|
<div class="stat-number">856</div>
|
|
|
|
|
<div class="stat-number">{{ chartData.borrowable || 0 }}</div>
|
|
|
|
|
<div class="stat-label">可借阅</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="stat-card orange">
|
|
|
|
|
<div class="stat-number">391</div>
|
|
|
|
|
<div class="stat-number">{{ chartData.borrowed || 0 }}</div>
|
|
|
|
|
<div class="stat-label">已借出</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="stat-card purple">
|
|
|
|
|
<div class="stat-number">23</div>
|
|
|
|
|
<div class="stat-number">{{ chartData.maintaining || 0 }}</div>
|
|
|
|
|
<div class="stat-label">维护中</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@ -35,21 +35,42 @@
|
|
|
|
|
<div class="search-section">
|
|
|
|
|
<el-form :model="filters" inline>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-input v-model="filters.keyword" placeholder="搜索书名、作者、ISBN"></el-input>
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="filters.keyword"
|
|
|
|
|
placeholder="搜索书名、作者"
|
|
|
|
|
clearable
|
|
|
|
|
@clear="handleSearch"
|
|
|
|
|
></el-input>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-select v-model="filters.category" placeholder="全部分类" clearable>
|
|
|
|
|
<el-option label="技术类" value="tech"></el-option>
|
|
|
|
|
<el-option label="商业类" value="business"></el-option>
|
|
|
|
|
<el-option label="管理类" value="management"></el-option>
|
|
|
|
|
<el-option label="金融类" value="finance"></el-option>
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="filters.category"
|
|
|
|
|
placeholder="全部分类"
|
|
|
|
|
clearable
|
|
|
|
|
@clear="handleSearch"
|
|
|
|
|
@change="handleSearch"
|
|
|
|
|
>
|
|
|
|
|
<el-option label="全部分类" value=""></el-option>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="category in categoryList"
|
|
|
|
|
:key="category"
|
|
|
|
|
:label="category"
|
|
|
|
|
:value="category"
|
|
|
|
|
></el-option>
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
<el-select v-model="filters.status" placeholder="全部状态" clearable>
|
|
|
|
|
<el-option label="可借阅" value="available"></el-option>
|
|
|
|
|
<el-option label="已借出" value="borrowed"></el-option>
|
|
|
|
|
<el-option label="维护中" value="maintenance"></el-option>
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="filters.status"
|
|
|
|
|
placeholder="全部状态"
|
|
|
|
|
clearable
|
|
|
|
|
@clear="handleSearch"
|
|
|
|
|
@change="handleSearch"
|
|
|
|
|
>
|
|
|
|
|
<el-option label="全部状态" value=""></el-option>
|
|
|
|
|
<el-option label="可借阅" value="0"></el-option>
|
|
|
|
|
<el-option label="已借出" value="1"></el-option>
|
|
|
|
|
<el-option label="维护中" value="2"></el-option>
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
<el-form-item>
|
|
|
|
|
@ -74,42 +95,74 @@
|
|
|
|
|
<el-table-column type="selection" width="55"></el-table-column>
|
|
|
|
|
<el-table-column label="封面" width="80">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<img :src="scope.row.cover" alt="图书封面" class="book-cover">
|
|
|
|
|
<img v-if="scope.row.cover && scope.row.cover.url" :src="scope.row.cover.url" alt="图书封面" class="book-cover">
|
|
|
|
|
<div v-else class="no-cover">无封面</div>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="图书信息" min-width="250">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<div class="book-title">{{ scope.row.title }}</div>
|
|
|
|
|
<div class="book-author">作者:{{ scope.row.author }} · 出版社:{{ scope.row.publisher }} · {{ scope.row.year }}年</div>
|
|
|
|
|
<div class="book-title">{{ scope.row.title || '未设置标题' }}</div>
|
|
|
|
|
<div class="book-author">
|
|
|
|
|
作者:{{ scope.row.author || '未知' }}
|
|
|
|
|
<span v-if="scope.row.publisher">· 出版社:{{ scope.row.publisher }}</span>
|
|
|
|
|
<span v-if="scope.row.publish_year">· {{ scope.row.publish_year }}年</span>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="分类" width="100">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<el-tag :type="getCategoryTagType(scope.row.category)" size="small">{{ scope.row.categoryText }}</el-tag>
|
|
|
|
|
<el-tag :type="getCategoryTagType(scope.row.category)" size="small">{{ scope.row.category || '未分类' }}</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="ISBN" width="150">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
{{ scope.row.isbn }}
|
|
|
|
|
{{ scope.row.isbn || '未设置' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="状态" width="100">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<el-tag :type="getStatusTagType(scope.row.status)" size="small">{{ scope.row.statusText }}</el-tag>
|
|
|
|
|
<el-tag :type="getStatusTagType(scope.row.status)" size="small">{{ getStatusText(scope.row.status) }}</el-tag>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="添加时间" width="150">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<div class="time-display">{{ scope.row.addDate }}</div>
|
|
|
|
|
<div class="time-display-secondary">{{ scope.row.addTime }}</div>
|
|
|
|
|
<div class="time-display">{{ formatDate(scope.row.created_at) }}</div>
|
|
|
|
|
<div class="time-display-secondary">{{ formatTime(scope.row.created_at) }}</div>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column label="操作" width="200" fixed="right">
|
|
|
|
|
<el-table-column label="操作" width="280" fixed="right">
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
<div class="action-buttons">
|
|
|
|
|
<el-button type="primary" size="mini" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
|
|
|
|
|
<el-button type="info" size="mini" icon="el-icon-view" @click="handleView(scope.row)">详情</el-button>
|
|
|
|
|
<el-button v-if="scope.row.status === 'borrowed'" type="warning" size="mini" icon="el-icon-refresh-left" @click="handleReturn(scope.row)">归还</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
v-if="scope.row.status !== 1 && scope.row.status !== 2"
|
|
|
|
|
type="success"
|
|
|
|
|
size="mini"
|
|
|
|
|
icon="el-icon-reading"
|
|
|
|
|
@click="handleStatusChange(scope.row, 1)"
|
|
|
|
|
>已借阅</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
v-if="scope.row.status === 1"
|
|
|
|
|
type="warning"
|
|
|
|
|
size="mini"
|
|
|
|
|
icon="el-icon-refresh-left"
|
|
|
|
|
@click="handleStatusChange(scope.row, 0)"
|
|
|
|
|
>已归还</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
v-if="scope.row.status === 2"
|
|
|
|
|
type="success"
|
|
|
|
|
size="mini"
|
|
|
|
|
icon="el-icon-upload2"
|
|
|
|
|
@click="handleStatusChange(scope.row, 0)"
|
|
|
|
|
>上架</el-button>
|
|
|
|
|
<el-button
|
|
|
|
|
v-if="scope.row.status !== 2"
|
|
|
|
|
type="danger"
|
|
|
|
|
size="mini"
|
|
|
|
|
icon="el-icon-tools"
|
|
|
|
|
@click="handleStatusChange(scope.row, 2)"
|
|
|
|
|
>维护</el-button>
|
|
|
|
|
<el-button type="danger" size="mini" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
@ -130,9 +183,9 @@
|
|
|
|
|
></el-pagination>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 添加图书弹窗 -->
|
|
|
|
|
<!-- 添加/编辑图书弹窗 -->
|
|
|
|
|
<el-dialog
|
|
|
|
|
title="添加图书"
|
|
|
|
|
:title="isEdit ? '编辑图书' : '添加图书'"
|
|
|
|
|
:visible.sync="showUploadModal"
|
|
|
|
|
width="600px"
|
|
|
|
|
:before-close="handleCloseModal"
|
|
|
|
|
@ -171,7 +224,7 @@
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<el-form-item label="出版年份">
|
|
|
|
|
<el-input-number v-model="bookForm.year" :min="1900" :max="2030" placeholder="年份"></el-input-number>
|
|
|
|
|
<el-input-number v-model="bookForm.year" :min="1949" :max="2030" placeholder="年份"></el-input-number>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
@ -217,73 +270,147 @@
|
|
|
|
|
</el-form>
|
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
|
|
<el-button @click="showUploadModal = false">取消</el-button>
|
|
|
|
|
<el-button type="primary" @click="saveBook">保存图书</el-button>
|
|
|
|
|
<el-button type="primary" @click="saveBook">{{ isEdit ? '更新图书' : '保存图书' }}</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
|
|
|
|
<!-- 图书详情弹窗 -->
|
|
|
|
|
<el-dialog
|
|
|
|
|
title="图书详情"
|
|
|
|
|
:visible.sync="showDetailModal"
|
|
|
|
|
width="700px"
|
|
|
|
|
:before-close="handleCloseDetailModal"
|
|
|
|
|
>
|
|
|
|
|
<div v-if="currentBook" class="book-detail">
|
|
|
|
|
<!-- 基本信息 -->
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
<div class="section-title">
|
|
|
|
|
<i class="el-icon-info"></i>
|
|
|
|
|
基本信息
|
|
|
|
|
</div>
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">书名:</label>
|
|
|
|
|
<span class="detail-value">{{ currentBook.title || '未设置' }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">作者:</label>
|
|
|
|
|
<span class="detail-value">{{ currentBook.author || '未知' }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">ISBN:</label>
|
|
|
|
|
<span class="detail-value">{{ currentBook.isbn || '未设置' }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">出版社:</label>
|
|
|
|
|
<span class="detail-value">{{ currentBook.publisher || '未设置' }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">出版年份:</label>
|
|
|
|
|
<span class="detail-value">{{ currentBook.publish_year || '未设置' }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">分类:</label>
|
|
|
|
|
<el-tag :type="getCategoryTagType(currentBook.category)" size="small">{{ currentBook.category || '未分类' }}</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">图书状态:</label>
|
|
|
|
|
<el-tag :type="getStatusTagType(currentBook.status)" size="small">{{ getStatusText(currentBook.status) }}</el-tag>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">图书简介:</label>
|
|
|
|
|
<div class="detail-description">{{ currentBook.description || '暂无简介' }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 图书封面 -->
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
<div class="section-title">
|
|
|
|
|
<i class="el-icon-picture"></i>
|
|
|
|
|
图书封面
|
|
|
|
|
</div>
|
|
|
|
|
<div class="cover-display">
|
|
|
|
|
<img v-if="currentBook.cover && currentBook.cover.url" :src="currentBook.cover.url" alt="图书封面" class="detail-cover">
|
|
|
|
|
<div v-else class="no-cover-detail">
|
|
|
|
|
<i class="el-icon-picture-outline" style="font-size: 48px; color: #d1d5db;"></i>
|
|
|
|
|
<div style="color: #9ca3af; margin-top: 10px;">暂无封面</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 其他信息 -->
|
|
|
|
|
<div class="form-section">
|
|
|
|
|
<div class="section-title">
|
|
|
|
|
<i class="el-icon-document"></i>
|
|
|
|
|
其他信息
|
|
|
|
|
</div>
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">创建时间:</label>
|
|
|
|
|
<span class="detail-value">{{ formatDateTime(currentBook.created_at) }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
<el-col :span="12">
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">更新时间:</label>
|
|
|
|
|
<span class="detail-value">{{ formatDateTime(currentBook.updated_at) }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</el-col>
|
|
|
|
|
</el-row>
|
|
|
|
|
<div class="detail-item">
|
|
|
|
|
<label class="detail-label">图书ID:</label>
|
|
|
|
|
<span class="detail-value">{{ currentBook.id }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
|
|
<el-button @click="showDetailModal = false">关闭</el-button>
|
|
|
|
|
<el-button type="primary" @click="handleEdit(currentBook)">编辑图书</el-button>
|
|
|
|
|
</div>
|
|
|
|
|
</el-dialog>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
import { save } from '@/api/library'
|
|
|
|
|
import { save, index, destroy } from '@/api/library'
|
|
|
|
|
import { uploads } from '@/api/uploads'
|
|
|
|
|
export default {
|
|
|
|
|
name: 'Library',
|
|
|
|
|
data() {
|
|
|
|
|
return {
|
|
|
|
|
showUploadModal: false,
|
|
|
|
|
showDetailModal: false,
|
|
|
|
|
isEdit: false,
|
|
|
|
|
editBookId: null,
|
|
|
|
|
filters: {
|
|
|
|
|
keyword: '',
|
|
|
|
|
category: '',
|
|
|
|
|
status: ''
|
|
|
|
|
},
|
|
|
|
|
list: [
|
|
|
|
|
{
|
|
|
|
|
id: 1,
|
|
|
|
|
title: '深度学习实战指南',
|
|
|
|
|
author: '张三',
|
|
|
|
|
publisher: '机械工业出版社',
|
|
|
|
|
year: '2023',
|
|
|
|
|
isbn: '978-7-111-12345-6',
|
|
|
|
|
category: 'tech',
|
|
|
|
|
categoryText: '技术类',
|
|
|
|
|
status: 'available',
|
|
|
|
|
statusText: '可借阅',
|
|
|
|
|
cover: 'https://via.placeholder.com/50x70/4285f4/ffffff?text=书',
|
|
|
|
|
addDate: '2024-01-15',
|
|
|
|
|
addTime: '10:30'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 2,
|
|
|
|
|
title: '创业公司股权设计',
|
|
|
|
|
author: '李四',
|
|
|
|
|
publisher: '中信出版社',
|
|
|
|
|
year: '2023',
|
|
|
|
|
isbn: '978-7-508-67890-1',
|
|
|
|
|
category: 'business',
|
|
|
|
|
categoryText: '商业类',
|
|
|
|
|
status: 'borrowed',
|
|
|
|
|
statusText: '已借出',
|
|
|
|
|
cover: 'https://via.placeholder.com/50x70/ff9800/ffffff?text=书',
|
|
|
|
|
addDate: '2024-01-14',
|
|
|
|
|
addTime: '15:20'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 3,
|
|
|
|
|
title: '敏捷项目管理实践',
|
|
|
|
|
author: '王五',
|
|
|
|
|
publisher: '电子工业出版社',
|
|
|
|
|
year: '2022',
|
|
|
|
|
isbn: '978-7-121-34567-8',
|
|
|
|
|
category: 'management',
|
|
|
|
|
categoryText: '管理类',
|
|
|
|
|
status: 'available',
|
|
|
|
|
statusText: '可借阅',
|
|
|
|
|
cover: 'https://via.placeholder.com/50x70/4caf50/ffffff?text=书',
|
|
|
|
|
addDate: '2024-01-13',
|
|
|
|
|
addTime: '09:15'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
total: 1247,
|
|
|
|
|
list: [],
|
|
|
|
|
total: 0,
|
|
|
|
|
listQuery: {
|
|
|
|
|
page: 1,
|
|
|
|
|
limit: 10
|
|
|
|
|
@ -300,6 +427,7 @@ export default {
|
|
|
|
|
cover: '',
|
|
|
|
|
cover_id: ''
|
|
|
|
|
},
|
|
|
|
|
currentBook: null,
|
|
|
|
|
bookRules: {
|
|
|
|
|
title: [
|
|
|
|
|
{ required: true, message: '请输入书名', trigger: 'blur' }
|
|
|
|
|
@ -310,13 +438,64 @@ export default {
|
|
|
|
|
category: [
|
|
|
|
|
{ required: true, message: '请输入分类', trigger: 'blur' }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
chartData: {
|
|
|
|
|
total: 0,
|
|
|
|
|
borrowable: 0,
|
|
|
|
|
borrowed: 0,
|
|
|
|
|
maintaining: 0
|
|
|
|
|
},
|
|
|
|
|
categoryList: []
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
created() {
|
|
|
|
|
this.getList()
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
async getList() {
|
|
|
|
|
try {
|
|
|
|
|
const params = {
|
|
|
|
|
page: this.listQuery.page,
|
|
|
|
|
limit: this.listQuery.limit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 构建二维数组形式的filter参数
|
|
|
|
|
let filterIndex = 0
|
|
|
|
|
|
|
|
|
|
// 关键词搜索
|
|
|
|
|
if (this.filters.keyword) {
|
|
|
|
|
params.keyword = this.filters.keyword
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.filters.category) {
|
|
|
|
|
params[`filter[${filterIndex}][key]`] = 'category'
|
|
|
|
|
params[`filter[${filterIndex}][op]`] = 'eq'
|
|
|
|
|
params[`filter[${filterIndex}][value]`] = this.filters.category
|
|
|
|
|
filterIndex++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.filters.status !== '') {
|
|
|
|
|
params[`filter[${filterIndex}][key]`] = 'status'
|
|
|
|
|
params[`filter[${filterIndex}][op]`] = 'eq'
|
|
|
|
|
params[`filter[${filterIndex}][value]`] = this.filters.status
|
|
|
|
|
filterIndex++
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const res = await index(params)
|
|
|
|
|
// 处理新的API响应结构
|
|
|
|
|
this.list = res.list?.data || []
|
|
|
|
|
this.total = res.list?.total || 0
|
|
|
|
|
this.listQuery.page = res.list?.current_page || 1
|
|
|
|
|
this.chartData = res.chart || {}
|
|
|
|
|
this.categoryList = res.category || []
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('获取图书列表失败:', error)
|
|
|
|
|
this.$message.error('获取图书列表失败')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
handleSearch() {
|
|
|
|
|
console.log('搜索条件:', this.filters)
|
|
|
|
|
this.$message.success('搜索已触发')
|
|
|
|
|
this.listQuery.page = 1
|
|
|
|
|
this.getList()
|
|
|
|
|
},
|
|
|
|
|
handleExport() {
|
|
|
|
|
console.log('导出数据')
|
|
|
|
|
@ -330,42 +509,75 @@ export default {
|
|
|
|
|
this.multipleSelection = val
|
|
|
|
|
},
|
|
|
|
|
getCategoryTagType(category) {
|
|
|
|
|
const categoryMap = {
|
|
|
|
|
tech: 'primary',
|
|
|
|
|
business: 'success',
|
|
|
|
|
management: 'warning',
|
|
|
|
|
finance: 'danger'
|
|
|
|
|
}
|
|
|
|
|
return categoryMap[category] || 'info'
|
|
|
|
|
// 所有分类使用固定颜色
|
|
|
|
|
return 'primary'
|
|
|
|
|
},
|
|
|
|
|
getStatusTagType(status) {
|
|
|
|
|
const statusMap = {
|
|
|
|
|
available: 'success',
|
|
|
|
|
borrowed: 'warning',
|
|
|
|
|
maintenance: 'danger'
|
|
|
|
|
0: 'success', // 可借阅
|
|
|
|
|
1: 'warning', // 已借出
|
|
|
|
|
2: 'danger' // 维护中
|
|
|
|
|
}
|
|
|
|
|
return statusMap[status] || 'info'
|
|
|
|
|
},
|
|
|
|
|
getStatusText(status) {
|
|
|
|
|
const statusText = {
|
|
|
|
|
0: '可借阅',
|
|
|
|
|
1: '已借出',
|
|
|
|
|
2: '维护中'
|
|
|
|
|
}
|
|
|
|
|
return statusMap[status]
|
|
|
|
|
return statusText[status] || '未知状态'
|
|
|
|
|
},
|
|
|
|
|
handleEdit(row) {
|
|
|
|
|
console.log('编辑:', row.id)
|
|
|
|
|
this.$message.info('跳转到编辑页面')
|
|
|
|
|
this.isEdit = true
|
|
|
|
|
this.editBookId = row.id
|
|
|
|
|
// 填充表单数据
|
|
|
|
|
this.bookForm = {
|
|
|
|
|
title: row.title || '',
|
|
|
|
|
author: row.author || '',
|
|
|
|
|
isbn: row.isbn || '',
|
|
|
|
|
publisher: row.publisher || '',
|
|
|
|
|
year: row.publish_year ? parseInt(row.publish_year) : null,
|
|
|
|
|
category: row.category || '',
|
|
|
|
|
description: row.description || '',
|
|
|
|
|
cover: row.cover && row.cover.url ? row.cover.url : '',
|
|
|
|
|
cover_id: row.cover_id || ''
|
|
|
|
|
}
|
|
|
|
|
this.showUploadModal = true
|
|
|
|
|
},
|
|
|
|
|
handleView(row) {
|
|
|
|
|
console.log('查看详情:', row.id)
|
|
|
|
|
this.$message.info('跳转到详情页面')
|
|
|
|
|
this.currentBook = row
|
|
|
|
|
this.showDetailModal = true
|
|
|
|
|
},
|
|
|
|
|
handleReturn(row) {
|
|
|
|
|
this.$confirm('确认这本图书已归还吗?', '提示', {
|
|
|
|
|
handleStatusChange(row, status) {
|
|
|
|
|
const statusText = {
|
|
|
|
|
0: '可借阅',
|
|
|
|
|
1: '已借阅',
|
|
|
|
|
2: '维护'
|
|
|
|
|
}
|
|
|
|
|
let actionText = ''
|
|
|
|
|
if (row.status === 2 && status === 0) {
|
|
|
|
|
actionText = '上架'
|
|
|
|
|
} else {
|
|
|
|
|
actionText = statusText[status]
|
|
|
|
|
}
|
|
|
|
|
this.$confirm(`确认将这本图书状态变更为"${actionText}"吗?`, '提示', {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
}).then(() => {
|
|
|
|
|
console.log('归还图书:', row.id)
|
|
|
|
|
row.status = 'available'
|
|
|
|
|
row.statusText = '可借阅'
|
|
|
|
|
this.$message.success('图书归还成功!')
|
|
|
|
|
}).then(async () => {
|
|
|
|
|
try {
|
|
|
|
|
await save({ id: row.id, status: status })
|
|
|
|
|
this.$message.success('图书状态变更成功!')
|
|
|
|
|
this.getList() // 重新获取列表
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('状态变更失败:', error)
|
|
|
|
|
this.$message.error('状态变更失败,请重试')
|
|
|
|
|
}
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
this.$message.info('已取消归还')
|
|
|
|
|
this.$message.info('已取消变更')
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
handleDelete(row) {
|
|
|
|
|
@ -373,30 +585,36 @@ export default {
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
type: 'warning'
|
|
|
|
|
}).then(() => {
|
|
|
|
|
console.log('删除图书:', row.id)
|
|
|
|
|
// 这里应该调用删除API
|
|
|
|
|
const index = this.list.findIndex(item => item.id === row.id)
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
this.list.splice(index, 1)
|
|
|
|
|
}).then(async () => {
|
|
|
|
|
try {
|
|
|
|
|
await destroy({ id: row.id })
|
|
|
|
|
this.$message.success('图书删除成功!')
|
|
|
|
|
this.getList() // 重新获取列表
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('删除图书失败:', error)
|
|
|
|
|
this.$message.error('删除失败,请重试')
|
|
|
|
|
}
|
|
|
|
|
this.$message.success('图书删除成功!')
|
|
|
|
|
}).catch(() => {
|
|
|
|
|
this.$message.info('已取消删除')
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
handleSizeChange(val) {
|
|
|
|
|
this.listQuery.limit = val
|
|
|
|
|
console.log('每页显示条数:', val)
|
|
|
|
|
this.getList()
|
|
|
|
|
},
|
|
|
|
|
handleCurrentChange(val) {
|
|
|
|
|
this.listQuery.page = val
|
|
|
|
|
console.log('当前页:', val)
|
|
|
|
|
this.getList()
|
|
|
|
|
},
|
|
|
|
|
handleCloseModal() {
|
|
|
|
|
this.resetForm()
|
|
|
|
|
this.isEdit = false
|
|
|
|
|
this.editBookId = null
|
|
|
|
|
this.showUploadModal = false
|
|
|
|
|
},
|
|
|
|
|
handleCloseDetailModal() {
|
|
|
|
|
this.showDetailModal = false
|
|
|
|
|
},
|
|
|
|
|
triggerCoverUpload() {
|
|
|
|
|
this.$refs.coverInput.click()
|
|
|
|
|
},
|
|
|
|
|
@ -430,11 +648,11 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
async saveBook() {
|
|
|
|
|
this.$refs.bookForm.validate(async (valid) => {
|
|
|
|
|
this.$refs.bookForm.validate(async(valid) => {
|
|
|
|
|
if (valid) {
|
|
|
|
|
const loading = this.$loading({
|
|
|
|
|
lock: true,
|
|
|
|
|
text: '正在保存...',
|
|
|
|
|
text: this.isEdit ? '正在更新...' : '正在保存...',
|
|
|
|
|
spinner: 'el-icon-loading',
|
|
|
|
|
background: 'rgba(0, 0, 0, 0.7)'
|
|
|
|
|
})
|
|
|
|
|
@ -449,16 +667,24 @@ export default {
|
|
|
|
|
description: this.bookForm.description,
|
|
|
|
|
cover_id: this.bookForm.cover_id
|
|
|
|
|
}
|
|
|
|
|
console.log('params', params)
|
|
|
|
|
await save(params)
|
|
|
|
|
|
|
|
|
|
if (this.isEdit) {
|
|
|
|
|
// 编辑模式,添加ID参数
|
|
|
|
|
params.id = this.editBookId
|
|
|
|
|
await save(params) // 这里可能需要调用不同的API,暂时用save
|
|
|
|
|
} else {
|
|
|
|
|
// 新增模式
|
|
|
|
|
await save(params)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loading.close()
|
|
|
|
|
this.$message.success('图书添加成功!')
|
|
|
|
|
this.$message.success(this.isEdit ? '图书更新成功!' : '图书添加成功!')
|
|
|
|
|
this.showUploadModal = false
|
|
|
|
|
this.resetForm()
|
|
|
|
|
// 重新获取列表或手动添加
|
|
|
|
|
this.getList() // 重新获取列表
|
|
|
|
|
} catch (e) {
|
|
|
|
|
loading.close()
|
|
|
|
|
this.$message.error('添加失败,请重试' + e.message)
|
|
|
|
|
this.$message.error((this.isEdit ? '更新' : '添加') + '失败,请重试' + e.message)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this.$message.error('请填写必填字段')
|
|
|
|
|
@ -479,15 +705,23 @@ export default {
|
|
|
|
|
cover: '',
|
|
|
|
|
cover_id: ''
|
|
|
|
|
}
|
|
|
|
|
this.isEdit = false
|
|
|
|
|
this.editBookId = null
|
|
|
|
|
},
|
|
|
|
|
getCategoryText(category) {
|
|
|
|
|
const categoryMap = {
|
|
|
|
|
tech: '技术类',
|
|
|
|
|
business: '商业类',
|
|
|
|
|
management: '管理类',
|
|
|
|
|
finance: '金融类'
|
|
|
|
|
}
|
|
|
|
|
return categoryMap[category] || category || ''
|
|
|
|
|
formatDate(dateString) {
|
|
|
|
|
if (!dateString) return ''
|
|
|
|
|
const date = new Date(dateString)
|
|
|
|
|
return date.toLocaleDateString('zh-CN')
|
|
|
|
|
},
|
|
|
|
|
formatTime(dateString) {
|
|
|
|
|
if (!dateString) return ''
|
|
|
|
|
const date = new Date(dateString)
|
|
|
|
|
return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' })
|
|
|
|
|
},
|
|
|
|
|
formatDateTime(dateString) {
|
|
|
|
|
if (!dateString) return ''
|
|
|
|
|
const date = new Date(dateString)
|
|
|
|
|
return date.toLocaleString('zh-CN')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -550,9 +784,7 @@ export default {
|
|
|
|
|
.stat-card.purple { border-left-color: #9b59b6; }
|
|
|
|
|
|
|
|
|
|
.stat-number {
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
color: #2c3e50;
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.stat-label {
|
|
|
|
|
@ -684,6 +916,81 @@ export default {
|
|
|
|
|
text-align: right;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 详情弹窗样式 */
|
|
|
|
|
.book-detail {
|
|
|
|
|
max-height: 70vh;
|
|
|
|
|
overflow-y: auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.detail-item {
|
|
|
|
|
margin-bottom: 15px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.detail-label {
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
color: #2c3e50;
|
|
|
|
|
min-width: 80px;
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.detail-value {
|
|
|
|
|
color: #374151;
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
flex: 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.detail-description {
|
|
|
|
|
color: #374151;
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
padding: 12px;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
border-left: 3px solid #3498db;
|
|
|
|
|
margin-top: 5px;
|
|
|
|
|
white-space: pre-wrap;
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.cover-display {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
min-height: 200px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.detail-cover {
|
|
|
|
|
max-width: 200px;
|
|
|
|
|
max-height: 280px;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.no-cover-detail {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
width: 200px;
|
|
|
|
|
height: 280px;
|
|
|
|
|
border: 2px dashed #d1d5db;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.no-cover {
|
|
|
|
|
color: #9ca3af;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
background: #f8f9fa;
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
border: 1px dashed #d1d5db;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Element UI 表格样式覆盖 */
|
|
|
|
|
::v-deep .el-table th {
|
|
|
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
|
|
|