<script setup lang="ts">
import {onMounted, ref, computed, type Component, onUnmounted, provide} from 'vue'
import {ElMessage, ElMessageBox} from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
import {authApi} from './api/auth'
import {deviceApi, type DeviceItem, type DeviceQuota} from './api/device'
import {getOrCreateDeviceId} from './utils/deviceId'
import {getToken, setToken, removeToken, getUsernameFromToken, getClientIdFromToken} from './utils/token'
import {CONFIG} from './api/http'
import {getSettings} from './utils/settings'
import LoginDialog from './components/auth/LoginDialog.vue'
import RegisterDialog from './components/auth/RegisterDialog.vue'
import NavigationBar from './components/layout/NavigationBar.vue'
import RakutenDashboard from './components/rakuten/RakutenDashboard.vue'
import AmazonDashboard from './components/amazon/AmazonDashboard.vue'
import ZebraDashboard from './components/zebra/ZebraDashboard.vue'
import UpdateDialog from './components/common/UpdateDialog.vue'
import SettingsDialog from './components/common/SettingsDialog.vue'
import TrialExpiredDialog from './components/common/TrialExpiredDialog.vue'

const dashboardsMap: Record<string, Component> = {
  rakuten: RakutenDashboard,
  amazon: AmazonDashboard,
  zebra: ZebraDashboard,
}

const activeDashboard = computed<Component | null>(() => {
  if (!isAuthenticated.value) return null
  return dashboardsMap[activeMenu.value] || null
})

const isDefaultPanel = computed(() => ['rakuten', 'amazon', 'zebra'].includes(activeMenu.value))
const showHomeSplash = computed(() => !isAuthenticated.value && isDefaultPanel.value)
const showPlaceholder = computed(() => !showHomeSplash.value && !activeDashboard.value)

// 导航历史栈
const navigationHistory = ref<string[]>(['rakuten'])
const currentHistoryIndex = ref(0)

// 应用状态
const activeMenu = ref('rakuten')
const isAuthenticated = ref(false)
const showAuthDialog = ref(false)
const showRegDialog = ref(false)
const zhCnLocale = zhCn
const currentUsername = ref('')
const showDeviceDialog = ref(false)
const deviceLoading = ref(false)
const devices = ref<DeviceItem[]>([])
const deviceQuota = ref<DeviceQuota>({limit: 0, used: 0})
const userPermissions = ref<string>('')

// VIP状态
const vipExpireTime = ref<Date | null>(null)
const deviceTrialExpired = ref(false)
const accountType = ref<string>('trial')
const vipStatus = computed(() => {
  if (!vipExpireTime.value) return { isVip: false, daysLeft: 0, status: 'expired' }
  const now = new Date()
  const expire = new Date(vipExpireTime.value)
  const daysLeft = Math.ceil((expire.getTime() - now.getTime()) / (1000 * 60 * 60 * 24))
  
  if (daysLeft <= 0) return { isVip: false, daysLeft: 0, status: 'expired' }
  if (daysLeft <= 7) return { isVip: true, daysLeft, status: 'warning' }
  if (daysLeft <= 30) return { isVip: true, daysLeft, status: 'normal' }
  return { isVip: true, daysLeft, status: 'active' }
})

// 功能可用性（账号VIP + 设备试用期）
const canUseFunctions = computed(() => {
  // 付费账号不受设备限制
  if (accountType.value === 'paid') return vipStatus.value.isVip
  // 试用账号需要账号VIP有效 且 设备未过期
  return vipStatus.value.isVip && !deviceTrialExpired.value
})

// 更新对话框状态
const showUpdateDialog = ref(false)
const updateDialogRef = ref()

// 设置对话框状态
const showSettingsDialog = ref(false)

// 试用期过期对话框
const showTrialExpiredDialog = ref(false)
const trialExpiredType = ref<'device' | 'account' | 'both' | 'subscribe'>('device')

// 菜单配置 - 复刻ERP客户端格式
const menuConfig = [
  {key: 'rakuten', name: 'Rakuten', index: 'rakuten', icon: 'R'},
  {key: 'amazon', name: 'Amazon', index: 'amazon', icon: 'A'},
  {key: 'zebra', name: 'Zebra', index: 'zebra', icon: 'Z'},
  {key: 'shopee', name: 'Shopee', index: 'shopee', icon: 'S'},
]

