forked from natuka/web.puabadge.com
修改:前端判断剩余生图次数
This commit is contained in:
1 parent
6dd4b4a724
commit
505c585772
1 file changed
+81
-7
@@ -197,7 +197,15 @@ const caseItems = [
|
|||||||
{ label: config.messages.caseLabels[2], src: config.images.caseScene },
|
{ label: config.messages.caseLabels[2], src: config.images.caseScene },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剩余次数:
|
||||||
|
* - 首屏用接口 remain_count 打底
|
||||||
|
* - 之后只按「本地点成功出图」递减
|
||||||
|
* - 接口若未扣减(仍返回原值),不会把次数加回去
|
||||||
|
*/
|
||||||
const remainCount = ref(0)
|
const remainCount = ref(0)
|
||||||
|
/** 打底时已统计到的成功次数;新增成功 = 当前成功数 - baselineUsed */
|
||||||
|
const remainBaselineUsed = ref(0)
|
||||||
const sessionId = ref('')
|
const sessionId = ref('')
|
||||||
const subjectName = ref('')
|
const subjectName = ref('')
|
||||||
/** stat 返回的主体文案(订单约定主体,标签始终展示此值) */
|
/** stat 返回的主体文案(订单约定主体,标签始终展示此值) */
|
||||||
@@ -270,6 +278,64 @@ const isEditing = computed(() => !!editingResultId.value)
|
|||||||
const isPendingCartoon = computed(
|
const isPendingCartoon = computed(
|
||||||
() => Boolean(pendingPreview.value && photoInspect.value && isCartoonImage(photoInspect.value)),
|
() => Boolean(pendingPreview.value && photoInspect.value && isCartoonImage(photoInspect.value)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/** 统计已消耗的生图次数:成功 task + 对话里已出的结果卡 */
|
||||||
|
function countUsedGenerations() {
|
||||||
|
const ids = new Set<string>()
|
||||||
|
const detail = sessionDetail.value as { tasks?: Array<Record<string, any>> } | null
|
||||||
|
detail?.tasks?.forEach((task) => {
|
||||||
|
const taskId = String(task?.task_id || '').trim()
|
||||||
|
if (!taskId) return
|
||||||
|
const images = Array.isArray(task.images) ? task.images : []
|
||||||
|
const hasImage = images.some((image: any) => Boolean(image?.url))
|
||||||
|
const status = String(task.status || '').toLowerCase()
|
||||||
|
if (status === 'success' || hasImage) ids.add(`task:${taskId}`)
|
||||||
|
})
|
||||||
|
messages.value.forEach((msg) => {
|
||||||
|
if (msg.type !== 'result') return
|
||||||
|
const taskId = String(msg.taskId || '').trim()
|
||||||
|
// 与 task 去重;无 taskId 的本地结果用消息 id
|
||||||
|
ids.add(taskId ? `task:${taskId}` : `msg:${msg.id}`)
|
||||||
|
})
|
||||||
|
return ids.size
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首屏打底:接口 remain_count 在京东侧常不随出图减少,这里当作可生图总额,
|
||||||
|
* 再按会话内已成功次数扣除;后续只减不增。
|
||||||
|
*/
|
||||||
|
function seedRemainFromApi(apiRemainRaw?: unknown) {
|
||||||
|
const apiRemain = Number(apiRemainRaw)
|
||||||
|
remainBaselineUsed.value = 0
|
||||||
|
remainCount.value = Number.isFinite(apiRemain) ? Math.max(0, apiRemain) : 0
|
||||||
|
refreshRemainByUsed()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 按已成功出图数重算剩余(只减不加) */
|
||||||
|
function refreshRemainByUsed(apiRemainRaw?: unknown) {
|
||||||
|
const used = countUsedGenerations()
|
||||||
|
const earned = Math.max(0, used - remainBaselineUsed.value)
|
||||||
|
remainCount.value = Math.max(0, remainCount.value - earned)
|
||||||
|
remainBaselineUsed.value = used
|
||||||
|
|
||||||
|
const apiRemain = Number(apiRemainRaw)
|
||||||
|
if (!Number.isFinite(apiRemain)) return
|
||||||
|
// 接口若已扣得更少,跟随接口;偏高(未扣)则忽略,避免加回次数
|
||||||
|
if (apiRemain < remainCount.value) {
|
||||||
|
remainCount.value = Math.max(0, apiRemain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生图接口成功即扣 1 次(不等待过渡动画),并抬高 baseline 避免结果入列后重复扣 */
|
||||||
|
function noteGenerationSuccess() {
|
||||||
|
remainCount.value = Math.max(0, remainCount.value - 1)
|
||||||
|
remainBaselineUsed.value += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetRemainQuota() {
|
||||||
|
remainCount.value = 0
|
||||||
|
remainBaselineUsed.value = 0
|
||||||
|
}
|
||||||
const titleSpec = computed(() => productTitleSpecFromOrder(orderStat.value))
|
const titleSpec = computed(() => productTitleSpecFromOrder(orderStat.value))
|
||||||
const hasRequiredTitle = computed(() => {
|
const hasRequiredTitle = computed(() => {
|
||||||
if (!titleSpec.value) return true
|
if (!titleSpec.value) return true
|
||||||
@@ -655,17 +721,17 @@ function onGenerateStageDone(generatingId: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pending.uploadId) lastUploadId.value = pending.uploadId
|
if (pending.uploadId) lastUploadId.value = pending.uploadId
|
||||||
remainCount.value = Math.max(0, remainCount.value - 1)
|
// 成功扣次已在 noteGenerationSuccess;这里只把 baseline 与结果卡对齐
|
||||||
|
remainBaselineUsed.value = Math.max(remainBaselineUsed.value, countUsedGenerations())
|
||||||
isBusy.value = false
|
isBusy.value = false
|
||||||
photoInspect.value = null
|
photoInspect.value = null
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
// 仅同步剩余次数,避免整页历史重绘冲掉当前气泡
|
// 仅同步剩余次数;接口未扣减时不会把次数加回去
|
||||||
void badgeApi
|
void badgeApi
|
||||||
.getOrderStat({})
|
.getOrderStat({})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
const count = Number(res?.remain_count)
|
|
||||||
if (Number.isFinite(count)) remainCount.value = Math.max(0, count)
|
|
||||||
orderStat.value = res || orderStat.value
|
orderStat.value = res || orderStat.value
|
||||||
|
refreshRemainByUsed(res?.remain_count)
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
}
|
}
|
||||||
@@ -797,6 +863,8 @@ async function startGenerate(opts: {
|
|||||||
startedAt,
|
startedAt,
|
||||||
}
|
}
|
||||||
patchGeneratingResult(generatingId, resultUrl)
|
patchGeneratingResult(generatingId, resultUrl)
|
||||||
|
// 接口已成功出图:立刻扣剩余次数(不依赖过渡动画是否播完)
|
||||||
|
noteGenerationSuccess()
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
removeGenerating(generatingId)
|
removeGenerating(generatingId)
|
||||||
@@ -942,6 +1010,8 @@ function applySessionHistory(detail: ReturnType<typeof jingdongApi.parseSessionD
|
|||||||
})
|
})
|
||||||
messages.value = next
|
messages.value = next
|
||||||
if (latestUpload) lastUploadId.value = latestUpload
|
if (latestUpload) lastUploadId.value = latestUpload
|
||||||
|
// 历史回填后:用接口总额 - 已成功次数
|
||||||
|
seedRemainFromApi(orderStat.value?.remain_count)
|
||||||
scrollToBottom()
|
scrollToBottom()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -949,6 +1019,7 @@ function fetchSessionDetail(sid: string) {
|
|||||||
const id = String(sid || '').trim()
|
const id = String(sid || '').trim()
|
||||||
if (!id) {
|
if (!id) {
|
||||||
sessionDetail.value = null
|
sessionDetail.value = null
|
||||||
|
seedRemainFromApi(orderStat.value?.remain_count)
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
return jingdongApi
|
return jingdongApi
|
||||||
@@ -965,6 +1036,7 @@ function fetchSessionDetail(sid: string) {
|
|||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
sessionDetail.value = null
|
sessionDetail.value = null
|
||||||
|
seedRemainFromApi(orderStat.value?.remain_count)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -974,19 +1046,21 @@ function fetchOrderStat() {
|
|||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
// interceptor 已解包 data:remain_count / subject_name / type_name / session_id / prod_id ...
|
// interceptor 已解包 data:remain_count / subject_name / type_name / session_id / prod_id ...
|
||||||
orderStat.value = res || {}
|
orderStat.value = res || {}
|
||||||
const count = Number(res?.remain_count)
|
|
||||||
remainCount.value = Number.isFinite(count) ? Math.max(0, count) : 0
|
|
||||||
subjectNameFromStat.value = String(res?.subject_name || '').trim()
|
subjectNameFromStat.value = String(res?.subject_name || '').trim()
|
||||||
subjectName.value = subjectNameFromStat.value
|
subjectName.value = subjectNameFromStat.value
|
||||||
styleName.value = String(res?.style_name || '').trim()
|
styleName.value = String(res?.style_name || '').trim()
|
||||||
typeName.value = String(res?.type_name || '').trim()
|
typeName.value = String(res?.type_name || '').trim()
|
||||||
sessionId.value = String(res?.session_id || '').trim()
|
sessionId.value = String(res?.session_id || '').trim()
|
||||||
subjectMatched.value = true
|
subjectMatched.value = true
|
||||||
|
// 先记下接口值;等会话历史回来后再按已生成次数扣除
|
||||||
|
const apiRemain = Number(res?.remain_count)
|
||||||
|
remainCount.value = Number.isFinite(apiRemain) ? Math.max(0, apiRemain) : 0
|
||||||
|
remainBaselineUsed.value = 0
|
||||||
return fetchSessionDetail(sessionId.value)
|
return fetchSessionDetail(sessionId.value)
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
orderStat.value = null
|
orderStat.value = null
|
||||||
remainCount.value = 0
|
resetRemainQuota()
|
||||||
subjectName.value = ''
|
subjectName.value = ''
|
||||||
subjectNameFromStat.value = ''
|
subjectNameFromStat.value = ''
|
||||||
styleName.value = ''
|
styleName.value = ''
|
||||||
|
|||||||
Reference in new issue
Block a user