<template>
  <div class="ticket-detail-page">
    <!-- 头部信息 -->
    <div class="page-header">
      <div class="header-left">
        <el-button icon="ArrowLeft" @click="goBack">返回列表</el-button>
        <el-popover placement="bottom-start" :width="300" trigger="click" v-if="ticketInfo" @show="fetchUserDetail">
          <template #reference>
            <div class="user-info clickable">
              <el-avatar :size="36" :src="ticketInfo.avatar">{{ ticketInfo.username?.charAt(0) }}</el-avatar>
              <div class="user-detail">
                <div class="username">{{ ticketInfo.username }}</div>
                <div class="create-time">创建于 {{ ticketInfo.createTime }}</div>
              </div>
            </div>
          </template>
          <div class="user-popover" v-loading="isLoadingUser">
            <div class="popover-header">
              <el-avatar :size="48" :src="userDetail?.Avatar || ticketInfo.avatar">{{ ticketInfo.username?.charAt(0) }}</el-avatar>
              <div class="popover-info">
                <div class="popover-name">{{ userDetail?.UserName || ticketInfo.username }}</div>
                <div class="popover-id">UID: {{ ticketInfo.userId }}</div>
              </div>
            </div>
            <el-divider style="margin: 12px 0" />
            <div class="popover-items">
              <div class="popover-item">
                <span class="label">手机号</span>
                <span class="value">{{ userDetail?.Phone || '-' }}</span>
              </div>
              <div class="popover-item">
                <span class="label">邮箱</span>
                <span class="value">{{ userDetail?.Email || '-' }}</span>
              </div>
              <div class="popover-item">
                <span class="label">实名状态</span>
                <el-tag :type="userDetail?.RealName?.Status === 1 ? 'success' : 'info'" size="small">
                  {{ userDetail?.RealName?.Status === 1 ? '已实名' : '未实名' }}
                </el-tag>
              </div>
              <div class="popover-item">
                <span class="label">用户组</span>
                <span class="value">{{ userDetail?.UserGroup?.Name || '-' }}</span>
              </div>
              <!-- <div class="popover-item">
                <span class="label">管理员组</span>
                <span class="value">{{ userDetail?.AdminGroup?.name || '-' }}</span>
              </div> -->
            </div>
            <el-button type="primary" size="small" style="width: 100%; margin-top: 12px" @click="goToUserDetail">
              查看完整资料
            </el-button>
          </div>
        </el-popover>
        <div class="ticket-title" v-if="ticketInfo">
          <span class="weight-indicator" :class="'weight-' + ticketInfo.weight" :title="getWeightLabel(ticketInfo.weight)"></span>
          {{ ticketInfo.title }}
        </div>
        <el-tag v-if="ticketInfo?.workOrderType?.name" size="small" type="info" class="type-tag">{{ ticketInfo.workOrderType.name }}</el-tag>
      </div>
      <div class="header-right" v-if="ticketInfo">
        <span class="ticket-id-badge" @click="copyTicketId" title="点击复制工单号">
          #{{ ticketInfo.id }}
          <el-icon :size="12"><DocumentCopy /></el-icon>
        </span>
        <el-select 
          v-model="ticketInfo.status" 
          size="small" 
          style="width: 120px"
          :class="'status-select-' + ticketInfo.status"
          @change="handleStatusChange"
        >
          <el-option label="待处理" value="pending" />
          <el-option label="处理中" value="processing" />
          <el-option label="已回复" value="replied" />
          <el-option label="已完成" value="completed" />
        </el-select>
        <el-button
          v-if="ticketInfo.status !== 'completed'"
          type="success"
          size="small"
          @click="handleComplete"
        >
          结束工单
        </el-button>
      </div>
    </div>

    <!-- 关联商品信息 -->
    <div class="goods-info-panel" v-if="ticketInfo?.userGoods">
      <div class="goods-panel-header">
        <el-icon :size="14"><Box /></el-icon>
        <span class="goods-panel-title">关联商品</span>
        <span class="gp-link gp-jump" @click="goToUserGoods">查看详情 →</span>
      </div>
      <div class="goods-panel-body">
        <div class="goods-panel-item" v-if="ticketInfo.userGoods.good?.name || ticketInfo.userGoods.tag">
          <span class="gp-label">商品</span>
          <span class="gp-value">{{ ticketInfo.userGoods.good?.name || ticketInfo.userGoods.tag }}</span>
        </div>
        <div class="goods-panel-item" v-if="ticketInfo.userGoods.tag">
          <span class="gp-label">分类</span>
          <el-tag size="small" type="info">{{ ticketInfo.userGoods.tag }}</el-tag>
        </div>
        <div class="goods-panel-item" v-if="ticketInfo.userGoods.itemArg?.name">
          <span class="gp-label">实例</span>
          <span class="gp-value">{{ ticketInfo.userGoods.itemArg.name }}</span>
        </div>
        <div class="goods-panel-item" v-if="ticketInfo.userGoods.itemArg?.status">
          <span class="gp-label">状态</span>
          <span class="gp-status-indicator" :class="ticketInfo.userGoods.itemArg.status === 'running' ? 'running' : 'other'"></span>
          <el-tag :type="ticketInfo.userGoods.itemArg.status === 'running' ? 'success' : 'warning'" size="small">{{ ticketInfo.userGoods.itemArg.status }}</el-tag>
        </div>
        <div class="goods-panel-item" v-if="ticketInfo.userGoods.itemArg?.ips">
          <span class="gp-label">IP</span>
          <span class="gp-value gp-ips gp-copyable" @click.stop="copyText(ticketInfo.userGoods.itemArg.ips)" title="点击复制">{{ ticketInfo.userGoods.itemArg.ips }}</span>
        </div>
        <div class="goods-panel-item" v-if="ticketInfo.userGoods.expireTime">
          <span class="gp-label">到期</span>
          <span class="gp-value">{{ formatGoodsTime(ticketInfo.userGoods.expireTime) }}</span>
        </div>
      </div>
    </div>

    <!-- 聊天记录 -->
    <div class="chat-container" v-loading="isLoadingMessages">
      <div class="chat-messages" ref="messagesContainer">
        <template v-for="(message, index) in messages" :key="index">
          <div class="time-separator" v-if="showTimeSeparator(index)">
            <span class="time-separator-text">{{ formatMessageTime(message.time) }}</span>
          </div>
          <div :class="['message-item', message.isAdmin ? 'message-admin' : 'message-user']">
            <div class="message-avatar" v-if="!message.isAdmin">
              <el-avatar :size="36" :src="message.avatar">{{ ticketInfo?.username?.charAt(0) || 'U' }}</el-avatar>
            </div>
            <div class="message-content">
              <div class="message-text" v-if="message.content">
                {{ message.content }}
                <span 
                  v-if="message.isAdmin && !message.isTempMessage"
                  class="edit-btn"
                  @click="handleEditMessage(message)"
                  title="编辑消息"
                >
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
                    <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/>
                  </svg>
                </span>
              </div>
              <div class="message-images" v-if="message.images && message.images.length">
                <img
                  v-for="(img, imgIndex) in message.images"
                  :key="imgIndex"
                  :src="img"
                  class="message-image"
                  @click="openImage(img)"
                />
              </div>
              <div class="message-time" v-if="!showTimeSeparator(index)">{{ formatMessageTime(message.time) }}</div>
            </div>
            <div class="message-avatar" v-if="message.isAdmin">
              <el-avatar :size="36" :src="message.avatar">A</el-avatar>
            </div>
          </div>
        </template>
      </div>
      <div class="new-message-tip" v-if="hasNewMessages" @click="scrollToBottom">
        有新消息 ↓
      </div>
    </div>

    <!-- 回复输入区域 -->
    <div class="reply-container" v-if="ticketInfo && ticketInfo.status !== 'completed'">
      <!-- 图片预览 -->
      <div class="upload-preview" v-if="selectedImages.length > 0">
        <div class="preview-item" v-for="(image, index) in selectedImages" :key="index">
          <img :src="image" alt="预览图片" />
          <div class="delete-preview" @click="removeImage(index)">×</div>
        </div>
      </div>

      <!-- 回复模板 -->
      <div class="reply-templates">
        <el-input
          v-model="templateKeyword"
          placeholder="筛选模板"
          size="small"
          clearable
          class="template-filter-input"
          @input="() => fetchTemplateList(true)"
        />
        <el-tooltip
          v-for="tpl in templateList"
          :key="tpl.id"
          :content="tpl.content?.slice(0, 80) + (tpl.content?.length > 80 ? '...' : '')"
          placement="top"
          :show-after="400"
        >
          <div class="template-tag" @click="useTemplate(tpl)">
            <span class="template-tag-name">{{ tpl.name }}</span>
            <el-icon class="template-tag-delete" @click.stop="handleTemplateDelete(tpl)"><Close /></el-icon>
          </div>
        </el-tooltip>
        <div class="template-tag template-tag-add" @click="openAddTemplate">
          <el-icon><Plus /></el-icon>
          <span>新增模板</span>
        </div>
      </div>

      <!-- 输入框 -->
      <div 
        class="input-area"
        @drop.prevent="handleDrop"
        @dragover.prevent="handleDragOver"
        @dragleave.prevent="handleDragLeave"
        :class="{ 'drag-over': isDragOver }"
      >
        <div class="textarea-wrap">
          <el-input
            ref="textareaRef"
            v-model="messageInput"
            type="textarea"
            :rows="3"
            placeholder="请输入回复内容（支持粘贴图片和拖拽图片）..."
            @keyup.ctrl.enter="sendMessage"
          />
          <span class="char-count" v-if="messageInput.length > 0">{{ messageInput.length }}</span>
        </div>
        <div class="input-actions">
          <div class="left-actions">
            <el-upload
              action="#"
              :auto-upload="false"
              :show-file-list="false"
              :on-change="handleFileChange"
              multiple
              accept="image/*"
            >
              <el-button type="primary" plain icon="Plus">图片</el-button>
            </el-upload>
            <el-button plain @click="saveCurrentAsTemplate" :disabled="!messageInput.trim()">存为模板</el-button>
            <el-button plain @click="loadMoreTemplates" :loading="templateLoadingMore" v-if="templateHasMore">加载更多</el-button>
          </div>
          <span class="hint-text">Ctrl + Enter 发送</span>
          <el-button
            :type="sendSuccess ? 'success' : 'primary'"
            :disabled="!messageInput.trim() && selectedImages.length === 0"
            :loading="isSending"
            @click="sendMessage"
            :class="{ 'send-success-anim': sendSuccess }"
          >
            {{ sendSuccess ? '✓' : '发送' }}
          </el-button>
        </div>
      </div>
    </div>

    <!-- 已结束提示 -->
    <div class="closed-notice" v-else-if="ticketInfo && ticketInfo.status === 'completed'">
      <el-alert title="该工单已结束，无法继续回复" type="info" :closable="false" />
    </div>

    <!-- 模板编辑对话框 -->
    <el-dialog
      v-model="showTemplateDialog"
      :title="isEditingTemplate ? '编辑模板' : '新增模板'"
      width="480px"
      destroy-on-close
    >
      <el-form label-width="80px">
        <el-form-item label="模板名称">
          <el-input v-model="templateForm.name" placeholder="请输入模板名称" maxlength="50" />
        </el-form-item>
        <el-form-item label="模板内容">
          <el-input v-model="templateForm.content" type="textarea" :rows="5" placeholder="请输入模板内容" maxlength="1000" show-word-limit />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="showTemplateDialog = false">取消</el-button>
        <el-button type="primary" @click="handleTemplateSave">保存</el-button>
      </template>
    </el-dialog>

    <!-- 编辑消息对话框 -->
    <el-dialog v-model="editDialogVisible" title="编辑消息" width="600px">
      <el-form>
        <el-form-item label="消息内容">
          <el-input
            v-model="editMessageContent"
            type="textarea"
            :rows="4"
            placeholder="请输入消息内容"
          />
        </el-form-item>
        <el-form-item label="图片">
          <!-- 现有图片预览 -->
          <div class="edit-images-container">
            <div class="edit-preview-item" v-for="(image, index) in editMessageImages" :key="index">
              <img :src="image" alt="图片" />
              <div class="delete-preview" @click="removeEditImage(index)">×</div>
            </div>
            <!-- 添加图片按钮 -->
            <el-upload
              action="#"
              :auto-upload="false"
              :show-file-list="false"
              :on-change="handleEditFileChange"
              multiple
              accept="image/*"
            >
              <div class="add-image-btn">
                <el-icon :size="24"><Plus /></el-icon>
                <div class="add-text">添加图片</div>
              </div>
            </el-upload>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="editDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="isEditingSaving" @click="saveEditMessage">保存</el-button>
      </template>
    </el-dialog>

    <!-- 图片查看器 -->
    <el-dialog v-model="imageViewerVisible" width="auto" destroy-on-close>
      <img :src="currentViewImage" style="max-width: 100%; max-height: 80vh;" />
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick, onBeforeUnmount, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getTicketDetail, replyTicket, closeTicket, updateTicketInfo, updateTicketReplayInfo, getReplyTemplateList, createReplyTemplate, updateReplyTemplate, deleteReplyTemplate } from '@/api/ticket'
import { Plus, Box, Search, Edit, Delete, Close, DocumentCopy } from '@element-plus/icons-vue'
import { getUserInfo } from '@/api/admin/user'
import { uploadFile } from '@/api/admin/file'
import { useUserStore } from '@/store/userStore'
import { useTagsViewStore } from '@/store/tagsViewStore'