// 权限检查 - 复刻ERP客户端逻辑
function hasPermission(module: string) {
  // 默认显示的基础菜单（未登录时也显示）
  const defaultModules = ['rakuten', 'amazon', 'zebra']

  if (!isAuthenticated.value) {
    return defaultModules.includes(module)
  }

  const permissions = userPermissions.value
  if (!permissions) {
    return defaultModules.includes(module) // 没有权限信息时显示默认菜单
  }
  return permissions.includes(module)
}

const visibleMenus = computed(() => menuConfig.filter(item => hasPermission(item.key)))

const canGoBack = computed(() => currentHistoryIndex.value > 0)
const canGoForward = computed(() => currentHistoryIndex.value < navigationHistory.value.length - 1)

function showContent() {
  const loading = document.getElementById('loading')
  if (loading) {
    loading.style.opacity = '0'
    setTimeout(() => {
      loading.style.display = 'none'
    }, 100)
  }
  const app = document.getElementById('app-root')
  if (app) app.style.opacity = '1'
}

function addToHistory(menu: string) {
  if (navigationHistory.value[currentHistoryIndex.value] !== menu) {
    navigationHistory.value = navigationHistory.value.slice(0, currentHistoryIndex.value + 1)
    navigationHistory.value.push(menu)
    currentHistoryIndex.value = navigationHistory.value.length - 1
  }
}

function goBack() {
  if (canGoBack.value) {
    currentHistoryIndex.value--
    activeMenu.value = navigationHistory.value[currentHistoryIndex.value]
  }
}

function goForward() {
  if (canGoForward.value) {
    currentHistoryIndex.value++
    activeMenu.value = navigationHistory.value[currentHistoryIndex.value]
  }
}

function reloadPage() {
  window.location.reload()
}

function handleMenuSelect(key: string) {
  // 检查是否需要认证
  const authRequiredMenus = ['rakuten', 'amazon', 'zebra', 'shopee']
  if (!isAuthenticated.value && authRequiredMenus.includes(key)) {
    showAuthDialog.value = true
    return
  }

  activeMenu.value = key
  addToHistory(key)
}

async function handleLoginSuccess(data: { token: string; permissions?: string; expireTime?: string; accountType?: string; deviceTrialExpired?: boolean }) {
  try {
    setToken(data.token)
    isAuthenticated.value = true
    showAuthDialog.value = false
    showRegDialog.value = false
    
    currentUsername.value = getUsernameFromToken(data.token)
    userPermissions.value = data.permissions || ''
    vipExpireTime.value = data.expireTime ? new Date(data.expireTime) : null
    accountType.value = data.accountType || 'trial'
    deviceTrialExpired.value = data.deviceTrialExpired || false
    
    const deviceId = await getOrCreateDeviceId()
    await deviceApi.register({
      username: currentUsername.value,
      deviceId,
      os: navigator.platform
    })
    SSEManager.connect()

    // 根据不同场景显示提示
    const accountExpired = vipExpireTime.value && new Date() > vipExpireTime.value
    const deviceExpired = deviceTrialExpired.value
    const isPaid = accountType.value === 'paid'
    
    if (deviceExpired && accountExpired) {
      // 场景4: 试用已到期，请订阅
      trialExpiredType.value = 'both'
      showTrialExpiredDialog.value = true
    } else if (accountExpired) {
      // 场景3: 账号试用已到期，请订阅
      trialExpiredType.value = 'account'
      showTrialExpiredDialog.value = true
    } else if (deviceExpired) {
      // 场景2: 设备试用已到期，请更换设备或订阅
      trialExpiredType.value = 'device'
      showTrialExpiredDialog.value = true
    }
  } catch (e: any) {
    isAuthenticated.value = false
    showAuthDialog.value = true
    removeToken()
    ElMessage.error(e?.message || '设备注册失败')
  }
}

function clearLocalAuth() {
  removeToken()
  isAuthenticated.value = false
  currentUsername.value = ''
  userPermissions.value = ''
  vipExpireTime.value = null
  deviceTrialExpired.value = false
  accountType.value = 'trial'
  showAuthDialog.value = true
  showDeviceDialog.value = false
  SSEManager.disconnect()
}

async function logout() {
  try {
    const deviceId = getClientIdFromToken()
    if (deviceId) await deviceApi.remove({ deviceId, username: currentUsername.value })
  } catch (error) {
    console.warn('离线通知失败:', error)
  }
  clearLocalAuth()
}

async function handleUserClick() {
  if (!isAuthenticated.value) {
    showAuthDialog.value = true
    return
  }
  try {
    await ElMessageBox.confirm('确认退出登录？', '提示', {
      type: 'warning',
      confirmButtonText: '退出',
      cancelButtonText: '取消'
    })
    await logout()
  } catch {}
}

