feat: 完成项目基础功能搭建与样式优化

1.  新增评估选择组件、本地草稿存储与新闻/金融内容服务
2.  重构页面布局与样式:调整按钮阴影、图标尺寸、导航栏样式
3.  更新启动页、报告页、消息中心等页面UI与交互逻辑
4.  替换图标资源,调整禁用态透明度
5.  补充README文档与本地数据模拟实现
This commit is contained in:
hujun
2026-09-18 12:59:43 +08:00
parent b0ee4f9d7e
commit 94a4558290
30 changed files with 1376 additions and 640 deletions
+40 -15
View File
@@ -3,18 +3,20 @@
<AppHeader title="AI融资助手" />
<scroll-view scroll-y class="chat-scroll" :scroll-into-view="lastMessageId" :style="contentStyle(210, false)">
<view class="chat-content">
<view class="assistant-intro"><image src="/static/mobile/images/robot.png" mode="aspectFit" class="assistant-intro-image"></image><view class="assistant-bubble"><text>您好!我是AI融资助手,可以帮您解答融资相关问题。</text></view></view>
<view class="assistant-intro"><image src="/static/mobile/images/robot.png" mode="aspectFit" class="assistant-intro-image"></image><view class="assistant-bubble"><text class="bubble-text">您好!我是AI融资助手,可以帮您了解融资条件、准备材料和比较方案。</text></view></view>
<view class="quick-questions">
<view class="question" v-for="item in questions" :key="item" @click="ask(item)"><text>{{ item }}</text><AppIcon name="chevron-right" :size="28" muted /></view>
<view class="question" v-for="item in questions" :key="item" @click="ask(item)"><text class="question-text">{{ item }}</text><AppIcon name="chevron-right" :size="28" muted /></view>
</view>
<view v-for="(item,index) in messages" :key="index" :id="'message-' + index" :class="item.role == 'user' ? 'message-row user-row' : 'message-row'">
<image v-if="item.role == 'assistant'" class="message-avatar" src="/static/mobile/images/robot.png" mode="aspectFit"></image>
<view :class="item.role == 'user' ? 'message-bubble user-bubble' : 'message-bubble'"><text>{{ item.text }}</text></view>
<view :class="item.role == 'user' ? 'message-bubble user-bubble' : 'message-bubble'"><text :class="item.role == 'user' ? 'bubble-text user-text' : 'bubble-text'">{{ item.text }}</text></view>
</view>
<view v-if="errorMessage.length > 0" class="assistant-error"><text>{{ errorMessage }}</text><text @click="retry" class="assistant-error-text-last-child">重试</text></view>
<view v-if="sending" class="message-row"><image class="message-avatar" src="/static/mobile/images/robot.png" mode="aspectFit"></image><view class="message-bubble"><text class="sending-text">正在整理建议…</text></view></view>
<view v-if="errorMessage.length > 0" class="assistant-error"><text class="error-text">{{ errorMessage }}</text><text @click="retry" class="retry-text">重试</text></view>
<view id="chat-end" class="chat-end"></view>
</view>
</scroll-view>
<view class="chat-input" :style="bottomStyle(17)"><input v-model="draft" confirm-type="send" @confirm="send" placeholder="请输入您的问题..." class="chat-input-input" /><button @click="send" class="chat-input-button"><AppIcon name="send" :size="34" /></button></view>
<view class="chat-input" :style="bottomStyle(17)"><input v-model="draft" confirm-type="send" @confirm="send" placeholder="请输入您的问题..." class="chat-input-input" /><button @click="send" :disabled="sending || draft.trim().length == 0" :class="sending || draft.trim().length == 0 ? 'chat-input-button send-disabled' : 'chat-input-button'"><AppIcon name="send" :size="40" /></button></view>
</view>
</template>
@@ -25,25 +27,37 @@
import AppIcon from '@/components/AppIcon.uvue'
import { sendAssistantMessage } from '@/services/api.uts'
const questions = ['我的融资额度受哪些因素影响?', '如何提高贷款通过率?', '企业融资需要哪些材料?', '有哪些适合我的方案?']
const messages = ref<UTSJSONObject[]>([])
type ChatMessage = { role: string, text: string }
const messages = ref<ChatMessage[]>([])
const draft = ref('')
const lastMessageId = ref('')
const lastQuestion = ref('')
const sending = ref(false)
const errorMessage = ref('')
const send = async () => {
const scrollToEnd = async () => {
lastMessageId.value = ''
await nextTick()
lastMessageId.value = 'chat-end'
}
const requestAnswer = async (text: string) => {
sending.value = true
errorMessage.value = ''
scrollToEnd()
try { const answer = await sendAssistantMessage(text); const response: ChatMessage = { role: 'assistant', text: answer }; messages.value.push(response) } catch (error) { errorMessage.value = '暂未收到回复,请重试' }
sending.value = false
scrollToEnd()
}
const send = () => {
const text = draft.value.trim()
if (text.length == 0 || sending.value) return
lastQuestion.value = text
messages.value.push({ role: 'user', text: text })
const message: ChatMessage = { role: 'user', text: text }
messages.value.push(message)
draft.value = ''
sending.value = true
errorMessage.value = ''
try { const answer = await sendAssistantMessage(text); messages.value.push({ role: 'assistant', text: answer }); lastMessageId.value = 'message-' + (messages.value.length - 1) } catch (error) { errorMessage.value = '消息发送失败,请稍后重试' }
sending.value = false
requestAnswer(text)
}
const ask = (text: string) => { draft.value = text; send() }
const retry = () => { draft.value = lastQuestion.value; errorMessage.value = ''; send() }
const ask = (text: string) => { if (sending.value) return; draft.value = text; send() }
const retry = () => { if (!sending.value && lastQuestion.value.length > 0) requestAnswer(lastQuestion.value) }
</script>
<style>
@@ -61,7 +75,18 @@
.user-bubble { color: #fff; background-color: #0868f7; border-color: #0868f7; border-radius: 22rpx 8rpx 22rpx 22rpx; }
.chat-input { position: fixed; left: 0; right: 0; bottom: 0; min-height: 114rpx; padding: 17rpx 24rpx; background-color: #fff; border-top: 1rpx solid #e3eaf4; flex-direction: row; align-items: center; }
.chat-input-input { flex: 1; height: 78rpx; border-radius: 39rpx; background-color: #f2f5f9; padding: 0 28rpx; font-size: 25rpx; }
.chat-input-button { width: 76rpx; height: 76rpx; line-height: 76rpx; border-radius: 50%; margin-left: 15rpx; padding: 0; background-color: #0868f7; color: #fff; font-size: 29rpx; }
.chat-input-button { width: 76rpx; height: 76rpx; line-height: 76rpx; border-radius: 50%; margin-left: 15rpx; padding: 0; background-color: #0868f7; align-items: center; justify-content: center; flex-shrink: 0; }
.send-disabled { opacity: .55; }
/* #ifndef APP */
.chat-input-button { display: flex; }
/* #endif */
.bubble-text { font-size: 27rpx; line-height: 43rpx; color: #344259; }
.user-text { color: #ffffff; }
.question-text { flex: 1; margin-right: 12rpx; color: #0868f7; font-size: 24rpx; line-height: 38rpx; }
.sending-text { font-size: 25rpx; line-height: 40rpx; color: #75869d; }
.error-text { flex: 1; color: #bb4857; font-size: 23rpx; line-height: 36rpx; }
.retry-text { color: #0868f7; font-size: 25rpx; padding: 0 6rpx; }
.chat-end { height: 12rpx; }
.assistant-error { margin: 18rpx 0 0 94rpx; color: #e05a5a; font-size: 21rpx; flex-direction: row; justify-content: space-between; }
.assistant-error-text-last-child { color: #0868f7; margin-left: 18rpx; }
</style>