const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const tagsViewStore = useTagsViewStore()

// 工单信息
const ticketInfo = ref(null)
const messages = ref([])
const isLoadingMessages = ref(false)
const isSending = ref(false)
const sendSuccess = ref(false)

// 用户详情弹窗
const userDetail = ref(null)
const isLoadingUser = ref(false)

// 输入相关
const messageInput = ref('')
const selectedImages = ref([])
const selectedFiles = ref([]) // 存储原始文件对象
const messagesContainer = ref(null)
const textareaRef = ref(null)
const isDragOver = ref(false)

// 图片查看
const imageViewerVisible = ref(false)
const currentViewImage = ref('')

// 编辑消息
const editDialogVisible = ref(false)
const editMessageContent = ref('')
const editMessageImages = ref([])
const editMessageFiles = ref([])
const editOriginalFileIds = ref([]) // 保存原始文件ID
const editingMessage = ref(null)
const isEditingSaving = ref(false)

// 定时刷新
const refreshTimer = ref(null)

// 回复模板
const templateList = ref([])
const templateKeyword = ref('')
const templatePage = ref(1)
const templatePageSize = ref(10)
const templateTotal = ref(0)
const templateHasMore = ref(false)
const templateLoadingMore = ref(false)
const showTemplateDialog = ref(false)
const templateForm = ref({ id: null, name: '', content: '' })
const isEditingTemplate = ref(false)

