feat(aigc): add travel postcard AIGC feature

Add complete travel postcard AIGC creation workflow including:
- New AIGC pages: template selection home, result detail, and history records
- Reusable UI components: template card, flow steps, result preview, action buttons, record lists
- Static assets including template images, fonts and styles
- Updated TopNavBar component to support menu button alignment
- Register new AIGC page routes in pages.json
- Add mock data for templates, user records and result details
This commit is contained in:
duanshuwen
2026-07-05 17:47:37 +08:00
parent ca680ab41b
commit f47f68e19b
35 changed files with 1716 additions and 18 deletions

View File

@@ -0,0 +1,105 @@
<template>
<view class="aigc-detail-page">
<AigcTopBar :points="pointBalance" @back="handleBack" @history="handleOpenRecords" @recharge="handleRecharge" />
<view class="aigc-detail-content">
<ResultPreview :result="result" />
<ResultMeta :items="metaItems" />
<ContinuationCard :info="continuationInfo" @upgrade="handleUpgradeToVideo" />
<ResultActions @save="handleSave" @share="handleShare" />
<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>
</view>
</template>
<script setup>
import { computed, ref } from "vue";
import AigcTopBar from "@/pages-aigc/components/AigcTopBar/index.vue";
import ContinuationCard from "./components/ContinuationCard/index.vue";
import ResultActions from "./components/ResultActions/index.vue";
import ResultMeta from "./components/ResultMeta/index.vue";
import ResultPreview from "./components/ResultPreview/index.vue";
import { aigcDetailResult } from "./data/result.js";
const pointBalance = ref(300);
const result = aigcDetailResult;
const metaItems = computed(() => [
{
label: "结果",
value: result.resultLabel,
},
{
label: "已消耗",
value: result.consumedText,
},
{
label: "余额",
value: `${pointBalance.value}积分`,
},
]);
const continuationInfo = computed(() => ({
title: result.continuationTitle,
desc: result.continuationDesc,
cost: result.continuationCost,
buttonText: result.continuationButtonText,
}));
const showPlaceholderToast = (title) => {
uni.showToast({
title,
icon: "none",
});
};
const handleBack = () => {
const pages = getCurrentPages();
if (pages.length > 1) {
uni.navigateBack();
}
};
const handleRecharge = () => {
showPlaceholderToast("积分充值");
};
const handleUpgradeToVideo = () => {
showPlaceholderToast("升级为动效视频");
};
const handleSave = () => {
showPlaceholderToast("保存图片");
};
const handleShare = () => {
showPlaceholderToast("分享好友");
};
const handleRegenerate = () => {
showPlaceholderToast("再生成一版");
};
const handleChangeTemplate = () => {
uni.navigateTo({
url: "/pages-aigc/home/home",
fail: () => showPlaceholderToast("换个模板"),
});
};
const handleOpenRecords = () => {
uni.navigateTo({
url: "/pages-aigc/record/record",
fail: () => showPlaceholderToast("历史记录"),
});
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>