feat: add discovery tool cards, refactor AiTabSwitch and update client configs
- Update xiaoqi client configuration: adjust clientId, sync appid across config files and switch to production build by setting developVersion to false - Refactor AiTabSwitch component to use background images instead of inline image tags, clean up redundant SCSS styles and replace tab icon assets - Add three new Discovery page tool components: audio guide, map guide and photo generator cards - Clean up unused code in Discovery page and ChatMainList component, remove unused scroll view and computed property - Fix regex pattern and formatting issues in update-appid.js script - Comment out unused SpriteAnimator component in ChatMainList
This commit is contained in:
116
src/pages/Discovery/components/DiscoveryPhotoToolCard/index.vue
Normal file
116
src/pages/Discovery/components/DiscoveryPhotoToolCard/index.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<view
|
||||
class="discovery-photo-tool-card"
|
||||
hover-class="is-pressed"
|
||||
hover-stay-time="80"
|
||||
@tap="handleSelect"
|
||||
>
|
||||
<view class="photo-visual">
|
||||
<view class="camera-illustration">
|
||||
<view class="camera-top" />
|
||||
<view class="camera-flash" />
|
||||
<view class="camera-body">
|
||||
<view class="camera-lens">
|
||||
<view class="camera-lens-inner" />
|
||||
</view>
|
||||
<view class="camera-dot is-large" />
|
||||
<view class="camera-dot is-small" />
|
||||
</view>
|
||||
</view>
|
||||
<text class="photo-badge ellipsis-1">{{ normalizedItem.badge }}</text>
|
||||
</view>
|
||||
|
||||
<view class="photo-content">
|
||||
<text class="photo-title ellipsis-1">{{ normalizedItem.title }}</text>
|
||||
<text class="photo-subtitle ellipsis-1">{{ normalizedItem.subTitle }}</text>
|
||||
|
||||
<view class="photo-options">
|
||||
<view
|
||||
v-for="(option, index) in normalizedItem.options"
|
||||
:key="getOptionKey(option, index)"
|
||||
class="photo-option"
|
||||
hover-class="is-option-pressed"
|
||||
hover-stay-time="80"
|
||||
@tap.stop="handleOptionSelect(option, index)"
|
||||
>
|
||||
<view class="photo-option-thumb">
|
||||
<image
|
||||
v-if="option.coverImage"
|
||||
class="photo-option-image"
|
||||
:src="option.coverImage"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view
|
||||
v-else
|
||||
class="photo-option-placeholder"
|
||||
:class="`is-${index}`"
|
||||
/>
|
||||
</view>
|
||||
<text class="photo-option-label ellipsis-1">{{ option.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
const DEFAULT_OPTIONS = [
|
||||
{ id: "check-in", label: "景点打卡" },
|
||||
{ id: "companion", label: "小七陪伴" },
|
||||
{ id: "memory", label: "风格纪念" },
|
||||
];
|
||||
|
||||
const DEFAULT_ITEM = {
|
||||
id: "travel-photo",
|
||||
title: "在卧龙潭和小七合影",
|
||||
subTitle: "生成你在卧龙潭的专属纪念照",
|
||||
badge: "旅行纪念照",
|
||||
options: DEFAULT_OPTIONS,
|
||||
};
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["didSelectItem", "didSelectOption"]);
|
||||
|
||||
const normalizeOption = (option, index) => ({
|
||||
raw: option,
|
||||
id: option.id ?? option.tabContentId ?? index,
|
||||
label: option.label || option.title || DEFAULT_OPTIONS[index]?.label || "",
|
||||
coverImage: option.coverImage || option.image || option.url || "",
|
||||
});
|
||||
|
||||
const normalizedItem = computed(() => {
|
||||
const source = Object.keys(props.item).length > 0 ? props.item : DEFAULT_ITEM;
|
||||
const options = source.options || source.children || source.items || DEFAULT_OPTIONS;
|
||||
|
||||
return {
|
||||
raw: source,
|
||||
id: source.id ?? source.tabContentId ?? DEFAULT_ITEM.id,
|
||||
title: source.title || DEFAULT_ITEM.title,
|
||||
subTitle: source.subTitle || source.desc || DEFAULT_ITEM.subTitle,
|
||||
badge: source.badge || source.tag || DEFAULT_ITEM.badge,
|
||||
options: options.slice(0, 3).map(normalizeOption),
|
||||
};
|
||||
});
|
||||
|
||||
const getOptionKey = (option, index) => option.id ?? option.label ?? index;
|
||||
|
||||
const handleSelect = () => {
|
||||
emit("didSelectItem", normalizedItem.value.raw);
|
||||
};
|
||||
|
||||
const handleOptionSelect = (option, index) => {
|
||||
emit("didSelectOption", option.raw, normalizedItem.value.raw, index);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
@@ -0,0 +1,259 @@
|
||||
.discovery-photo-tool-card {
|
||||
width: 100%;
|
||||
height: 142px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.discovery-photo-tool-card.is-pressed {
|
||||
opacity: 0.94;
|
||||
}
|
||||
|
||||
.photo-visual {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
flex: 0 0 88px;
|
||||
width: 88px;
|
||||
height: 142px;
|
||||
overflow: hidden;
|
||||
border-radius: 28px;
|
||||
background: #c8f4ab;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.photo-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 142px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px 12px 12px;
|
||||
border-radius: 28px;
|
||||
background: #ffffff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.photo-title {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
color: #142034;
|
||||
font-size: 19px;
|
||||
line-height: 25px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.photo-subtitle {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
margin-top: 2px;
|
||||
color: #9aa4b4;
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.camera-illustration {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 34px;
|
||||
width: 66px;
|
||||
height: 58px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.camera-top {
|
||||
position: absolute;
|
||||
left: 25px;
|
||||
top: 0;
|
||||
width: 28px;
|
||||
height: 30px;
|
||||
border-radius: 9px 9px 0 0;
|
||||
background: #5b6d84;
|
||||
}
|
||||
|
||||
.camera-top::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
top: 9px;
|
||||
width: 18px;
|
||||
height: 12px;
|
||||
border-radius: 4px;
|
||||
background: #ffe97b;
|
||||
}
|
||||
|
||||
.camera-flash {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: -10px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 9px;
|
||||
background: #ffd85c;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.camera-body {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 66px;
|
||||
height: 42px;
|
||||
border-radius: 12px;
|
||||
background: #526376;
|
||||
}
|
||||
|
||||
.camera-body::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 0;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 4px;
|
||||
background: #f2768d;
|
||||
}
|
||||
|
||||
.camera-lens {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 5px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: #f8fbff;
|
||||
box-shadow: -6px 7px 0 rgba(35, 48, 67, 0.4);
|
||||
}
|
||||
|
||||
.camera-lens-inner {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: #6fd7ee;
|
||||
}
|
||||
|
||||
.camera-dot {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
border-radius: 50%;
|
||||
background: #7f91a5;
|
||||
}
|
||||
|
||||
.camera-dot.is-large {
|
||||
top: 7px;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
.camera-dot.is-small {
|
||||
top: 15px;
|
||||
width: 3px;
|
||||
height: 3px;
|
||||
}
|
||||
|
||||
.photo-badge {
|
||||
position: absolute;
|
||||
left: 9px;
|
||||
right: 9px;
|
||||
bottom: 15px;
|
||||
height: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #142034;
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.photo-badge::before,
|
||||
.photo-badge::after {
|
||||
content: "";
|
||||
flex: 0 0 4px;
|
||||
width: 4px;
|
||||
height: 12px;
|
||||
margin: 0 4px;
|
||||
border-top: 4px solid #142034;
|
||||
border-bottom: 4px solid #142034;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.photo-badge::before {
|
||||
border-left: 4px solid #142034;
|
||||
}
|
||||
|
||||
.photo-badge::after {
|
||||
border-right: 4px solid #142034;
|
||||
}
|
||||
|
||||
.photo-options {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.photo-option {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.photo-option.is-option-pressed {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.photo-option-thumb {
|
||||
width: 70px;
|
||||
height: 48px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
background: #dff5ef;
|
||||
}
|
||||
|
||||
.photo-option-image,
|
||||
.photo-option-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.photo-option-placeholder {
|
||||
background:
|
||||
radial-gradient(circle at 28% 68%, rgba(255, 255, 255, 0.9) 0 5px, transparent 6px),
|
||||
linear-gradient(145deg, rgba(9, 83, 68, 0.75), rgba(14, 170, 112, 0.2)),
|
||||
linear-gradient(135deg, #0c5f58 0%, #4ecf9d 100%);
|
||||
}
|
||||
|
||||
.photo-option-placeholder.is-1 {
|
||||
background:
|
||||
radial-gradient(circle at 50% 24%, rgba(255, 255, 255, 0.82) 0 5px, transparent 6px),
|
||||
linear-gradient(180deg, rgba(6, 87, 73, 0.18), rgba(11, 91, 76, 0.7)),
|
||||
linear-gradient(135deg, #196d63 0%, #50c6b3 100%);
|
||||
}
|
||||
|
||||
.photo-option-placeholder.is-2 {
|
||||
background:
|
||||
radial-gradient(circle at 70% 48%, rgba(255, 217, 91, 0.8) 0 5px, transparent 6px),
|
||||
linear-gradient(140deg, rgba(14, 50, 37, 0.68), rgba(67, 149, 83, 0.3)),
|
||||
linear-gradient(135deg, #28583b 0%, #9ac978 100%);
|
||||
}
|
||||
|
||||
.photo-option-label {
|
||||
display: block;
|
||||
max-width: 76px;
|
||||
margin: 5px auto 0;
|
||||
color: $theme-color-500;
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
Reference in New Issue
Block a user