Files
urbanLifeline/urbanLifelineWeb/packages/workcase_wechat/pages/index/index.uvue
2025-12-10 17:00:54 +08:00

366 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="chat-container">
<!-- 顶部标题栏 -->
<view class="header" :style="{ paddingTop: headerPaddingTop + 'px', height: headerTotalHeight + 'px' }">
<text class="title">泰豪小电</text>
<button class="workcase-btn" @tap="goToWorkList">
<image class="btn-icon" src="/static/imgs/case.svg" />
<text class="btn-text">我的工单</text>
</button>
</view>
<!-- 聊天消息区域 -->
<scroll-view class="chat-messages" scroll-y="true" :scroll-top="scrollTop" scroll-with-animation="true">
<!-- 默认欢迎界面 -->
<view class="welcome-container" v-if="messages.length === 0">
<image class="welcome-image" src="/static/imgs/defaultchat.png" />
<text class="welcome-text-primary">Hi~ 有什么可以帮您!</text>
<text class="welcome-text-secondary">泰豪小电为您服务:)</text>
</view>
<!-- 聊天消息列表 -->
<view class="messages-list" v-else>
<view class="message-item" v-for="(item, index) in messages" :key="index"
:class="item.type === 'user' ? 'user-message' : 'bot-message'">
<!-- 用户消息(右侧) -->
<view class="user-message-content" v-if="item.type === 'user'">
<view class="message-bubble user-bubble">
<text class="message-text">{{item.content}}</text>
</view>
<view class="avatar user-avatar">
<text class="avatar-text">我</text>
</view>
</view>
<!-- Bot/员工消息(左侧) -->
<view class="bot-message-content" v-else>
<view class="avatar bot-avatar">
<text class="avatar-text">AI</text>
</view>
<view class="message-bubble bot-bubble">
<text class="message-text">{{item.content}}</text>
</view>
</view>
<text class="message-time">{{item.time}}</text>
</view>
</view>
</scroll-view>
<!-- 底部操作区域 -->
<view class="bottom-area">
<!-- 第一行:按钮和快速问题 -->
<view class="top-row">
<view class="main-actions">
<button class="action-btn primary" @tap="contactHuman">
<text class="action-text">联系人工</text>
</button>
<button class="action-btn secondary" @tap="showCreator">
<text class="action-text">创建工单</text>
</button>
</view>
<!-- 竖向分隔线 -->
<view class="divider-line"></view>
<!-- 快速问题 -->
<view class="quick-section">
<button class="quick-btn" @tap="handleQuickQuestion">
<text class="quick-text">查询质保状态</text>
</button>
</view>
</view>
<!-- 输入区域 -->
<view class="input-section">
<input class="chat-input" v-model="inputText" placeholder="输入问题来问我~" @confirm="sendMessage" />
<button class="add-btn" @tap="showUploadOptions">
<text class="add-icon">+</text>
</button>
</view>
</view>
<!-- 工单创建弹窗 -->
<WorkcaseCreator v-if="showWorkcaseCreator" :show="showWorkcaseCreator" @close="hideCreator"
@success="onWorkcaseCreated" />
</view>
</template>
<script setup lang="ts">
import { ref, nextTick, onMounted } from 'vue'
import WorkcaseCreator from '@/components/WorkcaseCreator/WorkcaseCreator.uvue'
// 接口定义
interface Message {
type : 'user' | 'bot'
content : string
time : string
actions ?: string[] | null
}
interface WorkcaseData {
title : string
category : string
priority : string
description : string
contact : string
images : string[]
}
// 响应式数据
const messages = ref<Message[]>([])
const inputText = ref<string>('')
const isTyping = ref<boolean>(false)
const scrollTop = ref<number>(0)
const showWorkcaseCreator = ref<boolean>(false)
const statusBarHeight = ref<number>(0)
const headerPaddingTop = ref<number>(44) // header顶部padding默认44px
const headerTotalHeight = ref<number>(76) // header总高度默认76px
// 生命周期
onMounted(() => {
// 设置页面标题
uni.setNavigationBarTitle({
title: '智能助手'
})
// 获取系统信息和安全区域
uni.getSystemInfo({
success: (res) => {
console.log('系统信息:', res)
console.log('状态栏高度:', res.statusBarHeight)
statusBarHeight.value = res.statusBarHeight || 0
console.log('安全区域:', res.safeArea)
console.log('安全区域insets:', res.safeAreaInsets)
// #ifdef MP-WEIXIN
// 获取胶囊按钮信息仅小程序计算header位置
try {
const menuButtonInfo = uni.getMenuButtonBoundingClientRect()
console.log('胶囊按钮信息:', menuButtonInfo)
// 计算header的paddingTop和总高度
// paddingTop = 胶囊按钮的top值
// 总高度 = 胶囊按钮bottom值
headerPaddingTop.value = menuButtonInfo.top
headerTotalHeight.value = menuButtonInfo.bottom
console.log('header paddingTop:', headerPaddingTop.value)
console.log('header totalHeight:', headerTotalHeight.value)
} catch (e) {
console.log('获取胶囊按钮信息失败:', e)
// 使用默认值
headerPaddingTop.value = 44
headerTotalHeight.value = 76
}
// #endif
}
})
})
// 发送消息
function sendMessage() {
const text = inputText.value.trim()
if (!text || isTyping.value) return
// 添加用户消息
addMessage('user', text)
inputText.value = ''
// 模拟AI回复
simulateAIResponse(text)
}
// 添加消息
function addMessage(type : 'user' | 'bot', content : string, actions : string[] | null = null) {
const now = new Date()
const time = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`
messages.value.push({
type,
content,
time,
actions
})
// 滚动到底部
nextTick(() => {
scrollToBottom()
})
}
// 模拟AI回复
function simulateAIResponse(userMessage : string) {
isTyping.value = true
setTimeout(() => {
isTyping.value = false
let response = ''
let actions : string[] | null = null
// 根据用户输入生成回复
if (userMessage.includes('工单') || userMessage.includes('报修') || userMessage.includes('问题')) {
response = '我理解您需要处理工单相关的事务。我可以帮您:'
actions = ['创建新工单', '查看工单状态', '联系客服']
} else if (userMessage.includes('你好') || userMessage.includes('您好')) {
response = '您好!很高兴为您服务。请问有什么可以帮助您的吗?'
actions = ['创建工单', '查看工单', '常见问题']
} else if (userMessage.includes('帮助') || userMessage.includes('功能')) {
response = '我可以为您提供以下服务:\n1. 创建工单 - 报告问题或提交服务请求\n2. 查看工单 - 跟踪您的工单处理进度\n3. 智能问答 - 解答常见问题'
actions = ['创建工单', '查看工单']
} else {
response = '感谢您的咨询。如果您遇到具体问题,建议创建工单,我们的专业团队会尽快为您处理。'
actions = ['创建工单', '联系人工客服']
}
addMessage('bot', response, actions)
}, 1000 + Math.random() * 1000)
}
// 快捷操作
function quickAction(action : string) {
if (action === '创建工单') {
showCreator()
} else if (action === '查看工单') {
goToWorkList()
} else {
addMessage('user', action)
simulateAIResponse(action)
}
}
// 处理建议操作
function handleSuggestedAction(action : string) {
if (action === '创建工单' || action === '创建新工单') {
showCreator()
} else if (action === '查看工单' || action === '查看工单状态') {
goToWorkList()
} else if (action === '联系客服' || action === '联系人工客服') {
uni.showModal({
title: '联系客服',
content: '客服电话400-123-4567\n工作时间9:00-18:00',
showCancel: false
})
} else {
addMessage('user', action)
simulateAIResponse(action)
}
}
// 显示工单创建器
function showCreator() {
showWorkcaseCreator.value = true
}
// 隐藏工单创建器
function hideCreator() {
showWorkcaseCreator.value = false
}
// 工单创建成功
function onWorkcaseCreated(workcaseData : WorkcaseData) {
hideCreator()
uni.showToast({
title: '工单创建成功',
icon: 'success'
})
// 添加成功消息
addMessage('bot', `工单创建成功!\n标题${workcaseData.title}\n分类${workcaseData.category}\n我们会尽快处理您的问题。`, ['查看工单', '创建新工单'])
}
// 跳转到工单列表
function goToWorkList() {
uni.navigateTo({
url: '/pages/workcase/list'
})
}
// 滚动到底部
function scrollToBottom() {
scrollTop.value = 999999
}
// 联系人工客服
function contactHuman() {
uni.showModal({
title: '联系人工客服',
content: '客服电话400-123-4567\n工作时间9:00-18:00\n\n是否拨打电话',
confirmText: '拨打',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
uni.makePhoneCall({
phoneNumber: '400-123-4567'
})
}
}
})
}
// 处理快速问题
function handleQuickQuestion() {
addMessage('user', '查询质保状态')
simulateAIResponse('查询质保状态')
}
// 显示上传选项
function showUploadOptions() {
uni.showActionSheet({
itemList: ['拍照', '从相册选择', '选择文件'],
success: (res) => {
switch (res.tapIndex) {
case 0:
// 拍照
chooseImageFromCamera()
break
case 1:
// 从相册选择
chooseImageFromAlbum()
break
case 2:
// 选择文件
chooseFile()
break
}
}
})
}
// 拍照
function chooseImageFromCamera() {
uni.chooseImage({
count: 1,
sourceType: ['camera'],
success: (res) => {
// 处理图片上传逻辑
console.log('选择的图片:', res.tempFilePaths)
addMessage('user', '[图片]')
simulateAIResponse('收到您发送的图片')
}
})
}
// 从相册选择
function chooseImageFromAlbum() {
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
// 处理图片上传逻辑
console.log('选择的图片:', res.tempFilePaths)
addMessage('user', '[图片]')
simulateAIResponse('收到您发送的图片')
}
})
}
// 选择文件
function chooseFile() {
// 这里可以扩展文件选择功能
uni.showToast({
title: '文件选择功能开发中',
icon: 'none'
})
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>