【项目实训】基于大模型的小学语数英辅助教育平台 | 前端搭建(9)

本次前端采用了vue,具体呈现的效果如下
题目生成前端

1. 组件结构

<template>
  <div class="chatHome">
    <div class="chatLeft">
      <div class="title">
        <br/>
        <br/>
        <h1>Question Generation</h1>
      </div>
      <div class="options">
        <input v-model="newOption" placeholder="输入选项" />
        <button class = "addOption" @click="addOption">提交</button>
        <div class="options-wrapper">
          <div
            class="optionList"
            v-for="option in options"
            :key="option.id"
            :class="{ selected: option.id === currentOption }"
            @click="selectOption(option)"
            @mouseover="showDeleteButton(option.id)"
            @mouseleave="hideDeleteButton(option.id)"
          >
            {{ option.knowledge }}
            <button
              v-if="option.showDelete"
              class="delete-button"
              @click.stop="deleteOption(option.id)"
            >
              删除
            </button>
          </div>
        </div>
        <div class="button-group">
          <button class="regenerate-button" @click="reGenerate">重新生成</button>
          <button
              class="collect-button"
              @click="collect"
              :class="{ collected: isOptionCollected }"
          >
            {{ collectButtonText }}
          </button>
        </div>
      </div>
    </div>
    <div class="chatRight">
      <div v-if="showChatWindow">
        <ChatWindow :frinedInfo="chatWindowInfo"></ChatWindow>
      </div>
      <div class="showIcon" v-else>
        <span class="iconfont icon-snapchat"></span>
      </div>
    </div>
  </div>
</template>

2. 脚本逻辑

import OptionCard from "@/components/OptionCard.vue";
import ChatWindow from "./chatwindow.vue";
import { generateUUID } from "@/util/util.js";
import { chatgpt_generate } from "@/api/getData";
import Showdown from "showdown";
import { options } from "axios";

