Files
akmon/pages/mall/nfc/librarian/index.uvue
2026-01-20 08:04:15 +08:00

1252 lines
29 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>