1252 lines
29 KiB
Plaintext
1252 lines
29 KiB
Plaintext
<template>
|
||
<view class="librarian-workspace">
|
||
<!-- 图书管理员信息头部 -->
|
||
<view class="librarian-header">
|
||
<view class="librarian-info">
|
||
<image class="avatar" :src="librarianInfo.avatar || '/static/default-avatar.png'" />
|
||
<view class="info">
|
||
<text class="name">{{ librarianInfo.name }}</text>
|
||
<text class="department">{{ librarianInfo.department }}</text>
|
||
<text class="position">{{ librarianInfo.position }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="work-status" :class="librarianInfo.status">
|
||
<text class="status-text">{{ getStatusText(librarianInfo.status) }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 图书馆实时状态 -->
|
||
<view class="library-status">
|
||
<view class="section-title">图书馆状态</view>
|
||
<view class="status-grid">
|
||
<view class="status-card">
|
||
<text class="status-value">{{ libraryData.currentReaders }}</text>
|
||
<text class="status-label">在馆人数</text>
|
||
</view>
|
||
<view class="status-card">
|
||
<text class="status-value">{{ libraryData.availableSeats }}</text>
|
||
<text class="status-label">可用座位</text>
|
||
</view>
|
||
<view class="status-card">
|
||
<text class="status-value">{{ libraryData.todayBorrows }}</text>
|
||
<text class="status-label">今日借阅</text>
|
||
</view>
|
||
<view class="status-card">
|
||
<text class="status-value">{{ libraryData.todayReturns }}</text>
|
||
<text class="status-label">今日归还</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 快速借还书 -->
|
||
<view class="quick-operations">
|
||
<view class="section-title">快速操作</view>
|
||
<view class="operation-buttons">
|
||
<button class="operation-btn borrow" @click="startQuickBorrow">
|
||
<image class="btn-icon" src="/static/icons/borrow.png" />
|
||
<text class="btn-text">快速借书</text>
|
||
</button>
|
||
|
||
<button class="operation-btn return" @click="startQuickReturn">
|
||
<image class="btn-icon" src="/static/icons/return.png" />
|
||
<text class="btn-text">快速还书</text>
|
||
</button>
|
||
|
||
<button class="operation-btn scan" @click="startBookScan">
|
||
<image class="btn-icon" src="/static/icons/scan.png" />
|
||
<text class="btn-text">扫码操作</text>
|
||
</button>
|
||
|
||
<button class="operation-btn search" @click="goToBookSearch">
|
||
<image class="btn-icon" src="/static/icons/search.png" />
|
||
<text class="btn-text">图书检索</text>
|
||
</button>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 待处理事务 -->
|
||
<view class="pending-tasks">
|
||
<view class="section-header">
|
||
<text class="section-title">待处理事务</text>
|
||
<text class="task-count">{{ pendingTasks.length }}项</text>
|
||
</view>
|
||
|
||
<view class="task-list">
|
||
<view class="task-item" v-for="task in pendingTasks" :key="task.id" :class="task.priority">
|
||
<view class="task-icon" :class="task.type">
|
||
<image :src="getTaskIcon(task.type)" />
|
||
</view>
|
||
<view class="task-content">
|
||
<text class="task-title">{{ task.title }}</text>
|
||
<text class="task-description">{{ task.description }}</text>
|
||
<text class="task-time">{{ formatTime(task.createTime) }}</text>
|
||
</view>
|
||
<button class="task-action" @click="handleTask(task)">
|
||
{{ getTaskActionText(task.type) }}
|
||
</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 借阅统计图表 -->
|
||
<view class="borrowing-stats">
|
||
<view class="section-title">借阅统计</view>
|
||
<view class="stats-tabs">
|
||
<text class="tab-item"
|
||
:class="{ active: activeTab === 'today' }"
|
||
@click="switchTab('today')">今日</text>
|
||
<text class="tab-item"
|
||
:class="{ active: activeTab === 'week' }"
|
||
@click="switchTab('week')">本周</text>
|
||
<text class="tab-item"
|
||
:class="{ active: activeTab === 'month' }"
|
||
@click="switchTab('month')">本月</text>
|
||
</view>
|
||
|
||
<view class="chart-container">
|
||
<view class="chart-item" v-for="item in chartData" :key="item.label">
|
||
<view class="chart-bar">
|
||
<view class="bar-fill" :style="{ height: item.percentage + '%' }"></view>
|
||
</view>
|
||
<text class="chart-label">{{ item.label }}</text>
|
||
<text class="chart-value">{{ item.value }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 热门图书 -->
|
||
<view class="popular-books">
|
||
<view class="section-header">
|
||
<text class="section-title">热门图书</text>
|
||
<text class="view-more" @click="goToBookRanking">查看更多</text>
|
||
</view>
|
||
|
||
<scroll-view scroll-x="true" class="books-scroll">
|
||
<view class="book-item" v-for="book in popularBooks" :key="book.id">
|
||
<image class="book-cover" :src="book.cover || '/static/default-book.png'" />
|
||
<view class="book-info">
|
||
<text class="book-title">{{ book.title }}</text>
|
||
<text class="book-author">{{ book.author }}</text>
|
||
<view class="book-stats">
|
||
<view class="stat-item">
|
||
<text class="stat-label">借阅</text>
|
||
<text class="stat-value">{{ book.borrowCount }}</text>
|
||
</view>
|
||
<view class="stat-item">
|
||
<text class="stat-label">库存</text>
|
||
<text class="stat-value">{{ book.available }}/{{ book.total }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<button class="book-action" @click="viewBookDetails(book)">详情</button>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
|
||
<!-- 最近活动 -->
|
||
<view class="recent-activities">
|
||
<view class="section-title">最近活动</view>
|
||
|
||
<view class="activity-list">
|
||
<view class="activity-item" v-for="activity in recentActivities" :key="activity.id">
|
||
<view class="activity-time">{{ formatActivityTime(activity.time) }}</view>
|
||
<view class="activity-content">
|
||
<view class="activity-header">
|
||
<text class="user-info">{{ activity.userName }} ({{ activity.userType }})</text>
|
||
<view class="activity-type" :class="activity.type">
|
||
{{ getActivityTypeText(activity.type) }}
|
||
</view>
|
||
</view>
|
||
<text class="book-title">《{{ activity.bookTitle }}》</text>
|
||
<view class="activity-details" v-if="activity.details">
|
||
<text class="detail-text">{{ activity.details }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 管理功能菜单 -->
|
||
<view class="management-functions">
|
||
<view class="section-title">管理功能</view>
|
||
<view class="function-grid">
|
||
<view class="function-item" @click="goToBookCatalog">
|
||
<image class="function-icon" src="/static/icons/catalog.png" />
|
||
<text class="function-text">图书目录</text>
|
||
</view>
|
||
|
||
<view class="function-item" @click="goToReaderManagement">
|
||
<image class="function-icon" src="/static/icons/readers.png" />
|
||
<text class="function-text">读者管理</text>
|
||
</view>
|
||
|
||
<view class="function-item" @click="goToOverdueManagement">
|
||
<image class="function-icon" src="/static/icons/overdue.png" />
|
||
<text class="function-text">逾期管理</text>
|
||
<view class="function-badge" v-if="overdueCount > 0">
|
||
{{ overdueCount }}
|
||
</view>
|
||
</view>
|
||
|
||
<view class="function-item" @click="goToReservationManagement">
|
||
<image class="function-icon" src="/static/icons/reservation.png" />
|
||
<text class="function-text">预约管理</text>
|
||
<view class="function-badge" v-if="reservationCount > 0">
|
||
{{ reservationCount }}
|
||
</view>
|
||
</view>
|
||
|
||
<view class="function-item" @click="goToInventoryManagement">
|
||
<image class="function-icon" src="/static/icons/inventory.png" />
|
||
<text class="function-text">库存管理</text>
|
||
</view>
|
||
|
||
<view class="function-item" @click="goToAccessControl">
|
||
<image class="function-icon" src="/static/icons/access.png" />
|
||
<text class="function-text">门禁管理</text>
|
||
</view>
|
||
|
||
<view class="function-item" @click="goToDataReports">
|
||
<image class="function-icon" src="/static/icons/reports.png" />
|
||
<text class="function-text">数据报表</text>
|
||
</view>
|
||
|
||
<view class="function-item" @click="goToSystemSettings">
|
||
<image class="function-icon" src="/static/icons/settings.png" />
|
||
<text class="function-text">系统设置</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 座位管理 -->
|
||
<view class="seat-management">
|
||
<view class="section-header">
|
||
<text class="section-title">座位管理</text>
|
||
<button class="seat-overview-btn" @click="goToSeatOverview">
|
||
座位总览
|
||
</button>
|
||
</view>
|
||
|
||
<view class="floor-tabs">
|
||
<text class="floor-tab"
|
||
v-for="floor in floors"
|
||
:key="floor.id"
|
||
:class="{ active: activeFloor === floor.id }"
|
||
@click="switchFloor(floor.id)">
|
||
{{ floor.name }}
|
||
</text>
|
||
</view>
|
||
|
||
<view class="seat-stats">
|
||
<view class="seat-stat-item">
|
||
<text class="stat-number">{{ currentFloorData.total }}</text>
|
||
<text class="stat-label">总座位</text>
|
||
</view>
|
||
<view class="seat-stat-item">
|
||
<text class="stat-number">{{ currentFloorData.occupied }}</text>
|
||
<text class="stat-label">已占用</text>
|
||
</view>
|
||
<view class="seat-stat-item">
|
||
<text class="stat-number">{{ currentFloorData.available }}</text>
|
||
<text class="stat-label">可用</text>
|
||
</view>
|
||
<view class="seat-stat-item">
|
||
<text class="stat-number">{{ currentFloorData.reserved }}</text>
|
||
<text class="stat-label">已预约</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 系统通知 -->
|
||
<view class="system-notifications" v-if="notifications.length > 0">
|
||
<view class="section-title">系统通知</view>
|
||
<view class="notification-list">
|
||
<view class="notification-item"
|
||
v-for="notification in notifications"
|
||
:key="notification.id"
|
||
:class="notification.level">
|
||
<view class="notification-icon">
|
||
<image :src="getNotificationIcon(notification.level)" />
|
||
</view>
|
||
<view class="notification-content">
|
||
<text class="notification-title">{{ notification.title }}</text>
|
||
<text class="notification-message">{{ notification.message }}</text>
|
||
</view>
|
||
<text class="notification-time">{{ formatTime(notification.time) }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
librarianInfo: {
|
||
name: '陈老师',
|
||
department: '图书馆',
|
||
position: '图书管理员',
|
||
status: 'working',
|
||
avatar: ''
|
||
},
|
||
libraryData: {
|
||
currentReaders: 342,
|
||
availableSeats: 158,
|
||
todayBorrows: 67,
|
||
todayReturns: 52
|
||
},
|
||
pendingTasks: [
|
||
{
|
||
id: 1,
|
||
type: 'overdue',
|
||
title: '逾期图书提醒',
|
||
description: '张小明《数据结构》逾期3天',
|
||
priority: 'high',
|
||
createTime: new Date(Date.now() - 3600000)
|
||
},
|
||
{
|
||
id: 2,
|
||
type: 'reservation',
|
||
title: '预约到书通知',
|
||
description: '李小红预约的《算法导论》已到书',
|
||
priority: 'normal',
|
||
createTime: new Date(Date.now() - 7200000)
|
||
}
|
||
],
|
||
activeTab: 'today',
|
||
chartData: [
|
||
{ label: '借阅', value: 67, percentage: 80 },
|
||
{ label: '归还', value: 52, percentage: 62 },
|
||
{ label: '续借', value: 23, percentage: 28 },
|
||
{ label: '预约', value: 15, percentage: 18 }
|
||
],
|
||
popularBooks: [
|
||
{
|
||
id: 1,
|
||
title: '数据结构与算法分析',
|
||
author: 'Mark Allen Weiss',
|
||
cover: '',
|
||
borrowCount: 45,
|
||
available: 3,
|
||
total: 10
|
||
},
|
||
{
|
||
id: 2,
|
||
title: '深入理解计算机系统',
|
||
author: 'Randal E. Bryant',
|
||
cover: '',
|
||
borrowCount: 38,
|
||
available: 1,
|
||
total: 8
|
||
}
|
||
],
|
||
recentActivities: [
|
||
{
|
||
id: 1,
|
||
userName: '张小明',
|
||
userType: '学生',
|
||
type: 'borrow',
|
||
bookTitle: '算法导论',
|
||
time: new Date(Date.now() - 1800000),
|
||
details: '借期30天'
|
||
},
|
||
{
|
||
id: 2,
|
||
userName: '李小红',
|
||
userType: '教师',
|
||
type: 'return',
|
||
bookTitle: '软件工程',
|
||
time: new Date(Date.now() - 3600000),
|
||
details: '准时归还'
|
||
}
|
||
],
|
||
overdueCount: 15,
|
||
reservationCount: 8,
|
||
floors: [
|
||
{ id: 1, name: '1F' },
|
||
{ id: 2, name: '2F' },
|
||
{ id: 3, name: '3F' }
|
||
],
|
||
activeFloor: 1,
|
||
currentFloorData: {
|
||
total: 200,
|
||
occupied: 142,
|
||
available: 58,
|
||
reserved: 15
|
||
},
|
||
notifications: [
|
||
{
|
||
id: 1,
|
||
level: 'warning',
|
||
title: '系统维护通知',
|
||
message: '今晚23:00-01:00系统维护,请提前处理相关业务',
|
||
time: new Date(Date.now() - 1800000)
|
||
}
|
||
]
|
||
}
|
||
},
|
||
onLoad() {
|
||
this.loadLibrarianData()
|
||
},
|
||
onPullDownRefresh() {
|
||
this.refreshData()
|
||
},
|
||
methods: {
|
||
loadLibrarianData() {
|
||
this.loadLibraryStatus()
|
||
this.loadPendingTasks()
|
||
this.loadBorrowingStats()
|
||
this.loadPopularBooks()
|
||
this.loadRecentActivities()
|
||
},
|
||
refreshData() {
|
||
Promise.all([
|
||
this.loadLibrarianData()
|
||
]).then(() => {
|
||
uni.stopPullDownRefresh()
|
||
})
|
||
},
|
||
loadLibraryStatus() {
|
||
uni.request({
|
||
url: '/api/v1/librarian/library-status',
|
||
success: (res) => {
|
||
this.libraryData = res.data
|
||
}
|
||
})
|
||
},
|
||
loadPendingTasks() {
|
||
uni.request({
|
||
url: '/api/v1/librarian/pending-tasks',
|
||
success: (res) => {
|
||
this.pendingTasks = res.data
|
||
}
|
||
})
|
||
},
|
||
loadBorrowingStats() {
|
||
uni.request({
|
||
url: `/api/v1/librarian/borrowing-stats?period=${this.activeTab}`,
|
||
success: (res) => {
|
||
this.chartData = res.data
|
||
}
|
||
})
|
||
},
|
||
loadPopularBooks() {
|
||
uni.request({
|
||
url: '/api/v1/librarian/popular-books',
|
||
success: (res) => {
|
||
this.popularBooks = res.data
|
||
}
|
||
})
|
||
},
|
||
loadRecentActivities() {
|
||
uni.request({
|
||
url: '/api/v1/librarian/recent-activities',
|
||
success: (res) => {
|
||
this.recentActivities = res.data
|
||
}
|
||
})
|
||
},
|
||
getStatusText(status) {
|
||
const statusMap = {
|
||
working: '工作中',
|
||
break: '休息中',
|
||
off: '下班'
|
||
}
|
||
return statusMap[status] || '未知'
|
||
},
|
||
// 快速操作
|
||
startQuickBorrow() {
|
||
uni.navigateTo({
|
||
url: '/pages/mall/nfc/librarian/quick-borrow'
|
||
})
|
||
},
|
||
startQuickReturn() {
|
||
uni.navigateTo({
|
||
url: '/pages/mall/nfc/librarian/quick-return'
|
||
})
|
||
},
|
||
startBookScan() {
|
||
uni.scanCode({
|
||
success: (res) => {
|
||
this.handleScannedCode(res.result)
|
||
},
|
||
fail: () => {
|
||
uni.showToast({
|
||
title: '扫码失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
})
|
||
},
|
||
handleScannedCode(code) {
|
||
// 处理扫码结果
|
||
uni.navigateTo({
|
||
url: `/pages/mall/nfc/librarian/book-operation?code=${code}`
|
||
})
|
||
},
|
||
goToBookSearch() {
|
||
uni.navigateTo({
|
||
url: '/pages/mall/nfc/librarian/book-search'
|
||
})
|
||
},
|
||
// 任务处理
|
||
handleTask(task) {
|
||
switch (task.type) {
|
||
case 'overdue':
|
||
this.handleOverdueTask(task)
|
||
break
|
||
case 'reservation':
|
||
this.handleReservationTask(task)
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
},
|
||
handleOverdueTask(task) {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/nfc/librarian/overdue-detail?taskId=${task.id}`
|
||
})
|
||
},
|
||
handleReservationTask(task) {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/nfc/librarian/reservation-detail?taskId=${task.id}`
|
||
})
|
||
},
|
||
getTaskIcon(type) {
|
||
const icons = {
|
||
overdue: '/static/icons/overdue-task.png',
|
||
reservation: '/static/icons/reservation-task.png',
|
||
maintenance: '/static/icons/maintenance-task.png'
|
||
}
|
||
return icons[type] || icons.overdue
|
||
},
|
||
getTaskActionText(type) {
|
||
const actions = {
|
||
overdue: '处理',
|
||
reservation: '通知',
|
||
maintenance: '维护'
|
||
}
|
||
return actions[type] || '处理'
|
||
},
|
||
// 统计图表
|
||
switchTab(tab) {
|
||
this.activeTab = tab
|
||
this.loadBorrowingStats()
|
||
},
|
||
// 热门图书
|
||
viewBookDetails(book) {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/nfc/librarian/book-details?bookId=${book.id}`
|
||
})
|
||
},
|
||
goToBookRanking() {
|
||
uni.navigateTo({
|
||
url: '/pages/mall/nfc/librarian/book-ranking'
|
||
})
|
||
},
|
||
// 活动记录
|
||
getActivityTypeText(type) {
|
||
const typeMap = {
|
||
borrow: '借阅',
|
||
return: '归还',
|
||
renew: '续借',
|
||
reserve: '预约'
|
||
}
|
||
return typeMap[type] || '未知'
|
||
},
|
||
// 管理功能导航
|
||
goToBookCatalog() {
|
||
uni.navigateTo({ url: '/pages/mall/nfc/librarian/book-catalog' })
|
||
},
|
||
goToReaderManagement() {
|
||
uni.navigateTo({ url: '/pages/mall/nfc/librarian/reader-management' })
|
||
},
|
||
goToOverdueManagement() {
|
||
uni.navigateTo({ url: '/pages/mall/nfc/librarian/overdue-management' })
|
||
},
|
||
goToReservationManagement() {
|
||
uni.navigateTo({ url: '/pages/mall/nfc/librarian/reservation-management' })
|
||
},
|
||
goToInventoryManagement() {
|
||
uni.navigateTo({ url: '/pages/mall/nfc/librarian/inventory-management' })
|
||
},
|
||
goToAccessControl() {
|
||
uni.navigateTo({ url: '/pages/mall/nfc/librarian/access-control' })
|
||
},
|
||
goToDataReports() {
|
||
uni.navigateTo({ url: '/pages/mall/nfc/librarian/data-reports' })
|
||
},
|
||
goToSystemSettings() {
|
||
uni.navigateTo({ url: '/pages/mall/nfc/librarian/system-settings' })
|
||
},
|
||
// 座位管理
|
||
switchFloor(floorId) {
|
||
this.activeFloor = floorId
|
||
this.loadFloorData(floorId)
|
||
},
|
||
loadFloorData(floorId) {
|
||
uni.request({
|
||
url: `/api/v1/librarian/floor-data?floorId=${floorId}`,
|
||
success: (res) => {
|
||
this.currentFloorData = res.data
|
||
}
|
||
})
|
||
},
|
||
goToSeatOverview() {
|
||
uni.navigateTo({
|
||
url: '/pages/mall/nfc/librarian/seat-overview'
|
||
})
|
||
},
|
||
// 通知处理
|
||
getNotificationIcon(level) {
|
||
const icons = {
|
||
info: '/static/icons/info-notification.png',
|
||
warning: '/static/icons/warning-notification.png',
|
||
error: '/static/icons/error-notification.png'
|
||
}
|
||
return icons[level] || icons.info
|
||
},
|
||
// 时间格式化
|
||
formatTime(time) {
|
||
const now = new Date()
|
||
const diff = now - time
|
||
const minutes = Math.floor(diff / 60000)
|
||
|
||
if (minutes < 1) return '刚刚'
|
||
if (minutes < 60) return `${minutes}分钟前`
|
||
|
||
const hours = Math.floor(minutes / 60)
|
||
if (hours < 24) return `${hours}小时前`
|
||
|
||
return time.toLocaleDateString()
|
||
},
|
||
formatActivityTime(time) {
|
||
return time.toLocaleTimeString('zh-CN', {
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style>
|
||
.librarian-workspace {
|
||
padding: 20rpx;
|
||
background-color: #f8f9fa;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.librarian-header {
|
||
background: linear-gradient(135deg, #6f42c1 0%, #563d7c 100%);
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 30rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.librarian-info {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.avatar {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 40rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.info {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.name {
|
||
color: white;
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.department, .position {
|
||
color: rgba(255, 255, 255, 0.8);
|
||
font-size: 24rpx;
|
||
margin-bottom: 4rpx;
|
||
}
|
||
|
||
.work-status {
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border-radius: 12rpx;
|
||
padding: 16rpx;
|
||
}
|
||
|
||
.work-status.working {
|
||
background: rgba(40, 167, 69, 0.2);
|
||
}
|
||
|
||
.status-text {
|
||
color: white;
|
||
font-size: 24rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.library-status, .quick-operations, .pending-tasks, .borrowing-stats,
|
||
.popular-books, .recent-activities, .management-functions, .seat-management,
|
||
.system-notifications {
|
||
background: white;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.status-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.status-card {
|
||
text-align: center;
|
||
padding: 20rpx;
|
||
border: 1rpx solid #eee;
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.status-value {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #6f42c1;
|
||
margin-bottom: 8rpx;
|
||
display: block;
|
||
}
|
||
|
||
.status-label {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.operation-buttons {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.operation-btn {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 30rpx 20rpx;
|
||
border: 2rpx solid;
|
||
border-radius: 12rpx;
|
||
background: none;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.operation-btn.borrow {
|
||
border-color: #28a745;
|
||
background: #f8fff8;
|
||
}
|
||
|
||
.operation-btn.return {
|
||
border-color: #17a2b8;
|
||
background: #f0f8ff;
|
||
}
|
||
|
||
.operation-btn.scan {
|
||
border-color: #ffc107;
|
||
background: #fffbf0;
|
||
}
|
||
|
||
.operation-btn.search {
|
||
border-color: #6f42c1;
|
||
background: #f8f7ff;
|
||
}
|
||
|
||
.btn-icon {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.btn-text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
text-align: center;
|
||
}
|
||
|
||
.task-count {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
background: #f8f9fa;
|
||
padding: 8rpx 16rpx;
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.task-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.task-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20rpx;
|
||
border-radius: 12rpx;
|
||
border-left: 6rpx solid;
|
||
}
|
||
|
||
.task-item.high {
|
||
border-left-color: #dc3545;
|
||
background: #fff5f5;
|
||
}
|
||
|
||
.task-item.normal {
|
||
border-left-color: #28a745;
|
||
background: #f8fff8;
|
||
}
|
||
|
||
.task-icon {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
margin-right: 20rpx;
|
||
border-radius: 8rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.task-icon image {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
}
|
||
|
||
.task-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.task-title {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.task-description {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.task-time {
|
||
font-size: 20rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.task-action {
|
||
background: #6f42c1;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 8rpx;
|
||
padding: 12rpx 20rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.stats-tabs {
|
||
display: flex;
|
||
margin-bottom: 30rpx;
|
||
background: #f8f9fa;
|
||
border-radius: 12rpx;
|
||
padding: 8rpx;
|
||
}
|
||
|
||
.tab-item {
|
||
flex: 1;
|
||
text-align: center;
|
||
padding: 16rpx;
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
border-radius: 8rpx;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.tab-item.active {
|
||
background: #6f42c1;
|
||
color: white;
|
||
}
|
||
|
||
.chart-container {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
align-items: flex-end;
|
||
height: 200rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.chart-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.chart-bar {
|
||
width: 60rpx;
|
||
height: 150rpx;
|
||
background: #f0f0f0;
|
||
border-radius: 8rpx;
|
||
overflow: hidden;
|
||
margin-bottom: 16rpx;
|
||
position: relative;
|
||
}
|
||
|
||
.bar-fill {
|
||
position: absolute;
|
||
bottom: 0;
|
||
width: 100%;
|
||
background: linear-gradient(to top, #6f42c1, #8a63d2);
|
||
border-radius: 8rpx;
|
||
transition: height 0.3s ease;
|
||
}
|
||
|
||
.chart-label {
|
||
font-size: 20rpx;
|
||
color: #666;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.chart-value {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.view-more {
|
||
font-size: 24rpx;
|
||
color: #6f42c1;
|
||
}
|
||
|
||
.books-scroll {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.book-item {
|
||
display: inline-block;
|
||
width: 280rpx;
|
||
margin-right: 20rpx;
|
||
border: 1rpx solid #eee;
|
||
border-radius: 12rpx;
|
||
padding: 20rpx;
|
||
}
|
||
|
||
.book-cover {
|
||
width: 100%;
|
||
height: 200rpx;
|
||
border-radius: 8rpx;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.book-info {
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.book-title {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
margin-bottom: 8rpx;
|
||
display: block;
|
||
}
|
||
|
||
.book-author {
|
||
font-size: 20rpx;
|
||
color: #666;
|
||
margin-bottom: 16rpx;
|
||
display: block;
|
||
}
|
||
|
||
.book-stats {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.stat-item {
|
||
text-align: center;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 18rpx;
|
||
color: #999;
|
||
margin-bottom: 4rpx;
|
||
display: block;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 20rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.book-action {
|
||
background: #6f42c1;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 8rpx;
|
||
padding: 12rpx;
|
||
font-size: 20rpx;
|
||
width: 100%;
|
||
}
|
||
|
||
.activity-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.activity-item {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
padding: 20rpx;
|
||
border: 1rpx solid #eee;
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.activity-time {
|
||
font-size: 20rpx;
|
||
color: #999;
|
||
min-width: 100rpx;
|
||
margin-right: 20rpx;
|
||
}
|
||
|
||
.activity-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.activity-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.user-info {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.activity-type {
|
||
padding: 4rpx 12rpx;
|
||
border-radius: 8rpx;
|
||
font-size: 18rpx;
|
||
}
|
||
|
||
.activity-type.borrow {
|
||
background: #d4edda;
|
||
color: #155724;
|
||
}
|
||
|
||
.activity-type.return {
|
||
background: #d1ecf1;
|
||
color: #0c5460;
|
||
}
|
||
|
||
.book-title {
|
||
font-size: 22rpx;
|
||
color: #666;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.activity-details {
|
||
font-size: 20rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.function-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.function-item {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 30rpx 20rpx;
|
||
border: 1rpx solid #eee;
|
||
border-radius: 12rpx;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.function-item:hover {
|
||
border-color: #6f42c1;
|
||
background: #f8f7ff;
|
||
}
|
||
|
||
.function-icon {
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.function-text {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
text-align: center;
|
||
}
|
||
|
||
.function-badge {
|
||
position: absolute;
|
||
top: 16rpx;
|
||
right: 16rpx;
|
||
background: #dc3545;
|
||
color: white;
|
||
font-size: 18rpx;
|
||
padding: 4rpx 8rpx;
|
||
border-radius: 12rpx;
|
||
min-width: 24rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.seat-overview-btn {
|
||
background: #6f42c1;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 8rpx;
|
||
padding: 12rpx 20rpx;
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.floor-tabs {
|
||
display: flex;
|
||
margin-bottom: 20rpx;
|
||
background: #f8f9fa;
|
||
border-radius: 12rpx;
|
||
padding: 8rpx;
|
||
}
|
||
|
||
.floor-tab {
|
||
flex: 1;
|
||
text-align: center;
|
||
padding: 16rpx;
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
border-radius: 8rpx;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.floor-tab.active {
|
||
background: #6f42c1;
|
||
color: white;
|
||
}
|
||
|
||
.seat-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.seat-stat-item {
|
||
text-align: center;
|
||
padding: 20rpx;
|
||
border: 1rpx solid #eee;
|
||
border-radius: 12rpx;
|
||
}
|
||
|
||
.stat-number {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #6f42c1;
|
||
margin-bottom: 8rpx;
|
||
display: block;
|
||
}
|
||
|
||
.notification-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.notification-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 20rpx;
|
||
border-radius: 12rpx;
|
||
border-left: 6rpx solid;
|
||
}
|
||
|
||
.notification-item.info {
|
||
border-left-color: #17a2b8;
|
||
background: #f0f8ff;
|
||
}
|
||
|
||
.notification-item.warning {
|
||
border-left-color: #ffc107;
|
||
background: #fffbf0;
|
||
}
|
||
|
||
.notification-item.error {
|
||
border-left-color: #dc3545;
|
||
background: #fff5f5;
|
||
}
|
||
|
||
.notification-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
margin-right: 20rpx;
|
||
border-radius: 8rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.notification-icon image {
|
||
width: 24rpx;
|
||
height: 24rpx;
|
||
}
|
||
|
||
.notification-content {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.notification-title {
|
||
font-size: 24rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.notification-message {
|
||
font-size: 22rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.notification-time {
|
||
font-size: 20rpx;
|
||
color: #999;
|
||
margin-left: 20rpx;
|
||
}
|
||
</style>
|