feat: add gift points toast and refactor useTemplate layout

Add a new gift points notification toast to the AIGC home page for new user signup rewards.
Restructure the useTemplate page's layout and SCSS, split the content container and add dedicated popup host for modal steps.
Remove the unused UploadTemplatePreview component and all related references from the codebase.
This commit is contained in:
duanshuwen
2026-07-05 20:06:18 +08:00
parent b381c712df
commit d95e90127e
7 changed files with 148 additions and 161 deletions

View File

@@ -0,0 +1,37 @@
<template>
<view v-if="visible" class="gift-points-toast" role="status">
<text class="gift-points-badge">{{ title }}</text>
<text class="gift-points-message">{{ message }}</text>
<view class="gift-points-close" @tap="handleClose">
<uni-icons type="closeempty" size="20" color="#ffffff" />
</view>
</view>
</template>
<script setup>
defineProps({
visible: {
type: Boolean,
default: true,
},
title: {
type: String,
default: "300积分已到账",
},
message: {
type: String,
default: "新用户权益已发放,可用于图片版或动效视频版内容升级。",
},
});
const emit = defineEmits(["close", "update:visible"]);
const handleClose = () => {
emit("update:visible", false);
emit("close");
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>

View File

@@ -0,0 +1,63 @@
.gift-points-toast {
position: absolute;
z-index: 6;
top: 4px;
right: 16px;
left: 16px;
height: 50px;
display: flex;
align-items: center;
gap: 8px;
overflow: hidden;
padding: 7px 7px 7px 10px;
border: 1px solid rgba(94, 171, 255, 0.56);
border-radius: 18px;
background: #172951f0;
box-shadow: 0 10px 22px rgba(15, 68, 120, 0.18);
box-sizing: border-box;
}
.gift-points-badge {
flex: 0 0 111px;
width: 111px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
border-radius: 999px;
background: #20cf75;
color: #ffffff;
font-size: 12px;
line-height: 30px;
font-weight: 900;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22);
box-sizing: border-box;
}
.gift-points-message {
flex: 1 1 auto;
min-width: 0;
max-height: 32px;
overflow: hidden;
color: rgba(239, 250, 255, 0.94);
font-size: 11px;
line-height: 16px;
font-weight: 800;
text-overflow: ellipsis;
}
.gift-points-close {
flex: 0 0 28px;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: rgba(255, 255, 255, 0.12);
box-sizing: border-box;
}

View File

