<template>
  <div class="console">

    <div class="left-panel">
      <h2 class="panel-title">学员列表</h2>
      <div class="search-bar">
        <el-input
          v-model="searchKeyword"
          placeholder="搜索用户昵称"
          size="small"
          clearable
          @keyup.enter.native="searchUsers"
        />
        <el-button type="primary" size="small" @click="searchUsers">搜索</el-button>
      </div>
      <el-tabs class="console-tabs" v-model="tabLeft.activeName" @tab-click="handleUserClick" :stretch="true">
        <el-tab-pane :label="alLabel" name="al">
          <el-scrollbar class="panel-scroll" ref="manageLeftRef_al">
            <div class="user-list-item" v-for="u in alDisplayList" :key="u.userId">
              <el-avatar :size="36" :src="u.avatar" class="user-avatar" />
              <div class="user-meta">
                <div class="user-name">{{ u.nickName }}</div>
                <div class="user-id">{{ u.userId }}</div>
              </div>
              <el-popover width="120" trigger="click" popper-class="user-action-popover">
                <a class="action-link" @click="changeUserState(u)">{{ u.msgStatus === 1 ? '解禁' : '禁言' }}</a>
                <a class="action-link" @click="blockUser(u)">拉黑</a>
                <i class="el-icon-more user-more-btn" slot="reference"></i>
              </el-popover>
            </div>
          </el-scrollbar>
        </el-tab-pane>
        <el-tab-pane :label="onlineLabel" name="online">
          <el-scrollbar class="panel-scroll" ref="manageLeftRef_online">
            <div class="user-list-item" v-for="u in onlineDisplayList" :key="u.userId">
              <el-avatar :size="36" :src="u.avatar" class="user-avatar" />
              <div class="user-meta">
                <div class="user-name">{{ u.nickName }}</div>
                <div class="user-id">{{ u.userId }}</div>
              </div>
              <el-popover width="120" trigger="click" popper-class="user-action-popover">
                <a class="action-link" @click="changeUserState(u)">{{ u.msgStatus === 1 ? '解禁' : '禁言' }}</a>
                <a class="action-link" @click="blockUser(u)">拉黑</a>
                <i class="el-icon-more user-more-btn" slot="reference"></i>
              </el-popover>
            </div>
          </el-scrollbar>
        </el-tab-pane>
        <el-tab-pane :label="offlineLabel" name="offline">
          <el-scrollbar class="panel-scroll" ref="manageLeftRef_offline">
            <div class="user-list-item" v-for="u in offlineDisplayList" :key="u.userId">
              <el-avatar :size="36" :src="u.avatar" class="user-avatar" />
              <div class="user-meta">
                <div class="user-name">{{ u.nickName }}</div>
                <div class="user-id">{{ u.userId }}</div>
              </div>
              <el-popover width="120" trigger="click" popper-class="user-action-popover">
                <a class="action-link" @click="changeUserState(u)">{{ u.msgStatus === 1 ? '解禁' : '禁言' }}</a>
                <a class="action-link" @click="blockUser(u)">拉黑</a>
                <i class="el-icon-more user-more-btn" slot="reference"></i>
              </el-popover>
            </div>
          </el-scrollbar>
        </el-tab-pane>
        <el-tab-pane :label="silencedUserLabel" name="silenced">
          <el-scrollbar class="panel-scroll" ref="manageLeftRef_silenced">
            <div class="user-list-item" v-for="u in silencedDisplayList" :key="u.userId">
              <el-avatar :size="36" :src="u.avatar" class="user-avatar" />
              <div class="user-meta">
                <div class="user-name">{{ u.nickName }}</div>
                <div class="user-id">{{ u.userId }}</div>
              </div>
              <el-popover width="120" trigger="click" popper-class="user-action-popover">
                <a class="action-link" @click="changeUserState(u)">{{ u.msgStatus === 1 ? '解禁' : '禁言' }}</a>
                <a class="action-link" @click="blockUser(u)">拉黑</a>
                <i class="el-icon-more user-more-btn" slot="reference"></i>
              </el-popover>
            </div>
          </el-scrollbar>
        </el-tab-pane>
      </el-tabs>
    </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>
      </div>

      <div class="panel-card ops-panel">
        <el-tabs v-model="opsTabActive" class="ops-tabs">
          <el-tab-pane label="营销" name="marketing">
            <div class="marketing-panel" v-loading="marketingLoading">
              <div class="marketing-toolbar">
                <span class="toolbar-label">显示购物车</span>
                <el-switch v-model="showCart" @change="showCartChange" />
                <el-alert
                  class="marketing-tip"
                  title="置顶商品弹窗优先展示时，其他同位置弹窗将不再展示"
                  type="info"
                  :closable="false"
                  show-icon
                />
              </div>
              <el-radio-group v-model="marketingCategory" size="mini" class="marketing-categories" @change="clearMarketingSelection">
                <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-cards" v-if="marketingCategory === 'goods' && currentMarketingList.length">
                  <div
                    v-for="item in currentMarketingList"
                    :key="getMarketingItemKey(item)"
                    class="marketing-card"
                    :class="{ selected: isMarketingItemSelected(item) }"
                    @click="selectMarketingItem(item)"
                  >
                    <div class="card-image-wrap">
                      <img :src="item.imgUrl || item.image" class="card-image" />
                      <div class="card-tags">
                        <el-tag v-if="item.isShow" type="warning" size="mini" effect="dark">展示中</el-tag>
                        <el-tag v-if="item.status == 1" type="success" size="mini" effect="dark">已上架</el-tag>
                      </div>
                      <div class="card-overlay">
                        <el-button size="mini" round :disabled="item.status == 1" @click.stop="handleGoodsShelf(item, 1)">上架</el-button>
                        <el-button size="mini" type="danger" round :disabled="item.status == 0" @click.stop="handleGoodsShelf(item, 0)">下架</el-button>
                        <el-button size="mini" type="primary" round @click.stop="handleGoodsShowToggle(item)">{{ item.isShow ? '收起' : '展示' }}</el-button>
                      </div>
                    </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>
                  </div>
                </div>
                <!-- 优惠券 / 核销券 / 红包 / 抽奖：列表 -->
                <div class="marketing-list" v-else-if="marketingCategory !== 'goods' && currentMarketingList.length">
                  <div
                    v-for="item in currentMarketingList"
                    :key="getMarketingItemKey(item)"
                    class="marketing-list-item"
                    :class="{ selected: isMarketingItemSelected(item) }"
                    @click="selectMarketingItem(item)"
                  >
                    <div class="list-main">
                      <div class="list-title" :title="getMarketingItemTitle(item)">{{ getMarketingItemTitle(item) }}</div>
                      <div class="list-meta">
                        <span v-if="getMarketingItemPrice(item)" class="list-price">¥{{ getMarketingItemPrice(item) }}</span>
                        <span v-if="getMarketingListMeta(item)">{{ getMarketingListMeta(item) }}</span>
                      </div>
                      <div class="list-tags">
                        <el-tag v-if="(marketingCategory === 'coupon' || marketingCategory === 'verifyCoupon') && item.isShow" type="warning" size="mini">展示中</el-tag>
                        <el-tag v-if="(marketingCategory === 'lottery' || marketingCategory === 'red') && isRedLotteryRunning(item)" type="success" size="mini">进行中</el-tag>
                      </div>
                    </div>
                    <div class="list-actions" @click.stop>
                      <template v-if="marketingCategory === 'lottery'">
                        <el-button size="mini" type="primary" @click="handleLotteryStatusChange(item, '1')">开始</el-button>
                        <el-button size="mini" @click="handleLotteryStatusChange(item, '3')">暂停</el-button>
                        <el-button size="mini" type="danger" @click="handleLotteryStatusChange(item, '2')">结算</el-button>
                      </template>
                      <template v-else-if="marketingCategory === 'red'">
                        <el-button size="mini" type="primary" @click="handleRedStatusChange(item, '1')">开始</el-button>
                        <el-button size="mini" @click="handleRedStatusChange(item, '3')">暂停</el-button>
                        <el-button size="mini" type="danger" @click="handleRedStatusChange(item, '2')">结算</el-button>
                      </template>
                      <template v-else-if="marketingCategory === 'coupon'">
                        <el-button size="mini" @click="openCouponBindDialog(item)">绑定商品</el-button>
                        <el-button size="mini" type="primary" @click="handleCouponShowToggle(item)">{{ item.isShow ? '收起' : '展示' }}</el-button>
                      </template>
                      <template v-else-if="marketingCategory === 'verifyCoupon'">
                        <el-button size="mini" type="primary" @click="handleCouponShowToggle(item)">{{ item.isShow ? '收起' : '展示' }}</el-button>
                      </template>
                    </div>
                  </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>
            </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>
              </div>
            </div>
          </el-tab-pane>
        </el-tabs>
      </div>
    </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>
            <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 class="panel-card watermark">
        <h3 class="section-title">直播氛围自动化</h3>
        <el-input
          type="textarea"
          :rows="4"
          :disabled="autoWatermark"
          v-model="watermarkTemplate"
          placeholder="水军弹幕内容模板，每行一条"
          resize="none"
        />
        <div class="watermark-options">
          <span class="toolbar-label">发送间隔</span>
          <el-input-number v-model="interval" :min="1" :disabled="autoWatermark" size="mini" controls-position="right" />
          <span class="toolbar-label">秒</span>
          <el-checkbox v-model="autoWatermark" @change="changeAutoWatermark">启用水军自动化</el-checkbox>
        </div>
      </div>
    </div>

    <el-dialog title="绑定商品" :visible.sync="couponBindDialogVisible" width="480px" append-to-body>
      <el-form label-width="80px">
        <el-form-item label="直播商品">
          <el-select v-model="couponBindForm.goodsId" placeholder="请选择商品" filterable style="width: 100%;">
            <el-option
              v-for="g in bindGoodsOptions"
              :key="g.goodsId"
              :label="g.productName"
              :value="g.goodsId"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer">
        <el-button @click="couponBindDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="confirmCouponBind">确 定</el-button>
      </div>
    </el-dialog>

  </div>
