566 lines
14 KiB
Vue
566 lines
14 KiB
Vue
<template>
|
|
<div class="app-container">
|
|
<el-card class="box-card" shadow="hover">
|
|
<!-- 操作按钮 -->
|
|
<div class="operation-buttons">
|
|
<el-button type="primary" icon="el-icon-edit" size="small" @click="handleUpdate"
|
|
v-hasPermi="['system:room:edit']">修改房间</el-button>
|
|
</div>
|
|
|
|
<!-- 房间基本信息 -->
|
|
<div class="room-header">
|
|
<el-row :gutter="40">
|
|
<el-col :span="8">
|
|
<div class="image-wrapper">
|
|
<el-image :src="room.picture" fit="cover" class="room-image">
|
|
<div slot="error" class="image-slot">
|
|
<i class="el-icon-picture-outline"></i>
|
|
</div>
|
|
</el-image>
|
|
</div>
|
|
</el-col>
|
|
<el-col :span="16">
|
|
<div class="room-title">
|
|
<h2>{{ room.roomName }}</h2>
|
|
<el-tag :type="room.status === '1' ? 'success' : 'info'" class="status-tag" effect="dark">
|
|
{{ room.status === '1' ? '正常' : '停用' }}
|
|
</el-tag>
|
|
</div>
|
|
<div class="room-info">
|
|
<el-descriptions :column="2" border size="medium">
|
|
<el-descriptions-item label="所属门店">
|
|
<span class="info-text">{{ room.storeName }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="商户ID">
|
|
<span class="info-text">{{ room.merchantId }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="房间ID">
|
|
<span class="info-text">{{ room.roomId }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="房间类型">
|
|
<span class="info-text">{{ getRoomType(room.type) }} / {{ getRoomType2(room.type2) }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="基础价格">
|
|
<span class="price">¥{{ room.hour }}</span>
|
|
<span class="unit">/小时</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="销售数量">
|
|
<span class="info-text">{{ room.soldNum || '暂无数据' }}</span>
|
|
</el-descriptions-item>
|
|
</el-descriptions>
|
|
|
|
<div class="tags-section">
|
|
<span class="label">房间标签:</span>
|
|
<div class="tags-wrapper">
|
|
<dict-tag v-for="tag in room.tags" :key="tag" :options="dict.type.ss_room_tags" :value="tag"
|
|
class="tag-item" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</el-col>
|
|
</el-row>
|
|
</div>
|
|
|
|
|
|
|
|
<!-- WiFi信息 -->
|
|
<div v-if="room.wifi" class="section-block">
|
|
<h3>
|
|
<i class="el-icon-connection"></i>
|
|
WiFi信息
|
|
</h3>
|
|
<el-descriptions :column="2" border size="medium">
|
|
<el-descriptions-item label="WiFi名称">
|
|
<span class="info-text">{{ room.wifi }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="WiFi密码">
|
|
<span class="info-text">{{ room.wifiPassword }}</span>
|
|
</el-descriptions-item>
|
|
</el-descriptions>
|
|
</div>
|
|
|
|
<!-- 系统信息 -->
|
|
<div class="section-block">
|
|
<h3>
|
|
<i class="el-icon-info"></i>
|
|
系统信息
|
|
</h3>
|
|
<el-descriptions :column="3" border size="medium">
|
|
<el-descriptions-item label="创建人">
|
|
<span class="info-text">{{ room.createBy || '暂无' }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="创建时间">
|
|
<span class="info-text">{{ room.createTime || '暂无' }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="更新人">
|
|
<span class="info-text">{{ room.updateBy || '暂无' }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="更新时间">
|
|
<span class="info-text">{{ room.updateTime || '暂无' }}</span>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="备注" :span="2">
|
|
<span class="info-text">{{ room.remark || '暂无' }}</span>
|
|
</el-descriptions-item>
|
|
</el-descriptions>
|
|
</div>
|
|
</el-card>
|
|
|
|
<!-- 修改房间弹窗 -->
|
|
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
|
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
|
<el-form-item label="房间名" prop="roomName">
|
|
<el-input v-model="form.roomName" placeholder="请输入房间名" />
|
|
</el-form-item>
|
|
<el-form-item label="店铺" prop="storeId">
|
|
<el-select v-model="form.storeId" clearable filterable placeholder="请选择">
|
|
<el-option v-for="item in storeOptions" :key="item.storeId" :label="item.name" :value="item.storeId" />
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="类型" prop="type">
|
|
<el-select v-model="form.type" placeholder="请选择类型">
|
|
<el-option v-for="dict in dict.type.ss_room_type" :key="dict.value" :label="dict.label"
|
|
:value="dict.value"></el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="图片" prop="picture">
|
|
<image-upload v-model="form.picture" />
|
|
</el-form-item>
|
|
<el-form-item label="标签" prop="tags">
|
|
<el-select v-model="form.tags" placeholder="请选择标签" clearable multiple style="width: auto; min-width: 240px">
|
|
<el-option v-for="dict in dict.type.ss_room_tags" :key="dict.value" :label="dict.label"
|
|
:value="dict.value" />
|
|
</el-select>
|
|
</el-form-item>
|
|
</el-form>
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button type="primary" @click="submitForm">确 定</el-button>
|
|
<el-button @click="cancel">取 消</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
<el-tabs v-model="activeTab" class="detail-tabs">
|
|
|
|
<el-tab-pane label="订单列表" name="orders">
|
|
<order :roomId="room.roomId"></order>
|
|
</el-tab-pane>
|
|
|
|
<el-tab-pane label="设备列表" name="devices">
|
|
<device :roomId="room.roomId"></device>
|
|
</el-tab-pane>
|
|
<el-tab-pane label="套餐列表" name="rules">
|
|
<rule :roomId="room.roomId"></rule>
|
|
</el-tab-pane>
|
|
<el-tab-pane label="设施列表" name="equipments">
|
|
<equipment :roomId="room.roomId"></equipment>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { getRoom, updateRoom } from '@/api/system/room'
|
|
import { getDicts } from '@/api/system/dict/data'
|
|
import { listStore } from "@/api/system/store"
|
|
import order from '@/views/system/order/index.vue'
|
|
import device from '@/views/system/device/index.vue'
|
|
import rule from '@/views/system/rule/index.vue'
|
|
import equipment from '@/views/system/equipment/index.vue'
|
|
export default {
|
|
name: 'RoomDetail',
|
|
dicts: ['ss_room_type', 'ss_room_tags', 'ss_room_status'],
|
|
components: { order, device, rule, equipment },
|
|
data() {
|
|
return {
|
|
// 是否显示弹出层
|
|
open: false,
|
|
// 弹出层标题
|
|
title: "",
|
|
room: {},
|
|
// 房间类型字典
|
|
roomTypeOptions: [],
|
|
// 房间类型2字典
|
|
roomType2Options: [],
|
|
// 房间标签字典
|
|
roomTagOptions: [],
|
|
// 店铺选项
|
|
storeOptions: [],
|
|
// 表单参数
|
|
form: {},
|
|
// 表单校验
|
|
rules: {
|
|
roomName: [
|
|
{ required: true, message: "房间名不能为空", trigger: "blur" }
|
|
],
|
|
storeId: [
|
|
{ required: true, message: "店铺不能为空", trigger: "blur" }
|
|
],
|
|
type: [
|
|
{ required: true, message: "类型不能为空", trigger: "blur" }
|
|
],
|
|
tags: [
|
|
{ required: true, message: "标签不能为空", trigger: "change" }
|
|
],
|
|
},
|
|
activeTab: 'orders',
|
|
}
|
|
},
|
|
|
|
created() {
|
|
this.getDetail()
|
|
this.getDictData()
|
|
this.getStoreOptions()
|
|
},
|
|
|
|
methods: {
|
|
/** 获取房间详情 */
|
|
async getDetail() {
|
|
try {
|
|
const roomId = this.$route.params.roomId
|
|
const response = await getRoom(roomId)
|
|
this.room = response.data
|
|
} catch (error) {
|
|
console.error('获取房间详情失败:', error)
|
|
this.$message.error('获取房间详情失败')
|
|
}
|
|
},
|
|
|
|
/** 获取字典数据 */
|
|
async getDictData() {
|
|
try {
|
|
const [typeRes, type2Res, tagRes] = await Promise.all([
|
|
getDicts('room_type'),
|
|
getDicts('room_type2'),
|
|
getDicts('room_tag')
|
|
])
|
|
this.roomTypeOptions = typeRes.data
|
|
this.roomType2Options = type2Res.data
|
|
this.roomTagOptions = tagRes.data
|
|
} catch (error) {
|
|
console.error('获取字典数据失败:', error)
|
|
this.$message.error('获取字典数据失败')
|
|
}
|
|
},
|
|
|
|
/** 获取店铺选项 */
|
|
getStoreOptions() {
|
|
listStore({ pageNum: 1, pageSize: 999 }).then(response => {
|
|
this.storeOptions = response.rows;
|
|
});
|
|
},
|
|
|
|
/** 获取房间类型名称 */
|
|
getRoomType(type) {
|
|
const found = this.roomTypeOptions.find(item => item.dictValue === type)
|
|
return found ? found.dictLabel : type
|
|
},
|
|
|
|
/** 获取房间类型2名称 */
|
|
getRoomType2(type) {
|
|
const found = this.roomType2Options.find(item => item.dictValue === type)
|
|
return found ? found.dictLabel : type
|
|
},
|
|
|
|
/** 获取标签名称 */
|
|
getTagName(tag) {
|
|
const found = this.roomTagOptions.find(item => item.dictValue === tag)
|
|
return found ? found.dictLabel : tag
|
|
},
|
|
|
|
/** 修改按钮操作 */
|
|
handleUpdate() {
|
|
this.reset();
|
|
this.form = { ...this.room };
|
|
this.open = true;
|
|
this.title = "修改房间";
|
|
},
|
|
|
|
// 取消按钮
|
|
cancel() {
|
|
this.open = false;
|
|
this.reset();
|
|
},
|
|
|
|
// 表单重置
|
|
reset() {
|
|
this.form = {
|
|
roomId: undefined,
|
|
roomName: undefined,
|
|
storeId: undefined,
|
|
type: undefined,
|
|
picture: undefined,
|
|
tags: []
|
|
};
|
|
this.resetForm("form");
|
|
},
|
|
|
|
/** 提交按钮 */
|
|
submitForm() {
|
|
this.$refs["form"].validate(valid => {
|
|
if (valid) {
|
|
updateRoom(this.form).then(response => {
|
|
this.$modal.msgSuccess("修改成功");
|
|
this.open = false;
|
|
this.getDetail();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.detail-tabs {
|
|
margin-top: 20px;
|
|
|
|
.search-form {
|
|
margin-bottom: 20px;
|
|
|
|
.el-form-item {
|
|
margin-bottom: 10px;
|
|
}
|
|
}
|
|
}
|
|
.app-container {
|
|
padding: 24px;
|
|
background-color: #f5f7fa;
|
|
min-height: calc(100vh - 84px);
|
|
}
|
|
|
|
.operation-buttons {
|
|
margin-bottom: 20px;
|
|
text-align: right;
|
|
}
|
|
|
|
.box-card {
|
|
border-radius: 12px;
|
|
padding: 24px;
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.box-card:hover {
|
|
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.room-header {
|
|
margin-bottom: 48px;
|
|
}
|
|
|
|
.image-wrapper {
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
transition: all 0.3s ease;
|
|
position: relative;
|
|
}
|
|
|
|
.image-wrapper:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
.room-image {
|
|
width: 100%;
|
|
height: 320px;
|
|
border-radius: 12px;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.room-title {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 28px;
|
|
padding-bottom: 16px;
|
|
border-bottom: 1px solid #EBEEF5;
|
|
}
|
|
|
|
.room-title h2 {
|
|
margin: 0;
|
|
margin-right: 15px;
|
|
font-size: 28px;
|
|
color: #303133;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.status-tag {
|
|
margin-left: auto;
|
|
padding: 0 16px;
|
|
height: 28px;
|
|
line-height: 28px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.room-info {
|
|
margin-top: 28px;
|
|
}
|
|
|
|
.info-text {
|
|
color: #606266;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.tags-section {
|
|
margin-top: 28px;
|
|
padding: 16px;
|
|
background: #f9fafc;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.tags-wrapper {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
.label {
|
|
color: #606266;
|
|
margin-right: 16px;
|
|
font-weight: 500;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.tag-item {
|
|
margin-right: 10px;
|
|
margin-bottom: 8px;
|
|
border-radius: 4px;
|
|
padding: 0 12px;
|
|
height: 28px;
|
|
line-height: 26px;
|
|
}
|
|
|
|
.section-block {
|
|
margin-top: 48px;
|
|
padding-top: 32px;
|
|
border-top: 1px solid #EBEEF5;
|
|
}
|
|
|
|
.section-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 28px;
|
|
}
|
|
|
|
h3 {
|
|
margin: 0;
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: #303133;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
h3 i {
|
|
margin-right: 12px;
|
|
font-size: 24px;
|
|
color: #409EFF;
|
|
}
|
|
|
|
.total-rules {
|
|
margin-top: 3px;
|
|
}
|
|
|
|
.price {
|
|
color: #F56C6C;
|
|
font-weight: 600;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.unit {
|
|
color: #909399;
|
|
margin-left: 4px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.image-slot {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #f5f7fa;
|
|
}
|
|
|
|
.image-slot i {
|
|
font-size: 48px;
|
|
color: #909399;
|
|
}
|
|
|
|
.custom-table {
|
|
margin-top: 16px;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
:deep(.el-descriptions) {
|
|
padding: 20px;
|
|
background-color: #fff;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
:deep(.el-descriptions__label) {
|
|
font-weight: 500;
|
|
color: #606266;
|
|
}
|
|
|
|
:deep(.el-descriptions__content) {
|
|
padding: 12px 16px;
|
|
}
|
|
|
|
:deep(.el-table th) {
|
|
background-color: #f5f7fa !important;
|
|
font-weight: 500;
|
|
}
|
|
|
|
:deep(.el-table--border) {
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
:deep(.el-descriptions__body) {
|
|
background-color: #fff;
|
|
}
|
|
|
|
:deep(.el-descriptions-item__label) {
|
|
background-color: #f5f7fa;
|
|
font-weight: 500;
|
|
}
|
|
|
|
// 标签选择器样式
|
|
.el-select {
|
|
:deep(.el-select__tags) {
|
|
flex-wrap: wrap;
|
|
|
|
.el-tag {
|
|
margin: 2px;
|
|
max-width: none;
|
|
}
|
|
}
|
|
|
|
:deep(.el-input__inner) {
|
|
height: auto;
|
|
min-height: 32px;
|
|
padding-top: 4px;
|
|
padding-bottom: 4px;
|
|
}
|
|
}
|
|
|
|
.el-select-dropdown__item {
|
|
padding: 0 10px;
|
|
height: 32px;
|
|
line-height: 32px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.el-form-item {
|
|
margin-bottom: 18px;
|
|
|
|
.el-select {
|
|
width: auto;
|
|
min-width: 240px;
|
|
max-width: 100%;
|
|
}
|
|
}
|
|
</style> |