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:
91
src/pages-aigc/components/AigcTopBar/index.vue
Normal file
91
src/pages-aigc/components/AigcTopBar/index.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<view class="aigc-topbar" :style="topbarStyle">
|
||||
<view class="aigc-nav-row">
|
||||
<view class="aigc-topbar-back" @tap="emit('back')">
|
||||
<uni-icons class="aigc-back-icon" fontFamily="znicons" size="22" color="#172033">
|
||||
{{ zniconsMap["zn-nav-arrow-left"] }}
|
||||
</uni-icons>
|
||||
</view>
|
||||
|
||||
<view v-if="showActions" class="aigc-topbar-actions">
|
||||
<view class="aigc-wallet-button" @tap="emit('recharge')">
|
||||
<text class="aigc-wallet-label">{{ rechargeLabel }}</text>
|
||||
<text class="aigc-wallet-points">
|
||||
<text class="aigc-wallet-number">{{ points }}</text>
|
||||
积分
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="aigc-history-button" @tap="emit('history')">
|
||||
<uni-icons class="aigc-history-icon" fontFamily="znicons" size="22" color="#436783">
|
||||
{{ zniconsMap["zn-clock"] }}
|
||||
</uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { zniconsMap } from "@/static/fonts/znicons.js";
|
||||
|
||||
defineProps({
|
||||
points: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
},
|
||||
rechargeLabel: {
|
||||
type: String,
|
||||
default: "充值",
|
||||
},
|
||||
showActions: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["back", "history", "recharge"]);
|
||||
|
||||
const statusBarHeight = ref(0);
|
||||
const navHeight = ref(52);
|
||||
const capsuleSafeWidth = ref(0);
|
||||
|
||||
const topbarStyle = computed(() => ({
|
||||
"--aigc-status-height": `${statusBarHeight.value}px`,
|
||||
"--aigc-nav-height": `${navHeight.value}px`,
|
||||
"--aigc-capsule-safe-width": `${capsuleSafeWidth.value}px`,
|
||||
}));
|
||||
|
||||
onMounted(() => {
|
||||
try {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
statusBarHeight.value = systemInfo.statusBarHeight || 0;
|
||||
|
||||
const menuButton =
|
||||
typeof uni.getMenuButtonBoundingClientRect === "function"
|
||||
? uni.getMenuButtonBoundingClientRect()
|
||||
: null;
|
||||
|
||||
if (menuButton?.width && menuButton?.left) {
|
||||
const menuTopGap = Math.max(menuButton.top - statusBarHeight.value, 0);
|
||||
const windowWidth = systemInfo.windowWidth || 375;
|
||||
|
||||
navHeight.value = Math.max(menuButton.height + menuTopGap * 2, 44);
|
||||
capsuleSafeWidth.value = Math.max(windowWidth - menuButton.left + 8, 96);
|
||||
return;
|
||||
}
|
||||
|
||||
navHeight.value = statusBarHeight.value > 0 ? 44 : 52;
|
||||
capsuleSafeWidth.value = 0;
|
||||
} catch (error) {
|
||||
statusBarHeight.value = 0;
|
||||
navHeight.value = 52;
|
||||
capsuleSafeWidth.value = 0;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
138
src/pages-aigc/components/AigcTopBar/styles/index.scss
Normal file
138
src/pages-aigc/components/AigcTopBar/styles/index.scss
Normal file
@@ -0,0 +1,138 @@
|
||||
@font-face {
|
||||
font-family: znicons;
|
||||
src: url("@/static/fonts/znicons.ttf");
|
||||
}
|
||||
|
||||
.aigc-topbar {
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
flex: 0 0 auto;
|
||||
padding: var(--aigc-status-height) 12px 8px;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
rgba(235, 249, 255, 0.92) 0%,
|
||||
rgba(240, 251, 247, 0.72) 66%,
|
||||
rgba(240, 251, 247, 0) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.aigc-nav-row {
|
||||
height: var(--aigc-nav-height);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding-right: var(--aigc-capsule-safe-width);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.aigc-topbar-back {
|
||||
flex: 0 0 40px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.86);
|
||||
color: #172033;
|
||||
box-shadow: 0 8px 18px rgba(18, 48, 56, 0.08);
|
||||
}
|
||||
|
||||
.aigc-back-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: translateX(-1px);
|
||||
}
|
||||
|
||||
.aigc-topbar-actions {
|
||||
flex: 1 1 auto;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
height: 40px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 36px;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 2px 3px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.76);
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.86);
|
||||
box-shadow: 0 8px 18px rgba(18, 48, 56, 0.08);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.aigc-history-button,
|
||||
.aigc-wallet-button {
|
||||
height: 36px;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.aigc-history-button {
|
||||
width: 36px;
|
||||
flex: 0 0 36px;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
color: #436783;
|
||||
}
|
||||
|
||||
.aigc-history-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.aigc-wallet-button {
|
||||
justify-content: space-between;
|
||||
gap: 6px;
|
||||
padding: 0 9px 0 8px;
|
||||
background: #102942;
|
||||
color: #ffffff;
|
||||
box-shadow:
|
||||
0 8px 18px rgba(18, 48, 56, 0.1),
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
.aigc-wallet-label {
|
||||
height: 24px;
|
||||
flex: 0 0 auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
border-radius: 999px;
|
||||
background: rgba(32, 207, 117, 0.18);
|
||||
color: #50e093;
|
||||
font-size: 10px;
|
||||
line-height: 24px;
|
||||
font-weight: 900;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.aigc-wallet-points {
|
||||
min-width: 0;
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
overflow: hidden;
|
||||
color: #ffffff;
|
||||
font-size: 10px;
|
||||
line-height: 1;
|
||||
font-weight: 800;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.aigc-wallet-number {
|
||||
margin-right: 2px;
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
font-weight: 900;
|
||||
}
|
||||
Reference in New Issue
Block a user