</template>

<script>
import LivePlayer from './LivePlayer.vue';
import {blockUser, changeUserStatus, getLiveUserTotals, dashBoardWatchUserList} from '@/api/live/liveWatchUser'
import { listLiveSingleMsg,delLiveMsg } from '@/api/live/liveMsg'
import { getLive, updateShowCart } from '@/api/live/live'
import { consoleList } from '@/api/live/task'
import { listLiveGoods, handleShelfOrUn, handleIsShowChange as handleGoodsIsShowChange } from '@/api/live/liveGoods'
import { listLiveCoupon, handleIsShowChange as handleCouponIsShowChange, updateLiveCouponBind } from '@/api/live/liveCoupon'
import { listLiveLotteryConf, updateLiveLotteryConf } from '@/api/live/liveLotteryConf'
import { listLiveRedConf, updateLiveRedConf } from '@/api/live/liveRedConf'
import ScreenScale from './ScreenScale.vue'; // 路径根据实际位置调整


export default {
  components: {
    LivePlayer,ScreenScale
  },
  props: {
    liveId: {
      type: String,
      default: null
    }
  },
  data() {
    return {
      watermarkIndex: 0,
      watermarkList:[],
      watermarkTemplate: '',
      liveInfo: {},
      videoParam:{
        startTime:'',
        livingUrl: '',
        liveType: 1,
        videoUrl: '',
      },
      msgList:[],
      currentTab: 'al',
      searchKeyword: '',
      globalVisible: false,
      interval: 10,
      autoWatermark: false,
      streamUrl: 'rtmp://your-live-stream-url',
      users: [
        { id: 1, name: '用户1', avatar: 'https://via.placeholder.com/40', status: 'online', statusText: '在线', silenced: false, msgStatus: false },
        { id: 2, name: '用户2', avatar: 'https://via.placeholder.com/40', status: 'online', statusText: '在线', silenced: false, msgStatus: true },
        { id: 3, name: '用户3', avatar: 'https://via.placeholder.com/40', status: 'offline', statusText: '离线', silenced: true, msgStatus: false },
        { id: 4, name: '用户4', avatar: 'https://via.placeholder.com/40', status: 'online', statusText: '在线', silenced: false, msgStatus: false },
        { id: 5, name: '用户5', avatar: 'https://via.placeholder.com/40', status: 'offline', statusText: '离线', silenced: false, msgStatus: false }
      ],
      messages: [
        { id: 1, user: '用户1', avatar: 'https://via.placeholder.com/30', text: '这个产品怎么样？', isVisible: true },
        { id: 2, user: '用户2', avatar: 'https://via.placeholder.com/30', text: '看起来不错', isVisible: true },
        { id: 3, user: '用户3', avatar: 'https://via.placeholder.com/30', text: '有优惠吗？', isVisible: true }
      ],
      timelineItems: [
        { "searchValue": null,
          "createBy": null,
          "createTime": "2025-09-23 10:36:17",
          "updateBy": null,
          "updateTime": "2025-10-17 09:18:00",
          "remark": null,
          "params": {},
          "id": 6573,
          "liveId": 128,
          "taskName": "2",
          "taskType": 1,
          "triggerType": 2,
          "triggerValue": "2025-01-01T00:02:00.000+0800",
          "absValue": "2025-11-23T10:43:00.000+0800",
          "status": 1,
          "finishStatus": 0 },
      ],
      userTotal: {
        online: 0,       // 在线总人数
        offline: 0,      // 离线总人数
        silenced: 0,      // 禁言总人数
        al: 0
      },
      tabLeft: {
        activeName: "al",
      },
      taskParams:{
        currentPage: 1,
        pageSize: 20,
        prevPage: 0,
        totalLoaded: 0,
        total: 0,
        hasMore: true,
        hasPrev: false
      },
      loadMsgMaxPage: 2,
      liveWsUrl: process.env.VUE_APP_LIVE_WS_URL + '/app/webSocket',
      alDisplayList: [],
      onlineDisplayList: [],    // 在线用户显示列表
      offlineDisplayList: [],   // 离线用户显示列表
      silencedDisplayList: [],  // 禁言用户显示列表
      // 各Tab的分页参数
      pageParams: {
        al: {
          currentPage: 1,
          pageSize: 20,
          prevPage: 0,
          totalLoaded: 0,
          total: 0,
          hasMore: true,
          hasPrev: false
        },
        online: {
          currentPage: 1,       // 当前页（下一页加载用）
          pageSize: 20,       // 当前页（下一页加载用）
          prevPage: 0,          // 上一页页码（上一页加载用）
          totalLoaded: 0,       // 已加载总条数
          total: 0,             // 总数据量
          hasMore: true,        // 是否有下一页
          hasPrev: false        // 是否有上一页
        },
        offline: {
          currentPage: 1,
          pageSize: 20,
          prevPage: 0,
          totalLoaded: 0,
          total: 0,
          hasMore: true,
          hasPrev: false
        },
        silenced: {
          currentPage: 1,
          pageSize: 20,
          prevPage: 0,
          totalLoaded: 0,
          total: 0,
          hasMore: true,
          hasPrev: false
        }
      },
      scrLoading: {
        al: { next: false, prev: false },
        online: { next: false, prev: false },
        offline: { next: false, prev: false },
        silenced: { next: false, prev: false }
      },
      newMsg:'',
      autoMsgTimer: null,
      checkInterval: 2000, // 检查间隔（1分钟，可根据需求调整）
      // 消息滚动控制
      isAutoScrollEnabled: true, // 是否启用自动滚动
      autoScrollTimer: null, // 自动滚动定时器
      showLoadLatestBtn: false, // 是否显示加载最新消息按钮
      isLoadingLatest: false, // 是否正在加载最新消息
      scrollDebounceTimer: null, // 滚动防抖定时器
      msgParams: {
        pageNum: 1,
        pageSize: 30,
        liveId: null
      },
      opsTabActive: 'marketing',
      marketingCategory: 'goods',
      marketingCategories: [
        { key: 'goods', label: '商品' },
        { key: 'coupon', label: '优惠券' },
        { key: 'verifyCoupon', label: '核销券' },
        { key: 'red', label: '红包' },
        { key: 'lottery', label: '抽奖' }
      ],
      marketingLoading: false,
      showCart: true,
      goodsLiveList: [],
      couponLiveList: [],
      lotteryList: [],
      redList: [],
      couponTypeOptions: [],
      lotteryStatusOptions: [],
      redStatusOptions: [],
      selectedMarketingItem: null,
      couponBindDialogVisible: false,
      couponBindForm: { couponId: null, goodsId: null },
      bindGoodsOptions: []
    };
  },
  computed: {
    userId() {
      return this.$store.state.user.user.userId
    },
    companyId() {
      return this.$store.state.user.user.companyId
    },
    onlineLabel() {
      return `在线(${this.userTotal.online})`;
    },
    alLabel() {
      return `全部(${this.userTotal.al})`;
    },
    offlineLabel() {
      return `离线(${this.userTotal.offline})`;
    },
    silencedUserLabel() {
      return `禁言(${this.userTotal.silenced})`;
    },
    currentMarketingList() {
      if (this.marketingCategory === 'goods') {
        return this.goodsLiveList;
      }
      if (this.marketingCategory === 'lottery') {
        return this.lotteryList;
      }
      if (this.marketingCategory === 'red') {
        return this.redList;
      }
      if (this.marketingCategory === 'coupon') {
        return this.couponLiveList.filter(item => !this.isVerifyCouponType(item));
      }
      return this.couponLiveList.filter(item => this.isVerifyCouponType(item));
    }
  },
  created() {
    if(!this.liveId) return
    this.loadMarketingDicts()
    this.getList()
    this.handleUserClick({name:'al'})
    this.connectWebSocket()
    this.getLive()
  },
  mounted() {
    this.$nextTick(() => {
      this.restoreChatScrollPosition();

      if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
        this.$refs.manageRightRef.wrap.addEventListener('scroll', this.saveChatScrollPosition);
      }
    });
    this.initScrollListeners();
  },
  methods: {
    loadMarketingDicts() {
      this.getDicts('store_coupon_type').then(response => {
        this.couponTypeOptions = response.data || [];
      });
      this.getDicts('sys_live_lottery_status').then(response => {
        this.lotteryStatusOptions = response.data || [];
      });
      this.getDicts('sys_live_red_status').then(response => {
        this.redStatusOptions = response.data || [];
      });
    },
    loadMarketingData() {
      if (!this.liveId) return;
      this.marketingLoading = true;
      const query = { liveId: this.liveId, pageNum: 1, pageSize: 100 };
      Promise.all([
        listLiveGoods(query),
        listLiveCoupon(query),
        listLiveLotteryConf(query),
        listLiveRedConf(query)
      ]).then(([goodsRes, couponRes, lotteryRes, redRes]) => {
        if (goodsRes.code === 200) {
          this.goodsLiveList = (goodsRes.rows || []).map(item => ({
            ...item,
            isShow: item.isShow === 1 || item.isShow === true
          }));
        }
        if (couponRes.code === 200) {
          this.couponLiveList = (couponRes.rows || []).map(item => ({
            ...item,
            isShow: item.isShow === 1 || item.isShow === true
          }));
        }
        if (lotteryRes.code === 200) {
          this.lotteryList = lotteryRes.rows || [];
        }
        if (redRes.code === 200) {
          this.redList = redRes.rows || [];
        }
      }).finally(() => {
        this.marketingLoading = false;
      });
    },
    clearMarketingSelection() {
      this.selectedMarketingItem = null;
    },
    isVerifyCouponType(item) {
      const label = this.selectDictLabel(this.couponTypeOptions, item.type) || '';
      return label.includes('核销') || label.includes('代金券');
    },
    getMarketingItemKey(item) {
      if (this.marketingCategory === 'goods') return `goods-${item.goodsId}`;
      if (this.marketingCategory === 'lottery') return `lottery-${item.lotteryId}`;
      if (this.marketingCategory === 'red') return `red-${item.redId}`;
      return `coupon-${item.id || item.couponId}`;
    },
    getMarketingItemTitle(item) {
      if (this.marketingCategory === 'lottery') {
        return item.desc || `抽奖 #${item.lotteryId}`;
      }
      if (this.marketingCategory === 'red') {
        return item.desc || `红包 #${item.redId}`;
      }
      return item.productName || item.title || '-';
    },
    getMarketingItemPrice(item) {
      if (this.marketingCategory === 'goods') {
        return item.price;
      }
      if (this.marketingCategory === 'coupon' || this.marketingCategory === 'verifyCoupon') {
        return item.couponPrice;
      }
      return '';
    },
    getMarketingListMeta(item) {
      if (this.marketingCategory === 'lottery') {
        return this.selectDictLabel(this.lotteryStatusOptions, item.lotteryStatus) || '';
      }
      if (this.marketingCategory === 'red') {
        return this.selectDictLabel(this.redStatusOptions, item.redStatus) || '';
      }
      const typeLabel = this.selectDictLabel(this.couponTypeOptions, item.type);
      const parts = [];
      if (item.useMinPrice) {
        parts.push(`满${item.useMinPrice}可用`);
      }
      if (this.marketingCategory === 'coupon' && item.productName) {
        parts.push(`已绑：${item.productName}`);
      }
      if (typeLabel) {
        parts.push(typeLabel);
      }
      return parts.join(' · ');
    },
    isRedLotteryRunning(item) {
      const status = this.marketingCategory === 'red' ? item.redStatus : item.lotteryStatus;
      return status + '' === '1' || status + '' === '3';
    },
    isMarketingItemSelected(item) {
      if (!this.selectedMarketingItem) return false;
      return this.getMarketingItemKey(item) === this.getMarketingItemKey(this.selectedMarketingItem);
    },
    selectMarketingItem(item) {
      this.selectedMarketingItem = item;
    },
    ensureSocket() {
      if (!this.socket) {
        this.$message.error('请从直播间开启 WebSocket 连接');
        return false;
      }
      return true;
    },
    handleGoodsShelf(row, status) {
      handleShelfOrUn({ goodsIds: [row.goodsId], status, liveId: this.liveId }).then(res => {
        if (res.code === 200) {
          row.status = status;
          this.$message.success(status === 1 ? '上架成功' : '下架成功');
        } else {
          this.$message.error(res.msg);
        }
      });
    },
    handleGoodsShowToggle(row) {
      this.toggleGoodsShow(row, !row.isShow);
    },
    handleCouponShowToggle(row) {
      this.toggleCouponShow(row, !row.isShow);
    },
    openCouponBindDialog(row) {
      this.couponBindForm = { couponId: row.id, goodsId: row.goodsId || null };
      listLiveGoods({ liveId: this.liveId, pageNum: 1, pageSize: 100 }).then(res => {
        if (res.code === 200) {
          this.bindGoodsOptions = res.rows || [];
          this.couponBindDialogVisible = true;
        }
      });
    },
    confirmCouponBind() {
      if (!this.couponBindForm.goodsId) {
        this.$message.warning('请选择商品');
        return;
      }
      updateLiveCouponBind({
        goodsId: this.couponBindForm.goodsId,
        couponId: this.couponBindForm.couponId,
        liveId: this.liveId
      }).then(res => {
        if (res.code === 200) {
          this.$message.success('绑定成功');
          this.couponBindDialogVisible = false;
          this.loadMarketingData();
        } else {
          this.$message.error(res.msg);
        }
      });
    },
    toggleGoodsShow(row, targetStatus) {
      if (!this.ensureSocket()) return;
      handleGoodsIsShowChange({
        goodsIds: [row.goodsId],
        isShow: targetStatus,
        liveId: this.liveId
      }).then(res => {
        if (res.code === 200) {
          row.isShow = res.isShow;
          if (res.msg === '目前仅支持单一物品展示') {
            this.$message.error(res.msg);
          }
          this.socket.send(JSON.stringify({
            cmd: 'goods',
            data: { liveId: this.liveId, goodsId: row.goodsId, status: targetStatus ? 1 : 0 }
          }));
        }
      });
    },
    toggleCouponShow(row, targetStatus) {
      if (!this.ensureSocket()) return;
      handleCouponIsShowChange({
        couponId: row.id,
        isShow: targetStatus,
        liveId: this.liveId
      }).then(res => {
        if (res.code === 200) {
          row.isShow = targetStatus;
          if (res.msg === '目前仅支持单一优惠券推送') {
            this.$message.error(res.msg);
            return;
          }
          this.socket.send(JSON.stringify({
            cmd: 'coupon',
            data: {
              liveId: this.liveId,
              couponIssueId: row.id,
              status: targetStatus ? 1 : 0,
              goodsId: row.goodsId,
              couponName: row.title,
              couponPrice: row.couponPrice,
              useMinPrice: row.useMinPrice,
              couponTime: row.couponTime
            }
          }));
        }
      });
    },
    handleLotteryStatusChange(row, status) {
      if (!this.ensureSocket()) return;
      if (row.lotteryStatus + '' === '2') {
        this.$message.error('已结束的抽奖不能进行操作');
        return;
      }
      if (status === '1' && row.lotteryStatus + '' !== '0' && row.lotteryStatus + '' !== '3') {
        this.$message.error('只能对未开始或暂停的抽奖进行开始操作');
        return;
      }
      if (status === '2' && row.lotteryStatus + '' !== '1' && row.lotteryStatus + '' !== '3') {
        this.$message.error('只能对进行中或暂停的抽奖进行结算');
        return;
      }
      if (status === '3' && row.lotteryStatus + '' !== '1') {
        this.$message.error('只能对进行中的抽奖执行暂停操作');
        return;
      }
      const param = {
        lotteryId: row.lotteryId,
        lotteryStatus: status,
        duration: row.duration,
        liveId: this.liveId,
        status
      };
      updateLiveLotteryConf(param).then(response => {
        if (response.code === 200) {
          this.socket.send(JSON.stringify({ cmd: 'lottery', data: param }));
          this.$message.success('操作成功');
          this.loadMarketingData();
        } else {
          this.$message.error(response.msg);
        }
      });
    },
    handleRedStatusChange(row, status) {
      if (!this.ensureSocket()) return;
      if (row.redStatus + '' === '2') {
        this.$message.error('已结束的红包不能进行操作');
        return;
      }
      if (status === '1' && row.redStatus + '' !== '0' && row.redStatus + '' !== '3') {
        this.$message.error('只能对未开始或暂停的红包进行开始操作');
        return;
      }
      if (status === '2' && row.redStatus + '' !== '1' && row.redStatus + '' !== '3') {
        this.$message.error('只能对进行中或暂停的红包进行结算');
        return;
      }
      if (status === '3' && row.redStatus + '' !== '1') {
        this.$message.error('只能对进行中的红包执行暂停操作');
        return;
      }
      const param = {
        redId: row.redId,
        redStatus: status,
        totalLots: row.totalLots,
        totalSend: row.totalSend,
        redType: row.redType,
        redNum: row.redNum,
        liveId: this.liveId,
        duration: row.duration,
        status
      };
      updateLiveRedConf(param).then(response => {
        if (response.code === 200) {
          this.socket.send(JSON.stringify({ cmd: 'red', data: param }));
          this.$message.success('操作成功');
          this.loadMarketingData();
        } else {
          this.$message.error(response.msg);
        }
      });
    },
    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() {
      // 点击消息框时，停止自动滚动
      this.isAutoScrollEnabled = false;
      // 停止自动滚动定时器
      if (this.autoScrollTimer) {
        clearTimeout(this.autoScrollTimer);
        this.autoScrollTimer = null;
      }
      // 检查是否在底部，如果不在底部则显示加载最新消息按钮
      this.$nextTick(() => {
        if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
          const wrap = this.$refs.manageRightRef.wrap;
          const scrollHeight = wrap.scrollHeight;
          const clientHeight = wrap.clientHeight;
          const currentScrollTop = wrap.scrollTop;
          const maxScrollTop = scrollHeight - clientHeight;

          if (currentScrollTop < maxScrollTop - 50) {
            this.showLoadLatestBtn = true;
          }
        }
      });
    },
    // 滚动到底部
    scrollToBottom(forceScroll = false) {
      // 如果自动滚动被禁用且不是强制滚动，则不执行
      if (!this.isAutoScrollEnabled && !forceScroll) {
        return;
      }

      if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
        this.$nextTick(() => {
          const wrap = this.$refs.manageRightRef.wrap;
          if (!wrap) return;

          const scrollHeight = wrap.scrollHeight;
          const clientHeight = wrap.clientHeight;
          const currentScrollTop = wrap.scrollTop;
          const maxScrollTop = scrollHeight - clientHeight;

          // 强制滚动或启用自动滚动时，直接滚动到底部并隐藏按钮
          if (forceScroll || this.isAutoScrollEnabled) {
            this.showLoadLatestBtn = false;
            wrap.scrollTop = maxScrollTop;
          }
        });
      }
    },
    // 加载最新消息
    loadLatestMessages() {
      // 如果正在加载，直接返回
      if (this.isLoadingLatest) {
        return;
      }
      this.isLoadingLatest = true;
      this.showLoadLatestBtn = false;
      // 恢复自动滚动
      this.isAutoScrollEnabled = true;
      // 重新请求最新消息
      this.resetMsgParams();
      // loadMsgList 中会自动滚动到底部，因为 isAutoScrollEnabled 已经是 true
      this.loadMsgList();
    },
    singleVisible(m){
      // 过滤当前所有消息 找到userId的相同的消息 更改他们的自可见状态
      m.singleVisible= m.singleVisible === 1 ? 0 : 1
      this.msgList.forEach(m1 => {m1.singleVisible = m1.userId === m.userId ? m.singleVisible : !m.singleVisible})
      // 消息自可见
      let msg = {
        liveId: this.liveId,
        userId: m.userId,
        userType: 0,
        cmd: 'singleVisible',
        status:m.singleVisible
      }
      this.socket.send(JSON.stringify(msg))
    },
    deleteMsg(m){
      // 1. 弹出确认对话框
      this.$confirm('此操作将永久删除该消息, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delLiveMsg(m.msgId).then(res => {
          if (res.code === 200) {
            const index = this.msgList.findIndex(item => item.msgId === m.msgId);
            if (index !== -1) {
              this.msgList.splice(index, 1);
              console.log(`消息 ${m.msgId} 已在本地删除。`);
            }
            let msg = {
              liveId: this.liveId,
              userId: m.userId,
              msg: m.msgId, // 关键：将消息ID发送给后台
              cmd: 'deleteMsg',
            };
            this.socket.send(JSON.stringify(msg));
            // 可以在这里给用户一个删除成功的提示
            this.$message({
              type: 'success',
              message: '消息删除成功!'
            });
          }
        })
      }).catch(() => {
        // 3. 用户点击“取消”或关闭对话框后的回调
        this.$message({
          type: 'info',
          message: '已取消删除'
        });
      });
    },
    globalVisibleChange( val){
      // 消息自可见
      let msg = {
        liveId: this.liveId,
        userId: '9999',
        userType: 0,
        cmd: 'globalVisible',
        status:this.globalVisible ? 1 :0
      }
      this.socket.send(JSON.stringify(msg))
    },
    showCartChange(val) {
      const status = val ? 1 : 0
      updateShowCart({ liveId: this.liveId, showCart: status }).then(res => {
        if (res.code !== 200) {
          this.$message.error(res.msg || '更新购物车显示状态失败')
          this.showCart = !val
          return
        }
        if (this.socket && this.socket.readyState === WebSocket.OPEN) {
          this.socket.send(JSON.stringify({
            liveId: this.liveId,
            userId: '9999',
            userType: 0,
            cmd: 'showCart',
            status
          }))
        }
      }).catch(() => {
        this.showCart = !val
        this.$message.error('更新购物车显示状态失败')
      })
    },
    changeAutoWatermark( val){
      this.watermarkList = this.watermarkTemplate
        .split('\n')
        .map(line => line.trim())
        .filter(line => line !== '');
      if(this.watermarkTemplate.length < 1 || this.watermarkList.length === 0) {
        this.$message.warning('请先填写水印模板')
        this.$nextTick(() => {
          this.autoWatermark = false
        });
        return
      }
      this.disabled = this.autoWatermark
      if(this.autoWatermark){
        this.autoMsgTimer = setInterval(() => {
          this.sendNormalMessage()
        }, 1000 * this.interval)
      } else {
        clearInterval(this.autoMsgTimer)
        this.watermarkIndex = 0;
        this.watermarkList = [];
      }
    },
    sendNormalMessage() {
      if(this.watermarkIndex >= this.watermarkList.length){
        clearInterval(this.autoMsgTimer)
        this.watermarkIndex = 0;
        this.watermarkList = [];
        this.$message.success('自动发送消息已结束');
        this.$nextTick(() => {
          this.autoWatermark = false
        });
        return;
      }
      const curMsg = this.watermarkList[this.watermarkIndex]
      // 发送前简单校验
      if (curMsg.trim() === '') {
        return;
      }
      let msg = {
        msg: curMsg,
        liveId: this.liveId,
        userId: '9999',
        userType: 0,
        cmd: 'sendNormalMsg',
        avatar: this.$store.state.user.user.avatar,
        nickName: this.$store.state.user.user.nickName,
      }
      this.socket.send(JSON.stringify(msg))
      this.watermarkIndex += 1
    },
    sendMessage() {
      // 发送前简单校验
      if (this.newMsg.trim() === '') {
        return;
      }

      let msg = {
        msg: this.newMsg,
        liveId: this.liveId,
        userId: this.userId,
        userType: 1,
        cmd: 'sendMsg',
        avatar: this.$store.state.user.user.avatar,
        nickName: this.$store.state.user.user.nickName,
      }

      this.socket.send(JSON.stringify(msg))

      this.newMsg = '';
    },
    handleWsMessage(event) {
      let { code, data } = JSON.parse(event.data)
      if (code === 200) {
        let { cmd } = data
        if (cmd === 'sendMsg') {
          let message = JSON.parse(data.data)

          let user = this.alDisplayList.find(u => u.userId === message.userId)
          if (user) {
            message.msgStatus = user.msgStatus
          } else {
            message.msgStatus = 0
          }
          delete message.params
          if(this.msgList.length > 50){
            this.msgList.shift()
          }
          this.msgList.push(message)
          // 如果启用自动滚动，自动滚动到底部
          if (this.isAutoScrollEnabled) {
            this.$nextTick(() => {
              this.autoScrollTimer = setTimeout(() => {
                this.scrollToBottom();
              }, 200);
            });
          } else {
            // 自动滚动被禁用时，显示加载最新消息按钮
            this.showLoadLatestBtn = true;
          }
        } else if (cmd === 'entry' || cmd === 'out') {
          const user = data;
          const online = cmd === 'entry' ? 0 : 1; // 0=在线，1=离线
          const info = {
            online:online,
            msgStatus: user.msgStatus || 0,
            nickName: user.nickName || '',
            userType: user.userType || 0,
            userId: user.userId || '',
          };

          // 1. 更新总人数（在线/离线互转）
          if (cmd === 'entry') {
            this.userTotal.online += 1;
            this.userTotal.offline = Math.max(0, this.userTotal.offline - 1); // 确保不小于0
          } else {
            this.userTotal.offline += 1;
            this.userTotal.online = Math.max(0, this.userTotal.online - 1); // 确保不小于0
          }
          // 2. 强制更新相关列表（无论当前激活哪个Tab）
          if (cmd === 'entry') {
            // 用户进入：从离线列表删除，添加到在线列表
            this.offlineDisplayList = this.offlineDisplayList.filter(u => u.userId !== user.userId);
            const newOnlineList = this.onlineDisplayList.filter(u => u.userId !== user.userId);
            newOnlineList.push(info);
            this.onlineDisplayList = newOnlineList.slice(-40); // 限制最大50条
          } else {
            // 用户离开：从在线列表删除，添加到离线列表
            this.onlineDisplayList = this.onlineDisplayList.filter(u => u.userId !== user.userId);
            const newOfflineList = this.offlineDisplayList.filter(u => u.userId !== user.userId);
            newOfflineList.push(info);
            this.offlineDisplayList = newOfflineList.slice(-40); // 限制最大50条
          }
          // 3. 处理禁言列表（如果用户是禁言状态，无论进出都要同步）
          if (info.msgStatus === 1) {
            // 禁言用户：从禁言列表删除旧数据，添加新数据
            const newSilencedList = this.silencedDisplayList.filter(u => u.userId !== user.userId);
            newSilencedList.push(info);
            this.silencedDisplayList = newSilencedList.slice(-40);
          } else {
            // 非禁言用户：从禁言列表删除（如果存在）
            this.silencedDisplayList = this.silencedDisplayList.filter(u => u.userId !== user.userId);
          }

        } else if (cmd === 'live_start') {

        } else if (cmd === 'live_end') {

        }
      }
    },
    getLive(){
      getLive(this.liveId).then(res => {
        if (res.code == 200) {
          if (res.data.isAudit != 1) {
            this.$message.error("当前直播间未经审核");
            this.loading = false
            return
          }
          this.isAudit = true
          this.status = res.data.status
          this.videoParam.startTime = new Date(res.data.startTime).getTime()
          if(res.data.status == 4){
            this.videoParam.liveType = 3
            this.videoParam.videoUrl = res.data.videoUrl;
          }else {
            if (res.data.status != 2) {
              this.$message.error("当前直播间未直播");
              this.loading = false
              return
            }
            if (res.data.liveType == 1) {
              this.videoParam.livingUrl = res.data.flvHlsUrl
              this.videoParam.livingUrl = this.videoParam.livingUrl.replace("flv","m3u8")
              // this.$nextTick(() => {
              //   this.initPlayer()
              // })
              // this.processInterval = setInterval(this.updateLiveProgress, 1000);
            } else {
              this.videoParam.liveType = 2
              this.videoParam.videoUrl = res.data.videoUrl;
              // this.$nextTick(() => {
              //   this.initVideoPlayer(res.data.startTime)
              // })
            }
          }
          this.$nextTick(() => {
            this.globalVisible = res.data.globalVisible
            this.showCart = res.data.showCart == null || res.data.showCart === 1
            this.$refs.livePlayer.initPlayer()
          })
          this.loading = false
        } else {
          this.$message.error(res.msg)
          this.loading = false
        }
        this.liveInfo = res.data
      })
    },
    connectWebSocket() {
      this.$store.dispatch('initLiveWs', {
        liveWsUrl: this.liveWsUrl,
        liveId: this.liveId,
        userId: this.userId
      })
      this.socket = this.$store.state.liveWs[this.liveId]
      this.socket.onmessage = (event) => this.handleWsMessage(event)
    },
    changeUserState(u) {
      const displayList = this[`${this.currentTab}DisplayList`];
      // 修改状态
      changeUserStatus({liveId: u.liveId, userId: u.userId}).then(response => {
        let { code } = response;
        if (200 === code) {
          u.msgStatus = u.msgStatus === 0 ? 1 : 0
          // 同步更新消息列表中相同用户的状态
          this.msgList.forEach(msg => {
            if (msg.userId === u.userId) {
              msg.msgStatus = u.msgStatus;
            }
          });

          displayList.forEach(user => {
            if (user.userId === u.userId) {
              user.msgStatus = u.msgStatus;
            }
          });
          // 4. 关键：重新筛选所有Tab的显示列表，确保状态同步
          this.refreshUserDisplayLists(u);

          let msg = u.msgStatus === 0 ? "已解禁" : "已禁言"
          this.msgSuccess(msg);
          return
        }
        this.msgError("操作失败");
      })
    },
    refreshUserDisplayLists(user) {
      const { userId, msgStatus: newStatus, online } = user;
      const oldStatus = newStatus === 1 ? 0 : 1; // 操作前的状态（反向）

      // 1. 禁言操作（newStatus=1）：从原在线/离线列表移除，加入禁言列表
      if (newStatus === 1) {
        // 从在线/离线列表中移除该用户（根据当前在线状态）
        if (online === 0) {
          this.onlineDisplayList = this.onlineDisplayList.filter(u => u.userId !== userId);
          this.userTotal.online = Math.max(0, this.userTotal.online - 1);
        } else {
          this.offlineDisplayList = this.offlineDisplayList.filter(u => u.userId !== userId);
          this.userTotal.offline = Math.max(0, this.userTotal.offline - 1);
        }
        this.userTotal.silenced = this.userTotal.silenced + 1;
        // 添加到禁言列表（去重+限制长度）
        const silencedList = this.silencedDisplayList.filter(u => u.userId !== userId);
        silencedList.push(user);
        this.silencedDisplayList = silencedList.slice(-40);
      }

      // 2. 解禁操作（newStatus=0）：从禁言列表移除，回到原在线/离线列表
      else {
        // 从禁言列表移除
        this.silencedDisplayList = this.silencedDisplayList.filter(u => u.userId !== userId);
        this.userTotal.silenced = Math.max(0, this.userTotal.silenced - 1);
        // 回到对应的在线/离线列表（根据当前在线状态）
        if (online === 0) {
          // 加入在线列表（去重+限制长度）
          const onlineList = this.onlineDisplayList.filter(u => u.userId !== userId);
          onlineList.push(user);
          this.onlineDisplayList = onlineList.slice(-40);
          this.userTotal.online = this.userTotal.online + 1;
        } else {
          // 加入离线列表（去重+限制长度）
          const offlineList = this.offlineDisplayList.filter(u => u.userId !== userId);
          offlineList.push(user);
          this.offlineDisplayList = offlineList.slice(-40);
          this.userTotal.offline = this.userTotal.offline + 1;
        }
      }
    },
    blockUser(u){
      this.$confirm('是否确认封禁用户账号为:"' + u.nickName + '-' + u.userId + '"?', "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      }).then(function() {
        return blockUser(u.userId);
      }).then(() => {
        if(u.msgStatus === 1){
          this.userTotal.silenced -= 1
          this.silencedDisplayList = this.silencedDisplayList.filter(user => user.userId !== u.userId)
        } else if( u.online === 0){
          this.userTotal.online -= 1
          this.onlineDisplayList = this.onlineDisplayList.filter(user => user.userId !== u.userId)
        } else {
          this.userTotal.offline -= 1
          this.offlineDisplayList = this.offlineDisplayList.filter(user => user.userId !== u.userId)
        }
        this.userTotal.al -= 1
        this.alDisplayList = this.alDisplayList.filter(user => user.userId !== u.userId)
        let msg = {
          msg: "",
          liveId: this.liveId,
          userId: u.userId,
          userType: 0,
          cmd: 'blockUser',
          avatar: this.$store.state.user.user.avatar,
          nickName: this.$store.state.user.user.nickName
        }
        this.socket.send(JSON.stringify(msg))
        this.msgSuccess("封禁成功");


      }).catch(() => {});
    },
    searchUsers(){
      this.resetUserParams()
      this.loadNextPage(this.currentTab)
    },
    handleUserClick(tab){
      const tabName = tab.name;
      this.currentTab = tabName;
      const params = this.pageParams[tabName];
      const displayList = this[`${tabName}DisplayList`];
      // 首次切换到该Tab或列表为空时初始化
      if (displayList.length < 20) {
        // 重置分页参数
        params.currentPage = 1;
        params.pageSize = 20;
        params.prevPage = 0;
        params.totalLoaded = 0;
        params.hasMore = true;
        params.hasPrev = false;
        // 加载第一页
        this.loadNextPage(tabName);
      } else {
        // 非首次切换，恢复滚动位置
        this.$nextTick(() => {
          const scrollEl = this.getScrollElement(tabName);
          if (scrollEl) {
            scrollEl.scrollTop = this.tabScrollPositions[tabName] || 0;
          }
        });
      }
    },
    loadNextPage(tabName) {
      const params = this.pageParams[tabName];
      const displayList = this[`${tabName}DisplayList`];

      // 若没有更多数据或正在加载，直接返回
      if (!params.hasMore || this.scrLoading[tabName].next) {
        return;
      }

      this.scrLoading[tabName].next = true;
      const queryParams = {
        liveId: this.liveId,
        pageNum: params.currentPage,
        pageSize: 20,
        online: tabName === 'online' ? 0 : 1,
        msgStatus: tabName === 'silenced' ? 1 : 0,
        all: tabName === 'al' ? 1 : 0,
        userName: this.searchKeyword
      };
      // 调用接口加载对应状态的分页数据（需后端支持按状态筛选）
      dashBoardWatchUserList(queryParams).then(response => {
        this.scrLoading[tabName].next = false;
        if (response.code !== 200) return;

        const { rows, total } = response;
        params.total = total; // 记录总数据量
        // 过滤重复数据（基于userId）
        const newRows = rows.filter(row =>
          !displayList.some(u => u.userId === row.userId)
        );
        displayList.push(...newRows)
        // 添加新数据并限制最大长度（避免内存占用过大）
        if (displayList.length >= 40) { // 最大保留100条
          this[`${tabName}DisplayList`] = displayList.slice(-40);
          // 记录滚动位置（用于加载后校准）
          const scrollEl = this.getScrollElement(tabName);
          // 校准滚动位置（保持视觉连续性）
          this.$nextTick(() => {
            if (scrollEl) {
              scrollEl.scrollTop = scrollEl.scrollHeight * 0.5;
            }
          });
        }
        // 更新分页状态
        params.hasMore = params.currentPage * params.pageSize < total;
        params.currentPage += 1;
        params.hasPrev = params.currentPage > 2; // 当前页>2时一定有上一页
        params.prevPage = params.currentPage - 2;
      }).catch(() => {
        this.scrLoading[tabName].next = false;
      });
    },
    // 新增：加载上一页（向上滚动时）
    loadPrevPage(tabName) {
      const params = this.pageParams[tabName];
      const displayList = this[`${tabName}DisplayList`];
      // 边界校验：无上一页/正在加载/当前页<=1
      console.log(`加载 ${tabName} 上一页`);
      console.log(!params.hasPrev || this.scrLoading[tabName].prev || params.currentPage <= 1)
      if (!params.hasPrev || this.scrLoading[tabName].prev || params.currentPage <= 1) {
        return;
      }
      this.scrLoading[tabName].prev = true;
      const targetPage = params.prevPage > 0 ? params.prevPage : params.currentPage - 2;
      const queryParams = {
        liveId: this.liveId,
        pageNum: targetPage,
        pageSize: 20,
        online: tabName === 'online' ? 0 : 1,
        msgStatus: tabName === 'silenced' ? 1 : 0,
        all: tabName === 'al' ? 1 : 0,
        userName: this.searchKeyword
      };
      dashBoardWatchUserList(queryParams).then(response => {
        this.scrLoading[tabName].prev = false;
        if (response.code !== 200) return;

        const { rows } = response;
        if (rows.length === 0) {
          params.hasPrev = false;
          return;
        }

        // 记录滚动位置（用于加载后校准）
        const scrollEl = this.getScrollElement(tabName);
        const scrollTop = scrollEl?.scrollTop || 0;
        const itemHeight = 80; // 预估行高（根据实际样式调整）
        const newItemsHeight = rows.length * itemHeight;

        // 过滤重复数据并添加到列表头部
        const newRows = rows.filter(row => !displayList.some(u => u.userId === row.userId));
        this[`${tabName}DisplayList`] = [...newRows, ...displayList];
        params.totalLoaded += newRows.length;

        // 限制最大长度
        if (this[`${tabName}DisplayList`].length > 40) {
          this[`${tabName}DisplayList`] = this[`${tabName}DisplayList`].slice(0, 40);
        }

        // 更新分页状态
        params.prevPage = targetPage - 1;
        params.hasPrev = targetPage > 1; // 上一页页码>1时还有更多上一页
        params.currentPage = params.currentPage - 1;
        if(params.currentPage * 20 < params.total) params.hasMore = true;
        // 校准滚动位置（保持视觉连续性）
        this.$nextTick(() => {
          if (scrollEl) {
            scrollEl.scrollTop = scrollEl.scrollHeight * 0.5;
          }
        });
      }).catch(() => {
        this.scrLoading[tabName].prev = false;
      });
    },
    getList() {
      this.resetUserParams()
      this.resetMsgParams()
      // this.loadUserList()
      this.loadUserTotals(); // 先加载总人数
      // this.handleClick('online')
      // this.handleClick({name:'online'})
      this.loadMsgList()
      this.loadLiveTask()
      this.loadMarketingData()
    },
    formatDate(value) {
      // 检查值是否存在且为日期类型（或可转换为日期）
      if (!value) return '';

      let date;
      // 处理字符串类型的日期
      if (typeof value === 'string') {
        date = new Date(value);
      }
      // 处理Date对象
      else if (value instanceof Date) {
        date = value;
      }
      // 无效类型直接返回原值
      else {
        return value;
      }

      // 检查是否为有效日期
      if (isNaN(date.getTime())) {
        return value;
      }

      // 格式化年月日时分秒（补零处理）
      const year = date.getFullYear();
      const month = String(date.getMonth() + 1).padStart(2, '0');
      const day = String(date.getDate()).padStart(2, '0');
      const hours = String(date.getHours()).padStart(2, '0');
      const minutes = String(date.getMinutes()).padStart(2, '0');
      const seconds = String(date.getSeconds()).padStart(2, '0');

      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },
    loadLiveTask(){
      if(!this.taskParams.hasMore) return
      const queryParams = {
        liveId: this.liveId,
        pageSize: 10,
        pageNum: 1
      }
      consoleList(queryParams).then(res => {
        let {code, rows,total} = res;
        if (code === 200) {
          this.taskParams.total = total
          this.timelineItems = rows
          if(rows.length  < this.taskParams.pageSize){
            this.taskParams.hasMore = false
          }
          this.startTaskTimer()
        } else {
          this.stopTaskTimer()
        }
      })
    },
    loadMsgList(){
      // 直播间消息
      listLiveSingleMsg({
        liveId:this.liveId,
        pageNum: this.msgParams.pageNum,
        pageSize: this.msgParams.pageSize
      }).then(response => {
        let {code, rows,total} = response;
        if (code === 200) {
          let totalPage = (total % this.msgParams.pageSize == 0) ? Math.floor(total / this.msgParams.pageSize) : Math.floor(total / this.msgParams.pageSize + 1);
          rows.forEach(row => {
            if (!this.msgList.some(m => m.msgId === row.msgId)) {
              let user = this.alDisplayList.find(u => u.userId === row.userId)
              if (user) {
                row.msgStatus = user.msgStatus
              } else {
                row.msgStatus = 0
              }
              this.msgList.push(row)
            }
          })

          this.msgList.reverse()
          // 同步更新消息列表中相同用户的状态
          this.alDisplayList.forEach(u => {
            this.msgList.filter(m => m.userId === u.userId).forEach(m => m.msgStatus = u.msgStatus)
          })
          // 所有消息加载完成后，根据自动滚动状态决定是否滚动
          this.$nextTick(() => {
            setTimeout(() => {
              // 重置加载状态
              this.isLoadingLatest = false;

              if (this.isAutoScrollEnabled) {
                // 如果启用自动滚动，强制滚动到底部并隐藏按钮
                this.scrollToBottom(true);
              } else {
                // 如果禁用自动滚动，检查是否在底部，决定是否显示按钮
                if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
                  const wrap = this.$refs.manageRightRef.wrap;
                  const scrollHeight = wrap.scrollHeight;
                  const clientHeight = wrap.clientHeight;
                  const currentScrollTop = wrap.scrollTop;
                  const maxScrollTop = scrollHeight - clientHeight;

                  if (currentScrollTop < maxScrollTop - 50) {
                    this.showLoadLatestBtn = true;
                  } else {
                    this.showLoadLatestBtn = false;
                  }
                }
              }
            }, 300);
          });
        }
      })

      // 添加滚动监听
      this.$nextTick(() => {
        if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
          this.$refs.manageRightRef.wrap.addEventListener("scroll", this.manageRightScroll)
        }
      })
    },
    // 消息滚动监听（带防抖）
    manageRightScroll() {
      // 清除之前的防抖定时器
      if (this.scrollDebounceTimer) {
        clearTimeout(this.scrollDebounceTimer);
      }

      // 设置防抖，300ms内只执行一次
      this.scrollDebounceTimer = setTimeout(() => {
        this.saveChatScrollPosition();

        // 检查是否滚动到底部
        if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
          const wrap = this.$refs.manageRightRef.wrap;
          const scrollHeight = wrap.scrollHeight;
          const clientHeight = wrap.clientHeight;
          const currentScrollTop = wrap.scrollTop;
          const maxScrollTop = scrollHeight - clientHeight;

          // 如果滚动到底部（距离底部小于50px），隐藏按钮并恢复自动滚动
          if (currentScrollTop >= maxScrollTop - 50) {
            this.showLoadLatestBtn = false;
            this.isAutoScrollEnabled = true;
          }
        }
      }, 300);
    },
    loadUserTotals() {
      if (!this.liveId) return;
      // 假设后端提供一个接口返回总人数（如果没有，可通过首次加载全量数据后统计）
      getLiveUserTotals({ liveId: this.liveId }).then(res => {
        if (res.code === 200) {
          this.userTotal = res.data; // { online, offline, silenced }
        }
      });
    },
    toggleBlack(user) {
      user.isBlack = !user.isBlack;
    },
    toggleMute(user) {
      user.isMuted = !user.isMuted;
    },
    toggleVisible(msg) {
      msg.isVisible = !msg.isVisible;
    },
    deleteMessage(msg) {
      const index = this.messages.indexOf(msg);
      if (index > -1) {
        this.messages.splice(index, 1);
      }
    },
    addTimelineItem() {
      this.timelineItems.push({ time: '00:00', action: '新动作' });
    },
    removeTimelineItem(item) {
      const index = this.timelineItems.indexOf(item);
      if (index > -1) {
        this.timelineItems.splice(index, 1);
      }
    },
    resetUserParams() {
      // 重置各Tab的显示列表和分页参数
      this.alDisplayList = [];
      this.onlineDisplayList = [];   // 在线用户显示列表
      this.offlineDisplayList = [];   // 离线用户显示列表
      this.silencedDisplayList = [];  // 禁言用户显示列表
      this.pageParams=  {
        al: {
          currentPage: 1,
          pageSize: 20,
          prevPage: 0,
          totalLoaded: 0,
          total: 0,
          hasMore: true,
          hasPrev: false
        },
        online: {
          currentPage: 1,       // 当前页（下一页加载用）
          pageSize: 20,       // 当前页（下一页加载用）
          prevPage: 0,          // 上一页页码（上一页加载用）
          totalLoaded: 0,       // 已加载总条数
          total: 0,             // 总数据量
          hasMore: true,        // 是否有下一页
          hasPrev: false        // 是否有上一页
        },
        offline: {
          currentPage: 1,
          pageSize: 20,
          prevPage: 0,
          totalLoaded: 0,
          total: 0,
          hasMore: true,
          hasPrev: false
        },
        silenced: {
          currentPage: 1,
          pageSize: 20,
          prevPage: 0,
          totalLoaded: 0,
          total: 0,
          hasMore: true,
          hasPrev: false
        }
      },
        this.scrLoading = {
          al: { next: false, prev: false },
          online: { next: false, prev: false },
          offline: { next: false, prev: false },
          silenced: { next: false, prev: false }
        }
    },
    resetMsgParams() {
      // 消息参数保留
      this.msgList = [];
      this.msgParams = {
        pageNum: 1,
        pageSize: 30,
        liveId: this.liveId
      };
      // 重置时不改变按钮状态，由后续的滚动逻辑决定
      this.taskParams = {
        currentPage: 1,
        pageSize: 20,
        prevPage: 0,
        totalLoaded: 0,
        total: 0,
        hasMore: true,
        hasPrev: false
      }
    },
    getScrollElement(tabName) {
      const scrollRefs = {
        al: this.$refs.manageLeftRef_al,
        online: this.$refs.manageLeftRef_online,
        offline: this.$refs.manageLeftRef_offline,
        silenced: this.$refs.manageLeftRef_silenced
      };
      return scrollRefs[tabName]?.wrap;
    },
    // 初始化滚动监听（在mounted中调用）
    initScrollListeners() {
      // 为每个Tab的滚动容器添加监听
      this.$nextTick(() => {
        const scrollRefs = {
          al: this.$refs.manageLeftRef_al,
          online: this.$refs.manageLeftRef_online,
          offline: this.$refs.manageLeftRef_offline,
          silenced: this.$refs.manageLeftRef_silenced
        };

        Object.keys(scrollRefs).forEach(tabName => {
          const scrollEl = scrollRefs[tabName]?.wrap;
          if (scrollEl) {
            scrollEl.addEventListener('scroll', () =>
              this.handleTabScroll(tabName, scrollEl)
            );
          }
        });
      });
    },
    // 处理Tab滚动事件（判断是否触底）
    handleTabScroll(tabName, scrollEl) {
      const { scrollTop, scrollHeight, clientHeight } = scrollEl;
      const bottomThreshold = 50; // 距离底部100px触发下一页
      const topThreshold = 50;    // 距离顶部100px触发上一页

      // 加载下一页（滚动到底部附近）
      if (scrollHeight - scrollTop - clientHeight < bottomThreshold) {
        this.loadNextPage(tabName);
      }

      // 加载上一页（滚动到顶部附近）
      if (scrollTop < topThreshold) {
        this.loadPrevPage(tabName);
      }
    },
    // 恢复聊天滚动位置
    restoreChatScrollPosition() {
      if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
        this.$refs.manageRightRef.wrap.scrollTop = this.chatScrollTop;
      }
    },
    // 保存聊天滚动位置
    saveChatScrollPosition() {
      if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
        this.chatScrollTop = this.$refs.manageRightRef.wrap.scrollHeight - this.$refs.manageRightRef.wrap.clientHeight;
      }
    },
    /**
     * 停止任务检测定时器
     */
    stopTaskTimer() {
      if (this.taskTimer) {
        clearInterval(this.taskTimer);
        this.taskTimer = null;
      }
    },
    /**
     * 启动任务检测定时器
     */
    startTaskTimer() {
      // 先清除已有定时器，避免重复
      if (this.taskTimer) {
        clearInterval(this.taskTimer);
      }

      // 立即执行一次检查
      this.checkTaskExpiration();

      // 启动定时器，定期检查
      this.taskTimer = setInterval(() => {
        this.checkTaskExpiration();
      }, this.checkInterval);
    },
    /**
     * 检查时间轴第一条任务是否过期
     */
    checkTaskExpiration() {
      // 如果没有任务，直接返回
      if (!this.timelineItems || this.timelineItems.length === 0) {
        this.stopTaskTimer()
        return;
      };

      // 获取第一条任务的时间
      const firstTask = this.timelineItems[0];
      const taskTime = new Date(firstTask.absValue).getTime();
      const currentTime = new Date().getTime();

      // 如果任务时间已过当前时间（过期），重新加载任务列表
      if (taskTime < currentTime) {
        this.timelineItems.shift()
        this.loadLiveTask(); // 重新加载任务列表
      }
    },
  },
  beforeDestroy() {
    if (this.autoMsgTimer != null) {
      clearInterval(this.autoMsgTimer);
    }
    if (this.autoScrollTimer) {
      clearTimeout(this.autoScrollTimer);
    }
    if (this.scrollDebounceTimer) {
      clearTimeout(this.scrollDebounceTimer);
    }
    // 移除滚动监听器
    if (this.$refs.manageRightRef && this.$refs.manageRightRef.wrap) {
      this.$refs.manageRightRef.wrap.removeEventListener("scroll", this.manageRightScroll);
    }
  },
  // 使用 deactivated 和 activated 钩子替代 beforeDestroy 和 destroyed
  deactivated() {
    this.saveChatScrollPosition();
  },
  activated() {
    this.$nextTick(() => {
      this.restoreChatScrollPosition();
    });
    // todo yhq
    // this.$nextTick(() => {
    //   const video = this.$refs.videoPlayer;
    //   if (video != null) {
    //     this.initVideoPlayer(this.liveInfo.startTime)
    //   }
    // })
  },
};
</script>

