基于vue3+pinia2仿ChatGPT聊天实例|vite4.x仿chatgpt界面
使用vue3+pinia2开发仿制chatgpt界面聊天实例Vue3-Chatgpt
基于Vue3.x+Pinia2+VueRouter+Vue3-Markdown等技术构建仿ChatGPT网页端聊天程序。支持经典+分栏界面布局、light/dark模式、全屏+半屏显示、Markdown语法解析、侧边栏隐藏等功能。


技术框架
- 编辑工具:Cursor
- 框架技术:Vue3+Vite4.x+Pinia2
- 组件库:VEPlus (基于vue3桌面端组件库)
- 国际化多语言:vue-i18n^9.2.2
- 代码高亮:highlight.js^11.7.0
- 本地存储:pinia-plugin-persistedstate^3.1.0
- markdown解析:vue3-markdown-it


项目目录结构














vite.config.js配置
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
import { parseEnv } from './src/utils/env'// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {const viteEnv = loadEnv(mode, process.cwd())const env = parseEnv(viteEnv)return {plugins: [vue()],// base: '/',// mode: 'development', // development|production/*构建选项*/build: {// minify: 'esbuild', // 打包方式 esbuild(打包快)|terser// chunkSizeWarningLimit: 2000, // 打包大小警告// rollupOptions: {// output: {// chunkFileNames: 'assets/js/[name]-[hash].js',// entryFileNames: 'assets/js/[name]-[hash].js',// assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',// }// }},esbuild: {// 打包去除 console.log 和 debuggerdrop: env.VITE_DROP_CONSOLE ? ['console', 'debugger'] : []},/*开发服务器选项*/server: {// 端口port: env.VITE_PORT,// 是否浏览器自动打开open: env.VITE_OPEN,// 开启httpshttps: env.VITE_HTTPS,// 代理配置proxy: {// ...}},resolve: {// 设置别名alias: {'@': resolve(__dirname, 'src'),'@assets': resolve(__dirname, 'src/assets'),'@components': resolve(__dirname, 'src/components'),'@views': resolve(__dirname, 'src/views'),// 解决vue-i18n警告提示:You are running the esm-bundler build of vue-i18n.'vue-i18n': 'vue-i18n/dist/vue-i18n.cjs.js'}}}
})
main.js主入口
import { createApp } from 'vue'
import App from './App.vue'// 引入Router和Store
import Router from './router'
import Store from './store'// 引入插件配置
import Plugins from './plugins'const app = createApp(App)app
.use(Router)
.use(Store)
.use(Plugins)
.mount('#app')
vue3.x组件库
项目中使用的组件库是基于vue3自定义UI组件库Ve-plus。一个支持40+组件的轻量级组件库。


安装组件
yarn add ve-plus
npm i ve-plus --save
https://blog.csdn.net/yanxinyun1990/article/details/129312570
整体布局
项目支持2种布局模式,整体分为顶栏+侧边栏+主体内容三大模块构成。


<div class="ve__layout-body flex1 flexbox"><!-- //中间栏 --><div class="ve__layout-menus flexbox" :class="{'hidden': store.config.collapse}"><aside class="ve__layout-aside flexbox flex-col"><ChatNew /><Scrollbar class="flex1" autohide size="4" gap="1"><ChatList /></Scrollbar><ExtraLink /><Collapse /></aside></div><!-- //右边栏 --><div class="ve__layout-main flex1 flexbox flex-col"><!-- 主内容区 --><Main /></div>
</div>
<template><div class="vegpt__editor"><div class="vegpt__editor-inner"><Flex :gap="0"><Popover placement="top" trigger="click" width="150"><Button class="btn" type="link" icon="ve-icon-yuyin1" v-tooltip="{content: '发送语音', theme: 'light', arrow: false}"></Button><template #content><div class="flexbox flex-alignc flex-col" style="padding: 15px 0;"><Icon name="ve-icon-yuyin" size="40" color="#0fa27e" /><p class="fs-12 mb-15 c-999">网络不给力</p><Button size="small"><i style="background:#f00;border-radius:50%;box-shadow:0 1px 2px #999;margin-right:5px;height:8px;width:8px;"></i>开始讲话</Button></div></template></Popover><Button class="btn" type="link" v-tooltip="{content: '发送图片', theme: 'light', arrow: false}"><Icon name="ve-icon-photo" size="16" cursor /><input ref="uploadImgRef" type="file" title="" accept="image/*" @change="handleUploadImage" /></Button><Inputclass="flex1"ref="editorRef"v-model="editorText"type="textarea":autosize="{maxRows: 4}"clearableplaceholder="Prompt..."@keydown="handleKeydown"@clear="handleClear"style="margin: 0 5px;"/><Button class="btn" type="link" icon="ve-icon-submit" @click="handleSubmit"></Button></Flex></div></div>
</template>
import { ref, watch } from 'vue'
import { guid } from '@/utils'
import { chatStore } from '@/store/modules/chat'const props = defineProps({value: { type: [String, Number] }
})
const emit = defineEmits(['clear'])const chatState = chatStore()const uploadImgRef = ref()
const editorRef = ref()
const editorText = ref(props.value)// ...// 发送会话
const handleSubmit = () => {editorRef.value.focus()if(!editorText.value) returnlet data = {type: 'text',role: 'User',key: guid(),content: editorText.value}chatState.addSession(data)// 清空editorText.value = ''
}
const handleKeydown = (e) => {// ctrl+enterif(e.ctrlKey && e.keyCode == 13) {handleSubmit()}
}
const handleClear = () => {emit('clear')
}
// 选择图片
const handleUploadImage = () => {let file = uploadImgRef.value.files[0]if(!file) returnlet size = Math.floor(file.size / 1024)console.log(size)if(size > 2*1024) {Message.danger('图片大小不能超过2M')uploadImgRef.value.value = ''return false}let reader = new FileReader()reader.readAsDataURL(file)reader.onload = function() {let img = this.resultlet data = {type: 'image',role: 'User',key: guid(),content: img}chatState.addSession(data)}
}

