Compare commits
3 Commits
93dd4f388f
...
9f0881a284
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f0881a284 | ||
|
|
57f6cdd85e | ||
|
|
06afbcc5c1 |
84
docs/superpowers/plans/2026-08-05-aigc-upgrade-image.md
Normal file
84
docs/superpowers/plans/2026-08-05-aigc-upgrade-image.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# AIGC Upgrade Image Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Show the already generated source image in the `useTemplate` upgrade flow while preserving the selected template copy.
|
||||
|
||||
**Architecture:** Keep `upgradeTaskId` as the navigation contract. In `useTemplate.vue`, load the source generator task detail only for upgrade flows, then overlay its `imageResultUrl` onto the selected template as `templateContentUrl`. `TemplateVersionHero` remains unchanged because it already renders `templateContentUrl`.
|
||||
|
||||
**Tech Stack:** Vue 3 `<script setup>`, uni-app lifecycle/API wrappers, Node.js built-in test runner.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add a failing regression assertion
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/aigc-detail-continuation.test.cjs`
|
||||
|
||||
- [ ] **Step 1: Add the upgrade-source-image test**
|
||||
|
||||
Append a test that reads `src/pages-aigc/useTemplate/useTemplate.vue` and asserts that the page imports `getAigcGeneratorTaskDetail`, calls it with `{ taskId: upgradeTaskId.value }`, and assigns `imageResultUrl` to `templateContentUrl` inside the `currentTemplate` computed value.
|
||||
|
||||
- [ ] **Step 2: Run the focused test and verify RED**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test tests/aigc-detail-continuation.test.cjs
|
||||
```
|
||||
|
||||
Expected: the existing tests pass and the new source-image test fails because `useTemplate.vue` does not yet load the source task detail or overlay `imageResultUrl`.
|
||||
|
||||
### Task 2: Load and display the generated source image
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/pages-aigc/useTemplate/useTemplate.vue:46-107,116-184`
|
||||
|
||||
- [ ] **Step 1: Add source task state and API import**
|
||||
|
||||
Import `getAigcGeneratorTaskDetail` from the existing AIGC API module and add `const upgradeSourceTaskDetail = ref(null);` beside the existing upgrade state.
|
||||
|
||||
- [ ] **Step 2: Overlay the source image in `currentTemplate`**
|
||||
|
||||
Keep the existing template lookup as the base value. When `isImageToVideoUpgrade.value` is true and `upgradeSourceTaskDetail.value.imageResultUrl` is non-empty, return a shallow copy with `templateContentUrl` set to that URL; otherwise return the base template unchanged.
|
||||
|
||||
Use this shape:
|
||||
|
||||
```js
|
||||
const currentTemplate = computed(() => {
|
||||
const template =
|
||||
templates.value.find((item) => item.templateId === templateId.value) || templates.value[0] || {};
|
||||
const imageResultUrl = String(upgradeSourceTaskDetail.value?.imageResultUrl || "").trim();
|
||||
|
||||
if (!isImageToVideoUpgrade.value || !imageResultUrl) return template;
|
||||
return { ...template, templateContentUrl: imageResultUrl };
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Fetch the source task detail only for upgrade flows**
|
||||
|
||||
Add `fetchUpgradeSourceTaskDetail` after `fetchImageToVideoItemDetail`. Return immediately for non-upgrade flows. For an upgrade, call `getAigcGeneratorTaskDetail({ taskId: upgradeTaskId.value })`; on a valid object response assign `upgradeSourceTaskDetail.value`, otherwise show `获取原图片失败`. Catch the request error, log a warning, and show the same toast. Call it from `fetchPageData` after `fetchTemplateList` and before the existing item-list request.
|
||||
|
||||
- [ ] **Step 4: Run the focused test and verify GREEN**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
node --test tests/aigc-detail-continuation.test.cjs
|
||||
```
|
||||
|
||||
Expected: all tests pass with zero failures.
|
||||
|
||||
### Task 3: Check the final diff
|
||||
|
||||
**Files:**
|
||||
- Verify: `src/pages-aigc/useTemplate/useTemplate.vue`
|
||||
- Verify: `tests/aigc-detail-continuation.test.cjs`
|
||||
|
||||
- [ ] **Step 1: Run whitespace validation**
|
||||
|
||||
Run `git diff --check` and expect exit code 0.
|
||||
|
||||
- [ ] **Step 2: Confirm scope**
|
||||
|
||||
Run `git status --short` and confirm only the intended source/test changes remain uncommitted; preserve the user’s pre-existing `detail.vue` and `AigcApi.js` work without rewriting it.
|
||||
@@ -0,0 +1,24 @@
|
||||
# AIGC 图片升级视频页展示原图设计
|
||||
|
||||
## 目标
|
||||
|
||||
从图片生成结果详情页点击“升级为动效视频”后,进入 `useTemplate` 页面时,顶部展示原任务已生成的图片,让用户明确当前要升级的视频来源。
|
||||
|
||||
## 方案
|
||||
|
||||
详情页继续只传递 `upgradeTaskId`、模板 ID 和生成项 ID。`useTemplate` 页面在检测到升级流程后,使用 `upgradeTaskId` 请求原任务详情,读取 `imageResultUrl`,并在 `currentTemplate` 的计算结果上覆盖 `templateContentUrl`。模板标题、标签和副标题保持模板列表返回值,避免改变现有文案语义。
|
||||
|
||||
`TemplateVersionHero` 无需改动:它已经优先读取 `templateContentUrl` 作为媒体地址,图片地址不会匹配视频扩展名,因此会按图片渲染。
|
||||
|
||||
## 数据流
|
||||
|
||||
1. `detail.vue` 通过 `upgradeTaskId` 跳转到 `useTemplate`。
|
||||
2. `useTemplate.vue` 并行/顺序加载模板列表、升级生成项详情和原任务详情。
|
||||
3. 原任务详情成功且存在 `imageResultUrl` 时,`currentTemplate` 返回基础模板字段加 `templateContentUrl: imageResultUrl`。
|
||||
4. 原任务详情缺失或请求失败时,保留模板默认图片,并提示用户图片信息加载失败;升级创建流程仍按现有费用和任务参数校验执行。
|
||||
|
||||
## 验证
|
||||
|
||||
- 增加静态回归测试,确认升级流程请求原任务详情,并将 `imageResultUrl` 覆盖到 `currentTemplate` 的 `templateContentUrl`。
|
||||
- 运行现有 AIGC continuation 测试和新增回归测试。
|
||||
- 运行 `git diff --check`;不运行项目生产构建或微信小程序开发命令。
|
||||
@@ -3,20 +3,22 @@
|
||||
<AigcTopBar :points="pointBalance" @back="handleBack" @history="handleOpenRecords" @recharge="handleRecharge" />
|
||||
|
||||
<view class="aigc-detail-content">
|
||||
<template v-if="taskDetail">
|
||||
<ResultPreview v-if="result.cover" class="aigc-detail-preview" :result="result" />
|
||||
<view class="aigc-detail-controls">
|
||||
<ResultMeta :items="metaItems" />
|
||||
<ResultActions :saving="isSaving" :media-type="result.mediaType" :share-ready="Boolean(shareKey)"
|
||||
:share-preparing="isPreparingShare" @save="handleSave" @prepare-share="handlePrepareShare" />
|
||||
|
||||
<view class="aigc-detail-text-actions">
|
||||
<view class="aigc-detail-text-action" @tap="handleRegenerate">再生成一版</view>
|
||||
<view class="aigc-detail-text-action" @tap="handleChangeTemplate">换个模板</view>
|
||||
<view class="aigc-detail-text-action" @tap="handleOpenRecords">历史记录</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-if="taskDetail">
|
||||
<ResultPreview v-if="result.cover" class="aigc-detail-preview" :result="result" />
|
||||
<view class="aigc-detail-controls">
|
||||
<!-- <ResultMeta :items="metaItems" /> -->
|
||||
<ContinuationCard v-if="result.mediaType === 'image'" :info="continuationInfo"
|
||||
@upgrade="handleUpgradeToVideo" />
|
||||
<ResultActions :saving="isSaving" :media-type="result.mediaType" :share-ready="Boolean(shareKey)"
|
||||
:share-preparing="isPreparingShare" @save="handleSave" @prepare-share="handlePrepareShare" />
|
||||
|
||||
<view class="aigc-detail-text-actions">
|
||||
<view class="aigc-detail-text-action" @tap="handleRegenerate">再生成一版</view>
|
||||
<view class="aigc-detail-text-action" @tap="handleChangeTemplate">换个模板</view>
|
||||
<view class="aigc-detail-text-action" @tap="handleOpenRecords">历史记录</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<Privacy :visible="privacyVisible" :contract-name="privacyContractName" @agree="handlePrivacyAgree"
|
||||
@@ -39,11 +41,11 @@ import {
|
||||
createAigcGeneratorTask,
|
||||
createAigcGeneratorTaskShare,
|
||||
getAigcGeneratorTaskDetail,
|
||||
} from "@/pages-aigc/request/AigcApi.js";
|
||||
} from "@/pages-aigc/request/AigcApi.js";
|
||||
import PointInsufficientDialog from "@/pages-aigc/useTemplate/components/PointInsufficientDialog/index.vue";
|
||||
import ContinuationCard from "./components/ContinuationCard/index.vue";
|
||||
import RegenerateConfirmPopup from "./components/RegenerateConfirmPopup/index.vue";
|
||||
import ResultActions from "./components/ResultActions/index.vue";
|
||||
import ResultMeta from "./components/ResultMeta/index.vue";
|
||||
import ResultPreview from "./components/ResultPreview/index.vue";
|
||||
|
||||
const { pointBalance, fetchCurrentCredit } = useCurrentCredit();
|
||||
@@ -57,6 +59,7 @@ const privacyContractName = ref("隐私保护指引");
|
||||
const pendingSaveAfterPrivacy = ref(false);
|
||||
const regeneratePopupRef = ref(null);
|
||||
const isRegenerating = ref(false);
|
||||
const isUpgradingToVideo = ref(false);
|
||||
const pointDialogVisible = ref(false);
|
||||
|
||||
const GENERATOR_TYPE_TEXT = {
|
||||
@@ -89,7 +92,7 @@ const result = computed(() => {
|
||||
|
||||
const imageUrl = record.imageResultUrl || "";
|
||||
const videoUrl = record.videoResultUrl || "";
|
||||
const isVideo = Number(record.generatorType) === 1;
|
||||
const isVideo = [1, 2].includes(Number(record.generatorType));
|
||||
const typeText = getMappedText(GENERATOR_TYPE_TEXT, record.generatorType, "类型");
|
||||
const statusText = getMappedText(TASK_STATUS_TEXT, record.taskStatus, "状态");
|
||||
const consumedText =
|
||||
@@ -138,6 +141,12 @@ const metaItems = computed(() => {
|
||||
|
||||
const sharePreviewImage = computed(() => taskDetail.value?.imageResultUrl || "");
|
||||
const regenerateCost = computed(() => Math.max(0, Number(taskDetail.value?.generatorCost) || 0));
|
||||
const continuationInfo = {
|
||||
title: "创意续作",
|
||||
desc: "让这张图动起来 · 5秒内动效视频",
|
||||
cost: "追加消耗 650积分",
|
||||
buttonText: "升级为动效视频",
|
||||
};
|
||||
|
||||
const showPlaceholderToast = (title) => {
|
||||
uni.showToast({
|
||||
@@ -182,6 +191,7 @@ onLoad((query = {}) => {
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
isUpgradingToVideo.value = false;
|
||||
fetchCurrentCredit();
|
||||
});
|
||||
|
||||
@@ -249,6 +259,35 @@ const handleRecharge = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpgradeToVideo = () => {
|
||||
if (isUpgradingToVideo.value || result.value.mediaType !== "image") return;
|
||||
|
||||
const sourceTaskId = String(taskDetail.value?.taskId || taskId.value || "").trim();
|
||||
if (!sourceTaskId) {
|
||||
showPlaceholderToast("缺少任务ID");
|
||||
return;
|
||||
}
|
||||
|
||||
const templateId = String(taskDetail.value?.templateId || "").trim();
|
||||
const templateItemId = String(taskDetail.value?.templateItemId || "").trim();
|
||||
const query = [
|
||||
templateId && `templateId=${encodeURIComponent(templateId)}`,
|
||||
`upgradeTaskId=${encodeURIComponent(sourceTaskId)}`,
|
||||
templateItemId && `upgradeTemplateItemId=${encodeURIComponent(templateItemId)}`,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("&");
|
||||
|
||||
isUpgradingToVideo.value = true;
|
||||
uni.navigateTo({
|
||||
url: `/pages-aigc/useTemplate/useTemplate?${query}`,
|
||||
fail: () => {
|
||||
isUpgradingToVideo.value = false;
|
||||
showPlaceholderToast("打开图片生成页面失败");
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getMediaFileExtension = (url, mediaType) => {
|
||||
const pathname = String(url || "").split(/[?#]/)[0];
|
||||
const matchedExtension = pathname.match(/\.([a-z0-9]{2,5})$/i)?.[1]?.toLowerCase();
|
||||
@@ -372,7 +411,7 @@ const removeDownloadedMedia = (filePath, shouldCleanup) => {
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.getFileSystemManager().unlink({
|
||||
filePath,
|
||||
fail: () => {},
|
||||
fail: () => { },
|
||||
});
|
||||
// #endif
|
||||
};
|
||||
|
||||
@@ -30,6 +30,21 @@ function createAigcGeneratorTask(args) {
|
||||
);
|
||||
}
|
||||
|
||||
function createAigcImageToVideoTask(args) {
|
||||
return request.post(
|
||||
"/hotelBiz/aigcGeneratorTask/createAigcImageToVideoTask",
|
||||
args,
|
||||
{ sensitive: true },
|
||||
);
|
||||
}
|
||||
|
||||
function getAigcImageToVideoItemDetail(args) {
|
||||
return request.post(
|
||||
"/hotelBiz/aigcGeneratorTask/aigcImageToVideoItemDetail",
|
||||
args,
|
||||
);
|
||||
}
|
||||
|
||||
function getCurrentCredit() {
|
||||
return request.get("/hotelBiz/credit/current", {});
|
||||
}
|
||||
@@ -62,6 +77,8 @@ export {
|
||||
getAigcGeneratorTaskList,
|
||||
getAigcGeneratorTaskDetail,
|
||||
createAigcGeneratorTask,
|
||||
createAigcImageToVideoTask,
|
||||
getAigcImageToVideoItemDetail,
|
||||
getCurrentCredit,
|
||||
getCreditLedgerPage,
|
||||
getPointsTopUpAgreement,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.template-version-hero {
|
||||
position: relative;
|
||||
height: 360px;
|
||||
height: 380px;
|
||||
overflow: hidden;
|
||||
border-radius: 24px;
|
||||
background: var(--template-accent, #0a4d46);
|
||||
|
||||
@@ -46,11 +46,14 @@ import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import Privacy from "@/components/Privacy/index.vue";
|
||||
import AigcTopBar from "@/pages-aigc/components/AigcTopBar/index.vue";
|
||||
import { useCurrentCredit } from "@/pages-aigc/hooks/useCurrentCredit.js";
|
||||
import { getWechatLoginCode } from "@/pages-aigc/services/wechatLogin.js";
|
||||
import {
|
||||
createAigcGeneratorTask,
|
||||
getAigcTemplateItemList,
|
||||
getAigcTemplateList,
|
||||
import { getWechatLoginCode } from "@/pages-aigc/services/wechatLogin.js";
|
||||
import {
|
||||
createAigcImageToVideoTask,
|
||||
createAigcGeneratorTask,
|
||||
getAigcImageToVideoItemDetail,
|
||||
getAigcGeneratorTaskDetail,
|
||||
getAigcTemplateItemList,
|
||||
getAigcTemplateList,
|
||||
} from "@/pages-aigc/request/AigcApi.js";
|
||||
import { updateImageFile } from "@/request/api/UpdateFile.js";
|
||||
import GenerateConfirmPanel from "./components/GenerateConfirmPanel/index.vue";
|
||||
@@ -72,14 +75,27 @@ const uploadedImageUrl = ref("");
|
||||
const currentStep = ref("version");
|
||||
const pointDialogVisible = ref(false);
|
||||
const isUploading = ref(false);
|
||||
const isCreatingTask = ref(false);
|
||||
const privacyVisible = ref(false);
|
||||
const privacyContractName = ref("隐私保护指引");
|
||||
const pendingImageSourceType = ref("");
|
||||
const isCreatingTask = ref(false);
|
||||
const privacyVisible = ref(false);
|
||||
const privacyContractName = ref("隐私保护指引");
|
||||
const pendingImageSourceType = ref("");
|
||||
const upgradeTaskId = ref("");
|
||||
const upgradeTemplateItemId = ref("");
|
||||
const imageToVideoItemDetail = ref(null);
|
||||
const upgradeSourceTaskDetail = ref(null);
|
||||
|
||||
const isImageToVideoUpgrade = computed(() => Boolean(upgradeTaskId.value));
|
||||
const IMAGE_GENERATION_COST = 350;
|
||||
const VIDEO_GENERATION_COST = 1000;
|
||||
|
||||
const currentTemplate = computed(() => {
|
||||
return templates.value.find((item) => item.templateId === templateId.value) || templates.value[0] || {};
|
||||
});
|
||||
const currentTemplate = computed(() => {
|
||||
const template =
|
||||
templates.value.find((item) => item.templateId === templateId.value) || templates.value[0] || {};
|
||||
const imageResultUrl = String(upgradeSourceTaskDetail.value?.imageResultUrl || "").trim();
|
||||
|
||||
if (!isImageToVideoUpgrade.value || !imageResultUrl) return template;
|
||||
return { ...template, templateContentUrl: imageResultUrl };
|
||||
});
|
||||
|
||||
const currentTemplateItem = computed(() => {
|
||||
return (
|
||||
@@ -89,16 +105,54 @@ const currentTemplateItem = computed(() => {
|
||||
);
|
||||
});
|
||||
|
||||
const currentCost = computed(() => {
|
||||
return Number(currentTemplateItem.value.generatorCost) || 0;
|
||||
});
|
||||
const currentCost = computed(() => {
|
||||
return isImageToVideoUpgrade.value
|
||||
? Number(imageToVideoItemDetail.value?.generatorCost) || 0
|
||||
: Number(currentTemplateItem.value.generatorType) === 1
|
||||
? VIDEO_GENERATION_COST
|
||||
: IMAGE_GENERATION_COST;
|
||||
});
|
||||
|
||||
const showPlaceholderToast = (title) => {
|
||||
const showPlaceholderToast = (title) => {
|
||||
uni.showToast({
|
||||
title,
|
||||
icon: "none",
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const fetchImageToVideoItemDetail = async () => {
|
||||
if (!isImageToVideoUpgrade.value) return;
|
||||
|
||||
try {
|
||||
const res = await getAigcImageToVideoItemDetail({ taskId: upgradeTaskId.value });
|
||||
if (res?.code === 0 && res.data && typeof res.data === "object" && !Array.isArray(res.data)) {
|
||||
imageToVideoItemDetail.value = res.data;
|
||||
return;
|
||||
}
|
||||
|
||||
showPlaceholderToast(res?.msg || "获取升级视频费用失败");
|
||||
} catch (error) {
|
||||
console.warn("获取AIGC图片升级视频生成项详情失败", error);
|
||||
showPlaceholderToast("获取升级视频费用失败");
|
||||
}
|
||||
};
|
||||
|
||||
const fetchUpgradeSourceTaskDetail = async () => {
|
||||
if (!isImageToVideoUpgrade.value) return;
|
||||
|
||||
try {
|
||||
const res = await getAigcGeneratorTaskDetail({ taskId: upgradeTaskId.value });
|
||||
if (res?.code === 0 && res.data && typeof res.data === "object" && !Array.isArray(res.data)) {
|
||||
upgradeSourceTaskDetail.value = res.data;
|
||||
return;
|
||||
}
|
||||
|
||||
showPlaceholderToast("获取原图片失败");
|
||||
} catch (error) {
|
||||
console.warn("获取AIGC原图片任务详情失败", error);
|
||||
showPlaceholderToast("获取原图片失败");
|
||||
}
|
||||
};
|
||||
|
||||
const resetSelectedPhoto = () => {
|
||||
selectedImageLocalPath.value = "";
|
||||
@@ -127,25 +181,39 @@ const fetchTemplateItemList = async () => {
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await getAigcTemplateItemList({ templateId: templateId.value });
|
||||
if (res?.code === 0 && Array.isArray(res.data)) {
|
||||
templateItems.value = res.data;
|
||||
selectedTemplateItemId.value = res.data[0]?.templateItemId || "";
|
||||
}
|
||||
const res = await getAigcTemplateItemList({ templateId: templateId.value });
|
||||
if (res?.code === 0 && Array.isArray(res.data)) {
|
||||
templateItems.value = res.data;
|
||||
const selectedUpgradeItem = res.data.find(
|
||||
(item) =>
|
||||
String(item.templateItemId || "") === upgradeTemplateItemId.value &&
|
||||
Number(item.generatorType) === 0,
|
||||
);
|
||||
const firstImageItem = res.data.find((item) => Number(item.generatorType) === 0);
|
||||
selectedTemplateItemId.value =
|
||||
(isImageToVideoUpgrade.value ? selectedUpgradeItem || firstImageItem : res.data[0])?.templateItemId || "";
|
||||
if (isImageToVideoUpgrade.value) {
|
||||
currentStep.value = "generateConfirm";
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("获取AIGC模板生成项失败", error);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPageData = async () => {
|
||||
await fetchTemplateList();
|
||||
await fetchTemplateItemList();
|
||||
};
|
||||
const fetchPageData = async () => {
|
||||
await fetchTemplateList();
|
||||
await fetchImageToVideoItemDetail();
|
||||
await fetchUpgradeSourceTaskDetail();
|
||||
await fetchTemplateItemList();
|
||||
};
|
||||
|
||||
onLoad((query = {}) => {
|
||||
templateId.value = query.templateId || "";
|
||||
fetchPageData();
|
||||
});
|
||||
onLoad((query = {}) => {
|
||||
templateId.value = String(query.templateId || "").trim();
|
||||
upgradeTaskId.value = String(query.upgradeTaskId || "").trim();
|
||||
upgradeTemplateItemId.value = String(query.upgradeTemplateItemId || "").trim();
|
||||
fetchPageData();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
fetchCurrentCredit();
|
||||
@@ -317,26 +385,31 @@ const handleClosePhotoConfirm = () => {
|
||||
currentStep.value = "photoPick";
|
||||
};
|
||||
|
||||
const handleConfirmPhoto = () => {
|
||||
if (!uploadedImageUrl.value) {
|
||||
showPlaceholderToast("请先上传图片");
|
||||
currentStep.value = "photoPick";
|
||||
const handleConfirmPhoto = () => {
|
||||
if (!uploadedImageUrl.value) {
|
||||
showPlaceholderToast("请先上传图片");
|
||||
currentStep.value = "photoPick";
|
||||
return;
|
||||
}
|
||||
|
||||
currentStep.value = "generateConfirm";
|
||||
};
|
||||
|
||||
const handleGenerate = async () => {
|
||||
if (isCreatingTask.value) return;
|
||||
const handleGenerate = async () => {
|
||||
if (isCreatingTask.value) return;
|
||||
|
||||
const templateItemId = currentTemplateItem.value.templateItemId;
|
||||
if (!templateItemId) {
|
||||
showPlaceholderToast("请选择生成类型");
|
||||
return;
|
||||
}
|
||||
if (!templateItemId) {
|
||||
showPlaceholderToast("请选择生成类型");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isImageToVideoUpgrade.value && !imageToVideoItemDetail.value) {
|
||||
showPlaceholderToast("升级视频费用加载失败,请稍后重试");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uploadedImageUrl.value) {
|
||||
if (!isImageToVideoUpgrade.value && !uploadedImageUrl.value) {
|
||||
showPlaceholderToast("请先上传图片");
|
||||
currentStep.value = "photoPick";
|
||||
return;
|
||||
@@ -354,17 +427,33 @@ const handleGenerate = async () => {
|
||||
uni.showLoading({
|
||||
title: "创建中",
|
||||
mask: true,
|
||||
});
|
||||
|
||||
try {
|
||||
const wxLoginCode = await getWechatLoginCode();
|
||||
const res = await createAigcGeneratorTask({
|
||||
templateItemId,
|
||||
imageUrlList: [uploadedImageUrl.value],
|
||||
wxLoginCode,
|
||||
});
|
||||
|
||||
const taskId = String(res?.data || "").trim();
|
||||
});
|
||||
|
||||
try {
|
||||
let res;
|
||||
if (isImageToVideoUpgrade.value) {
|
||||
const wxLoginCode = await getWechatLoginCode();
|
||||
res = await createAigcImageToVideoTask({
|
||||
taskId: upgradeTaskId.value,
|
||||
wxLoginCode,
|
||||
});
|
||||
} else {
|
||||
const wxLoginCode = await getWechatLoginCode();
|
||||
res = await createAigcGeneratorTask({
|
||||
templateItemId,
|
||||
imageUrlList: [uploadedImageUrl.value],
|
||||
wxLoginCode,
|
||||
});
|
||||
}
|
||||
|
||||
if (isImageToVideoUpgrade.value && String(res?.msg || "").includes("积分余额不足")) {
|
||||
pointDialogVisible.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const taskId = String(
|
||||
typeof res?.data === "object" && res.data !== null ? res.data.taskId : res?.data || "",
|
||||
).trim();
|
||||
if (res?.code === 0 && taskId) {
|
||||
fetchCurrentCredit();
|
||||
uni.redirectTo({
|
||||
|
||||
Reference in New Issue
Block a user