<style scoped>
/* 布局 */
.console {
  display: flex;
  height: 100vh;
  overflow: hidden;
  background: #f5f7fa;
}

.left-panel,
.middle-panel,
.right-panel {
  display: flex;
  flex-direction: column;
  padding: 16px;
  box-sizing: border-box;
  overflow: hidden;
}

.left-panel {
  width: 28%;
  border-right: 1px solid #ebeef5;
}

.middle-panel {
  width: 42%;
  border-right: 1px solid #ebeef5;
  gap: 12px;
}

.right-panel {
  width: 30%;
  overflow-y: auto;
  gap: 12px;
}

/* 通用标题与卡片 */
.panel-title {
  margin: 0 0 12px;
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  line-height: 1.4;
}

.section-title {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  color: #303133;
}

.section-subtitle {
  margin: 0 0 8px;
  font-size: 13px;
  color: #909399;
}

.section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.panel-card {
  background: #fff;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 12px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
}

.toolbar-label {
  font-size: 13px;
  color: #606266;
}

.action-link {
  display: inline-block;
  margin-right: 10px;
  font-size: 12px;
  color: #f56c6c;
  cursor: pointer;
}

.action-link:hover {
  opacity: 0.85;
}

.panel-footer {
  display: flex;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid #ebeef5;
}

