前端:模仿gpt对话,包括实现逐字输出效果和各种注意点

场景:vue3+TypeScript  注:文中的泛型暂时都用any代替。question.ts是外部引入的问题列表,是仿照人工智能gpt对话。此页是 左侧选择对应菜单,右侧显示内容

我的主要思路,把每次的问题和答案都放在一个数组里面,通过push方法添加,在页面上通过v-for循环,部分代码做一个展示,这样的话可以输入问题,答案会直接显示在上面。这里的centerplace还做了点赞和踩的功能。

   let centerplcae=reactive<any>([])

  <div class="center-question" v-for="(item,index) in centerplace" :key="item.id">

centerplace.push({

        id: centerplace.length + 1, // 按照长度生成id,

        DateTime: formattedDate, //此时的时间

        question: inputtext.value,   //发送的问题

        answer: AIanswer.value,   //对应的答案

        dianzan:ref(false),//点赞

        cai:ref(false) //踩

    })

这是最原始的,现在要加入逐字输出的效果

思路:使用定时器来实现,页面上做个显示,但是还有个棘手的怎么定时器结束,东西还要正确显示在页面上,而且定时器的模板语法也要放进循环体里面,这样会导致后面输入回答的内容影响前面几次回答的内容,解决这几个的思路是:取一个新的dom元素,当定时器循环的时候,增加一个变量用于判断定时器是否在进行中,展示的是一个逐字输出的模板,当定时器结束的时候,新的dom元素获取到这个值并且展示在页面上,逐字输出的dom销毁,为了不影响后面的回答内容,在循环体里面要让定时器dom找最后一个循环即可。 上关键代码

let typedText = ref('')

let testjjy = reactive<string[]>([])

let isLoading = ref(false)

 <div class="answer">

                                <p v-html="testjjy[index]" v-if="!isLastIndex(index) || isLoading == true"></p>

                <p v-if="isLastIndex(index) && isLoading === false" v-html="typedText"></p>

                            </div>

//取最后一次

const isLastIndex = computed(() => {

  return (index:any) => index === centerplace.length - 1;

});

//定时器

const typeEffect = (text: string) => {

  typedText.value = "";

  let index = 0;

  isButton.value=true

  const intervalId = setInterval(() => {

    if (index >= text.length) {

      clearInterval(intervalId);

      isLoading.value = true;

      isButton.value=false

      testjjy.push(text);

      return;

    }

    isLoading.value=false

    typedText.value += text.charAt(index);

    index++;

  }, 50);

};

其他感觉要的点

1:模糊搜索

const pattern = new RegExp(inputtext.value, 'i'); //构建正则表达式,表示可以忽略大小写,模糊匹配

2:个人觉得最关键的地方

  <p v-html="testjjy[index]" v-if="!isLastIndex(index) || isLoading == true"></p>

                <p v-if="isLastIndex(index) && isLoading === false" v-html="typedText"></p>

这一段是回答内容的展示,第一段是正常内容,判断的标准是:当没有输入问题的时候,isLoding==true,会正常显示所有内容,当输入问题,isLoding会先变成false,最后一个回答因为判断语句是!isLastindex,所以当定时器在进行的时候,这一dom是不会出现的,当定时器结束的时候,isLoding ==true,再展示出来,这样就避免了和下面逐字输出的dom相互冲撞。而第二段是逐字输出,只取最后一次循环 isLastIndex(index) ,isLoding用于判断定时器是否开启。

简单地说定时器开启的时候第二个p标签内容在展示,第一个消失。当定时器结束的时候,第二个消失,第一个挤上,这样就做到了想要的效果。

上完整示例代码

<template>

    <div class="all">

       

        <div class="left">

            <div class="Tagboard">

                <el-tabs :tab-position="tabPosition" style="height:auto;" @tab-click="click" class="demo-tabs">

                    <el-tab-pane label="选择书籍" disabled="true"></el-tab-pane>

                    <div v-for="(item, index) in Tablist" :key="index">

                        <el-tab-pane :label=item></el-tab-pane>

                    </div>

                </el-tabs>

                <div style="margin-left: 10vw;">

                <el-button @click="chaxun" style="background-color: skyblue; color: #000;">

    点击查询上一次对话

  </el-button>

  <el-dialog v-model="visible" :show-close="false">

    <template #header="{ close, titleId, titleClass }">

      <div class="my-header">

        <h4 :id="titleId" :class="titleClass">上一次对话</h4>

        <el-button type="danger" @click="close">

          关闭

        </el-button>

      </div>

    </template>

    <div><p style="color: skyblue;">问题是:</p>

        <p>{{lastquestion}}</p></div>

    <div><p style="color:gold;">回答是:</p>

        <p v-html="lastanswer"></p></div>

  </el-dialog>

  </div>



 

