From 190793b156c0d9d51ff6d81ddc968ae13a6270ec Mon Sep 17 00:00:00 2001 From: duanshuwen Date: Sun, 5 Jul 2026 21:50:49 +0800 Subject: [PATCH] feat(useTemplate): add point insufficient dialog and progress panel Create PointInsufficientDialog component to notify users of insufficient points before generation. Add GeneratingProgressPanel to display generation progress, steps and cost freeze info. Integrate point balance validation into the generate workflow and update the main page to handle generating state. --- .../GeneratingProgressPanel/index.vue | 56 ++++++++++++ .../GeneratingProgressPanel/styles/index.scss | 87 +++++++++++++++++++ .../PointInsufficientDialog/index.vue | 65 ++++++++++++++ .../PointInsufficientDialog/styles/index.scss | 70 +++++++++++++++ src/pages-aigc/useTemplate/useTemplate.vue | 34 +++++++- 5 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 src/pages-aigc/useTemplate/components/GeneratingProgressPanel/index.vue create mode 100644 src/pages-aigc/useTemplate/components/GeneratingProgressPanel/styles/index.scss create mode 100644 src/pages-aigc/useTemplate/components/PointInsufficientDialog/index.vue create mode 100644 src/pages-aigc/useTemplate/components/PointInsufficientDialog/styles/index.scss diff --git a/src/pages-aigc/useTemplate/components/GeneratingProgressPanel/index.vue b/src/pages-aigc/useTemplate/components/GeneratingProgressPanel/index.vue new file mode 100644 index 0000000..6d352c4 --- /dev/null +++ b/src/pages-aigc/useTemplate/components/GeneratingProgressPanel/index.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/src/pages-aigc/useTemplate/components/GeneratingProgressPanel/styles/index.scss b/src/pages-aigc/useTemplate/components/GeneratingProgressPanel/styles/index.scss new file mode 100644 index 0000000..9911007 --- /dev/null +++ b/src/pages-aigc/useTemplate/components/GeneratingProgressPanel/styles/index.scss @@ -0,0 +1,87 @@ +.generating-progress-panel { + margin-top: 20px; +} + +.generating-progress-row { + height: 18px; + display: grid; + grid-template-columns: minmax(0, 1fr) 34px; + align-items: center; + gap: 10px; +} + +.generating-progress-track { + width: 100%; + height: 12px; + overflow: hidden; + border-radius: 999px; + background: rgba(255, 255, 255, 0.78); +} + +.generating-progress-fill { + height: 100%; + min-width: 24px; + border-radius: 999px; + background: linear-gradient(90deg, #20cf75 0%, #f2d646 100%); +} + +.generating-progress-text { + color: #061e34; + font-size: 15px; + line-height: 18px; + font-weight: 900; + text-align: right; + white-space: nowrap; +} + +.generating-step-list { + display: flex; + flex-direction: column; + gap: 10px; + margin-top: 16px; +} + +.generating-step-item { + height: 40px; + display: flex; + align-items: center; + gap: 10px; + padding: 0 12px; + border-radius: 14px; + background: rgba(255, 255, 255, 0.72); + box-sizing: border-box; +} + +.generating-step-dot { + flex: 0 0 18px; + width: 18px; + height: 18px; + border: 2px solid #d6e8f4; + border-radius: 50%; + background: rgba(255, 255, 255, 0.7); + box-sizing: border-box; +} + +.generating-step-label { + min-width: 0; + overflow: hidden; + color: #6c7e96; + font-size: 13px; + line-height: 18px; + font-weight: 900; + text-overflow: ellipsis; + white-space: nowrap; +} + +.generating-freeze-text { + display: block; + overflow: hidden; + margin: 18px 14px 0; + color: #7b8da4; + font-size: 12px; + line-height: 18px; + font-weight: 800; + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/src/pages-aigc/useTemplate/components/PointInsufficientDialog/index.vue b/src/pages-aigc/useTemplate/components/PointInsufficientDialog/index.vue new file mode 100644 index 0000000..7918103 --- /dev/null +++ b/src/pages-aigc/useTemplate/components/PointInsufficientDialog/index.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/src/pages-aigc/useTemplate/components/PointInsufficientDialog/styles/index.scss b/src/pages-aigc/useTemplate/components/PointInsufficientDialog/styles/index.scss new file mode 100644 index 0000000..5217bfd --- /dev/null +++ b/src/pages-aigc/useTemplate/components/PointInsufficientDialog/styles/index.scss @@ -0,0 +1,70 @@ +.point-dialog { + width: 318px; + max-width: calc(100vw - 56px); + min-height: 220px; + padding: 29px 24px 22px; + border: 1px solid rgba(20, 143, 255, 0.8); + border-radius: 20px; + background: #dceeff; + box-shadow: 0 18px 38px rgba(8, 28, 44, 0.22); + box-sizing: border-box; +} + +.point-dialog-title { + display: block; + color: #102942; + font-size: 22px; + line-height: 29px; + font-weight: 900; + text-align: center; +} + +.point-dialog-desc { + display: block; + overflow: hidden; + margin: 15px auto 0; + max-width: 228px; + color: #506985; + font-size: 14px; + line-height: 22px; + font-weight: 800; + text-align: center; +} + +.point-dialog-actions { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 18px; + margin-top: 28px; +} + +.point-dialog-button { + min-width: 0; + height: 54px; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + border-radius: 999px; + font-size: 16px; + line-height: 22px; + font-weight: 900; + text-overflow: ellipsis; + white-space: nowrap; + box-sizing: border-box; +} + +.point-dialog-button.is-cancel { + border: 1px solid rgba(124, 168, 207, 0.28); + background: rgba(255, 255, 255, 0.14); + color: #102942; +} + +.point-dialog-button.is-primary { + background: #061e34; + color: #ffffff; +} + +.point-dialog-button.is-pressed { + opacity: 0.86; +} diff --git a/src/pages-aigc/useTemplate/useTemplate.vue b/src/pages-aigc/useTemplate/useTemplate.vue index 6b4b6d5..c83a3b5 100644 --- a/src/pages-aigc/useTemplate/useTemplate.vue +++ b/src/pages-aigc/useTemplate/useTemplate.vue @@ -19,6 +19,11 @@ @generate="handleGenerate" @recharge="handleRecharge" /> + @@ -67,9 +79,11 @@ import AigcTopBar from "@/pages-aigc/components/AigcTopBar/index.vue"; import { aigcTemplates } from "@/pages-aigc/home/data/templates.js"; import guideAvatar from "./assets/xiaoqi-avatar.png"; import GenerateConfirmPanel from "./components/GenerateConfirmPanel/index.vue"; +import GeneratingProgressPanel from "./components/GeneratingProgressPanel/index.vue"; import PhotoConfirmDrawer from "./components/PhotoConfirmDrawer/index.vue"; import PhotoGuidePanel from "./components/PhotoGuidePanel/index.vue"; import PhotoPickDrawer from "./components/PhotoPickDrawer/index.vue"; +import PointInsufficientDialog from "./components/PointInsufficientDialog/index.vue"; import TemplateVersionHero from "./components/TemplateVersionHero/index.vue"; import VersionOptionList from "./components/VersionOptionList/index.vue"; import { negativeExamples, positiveExamples } from "./data/photoGuideExamples.js"; @@ -79,6 +93,7 @@ const pointBalance = ref(300); const templateId = ref(""); const selectedVersion = ref("image"); const currentStep = ref("version"); +const pointDialogVisible = ref(false); const currentTemplate = computed(() => { return aigcTemplates.find((item) => item.id === templateId.value) || aigcTemplates[0] || {}; @@ -150,7 +165,24 @@ const handleConfirmPhoto = () => { }; const handleGenerate = () => { - showPlaceholderToast("开始生成"); + const cost = Number(currentVersion.value.cost) || 0; + const balance = Number(pointBalance.value) || 0; + + if (balance < cost) { + pointDialogVisible.value = true; + return; + } + + currentStep.value = "generating"; +}; + +const handleClosePointDialog = () => { + pointDialogVisible.value = false; +}; + +const handlePointRecharge = () => { + pointDialogVisible.value = false; + handleRecharge(); };