/* 学员列表 */
.search-bar {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
}

.search-bar .el-input {
  flex: 1;
}

.console-tabs {
  flex: 1;
  min-height: 0;
}

.console-tabs ::v-deep .el-tabs__content {
  height: calc(100% - 40px);
}

.console-tabs ::v-deep .el-tab-pane {
  height: 100%;
}

.panel-scroll {
  height: calc(100vh - 180px);
}

.user-list-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 8px;
  border-bottom: 1px solid #f2f6fc;
}

.user-list-item:hover {
  background: #f5f7fa;
}

.user-meta {
  flex: 1;
  min-width: 0;
}

.user-name {
  font-size: 13px;
  color: #303133;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-id {
  margin-top: 2px;
  font-size: 12px;
  color: #909399;
}

.user-more-btn {
  color: #909399;
  cursor: pointer;
  padding: 4px;
}

.user-more-btn:hover {
  color: #409eff;
}

/* 讨论区消息 */
.discussion-messages {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.message-container {
  position: relative;
  flex: 1;
  min-height: 0;
}

.msg-scroll {
  height: calc(100vh - 520px);
  min-height: 180px;
}

.msg-item + .msg-item {
  margin-top: 8px;
}

.msg-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.msg-row--self {
  justify-content: flex-end;
}

.msg-content {
  max-width: 72%;
}

.msg-content--self {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

.msg-nickname {
  margin-bottom: 4px;
  font-size: 12px;
  color: #909399;
}

.msg-bubble {
  padding: 8px 10px;
  border-radius: 4px;
  background: #f4f4f5;
  font-size: 13px;
  line-height: 1.5;
  color: #303133;
  word-break: break-word;
}

.msg-bubble--self {
  background: #ecf5ff;
}

.msg-actions {
  margin-top: 6px;
}

.msg-avatar {
  flex-shrink: 0;
}

.scroll-bottom-space {
  height: 16px;
}

.load-latest-btn {
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 2;
}

/* 营销 / 系统消息 */
.ops-panel {
  flex-shrink: 0;
}

.ops-tabs ::v-deep .el-tabs__header {
  margin-bottom: 10px;
}

.ops-tabs ::v-deep .el-tabs__content {
  overflow: visible;
}

.marketing-panel,
.system-msg-panel {
  display: flex;
  flex-direction: column;
}

.marketing-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
  flex-wrap: wrap;
}

.marketing-tip {
  flex: 1;
  min-width: 200px;
  padding: 4px 8px;
}

.marketing-tip ::v-deep .el-alert__title {
  font-size: 12px;
}

.marketing-categories {
  margin-bottom: 10px;
}

.marketing-scroll {
  height: 150px;
}

.marketing-cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  padding-right: 4px;
}

