|
|
@@ -82,54 +82,18 @@
|
|
|
</div>
|
|
|
|
|
|
<div class="middle-panel">
|
|
|
- <h2 class="panel-title">消息管理</h2>
|
|
|
-
|
|
|
- <div class="panel-card discussion-messages">
|
|
|
- <div class="section-header">
|
|
|
- <h3 class="section-title">讨论区消息</h3>
|
|
|
- <el-checkbox v-model="globalVisible" @change="globalVisibleChange">全局用户自见</el-checkbox>
|
|
|
- </div>
|
|
|
- <div class="message-container" @click="handleMessageBoxClick">
|
|
|
- <el-scrollbar class="msg-scroll" ref="manageRightRef">
|
|
|
- <div v-for="m in msgList" :key="m.msgId" class="msg-item">
|
|
|
- <div v-if="m.userId === userId && m.msgId == null" class="msg-row msg-row--self">
|
|
|
- <div class="msg-content msg-content--self">
|
|
|
- <div class="msg-nickname">{{ m.nickName }}</div>
|
|
|
- <div class="msg-bubble msg-bubble--self">{{ m.msg }}</div>
|
|
|
- </div>
|
|
|
- <el-avatar :size="32" :src="m.avatar" class="msg-avatar" />
|
|
|
- </div>
|
|
|
- <div v-else class="msg-row">
|
|
|
- <el-avatar :size="32" :src="m.avatar" class="msg-avatar" />
|
|
|
- <div class="msg-content">
|
|
|
- <div class="msg-nickname">{{ m.nickName }}</div>
|
|
|
- <div class="msg-bubble">{{ m.msg }}</div>
|
|
|
- <div class="msg-actions">
|
|
|
- <a class="action-link" @click.stop="changeUserState(m)">{{ m.msgStatus === 1 ? '解禁' : '禁言' }}</a>
|
|
|
- <a class="action-link" @click.stop="blockUser(m)">拉黑</a>
|
|
|
- <a class="action-link" @click.stop="singleVisible(m)">{{ m.singleVisible === 1 ? '解除用户自见' : '用户自见' }}</a>
|
|
|
- <a class="action-link" @click.stop="deleteMsg(m)">删除</a>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="scroll-bottom-space"></div>
|
|
|
- </el-scrollbar>
|
|
|
- <el-button
|
|
|
- v-if="showLoadLatestBtn"
|
|
|
- class="load-latest-btn"
|
|
|
- type="primary"
|
|
|
- size="mini"
|
|
|
- @click.stop="loadLatestMessages"
|
|
|
- :disabled="isLoadingLatest"
|
|
|
- :loading="isLoadingLatest"
|
|
|
- icon="el-icon-refresh"
|
|
|
- >加载最新消息</el-button>
|
|
|
+ <div class="panel-card live-player-card">
|
|
|
+ <h3 class="section-title">直播观看</h3>
|
|
|
+ <div class="live-player-wrapper">
|
|
|
+ <div v-if="showLivePlaceholder" class="live-placeholder">
|
|
|
+ <span class="live-placeholder-text">{{ livePlaceholderText }}</span>
|
|
|
+ </div>
|
|
|
+ <LivePlayer v-else ref="livePlayer" :videoParam="videoParam" />
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
<div class="panel-card ops-panel">
|
|
|
- <el-tabs v-model="opsTabActive" class="ops-tabs">
|
|
|
+ <el-tabs v-model="opsTabActive" class="ops-tabs" tab-position="left">
|
|
|
<el-tab-pane label="营销" name="marketing">
|
|
|
<div class="marketing-panel" v-loading="marketingLoading">
|
|
|
<div class="marketing-toolbar">
|
|
|
@@ -143,14 +107,15 @@
|
|
|
show-icon
|
|
|
/>
|
|
|
</div>
|
|
|
- <el-radio-group v-model="marketingCategory" size="mini" class="marketing-categories" @change="clearMarketingSelection">
|
|
|
+ <el-radio-group v-model="marketingCategory" size="mini" class="marketing-categories" @change="handleMarketingCategoryChange">
|
|
|
<el-radio-button v-for="cat in marketingCategories" :key="cat.key" :label="cat.key">{{ cat.label }}</el-radio-button>
|
|
|
</el-radio-group>
|
|
|
- <el-scrollbar class="marketing-scroll">
|
|
|
+ <div class="marketing-content" :class="{ 'has-marketing-pagination': marketingListTotal > 0 }">
|
|
|
+ <div class="marketing-body">
|
|
|
<!-- 商品:图片卡片 -->
|
|
|
- <div class="marketing-cards" v-if="marketingCategory === 'goods' && currentMarketingList.length">
|
|
|
+ <div class="marketing-cards" v-if="marketingCategory === 'goods' && paginatedMarketingList.length">
|
|
|
<div
|
|
|
- v-for="item in currentMarketingList"
|
|
|
+ v-for="item in paginatedMarketingList"
|
|
|
:key="getMarketingItemKey(item)"
|
|
|
class="marketing-card"
|
|
|
:class="{ selected: isMarketingItemSelected(item) }"
|
|
|
@@ -170,16 +135,14 @@
|
|
|
</div>
|
|
|
<div class="card-info">
|
|
|
<div class="card-title" :title="item.productName">{{ item.productName }}</div>
|
|
|
- <div class="card-bottom">
|
|
|
- <span class="card-price" v-if="item.price">¥{{ item.price }}</span>
|
|
|
- </div>
|
|
|
+ <div class="card-price" v-if="item.price">¥{{ item.price }}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- 优惠券 / 核销券 / 红包 / 抽奖:列表 -->
|
|
|
- <div class="marketing-list" v-else-if="marketingCategory !== 'goods' && currentMarketingList.length">
|
|
|
+ <div class="marketing-list" v-else-if="marketingCategory !== 'goods' && paginatedMarketingList.length">
|
|
|
<div
|
|
|
- v-for="item in currentMarketingList"
|
|
|
+ v-for="item in paginatedMarketingList"
|
|
|
:key="getMarketingItemKey(item)"
|
|
|
class="marketing-list-item"
|
|
|
:class="{ selected: isMarketingItemSelected(item) }"
|
|
|
@@ -218,24 +181,37 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
<el-empty v-else description="暂无数据" :image-size="60" />
|
|
|
- </el-scrollbar>
|
|
|
- <div class="panel-footer">
|
|
|
- <el-button size="mini" @click="handleActivityRecord">活动记录</el-button>
|
|
|
- <el-button size="mini" @click="handleDistributionRecord">发放记录</el-button>
|
|
|
+ </div>
|
|
|
+ <pagination
|
|
|
+ v-if="marketingListTotal > 0"
|
|
|
+ class="marketing-pagination"
|
|
|
+ :total="marketingListTotal"
|
|
|
+ :page.sync="marketingPageNum"
|
|
|
+ :limit.sync="marketingPageSize"
|
|
|
+ layout="total, prev, pager, next"
|
|
|
+ :pager-count="3"
|
|
|
+ :background="false"
|
|
|
+ small
|
|
|
+ :auto-scroll="false"
|
|
|
+ @pagination="handleMarketingPagination"
|
|
|
+ />
|
|
|
</div>
|
|
|
</div>
|
|
|
</el-tab-pane>
|
|
|
- <el-tab-pane label="系统消息" name="systemMsg">
|
|
|
- <div class="system-msg-panel">
|
|
|
- <el-input
|
|
|
- type="textarea"
|
|
|
- :rows="3"
|
|
|
- placeholder="输入系统消息"
|
|
|
- v-model="newMsg"
|
|
|
- resize="none"
|
|
|
- />
|
|
|
- <div class="panel-footer">
|
|
|
- <el-button type="primary" size="mini" @click="sendMessage">发送消息</el-button>
|
|
|
+ <el-tab-pane label="运营自动化" name="automation">
|
|
|
+ <div class="automation-panel">
|
|
|
+ <p class="section-subtitle">时间轴设置</p>
|
|
|
+ <div class="automation-body">
|
|
|
+ <div class="timeline-items">
|
|
|
+ <div class="timeline-item" v-for="item in timelineItems.slice(0, 2)" :key="item.id || item.absValue">
|
|
|
+ <div class="timeline-info">
|
|
|
+ <div class="timeline-time">{{ formatDate(item.absValue) }}</div>
|
|
|
+ <div class="timeline-action">{{ item.taskName }}</div>
|
|
|
+ </div>
|
|
|
+ <el-button type="text" size="mini" class="action-link" @click="removeTimelineItem(item)">删除</el-button>
|
|
|
+ </div>
|
|
|
+ <el-empty v-if="!timelineItems.length" description="暂无任务" :image-size="48" />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</el-tab-pane>
|
|
|
@@ -244,24 +220,60 @@
|
|
|
</div>
|
|
|
|
|
|
<div class="right-panel">
|
|
|
- <h2 class="panel-title">运营工具</h2>
|
|
|
- <div class="panel-card live-player">
|
|
|
- <h3 class="section-title">直播观看</h3>
|
|
|
- <LivePlayer ref="livePlayer" :videoParam="videoParam" />
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="panel-card automation">
|
|
|
- <h3 class="section-title">运营自动化</h3>
|
|
|
- <p class="section-subtitle">时间轴设置</p>
|
|
|
- <div class="timeline-items">
|
|
|
- <div class="timeline-item" v-for="item in timelineItems.slice(0, 2)" :key="item.id || item.absValue">
|
|
|
- <div class="timeline-info">
|
|
|
- <div class="timeline-time">{{ formatDate(item.absValue) }}</div>
|
|
|
- <div class="timeline-action">{{ item.taskName }}</div>
|
|
|
+ <div class="discussion-messages">
|
|
|
+ <div class="discussion-header">
|
|
|
+ <h3 class="discussion-title">讨论</h3>
|
|
|
+ <div class="discussion-header-line"></div>
|
|
|
+ </div>
|
|
|
+ <div class="discussion-toolbar">
|
|
|
+ <el-checkbox v-model="globalVisible" @change="globalVisibleChange">全局用户自见</el-checkbox>
|
|
|
+ </div>
|
|
|
+ <div class="message-container" @click="handleMessageBoxClick">
|
|
|
+ <el-scrollbar class="msg-scroll" ref="manageRightRef">
|
|
|
+ <div v-for="m in msgList" :key="m.msgId" class="msg-item">
|
|
|
+ <div v-if="m.userId === userId && m.msgId == null" class="msg-row msg-row--self">
|
|
|
+ <div class="msg-content msg-content--self">
|
|
|
+ <div class="msg-nickname">{{ m.nickName }}</div>
|
|
|
+ <div class="msg-bubble msg-bubble--self">{{ m.msg }}</div>
|
|
|
+ </div>
|
|
|
+ <el-avatar :size="32" :src="m.avatar" class="msg-avatar" />
|
|
|
+ </div>
|
|
|
+ <div v-else class="msg-row">
|
|
|
+ <el-avatar :size="32" :src="m.avatar" class="msg-avatar" />
|
|
|
+ <div class="msg-content">
|
|
|
+ <div class="msg-nickname">{{ m.nickName }}</div>
|
|
|
+ <div class="msg-bubble">{{ m.msg }}</div>
|
|
|
+ <div class="msg-actions">
|
|
|
+ <a class="action-link" @click.stop="changeUserState(m)">{{ m.msgStatus === 1 ? '解禁' : '禁言' }}</a>
|
|
|
+ <a class="action-link" @click.stop="blockUser(m)">拉黑</a>
|
|
|
+ <a class="action-link" @click.stop="singleVisible(m)">{{ m.singleVisible === 1 ? '解除用户自见' : '用户自见' }}</a>
|
|
|
+ <a class="action-link" @click.stop="deleteMsg(m)">删除</a>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <el-button type="text" size="mini" class="action-link" @click="removeTimelineItem(item)">删除</el-button>
|
|
|
+ <div class="scroll-bottom-space"></div>
|
|
|
+ </el-scrollbar>
|
|
|
+ </div>
|
|
|
+ <div class="discussion-input">
|
|
|
+ <el-input
|
|
|
+ type="textarea"
|
|
|
+ v-model="newMsg"
|
|
|
+ placeholder="请输入消息..."
|
|
|
+ :rows="4"
|
|
|
+ resize="none"
|
|
|
+ />
|
|
|
+ <div class="discussion-input-actions">
|
|
|
+ <el-button
|
|
|
+ v-if="showLoadLatestBtn"
|
|
|
+ class="discussion-action-btn"
|
|
|
+ size="small"
|
|
|
+ @click="loadLatestMessages"
|
|
|
+ :disabled="isLoadingLatest"
|
|
|
+ :loading="isLoadingLatest"
|
|
|
+ >加载最新</el-button>
|
|
|
+ <el-button class="discussion-send-btn" type="primary" size="small" @click="sendMessage">发送</el-button>
|
|
|
</div>
|
|
|
- <el-empty v-if="!timelineItems.length" description="暂无任务" :image-size="48" />
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -269,7 +281,7 @@
|
|
|
<h3 class="section-title">直播氛围自动化</h3>
|
|
|
<el-input
|
|
|
type="textarea"
|
|
|
- :rows="4"
|
|
|
+ :rows="3"
|
|
|
:disabled="autoWatermark"
|
|
|
v-model="watermarkTemplate"
|
|
|
placeholder="水军弹幕内容模板,每行一条"
|
|
|
@@ -335,6 +347,8 @@ export default {
|
|
|
watermarkList:[],
|
|
|
watermarkTemplate: '',
|
|
|
liveInfo: {},
|
|
|
+ isAudit: false,
|
|
|
+ liveStatus: 0,
|
|
|
videoParam:{
|
|
|
startTime:'',
|
|
|
livingUrl: '',
|
|
|
@@ -471,6 +485,8 @@ export default {
|
|
|
{ key: 'lottery', label: '抽奖' }
|
|
|
],
|
|
|
marketingLoading: false,
|
|
|
+ marketingPageNum: 1,
|
|
|
+ marketingPageSize: 3,
|
|
|
showCart: true,
|
|
|
goodsLiveList: [],
|
|
|
couponLiveList: [],
|
|
|
@@ -504,6 +520,24 @@ export default {
|
|
|
silencedUserLabel() {
|
|
|
return `禁言(${this.userTotal.silenced})`;
|
|
|
},
|
|
|
+ showLivePlaceholder() {
|
|
|
+ if (!this.isAudit) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (this.liveStatus === 4) {
|
|
|
+ return !this.videoParam.videoUrl;
|
|
|
+ }
|
|
|
+ if (this.liveStatus !== 2) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (this.videoParam.liveType === 1) {
|
|
|
+ return !this.videoParam.livingUrl;
|
|
|
+ }
|
|
|
+ return !this.videoParam.videoUrl;
|
|
|
+ },
|
|
|
+ livePlaceholderText() {
|
|
|
+ return '直播未开启';
|
|
|
+ },
|
|
|
currentMarketingList() {
|
|
|
if (this.marketingCategory === 'goods') {
|
|
|
return this.goodsLiveList;
|
|
|
@@ -518,6 +552,13 @@ export default {
|
|
|
return this.couponLiveList.filter(item => !this.isVerifyCouponType(item));
|
|
|
}
|
|
|
return this.couponLiveList.filter(item => this.isVerifyCouponType(item));
|
|
|
+ },
|
|
|
+ marketingListTotal() {
|
|
|
+ return this.currentMarketingList.length;
|
|
|
+ },
|
|
|
+ paginatedMarketingList() {
|
|
|
+ const start = (this.marketingPageNum - 1) * this.marketingPageSize;
|
|
|
+ return this.currentMarketingList.slice(start, start + this.marketingPageSize);
|
|
|
}
|
|
|
},
|
|
|
created() {
|
|
|
@@ -585,6 +626,14 @@ export default {
|
|
|
clearMarketingSelection() {
|
|
|
this.selectedMarketingItem = null;
|
|
|
},
|
|
|
+ handleMarketingCategoryChange() {
|
|
|
+ this.clearMarketingSelection();
|
|
|
+ this.marketingPageNum = 1;
|
|
|
+ this.marketingPageSize = 3;
|
|
|
+ },
|
|
|
+ handleMarketingPagination() {
|
|
|
+ this.selectedMarketingItem = null;
|
|
|
+ },
|
|
|
isVerifyCouponType(item) {
|
|
|
const label = this.selectDictLabel(this.couponTypeOptions, item.type) || '';
|
|
|
return label.includes('核销') || label.includes('代金券');
|
|
|
@@ -817,17 +866,6 @@ export default {
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
- handleActivityRecord() {
|
|
|
- if (!this.timelineItems.length) {
|
|
|
- this.$message.info('暂无活动记录');
|
|
|
- return;
|
|
|
- }
|
|
|
- const names = this.timelineItems.map(item => `${this.formatDate(item.absValue)} ${item.taskName}`).join('\n');
|
|
|
- this.$alert(names, '活动记录', { confirmButtonText: '确定' });
|
|
|
- },
|
|
|
- handleDistributionRecord() {
|
|
|
- this.$message.info('发放记录请在直播配置-优惠券/红包配置中查看');
|
|
|
- },
|
|
|
// 点击消息框
|
|
|
handleMessageBoxClick() {
|
|
|
// 点击消息框时,停止自动滚动
|
|
|
@@ -1135,7 +1173,7 @@ export default {
|
|
|
return
|
|
|
}
|
|
|
this.isAudit = true
|
|
|
- this.status = res.data.status
|
|
|
+ this.liveStatus = res.data.status
|
|
|
this.videoParam.startTime = new Date(res.data.startTime).getTime()
|
|
|
if(res.data.status == 4){
|
|
|
this.videoParam.liveType = 3
|
|
|
@@ -1164,7 +1202,9 @@ export default {
|
|
|
this.$nextTick(() => {
|
|
|
this.globalVisible = res.data.globalVisible
|
|
|
this.showCart = res.data.showCart == null || res.data.showCart === 1
|
|
|
- this.$refs.livePlayer.initPlayer()
|
|
|
+ if (this.$refs.livePlayer) {
|
|
|
+ this.$refs.livePlayer.initPlayer()
|
|
|
+ }
|
|
|
})
|
|
|
this.loading = false
|
|
|
} else {
|
|
|
@@ -1836,7 +1876,7 @@ export default {
|
|
|
/* 布局 */
|
|
|
.console {
|
|
|
display: flex;
|
|
|
- height: 100vh;
|
|
|
+ height: 100%;
|
|
|
overflow: hidden;
|
|
|
background: #f5f7fa;
|
|
|
}
|
|
|
@@ -1846,31 +1886,34 @@ export default {
|
|
|
.right-panel {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
- padding: 16px;
|
|
|
+ min-height: 0;
|
|
|
+ padding: 12px;
|
|
|
box-sizing: border-box;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.left-panel {
|
|
|
- width: 28%;
|
|
|
+ width: 22%;
|
|
|
border-right: 1px solid #ebeef5;
|
|
|
}
|
|
|
|
|
|
.middle-panel {
|
|
|
- width: 42%;
|
|
|
+ width: 48%;
|
|
|
border-right: 1px solid #ebeef5;
|
|
|
gap: 12px;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.right-panel {
|
|
|
width: 30%;
|
|
|
- overflow-y: auto;
|
|
|
- gap: 12px;
|
|
|
+ gap: 8px;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
/* 通用标题与卡片 */
|
|
|
.panel-title {
|
|
|
- margin: 0 0 12px;
|
|
|
+ margin: 0 0 8px;
|
|
|
+ flex-shrink: 0;
|
|
|
font-size: 16px;
|
|
|
font-weight: 600;
|
|
|
color: #303133;
|
|
|
@@ -1946,10 +1989,13 @@ export default {
|
|
|
.console-tabs {
|
|
|
flex: 1;
|
|
|
min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
}
|
|
|
|
|
|
.console-tabs ::v-deep .el-tabs__content {
|
|
|
- height: calc(100% - 40px);
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
}
|
|
|
|
|
|
.console-tabs ::v-deep .el-tab-pane {
|
|
|
@@ -1957,7 +2003,11 @@ export default {
|
|
|
}
|
|
|
|
|
|
.panel-scroll {
|
|
|
- height: calc(100vh - 180px);
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.panel-scroll ::v-deep .el-scrollbar {
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
|
|
|
.user-list-item {
|
|
|
@@ -2001,23 +2051,122 @@ export default {
|
|
|
color: #409eff;
|
|
|
}
|
|
|
|
|
|
-/* 讨论区消息 */
|
|
|
+/* 中间直播画面 */
|
|
|
+.live-player-card {
|
|
|
+ flex: 3;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ margin: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 10px 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.live-player-card .section-title {
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-bottom: 6px;
|
|
|
+}
|
|
|
+
|
|
|
+.live-player-wrapper {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.live-placeholder {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ max-height: 100%;
|
|
|
+ background: #000;
|
|
|
+ border-radius: 4px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.live-placeholder-text {
|
|
|
+ color: #fff;
|
|
|
+ font-size: 26px;
|
|
|
+ font-weight: 700;
|
|
|
+ letter-spacing: 3px;
|
|
|
+ user-select: none;
|
|
|
+}
|
|
|
+
|
|
|
+.live-player-card ::v-deep .live-player {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ max-height: 100%;
|
|
|
+ height: 100%;
|
|
|
+ margin-bottom: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: #000;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.live-player-card ::v-deep .player {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ max-height: 100%;
|
|
|
+ min-height: 0;
|
|
|
+ border-radius: 4px;
|
|
|
+ object-fit: contain;
|
|
|
+}
|
|
|
+
|
|
|
+/* 讨论区 */
|
|
|
.discussion-messages {
|
|
|
flex: 1;
|
|
|
min-height: 0;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ border-radius: 4px;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-header {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 12px 16px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-title {
|
|
|
+ margin: 0;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #36cfc9;
|
|
|
+ line-height: 1.4;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-header-line {
|
|
|
+ margin-top: 10px;
|
|
|
+ height: 2px;
|
|
|
+ background: #36cfc9;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-toolbar {
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ padding: 8px 16px 0;
|
|
|
}
|
|
|
|
|
|
.message-container {
|
|
|
position: relative;
|
|
|
flex: 1;
|
|
|
min-height: 0;
|
|
|
+ padding: 8px 16px 0;
|
|
|
}
|
|
|
|
|
|
.msg-scroll {
|
|
|
- height: calc(100vh - 520px);
|
|
|
- min-height: 180px;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.msg-scroll ::v-deep .el-scrollbar {
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
|
|
|
.msg-item + .msg-item {
|
|
|
@@ -2076,87 +2225,253 @@ export default {
|
|
|
height: 16px;
|
|
|
}
|
|
|
|
|
|
-.load-latest-btn {
|
|
|
- position: absolute;
|
|
|
- right: 12px;
|
|
|
- bottom: 12px;
|
|
|
- z-index: 2;
|
|
|
+.discussion-input {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 12px 16px 16px;
|
|
|
+ border-top: 1px solid #f0f0f0;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-input ::v-deep .el-textarea__inner {
|
|
|
+ background: #f5f5f5;
|
|
|
+ border: none;
|
|
|
+ border-radius: 6px;
|
|
|
+ padding: 12px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #303133;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-input ::v-deep .el-textarea__inner:focus {
|
|
|
+ border: none;
|
|
|
+ box-shadow: none;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-input-actions {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ gap: 8px;
|
|
|
+ margin-top: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-action-btn {
|
|
|
+ background: #36cfc9;
|
|
|
+ border-color: #36cfc9;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-action-btn:hover,
|
|
|
+.discussion-action-btn:focus {
|
|
|
+ background: #2eb8ab;
|
|
|
+ border-color: #2eb8ab;
|
|
|
+ color: #fff;
|
|
|
}
|
|
|
|
|
|
-/* 营销 / 系统消息 */
|
|
|
+.discussion-send-btn {
|
|
|
+ background: #36cfc9;
|
|
|
+ border-color: #36cfc9;
|
|
|
+}
|
|
|
+
|
|
|
+.discussion-send-btn:hover,
|
|
|
+.discussion-send-btn:focus {
|
|
|
+ background: #2eb8ab;
|
|
|
+ border-color: #2eb8ab;
|
|
|
+}
|
|
|
+
|
|
|
+/* 营销 / 运营自动化 */
|
|
|
.ops-panel {
|
|
|
- flex-shrink: 0;
|
|
|
+ flex: 2;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ margin: 0;
|
|
|
+ padding: 8px 10px 10px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.ops-tabs {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.ops-tabs ::v-deep.el-tabs--left {
|
|
|
+ display: flex;
|
|
|
+ height: 100%;
|
|
|
}
|
|
|
|
|
|
.ops-tabs ::v-deep .el-tabs__header {
|
|
|
- margin-bottom: 10px;
|
|
|
+ margin-right: 12px;
|
|
|
+ margin-bottom: 0;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.ops-tabs ::v-deep .el-tabs__content {
|
|
|
- overflow: visible;
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ height: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.ops-tabs ::v-deep .el-tab-pane {
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.ops-tabs ::v-deep .el-tabs__item {
|
|
|
+ padding: 0 12px;
|
|
|
+ height: 32px;
|
|
|
+ line-height: 32px;
|
|
|
+ font-size: 13px;
|
|
|
}
|
|
|
|
|
|
.marketing-panel,
|
|
|
-.system-msg-panel {
|
|
|
+.automation-panel {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.marketing-toolbar {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
- gap: 10px;
|
|
|
- margin-bottom: 10px;
|
|
|
+ gap: 6px;
|
|
|
+ margin-bottom: 6px;
|
|
|
flex-wrap: wrap;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.marketing-toolbar .toolbar-label {
|
|
|
+ font-size: 12px;
|
|
|
}
|
|
|
|
|
|
.marketing-tip {
|
|
|
flex: 1;
|
|
|
- min-width: 200px;
|
|
|
- padding: 4px 8px;
|
|
|
+ min-width: 160px;
|
|
|
+ padding: 2px 6px;
|
|
|
}
|
|
|
|
|
|
.marketing-tip ::v-deep .el-alert__title {
|
|
|
- font-size: 12px;
|
|
|
+ font-size: 11px;
|
|
|
+ line-height: 1.3;
|
|
|
}
|
|
|
|
|
|
.marketing-categories {
|
|
|
- margin-bottom: 10px;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
-.marketing-scroll {
|
|
|
- height: 150px;
|
|
|
+.marketing-content {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.marketing-content.has-marketing-pagination {
|
|
|
+ padding: 0 2px 0;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.marketing-body,
|
|
|
+.automation-body {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.marketing-content.has-marketing-pagination .marketing-body {
|
|
|
+ flex: 1 1 auto;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.marketing-pagination {
|
|
|
+ flex: 0 0 auto;
|
|
|
+ width: 100%;
|
|
|
+ margin-top: 4px;
|
|
|
+ padding: 4px 0 2px;
|
|
|
+ border-top: 1px solid #f0f2f5;
|
|
|
+ background: #fff;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.marketing-pagination ::v-deep .pagination-container {
|
|
|
+ width: 100%;
|
|
|
+ padding: 0 !important;
|
|
|
+ margin: 0 !important;
|
|
|
+ text-align: center;
|
|
|
+ background: transparent;
|
|
|
+}
|
|
|
+
|
|
|
+.marketing-pagination ::v-deep .el-pagination {
|
|
|
+ display: inline-flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ padding: 0;
|
|
|
+ font-weight: normal;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+.marketing-pagination ::v-deep .el-pagination__total {
|
|
|
+ margin-right: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.automation-panel .section-subtitle {
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.ops-panel .timeline-item {
|
|
|
+ padding: 6px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.ops-panel .timeline-time,
|
|
|
+.ops-panel .timeline-action {
|
|
|
+ font-size: 12px;
|
|
|
}
|
|
|
|
|
|
.marketing-cards {
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(2, 1fr);
|
|
|
- gap: 8px;
|
|
|
- padding-right: 4px;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 2px 4px 10px 0;
|
|
|
}
|
|
|
|
|
|
.marketing-card {
|
|
|
+ width: 100px;
|
|
|
border: 1px solid #ebeef5;
|
|
|
- border-radius: 4px;
|
|
|
+ border-radius: 6px;
|
|
|
overflow: hidden;
|
|
|
cursor: pointer;
|
|
|
background: #fff;
|
|
|
- transition: border-color 0.2s;
|
|
|
+ transition: border-color 0.2s, box-shadow 0.2s;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.marketing-card:hover,
|
|
|
.marketing-card.selected {
|
|
|
border-color: #409eff;
|
|
|
+ box-shadow: 0 2px 8px rgba(64, 158, 255, 0.12);
|
|
|
}
|
|
|
|
|
|
.card-image-wrap {
|
|
|
position: relative;
|
|
|
- height: 72px;
|
|
|
+ width: 100px;
|
|
|
+ height: 100px;
|
|
|
overflow: hidden;
|
|
|
background: #f5f7fa;
|
|
|
+ flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
.card-image {
|
|
|
+ display: block;
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
object-fit: cover;
|
|
|
@@ -2164,68 +2479,96 @@ export default {
|
|
|
|
|
|
.card-tags {
|
|
|
position: absolute;
|
|
|
- top: 6px;
|
|
|
- left: 6px;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ z-index: 2;
|
|
|
display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
gap: 4px;
|
|
|
+ padding: 6px 5px 5px;
|
|
|
+ background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0.15) 70%, transparent);
|
|
|
+ pointer-events: none;
|
|
|
+}
|
|
|
+
|
|
|
+.card-tags ::v-deep .el-tag {
|
|
|
+ height: auto;
|
|
|
+ min-height: 18px;
|
|
|
+ line-height: 1.2;
|
|
|
+ padding: 2px 6px;
|
|
|
+ font-size: 11px;
|
|
|
+ border: none;
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.card-overlay {
|
|
|
position: absolute;
|
|
|
inset: 0;
|
|
|
+ z-index: 3;
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- gap: 4px;
|
|
|
- padding: 6px;
|
|
|
- background: rgba(0, 0, 0, 0.5);
|
|
|
+ gap: 2px;
|
|
|
+ padding: 4px;
|
|
|
+ background: rgba(0, 0, 0, 0.55);
|
|
|
opacity: 0;
|
|
|
transition: opacity 0.2s;
|
|
|
}
|
|
|
|
|
|
+.card-overlay .el-button {
|
|
|
+ padding: 4px 8px;
|
|
|
+ font-size: 11px;
|
|
|
+}
|
|
|
+
|
|
|
.marketing-card:hover .card-overlay {
|
|
|
opacity: 1;
|
|
|
}
|
|
|
|
|
|
.card-info {
|
|
|
- padding: 6px 8px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 100px;
|
|
|
+ padding: 4px 4px 6px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 4px;
|
|
|
}
|
|
|
|
|
|
.card-title {
|
|
|
- font-size: 12px;
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+ font-size: 11px;
|
|
|
color: #303133;
|
|
|
+ line-height: 1.3;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
-.card-bottom {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: space-between;
|
|
|
- margin-top: 4px;
|
|
|
-}
|
|
|
-
|
|
|
.card-price {
|
|
|
- font-size: 12px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 11px;
|
|
|
font-weight: 600;
|
|
|
color: #f56c6c;
|
|
|
+ line-height: 1.2;
|
|
|
}
|
|
|
|
|
|
.marketing-list {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
- gap: 8px;
|
|
|
- padding-right: 4px;
|
|
|
+ gap: 6px;
|
|
|
+ padding: 2px 0 4px;
|
|
|
}
|
|
|
|
|
|
.marketing-list-item {
|
|
|
display: flex;
|
|
|
+ flex-direction: row;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- gap: 10px;
|
|
|
- padding: 10px;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 8px 10px;
|
|
|
border: 1px solid #ebeef5;
|
|
|
border-radius: 4px;
|
|
|
background: #fff;
|
|
|
@@ -2245,20 +2588,22 @@ export default {
|
|
|
}
|
|
|
|
|
|
.list-title {
|
|
|
- font-size: 13px;
|
|
|
+ font-size: 12px;
|
|
|
color: #303133;
|
|
|
+ line-height: 1.4;
|
|
|
+ word-break: break-all;
|
|
|
+ display: -webkit-box;
|
|
|
+ -webkit-line-clamp: 2;
|
|
|
+ -webkit-box-orient: vertical;
|
|
|
overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.list-meta {
|
|
|
margin-top: 4px;
|
|
|
font-size: 12px;
|
|
|
color: #909399;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- white-space: nowrap;
|
|
|
+ line-height: 1.4;
|
|
|
+ word-break: break-all;
|
|
|
}
|
|
|
|
|
|
.list-price {
|
|
|
@@ -2282,10 +2627,9 @@ export default {
|
|
|
justify-content: flex-end;
|
|
|
}
|
|
|
|
|
|
-/* 右侧运营工具 */
|
|
|
-.live-player,
|
|
|
-.automation,
|
|
|
+/* 右侧氛围自动化 */
|
|
|
.watermark {
|
|
|
+ flex-shrink: 0;
|
|
|
margin: 0;
|
|
|
}
|
|
|
|
|
|
@@ -2321,9 +2665,21 @@ export default {
|
|
|
margin-top: 10px;
|
|
|
}
|
|
|
|
|
|
-/* 滚动条 */
|
|
|
-::v-deep .el-scrollbar__wrap {
|
|
|
+/* 隐藏滚动条,保留滚动能力 */
|
|
|
+.console ::v-deep .el-scrollbar__bar {
|
|
|
+ display: none !important;
|
|
|
+}
|
|
|
+
|
|
|
+.console ::v-deep .el-scrollbar__wrap {
|
|
|
overflow-x: hidden !important;
|
|
|
+ scrollbar-width: none;
|
|
|
+ -ms-overflow-style: none;
|
|
|
+}
|
|
|
+
|
|
|
+.console ::v-deep .el-scrollbar__wrap::-webkit-scrollbar {
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ display: none;
|
|
|
}
|
|
|
</style>
|
|
|
|