<template>
  <div class="app-container qw-msg-audit-page">
    <div class="audit-shell">
      <!-- 左：主体 + 员工 -->
      <aside class="audit-left">
        <div class="aside-block aside-corp">
          <div class="block-label">企微主体</div>
          <el-select
            v-model="corpId"
            filterable
            clearable
            placeholder="请选择企微主体"
            size="small"
            class="corp-select"
            :loading="corpLoading"
            @change="handleCorpChange"
          >
            <el-option
              v-for="item in corpList"
              :key="item.dictValue"
              :label="item.dictLabel"
              :value="item.dictValue"
            />
          </el-select>
        </div>
        <div v-loading="userLoading" class="aside-block aside-users">
          <div class="block-label">员工</div>
          <el-input
            v-model="userFilter"
            size="small"
            clearable
            placeholder="筛选当前页"
            prefix-icon="el-icon-search"
            class="user-search"
          />
          <el-scrollbar class="user-scroll">
            <div
              v-for="u in filteredUsers"
              :key="userRowKey(u)"
              class="user-item"
              :class="{ active: selectedUser && selectedUser.qwUserId === u.qwUserId }"
              @click="selectUser(u)"
            >
              <span class="user-name">{{ displayUserName(u) }}</span>
              <span class="user-id text-muted">{{ u.qwUserId }}</span>
            </div>
            <el-empty
              v-if="!userLoading && filteredUsers.length === 0"
              :image-size="72"
              description="暂无员工"
            />
          </el-scrollbar>
          <pagination
            v-show="userTotal > 0"
            small
            class="user-pagination"
            layout="prev, pager, next"
            :total="userTotal"
            :page.sync="userQuery.pageNum"
            :limit.sync="userQuery.pageSize"
            @pagination="loadUserList"
          />
        </div>
      </aside>

      <!-- 中：会话列表 -->
      <aside class="audit-conv">
        <div class="conv-head">
          <span class="conv-head-title">会话</span>
          <el-radio-group
            v-model="chatScope"
            size="mini"
            :disabled="!selectedUser"
            @change="handleChatScopeChange"
          >
            <el-radio-button label="single">单聊</el-radio-button>
            <el-radio-button label="group">群聊</el-radio-button>
          </el-radio-group>
        </div>

        <div v-loading="convLoading" class="conv-body">
          <el-scrollbar class="conv-scroll">
            <div
              v-for="(c, idx) in conversationList"
              :key="convKey(c, idx)"
              class="conv-item"
              :class="{ active: isSelectedConv(c) }"
              @click="selectConversation(c)"
            >
              <div class="conv-item-main">
                <el-avatar :src="convAvatar(c)" :size="40" shape="square" class="conv-avatar" />
                <div class="conv-text">
                  <div class="conv-title">{{ convTitle(c) }}</div>
                </div>
              </div>
            </div>
            <el-empty
              v-if="!convLoading && selectedUser && conversationList.length === 0"
              :image-size="56"
              description="暂无会话"
            />
            <div v-if="!selectedUser" class="conv-placeholder text-muted">请先选择左边的员工</div>
          </el-scrollbar>
          <pagination
            v-show="conversationTotal > 0"
            small
            class="conv-pagination"
            layout="prev, pager, next"
            :total="conversationTotal"
            :page.sync="conversationQuery.pageNum"
            :limit.sync="conversationQuery.pageSize"
            @pagination="loadConversationList"
          />
        </div>
      </aside>

      <!-- 右：聊天记录 -->
      <section class="audit-chat">
        <div class="chat-toolbar">
          <div class="toolbar-title">
            <template v-if="selectedUser && selectedConversation">
              <el-avatar :src="convAvatar(selectedConversation)" :size="36" shape="square" class="toolbar-avatar" />
              <span class="toolbar-name">{{ convTitle(selectedConversation) }}</span>
              <span class="text-muted toolbar-sub">· {{ displayUserName(selectedUser) }}</span>
            </template>
            <span v-else-if="selectedUser" class="text-muted">请选择会话</span>
            <span v-else class="text-muted">请先选择员工和会话</span>
          </div>
        </div>

        <div v-loading="msgLoading" class="chat-panel">
          <template v-if="selectedUser && selectedConversation">
            <el-scrollbar ref="msgScroll" class="msg-scroll">
              <div class="msg-list">
                <div v-if="msgLoadingMore" class="msg-load-tip">加载更早的消息…</div>
                <div
                  v-for="msg in messages"
                  :key="msg.id || msg.msgId"
                  class="msg-row"
                  :class="{ 'is-self': isSelfMessage(msg) }"
                >
                  <div class="msg-meta">
                    <span class="from">{{ msg.fromUserName }}</span>
                    <span class="time">{{ formatMsgTime(msg.msgTime) }}</span>
                    <span v-if="chatScope === 'group' && msg.roomId" class="room-tag">群 {{ shortRoom(msg.roomId) }}</span>
                  </div>
                  <div class="bubble">
                    <div v-if="msg.textContent" class="text">{{ msg.textContent }}</div>
                    <div
                      v-if="msg.mediaOssUrl"
                      class="media-box"
                      :class="'media-kind-' + msgMediaCategory(msg)"
                    >
                      <template v-if="msgMediaCategory(msg) === 'image'">
                        <img class="media-img" :src="msg.mediaOssUrl" alt="图片" />
                      </template>
                      <template v-else-if="msgMediaCategory(msg) === 'video'">
                        <div class="media-type-tag">{{ mediaKindTitle(msg) }}</div>
                        <video class="media-video" :src="msg.mediaOssUrl" controls preload="metadata" />
                      </template>
                      <template v-else-if="msgMediaCategory(msg) === 'voice'">
                        <div class="media-type-tag">{{ mediaKindTitle(msg) }}</div>
                        <audio class="media-audio" :src="msg.mediaOssUrl" controls preload="metadata" />
                      </template>
                      <template v-else>
                        <a
                          class="media-file-link"
                          :href="msg.mediaOssUrl"
                          target="_blank"
                          rel="noopener"
                        >{{ mediaKindTitle(msg) }}</a>
                        <span v-if="msg.mediaFileName" class="media-file-name">{{ msg.mediaFileName }}</span>
                      </template>
                    </div>
                    <div v-if="!msg.textContent && !msg.mediaOssUrl" class="fallback text-muted">
                      [{{ msgTypeLabel(msg.msgType) }}]
                      <template v-if="msg.mediaFileName">{{ msg.mediaFileName }}</template>
                    </div>
                  </div>
