feat(aigc): fully integrate backend API and replace mock data
- Replace all static mock data with real backend API calls for templates, generation tasks, credit balance and recharge - Remove deprecated mock data files including templates.js, versionOptions.js, records.js and packages.js - Add useCurrentCredit composable for fetching and managing user credit balance - Update all components to align with new backend data shapes (e.g. templateItemId instead of id) - Add loading and disabled states for interactive UI elements - Implement full WeChat mini-program payment flow for credit recharge - Fix template and record card UI styling and media handling - Set developVersion flag to true for testing environment
This commit is contained in:
@@ -8,30 +8,44 @@
|
||||
:is-mask-click="false"
|
||||
>
|
||||
<view class="photo-pick-drawer">
|
||||
<view class="photo-pick-close" @tap="emit('close')">
|
||||
<uni-icons type="closeempty" size="30" color="#8fa2ba" />
|
||||
</view>
|
||||
|
||||
<text class="photo-pick-title">选择照片</text>
|
||||
|
||||
<view class="photo-pick-card">
|
||||
<view class="photo-pick-plus">+</view>
|
||||
<text class="photo-pick-card-title">上传照片或视频素材</text>
|
||||
<text class="photo-pick-card-desc">
|
||||
选择后会自动进行清晰度、人脸数量和遮挡检测
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="photo-pick-actions">
|
||||
<view class="photo-pick-action" hover-class="is-pressed" @tap="emit('camera')">
|
||||
拍照
|
||||
<view
|
||||
class="photo-pick-close"
|
||||
:class="{ 'is-disabled': loading }"
|
||||
@tap="handleClose"
|
||||
>
|
||||
<uni-icons type="closeempty" size="30" color="#8fa2ba" />
|
||||
</view>
|
||||
<view class="photo-pick-action" hover-class="is-pressed" @tap="emit('album')">
|
||||
相册
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="photo-pick-hint">建议使用半身照,避免墨镜、口罩、强逆光。</text>
|
||||
<text class="photo-pick-title">选择照片</text>
|
||||
|
||||
<view class="photo-pick-card">
|
||||
<view class="photo-pick-plus">+</view>
|
||||
<text class="photo-pick-card-title">上传照片素材</text>
|
||||
<text class="photo-pick-card-desc">
|
||||
选择后会自动进行清晰度、人脸数量和遮挡检测
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="photo-pick-actions">
|
||||
<view
|
||||
class="photo-pick-action"
|
||||
:class="{ 'is-disabled': loading }"
|
||||
:hover-class="loading ? 'none' : 'is-pressed'"
|
||||
@tap="handleCamera"
|
||||
>
|
||||
拍照
|
||||
</view>
|
||||
<view
|
||||
class="photo-pick-action"
|
||||
:class="{ 'is-disabled': loading }"
|
||||
:hover-class="loading ? 'none' : 'is-pressed'"
|
||||
@tap="handleAlbum"
|
||||
>
|
||||
相册
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="photo-pick-hint">建议使用半身照,避免墨镜、口罩、强逆光。</text>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
@@ -39,9 +53,34 @@
|
||||
<script setup>
|
||||
import { nextTick, onMounted, ref } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["close", "camera", "album"]);
|
||||
const popupRef = ref(null);
|
||||
|
||||
const handleClose = () => {
|
||||
if (props.loading) return;
|
||||
|
||||
emit("close");
|
||||
};
|
||||
|
||||
const handleCamera = () => {
|
||||
if (props.loading) return;
|
||||
|
||||
emit("camera");
|
||||
};
|
||||
|
||||
const handleAlbum = () => {
|
||||
if (props.loading) return;
|
||||
|
||||
emit("album");
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick();
|
||||
popupRef.value?.open();
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.photo-pick-close.is-disabled {
|
||||
opacity: 0.48;
|
||||
}
|
||||
|
||||
.photo-pick-title {
|
||||
display: block;
|
||||
margin: 1px 0 17px;
|
||||
@@ -111,6 +115,10 @@
|
||||
opacity: 0.82;
|
||||
}
|
||||
|
||||
.photo-pick-action.is-disabled {
|
||||
opacity: 0.58;
|
||||
}
|
||||
|
||||
.photo-pick-hint {
|
||||
display: block;
|
||||
margin: 10px 0 0;
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
<view
|
||||
class="template-version-hero"
|
||||
:class="`is-${variant}`"
|
||||
:style="{ '--template-accent': template.accent || '#0a4d46' }"
|
||||
>
|
||||
<video
|
||||
v-if="isVideoTemplate"
|
||||
v-if="templateMediaUrl && isVideoTemplate"
|
||||
class="template-version-video"
|
||||
:src="template.cover"
|
||||
:src="templateMediaUrl"
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
@@ -16,13 +15,13 @@
|
||||
:show-center-play-btn="false"
|
||||
object-fit="cover"
|
||||
/>
|
||||
<image v-else class="template-version-image" :src="template.cover" mode="aspectFill" />
|
||||
<image v-else-if="templateMediaUrl" class="template-version-image" :src="templateMediaUrl" mode="aspectFill" />
|
||||
<view class="template-version-shade" />
|
||||
|
||||
<view class="template-version-copy">
|
||||
<text class="template-version-badge">{{ template.badge || "同源双版本" }}</text>
|
||||
<text class="template-version-title">{{ template.title }}</text>
|
||||
<text class="template-version-desc">{{ template.desc }}</text>
|
||||
<text class="template-version-badge">{{ template.templateTag }}</text>
|
||||
<text class="template-version-title">{{ template.templateTitle || template.templateName }}</text>
|
||||
<text class="template-version-desc">{{ template.templateSubTitle || template.templateDescription }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -43,11 +42,12 @@ const props = defineProps({
|
||||
|
||||
const VIDEO_EXT_REGEXP = /\.(mp4|mov|webm|m4v)(\?.*)?$/i;
|
||||
|
||||
const isVideoTemplate = computed(() => {
|
||||
const mediaType = props.template.type || props.template.mediaType;
|
||||
if (mediaType === "video") return true;
|
||||
const templateMediaUrl = computed(() => {
|
||||
return props.template.templateContentUrl || props.template.coverPhotoUrl || "";
|
||||
});
|
||||
|
||||
return VIDEO_EXT_REGEXP.test(props.template.cover || "");
|
||||
const isVideoTemplate = computed(() => {
|
||||
return VIDEO_EXT_REGEXP.test(templateMediaUrl.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -6,16 +6,19 @@
|
||||
@tap="emit('select', option)"
|
||||
>
|
||||
<view class="version-option-copy">
|
||||
<text class="version-option-title">{{ option.label }}</text>
|
||||
<text class="version-option-desc">{{ option.desc }}</text>
|
||||
<text class="version-option-title">{{ option.itemTitle || option.templateItemId }}</text>
|
||||
<text class="version-option-desc">{{ option.itemSubTitle }}</text>
|
||||
<text class="version-option-type">{{ generatorTypeText }}</text>
|
||||
</view>
|
||||
|
||||
<text class="version-option-cost">{{ option.cost }}积分</text>
|
||||
<text class="version-option-cost">{{ option.generatorCost }}积分</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
option: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
@@ -27,6 +30,12 @@ defineProps({
|
||||
});
|
||||
|
||||
const emit = defineEmits(["select"]);
|
||||
|
||||
const generatorTypeText = computed(() => {
|
||||
if (props.option.generatorType === 0) return "图片生成";
|
||||
if (props.option.generatorType === 1) return "视频生成";
|
||||
return `类型 ${props.option.generatorType}`;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
.version-option-title,
|
||||
.version-option-desc,
|
||||
.version-option-type,
|
||||
.version-option-cost {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
@@ -51,6 +52,14 @@
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.version-option-type {
|
||||
margin-top: 4px;
|
||||
color: #9aa6b8;
|
||||
font-size: 10px;
|
||||
line-height: 14px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.version-option-cost {
|
||||
color: #12a765;
|
||||
font-size: 15px;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<view class="version-option-list">
|
||||
<VersionOptionCard
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:key="option.templateItemId"
|
||||
:option="option"
|
||||
:selected="option.value === selectedValue"
|
||||
:selected="option.templateItemId === selectedValue"
|
||||
@select="emit('select', $event)"
|
||||
/>
|
||||
</view>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
export const versionOptions = [
|
||||
{
|
||||
value: "image",
|
||||
label: "图片版",
|
||||
desc: "生成一张高清旅行图片,适合保存和分享。",
|
||||
cost: 100,
|
||||
},
|
||||
{
|
||||
value: "video",
|
||||
label: "动效视频版 · 5秒内",
|
||||
desc: "先生成图片底图,再升级为 5秒内动效视频。",
|
||||
cost: 200,
|
||||
},
|
||||
];
|
||||
@@ -14,27 +14,27 @@
|
||||
|
||||
<GenerateConfirmPanel
|
||||
v-if="currentStep === 'generateConfirm'"
|
||||
:cost="currentVersion.cost || 100"
|
||||
:cost="currentCost"
|
||||
:balance="pointBalance"
|
||||
@generate="handleGenerate"
|
||||
@recharge="handleRecharge"
|
||||
/>
|
||||
<GeneratingProgressPanel
|
||||
v-else-if="currentStep === 'generating'"
|
||||
:cost="currentVersion.cost || 100"
|
||||
:cost="currentCost"
|
||||
:progress="8"
|
||||
@complete="handleGenerateComplete"
|
||||
/>
|
||||
|
||||
<template v-else>
|
||||
<VersionOptionList
|
||||
:options="versionOptions"
|
||||
:selected-value="selectedVersion"
|
||||
@select="handleSelectVersion"
|
||||
:options="templateItems"
|
||||
:selected-value="selectedTemplateItemId"
|
||||
@select="handleSelectTemplateItem"
|
||||
/>
|
||||
|
||||
<text class="aigc-use-template-note">
|
||||
动效视频版会先生成图片底图,再升级为 5秒内动效视频。
|
||||
动效视频版会先生图,再升级为 5 秒内动效视频。
|
||||
</text>
|
||||
</template>
|
||||
</view>
|
||||
@@ -51,6 +51,7 @@
|
||||
</view>
|
||||
<view v-if="currentStep === 'photoPick'" class="aigc-use-template-popup-host">
|
||||
<PhotoPickDrawer
|
||||
:loading="isUploading"
|
||||
@close="handleCloseGuide"
|
||||
@camera="handlePickCamera"
|
||||
@album="handlePickAlbum"
|
||||
@@ -58,14 +59,14 @@
|
||||
</view>
|
||||
<view v-if="currentStep === 'photoConfirm'" class="aigc-use-template-popup-host">
|
||||
<PhotoConfirmDrawer
|
||||
:avatar-src="guideAvatar"
|
||||
:avatar-src="selectedImageLocalPath || guideAvatar"
|
||||
@close="handleClosePhotoConfirm"
|
||||
@confirm="handleConfirmPhoto"
|
||||
/>
|
||||
</view>
|
||||
<PointInsufficientDialog
|
||||
v-if="pointDialogVisible"
|
||||
:cost="currentVersion.cost || 100"
|
||||
:cost="currentCost"
|
||||
:balance="pointBalance"
|
||||
@cancel="handleClosePointDialog"
|
||||
@recharge="handlePointRecharge"
|
||||
@@ -75,9 +76,15 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import AigcTopBar from "@/pages-aigc/components/AigcTopBar/index.vue";
|
||||
import { aigcTemplates } from "@/pages-aigc/home/data/templates.js";
|
||||
import { useCurrentCredit } from "@/pages-aigc/hooks/useCurrentCredit.js";
|
||||
import {
|
||||
createAigcGeneratorTask,
|
||||
getAigcTemplateItemList,
|
||||
getAigcTemplateList,
|
||||
} from "@/request/api/AigcApi.js";
|
||||
import { updateImageFile } from "@/request/api/UpdateFile.js";
|
||||
import guideAvatar from "./assets/xiaoqi-avatar.png";
|
||||
import GenerateConfirmPanel from "./components/GenerateConfirmPanel/index.vue";
|
||||
import GeneratingProgressPanel from "./components/GeneratingProgressPanel/index.vue";
|
||||
@@ -88,24 +95,34 @@ import PointInsufficientDialog from "./components/PointInsufficientDialog/index.
|
||||
import TemplateVersionHero from "./components/TemplateVersionHero/index.vue";
|
||||
import VersionOptionList from "./components/VersionOptionList/index.vue";
|
||||
import { negativeExamples, positiveExamples } from "./data/photoGuideExamples.js";
|
||||
import { versionOptions } from "./data/versionOptions.js";
|
||||
|
||||
const pointBalance = ref(300);
|
||||
const { pointBalance, fetchCurrentCredit } = useCurrentCredit();
|
||||
const templateId = ref("");
|
||||
const selectedVersion = ref("image");
|
||||
const templates = ref([]);
|
||||
const templateItems = ref([]);
|
||||
const selectedTemplateItemId = ref("");
|
||||
const selectedImageLocalPath = ref("");
|
||||
const uploadedImageUrl = ref("");
|
||||
const createdTaskId = ref("");
|
||||
const currentStep = ref("version");
|
||||
const pointDialogVisible = ref(false);
|
||||
const isUploading = ref(false);
|
||||
const isCreatingTask = ref(false);
|
||||
|
||||
const currentTemplate = computed(() => {
|
||||
return aigcTemplates.find((item) => item.id === templateId.value) || aigcTemplates[0] || {};
|
||||
return templates.value.find((item) => item.templateId === templateId.value) || templates.value[0] || {};
|
||||
});
|
||||
|
||||
const currentVersion = computed(() => {
|
||||
return versionOptions.find((item) => item.value === selectedVersion.value) || versionOptions[0] || {};
|
||||
const currentTemplateItem = computed(() => {
|
||||
return (
|
||||
templateItems.value.find((item) => item.templateItemId === selectedTemplateItemId.value) ||
|
||||
templateItems.value[0] ||
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
onLoad((query = {}) => {
|
||||
templateId.value = query.templateId || "";
|
||||
const currentCost = computed(() => {
|
||||
return Number(currentTemplateItem.value.generatorCost) || 0;
|
||||
});
|
||||
|
||||
const showPlaceholderToast = (title) => {
|
||||
@@ -115,6 +132,57 @@ const showPlaceholderToast = (title) => {
|
||||
});
|
||||
};
|
||||
|
||||
const resetSelectedPhoto = () => {
|
||||
selectedImageLocalPath.value = "";
|
||||
uploadedImageUrl.value = "";
|
||||
};
|
||||
|
||||
const fetchTemplateList = async () => {
|
||||
try {
|
||||
const res = await getAigcTemplateList();
|
||||
if (res?.code === 0 && Array.isArray(res.data)) {
|
||||
templates.value = res.data;
|
||||
if (!templateId.value && res.data[0]?.templateId) {
|
||||
templateId.value = res.data[0].templateId;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("获取AIGC模板列表失败", error);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchTemplateItemList = async () => {
|
||||
if (!templateId.value) {
|
||||
templateItems.value = [];
|
||||
selectedTemplateItemId.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
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 || "";
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("获取AIGC模板生成项失败", error);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchPageData = async () => {
|
||||
await fetchTemplateList();
|
||||
await fetchTemplateItemList();
|
||||
};
|
||||
|
||||
onLoad((query = {}) => {
|
||||
templateId.value = query.templateId || "";
|
||||
fetchPageData();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
fetchCurrentCredit();
|
||||
});
|
||||
|
||||
const handleBack = () => {
|
||||
const pages = getCurrentPages();
|
||||
if (pages.length > 1) {
|
||||
@@ -136,8 +204,11 @@ const handleRecharge = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelectVersion = (option) => {
|
||||
selectedVersion.value = option.value;
|
||||
const handleSelectTemplateItem = (option) => {
|
||||
if (!option?.templateItemId) return;
|
||||
|
||||
selectedTemplateItemId.value = option.templateItemId;
|
||||
resetSelectedPhoto();
|
||||
currentStep.value = "uploadGuide";
|
||||
};
|
||||
|
||||
@@ -149,12 +220,91 @@ const handleConfirmGuide = () => {
|
||||
currentStep.value = "photoPick";
|
||||
};
|
||||
|
||||
const getChosenFilePath = (res) => {
|
||||
return res?.tempFiles?.[0]?.tempFilePath || res?.tempFilePaths?.[0] || res?.tempFiles?.[0]?.path || "";
|
||||
};
|
||||
|
||||
const isChooseCanceled = (error) => {
|
||||
const message = String(error?.errMsg || error?.message || "");
|
||||
return message.includes("cancel") || message.includes("取消");
|
||||
};
|
||||
|
||||
const handleChooseImageSuccess = async (res) => {
|
||||
const filePath = getChosenFilePath(res);
|
||||
if (!filePath) {
|
||||
showPlaceholderToast("请选择图片");
|
||||
return;
|
||||
}
|
||||
|
||||
selectedImageLocalPath.value = filePath;
|
||||
uploadedImageUrl.value = "";
|
||||
isUploading.value = true;
|
||||
uni.showLoading({
|
||||
title: "上传中",
|
||||
mask: true,
|
||||
});
|
||||
|
||||
try {
|
||||
const uploadRes = await updateImageFile(filePath);
|
||||
if (uploadRes?.code === 0 && uploadRes.data) {
|
||||
uploadedImageUrl.value = uploadRes.data;
|
||||
currentStep.value = "photoConfirm";
|
||||
} else {
|
||||
resetSelectedPhoto();
|
||||
showPlaceholderToast(uploadRes?.msg || "图片上传失败");
|
||||
}
|
||||
} catch (error) {
|
||||
resetSelectedPhoto();
|
||||
console.warn("上传AIGC生成图片失败", error);
|
||||
showPlaceholderToast("图片上传失败");
|
||||
} finally {
|
||||
isUploading.value = false;
|
||||
uni.hideLoading();
|
||||
}
|
||||
};
|
||||
|
||||
const handleChooseImageFail = (error) => {
|
||||
if (!isChooseCanceled(error)) {
|
||||
console.warn("选择AIGC生成图片失败", error);
|
||||
showPlaceholderToast("选择图片失败");
|
||||
}
|
||||
};
|
||||
|
||||
const chooseImageWithSource = (sourceType) => {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.chooseMedia({
|
||||
count: 1,
|
||||
mediaType: ["image"],
|
||||
sourceType: [sourceType],
|
||||
sizeType: ["compressed"],
|
||||
success: handleChooseImageSuccess,
|
||||
fail: handleChooseImageFail,
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ["compressed"],
|
||||
sourceType: [sourceType],
|
||||
success: handleChooseImageSuccess,
|
||||
fail: handleChooseImageFail,
|
||||
});
|
||||
// #endif
|
||||
};
|
||||
|
||||
const chooseAndUploadImage = (sourceType) => {
|
||||
if (isUploading.value) return;
|
||||
|
||||
chooseImageWithSource(sourceType);
|
||||
};
|
||||
|
||||
const handlePickCamera = () => {
|
||||
currentStep.value = "photoConfirm";
|
||||
chooseAndUploadImage("camera");
|
||||
};
|
||||
|
||||
const handlePickAlbum = () => {
|
||||
currentStep.value = "photoConfirm";
|
||||
chooseAndUploadImage("album");
|
||||
};
|
||||
|
||||
const handleClosePhotoConfirm = () => {
|
||||
@@ -162,11 +312,31 @@ const handleClosePhotoConfirm = () => {
|
||||
};
|
||||
|
||||
const handleConfirmPhoto = () => {
|
||||
if (!uploadedImageUrl.value) {
|
||||
showPlaceholderToast("请先上传图片");
|
||||
currentStep.value = "photoPick";
|
||||
return;
|
||||
}
|
||||
|
||||
currentStep.value = "generateConfirm";
|
||||
};
|
||||
|
||||
const handleGenerate = () => {
|
||||
const cost = Number(currentVersion.value.cost) || 0;
|
||||
const handleGenerate = async () => {
|
||||
if (isCreatingTask.value) return;
|
||||
|
||||
const templateItemId = currentTemplateItem.value.templateItemId;
|
||||
if (!templateItemId) {
|
||||
showPlaceholderToast("请选择生成类型");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uploadedImageUrl.value) {
|
||||
showPlaceholderToast("请先上传图片");
|
||||
currentStep.value = "photoPick";
|
||||
return;
|
||||
}
|
||||
|
||||
const cost = currentCost.value;
|
||||
const balance = Number(pointBalance.value) || 0;
|
||||
|
||||
if (balance < cost) {
|
||||
@@ -174,12 +344,42 @@ const handleGenerate = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
currentStep.value = "generating";
|
||||
isCreatingTask.value = true;
|
||||
uni.showLoading({
|
||||
title: "创建中",
|
||||
mask: true,
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await createAigcGeneratorTask({
|
||||
templateItemId,
|
||||
imageUrlList: [uploadedImageUrl.value],
|
||||
});
|
||||
|
||||
if (res?.code === 0 && res.data) {
|
||||
createdTaskId.value = res.data;
|
||||
currentStep.value = "generating";
|
||||
fetchCurrentCredit();
|
||||
} else {
|
||||
showPlaceholderToast(res?.msg || "创建任务失败");
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("创建AIGC生成任务失败", error);
|
||||
showPlaceholderToast("创建任务失败");
|
||||
} finally {
|
||||
isCreatingTask.value = false;
|
||||
uni.hideLoading();
|
||||
}
|
||||
};
|
||||
|
||||
const handleGenerateComplete = () => {
|
||||
if (!createdTaskId.value) {
|
||||
showPlaceholderToast("任务创建失败");
|
||||
return;
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url: "/pages-aigc/detail/detail",
|
||||
url: `/pages-aigc/detail/detail?taskId=${encodeURIComponent(createdTaskId.value)}`,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user