feat(aigc/useTemplate): add multi-step template generation confirmation workflow
- add PhotoConfirmDrawer component for post-photo-pick quality verification - add GenerateConfirmPanel to display generation point cost and available balance - extend TemplateVersionHero to support custom variant styles - refactor useTemplate page to use step-based workflow flow
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<view class="generate-confirm-panel">
|
||||
<view class="generate-points-summary">
|
||||
<view class="generate-point-card">
|
||||
<text class="generate-point-label">本次消耗</text>
|
||||
<text class="generate-point-value">{{ cost }}积分</text>
|
||||
</view>
|
||||
<view class="generate-point-card">
|
||||
<text class="generate-point-label">当前可用</text>
|
||||
<text class="generate-point-value">{{ balance }}积分</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="generate-freeze-note">
|
||||
<text class="generate-freeze-title">积分冻结规则</text>
|
||||
<text class="generate-freeze-desc">
|
||||
开始生成后将先冻结 {{ cost }} 积分,生成成功后扣除,失败会自动退回。
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="generate-confirm-actions">
|
||||
<view
|
||||
class="generate-action is-primary"
|
||||
hover-class="is-pressed"
|
||||
@tap="emit('generate')"
|
||||
>
|
||||
开始生成
|
||||
</view>
|
||||
<view
|
||||
class="generate-action is-secondary"
|
||||
hover-class="is-pressed"
|
||||
@tap="emit('recharge')"
|
||||
>
|
||||
充值积分
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
cost: {
|
||||
type: [Number, String],
|
||||
default: 100,
|
||||
},
|
||||
balance: {
|
||||
type: [Number, String],
|
||||
default: 300,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["generate", "recharge"]);
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
@@ -0,0 +1,124 @@
|
||||
.generate-confirm-panel {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.generate-points-summary {
|
||||
height: 80px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.generate-point-card {
|
||||
min-width: 0;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
border-radius: 18px;
|
||||
background: rgba(255, 255, 255, 0.68);
|
||||
box-shadow: 0 8px 18px rgba(18, 48, 56, 0.04);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.generate-point-label,
|
||||
.generate-point-value {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.generate-point-label {
|
||||
color: #7a8596;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.generate-point-value {
|
||||
margin-top: 7px;
|
||||
color: #102942;
|
||||
font-size: 21px;
|
||||
line-height: 27px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.generate-freeze-note {
|
||||
min-height: 86px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-top: 14px;
|
||||
padding: 17px 16px;
|
||||
border-radius: 18px;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
box-shadow: 0 8px 18px rgba(18, 48, 56, 0.04);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.generate-freeze-title,
|
||||
.generate-freeze-desc {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.generate-freeze-title {
|
||||
color: #172033;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-weight: 900;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.generate-freeze-desc {
|
||||
margin-top: 6px;
|
||||
color: #52637a;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.generate-confirm-actions {
|
||||
height: 48px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
|
||||
gap: 10px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.generate-action {
|
||||
min-width: 0;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
border-radius: 999px;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 900;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.generate-action.is-primary {
|
||||
background: #20cf75;
|
||||
color: #ffffff;
|
||||
box-shadow: 0 12px 24px rgba(32, 207, 117, 0.25);
|
||||
}
|
||||
|
||||
.generate-action.is-secondary {
|
||||
background: rgba(255, 255, 255, 0.82);
|
||||
color: #3d5066;
|
||||
}
|
||||
|
||||
.generate-action.is-pressed {
|
||||
opacity: 0.86;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<uni-popup
|
||||
ref="popupRef"
|
||||
type="bottom"
|
||||
background-color="transparent"
|
||||
mask-background-color="rgba(0, 0, 0, 0)"
|
||||
:safe-area="false"
|
||||
:is-mask-click="false"
|
||||
>
|
||||
<view class="photo-confirm-drawer">
|
||||
<view class="photo-confirm-close" @tap="emit('close')">
|
||||
<uni-icons type="closeempty" size="30" color="#8fa2ba" />
|
||||
</view>
|
||||
|
||||
<text class="photo-confirm-title">照片确认</text>
|
||||
|
||||
<view class="photo-confirm-card">
|
||||
<view class="photo-confirm-avatar">
|
||||
<image class="photo-confirm-avatar-image" :src="avatarSrc" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="photo-confirm-copy">
|
||||
<text class="photo-confirm-card-title">照片已通过基础质检</text>
|
||||
<text class="photo-confirm-card-desc">正脸清晰 · 单人入镜 · 光线可用</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="photo-confirm-primary" hover-class="is-pressed" @tap="emit('confirm')">
|
||||
下一步确认
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick, onMounted, ref } from "vue";
|
||||
import defaultAvatar from "../../assets/xiaoqi-avatar.png";
|
||||
|
||||
defineProps({
|
||||
avatarSrc: {
|
||||
type: String,
|
||||
default: defaultAvatar,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["close", "confirm"]);
|
||||
const popupRef = ref(null);
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick();
|
||||
popupRef.value?.open();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
@@ -0,0 +1,111 @@
|
||||
.photo-confirm-drawer {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
max-width: 100%;
|
||||
min-height: 446px;
|
||||
margin-top: -34px;
|
||||
padding: 30px 38px 28px;
|
||||
border-radius: 28px 28px 0 0;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 -8px 28px rgba(18, 35, 48, 0.08);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.photo-confirm-close {
|
||||
position: absolute;
|
||||
left: 24px;
|
||||
top: 28px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
color: #9aa4b2;
|
||||
}
|
||||
|
||||
.photo-confirm-title {
|
||||
display: block;
|
||||
margin: 6px 0 23px;
|
||||
color: #111827;
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
font-weight: 900;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.photo-confirm-card {
|
||||
width: 100%;
|
||||
min-height: 74px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 13px 16px;
|
||||
border-radius: 16px;
|
||||
background: #f0fbfd;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.photo-confirm-avatar {
|
||||
flex: 0 0 48px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
overflow: hidden;
|
||||
border-radius: 50%;
|
||||
background: #d8f1f7;
|
||||
}
|
||||
|
||||
.photo-confirm-avatar-image {
|
||||
width: 64px;
|
||||
height: 92px;
|
||||
display: block;
|
||||
margin: -14px 0 0 -8px;
|
||||
}
|
||||
|
||||
.photo-confirm-copy {
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.photo-confirm-card-title,
|
||||
.photo-confirm-card-desc {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.photo-confirm-card-title {
|
||||
color: #172033;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.photo-confirm-card-desc {
|
||||
margin-top: 2px;
|
||||
color: #56708c;
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.photo-confirm-primary {
|
||||
width: 100%;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-top: 26px;
|
||||
border-radius: 999px;
|
||||
background: #061e34;
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
font-weight: 900;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.photo-confirm-primary.is-pressed {
|
||||
opacity: 0.86;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<view
|
||||
class="template-version-hero"
|
||||
:class="`is-${variant}`"
|
||||
:style="{ '--template-accent': template.accent || '#0a4d46' }"
|
||||
>
|
||||
<image class="template-version-image" :src="template.cover" mode="aspectFill" />
|
||||
@@ -20,6 +21,10 @@ defineProps({
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
variant: {
|
||||
type: String,
|
||||
default: "default",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
box-shadow: 0 16px 30px rgba(15, 29, 37, 0.1);
|
||||
}
|
||||
|
||||
.template-version-hero.is-confirm {
|
||||
height: 248px;
|
||||
border-radius: 18px;
|
||||
box-shadow: 0 12px 24px rgba(15, 29, 37, 0.08);
|
||||
}
|
||||
|
||||
.template-version-image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -82,3 +88,28 @@
|
||||
line-height: 18px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.template-version-hero.is-confirm .template-version-copy {
|
||||
right: 16px;
|
||||
bottom: 18px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
.template-version-hero.is-confirm .template-version-badge {
|
||||
height: 22px;
|
||||
max-width: 88px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.template-version-hero.is-confirm .template-version-title {
|
||||
margin-top: 9px;
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.template-version-hero.is-confirm .template-version-desc {
|
||||
max-width: 294px;
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 24px 18px;
|
||||
padding: 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,15 +12,25 @@
|
||||
<view class="aigc-use-template-content">
|
||||
<TemplateVersionHero :template="currentTemplate" />
|
||||
|
||||
<VersionOptionList
|
||||
:options="versionOptions"
|
||||
:selected-value="selectedVersion"
|
||||
@select="handleSelectVersion"
|
||||
<GenerateConfirmPanel
|
||||
v-if="currentStep === 'generateConfirm'"
|
||||
:cost="currentVersion.cost || 100"
|
||||
:balance="pointBalance"
|
||||
@generate="handleGenerate"
|
||||
@recharge="handleRecharge"
|
||||
/>
|
||||
|
||||
<text class="aigc-use-template-note">
|
||||
动效视频版会先生成图片底图,再升级为 5秒内动效视频。
|
||||
</text>
|
||||
<template v-else>
|
||||
<VersionOptionList
|
||||
:options="versionOptions"
|
||||
:selected-value="selectedVersion"
|
||||
@select="handleSelectVersion"
|
||||
/>
|
||||
|
||||
<text class="aigc-use-template-note">
|
||||
动效视频版会先生成图片底图,再升级为 5秒内动效视频。
|
||||
</text>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -40,6 +50,13 @@
|
||||
@album="handlePickAlbum"
|
||||
/>
|
||||
</view>
|
||||
<view v-if="currentStep === 'photoConfirm'" class="aigc-use-template-popup-host">
|
||||
<PhotoConfirmDrawer
|
||||
:avatar-src="guideAvatar"
|
||||
@close="handleClosePhotoConfirm"
|
||||
@confirm="handleConfirmPhoto"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -49,6 +66,8 @@ import { onLoad } from "@dcloudio/uni-app";
|
||||
import AigcTopBar from "@/pages-aigc/components/AigcTopBar/index.vue";
|
||||
import { aigcTemplates } from "@/pages-aigc/home/data/templates.js";
|
||||
import guideAvatar from "./assets/xiaoqi-avatar.png";
|
||||
import GenerateConfirmPanel from "./components/GenerateConfirmPanel/index.vue";
|
||||
import PhotoConfirmDrawer from "./components/PhotoConfirmDrawer/index.vue";
|
||||
import PhotoGuidePanel from "./components/PhotoGuidePanel/index.vue";
|
||||
import PhotoPickDrawer from "./components/PhotoPickDrawer/index.vue";
|
||||
import TemplateVersionHero from "./components/TemplateVersionHero/index.vue";
|
||||
@@ -56,7 +75,7 @@ import VersionOptionList from "./components/VersionOptionList/index.vue";
|
||||
import { negativeExamples, positiveExamples } from "./data/photoGuideExamples.js";
|
||||
import { versionOptions } from "./data/versionOptions.js";
|
||||
|
||||
const pointBalance = ref(0);
|
||||
const pointBalance = ref(300);
|
||||
const templateId = ref("");
|
||||
const selectedVersion = ref("image");
|
||||
const currentStep = ref("version");
|
||||
@@ -65,6 +84,10 @@ 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 || "";
|
||||
});
|
||||
@@ -111,11 +134,23 @@ const handleConfirmGuide = () => {
|
||||
};
|
||||
|
||||
const handlePickCamera = () => {
|
||||
showPlaceholderToast("拍照");
|
||||
currentStep.value = "photoConfirm";
|
||||
};
|
||||
|
||||
const handlePickAlbum = () => {
|
||||
showPlaceholderToast("相册");
|
||||
currentStep.value = "photoConfirm";
|
||||
};
|
||||
|
||||
const handleClosePhotoConfirm = () => {
|
||||
currentStep.value = "photoPick";
|
||||
};
|
||||
|
||||
const handleConfirmPhoto = () => {
|
||||
currentStep.value = "generateConfirm";
|
||||
};
|
||||
|
||||
const handleGenerate = () => {
|
||||
showPlaceholderToast("开始生成");
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user