<!--                  <div class="msg-extra text-muted">-->
<!--                    <span v-if="msg.toList">to: {{ formatToList(msg.toList) }}</span>-->
<!--                    <span v-if="msg.fromUserRole != null && msg.fromUserRole !== ''"> · 角色 {{ msg.fromUserRole }}</span>-->
<!--                  </div>-->
                </div>
              </div>
              <el-empty v-if="!msgLoading && messages.length === 0" description="暂无消息" />
            </el-scrollbar>
          </template>
          <el-empty v-else-if="!selectedUser" description="在左侧选择员工和会话" />
          <el-empty v-else description="选择会话后查看消息记录" />
        </div>
      </section>
    </div>
  </div>
</template>

<script>
import { getMyQwCompanyList } from '@/api/qw/user'
import { qwList } from '@/api/qw/qwUser'
import { listQwMsgAuditConversation, listQwMsgAuditMessage } from '@/api/qw/qwMsgAuditMessage'

export default {
  name: 'QwMsgAuditMessage',
  data() {
    return {
      corpId: null,
      corpList: [],
      corpLoading: false,
      userList: [],
      userTotal: 0,
      userQuery: {
        pageNum: 1,
        pageSize: 20
      },
      userLoading: false,
      userFilter: '',
      selectedUser: null,
      chatScope: 'single',
      conversationList: [],
      conversationTotal: 0,
      conversationQuery: {
        pageNum: 1,
        pageSize: 15
      },
      convLoading: false,
      selectedConversation: null,
      messages: [],
      msgPageSize: 15,
      msgPageNum: 1,
      msgTotal: 0,
      msgHasMore: false,
      msgLoadingMore: false,
      msgLoading: false,
      _msgScrollWrap: null,
      _onMsgScroll: null
    }
  },
  computed: {
    filteredUsers() {
      const q = (this.userFilter || '').toLowerCase()
      if (!q) return this.userList
      return this.userList.filter((u) => {
        const name = (u.qwUserName || u.nickName || '').toLowerCase()
        const id = u.qwUserId != null ? String(u.qwUserId).toLowerCase() : ''
        return name.includes(q) || id.includes(q)
      })
    }
  },
  created() {
    this.loadCorpList()
  },
  // 离开页面时去掉滚动监听，避免内存泄漏
  beforeDestroy() {
    this.unbindMsgScroll()
  },
  methods: {
    // 气泡里显示时间
    formatMsgTime(t) {
      if (!t) return ''
      return this.parseTime(t)
    },
    // 群聊里 roomId 太长时缩略展示
    shortRoom(roomId) {
      if (!roomId) return ''
      const s = String(roomId)
      return s.length > 12 ? s.slice(0, 10) + '…' : s
    },

    // toList 可能是对象，转成可读字符串
    formatToList(toList) {
      if (toList == null) return ''
      if (typeof toList === 'string') return toList
      try {
        return JSON.stringify(toList)
      } catch (e) {
        return String(toList)
      }
    },
    msgTypeLabel(type) {
      if (type == null || type === '') return '未知类型'
      return String(type)
    },
    // 仅按 msgType 字符串区分：image / emotion → 图片，voice → 语音，video → 视频，file → 文件，其余按文件
    msgMediaCategory(msg) {
      if (!msg) return 'file'
      const s = msg.msgType == null ? '' : String(msg.msgType).toLowerCase()
      if (s === 'image' || s === 'emotion') return 'image'
      if (s === 'voice') return 'voice'
      if (s === 'video') return 'video'
      if (s === 'file') return 'file'
      return 'file'
    },
    mediaKindTitle(msg) {
      const map = { image: '图片', voice: '语音', video: '视频', file: '文件' }
      return map[this.msgMediaCategory(msg)] || '附件'
    },
    // 是否当前员工自己发的（用于绿气泡靠右）
    isSelfMessage(msg) {
      if (!this.selectedUser || !msg.fromUser) return false
      return String(msg.fromUser) === String(this.selectedUser.qwUserId)
    },
    displayUserName(u) {
      if (!u) return ''
      return u.qwUserName || ''
    },
    userRowKey(u) {
      return u.qwUserId
    },
    convKey(c, idx) {
      if (c && c.conversationKey != null) return String(c.conversationKey)
      return 'conv-' + idx
    },
    convTitle(c) {
      if (!c) return ''
      if (c.name) return c.name
      if (this.chatScope === 'group') {
        return c.roomName || '群聊'
      }
      return c.title || '—'
    },
    // 接口头像链接字段 Avatar（兼容 avatar）
    convAvatar(c) {
      if (!c) return ''
      return c.Avatar || c.avatar || ''
    },
    isSelectedConv(c) {
      if (!c || !this.selectedConversation) return false
      const a = c.conversationKey
      const b = this.selectedConversation.conversationKey
      if (a == null || b == null) return false
      return String(a) === String(b)
    },

    // full=true：换主体、员工被踢出当前页等，清空中间会话列表 + 右侧消息；full=false：只清空右侧消息与分页状态
    resetSession(full) {
      if (full) {
        this.selectedConversation = null
        this.conversationList = []
        this.conversationTotal = 0
        this.conversationQuery.pageNum = 1
      }
      this.messages = []
      this.msgPageNum = 1
      this.msgTotal = 0
      this.msgHasMore = false
    },

    // 拉主体下拉，默认选中第一项并顺带请求员工列表
    async loadCorpList() {
      this.corpLoading = true
      try {
        const res = await getMyQwCompanyList()
        this.corpList = res.data || []
        if (this.corpList.length > 0) {
          this.corpId = this.corpList[0].dictValue
          await this.handleCorpChange()
        } else {
          this.corpId = null
        }
      } catch (e) {
        this.corpList = []
        this.corpId = null
        this.$message.warning('获取企微主体失败')
      } finally {
        this.corpLoading = false
      }
    },

    // 左侧员工分页（依赖当前 corpId）
    async loadUserList() {
      if (!this.corpId) {
        this.userList = []
        this.userTotal = 0
        return
      }
      this.userLoading = true
      try {
        const res = await qwList({
          corpId: this.corpId,
          pageNum: this.userQuery.pageNum,
          pageSize: this.userQuery.pageSize
        })
        this.userList = res.rows || []
        this.userTotal = res.total || 0
        if (
          this.selectedUser &&
          !this.userList.some((u) => String(u.qwUserId) === String(this.selectedUser.qwUserId))
        ) {
          this.selectedUser = null
          this.resetSession(true)
        }
      } catch (e) {
        this.userList = []
        this.userTotal = 0
        this.$message.warning('获取员工列表失败')
      } finally {
        this.userLoading = false
      }
    },

    // 换主体：清空选人、会话、消息，再拉员工
    async handleCorpChange() {
      this.selectedUser = null
      this.resetSession(true)
      this.unbindMsgScroll()
      this.userQuery.pageNum = 1
      if (!this.corpId) {
        this.userList = []
        this.userTotal = 0
        return
      }
      await this.loadUserList()
    },

    // 点某个员工：拉中间会话列表
    async selectUser(u) {
      this.selectedUser = u
      this.selectedConversation = null
      this.resetSession(false)
      this.conversationQuery.pageNum = 1
      this.unbindMsgScroll()
      await this.loadConversationList()
    },

    // 单聊 / 群聊切换：重新拉会话列表，右侧清空
    async handleChatScopeChange() {
      if (!this.selectedUser) return
      this.selectedConversation = null
      this.resetSession(false)
      this.conversationQuery.pageNum = 1
      this.unbindMsgScroll()
      await this.loadConversationList()
    },

    // 中间栏会话分页
    async loadConversationList() {
      if (!this.selectedUser || !this.corpId) {
        this.conversationList = []
        this.conversationTotal = 0
        return
      }
      this.convLoading = true
      try {
        const res = await listQwMsgAuditConversation({
          corpId: this.corpId,
          qwUserId: this.selectedUser.qwUserId,
          chatScope: this.chatScope,
          pageNum: this.conversationQuery.pageNum,
          pageSize: this.conversationQuery.pageSize
        })
        const rows = res.rows || res.data
        this.conversationList = Array.isArray(rows) ? rows : []
        this.conversationTotal = res.total != null ? res.total : 0
        if (this.selectedConversation && !this.conversationList.some((c) => this.isSelectedConv(c))) {
          this.selectedConversation = null
          this.resetSession(false)
        }
      } catch (e) {
        this.conversationList = []
        this.conversationTotal = 0
        this.$message.warning('获取会话列表失败')
      } finally {
        this.convLoading = false
      }
    },

    async selectConversation(c) {
      if (!c || c.conversationKey == null || c.conversationKey === '') {
        this.$message.warning('会话参数有误，无法加载消息')
        return
      }
      this.selectedConversation = c
      this.resetSession(false)
      this.unbindMsgScroll()
      this.msgLoading = true
      try {
        await this.fetchMessagePage(1, true)
        this.$nextTick(() => {
          this.scrollMsgBottom()
          this.bindMsgScroll()
        })
      } finally {
        this.msgLoading = false
      }
    },

    // 消息列表按时间降序时，reverse 后展示为「上旧下新」
    async fetchMessagePage(pageNum, replace) {
      const key = this.selectedConversation && this.selectedConversation.conversationKey
      if (key == null || key === '') {
        return
      }
      const res = await listQwMsgAuditMessage({
        corpId: this.corpId,
        conversationKey: key,
        pageNum,
        pageSize: this.msgPageSize
      })
      const raw = res.rows || res.data
      const rows = Array.isArray(raw) ? raw : []
      const asc = rows.slice().reverse()
      const total = res.total != null ? Number(res.total) : null

      if (replace) {
        this.messages = asc
        this.msgPageNum = pageNum
        this.msgTotal = total != null ? total : 0
      } else {
        this.messages = [...asc, ...this.messages]
        this.msgPageNum = pageNum
      }
      if (total != null) {
        this.msgHasMore = this.messages.length < total
      } else {
        this.msgHasMore = rows.length >= this.msgPageSize
      }
    },

    async loadOlderMessages() {
      if (!this.selectedConversation || !this.msgHasMore) return
      const key = this.selectedConversation.conversationKey
      if (key == null || key === '') return
      if (this.msgLoading || this.msgLoadingMore) return

      const nextPage = this.msgPageNum + 1
      const scrollbar = this.$refs.msgScroll
      const wrap = scrollbar && scrollbar.wrap
      const oldScrollHeight = wrap ? wrap.scrollHeight : 0
      const oldScrollTop = wrap ? wrap.scrollTop : 0

      this.msgLoadingMore = true
      try {
        await this.fetchMessagePage(nextPage, false)
      } finally {
        this.msgLoadingMore = false
        this.$nextTick(() => {
          if (wrap) {
            const delta = wrap.scrollHeight - oldScrollHeight
            wrap.scrollTop = oldScrollTop + delta
          }
        })
      }
    },

    bindMsgScroll() {
      this.unbindMsgScroll()
      this.$nextTick(() => {
        const sb = this.$refs.msgScroll
        if (!sb || !sb.wrap) return
        this._msgScrollWrap = sb.wrap
        // 距顶部很近时尝试加载更早消息
        this._onMsgScroll = () => {
          const wrap = this._msgScrollWrap
          if (!wrap || wrap.scrollTop > 100) return
          this.loadOlderMessages()
        }
        sb.wrap.addEventListener('scroll', this._onMsgScroll, { passive: true })
      })
    },

      // 移除消息滚动容器上的scroll事件监听
    unbindMsgScroll() {
      if (this._msgScrollWrap && this._onMsgScroll) {
        this._msgScrollWrap.removeEventListener('scroll', this._onMsgScroll)
      }
      this._msgScrollWrap = null
      this._onMsgScroll = null
    },

    scrollMsgBottom() {
      const ref = this.$refs.msgScroll
      if (ref && ref.wrap) {
        ref.wrap.scrollTop = ref.wrap.scrollHeight
      }
    }
  }
}
</script>

