<template>
  <div class="product-machine-add">
    <div class="header">
      <el-button type="text" @click="handleBack">返回</el-button>
      <h2 class="title">添加出售机器</h2>
    </div>

    <!-- <el-alert
      class="notice-alert"
      type="warning"
      show-icon
      :closable="false"
      title="新增出售机器必须在 M2pool 有挖矿算力记录才能添加出租"
      description="建议稳定在 M2pool 矿池挖矿 24 小时之后，再添加出售该机器"
    /> -->

    <el-card shadow="never" class="form-card">
      <el-form ref="machineForm" :model="form" :rules="rules" label-width="160px" size="small">
        <el-form-item label="矿机种类">
          <el-radio-group v-model="form.machineCategory" @change="handleMachineCategoryChange">
            <el-radio label="ASIC">ASIC</el-radio>
            <el-radio label="GPU">GPU</el-radio>
          </el-radio-group>
        </el-form-item>
        <!-- ASIC：币种与算法（支持多个，逗号分隔） -->
        <el-form-item label="币种(多个用逗号隔开)" prop="coinsInput" :required="form.machineCategory === 'ASIC'">
          <el-input
            v-model="form.coinsInput"
            placeholder="例如：USDT, BTC, ETH"
            style="width: 50%;"
            @input="handleCoinsInput"
          />
        </el-form-item>
        <el-form-item label="算法(多个用逗号隔开)" prop="algorithmsInput" :required="form.machineCategory === 'ASIC'">
          <el-input
            v-model="form.algorithmsInput"
            placeholder="例如：SHA-256, ETHASH"
            style="width: 50%;"
            @input="handleAlgorithmsInput"
          />
        </el-form-item>
        <div style="text-align:left; color:#909399; font-size:12px; margin:-6px 0 10px 160px;">
          输入多个用逗号隔开
        </div>

        <el-form-item label="矿机型号" prop="type" :required="true">
          <el-input style="width: 50%;" v-model="form.type" placeholder="示例：龍珠" :maxlength="20" @input="handleTypeInput" />
        </el-form-item>
        <el-form-item label="理论算力" prop="theoryPower">
          <el-input
            v-model="form.theoryPower"
            placeholder="请输入单机理论算力"
            inputmode="decimal"
            @input="handleNumeric('theoryPower')"
            style="width: 50%;"
          />
        </el-form-item>
        <el-form-item label="算力单位" prop="unit">
          <el-select v-model="form.unit" placeholder="请选择算力单位">
            <el-option label="KH/S" value="KH/S" />
            <el-option label="MH/S" value="MH/S" />
            <el-option label="GH/S" value="GH/S" />
            <el-option label="TH/S" value="TH/S" />
            <el-option label="PH/S" value="PH/S" />
          </el-select>
        </el-form-item>
        <el-form-item label="最大租赁天数" prop="maxLeaseDays">
          <el-input
            v-model="form.maxLeaseDays"
            placeholder="1-365"
            inputmode="numeric"
            @input="handleNumeric('maxLeaseDays')"
            style="width: 50%;"
          >
            <template slot="append">天</template>
          </el-input>
        </el-form-item>
        <el-form-item label="功耗" prop="powerDissipation">
          <el-input
            v-model="form.powerDissipation"         
            inputmode="decimal"
            @input="handleNumeric('powerDissipation')"
            style="width: 50%;"
          >
            <template slot="append">kw/h</template>
          </el-input>
        </el-form-item>
      
        <el-form-item
          label="统一售价"
          :prop="(payTypeDefs && payTypeDefs.length) ? 'costMap' : 'cost'"
          :required="true"
        >
          <span slot="label">统一售价</span>
          <!-- 若商品定义了多个结算币种，则按链-币种动态生成多个售价输入；否则回退为旧的 USDT 单价 -->
          <div v-if="payTypeDefs && payTypeDefs.length" class="cost-multi">
            <div v-for="pt in payTypeDefs" :key="pt.key" class="cost-item">
              <el-input
                v-model="form.costMap[pt.key]"
                placeholder="请输入价格"
                inputmode="decimal"
                @input="val => handleCostMapInput(pt.key, val)"
                style="width: 50%;"
              >
                <template slot="append">{{ pt.label }}</template>
              </el-input>
            </div>
          </div>
          <el-input
            v-else
            v-model="form.cost"
            placeholder="请输入成本（USDT）"
            inputmode="decimal"
            @input="handleNumeric('cost')"
            style="width: 50%;"
          >
            <template slot="append">USDT</template>
          </el-input>
        </el-form-item>
      
      
        <!-- 出售机器数量（统一使用，GPU 仅作引导不在本页提交） -->
        <el-form-item label="出售机器数量(台)" prop="sellCount" :required="true">
          <el-input
            v-model="form.sellCount"
            placeholder="0 - 9999"
            inputmode="numeric"
            style="width: 50%;"
            @input="handleSellCountInput"
            @blur="handleSellCountBlur"
          />
        </el-form-item>
      </el-form>
    </el-card>

    <div class="actions">
      <el-button @click="handleBack">取消</el-button>
      <el-button type="primary" :loading="saving" @click="handleSave">确认添加</el-button>
    </div>
    
    <!-- 上架确认弹窗 -->
    <el-dialog
      title="请确认上架信息"
      :visible.sync="confirmVisible"
      width="560px"
    >
      <div style="text-align:left;line-height:1.9;">
        <div>币种：<b>{{ confirmData.coin }}</b></div>
        <div>算法：<b>{{ confirmData.algorithm }}</b></div>
        <div>最大租赁天数：<b>{{ confirmData.maxLeaseDays || '-' }}</b></div>
        <div>出售机器数量：<b>{{ confirmData.saleNumbers || '-' }}</b></div>
        <div style="margin-top:8px;">售价：</div>
        <el-table
          :data="confirmData.priceList"
          border
          size="mini"
          style="width:100%;"
        >
          <el-table-column prop="chain" label="链" width="120" />
          <el-table-column prop="coin" label="币种" width="120" />
          <el-table-column label="价格">
            <template slot-scope="scope">
              {{ scope.row.price }}
            </template>
          </el-table-column>
        </el-table>
        <p style="color:#666;margin-top:12px;">请仔细确认以上参数无误后提交。</p>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="confirmVisible = false">取消</el-button>
        <el-button type="primary" :loading="saving" @click="doSubmit">确认提交</el-button>
      </span>
    </el-dialog>
    <!-- GPU 引导弹窗 -->
    <el-dialog title="GPU 客户端指引" :visible.sync="gpuDialogVisible" width="520px" @close="handleGpuDialogClosed">
      <div style="text-align:left; line-height:1.8;">
        <div style="display:flex; align-items:center; gap:12px; margin-bottom:12px;">
          <el-button type="primary" @click="handleDownloadClient">下载客户端</el-button>
          <el-button type="success" :disabled="!hasDownloadedClient" @click="handleGpuClientStarted">已启动客户端</el-button>
        </div>
        <div style="color:#555;">
          <div style="margin-bottom:6px; font-weight:600;">注意事项：</div>
          <ol style="padding-left:18px;">
            <li>请直接下载客户端后并启动，客户端显示 GPU 信息后，启动完成点击“已启动客户端”按钮（若未完全启动点击按钮会创建失败）。</li>
            <li>涉及多台主机，每个主机都需要配置相同客户端。</li>
            <li>客户端身份信息和本网站身份信息一致。</li>
          </ol>
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="gpuDialogVisible=false">关闭</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { addSingleOrBatchMachine ,downloadClient,addAsicMachine} from '../../api/machine'
import { getPayTypes } from '../../api/products'
export default {
  name: 'AccountProductMachineAdd',
  data() {
    return {
      form: {
        productId: Number(this.$route.query.productId) || null,
        coin: this.$route.query.coin || '',
        productName: this.$route.query.name || '',
        /** 矿机种类：ASIC 或 GPU，默认 ASIC */
        machineCategory: 'ASIC',
        /** 出售机器数量（仅 ASIC 模式使用） */
        sellCount: '',
        /** ASIC 模式下币种/算法输入（逗号分隔的原始文本） */
        coinsInput: '',
        algorithmsInput: '',
        powerDissipation: null,
        theoryPower: null,
        type: '',
        unit: 'TH/S',
        cost: '',
        costMap: {}, // { 'CHAIN-COIN': '123.45' }
        maxLeaseDays: ''
      },
      confirmVisible: false,
      confirmData: {
        coin: '',
        algorithm: '',
        maxLeaseDays: '',
        saleNumbers: '',
        priceList: []
      },
      rules: {
        productName: [ { required: true, message: '商品名称不能为空', trigger: 'change' } ],
        type: [
          { required: true, message: '矿机型号不能为空', trigger: 'blur' },
          {
            validator: (rule, value, callback) => {
              const s = String(value || '')
              // 不允许全是空格
              if (s && s.trim().length === 0) {
                callback(new Error('矿机型号不能全是空格'))
                return
              }
              callback()
            },
            trigger: 'blur'
          }
        ],
        coinsInput: [
          {
            validator: (rule, value, callback) => {
              if (String(this.form.machineCategory).toUpperCase() !== 'ASIC') { callback(); return }
              const s = String(value || '').trim()
              if (!s) { callback(new Error('请输入币种，多个用逗号隔开')); return }
              // 禁止汉字，且仅允许英数字与逗号/空格/连字符
              if (/[\u4e00-\u9fa5]/.test(s)) { callback(new Error('币种不允许输入汉字')); return }
              // 逐项校验（英文、数字，长度1-10）
              const tokens = s.split(/[,\s，、]+/).map(i => i.trim()).filter(Boolean)
              const pattern = /^[A-Za-z0-9]{1,10}$/
              for (let i = 0; i < tokens.length; i += 1) {
                if (!pattern.test(tokens[i])) {
                  callback(new Error(`币种“${tokens[i]}”格式非法，仅允许字母或数字`))
                  return
                }
              }
              callback()
            },
            trigger: 'blur'
          }
        ],
        algorithmsInput: [
          {
            validator: (rule, value, callback) => {
              if (String(this.form.machineCategory).toUpperCase() !== 'ASIC') { callback(); return }
              const s = String(value || '').trim()
              if (!s) { callback(new Error('请输入算法，多个用逗号隔开')); return }
              if (/[\u4e00-\u9fa5]/.test(s)) { callback(new Error('算法不允许输入汉字')); return }
              // 逐项校验（字母/数字/连字符，2-20）
              const tokens = s.split(/[,\s，、]+/).map(i => i.trim()).filter(Boolean)
              const pattern = /^[A-Za-z0-9-]{2,20}$/
              for (let i = 0; i < tokens.length; i += 1) {
                if (!pattern.test(tokens[i])) {
                  callback(new Error(`算法“${tokens[i]}”格式非法，仅允许字母、数字或“-”`))
                  return
                }
              }
              callback()
            },
            trigger: 'blur'
          }
        ],
        sellCount: [
          {
            validator: (rule, value, callback) => {
              if (this.form.machineCategory !== 'ASIC') { callback(); return }
              const raw = String(value ?? '')
              if (raw === '') { callback(new Error('请输入出售机器数量')); return }
              if (!/^\d{1,4}$/.test(raw)) { callback(new Error('请输入 0-9999 的整数')); return }
              const n = Number(raw)
              if (!Number.isInteger(n) || n < 0 || n > 9999) { callback(new Error('范围需在 0-9999')); return }
              callback()
            },
            trigger: 'blur'
          }
        ],
        powerDissipation: [
          { required: true, message: '功耗不能为空', trigger: 'blur' },
          {
            validator: (rule, value, callback) => {
              const str = String(value || '')
              if (!str) { callback(new Error('功耗不能为空')); return }
              const pattern = /^\d{1,6}(\.\d{1,4})?$/
              if (!pattern.test(str)) { callback(new Error('功耗整数最多6位，小数最多4位')); return }
              if (Number(str) <= 0) { callback(new Error('功耗必须大于0')); return }
              callback()
            },
            trigger: 'blur'
          }
        ],
        theoryPower: [
          { required: true, message: '理论算力不能为空', trigger: 'blur' },
          {
            validator: (rule, value, callback) => {
              const str = String(value || '')
              if (!str) { callback(new Error('理论算力不能为空')); return }
              const pattern = /^\d{1,6}(\.\d{1,4})?$/
              if (!pattern.test(str)) { callback(new Error('理论算力整数最多6位，小数最多4位')); return }
              if (Number(str) <= 0) { callback(new Error('理论算力必须大于0')); return }
              callback()
            },
            trigger: 'blur'
          }
        ],
        unit: [ { required: true, message: '请选择算力单位', trigger: 'change' } ],
        cost: [
          {
            validator(rule, value, callback) {
              // 若为多结算币种模式，跳过此校验（统一售价由每种币种的输入框承担）
              if (Array.isArray(this.payTypeDefs) && this.payTypeDefs.length > 0) {
                callback()
                return
              }
              const str = String(value || '')
              if (!str) {
                callback(new Error('请填写机器成本（USDT）'))
                return
              }
              const pattern = /^\d{1,12}(\.\d{1,2})?$/
              if (!pattern.test(str)) {
                callback(new Error('成本整数最多12位，小数最多2位'))
                return
              }
              if (Number(str) <= 0) {
                callback(new Error('成本必须大于 0'))
                return
              }
              callback()
            },
            trigger: 'blur'
          }
        ]
        ,
        maxLeaseDays: [
          { required: true, message: '请填写最大租赁天数', trigger: 'blur' },
          {
            validator: (rule, value, callback) => {
              const raw = String(value ?? '')
              if (!raw) { callback(new Error('请填写最大租赁天数')); return }
              if (!/^\d{1,3}$/.test(raw)) { callback(new Error('仅允许整数，范围 1-365')); return }
              const n = Number(raw)
              if (!Number.isInteger(n) || n < 1 || n > 365) { callback(new Error('范围需在 1-365 天')); return }
              callback()
            },
            trigger: 'blur'
          }
        ]
      },
      miners: [
      // {
      //           "user": "lx_888",
      //           "miner": null,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "lx999",
      //           "miner": null,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "lx88",
      //           "miner": null,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "lx6666",
      //           "miner": null,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "lx_999",
      //           "miner": null,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "Lx_6966",
      //           "miner": null,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "LX_666",
      //           "miner": null,
      //           "coin": "nexa"
      //       },
      ],
      minersLoading: false,
      selectedMiner: '', // 格式 user|coin
      machineOptions: [
      // {
      //           "user": "lx_888",
      //           "miner": `iusfhufhu`,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "lx999",
      //           "miner": `iusfhufhu2`,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "lx88",
      //           "miner": `iusfhufhu3`,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "lx6666",
      //           "miner": `iusfhufhu4`,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "lx_999",
      //           "miner": `iusfhufhu5`,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "Lx_6966",
      //           "miner": `iusfhufhu6`,
      //           "coin": "nexa"
      //       },
      //       {
      //           "user": "LX_666",
      //           "miner": `iusfhufhu7`,
      //           "coin": "nexa"
      //       },
      ],
      machinesLoading: false,
      selectedMachines: [],
      selectedMachineRows: [],
      saving: false,
      lastCostBaseline: 0,
      lastCostMapBaseline: {}, // { key: number }
      lastTypeBaseline: '',
      lastMaxLeaseDaysBaseline: 0,
      lastPowerDissipationBaseline: 0,
      lastTheoryPowerBaseline: 0,
      lastUnitBaseline: 'TH/S',
      /** GPU 引导弹窗可见性 */
      gpuDialogVisible: false,
      /** GPU 客户端下载地址（可通过环境变量配置：VUE_APP_GPU_CLIENT_URL） */
      clientDownloadUrl: process.env.VUE_APP_GPU_CLIENT_URL || '',
      /** 是否点击过下载客户端（用于控制“已启动客户端”按钮禁用态） */
      hasDownloadedClient: false,
      /** 支持的支付方式定义（用于动态渲染统一售价输入组） */
      payTypeDefs: [],
      params:{
        cost:353400,
        powerDissipation:0.01,
        theoryPower:1000,
        type:"",
        unit:"TH/S",
        productId:1,
        productMachineURDVos:[
            {
                "user":"lx_888",             
                "miner":"iusfhufhu",
                "price":353400,
                "type":"",
                "state":0
            },
            {
                "user":"lx_888",             
                "miner":"iusfhufhu2",
                "price":353400,
                "type":"",
                "state":0
            },

        ]

      }
    }
  },
  created() {
    this.initPayTypesFromRoute()
    this.lastTypeBaseline = this.form.type
    // 绑定基于组件实例的校验器，避免 this 丢失
    if (this.rules && this.rules.cost) {
      this.$set(this.rules, 'cost', [{ validator: this.validateCost, trigger: 'blur' }])
    }
    // 多币种价格专用校验
    this.$set(this.rules, 'costMap', [{ validator: this.validateCostMap, trigger: 'blur' }])

    this.getPayTypes()
  },
  methods: {
    /** 实时过滤币种输入中的中文字符（仅保留英文/数字/分隔符） */
    handleCoinsInput() {
      let v = String(this.form.coinsInput || '')
      // 去除中文
      v = v.replace(/[\u4e00-\u9fa5]/g, '')
      this.form.coinsInput = v
    },
    /** 实时过滤算法输入中的中文字符（仅保留英文/数字/连字符/分隔符） */
    handleAlgorithmsInput() {
      let v = String(this.form.algorithmsInput || '')
      v = v.replace(/[\u4e00-\u9fa5]/g, '')
      this.form.algorithmsInput = v
    },
    /** 将输入按中英文逗号、空格分割，去空，统一英文逗号连接；可选：统一大写 */
    normalizeCsv(input, upper = true) {
      const arr = String(input || '')
        .split(/[,\s，、]+/)
        .map(s => s.trim())
        .filter(Boolean)
      const list = upper ? arr.map(s => s.toUpperCase()) : arr
      return list.join(',')
    },
    /** 从 payTypeDefs 与 costMap 生成价格列表 */
    buildPriceList() {
      const list = []
      const defs = Array.isArray(this.payTypeDefs) ? this.payTypeDefs : []
      defs.forEach(d => {
        const key = d.key
        const priceRaw = this.form.costMap ? this.form.costMap[key] : ''
        const priceNum = Number(priceRaw)
        // 允许为空/非数字则不加入
        if (!Number.isFinite(priceNum) || priceNum <= 0) return
        list.push({
          chain: d.chain,
          coin: d.coin,
          price: priceNum
        })
      })
      return list
    },
    async getPayTypes() {
      try {
        const res = await getPayTypes()
        // 期望结构：{ code:200, data:[ { payChain, payCoin, payCoinImage } ] }
        if (res && (res.code === 0 || res.code === 200)) {
          const list = Array.isArray(res.data) ? res.data : []
          const defs = []
          const seen = new Set()
          list.forEach(it => {
            const chain = String(it && it.payChain ? it.payChain : '').toUpperCase()
            const coin = String(it && it.payCoin ? it.payCoin : '').toUpperCase()
            if (!chain && !coin) return
            const key = [chain, coin].filter(Boolean).join('-')
            if (seen.has(key)) return
            seen.add(key)
            defs.push({
              chain,
              coin,
              key,
              label: key,
              image: it && it.payCoinImage ? String(it.payCoinImage) : ''
            })
          })
          // 根据接口结果渲染“统一售价”输入组
          this.payTypeDefs = defs
          const nextCostMap = {}
          this.payTypeDefs.forEach(d => {
            // 保留已输入的数值；否则置空
            nextCostMap[d.key] = (this.form.costMap && this.form.costMap[d.key]) || ''
          })
          this.form.costMap = nextCostMap
        }
      } catch (e) {
        // 忽略错误，维持当前 payTypeDefs
      }
    },
    /**
     * ASIC 模式：出售机器数量输入，仅允许 0-9999 的整数
     */
    handleSellCountInput() {
      let v = String(this.form.sellCount ?? '')
      // 仅数字
      v = v.replace(/\D/g, '')
      // 限制最多4位
      if (v.length > 4) v = v.slice(0, 4)
      // 限制最大 9999
      if (v) {
        const n = Number(v)
        if (n > 9999) v = '9999'
      }
      this.form.sellCount = v
    },
    handleSellCountBlur() {
      const raw = String(this.form.sellCount ?? '')
      if (raw === '') return
      const n = Number(raw)
      if (!Number.isInteger(n) || n < 0 || n > 9999) {
        this.$message.warning('出售机器数量需为 0-9999 的整数')
        this.form.sellCount = ''
      }
    },
    /**
     * 矿机种类变更：若选择 GPU，弹出引导弹窗；ASIC 则保持当前页面逻辑
     * @param {string} val
     */
    handleMachineCategoryChange(val) {
      if (String(val).toUpperCase() === 'GPU') {
        this.gpuDialogVisible = true
        // 首次打开时禁用“已启动客户端”按钮
        this.hasDownloadedClient = false
      } else {
        this.gpuDialogVisible = false
      }
    },
    /**
     * 下载 GPU 客户端
     */
    handleDownloadClient() {
      // 走后端接口下载客户端程序
      downloadClient()
        .then((res) => {
          // 处理 blob 下载（兼容封装返回 data 或直接返回 Blob）
          const data = (res && res.data) ? res.data : res
          const blob = data instanceof Blob ? data : new Blob([data], { type: 'application/octet-stream' })
          const url = window.URL.createObjectURL(blob)
          const a = document.createElement('a')
          a.style.display = 'none'
          a.href = url
          // 默认文件名（可由后端 Content-Disposition 提供，这里简单兜底）
          a.download = 'gpu-client.zip'
          document.body.appendChild(a)
          a.click()
          document.body.removeChild(a)
          window.URL.revokeObjectURL(url)
          this.$message.success('客户端下载已开始')
          this.hasDownloadedClient = true
        })
        .catch(() => {
          this.$message.error('下载失败，请稍后重试')
        })
    },
    /**
     * GPU 客户端已启动：跳转至商品列表
     */
    handleGpuClientStarted() {
      // 跳转到“个人中心-商品列表”页面
      this.$router.push('/account/products')
    },
    /**
     * GPU 弹窗关闭：自动恢复为 ASIC
     */
    handleGpuDialogClosed() {
      this.form.machineCategory = 'ASIC'
      this.gpuDialogVisible = false
    },
    /** 统一售价校验：多结算币种时跳过，单价时按 USDT 校验 */
    validateCost(rule, value, callback) {
      // 多支付方式：逐个校验 costMap
      if (Array.isArray(this.payTypeDefs) && this.payTypeDefs.length > 0) {
        return this.validateCostMap(rule, value, callback)
      }
      const str = String(value || '')
      if (!str) { callback(new Error('请填写机器成本（USDT）')); return }
      const pattern = /^\d{1,12}(\.\d{1,2})?$/
      if (!pattern.test(str)) { callback(new Error('成本整数最多12位，小数最多2位')); return }
      if (Number(str) <= 0) { callback(new Error('成本必须大于 0')); return }
      callback()
    },
    // 多支付方式下的价格校验：要求每个支付方式都需填写有效价格
    validateCostMap(rule, value, callback) {
      try {
        const defs = Array.isArray(this.payTypeDefs) ? this.payTypeDefs : []
        if (!defs.length) { callback(); return }
        const pattern = /^\d{1,12}(\.\d{1,2})?$/
        for (let i = 0; i < defs.length; i += 1) {
          const d = defs[i]
          const key = d.key
          const v = this.form && this.form.costMap ? String(this.form.costMap[key] || '') : ''
          if (!v) { callback(new Error(`请填写 ${d.label} 的价格`)); return }
          if (!pattern.test(v)) { callback(new Error(`${d.label} 价格整数最多12位，小数最多2位`)); return }
          if (Number(v) <= 0) { callback(new Error(`${d.label} 价格必须大于0`)); return }
        }
        callback()
      } catch (e) {
        callback(new Error('价格填写有误，请检查'))
      }
    },
    /** 解析路由参数中的支付方式，生成标准定义 */
    initPayTypesFromRoute() {
      this.payTypeDefs = []
      try {
        const raw = this.$route.query.payTypes
        if (!raw) return
        const arr = JSON.parse(decodeURIComponent(raw))
        if (!Array.isArray(arr)) return
        const defs = []
        arr.forEach(it => {
          const chain = String(it && it.chain ? it.chain : '').toUpperCase()
          const coin = String(it && it.coin ? it.coin : '').toUpperCase()
          if (!chain && !coin) return
          const key = [chain, coin].filter(Boolean).join('-')
          const label = key
          defs.push({ chain, coin, key, label })
        })
        // 去重
        const map = new Map()
        defs.forEach(d => { if (!map.has(d.key)) map.set(d.key, d) })
        this.payTypeDefs = Array.from(map.values())
        // 初始化统一售价映射
        const initCostMap = {}
        this.payTypeDefs.forEach(d => { initCostMap[d.key] = '' })
        this.form.costMap = initCostMap
        this.lastCostMapBaseline = { ...initCostMap }
      } catch (e) {
        this.payTypeDefs = []
      }
    },
    handleBack() {
      this.$router.back()
    },
    handleNumeric(key) {
      // 仅允许数字和一个小数点
      let v = String(this.form[key] ?? '')
      // 清理非法字符
      v = v.replace(/[^0-9.]/g, '')
      // 保留第一个小数点
      const firstDot = v.indexOf('.')
      if (firstDot !== -1) {
        v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '')
      }
      const endsWithDot = v.endsWith('.')
      if (key === 'cost') {
        // 成本：整数最多12位，小数最多2位
        const parts = v.split('.')
        let intPart = parts[0] || ''
        let decPart = parts[1] || ''
        if (intPart.length > 12) {
          intPart = intPart.slice(0, 12)
        }
        if (decPart) {
          decPart = decPart.slice(0, 2)
        }
        v = decPart.length ? `${intPart}.${decPart}` : (endsWithDot ? `${intPart}.` : intPart)
      } else if (key === 'powerDissipation' || key === 'theoryPower') {
        // 功耗/理论算力：整数最多6位，小数最多4位
        const parts = v.split('.')
        let intPart = parts[0] || ''
        let decPart = parts[1] || ''
        if (intPart.length > 6) {
          intPart = intPart.slice(0, 6)
        }
        if (decPart) {
          decPart = decPart.slice(0, 4)
        }
        v = decPart.length ? `${intPart}.${decPart}` : (endsWithDot ? `${intPart}.` : intPart)
      } else if (key === 'maxLeaseDays') {
        // 最大租赁天数：仅整数，范围 1-365，输入阶段限制为最多3位数字
        v = v.replace(/\D/g, '')
        if (v.length > 3) v = v.slice(0, 3)
        this.form[key] = v
        this.syncMaxLeaseDaysToRows()
        return
      } else {
        // 其他：最多6位小数（保持原有逻辑）
        if (firstDot !== -1) {
          const [intPart, decPart] = v.split('.')
          v = intPart + '.' + (decPart ? decPart.slice(0, 6) : '')
        }
      }
      this.form[key] = v
    },
    /** 顶部多结算币种统一售价输入 */
    handleCostMapInput(key, val) {
      // 价格输入：整数最多12位，小数最多2位；允许尾随小数点
      let v = String(val ?? this.form.costMap[key] ?? '')
      v = v.replace(/[^0-9.]/g, '')
      const firstDot = v.indexOf('.')
      if (firstDot !== -1) {
        v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '')
      }
      const endsWithDot = v.endsWith('.')
      const parts = v.split('.')
      let intPart = parts[0] || ''
      let decPart = parts[1] || ''
      if (intPart.length > 12) intPart = intPart.slice(0, 12)
      if (decPart) decPart = decPart.slice(0, 2)
      v = decPart.length ? `${intPart}.${decPart}` : (endsWithDot ? `${intPart}.` : intPart)
      this.$set(this.form.costMap, key, v)
    },
    /**
     * 顶部矿机型号输入：限制20字符
     */
    handleTypeInput() {
      if (typeof this.form.type === 'string' && this.form.type.length > 20) {
        this.form.type = this.form.type.slice(0, 20)
      }
    },
    syncCostToRows() {
      const newCost = Number(this.form.cost)
      if (!Number.isFinite(newCost)) {
        return
      }
      const oldBaseline = this.lastCostBaseline
      this.selectedMachineRows = this.selectedMachineRows.map(row => {
        const priceNum = Number(row.price)
        if (!Number.isFinite(priceNum) || priceNum === oldBaseline) {
          return { ...row, price: newCost }
        }
        return row
      })
      this.lastCostBaseline = newCost
    },
    updateMachineType() {
      // 仅记录最近一次外层输入，避免无用同步逻辑
      this.lastTypeBaseline = this.form.type
    },
    /**
     * 行内功耗输入（限制：整数最多6位，小数最多4位）
     */
    handleRowPowerDissipationInput(index) {
      let v = String(this.selectedMachineRows[index].powerDissipation ?? '')
      v = v.replace(/[^0-9.]/g, '')
      const firstDot = v.indexOf('.')
      if (firstDot !== -1) {
        v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '')
      }
      const endsWithDot = v.endsWith('.')
      const parts = v.split('.')
      let intPart = parts[0] || ''
      let decPart = parts[1] || ''
      if (intPart.length > 6) intPart = intPart.slice(0, 6)
      if (decPart) decPart = decPart.slice(0, 4)
      v = decPart.length ? `${intPart}.${decPart}` : (endsWithDot ? `${intPart}.` : intPart)
      this.$set(this.selectedMachineRows[index], 'powerDissipation', v)
    },
    /**
     * 行内功耗校验
     */
    handleRowPowerDissipationBlur(index) {
      const raw = String(this.selectedMachineRows[index].powerDissipation ?? '')
      const pattern = /^\d{1,6}(\.\d{1,4})?$/
      if (!raw || Number(raw) <= 0 || !pattern.test(raw)) {
        this.$message.warning('功耗需大于0，整数最多6位，小数最多4位')
        this.$set(this.selectedMachineRows[index], 'powerDissipation', '')
      }
    },
    /**
     * 行内理论算力输入（限制：整数最多6位，小数最多4位）
     */
    handleRowTheoryPowerInput(index) {
      let v = String(this.selectedMachineRows[index].theoryPower ?? '')
      v = v.replace(/[^0-9.]/g, '')
      const firstDot = v.indexOf('.')
      if (firstDot !== -1) {
        v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '')
      }
      const endsWithDot = v.endsWith('.')
      const parts = v.split('.')
      let intPart = parts[0] || ''
      let decPart = parts[1] || ''
      if (intPart.length > 6) intPart = intPart.slice(0, 6)
      if (decPart) decPart = decPart.slice(0, 4)
      v = decPart.length ? `${intPart}.${decPart}` : (endsWithDot ? `${intPart}.` : intPart)
      this.$set(this.selectedMachineRows[index], 'theoryPower', v)
    },
    /**
     * 行内理论算力校验
     */
    handleRowTheoryPowerBlur(index) {
      const raw = String(this.selectedMachineRows[index].theoryPower ?? '')
      const pattern = /^\d{1,6}(\.\d{1,4})?$/
      if (!raw || Number(raw) <= 0 || !pattern.test(raw)) {
        this.$message.warning('理论算力需大于0，整数最多6位，小数最多4位')
        this.$set(this.selectedMachineRows[index], 'theoryPower', '')
      }
    },
    /**
     * 行内单位变更
     */
    handleRowUnitChange(index, value) {
      this.$set(this.selectedMachineRows[index], 'unit', value)
    },
    syncMaxLeaseDaysToRows() {
      const raw = this.form.maxLeaseDays
      const n = Number(raw)
      if (!Number.isInteger(n)) return
      const oldBaseline = this.lastMaxLeaseDaysBaseline
      this.selectedMachineRows = this.selectedMachineRows.map(row => {
        const rowNum = Number(row.maxLeaseDays)
        if (!Number.isInteger(rowNum) || rowNum === oldBaseline) {
          return { ...row, maxLeaseDays: n }
        }
        return row
      })
      this.lastMaxLeaseDaysBaseline = n
    },
    handleRowMaxLeaseDaysInput(index) {
      let v = String(this.selectedMachineRows[index].maxLeaseDays ?? '')
      v = v.replace(/\D/g, '')
      if (v.length > 3) v = v.slice(0, 3)
      this.$set(this.selectedMachineRows[index], 'maxLeaseDays', v)
    },
    handleRowMaxLeaseDaysBlur(index) {
      const raw = String(this.selectedMachineRows[index].maxLeaseDays ?? '')
      if (!/^\d{1,3}$/.test(raw)) {
        this.$message.warning('最大租赁天数需为 1-365 的整数')
        this.$set(this.selectedMachineRows[index], 'maxLeaseDays', '')
        return
      }
      const n = Number(raw)
      if (!Number.isInteger(n) || n < 1 || n > 365) {
        this.$message.warning('最大租赁天数需为 1-365 的整数')
        this.$set(this.selectedMachineRows[index], 'maxLeaseDays', '')
      }
    },
    handleRowPriceInput(index) {
      // 价格输入：整数最多12位，小数最多2位；允许尾随小数点
      let v = String(this.selectedMachineRows[index].price ?? '')
      v = v.replace(/[^0-9.]/g, '')
      const firstDot = v.indexOf('.')
      if (firstDot !== -1) {
        v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '')
      }
      const endsWithDot = v.endsWith('.')
      const parts = v.split('.')
      let intPart = parts[0] || ''
      let decPart = parts[1] || ''
      if (intPart.length > 12) { intPart = intPart.slice(0, 12) }
      if (decPart) { decPart = decPart.slice(0, 2) }
      v = decPart.length ? `${intPart}.${decPart}` : (endsWithDot ? `${intPart}.` : intPart)
      this.$set(this.selectedMachineRows[index], 'price', v)
    },
    /** 行内多结算币种价格输入 */
    handleRowPriceMapInput(index, key) {
      // 价格输入：整数最多12位，小数最多2位；允许尾随小数点
      const row = this.selectedMachineRows[index]
      const map = { ...(row.priceMap || {}) }
      let v = String(map[key] ?? '')
      v = v.replace(/[^0-9.]/g, '')
      const firstDot = v.indexOf('.')
      if (firstDot !== -1) {
        v = v.slice(0, firstDot + 1) + v.slice(firstDot + 1).replace(/\./g, '')
      }
      const endsWithDot = v.endsWith('.')
      const parts = v.split('.')
      let intPart = parts[0] || ''
      let decPart = parts[1] || ''
      if (intPart.length > 12) intPart = intPart.slice(0, 12)
      if (decPart) decPart = decPart.slice(0, 2)
      v = decPart.length ? `${intPart}.${decPart}` : (endsWithDot ? `${intPart}.` : intPart)
      map[key] = v
      this.$set(this.selectedMachineRows[index], 'priceMap', map)
    },
    handleRowPriceMapBlur(index, key) {
      const row = this.selectedMachineRows[index]
      const raw = String((row.priceMap && row.priceMap[key]) ?? '')
      const pattern = /^\d{1,12}(\.\d{1,2})?$/
      if (!raw || Number(raw) <= 0 || !pattern.test(raw)) {
        this.$message.warning('价格必须大于0，整数最多12位，小数最多2位')
        const map = { ...(row.priceMap || {}) }
        map[key] = ''
        this.$set(this.selectedMachineRows[index], 'priceMap', map)
      }
    },
    handleRowPriceBlur(index) {
      const raw = String(this.selectedMachineRows[index].price ?? '')
      const pattern = /^\d{1,12}(\.\d{1,2})?$/
      if (!raw || Number(raw) <= 0 || !pattern.test(raw)) {
        this.$message.warning('价格必须大于0，整数最多12位，小数最多2位')
        this.$set(this.selectedMachineRows[index], 'price', '')
      }
    },
    handleRowTypeInput(index) {
      // 处理矿机型号输入
      const raw = String(this.selectedMachineRows[index].type || '')
      const v = raw.length > 20 ? raw.slice(0, 20) : raw
      this.$set(this.selectedMachineRows[index], 'type', v)
    },
    handleRowTypeBlur(index) {
      const raw = this.selectedMachineRows[index].type
      const isOnlySpaces = (v) => typeof v === 'string' && v.length > 0 && v.trim().length === 0
      if (isOnlySpaces(raw)) {
        this.$message.warning('矿机型号不能全是空格')
        this.$set(this.selectedMachineRows[index], 'type', '')
      }
    },
    handleToggleState(index) {
      // 切换上下架状态：0上架，1下架
      const currentState = this.selectedMachineRows[index].state
      this.$set(this.selectedMachineRows[index], 'state', currentState === 0 ? 1 : 0)
    },
    async fetchMiners() {
      this.minersLoading = true
      try {
        // 按商品币种筛选挖矿账户
        const res = await getUserMinersList({ coin: this.form.coin || "" })
        const data = res?.data
        let list = []
        if (Array.isArray(data)) {
          list = data
        } else if (data && typeof data === 'object') {
          // 现在的结构是 { coin: [ { user, coin }, ... ], coin2: [...] }
          Object.keys(data).forEach(coinKey => {
            const arr = Array.isArray(data[coinKey]) ? data[coinKey] : []
            arr.forEach(item => {
              if (item && item.user && item.coin) {
                list.push({ user: item.user, coin: item.coin, miner: item.miner || null })
              }
            })
          })
        } else if (data && data.additionalProperties1) {
          list = [data.additionalProperties1]
        }

        // 如页面带了 product coin，则仅展示该币种的账户
        if (this.form.coin) {
          list = list.filter(i => i.coin === this.form.coin)
        }
        this.miners = list
      } catch (e) {
        console.error('获取挖矿账户失败', e)
      } finally {
        this.minersLoading = false
      }
    },
    async handleMinerChange(val) {
      this.selectedMachines = []
      if (!val) {
        this.machineOptions = []
        return
      }
      const [user, coin] = val.split('|')
      this.machinesLoading = true
      try {
        // 按照API文档要求，传递 userMinerVo 对象
        const userMinerVo = {
          coin: coin,
          user: user
        }
        const res = await getUserMachineList(userMinerVo)
        const data = res?.data || []
        this.machineOptions = Array.isArray(data) ? data : []
        
        // 调试信息
        console.log('选择挖矿账户:', { user, coin })
        console.log('获取机器列表响应:', res)
        console.log('机器列表数据:', this.machineOptions)
      } catch (e) {
        console.error('获取机器列表失败', e)
       
      } finally {
        this.machinesLoading = false
      }
    },
    async handleSave() {
      // 表单校验（除矿机型号外其他必填）
      try {
        const ok = await this.$refs.machineForm.validate()
        if (!ok) {
          return
        }
      } catch (e) {
        return
      }
      // if (!this.form.productId) {
      //   this.$message.warning('缺少商品ID')
      //   return
      // }
      // 现在统一按出售数量提交（GPU 模式不在本页提交）
      {
        // ASIC：校验出售机器数量（允许 0-9999；为 0 则提示）
        const raw = String(this.form.sellCount ?? '')
        if (raw === '') {
          this.$message.warning('请输入出售机器数量')
          return
        }
        const n = Number(raw)
        if (!Number.isInteger(n) || n < 0 || n > 9999) {
          this.$message.warning('出售机器数量需为 0-9999 的整数')
          return
        }
        if (n === 0) {
          this.$message.warning('出售机器数量为 0，无需提交')
          return
        }
      }
      // 校验：矿机型号不可全空格（允许为空或包含空格的正常文本）
      const isOnlySpaces = (v) => typeof v === 'string' && v.length > 0 && v.trim().length === 0
      if (isOnlySpaces(this.form.type)) {
        this.$message.warning('矿机型号不能全是空格')
        return
      }
      const invalidTypeRowIndex = this.selectedMachineRows.findIndex(r => isOnlySpaces(r.type))
      if (invalidTypeRowIndex !== -1) {
        this.$message.warning('存在行的矿机型号全是空格，请修正后再试')
        return
      }
      // 统一售价与最大租赁天数已在表单级校验中处理，无需逐机校验
      // 组装确认数据并弹框
      const coinStr = this.normalizeCsv(this.form.coinsInput || this.form.coin, true)
      const algoStr = this.normalizeCsv(this.form.algorithmsInput, true)
      this.confirmData = {
        coin: coinStr || '-',
        algorithm: algoStr || '-',
        maxLeaseDays: this.form.maxLeaseDays,
        saleNumbers: this.form.sellCount,
        priceList: this.buildPriceList()
      }
      this.confirmVisible = true
    }
    ,
    async doSubmit() {
      this.saving = true
      try {
        // 统一售卖新增接口参数
        const payload = {
          // 逗号分隔（中英文逗号都兼容），统一为英文逗号并大写
          coin: this.normalizeCsv(this.form.coinsInput || this.form.coin, true),
          algorithm: this.normalizeCsv(this.form.algorithmsInput, true),
          maxLeaseDays: Number(this.form.maxLeaseDays) || 0,
          name: this.form.type,
          powerDissipation: Number(this.form.powerDissipation) || 0,
          theoryPower: Number(this.form.theoryPower) || 0,
          unit: this.form.unit,
          saleNumbers: Number(this.form.sellCount) || 0,
          priceList: this.buildPriceList()
        }
        // 过滤空价目
        payload.priceList = (payload.priceList || []).filter(p => Number(p.price) > 0)

        console.log(payload,"请求参数")

        const res = await addAsicMachine(payload)
        if (res && (res.code === 0 || res.code === 200)) {
        
          this.$message({
            message: '添加成功',
            duration: 3000,
            showClose: true,
            type: 'success'
          })
          this.confirmVisible = false
          this.$router.push('/account/products')
        } 
      } catch (e) {
        console.error('添加出售机器失败', e)
        console.log('添加失败')
      } finally {
        this.saving = false
      }
    }
  }
  
}
</script>