function showRegisterDialog() {
  showAuthDialog.value = false
  showRegDialog.value = true
}

function backToLogin() {
  showRegDialog.value = false
  
  showAuthDialog.value = true
}

async function checkAuth() {
  try {
    const token = getToken()
    if (!token) {
      if (['rakuten', 'amazon', 'zebra', 'shopee'].includes(activeMenu.value)) {
        showAuthDialog.value = true
      }
      return
    }

    const res = await authApi.verifyToken(token)
    isAuthenticated.value = true
    currentUsername.value = getUsernameFromToken(token)
    userPermissions.value = res.data.permissions || ''
    deviceTrialExpired.value = res.data.deviceTrialExpired || false
    accountType.value = res.data.accountType || 'trial'
    
    if (res.data.expireTime) {
      vipExpireTime.value = new Date(res.data.expireTime)
    }
    
    SSEManager.connect()
  } catch {
    removeToken()
    if (['rakuten', 'amazon', 'zebra', 'shopee'].includes(activeMenu.value)) {
      showAuthDialog.value = true
    }
  }
}

// 刷新VIP状态（采集前调用）
async function refreshVipStatus() {
  try {
    const token = getToken()
    if (!token) return false
    
    const res = await authApi.verifyToken(token)
    deviceTrialExpired.value = res.data.deviceTrialExpired || false
    accountType.value = res.data.accountType || 'trial'
    if (res.data.expireTime) {
      vipExpireTime.value = new Date(res.data.expireTime)
    }
    return true
  } catch {
    return false
  }
}

// 判断过期类型
function checkExpiredType(): 'device' | 'account' | 'both' | 'subscribe' {
  const accountExpired = vipExpireTime.value && new Date() > vipExpireTime.value
  const deviceExpired = deviceTrialExpired.value
  
  if (deviceExpired && accountExpired) return 'both'
  if (accountExpired) return 'account'
  if (deviceExpired) return 'device'
  return 'account' // 默认
}

// 打开订阅对话框
function openSubscriptionDialog() {
  // 如果VIP有效，显示订阅/续费提示；如果已过期，显示过期提示
  if (vipStatus.value.isVip) {
    trialExpiredType.value = 'subscribe'
  } else {
    trialExpiredType.value = checkExpiredType()
  }
  showTrialExpiredDialog.value = true
}

// 提供给子组件使用
provide('refreshVipStatus', refreshVipStatus)
provide('checkExpiredType', checkExpiredType)

const SSEManager = {
  connection: null as EventSource | null,
  async connect() {
    if (this.connection) return

    try {
      const token = getToken()
      if (!token) return

      const clientId = getClientIdFromToken()
      if (!clientId) return

      const src = new EventSource(`${CONFIG.SSE_URL}?clientId=${clientId}&token=${token}`)
      this.connection = src
      src.onopen = () => console.log('SSE连接已建立')
      src.onmessage = (e) => this.handleMessage(e)
      src.onerror = () => this.handleError()
    } catch (e: any) {
      console.warn('SSE连接失败:', e?.message || e)
      this.disconnect()
    }
  },

  handleMessage(e: MessageEvent) {
    try {
      if (e.type === 'ping') return

      console.log('SSE消息:', e.data)
      const payload = JSON.parse(e.data)
      switch (payload.type) {
        case 'ready':
          console.log('SSE连接已就绪')
          break
        case 'DEVICE_REMOVED':
          clearLocalAuth()
          ElMessage.warning('会话已失效，请重新登录')
          break
        case 'FORCE_LOGOUT':
          logout()
          ElMessage.warning('会话已失效，请重新登录')
          break
        case 'PERMISSIONS_UPDATED':
          checkAuth()
          break
        case 'ACCOUNT_EXPIRED':
          vipExpireTime.value = null
          ElMessage.warning('您的VIP已过期，部分功能将受限')
          break
        case 'VIP_RENEWED':
          checkAuth()
          ElMessage.success('VIP已续费成功')
          break
      }
    } catch (err) {
      console.error('SSE消息处理失败:', err, '原始数据:', e.data)
    }
  },

  handleError() {
    console.warn('SSE连接失败,已断开')
    this.disconnect()
  },

  disconnect() {
    if (this.connection) {
      this.connection.close()
      this.connection = null
    }
  }
}

async function openDeviceManager() {
  if (!isAuthenticated.value) {
    showAuthDialog.value = true
    return
  }
  showDeviceDialog.value = true
  await fetchDeviceData()
}

