feat: add aigc record, video preview & custom recharge

- create useAigcRecordStore to centralize current AIGC generation record state
- add video media type support to ResultPreview component
- update RecordCard to only display view button for completed tasks
- implement custom recharge amount with input validation and 9999 max limit
- refactor detail page to load record from Pinia store instead of mock data
- clean up TemplateCarousel markup and remove unused badge styles
- fix minor formatting and code style issues
This commit is contained in:
duanshuwen
2026-07-13 21:25:17 +08:00
parent b5952961fe
commit 10638e0806
10 changed files with 184 additions and 112 deletions

View File

@@ -5,7 +5,7 @@
<view class="aigc-detail-content">
<ResultPreview :result="result" />
<ResultMeta :items="metaItems" />
<ContinuationCard :info="continuationInfo" @upgrade="handleUpgradeToVideo" />
<ContinuationCard v-if="continuationInfo" :info="continuationInfo" @upgrade="handleUpgradeToVideo" />
<ResultActions @save="handleSave" @share="handleShare" />
<view class="aigc-detail-text-actions">
@@ -20,8 +20,10 @@
<script setup>
import { computed } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { storeToRefs } from "pinia";
import AigcTopBar from "@/pages-aigc/components/AigcTopBar/index.vue";
import { useCurrentCredit } from "@/pages-aigc/hooks/useCurrentCredit.js";
import { useAigcRecordStore } from "@/store";
import ContinuationCard from "./components/ContinuationCard/index.vue";
import ResultActions from "./components/ResultActions/index.vue";
import ResultMeta from "./components/ResultMeta/index.vue";
@@ -29,33 +31,94 @@ import ResultPreview from "./components/ResultPreview/index.vue";
import { aigcDetailResult } from "./data/result.js";
const { pointBalance, fetchCurrentCredit } = useCurrentCredit();
const result = aigcDetailResult;
const aigcRecordStore = useAigcRecordStore();
const { currentRecord } = storeToRefs(aigcRecordStore);
const GENERATOR_TYPE_TEXT = {
0: "图片版",
1: "视频版",
};
const result = computed(() => {
const record = currentRecord.value;
if (!record) return aigcDetailResult;
const imageUrl = record.imageResultUrl || "";
const videoUrl = record.videoResultUrl || "";
const isVideo = Boolean(videoUrl) && (record.generatorType === 1 || !imageUrl);
const typeText =
GENERATOR_TYPE_TEXT[record.generatorType] ||
(record.generatorType === undefined ? "生成结果" : `类型${record.generatorType}`);
const consumedText =
record.generatorCost === undefined || record.generatorCost === null || record.generatorCost === ""
? "-"
: `${record.generatorCost}积分`;
return {
id: record.taskId,
title: record.itemTitle || record.taskId || "生成结果",
cover: isVideo ? videoUrl : imageUrl || videoUrl,
mediaType: isVideo ? "video" : "image",
accent: "#0a4d46",
variantLabel: typeText,
resultLabel: typeText,
consumedText,
desc: record.itemSubTitle || "生成任务已完成",
};
});
onShow(() => {
fetchCurrentCredit();
});
const metaItems = computed(() => [
{
label: "结果",
value: result.resultLabel,
},
{
label: "已消耗",
value: result.consumedText,
},
{
label: "余额",
value: `${pointBalance.value}积分`,
},
]);
const metaItems = computed(() => {
if (currentRecord.value) {
const record = currentRecord.value;
const completeTime =
record.videoGeneratorCompleteTime || record.imageGeneratorCompleteTime || record.createTime || "-";
const continuationInfo = computed(() => ({
title: result.continuationTitle,
desc: result.continuationDesc,
cost: result.continuationCost,
buttonText: result.continuationButtonText,
}));
return [
{
label: "结果",
value: result.value.resultLabel,
},
{
label: "已消耗",
value: result.value.consumedText,
},
{
label: "完成时间",
value: completeTime,
},
];
}
return [
{
label: "结果",
value: result.value.resultLabel,
},
{
label: "已消耗",
value: result.value.consumedText,
},
{
label: "余额",
value: `${pointBalance.value}积分`,
},
];
});
const continuationInfo = computed(() => {
if (currentRecord.value) return null;
return {
title: result.value.continuationTitle,
desc: result.value.continuationDesc,
cost: result.value.continuationCost,
buttonText: result.value.continuationButtonText,
};
});
const showPlaceholderToast = (title) => {
uni.showToast({