export default {
  name: "App",
  components: {
    OptionCard,
    ChatWindow,
  },
  data() {
    return {
      newOption: "",
      options: [],
      currentOption: "",
      showChatWindow: false,
      chatWindowInfo: "",
      isSend: false,
    };
  },
  mounted() {
    if(localStorage.getItem("question") != null) {
      let question = JSON.parse(localStorage.getItem("question"));
      let collection = JSON.parse(localStorage.getItem("collection"));
      for(let i = 0; i < question.length; i++) {
        question[i].showDelete = false;
        question[i].isCollected = collection.some(item => item.id === question[i].id);
        this.options.push(question[i]);
      }
    }
  },
  methods: {
    addOption() {
      if (this.newOption.trim() !== "") {
        let new_option = {
          knowledge: this.newOption.trim(),
          content: "",
          analysis: "",
          answer: "",
          id: generateUUID(),
          showDelete: false,
          isCollected: false,
        };
        let data = { msg: new_option.knowledge.toString() };
        this.newOption = '';
        chatgpt_generate(data).then((res) => {
          let converter = new Showdown.Converter();
          let htmlStr = res.msg;
          let convertedHtml = converter.makeHtml(htmlStr);
          this.isSend = false;
          let question = JSON.parse(localStorage.getItem("question"));
          let threePart = this.extractContent(convertedHtml);
          new_option.content = threePart[0];
          new_option.analysis = threePart[1];
          new_option.answer = threePart[2];
          this.options.unshift(new_option);
          this.showChatWindow = true;
          this.chatWindowInfo = new_option;
          this.isSend = true;
          question.unshift(new_option);
          localStorage.setItem("question", JSON.stringify(question));
          this.currentOption = new_option.id;
        });
      } else {
        this.$message({
          message: "消息为空",
          type: "warning",
        });
      }
    },
    showDeleteButton(id) {
      const option = this.options.find(opt => opt.id === id);
      if (option) option.showDelete = true;
    },
    hideDeleteButton(id) {
      const option = this.options.find(opt => opt.id === id);
      if (option) option.showDelete = false;
    },
    deleteOption(id) {
      this.options = this.options.filter(option => option.id !== id);
      localStorage.setItem("question", JSON.stringify(this.options));
      this.showChatWindow = false;
    },
    extractContent(htmlString) {
      let parser = new DOMParser();
      let doc = parser.parseFromString(htmlString, 'text/html');

      let contentSections = ["题目内容:", "解析:", "答案:"];
      let result = [];

      contentSections.forEach((section, index) => {
        let element = Array.from(doc.body.querySelectorAll('p')).find(p => p.innerHTML.includes(section));
        if (element) {
          let content = element.innerHTML.replace(section, "").trim();
          let sibling = element.nextElementSibling;
          while (sibling && !contentSections.some(sec => sibling.innerHTML.includes(sec))) {
            content += " " + sibling.innerHTML.trim();
            sibling = sibling.nextElementSibling;
          }
          content = content.replace("<strong>", "").replace("</strong>", "");
          result.push(content);
        } else {
          result.push("");
        }
      });
      return result;
    },
    selectOption(option) {
      this.showChatWindow = true;
      this.chatWindowInfo = option;
      this.currentOption = option.id;
    },
    reGenerate() {
      if (!this.showChatWindow) return;
      const option = this.options.find(opt => opt.id === this.currentOption);
      if (option) {
        let data = { "msg": option.knowledge.toString() };
        chatgpt_generate(data).then((res) => {
          let converter = new Showdown.Converter();
          let htmlStr = res.msg;
          let convertedHtml = converter.makeHtml(htmlStr);
          let threePart = this.extractContent(convertedHtml);
          option.content = threePart[0];
          option.analysis = threePart[1];
          option.answer = threePart[2];

          let question = JSON.parse(localStorage.getItem("question"));
          const index = question.findIndex(q => q.id === option.id);
          if (index !== -1) {
            question[index] = option;
            localStorage.setItem("question", JSON.stringify(question));
          }
          this.chatWindowInfo = option;
        });
      }
    },
    collect() {
      if (!this.showChatWindow) return;
      let collection = JSON.parse(localStorage.getItem("collection"));
      const option = this.options.find(opt => opt.id === this.currentOption);
      if (option.isCollected) {
        collection = collection.filter(item => item.id !== option.id);
      } else {
        collection.push(option);
      }
      option.isCollected = !option.isCollected;
      localStorage.setItem("collection", JSON.stringify(collection));
    },
  },
  computed: {
    isOptionCollected() {
      if (!this.showChatWindow) return false;
      const option = this.options.find(opt => opt.id === this.currentOption);
      return option ? option.isCollected : false;
    },
    collectButtonText() {
      return this.isOptionCollected ? '已收藏' : '收藏';
    },
  },
};
</script>

3. 样式