@@ -3,6 +3,11 @@
<AigcTopBar :points="pointBalance" @back="handleBack" @history="handleHistory" @recharge="handleRecharge" />
<view class="aigc-home-browser">
<GiftPointsToast
:visible="giftToastVisible"
@close="handleCloseGiftToast"
/>
<TemplateCarousel v-model="activeIndex" :templates="templates" @select="handleSelectTemplate" />
<FlowSteps :steps="steps" />
@@ -13,12 +18,14 @@
<script setup>
import { ref } from "vue";
import AigcTopBar from "@/pages-aigc/components/AigcTopBar/index.vue";
import GiftPointsToast from "./components/GiftPointsToast/index.vue";
import TemplateCarousel from "./components/TemplateCarousel/index.vue";
import FlowSteps from "./components/FlowSteps/index.vue";
import { aigcFlowSteps, aigcTemplates } from "./data/templates.js";
const pointBalance = ref(300);
const activeIndex = ref(0);
const giftToastVisible = ref(true);
const templates = aigcTemplates;
const steps = aigcFlowSteps;
@@ -44,6 +51,10 @@ const handleRecharge = () => {
showPlaceholderToast("积分充值");
};
const handleCloseGiftToast = () => {
giftToastVisible.value = false;
};
const handleSelectTemplate = (template) => {
uni.navigateTo({
url: `/pages-aigc/useTemplate/useTemplate?templateId=${encodeURIComponent(template.id || "")}`,

View File

@@ -1,42 +0,0 @@
<template>
<view
class="upload-template-preview"
:style="{ '--upload-accent': template.accent || '#0a4d46' }"
>
<image class="upload-template-image" :src="template.cover" mode="aspectFill" />
<view class="upload-template-shade" />
<view class="upload-template-copy">
<text class="upload-template-badge">{{ version.label || "图片版" }}</text>
<text class="upload-template-title">{{ template.title }}</text>
<text class="upload-template-desc">{{ previewDesc }}</text>
</view>
</view>
</template>
<script setup>
import { computed } from "vue";
const props = defineProps({
template: {
type: Object,
default: () => ({}),
},
version: {
type: Object,
default: () => ({}),
},
});
const previewDesc = computed(() => {
if (props.template.desc) {
return props.template.desc;
}
return "上传一张清晰半身照,生成旅行内容";
});
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>

View File

@@ -1,85 +0,0 @@
.upload-template-preview {
position: relative;
height: 286px;
overflow: hidden;
border-radius: 0 0 26px 26px;
background: var(--upload-accent, #0a4d46);
color: #ffffff;
}
.upload-template-image {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
}
.upload-template-shade {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: linear-gradient(
180deg,
rgba(8, 22, 28, 0.04) 0%,
rgba(8, 22, 28, 0.16) 46%,
rgba(8, 22, 28, 0.72) 100%
);
}
.upload-template-copy {
position: absolute;
z-index: 1;
right: 16px;
bottom: 92px;
left: 16px;
min-width: 0;
color: #ffffff;
}
.upload-template-badge {
height: 20px;
display: inline-flex;
align-items: center;
max-width: 130px;
overflow: hidden;
padding: 0 8px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.72);
color: #172033;
font-size: 9px;
line-height: 20px;
font-weight: 900;
letter-spacing: 0.7px;
text-overflow: ellipsis;
white-space: nowrap;
}
.upload-template-title,
.upload-template-desc {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.upload-template-title {
margin-top: 10px;
color: #ffffff;
font-size: 24px;
line-height: 30px;
font-weight: 900;
}
.upload-template-desc {
margin-top: 6px;
color: rgba(255, 255, 255, 0.78);
font-size: 12px;
line-height: 18px;
font-weight: 800;
}

View File

@@ -17,16 +17,31 @@
box-sizing: border-box;
}
.aigc-use-template-content {
.aigc-use-template-body {
position: relative;
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
.aigc-use-template-content {
height: 100%;
min-height: 0;
overflow: hidden;
padding: 24px 18px;
box-sizing: border-box;
}
.aigc-use-template-content.is-upload-guide {
padding: 0 12px;
.aigc-use-template-popup-host {
position: fixed;
z-index: 30;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
}
.aigc-use-template-note {

View File

@@ -8,11 +8,8 @@
@recharge="handleRecharge"
/>
<view
class="aigc-use-template-content"
:class="{ 'is-upload-guide': currentStep !== 'version' }"
>
<template v-if="currentStep === 'version'">
<view class="aigc-use-template-body">
<view class="aigc-use-template-content">
<TemplateVersionHero :template="currentTemplate" />
<VersionOptionList
@@ -24,28 +21,24 @@
<text class="aigc-use-template-note">
动效视频版会先生成图片底图再升级为 5秒内动效视频
</text>
</template>
</view>
</view>
<template v-else>
<UploadTemplatePreview
:template="currentTemplate"
:version="currentVersion"
/>
<PhotoGuidePanel
v-if="currentStep === 'uploadGuide'"
:avatar-src="guideAvatar"
:positive-examples="positiveExamples"
:negative-examples="negativeExamples"
@close="handleCloseGuide"
@confirm="handleConfirmGuide"
/>
<PhotoPickDrawer
v-else
@close="handleCloseGuide"
@camera="handlePickCamera"
@album="handlePickAlbum"
/>
</template>
<view v-if="currentStep === 'uploadGuide'" class="aigc-use-template-popup-host">
<PhotoGuidePanel
:avatar-src="guideAvatar"
:positive-examples="positiveExamples"
:negative-examples="negativeExamples"
@close="handleCloseGuide"
@confirm="handleConfirmGuide"
/>
</view>
<view v-if="currentStep === 'photoPick'" class="aigc-use-template-popup-host">
<PhotoPickDrawer
@close="handleCloseGuide"
@camera="handlePickCamera"
@album="handlePickAlbum"
/>
</view>
</view>
</template>
@@ -59,7 +52,6 @@ import guideAvatar from "./assets/xiaoqi-avatar.png";
import PhotoGuidePanel from "./components/PhotoGuidePanel/index.vue";
import PhotoPickDrawer from "./components/PhotoPickDrawer/index.vue";
import TemplateVersionHero from "./components/TemplateVersionHero/index.vue";
import UploadTemplatePreview from "./components/UploadTemplatePreview/index.vue";
import VersionOptionList from "./components/VersionOptionList/index.vue";
import { negativeExamples, positiveExamples } from "./data/photoGuideExamples.js";
import { versionOptions } from "./data/versionOptions.js";
@@ -73,10 +65,6 @@ const currentTemplate = computed(() => {
return aigcTemplates.find((item) => item.id === templateId.value) || aigcTemplates[0] || {};
});
const currentVersion = computed(() => {
return versionOptions.find((item) => item.value === selectedVersion.value) || versionOptions[0] || {};
});
onLoad((query = {}) => {
templateId.value = query.templateId || "";
});