const fetchTemplateList = async (reset = true) => {
  try {
    if (reset) templatePage.value = 1
    const params = { count: templatePageSize.value, page: templatePage.value }
    if (templateKeyword.value) params.keyword = templateKeyword.value
    const res = await getReplyTemplateList(params)
    if (res.code === 200) {
      const list = res.data?.data || []
      templateTotal.value = res.data?.all_count || 0
      if (reset) {
        templateList.value = list
      } else {
        templateList.value = [...templateList.value, ...list]
      }
      templateHasMore.value = templateList.value.length < templateTotal.value
    }
  } catch (e) {
    console.error('获取模板列表失败', e)
  }
}

const loadMoreTemplates = async () => {
  templateLoadingMore.value = true
  templatePage.value++
  await fetchTemplateList(false)
  templateLoadingMore.value = false
}

const useTemplate = (tpl) => {
  messageInput.value = tpl.content
}

const openAddTemplate = () => {
  isEditingTemplate.value = false
  templateForm.value = { id: null, name: '', content: '' }
  showTemplateDialog.value = true
}

const openEditTemplate = (tpl) => {
  isEditingTemplate.value = true
  templateForm.value = { id: tpl.id, name: tpl.name, content: tpl.content }
  showTemplateDialog.value = true
}

const handleTemplateSave = async () => {
  if (!templateForm.value.name.trim() || !templateForm.value.content.trim()) {
    ElMessage.warning('模板名称和内容不能为空')
    return
  }
  try {
    if (isEditingTemplate.value) {
      const res = await updateReplyTemplate(templateForm.value)
      if (res.code === 200) {
        ElMessage.success('模板已更新')
      } else {
        ElMessage.error(res.message || '更新失败')
        return
      }
    } else {
      const res = await createReplyTemplate({ name: templateForm.value.name, content: templateForm.value.content })
      if (res.code === 200) {
        ElMessage.success('模板已创建')
      } else {
        ElMessage.error(res.message || '创建失败')
        return
      }
    }
    showTemplateDialog.value = false
    fetchTemplateList()
  } catch (e) {
    ElMessage.error('操作失败')
  }
}

const handleTemplateDelete = async (tpl) => {
  try {
    await ElMessageBox.confirm(`确定删除模板「${tpl.name}」？`, '删除确认', { type: 'warning' })
    const res = await deleteReplyTemplate({ id: tpl.id })
    if (res.code === 200) {
      ElMessage.success('已删除')
      fetchTemplateList()
    } else {
      ElMessage.error(res.message || '删除失败')
    }
  } catch (e) {
    // 取消删除
  }
}

const saveCurrentAsTemplate = () => {
  if (!messageInput.value.trim()) {
    ElMessage.warning('输入框内容为空，无法保存为模板')
    return
  }
  isEditingTemplate.value = false
  templateForm.value = { id: null, name: '', content: messageInput.value.trim() }
  showTemplateDialog.value = true
}

// 状态转换
const convertStatusToString = (status) => {
  const statusMap = { 0: 'pending', 1: 'processing', 2: 'replied', 3: 'completed' }
  return statusMap[status] || 'processing'
}

const getStatusText = (status) => {
  const statusMap = { pending: '待处理', processing: '处理中', replied: '已回复', completed: '已完成' }
  return statusMap[status] || status
}

const getStatusType = (status) => {
  const typeMap = { pending: 'warning', processing: 'primary', replied: 'info', completed: 'success' }
  return typeMap[status] || ''
}

// 判断是否是管理员
const isAdmin = (userId) => {
  return userId === userStore.userInfo?.user_id
}

// 比较两个消息列表是否相同
const messagesEqual = (oldMessages, newMessages) => {
  if (oldMessages.length !== newMessages.length) return false
  
  for (let i = 0; i < oldMessages.length; i++) {
    const oldMsg = oldMessages[i]
    const newMsg = newMessages[i]
    
    // 比较关键字段
    if (oldMsg.id !== newMsg.id ||
        oldMsg.content !== newMsg.content ||
        oldMsg.images?.length !== newMsg.images?.length) {
      return false
    }
    
    // 比较图片URL
    if (oldMsg.images && newMsg.images) {
      for (let j = 0; j < oldMsg.images.length; j++) {
        if (oldMsg.images[j] !== newMsg.images[j]) {
          return false
        }
      }
    }
  }
  
  return true
}

