Compare commits
5 Commits
71c5e86bb8
...
2c9377c019
| Author | SHA1 | Date | |
|---|---|---|---|
| 2c9377c019 | |||
| 722dec025e | |||
| d54ff8895e | |||
| b41ca9c4a2 | |||
| 058c9c0e77 |
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
@@ -7,6 +7,12 @@
|
|||||||
@tap="handleSwitch(0)"
|
@tap="handleSwitch(0)"
|
||||||
>
|
>
|
||||||
<view class="tab-content">
|
<view class="tab-content">
|
||||||
|
<image
|
||||||
|
v-if="leftSelected || leftUnselected"
|
||||||
|
:src="modelValue === 0 ? (leftSelected || leftUnselected) : (leftUnselected || leftSelected)"
|
||||||
|
class="tab-image"
|
||||||
|
mode="aspectFill"
|
||||||
|
/>
|
||||||
<text class="tab-text">探索发现</text>
|
<text class="tab-text">探索发现</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -17,8 +23,17 @@
|
|||||||
@tap="handleSwitch(1)"
|
@tap="handleSwitch(1)"
|
||||||
>
|
>
|
||||||
<view class="tab-content">
|
<view class="tab-content">
|
||||||
|
<image
|
||||||
|
v-if="rightSelected || rightUnselected"
|
||||||
|
:src="modelValue === 1 ? (rightSelected || rightUnselected) : (rightUnselected || rightSelected)"
|
||||||
|
class="tab-image"
|
||||||
|
mode="aspectFill"
|
||||||
|
/>
|
||||||
<text class="tab-text">AI伴游</text>
|
<text class="tab-text">AI伴游</text>
|
||||||
<view v-if="showDot" class="status-dot"></view>
|
<view
|
||||||
|
v-if="showDot"
|
||||||
|
:class="['status-dot', modelValue === 1 ? 'status-dot--active' : 'status-dot--inactive']"
|
||||||
|
></view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -26,6 +41,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
|
import leftSelected from "./images/L_02.png";
|
||||||
|
import leftUnselected from "./images/L_01.png";
|
||||||
|
import rightSelected from "./images/R_02.png";
|
||||||
|
import rightUnselected from "./images/R_01.png";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: { type: Number, default: 0 },
|
modelValue: { type: Number, default: 0 },
|
||||||
showDot: { type: Boolean, default: true },
|
showDot: { type: Boolean, default: true },
|
||||||
@@ -47,23 +68,21 @@ const handleSwitch = (i) => {
|
|||||||
.tab-container {
|
.tab-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 48px;
|
height: 50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
/* 基础容器不做裁切,交给内部 Item */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: 48px;
|
height: 50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 选中态提升层级,压住对方的交汇线 */
|
|
||||||
.tab-item.active {
|
.tab-item.active {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
@@ -74,91 +93,57 @@ const handleSwitch = (i) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
/* 未选中样式:半透明渐变 */
|
|
||||||
background: rgba(0, 0, 0, 0.05);
|
|
||||||
transition: background 0.3s;
|
transition: background 0.3s;
|
||||||
}
|
overflow: hidden;
|
||||||
|
|
||||||
.tab-item.active .tab-content {
|
|
||||||
/* 选中样式:纯白 */
|
|
||||||
background: linear-gradient(
|
|
||||||
180deg,
|
|
||||||
rgba(255, 255, 255, 0) 0%,
|
|
||||||
#f0f8f3 75.52%
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-text {
|
.tab-text {
|
||||||
font-size: 15px;
|
font-size: 18px;
|
||||||
color: rgba(255, 255, 255, 0.95);
|
font-weight: 500;
|
||||||
|
color: rgba(255, 255, 255, 0.65);
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-image {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
object-fit: cover;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
.tab-item.active .tab-text {
|
.tab-item.active .tab-text {
|
||||||
color: #2e312f;
|
color: #2e312f;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------- 核心:异形路径优化 ------------------- */
|
|
||||||
|
|
||||||
/* 路径逻辑:
|
|
||||||
1. H 指令缩短,让出更多空间给交汇处。
|
|
||||||
2. C 指令(贝塞尔曲线)的终点设在高度 48 的位置,确保底部平齐不留空隙。
|
|
||||||
3. 通过 margin-right/left 让两个形状在中心高度(24px)处重叠。
|
|
||||||
*/
|
|
||||||
|
|
||||||
.is-left {
|
.is-left {
|
||||||
margin-right: -14px;
|
margin-right: -24px;
|
||||||
/* 减小重叠宽度,使形状更精巧 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-left .tab-content {
|
|
||||||
/* 路径:左侧顶满 -> 顶部直线 -> 在中间开始向下弯曲 -> 底部平齐拉回 */
|
|
||||||
-webkit-mask-image: url("./images/L_01.png");
|
|
||||||
mask-image: url("./images/L_01.png");
|
|
||||||
-webkit-mask-size: 100% 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-right {
|
.is-right {
|
||||||
margin-left: -14px;
|
margin-left: -24px;
|
||||||
}
|
|
||||||
|
|
||||||
.is-right .tab-content {
|
|
||||||
-webkit-mask-image: url("./images/R_01.png");
|
|
||||||
mask-image: url("./images/R_01.png");
|
|
||||||
-webkit-mask-size: 100% 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------- 选中态的渐变边框 ------------------- */
|
|
||||||
|
|
||||||
.tab-item.active::after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: 15;
|
|
||||||
pointer-events: none;
|
|
||||||
/* 360deg 渐变 */
|
|
||||||
background: linear-gradient(
|
|
||||||
0deg,
|
|
||||||
rgba(255, 255, 255, 1) 0%,
|
|
||||||
rgba(255, 255, 255, 0) 100%
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-left.active::after {
|
|
||||||
-webkit-mask-image: url("./images/L_02.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-right.active::after {
|
|
||||||
-webkit-mask-image: url("./images/R_02.png");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot {
|
.status-dot {
|
||||||
width: 7px;
|
display: inline-block;
|
||||||
height: 7px;
|
margin-left: 6px;
|
||||||
background-color: #26d46c;
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-left: 5px;
|
z-index: 22;
|
||||||
transform: translateY(-8px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-dot--active {
|
||||||
|
background-color: #26d46c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot--inactive {
|
||||||
|
background-color: rgba(255, 255, 255, 0.65);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
.module-title {
|
.module-title {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
color: #171717;
|
color: #171717;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
53
src/pages/Discovery/components/FindTabs/index.vue
Normal file
53
src/pages/Discovery/components/FindTabs/index.vue
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<template>
|
||||||
|
<view class="find-tabs-wrapper">
|
||||||
|
<scroll-view class="tabs-scroll" scroll-x="true" :scroll-into-view="'tab-' + modelValue" scroll-with-animation="true">
|
||||||
|
<view class="tabs-list">
|
||||||
|
<view
|
||||||
|
v-for="(tab, idx) in tabs"
|
||||||
|
:key="idx"
|
||||||
|
:id="'tab-' + idx"
|
||||||
|
class="tab-item"
|
||||||
|
:class="{ active: modelValue === idx }"
|
||||||
|
@tap="handleSwitch(idx)"
|
||||||
|
>
|
||||||
|
<view class="tab-content">
|
||||||
|
<view class="tab-label">
|
||||||
|
<text class="tab-text">{{ tab.label }}</text>
|
||||||
|
<image v-if="modelValue === idx && indicatorSrc" :src="indicatorSrc" class="tab-indicator" mode="widthFix" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import indicatorSrc from "./images/selected_tabs_icon.png";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { type: Number, default: 0 },
|
||||||
|
tabs: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [
|
||||||
|
{ label: '小七孔古桥' },
|
||||||
|
{ label: '翠谷瀑布' },
|
||||||
|
{ label: '鸳鸯湖' },
|
||||||
|
{ label: '天河潭' },
|
||||||
|
{ label: '卧龙潭' }
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'change']);
|
||||||
|
|
||||||
|
const handleSwitch = (i) => {
|
||||||
|
emit('update:modelValue', i);
|
||||||
|
emit('change', i);
|
||||||
|
};
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "./styles/index.scss";
|
||||||
|
</style>
|
||||||
70
src/pages/Discovery/components/FindTabs/styles/index.scss
Normal file
70
src/pages/Discovery/components/FindTabs/styles/index.scss
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
.find-tabs-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-scroll {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-list {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
height: 50px;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 50px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item:last-child {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-label {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-text {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(128, 140, 153, 0.9);
|
||||||
|
z-index: 5;
|
||||||
|
padding: 0 4px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item.active .tab-text {
|
||||||
|
color: #0b0b0b;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-indicator {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -6px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 56px;
|
||||||
|
height: auto;
|
||||||
|
z-index: 6;
|
||||||
|
}
|
||||||
78
src/pages/Discovery/components/QuickQuestions/index.vue
Normal file
78
src/pages/Discovery/components/QuickQuestions/index.vue
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<view class="container pl-12">
|
||||||
|
<ModuleTitle :title="themeName" />
|
||||||
|
|
||||||
|
<view class="container-scroll font-size-0 scroll-x whitespace-nowrap">
|
||||||
|
|
||||||
|
<view class="card-item bg-white inline-block rounded-20 p-10 mr-10"
|
||||||
|
v-for="(item, index) in recommendPostsList" :key="index" @click="sendReply(item)">
|
||||||
|
|
||||||
|
<view class="flex flex-row items-center">
|
||||||
|
<image class="card-img rounded-14" :src="item.coverPhoto" mode="aspectFill" />
|
||||||
|
|
||||||
|
<view class="ml-8 mt-4 border-box">
|
||||||
|
<view class="font-size-12 font-600 color-171717 ellipsis-1">
|
||||||
|
{{ item.title }}
|
||||||
|
</view>
|
||||||
|
<view class="font-size-9 color-94A3B8 ellipsis-1">
|
||||||
|
{{ item.subTitle }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { defineProps } from "vue";
|
||||||
|
import { SEND_MESSAGE_CONTENT_TEXT, SEND_MESSAGE_COMMAND_TYPE } from "@/constant/constant";
|
||||||
|
import ModuleTitle from "@/components/ModuleTitle/index.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
themeName: {
|
||||||
|
type: String,
|
||||||
|
default: "快捷提问",
|
||||||
|
},
|
||||||
|
recommendPostsList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [
|
||||||
|
{
|
||||||
|
title: "小七孔古桥",
|
||||||
|
subTitle: "小七孔古桥",
|
||||||
|
coverPhoto: "https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&q=80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "翠谷瀑布",
|
||||||
|
subTitle: "翠谷瀑布",
|
||||||
|
coverPhoto: "https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&q=80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "鸳鸯湖",
|
||||||
|
subTitle: "鸳鸯湖",
|
||||||
|
coverPhoto: "https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&q=80",
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "卧龙潭",
|
||||||
|
subTitle: "卧龙潭",
|
||||||
|
coverPhoto: "https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&q=80",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const sendReply = (item) => {
|
||||||
|
if (item.userInputContentType && item.userInputContentType === '1') {
|
||||||
|
const commonItem = { type: item.userInputContent, title: item.topic }
|
||||||
|
uni.$emit(SEND_MESSAGE_COMMAND_TYPE, commonItem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uni.$emit(SEND_MESSAGE_CONTENT_TEXT, item.userInputContent);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "./styles/index.scss";
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
.container-scroll {
|
||||||
|
margin: 4px 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-item {
|
||||||
|
width: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-img {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
@@ -1,14 +1,22 @@
|
|||||||
<template>
|
<template>
|
||||||
<AiTabSwitch v-model="tabIndex" :list="['探索发现', 'AI伴游']" @change="handleChange" />
|
<view>
|
||||||
|
<FindTabs v-model="activeIndex" @change="handleTabChange" />
|
||||||
|
<QuickQuestions />
|
||||||
|
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import AiTabSwitch from "@/components/AiTabSwitch/index.vue";
|
import FindTabs from "./components/FindTabs/index.vue";
|
||||||
|
import QuickQuestions from "./components/QuickQuestions/index.vue";
|
||||||
|
|
||||||
const tabIndex = ref(0);
|
const activeIndex = ref(0);
|
||||||
|
|
||||||
const handleChange = (i) => {
|
const handleTabChange = (index) => {
|
||||||
console.log("切换:", i);
|
activeIndex.value = index;
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -27,25 +27,9 @@
|
|||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<view>
|
<view class="tab-content">
|
||||||
<view
|
<Discovery v-if="tabIndex === 0" />
|
||||||
class="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center"
|
<ChatMainList v-if="tabIndex === 1" />
|
||||||
>
|
|
||||||
<text class="font-size-24 font-bold color-white mb-4"
|
|
||||||
>欢迎来到AI助手</text
|
|
||||||
>
|
|
||||||
<text class="font-size-16 color-white mb-8"
|
|
||||||
>您的智能聊天伴侣,随时为您提供帮助</text
|
|
||||||
>
|
|
||||||
<view class="flex space-x-4">
|
|
||||||
<view class="px-6 py-2 bg-green-500 text-white rounded-lg"
|
|
||||||
>开始聊天</view
|
|
||||||
>
|
|
||||||
<view class="px-6 py-2 bg-gray-300 text-gray-700 rounded-lg"
|
|
||||||
>了解更多</view
|
|
||||||
>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -57,8 +41,9 @@ import { onLoad } from "@dcloudio/uni-app";
|
|||||||
|
|
||||||
import HomeNavBar from "./components/HomeNavBar.vue";
|
import HomeNavBar from "./components/HomeNavBar.vue";
|
||||||
import HomeWelcome from "./components/HomeWelcome.vue";
|
import HomeWelcome from "./components/HomeWelcome.vue";
|
||||||
|
|
||||||
import AiTabSwitch from "@/components/AiTabSwitch/index.vue";
|
import AiTabSwitch from "@/components/AiTabSwitch/index.vue";
|
||||||
|
import ChatMainList from "../ChatMain/ChatMainList/index.vue";
|
||||||
|
import Discovery from "../Discovery/index.vue";
|
||||||
|
|
||||||
const tabIndex = ref(0);
|
const tabIndex = ref(0);
|
||||||
|
|
||||||
@@ -80,7 +65,5 @@ onLoad(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.bg-color {
|
|
||||||
background: red;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -40,6 +40,10 @@
|
|||||||
color: #ff3d60;
|
color: #ff3d60;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-94A3B8 {
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
.theme-color-500 {
|
.theme-color-500 {
|
||||||
color: $theme-color-500;
|
color: $theme-color-500;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rounded-14 {
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
.rounded-16 {
|
.rounded-16 {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user