|
|
|
@@ -179,19 +179,30 @@ |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- ==================== 数量 ==================== --> |
|
|
|
<view v-if="canEdit" class="section"> |
|
|
|
<view v-if="canEdit && !configLoading && quantityEnabled" class="section"> |
|
|
|
<view class="section-head"> |
|
|
|
<text class="tool-section-title">生成数量</text> |
|
|
|
<text class="price">{{ unitPoints }}点/张,共{{ totalPoints }}点</text> |
|
|
|
</view> |
|
|
|
<view class="quantity"> |
|
|
|
<view class="quantity-btn" @click="decreaseQuantity">-</view> |
|
|
|
<view class="quantity-btn" :class="{ disabled: quantity <= 1 }" @click="decreaseQuantity">-</view> |
|
|
|
<text class="quantity-value">{{ quantity }}</text> |
|
|
|
<view class="quantity-btn" @click="increaseQuantity">+</view> |
|
|
|
<view class="quantity-btn" :class="{ disabled: quantity >= maxCount }" @click="increaseQuantity">+</view> |
|
|
|
</view> |
|
|
|
<text class="note">按单张收费,一次最多生成{{ maxCount }}张,失败的不扣点</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view v-else-if="canEdit && !configLoading" class="section"> |
|
|
|
<view class="section-head"> |
|
|
|
<text class="tool-section-title">生成数量</text> |
|
|
|
<text class="price">{{ unitPoints }}点/张</text> |
|
|
|
</view> |
|
|
|
<view class="single-quantity"> |
|
|
|
<text>固定 1 张</text> |
|
|
|
</view> |
|
|
|
<text class="note">后台已关闭多张生成,本次只生成1张</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- ==================== 补充描述 ==================== --> |
|
|
|
<view v-if="canEdit" class="section"> |
|
|
|
<view class="section-head"> |
|
|
|
@@ -285,6 +296,7 @@ const activeRatio = ref('') |
|
|
|
const options = reactive({}) |
|
|
|
const quantity = ref(1) |
|
|
|
const maxCount = ref(4) |
|
|
|
const quantityEnabled = ref(true) |
|
|
|
const unitPoints = ref(0) |
|
|
|
const extraPrompt = ref('') |
|
|
|
const localImage = ref('') |
|
|
|
@@ -306,7 +318,8 @@ const hasDemo = computed(() => Boolean(demoPair.value.original && demoPair.value |
|
|
|
const currentStyle = computed(() => styles.value.find((item) => item.key === activeStyle.value) || {}) |
|
|
|
const currentGroups = computed(() => currentStyle.value.groups || []) |
|
|
|
const currentPoints = computed(() => Number(balance.value.points || balance.value.point_balance || 0)) |
|
|
|
const totalPoints = computed(() => unitPoints.value * quantity.value) |
|
|
|
const effectiveQuantity = computed(() => (quantityEnabled.value ? quantity.value : 1)) |
|
|
|
const totalPoints = computed(() => unitPoints.value * effectiveQuantity.value) |
|
|
|
const isPending = computed(() => [10, 20].includes(Number(job.value.status))) |
|
|
|
const canEdit = computed(() => !job.value.photo_open_id || Number(job.value.status) < 0) |
|
|
|
const resultUrls = computed(() => job.value.result_urls || []) |
|
|
|
@@ -359,19 +372,50 @@ watch([activeModel, quantity], () => { |
|
|
|
if (!configLoading.value) loadConfig(true) |
|
|
|
}) |
|
|
|
|
|
|
|
function pickFirstDefined(values) { |
|
|
|
return values.find((value) => value !== undefined && value !== null && value !== '') |
|
|
|
} |
|
|
|
|
|
|
|
function normalizeQuantityEnabled(data = {}) { |
|
|
|
const raw = pickFirstDefined([ |
|
|
|
data.quantity_enabled, |
|
|
|
data.quantity_supported, |
|
|
|
data.product && data.product.quantity_enabled, |
|
|
|
data.billing && data.billing.product && data.billing.product.quantity_enabled, |
|
|
|
data.billing && data.billing.quote && data.billing.quote.product && data.billing.quote.product.quantity_enabled |
|
|
|
]) |
|
|
|
if (raw === undefined) return Number(data.max_count || 1) > 1 |
|
|
|
if (typeof raw === 'boolean') return raw |
|
|
|
return !['0', 'false', 'no', 'off', 'unsupported', 'not_support', '不支持'].includes(String(raw).toLowerCase()) |
|
|
|
} |
|
|
|
|
|
|
|
function applyQuantityConfig(data = {}) { |
|
|
|
const enabled = normalizeQuantityEnabled(data) |
|
|
|
const rawMax = pickFirstDefined([ |
|
|
|
data.max_count, |
|
|
|
data.product && data.product.max_quantity, |
|
|
|
data.billing && data.billing.product && data.billing.product.max_quantity, |
|
|
|
data.billing && data.billing.quote && data.billing.quote.product && data.billing.quote.product.max_quantity |
|
|
|
]) |
|
|
|
const nextMax = enabled ? Math.max(1, Number(rawMax || maxCount.value || 1)) : 1 |
|
|
|
quantityEnabled.value = enabled |
|
|
|
maxCount.value = nextMax |
|
|
|
quantity.value = enabled ? Math.min(Math.max(1, quantity.value), nextMax) : 1 |
|
|
|
} |
|
|
|
|
|
|
|
async function loadConfig(silent = false) { |
|
|
|
try { |
|
|
|
const res = await portraitApi.getConfig({ |
|
|
|
style: activeStyle.value || undefined, |
|
|
|
model: activeModel.value || undefined, |
|
|
|
count: quantity.value |
|
|
|
count: effectiveQuantity.value |
|
|
|
}) |
|
|
|
const data = res.data || {} |
|
|
|
models.value = data.models || [] |
|
|
|
styles.value = data.styles || [] |
|
|
|
ratios.value = data.ratios || [] |
|
|
|
tips.value = data.tips || [] |
|
|
|
maxCount.value = Number(data.max_count || 4) |
|
|
|
applyQuantityConfig(data) |
|
|
|
unitPoints.value = Number(data.unit_points || 0) |
|
|
|
if (!activeModel.value) activeModel.value = data.default_model || (models.value[0] || {}).key || '' |
|
|
|
if (!activeRatio.value) { |
|
|
|
@@ -506,7 +550,7 @@ async function submit() { |
|
|
|
style: activeStyle.value, |
|
|
|
model: activeModel.value, |
|
|
|
ratio: activeRatio.value, |
|
|
|
count: quantity.value, |
|
|
|
count: effectiveQuantity.value, |
|
|
|
extra_prompt: extraPrompt.value, |
|
|
|
request_id: guid(), |
|
|
|
...options |
|
|
|
@@ -640,10 +684,12 @@ function goRecharge() { |
|
|
|
} |
|
|
|
|
|
|
|
function decreaseQuantity() { |
|
|
|
if (!quantityEnabled.value || quantity.value <= 1) return |
|
|
|
quantity.value = Math.max(1, quantity.value - 1) |
|
|
|
} |
|
|
|
|
|
|
|
function increaseQuantity() { |
|
|
|
if (!quantityEnabled.value || quantity.value >= maxCount.value) return |
|
|
|
quantity.value = Math.min(maxCount.value, quantity.value + 1) |
|
|
|
} |
|
|
|
</script> |
|
|
|
@@ -962,7 +1008,23 @@ function increaseQuantity() { |
|
|
|
text-align: center; |
|
|
|
background: #eef7ff; |
|
|
|
} |
|
|
|
.quantity-btn.disabled { |
|
|
|
color: #a8bfd6; |
|
|
|
background: #f3f7fb; |
|
|
|
} |
|
|
|
.quantity-value { min-width: 60rpx; color: #172033; font-size: 32rpx; font-weight: 900; text-align: center; } |
|
|
|
.single-quantity { |
|
|
|
margin-top: 22rpx; |
|
|
|
height: 76rpx; |
|
|
|
padding: 0 26rpx; |
|
|
|
border-radius: 20rpx; |
|
|
|
color: #0b8cff; |
|
|
|
font-size: 28rpx; |
|
|
|
font-weight: 900; |
|
|
|
line-height: 76rpx; |
|
|
|
background: #eef7ff; |
|
|
|
box-sizing: border-box; |
|
|
|
} |
|
|
|
.note { display: block; margin-top: 16rpx; color: #8a95a6; font-size: 22rpx; } |
|
|
|
|
|
|
|
.textarea { |
|
|
|
|