<style scoped lang="scss">
.qw-msg-audit-page {
  // 整页占满主内容区高度，避免外层再出一条纵向滚动条；只让内部列表滚动
  height: calc(100vh - 120px);
  max-height: calc(100vh - 120px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-sizing: border-box;

  .audit-shell {
    flex: 1;
    min-height: 0;
    display: flex;
    border: 1px solid #ebeef5;
    border-radius: 4px;
    background: #fff;
    overflow: hidden;
  }

  .audit-left {
    width: 260px;
    flex-shrink: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    border-right: 1px solid #ebeef5;
    background: #fafafa;
  }

  .audit-conv {
    width: 220px;
    flex-shrink: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    border-right: 1px solid #ebeef5;
    background: #fff;
  }

  .conv-head {
    flex-shrink: 0;
    padding: 10px 8px;
    border-bottom: 1px solid #ebeef5;
    display: flex;
    flex-direction: column;
    gap: 8px;

    .conv-head-title {
      font-size: 12px;
      color: #909399;
    }

    ::v-deep .el-radio-group {
      display: flex;
      width: 100%;
    }

    ::v-deep .el-radio-button {
      flex: 1;

      .el-radio-button__inner {
        width: 100%;
        padding: 6px 8px;
      }
    }
  }

  .conv-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .conv-scroll {
    flex: 1;
    min-height: 160px;
  }

  .conv-placeholder {
    padding: 24px 12px;
    font-size: 12px;
    text-align: center;
  }

  .conv-item {
    padding: 8px 10px;
    margin: 0 6px 6px;
    border-radius: 6px;
    cursor: pointer;
    border: 1px solid transparent;
    transition: background 0.15s;

    &:hover {
      background: #f5f7fa;
    }

    &.active {
      border-color: #c2e7b0;
      background: #f0f9eb;
    }

    .conv-item-main {
      display: flex;
      align-items: center;
      gap: 10px;
    }

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

    .conv-text {
      flex: 1;
      min-width: 0;
    }

    .conv-title {
      font-size: 13px;
      color: #303133;
      line-height: 1.4;
      word-break: break-all;
    }
  }

  .conv-pagination {
    flex-shrink: 0;
    padding: 4px;

    ::v-deep .pagination-container {
      margin: 0;
      padding: 0;
    }
  }

  .aside-block {
    padding: 12px;
  }

  .aside-corp {
    flex-shrink: 0;
    border-bottom: 1px solid #ebeef5;
  }

  .aside-users {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }

  .block-label {
    font-size: 12px;
    color: #909399;
    margin-bottom: 8px;
  }

  .corp-select {
    width: 100%;
  }

  .user-search {
    margin-bottom: 8px;
  }

  .user-pagination {
    margin-top: 8px;
    padding: 0 4px;

    ::v-deep .pagination-container {
      margin: 0;
      padding: 0;
    }
  }

  .user-scroll {
    flex: 1;
    min-height: 200px;
  }

  .user-item {
    padding: 8px 10px;
    margin-bottom: 4px;
    border-radius: 4px;
    cursor: pointer;
    background: #fff;
    border: 1px solid transparent;
    transition: background 0.15s;

    &:hover {
      background: #f0f9eb;
    }

    &.active {
      border-color: #67c23a;
      background: #f0f9eb;
    }

    .user-name {
      display: block;
      font-size: 14px;
      color: #303133;
    }

    .user-id {
      font-size: 12px;
    }
  }

  .text-muted {
    color: #909399;
    font-size: 12px;
  }

  .audit-chat {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .chat-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 16px;
    border-bottom: 1px solid #ebeef5;
    flex-shrink: 0;
    gap: 12px;
    flex-wrap: wrap;
  }

  .toolbar-title {
    font-size: 14px;
    font-weight: 500;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
  }

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

  .toolbar-name {
    font-weight: 500;
  }

  .toolbar-sub {
    font-weight: normal;
    font-size: 13px;
  }

  .chat-panel {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: #ededed;
    position: relative;
  }

  // flex 子项里 el-scrollbar 用 height:0 + flex:1 才能拿到确定高度，只在此处滚动
  .msg-scroll {
    flex: 1;
    min-height: 0;
    height: 0;

    ::v-deep .el-scrollbar__wrap {
      overflow-x: hidden;
    }
  }

  .msg-load-tip {
    text-align: center;
    font-size: 12px;
    color: #909399;
    padding: 8px 0 4px;
  }

  .msg-list {
    width: 100%;
    box-sizing: border-box;
    padding: 12px 15px;
  }

  .msg-row {
    width: 100%;
    margin-bottom: 14px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;

    &.is-self {
      align-items: flex-end;

      .bubble {
        background: #95ec69;
        color: #000;
      }
    }
  }

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

    .from {
      margin-right: 8px;
    }

    .room-tag {
      margin-left: 8px;
      color: #67c23a;
    }
  }

  .bubble {
    // 用插值交给浏览器解析 min()，避免 dart-sass 把 min 当 Sass 函数报单位不兼容
    max-width: #{"min(78%, 560px)"};
    padding: 8px 12px;
    border-radius: 6px;
    background: #fff;
    word-break: break-word;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);

    .text {
      line-height: 1.5;
      font-size: 14px;
    }

    .text + .media-box {
      margin-top: 8px;
    }

    .media-box {
      font-size: 13px;
      max-width: 100%;
    }

    .media-type-tag {
      font-size: 12px;
      color: #909399;
      margin-bottom: 6px;
    }

    .media-img {
      display: block;
      max-width: 220px;
      max-height: 260px;
      border-radius: 4px;
    }

    .media-video {
      display: block;
      max-width: 280px;
      max-height: 220px;
      border-radius: 4px;
      background: #000;
    }

    .media-audio {
      display: block;
      width: 260px;
      max-width: 100%;
      height: 36px;
    }

    .media-file-link {
      color: #409eff;
    }

    .media-file-name {
      display: block;
      margin-top: 4px;
      color: #606266;
      font-size: 12px;
      word-break: break-all;
    }
  }

  .msg-extra {
    margin-top: 4px;
    font-size: 11px;
    max-width: 75%;
  }
}
</style>