<div style="margin-left: 11.8dvw;margin-top: 1dvw;">

  <el-button @click="Mylike" style="background-color: red; color: #000;">

    我的喜欢

  </el-button>

  <el-dialog v-model="visiblelove" :show-close="false">

    <template #header="{ close, titleId, titleClass }">

      <div class="my-header">

        <h4 :id="titleId" :class="titleClass">我的喜欢</h4>

        <el-button type="danger" @click="close">

          关闭

        </el-button>

      </div>

    </template>

    <div v-for="(item,index) in myloveqs" :key="item" style="margin-top: 1vw;">

        <span style="color: skyblue;">我的问题</span>:{{myloveqs[index]}}<br> <span style="color:gold;">回答是:</span> <p v-html="mylovean[index]"></p>

    </div>

  </el-dialog>

            </div>

        </div>

    </div>

        <div class="right">

            <transition name="fade" :appear="true">

                <div v-if="IsShow" class="show">

                    <div class="top">

                        <h1>{{ text }}</h1>

                    </div>

                    <div class="center">

                        <div class="center-question" v-for="(item,index) in centerplace" :key="item.id">

                            <div class="userquestion">

                               

                                <p>{{ item.question }}</p>

                                <svg t="1700792823007" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5317" width="40" height="40"><path d="M665.8 390c0 53.9 43.7 97.6 97.6 97.6 53.9 0 97.6-43.7 97.6-97.6 0-53.9-43.7-97.6-97.6-97.6-53.9 0-97.6 43.6-97.6 97.6z m-77.2 242.8s0 0.1 0 0z m349.6 1.3v-0.2 0.2z m0-0.3v-0.3 0.3zM851.9 508.2l-8-0.1c-2.8 0-7.1 1.1-9.5 2.4 0 0-6.4 3.7-12.2 6.2-17.5 7.5-37.4 11.9-58.5 11.9-21 0-40.9-4.2-58.3-11.7-5.9-2.5-12.5-6.3-12.5-6.3-2.5-1.4-6.7-2.5-9.5-2.4l-7.9 0.1c-32 4.2-65.5 32.6-75.2 63.2 0 0-10.2 20.7-11.7 61.4-0.1 5.3 4.2 12 9.6 14.9 0 0 54.4 35 165.1 35 110.7 0 165.1-35 165.1-35 5.4-2.9 9.8-10.3 9.6-15-1.4-40.5-11.3-60.4-11.3-60.4-8.8-30.9-42.9-59.5-74.8-64.2zM938.2 633v-0.2 0.2z m0 0.5v-0.4 0.4z m0 0M254.8 481c47.6 0 87.2-34.1 95.8-79.2-13.6-24.3-21.4-52.2-21.8-81.8-17.9-20.9-44.4-34.1-74-34.1-53.9 0-97.6 43.7-97.6 97.6 0 53.8 43.7 97.5 97.6 97.5zM225 602.4c10.8-33.2 36.4-64.1 67.6-85-11.9 3.1-24.5 4.7-37.6 4.7-21 0-40.9-4.2-58.3-11.7-5.9-2.5-12.5-6.3-12.5-6.3-2.5-1.4-6.7-2.5-9.5-2.4l-7.9 0.1c-32 4.2-65.5 32.6-75.2 63.2 0 0-10.2 20.7-11.7 61.4-0.1 5.3 4.2 12 9.6 14.9 0 0 39.1 25 118.1 32.7 4.9-41.9 14.9-66 17.4-71.6z" fill="#AED7FF" p-id="5318"></path><path d="M763.5 708.4l1.2-0.8c0.4-0.3 1-1.3 1.5-2.1-4.4-54.7-18.5-82.2-18.7-82.5l-1.8-4.2c-12.5-37.8-57.6-73.7-99-79l-10.8 0.3c-0.1 0.1-1.7 0.5-2.4 0.8-2.8 1.8-12.1 7.4-21.2 11.7-31.7 15.3-66.4 23.8-103 25.3-36 1.5-72.2-4.3-104.5-16.6-8.8-3.3-17.8-7.8-21.6-9.7-37.3 15.9-70.9 51.5-80.9 88.5 0 0-13.6 30.5-13.3 89.4 0.1 3.6 1.6 7.5 3.9 11.1 37.6 13.8 112.8 34 223.6 29.5 164.4-6.6 246.2-61.1 247-61.7zM526 216.5c-78 0-141.2 63.2-141.2 141.2 0 8.4 0.9 16.6 2.3 24.6 22.3 38.7 64 65 111.8 65 71.1 0 128.9-57.8 128.9-128.9 0-30.8-10.9-59.1-29-81.4-21.3-13-46.1-20.5-72.8-20.5z" fill="#AED7FF" p-id="5319"></path><path d="M500.3 801.7c-173.7 0-262.9-52.5-271.7-58-13.7-7.5-23.5-23.2-23.3-37.7v-0.3c2.2-61.4 16.6-96.3 19.8-103.3 17.7-54.8 75.9-103.4 132.8-111l1.9-0.1 12.6-0.1c7.3-0.1 16.9 2.2 23.3 5.9 0.2 0.1 9.9 5.7 18.4 9.3 26.5 11.4 56.6 17.4 86.9 17.4 30.7 0 60.1-5.9 87.2-17.6 8.4-3.5 17.8-9 17.9-9l0.5-0.3c6.2-3.3 15.7-5.7 22.7-5.7l14 0.1 1.1 0.2c57.1 8.4 115.9 58.7 131.9 112.5 3.3 7.4 17 41.1 19 101.5v0.7h0.4v0.4h-0.4v0.2h0.4v0.6h-0.4 0.4v0.5h-0.4v0.1h0.4-0.4c-0.8 13.2-10.7 28.7-23.1 35.7-8.1 5-97.3 58-271.9 58z m-263.2-95.2c0.1 2 3 7.3 6.8 9.3l1.2 0.7c0.8 0.5 86 53.3 255.1 53.3 169.2 0 254.3-52.8 255.2-53.3l1-0.6c3.2-1.7 6.7-7.3 7.1-9.7-2.1-59.5-16.3-89.4-16.4-89.7l-0.6-1.3-0.4-1.4c-12-42.3-60.1-83.6-105.3-90.8l-11.7-0.1c-1.6 0-5.7 1-7.5 1.9-2 1.1-11.7 6.6-21 10.5-31 13.4-64.6 20.2-99.7 20.2-34.6 0-68.9-6.9-99.4-20-10.2-4.4-21.1-10.7-21.6-10.9-1.3-0.7-5.2-1.7-6.9-1.7h-0.3l-11.7 0.1c-44.3 6.3-92.7 47.3-106.1 89.9l-0.4 1.2-0.5 1.1c-0.1 0.2-14.8 31.3-17 91l0.1 0.1h-0.1c0.1 0 0.1 0.1 0.1 0.2zM500.6 490c-94.7 0-171.8-77.1-171.8-171.8 0-94.7 77.1-171.8 171.8-171.8 94.7 0 171.8 77.1 171.8 171.8-0.1 94.7-77.1 171.8-171.8 171.8z m0-311.7c-77.2 0-139.9 62.8-139.9 139.9 0 77.2 62.8 139.9 139.9 139.9 77.2 0 139.9-62.8 139.9-139.9 0-77.2-62.8-139.9-139.9-139.9z" fill="#1195FE" p-id="5320"></path><path d="M500.3 812.7c-176.4 0-267.7-53.5-277.5-59.6-16.8-9.1-28.8-28.7-28.5-47.3 2.2-61.5 15.9-97.1 20.5-107.4 19.1-58.2 81.2-109.9 141.7-117.9l2.6-0.2 13.2-0.2c9.2-0.1 20.8 2.7 28.8 7.3 0.2 0.1 9.5 5.4 17.3 8.8 25.2 10.8 53.7 16.5 82.5 16.5 29.2 0 57.1-5.6 82.8-16.7 7.8-3.3 16.7-8.4 16.8-8.4l0.7-0.4c8-4.3 19.2-7 28-7l16.7 0.4c61.4 9 123 61.5 140.7 119.5 4.2 9.6 16.2 41.1 19.3 95h0.5l0.4 23.3-2.2 0.1c-4 14-14.3 27.7-27 34.8-9.4 5.8-100.3 59.4-277.3 59.4zM373 502.1h-0.4l-13.9 0.2c-52.3 6.9-106.6 52.4-123.1 103.4l-0.4 1.2c-2.8 6.1-16.6 39.5-18.8 99.1-0.2 10.5 7.4 22.5 17.5 28 9.8 6.1 96.2 56.6 266.5 56.6 170.8 0 256.8-50.6 266-56.4 9.4-5.3 17.2-17.2 18-26.7V706c-2-59.2-15.4-91.7-18.1-97.7l-0.5-1.4c-14.9-49.9-70-96.9-123-104.7h-0.3l-13.3-0.1c-5.1 0-12.8 1.9-17.4 4.4-0.6 0.3-10.3 5.9-19.3 9.7-28.4 12.3-59.2 18.5-91.5 18.5-31.8 0-63.3-6.3-91.2-18.3-9.1-3.9-19.5-9.9-19.6-9.9-4.5-2.5-11.8-4.4-17.2-4.4z m127.3 278.8c-172.2 0-260.2-54.5-261-55l-0.9-0.5c-4.5-2.3-8.2-6.9-10.3-11.4l-2.1-1 0.2-7.3c0.1-2.1 0.2-4.1 0.3-6.1l0.2-4.2c3.5-54.7 17-83.5 17.6-84.8l0.3-0.8c14.7-46.8 66.3-90.5 115-97.5l1.5-0.1 11.7-0.1c3.8 0.1 9.5 1.3 12.6 3.1 1.2 0.7 11.3 6.4 20.5 10.4 29.1 12.5 62 19.1 95.1 19.1 33.6 0 65.7-6.5 95.3-19.3 8.8-3.7 18.1-9 19.9-10 3.5-1.8 9.3-3.3 13-3.3l13.4 0.3c49.7 7.9 100.9 52.1 114.2 98.7l0.3 0.9c1.6 3.5 15.5 34.4 17.6 94.1v1l-0.2 1c-0.8 5.6-6.3 14.3-12.7 17.8l-0.6 0.4c-0.7 0.1-88.3 54.6-260.9 54.6z m-229.2-63.7c34.1 15.1 110.9 41.6 229.2 41.6 164.5 0 248.5-51.1 249.3-51.7l1.2-0.7c0.4-0.3 1.1-1.2 1.6-2-2.2-54.9-15.2-82.9-15.3-83.2l-1.6-4.2c-10.9-38.3-54.6-76-95.7-82.9L629 534c-0.1 0.1-1.7 0.5-2.4 0.7-2.9 1.6-12.4 6.9-21.6 10.8-32.3 14-67.3 21-103.9 21-36.1 0-71.9-7.2-103.7-20.9-9.5-4.1-19.3-9.6-22.2-11.2-0.7-0.2-1.9-0.5-2.4-0.5l-10.6 0.1c-40.3 6.1-84.3 43.6-96.4 82.2l-1.6 3.9c-0.1 0.1-12.6 27.6-15.6 79.5l22.5 17.6z m481.8-13.6zM500.6 501c-100.8 0-182.8-82-182.8-182.8 0-100.8 82-182.8 182.8-182.8s182.8 82 182.8 182.8C683.3 419 601.3 501 500.6 501z m0-343.5c-88.6 0-160.8 72.1-160.8 160.8 0 88.6 72.1 160.8 160.8 160.8S661.4 407 661.4 318.3c-0.1-88.7-72.2-160.8-160.8-160.8z m0 311.7c-83.2 0-151-67.7-151-151s67.7-151 151-151 151 67.7 151 151-67.8 151-151 151z m0-279.9c-71.1 0-128.9 57.8-128.9 128.9 0 71.1 57.8 128.9 128.9 128.9 71.1 0 128.9-57.8 128.9-128.9 0-71.1-57.9-128.9-128.9-128.9z" fill="#1195FE" p-id="5321"></path></svg>

                            </div>

                           

                            <div style="display: flex; align-items: center;">

                              <div>

                      <svg t="1700793310715" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6602" width="40" height="40"><path d="M652.839385 929.476923h-472.615385a47.261538 47.261538 0 0 0 0 94.523077h472.615385a47.261538 47.261538 0 0 0 0-94.523077z" fill="#EA8978" p-id="6603"></path><path d="M855.433846 436.066462a78.769231 78.769231 0 0 0-109.016615 22.370461L700.100923 528.699077V252.061538a252.061538 252.061538 0 0 0-252.061538-252.061538H385.024a252.061538 252.061538 0 0 0-252.061538 252.061538v519.876924a126.030769 126.030769 0 0 0 126.030769 126.030769h315.076923a126.030769 126.030769 0 0 0 96.728615-47.261539 77.824 77.824 0 0 0 16.384-17.32923l190.936616-289.240616a78.769231 78.769231 0 0 0-22.685539-108.071384zM258.993231 403.298462a31.507692 31.507692 0 1 1 31.507692 31.507692 31.507692 31.507692 0 0 1-31.507692-31.507692z m304.994461 132.332307a149.661538 149.661538 0 0 1-291.76123 5.986462 23.630769 23.630769 0 1 1 46.00123-11.342769 102.4 102.4 0 0 0 199.75877-4.096 23.630769 23.630769 0 1 1 46.316307 9.452307zM542.562462 434.806154a31.507692 31.507692 0 1 1 31.507692-31.507692 31.507692 31.507692 0 0 1-31.507692 31.507692z" fill="#9FE2CD" p-id="6604"></path></svg>

                    </div>

                      <div>

                      <div style="margin-top: 10px;">

                                <span>{{ item.DateTime }}</span></div>

                            <div class="answer">

                                <p v-html="testjjy[index]" v-if="!isLastIndex(index) || isLoading == true"></p>

                <p v-if="isLastIndex(index) && isLoading === false" v-html="typedText"></p>

                            </div>

                        </div>

                        </div>

                            <div style="position: absolute;right: 50%;margin-top: 10px;display: flex;align-items: center;">

                             

                                <span style="margin-right: 5px;cursor: pointer;" @click="zan(item)"><svg v-if="item.dianzan.value == false"

                                        t="1700123725087" class="icon" viewBox="0 0 1024 1024" version="1.1"

                                        xmlns="http://www.w3.org/2000/svg" p-id="1468" width="20" height="20">

                                        <path

                                            d="M832 364.8h-147.2s19.2-64 32-179.2c6.4-57.6-38.4-115.2-102.4-121.6h-12.8c-51.2 0-83.2 32-102.4 76.8l-38.4 96c-32 64-57.6 102.4-76.8 115.2-25.6 12.8-121.6 12.8-128 12.8H128c-38.4 0-64 25.6-64 57.6v480c0 32 25.6 57.6 64 57.6h646.4c96 0 121.6-64 134.4-153.6l51.2-307.2c6.4-70.4-6.4-134.4-128-134.4z m-576 537.6H128V422.4h128v480z m640-409.6l-51.2 307.2c-12.8 57.6-12.8 102.4-76.8 102.4H320V422.4c44.8 0 70.4-6.4 89.6-19.2 32-12.8 64-64 108.8-147.2 25.6-64 38.4-96 44.8-102.4 6.4-19.2 19.2-32 44.8-32h6.4c32 0 44.8 32 44.8 51.2-12.8 102.4-32 166.4-32 166.4l-25.6 83.2h243.2c19.2 0 32 0 44.8 12.8 12.8 12.8 6.4 38.4 6.4 57.6z"

                                            fill="#ef4b36" p-id="1469"> </path>

                                    </svg>

                                    <svg v-if="item.dianzan.value==true" t="1700124249893" class="icon" viewBox="0 0 1024 1024" version="1.1"

                                        xmlns="http://www.w3.org/2000/svg" p-id="3594" width="20" height="20">

                                        <path

                                            d="M813.804544 402.39616l-144.41472 0.526336 59.636736-90.477568c59.628544-117.209088-30.844928-180.95104-30.844928-180.95104-63.746048-47.295488-93.242368 30.880768-93.242368 30.880768-118.556672 248.77056-312.89344 236.065792-312.89344 236.065792l-55.392256 0-62.306304 0c0 0-57.133056 0.248832-56.393728 62.539776l0 354.486272c1.98144 61.357056 55.428096 65.0752 55.428096 65.0752l41.884672 0 166.79424 0.605184 372.911104 0c52.445184 0 75.149312-27.84256 94.958592-94.959616l58.83392-235.418624C925.108224 449.876992 866.250752 402.39616 813.804544 402.39616zM219.02336 823.064576c0 10.933248-8.844288 19.777536-19.777536 19.777536s-19.777536-8.844288-19.777536-19.777536L179.468288 462.127104c0-10.933248 8.844288-19.777536 19.777536-19.777536s19.777536 8.844288 19.777536 19.777536L219.02336 823.064576z"

                                            fill="#FF9000" p-id="3595"></path>

                                    </svg>

                                </span>

                                <span style="margin-right: 5px;cursor: pointer;" @click="buxing(item)">

                                    <svg v-if="item.cai.value==false" t="1700123776163" class="icon" viewBox="0 0 1024 1024" version="1.1"

                                        xmlns="http://www.w3.org/2000/svg" p-id="2531" width="20" height="20">

                                        <path

                                            d="M544 928c63.312 0 105.072-30.5504 118.896-88.3216 11.4096-47.6928 3.8096-113.904-21.9616-199.6784h167.0048c66.2736 0 120-53.7264 120-120a120 120 0 0 0-1.9792-21.7008l-60.7168-330.2128C857.5648 126.3232 821.1584 96 778.6944 96H511.784c-40.5808 0-90.6256 10.0448-151.216 45.4352A136 136 0 0 1 291.976 160H152c-30.928 0-56 25.072-56 56v368c0 30.928 25.072 56 56 56h128.7584c47.864 0 82.496 13.2688 108.4384 38.2784 21.6144 20.8368 37.2048 49.3392 51.1376 89.5744 3.184 9.1968 6.2352 18.8 9.8736 30.9008 1.2 3.9952 7.3424 24.7648 9.0784 30.4848 9.2816 30.5936 16.376 48.8912 26.2752 64.2224C499.7968 915.504 519.1296 928 544 928z m0-48c-13.824 0-23.8736-15.5664-38.7824-64.6976-1.6736-5.52-7.792-26.208-9.0432-30.3712-3.8128-12.6784-7.048-22.8688-10.4816-32.784-16.1856-46.7424-35.1408-81.392-63.1824-108.4256-30.4448-29.3488-69.5456-46.6832-118.5088-50.7776V207.6064a184 184 0 0 0 80.776-24.7232C438.6848 151.3952 481.3824 144 511.7856 144h266.9088c19.3024 0 35.8512 13.7824 39.3408 32.7664l60.7168 330.2128a72 72 0 0 1 1.1872 13.0208c0 39.7648-32.2352 72-72 72H616.9888a30.4 30.4 0 0 0-9.384 1.4848c-15.9696 5.184-24.7136 22.3296-19.5312 38.2992 29.008 89.3728 38.0272 155.3952 28.1392 196.7248C607.7328 863.9472 585.792 880 544 880zM256 208v384H152a8 8 0 0 1-8-8V216a8 8 0 0 1 8-8h104z"

                                            fill="#979797" p-id="2532"></path>

                                    </svg>

                                    <svg v-if="item.cai.value==true" t="1700124466227" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4613" width="20" height="20"><path d="M611.188364 651.962182h226.56a93.090909 93.090909 0 0 0 91.834181-108.334546l-61.905454-372.689454A93.090909 93.090909 0 0 0 775.889455 93.090909H372.968727v558.871273c82.152727 81.338182 72.866909 210.571636 88.832 242.338909 15.941818 31.767273 47.616 36.119273 55.621818 36.608 39.703273 0 179.665455-32.395636 93.789091-278.946909zM313.832727 651.636364V93.090909H202.891636a93.090909 93.090909 0 0 0-92.997818 88.901818l-16.709818 372.363637A93.090909 93.090909 0 0 0 186.181818 651.636364h127.650909z" fill="#333333" p-id="4614"></path></svg>

                                </span>

                            </div>

                        </div>

                    </div>

                    <div class="bottom">

                        <el-tooltip :content="Topcenter" placement="top">

                            <textarea type="text" v-model="inputtext" name="text" maxlength="50" rows="5"

                                placeholder="请输入您的问题" class="shuru" ref="inputref" style="height: 50%;"/>

                        </el-tooltip>

                        <div class="bottom-text">

                            <p>{{ maxinputlength || 0 }} / 50</p>

                            <div class="button" :class="{active:isButton}" @click="put">

                                <span>提交</span>

                            </div>

                        </div>

                    </div>

                </div>

            </transition>

        </div>

    </div>

