Files
webs/power_leasing/src/views/account/productDetail.vue
2025-11-07 16:30:03 +08:00

757 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="account-product-detail">
<div class="header">
<el-button type="text" @click="handleBack">返回</el-button>
<h2 class="title">商品详情</h2>
</div>
<!-- 基础信息采用工单详情的两列表单风格 -->
<el-card shadow="never" class="detail-card">
<el-form :model="product" label-width="90px" class="detail-form" size="small">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="商品ID">
<el-input :value="product && product.id" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="店铺ID">
<el-input :value="product && product.shopId" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="名称">
<el-input :value="product && product.name" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="币种">
<el-input :value="product && product.coin" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="算法">
<el-input :value="product && product.algorithm" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-form-item label="价格范围">
<el-input :value="product && product.priceRange" disabled />
</el-form-item> -->
<el-form-item label="类型">
<el-input :value="product && (product.type === 1 ? '算力套餐' : '挖矿机器')" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-input :value="product && (product.state === 1 ? '下架' : '上架')" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
</el-col>
<!-- <el-col :span="24">
<el-form-item label="图片">
<div class="image-row">
<el-image v-if="product && product.image" :src="product.image" fit="cover" class="cover" />
<span v-else class="placeholder">暂无图片</span>
</div>
</el-form-item>
</el-col> -->
<el-col :span="24">
<el-form-item label="描述">
<el-input type="textarea" :rows="3" :value="product && product.description" disabled />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- 机器组合信息模拟处理记录块状区域 -->
<el-card shadow="never" class="detail-card" v-loading="updateLoading">
<div slot="header" class="section-title">机器组合</div>
<div v-if="machineList && machineList.length">
<el-table :data="machineList" border stripe style="width: 100%">
<el-table-column prop="user" label="挖矿账户" />
<el-table-column prop="id" label="矿机ID" />
<el-table-column prop="miner" label="机器编号" />
<el-table-column label="实际算力" width="100">
<template slot="header">
<el-tooltip content="实际算力为该机器在本矿池过去24H的平均算力" effect="dark" placement="top">
<i class="el-icon-question label-help" aria-label="帮助" tabindex="0"></i>
</el-tooltip>
<span>实际算力</span>
</template>
<template slot-scope="scope">{{ scope.row.computingPower }} {{ scope.row.unit || '' }}</template>
</el-table-column>
<el-table-column label="理论算力" min-width="140">
<template #default="scope">
<el-input
v-model="scope.row.theoryPower"
size="small"
inputmode="decimal"
:disabled="isRowDisabled(scope.row)"
@input="handleTheoryPowerInput(scope.$index)"
@blur="handleTheoryPowerBlur(scope.$index)"
:class="{ 'changed-input': isCellChanged(scope.row, 'theoryPower') }"
style="max-width: 260px;"
>
<template slot="append">
<el-select v-model="scope.row.unit" size="mini" :disabled="isRowDisabled(scope.row)" class="append-select append-select--unit" style="width: 90px;">
<el-option v-for="u in unitOptions" :key="u" :label="u" :value="u" />
</el-select>
</template>
</el-input>
</template>
</el-table-column>
<el-table-column label="功耗(kw/h)" >
<template #default="scope">
<el-input
v-model="scope.row.powerDissipation"
size="small"
inputmode="decimal"
:disabled="isRowDisabled(scope.row)"
@input="handleNumericCell(scope.$index, 'powerDissipation')"
@blur="handlePowerDissipationBlur(scope.$index)"
:class="{ 'changed-input': isCellChanged(scope.row, 'powerDissipation') }"
style="max-width: 260px;"
>
<!-- <template slot="append">kw/h</template> -->
</el-input>
</template>
</el-table-column>
<el-table-column label="型号" >
<template #default="scope">
<el-input
v-model="scope.row.type"
size="small"
:maxlength="20"
:disabled="isRowDisabled(scope.row)"
@input="handleTypeCell(scope.$index)"
:class="{ 'changed-input': isCellChanged(scope.row, 'type') }"
style="max-width: 180px;"
/>
</template>
</el-table-column>
<el-table-column label="售价" width="188">
<template slot="header">
<el-tooltip effect="dark" placement="top">
<div slot="content">
卖家最终收款金额 = 机器售价 × 波动率<br/>
波动率规则<br/>
10% - 5%包含5%波动率 = 1按售价结算<br/>
25%以上波动率 = 实际算力 / 理论算力且不会超过 1,即最终结算时不会超过机器售价
</div>
<i class="el-icon-question label-help" aria-label="帮助" tabindex="0"></i>
</el-tooltip>
<span>售价按结算币种</span>
</template>
<template slot-scope="scope">
<el-input
v-model="scope.row._priceEditing"
size="small"
inputmode="decimal"
:disabled="isRowDisabled(scope.row)"
@input="handleNumericCell(scope.$index, 'price')"
@blur="handlePriceBlur(scope.$index)"
:class="{ 'changed-input': isCellChanged(scope.row, 'price') }"
style="max-width: 260px;"
>
<template slot="append">
<el-select v-model="scope.row._selectedPayIndex" size="mini" @change="handlePayTypeChange(scope.$index)" class="append-select append-select--coin" style="width:120px;">
<el-option
v-for="(pt, i) in (scope.row.priceList || [])"
:key="pt.payTypeId || i"
:label="[String(pt.chain||'').toUpperCase(), String(pt.coin||'').toUpperCase()].filter(Boolean).join('-')"
:value="i"
/>
</el-select>
</template>
</el-input>
</template>
</el-table-column>
<el-table-column label="最大租赁天数(天)" width="100">
<template #default="scope">
<el-input
v-model="scope.row.maxLeaseDays"
size="small"
inputmode="numeric"
:disabled="isRowDisabled(scope.row)"
@input="handleMaxLeaseDaysInput(scope.$index)"
@blur="handleMaxLeaseDaysBlur(scope.$index)"
:class="{ 'changed-input': isCellChanged(scope.row, 'maxLeaseDays') }"
style="max-width: 260px;"
>
<template slot="append"></template>
</el-input>
</template>
</el-table-column>
<el-table-column label="上下架" min-width="140">
<template #default="scope">
<el-switch
v-model="scope.row.state"
:active-value="0"
:inactive-value="1"
active-text="上架"
inactive-text="下架"
:disabled="isRowDisabled(scope.row)"
@change="handleStateChange(scope.$index)"
/>
</template>
</el-table-column>
<el-table-column label="售出状态" min-width="100">
<template #default="scope">
<el-tag :type="scope.row.saleState === 0 ? 'info' : (scope.row.saleState === 1 ? 'danger' : 'warning')">
{{ scope.row.saleState === 0 ? '未售出' : (scope.row.saleState === 1 ? '已售出' : '售出中') }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" min-width="120">
<template #default="scope">
<el-button type="text" size="small" style="color:#f56c6c" :disabled="isRowDisabled(scope.row)" @click="handleDeleteMachine(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div v-else class="empty-text">暂无组合数据</div>
</el-card>
<div class="actions" v-if="machineList && machineList.length">
<el-button type="primary" @click="handleOpenConfirm">提交修改机器</el-button>
</div>
<!-- 提交确认弹窗 -->
<el-dialog
title="确认提交修改"
:visible.sync="confirmVisible"
width="520px"
>
<div>
<p>请仔细确认已选择机器机器组合里的机器价格及相关参数定义</p>
<p>机器修改上架后一经售出在机器出售期间不能修改价格及机器参数</p>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="confirmVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmitMachines">确认提交修改</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getMachineInfoById } from '../../api/products'
import { getMachineListForUpdate,updateMachine,deleteMachine } from '../../api/machine'
export default {
name: 'AccountProductDetail',
data() {
return {
loading: false,
product: null,
ranges: [],
machineList: [],
productId:null,
confirmVisible: false,
// 机器“上下架状态”快照用于失败回滚key 为机器 idvalue 为提交前的 state
stateSnapshot: {},
// 可编辑字段快照(用于变更高亮)
fieldSnapshot: {},
updateLoading:false,
// 算力单位选项(与新增出售机器页面保持一致)
unitOptions: ['KH/S','MH/S','GH/S','TH/S','PH/S'],
}
},
created() {
this.productId= Number(this.$route.params.id)
if (this.productId) {
this.fetchDetail({ id:this.productId })
this.fetchMachineList({ id:this.productId })
}
},
methods: {
/** 结算币种切换时,更新当前编辑价格 */
handlePayTypeChange(index) {
const row = this.machineList && this.machineList[index]
if (!row) return
const sel = Number(row._selectedPayIndex || 0)
const list = Array.isArray(row.priceList) ? row.priceList : []
const target = list[sel] || {}
this.$set(this.machineList, index, { ...row, _priceEditing: String(target.price ?? '') })
},
/**
* 判断行是否不可编辑(已售出则禁用)
* @param {Object} row - 当前行数据
* @returns {boolean}
*/
isRowDisabled(row) {
if (!row) return false
return Number(row.saleState) === 1
},
handleOpenConfirm() {
if (!this.machineList || !this.machineList.length) {
this.$message.warning('没有可提交的数据')
return
}
this.confirmVisible = true
},
async fetchDetail(params) {
this.loading = true
try {
const res = await getMachineInfoById(params)
const data = res?.data || {}
this.product = data
this.ranges = Array.isArray(data.productMachineRangeList) ? data.productMachineRangeList : []
} catch (e) {
console.error('获取商品详情失败', e)
console.log('获取商品详情失败')
} finally {
this.loading = false
}
},
async fetchMachineList(params) {
const res = await getMachineListForUpdate(params)
if (res && res.code === 200) {
const rows = Array.isArray(res.rows) ? res.rows : []
this.machineList = rows.map(r => {
const list = Array.isArray(r.priceList) ? r.priceList : []
const sel = 0
const first = list[sel] || {}
return { ...r, _selectedPayIndex: sel, _priceEditing: String(first.price ?? '') }
})
this.refreshStateSnapshot()
this.refreshFieldSnapshot()
}
},
/**
* 刷新状态快照:以当前列表为准记录每条机器的 state
* @returns {void}
*/
refreshStateSnapshot() {
const snapshot = {}
const list = Array.isArray(this.machineList) ? this.machineList : []
for (let i = 0; i < list.length; i += 1) {
const row = list[i]
if (row && typeof row.id !== 'undefined') {
snapshot[row.id] = row.state
}
}
this.stateSnapshot = snapshot
},
/**
* 刷新可编辑字段快照,用于“变更高亮”对比
* @returns {void}
*/
refreshFieldSnapshot() {
const snapshot = {}
const list = Array.isArray(this.machineList) ? this.machineList : []
for (let i = 0; i < list.length; i += 1) {
const row = list[i]
if (!row || typeof row.id === 'undefined') continue
const priceMap = {}
if (Array.isArray(row.priceList)) {
row.priceList.forEach(p => { if (p) priceMap[String(p.payTypeId ?? '')] = String(p.price ?? '') })
}
snapshot[row.id] = {
theoryPower: String(row.theoryPower ?? ''),
powerDissipation: String(row.powerDissipation ?? ''),
type: String(row.type ?? ''),
priceMap,
maxLeaseDays: String(row.maxLeaseDays ?? ''),
}
}
this.fieldSnapshot = snapshot
},
/**
* 判断单元格是否被修改(与快照对比)
* @param {Object} row
* @param {string} key
* @returns {boolean}
*/
isCellChanged(row, key) {
if (!row || typeof row.id === 'undefined') return false
const snap = this.fieldSnapshot[row.id] || {}
if (key === 'price') {
const sel = Number(row._selectedPayIndex || 0)
const pt = Array.isArray(row.priceList) && row.priceList[sel] ? row.priceList[sel] : null
const pid = String(pt && pt.payTypeId ? pt.payTypeId : sel)
const cur = String(pt && pt.price != null ? pt.price : '')
const ori = String((snap.priceMap && snap.priceMap[pid]) || '')
return cur !== ori
}
const current = String(row[key] ?? '')
const original = String(snap[key] ?? '')
return current !== original
},
/**
* 回滚上下架状态:当提交失败时将每行的 state 恢复为提交前
* @returns {void}
*/
restoreStateSnapshot() {
if (!this.machineList || !this.machineList.length) return
for (let i = 0; i < this.machineList.length; i += 1) {
const currentRow = this.machineList[i]
if (!currentRow || typeof currentRow.id === 'undefined') continue
const prevState = this.stateSnapshot[currentRow.id]
if (typeof prevState !== 'undefined') {
this.$set(this.machineList[i], 'state', prevState)
}
}
},
/**
* 提交机器修改;失败或异常时回滚上下架状态
* @param {Array} params - 要更新的机器列表 payload
* @returns {Promise<void>}
*/
async updateMachineList(params) {
this.updateLoading = true
try {
const res = await updateMachine(params)
if (res && res.code === 200) {
this.$message.success('更新成功')
// 成功后刷新列表(并在列表刷新后更新快照)
this.fetchMachineList({ id:this.productId })
} else {
// 失败回滚上下架状态
this.restoreStateSnapshot()
}
} catch (e) {
// 异常回滚上下架状态
this.restoreStateSnapshot()
}
this.updateLoading = false
},
async deleteMachine(params) {
const res = await deleteMachine(params)
if (res && res.code === 200) {
this.$message.success('删除成功')
this.fetchMachineList({ id:this.productId })
}
},
handleTheoryPowerInput(index) {
const rowItem = this.machineList && this.machineList[index]
if (!rowItem || this.isRowDisabled(rowItem)) return
// 输入阶段限制整数最多6位小数最多4位允许结尾小数点
let v = String(this.machineList[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.machineList, index, { ...this.machineList[index], theoryPower: v })
},
handleNumericCell(index, key) {
const rowItem = this.machineList && this.machineList[index]
if (!rowItem || this.isRowDisabled(rowItem)) return
// 输入阶段限制:
// - 功耗6 位整数 + 4 位小数
// - 价格12 位整数 + 2 位小数
// - 其他保持原逻辑6 位小数)
let v = String(key === 'price' ? (this.machineList[index]._priceEditing ?? '') : (this.machineList[index][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, '')
}
if (key === 'powerDissipation') {
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)
} else if (key === 'price') {
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.machineList[index], '_priceEditing', v)
const row = this.machineList[index]
const sel = Number(row._selectedPayIndex || 0)
if (Array.isArray(row.priceList) && row.priceList[sel]) {
this.$set(row.priceList[sel], 'price', v)
}
} else {
if (firstDot !== -1) {
const [i, d] = v.split('.')
v = i + '.' + (d ? d.slice(0, 6) : '')
}
}
if (key !== 'price') {
const row = { ...this.machineList[index], [key]: v }
this.$set(this.machineList, index, row)
}
},
handlePriceBlur(index) {
const raw = String(this.machineList[index]._priceEditing ?? '')
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.machineList[index], '_priceEditing', '')
const row = this.machineList[index]
const sel = Number(row._selectedPayIndex || 0)
if (Array.isArray(row.priceList) && row.priceList[sel]) {
this.$set(row.priceList[sel], 'price', '')
}
}
},
handleMaxLeaseDaysInput(index) {
const rowItem = this.machineList && this.machineList[index]
if (!rowItem || this.isRowDisabled(rowItem)) return
let v = String(this.machineList[index].maxLeaseDays ?? '')
v = v.replace(/\D/g, '')
if (v.length > 3) v = v.slice(0, 3)
const row = { ...this.machineList[index], maxLeaseDays: v }
this.$set(this.machineList, index, row)
},
handleMaxLeaseDaysBlur(index) {
const raw = String(this.machineList[index].maxLeaseDays ?? '')
if (!/^\d{1,3}$/.test(raw)) {
this.$message.warning('最大租赁天数需为 1-365 的整数')
const row = { ...this.machineList[index], maxLeaseDays: '' }
this.$set(this.machineList, index, row)
return
}
const n = Number(raw)
if (!Number.isInteger(n) || n < 1 || n > 365) {
this.$message.warning('最大租赁天数需为 1-365 的整数')
const row = { ...this.machineList[index], maxLeaseDays: '' }
this.$set(this.machineList, index, row)
}
},
handleTheoryPowerBlur(index) {
const raw = String(this.machineList[index].theoryPower ?? '')
const pattern = /^\d{1,6}(\.\d{1,4})?$/
if (!raw || Number(raw) <= 0 || !pattern.test(raw)) {
this.$message.warning('理论算力必须大于0')
const row = { ...this.machineList[index], theoryPower: '' }
this.$set(this.machineList, index, row)
}
},
handlePowerDissipationBlur(index) {
const raw = String(this.machineList[index].powerDissipation ?? '')
const pattern = /^\d{1,6}(\.\d{1,4})?$/
if (!raw || Number(raw) <= 0 || !pattern.test(raw)) {
this.$message.warning('功耗必须大于0')
const row = { ...this.machineList[index], powerDissipation: '' }
this.$set(this.machineList, index, row)
}
},
handleTypeCell(index) {
const rowItem = this.machineList && this.machineList[index]
if (!rowItem || this.isRowDisabled(rowItem)) return
const row = { ...this.machineList[index], type: this.machineList[index].type }
this.$set(this.machineList, index, row)
},
handleStateChange(index) {
const rowItem = this.machineList && this.machineList[index]
if (!rowItem || this.isRowDisabled(rowItem)) return
const row = { ...this.machineList[index], state: this.machineList[index].state }
this.$set(this.machineList, index, row)
},
async handleDeleteMachine(row) {
if (!row || !row.id) return
if (this.isRowDisabled(row)) {
this.$message.warning('该矿机已售出,无法删除')
return
}
try {
await this.$confirm('确定删除该矿机吗?删除后不可恢复', '提示', {
confirmButtonText: '删除',
cancelButtonText: '取消',
type: 'warning'
})
const res = await deleteMachine({ id: row.id })
if (res && res.code === 200) {
this.$message.success('删除成功')
this.fetchMachineList({ id: this.productId })
}
} catch (e) {
// 用户取消
}
},
async handleSubmitMachines() {
if (!this.machineList || !this.machineList.length) {
this.$message.warning('没有可提交的数据')
return
}
try {
// 提交前强校验:理论算力、功耗、单价必须填写且格式正确(全部行都校验)
const powerPattern = /^\d{1,6}(\.\d{1,4})?$/
const pricePattern = /^\d{1,12}(\.\d{1,2})?$/
const isOnlySpaces = (v) => typeof v === 'string' && v.trim().length === 0 && v.length > 0
for (let i = 0; i < this.machineList.length; i += 1) {
const row = this.machineList[i]
const rowLabel = row && (row.miner || row.id || i + 1)
const theoryRaw = String(row.theoryPower ?? '')
const priceRaw = String(row._priceEditing ?? '')
const typeRaw = String(row.type ?? '')
const dissRaw = String(row.powerDissipation ?? '')
const daysRaw = String(row.maxLeaseDays ?? '')
if (!theoryRaw || Number(theoryRaw) <= 0 || !powerPattern.test(theoryRaw)) {
this.$message.warning(`${i + 1}行(机器:${rowLabel}) 理论算力必须大于0整数最多6位小数最多4位`)
return
}
if (!dissRaw || Number(dissRaw) <= 0 || !powerPattern.test(dissRaw)) {
this.$message.warning(`${i + 1}行(机器:${rowLabel}) 功耗必须大于0整数最多6位小数最多4位`)
return
}
if (!priceRaw || Number(priceRaw) <= 0 || !pricePattern.test(priceRaw)) {
this.$message.warning(`${i + 1}行(机器:${rowLabel}) 单价必须大于0整数最多12位小数最多2位`)
return
}
if (!/^\d{1,3}$/.test(daysRaw) || !Number.isInteger(Number(daysRaw)) || Number(daysRaw) < 1 || Number(daysRaw) > 365) {
this.$message.warning(`${i + 1}行(机器:${rowLabel}) 最大租赁天数需为 1-365 的整数`)
return
}
// 型号允许为空,但如果填写则不能全空格
if (typeRaw && isOnlySpaces(typeRaw)) {
this.$message.warning(`${i + 1}行(机器:${rowLabel}) 型号不能全是空格`)
return
}
}
const payload = this.machineList.map(m => ({
id: m.id,
powerDissipation: Number(m.powerDissipation ?? 0),
priceList: Array.isArray(m.priceList) ? m.priceList.map(p => ({ ...p, price: Number(p && p.price != null && p.price !== '' ? p.price : 0) })) : [],
state: Number(m.state ?? 0),
theoryPower: Number(m.theoryPower ?? 0),
type: m.type || '',
maxLeaseDays: Number(m.maxLeaseDays ?? 0),
unit: m.unit || ''
}))
// 关闭外层确认弹窗,直接提交
this.confirmVisible = false
console.log(payload, 'payload');
await this.updateMachineList(payload)
} catch (e) {
// 异常处理
}
},
handleBack() {
this.$router.back()
}
}
}
</script>
<style scoped>
.account-product-detail { padding: 8px; }
.header { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.title { margin: 0; font-size: 18px; font-weight: 600; }
.detail-card { margin-bottom: 12px; }
.detail-form { padding: 4px 8px; }
.image-row { display: flex; align-items: center; min-height: 120px; }
.cover { width: 200px; height: 120px; object-fit: cover; border-radius: 4px; background: #f5f5f5; border: 1px solid #eee; }
.placeholder { color: #999; }
.section-title { font-weight: 600; }
.ranges-wrapper { display: grid; gap: 12px; }
.range-block { border: 1px solid #f0f0f0; background: #fcfcfc; border-radius: 6px; padding: 10px; }
.item { color: #444; line-height: 24px; }
.machines-box { margin-top: 8px; border-top: 1px dashed #e5e5e5; padding-top: 8px; }
.machine-row { display: flex; flex-wrap: wrap; gap: 8px; color: #555; line-height: 22px; }
.split { width: 8px; }
.empty-text { color: #909399; text-align: center; padding: 12px 0; }
.label-help { margin-left: 4px; color: #909399; cursor: help; }
/* ::v-deep .el-form-item__content{
margin-left: 52px !important;
} */
</style>
<style>
.el-input-group__append, .el-input-group__prepend{
padding: 0 5px !important;
}
.account-product-detail .el-table .el-input,
.account-product-detail .el-table .el-textarea{
width: 94% !important; /* 仅限制表格内输入宽度,避免影响上面的基础信息区域 */
}
/* 基础信息表单保持满宽,确保“描述”与上方输入左侧对齐 */
.account-product-detail .detail-form .el-input,
.account-product-detail .detail-form .el-textarea{
width: 100% !important;
}
/* 让追加区裁剪内部元素,避免 el-select 下拉箭头溢出到单元格外 */
.el-input-group__append,
.el-input-group__prepend{
overflow: hidden;
}
/* 追加在输入框右侧的下拉(单位/结算币种)细节优化 */
.append-select .el-input__inner{
/* 预留更多箭头空间,避免被右侧裁剪 */
padding-right: 28px;
height: 30px;
line-height: 30px;
}
.append-select .el-select__caret{
right: 10px; /* 箭头往内侧移动,防止被裁切 */
transform: scale(.85); /* 缩小箭头,保证完全显示 */
}
.append-select .el-input__icon{
line-height: 30px; /* 垂直居中,避免上下被裁切 */
}
/* 变化高亮:为输入框外层添加红色边框,视觉醒目但不改变布局 */
.changed-input .el-input__inner,
.changed-input input.el-input__inner,
/* 带有 append 时,同步高亮右侧追加区的边框,保证整体连贯 */
.changed-input .el-input-group__append {
border-color: #f56c6c !important;
}
.el-input.is-disabled .el-input__inner{
color: #000 !important;
}
.el-textarea.is-disabled .el-textarea__inner{
color: #000 !important;
}
</style>