<style scoped>
.chatHome {
  display: flex;

  .chatLeft {
    width: 190px;

    .title {
      color: #fff;
      padding-left: 10px;
    }

    .options {
      margin-top: 45px;

      input {
        border-width: 0;
        border-radius: 10px;
        padding: 10px;
        background-color: #fff;
        color: rgb(176, 178, 189);
        cursor: pointer;

        &:hover {
          background-color: rgb(176, 178, 189);
        }
      }

      .addOption {
        margin-top: 20px;
        border-width: 0;
        border-radius: 10px;
        background-color: rgb(50, 54, 68);
        color: #fff;
        width: 185px;
        height: 30px;
        cursor: pointer;

        &:hover {
          background-color: #1d90f5;
        }
      }

      .options-wrapper {
        padding-left: 10px;
        height: 40vh;
        margin-top: 20px;
        overflow: hidden;
        border-radius: 10px;
        background-color: rgb(50, 54, 68);
        overflow-y: scroll;

        .optionList {
          display: flex;
          justify-content: space-between;
          align-items: center;
          padding: 10px;
          border-radius: 10px;
          background-color: rgb(79, 84, 103);
          margin: 10px 10px 0 0;
          cursor: pointer;


          color: white;
          position: relative;

          &:hover {
            background-color: #1d90f5;
          }
        }

        .optionList.selected {
          background-color: #1d90f5;
        }

        .delete-button {
          position: absolute;
          top: 10px;
          right: 10px;
          display: none;
          background-color: #932828;
          color: white;
          border: none;
          border-radius: 5px;
          padding: 5px;
          cursor: pointer;
        }

        .optionList:hover .delete-button {
          display: block;
        }

        &::-webkit-scrollbar {
          width: 0;
          height: 0;
          display: none;
        }
      }

      .button-group {
        display: flex;
        justify-content: space-between;
        margin-top: 10px;

        .regenerate-button, .collect-button {
          width: 85px;
          height: 30px;
          border: none;
          border-radius: 10px;
          background-color: rgb(50, 54, 68);
          color: #fff;
          cursor: pointer;

          &:hover {
            background-color: #1d90f5;
          }
        }

        .collected {
          background-color: #28a745;
          &hover {
            background-color: #218838;
          }
        }
      }
    }
  }

  .chatRight {
    flex: 1;
    padding-right: 30px;

    .showIcon {
      position: absolute;
      top: calc(50% - 150px);
      left: calc(50% - 50px);

      .icon-snapchat {
        width: 300px;
        height: 300px;
        font-size: 300px;
      }
    }
  }
}
</style>

详细解释

模板部分
  1. 左侧选项管理部分(chatLeft)

    • 包含一个标题“Question Generation”。
    • 一个输入框用于添加新选项。
    • 一个“提交”按钮,点击后调用addOption方法。
    • 选项列表通过v-for指令遍历options数组生成,每个选项可以显示其内容并有一个删除按钮。
    • “重新生成”和“收藏”按钮用于重新生成问题和收藏问题。
  2. 右侧聊天窗口部分(chatRight)

    • 根据showChatWindow变量的值,显示聊天窗口或一个默认图标。
脚本部分
  1. 导入组件和工具

    • OptionCardChatWindow组件。
    • generateUUID用于生成唯一ID。
    • chatgpt_generate用于调用API生成问题内容。
    • Showdown用于将Markdown转换为HTML。
  2. 数据定义

    • newOption:存储用户输入的新选项。
    • options:选项列表。
    • currentOption:当前选中的选项ID。
    • showChatWindow:控制聊天窗口的显示。
    • chatWindowInfo:当前聊天窗口显示的信息。
    • isSend:控制发送状态。
  3. 生命周期钩子

    • mounted:组件加载时,从localStorage获取问题列表和收藏状态,并初始化选项列表。
  4. 方法

    • addOption:添加新选项,并通过chatgpt_generate获取生成内容,解析并存储在本地。
    • showDeleteButtonhideDeleteButton:控制删除按钮的显示和隐藏。
    • deleteOption:删除选项,并更新localStorage
    • extractContent:解析生成的HTML内容,提取题目、解析和答案。
    • selectOption:选择选项并显示在聊天窗口。
    • reGenerate:重新生成当前选项的内容,并更新localStorage
    • collect:收藏或取消收藏当前选项,并更新localStorage
  5. 计算属性

    • isOptionCollected:判断当前选项是否被收藏。
    • collectButtonText:根据收藏状态显示按钮文本。
样式部分
  • 总体布局

    • .chatHome使用flex布局,分为左侧和右侧。
  • 左侧样式

    • .chatLeft:设置宽度和内边距。
    • .options:包括输入框、提交按钮、选项列表及按钮组的样式。
    • .options-wrapper:设置选项列表的滚动条样式和选项卡样式。
  • 右侧样式

    • .chatRight:设置填充和默认图标的样式。

总结

用户可以添加、删除、重新生成和收藏问题,数据通过localStorage进行持久化。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值