// 获取工单详情
const fetchTicketDetail = async (showLoading = true) => {
  // 兼容 id 和 work_id 两种参数名
  const workId = route.query.id || route.query.work_id
  if (!workId) {
    // 没有ID时静默跳转到列表页
    router.replace('/ticket/list')
    return
  }

  try {
    if (showLoading) {
      isLoadingMessages.value = true
    }
    const res = await getTicketDetail(workId)

    if (res.code === 200) {
      const detail = res.data
      ticketInfo.value = {
        id: detail.id,
        title: detail.name,
        username: detail.user?.userName || `用户${detail.user?.userId || 'Unknown'}`,
        userId: detail.user?.userId,
        avatar: detail.user?.coverUrl || '',
        createTime: new Date(detail.created_at).toLocaleString(),
        status: convertStatusToString(detail.status),
        userGoods: detail.userGoods ? parseUserGoods(detail.userGoods) : null,
        workOrderType: detail.workOrderType || null,
        weight: detail.weight
      }

      // 处理消息列表并按ID排序
      if (detail.content && detail.content.length > 0) {
        const newMessages = detail.content
          .map((msg) => ({
            id: msg.id,
            content: msg.content !== 'empty' ? msg.content : null,
            images: msg.flies ? msg.flies.map(file => file.url) : [],
            fileIds: msg.flies ? msg.flies.map(file => file.id) : [], // 保存文件ID
            time: msg.created_at || msg.updated_at || new Date().toLocaleString(),
            isAdmin: isAdmin(msg.user?.userId),
            userId: msg.user?.userId,
            avatar: msg.user?.coverUrl || ''
          }))
          .sort((a, b) => a.id - b.id) // 按ID从小到大排序
        
        // 比较新旧消息列表，只有在有变化时才更新
        const hasChanges = !messagesEqual(messages.value, newMessages)
        
        if (hasChanges) {
          const isNewMsg = newMessages.length > messages.value.length
          messages.value = newMessages
          
          if (showLoading) {
            nextTick(() => scrollToBottom())
          } else if (isNewMsg) {
            const container = messagesContainer.value
            const isAtBottom = container && (container.scrollHeight - container.scrollTop - container.clientHeight < 80)
            if (isAtBottom) {
              nextTick(() => scrollToBottom())
            } else {
              hasNewMessages.value = true
            }
          }
        }
      }
    } else {
      ElMessage.error(res.message || '获取工单详情失败')
    }
  } catch (error) {
    console.error('获取工单详情出错:', error)
    if (showLoading) {
      ElMessage.error('网络错误，请稍后重试')
    }
  } finally {
    if (showLoading) {
      isLoadingMessages.value = false
    }
  }
}

// 发送消息
const sendMessage = async () => {
  if ((!messageInput.value.trim() && selectedImages.value.length === 0) || isSending.value) return

  const workId = route.query.id || route.query.work_id
  const content = messageInput.value.trim() || 'empty'

  try {
    isSending.value = true
    const inputMsg = messageInput.value.trim()
    const inputImages = [...selectedImages.value]
    const inputFiles = [...selectedFiles.value]

    // 上传图片并获取文件ID
    let fileIds = []
    if (inputFiles.length > 0) {
      try {
        const formData = new FormData()
        
        // 多个 file_names 和 files 条目在同一请求中
        inputFiles.forEach((file) => {
          formData.append('file_names', file.name)
          formData.append('files', file)
        })
        
        // 设置上传类型为工单
        formData.append('update_type', 'work_order')
        formData.append('open_down', 'true')
        
        const uploadRes = await uploadFile(formData)
        
        if (uploadRes.data?.code === 200) {
          // 从返回的数据中提取文件ID
          const data = uploadRes.data.data
          if (Array.isArray(data)) {
            fileIds = data.map(item => String(item.id))
          } else if (data?.id) {
            fileIds = [String(data.id)]
          }
          
          if (fileIds.length === 0) {
            ElMessage.error('未获取到文件ID')
            isSending.value = false
            return
          }
        } else {
          ElMessage.error(uploadRes.data?.message || '图片上传失败')
          isSending.value = false
          return
        }
      } catch (error) {
        console.error('图片上传失败:', error)
        ElMessage.error('图片上传失败，请重试')
        isSending.value = false
        return
      }
    }

    messageInput.value = ''
    selectedImages.value = []
    selectedFiles.value = []

    // 临时消息
    const tempMsg = {
      id: Date.now(),
      content: inputMsg || null,
      images: inputImages,
      time: new Date().toLocaleString(),
      isAdmin: true,
      userId: userStore.userInfo?.user_id,
      avatar: userStore.userInfo?.cover_url || '',
      isTempMessage: true
    }
    messages.value.push(tempMsg)
    await nextTick()
    scrollToBottom()

    const res = await replyTicket(workId, content, fileIds.join(','))

    if (res.code === 200) {
      messages.value = messages.value.filter(msg => !msg.isTempMessage)
      await fetchTicketDetail()
      sendSuccess.value = true
      setTimeout(() => { sendSuccess.value = false }, 1500)
    } else {
      messages.value = messages.value.filter(msg => !msg.isTempMessage)
      messageInput.value = inputMsg
      selectedImages.value = inputImages
      selectedFiles.value = inputFiles
      ElMessage.error(res.message || '发送失败')
    }
  } catch (error) {
    console.error('发送消息出错:', error)
    ElMessage.error('网络错误，请稍后重试')
    messages.value = messages.value.filter(msg => !msg.isTempMessage)
  } finally {
    isSending.value = false
  }
}

// 修改工单状态
const handleStatusChange = async (newStatus) => {
  const statusMap = {
    'pending': 0,
    'processing': 1,
    'replied': 2,
    'completed': 3
  }
  
  const oldStatus = ticketInfo.value.status
  
  try {
    const formData = new FormData()
    formData.append('work_id', route.query.id || route.query.work_id)
    formData.append('Status', statusMap[newStatus])
    
    const res = await updateTicketInfo(formData)
    
    if (res.code === 200) {
      ElMessage.success('工单状态已更新')
      ticketInfo.value.status = newStatus
    } else {
      ElMessage.error(res.message || '更新失败')
      ticketInfo.value.status = oldStatus // 恢复原状态
    }
  } catch (error) {
    console.error('更新工单状态出错:', error)
    ElMessage.error('网络错误，请稍后重试')
    ticketInfo.value.status = oldStatus // 恢复原状态
  }
}

