Merge branch 'aigc' of https://git.nianxx.cn/zoujing/YGChatCS into home3.0

# Conflicts:
#	src/pages-aigc/agreement/agreement.vue
#	src/pages-booking/index.vue
#	src/pages.json
#	src/request/api/AigcApi.js
#	src/utils/index.js

合并了代码
This commit is contained in:
2026-07-28 12:57:04 +08:00
250 changed files with 10010 additions and 14382 deletions

View File

@@ -1,95 +1,100 @@
<template>
<view class="aigc-topbar" :style="topbarStyle">
<view class="aigc-nav-row">
<view class="aigc-topbar-back" @tap="emit('back')">
<uni-icons v-if="leftAction === 'home'" class="aigc-back-icon is-home" type="home-filled" size="20"
color="#172033" />
<uni-icons v-else 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-points-display">
<text class="aigc-wallet-points">
<text class="aigc-wallet-number">{{ displayPoints }}</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";
const props = defineProps({
points: {
type: [Number, String],
default: 0,
},
showActions: {
type: Boolean,
default: true,
},
leftAction: {
type: String,
default: "back",
validator: (value) => ["back", "home"].includes(value),
},
});
const emit = defineEmits(["back", "history"]);
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`,
}));
const displayPoints = computed(() => Number(props.points) || 0);
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>
<template>
<view class="aigc-topbar" :style="topbarStyle">
<view class="aigc-nav-row">
<view class="aigc-topbar-back" @tap="emit('back')">
<uni-icons v-if="leftAction === 'home'" class="aigc-back-icon is-home" type="home-filled" size="20"
color="#172033" />
<uni-icons v-else 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">{{ displayPoints }}</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";
const props = defineProps({
points: {
type: [Number, String],
default: 0,
},
rechargeLabel: {
type: String,
default: "充值",
},
showActions: {
type: Boolean,
default: true,
},
leftAction: {
type: String,
default: "back",
validator: (value) => ["back", "home"].includes(value),
},
});
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`,
}));
const displayPoints = computed(() => Number(props.points) || 0);
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>

View File

@@ -1,127 +1,137 @@
@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 {
position: relative;
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 36px;
width: 36px;
height: 36px;
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-back-icon.is-home {
transform: none;
}
.aigc-topbar-actions {
position: absolute;
left: 50%;
transform: translateX(-50%);
flex: 0 0 auto;
width: auto;
min-width: 0;
height: 36px;
display: grid;
grid-template-columns: auto 36px;
align-items: center;
gap: 6px;
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-points-display {
height: 36px;
min-width: 0;
display: flex;
align-items: center;
margin: 0;
padding: 0;
border-radius: 50px;
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-points-display {
min-width: 84px;
max-width: 112px;
justify-content: center;
padding: 0 12px;
background: #102942;
color: #ffffff;
}
.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;
}
@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 36px;
width: 36px;
height: 36px;
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-back-icon.is-home {
transform: none;
}
.aigc-topbar-actions {
flex: 1 1 auto;
width: auto;
min-width: 0;
height: 36px;
display: grid;
grid-template-columns: minmax(0, 1fr) 36px;
align-items: center;
gap: 6px;
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: 50px;
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 8px;
background: #102942;
color: #ffffff;
}
.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;
}