</template>

<script setup lang="ts">

import { reactive, ref, computed } from 'vue';

import { QuestionAndAnswer, minganci } from '../example/question.ts'


 

let tabPosition = ref('left')

let Tablist = reactive([

    "《C程序设计语言》", "《Java 并发编程实战》", "《Linux多线程服务端编程》", "《Windows 核心编程》", "《设计数据密集型应用》"

])

let IsShow = ref(false)

let text = ref('')

let inputtext = ref('')

let centerplace = reactive<any>([])

const visible = ref(false)

const visiblelove = ref(false)

let lastquestion=ref<String>()

let lastanswer = ref<String>()

let myloveqs= reactive([])

let mylovean = reactive([])

let inputref = ref(null)

let isButton = ref(false)

let typedText = ref('')

let testjjy = reactive<string[]>([])

let isLoading = ref(false)


 

//answer插入人工智能信息

const put = () => {

    const currentDate = new Date();

    const formattedDate = `${currentDate.getFullYear()}-${currentDate.getMonth() + 1}-${currentDate.getDate()} ${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;

    const Index = Object.keys(QuestionAndAnswer).indexOf(text.value)

    const AIanswer = ref('对不起,暂无题库')

    for (let j = 0; j < Object.values(QuestionAndAnswer)[Index].length; j++) {

        const pattern = new RegExp(inputtext.value, 'i'); //构建正则表达式,表示可以忽略大小写,模糊匹配

        if (pattern.test(Object.values(QuestionAndAnswer)[Index][j][0])) {

            AIanswer.value = Object.values(QuestionAndAnswer)[Index][j][1]

        }

    }

    for (let i = 0; i < minganci.length; i++) {

        const patterntwo = new RegExp(minganci[i], 'i');

        if (patterntwo.test(inputtext.value)) {

            AIanswer.value = '对不起,您有敏感词汇,请检查并重新发送'

        }

    }

    centerplace.push({

        id: centerplace.length + 1, // 按照长度生成id,

        DateTime: formattedDate,

        question: inputtext.value,

        answer: AIanswer.value,

        dianzan:ref(false),

        cai:ref(false)

    })

    typeEffect(centerplace[centerplace.length-1].answer)


 

    localStorage.setItem('question',centerplace[centerplace.length-1].question)

    localStorage.setItem('answer',centerplace[centerplace.length-1].answer)

    inputtext.value = '';

    (inputref.value as HTMLInputElement | null)?.focus()

}


 

const chaxun=()=>{

    lastquestion.value=localStorage.getItem('question') as string

    lastanswer.value=localStorage.getItem('answer') as string

    visible.value=true

}

const Topcenter = computed(() => {

    const Index = Object.keys(QuestionAndAnswer).indexOf(text.value)

    return '你可以问: ' + Object.values(QuestionAndAnswer)[Index][0][0]

})

const click = (tab: any) => {

    text.value = tab.props.label

    testjjy = []

    centerplace = []

    typedText.value= ''

    if (IsShow.value == false) {

        IsShow.value = true

    } else {

        IsShow.value = false

        setTimeout(() => {

            IsShow.value = true

        }, 100);

    }

}

const isLastIndex = computed(() => {

  return (index:any) => index === centerplace.length - 1;

});



 

const typeEffect = (text: string) => {

  typedText.value = "";

  let index = 0;

  isButton.value=true

  const intervalId = setInterval(() => {

    if (index >= text.length) {

      clearInterval(intervalId);

      isLoading.value = true;

      isButton.value=false

      testjjy.push(text);

      return;

    }

    isLoading.value=false

    typedText.value += text.charAt(index);

    index++;

  }, 50);

};



 

const zan = (item:any)=>{

    item.dianzan.value=!item.dianzan.value;

    item.cai.value=false

    // 从本地存储中获取之前保存的点赞数量数组

  let xihuanqs = JSON.parse(localStorage.getItem('xihuanqs') || '[]');

  let xihuanan = JSON.parse(localStorage.getItem('xihuanan') || '[]');

  // 将新的点赞数量添加到数组中

  let isExitQuestion = xihuanqs.some((q:any)=>q=== item.question)

  if(!isExitQuestion){

    xihuanqs.push(item.question);

  xihuanan.push(item.answer);

  // 将更新后的数组保存到本地存储中

  localStorage.setItem('xihuanqs', JSON.stringify(xihuanqs));

  localStorage.setItem('xihuanan', JSON.stringify(xihuanan));

  }

}

const Mylike = ()=>{

    visiblelove.value=true

    myloveqs = (JSON.parse(localStorage.getItem('xihuanqs') as string))

    mylovean = (JSON.parse(localStorage.getItem('xihuanan') as string))

}

const buxing=(item:any)=>{

    item.cai.value=!item.cai.value;

    item.dianzan.value=false

    let xihuanqs = JSON.parse(localStorage.getItem('xihuanqs') || '[]');

   let xihuanan = JSON.parse(localStorage.getItem('xihuanan') || '[]');

   // 判断要取消点赞的问题和答案是否已经存在于本地存储中

  const questionIndex = xihuanqs.indexOf(item.question);

  const answerIndex = xihuanan.indexOf(item.answer);

  if (questionIndex !== -1 && answerIndex !== -1) {

    // 从数组中删除要取消点赞的问题和答案

    xihuanqs.splice(questionIndex, 1);

    xihuanan.splice(answerIndex, 1);

    // 将更新后的数组保存到本地存储中

  localStorage.setItem('xihuanqs', JSON.stringify(xihuanqs));

  localStorage.setItem('xihuanan', JSON.stringify(xihuanan));

  }

}


 

const maxinputlength = computed(() => {

    return inputtext.value.length

})

</script>

<style scoped lang="scss">

:deep(.my-header) {

  display: flex;

  flex-direction: row;

  justify-content: space-between;

}

.all {

    display: flex;

    width: 100%;

    height: 100%;

    .left {

        flex: 1;

        display: flex;

        justify-content: center;

        align-items: center;

        .Tagboard {

            .demo-tabs {

                padding: 32px;

                color: #6b778c;

                font-size: 32px;

                font-weight: 600;

                :deep(.el-tabs__item) {

                    font-size: 25px;

                    margin: 10px;

                }

            }

        }


 

    }

    .right {

        flex: 1;

        display: flex;

        width: 100%;

        align-items: center;

        position: relative;

        overflow: hidden;

        .fade-enter-active {

            animation: jinge 1s;

        }

        @keyframes jinge {

            from {

                transform: translateX(100%)

            }

            to {

                transform: translateX(0%);

            }

        }

        .show {

            width: 100%;

            height: 100%;

            position: absolute;

            right: 0;

            background-color: skyblue;

            .top {

                height: 10%;

                display: flex;

                justify-content: left;

                align-items: center;

                h1 {

                    margin-left: 10%;

                    font-size: 2rem;

                }

            }

            .center {

                height: 70%;

                background-color: rgb(235, 235, 235);

                display: flex;

                flex-direction: column;

                align-items: center;

                overflow: auto;

                .center-question {

                    width: 95%;

                    height: auto;

                    margin: 20px 0px;

                    margin-bottom: 3rem;

                    position: relative;

                    .userquestion {

                        width: 100%;

                        height: auto;

                        display: flex;

                        align-items: center;

                        justify-content: flex-end;

                        p {

                            margin-right: 1rem;

                            padding: 5px;

                            background-color: skyblue;

                            border-radius: 8px;

                            color: #000;

                        }

                    }

                    .answer {

                        width: 21vw;

                        height: auto;

                        display: flex;

                        align-items: center;

                        justify-content: flex-start;

                        background-color: white;


 

                        p {

                            margin-left: 1rem;

                            padding: 5px;

                            background-color: white;

                            border-radius: 8px;

                            color: black;

                        }

                    }

                }

            }

            .bottom {

                height: 20%;

                width: 100%;

                background-color:#faf4f4;

       

                .shuru {

                    width: 96%;

                    resize: none;

                    background-color: #faf4f4;

                    margin: 1rem;

                    font-size: 20px;

                    letter-spacing: 4px;

                    border: none;

                }

               

                .bottom-text {

                    width: 95%;

                    margin: auto;

                    height:50%;

                    display: flex;

                    justify-content: space-between;

                    .button {

                        height: 2rem;

                        width: 8rem;

                        text-align: center;

                        line-height: 2rem;

                        background-color: skyblue;

                        color: #000;

                        cursor: pointer;

                    }

                    .button.active{                

                        background-color: gray;

                        pointer-events: none;

                    }

                }

            }

        }

    }

}</style>

其中还有引入的question,question的头部内容,需要和TabList相对应,这只是个简单示范案例,如果是调用接口的话,最好使用数据流的方式。也是大差不差的。

question.ts内容

export const QuestionAndAnswer = {

    "《C程序设计语言》":[

        ["C语言难学习吗", "对于不同的人来说,学习C语言的难易程度是不一样的,但总体来说,C语言相对于其他编程语言来说,学习难度较高。但对于想要深入学习计算机科学和编程的人来说,C语言是一门非常重要的基础编程语言,掌握它将会对编程技能的提高和职业发展的帮助很大。"],

        ["这本书涵盖的知识点", "主要包括了C语言基本语法,程序设计;标准库函数;指针和数组,结构和联合,C语言高级特性,示例程序设计等。"],

        ["学好这本书有哪些课程推荐", "您可以按照以下课程推荐:1:<a href=''>C程序设计语言</a>。2:<a href=''>C语言程序设计</a>。3:<a href=''>C语言程序设计高级篇</a>。4:<a href=''>数据结构与算法分析</a>。5:<a href=''>Linux系统编程</a>。"]

    ],

    "《Java 并发编程实战》":[

        ["什么是Java", "Java是一门面向对象的高级编程语言,不仅吸收了C语言的各种优点,还摒弃了C里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。"],

        ["这本书的实战内容有关于微服务内容吗", "有的,书中的第三章《微服务架构与开发》会详细介绍关于java的微服务内容。"],

        ["lambda表达式是什么", "lambda表达式是一种匿名函数,可以用来简化代码。lambda表达式的语法是lambda arguments: expression,其中arguments是函数的参数,expression是函数的返回值。"],

        ["学好这本书有哪些课程推荐", "您可以按照以下课程推荐:1:<a href=''>Java基础课程</a>。2:<a href=''>Java微服务</a>。3:<a href=''>Java高并发</a>。4:<a href=''>Java高级程序设计</a>。5:<a href=''>数据结构与算法分析</a>。"]

    ],

    "《Linux多线程服务端编程》":[

        ["这本书有哪些摘要", "这本书主要介绍了Linux下多线程服务端编程的相关知识,包括多线程编程基础、线程同步与互斥、信号处理、网络编程、多线程服务器设计等内容。通过学习本书,读者可以掌握Linux下多线程编程的技术,提高服务器性能和稳定性。"],

        ["这本书涵盖的知识点", "主要涵盖了这几个知识点:硬件和操作系统的发展对多线程编程的影响;C++11的多线程编程支持;新的线程同步和互斥工具,如原子操作和读写锁;面向对象设计和设计模式在多线程编程中的应用;多线程网络编程的新技术,如异步I/O和多路复用;Docker和容器化技术等等。"],

        ["学好这本书有哪些课程推荐", "您可以按照以下课程推荐:1:<a href=''>Linux 基础课程</a>。2:<a href=''>Linux 系统管理</a>。3:<a href=''>Linux 内核开发</a>。4:<a href=''>Linux 网络编程</a>。5:<a href=''>Linux 安全与防护</a>。"]

    ],

    "《Windows 核心编程》":[

        ["windows有哪些编程语言", "目前比较流行的有python,java,C++,c,javascript,swift,php等,你可以问我一个具体的语言。"],

        ["学好这本书对我有什么帮助", "提高编程技能:系统编程是编程领域中较为复杂和高级的领域之一,学习这本书可以提高你的编程技能和编程思维,帮助你成为更加优秀的程序员。对于那些想要从事系统编程或者Windows平台开发的程序员来说,学好《Windows核心编程》可以为你的职业发展带来很大的帮助。掌握系统编程和Windows平台的开发技能,可以为你在软件开发行业中找到更好的职业和机会。"],

        ["学好这本书有哪些课程推荐", "您可以按照以下课程推荐:1:<a href=''>windows编程</a>。2:<a href=''>windows核心编程</a>。3:<a href=''>Windows驱动程序开发</a>。4:<a href=''>Win32 API编程</a>。5:<a href=''>Windows编程精粹</a>。"]

    ],

    "《设计数据密集型应用》":[

        ["学好这本书我需要提前掌握什么技能", "编程语言:该书主要以Java、Python和Go等编程语言为例,因此需要掌握至少一门这些语言中的一门或多门。数据库:该书涉及到大量关于数据库的技术,例如数据库的设计、查询优化、事务、分布式数据库等,因此需要掌握SQL和至少一种关系型或非关系型数据库。数据结构和算法:该书中涉及到很多算法和数据结构,例如哈希表、排序算法、搜索算法等,因此需要掌握基本的数据结构和算法。"],

        ["这本书的内容摘要", "本书讨论了大量关于数据密集型应用的核心概念、原则和技术。它包含了对可靠性、可扩展性和可维护性的深入讨论,以及分布式数据的复制、分片和可扩展性的讨论。此外,本书还介绍了批处理和流处理,以及分布式系统的概念和应用。 最后,本书还讨论了数据系统未来的发展方向。本书是一本深入探讨数据密集型应用设计和构建的重要参考书,适合那些想要开发数据密集型应用的软件工程师和数据工程师阅读。"],

        ["学好这本书有哪些课程推荐", "您可以按照以下课程推荐:1:<a href=''>设计数据密集型应用</a>。2:<a href=''>分布式系统原理与范型</a>。3:<a href=''>数据库系统实现</a>。4:<a href=''>大规模分布式系统设计</a>。5:<a href=''>流处理系统设计</a>。"]

    ]

};

export const minganci = ['草','靠','政治']


分为两部分,问题和敏感词
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值