share-space-vue/src/views/system/room/room_detail.vue
2025-03-03 15:29:30 +08:00

1113 lines
31 KiB
Vue
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>
<div class="app-container">
<el-card class="box-card" shadow="hover">
<!-- 操作按钮 -->
<div class="operation-buttons">
<el-popover placement="top" trigger="hover">
<div class="qr-code-box">
<qr-code :text="getCodeText(room)" :width="150" :height="150" />
<p>扫描二维码进入房间</p>
</div>
<el-button slot="reference" type="primary" icon="el-icon-picture">查看</el-button>
</el-popover>
<el-button
type="success"
icon="el-icon-unlock"
size="small"
v-if="!isEquipment"
@click="handleOpenDoor"
>开门</el-button>
<el-button
type="primary"
icon="el-icon-unlock"
size="small"
@click="handleSwitchAll(true)"
>全开</el-button>
<el-button
type="warning"
icon="el-icon-lock"
size="small"
@click="handleSwitchAll(false)"
>全关</el-button>
<el-button type="primary" icon="el-icon-edit" size="small" @click="handleUpdate"
v-hasPermi="['system:room:edit']">修改</el-button>
<el-button
type="success"
icon="el-icon-plus"
size="small"
@click="handleBandRule"
v-hasPermi="['system:room:edit']"
>应用套餐</el-button>
</div>
<!-- 基本信息 -->
<div class="room-header">
<el-row :gutter="40">
<el-col :span="6">
<div class="image-wrapper">
<el-carousel
ref="carousel"
height="200px"
indicator-position="outside"
:autoplay="true"
trigger="click"
arrow="always"
>
<el-carousel-item v-for="(url, index) in room.pictures" :key="index">
<el-image
:src="url"
class="carousel-image"
fit="fill"
>
<div slot="error" class="image-slot">
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
</el-carousel-item>
</el-carousel>
</div>
</el-col>
<el-col :span="18">
<div class="room-title">
<h2>{{ room.roomName }}</h2>
<dict-tag :options="dict.type.ss_room_status" :value="room.status"/>
</div>
<div class="room-info">
<el-descriptions :column="4" border size="medium"
:content-style="{ textAlign: 'left', padding: '8px' }"
:label-style="{ textAlign: 'right', padding: '8px', fontWeight: 'bold' }"
class="compact-descriptions"
>
<el-descriptions-item label="所属门店">
<router-link
:to="`/system/storeDetail/index/${room.storeId}`"
class="link-type">
{{ room.storeName }}
</router-link>
</el-descriptions-item>
<el-descriptions-item label="ID">
<span class="info-text">{{ room.roomId }}</span>
</el-descriptions-item>
<el-descriptions-item label="商户">
<router-link
:to="`/user/detail/${room.merchantId}`"
class="link-type">
{{ room.merchantName }}
</router-link>
</el-descriptions-item>
<el-descriptions-item label="类型">
<div class="type-tags">
<dict-tag :options="dict.type.ss_room_type" :value="room.type" />
<dict-tag :options="dict.type.ss_room_type2" :value="room.type2" />
</div>
</el-descriptions-item>
<el-descriptions-item label="标签" :span="2">
<div class="tags-container">
<dict-tag
v-for="tag in room.tags"
:key="tag"
:options="dict.type.ss_room_tags"
:value="tag"
/>
</div>
</el-descriptions-item>
<el-descriptions-item label="WiFi名称" :span="2">
<span class="info-text" v-if="room.wifi">
{{ room.wifi }}({{ room.wifiPassword }})
</span>
<span class="info-text" v-else>
--
</span>
</el-descriptions-item>
<el-descriptions-item label="总营收" :span="2">
<span class="info-text red">{{ room.totalIncome || '0' }}元</span>
</el-descriptions-item>
<el-descriptions-item label="总订单数">
<span class="info-text">{{ room.soldNum || '0' }}</span>
</el-descriptions-item>
</el-descriptions>
</div>
</el-col>
</el-row>
</div>
<!-- &lt;!&ndash; WiFi信息 &ndash;&gt;-->
<!-- <div class="section-block">-->
<!-- <h3>-->
<!-- <i class="el-icon-connection"></i>-->
<!-- WiFi信息-->
<!-- </h3>-->
<!-- -->
<!-- </div>-->
<!-- &lt;!&ndash; 系统信息 &ndash;&gt;-->
<!-- <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="800px" 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="isEquipment?'设施码':'房间码'" prop="code">
<el-input
v-model="form.code"
placeholder="请输入房间码"
style="width: calc(100% - 70px); margin-right: 10px;"
/>
<el-button type="success" @click="generateAndSetCode(isEquipment?'3':'2')">生成</el-button>
</el-form-item>
<el-form-item label="图片" prop="picture">
<image-upload
v-model="form.picture"
:value="form.picture || (Array.isArray(form.pictures) ? form.pictures.join(',') : '')"
:limit="5"
:fileSize="5"
:fileType="['png', 'jpg', 'jpeg']"
tip="建议尺寸750px * 750px大小不超过5M"
@input="val => {
form.picture = val;
form.pictures = val ? val.split(',').filter(Boolean) : [];
}"
/>
</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-item label="套餐" prop="ruleIds">-->
<!-- <el-select-->
<!-- v-model="form.ruleIds"-->
<!-- multiple-->
<!-- filterable-->
<!-- placeholder="请选择套餐"-->
<!-- style="width: 100%"-->
<!-- >-->
<!-- <el-option-->
<!-- v-for="item in ruleOptions"-->
<!-- :key="item.ruleId"-->
<!-- :label="item.name"-->
<!-- :value="item.ruleId"-->
<!-- />-->
<!-- </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" :lazy="true">
<order v-if="room.roomId != null"
:query="{
roomId: room.roomId,
storeId: Number(room.storeId),
merchantId: room.merchantId
}" />
</el-tab-pane>
<el-tab-pane label="套餐列表" name="rules" :lazy="true">
<rule :query="{
roomId: room.roomId,
storeId: Number(room.storeId),
merchantId: room.merchantId
}" />
</el-tab-pane>
<el-tab-pane v-if="!isEquipment" label="设施列表" name="equipments" :lazy="true">
<equipment :query="{
roomId: room.roomId,
storeId: Number(room.storeId),
merchantId: room.merchantId
}" />
</el-tab-pane>
<el-tab-pane label="设备列表" name="devices" :lazy="true">
<device :query="{
roomId: room.roomId,
storeId: Number(room.storeId),
userId: room.merchantId
}" />
</el-tab-pane>
</el-tabs>
<!-- 套餐选择弹窗 -->
<el-dialog
title="选择套餐"
:visible.sync="ruleDialogVisible"
width="800px"
append-to-body
@opened="handleRuleDialogOpen"
>
<div class="dialog-content">
<el-form :model="ruleQuery" ref="ruleQuery" :inline="true" class="search-form">
<el-form-item label="套餐名称" prop="explain">
<el-input v-model="ruleQuery.explain" placeholder="请输入套餐名称" clearable size="small" @change="handleRuleQuery" />
</el-form-item>
<el-form-item label="收费模式" prop="mode">
<el-select v-model="ruleQuery.mode" placeholder="请选择收费模式" @change="handleRuleQuery" clearable size="small">
<el-option
v-for="dict in dict.type.ss_fee_rule_mode"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleRuleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetRuleQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table
ref="ruleTable"
v-loading="ruleLoading"
:data="ruleList"
height="400"
@selection-change="handleRuleSelectionChange"
highlight-current-row
style="width: 100%"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="套餐名称" prop="explain" />
<el-table-column label="收费模式" prop="mode" align="center">
<template slot-scope="{row}">
<dict-tag :options="dict.type.ss_fee_rule_mode" :value="row.mode" />
</template>
</el-table-column>
<el-table-column label="小时" prop="hours" align="center">
<template slot-scope="{row}">
{{ row.hours !== null && row.hours !== undefined ? row.hours + ' 小时' : '--' }}
</template>
</el-table-column>
<el-table-column label="单价" prop="price" align="center">
<template slot-scope="{row}">
{{ row.price !== null && row.price !== undefined ? row.price + ' 元' : '--' }}
</template>
</el-table-column>
</el-table>
<pagination
v-show="ruleTotal > 0"
:total="ruleTotal"
:page.sync="ruleQuery.pageNum"
:limit.sync="ruleQuery.pageSize"
@pagination="loadRuleList"
/>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="confirmSelectRule" :loading="bandLoading"> </el-button>
<el-button @click="ruleDialogVisible = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {bandRules, getRoom, updateRoom, bandRule, openRoomGate, switchAllDevices} 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'
import { listRule } from "@/api/system/rule"
import room from "@/views/system/room/index.vue";
import QrCode from '@/components/QrCode'
import { getDomain } from "@/api/common/common";
import Log from "@/views/system/commandLog/index.vue";
import { deviceSwitch } from "@/api/system/device";
import {generateCode} from "@/utils/ruoyi";
export default {
name: 'RoomDetail',
dicts: ['ss_room_type', 'ss_room_type2', 'ss_room_tags','ss_fee_rule_mode','ss_room_status'],
components: {Log, room, order, device, rule, equipment, QrCode },
data() {
return {
domain: '', // 域名
// 是否显示弹出层
open: false,
// 弹出层标题
title: "",
room: {
feeRules: []
},
// 标签字典
roomTagOptions: [],
// 店铺选项
storeOptions: [],
ruleOptions: [],
// 表单参数
form: {
roomId: undefined,
roomName: undefined,
storeId: undefined,
type: undefined,
picture: undefined,
pictures: [],
tags: []
},
// 表单校验
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',
// 套餐选择相关
ruleDialogVisible: false,
ruleLoading: false,
bandLoading: false,
ruleList: [],
ruleTotal: 0,
selectedRules: [],
ruleQuery: {
pageNum: 1,
pageSize: 10,
merchantId: null,
explain: undefined,
mode: undefined
},
}
},
computed: {
isEquipment() {
return this.$route.query.type === 'equipment';
}
},
created() {
this.handleRuleQuery()
this.getDetail()
this.getDictData()
this.getStoreOptions()
this.getDomain2()
},
methods: {
generateAndSetCode(type) {
this.form.code = generateCode(type);
},
handleRuleQuery() {
this.ruleQuery.pageNum = 1;
this.loadRuleList();
},
/** 获取房间详情 */
async getDetail() {
try {
const roomId = this.$route.params.roomId
const response = await getRoom(roomId)
this.room = response.data
console.log('房间详情数据:', this.room)
// 确保 billingMode 是数组
if (!Array.isArray(this.room.billingMode)) {
this.room.billingMode = this.room.billingMode ? [this.room.billingMode] : ['1'];
}
// 处理图片回显
if (Array.isArray(this.room.pictures) && this.room.pictures.length > 0) {
this.room.picture = this.room.pictures.join(',');
} else {
this.room.picture = '';
this.room.pictures = [];
}
// this.handleRuleQuery();
//
// // 获取套餐列表并设置选中状态
// listRule({ pageSize: 999, merchantId: this.room.merchantId }).then(response => {
// const ruleList = response.rows;
// // console.log('获取到的套餐列表:', ruleList)
// // console.log('房间已选套餐IDs:', this.room.ruleIds)
// // 根据 ruleIds 找到对应的完整套餐数据
// this.selectedRules = ruleList.filter(rule =>
// this.room.ruleIds && this.room.ruleIds.includes(rule.ruleId)
// );
// console.log('初始化选中的套餐:', this.selectedRules)
// if (this.selectedRules) {
// this.selectedRules.forEach(row => {
// this.$refs.ruleTable.toggleRowSelection(row,true);
// });
// }
// });
} catch (error) {
console.error('获取房间/设施详情失败:', error)
this.$message.error('获取房间/设施详情失败')
}
},
/** 获取字典数据 */
async getDictData() {
try {
const [typeRes, type2Res, tagRes] = await Promise.all([
getDicts('ss_room_type'),
getDicts('ss_room_type2'),
getDicts('ss_room_tags')
])
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;
});
},
loadRuleOptions() {
listRule({ pageSize: 999 ,roomId: this.room.roomId}).then(response => {
this.ruleOptions = response.rows;
});
},
/** 获取标签名称 */
getTagName(tag) {
const found = this.roomTagOptions.find(item => item.dictValue === tag)
return found ? found.dictLabel : tag
},
/** 修改按钮操作 */
handleUpdate() {
this.open = true;
this.title = "修改" + (this.isEquipment ? "设施" : "房间");
this.form = {
...this.room,
pictures: this.room.pictures || []
};
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
roomId: undefined,
roomName: undefined,
storeId: undefined,
type: undefined,
picture: undefined,
pictures: [],
tags: []
};
this.resetForm("form");
},
resetRuleQuery() {
this.ruleQuery = {
pageNum: 1,
pageSize: 10,
merchantId: this.room.merchantId,
explain: undefined,
mode: undefined
};
this.loadRuleList();
},
/** 表单提交 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
// 如果是设施且修改了开锁方式,先发送开关命令
if (this.isEquipment &&
this.form.deviceId &&
this.form.unlockMode !== this.room.unlockMode) {
// 通电开锁(1)时发送断电命令(false),断电开锁(2)时发送通电命令(true)
const open = this.form.unlockMode === "2";
deviceSwitch({
deviceId: this.form.deviceId,
open: open
}).then(() => {
// 开关命令成功后,保存配置
this.saveForm();
}).catch(() => {
this.$modal.msgError("设备开关操作失败");
});
} else {
// 不需要发送开关命令,直接保存
this.saveForm();
}
}
});
},
/** 保存表单 */
saveForm() {
let data = {
...this.form
};
updateRoom(data).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getDetail();
});
},
/** 获取状态对应的类型 */
getStatusType(status) {
const statusMap = {
'1': 'success', // 空闲中
'2': 'warning', // 打扫中
'3': 'info' // 离线
};
return statusMap[status] || 'info';
},
/** 获取状态文本 */
getStatusText(status) {
const statusMap = {
'1': '空闲中',
'2': '未打扫',
'3': '使用中',
'4': '打扫中',
'8': '下架'
};
return statusMap[status] || '未知状态';
},
/** 打开套餐选择弹窗 */
handleBandRule: function () {
this.ruleDialogVisible = true;
// 等待弹窗和表格渲染完成后再设置选中状态
this.$nextTick(() => {
// 获取套餐列表
listRule({ pageSize: 999, mode: 2, merchantId: this.room.merchantId }).then(response => {
this.ruleList = response.rows;
// 找到需要选中的行
const selectedRules = this.ruleList.filter(rule =>
this.room.ruleIds && this.room.ruleIds.includes(rule.ruleId)
);
// 确保表格组件已经挂载
if (this.$refs.ruleTable) {
this.toggleSelection(selectedRules);
}
});
});
},
/** 加载套餐列表 */
loadRuleList() {
if(this.ruleQuery.merchantId){
this.ruleLoading = true;
listRule(this.ruleQuery).then(response => {
this.ruleList = response.rows;
this.ruleTotal = response.total;
this.ruleLoading = false;
}).catch(() => {
this.ruleLoading = false;
});
}
},
/** 选择套餐 */
handleRuleSelect(row) {
this.selectedRules = [row];
},
/** 确认应用套餐 */
confirmBandRule() {
if (this.selectedRules.length === 0) {
this.$modal.msgError("请选择要应用的套餐");
return;
}
this.bandLoading = true;
bandRule({
ruleIds: this.selectedRules.map(rule => rule.ruleId),
roomId: this.room.roomId
}).then(() => {
this.$modal.msgSuccess("套餐应用成功");
this.ruleDialogVisible = false;
this.getDetail(); // 刷新详情
}).finally(() => {
this.bandLoading = false;
});
},
handleRuleDialogOpen() {
this.ruleQuery.merchantId = this.room.merchantId;
this.loadRuleList();
},
toggleSelection(rows) {
// 确保表格组件存在
if (!this.$refs.ruleTable) {
console.warn('表格组件未初始化');
return;
}
// 先清除所有选择
this.$refs.ruleTable.clearSelection();
// 如果有需要选中的行,则选中它们
if (rows && rows.length > 0) {
rows.forEach(row => {
this.$refs.ruleTable.toggleRowSelection(row, true);
});
}
},
handleRuleSelectionChange(selection) {
this.selectedRules = selection;
},
confirmSelectRule() {
if (this.selectedRules.length === 0) {
this.$message.warning('请选择套餐');
return;
}
console.log('确认选择的套餐:', this.selectedRules)
this.bandLoading = true;
bandRules({
ruleIds: this.selectedRules.map(rule => rule.ruleId),
roomId: this.room.roomId
}).then(() => {
this.$modal.msgSuccess("套餐应用成功");
this.ruleDialogVisible = false;
this.getDetail(); // 刷新详情
}).finally(() => {
this.bandLoading = false;
});
},
// 获取域名
getDomain2() {
getDomain().then(response => {
if (response.data) {
this.domain = response.data;
}
}).catch(() => {
this.$message.error("获取全局域名失败")
})
},
// 获取二维码文本
getCodeText(room) {
let url = this.domain + `?f=` + room.qrText;
return this.domain ? url : '';
},
/** 开门按钮操作 */
handleOpenDoor() {
this.$modal.confirm('是否确认为"' + this.room.roomName + '"开门?').then(() => {
return openRoomGate(this.room.roomId);
}).then(() => {
this.$modal.msgSuccess("开门成功");
}).catch(() => {});
},
/** 全开/全关按钮操作 */
handleSwitchAll(open) {
const actionText = open ? '打开' : '关闭';
this.$modal.confirm(`是否确认${actionText}房间"${this.room.roomName}"的所有设备?`).then(() => {
return switchAllDevices(this.room.roomId, open);
}).then(() => {
this.$modal.msgSuccess(`${actionText}成功`);
}).catch(() => {});
},
}
}
</script>
<style lang="scss" scoped>
.app-container {
padding: 24px;
background-color: #f5f7fa;
min-height: calc(100vh - 84px);
}
.operation-buttons {
display: flex;
flex-wrap: wrap;
gap: 5px;
justify-content: flex-end;
margin-bottom: 20px;
text-align: right;
.el-button {
margin: 0;
padding: 10px 10px;
}
}
.box-card {
border-radius: 12px;
padding: 0px 24px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
&:hover {
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.1);
}
}
.room-header {
margin-bottom: -40px;
}
.image-wrapper {
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
:deep(.el-carousel) {
.el-carousel__indicators {
bottom: -20px;
}
.el-carousel__arrow {
background-color: rgba(0, 0, 0, 0.3);
&:hover {
background-color: rgba(0, 0, 0, 0.5);
}
}
.el-carousel__item {
background-color: #f5f7fa;
overflow: hidden;
.carousel-image {
width: 100%;
height: 100%;
display: block;
:deep(.el-image__inner) {
width: 100%;
height: 100%;
object-fit: cover;
}
.image-slot {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #f5f7fa;
color: #909399;
font-size: 30px;
}
}
}
}
&:hover {
transform: translateY(-5px);
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
}
}
.room-title {
display: flex;
align-items: center;
margin-bottom: 28px;
padding-bottom: 16px;
border-bottom: 1px solid #EBEEF5;
h2 {
margin: 0;
margin-right: 15px;
font-size: 28px;
color: #303133;
font-weight: 600;
}
.status-tag {
padding: 0 12px;
height: 24px;
line-height: 24px;
font-size: 12px;
}
}
.room-info {
margin-top: 20px;
}
.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;
h3 {
margin: 0;
font-size: 20px;
font-weight: 600;
color: #303133;
display: flex;
align-items: center;
i {
margin-right: 12px;
font-size: 24px;
color: #409EFF;
}
}
}
.price {
color: #F56C6C;
font-weight: 600;
font-size: 16px;
}
.unit {
color: #909399;
margin-left: 4px;
font-size: 14px;
}
:deep(.el-descriptions) {
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
.el-descriptions__label {
font-weight: 500;
color: #606266;
min-width: 90px;
}
.el-descriptions__content {
padding: 16px;
}
.el-descriptions__body {
background-color: #fff;
}
.el-descriptions-item__label {
background-color: #f5f7fa;
font-weight: 500;
}
.el-descriptions-item__content {
display: flex;
align-items: center;
}
}
.detail-tabs {
margin-top: 20px;
.search-form {
margin-bottom: 20px;
.el-form-item {
margin-bottom: 10px;
}
}
}
// 标签选择器样式
.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%;
}
}
.type-tags {
display: flex;
gap: 5px;
flex-wrap: wrap;
}
.tag-item {
margin-right: 5px;
}
.el-descriptions-item {
.el-tag {
margin: 2px;
}
}
.link-type {
color: #11A983;
text-decoration: none;
&:hover {
color: #11A98330;
text-decoration: underline;
}
}
.dialog-content {
padding: 0 20px;
.el-table {
margin: 15px 0;
.el-table__row {
cursor: pointer;
&.current-row {
background-color: #f0f9eb;
}
}
}
}
.tags-container {
display: flex;
align-items: center;
gap: 4px;
:deep(.el-tag) {
margin: 0;
height: 22px;
line-height: 20px;
padding: 0 8px;
}
}
.qr-code-box {
text-align: center;
padding: 10px;
p {
margin: 10px 0 0;
color: #666;
font-size: 14px;
}
}
/* 紧凑布局 */
.compact-descriptions {
margin: 0;
padding: 0;
}
.compact-descriptions ::v-deep .el-descriptions-item__label {
text-align: right;
padding-right: 12px;
font-weight: bold;
}
.compact-descriptions ::v-deep .el-descriptions-item__content {
text-align: left;
padding-left: 12px;
}
.red{
color: red;
font-weight: bold;
}
</style>