<template>
  <div class="user-vm-list">
    <el-card class="main-container" shadow="never">
      <div class="filter-section">
        <div class="filter-content">
          <el-form :inline="true" class="search-form">
            <el-form-item label="用户ID">
              <el-input :model-value="filterUserName || (query.user_id ? `${query.user_id}` : '')"
                readonly placeholder="筛选用户" clearable style="width:140px;cursor:pointer"
                @click="showFilterUserSelector = true"
                @clear="query.user_id = ''; filterUserName = ''; handleSearch()" />
            </el-form-item>
            <el-form-item label="商品ID">
              <el-input :model-value="filterGoodName || (query.good_id ? `${query.good_id}` : '')"
                readonly placeholder="筛选商品" clearable style="width:140px;cursor:pointer"
                @click="showFilterProductSelector = true"
                @clear="query.good_id = ''; filterGoodName = ''; handleSearch()" />
            </el-form-item>
            <el-form-item label="关键词">
              <el-input v-model="query.key" placeholder="搜索关键词" clearable style="width:180px"
                @keyup.enter="handleSearch" @clear="handleSearch">
                <template #prefix><el-icon><Search /></el-icon></template>
              </el-input>
            </el-form-item>
            <el-form-item label="绑定状态">
              <el-select v-model="query.bound" placeholder="全部" clearable style="width:120px" @change="handleSearch">
                <el-option label="已绑定" :value="true" />
                <el-option label="未绑定" :value="false" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="handleSearch">
                <el-icon><Search /></el-icon>查询
              </el-button>
              <el-button @click="query.user_id = ''; query.good_id = ''; query.key = ''; query.bound = null; filterUserName = ''; filterGoodName = ''; handleSearch()">重置</el-button>
            </el-form-item>
          </el-form>
          <div class="action-bar">
            <el-button type="primary" @click="handleCreate()">
              <el-icon><Plus /></el-icon>新建用户虚拟机
            </el-button>
            <el-button type="success" @click="loadList">
              <el-icon><Refresh /></el-icon>刷新
            </el-button>
          </div>
        </div>
      </div>

      <div class="table-section">
        <el-alert v-if="listError" :title="listError" type="warning" :closable="false" show-icon style="margin:12px 20px 0" />
        <el-table :data="list" v-loading="loading" stripe style="width:100%"
          :header-cell-style="{ background: '#f8f9fa', color: '#2c3e50', fontWeight: 600, fontSize: '13px' }">
      <el-table-column label="用户商品ID" width="110">
        <template #default="{ row }">{{ row.id }}</template>
      </el-table-column>
      <el-table-column label="商品名称" min-width="150" show-overflow-tooltip>
        <template #default="{ row }">
          <el-link v-if="row.good?.name && row.itemId" type="primary" :underline="false" @click.stop="goDetail(row)">{{ row.good.name }}(ID:{{ row.good.id }})</el-link>
          <span v-else>{{ row.good?.name ? `${row.good.name}(ID:${row.good.id})` : '-' }}</span>
        </template>
      </el-table-column>
      <el-table-column label="用户" min-width="140" show-overflow-tooltip>
        <template #default="{ row }">
          <el-link v-if="row.userId || row.user_id" type="primary" :underline="false" @click.stop="router.push({ path: '/user/detail', query: { user_id: row.userId || row.user_id } })">{{ row.user?.UserName || '-' }}</el-link>
          <span v-else>-</span>
          <span style="color:#909399;font-size:12px"> (ID:{{ row.userId || row.user_id || '-' }})</span>
        </template>
      </el-table-column>
      <el-table-column label="绑定状态" width="90">
        <template #default="{ row }">
          <el-tag :type="row.itemId ? 'success' : 'info'" size="small">
            {{ row.itemId ? '已绑定' : '未绑定' }}
          </el-tag>
        </template>
      </el-table-column>
      <el-table-column label="续费价格" width="100">
        <template #default="{ row }">
          <span v-if="row.renewPrice">¥{{ (row.renewPrice / 100).toFixed(2) }}</span>
          <span v-else>-</span>
        </template>
      </el-table-column>
      <el-table-column label="基础价格" width="100">
        <template #default="{ row }">
          <span v-if="row.basePrice">¥{{ (row.basePrice / 100).toFixed(2) }}</span>
          <span v-else>-</span>
        </template>
      </el-table-column>
      <el-table-column label="到期时间" width="150">
        <template #default="{ row }">{{ formatExpireTime(row.expireTime) }}</template>
      </el-table-column>
      <el-table-column label="操作" width="200" fixed="right">
        <template #default="{ row }">
          <el-button v-if="row.itemId && row.itemId !== 0" link type="primary" size="small" @click="goDetail(row)">详情</el-button>
          <el-button v-if="row.itemId && row.itemId !== 0" link type="primary" size="small" @click="handleEdit(row)">编辑</el-button>
          <el-button v-if="!row.itemId || row.itemId === 0" link type="success" size="small" @click="handleBindVm(row)">绑定虚拟机</el-button>
          <el-dropdown trigger="click" @command="cmd => handleMoreCmd(cmd, row)" style="margin-left:8px">
            <el-button link type="primary" size="small" style="transform: translateY(4px);">更多<el-icon style="margin-left:2px;"><ArrowDown /></el-icon></el-button>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item command="remind">提醒记录</el-dropdown-item>
                <el-dropdown-item command="send">发送提醒</el-dropdown-item>
                <el-dropdown-item command="delete" divided style="color:#F56C6C">删除商品</el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </template>
      </el-table-column>
    </el-table>

        <el-pagination
          v-model:current-page="query.page"
          v-model:page-size="query.count"
          :page-sizes="[10, 20, 50]"
          :total="total"
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="s => { query.count = s; query.page = 1; loadList() }"
          @current-change="p => { query.page = p; loadList() }"
          background
          class="pagination"
        />
      </div>
    </el-card>

    <!-- 新建虚拟机 / 绑定虚拟机弹窗 -->
    <el-dialog v-model="createVisible" title="创建虚拟机/绑定已有虚拟机" width="900px" destroy-on-close class="scrollable-dialog" @opened="onCreateDialogOpened">
      <el-tabs v-model="createDialogTab" style="margin-top:-10px">
        <el-tab-pane label="创建用户虚拟机" name="create">
          <el-form ref="createFormRef" :model="createForm" :rules="createRules" label-width="120px" v-loading="createLoading">
            <!-- 行1: 商品 + 用户 -->
            <el-row :gutter="20">
              <el-col :span="12">
                <el-form-item label="商品" prop="good_id">
                  <div class="selector-row">
                    <el-input :model-value="createForm._goodName || (createForm.good_id ? `商品 #${createForm.good_id}` : '')" readonly placeholder="请选择商品" />
                    <el-button type="primary" @click="showProductSelector = true">选择</el-button>
                  </div>
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="用户" prop="user_id">
                  <div class="selector-row">
                    <el-input :model-value="createForm._userName || (createForm.user_id ? `用户 #${createForm.user_id}` : '')" readonly placeholder="请选择用户" />
                    <el-button type="primary" @click="showUserSelector = true">选择</el-button>
                  </div>
                </el-form-item>
              </el-col>
            </el-row>
        <!-- 行2: 虚拟机名称 -->
        <el-form-item label="虚拟机名称" prop="name">
          <el-input v-model="createForm.name" placeholder="虚拟机名称" />
        </el-form-item>
        <!-- 行3: 内存 + vCPU -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="内存" prop="memory">
              <div class="unit-input-row">
                <el-input-number v-model="createForm._memoryValue" :min="0" controls-position="right" style="flex:1" />
                <el-select v-model="createForm._memoryUnit" class="unit-select">
                  <el-option label="MB" value="MB" /><el-option label="GB" value="GB" />
                </el-select>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="vCPU" prop="vcpu">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.vcpu" :min="0" controls-position="right" style="flex:1" />
                <span class="unit-text">核</span>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
        <!-- 行4: 系统盘 + 主控服务 -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="系统盘" prop="system_size">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.system_size" :min="0" controls-position="right" style="flex:1" />
                <el-select v-model="createForm._systemSizeUnit" class="unit-select">
                  <el-option label="GB" value="GB" /><el-option label="TB" value="TB" />
                </el-select>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="主控服务">
              <div class="selector-row">
                <el-input :model-value="createForm._serviceName || (createForm._serviceId ? `主控 #${createForm._serviceId}` : '')" readonly placeholder="选择主控服务" />
                <el-button type="primary" @click="showServiceSelector = true">选择</el-button>
                <el-button v-if="createForm._serviceId" @click="createForm._serviceId = 0; createForm._serviceName = ''; createForm.image_id = 0; createForm._imageName = ''">清除</el-button>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
        <!-- 行5: 下行带宽 + 镜像 -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="下行带宽">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.rx_bandwidth" :min="0" controls-position="right" style="flex:1" />
                <el-select v-model="createForm._rxUnit" class="unit-select">
                  <el-option label="Mbps" value="Mbps" /><el-option label="Gbps" value="Gbps" />
                </el-select>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="镜像" prop="image_id">
              <div class="selector-row">
                <el-input :model-value="createForm._imageName || (createForm.image_id ? `镜像 #${createForm.image_id}` : '')" readonly placeholder="请先选择商品" />
                <el-button type="primary" @click="showImageSelector = true" :disabled="!createForm.good_id">选择</el-button>
                <el-button v-if="createForm.image_id" @click="createForm.image_id = 0; createForm._imageName = ''">清除</el-button>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
        <!-- 行6: 上行带宽 + 额外数据卷 -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="上行带宽">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.tx_bandwidth" :min="0" controls-position="right" style="flex:1" />
                <el-select v-model="createForm._txUnit" class="unit-select">
                  <el-option label="Mbps" value="Mbps" /><el-option label="Gbps" value="Gbps" />
                </el-select>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="数据卷">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.data_volume_size" :min="0" controls-position="right" style="flex:1" />
                <span class="unit-text">GB</span>
              </div>
              <div style="font-size:12px;color:#909399;margin-top:2px">额外数据卷大小，0 表示不创建</div>
            </el-form-item>
          </el-col>
        </el-row>
        <!-- 行7: IPv4 + IPv6 -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="IPv4数量">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.ipv4_num" :min="0" controls-position="right" style="flex:1" />
                <span class="unit-text">个</span>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="IPv6数量">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.ipv6_num" :min="0" controls-position="right" style="flex:1" />
                <span class="unit-text">个</span>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="快照上限">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.snapshot_num" :min="0" controls-position="right" style="flex:1" />
                <span class="unit-text">个</span>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="备份上限">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.backup_num" :min="0" controls-position="right" style="flex:1" />
                <span class="unit-text">个</span>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
        <!-- 流量策略（可选） -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="流量上限">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.traffic_max" :min="0" controls-position="right" style="flex:1" />
                <span class="unit-text">MB</span>
              </div>
              <div style="font-size:12px;color:#909399;margin-top:2px">0 表示不限流量</div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
          </el-col>
        </el-row>
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="耗尽下行限速">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.traffic_exhausted_rx_mbps" :min="0" :precision="2" controls-position="right" style="flex:1" />
                <span class="unit-text">Mbps</span>
              </div>
              <div style="font-size:12px;color:#909399;margin-top:2px">流量耗尽后下行速率，0 表示不限</div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="耗尽上行限速">
              <div class="unit-input-row">
                <el-input-number v-model="createForm.traffic_exhausted_tx_mbps" :min="0" :precision="2" controls-position="right" style="flex:1" />
                <span class="unit-text">Mbps</span>
              </div>
              <div style="font-size:12px;color:#909399;margin-top:2px">流量耗尽后上行速率，0 表示不限</div>
            </el-form-item>
          </el-col>
        </el-row>
        <!-- 行9: 续费价格 + 基础价格 -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="续费价格">
              <div class="unit-input-row">
                <el-input-number v-model="createForm._renewPriceYuan" :min="0" :precision="2" controls-position="right" style="flex:1" />
                <span class="unit-text">元</span>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="基础价格">
              <div class="unit-input-row">
                <el-input-number v-model="createForm._basePriceYuan" :min="0" :precision="2" controls-position="right" style="flex:1" />
                <span class="unit-text">元</span>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
        <!-- 行9: 基础价格 + 订单 -->
        <!-- 行10: 订单 + 到期时间 -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="订单">
              <div class="selector-row">
                <el-input :model-value="createForm._orderName || (createForm.order_id ? `订单 #${createForm.order_id}` : '')" readonly placeholder="可选" />
                <el-button type="primary" @click="showOrderSelector = true">选择</el-button>
                <el-button v-if="createForm.order_id" @click="createForm.order_id = 0; createForm._orderName = ''">清除</el-button>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="到期时间">
              <el-date-picker v-model="createForm.expire_time" type="datetime" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" />
            </el-form-item>
          </el-col>
        </el-row>
        <!-- 行11: 宿主机 + 宿主机组 -->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="指定宿主机">
              <div class="selector-row">
                <el-input :model-value="createForm._hostName || (createForm.host_id ? `宿主机 #${createForm.host_id}` : '')" readonly placeholder="可选，不选则自动分配" />
                <el-button type="primary" @click="showHostSelector = true" :disabled="!createForm._serviceId">选择</el-button>
                <el-button v-if="createForm.host_id" @click="createForm.host_id = 0; createForm._hostName = ''">清除</el-button>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="指定宿主机组">
              <div class="selector-row">
                <el-input :model-value="createForm._hostGroupName || (createForm.host_group_id ? `主机组 #${createForm.host_group_id}` : '')" readonly placeholder="可选，不选则用商品绑定的" />
                <el-button type="primary" @click="showHostGroupSelector = true" :disabled="!createForm._serviceId">选择</el-button>
                <el-button v-if="createForm.host_group_id" @click="createForm.host_group_id = 0; createForm._hostGroupName = ''">清除</el-button>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="网络">
              <div class="selector-row">
                <el-input :model-value="createForm._networkNames || ''" readonly placeholder="可选，可多选" />
                <el-button type="primary" @click="showNetworkSelector = true" :disabled="!createForm._serviceId || !createForm.host_id">选择</el-button>
                <el-button v-if="createForm.network_ids.length" @click="createForm.network_ids = []; createForm._networkNames = ''">清除</el-button>
              </div>
              <div v-if="!createForm.host_id && createForm._serviceId" style="font-size:12px;color:#c0c4cc;margin-top:2px">请先选择宿主机</div>
            </el-form-item>
          </el-col>
        </el-row>
            <!-- 行12: 备注 -->
            <el-form-item label="备注">
              <el-input v-model="createForm.note" type="textarea" :rows="2" />
            </el-form-item>
          </el-form>
        </el-tab-pane>
        <el-tab-pane label="绑定虚拟机" name="bind">
          <el-form ref="bindGoodsFormRef" :model="bindGoodsForm" :rules="bindGoodsFormRules" label-width="110px">
            <el-form-item label="商品" prop="good_id">
              <div class="selector-row">
                <el-input :model-value="bindGoodsForm._goodName || (bindGoodsForm.good_id ? `商品 #${bindGoodsForm.good_id}` : '')"
                  readonly placeholder="请选择商品" style="flex:1" />
                <el-button type="primary" @click="showBindGoodsProductSelector = true" style="margin-left:8px">选择</el-button>
                <el-button v-if="bindGoodsForm.good_id" @click="bindGoodsForm.good_id = 0; bindGoodsForm._goodName = ''; bindGoodsForm._goodTag = ''; bindGoodsForm.item_id = 0; bindGoodsForm._itemName = ''" style="margin-left:4px">清除</el-button>
              </div>
            </el-form-item>
            <el-form-item label="用户" prop="user_id">
              <div class="selector-row">
                <el-input :model-value="bindGoodsForm._userName || (bindGoodsForm.user_id ? `用户 #${bindGoodsForm.user_id}` : '')"
                  readonly placeholder="请选择用户" style="flex:1" />
                <el-button type="primary" @click="showBindGoodsUserSel = true" style="margin-left:8px">选择</el-button>
                <el-button v-if="bindGoodsForm.user_id" @click="bindGoodsForm.user_id = 0; bindGoodsForm._userName = ''" style="margin-left:4px">清除</el-button>
              </div>
            </el-form-item>
            <el-form-item label="订单">
              <div class="selector-row">
                <el-input :model-value="bindGoodsForm._orderName || (bindGoodsForm.order_id ? `订单 #${bindGoodsForm.order_id}` : '')"
                  readonly placeholder="可选" style="flex:1" />
                <el-button type="primary" @click="showBindGoodsOrderSelector = true" style="margin-left:8px">选择</el-button>
                <el-button v-if="bindGoodsForm.order_id" @click="bindGoodsForm.order_id = 0; bindGoodsForm._orderName = ''" style="margin-left:4px">清除</el-button>
              </div>
            </el-form-item>
            <el-form-item label="套餐">
              <div class="selector-row">
                <el-input :model-value="bindGoodsForm._planName || (bindGoodsForm.good_plan_id ? `套餐 #${bindGoodsForm.good_plan_id}` : '')"
                  readonly placeholder="可选，选择后自动填入参数" style="flex:1" />
                <el-button type="primary" @click="showBindGoodsPlanSelector = true" :disabled="!bindGoodsForm.good_id" style="margin-left:8px">选择</el-button>
                <el-button v-if="bindGoodsForm.good_plan_id" @click="bindGoodsForm.good_plan_id = 0; bindGoodsForm._planName = ''" style="margin-left:4px">清除</el-button>
              </div>
            </el-form-item>
            <el-form-item label="归属项">
              <div class="selector-row">
                <el-input :model-value="bindGoodsForm._itemName || (bindGoodsForm.item_id ? `#${bindGoodsForm.item_id}` : '')"
                  readonly placeholder="可选" style="flex:1" />
                <el-button type="primary" @click="handleBindGoodsItemSelect" :disabled="!bindGoodsForm.good_id" style="margin-left:8px">
                  {{ bindGoodsForm._goodTag === '云服务器' ? '选择虚拟机' : '使用商品ID' }}
                </el-button>
                <el-button v-if="bindGoodsForm.item_id" @click="bindGoodsForm.item_id = 0; bindGoodsForm._itemName = ''" style="margin-left:4px">清除</el-button>
              </div>
              <div v-if="!bindGoodsForm.good_id" class="form-hint disabled">请先选择商品</div>
              <div v-else-if="bindGoodsForm._goodTag === '云服务器'" class="form-hint">云服务器商品，点击选择用户虚拟机作为归属项</div>
              <div v-else class="form-hint">普通商品，点击将商品ID赋值为归属项</div>
            </el-form-item>
            <el-form-item label="续费价格">
              <div class="unit-input-row">
                <el-input-number v-model="bindGoodsForm._renewYuan" :min="0" :precision="2" controls-position="right" style="flex:1" />
                <span class="unit-text">元</span>
              </div>
            </el-form-item>
            <el-form-item label="基础价格">
              <div class="unit-input-row">
                <el-input-number v-model="bindGoodsForm._baseYuan" :min="0" :precision="2" controls-position="right" style="flex:1" />
                <span class="unit-text">元</span>
              </div>
            </el-form-item>
            <el-form-item label="到期时间">
              <el-date-picker v-model="bindGoodsForm.expire_time" type="datetime"
                format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" />
            </el-form-item>
            <el-form-item label="备注">
              <el-input v-model="bindGoodsForm.note" type="textarea" :rows="2" />
            </el-form-item>
          </el-form>
        </el-tab-pane>
      </el-tabs>
      <template #footer>
        <el-button @click="createVisible = false">取消</el-button>
        <el-button v-if="createDialogTab === 'create'" type="primary" :loading="createLoading" @click="submitCreate">确定创建</el-button>
        <el-button v-if="createDialogTab === 'bind'" type="primary" :loading="bindGoodsFormLoading" @click="submitBindGoodsForm">确定</el-button>
      </template>
    </el-dialog>

    <!-- 编辑用户商品弹窗 -->
    <el-dialog v-model="editVisible" title="编辑用户商品" width="600px" destroy-on-close class="scrollable-dialog">
      <el-form ref="editFormRef" :model="editForm" :rules="editRules" label-width="110px">
        <el-form-item label="归属项">
          <div class="selector-row">
            <el-input :model-value="editForm._itemName || (editForm.item_id ? `虚拟机 #${editForm.item_id}` : '')" readonly placeholder="可选" style="flex:1" />
            <el-button type="primary" @click="handleEditItemSelect" :disabled="!editForm._goodId" style="margin-left:8px">{{ editForm._goodTag === '云服务器' ? '选择用户虚拟机' : '使用商品ID' }}</el-button>
            <el-button v-if="editForm.item_id" @click="editForm.item_id = 0; editForm._itemName = ''" style="margin-left:4px">清除</el-button>
          </div>
          <div v-if="editForm._goodTag === '云服务器'" class="form-hint">云服务器商品，点击选择用户虚拟机作为归属项</div>
          <div v-else class="form-hint">普通商品，点击分配商品ID作为归属项</div>
        </el-form-item>
        <el-form-item label="续费价格">
          <div class="unit-input-row">
            <el-input-number v-model="editForm._renewYuan" :min="0" :precision="2" controls-position="right" style="flex:1" />
            <span class="unit-text">元</span>
          </div>
        </el-form-item>
        <el-form-item label="基础价格">
          <div class="unit-input-row">
            <el-input-number v-model="editForm._baseYuan" :min="0" :precision="2" controls-position="right" style="flex:1" />
            <span class="unit-text">元</span>
          </div>
        </el-form-item>
        <el-form-item label="到期时间">
          <el-date-picker v-model="editForm.expire_time" type="datetime" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" />
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="editForm.note" type="textarea" :rows="2" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="editVisible = false">取消</el-button>
          <el-button type="primary" :loading="editLoading" @click="submitEdit">保存</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 用户虚拟机选择弹窗 -->
    <el-dialog v-model="showVmListDialog" title="选择用户虚拟机" width="800px" append-to-body destroy-on-close>
      <div style="margin-bottom:12px">
        <el-form :inline="true" size="default">
          <el-form-item label="关键词">
            <el-input v-model="vmListQuery.key" placeholder="搜索" clearable style="width:180px"
              @keyup.enter="loadVmListForItem" @clear="loadVmListForItem" />
          </el-form-item>
          <el-form-item label="用户ID">
            <div class="selector-row">
              <el-input :model-value="vmListQuery._userName || (vmListQuery.user_id ? `用户 #${vmListQuery.user_id}` : '')"
                readonly placeholder="按用户筛选" style="flex:1" @click="showVmUserSelector = true" />
              <el-button v-if="vmListQuery.user_id" @click="vmListQuery.user_id = ''; vmListQuery._userName = ''; loadVmListForItem()" style="margin-left:4px">清除</el-button>
            </div>
          </el-form-item>
          <el-form-item label="状态">
            <el-select v-model="vmListQuery.status" placeholder="筛选状态" clearable style="width:120px" @change="loadVmListForItem">
              <el-option label="运行中" value="running" />
              <el-option label="已停止" value="stopped" />
              <el-option label="未知" value="unknown" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="loadVmListForItem">搜索</el-button>
            <el-button @click="loadVmListForItem" :icon="Refresh">刷新</el-button>
            <el-button @click="resetVmListFilters">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
      <el-table :data="vmListForItem" v-loading="vmListLoading" highlight-current-row
        @current-change="r => vmListSelected = r" :height="350" style="width:100%"
        :header-cell-style="{ background: '#f8f9fa', color: '#2c3e50', fontWeight: 600 }">
        <el-table-column prop="id" label="ID" width="80" />
        <el-table-column label="虚拟机名称" min-width="160" show-overflow-tooltip>
          <template #default="{ row }">{{ row.name || '-' }}</template>
        </el-table-column>
        <el-table-column label="配置" min-width="120">
          <template #default="{ row }">
            <div v-if="row.vcpu && row.memory">
              {{ row.vcpu }}core / {{ formatMemory(row.memory) }}
            </div>
            <span v-else>-</span>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="80">
          <template #default="{ row }">
            <el-tag :type="getStatusType(row.status)" size="small">
              {{ getStatusText(row.status) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="绑定状态" width="90">
          <template #default="{ row }">
            <el-tag :type="row.bound ? 'success' : 'info'" size="small">
              {{ row.bound ? '已绑定' : '未绑定' }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="IP地址" min-width="180" show-overflow-tooltip>
          <template #default="{ row }">{{ row.ips || '-' }}</template>
        </el-table-column>
        <el-table-column label="用户ID" width="80">
          <template #default="{ row }">{{ row.user_id || '-' }}</template>
        </el-table-column>
        <template #empty>
          <el-empty description="暂无虚拟机数据" :image-size="80" />
        </template>
      </el-table>
      <div style="display:flex;justify-content:flex-end;margin-top:12px">
        <el-pagination v-model:current-page="vmListQuery.page" v-model:page-size="vmListQuery.count"
          :total="vmListTotal" :page-sizes="[10,20,50]" layout="total,sizes,prev,pager,next" background
          @size-change="s => { vmListQuery.count = s; vmListQuery.page = 1; loadVmListForItem() }"
          @current-change="p => { vmListQuery.page = p; loadVmListForItem() }" />
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="showVmListDialog = false">取消</el-button>
          <el-button type="primary" :disabled="!vmListSelected" @click="confirmVmForItem">确定选择</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 订单参数配置弹窗 -->
    <el-dialog v-model="showArgsDialog" title="配置订单参数" width="600px" append-to-body destroy-on-close class="scrollable-dialog">
      <div v-if="argsSpecLoading" v-loading="true" style="min-height:120px"></div>
      <el-empty v-else-if="argsSpecList.length === 0" description="该商品暂无参数配置" :image-size="80" />
      <div v-else>
        <div v-for="spec in argsSpecList" :key="spec.id" class="args-spec-item">
          <div class="args-spec-label">
            {{ spec.name }}
            <el-tag v-if="spec.must" size="small" type="danger" style="margin-left:6px">必填</el-tag>
          </div>
          <template v-if="spec.type === 'select' && spec.attrs && spec.attrs.length > 0">
            <el-radio-group v-model="argsValues[spec.id]" size="small" @change="buildArgsJson">
              <el-radio-button v-for="attr in spec.attrs" :key="attr.id" :value="attr.id">{{ attr.name }}</el-radio-button>
            </el-radio-group>
          </template>
          <template v-else-if="spec.type === 'number'">
            <div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap">
              <el-input-number
                v-model="argsDisplayValues[spec.id]"
                :min="hasUnit(spec) ? fromBaseUnit(spec.min ?? 0, argsDisplayUnits[spec.id], getArgKey(spec)) : (spec.min ?? 0)"
                :max="hasUnit(spec) ? fromBaseUnit(spec.max ?? 0, argsDisplayUnits[spec.id], getArgKey(spec)) : (spec.max ?? 0)"
                :step="hasUnit(spec) ? (fromBaseUnit(spec.step ?? 1, argsDisplayUnits[spec.id], getArgKey(spec)) || 1) : (spec.step ?? 1)"
                :step-strictly="true"
                @change="onArgsNumberChange(spec)"
                style="width:200px"
              />
              <el-select v-if="hasUnit(spec)" :model-value="argsDisplayUnits[spec.id]" size="default" style="width:90px" @change="(newUnit) => onArgsUnitChange(spec, newUnit)">
                <el-option v-for="u in getParamUnits(spec)" :key="u" :label="u" :value="u" />
              </el-select>
              <span class="form-hint" style="margin-top:0">范围: {{ spec.min ?? 0 }} ~ {{ spec.max ?? 0 }}
                <template v-if="hasUnit(spec)"> {{ getBaseUnit(getArgKey(spec)) }}</template>，步长: {{ spec.step ?? 1 }}</span>
            </div>
          </template>
          <template v-else>
            <el-input v-model="argsValues[spec.id]" placeholder="请输入值" style="width:200px" @input="buildArgsJson" />
          </template>
        </div>
        <div v-if="editForm.order_args" style="margin-top:16px">
          <div class="form-hint" style="margin-bottom:6px;margin-top:0">生成的参数 JSON：</div>
          <el-input v-model="editForm.order_args" type="textarea" :rows="4" readonly style="font-family:monospace;font-size:12px" />
        </div>
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="showArgsDialog = false">取消</el-button>
          <el-button type="primary" @click="showArgsDialog = false">确定</el-button>
        </div>
      </template>
    </el-dialog>

    <!-- 到期提醒记录弹窗 -->
    <el-dialog v-model="remindVisible" title="到期提醒记录" width="700px" destroy-on-close append-to-body>
      <div style="margin-bottom:12px;display:flex;justify-content:space-between;align-items:center">
        <span style="font-size:13px;color:#909399">用户商品 ID: {{ remindGoodsId }}</span>
        <el-button type="primary" size="small" :icon="Refresh" @click="loadRemindList">刷新</el-button>
      </div>
      <el-table :data="remindList" v-loading="remindLoading" stripe size="small" :max-height="400">
        <el-table-column prop="id" label="ID" width="60" />
        <el-table-column label="用户" width="100">
          <template #default="{ row }">{{ row.user?.UserName || row.user?.user_name || `#${row.userId ?? row.user_id ?? '-'}` }}</template>
        </el-table-column>
        <el-table-column label="提醒类型" width="80">
          <template #default="{ row }">
            <el-tag size="small" :type="row.type === 'manual' ? 'warning' : 'info'">{{ row.type === 'manual' ? '手动' : '自动' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="发送方式" width="80">
          <template #default="{ row }">
            <el-tag size="small" :type="row.method === 'sms' ? 'success' : row.method === 'email' ? 'primary' : 'info'">{{ row.method === 'sms' ? '短信' : row.method === 'email' ? '邮件' : (row.method || '-') }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="发送状态" width="80">
          <template #default="{ row }">
            <el-tag size="small" :type="row.success ? 'success' : 'danger'">{{ row.success ? '成功' : '失败' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="发送时间" min-width="160">
          <template #default="{ row }">{{ formatRemindTime(row) }}</template>
        </el-table-column>
        <el-table-column label="备注" min-width="120" show-overflow-tooltip>
          <template #default="{ row }">{{ row.note || '-' }}</template>
        </el-table-column>
      </el-table>
      <div style="display:flex;justify-content:flex-end;margin-top:12px" v-if="remindTotal > remindQuery.count">
        <el-pagination v-model:current-page="remindQuery.page" :page-size="remindQuery.count" :total="remindTotal" layout="total, prev, pager, next" small background @current-change="loadRemindList" />
      </div>
    </el-dialog>

    <!-- 选择器组件 -->
    <ProductSelector v-model="showProductSelector" default-tag="云服务器" @confirm="handleProductSelect" />
    <ProductSelector v-model="showProductSelectorEdit" default-tag="云服务器" @confirm="handleProductSelectEdit" />
    <UserSelector v-model:visible="showUserSelector" @select="u => { createForm.user_id = u.user_id; createForm._userName = u.user_name }" />
    <UserSelector v-model:visible="showUserSelectorEdit" @select="u => { editForm.user_id = u.user_id; editForm._userName = u.user_name }" />
    <UserSelector v-model:visible="showVmUserSelector" @select="handleVmUserSelect" />
    <OrderSelector v-model="showOrderSelector" @confirm="o => { createForm.order_id = o.id; createForm._orderName = o.name }" />
    <OrderSelector v-model="showOrderSelectorEdit" @confirm="handleOrderSelectEdit" />
    <PlanSelector v-model="showPlanSelector" :good-id="createForm.good_id || 0" @confirm="handlePlanSelectedForCreate" />
    <PlanSelector v-model="showPlanSelectorEdit" :good-id="editForm.good_id || 0" @confirm="handlePlanSelectEdit" />
    <KvmServiceSelector v-model="showServiceSelector" @confirm="s => { createForm._serviceId = s.id; createForm._serviceName = s.name; createForm.image_id = 0; createForm._imageName = ''; createForm.host_id = 0; createForm._hostName = ''; createForm.host_group_id = 0; createForm._hostGroupName = ''; createForm.network_ids = []; createForm._networkNames = '' }" />
    <ImageSelectorPopup v-model="showImageSelector" :good-id="createForm.good_id || 0" :use-user-vm-api="true" @confirm="img => { createForm.image_id = img.id; createForm._imageName = img.name }" />
    <!-- 宿主机选择器 -->
    <HostSelectorPopup v-model="showHostSelector" :service-id="createForm._serviceId || 0" @confirm="h => { createForm.host_id = h.id; createForm._hostName = h.name || h.ip; createForm.network_ids = []; createForm._networkNames = '' }" />
    <!-- 宿主机组选择器 -->
    <HostGroupSelectorPopup v-model="showHostGroupSelector" :service-id="createForm._serviceId || 0" @confirm="g => { createForm.host_group_id = g.id; createForm._hostGroupName = g.name }" />
    <!-- 网络选择器（多选用弹窗内表格） -->
    <NetworkSelectorPopup v-model="showNetworkSelector" :service-id="createForm._serviceId || 0" :host-id="createForm.host_id || 0" filter-used="false" @confirm="n => addNetwork(n)" />
    <UserVmSecurityGroupSelector v-model="showSgSelector" :user-goods-id="editForm.id" @confirm="sg => { editForm.port_group_id = sg.id; editForm._sgName = sg.name }" />
    <UserVmNetworkSelector v-model="showEditNetworkSelector" :user-goods-id="editForm.id" @confirm="net => { editForm.internet_network_id = net.id; editForm._networkName = net.name }" />

    <!-- 绑定虚拟机弹窗 -->
    <el-dialog v-model="bindVmDialogVisible" title="绑定虚拟机" width="900px" destroy-on-close append-to-body>
      <div v-if="bindTargetRow" style="margin-bottom:8px;color:#909399;font-size:13px">
        绑定目标用户商品: <b>{{ bindTargetRow.good?.name || '-' }}</b>（ID: {{ bindTargetRow.id }}），用户: {{ bindTargetRow.user?.UserName || '-' }}
      </div>
      <!-- 全局模式：商品选择 + 筛选 -->
      <template v-if="!bindTargetRow">
        <div style="margin-bottom:12px">
          <el-form :inline="true" size="default">
            <el-form-item label="商品">
              <div class="selector-row" style="width:260px">
                <el-input
                  :model-value="bindSelectedProduct ? `${bindSelectedProduct.name}（ID: ${bindSelectedProduct.id}）` : ''"
                  readonly placeholder="请先选择商品" style="flex:1;cursor:pointer"
                  @click="showBindProductSelector = true" />
                <el-button v-if="bindSelectedProduct" link @click.stop="bindSelectedProduct = null; bindVmList = []; bindVmTotal = 0">清除</el-button>
              </div>
            </el-form-item>
            <el-form-item label="关键词">
              <el-input v-model="bindVmQuery.key" placeholder="搜索" clearable style="width:140px"
                :disabled="!bindSelectedProduct"
                @keyup.enter="loadBindVmList" @clear="loadBindVmList" />
            </el-form-item>
            <el-form-item label="状态">
              <el-select v-model="bindVmQuery.status" placeholder="全部" clearable style="width:110px"
                :disabled="!bindSelectedProduct" @change="loadBindVmList">
                <el-option label="运行中" value="running" />
                <el-option label="已停止" value="stopped" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" :disabled="!bindSelectedProduct" @click="loadBindVmList">搜索</el-button>
              <el-button :disabled="!bindSelectedProduct" @click="bindVmQuery.key = ''; bindVmQuery.status = ''; loadBindVmList()">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
        <el-alert v-if="!bindSelectedProduct" title="请先选择商品，选择后将自动加载该商品下的虚拟机列表" type="info" :closable="false" show-icon style="margin-bottom:12px" />
      </template>
      <!-- 行内模式：只有筛选 -->
      <div v-else style="margin-bottom:12px">
        <el-form :inline="true" size="default">
          <el-form-item label="关键词">
            <el-input v-model="bindVmQuery.key" placeholder="搜索" clearable style="width:160px"
              @keyup.enter="loadBindVmList" @clear="loadBindVmList" />
          </el-form-item>
          <el-form-item label="状态">
            <el-select v-model="bindVmQuery.status" placeholder="全部" clearable style="width:120px" @change="loadBindVmList">
              <el-option label="运行中" value="running" />
              <el-option label="已停止" value="stopped" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="loadBindVmList">搜索</el-button>
            <el-button @click="bindVmQuery.key = ''; bindVmQuery.status = ''; loadBindVmList()">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
      <el-table v-if="bindTargetRow || bindSelectedProduct" :data="bindVmList" v-loading="bindVmLoading" stripe :height="380" style="width:100%"
        :header-cell-style="{ background: '#f8f9fa', color: '#2c3e50', fontWeight: 600 }">
        <el-table-column prop="id" label="ID" width="80" />
        <el-table-column label="虚拟机名称" min-width="150" show-overflow-tooltip>
          <template #default="{ row }">{{ row.name || '-' }}</template>
        </el-table-column>
        <el-table-column label="配置" min-width="120">
          <template #default="{ row }">
            <span v-if="row.vcpu && row.memory">{{ row.vcpu }}核 / {{ formatMemory(row.memory) }}</span>
            <span v-else>-</span>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="80">
          <template #default="{ row }">
            <el-tag :type="vmStatusType(row.status)" size="small">{{ vmStatusLabel(row.status) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="绑定状态" width="90">
          <template #default="{ row }">
            <el-tag :type="row.bound ? 'success' : 'info'" size="small">{{ row.bound ? '已绑定' : '未绑定' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="IP地址" min-width="180" show-overflow-tooltip>
          <template #default="{ row }">{{ row.ips || '-' }}</template>
        </el-table-column>
        <el-table-column label="用户" width="80">
          <template #default="{ row }">{{ row.user_id || '-' }}</template>
        </el-table-column>
        <el-table-column label="操作" width="80" fixed="right">
          <template #default="{ row }">
            <el-button v-if="!row.bound" link type="primary" size="small"
              :loading="bindSubmitLoading && bindSubmitVmId === row.id"
              @click="onBindVmClick(row)">绑定</el-button>
            <span v-else class="text-muted">-</span>
          </template>
        </el-table-column>
        <template #empty>
          <el-empty description="暂无虚拟机数据" :image-size="80" />
        </template>
      </el-table>
      <div v-if="bindTargetRow || bindSelectedProduct" style="display:flex;justify-content:flex-end;margin-top:12px">
        <el-pagination v-model:current-page="bindVmQuery.page" v-model:page-size="bindVmQuery.count"
          :total="bindVmTotal" :page-sizes="[10,20,50]" layout="total,sizes,prev,pager,next" background
          @size-change="s => { bindVmQuery.count = s; bindVmQuery.page = 1; loadBindVmList() }"
          @current-change="p => { bindVmQuery.page = p; loadBindVmList() }" />
      </div>
      <template #footer>
        <el-button @click="bindVmDialogVisible = false">关闭</el-button>
      </template>
    </el-dialog>

    <!-- 选择用户商品弹窗（全局绑定时使用） -->
    <el-dialog v-model="bindGoodsDialogVisible" title="选择要绑定的用户商品" width="750px" destroy-on-close append-to-body>
      <div style="margin-bottom:8px;color:#909399;font-size:13px">
        待绑定虚拟机: <b>{{ bindSelectedVm?.name || '-' }}</b>（ID: {{ bindSelectedVm?.id }}）
      </div>
      <div style="margin-bottom:12px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px">
        <el-form :inline="true" size="default" style="margin:0">
          <el-form-item label="用户" style="margin-bottom:0">
            <div class="selector-row" style="width:200px">
              <el-input
                :model-value="bindGoodsQuery._userName || (bindGoodsQuery.user_id ? `用户 #${bindGoodsQuery.user_id}` : '')"
                readonly placeholder="点击选择用户" style="flex:1;cursor:pointer"
                @click="showBindGoodsUserSelector = true" />
              <el-button v-if="bindGoodsQuery.user_id" link @click.stop="bindGoodsQuery.user_id = ''; bindGoodsQuery._userName = ''; loadBindGoodsList()">清除</el-button>
            </div>
          </el-form-item>
          <el-form-item style="margin-bottom:0">
            <el-button type="primary" @click="loadBindGoodsList">搜索</el-button>
          </el-form-item>
        </el-form>
        <el-button type="primary" @click="handleCreateFromBind">新建用户商品</el-button>
      </div>
      <el-table :data="bindGoodsList" v-loading="bindGoodsLoading" highlight-current-row
        @current-change="r => bindGoodsSelected = r" :height="300" style="width:100%"
        :header-cell-style="{ background: '#f8f9fa', color: '#2c3e50', fontWeight: 600 }">
        <el-table-column prop="id" label="ID" width="70" />
        <el-table-column label="商品名称" min-width="150" show-overflow-tooltip>
          <template #default="{ row }">{{ row.good?.name || '-' }}</template>
        </el-table-column>
        <el-table-column label="用户" min-width="120">
          <template #default="{ row }">{{ row.user?.UserName || '-' }} ({{ row.userId || row.user_id || '-' }})</template>
        </el-table-column>
        <el-table-column label="绑定状态" width="90">
          <template #default="{ row }">
            <el-tag :type="row.itemId ? 'success' : 'info'" size="small">{{ row.itemId ? '已绑定' : '未绑定' }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="到期时间" width="150">
          <template #default="{ row }">{{ formatExpireTime(row.expireTime) }}</template>
        </el-table-column>
        <template #empty>
          <el-empty description="暂无用户商品数据" :image-size="80" />
        </template>
      </el-table>
      <div style="display:flex;justify-content:flex-end;margin-top:12px">
        <el-pagination v-model:current-page="bindGoodsQuery.page" v-model:page-size="bindGoodsQuery.count"
          :total="bindGoodsTotal" :page-sizes="[10,20,50]" layout="total,sizes,prev,pager,next" background
          @size-change="s => { bindGoodsQuery.count = s; bindGoodsQuery.page = 1; loadBindGoodsList() }"
          @current-change="p => { bindGoodsQuery.page = p; loadBindGoodsList() }" />
      </div>
      <template #footer>
        <el-button @click="bindGoodsDialogVisible = false">取消</el-button>
        <el-button type="primary" :disabled="!bindGoodsSelected" :loading="bindSubmitLoading" @click="confirmGlobalBind">确定绑定</el-button>
      </template>
    </el-dialog>
    <UserSelector v-model:visible="showBindGoodsUserSelector" @select="handleBindGoodsUserSelect" />

    <!-- 绑定专用商品选择器 -->
    <ProductSelector v-model="showBindProductSelector" default-tag="云服务器" @confirm="handleBindProductSelected" />

    <!-- 新建用户商品弹窗（绑定流程中使用） -->
    <el-dialog v-model="bindCreateGoodsVisible" title="新建用户商品" width="520px" destroy-on-close append-to-body>
      <el-form ref="bindCreateGoodsFormRef" :model="bindCreateGoodsForm" :rules="bindCreateGoodsRules" label-width="100px">
        <el-form-item label="商品" prop="good_id">
          <div class="selector-row">
            <el-input :model-value="bindCreateGoodsForm._goodName || (bindCreateGoodsForm.good_id ? `商品 #${bindCreateGoodsForm.good_id}` : '')"
              readonly placeholder="请选择商品" style="flex:1" />
            <el-button type="primary" @click="showBindCreateProductSelector = true" style="margin-left:8px">选择</el-button>
          </div>
        </el-form-item>
        <el-form-item label="用户" prop="user_id">
          <div class="selector-row">
            <el-input :model-value="bindCreateGoodsForm._userName || (bindCreateGoodsForm.user_id ? `用户 #${bindCreateGoodsForm.user_id}` : '')"
              readonly placeholder="请选择用户" style="flex:1" />
            <el-button type="primary" @click="showBindCreateUserSelector = true" style="margin-left:8px">选择</el-button>
          </div>
        </el-form-item>
        <el-form-item label="续费价格">
          <div class="unit-input-row">
            <el-input-number v-model="bindCreateGoodsForm._renewYuan" :min="0" :precision="2" controls-position="right" style="flex:1" />
            <span class="unit-text">元</span>
          </div>
        </el-form-item>
        <el-form-item label="基础价格">
          <div class="unit-input-row">
            <el-input-number v-model="bindCreateGoodsForm._baseYuan" :min="0" :precision="2" controls-position="right" style="flex:1" />
            <span class="unit-text">元</span>
          </div>
        </el-form-item>
        <el-form-item label="到期时间">
          <el-date-picker v-model="bindCreateGoodsForm.expire_time" type="datetime"
            format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%" />
        </el-form-item>
        <el-form-item label="备注">
          <el-input v-model="bindCreateGoodsForm.note" type="textarea" :rows="2" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="bindCreateGoodsVisible = false">取消</el-button>
        <el-button type="primary" :loading="bindCreateGoodsLoading" @click="submitBindCreateGoods">确定</el-button>
      </template>
    </el-dialog>
    <ProductSelector v-model="showBindCreateProductSelector" default-tag="云服务器" @confirm="p => { bindCreateGoodsForm.good_id = p.id; bindCreateGoodsForm._goodName = p.name }" />
    <UserSelector v-model:visible="showBindCreateUserSelector" @select="u => { bindCreateGoodsForm.user_id = u.user_id; bindCreateGoodsForm._userName = u.user_name }" />

    <!-- 绑定tab的选择器 -->
    <ProductSelector v-model="showBindGoodsProductSelector" default-tag="云服务器" @confirm="p => { bindGoodsForm.good_id = p.id; bindGoodsForm._goodName = p.name; bindGoodsForm._goodTag = p.tag || '云服务器' }" />
    <UserSelector v-model:visible="showBindGoodsUserSel" @select="u => { bindGoodsForm.user_id = u.user_id; bindGoodsForm._userName = u.user_name }" />
    <OrderSelector v-model="showBindGoodsOrderSelector" @confirm="o => { bindGoodsForm.order_id = o.id; bindGoodsForm._orderName = o.name }" />
    <PlanSelector v-model="showBindGoodsPlanSelector" :good-id="bindGoodsForm.good_id || 0" @confirm="p => { bindGoodsForm.good_plan_id = p.id; bindGoodsForm._planName = p.name }" />

    <!-- 筛选区选择器 -->
    <UserSelector v-model:visible="showFilterUserSelector" @select="u => { query.user_id = u.user_id; filterUserName = u.user_name; handleSearch() }" />
    <ProductSelector v-model="showFilterProductSelector" default-tag="云服务器" @confirm="p => { query.good_id = p.id; filterGoodName = p.name; handleSearch() }" />
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Refresh, Search, ArrowDown } from '@element-plus/icons-vue'
import { getUserVmList, getUserVmDetail, createUserVm, updateUserVm, deleteUserVm, getUserGoodsList, createUserGoods, updateUserGoods, deleteUserGoods, bindUserVm, getExpireRemindList, sendExpireRemind } from '@/api/admin/userVm'
import { getProductParameterList, getProductPlanDetail } from '@/api/admin/product'
import { hasUnit, getArgKey, getBaseUnit, getParamUnits, getParamDefaultUnit, toBaseUnit, fromBaseUnit } from '@/utils/dynamicUnit'
import { extractApiError } from '@/utils/kvmErrorUtil'
import { formatToApiTime, vmStatusLabel, vmStatusType } from '@/utils/tool'
import ProductSelector from '@/components/admin/ProductSelector.vue'
import UserSelector from '@/components/UserSelector/index.vue'
import OrderSelector from '@/components/admin/OrderSelector.vue'
import PlanSelector from '@/components/admin/PlanSelector.vue'
import KvmServiceSelector from '@/components/admin/KvmServiceSelector.vue'
import ImageSelectorPopup from '@/components/admin/ImageSelectorPopup.vue'
import HostSelectorPopup from '@/components/admin/HostSelectorPopup.vue'
import HostGroupSelectorPopup from '@/components/admin/HostGroupSelectorPopup.vue'
import NetworkSelectorPopup from '@/components/admin/NetworkSelectorPopup.vue'
import UserVmSecurityGroupSelector from '@/components/admin/UserVmSecurityGroupSelector.vue'
import UserVmNetworkSelector from '@/components/admin/UserVmNetworkSelector.vue'
import dayjs from 'dayjs'

const router = useRouter()
const loading = ref(false)
const list = ref([])
const total = ref(0)
const query = reactive({ page: 1, count: 10, bound: null, user_id: '', good_id: '', key: '' })
const filterUserName = ref('')
const filterGoodName = ref('')
const showFilterUserSelector = ref(false)
const showFilterProductSelector = ref(false)

const listError = ref('')

const formatMemory = (kb) => {
  if (!kb) return '-'
  if (kb >= 1048576) return (kb / 1048576).toFixed(1) + ' GB'
  if (kb >= 1024) return (kb / 1024).toFixed(0) + ' MB'
  return kb + ' KB'
}

const formatExpireTime = (t) => {
  if (!t) return '-'
  const d = dayjs(t)
  if (d.year() < 2000) return '永久'
  return d.format('YYYY-MM-DD HH:mm')
}

const loadGoods = async () => {
  // 不再需要加载商品列表，直接加载用户商品
  loadList()
}


const loadList = async () => {
  loading.value = true
  listError.value = ''
  try {
    const params = { page: query.page, count: query.count, tag: '云服务器' }
    if (query.bound !== null && query.bound !== undefined && query.bound !== '') params.bound = query.bound
    if (query.user_id) params.user_id = query.user_id
    if (query.good_id) params.good_id = query.good_id
    if (query.key) params.key = query.key
    const res = await getUserGoodsList(params)
    if (res?.data?.code === 200 && res?.data?.data) {
      const d = res.data.data
      list.value = d.data || (Array.isArray(d) ? d : [])
      total.value = d.meta?.count ?? d.all_count ?? d.total ?? list.value.length
    } else {
      list.value = []
      total.value = 0
      if (res?.data?.message) {
        listError.value = res.data.message
      }
    }
  } catch (e) {
    list.value = []
    total.value = 0
    const errData = e?.response?.data
    listError.value = extractApiError(errData, '获取列表失败')
  } finally { loading.value = false }
}

const handleSearch = () => { query.page = 1; loadList() }


const goDetail = (row) => {
  if (!row.id) return
  router.push({ path: '/user-goods/vm-detail', query: { id: row.id } })
}

// ---- 新建 ----
const createVisible = ref(false)
const createLoading = ref(false)
const createDialogTab = ref('create')
let pendingTab = 'create'
const onCreateDialogOpened = () => { createDialogTab.value = pendingTab }

// 绑定虚拟机 tab（新增用户商品）
const bindGoodsFormRef = ref(null)
const bindGoodsFormLoading = ref(false)
const showBindGoodsProductSelector = ref(false)
const showBindGoodsUserSel = ref(false)
const showBindGoodsOrderSelector = ref(false)
const showBindGoodsPlanSelector = ref(false)
const bindGoodsForm = reactive({
  good_id: 0, _goodName: '', _goodTag: '', user_id: 0, _userName: '',
  order_id: 0, _orderName: '', good_plan_id: 0, _planName: '',
  item_id: 0, _itemName: '', order_args: '',
  _renewYuan: 0, _baseYuan: 0, expire_time: '', note: ''
})
const bindGoodsFormRules = {
  good_id: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请选择商品')), trigger: 'change' }],
  user_id: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请选择用户')), trigger: 'change' }]
}
const resetBindGoodsForm = () => {
  Object.assign(bindGoodsForm, {
    good_id: 0, _goodName: '', _goodTag: '', user_id: 0, _userName: '',
    order_id: 0, _orderName: '', good_plan_id: 0, _planName: '',
    item_id: 0, _itemName: '', order_args: '',
    _renewYuan: 0, _baseYuan: 0, expire_time: '', note: ''
  })
}
const handleBindGoodsItemSelect = () => {
  if (bindGoodsForm._goodTag === '云服务器') {
    vmItemTarget.value = 'bind'
    showVmListDialog.value = true
    loadVmListForItem()
  } else {
    bindGoodsForm.item_id = bindGoodsForm.good_id
    bindGoodsForm._itemName = `商品 #${bindGoodsForm.good_id}`
    ElMessage.success('已将商品ID赋值为归属项')
  }
}
const submitBindGoodsForm = async () => {
  try { await bindGoodsFormRef.value?.validate() } catch { return }
  bindGoodsFormLoading.value = true
  try {
    const payload = {
      good_id: bindGoodsForm.good_id,
      user_id: bindGoodsForm.user_id,
      item_id: bindGoodsForm.item_id || 0,
      renew_price: Math.round((bindGoodsForm._renewYuan || 0) * 100),
      base_price: Math.round((bindGoodsForm._baseYuan || 0) * 100),
      note: bindGoodsForm.note || ''
    }
    if (bindGoodsForm.order_id) payload.order_id = bindGoodsForm.order_id
    if (bindGoodsForm.good_plan_id) payload.good_plan_id = bindGoodsForm.good_plan_id
    if (bindGoodsForm.order_args) payload.order_args = bindGoodsForm.order_args
    if (bindGoodsForm.expire_time) payload.expire_time = formatToApiTime(bindGoodsForm.expire_time)
    const res = await createUserGoods(payload)
    if (res?.data?.code === 200) {
      ElMessage.success('创建用户商品成功')
      createVisible.value = false
      loadList()
    } else ElMessage.error(extractApiError(res?.data, '创建失败'))
  } catch (e) { ElMessage.error(extractApiError(e?.response?.data, '创建失败')) }
  finally { bindGoodsFormLoading.value = false }
}
const createFormRef = ref(null)
const showProductSelector = ref(false)
const showUserSelector = ref(false)
const showOrderSelector = ref(false)
const showPlanSelector = ref(false)
const handlePlanSelectedForCreate = (plan) => {
  createForm.good_plan_id = plan.id
  createForm._planName = plan.name || `套餐 #${plan.id}`
}
const showServiceSelector = ref(false)
const showImageSelector = ref(false)
const showHostSelector = ref(false)
const showHostGroupSelector = ref(false)
const showNetworkSelector = ref(false)

// 编辑相关变量
const editFormRef = ref(null)
const showProductSelectorEdit = ref(false)
const showUserSelectorEdit = ref(false)
const showOrderSelectorEdit = ref(false)
const showPlanSelectorEdit = ref(false)

// 订单参数配置
const argsSpecList = ref([])
const argsSpecLoading = ref(false)
const argsValues = reactive({})
const argsDisplayValues = reactive({})
const argsDisplayUnits = reactive({})
const showArgsDialog = ref(false)

// ---- item_id 选择 ----
const vmItemTarget = ref('create')
const showVmListDialog = ref(false)
const vmListForItem = ref([])
const vmListLoading = ref(false)
const vmListSelected = ref(null)
const vmListTotal = ref(0)
const vmListQuery = reactive({ page: 1, count: 10, key: '', user_id: '', status: '', _userName: '' })
const showVmUserSelector = ref(false)

const createForm = reactive({
  good_id: 0, _goodName: '', user_id: 0, _userName: '',
  order_id: 0, _orderName: '', name: '',
  _memoryValue: 0, _memoryUnit: 'MB', vcpu: 0,
  system_size: 0, _systemSizeUnit: 'GB',
  rx_bandwidth: 0, _rxUnit: 'Mbps',
  tx_bandwidth: 0, _txUnit: 'Mbps',
  _serviceId: 0, _serviceName: '', image_id: 0, _imageName: '',
  host_id: 0, _hostName: '', host_group_id: 0, _hostGroupName: '',
  network_ids: [], _networkNames: '',
  ipv4_num: 0, ipv6_num: 0, snapshot_num: 0, backup_num: 0,
  _renewPriceYuan: 0, _basePriceYuan: 0,
  data_volume_size: 0, note: '', expire_time: '',
  traffic_max: 0, traffic_exhausted_rx_mbps: 0, traffic_exhausted_tx_mbps: 0
})

const createRules = {
  good_id: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请选择商品')), trigger: 'change' }],
  user_id: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请选择用户')), trigger: 'change' }],
  memory: [{ required: true, validator: (r, v, cb) => createForm._memoryValue > 0 ? cb() : cb(new Error('请填写内存')), trigger: 'blur' }],
  vcpu: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请填写vCPU')), trigger: 'blur' }],
  system_size: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请填写系统盘大小')), trigger: 'blur' }],
  image_id: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请选择镜像')), trigger: 'blur' }]
}

const editRules = {
  // 简化的验证规则，只验证必要字段
}

const handleCreate = (tab = 'create') => {
  Object.assign(createForm, {
    good_id: 0, _goodName: '', user_id: 0, _userName: '', order_id: 0, _orderName: '', name: '',
    _memoryValue: 0, _memoryUnit: 'MB', vcpu: 0,
    system_size: 0, _systemSizeUnit: 'GB',
    rx_bandwidth: 0, _rxUnit: 'Mbps', tx_bandwidth: 0, _txUnit: 'Mbps',
    _serviceId: 0, _serviceName: '', image_id: 0, _imageName: '',
    host_id: 0, _hostName: '', host_group_id: 0, _hostGroupName: '',
    network_ids: [], _networkNames: '',
    ipv4_num: 0, ipv6_num: 0, snapshot_num: 0, backup_num: 0,
    _renewPriceYuan: 0, _basePriceYuan: 0, data_volume_size: 0, note: '', expire_time: '',
    traffic_max: 0, traffic_exhausted_rx_mbps: 0, traffic_exhausted_tx_mbps: 0
  })
  resetBindGoodsForm()
  pendingTab = tab
  createVisible.value = true
}

// 处理编辑弹窗中的选择虚拟机功能
const handleSelectVmInEdit = async () => {
  if (!editForm._currentGoodId) {
    ElMessage.warning('当前编辑项没有商品ID')
    return
  }
  
  try {
    // 调用用户虚拟机列表API，传递当前编辑项的商品ID
    const res = await getUserVmList({ 
      page: 1, 
      count: 10,
      good_id: editForm._currentGoodId // 传递当前编辑项的商品ID
    })
    if (res.data.code === 200) {
      console.log('用户虚拟机列表:', res.data.data)
      ElMessage.success(`已获取商品ID ${editForm._currentGoodId} 的虚拟机数据`)
    }
  } catch (error) {
    console.error('获取用户虚拟机列表失败:', error)
    ElMessage.error(`获取商品ID ${editForm._currentGoodId} 的虚拟机数据失败`)
  }
}

// 处理商品选择
const handleProductSelect = async (product) => {
  // 设置商品信息
  createForm.good_id = product.id
  createForm._goodName = product.name
  createForm.image_id = 0
  createForm._imageName = ''
  
  // 调用用户虚拟机列表API
  try {
    const res = await getUserVmList({ 
      page: 1, 
      count: 10,
      good_id: product.id // 传递当前选择的商品ID
    })
    if (res.data.code === 200) {
      console.log('用户虚拟机列表:', res.data.data)
      ElMessage.success(`已获取商品 ${product.name} 的虚拟机数据`)
    }
  } catch (error) {
    console.error('获取用户虚拟机列表失败:', error)
    ElMessage.error(`获取商品 ${product.name} 的虚拟机数据失败`)
  }
}

const submitCreate = () => {
  createFormRef.value?.validate(async (valid) => {
    if (!valid) return
    createLoading.value = true
    try {
      const memKB = createForm._memoryUnit === 'GB'
        ? (createForm._memoryValue || 0) * 1024 * 1024
        : (createForm._memoryValue || 0) * 1024
      const sysSize = createForm._systemSizeUnit === 'TB'
        ? (createForm.system_size || 0) * 1024
        : (createForm.system_size || 0)
      const rxBw = createForm._rxUnit === 'Gbps'
        ? (createForm.rx_bandwidth || 0) * 1000
        : (createForm.rx_bandwidth || 0)
      const txBw = createForm._txUnit === 'Gbps'
        ? (createForm.tx_bandwidth || 0) * 1000
        : (createForm.tx_bandwidth || 0)
      const payload = {
        good_id: createForm.good_id,
        user_id: createForm.user_id,
        name: createForm.name,
        memory: Math.round(memKB),
        vcpu: createForm.vcpu,
        system_size: Math.round(sysSize),
        rx_bandwidth: Math.round(rxBw),
        tx_bandwidth: Math.round(txBw),
        image_id: createForm.image_id,
        ipv4_num: createForm.ipv4_num,
        ipv6_num: createForm.ipv6_num,
        snapshot_num: createForm.snapshot_num,
        backup_num: createForm.backup_num,
        renew_price: Math.round((createForm._renewPriceYuan || 0) * 100),
        base_price: Math.round((createForm._basePriceYuan || 0) * 100),
        note: createForm.note
      }
      if (createForm.data_volume_size > 0) payload.data_volume_size = createForm.data_volume_size
      if (createForm.order_id) payload.order_id = createForm.order_id
      if (createForm.expire_time) payload.expire_time = formatToApiTime(createForm.expire_time)
      if (createForm.host_id) payload.host_id = createForm.host_id
      if (createForm.host_group_id) payload.host_group_id = createForm.host_group_id
      if (createForm.network_ids.length) payload.network_ids = createForm.network_ids
      if (createForm.traffic_max > 0) payload.traffic_max = createForm.traffic_max
      if (createForm.traffic_exhausted_rx_mbps > 0) payload.traffic_exhausted_rx_mbps = createForm.traffic_exhausted_rx_mbps
      if (createForm.traffic_exhausted_tx_mbps > 0) payload.traffic_exhausted_tx_mbps = createForm.traffic_exhausted_tx_mbps
      const res = await createUserVm(payload)
      if (res?.data?.code === 200) { ElMessage.success('创建成功'); createVisible.value = false; loadList() }
      else ElMessage.error(extractApiError(res?.data, '创建失败'))
    } catch (e) { ElMessage.error(extractApiError(e?.response?.data, '创建失败')) } finally { createLoading.value = false }
  })
}

// 网络多选：每次选择追加（不重复）
const addNetwork = (n) => {
  if (!createForm.network_ids.includes(n.id)) {
    createForm.network_ids.push(n.id)
    const names = createForm._networkNames ? createForm._networkNames + ', ' + (n.name || n.address || `#${n.id}`) : (n.name || n.address || `#${n.id}`)
    createForm._networkNames = names
  }
}

// ---- 编辑 ----
const editVisible = ref(false)
const editLoading = ref(false)
const showSgSelector = ref(false)
const showEditNetworkSelector = ref(false)
const editForm = reactive({
  id: 0, 
  note: '', 
  _renewYuan: 0, 
  _baseYuan: 0, 
  expire_time: '',
  item_id: 0,
  _itemName: '',
  _goodId: 0,
  _goodTag: ''
})

const handleEdit = async (row) => {
  if (!row.itemId) { ElMessage.warning('该用户商品未绑定虚拟机，无法编辑'); return }
  
  Object.assign(editForm, {
    id: row.id,
    note: row.note || '',
    _renewYuan: ((row.renewPrice || row.renew_price || 0) / 100),
    _baseYuan: ((row.basePrice || row.base_price || 0) / 100),
    expire_time: row.expireTime || row.expire_time || '',
    item_id: row.itemId || row.item_id || 0,
    _itemName: row.itemName || row._itemName || '',
    _goodId: row.goodId || row.good_id || 0,
    _goodTag: row.good?.tag || row._goodTag || ''
  })
  
  editVisible.value = true
  editLoading.value = true
  try {
    const res = await getUserVmDetail({ user_goods_id: row.id })
    if (res?.data?.code === 200 && res?.data?.data) {
      const d = res.data.data
      const vm = d.vm?.data ?? d.vm
      if (vm) {
        editForm.rx_bandwidth = vm.rx_bandwidth || 0
        editForm.tx_bandwidth = vm.tx_bandwidth || 0
        editForm.ssh_port = vm.ssh_port || 22
        editForm.snapshot_num = vm.snapshot_num || 0
        editForm.backup_num = vm.backup_num || 0
        editForm.root_password = vm.root_password || ''
      }
      const inSg = d.vm?.in_port_group
      if (inSg) { editForm.port_group_id = inSg.id; editForm._sgName = inSg.name }
      const bridgeNet = (d.vm?.networks || []).find(n => n.type === 'bridge')
      if (bridgeNet) { editForm.internet_network_id = bridgeNet.id; editForm._networkName = bridgeNet.name || bridgeNet.address }
    }
  } catch { } finally { editLoading.value = false }
}

const submitEdit = async () => {
  editLoading.value = true
  try {
    const payload = {
      id: editForm.id,
      note: editForm.note,
      renew_price: Math.round((editForm._renewYuan || 0) * 100),
      base_price: Math.round((editForm._baseYuan || 0) * 100)
    }
    if (editForm.expire_time) payload.expire_time = formatToApiTime(editForm.expire_time)
    if (editForm.item_id) payload.item_id = editForm.item_id
    
    const res = await updateUserGoods(payload)
    if (res?.data?.code === 200) { ElMessage.success('保存成功'); editVisible.value = false; loadList() }
    else ElMessage.error(extractApiError(res?.data, '保存失败'))
  } catch (e) { ElMessage.error(extractApiError(e?.response?.data, '保存失败')) } finally { editLoading.value = false }
}

const handleProductSelectEdit = (p) => {
  editForm.good_id = p.id
  editForm._goodName = p.name
  editForm._goodTag = p.tag || ''
  editForm.item_id = 0
  editForm._itemName = ''
  clearArgsConfig()
}

const handleUserSelectEdit = (u) => {
  editForm.user_id = u.user_id
  editForm._userName = u.user_name
}

const handleOrderSelectEdit = (o) => {
  editForm.order_id = o.id
  editForm._orderName = o.name
}

const handlePlanSelectEdit = async (plan) => {
  editForm.good_plan_id = plan.id
  editForm._planName = plan.name || `套餐 #${plan.id}`
  if (plan.args) {
    editForm.order_args = typeof plan.args === 'string' ? plan.args : JSON.stringify(plan.args)
  }
  if (plan.id && editForm.good_id) {
    try {
      const res = await getProductPlanDetail({ good_id: String(editForm.good_id), plan_id: String(plan.id) })
      if (res?.data?.code === 200 && res.data.data?.args) {
        editForm.order_args = typeof res.data.data.args === 'string' ? res.data.data.args : JSON.stringify(res.data.data.args)
      }
    } catch { /* keep what we have */ }
  }
}

const handleItemSelect = () => {
  if (editForm._goodTag === '云服务器') {
    vmItemTarget.value = 'edit'
    showVmListDialog.value = true
    loadVmListForItem()
  } else {
    editForm.item_id = editForm.good_id
    editForm._itemName = `商品 #${editForm.good_id}`
    ElMessage.success('已将商品ID赋值为归属项')
  }
}

const handleEditItemSelect = () => {
  if (editForm._goodTag === '云服务器') {
    vmItemTarget.value = 'edit'
    showVmListDialog.value = true
    loadVmListForItem()
  } else {
    editForm.item_id = editForm._goodId
    editForm._itemName = `商品 #${editForm._goodId}`
    ElMessage.success('已将商品ID赋值为归属项')
  }
}

const argsCount = computed(() => {
  try { const arr = JSON.parse(editForm.order_args || '[]'); return Array.isArray(arr) ? arr.length : 0 } catch { return 0 }
})

const openArgsDialog = () => {
  if (!editForm.good_id) return
  showArgsDialog.value = true
  if (argsSpecList.value.length === 0) loadArgsSpec(editForm.good_id)
}

const clearArgsConfig = () => {
  argsSpecList.value = []
  for (const k in argsValues) delete argsValues[k]
  editForm.order_args = ''
}

const loadArgsSpec = async (goodId) => {
  if (!goodId) return
  argsSpecLoading.value = true
  try {
    const res = await getProductParameterList({ good_id: goodId })
    if (res?.data?.code === 200) {
      argsSpecList.value = res.data.data || []
      for (const spec of argsSpecList.value) {
        if (spec.type === 'number' && argsValues[spec.id] === undefined) {
          argsValues[spec.id] = spec.min ?? 0
          if (hasUnit(spec)) {
            argsDisplayUnits[spec.id] = getParamDefaultUnit(spec)
            argsDisplayValues[spec.id] = fromBaseUnit(spec.min ?? 0, argsDisplayUnits[spec.id], getArgKey(spec))
          } else {
            argsDisplayValues[spec.id] = spec.min ?? 0
          }
        }
      }
    }
  } catch { argsSpecList.value = [] } finally { argsSpecLoading.value = false }
}

const onArgsNumberChange = (spec) => {
  if (hasUnit(spec)) {
    argsValues[spec.id] = Math.round(toBaseUnit(argsDisplayValues[spec.id] || 0, argsDisplayUnits[spec.id], getArgKey(spec)))
  } else {
    argsValues[spec.id] = argsDisplayValues[spec.id]
  }
  buildArgsJson()
}
const onArgsUnitChange = (spec, newUnit) => {
  const argKey = getArgKey(spec)
  const oldUnit = argsDisplayUnits[spec.id]
  const oldDisplay = argsDisplayValues[spec.id] || 0
  const baseValue = oldUnit ? toBaseUnit(oldDisplay, oldUnit, argKey) : oldDisplay
  argsDisplayUnits[spec.id] = newUnit
  argsDisplayValues[spec.id] = fromBaseUnit(baseValue, newUnit, argKey)
  argsValues[spec.id] = Math.round(baseValue)
  buildArgsJson()
}

const buildArgsJson = () => {
  const argsArray = []
  for (const spec of argsSpecList.value) {
    const val = argsValues[spec.id]
    if (val === undefined || val === '') continue
    if (spec.type === 'select') {
      const attr = spec.attrs?.find(a => a.id === val)
      if (attr) argsArray.push({ arg_id: spec.id, name: spec.name, attr_id: attr.id, value: attr.value || '' })
    } else if (spec.type === 'number') {
      argsArray.push({ arg_id: spec.id, name: spec.name, attr_id: 0, number: Number(val) })
    } else {
      argsArray.push({ arg_id: spec.id, name: spec.name, attr_id: 0, value: String(val) })
    }
  }
  editForm.order_args = argsArray.length > 0 ? JSON.stringify(argsArray) : ''
}

const loadVmListForItem = async () => {
  vmListLoading.value = true
  try {
    const params = { page: vmListQuery.page, count: vmListQuery.count }
    if (vmListQuery.key) params.key = vmListQuery.key
    if (vmListQuery.user_id) params.user_id = parseInt(vmListQuery.user_id) || undefined
    if (vmListQuery.status) params.status = vmListQuery.status
    // good_id parameter
    if (vmItemTarget.value === 'edit' && editForm._goodId) {
      params.good_id = editForm._goodId
    } else if (vmItemTarget.value === 'create' && createForm.good_id) {
      params.good_id = createForm.good_id
    } else if (vmItemTarget.value === 'bind' && bindGoodsForm.good_id) {
      params.good_id = bindGoodsForm.good_id
    }
    const res = await getUserVmList(params)
    if (res?.data?.code === 200 && res?.data?.data) {
      const d = res.data.data
      vmListForItem.value = d.data || (Array.isArray(d) ? d : [])
      vmListTotal.value = d.all_count ?? d.total ?? vmListForItem.value.length
    }
  } catch { vmListForItem.value = [] } finally { vmListLoading.value = false }
}

const confirmVmForItem = () => {
  if (!vmListSelected.value) return
  const vm = vmListSelected.value
  if (vmItemTarget.value === 'edit') {
    editForm.item_id = vm.id
    editForm._itemName = `虚拟机 #${vm.id}`
  } else if (vmItemTarget.value === 'bind') {
    bindGoodsForm.item_id = vm.id
    bindGoodsForm._itemName = `虚拟机 #${vm.id}`
  } else {
    createForm.item_id = vm.id
    createForm._itemName = `虚拟机 #${vm.id}`
  }
  showVmListDialog.value = false
  vmListSelected.value = null
  ElMessage.success('虚拟机已选择')
}

const resetVmListFilters = () => {
  vmListQuery.key = ''
  vmListQuery.user_id = ''
  vmListQuery.status = ''
  vmListQuery._userName = ''
  vmListQuery.page = 1
  loadVmListForItem()
}

const handleVmUserSelect = (user) => {
  vmListQuery.user_id = user.user_id
  vmListQuery._userName = user.user_name
  showVmUserSelector.value = false
  loadVmListForItem()
}

const getStatusType = (status) => {
  switch (status) {
    case 'running': return 'success'
    case 'stop': return 'danger'
    case 'stopped': return 'danger'
    default: return 'info'
  }
}

const getStatusText = (status) => {
  switch (status) {
    case 'running': return '运行中'
    case 'stop': return '已停止'
    case 'stopped': return '已停止'
    default: return status || '未知'
  }
}

// ---- 更多操作 ----
const handleMoreCmd = (cmd, row) => {
  if (cmd === 'remind') openRemindList(row)
  else if (cmd === 'send') handleSendRemind(row)
  else if (cmd === 'delete') handleDeleteGoods(row)
}

// ---- 删除用户商品 ----
const handleDeleteGoods = (row) => {
  const hasBoundVm = row.itemId && row.itemId !== 0
  const msg = hasBoundVm
    ? `该商品（ID: ${row.id}）已绑定虚拟机（VM ID: ${row.itemId}），删除后虚拟机将不再关联此商品记录，确定删除？`
    : `确定删除该用户商品（ID: ${row.id}）吗？`
  ElMessageBox.confirm(msg, '删除确认', { type: 'error', confirmButtonText: '确认删除' })
    .then(async () => {
      try {
        const res = await deleteUserGoods({ id: row.id })
        if (res?.data?.code === 200) { ElMessage.success('删除成功'); loadList() }
        else ElMessage.error(extractApiError(res?.data, '删除失败'))
      } catch (e) { ElMessage.error(extractApiError(e?.response?.data, '删除失败')) }
    }).catch(() => {})
}

// ---- 到期提醒 ----
const remindVisible = ref(false)
const remindLoading = ref(false)
const remindList = ref([])
const remindTotal = ref(0)
const remindGoodsId = ref(0)
const remindQuery = reactive({ page: 1, count: 10 })

const openRemindList = (row) => {
  remindGoodsId.value = row.id
  remindQuery.page = 1
  remindVisible.value = true
  loadRemindList()
}

const formatRemindTime = (row) => {
  const t = row.CreatedAt || row.created_at || row.send_time
  if (!t || t.startsWith('0001')) return '-'
  try { return dayjs(t).format('YYYY-MM-DD HH:mm:ss') } catch { return t }
}

const loadRemindList = async () => {
  remindLoading.value = true
  try {
    const res = await getExpireRemindList({ user_goods_id: remindGoodsId.value, page: remindQuery.page, count: remindQuery.count })
    if (res?.data?.code === 200 && res?.data?.data) {
      const d = res.data.data
      remindList.value = d.data || d.list || (Array.isArray(d) ? d : [])
      remindTotal.value = d.all_count ?? d.meta?.count ?? d.total ?? remindList.value.length
    } else { remindList.value = []; remindTotal.value = 0 }
  } catch { remindList.value = []; remindTotal.value = 0 }
  finally { remindLoading.value = false }
}

const handleSendRemind = (row) => {
  ElMessageBox.confirm(`确定手动发送到期提醒给该用户商品（ID: ${row.id}）吗？`, '发送确认', { type: 'warning', confirmButtonText: '确认发送' })
    .then(async () => {
      try {
        const res = await sendExpireRemind({ user_goods_id: row.id, user_id: row.userId || row.user_id })
        if (res?.data?.code === 200) ElMessage.success('发送成功')
        else ElMessage.error(extractApiError(res?.data, '发送失败'))
      } catch (e) { ElMessage.error(extractApiError(e?.response?.data, '发送失败')) }
    }).catch(() => {})
}

// ---- 绑定虚拟机 ----
const bindVmDialogVisible = ref(false)
const bindTargetRow = ref(null)
const bindVmList = ref([])
const bindVmLoading = ref(false)
const bindVmTotal = ref(0)
const bindVmQuery = reactive({ page: 1, count: 10, key: '', status: '' })
const bindSubmitLoading = ref(false)
const bindSubmitVmId = ref(0)
const bindSelectedVm = ref(null)
const bindSelectedProduct = ref(null)
const showBindProductSelector = ref(false)

const bindGoodsDialogVisible = ref(false)
const bindGoodsList = ref([])
const bindGoodsLoading = ref(false)
const bindGoodsTotal = ref(0)
const bindGoodsSelected = ref(null)
const bindGoodsQuery = reactive({ page: 1, count: 10, user_id: '', _userName: '' })
const showBindGoodsUserSelector = ref(false)

const handleGlobalBindVm = () => {
  bindTargetRow.value = null
  bindSelectedProduct.value = null
  bindVmList.value = []
  bindVmTotal.value = 0
  bindVmQuery.page = 1
  bindVmQuery.key = ''
  bindVmQuery.status = ''
  bindVmDialogVisible.value = true
}

const handleBindProductSelected = (product) => {
  bindSelectedProduct.value = product
  bindVmQuery.page = 1
  bindVmQuery.key = ''
  bindVmQuery.status = ''
  loadBindVmList()
}

const handleBindVm = (row) => {
  bindTargetRow.value = row
  bindSelectedProduct.value = null
  bindVmQuery.page = 1
  bindVmQuery.key = ''
  bindVmQuery.status = ''
  bindVmDialogVisible.value = true
  loadBindVmList()
}

const loadBindVmList = async () => {
  bindVmLoading.value = true
  try {
    const params = { page: bindVmQuery.page, count: bindVmQuery.count }
    if (bindTargetRow.value) {
      const goodId = bindTargetRow.value.good?.id || bindTargetRow.value.goodId || 0
      if (goodId) params.good_id = goodId
    } else if (bindSelectedProduct.value) {
      params.good_id = bindSelectedProduct.value.id
    }
    if (bindVmQuery.key) params.key = bindVmQuery.key
    if (bindVmQuery.status) params.status = bindVmQuery.status
    const res = await getUserVmList(params)
    if (res?.data?.code === 200 && res?.data?.data) {
      const d = res.data.data
      bindVmList.value = d.data || (Array.isArray(d) ? d : [])
      bindVmTotal.value = d.all_count ?? d.total ?? bindVmList.value.length
    } else { bindVmList.value = []; bindVmTotal.value = 0 }
  } catch { bindVmList.value = [] } finally { bindVmLoading.value = false }
}

const onBindVmClick = (vm) => {
  if (bindTargetRow.value) {
    submitBindVm(vm)
  } else {
    bindSelectedVm.value = vm
    bindGoodsSelected.value = null
    bindGoodsQuery.page = 1
    bindGoodsQuery.user_id = ''
    bindGoodsQuery._userName = ''
    bindGoodsDialogVisible.value = true
    loadBindGoodsList()
  }
}

const handleBindGoodsUserSelect = (user) => {
  bindGoodsQuery.user_id = String(user.user_id || user.id || '')
  bindGoodsQuery._userName = user.user_name || user.name || ''
  showBindGoodsUserSelector.value = false
  loadBindGoodsList()
}

const bindCreateGoodsVisible = ref(false)
const bindCreateGoodsLoading = ref(false)
const bindCreateGoodsFormRef = ref(null)
const showBindCreateProductSelector = ref(false)
const showBindCreateUserSelector = ref(false)
const bindCreateGoodsForm = reactive({
  good_id: 0, _goodName: '', user_id: 0, _userName: '',
  _renewYuan: 0, _baseYuan: 0, expire_time: '', note: ''
})
const bindCreateGoodsRules = {
  good_id: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请选择商品')), trigger: 'change' }],
  user_id: [{ required: true, validator: (r, v, cb) => v > 0 ? cb() : cb(new Error('请选择用户')), trigger: 'change' }]
}

const handleCreateFromBind = () => {
  Object.assign(bindCreateGoodsForm, {
    good_id: 0, _goodName: '', user_id: 0, _userName: '',
    _renewYuan: 0, _baseYuan: 0, expire_time: '', note: ''
  })
  bindCreateGoodsVisible.value = true
}

const submitBindCreateGoods = async () => {
  try { await bindCreateGoodsFormRef.value?.validate() } catch { return }
  bindCreateGoodsLoading.value = true
  try {
    const payload = {
      good_id: bindCreateGoodsForm.good_id,
      user_id: bindCreateGoodsForm.user_id,
      renew_price: Math.round((bindCreateGoodsForm._renewYuan || 0) * 100),
      base_price: Math.round((bindCreateGoodsForm._baseYuan || 0) * 100),
      note: bindCreateGoodsForm.note || ''
    }
    if (bindCreateGoodsForm.expire_time) payload.expire_time = formatToApiTime(bindCreateGoodsForm.expire_time)
    const res = await createUserGoods(payload)
    if (res?.data?.code === 200) {
      ElMessage.success('创建用户商品成功')
      bindCreateGoodsVisible.value = false
      loadBindGoodsList()
    } else {
      ElMessage.error(extractApiError(res?.data, '创建失败'))
    }
  } catch (e) {
    ElMessage.error(extractApiError(e?.response?.data, '创建失败'))
  } finally { bindCreateGoodsLoading.value = false }
}

const loadBindGoodsList = async () => {
  bindGoodsLoading.value = true
  try {
    const params = { page: bindGoodsQuery.page, count: bindGoodsQuery.count, tag: '云服务器' }
    if (bindGoodsQuery.user_id) params.user_id = bindGoodsQuery.user_id
    const res = await getUserGoodsList(params)
    if (res?.data?.code === 200 && res?.data?.data) {
      const d = res.data.data
      bindGoodsList.value = d.data || (Array.isArray(d) ? d : [])
      bindGoodsTotal.value = d.meta?.count ?? d.all_count ?? d.total ?? bindGoodsList.value.length
    } else { bindGoodsList.value = []; bindGoodsTotal.value = 0 }
  } catch { bindGoodsList.value = [] } finally { bindGoodsLoading.value = false }
}

const confirmGlobalBind = async () => {
  if (!bindSelectedVm.value || !bindGoodsSelected.value) return
  bindSubmitLoading.value = true
  try {
    const res = await bindUserVm({
      user_goods_id: bindGoodsSelected.value.id,
      vm_id: bindSelectedVm.value.id
    })
    if (res?.data?.code === 200) {
      ElMessage.success('绑定虚拟机成功')
      bindGoodsDialogVisible.value = false
      loadBindVmList()
      loadList()
    } else {
      ElMessage.error(extractApiError(res?.data, '绑定失败'))
    }
  } catch (e) {
    ElMessage.error(extractApiError(e?.response?.data, '绑定失败'))
  } finally { bindSubmitLoading.value = false }
}

const submitBindVm = async (vm) => {
  if (!bindTargetRow.value) return
  bindSubmitLoading.value = true
  bindSubmitVmId.value = vm.id
  try {
    const res = await bindUserVm({
      user_goods_id: bindTargetRow.value.id,
      vm_id: vm.id
    })
    if (res?.data?.code === 200) {
      ElMessage.success('绑定虚拟机成功')
      loadBindVmList()
      loadList()
    } else {
      ElMessage.error(extractApiError(res?.data, '绑定失败'))
    }
  } catch (e) {
    ElMessage.error(extractApiError(e?.response?.data, '绑定失败'))
  } finally { bindSubmitLoading.value = false; bindSubmitVmId.value = 0 }
}

onMounted(() => {
  loadList()
})
</script>

<style scoped>
.user-vm-list { padding: 0; }

.main-container { border: 1px solid #e1e8ed; background: #ffffff; }
:deep(.el-card__body) { padding: 0; }

.filter-section { padding: 0; border-bottom: 1px solid #e1e8ed; background: #fafbfc; }
.filter-content { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; gap: 20px; flex-wrap: wrap; }
.search-form { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 0; }
.search-form :deep(.el-form-item) { margin-bottom: 0; margin-right: 0; }
.action-bar { display: flex; gap: 12px; flex-shrink: 0; flex-wrap: wrap; align-items: center; }

.table-section { padding: 0; }

.pagination { padding: 16px 20px; border-top: 1px solid #e1e8ed; background: #fafbfc; justify-content: flex-end; }

.selector-row { display: flex; align-items: center; width: 100%; gap: 8px; }
.selector-row .el-input { flex: 1; }
.unit-input-row { display: flex; align-items: center; gap: 6px; width: 100%; }
.unit-select { width: 90px; flex-shrink: 0; }
.unit-text { font-size: 13px; color: #606266; flex-shrink: 0; white-space: nowrap; min-width: 24px; }
.dialog-footer { display: flex; justify-content: flex-end; gap: 12px; padding: 0; }
.form-hint { font-size: 12px; color: #909399; margin-top: 4px; }
.args-spec-item { margin-bottom: 16px; padding-bottom: 16px; border-bottom: 1px solid #f0f0f0; }
.args-spec-item:last-child { border-bottom: none; }
.args-spec-label { font-size: 14px; font-weight: 500; color: #303133; margin-bottom: 8px; }

:global(.scrollable-dialog .el-dialog__body) { max-height: 65vh; overflow-y: auto; overflow-x: hidden; scrollbar-width: none; }
:global(.scrollable-dialog .el-dialog__body::-webkit-scrollbar) { display: none; }

@media (max-width: 768px) {
  .filter-content { flex-direction: column; align-items: stretch; gap: 12px; }
  .search-form { flex-direction: column; width: 100%; }
  .search-form :deep(.el-form-item) { width: 100%; }
  .action-bar { width: 100%; justify-content: flex-start; }
}
</style>