function openSettings() {
  showSettingsDialog.value = true
}

async function fetchDeviceData() {
  if (!currentUsername.value) {
    ElMessage.warning('未获取到用户名，请重新登录')
    return
  }
  try {
    deviceLoading.value = true
    const [quotaRes, listRes] = await Promise.all([
      deviceApi.getQuota(currentUsername.value),
      deviceApi.list(currentUsername.value)
    ])

    deviceQuota.value = quotaRes.data
    const clientId = getClientIdFromToken()
    devices.value = listRes.data.map(d => ({...d, isCurrent: d.deviceId === clientId}))
  } catch (e: any) {
    ElMessage.error(e?.message || '获取设备列表失败')
  } finally {
    deviceLoading.value = false
  }
}

async function confirmRemoveDevice(row: DeviceItem) {
  try {
    await ElMessageBox.confirm('确定要移除该设备吗？', '你确定要移除设备吗?', {
      confirmButtonText: '确定移除',
      cancelButtonText: '取消',
      type: 'warning'
    })

    await deviceApi.remove({deviceId: row.deviceId, username: currentUsername.value})
    devices.value = devices.value.filter(d => d.deviceId !== row.deviceId)
    deviceQuota.value.used = Math.max(0, deviceQuota.value.used - 1)

    if (row.deviceId === getClientIdFromToken()) {
      clearLocalAuth()
    }

    ElMessage.success('已移除设备')
  } catch (e: any) {
    if (e !== 'cancel') ElMessage.error('移除设备失败: ' + (e?.message || '未知错误'))
  }
}


onMounted(async () => {
  showContent()
  await checkAuth()
  
  // 检查是否有待安装的更新
  await checkPendingUpdate()
})

async function checkPendingUpdate() {
  try {
    const result = await (window as any).electronAPI.checkPendingUpdate()
    if (result && result.hasPendingUpdate) {
      // 有待安装的更新，直接弹出安装对话框
      showUpdateDialog.value = true
    }
  } catch (error) {
    console.error('检查待安装更新失败:', error)
  }
}

// 处理自动更新配置变化
function handleAutoUpdateChanged(enabled: boolean) {
  if (enabled && updateDialogRef.value) {
    updateDialogRef.value.checkForUpdatesNow()
  }
}

// 处理打开更新对话框
function handleOpenUpdateDialog() {
  showUpdateDialog.value = true
}

onUnmounted(() => {
  SSEManager.disconnect()
})
</script>