<style scoped>
.product-machine-add { padding: 8px; }
.header { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.title { margin: 0; font-size: 18px; font-weight: 600; }
.notice-alert { margin-bottom: 12px; }
.notice-alert :deep(.el-alert__content) { text-align: left; }
.notice-alert :deep(.el-alert__title),
.notice-alert :deep(.el-alert__description) { text-align: left; }
.label-help { margin-left: 4px; color: #909399; cursor: help; }
.form-card { margin-bottom: 12px; }
.actions { text-align: left; }

/* 统一左对齐，控件宽度 50% */
.product-machine-add :deep(.el-form-item__content) {
  justify-content: flex-start;
}
/* .product-machine-add :deep(.el-input),
.product-machine-add :deep(.el-select),
.product-machine-add :deep(.el-textarea) {
  width: 50%;
} */
.product-machine-add :deep(.el-input-group__append) {
  background: #f5f7fa;
  color: #606266;
  border-left: 1px solid #dcdfe6;
}

::v-deep .el-form-item__content{
    text-align: left;
 padding-left: 18px !important;
}

/* 多结算币种价格输入的布局优化 */
.cost-multi { display: grid; gap: 8px; }
.cost-item { display: flex; align-items: center; }
.price-multi { display: grid; gap: 8px; }
.price-items { display: grid; gap: 8px; }
/* 让 链-币种 附加区同宽、居中显示，整体对齐 */
.price-item :deep(.el-input-group__append),
.cost-item :deep(.el-input-group__append){
  width: 110px;
  min-width: 110px;
  text-align: center;
  padding: 0 8px;
  background: #f8fafc;
  color: #606266;
}
/* 缩小输入高度并保持垂直居中 */
.price-item :deep(.el-input__inner),
.cost-item :deep(.el-input__inner){
  height: 30px;
  line-height: 30px;
}
/* 让组内附加区高度与输入一致 */
.price-item :deep(.el-input-group__append),
.cost-item :deep(.el-input-group__append){
  height: 30px;
  line-height: 30px;
}
/* 略微收紧间距，让整体更紧凑 */
.price-multi { gap: 6px; }
.price-items { gap: 6px; }
.cost-multi { gap: 6px; }
</style>

