diff --git a/src/pages-aigc/detail/detail.vue b/src/pages-aigc/detail/detail.vue
index d0e5f40..90bc368 100644
--- a/src/pages-aigc/detail/detail.vue
+++ b/src/pages-aigc/detail/detail.vue
@@ -3,20 +3,22 @@
-
-
-
-
-
-
-
- 再生成一版
- 换个模板
- 历史记录
-
-
-
+
+
+
+
+
+
+
+
+ 再生成一版
+ 换个模板
+ 历史记录
+
+
+
{
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
};
diff --git a/src/pages-aigc/request/AigcApi.js b/src/pages-aigc/request/AigcApi.js
index d8e1b1c..ab6b04e 100644
--- a/src/pages-aigc/request/AigcApi.js
+++ b/src/pages-aigc/request/AigcApi.js
@@ -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,
diff --git a/src/pages-aigc/useTemplate/components/TemplateVersionHero/styles/index.scss b/src/pages-aigc/useTemplate/components/TemplateVersionHero/styles/index.scss
index 4b44cff..b9d4ba7 100644
--- a/src/pages-aigc/useTemplate/components/TemplateVersionHero/styles/index.scss
+++ b/src/pages-aigc/useTemplate/components/TemplateVersionHero/styles/index.scss
@@ -1,6 +1,6 @@
.template-version-hero {
position: relative;
- height: 360px;
+ height: 380px;
overflow: hidden;
border-radius: 24px;
background: var(--template-accent, #0a4d46);
diff --git a/src/pages-aigc/useTemplate/useTemplate.vue b/src/pages-aigc/useTemplate/useTemplate.vue
index c7519c3..17f3c96 100644
--- a/src/pages-aigc/useTemplate/useTemplate.vue
+++ b/src/pages-aigc/useTemplate/useTemplate.vue
@@ -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({