<template>


  <div>
    <div id="app-root" class="root">
      <div class="loading-container" id="loading">
        <div class="loading-spinner"></div>
      </div>
      <div class="erp-container">
        <div class="sidebar">
          <div class="user-avatar">
            <img src="/icon/icon.png" alt="logo"/>
          </div>
          <div class="menu-group-title">电商平台</div>
          <ul class="menu">
            <li
                v-for="item in visibleMenus"
                :key="item.key"
                class="menu-item"
                :class="{ active: activeMenu === item.key }"
                @click="handleMenuSelect(item.key)"
            >
              <span class="menu-text"><span class="menu-icon" :data-k="item.key">{{ item.icon }}</span>{{
                  item.name
                }}</span>
            </li>
          </ul>

          <!-- VIP状态卡片 -->
          <div v-if="isAuthenticated" class="vip-status-card" :class="'vip-' + vipStatus.status" @click="openSubscriptionDialog">
            <div class="vip-info">
              <div class="vip-status-text">
                <template v-if="vipStatus.isVip">
                  <span v-if="vipStatus.status === 'warning'">即将到期</span>
                  <span v-else>订阅中</span>
                </template>
              </div>
              <div class="vip-expire-date" v-if="vipExpireTime">
                有效期至：{{ vipExpireTime ? new Date(vipExpireTime).toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' }) : '-' }}
              </div>
            </div>
          </div>

        </div>

        <div class="main-content">
          <NavigationBar
              :can-go-back="canGoBack"
              :can-go-forward="canGoForward"
              :active-menu="activeMenu"
              @go-back="goBack"
              @go-forward="goForward"
              @reload="reloadPage"
              @user-click="handleUserClick"
              @open-device="openDeviceManager"
              @open-settings="openSettings"/>
          <div class="content-body">
            <div
                class="dashboard-home"
                v-if="showHomeSplash">
              <div class="icon-container">
                <img src="/image/111.png" alt="ERP Logo" class="main-icon"/>
              </div>
            </div>
            <keep-alive v-if="activeDashboard">
              <component :is="activeDashboard" :key="activeMenu" :is-vip="canUseFunctions"/>
            </keep-alive>
            <div v-if="showPlaceholder" class="placeholder">
              <div class="placeholder-card">
                <div class="placeholder-title">{{ activeMenu.toUpperCase() }} 面板</div>
                <div class="placeholder-desc">功能开发中...</div>
              </div>
            </div>
          </div>

          <!-- 认证组件 -->
          <LoginDialog
              v-model="showAuthDialog"
              @login-success="handleLoginSuccess"
              @show-register="showRegisterDialog"/>

          <RegisterDialog
              v-model="showRegDialog"
              @login-success="handleLoginSuccess"
              @back-to-login="backToLogin"/>

          <!-- 更新对话框 -->
          <UpdateDialog ref="updateDialogRef" v-model="showUpdateDialog" />

          <!-- 设置对话框 -->
          <SettingsDialog v-model="showSettingsDialog" @auto-update-changed="handleAutoUpdateChanged" @open-update-dialog="handleOpenUpdateDialog" />

          <!-- 试用期过期弹框 -->
          <TrialExpiredDialog v-model="showTrialExpiredDialog" :expired-type="trialExpiredType" />

          <!-- 设备管理弹框 -->
          <el-dialog
              v-model="showDeviceDialog"
              width="560px"
              :close-on-click-modal="false"
              align-center
              class="device-dialog">
            <template #header>
              <div class="device-dialog-header">
                <img src="/icon/img.png" alt="devices" class="device-illustration"/>
                <div class="device-title">设备管理 <span class="device-count">({{ deviceQuota.used || 0 }}/{{ deviceQuota.limit || 0 }})</span></div>
                <div class="device-subtitle">当前账号可以授权绑定 {{ deviceQuota.limit }} 台设备</div>
              </div>
            </template>
            <el-table :data="devices" size="small" :loading="deviceLoading" style="width:100%" stripe>
              <el-table-column label="设备名" min-width="180">
                <template #default="scope">
                  <span>{{ scope.row.name || scope.row.deviceId }}</span>
                  <el-tag v-if="scope.row.isCurrent" size="small" type="success" style="margin-left:6px;">本机</el-tag>
                </template>
              </el-table-column>
              <el-table-column label="状态" width="90">
                <template #default="scope">
                  <el-tag :type="scope.row.status==='online' ? 'success' : 'info'" size="small">
                    {{ scope.row.status === 'online' ? '已登录' : '已登出' }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column label="最近" min-width="130">
                <template #default="scope">
                  <span>{{ scope.row.lastActiveAt || '-' }}</span>
                </template>
              </el-table-column>
              <el-table-column label="操作" width="100">
                <template #default="scope">
                  <el-button type="text" size="small" style="color:#F56C6C" @click="confirmRemoveDevice(scope.row)">
                    移除设备
                  </el-button>
                </template>
              </el-table-column>
            </el-table>
            <template #footer>
              <el-button @click="showDeviceDialog=false">关闭</el-button>
            </template>
          </el-dialog>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>

.root {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  background-color: #f5f5f5;
  opacity: 0;
  transition: opacity 0.1s ease;
}

.loading-container {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  width: 100%;
  position: fixed;
  top: 0;
  left: 0;
  background-color: #f5f5f5;
  z-index: 9999;
  transition: opacity 0.1s ease;
}

.loading-spinner {
  width: 50px;
  height: 50px;
  border: 5px solid #e6e6e6;
  border-top: 5px solid #409EFF;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.erp-container {
  display: flex;
  height: 100vh;
}

.sidebar {
  width: 180px;
  min-width: 180px;
  flex-shrink: 0;
  background: #ffffff;
  border-right: 1px solid #e8eaec;
  padding: 16px 12px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}

.platform-icons {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 12px;
}

.picon {
  width: 28px;
  height: 28px;
  object-fit: contain;
}

.user-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px 0;
  border-bottom: 1px solid #e8eaec;
  margin: 0 0 12px 0;
}

.user-avatar img {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  object-fit: contain;
  background: #ffffff;
}

.menu-group-title {
  font-size: 12px;
  color: #909399;
  margin: 8px 6px 10px;
  text-align: left;
}

.menu {
  list-style: none;
  padding: 0;
  margin: 0;
}

.menu-item {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  border-radius: 8px;
  cursor: pointer;
  color: #333333;
  margin-bottom: 4px;
}

.menu-item:hover {
  background: #f5f7fa;
}

.menu-item.active {
  background: #ecf5ff !important;
  color: #409EFF !important;
}

.menu-text {
  font-size: 14px;
}

.menu-text {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.menu-icon {
  display: inline-flex;
  width: 18px;
  height: 18px;
  border-radius: 4px;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: #fff;
}

.menu-icon[data-k="rakuten"] {
  background: #BF0000;
}

.menu-icon[data-k="amazon"] {
  background: #FF9900;
  color: #1A1A1A;
}

.menu-icon[data-k="zebra"] {
  background: #34495e;
}

.menu-icon[data-k="shopee"] {
  background: #EE4D2D;
}

.main-content {
  flex: 1;
  min-width: 0;
  position: relative;
  display: flex;
  flex-direction: column;
}


.content-body {
  position: relative;
  flex: 1;
  background: #fff;
  min-height: 0;
  overflow: hidden;
}

.dashboard-home {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #ffffff;
  z-index: 100;
}

.icon-container {
  display: flex;
  justify-content: center;
}

.main-icon {
  width: 400px;
  height: 400px;
  border-radius: 20px;
  object-fit: contain;
}

.placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff;
}

.placeholder-card {
  background: #ffffff;
  border: 1px solid #e8eaec;
  border-radius: 12px;
  padding: 24px 28px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
  color: #2c3e50;
}

.placeholder-title {
  font-size: 18px;
  font-weight: 600;
  margin-bottom: 8px;
}

.placeholder-desc {
  font-size: 13px;
  color: #606266;
}
.device-dialog-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 12px 0 4px 0;
  margin-left: 40px;
}
.device-dialog :deep(.el-dialog__header) {
  text-align: center;
}
.device-dialog :deep(.el-dialog__body) { padding-top: 0; }
.device-illustration {
  width: 180px;
  height: auto;
  object-fit: contain;
  margin-bottom: 8px;
}
.device-title {
  font-size: 18px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 6px;
}
.device-count { color: #909399; font-weight: 500; }
.device-subtitle { font-size: 12px; color: #909399; }

/* 浮动版本信息 */
.version-info {
  position: fixed;
  right: 10px;
  bottom: 10px;
  background: rgba(255,255,255,0.9);
  padding: 5px 10px;
  border-radius: 4px;
  font-size: 12px;
  color: #909399;
  z-index: 1000;
  cursor: pointer;
  user-select: none;
}

/* VIP状态卡片样式 */
.vip-status-card {
  margin-top: auto;
  width: 100%;
  min-height: 64px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  box-sizing: border-box;
  background: linear-gradient(135deg, #FFFAF0 0%, #FFE4B5 50%, #FFD700 100%);
  box-shadow: 0 2px 8px rgba(255, 215, 0, 0.15);
  transition: all 0.3s ease;
  position: relative;
  cursor: pointer;
  user-select: none;
}

.vip-status-card:hover {
  box-shadow: 0 3px 10px rgba(255, 215, 0, 0.25);
  transform: translateY(-1px);
}

.vip-status-card:active {
  transform: translateY(0);
}

/* 正常状态和警告状态 - 统一温暖金色渐变 */
.vip-status-card.vip-active,
.vip-status-card.vip-normal,
.vip-status-card.vip-warning {
  background: linear-gradient(135deg, #FFFAF0 0%, #FFE4B5 50%, #FFD700 100%);
  box-shadow: 0 2px 8px rgba(255, 215, 0, 0.15);
}

/* 过期状态 - 灰色，保持水平布局 */
.vip-status-card.vip-expired {
  background: linear-gradient(135deg, #FAFAFA 0%, #E8E8E8 100%);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
}

.vip-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  text-align: left;
}

.vip-status-text {
  font-size: 13px;
  font-weight: 600;
  color: #8B6914;
  text-align: left;
  letter-spacing: 0.3px;
}

.vip-expire-date {
  font-size: 10px;
  color: #A67C00;
  line-height: 1.3;
  text-align: left;
  opacity: 0.9;
}

.vip-status-card.vip-expired .vip-info {
  align-items: flex-start;
}

.vip-status-card.vip-expired .vip-status-text {
  color: #909399;
}

.vip-status-card.vip-expired .vip-expire-date {
  color: #B0B0B0;
}
</style>

<style>
/* 全局样式：限制图片预览器大小 */
.el-image-viewer__img {
  max-width: 50vw !important;
  max-height: 50vh !important;
  width: auto !important;
  height: auto !important;
}
</style>