赞
踩
搭建的页面比价简单废话不多说先看效果图(页面功能包括了进入页面会首先请求后端热点问题显示,输入时提示可能会问的问题,点击超粘接会直接向机器人发送点击的问题,点击图片放大展示功能)
就不做其他讲解,直接上代码了
- <template>
- <div class="common-layout">
- <el-container>
- <el-header :style="{ height: '50px', width: '1000px' ,backgroundColor: '#87CEEB'}">
- <p class="centered-text">机器人</p></el-header>
- <el-main :style="{ height: '600px', width: '1000px' ,border: '2px solid #ccc' }">
- <div class="message-container" v-for="(message, index) in messages" :key="index"
- :class="getMessageClass(message.isSent)">
- <div v-if="message.isSent" class="message-container">
- <div class="bubble">
- <div class="message" v-html="message.content"></div>
- </div>
- <div class="avatar">
- <img src="./my.jpg" alt="Avatar" class="avatar-image"/>
- </div>
- </div>
- <div v-if="!message.isSent" class="message-container">
- <div class="avatar">
- <img src="./a.jpg" alt="Avatar" class="avatar-image"/>
- </div>
- <div class="bubble">
- <div class="message" v-html="message.content"
- @click.prevent="handleMessageClick($event)"></div>
- </div>
- </div>
- </div>
- </el-main>
- <el-row :style="{ width: '1000px' }">
- <AutomaticPrompt @keydown.enter="handleButtonClick" @updateState="getState"
- ref="automaticPromptRef"></AutomaticPrompt>
- <el-button type="primary" plain style="width: 50px;" @click="handleButtonClick">发送</el-button>
- </el-row>
- </el-container>
- </div>
- </template>
-
- <style>
-
- .centered-text {
- text-align: center;
- color: black;
- }
-
- .underline-link {
- text-decoration: underline;
- }
-
- .message-container {
- display: flex;
- align-items: center;
- margin-bottom: 10px;
- }
-
- .avatar {
- margin-left: 10px; /* 修改这里将头像放在消息框的右边 */
- }
-
- .avatar-image {
- width: 40px;
- height: 40px;
- border-radius: 50%;
- object-fit: cover;
- }
-
- .bubble {
- background-color: #e8e8e8;
- color: #000;
- padding: 10px;
- border-radius: 5px;
- }
-
- .message {
- text-align: left;
- margin: 0;
- }
-
- .message-container-right {
- justify-content: flex-end;
- }
-
- .message-container-left {
- justify-content: flex-start;
- }
- </style>
-
- <script lang="ts" setup>
- import {ref, onMounted} from 'vue';
- import AutomaticPrompt from './AutomaticPrompt.vue'
- import axios from 'axios';
- import ImageViewer from "@luohc92/vue3-image-viewer";
- import '@luohc92/vue3-image-viewer/dist/style.css';
-
-
- const automaticPromptRef = ref('');
-
- let msg: string = '';
- const messages = ref([]);
- //获取子组件中state的值,这个好像是写多余了,可以直接使用automaticPromptRef.value.setState('');获取state值
- const getState = (v) => {
- msg = v;
- };
-
- //对机器人回复的【link】标签进行渲染(替换字符串)
- const formatString = (str) => {
- str = str.replace(/(\[link submit="faqvote.*?\])/g, '<a class="underline-link" href="">');
- const replacedStr1 = str.replace(/(\[link.*?\])/g, '<br><a class="underline-link" href="">');
- const replacedStr2 = replacedStr1.replace(/\[\/link\]/g, `</a>`)
- const replacedStr3 = replacedStr2.replace(/\\r\\n/g, `<br>`)
- const replacedStr4 = replacedStr3.replace(/\\\\r\\\\n/g, ``)
- return replacedStr4;
- }
- //发送按钮
- const handleButtonClick = () => {
- messages.value.push({content: msg, isSent: true});
- sendMsg(msg);
- automaticPromptRef.value.setState('');
- };
- //向后端发送请求逻辑
- const sendMsg = async (msg: string) => {
- let responseMsg = '';
- try {
- //请求后端问题答案,并对问题答案进行封装,这里需要各位对各自的后端返回格式进行解析
- const response = await axios.get(`http://localhost:8080/question/` + msg);
- //正常情况的文本处理
- if (response.data.content !== undefined) {
- responseMsg = formatString(response.data.content);
- console.log(responseMsg)
- }
- //图片处理
- let mark = false;
- let imageTxt = '';
- let imageUrl = '';
- for (let i = 0; i < response.data.commands.length; i++) {
- if (response.data.commands[i].name === 'imgmsg' || response.data.commands[i].name === 'txtimage') {
- mark = true;
- for (let j = 0; j < response.data.commands[i].args.length; j++) {
- if (response.data.commands[i].args[j].includes('http://')) {
- imageUrl += response.data.commands[i].args[j];
- } else {
- imageTxt += response.data.commands[i].args[j] + '<br>'
- }
- }
- }
- }
- if (mark) {
- responseMsg = responseMsg + '<br>' + imageTxt + '<img src="' + imageUrl + '" alt="Image" style="width: 200px; height: auto;">'
- }
- if (response.data.relatedQuestions !== undefined && response.data.relatedQuestions.length !== 0) {
- responseMsg = responseMsg + '<br>您可能想问:'
- for (let i = 0; i < response.data.relatedQuestions.length; i++) {
- let responseIndex = i + 1
- responseMsg = responseMsg + '<br>' + responseIndex + ':' + '<a class="underline-link" href="">' + response.data.relatedQuestions[i] + '</a>'
- }
- }
- } catch (error) {
- console.error(error);
- responseMsg = '网络异常';
- }
- messages.value.push({content: responseMsg, isSent: false});
- }
-
- const handleMessageClick = (event) => {
- const target = event.target;
- if (target.tagName === 'A') {
- // 点击的是超链接
- // 执行相应的操作
- if (target.innerHTML === '解决') {
- alert('感谢您的使用')
- } else if (target.innerHTML === '未解决') {
- alert('很抱歉未能解决你的问题')
- } else {
- handleLinkClick(target.innerHTML);
- }
- } else if (target.tagName === 'IMG') {
- // 点击的图片进行放大操作
- ImageViewer({
- //切记额images这个参数是数组,我的target.valueof().src值是一个http的图片地址
- images: [target.valueOf().src],
- curIndex: 0,
- zIndex: 2000,
- showDownload: true,
- showThumbnail: true,
- handlePosition: "bottom",
- maskBgColor: "rgba(0,0,0,0.7)",
- onClose: () => {
- console.log("close");
- },
- });
-
- } else {
-
- }
- }
-
- const handleLinkClick = (msg) => {
- messages.value.push({content: msg, isSent: true})
- sendMsg(msg);
- }
- //消息框样式动态选择
- const getMessageClass = (isSent) => {
- return isSent ? 'message-container-right' : 'message-container-left';
- };
- //进入页面直接发送请求从后端获取热点数据
- onMounted(async () => {
- let responseMsg = '';
- try {
- const response = await axios.get(`http://localhost:8080/getHotAsk`);
- responseMsg = responseMsg + '<br>您可能想问:'
- for (let i = 0; i < response.data.length; i++) {
- let responseIndex = i + 1
- responseMsg = responseMsg + '<br>' + responseIndex + ':' + '<a class="underline-link" href="">' + response.data[i] + '</a>'
- }
- } catch (error) {
- console.error(error);
- responseMsg = '网络异常,暂时无法加载出热点问题';
- }
- messages.value.push({content: responseMsg, isSent: false})
- })
- </script>
-
上面代码中使用到了vue3-image-viewer,请自行下载,运行命令npm install --save @luohc92/vue3-image-viewer,同时代码中automaticPromptRef.value.setState('');的setState会爆红不影响使用,可以正常的去将子组件的值清除。下面是父组件中引用的子组件代码
- <template>
- <el-autocomplete :style="{ width: '950px' }" v-model="state" :fetch-suggestions="querySearchAsync"
- placeholder="请输入问题" @select="handleSelect" ref="automaticPromptRef"/>
- </template>
-
- <script lang="ts" setup>
- import { ref, watch, defineEmits ,defineExpose} from 'vue';
- import axios from 'axios';
- const state = ref('');
-
- interface LinkItem {
- value: string;
- link: string;
- }
-
- const links = ref<LinkItem[]>([]);
-
- const loadFromBackend = async (value: string) => {
- try {
- //输入时候请求后端根据输入值得到提示。 后端返回集合,集合里面对象属性为value和link都是string类型
- const response = await axios.get(`http://localhost:8080/getAutoMsg/${value}`);
- links.value = response.data;
- } catch (error) {
- console.error(error);
- }
- };
-
- const querySearchAsync = (queryString: string, cb: (arg: any) => void) => {
- const results = queryString ? links.value.filter(createFilter(queryString)) : links.value;
- cb(results);
- };
-
- const createFilter = (queryString: string) => {
- return (link: LinkItem) => {
- return link.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0;
- };
- };
-
- const handleSelect = (value: string) => {
-
- };
-
- const emit = defineEmits(['updateState']);
-
- watch(state, async (newValue) => {
- emit('updateState',newValue)
- if (newValue) {
- await loadFromBackend(newValue);
- } else {
- links.value = [];
- }
- });
-
- defineExpose({
- setState(res){
- state.value = res
- },
- getState(){
- return state.value
- }
- })
- </script>
对参数的解析需要各位去对照自己的去修改,后端就不展示给大家了,后端基本就几行代码都是调用公司的api。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。