初始化
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<scroll-view class="msgs" scroll-y :scroll-top="scrollTop">
|
||||
<view class="container">
|
||||
<view v-for="m in messages" :key="m.id" class="m" :class="{ me: m.role === 'user' }">
|
||||
<view class="bubble" :class="{ bme: m.role === 'user' }">
|
||||
<text class="txt">{{ m.text }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="chips" v-if="showChips">
|
||||
<view class="chip" @tap="send('推荐爆款项目')">推荐爆款项目</view>
|
||||
<view class="chip" @tap="send('我想预约今天')">我想预约今天</view>
|
||||
<view class="chip" @tap="send('敏感肌适合做什么')">敏感肌适合做什么</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="quick row">
|
||||
<view class="q" @tap="send('查档期')">查档期</view>
|
||||
<view class="q" @tap="send('看价格')">看价格</view>
|
||||
<view class="q" @tap="send('我要预约')">我要预约</view>
|
||||
</view>
|
||||
|
||||
<view class="bar">
|
||||
<view class="voice" @tap="mockVoice">按住说话</view>
|
||||
<input class="ipt" v-model="text" confirm-type="send" @confirm="send(text)" placeholder="说出你的需求,例如:想做补水/我想预约今天 14:30" />
|
||||
<view class="send" @tap="send(text)">发送</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { aiReply } from '@/common/aiRules'
|
||||
import { projects } from '@/common/mockData'
|
||||
|
||||
function mid() {
|
||||
return `${Date.now()}_${Math.floor(Math.random() * 10000)}`
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
projectId: '',
|
||||
messages: [],
|
||||
text: '',
|
||||
scrollTop: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showChips() {
|
||||
return this.messages.length < 4
|
||||
}
|
||||
},
|
||||
onLoad(query) {
|
||||
this.projectId = query.projectId || ''
|
||||
const base =
|
||||
'我是 AI 预约助手。你可以直接说“预约 + 时间 + 项目/需求”,我会把你带到预约/购买流程。'
|
||||
const ctx = this.projectId ? projects.find((x) => x.id === this.projectId) : null
|
||||
const intro = ctx ? `当前项目:${ctx.name}。你想预约哪个日期和时段?` : base
|
||||
this.messages = [
|
||||
{ id: mid(), role: 'assistant', text: intro }
|
||||
]
|
||||
this.bump()
|
||||
},
|
||||
methods: {
|
||||
bump() {
|
||||
this.$nextTick(() => {
|
||||
this.scrollTop = this.scrollTop + 99999
|
||||
})
|
||||
},
|
||||
send(raw) {
|
||||
const v = (raw || '').trim()
|
||||
if (!v) return
|
||||
this.messages.push({ id: mid(), role: 'user', text: v })
|
||||
this.text = ''
|
||||
|
||||
const r = aiReply(v)
|
||||
this.messages.push({ id: mid(), role: 'assistant', text: r.text })
|
||||
this.bump()
|
||||
|
||||
if (r.action?.type === 'go_booking') {
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({ url: `/pages/booking/create?projectId=${r.action.projectId}` })
|
||||
}, 450)
|
||||
}
|
||||
},
|
||||
mockVoice() {
|
||||
uni.showToast({ title: '语音输入(原型演示)', icon: 'none' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.msgs {
|
||||
flex: 1;
|
||||
}
|
||||
.m {
|
||||
display: flex;
|
||||
margin: 14rpx 0;
|
||||
}
|
||||
.me {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.bubble {
|
||||
max-width: 620rpx;
|
||||
padding: 18rpx 18rpx;
|
||||
border-radius: 22rpx;
|
||||
background: #fff;
|
||||
border: 1rpx solid rgba(17, 24, 39, 0.08);
|
||||
box-shadow: 0 10rpx 28rpx rgba(17, 24, 39, 0.06);
|
||||
}
|
||||
.bme {
|
||||
background: rgba(59, 130, 246, 0.12);
|
||||
border-color: rgba(59, 130, 246, 0.22);
|
||||
}
|
||||
.txt {
|
||||
font-size: 28rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.quick {
|
||||
padding: 12rpx 18rpx 6rpx;
|
||||
background: #fff;
|
||||
border-top: 1rpx solid rgba(17, 24, 39, 0.08);
|
||||
gap: 12rpx;
|
||||
}
|
||||
.q {
|
||||
padding: 12rpx 16rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(17, 24, 39, 0.06);
|
||||
font-size: 26rpx;
|
||||
font-weight: 800;
|
||||
}
|
||||
.bar {
|
||||
padding: 18rpx;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
gap: 12rpx;
|
||||
}
|
||||
.voice {
|
||||
width: 160rpx;
|
||||
height: 82rpx;
|
||||
border-radius: 18rpx;
|
||||
background: rgba(17, 24, 39, 0.06);
|
||||
font-size: 24rpx;
|
||||
font-weight: 900;
|
||||
color: rgba(17, 24, 39, 0.78);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.ipt {
|
||||
flex: 1;
|
||||
height: 82rpx;
|
||||
padding: 0 16rpx;
|
||||
border-radius: 18rpx;
|
||||
background: rgba(17, 24, 39, 0.05);
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.send {
|
||||
width: 140rpx;
|
||||
height: 82rpx;
|
||||
border-radius: 18rpx;
|
||||
background: linear-gradient(135deg, #111827 0%, #3b82f6 100%);
|
||||
color: #fff;
|
||||
font-weight: 900;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
margin: 8rpx 0 12rpx;
|
||||
}
|
||||
.chip {
|
||||
padding: 12rpx 16rpx;
|
||||
border-radius: 999rpx;
|
||||
background: rgba(17, 24, 39, 0.06);
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user