|
@@ -1,53 +1,135 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="admin-room-calendar">
|
|
<div class="admin-room-calendar">
|
|
|
- <h1>宠物房间管理</h1>
|
|
|
|
|
-
|
|
|
|
|
- <div class="toolbar">
|
|
|
|
|
- <el-select v-model="selectedRoomId" placeholder="选择房型" @change="fetchStatus">
|
|
|
|
|
- <el-option v-for="room in rooms" :key="room.id" :label="room.name" :value="room.id" />
|
|
|
|
|
- </el-select>
|
|
|
|
|
- <el-date-picker
|
|
|
|
|
- v-model="currentMonth"
|
|
|
|
|
- type="month"
|
|
|
|
|
- placeholder="选择月份"
|
|
|
|
|
- value-format="YYYY-MM"
|
|
|
|
|
- @change="fetchStatus"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <div class="header">
|
|
|
|
|
+ <h1>宠物房间管理</h1>
|
|
|
|
|
+ <el-button type="primary" @click="openCreate">+ 新增房型</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <RoomCalendar
|
|
|
|
|
- v-if="selectedRoomId"
|
|
|
|
|
- :room-id="selectedRoomId"
|
|
|
|
|
- :month="currentMonth"
|
|
|
|
|
- :status-list="roomStatusList"
|
|
|
|
|
- @date-click="handleDateClick"
|
|
|
|
|
- @month-change="onMonthChange"
|
|
|
|
|
- />
|
|
|
|
|
|
|
+ <el-table :data="rooms" border stripe v-loading="loading">
|
|
|
|
|
+ <el-table-column prop="name" label="房间名称" />
|
|
|
|
|
+ <el-table-column prop="roomType" label="房型类型" width="120">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ {{ roomTypeLabel(row.roomType) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column prop="capacity" label="容量" width="80" align="center" />
|
|
|
|
|
+ <el-table-column prop="pricePerNight" label="价格(元/天)" width="130" align="right" />
|
|
|
|
|
+ <el-table-column prop="description" label="描述" min-width="150" show-overflow-tooltip />
|
|
|
|
|
+ <el-table-column label="操作" width="300" fixed="right">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-button size="small" type="primary" @click="openEdit(row)">编辑</el-button>
|
|
|
|
|
+ <el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button>
|
|
|
|
|
+ <el-button size="small" @click="openStatus(row)">入住状态</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <el-dialog v-model="createVisible" title="新增房型" width="480px">
|
|
|
|
|
+ <el-form :model="roomForm" label-width="100px">
|
|
|
|
|
+ <el-form-item label="房间名称" required>
|
|
|
|
|
+ <el-input v-model="roomForm.roomName" placeholder="请输入房间名称" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="房型类型">
|
|
|
|
|
+ <el-select v-model="roomForm.roomType" placeholder="请选择房型类型" clearable>
|
|
|
|
|
+ <el-option label="标准间" value="STANDARD" />
|
|
|
|
|
+ <el-option label="豪华间" value="DELUXE" />
|
|
|
|
|
+ <el-option label="VIP" value="VIP" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="容量">
|
|
|
|
|
+ <el-input-number v-model="roomForm.capacity" :min="1" :max="10" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="价格(元/天)" required>
|
|
|
|
|
+ <el-input-number v-model="roomForm.pricePerDay" :min="0" :precision="2" :step="10" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="描述">
|
|
|
|
|
+ <el-input v-model="roomForm.description" type="textarea" :rows="3" placeholder="请输入房间描述" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <el-button @click="createVisible = false">取消</el-button>
|
|
|
|
|
+ <el-button type="primary" :loading="submitting" @click="handleCreate">保存</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <el-dialog v-model="editVisible" title="编辑房型" width="480px">
|
|
|
|
|
+ <el-form :model="editForm" label-width="100px">
|
|
|
|
|
+ <el-form-item label="房间名称" required>
|
|
|
|
|
+ <el-input v-model="editForm.roomName" placeholder="请输入房间名称" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="房型类型">
|
|
|
|
|
+ <el-select v-model="editForm.roomType" placeholder="请选择房型类型" clearable>
|
|
|
|
|
+ <el-option label="标准间" value="STANDARD" />
|
|
|
|
|
+ <el-option label="豪华间" value="DELUXE" />
|
|
|
|
|
+ <el-option label="VIP" value="VIP" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="容量">
|
|
|
|
|
+ <el-input-number v-model="editForm.capacity" :min="1" :max="10" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="价格(元/天)" required>
|
|
|
|
|
+ <el-input-number v-model="editForm.pricePerDay" :min="0" :precision="2" :step="10" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ <el-form-item label="描述">
|
|
|
|
|
+ <el-input v-model="editForm.description" type="textarea" :rows="3" placeholder="请输入房间描述" />
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <el-button @click="editVisible = false">取消</el-button>
|
|
|
|
|
+ <el-button type="primary" :loading="submitting" @click="handleUpdate">保存</el-button>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dialog>
|
|
|
|
|
+
|
|
|
|
|
+ <el-dialog v-model="statusDialogVisible" :title="`入住状态 - ${statusRoomName}`" width="540px">
|
|
|
|
|
+ <div class="status-dialog-body">
|
|
|
|
|
+ <div class="status-toolbar">
|
|
|
|
|
+ <el-date-picker
|
|
|
|
|
+ v-model="statusMonth"
|
|
|
|
|
+ type="month"
|
|
|
|
|
+ placeholder="选择月份"
|
|
|
|
|
+ value-format="YYYY-MM"
|
|
|
|
|
+ @change="fetchStatusForDialog"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <RoomCalendar
|
|
|
|
|
+ v-if="statusRoomId"
|
|
|
|
|
+ :room-id="statusRoomId"
|
|
|
|
|
+ :month="statusMonth"
|
|
|
|
|
+ :status-list="statusList"
|
|
|
|
|
+ @date-click="handleStatusDateClick"
|
|
|
|
|
+ @month-change="onStatusMonthChange"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
-import { ref, onMounted } from 'vue'
|
|
|
|
|
-import { ElMessage } from 'element-plus'
|
|
|
|
|
|
|
+import { reactive, ref, onMounted } from 'vue'
|
|
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
import type { BoardingRoom, RoomStatus } from '@/type'
|
|
import type { BoardingRoom, RoomStatus } from '@/type'
|
|
|
import RoomCalendar from '@/components/RoomCalendar.vue'
|
|
import RoomCalendar from '@/components/RoomCalendar.vue'
|
|
|
-import { getBoardingRoomController } from '@/api/boarding-room-controller'
|
|
|
|
|
import { getAdminBoardingRoomController } from '@/api/admin-boarding-room-controller'
|
|
import { getAdminBoardingRoomController } from '@/api/admin-boarding-room-controller'
|
|
|
-import type { RoomStatusDto } from '@/api/models'
|
|
|
|
|
|
|
+import type { BoardingRoomCreateDto, RoomStatusDto } from '@/api/models'
|
|
|
|
|
|
|
|
const rooms = ref<BoardingRoom[]>([])
|
|
const rooms = ref<BoardingRoom[]>([])
|
|
|
-const selectedRoomId = ref('')
|
|
|
|
|
-const currentMonth = ref(new Date().toISOString().slice(0, 7))
|
|
|
|
|
-const roomStatusList = ref<RoomStatus[]>([])
|
|
|
|
|
|
|
+const loading = ref(false)
|
|
|
|
|
+
|
|
|
|
|
+const roomTypeLabel = (type?: string) => {
|
|
|
|
|
+ const map: Record<string, string> = { STANDARD: '标准间', DELUXE: '豪华间', VIP: 'VIP' }
|
|
|
|
|
+ return map[type ?? ''] || type || '-'
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
const fetchRooms = async () => {
|
|
const fetchRooms = async () => {
|
|
|
|
|
+ loading.value = true
|
|
|
try {
|
|
try {
|
|
|
- const api = getBoardingRoomController()
|
|
|
|
|
- const res = await api.listRooms()
|
|
|
|
|
|
|
+ const api = getAdminBoardingRoomController()
|
|
|
|
|
+ const res = await api.listAll()
|
|
|
if (res.code === 200 && res.data) {
|
|
if (res.code === 200 && res.data) {
|
|
|
rooms.value = res.data.map(r => ({
|
|
rooms.value = res.data.map(r => ({
|
|
|
id: String(r.id ?? ''),
|
|
id: String(r.id ?? ''),
|
|
|
name: r.roomName ?? '',
|
|
name: r.roomName ?? '',
|
|
|
|
|
+ roomType: r.roomType ?? '',
|
|
|
capacity: r.capacity ?? 0,
|
|
capacity: r.capacity ?? 0,
|
|
|
pricePerNight: r.pricePerDay ?? 0,
|
|
pricePerNight: r.pricePerDay ?? 0,
|
|
|
description: r.description
|
|
description: r.description
|
|
@@ -55,16 +137,168 @@ const fetchRooms = async () => {
|
|
|
}
|
|
}
|
|
|
} catch {
|
|
} catch {
|
|
|
// ignore
|
|
// ignore
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// --- Create ---
|
|
|
|
|
+const createVisible = ref(false)
|
|
|
|
|
+const submitting = ref(false)
|
|
|
|
|
+const roomForm = reactive({
|
|
|
|
|
+ roomName: '',
|
|
|
|
|
+ roomType: '',
|
|
|
|
|
+ capacity: 1,
|
|
|
|
|
+ pricePerDay: 0,
|
|
|
|
|
+ description: ''
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const openCreate = () => {
|
|
|
|
|
+ roomForm.roomName = ''
|
|
|
|
|
+ roomForm.roomType = ''
|
|
|
|
|
+ roomForm.capacity = 1
|
|
|
|
|
+ roomForm.pricePerDay = 0
|
|
|
|
|
+ roomForm.description = ''
|
|
|
|
|
+ createVisible.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleCreate = async () => {
|
|
|
|
|
+ if (!roomForm.roomName.trim()) {
|
|
|
|
|
+ ElMessage.warning('请输入房间名称')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (roomForm.pricePerDay <= 0) {
|
|
|
|
|
+ ElMessage.warning('请输入有效的价格')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ submitting.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const api = getAdminBoardingRoomController()
|
|
|
|
|
+ const dto: BoardingRoomCreateDto = {
|
|
|
|
|
+ roomName: roomForm.roomName.trim(),
|
|
|
|
|
+ roomType: roomForm.roomType || undefined,
|
|
|
|
|
+ capacity: roomForm.capacity,
|
|
|
|
|
+ pricePerDay: roomForm.pricePerDay,
|
|
|
|
|
+ description: roomForm.description.trim() || undefined
|
|
|
|
|
+ }
|
|
|
|
|
+ const res = await api.create3(dto)
|
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
|
+ ElMessage.success('新增房型成功')
|
|
|
|
|
+ createVisible.value = false
|
|
|
|
|
+ await fetchRooms()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ElMessage.error(res.message || '新增失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ ElMessage.error(err.message || '新增失败')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ submitting.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// --- Edit ---
|
|
|
|
|
+const editVisible = ref(false)
|
|
|
|
|
+const editForm = reactive({
|
|
|
|
|
+ roomName: '',
|
|
|
|
|
+ roomType: '',
|
|
|
|
|
+ capacity: 1,
|
|
|
|
|
+ pricePerDay: 0,
|
|
|
|
|
+ description: ''
|
|
|
|
|
+})
|
|
|
|
|
+const editingId = ref('')
|
|
|
|
|
+
|
|
|
|
|
+const openEdit = (row: BoardingRoom) => {
|
|
|
|
|
+ editingId.value = row.id
|
|
|
|
|
+ editForm.roomName = row.name
|
|
|
|
|
+ editForm.roomType = row.roomType ?? ''
|
|
|
|
|
+ editForm.capacity = row.capacity
|
|
|
|
|
+ editForm.pricePerDay = row.pricePerNight
|
|
|
|
|
+ editForm.description = row.description ?? ''
|
|
|
|
|
+ editVisible.value = true
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const handleUpdate = async () => {
|
|
|
|
|
+ if (!editForm.roomName.trim()) {
|
|
|
|
|
+ ElMessage.warning('请输入房间名称')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ if (editForm.pricePerDay <= 0) {
|
|
|
|
|
+ ElMessage.warning('请输入有效的价格')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ submitting.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const api = getAdminBoardingRoomController()
|
|
|
|
|
+ const dto: BoardingRoomCreateDto = {
|
|
|
|
|
+ roomName: editForm.roomName.trim(),
|
|
|
|
|
+ roomType: editForm.roomType || undefined,
|
|
|
|
|
+ capacity: editForm.capacity,
|
|
|
|
|
+ pricePerDay: editForm.pricePerDay,
|
|
|
|
|
+ description: editForm.description.trim() || undefined
|
|
|
|
|
+ }
|
|
|
|
|
+ const res = await api.update2(Number(editingId.value), dto)
|
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
|
+ ElMessage.success('编辑房型成功')
|
|
|
|
|
+ editVisible.value = false
|
|
|
|
|
+ await fetchRooms()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ElMessage.error(res.message || '编辑失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ ElMessage.error(err.message || '编辑失败')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ submitting.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// --- Delete ---
|
|
|
|
|
+const handleDelete = async (id: string) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ await ElMessageBox.confirm('确认删除该房型?删除后相关数据将不可恢复。', '确认删除', {
|
|
|
|
|
+ confirmButtonText: '确认',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ type: 'warning'
|
|
|
|
|
+ })
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ const api = getAdminBoardingRoomController()
|
|
|
|
|
+ const res = await api.delete2(Number(id))
|
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
|
+ ElMessage.success('删除成功')
|
|
|
|
|
+ await fetchRooms()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ElMessage.error(res.message || '删除失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (err: any) {
|
|
|
|
|
+ ElMessage.error(err.message || '删除失败')
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const fetchStatus = async () => {
|
|
|
|
|
- if (!selectedRoomId.value || !currentMonth.value) return
|
|
|
|
|
|
|
+// --- Status Dialog ---
|
|
|
|
|
+const statusDialogVisible = ref(false)
|
|
|
|
|
+const statusRoomId = ref('')
|
|
|
|
|
+const statusRoomName = ref('')
|
|
|
|
|
+const statusMonth = ref(new Date().toISOString().slice(0, 7))
|
|
|
|
|
+const statusList = ref<RoomStatus[]>([])
|
|
|
|
|
+
|
|
|
|
|
+const openStatus = (row: BoardingRoom) => {
|
|
|
|
|
+ statusRoomId.value = row.id
|
|
|
|
|
+ statusRoomName.value = row.name
|
|
|
|
|
+ statusMonth.value = new Date().toISOString().slice(0, 7)
|
|
|
|
|
+ statusList.value = []
|
|
|
|
|
+ statusDialogVisible.value = true
|
|
|
|
|
+ fetchStatusForDialog()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const fetchStatusForDialog = async () => {
|
|
|
|
|
+ if (!statusRoomId.value || !statusMonth.value) return
|
|
|
try {
|
|
try {
|
|
|
- const api = getBoardingRoomController()
|
|
|
|
|
- const res = await api.getStatus(Number(selectedRoomId.value), { month: currentMonth.value })
|
|
|
|
|
|
|
+ const api = getAdminBoardingRoomController()
|
|
|
|
|
+ const res = await api.getStatus1(Number(statusRoomId.value), { month: statusMonth.value })
|
|
|
if (res.code === 200 && res.data) {
|
|
if (res.code === 200 && res.data) {
|
|
|
- roomStatusList.value = res.data.map(s => ({
|
|
|
|
|
|
|
+ statusList.value = res.data.map(s => ({
|
|
|
date: s.date ?? '',
|
|
date: s.date ?? '',
|
|
|
status: (s.status === 'AVAILABLE' ? 'AVAILABLE' : 'OCCUPIED') as 'AVAILABLE' | 'OCCUPIED'
|
|
status: (s.status === 'AVAILABLE' ? 'AVAILABLE' : 'OCCUPIED') as 'AVAILABLE' | 'OCCUPIED'
|
|
|
}))
|
|
}))
|
|
@@ -74,15 +308,15 @@ const fetchStatus = async () => {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const handleDateClick = async (date: string, status: 'AVAILABLE' | 'OCCUPIED') => {
|
|
|
|
|
|
|
+const handleStatusDateClick = async (date: string, status: 'AVAILABLE' | 'OCCUPIED') => {
|
|
|
const newStatus = status === 'AVAILABLE' ? 'OCCUPIED' : 'AVAILABLE'
|
|
const newStatus = status === 'AVAILABLE' ? 'OCCUPIED' : 'AVAILABLE'
|
|
|
try {
|
|
try {
|
|
|
const api = getAdminBoardingRoomController()
|
|
const api = getAdminBoardingRoomController()
|
|
|
const dto: RoomStatusDto = { date, status: newStatus }
|
|
const dto: RoomStatusDto = { date, status: newStatus }
|
|
|
- const res = await api.updateStatus1(Number(selectedRoomId.value), dto)
|
|
|
|
|
|
|
+ const res = await api.updateStatus1(Number(statusRoomId.value), dto)
|
|
|
if (res.code === 200) {
|
|
if (res.code === 200) {
|
|
|
ElMessage.success(`已将 ${date} 状态切换为 ${newStatus === 'AVAILABLE' ? '空闲' : '占用'}`)
|
|
ElMessage.success(`已将 ${date} 状态切换为 ${newStatus === 'AVAILABLE' ? '空闲' : '占用'}`)
|
|
|
- await fetchStatus()
|
|
|
|
|
|
|
+ await fetchStatusForDialog()
|
|
|
} else {
|
|
} else {
|
|
|
ElMessage.error(res.message || '操作失败')
|
|
ElMessage.error(res.message || '操作失败')
|
|
|
}
|
|
}
|
|
@@ -91,9 +325,9 @@ const handleDateClick = async (date: string, status: 'AVAILABLE' | 'OCCUPIED') =
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-const onMonthChange = (month: string) => {
|
|
|
|
|
- currentMonth.value = month
|
|
|
|
|
- fetchStatus()
|
|
|
|
|
|
|
+const onStatusMonthChange = (month: string) => {
|
|
|
|
|
+ statusMonth.value = month
|
|
|
|
|
+ fetchStatusForDialog()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
onMounted(fetchRooms)
|
|
onMounted(fetchRooms)
|
|
@@ -104,13 +338,22 @@ onMounted(fetchRooms)
|
|
|
padding: 20px;
|
|
padding: 20px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-h1 {
|
|
|
|
|
|
|
+.header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
margin-bottom: 20px;
|
|
margin-bottom: 20px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.toolbar {
|
|
|
|
|
- display: flex;
|
|
|
|
|
- gap: 16px;
|
|
|
|
|
- margin-bottom: 24px;
|
|
|
|
|
|
|
+h1 {
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.status-dialog-body {
|
|
|
|
|
+ min-height: 300px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.status-toolbar {
|
|
|
|
|
+ margin-bottom: 16px;
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|