14 changed files with 2170 additions and 19 deletions
-
134components/login-prompt.vue
-
7main.js
-
6package-lock.json
-
93pages.json
-
678pages/deepMate/deepMate.vue
-
399pages/start/Registration/Registration.vue
-
13pages/start/agreement/agreement.vue
-
134pages/start/components/login-prompt/login-prompt.vue
-
55pages/start/index/index.vue
-
371pages/start/login/login.vue
-
13pages/start/privacy/privacy.vue
-
194pages/start/select/select.vue
-
40pages/start/startup/startup.vue
-
18vue.config.js
@ -0,0 +1,134 @@ |
|||||
|
<template> |
||||
|
<view class="login-prompt" v-if="showPrompt"> |
||||
|
<view class="mask" :class="{ 'mask-show': showAnimation }" @click="hide"></view> |
||||
|
<view class="prompt-content" :class="{ 'slide-up': showAnimation }"> |
||||
|
<text class="prompt-title">登录以获得更好的体验</text> |
||||
|
<button class="login-btn" @click="goLogin">登录(推荐)</button> |
||||
|
<button class="visitor-btn" @click="continueAsVisitor">以访客身份继续</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, nextTick } from 'vue'; |
||||
|
|
||||
|
// 定义响应式数据 |
||||
|
const showPrompt = ref(false); |
||||
|
const showAnimation = ref(false); |
||||
|
|
||||
|
// 显示弹窗 |
||||
|
const show = () => { |
||||
|
showPrompt.value = true; |
||||
|
// 在下一帧触发动画 |
||||
|
nextTick(() => { |
||||
|
setTimeout(() => { |
||||
|
showAnimation.value = true; |
||||
|
}, 10); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// 隐藏弹窗 |
||||
|
const hide = () => { |
||||
|
showAnimation.value = false; |
||||
|
// 等待动画结束后再隐藏 |
||||
|
setTimeout(() => { |
||||
|
showPrompt.value = false; |
||||
|
}, 300); |
||||
|
}; |
||||
|
|
||||
|
// 跳转到登录页面 |
||||
|
const goLogin = () => { |
||||
|
uni.navigateTo({ |
||||
|
url: '/pages/login/login' |
||||
|
}); |
||||
|
hide(); |
||||
|
}; |
||||
|
|
||||
|
// 以访客身份继续 |
||||
|
const continueAsVisitor = () => { |
||||
|
// 设置访客模式 |
||||
|
uni.setStorageSync('visitorMode', true); |
||||
|
hide(); |
||||
|
}; |
||||
|
|
||||
|
// 暴露方法给外部使用 |
||||
|
defineExpose({ |
||||
|
show, |
||||
|
hide |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.login-prompt { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
z-index: 999; |
||||
|
} |
||||
|
|
||||
|
.mask { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background-color: rgba(0, 0, 0, 0.8); |
||||
|
opacity: 0; |
||||
|
transition: opacity 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.mask.mask-show { |
||||
|
opacity: 1; |
||||
|
} |
||||
|
|
||||
|
.prompt-content { |
||||
|
position: absolute; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
height: 300rpx; |
||||
|
border-radius: 20rpx 20rpx 0 0; |
||||
|
background-color: white; |
||||
|
padding: 20rpx 30rpx; |
||||
|
transform: translateY(100%); |
||||
|
transition: transform 0.3s ease; |
||||
|
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.3); |
||||
|
} |
||||
|
|
||||
|
.prompt-content.slide-up { |
||||
|
transform: translateY(0); |
||||
|
} |
||||
|
|
||||
|
.prompt-title { |
||||
|
display: block; |
||||
|
text-align: left; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 700; |
||||
|
color: #333; |
||||
|
margin-top: 10rpx; |
||||
|
margin-bottom: 30rpx; |
||||
|
} |
||||
|
|
||||
|
.login-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color:rgb(35, 84, 230); |
||||
|
color: white; |
||||
|
font-size: 32rpx; |
||||
|
line-height: 80rpx; |
||||
|
border-radius: 40rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.visitor-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color: #f5f5f5; |
||||
|
color: #333; |
||||
|
font-size: 32rpx; |
||||
|
line-height: 80rpx; |
||||
|
border-radius: 40rpx; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,6 @@ |
|||||
|
{ |
||||
|
"name": "deepChartVueApp", |
||||
|
"lockfileVersion": 3, |
||||
|
"requires": true, |
||||
|
"packages": {} |
||||
|
} |
||||
@ -0,0 +1,678 @@ |
|||||
|
<template> |
||||
|
<view class="deepMate-page"> |
||||
|
<!-- 顶部导航栏 --> |
||||
|
<view class="header" :style="{ paddingTop: safeAreaInsets?.top + 'px' }"> |
||||
|
<view class="header-left"> |
||||
|
<image src="../../static/icons/headset.png" class="icon"></image> |
||||
|
</view> |
||||
|
<view class="header-center"> |
||||
|
<text class="title">DeepMate</text> |
||||
|
</view> |
||||
|
<view class="header-right"> |
||||
|
<image src="../../static/icons/bell.png" class="icon"></image> |
||||
|
<image src="../../static/icons/clock.png" class="icon"></image> |
||||
|
<!-- 新增新会话按钮 |
||||
|
<button class="new-chat-button" @click="newChat"> |
||||
|
<text class="new-chat-text">新会话</text> |
||||
|
</button> --> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 主要内容区域 --> |
||||
|
<view class="main-content"> |
||||
|
<!-- 机器人头像和欢迎语 --> |
||||
|
<view class="robot-container" v-if="messages.length === 0"> |
||||
|
<image src="/static/robot.png" class="robot-avatar"></image> |
||||
|
<view class="welcome-message"> |
||||
|
<text class="greeting">Hi, 我是您的股市随身顾问~</text> |
||||
|
<text class="description">个股诊断、市场情绪解读,都可以找我。</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 功能标签栏 --> |
||||
|
<view class="function-tabs" v-if="messages.length === 0"> |
||||
|
<view class="tab-item ">个股诊断</view> |
||||
|
<view class="tab-item">市场情绪温度计</view> |
||||
|
<view class="tab-item">买卖时机提示</view> |
||||
|
<view class="tab-item">个股</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 特斯拉推荐卡片 --> |
||||
|
<view class="recommend-card" v-if="messages.length === 0"> |
||||
|
<view class="card-content"> |
||||
|
<image src="../../static/images/tesla-logo.png" class="logo"></image> |
||||
|
<view class="card-text"> |
||||
|
<text class="main-question">当前特斯拉该如何布局?</text> |
||||
|
<text class="stock-code">TSLA</text> |
||||
|
</view> |
||||
|
<image src="/static/icons/arrow-right.png" class="arrow-icon"></image> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 可能感兴趣的话题 --> |
||||
|
<view v-if="messages.length === 0" class="interest-section"> |
||||
|
<text class="section-title">- 您可能感兴趣 -</text> |
||||
|
<view class="topics-list"> |
||||
|
<view class="topic-item" v-for="topic in hotTopics" :key="topic.id"> |
||||
|
<image |
||||
|
:src="topic.icon" |
||||
|
class="tag-icon" |
||||
|
></image> |
||||
|
<text class="topic-text" @click="sendMessageList(topic.text)">{{ topic.text }}</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 聊天区域 --> |
||||
|
<view class="chat-container" v-if="messages.length > 0"> |
||||
|
<view class="message-list" id="messageList"> |
||||
|
<view |
||||
|
v-for="(message, index) in messages" |
||||
|
:key="index" |
||||
|
:class=" |
||||
|
message.isUser ? 'message user-message' : 'message bot-message' |
||||
|
" |
||||
|
> |
||||
|
<!-- 会话图标 --> |
||||
|
<text |
||||
|
:class=" |
||||
|
message.isUser |
||||
|
? 'fa-solid fa-user message-icon' |
||||
|
: 'fa-solid fa-robot message-icon' |
||||
|
" |
||||
|
></text> |
||||
|
<!-- 会话内容 --> |
||||
|
<view class="message-content"> |
||||
|
<text class="message-text">{{ message.content }}</text> |
||||
|
<!-- loading --> |
||||
|
<view |
||||
|
class="loading-dots" |
||||
|
v-if="message.isThinking || message.isTyping" |
||||
|
> |
||||
|
<text class="dot"></text> |
||||
|
<text class="dot"></text> |
||||
|
<text class="dot"></text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 输入框区域 --> |
||||
|
<view class="input-area"> |
||||
|
<view class="input-wrapper"> |
||||
|
<image src="../../static/icons/mic.png" class="mic-icon"></image> |
||||
|
<input |
||||
|
type="text" |
||||
|
placeholder="请输入股票代码/名称,获取AI洞察" |
||||
|
class="input-field" |
||||
|
v-model="inputMessage" |
||||
|
@confirm="sendMessage" |
||||
|
/> |
||||
|
<button class="send-button" @click="sendMessage" :disabled="isSending"> |
||||
|
<image |
||||
|
src="/static/icons/send.png" |
||||
|
class="send-icon" |
||||
|
></image> |
||||
|
</button> |
||||
|
</view> |
||||
|
<text class="disclaimer" |
||||
|
>以上数据由AI生成,不作为最终投资建议,决策需独立!</text |
||||
|
> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
const { safeAreaInsets } = uni.getSystemInfoSync(); |
||||
|
|
||||
|
import { ref, onMounted, nextTick } from "vue"; |
||||
|
|
||||
|
const inputMessage = ref(""); |
||||
|
const isSending = ref(false); |
||||
|
const uuid = ref(""); |
||||
|
const messages = ref([]); |
||||
|
const hotTopics = ref([ |
||||
|
{ |
||||
|
id: 1, |
||||
|
text: '英伟达(NVDA)股票情绪温度?', |
||||
|
icon: '../../static/icons/hot-tag.png' |
||||
|
}, |
||||
|
{ |
||||
|
id: 2, |
||||
|
text: '博通(AVGO)明天还能涨吗?', |
||||
|
icon: '../../static/icons/hot-tag.png' |
||||
|
}, |
||||
|
{ |
||||
|
id: 3, |
||||
|
text: '为什么Fluence Energy(FLNC)会暴涨?', |
||||
|
icon: '../../static/icons/hot-tag.png' |
||||
|
}, |
||||
|
{ |
||||
|
id: 4, |
||||
|
text: '为什么Fluence Energy(FLNC)会暴涨?', |
||||
|
icon: '../../static/icons/hot-tag.png' |
||||
|
} |
||||
|
]); |
||||
|
|
||||
|
// 初始化 |
||||
|
onMounted(() => { |
||||
|
initUUID(); |
||||
|
// 如果有历史消息,滚动到底部 |
||||
|
if (messages.value.length > 0) { |
||||
|
nextTick(() => { |
||||
|
scrollToBottom(); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// 初始化 UUID |
||||
|
const initUUID = () => { |
||||
|
let storedUUID = uni.getStorageSync('user_uuid'); |
||||
|
if (!storedUUID) { |
||||
|
storedUUID = generateUUID(); |
||||
|
uni.setStorageSync('user_uuid', storedUUID); |
||||
|
} |
||||
|
uuid.value = storedUUID; |
||||
|
}; |
||||
|
|
||||
|
// 生成简单UUID |
||||
|
const generateUUID = () => { |
||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { |
||||
|
var r = Math.random() * 16 | 0, |
||||
|
v = c == 'x' ? r : (r & 0x3 | 0x8); |
||||
|
return v.toString(16); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// 新会话 |
||||
|
const newChat = () => { |
||||
|
messages.value = []; |
||||
|
uni.removeStorageSync('user_uuid'); |
||||
|
initUUID(); |
||||
|
}; |
||||
|
|
||||
|
// 发送消息 |
||||
|
const sendMessage = () => { |
||||
|
if (inputMessage.value.trim() === "" || isSending.value) return; |
||||
|
|
||||
|
const userMessage = { |
||||
|
content: inputMessage.value, |
||||
|
isUser: true, |
||||
|
isThinking: false, |
||||
|
isTyping: false |
||||
|
}; |
||||
|
|
||||
|
messages.value.push(userMessage); |
||||
|
inputMessage.value = ""; |
||||
|
|
||||
|
// 滚动到底部 |
||||
|
nextTick(() => { |
||||
|
scrollToBottom(); |
||||
|
}); |
||||
|
|
||||
|
// 模拟机器人回复 |
||||
|
simulateBotResponse(userMessage.content); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
// 发送消息 |
||||
|
const sendMessageList = (listMessage) => { |
||||
|
|
||||
|
console.log(listMessage); |
||||
|
|
||||
|
|
||||
|
const userMessage = { |
||||
|
content: listMessage, |
||||
|
isUser: true, |
||||
|
isThinking: false, |
||||
|
isTyping: false |
||||
|
}; |
||||
|
|
||||
|
messages.value.push(userMessage); |
||||
|
inputMessage.value = ""; |
||||
|
|
||||
|
// 滚动到底部 |
||||
|
nextTick(() => { |
||||
|
scrollToBottom(); |
||||
|
}); |
||||
|
|
||||
|
// 模拟机器人回复 |
||||
|
simulateBotResponse(userMessage.content); |
||||
|
}; |
||||
|
|
||||
|
// 模拟机器人回复 |
||||
|
const simulateBotResponse = (userMessage) => { |
||||
|
isSending.value = true; |
||||
|
|
||||
|
// 添加机器人加载消息 |
||||
|
const botMsg = { |
||||
|
content: "", |
||||
|
isUser: false, |
||||
|
isTyping: true, |
||||
|
isThinking: false |
||||
|
}; |
||||
|
|
||||
|
messages.value.push(botMsg); |
||||
|
|
||||
|
// 滚动到底部 |
||||
|
nextTick(() => { |
||||
|
scrollToBottom(); |
||||
|
}); |
||||
|
|
||||
|
// 模拟流式响应 |
||||
|
let responseText = `我已经收到您的消息: "${userMessage}"。作为您的股市顾问,我可以为您提供专业的投资建议。请问您想了解哪方面的信息?`; |
||||
|
let index = 0; |
||||
|
|
||||
|
const typeWriter = () => { |
||||
|
if (index < responseText.length) { |
||||
|
botMsg.content += responseText.charAt(index); |
||||
|
index++; |
||||
|
|
||||
|
// 滚动到底部 |
||||
|
scrollToBottom(); |
||||
|
|
||||
|
setTimeout(typeWriter, 30); |
||||
|
} else { |
||||
|
botMsg.isTyping = false; |
||||
|
isSending.value = false; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
setTimeout(typeWriter, 500); |
||||
|
}; |
||||
|
|
||||
|
// 滚动到底部 |
||||
|
const scrollToBottom = () => { |
||||
|
const query = uni.createSelectorQuery(); |
||||
|
query.select('#messageList').boundingClientRect(); |
||||
|
query.selectViewport().scrollOffset(); |
||||
|
|
||||
|
query.exec((res) => { |
||||
|
if (res[0] && res[1]) { |
||||
|
uni.pageScrollTo({ |
||||
|
scrollTop: res[0].height, |
||||
|
duration: 100 |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.deepMate-page { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
height: 100vh; |
||||
|
background-color: #ffffff; |
||||
|
padding: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.header { |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 20rpx 30rpx; |
||||
|
background-color: #ffffff; |
||||
|
} |
||||
|
|
||||
|
.header-left, |
||||
|
.header-right { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.header-left .icon, |
||||
|
.header-right .icon { |
||||
|
width: 40rpx; |
||||
|
height: 40rpx; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.header-center .title { |
||||
|
|
||||
|
|
||||
|
font-size: 36rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333333; |
||||
|
} |
||||
|
|
||||
|
.new-chat-button { |
||||
|
background-color: #ff6600; |
||||
|
border: none; |
||||
|
border-radius: 8rpx; |
||||
|
padding: 10rpx 20rpx; |
||||
|
} |
||||
|
|
||||
|
.new-chat-text { |
||||
|
color: white; |
||||
|
font-size: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.main-content { |
||||
|
flex: 1; |
||||
|
padding: 30rpx; |
||||
|
overflow-y: auto; |
||||
|
margin-bottom: 120rpx; |
||||
|
} |
||||
|
|
||||
|
.robot-container { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-bottom: 30rpx; |
||||
|
} |
||||
|
|
||||
|
.robot-avatar { |
||||
|
width: 120rpx; |
||||
|
height: 120rpx; |
||||
|
border-radius: 50%; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.welcome-message { |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.greeting { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333333; |
||||
|
line-height: 48rpx; |
||||
|
} |
||||
|
|
||||
|
.description { |
||||
|
display: block; |
||||
|
font-size: 26rpx; |
||||
|
color: #666666; |
||||
|
line-height: 36rpx; |
||||
|
margin-top: 10rpx; |
||||
|
} |
||||
|
|
||||
|
.function-tabs { |
||||
|
display: flex; |
||||
|
margin-bottom: 30rpx; |
||||
|
} |
||||
|
|
||||
|
.tab-item { |
||||
|
padding: 5rpx 20rpx; |
||||
|
border-radius: 20rpx; |
||||
|
font-size: 20rpx; |
||||
|
font-weight: 700; |
||||
|
color: #666666; |
||||
|
background-color: #f0f0f0; |
||||
|
margin-right: 20rpx; |
||||
|
transition: all 0.3s; |
||||
|
} |
||||
|
|
||||
|
.tab-item.active { |
||||
|
color: #ff6600; |
||||
|
background-color: #fff; |
||||
|
border: 1rpx solid #ff6600; |
||||
|
} |
||||
|
|
||||
|
.recommend-card { |
||||
|
background: linear-gradient(180deg, #fee7ed 0%, #ffffff 100%); |
||||
|
border-radius: 20rpx; |
||||
|
padding: 30rpx; |
||||
|
margin-bottom: 30rpx; |
||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); |
||||
|
} |
||||
|
|
||||
|
.card-content { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.logo { |
||||
|
width: 80rpx; |
||||
|
height: 80rpx; |
||||
|
background-color: #ff0000; |
||||
|
border-radius: 10rpx; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.card-text { |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.main-question { |
||||
|
font-size: 32rpx; |
||||
|
color: #333333; |
||||
|
line-height: 48rpx; |
||||
|
} |
||||
|
|
||||
|
.stock-code { |
||||
|
display: block; |
||||
|
font-size: 24rpx; |
||||
|
color: #ff3b30; |
||||
|
background-color: #ffffff; |
||||
|
padding: 2rpx 15rpx; |
||||
|
border-radius: 12rpx; |
||||
|
margin-top: 8rpx; |
||||
|
width: fit-content; |
||||
|
border: 1rpx solid #ff3b30; |
||||
|
} |
||||
|
|
||||
|
.arrow-icon { |
||||
|
width: 32rpx; |
||||
|
height: 32rpx; |
||||
|
} |
||||
|
|
||||
|
.interest-section { |
||||
|
margin-bottom: 30rpx; |
||||
|
} |
||||
|
|
||||
|
.section-title { |
||||
|
display: block; |
||||
|
text-align: center; |
||||
|
font-size: 26rpx; |
||||
|
color: #666666; |
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.topics-list { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 15rpx; |
||||
|
} |
||||
|
|
||||
|
.topic-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 15rpx 20rpx; |
||||
|
background-color: #f0f0f0; |
||||
|
border-radius: 15rpx; |
||||
|
width: fit-content; |
||||
|
} |
||||
|
|
||||
|
.tag-icon { |
||||
|
width: 24rpx; |
||||
|
height: 24rpx; |
||||
|
margin-right: 10rpx; |
||||
|
} |
||||
|
|
||||
|
.topic-text { |
||||
|
font-size: 28rpx; |
||||
|
color: #333333; |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
/* 聊天区域样式 */ |
||||
|
.chat-container { |
||||
|
margin-top: 30rpx; |
||||
|
border-radius: 10rpx; |
||||
|
height: fit-content; |
||||
|
/* overflow-y: auto; */ |
||||
|
} |
||||
|
|
||||
|
.message-list { |
||||
|
/* padding: 20rpx; */ |
||||
|
} |
||||
|
|
||||
|
.message { |
||||
|
display: flex; |
||||
|
align-items: flex-start; |
||||
|
margin-bottom: 30rpx; |
||||
|
} |
||||
|
|
||||
|
.user-message { |
||||
|
flex-direction: row-reverse; |
||||
|
} |
||||
|
|
||||
|
.message-icon { |
||||
|
font-size: 24rpx; |
||||
|
margin: 0 10rpx; |
||||
|
padding: 10rpx; |
||||
|
border-radius: 50%; |
||||
|
background-color: #ddd; |
||||
|
width: 40rpx; |
||||
|
height: 40rpx; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
|
||||
|
.user-message .message-icon { |
||||
|
background-color: #007aff; |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
.bot-message .message-icon { |
||||
|
background-color: #34c759; |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
.message-content { |
||||
|
max-width: 70%; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.user-message .message-content { |
||||
|
background-color: #007aff; |
||||
|
border-radius: 10rpx; |
||||
|
padding: 15rpx; |
||||
|
} |
||||
|
|
||||
|
.bot-message .message-content { |
||||
|
background-color: #f0f0f0; |
||||
|
border-radius: 10rpx; |
||||
|
padding: 15rpx; |
||||
|
} |
||||
|
|
||||
|
.message-text { |
||||
|
font-size: 28rpx; |
||||
|
line-height: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.user-message .message-text { |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
.bot-message .message-text { |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.loading-dots { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding-top: 10rpx; |
||||
|
} |
||||
|
|
||||
|
.dot { |
||||
|
width: 10rpx; |
||||
|
height: 10rpx; |
||||
|
background-color: #666; |
||||
|
border-radius: 50%; |
||||
|
margin: 0 4rpx; |
||||
|
animation: loading 1.4s infinite ease-in-out both; |
||||
|
} |
||||
|
|
||||
|
.user-message .dot { |
||||
|
background-color: white; |
||||
|
} |
||||
|
|
||||
|
.dot:nth-child(1) { |
||||
|
animation-delay: -0.32s; |
||||
|
} |
||||
|
|
||||
|
.dot:nth-child(2) { |
||||
|
animation-delay: -0.16s; |
||||
|
} |
||||
|
|
||||
|
@keyframes loading { |
||||
|
0%, |
||||
|
80%, |
||||
|
100% { |
||||
|
transform: scale(0); |
||||
|
} |
||||
|
40% { |
||||
|
transform: scale(1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.input-area { |
||||
|
position: fixed; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
padding: 0 40rpx 80rpx 40rpx; |
||||
|
background-color: #ffffff; |
||||
|
} |
||||
|
|
||||
|
.input-wrapper { |
||||
|
position: relative; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 15rpx 20rpx; |
||||
|
background-color: rgb(220, 31, 29); |
||||
|
border-radius: 100rpx; |
||||
|
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1); |
||||
|
height: 50rpx; |
||||
|
} |
||||
|
|
||||
|
.mic-icon { |
||||
|
width: 36rpx; |
||||
|
height: 36rpx; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.input-field { |
||||
|
flex: 1; |
||||
|
font-size: 28rpx; |
||||
|
color: #ffffff; |
||||
|
background: none; |
||||
|
border: none; |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
.input-field::placeholder { |
||||
|
color: #ffffff !important; |
||||
|
opacity: 1; |
||||
|
} |
||||
|
|
||||
|
.send-button { |
||||
|
background: none; |
||||
|
border: none; |
||||
|
padding: 0; |
||||
|
margin-left: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.send-icon { |
||||
|
width: 36rpx; |
||||
|
height: 36rpx; |
||||
|
} |
||||
|
|
||||
|
.disclaimer { |
||||
|
font-size: 15rpx; |
||||
|
color: #999999; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
margin-top: 15rpx; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,399 @@ |
|||||
|
<template> |
||||
|
<view class="login-registration-container"> |
||||
|
<!-- 自定义导航栏 --> |
||||
|
<view class="custom-navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }"> |
||||
|
<view class="nav-left"> |
||||
|
<text class="back-btn" @click="goToLogin"><</text> |
||||
|
</view> |
||||
|
<view class="nav-right"> |
||||
|
<text class="headphone-btn">🎧</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- Logo --> |
||||
|
<image class="logo" src="/static/logo.png" mode="aspectFit"></image> |
||||
|
|
||||
|
<!-- 欢迎语 --> |
||||
|
<text class="welcome-text">欢迎来到 DeepChart</text> |
||||
|
|
||||
|
<!-- 邮箱/手机号切换 --> |
||||
|
<view class="switch-container"> |
||||
|
<text |
||||
|
class="switch-item" |
||||
|
:class="{ active: switchType === 'Email' }" |
||||
|
@click="switchEmail">邮箱</text> |
||||
|
<text |
||||
|
class="switch-item" |
||||
|
:class="{ active: switchType === 'Phone' }" |
||||
|
@click="switchPhone">手机号</text> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 输入框 --> |
||||
|
<view class="input-container"> |
||||
|
<input |
||||
|
v-if="switchType === 'Email'" |
||||
|
class="input-field" |
||||
|
type="text" |
||||
|
placeholder="输入邮箱地址" |
||||
|
v-model="email" |
||||
|
/> |
||||
|
<input |
||||
|
v-else |
||||
|
class="input-field" |
||||
|
type="text" |
||||
|
placeholder="输入手机号" |
||||
|
v-model="phone" |
||||
|
/> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 用户协议 --> |
||||
|
<view class="agreement-container"> |
||||
|
<checkbox class="checkbox" @click="checkboxClick"/> |
||||
|
<text class="agreement-text" |
||||
|
>接受 <text class="link" @click="openAgreement">用户协议</text> 和 |
||||
|
<text class="link" @click="openPrivacy">隐私政策</text></text |
||||
|
> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 注册按钮 --> |
||||
|
<button class="register-btn" @click="register">注册</button> |
||||
|
|
||||
|
<!-- 或者 --> |
||||
|
<text class="or-text">或者</text> |
||||
|
|
||||
|
<!-- 第三方登录 --> |
||||
|
<view class="third-party-login"> |
||||
|
<view class="third-party-btn" @click="loginWithApple"> |
||||
|
<image |
||||
|
class="apple-icon" |
||||
|
src="/static/apple-icon.png" |
||||
|
mode="aspectFit" |
||||
|
></image> |
||||
|
<text class="third-party-text">通过 Apple 继续</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="third-party-btn" @click="loginWithGoogle"> |
||||
|
<image |
||||
|
class="google-icon" |
||||
|
src="/static/google-icon.png" |
||||
|
mode="aspectFit" |
||||
|
></image> |
||||
|
<text class="third-party-text">通过 Google 继续</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 已有账号 --> |
||||
|
<view class="existing-account"> |
||||
|
<text class="account-text">已有账号?</text> |
||||
|
<text class="login-link" @click="goToLogin">登录</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref } from 'vue'; |
||||
|
|
||||
|
const email = ref(""); |
||||
|
const phone = ref(""); |
||||
|
const agreed = ref(false); |
||||
|
const switchType = ref("Email"); // 默认是邮箱注册 |
||||
|
const { safeAreaInsets } = uni.getSystemInfoSync() |
||||
|
|
||||
|
|
||||
|
function goBack() { |
||||
|
// 返回上一页 |
||||
|
uni.navigateBack(-1); |
||||
|
} |
||||
|
|
||||
|
function switchEmail() { |
||||
|
// 切换到邮箱注册 |
||||
|
switchType.value = "Email"; |
||||
|
} |
||||
|
|
||||
|
function switchPhone() { |
||||
|
// 切换到手机注册 |
||||
|
switchType.value = "Phone"; |
||||
|
} |
||||
|
|
||||
|
function checkboxClick() { |
||||
|
agreed.value = !agreed.value; |
||||
|
} |
||||
|
|
||||
|
function openAgreement() { |
||||
|
// 打开用户协议 |
||||
|
console.log("打开用户协议"); |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/agreement/agreement", |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function openPrivacy() { |
||||
|
// 打开隐私政策 |
||||
|
console.log("打开隐私政策"); |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/privacy/privacy", |
||||
|
}); |
||||
|
} |
||||
|
function register() { |
||||
|
// 注册逻辑 |
||||
|
if (switchType.value === "Email" && !email.value) { |
||||
|
uni.showToast({ |
||||
|
title: "请输入邮箱地址", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (switchType.value === "Phone" && !phone.value) { |
||||
|
uni.showToast({ |
||||
|
title: "请输入手机号", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!agreed.value) { |
||||
|
uni.showToast({ |
||||
|
title: "请同意用户协议和隐私政策", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 发送注册请求 |
||||
|
if (switchType.value === "Email") { |
||||
|
console.log("邮箱注册:", email.value); |
||||
|
} else { |
||||
|
console.log("手机号注册:", phone.value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function loginWithApple() { |
||||
|
// Apple登录逻辑 |
||||
|
console.log("通过Apple登录"); |
||||
|
} |
||||
|
|
||||
|
function loginWithGoogle() { |
||||
|
// Google登录逻辑 |
||||
|
console.log("通过Google登录"); |
||||
|
} |
||||
|
|
||||
|
function goToLogin() { |
||||
|
// 跳转到登录页 |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/login/login", |
||||
|
}); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.login-registration-container { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
padding: 0 40rpx; |
||||
|
height: 100vh; |
||||
|
background-color: #ffffff; |
||||
|
} |
||||
|
|
||||
|
/* 自定义导航栏样式 */ |
||||
|
.custom-navbar { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
/* z-index: 999; */ |
||||
|
width: 90%; |
||||
|
height: 80rpx; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 10rpx 40rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.nav-left, |
||||
|
.nav-right { |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.nav-right { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
} |
||||
|
|
||||
|
.back-btn, |
||||
|
.headphone-btn { |
||||
|
font-size: 36rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333333; |
||||
|
padding: 10rpx; |
||||
|
} |
||||
|
|
||||
|
.logo { |
||||
|
width: 120rpx; |
||||
|
height: 120rpx; |
||||
|
margin-bottom: 60rpx; |
||||
|
border-radius: 20%; |
||||
|
} |
||||
|
|
||||
|
.welcome-text { |
||||
|
font-size: 48rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333333; |
||||
|
margin-bottom: 60rpx; |
||||
|
text-align: left; |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
.switch-container { |
||||
|
display: flex; |
||||
|
margin-bottom: 40rpx; |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
|
||||
|
.switch-item { |
||||
|
font-size: 28rpx; |
||||
|
color: #999999; |
||||
|
padding: 10rpx 20rpx; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.switch-item::after { |
||||
|
content: ''; |
||||
|
position: absolute; |
||||
|
bottom: 0; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
width: 60%; /* 控制边框宽度 */ |
||||
|
height: 2rpx; |
||||
|
background-color: transparent; |
||||
|
} |
||||
|
|
||||
|
.switch-item.active { |
||||
|
color: #333333; |
||||
|
font-weight: 700; |
||||
|
} |
||||
|
|
||||
|
.switch-item.active::after { |
||||
|
content: ''; |
||||
|
position: absolute; |
||||
|
top: 60rpx; |
||||
|
bottom: 0; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
width: 30%; /* 控制边框宽度 */ |
||||
|
height: 7rpx; |
||||
|
background-color: #333333; |
||||
|
} |
||||
|
|
||||
|
.input-container { |
||||
|
width: 100%; |
||||
|
margin-bottom: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.input-field { |
||||
|
width: 90%; |
||||
|
height: 80rpx; |
||||
|
border-radius: 20rpx; |
||||
|
border: 2rpx solid #e5e5e5; |
||||
|
padding: 0 30rpx; |
||||
|
font-size: 28rpx; |
||||
|
color: #333333; |
||||
|
background-color: #f5f5f5; |
||||
|
} |
||||
|
|
||||
|
.agreement-container { |
||||
|
/* display: flex; */ |
||||
|
align-items: center; |
||||
|
margin-bottom: 40rpx; |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
|
||||
|
.checkbox { |
||||
|
width: 10rpx; |
||||
|
height: 10rpx; |
||||
|
margin-right: 30rpx; |
||||
|
/* flex: content; */ |
||||
|
} |
||||
|
|
||||
|
.agreement-text { |
||||
|
margin-left: 20rpx; |
||||
|
font-size: 24rpx; |
||||
|
color: #666666; |
||||
|
} |
||||
|
|
||||
|
.link { |
||||
|
color: #333333; |
||||
|
font-weight: bold; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
|
||||
|
.register-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color: #333333; |
||||
|
color: white; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: bold; |
||||
|
border-radius: 40rpx; |
||||
|
margin-bottom: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.or-text { |
||||
|
font-size: 24rpx; |
||||
|
color: #999999; |
||||
|
margin-bottom: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.third-party-login { |
||||
|
width: 100%; |
||||
|
margin-bottom: 60rpx; |
||||
|
} |
||||
|
.third-party-text { |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
.third-party-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color: white; |
||||
|
border: 2rpx solid rgb(249, 249, 249); |
||||
|
border-radius: 20rpx; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
margin-bottom: 20rpx; |
||||
|
font-size: 28rpx; |
||||
|
color: #333333; |
||||
|
} |
||||
|
|
||||
|
.apple-icon { |
||||
|
width: 30rpx; |
||||
|
height: 30rpx; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.google-icon { |
||||
|
width: 30rpx; |
||||
|
height: 30rpx; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.existing-account { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.account-text { |
||||
|
font-size: 24rpx; |
||||
|
color: #666666; |
||||
|
} |
||||
|
|
||||
|
.login-link { |
||||
|
font-size: 24rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333333; |
||||
|
margin-left: 10rpx; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,13 @@ |
|||||
|
<template> |
||||
|
<view> |
||||
|
用户协议 |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
|
||||
|
</style> |
||||
@ -0,0 +1,134 @@ |
|||||
|
<template> |
||||
|
<view class="login-prompt" v-if="showPrompt"> |
||||
|
<view class="mask" :class="{ 'mask-show': showAnimation }" @click="hide"></view> |
||||
|
<view class="prompt-content" :class="{ 'slide-up': showAnimation }"> |
||||
|
<text class="prompt-title">登录以获得更好的体验</text> |
||||
|
<button class="login-btn" @click="goLogin">登录(推荐)</button> |
||||
|
<button class="visitor-btn" @click="continueAsVisitor">以访客身份继续</button> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, nextTick } from 'vue'; |
||||
|
|
||||
|
// 定义响应式数据 |
||||
|
const showPrompt = ref(false); |
||||
|
const showAnimation = ref(false); |
||||
|
|
||||
|
// 显示弹窗 |
||||
|
const show = () => { |
||||
|
showPrompt.value = true; |
||||
|
// 在下一帧触发动画 |
||||
|
nextTick(() => { |
||||
|
setTimeout(() => { |
||||
|
showAnimation.value = true; |
||||
|
}, 10); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// 隐藏弹窗 |
||||
|
const hide = () => { |
||||
|
showAnimation.value = false; |
||||
|
// 等待动画结束后再隐藏 |
||||
|
setTimeout(() => { |
||||
|
showPrompt.value = false; |
||||
|
}, 300); |
||||
|
}; |
||||
|
|
||||
|
// 跳转到登录页面 |
||||
|
const goLogin = () => { |
||||
|
uni.navigateTo({ |
||||
|
url: '/pages/login/login' |
||||
|
}); |
||||
|
hide(); |
||||
|
}; |
||||
|
|
||||
|
// 以访客身份继续 |
||||
|
const continueAsVisitor = () => { |
||||
|
// 设置访客模式 |
||||
|
uni.setStorageSync('visitorMode', true); |
||||
|
hide(); |
||||
|
}; |
||||
|
|
||||
|
// 暴露方法给外部使用 |
||||
|
defineExpose({ |
||||
|
show, |
||||
|
hide |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.login-prompt { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
z-index: 999; |
||||
|
} |
||||
|
|
||||
|
.mask { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background-color: rgba(0, 0, 0, 0.8); |
||||
|
opacity: 0; |
||||
|
transition: opacity 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.mask.mask-show { |
||||
|
opacity: 1; |
||||
|
} |
||||
|
|
||||
|
.prompt-content { |
||||
|
position: absolute; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
height: 300rpx; |
||||
|
border-radius: 20rpx 20rpx 0 0; |
||||
|
background-color: white; |
||||
|
padding: 20rpx 30rpx; |
||||
|
transform: translateY(100%); |
||||
|
transition: transform 0.3s ease; |
||||
|
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.3); |
||||
|
} |
||||
|
|
||||
|
.prompt-content.slide-up { |
||||
|
transform: translateY(0); |
||||
|
} |
||||
|
|
||||
|
.prompt-title { |
||||
|
display: block; |
||||
|
text-align: left; |
||||
|
font-size: 28rpx; |
||||
|
font-weight: 700; |
||||
|
color: #333; |
||||
|
margin-top: 10rpx; |
||||
|
margin-bottom: 30rpx; |
||||
|
} |
||||
|
|
||||
|
.login-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color:rgb(35, 84, 230); |
||||
|
color: white; |
||||
|
font-size: 32rpx; |
||||
|
line-height: 80rpx; |
||||
|
border-radius: 40rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.visitor-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color: #f5f5f5; |
||||
|
color: #333; |
||||
|
font-size: 32rpx; |
||||
|
line-height: 80rpx; |
||||
|
border-radius: 40rpx; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,55 @@ |
|||||
|
<template> |
||||
|
<view class="content"> |
||||
|
<image class="logo" src="/static/logo.png"></image> |
||||
|
<view class="text-area"> |
||||
|
<text class="title" @click="showLoginPrompt">{{ title }}</text> |
||||
|
</view> |
||||
|
<LoginPrompt ref="loginPrompt"></LoginPrompt> |
||||
|
<button @click="toDeepMate">deepMate</button> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref } from "vue"; |
||||
|
|
||||
|
const title = ref("请先登录"); |
||||
|
const loginPrompt = ref(null); |
||||
|
|
||||
|
function showLoginPrompt() { |
||||
|
loginPrompt.value.show(); |
||||
|
} |
||||
|
|
||||
|
function toDeepMate() { |
||||
|
uni.navigateTo({ |
||||
|
url: '/pages/deepMate/deepMate' |
||||
|
}) |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
.content { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
|
||||
|
.logo { |
||||
|
height: 200rpx; |
||||
|
width: 200rpx; |
||||
|
margin-top: 200rpx; |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
margin-bottom: 50rpx; |
||||
|
} |
||||
|
|
||||
|
.text-area { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
} |
||||
|
|
||||
|
.title { |
||||
|
font-size: 36rpx; |
||||
|
color: #8f8f94; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,371 @@ |
|||||
|
<template> |
||||
|
<view |
||||
|
class="login-registration-container" |
||||
|
|
||||
|
> |
||||
|
<!-- 自定义导航栏 --> |
||||
|
<view class="custom-navbar" :style="{ paddingTop: safeAreaInsets?.top + 'px' }"> |
||||
|
<view class="nav-left"> |
||||
|
<text class="back-btn" @click="goToIndex"><</text> |
||||
|
</view> |
||||
|
<view class="nav-right"> |
||||
|
<text class="headphone-btn">🎧</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- Logo --> |
||||
|
<image class="logo" src="/static/logo.png" mode="aspectFit"></image> |
||||
|
|
||||
|
<!-- 欢迎语 --> |
||||
|
<text class="welcome-text">登录</text> |
||||
|
|
||||
|
<!-- 邮箱/手机号切换 --> |
||||
|
<view class="switch-container"> |
||||
|
<text |
||||
|
class="switch-item" |
||||
|
:class="{ active: switchType === 'Email' }" |
||||
|
@click="switchEmail" |
||||
|
>邮箱/用户名</text |
||||
|
> |
||||
|
<text |
||||
|
class="switch-item" |
||||
|
:class="{ active: switchType === 'Phone' }" |
||||
|
@click="switchPhone" |
||||
|
>手机号</text |
||||
|
> |
||||
|
</view> |
||||
|
<!-- 输入框 --> |
||||
|
<view class="input-container"> |
||||
|
<input |
||||
|
v-if="switchType === 'Email'" |
||||
|
class="input-field" |
||||
|
type="text" |
||||
|
placeholder="输入邮箱/用户名" |
||||
|
v-model="email" |
||||
|
/> |
||||
|
<input |
||||
|
v-else |
||||
|
class="input-field" |
||||
|
type="text" |
||||
|
placeholder="输入手机号" |
||||
|
v-model="phone" |
||||
|
/> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 用户协议 --> |
||||
|
<!-- <view class="agreement-container"> |
||||
|
<checkbox class="checkbox" v-model="agreed" /> |
||||
|
<text class="agreement-text" |
||||
|
>接受 <text class="link">用户协议</text> 和 |
||||
|
<text class="link">隐私政策</text></text |
||||
|
> |
||||
|
</view> --> |
||||
|
|
||||
|
<!-- 注册按钮 --> |
||||
|
<button class="register-btn" @click="register">下一步</button> |
||||
|
|
||||
|
<!-- 或者 --> |
||||
|
<text class="or-text">或者</text> |
||||
|
|
||||
|
<!-- 第三方登录 --> |
||||
|
<view class="third-party-login"> |
||||
|
<view class="third-party-btn" @click="loginWithApple"> |
||||
|
<image |
||||
|
class="apple-icon" |
||||
|
src="/static/apple-icon.png" |
||||
|
mode="aspectFit" |
||||
|
></image> |
||||
|
<text class="third-party-text">通过 Apple 继续</text> |
||||
|
</view> |
||||
|
|
||||
|
<view class="third-party-btn" @click="loginWithGoogle"> |
||||
|
<image |
||||
|
class="google-icon" |
||||
|
src="/static/google-icon.png" |
||||
|
mode="aspectFit" |
||||
|
></image> |
||||
|
<text class="third-party-text">通过 Google 继续</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 已有账号 --> |
||||
|
<view class="existing-account"> |
||||
|
<text class="account-text">未注册账号?</text> |
||||
|
<text class="login-link" @click="goToRegistration">注册</text> |
||||
|
</view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref } from "vue"; |
||||
|
|
||||
|
const email = ref(""); |
||||
|
const phone = ref(""); |
||||
|
const agreed = ref(false); |
||||
|
const switchType = ref("Email"); // 默认是邮箱注册 |
||||
|
const { safeAreaInsets } = uni.getSystemInfoSync(); |
||||
|
|
||||
|
function goToIndex() { |
||||
|
// 返回上一页 |
||||
|
uni.navigateTo({ url: '/pages/index/index' }); |
||||
|
} |
||||
|
|
||||
|
function switchEmail() { |
||||
|
// 切换到邮箱注册 |
||||
|
switchType.value = "Email"; |
||||
|
} |
||||
|
|
||||
|
function switchPhone() { |
||||
|
// 切换到手机注册 |
||||
|
switchType.value = "Phone"; |
||||
|
} |
||||
|
|
||||
|
function register() { |
||||
|
// 注册逻辑 |
||||
|
if (!email.value) { |
||||
|
uni.showToast({ |
||||
|
title: "请输入邮箱地址", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
if (!agreed.value) { |
||||
|
uni.showToast({ |
||||
|
title: "请同意用户协议和隐私政策", |
||||
|
icon: "none", |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
// 发送注册请求 |
||||
|
console.log("注册:", email.value); |
||||
|
} |
||||
|
|
||||
|
function loginWithApple() { |
||||
|
// Apple登录逻辑 |
||||
|
console.log("通过Apple登录"); |
||||
|
} |
||||
|
|
||||
|
function loginWithGoogle() { |
||||
|
// Google登录逻辑 |
||||
|
console.log("通过Google登录"); |
||||
|
} |
||||
|
|
||||
|
function goToRegistration() { |
||||
|
// 跳转到登录页 |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/Registration/Registration", |
||||
|
}); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.login-registration-container { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
padding: 0 40rpx; |
||||
|
height: 100vh; |
||||
|
background-color: #ffffff; |
||||
|
} |
||||
|
|
||||
|
/* 自定义导航栏样式 */ |
||||
|
.custom-navbar { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
/* z-index: 999; */ |
||||
|
width: 90%; |
||||
|
height: 80rpx; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
padding: 10rpx 40rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.nav-left, |
||||
|
.nav-right { |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.nav-right { |
||||
|
display: flex; |
||||
|
justify-content: flex-end; |
||||
|
} |
||||
|
|
||||
|
.back-btn, |
||||
|
.headphone-btn { |
||||
|
font-size: 36rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333333; |
||||
|
padding: 10rpx; |
||||
|
} |
||||
|
|
||||
|
.logo { |
||||
|
width: 120rpx; |
||||
|
height: 120rpx; |
||||
|
margin-bottom: 60rpx; |
||||
|
border-radius: 20%; |
||||
|
} |
||||
|
|
||||
|
.welcome-text { |
||||
|
font-size: 48rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333333; |
||||
|
margin-bottom: 60rpx; |
||||
|
text-align: left; |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
.switch-container { |
||||
|
display: flex; |
||||
|
margin-bottom: 40rpx; |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
|
||||
|
.switch-item { |
||||
|
font-size: 28rpx; |
||||
|
color: #999999; |
||||
|
padding: 10rpx 20rpx; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.switch-item::after { |
||||
|
content: ""; |
||||
|
position: absolute; |
||||
|
bottom: 0; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
width: 60%; /* 控制边框宽度 */ |
||||
|
height: 2rpx; |
||||
|
background-color: transparent; |
||||
|
} |
||||
|
|
||||
|
.switch-item.active { |
||||
|
color: #333333; |
||||
|
font-weight: 700; |
||||
|
} |
||||
|
|
||||
|
.switch-item.active::after { |
||||
|
content: ""; |
||||
|
position: absolute; |
||||
|
top: 60rpx; |
||||
|
bottom: 0; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
width: 30%; /* 控制边框宽度 */ |
||||
|
height: 7rpx; |
||||
|
background-color: #333333; |
||||
|
} |
||||
|
|
||||
|
.input-container { |
||||
|
width: 100%; |
||||
|
margin-bottom: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.input-field { |
||||
|
width: 90%; |
||||
|
height: 80rpx; |
||||
|
border-radius: 20rpx; |
||||
|
border: 2rpx solid #e5e5e5; |
||||
|
padding: 0 30rpx; |
||||
|
font-size: 28rpx; |
||||
|
color: #333333; |
||||
|
background-color: #f5f5f5; |
||||
|
} |
||||
|
|
||||
|
.agreement-container { |
||||
|
/* display: flex; */ |
||||
|
align-items: center; |
||||
|
margin-bottom: 40rpx; |
||||
|
align-self: flex-start; |
||||
|
} |
||||
|
|
||||
|
.checkbox { |
||||
|
width: 10rpx; |
||||
|
height: 10rpx; |
||||
|
margin-right: 30rpx; |
||||
|
/* flex: content; */ |
||||
|
} |
||||
|
|
||||
|
.agreement-text { |
||||
|
margin-left: 20rpx; |
||||
|
font-size: 24rpx; |
||||
|
color: #666666; |
||||
|
} |
||||
|
|
||||
|
.link { |
||||
|
color: #333333; |
||||
|
font-weight: bold; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
|
||||
|
.register-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color: #333333; |
||||
|
color: white; |
||||
|
font-size: 32rpx; |
||||
|
font-weight: bold; |
||||
|
border-radius: 40rpx; |
||||
|
margin-bottom: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.or-text { |
||||
|
font-size: 24rpx; |
||||
|
color: #999999; |
||||
|
margin-bottom: 40rpx; |
||||
|
} |
||||
|
|
||||
|
.third-party-login { |
||||
|
width: 100%; |
||||
|
margin-bottom: 60rpx; |
||||
|
} |
||||
|
.third-party-text { |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
.third-party-btn { |
||||
|
width: 100%; |
||||
|
height: 80rpx; |
||||
|
background-color: white; |
||||
|
border: 2rpx solid #e5e5e5; |
||||
|
border-radius: 40rpx; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
margin-bottom: 20rpx; |
||||
|
font-size: 28rpx; |
||||
|
color: #333333; |
||||
|
} |
||||
|
|
||||
|
.apple-icon { |
||||
|
width: 30rpx; |
||||
|
height: 30rpx; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.google-icon { |
||||
|
width: 30rpx; |
||||
|
height: 30rpx; |
||||
|
margin-right: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.existing-account { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.account-text { |
||||
|
font-size: 24rpx; |
||||
|
color: #666666; |
||||
|
} |
||||
|
|
||||
|
.login-link { |
||||
|
font-size: 24rpx; |
||||
|
font-weight: bold; |
||||
|
color: #333333; |
||||
|
margin-left: 10rpx; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,13 @@ |
|||||
|
<template> |
||||
|
<view> |
||||
|
隐私政策 |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
|
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
|
||||
|
</style> |
||||
@ -0,0 +1,194 @@ |
|||||
|
<template> |
||||
|
<view class="login-container"> |
||||
|
<!-- 顶部标题 --> |
||||
|
<view class="title-section"> |
||||
|
<text class="main-title">DeepChart</text> |
||||
|
</view> |
||||
|
<view class="subtitle-section"> |
||||
|
<text class="subtitle">您的股市随身顾问</text> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 手机卡片样式 --> |
||||
|
<view class="phone-card"> </view> |
||||
|
|
||||
|
<!-- 登录注册按钮 --> |
||||
|
<view class="button-group"> |
||||
|
<button class="login-button" @click="toLogin">登录</button> |
||||
|
<button class="register-button" @click="toRegistration">注册</button> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 底部导航栏 --> |
||||
|
<!-- <view class="bottom-nav"> |
||||
|
<navigator url="/pages/index/index" class="nav-item"> |
||||
|
<image |
||||
|
class="nav-icon" |
||||
|
src="/static/images/home.png" |
||||
|
mode="aspectFill" |
||||
|
></image> |
||||
|
<text class="nav-text">首页</text> |
||||
|
</navigator> |
||||
|
<navigator url="/pages/index/index" class="nav-item"> |
||||
|
<image |
||||
|
class="nav-icon" |
||||
|
src="/static/images/chart.png" |
||||
|
mode="aspectFill" |
||||
|
></image> |
||||
|
<text class="nav-text">行情</text> |
||||
|
</navigator> |
||||
|
<navigator url="/pages/index/index" class="nav-item active"> |
||||
|
<image |
||||
|
class="nav-icon" |
||||
|
src="/static/images/logo.png" |
||||
|
mode="aspectFill" |
||||
|
></image> |
||||
|
<text class="nav-text">DeepMate</text> |
||||
|
</navigator> |
||||
|
<navigator url="/pages/index/index" class="nav-item"> |
||||
|
<image |
||||
|
class="nav-icon" |
||||
|
src="/static/images/explore.png" |
||||
|
mode="aspectFill" |
||||
|
></image> |
||||
|
<text class="nav-text">深度探索</text> |
||||
|
</navigator> |
||||
|
<navigator url="/pages/index/index" class="nav-item"> |
||||
|
<image |
||||
|
class="nav-icon" |
||||
|
src="/static/images/profile.png" |
||||
|
mode="aspectFill" |
||||
|
></image> |
||||
|
<text class="nav-text">我的</text> |
||||
|
</navigator> |
||||
|
</view> --> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
function toRegistration() { |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/Registration/Registration", |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function toLogin() { |
||||
|
uni.navigateTo({ |
||||
|
url: "/pages/login/login", |
||||
|
}); |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.login-container { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
/* justify-content: space-between; */ |
||||
|
padding: 40rpx; |
||||
|
height: 100vh; |
||||
|
background-color: #ffffff; |
||||
|
} |
||||
|
|
||||
|
.title-section { |
||||
|
text-align: center; |
||||
|
margin-top: 120rpx; |
||||
|
|
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.main-title { |
||||
|
text-align: center; |
||||
|
font-size: 64rpx; |
||||
|
font-weight: 800; |
||||
|
color: #000000; |
||||
|
margin-bottom: 10rpx; |
||||
|
} |
||||
|
.subtitle-section { |
||||
|
margin-bottom: 100rpx; |
||||
|
} |
||||
|
.subtitle { |
||||
|
font-weight: bold; |
||||
|
font-size: 32rpx; |
||||
|
color: #333333; |
||||
|
} |
||||
|
|
||||
|
.phone-card { |
||||
|
background-image: url("/static/20251021-132531.jpg"); |
||||
|
background-size: 100% 100%; |
||||
|
background-position: center; |
||||
|
min-width: 400rpx; |
||||
|
min-height: 700rpx; |
||||
|
width: 400rpx; |
||||
|
height: 700rpx; |
||||
|
border-radius: 40rpx; |
||||
|
padding: 40rpx; |
||||
|
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.3); |
||||
|
position: relative; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.button-group { |
||||
|
display: flex; |
||||
|
gap: 40rpx; |
||||
|
margin: 80rpx 0; |
||||
|
width: 100%; |
||||
|
max-width: 600rpx; |
||||
|
} |
||||
|
|
||||
|
.login-button { |
||||
|
flex: 1; |
||||
|
background-color: #f5f5f5; |
||||
|
color: #000000; |
||||
|
border-radius: 60rpx; |
||||
|
font-size: 32rpx; |
||||
|
padding: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.register-button { |
||||
|
flex: 1; |
||||
|
background-color: #000000; |
||||
|
color: #ffffff; |
||||
|
border-radius: 60rpx; |
||||
|
font-size: 32rpx; |
||||
|
padding: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.bottom-nav { |
||||
|
display: flex; |
||||
|
justify-content: space-around; |
||||
|
align-items: center; |
||||
|
width: 100%; |
||||
|
height: 100rpx; |
||||
|
background-color: #ffffff; |
||||
|
position: fixed; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
border-top: 1rpx solid #e5e5e5; |
||||
|
} |
||||
|
|
||||
|
.nav-item { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
padding: 10rpx; |
||||
|
} |
||||
|
|
||||
|
.nav-item.active .nav-icon { |
||||
|
transform: scale(1.2); |
||||
|
} |
||||
|
|
||||
|
.nav-icon { |
||||
|
width: 40rpx; |
||||
|
height: 40rpx; |
||||
|
margin-bottom: 10rpx; |
||||
|
} |
||||
|
|
||||
|
.nav-text { |
||||
|
font-size: 24rpx; |
||||
|
color: #666666; |
||||
|
} |
||||
|
|
||||
|
.nav-item.active .nav-text { |
||||
|
color: #000000; |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,40 @@ |
|||||
|
<template> |
||||
|
<view class="background"> |
||||
|
<view class="logo-text"> DeepChart </view> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { onShow } from "@dcloudio/uni-app"; |
||||
|
|
||||
|
onShow(() => { |
||||
|
setTimeout(() => { |
||||
|
uni.redirectTo({ |
||||
|
url: "/pages/select/select", |
||||
|
animationType: "slide-in-right", |
||||
|
animationDuration: 1000, |
||||
|
}); |
||||
|
}, 3000); |
||||
|
}); |
||||
|
</script> |
||||
|
|
||||
|
<style> |
||||
|
.background { |
||||
|
background: linear-gradient(180deg, #2a0c4d, #1d0836, #0d0218); |
||||
|
width: 100vw; |
||||
|
height: 100vh; |
||||
|
} |
||||
|
|
||||
|
.logo-text { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
color: white; |
||||
|
font-weight: bold; |
||||
|
font-size: 24px; |
||||
|
position: absolute; |
||||
|
bottom: 5%; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,18 @@ |
|||||
|
// vue.config.js
|
||||
|
const webpack = require('webpack'); |
||||
|
|
||||
|
module.exports = { |
||||
|
configureWebpack: { |
||||
|
plugins: [ |
||||
|
new webpack.DefinePlugin({ |
||||
|
'__VUE_I18N_FULL_INSTALL__': JSON.stringify(true), |
||||
|
'__VUE_I18N_LEGACY_API__': JSON.stringify(false), |
||||
|
'__INTLIFY_PROD_DEVTOOLS__': JSON.stringify(false) |
||||
|
}) |
||||
|
] |
||||
|
}, |
||||
|
// 如果需要自定义其他 webpack 配置,可以在这里添加
|
||||
|
chainWebpack: (config) => { |
||||
|
// 例如,你可以在这里添加其他配置
|
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue