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 @@
+
+
+
+
+
+
+ {{ normalizedProgress }}%
+
+
+
+
+
+ {{ step }}
+
+
+
+
+ 已冻结 {{ cost }} 积分,生成成功后扣除,失败自动退回。
+
+
+
+
+
+
+
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 @@
+
+
+
+ 积分不足
+
+ 本次需 {{ normalizedCost }} 积分,当前仅 {{ normalizedBalance }} 积分,还差 {{ shortage }} 积分。
+
+
+
+
+ 稍后再说
+
+
+ 去充值
+
+
+
+
+
+
+
+
+
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();
};