.marketing-card {
  border: 1px solid #ebeef5;
  border-radius: 4px;
  overflow: hidden;
  cursor: pointer;
  background: #fff;
  transition: border-color 0.2s;
}

.marketing-card:hover,
.marketing-card.selected {
  border-color: #409eff;
}

.card-image-wrap {
  position: relative;
  height: 72px;
  overflow: hidden;
  background: #f5f7fa;
}

.card-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.card-tags {
  position: absolute;
  top: 6px;
  left: 6px;
  display: flex;
  gap: 4px;
}

.card-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 6px;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.2s;
}

.marketing-card:hover .card-overlay {
  opacity: 1;
}

.card-info {
  padding: 6px 8px;
}

.card-title {
  font-size: 12px;
  color: #303133;
  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;
  font-weight: 600;
  color: #f56c6c;
}

.marketing-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 4px;
}

.marketing-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
  transition: border-color 0.2s;
}

.marketing-list-item:hover,
.marketing-list-item.selected {
  border-color: #409eff;
  background: #f5f9ff;
}

.list-main {
  flex: 1;
  min-width: 0;
}

.list-title {
  font-size: 13px;
  color: #303133;
  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;
}

.list-price {
  margin-right: 6px;
  color: #f56c6c;
  font-weight: 600;
}

.list-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 6px;
}

.list-actions {
  display: flex;
  flex-shrink: 0;
  flex-wrap: wrap;
  gap: 4px;
  justify-content: flex-end;
}

/* 右侧运营工具 */
.live-player,
.automation,
.watermark {
  margin: 0;
}

.timeline-items {
  margin-top: 4px;
}

.timeline-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid #f2f6fc;
}

.timeline-time {
  font-size: 12px;
  color: #909399;
}

.timeline-action {
  margin-top: 2px;
  font-size: 13px;
  color: #303133;
}

.watermark-options {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

/* 滚动条 */
::v-deep .el-scrollbar__wrap {
  overflow-x: hidden !important;
}
</style>

<style>
.user-action-popover .action-link {
  display: block;
  margin: 0 0 8px;
  font-size: 13px;
  color: #f56c6c;
  cursor: pointer;
}

.user-action-popover .action-link:last-child {
  margin-bottom: 0;
}
</style>