/*** 聊天状态管理* @author YXY Q:282310962*/import { defineStore } from 'pinia'
import { guid, isEmpty } from '@/utils'export const chatStore = defineStore('chat', {state: () => ({// 聊天会话记录sessionId: '',session: []}),getters: {},actions: {// 创建新会话createSession(ssid) {this.sessionId = ssidthis.session.push({sessionId: ssid,title: '',data: []})},// 新增会话addSession(message) {// 判断当前会话uuid是否存在,不存在创建新会话if(!this.sessionId) {const ssid = guid()this.createSession(ssid)}this.session.map(item => {if(item.sessionId == this.sessionId) {if(!item.title) {item.title = message.content}item.data.push(message)}})// ...},// 获取会话getSession() {return this.session.find(item => item.sessionId == this.sessionId)},// 移除会话removeSession(ssid) {const index = this.session.findIndex(item => item?.sessionId === ssid)if(index > -1) {this.session.splice(index, 1)}this.sessionId = ''},// 删除某一条会话deleteSession(ssid) {// ...},// 清空会话clearSession() {this.session = []this.sessionId = ''}},// 本地持久化存储(默认存储localStorage)persist: true/* persist: {// key: 'chatStore', // 不设置则是默认appstorage: localStorage,paths: ['aa', 'bb'] // 设置缓存键} */
})
好了,基于vue3+vite4+pinia2开发模仿chatgpt聊天就分享到这里。
Tauri-Vue3聊天实例|Tauri跨端聊天
uniapp-ttlive短视频聊天|uniapp+uview仿抖音实例

相关文章:
基于vue3+pinia2仿ChatGPT聊天实例|vite4.x仿chatgpt界面
使用vue3pinia2开发仿制chatgpt界面聊天实例Vue3-Chatgpt 基于Vue3.xPinia2VueRouterVue3-Markdown等技术构建仿ChatGPT网页端聊天程序。支持经典分栏界面布局、light/dark模式、全屏半屏显示、Markdown语法解析、侧边栏隐藏等功能。 技术框架 编辑工具:Cursor框架…...
JDK动态代理和CGLIB动态代理
JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理 JDK动态代理和CGLIB动态代理 ① JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类,在获取代理对象时&#x…...
Jetpack Hilt 框架的基本使用
什么是 Hilt? Hilt 是一个功能强大、用法简单的依赖注入框架,于 2020 年加入到 Jetpack 家族中。它是 Android 团队联系了 Dagger2 团队,一起开发出来的一个专门面向 Android 的依赖注入框架。相比于 Dagger2,Hilt 最明显的特征就…...
exec()在不同namespace执行结果的区别
记录一个很tricky的问题,下面这段code在执行func1时会出现NameError: name List is not defined,但执行func2时一切正常。 import typescontent """ from typing import Listclass GeneratedData:qna: List"""def func1…...
人工智能革命中的22个隐藏职业:推动科技行业的变革
作者 | Manas Sadangi 随着人工智能技术的不断发展,它正在创造一系列前所未有的就业机会。虽然数据科学家、机器学习工程师和人工智能研究人员等传统的人工智能角色得到了广泛认可,但在推动科技行业变革方面,还有一些鲜为人知的职业同样重要。…...
算法题3 — 求字符串中的最长子串
文章目录 题目示例示例1示例2示例3 解题解法1解法2 leetcode 题目 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例1 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例…...
【FreeRTOS】——中断优先级设置中断相关寄存器临界段代码保护调度器挂起与恢复
目录 前言: 一、中断优先级设置 二、中断相关寄存器(STM32-Cortex M3) 三、临界段代码保护 四、任务调度器的挂起和恢复 总结: 前言: 博客笔记根据正点原子视频教程编辑,仅供学习交流使用࿰…...
1.2 什么是eBPF?(下)
四,eBPF的优势 4.1 eBPF程序的动态加载 eBPF程序可以动态地加载到内核中,或从内核中删除。这个要与内核模块的加载与卸载区分开来。这里顺便讨论下eBPF程序与内核模块的区别,如下: 而Linux内核模块是面向内核API编程的,可以直接运行在内核当中。eBPF程序是面向BPF体系结构…...
掌握哪些测试技术才能说自己已经学成了?
一、过硬的基础能力 其实所有的测试大佬都是从底层基础开始的,随着时间,经验的积累慢慢变成大佬。要想稳扎稳打在测试行业深耕,成为测试大牛,首当其冲的肯定就是拥有过硬的基础,所有的基础都是根基,后期所…...
什么是C语言?
C语言是一种高级编程语言,于1972年由Dennis Ritchie在贝尔实验室开发出来。它是一种通用的、结构化的编程语言,被广泛用于系统软件、嵌入式系统、游戏开发以及科学计算等领域。 C语言的设计目标是提供一种简洁、高效、可移植的编程语言,以便…...
SAP-物料主数据-质量管理视图字段解析
过账到质检库存:要勾选,否则收货后库存不进入质检库存HU检验:收货到启用HU管理的库位时产生检验批,例如某个成品物料是收货到C002库位,该库位启用了HU管理,那么此处要勾选。但是如果勾选了,却收…...
TOP RPA·脱普×实在丨日用品企业脱普签约实在智能,构建全域数据智能运营系统
近日,实在智能与脱普日用化学品(中国)有限公司(简称“脱普企业”)在脱普企业上海总部举行“全域数据智能运营”项目启动会,双方领导及项目组关键成员共同参会,就项目目标、实施进程、沟通机制等…...
【Android】Handler(四)Looper的相关知识点
Handler 机制是 Android 多线程间通信的一种常见方式。每个 Handler 对象由一个 Looper 和一个 MessageQueue 组成,用于将 Message 对象处理到指定的线程中。通过创建 Handler 实例,在子线程中创建 Message 对象并通过sendMessage()方法发送给 Handler&a…...
Redis缓存雪崩及解决办法
缓存雪崩 1.缓存雪崩是指在同- -时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到 达数据库,带来巨大压力。 2.解决方案: ◆给不同的Key的TTL添加随机值 ◆利用Redis集群提高服务的可用性 ◆给缓存业务添加降级限流策略 降级可做为系统的保底…...
Maven私服仓库配置-Nexus详解
目录 一、什么是Maven私服?二、Maven 私服优势三、Maven 私服搭建四、Sonatype Nexus介绍五、Nexus仓库属性和分类六、Nexus仓库配置以及创建仓库七、Nexus配置用户角色八、Maven SNAPSHOT(快照)九、项目当中配置Nexus上传依赖十、项目当中配置Nexus下载依赖十一、测…...
Systrace系列10 —— Binder 和锁竞争解读
本文主要是对 Systrace 中的 Binder 和锁信息进行简单介绍,简单介绍了 Binder 的情况,介绍了 Systrace 中 Binder 通信的表现形式,以及 Binder 信息查看,SystemServer 锁竞争分析等。 Binder 概述 Android 的大部分进程间通信都使用 Binder,这里对 Binder 不做过多的解释…...
React Hooks中使用useState异步回调获取不到最新值的问题
ReactHook中useState异步回调获取不到最新值及解决⽅案 预先了解 setState 的两种传参⽅式 1、直接传⼊新值 setState(options); 列如: const [state, setState] useState(0); setState(state 1); 2、传⼊回调函数 setState(callBack); 例如: …...
JavaScript 高级 (完结)
目录 深浅拷贝 浅拷贝 深拷贝 递归实现深拷贝 js库lodash里面cloneDeep内部实现了深拷贝 JSON序列化 异常处理 throw 抛异常 try /catch 捕获异常 debugg 处理this this指向 普通函数 箭头函数 改变this call() apply() bind() call apply bind 总结 性能优化…...
【P30】JMeter 事务控制器(Transaction Controller)
文章目录 一、事务控制器(Transaction Controller)参数说明二、测试计划设计2.2.1、勾选 Generate parent sample2.2.1、勾选 Include duration of timer and pre-post processors in generated sample 一、事务控制器(Transaction Controlle…...
【MySQL】MySQL的事务原理和实现?
文章目录 MySQL事务的底层实现原理一、事务的目的可靠性和并发处理 二、实现事务功能的三个技术2.1 redo log 与 undo log介绍2.1.1 redo log2.1.2undo log 2.2 mysql锁技术2.2.1 mysql锁技术 2.3 MVCC基础 三、事务的实现3.1 原子性的实现3.1.1 undo log 的生成3.1.2 根据undo…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