// 结束工单
const handleComplete = () => {
  ElMessageBox.confirm('确定要结束此工单吗？结束后将无法继续回复。', '确认操作', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(async () => {
    try {
      const res = await closeTicket(route.query.id || route.query.work_id)
      if (res.code === 200) {
        ElMessage.success('工单已成功结束')
        ticketInfo.value.status = 'completed'
      } else {
        ElMessage.error(res.message || '结束工单失败')
      }
    } catch (error) {
      ElMessage.error('网络错误，请稍后重试')
    }
  }).catch(() => {})
}

// 图片处理
const handleFileChange = (file) => {
  if (!file) return
  addImageFile(file.raw)
}

// 添加图片文件（统一处理函数）
const addImageFile = (file) => {
  // 验证文件类型
  if (!file.type.startsWith('image/')) {
    ElMessage.warning('只支持图片格式')
    return
  }
  
  // 验证文件大小（限制10MB）
  if (file.size > 10 * 1024 * 1024) {
    ElMessage.warning('图片大小不能超过10MB')
    return
  }
  
  // 保存原始文件对象用于上传
  selectedFiles.value.push(file)
  
  // 读取文件用于预览
  const reader = new FileReader()
  reader.onload = (e) => selectedImages.value.push(e.target.result)
  reader.readAsDataURL(file)
}

// 处理粘贴事件
const handlePaste = (e) => {
  const items = e.clipboardData?.items
  if (!items) return
  
  for (let i = 0; i < items.length; i++) {
    const item = items[i]
    if (item.type.indexOf('image') !== -1) {
      e.preventDefault()
      const file = item.getAsFile()
      if (file) {
        addImageFile(file)
        ElMessage.success('图片已添加')
      }
    }
  }
}

// 处理拖拽进入
const handleDragOver = (e) => {
  isDragOver.value = true
}

// 处理拖拽离开
const handleDragLeave = (e) => {
  isDragOver.value = false
}

// 处理文件拖放
const handleDrop = (e) => {
  isDragOver.value = false
  
  const files = e.dataTransfer?.files
  if (!files || files.length === 0) return
  
  let addedCount = 0
  for (let i = 0; i < files.length; i++) {
    const file = files[i]
    if (file.type.startsWith('image/')) {
      addImageFile(file)
      addedCount++
    }
  }
  
  if (addedCount > 0) {
    ElMessage.success(`已添加 ${addedCount} 张图片`)
  } else {
    ElMessage.warning('未找到图片文件')
  }
}

const removeImage = (index) => {
  selectedImages.value.splice(index, 1)
  selectedFiles.value.splice(index, 1)
}

const openImage = (img) => {
  currentViewImage.value = img
  imageViewerVisible.value = true
}

// 编辑消息
const handleEditMessage = (message) => {
  editingMessage.value = message
  editMessageContent.value = message.content || ''
  editMessageImages.value = message.images ? [...message.images] : []
  editOriginalFileIds.value = message.fileIds ? [...message.fileIds] : []
  editMessageFiles.value = []
  editDialogVisible.value = true
}

// 处理编辑对话框中的文件选择
const handleEditFileChange = (file) => {
  if (!file) return
  
  // 验证文件类型
  if (!file.raw.type.startsWith('image/')) {
    ElMessage.warning('只支持图片格式')
    return
  }
  
  // 验证文件大小（限制10MB）
  if (file.raw.size > 10 * 1024 * 1024) {
    ElMessage.warning('图片大小不能超过10MB')
    return
  }
  
  // 保存原始文件对象用于上传
  editMessageFiles.value.push(file.raw)
  
  // 读取文件用于预览
  const reader = new FileReader()
  reader.onload = (e) => editMessageImages.value.push(e.target.result)
  reader.readAsDataURL(file.raw)
}

// 删除编辑对话框中的图片
const removeEditImage = (index) => {
  const originalImagesCount = editingMessage.value?.images?.length || 0
  
  // 如果删除的是原始图片，从原始文件ID列表中删除
  if (index < originalImagesCount) {
    editOriginalFileIds.value.splice(index, 1)
  } else {
    // 如果删除的是新添加的图片，从新文件列表中删除
    const fileIndex = index - originalImagesCount
    if (fileIndex >= 0 && fileIndex < editMessageFiles.value.length) {
      editMessageFiles.value.splice(fileIndex, 1)
    }
  }
  
  // 从预览列表中删除
  editMessageImages.value.splice(index, 1)
}

// 保存编辑的消息
const saveEditMessage = async () => {
  if (!editMessageContent.value.trim()) {
    ElMessage.warning('消息内容不能为空')
    return
  }
  
  if (!editingMessage.value || !editingMessage.value.id) {
    ElMessage.error('无法获取消息ID')
    return
  }
  
  try {
    isEditingSaving.value = true
    
    // 如果有新添加的图片，先上传
    let newFileIds = []
    if (editMessageFiles.value.length > 0) {
      try {
        const formData = new FormData()
        
        // 多个 file_names 和 files 条目在同一请求中
        editMessageFiles.value.forEach((file) => {
          formData.append('file_names', file.name)
          formData.append('files', file)
        })
        
        formData.append('update_type', 'work_order')
        formData.append('open_down', 'true')
        
        const uploadRes = await uploadFile(formData)
        
        if (uploadRes.data?.code === 200) {
          const data = uploadRes.data.data
          if (Array.isArray(data)) {
            newFileIds = data.map(item => String(item.id))
          } else if (data?.id) {
            newFileIds = [String(data.id)]
          }
        } else {
          ElMessage.error(uploadRes.data?.message || '图片上传失败')
          isEditingSaving.value = false
          return
        }
      } catch (error) {
        console.error('图片上传失败:', error)
        ElMessage.error('图片上传失败，请重试')
        isEditingSaving.value = false
        return
      }
    }
    
    // 合并原始文件ID和新上传的文件ID
    const allFileIds = [...editOriginalFileIds.value, ...newFileIds]
    
    const formData = new FormData()
    formData.append('id', editingMessage.value.id)
    formData.append('content', editMessageContent.value.trim())
    formData.append('files', allFileIds.join(','))
    
    const res = await updateTicketReplayInfo(formData)
    
    if (res.code === 200) {
      ElMessage.success('消息已更新')
      editDialogVisible.value = false
      
      // 重新获取工单详情以确保数据同步
      await fetchTicketDetail(false)
    } else {
      ElMessage.error(res.message || '更新失败')
    }
  } catch (error) {
    console.error('更新消息出错:', error)
    ElMessage.error('网络错误，请稍后重试')
  } finally {
    isEditingSaving.value = false
  }
}


// 滚动到底部
const hasNewMessages = ref(false)

const showTimeSeparator = (index) => {
  if (index === 0) return true
  const curr = new Date(messages.value[index]?.time)
  const prev = new Date(messages.value[index - 1]?.time)
  if (isNaN(curr.getTime()) || isNaN(prev.getTime())) return false
  return (curr.getTime() - prev.getTime()) > 3600000
}

const scrollToBottom = () => {
  if (messagesContainer.value) {
    messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
    hasNewMessages.value = false
  }
}

// 格式化时间
const formatMessageTime = (timeStr) => {
  if (!timeStr) return ''
  try {
    const date = new Date(timeStr)
    if (isNaN(date.getTime())) return ''
    
    const now = new Date()
    const time = `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
    
    // 判断是否是今天
    const isToday = date.getFullYear() === now.getFullYear() &&
                    date.getMonth() === now.getMonth() &&
                    date.getDate() === now.getDate()
    
    if (isToday) {
      return time
    }
    
    // 判断是否是昨天
    const yesterday = new Date(now)
    yesterday.setDate(yesterday.getDate() - 1)
    const isYesterday = date.getFullYear() === yesterday.getFullYear() &&
                        date.getMonth() === yesterday.getMonth() &&
                        date.getDate() === yesterday.getDate()
    
    if (isYesterday) {
      return `昨天 ${time}`
    }
    
    // 判断是否是本周（周一到周日）
    // 获取本周一的日期（0点）
    const currentDay = now.getDay() // 0-6，0是周日
    const mondayOffset = currentDay === 0 ? -6 : 1 - currentDay // 周日的话往前推6天，其他往前推到周一
    const monday = new Date(now)
    monday.setDate(now.getDate() + mondayOffset)
    monday.setHours(0, 0, 0, 0)
    
    // 获取本周日的日期（23:59:59）
    const sunday = new Date(monday)
    sunday.setDate(monday.getDate() + 6)
    sunday.setHours(23, 59, 59, 999)
    
    // 判断消息日期是否在本周范围内
    if (date >= monday && date <= sunday) {
      const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
      return `${weekdays[date.getDay()]} ${time}`
    }
    
    // 其他情况显示完整日期时间
    const year = date.getFullYear()
    const month = String(date.getMonth() + 1).padStart(2, '0')
    const day = String(date.getDate()).padStart(2, '0')
    return `${year}-${month}-${day} ${time}`
  } catch (e) {
    return ''
  }
}

// 返回列表
const goBack = () => {
  tagsViewStore.delVisitedView(route)
  router.push('/ticket/list')
}

const getWeightLabel = (weight) => {
  const map = { 0: '常规', 1: '一般', 2: '紧急', 3: '非常紧急' }
  return map[weight] || '常规'
}

const copyTicketId = () => {
  const id = `#${ticketInfo.value.id}`
  navigator.clipboard.writeText(id).then(() => {
    ElMessage.success(`已复制 ${id}`)
  }).catch(() => {
    ElMessage.info(id)
  })
}

const copyText = (text) => {
  navigator.clipboard.writeText(text).then(() => {
    ElMessage.success('已复制')
  }).catch(() => {
    ElMessage.info(text)
  })
}

// 获取用户详情
const fetchUserDetail = async () => {
  if (!ticketInfo.value?.userId) return
  try {
    isLoadingUser.value = true
    const res = await getUserInfo({ user_id: ticketInfo.value.userId })
    if (res.data?.code === 200) {
      userDetail.value = res.data.data
    }
  } catch (error) {
    console.error('获取用户详情失败:', error)
  } finally {
    isLoadingUser.value = false
  }
}

// 跳转用户详情
const goToUserDetail = () => {
  if (ticketInfo.value?.userId) {
    const href = router.resolve({ path: '/user/detail', query: { user_id: ticketInfo.value.userId } }).href
    window.open(href, '_blank')
  }
}

const goToUserGoods = () => {
  const goods = ticketInfo.value?.userGoods
  if (!goods) return
  const href = router.resolve({ name: 'UserGoodsDetail', params: { id: goods.id } }).href
  window.open(href, '_blank')
}

const parseUserGoods = (raw) => {
  const goods = { ...raw }
  // itemArg 可能是 JSON 字符串
  if (typeof goods.itemArg === 'string') {
    try { goods.itemArg = JSON.parse(goods.itemArg) } catch { goods.itemArg = null }
  }
  return goods
}

const formatGoodsTime = (time) => {
  if (!time) return '—'
  const d = new Date(time)
  if (isNaN(d.getTime())) return '—'
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
}

// 定时刷新
const startAutoRefresh = () => {
  refreshTimer.value = setInterval(() => {
    // 只有当前路由仍在工单详情页且工单未完成时才刷新
    const workId = route.query.id || route.query.work_id
    if (route.path === '/ticket/detail' && workId && ticketInfo.value?.status !== 'completed') {
      fetchTicketDetail(false) // 定时刷新时不显示 loading
    }
  }, 10000)
}

const stopAutoRefresh = () => {
  if (refreshTimer.value) {
    clearInterval(refreshTimer.value)
    refreshTimer.value = null
  }
}

// 监听路由query变化，重新加载数据
watch(
  () => route.query.id || route.query.work_id,
  (newId) => {
    if (newId) {
      fetchTicketDetail()
    }
  }
)

// ticketInfo 加载后 textarea 才渲染（v-if），此时绑定粘贴事件
let pasteBindDone = false
watch(ticketInfo, (val) => {
  if (val && !pasteBindDone) {
    pasteBindDone = true
    nextTick(() => {
      const textarea = textareaRef.value?.$el?.querySelector('textarea')
      if (textarea) {
        textarea.addEventListener('paste', handlePaste)
      }
    })
  }
})

onMounted(() => {
  fetchTicketDetail()
  fetchTemplateList()
  startAutoRefresh()
})

onBeforeUnmount(() => {
  stopAutoRefresh()
  
  // 移除粘贴事件监听
  const textarea = textareaRef.value?.$el?.querySelector('textarea')
  if (textarea) {
    textarea.removeEventListener('paste', handlePaste)
  }
})
</script>

<style scoped>
.ticket-detail-page {
  padding: 0;
  display: flex;
  flex-direction: column;
  height: calc(100vh - 148px);
  min-height: 600px;
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: #fff;
  padding: 16px 20px;
  border-bottom: 1px solid #ebeef5;
}

.goods-info-panel {
  background: #f8fbff;
  border-bottom: 1px solid #e6f2ff;
  padding: 10px 20px;
}

.goods-panel-header {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
  color: #606266;
  font-size: 13px;
  font-weight: 500;
}

.goods-panel-title {
  color: #303133;
  flex: 1;
}

.goods-panel-header .gp-jump {
  font-size: 12px;
  font-weight: 400;
}

.goods-panel-body {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 24px;
}

.goods-panel-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
}

.goods-panel-item .gp-label {
  color: #909399;
}

.goods-panel-item .gp-value {
  color: #303133;
}

.goods-panel-item .gp-link {
  color: #409eff;
  cursor: pointer;
  font-weight: 500;
}

.goods-panel-item .gp-link:hover,
.goods-panel-header .gp-link:hover {
  text-decoration: underline;
}

.goods-panel-item .gp-ips {
  font-family: monospace;
  font-size: 12px;
  word-break: break-all;
}

.header-left {
  display: flex;
  align-items: center;
  gap: 16px;
}

.header-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.ticket-id, .ticket-id-badge {
  font-weight: 500;
  color: #303133;
  font-size: 14px;
  white-space: nowrap;
  flex-shrink: 0;
}

.user-info {
  display: flex;
  align-items: center;
  gap: 10px;
}

.user-info.clickable {
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 6px;
  transition: background 0.2s;
}

.user-info.clickable:hover {
  background: #f5f7fa;
}

.user-popover .popover-header {
  display: flex;
  align-items: center;
  gap: 12px;
}

.user-popover .popover-info .popover-name {
  font-size: 16px;
  font-weight: 500;
  color: #303133;
}

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

.user-popover .popover-items {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.user-popover .popover-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
  color: #606266;
}

.user-popover .popover-item .label {
  color: #909399;
}

.user-popover .popover-item .value.highlight {
  color: #e6a23c;
  font-weight: 500;
}

.user-detail .username {
  font-weight: 500;
  font-size: 14px;
}

.user-detail .create-time {
  font-size: 12px;
  color: #909399;
}

.ticket-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 15px;
  font-weight: 500;
  color: #303133;
  max-width: 300px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.weight-indicator {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.weight-indicator.weight-0 { background: #c0c4cc; }
.weight-indicator.weight-1 { background: #409eff; }
.weight-indicator.weight-2 { background: #e6a23c; }
.weight-indicator.weight-3 { background: #f56c6c; animation: pulse-weight 1.5s infinite; }

@keyframes pulse-weight {
  0% { box-shadow: 0 0 0 0 rgba(245,108,108,0.5); }
  70% { box-shadow: 0 0 0 5px rgba(245,108,108,0); }
  100% { box-shadow: 0 0 0 0 rgba(245,108,108,0); }
}

.type-tag {
  margin-left: 6px;
  flex-shrink: 0;
}

.ticket-id-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  background: #f4f4f5;
  border-radius: 4px;
  font-size: 13px;
  font-family: 'SF Mono', 'Menlo', monospace;
  color: #606266;
  cursor: pointer;
  transition: all 0.2s;
}

.ticket-id-badge:hover {
  background: #ecf5ff;
  color: #409eff;
}

.status-select-pending :deep(.el-input__wrapper) { box-shadow: 0 0 0 1px #e6a23c inset; }
.status-select-processing :deep(.el-input__wrapper) { box-shadow: 0 0 0 1px #409eff inset; }
.status-select-replied :deep(.el-input__wrapper) { box-shadow: 0 0 0 1px #909399 inset; }
.status-select-completed :deep(.el-input__wrapper) { box-shadow: 0 0 0 1px #67c23a inset; }

/* 商品面板增强 */
.gp-status-indicator {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  display: inline-block;
  margin-right: 4px;
}

.gp-status-indicator.running {
  background: #67c23a;
  animation: pulse-weight 1.5s infinite;
}

.gp-status-indicator.other {
  background: #c0c4cc;
}

.gp-copyable {
  cursor: pointer;
  transition: color 0.2s;
}

.gp-copyable:hover {
  color: #409eff;
}

/* 聊天区增强 */
.time-separator {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px 0;
}

.time-separator-text {
  font-size: 12px;
  color: #909399;
  background: #ebeef5;
  padding: 2px 12px;
  border-radius: 10px;
}

.new-message-tip {
  position: absolute;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  padding: 6px 16px;
  background: #409eff;
  color: #fff;
  border-radius: 16px;
  font-size: 12px;
  cursor: pointer;
  box-shadow: 0 2px 12px rgba(64,158,255,0.3);
  transition: all 0.2s;
  z-index: 10;
}

.new-message-tip:hover {
  background: #337ecc;
}

/* 输入框增强 */
.textarea-wrap {
  position: relative;
}

.char-count {
  position: absolute;
  bottom: 6px;
  right: 12px;
  font-size: 11px;
  color: #c0c4cc;
  pointer-events: none;
}

.send-success-anim {
  animation: send-pop 0.3s ease;
}

@keyframes send-pop {
  0% { transform: scale(1); }
  50% { transform: scale(1.1); }
  100% { transform: scale(1); }
}

.chat-container {
  position: relative;
  flex: 1;
  min-height: 400px;
  background: #f8f9fb;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
}

.message-item {
  display: flex;
  margin-bottom: 16px;
  gap: 12px;
}

.message-user {
  justify-content: flex-start;
}

.message-admin {
  justify-content: flex-end;
}

.message-content {
  max-width: 60%;
}

.message-text {
  background: #fff;
  padding: 12px 16px;
  border-radius: 12px 12px 12px 4px;
  word-break: break-word;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  position: relative;
  line-height: 1.5;
}

.message-text .edit-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: 8px;
  padding: 4px;
  cursor: pointer;
  opacity: 0.6;
  transition: all 0.2s;
  border-radius: 4px;
  vertical-align: middle;
}

.message-text .edit-btn:hover {
  opacity: 1;
  background: rgba(0, 0, 0, 0.1);
}

.message-text:hover .edit-btn {
  opacity: 1;
}

.message-admin .message-text {
  background: linear-gradient(135deg, #409eff, #337ecc);
  color: #fff;
  border-radius: 12px 12px 4px 12px;
}

.message-admin .message-text .edit-btn {
  color: #fff;
  opacity: 0.7;
}

.message-admin .message-text .edit-btn:hover {
  opacity: 1;
  background: rgba(255, 255, 255, 0.2);
}

.message-images {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.message-image {
  max-width: 200px;
  max-height: 200px;
  border-radius: 4px;
  cursor: pointer;
}

.message-time {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
}

.message-admin .message-time {
  text-align: right;
}

.reply-container {
  background: #fff;
  padding: 16px 20px;
  border-top: 1px solid #ebeef5;
}

.upload-preview {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.preview-item {
  position: relative;
  width: 80px;
  height: 80px;
}

.preview-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 4px;
}

.delete-preview {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 20px;
  height: 20px;
  background: #f56c6c;
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 14px;
}

.reply-templates {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}

.template-filter-input {
  width: 130px;
}

.template-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  font-size: 12px;
  border-radius: 4px;
  border: 1px solid var(--el-border-color);
  background: var(--el-fill-color-blank);
  cursor: pointer;
  transition: all 0.2s;
  user-select: none;
}

.template-tag:hover {
  border-color: var(--el-color-primary);
  color: var(--el-color-primary);
}

.template-tag-name {
  max-width: 100px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.template-tag-delete {
  font-size: 12px;
  color: var(--el-text-color-placeholder);
  border-radius: 50%;
  transition: all 0.2s;
}

.template-tag-delete:hover {
  color: var(--el-color-danger);
  background: var(--el-color-danger-light-9);
}

.template-tag-add {
  border-style: dashed;
  color: var(--el-text-color-secondary);
}

.template-tag-add:hover {
  border-color: var(--el-color-primary);
  color: var(--el-color-primary);
}

.input-area {
  display: flex;
  flex-direction: column;
  gap: 12px;
  position: relative;
  transition: all 0.3s;
}

.input-area.drag-over {
  background: #f0f9ff;
  border: 2px dashed #409eff;
  border-radius: 4px;
  padding: 8px;
}

.input-area.drag-over::before {
  content: '释放以添加图片';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #409eff;
  font-size: 14px;
  font-weight: 500;
  pointer-events: none;
  z-index: 1;
}

.input-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.left-actions {
  display: flex;
  gap: 8px;
}

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

.closed-notice {
  padding: 16px 20px;
  background: #fff;
  border-top: 1px solid #ebeef5;
}

.edit-images-container {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.edit-preview-item {
  position: relative;
  width: 100px;
  height: 100px;
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid #dcdfe6;
}

.edit-preview-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.edit-preview-item .delete-preview {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 24px;
  height: 24px;
  background: #f56c6c;
  color: #fff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.add-image-btn {
  width: 100px;
  height: 100px;
  border: 2px dashed #dcdfe6;
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s;
  color: #909399;
}

.add-image-btn:hover {
  border-color: #409eff;
  color: #409eff;
}

.add-image-btn .add-text {
  font-size: 12px;
  margin-top: 4px;
}

/* 平板尺寸响应式样式 */
@media (max-width: 1024px) and (min-width: 769px) {
  .page-header {
    padding: 12px 16px;
    flex-wrap: wrap;
    gap: 12px;
  }

  .header-left {
    flex-wrap: wrap;
    gap: 8px;
  }

  .ticket-title {
    max-width: 200px;
  }

  .header-right {
    flex-wrap: wrap;
    gap: 8px;
  }

  .message-content {
    max-width: 70%;
  }

  .input-area {
    gap: 10px;
  }
}

/* 移动端响应式样式 */
@media (max-width: 768px) {
  .ticket-detail-page {
    padding: 0;
  }

  .page-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
    padding: 12px;
    height: auto;
  }

  .header-left {
    flex-wrap: wrap;
    gap: 8px;
    width: 100%;
  }

  .header-left .el-button {
    padding: 8px 12px;
    font-size: 13px;
  }

  .user-info {
    order: 3;
    width: 100%;
    margin-top: 8px;
  }

  .ticket-title {
    order: 4;
    width: 100%;
    max-width: none;
    margin-top: 8px;
    white-space: normal;
    line-height: 1.4;
  }

  .header-right {
    width: 100%;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
  }

  .header-right .ticket-id {
    font-size: 12px;
  }

  .header-right .el-select {
    width: 100px !important;
  }

  .header-right .el-button {
    font-size: 12px;
    padding: 6px 10px;
  }

  .chat-container {
    min-height: 300px;
  }

  .chat-messages {
    padding: 12px;
  }

  .message-content {
    max-width: 80%;
  }

  .message-text {
    padding: 10px 12px;
    font-size: 14px;
  }

  .message-image {
    max-width: 150px;
    max-height: 150px;
  }

  .reply-container {
    padding: 12px;
  }

  .input-actions {
    flex-direction: column;
    gap: 12px;
  }

  .left-actions {
    width: 100%;
    justify-content: flex-start;
  }

  .input-actions .el-button--primary {
    width: 100%;
  }

  .hint-text {
    display: none;
  }

  /* 用户信息弹窗 */
  .user-popover {
    width: 100% !important;
  }

  .popover-header {
    flex-direction: column;
    text-align: center;
  }

  .popover-info {
    margin-top: 8px;
  }

  /* 编辑消息弹窗 */
  :deep(.el-dialog) {
    width: 90% !important;
    margin: 5vh auto !important;
  }

  .edit-images-container {
    gap: 8px;
  }

  .edit-preview-item,
  .add-image-btn {
    width: 80px;
    height: 80px;
  }
}

@media (max-width: 480px) {
  .header-left .el-button span {
    display: none;
  }

  .header-left .el-button .el-icon {
    margin: 0;
  }

  .message-content {
    max-width: 85%;
  }

  .preview-item {
    width: 60px;
    height: 60px;
  }
}
</style>
