|
|
@@ -1,103 +1,78 @@
|
|
|
<template>
|
|
|
- <div class="live-config-container">
|
|
|
- <el-card class="box-card live-config-header">
|
|
|
- <div class="detail-header">
|
|
|
- <div class="header-left-area">
|
|
|
- <img :src="liveInfo.liveImgUrl" alt="直播封面">
|
|
|
- <!-- 加载遮罩 -->
|
|
|
- <div class="ss-loading-mask" style="display: none;">
|
|
|
- <div class="ss-loading-spinner is-module-loading">
|
|
|
- <div class="ss-loading-dot-flashing"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <div class="live-config-page">
|
|
|
+ <!-- 顶部直播信息 -->
|
|
|
+ <div class="live-hero">
|
|
|
+ <div class="hero-cover">
|
|
|
+ <img v-if="liveInfo.liveImgUrl" :src="liveInfo.liveImgUrl" alt="直播封面">
|
|
|
+ <div v-else class="cover-placeholder">
|
|
|
+ <i class="el-icon-video-camera"></i>
|
|
|
</div>
|
|
|
+ <span class="status-badge" :class="statusClass">{{ statusText }}</span>
|
|
|
+ </div>
|
|
|
|
|
|
- <div class="header-middle-area">
|
|
|
- <div class="live-info-title">
|
|
|
- <div class="title-text">{{ liveInfo.liveName }}</div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="live-info-desc">
|
|
|
- <div class="live-type">{{ liveInfo.liveType == 1 ? '视频直播' : '录播' }}</div>
|
|
|
- <div class="line"></div>
|
|
|
- <div class="live-mode">{{ liveInfo.showType == 1 ? '横屏' : '竖屏' }}</div>
|
|
|
- <div class="big-screen-info">
|
|
|
- <div class="dataLarge">
|
|
|
- <a class="dataLarge__screen ss-popover__reference" aria-describedby="ss-popover-7614" tabindex="0" data-auth-id="818">
|
|
|
- <span class="dataLarge__screen__icon"></span>
|
|
|
- <span class="dataLarge__screen__txt">实时大屏</span>
|
|
|
- </a>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="live-info-state">
|
|
|
- <div class="info-state-text live-time">直播时间:{{ liveInfo.startTime }} 至 {{ liveInfo.finishTime }}</div>
|
|
|
- <div class="line"></div>
|
|
|
- <div class="info-state-text live-state">{{ liveInfo.status == 3 ? '已结束' : liveInfo.status == 2 ? '直播中' : '未开始'}}</div>
|
|
|
- <div class="line"></div>
|
|
|
- <div class="info-state-text live-active-state">{{ liveInfo.isShow == 1 ? '上架' : '下架' }}</div>
|
|
|
- <div class="line"></div>
|
|
|
+ <div class="hero-main">
|
|
|
+ <div class="hero-top">
|
|
|
+ <h1 class="live-title">{{ liveInfo.liveName || '直播配置' }}</h1>
|
|
|
+ <div class="hero-actions">
|
|
|
+ <el-button size="small" icon="el-icon-back" @click="goBack">返回列表</el-button>
|
|
|
+ <el-button size="small" type="primary" plain icon="el-icon-monitor" @click="goConsole">
|
|
|
+ 实时大屏
|
|
|
+ </el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
-
|
|
|
-<!-- <div class="header-right-area">-->
|
|
|
-<!-- <div class="operation-wrapper">-->
|
|
|
-<!-- <div class="operation-item">-->
|
|
|
-<!-- <div class="operation-item-icon sales-icon"></div>-->
|
|
|
-<!-- <div class="operation-item-text">中控台</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- <div class="line"></div>-->
|
|
|
-<!-- <div class="operation-item">-->
|
|
|
-<!-- <span class="operation-item-icon xe-iconfont"></span>-->
|
|
|
-<!-- <div class="operation-item-text">分享</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- <div class="line"></div>-->
|
|
|
-<!-- <div class="operation-item" data-auth-id="975">-->
|
|
|
-<!-- <span class="operation-item-icon xe-iconfont"></span>-->
|
|
|
-<!-- <div class="operation-item-text">恢复直播</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- <div class="line"></div>-->
|
|
|
-<!-- <div class="operation-item ss-popover__reference" aria-describedby="ss-popover-6482" tabindex="0">-->
|
|
|
-<!-- <span class="operation-item-icon xe-iconfont"></span>-->
|
|
|
-<!-- <div class="operation-item-text">更多</div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- </div>-->
|
|
|
-<!-- </div>-->
|
|
|
- </div>
|
|
|
- </el-card>
|
|
|
- <el-card class="box-card live-config-left">
|
|
|
- <div class="container">
|
|
|
- <!-- 左边菜单 -->
|
|
|
- <div class="left-menu">
|
|
|
- <el-menu default-active="1" class="el-menu-vertical-demo" @select="handleSelect">
|
|
|
- <el-menu-item :index="item.index" v-for="item in menuList" >
|
|
|
- <span>{{item.name}}</span>
|
|
|
- </el-menu-item>
|
|
|
- </el-menu>
|
|
|
+ <div class="meta-row">
|
|
|
+ <span class="meta-chip">
|
|
|
+ <i class="el-icon-film"></i>
|
|
|
+ {{ liveInfo.liveType == 1 ? '视频直播' : '录播' }}
|
|
|
+ </span>
|
|
|
+ <span class="meta-chip">
|
|
|
+ <i class="el-icon-full-screen"></i>
|
|
|
+ {{ liveInfo.showType == 1 ? '横屏' : '竖屏' }}
|
|
|
+ </span>
|
|
|
+ <span class="meta-chip" :class="liveInfo.isShow == 1 ? 'is-on' : 'is-off'">
|
|
|
+ <i :class="liveInfo.isShow == 1 ? 'el-icon-upload2' : 'el-icon-download'"></i>
|
|
|
+ {{ liveInfo.isShow == 1 ? '已上架' : '已下架' }}
|
|
|
+ </span>
|
|
|
</div>
|
|
|
- <!-- 右边信息 -->
|
|
|
- <div class="right-info">
|
|
|
- <!-- 动态组件 -->
|
|
|
- <component :is="currentComponent" :live-type="liveInfo.liveType"></component>
|
|
|
+
|
|
|
+ <div class="time-row">
|
|
|
+ <i class="el-icon-time"></i>
|
|
|
+ <span>直播时间:{{ liveInfo.startTime || '-' }} 至 {{ liveInfo.finishTime || '-' }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
-<!-- <el-tabs tab-position="left" style="height: 200px;">-->
|
|
|
-<!-- <el-tab-pane label="营销内容">营销内容</el-tab-pane>-->
|
|
|
-<!-- <el-tab-pane label="观看奖励">观看奖励</el-tab-pane>-->
|
|
|
-<!-- <el-tab-pane label="答题红包">答题红包</el-tab-pane>-->
|
|
|
-<!-- <el-tab-pane label="答题">答题</el-tab-pane>-->
|
|
|
-<!-- <el-tab-pane label="直播商品">直播商品</el-tab-pane>-->
|
|
|
-<!-- <el-tab-pane label="观看积分">观看积分</el-tab-pane>-->
|
|
|
-<!-- <el-tab-pane label="身份认证">-->
|
|
|
-<!-- <idCard :liveId="liveId" />-->
|
|
|
-<!-- </el-tab-pane>-->
|
|
|
-<!-- </el-tabs>-->
|
|
|
- </el-card>
|
|
|
+ </div>
|
|
|
|
|
|
+ <!-- 主体:侧栏 + 内容 -->
|
|
|
+ <div class="live-body">
|
|
|
+ <aside class="nav-panel">
|
|
|
+ <div class="nav-label">配置项</div>
|
|
|
+ <button
|
|
|
+ v-for="item in menuList"
|
|
|
+ :key="item.index"
|
|
|
+ type="button"
|
|
|
+ class="nav-item"
|
|
|
+ :class="{ active: activeMenu === item.index }"
|
|
|
+ @click="handleSelect(item.index)"
|
|
|
+ >
|
|
|
+ <span class="nav-icon" :class="'tone-' + item.tone">
|
|
|
+ <i :class="item.icon"></i>
|
|
|
+ </span>
|
|
|
+ <span class="nav-text">
|
|
|
+ <span class="nav-name">{{ item.name }}</span>
|
|
|
+ <span class="nav-desc">{{ item.desc }}</span>
|
|
|
+ </span>
|
|
|
+ <i class="el-icon-arrow-right nav-arrow"></i>
|
|
|
+ </button>
|
|
|
+ </aside>
|
|
|
+
|
|
|
+ <section class="content-panel">
|
|
|
+ <component :is="currentComponent" :live-type="liveInfo.liveType"></component>
|
|
|
+ </section>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
+
|
|
|
<script>
|
|
|
import WatchReward from './watchReward.vue';
|
|
|
import Answer from './answer.vue';
|
|
|
@@ -110,8 +85,7 @@ import LiveReplay from './liveReplay.vue'
|
|
|
import Preview from './preview.vue'
|
|
|
import LiveCoupon from './liveCoupon.vue'
|
|
|
import Barrage from './barrage.vue'
|
|
|
-import { listLive, getLive, delLive, addLive, updateLive, exportLive,selectCompanyTalent,handleShelfOrUn,handleDeleteSelected } from "@/api/live/live";
|
|
|
-
|
|
|
+import { getLive } from "@/api/live/live";
|
|
|
|
|
|
export default {
|
|
|
name: 'LiveConfig',
|
|
|
@@ -130,27 +104,24 @@ export default {
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
- activeTab: 'watchReward',
|
|
|
liveId: null,
|
|
|
liveInfo: {},
|
|
|
- socket:null,
|
|
|
- currentComponent: WatchReward,
|
|
|
+ socket: null,
|
|
|
+ activeMenu: 'watchReward',
|
|
|
+ currentComponent: 'WatchReward',
|
|
|
liveWsUrl: process.env.VUE_APP_LIVE_WS_URL + '/app/webSocket',
|
|
|
- menuList:[
|
|
|
- { name: '观看奖励', label: '观看奖励', index: 'watchReward'},
|
|
|
- { name: '直播预告', label: '直播预告', index: 'preview'},
|
|
|
- { name: '红包配置', label: '红包配置', index: 'liveRedConf'},
|
|
|
- { name: '抽奖配置', label: '抽奖配置', index: 'liveLotteryConf'},
|
|
|
- { name: '优惠券配置', label: '优惠券配置', index: 'liveCoupon'},
|
|
|
- // { name: '答题', label: '答题', index: 'answer'},
|
|
|
- { name: '直播商品', label: '直播商品', index: 'goods'},
|
|
|
- { name: '回放设置', label: '回放设置', index: 'liveReplay'},
|
|
|
- // { name: '观看积分', label: '观看积分', index: 'watchScore'},
|
|
|
- { name: '运营自动化', label: '运营自动化', index: 'task'},
|
|
|
- { name: '弹幕脚本', label: '弹幕脚本', index: 'barrage'},
|
|
|
- { name: '身份认证', label: '身份认证', index: 'idCard'},
|
|
|
+ menuList: [
|
|
|
+ { name: '观看奖励', index: 'watchReward', component: 'WatchReward', icon: 'el-icon-present', tone: 'blue', desc: '时长 / 完课奖励' },
|
|
|
+ { name: '直播预告', index: 'preview', component: 'Preview', icon: 'el-icon-bell', tone: 'cyan', desc: '预告信息配置' },
|
|
|
+ { name: '红包配置', index: 'liveRedConf', component: 'LiveRedConf', icon: 'el-icon-coin', tone: 'orange', desc: '直播红包规则' },
|
|
|
+ { name: '抽奖配置', index: 'liveLotteryConf', component: 'LiveLotteryConf', icon: 'el-icon-trophy', tone: 'gold', desc: '抽奖活动设置' },
|
|
|
+ { name: '优惠券配置', index: 'liveCoupon', component: 'LiveCoupon', icon: 'el-icon-ticket', tone: 'green', desc: '优惠券投放' },
|
|
|
+ { name: '直播商品', index: 'goods', component: 'Goods', icon: 'el-icon-goods', tone: 'purple', desc: '带货商品管理' },
|
|
|
+ { name: '回放设置', index: 'liveReplay', component: 'LiveReplay', icon: 'el-icon-video-play', tone: 'indigo', desc: '回放权限与展示' },
|
|
|
+ { name: '运营自动化', index: 'task', component: 'Task', icon: 'el-icon-s-operation', tone: 'teal', desc: '自动化任务' },
|
|
|
+ { name: '弹幕脚本', index: 'barrage', component: 'Barrage', icon: 'el-icon-chat-dot-round', tone: 'pink', desc: '弹幕脚本管理' },
|
|
|
+ { name: '身份认证', index: 'idCard', component: 'IdCard', icon: 'el-icon-user', tone: 'slate', desc: '观众身份校验' },
|
|
|
],
|
|
|
-
|
|
|
}
|
|
|
},
|
|
|
created() {
|
|
|
@@ -162,6 +133,14 @@ export default {
|
|
|
userId() {
|
|
|
return this.$store.state.user.user.userId
|
|
|
},
|
|
|
+ statusText() {
|
|
|
+ const map = { 1: '未开始', 2: '直播中', 3: '已结束' }
|
|
|
+ return map[this.liveInfo.status] || '未知'
|
|
|
+ },
|
|
|
+ statusClass() {
|
|
|
+ const map = { 1: 'pending', 2: 'living', 3: 'ended' }
|
|
|
+ return map[this.liveInfo.status] || 'pending'
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
connectWebSocket() {
|
|
|
@@ -171,147 +150,353 @@ export default {
|
|
|
userId: this.userId
|
|
|
})
|
|
|
this.socket = this.$store.state.liveWs[this.liveId]
|
|
|
- this.socket.onmessage = (event) => this.handleWsMessage(event)
|
|
|
+ if (this.socket) {
|
|
|
+ this.socket.onmessage = (event) => this.handleWsMessage(event)
|
|
|
+ }
|
|
|
},
|
|
|
- handleSelect(index){
|
|
|
- this.currentComponent = index; // 切换当前显示的组件
|
|
|
+ handleWsMessage() {
|
|
|
+ // 配置页仅保持连接,消息由中控台处理
|
|
|
+ },
|
|
|
+ handleSelect(index) {
|
|
|
+ const item = this.menuList.find(m => m.index === index)
|
|
|
+ if (!item) return
|
|
|
+ this.activeMenu = index
|
|
|
+ this.currentComponent = item.component
|
|
|
},
|
|
|
getLiving() {
|
|
|
getLive(this.liveId).then(res => {
|
|
|
- this.liveInfo = res.data
|
|
|
+ this.liveInfo = res.data || {}
|
|
|
})
|
|
|
},
|
|
|
+ goBack() {
|
|
|
+ this.$router.back()
|
|
|
+ },
|
|
|
+ goConsole() {
|
|
|
+ this.$router.push('/live/liveConsole/' + this.liveId)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
-
|
|
|
<style scoped>
|
|
|
-.el-tabs__header .is-top {
|
|
|
- display: none !important;
|
|
|
-}
|
|
|
-.live-config-header{
|
|
|
- padding: 5px;
|
|
|
- border: 1px solid #ebeef5;
|
|
|
+.live-config-page {
|
|
|
+ min-height: calc(100vh - 84px);
|
|
|
+ padding: 16px 16px 24px;
|
|
|
+ background:
|
|
|
+ radial-gradient(ellipse 80% 50% at 0% 0%, rgba(24, 144, 255, 0.08), transparent 55%),
|
|
|
+ radial-gradient(ellipse 60% 40% at 100% 0%, rgba(82, 196, 26, 0.06), transparent 50%),
|
|
|
+ linear-gradient(180deg, #f4f7fb 0%, #eef2f7 100%);
|
|
|
}
|
|
|
-.detail-header {
|
|
|
+
|
|
|
+/* ===== Hero ===== */
|
|
|
+.live-hero {
|
|
|
display: flex;
|
|
|
- padding: 20px;
|
|
|
- border-bottom: 1px solid #ebeef5;
|
|
|
+ gap: 20px;
|
|
|
+ padding: 20px 22px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ background: rgba(255, 255, 255, 0.92);
|
|
|
+ border: 1px solid #e6edf5;
|
|
|
+ border-radius: 14px;
|
|
|
+ box-shadow: 0 4px 20px rgba(31, 45, 61, 0.04);
|
|
|
+ backdrop-filter: blur(8px);
|
|
|
}
|
|
|
|
|
|
-.header-left-area {
|
|
|
- flex: 0 0 120px;
|
|
|
+.hero-cover {
|
|
|
position: relative;
|
|
|
+ flex: 0 0 120px;
|
|
|
+ width: 120px;
|
|
|
+ height: 120px;
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+ background: #e8eef5;
|
|
|
}
|
|
|
|
|
|
-.header-left-area img {
|
|
|
- width: 100px;
|
|
|
- height: 100px;
|
|
|
- border-radius: 4px;
|
|
|
+.hero-cover img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: cover;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+
|
|
|
+.cover-placeholder {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ color: #8fa0b5;
|
|
|
+ font-size: 36px;
|
|
|
+ background: linear-gradient(135deg, #e8eef5, #f2f6fa);
|
|
|
+}
|
|
|
+
|
|
|
+.status-badge {
|
|
|
+ position: absolute;
|
|
|
+ left: 8px;
|
|
|
+ bottom: 8px;
|
|
|
+ padding: 2px 8px;
|
|
|
+ border-radius: 999px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #fff;
|
|
|
+ line-height: 1.6;
|
|
|
+ backdrop-filter: blur(4px);
|
|
|
+}
|
|
|
+
|
|
|
+.status-badge.pending {
|
|
|
+ background: rgba(144, 147, 153, 0.88);
|
|
|
}
|
|
|
|
|
|
-.header-middle-area {
|
|
|
+.status-badge.living {
|
|
|
+ background: rgba(245, 108, 108, 0.92);
|
|
|
+ box-shadow: 0 0 0 0 rgba(245, 108, 108, 0.5);
|
|
|
+ animation: living-pulse 1.8s ease-out infinite;
|
|
|
+}
|
|
|
+
|
|
|
+.status-badge.ended {
|
|
|
+ background: rgba(96, 98, 102, 0.88);
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes living-pulse {
|
|
|
+ 0% { box-shadow: 0 0 0 0 rgba(245, 108, 108, 0.45); }
|
|
|
+ 70% { box-shadow: 0 0 0 8px rgba(245, 108, 108, 0); }
|
|
|
+ 100% { box-shadow: 0 0 0 0 rgba(245, 108, 108, 0); }
|
|
|
+}
|
|
|
+
|
|
|
+.hero-main {
|
|
|
flex: 1;
|
|
|
- padding: 0 20px;
|
|
|
+ min-width: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 10px;
|
|
|
}
|
|
|
|
|
|
-.header-right-area {
|
|
|
- flex: 0 0 200px;
|
|
|
+.hero-top {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 16px;
|
|
|
}
|
|
|
|
|
|
-.live-info-title .title-text {
|
|
|
- font-size: 20px;
|
|
|
- font-weight: 500;
|
|
|
- color: #303133;
|
|
|
+.live-title {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 22px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #1f2d3d;
|
|
|
+ line-height: 1.3;
|
|
|
+ letter-spacing: 0.2px;
|
|
|
}
|
|
|
|
|
|
-.live-info-desc {
|
|
|
+.hero-actions {
|
|
|
+ flex-shrink: 0;
|
|
|
display: flex;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.meta-row {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.meta-chip {
|
|
|
+ display: inline-flex;
|
|
|
align-items: center;
|
|
|
- margin-top: 10px;
|
|
|
+ gap: 4px;
|
|
|
+ padding: 4px 10px;
|
|
|
+ border-radius: 999px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #4a5d73;
|
|
|
+ background: #f0f4f9;
|
|
|
+ border: 1px solid #e4ebf3;
|
|
|
}
|
|
|
|
|
|
-.live-info-desc .line {
|
|
|
- width: 1px;
|
|
|
- height: 12px;
|
|
|
- background: #c0c4cc;
|
|
|
- margin: 0 10px;
|
|
|
+.meta-chip i {
|
|
|
+ font-size: 13px;
|
|
|
}
|
|
|
|
|
|
-.live-info-state {
|
|
|
+.meta-chip.is-on {
|
|
|
+ color: #389e0d;
|
|
|
+ background: #f6ffed;
|
|
|
+ border-color: #d9f7be;
|
|
|
+}
|
|
|
+
|
|
|
+.meta-chip.is-off {
|
|
|
+ color: #8c8c8c;
|
|
|
+ background: #fafafa;
|
|
|
+ border-color: #f0f0f0;
|
|
|
+}
|
|
|
+
|
|
|
+.time-row {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- margin-top: 10px;
|
|
|
+ gap: 6px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #6b7c93;
|
|
|
}
|
|
|
|
|
|
-.live-info-state .line {
|
|
|
- width: 1px;
|
|
|
- height: 12px;
|
|
|
- background: #c0c4cc;
|
|
|
- margin: 0 10px;
|
|
|
+.time-row i {
|
|
|
+ color: #8fa0b5;
|
|
|
}
|
|
|
|
|
|
-.live-state-dot {
|
|
|
- width: 8px;
|
|
|
- height: 8px;
|
|
|
- border-radius: 50%;
|
|
|
+/* ===== Body ===== */
|
|
|
+.live-body {
|
|
|
+ display: flex;
|
|
|
+ gap: 14px;
|
|
|
+ align-items: stretch;
|
|
|
+ min-height: calc(100vh - 280px);
|
|
|
}
|
|
|
|
|
|
-.live-state-dot-liveEnd {
|
|
|
- background: #909399;
|
|
|
+.nav-panel {
|
|
|
+ flex: 0 0 240px;
|
|
|
+ width: 240px;
|
|
|
+ padding: 14px 10px;
|
|
|
+ background: rgba(255, 255, 255, 0.95);
|
|
|
+ border: 1px solid #e6edf5;
|
|
|
+ border-radius: 14px;
|
|
|
+ box-shadow: 0 2px 12px rgba(31, 45, 61, 0.03);
|
|
|
+ align-self: flex-start;
|
|
|
+ position: sticky;
|
|
|
+ top: 12px;
|
|
|
+ max-height: calc(100vh - 120px);
|
|
|
+ overflow-y: auto;
|
|
|
}
|
|
|
|
|
|
-.info-state-text {
|
|
|
- font-size: 14px;
|
|
|
- color: #606266;
|
|
|
+.nav-label {
|
|
|
+ padding: 4px 12px 12px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #8fa0b5;
|
|
|
+ letter-spacing: 0.8px;
|
|
|
+ text-transform: uppercase;
|
|
|
}
|
|
|
|
|
|
-.operation-wrapper {
|
|
|
+.nav-item {
|
|
|
+ width: 100%;
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 10px 10px;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ border-radius: 10px;
|
|
|
+ background: transparent;
|
|
|
+ cursor: pointer;
|
|
|
+ text-align: left;
|
|
|
+ transition: all 0.18s ease;
|
|
|
+ outline: none;
|
|
|
}
|
|
|
|
|
|
-.operation-item {
|
|
|
+.nav-item:hover {
|
|
|
+ background: #f5f8fc;
|
|
|
+ border-color: #e8eef5;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-item.active {
|
|
|
+ background: linear-gradient(135deg, #edf5ff 0%, #f3f9ff 100%);
|
|
|
+ border-color: #cfe3ff;
|
|
|
+ box-shadow: 0 2px 8px rgba(24, 144, 255, 0.08);
|
|
|
+}
|
|
|
+
|
|
|
+.nav-icon {
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 34px;
|
|
|
+ height: 34px;
|
|
|
+ border-radius: 9px;
|
|
|
display: flex;
|
|
|
- flex-direction: column;
|
|
|
align-items: center;
|
|
|
- cursor: pointer;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #fff;
|
|
|
}
|
|
|
|
|
|
-.operation-item-text {
|
|
|
- font-size: 12px;
|
|
|
- color: #606266;
|
|
|
- margin-top: 4px;
|
|
|
+.tone-blue { background: linear-gradient(135deg, #1890ff, #36a3ff); }
|
|
|
+.tone-cyan { background: linear-gradient(135deg, #13c2c2, #36cfc9); }
|
|
|
+.tone-orange { background: linear-gradient(135deg, #fa8c16, #ffa940); }
|
|
|
+.tone-gold { background: linear-gradient(135deg, #faad14, #ffc53d); }
|
|
|
+.tone-green { background: linear-gradient(135deg, #52c41a, #73d13d); }
|
|
|
+.tone-purple { background: linear-gradient(135deg, #722ed1, #9254de); }
|
|
|
+.tone-indigo { background: linear-gradient(135deg, #2f54eb, #597ef7); }
|
|
|
+.tone-teal { background: linear-gradient(135deg, #08979c, #13c2c2); }
|
|
|
+.tone-pink { background: linear-gradient(135deg, #eb2f96, #f759ab); }
|
|
|
+.tone-slate { background: linear-gradient(135deg, #595959, #8c8c8c); }
|
|
|
+
|
|
|
+.nav-text {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 2px;
|
|
|
}
|
|
|
|
|
|
-.operation-wrapper .line {
|
|
|
- width: 1px;
|
|
|
- height: 20px;
|
|
|
- background: #c0c4cc;
|
|
|
- margin: 0 10px;
|
|
|
+.nav-name {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ line-height: 1.3;
|
|
|
}
|
|
|
|
|
|
-.container {
|
|
|
- display: flex;
|
|
|
- min-height: calc(100vh - 280px);
|
|
|
+.nav-item.active .nav-name {
|
|
|
+ color: #1890ff;
|
|
|
}
|
|
|
-.left-menu {
|
|
|
- width: 200px;
|
|
|
- border-right: 1px solid #e4e7ed;
|
|
|
- flex-shrink: 0; /* 不收缩 */
|
|
|
+
|
|
|
+.nav-desc {
|
|
|
+ font-size: 11px;
|
|
|
+ color: #909399;
|
|
|
+ line-height: 1.3;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
}
|
|
|
|
|
|
-.right-info {
|
|
|
- flex: 1;
|
|
|
- padding: 20px;
|
|
|
- min-height: 0;
|
|
|
- overflow-y: auto;
|
|
|
- max-height: calc(100vh - 280px);
|
|
|
+.nav-arrow {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #c0c4cc;
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateX(-4px);
|
|
|
+ transition: all 0.18s ease;
|
|
|
}
|
|
|
|
|
|
-.right-tabs {
|
|
|
- height: 100%;
|
|
|
+.nav-item:hover .nav-arrow,
|
|
|
+.nav-item.active .nav-arrow {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateX(0);
|
|
|
+ color: #1890ff;
|
|
|
}
|
|
|
|
|
|
+.content-panel {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ min-height: 520px;
|
|
|
+ padding: 0 4px 8px;
|
|
|
+ background: transparent;
|
|
|
+ border: none;
|
|
|
+ box-shadow: none;
|
|
|
+ overflow: auto;
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 960px) {
|
|
|
+ .live-body {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nav-panel {
|
|
|
+ flex: none;
|
|
|
+ width: 100%;
|
|
|
+ position: static;
|
|
|
+ max-height: none;
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
|
+ gap: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nav-label {
|
|
|
+ grid-column: 1 / -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ .hero-top {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|