mirror of
https://github.com/chaos-zhu/easynode.git
synced 2026-10-07 17:08:29 +08:00
✨ 新增AI问答组件及优化若干项
This commit is contained in:
+14
-7
@@ -1,13 +1,20 @@
|
||||
## [3.0.5](https://github.com/chaos-zhu/easynode/releases) (2025-04-xx)
|
||||
## TODO
|
||||
|
||||
* 新增AI问答&集成脚本生成功能(TODO
|
||||
* 新增服务器定时任务功能(TODO
|
||||
* 连接服务器下拉菜单分组展示(TODO
|
||||
* serv00 SFTP修复(TODO
|
||||
* 新增MCP server功能
|
||||
* AI问答集成终端、脚本一键执行等便捷功能
|
||||
* serv00 SFTP修复
|
||||
* 连接服务器下拉菜单分组展示
|
||||
* 新增终端链接跳转需按住ctrl键(防止误触)
|
||||
* 新增服务器定时任务功能
|
||||
|
||||
## [3.0.5](https://github.com/chaos-zhu/easynode/releases) (2025-04-04)
|
||||
|
||||
* 新增AI问答组件及相关配置项,支持deepseekR1、qwq思维链
|
||||
* 脚本库菜单自定义展示(可在本地设置中配置)
|
||||
* 字体优化
|
||||
* 支持在面板配置IP白名单
|
||||
* 支持在面板配置全局API-IP白名单
|
||||
* 修复终端工具栏高度塌陷
|
||||
* 修复多页面在内容数量超出视窗时溢出样式问题
|
||||
* 全局字体优化统一
|
||||
|
||||
## [3.0.4](https://github.com/chaos-zhu/easynode/releases) (2025-03-15)
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ docker run -d -p 8082:8082 --restart=always -v /root/easynode/db:/easynode/app/d
|
||||
- `DEBUG`: 启动debug日志 0:关闭 1:开启, 默认关闭
|
||||
- `ALLOWED_IPS`: 可以访问服务的IP白名单, 多个使用逗号分隔, 支持填写部分ip前缀,支持在面板设置。例如: `-e ALLOWED_IPS=127.0.0.1,196.168`
|
||||
|
||||
注意: docker默认不启用ipv6,请自行配置或者使用支持ipv6的跳板机中转.
|
||||
|
||||
## 监控服务安装
|
||||
|
||||
- 监控服务用于实时向服务端&web端推送**系统、公网IP、CPU、内存、硬盘、网卡**等基础信息
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
DEBUG=1
|
||||
|
||||
# 访问IP限制
|
||||
allowedIPs=['127.0.0.1']
|
||||
allowedIPs=127.0.0.1,192.168,255.
|
||||
|
||||
# 激活PLUS功能的授权码
|
||||
PLUS_KEY=
|
||||
|
||||
@@ -19,6 +19,7 @@ module.exports = {
|
||||
onekeyDBPath: path.join(process.cwd(),'app/db/onekey.db'),
|
||||
logDBPath: path.join(process.cwd(),'app/db/log.db'),
|
||||
plusDBPath: path.join(process.cwd(),'app/db/plus.db'),
|
||||
aiConfigDBPath: path.join(process.cwd(),'app/db/ai-config.db'),
|
||||
apiPrefix: '/api/v1',
|
||||
logConfig: {
|
||||
outDir: path.join(process.cwd(),'./app/logs'),
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
const path = require('path')
|
||||
const decryptAndExecuteAsync = require('../utils/decrypt-file')
|
||||
const { AIConfigDB } = require('../utils/db-class')
|
||||
|
||||
const aiConfigDB = new AIConfigDB().getInstance()
|
||||
|
||||
async function getAIConfig({ res }) {
|
||||
try {
|
||||
const config = await aiConfigDB.findOneAsync({})
|
||||
if (!config) {
|
||||
return res.success({ data: {} })
|
||||
}
|
||||
res.success({ data: config })
|
||||
} catch (error) {
|
||||
res.fail({ msg: '获取配置失败' })
|
||||
}
|
||||
}
|
||||
|
||||
async function getAIModels({ res, request }) {
|
||||
let { getAIModels } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
|
||||
if (getAIModels) {
|
||||
await getAIModels({ res, request })
|
||||
} else {
|
||||
return res.fail({ data: false, msg: 'Plus专属功能!' })
|
||||
}
|
||||
}
|
||||
|
||||
async function saveAIConfig({ res, request }) {
|
||||
let { saveAIConfig } = (await decryptAndExecuteAsync(path.join(__dirname, 'plus.js'))) || {}
|
||||
if (saveAIConfig) {
|
||||
await saveAIConfig({ res, request })
|
||||
} else {
|
||||
return res.fail({ data: false, msg: 'Plus专属功能!' })
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getAIConfig,
|
||||
saveAIConfig,
|
||||
getAIModels
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -7,6 +7,7 @@ const { getScriptList, getLocalScriptList, addScript, updateScriptList, removeSc
|
||||
const { getScriptGroupList, addScriptGroup, removeScriptGroup, updateScriptGroup } = require('../controller/script-group')
|
||||
const { getOnekeyRecord, removeOnekeyRecord } = require('../controller/onekey')
|
||||
const { getLog, saveIpWhiteList } = require('../controller/log')
|
||||
const { getAIConfig, saveAIConfig, getAIModels } = require('../controller/chat')
|
||||
|
||||
const ssh = [
|
||||
{
|
||||
@@ -266,4 +267,22 @@ const log = [
|
||||
controller: saveIpWhiteList
|
||||
}
|
||||
]
|
||||
module.exports = [].concat(ssh, host, user, notify, group, scripts, scriptGroup, onekey, log)
|
||||
|
||||
const aiConfig = [
|
||||
{
|
||||
method: 'get',
|
||||
path: '/ai-config',
|
||||
controller: getAIConfig
|
||||
},
|
||||
{
|
||||
method: 'post',
|
||||
path: '/ai-config',
|
||||
controller: saveAIConfig
|
||||
},
|
||||
{
|
||||
method: 'post',
|
||||
path: '/ai-models',
|
||||
controller: getAIModels
|
||||
}
|
||||
]
|
||||
module.exports = [].concat(ssh, host, user, notify, group, scripts, scriptGroup, onekey, log, aiConfig)
|
||||
|
||||
@@ -1 +1 @@
|
||||
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
|
||||
@@ -10,7 +10,8 @@ const {
|
||||
scriptGroupDBPath,
|
||||
onekeyDBPath,
|
||||
logDBPath,
|
||||
plusDBPath
|
||||
plusDBPath,
|
||||
aiConfigDBPath
|
||||
} = require('../config')
|
||||
|
||||
module.exports.KeyDB = class KeyDB {
|
||||
@@ -141,4 +142,15 @@ module.exports.PlusDB = class PlusDB {
|
||||
getInstance() {
|
||||
return PlusDB.instance
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.AIConfigDB = class AIConfigDB {
|
||||
constructor() {
|
||||
if (!AIConfigDB.instance) {
|
||||
AIConfigDB.instance = new Datastore({ filename: aiConfigDBPath, autoload: true })
|
||||
}
|
||||
}
|
||||
getInstance() {
|
||||
return AIConfigDB.instance
|
||||
}
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
U2FsdGVkX19h9PKGSt7KlCThmnjjqplBn5bV/KsYSEXHkRdn8GKHcu6wcjCsayQ/Ebm8ImN4TSA1PuU4ZAiz+ZtN0H7nT9ti8yvhfHE+EyAktgFjUv/NiOXGHhUEKykksuy8CNss1F1hV9dRfjGn15tpJwL/nU/aqgcScoHxMZo5IebjQycAio52IQkS2ikguaj687/8Ib4Ah38HMleo8/wuZYpaDQ3jkBgZAwFU9OqB4c7voO6r3G5cQfu4GZI/0cCNsath8CIQ1JPaqz3C5xrmAOcKBgJgw1GbgPZ2XneRZY92xRINDv7c3DvgH+qvtTg20Cmz77Dk/xEYyEBTWDLzkp6hXjg/ywT6m3WDcIMleg+Ze+pIWTPgKo2xzRgx2LUflm88iAWLHg2p6jCJvqVrqpsT9ciSEbj6duu5T1uqo+r1PzDovzqEv+b+/+KYFrWgB31XCe8ZvAv+OVPqY2DBubrxaikdstJELTFL7gZn3+SBBke18rOzkFCvu8PW2d+DoMWahNcoDpVxwAyaR7GH0UmEr3XXUn9o+g29Jf5u3U9y5hYWDLiJsvOMd2CeUpw1Q0ub8V1yLrSf8I53PxPOdeUF77p3f+zulqzjKqiUbDR7B6s4WGf0JEmN5eYEY2ND+SToOOHygwwwRxh5jgI6vzEUygG73bZ609jer47aMbwGs7mIbE8FF1Q5yjNPC+Z/o8XrMu4zCGbWmMTqJpmizd8oL6ZLKe0rwWRVF/7Yew1wJ0Vk+lLJOIcnBRC2JNIj54Q7V0TSnzEWDsPzaP/vx/x9S4YGC6A6RIYSismgNXz0GZm519UgoO33pSkRtJTVguXgVH9GfT7xgOeP3Y/1hLO/7OGj0zkbzzQoqHo=
|
||||
U2FsdGVkX18X5TRtUbdmc/+svI+ZQG53eCr1n5cNf1qpcB8oPWdgGLP0LUkMxAygavkY8tr/lLH4pgVRXcMXYN7OkS+q6B7O+BXXJtbJpNOa1pGIgGCJ1WHk3eiSMupSXhEfPPfv4eIsaMrGpAPIWsCg1H5u16KpeaP7MykpmbyHEzVrXIbddeiBneXySl5uNOiRk8qw/JQYCZSrt6D+Sp3xlBsiVyLwGkHxlcRWlVoe5VRkIgMtL9q+Dego/nk1r56iqIkNmnP+kmwPY2wMeOT6lPwYbeRlmdD9VRGRAkgrg1waKqvK5qOMYCMCVDubhvQ5ulD5JtGM0SgzlgWhYoias7HC7AM9FLd8+rUZYw1BXZ/J9eZu2H1gzmClEDWMeHcQuEPPddyUuP9q/hsADGsxxPMMvquEtuedzcx3FQN1dDVqDlkPNAW/DWZ9eB717gcS2jmQlCk+OdyAvlZhTyj/4GhThVrEc5FZo63Y9J7oE4p70/1NCWlnRUKAqBibCeiJkFHR7zcdlLKmUCgO1rXz+PjqSwemG+RJ4tGb1GLdztA6APB17xsBgI3hISM2LSDov/snkYKDgIxYkQctoKGF/c6TLeYYd1YKxWJ4cCeYB+Gko/bH2c+AHMbECKgxZGfCZOJaD8ksY0qRIllKAq52rPeb5kbaNikhkUnvqmCMqWdr7mi8JYHqzW7ys0hp5H6/8tyWxVrSh9EP2hXbpCQF3Wk+0zDt5Dflkiriw8xTr1mCOuSYA1C1M4PyKuaG60DUbLl7WqRxFAd87qwWC4A5fSfMlyWcu2JmZ9M6LfHY7BqKSS0nGQ9YEOwCPol00zeczmEs2WiP+5Esf0U/ZxluCHAmNbJI9ln5AR2RZDc=
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "server",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.5",
|
||||
"description": "easynode-server",
|
||||
"bin": "./bin/www",
|
||||
"scripts": {
|
||||
|
||||
+8
-10
@@ -1,16 +1,14 @@
|
||||
[
|
||||
{
|
||||
"version": "v3.0.4",
|
||||
"date": "2025-03-21",
|
||||
"version": "v3.0.5",
|
||||
"date": "2025-04-05",
|
||||
"features": [
|
||||
"新增脚本库分组功能",
|
||||
"终端页新增脚本库布局",
|
||||
"优化多行命令编辑器",
|
||||
"优化终端工具栏布局",
|
||||
"优化多项新增序号自动累加",
|
||||
"修复前端连接断开但未释放服务端ssh连接的bug",
|
||||
"修复终端页面同步会话在自动执行脚本开关为true时自动添加回车的bug",
|
||||
"【升级底层依赖库,提升安全性】"
|
||||
"新增AI问答组件及相关配置项,支持deepseekR1、qwq思维链",
|
||||
"脚本库菜单自定义展示(可在本地设置中配置)",
|
||||
"支持在面板配置全局API-IP白名单",
|
||||
"修复终端工具栏高度塌陷",
|
||||
"修复多页面在内容数量超出视窗时溢出样式问题",
|
||||
"全局字体优化统一"
|
||||
]
|
||||
}
|
||||
]
|
||||
+2
-2
@@ -6,8 +6,8 @@
|
||||
<meta name="viewport"
|
||||
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0">
|
||||
<title>EasyNode</title>
|
||||
<script src="//at.alicdn.com/t/c/font_3309550_x7zmcgwaxf.js"></script>
|
||||
</head>
|
||||
<script src="//at.alicdn.com/t/c/font_3309550_vrpmw9jmjf8.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
+7
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "3.0.4",
|
||||
"version": "3.0.5",
|
||||
"description": "easynode-web",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -29,13 +29,16 @@
|
||||
"@xterm/addon-search": "^0.15.0",
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"ant-design-x-vue": "^1.0.7",
|
||||
"axios": "^1.8.4",
|
||||
"codemirror": "^6.0.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"csv-parse": "^5.6.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"element-plus": "^2.9.7",
|
||||
"highlight.js": "^11.11.1",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"markdown-it": "^14.1.0",
|
||||
"pinia": "^3.0.1",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"vue": "^3.5.13",
|
||||
@@ -47,13 +50,13 @@
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.2",
|
||||
"code-inspector-plugin": "^0.20.7",
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-plugin-vue": "^10.0.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-vue": "^9.27.0",
|
||||
"sass": "^1.86.0",
|
||||
"unplugin-auto-import": "^19.1.2",
|
||||
"unplugin-vue-components": "^28.4.1",
|
||||
"vite": "^6.2.3",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vue-eslint-parser": "^10.1.1"
|
||||
"vue-eslint-parser": "^9.4.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,5 +147,14 @@ export default {
|
||||
},
|
||||
updatePlusKey(data) {
|
||||
return axios({ url: '/plus-conf', method: 'post', data })
|
||||
},
|
||||
getAIConfig() {
|
||||
return axios({ url: '/ai-config', method: 'get' })
|
||||
},
|
||||
saveAIConfig(data) {
|
||||
return axios({ url: '/ai-config', method: 'post', data })
|
||||
},
|
||||
getAIModels(data) {
|
||||
return axios({ url: '/ai-models', method: 'post', data })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
width="600px"
|
||||
title="AI API配置"
|
||||
:top="'15vh'"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:show-close="false"
|
||||
center
|
||||
custom-class="ai_config_container"
|
||||
>
|
||||
<el-form
|
||||
ref="AIconfigFormRef"
|
||||
:model="AIconfigFormData"
|
||||
:rules="rules"
|
||||
label-width="80px"
|
||||
class="config_form"
|
||||
>
|
||||
<el-form-item label="接口地址" prop="apiUrl">
|
||||
<el-autocomplete
|
||||
v-model.trim="AIconfigFormData.apiUrl"
|
||||
:fetch-suggestions="inputApiUrlSuggestion"
|
||||
style="width: 100%;"
|
||||
clearable
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<div class="value">{{ item.value }}</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
</el-form-item>
|
||||
<el-form-item label="API KEY" prop="apiKey">
|
||||
<el-input v-model="AIconfigFormData.apiKey" clearable placeholder="例如: sk-xxx" />
|
||||
</el-form-item>
|
||||
<el-form-item label="模型列表" prop="models">
|
||||
<div class="models_input_wrap">
|
||||
<el-input-tag
|
||||
v-model="AIconfigFormData.models"
|
||||
class="models_input_tag"
|
||||
tag-type="success"
|
||||
tag-effect="plain"
|
||||
clearable
|
||||
/>
|
||||
<el-button type="primary" :loading="fetchingModels" @click="handleFetchModels">获取模型</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-alert title="提示:" type="warning" :closable="false">
|
||||
<div class="ai_config_alert_content">
|
||||
<p>1. 接口地址需填写完整,例如:<span class="ai_config_alert_content_span">https://api.openai.com/v1/chat/completions</span></p>
|
||||
<p>2. 获取模型列表只支持通过<span class="ai_config_alert_content_span">https://{host}/v1/models API</span>获取</p>
|
||||
<p>3. 模型对话在web端进行,因此需供应方支持<span class="ai_config_alert_content_span">cors跨域</span>, 例如阿里通义API<span class="ai_config_alert_content_span">不支持</span></p>
|
||||
<p>4. 多渠道建议使用<a class="ai_config_alert_content_span one_api_link" href="https://github.com/songquanpeng/one-api" target="_blank">one-api</a>等专业AI平台聚合服务</p>
|
||||
</div>
|
||||
</el-alert>
|
||||
<template #footer>
|
||||
<footer>
|
||||
<div class="footer_btns">
|
||||
<el-button type="info" @click="handleClose">关闭</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="handleSave">保存</el-button>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch, getCurrentInstance } from 'vue'
|
||||
|
||||
const { proxy: { $api, $message, $store } } = getCurrentInstance()
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
aiConfig: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:show',])
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const visible = computed({
|
||||
get() {
|
||||
return props.show
|
||||
},
|
||||
set(newVal) {
|
||||
emit('update:show', newVal)
|
||||
}
|
||||
})
|
||||
|
||||
const AIconfigFormRef = ref(null)
|
||||
const fetchingModels = ref(false)
|
||||
|
||||
const AIconfigFormData = ref({
|
||||
apiUrl: '',
|
||||
apiKey: '',
|
||||
models: []
|
||||
})
|
||||
|
||||
watch(props.aiConfig, (newVal) => {
|
||||
if (Object.keys(newVal).length >= 3) {
|
||||
AIconfigFormData.value = { ...newVal }
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
const rules = {
|
||||
apiUrl: [
|
||||
{ required: true, message: '请输入接口地址', trigger: 'change' },
|
||||
{
|
||||
pattern: /^https?:\/\/.+/,
|
||||
message: '请输入以http或https开头的有效URL',
|
||||
trigger: 'change'
|
||||
},
|
||||
],
|
||||
apiKey: [{ required: true, message: '请输入API KEY', trigger: 'change' },],
|
||||
models: [{ required: true, message: '请输入或获取模型列表', trigger: 'change' },]
|
||||
}
|
||||
|
||||
const handleFetchModels = async () => {
|
||||
if (!AIconfigFormData.value.apiUrl || !AIconfigFormData.value.apiKey) {
|
||||
$message.warning('请先填写接口地址和API KEY')
|
||||
return
|
||||
}
|
||||
fetchingModels.value = true
|
||||
try {
|
||||
const { data } = await $api.getAIModels({
|
||||
apiUrl: AIconfigFormData.value.apiUrl,
|
||||
apiKey: AIconfigFormData.value.apiKey
|
||||
})
|
||||
console.log('models: ', data)
|
||||
if (Array.isArray(data)) {
|
||||
AIconfigFormData.value.models = data.map(item => item.id).filter(item => item)
|
||||
$message.success('获取模型列表成功')
|
||||
} else {
|
||||
$message.error(`获取模型列表失败:${ data.msg }`)
|
||||
}
|
||||
} catch (error) {
|
||||
$message.error(`获取模型列表失败:${ error.message }`)
|
||||
} finally {
|
||||
fetchingModels.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!AIconfigFormRef.value) return
|
||||
try {
|
||||
await AIconfigFormRef.value.validate()
|
||||
loading.value = true
|
||||
await $api.saveAIConfig(AIconfigFormData.value)
|
||||
await $store.getAIConfig()
|
||||
$message.success('保存成功')
|
||||
visible.value = false
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
const inputApiUrlSuggestion = (query, cb) => {
|
||||
if (!AIconfigFormData.value.apiUrl) return cb([{ value: 'https://api.openai.com/v1/chat/completions' },])
|
||||
const origin = new URL(AIconfigFormData.value.apiUrl).origin
|
||||
cb([{ value: `${ origin }/v1/chat/completions` },])
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.config_form {
|
||||
padding: 20px;
|
||||
}
|
||||
.models_input_wrap {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
.models_input_tag {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.ai_config_container {
|
||||
}
|
||||
|
||||
.ai_config_alert_content {
|
||||
padding: 0 8px;
|
||||
p {
|
||||
line-height: 28px;
|
||||
}
|
||||
.ai_config_alert_content_span {
|
||||
font-weight: bold;
|
||||
margin: 0 5px;
|
||||
}
|
||||
.one_api_link {
|
||||
color: var(--el-color-warning);
|
||||
text-decoration: underline;
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +1,29 @@
|
||||
<template>
|
||||
<div class="ai_button" @click="handleClick">
|
||||
<img src="@/assets/image/coding32.png" alt="AIHelper" />
|
||||
AI Helper
|
||||
<div>
|
||||
<PlusSupportTip>
|
||||
<div class="ai_button" @click="handleClick">
|
||||
<img src="@/assets/image/coding32.png" alt="AIHelper">
|
||||
AI Chat
|
||||
</div>
|
||||
</PlusSupportTip>
|
||||
<AiChat v-model:visible="visible" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const emit = defineEmits(['click']);
|
||||
import { ref } from 'vue'
|
||||
import AiChat from '@/components/ai-chat/index.vue'
|
||||
import PlusSupportTip from '@/components/common/PlusSupportTip.vue'
|
||||
|
||||
const visible = ref(false)
|
||||
// const emit = defineEmits(['click']);
|
||||
const handleClick = () => {
|
||||
emit('click');
|
||||
};
|
||||
// emit('click');
|
||||
visible.value = true
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.ai_button {
|
||||
cursor: pointer;
|
||||
min-width: 100px;
|
||||
@@ -36,7 +47,6 @@ const handleClick = () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ai_button:hover {
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
v-model="visible"
|
||||
size="100%"
|
||||
:modal="false"
|
||||
:with-header="true"
|
||||
:lock-scroll="false"
|
||||
:close-on-press-escape="false"
|
||||
modal-class="ai_chat_drawer"
|
||||
class="ai_chat_drawer"
|
||||
>
|
||||
<template #header>
|
||||
<div class="ai_header_wrap">
|
||||
<span class="title">AI Chat</span>
|
||||
<el-dropdown v-if="hasMoreModels" trigger="click" class="model_dropdown">
|
||||
<span class="model_dropdown_link">
|
||||
{{ activeModel }}
|
||||
<el-icon class="el-icon--right">
|
||||
<ArrowDown />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu class="model_dropdown_menu">
|
||||
<el-dropdown-item
|
||||
v-for="model in models"
|
||||
:key="model"
|
||||
:class="{ 'active': activeModel === model }"
|
||||
@click="handleModelChange(model)"
|
||||
>
|
||||
{{ model }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-icon :size="20" class="setting_icon" @click="handleSetting"><Setting /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<div class="chat_box">
|
||||
<div
|
||||
ref="chatListBox"
|
||||
class="chat_list_box"
|
||||
@scroll="handleScroll"
|
||||
>
|
||||
<div v-for="(item, index) in chatList" :key="item.id" class="chat_list_item">
|
||||
<Bubble
|
||||
:loading="isConnecting && index === chatList.length - 1"
|
||||
:placement="item.role === 'assistant' ? 'start' : 'end'"
|
||||
:content="item.content"
|
||||
:message-render="renderMarkdown"
|
||||
>
|
||||
<template #avatar>
|
||||
<svg-icon v-if="item.role === 'assistant'" name="icon-AI-money" style="width: 25px; height: 25px;color: var(--el-menu-active-color);" />
|
||||
<el-icon v-else :size="20" style="color: #887dfd;"><Avatar /></el-icon>
|
||||
</template>
|
||||
<template #header>
|
||||
<div v-show="item.reasoning" class="reasoning_box">
|
||||
<el-collapse :model-value="(isReasoning && item.isStreaming) ? [item.id] : []">
|
||||
<el-collapse-item :name="item.id">
|
||||
<template #title>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between;">
|
||||
<span style="color: #887dfd;">
|
||||
{{ (isReasoning && item.isStreaming) ? '思考中' : '已深度思考' }}
|
||||
{{ item.reasoningTime ? `(用时:${(item.reasoningTime / 1000).toFixed(1)}s)` : '' }}
|
||||
</span>
|
||||
<el-icon class="header-icon" style="color: #887dfd;margin-left: 10px;">
|
||||
<CircleCheck v-if="!isReasoning" style="color: #887dfd;" />
|
||||
<Loading v-else style="color: #887dfd;" />
|
||||
</el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<div v-html="md.render(item.reasoning || '')" />
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="index !== 0" #footer>
|
||||
<div class="action_btn" :style="item.role === 'assistant' ? 'left: 45px;' : 'right: 45px;'">
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Refresh"
|
||||
circle
|
||||
@click="regenerateMessage(item.id, activeModel)"
|
||||
/>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="CopyDocument"
|
||||
circle
|
||||
@click="copyContent(item.content)"
|
||||
/>
|
||||
<el-button
|
||||
size="small"
|
||||
:icon="Delete"
|
||||
circle
|
||||
@click="deleteMessage(item.id)"
|
||||
/>
|
||||
<el-button
|
||||
v-show="item.role === 'user'"
|
||||
size="small"
|
||||
:icon="EditPen"
|
||||
circle
|
||||
@click="editMessage(item.content)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Bubble>
|
||||
</div>
|
||||
<el-divider v-show="chatList.length > 1" content-position="center" class="clear_history_divider">
|
||||
<svg-icon name="icon-saoba" style="width: 16px; height: 16px;" />
|
||||
<el-popconfirm title="确定清空?" @confirm="clearChat">
|
||||
<template #reference>
|
||||
<span class="clear_history">清空历史记录</span>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</el-divider>
|
||||
</div>
|
||||
<div class="sender_box">
|
||||
<Sender
|
||||
v-model:value="question"
|
||||
:loading="loading"
|
||||
@submit="submit"
|
||||
@cancel="stopGeneration"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<AiApiConfig v-model:show="aiApiConfigVisible" :ai-config="aiConfig" />
|
||||
</el-drawer>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, computed, h, nextTick, watch, getCurrentInstance } from 'vue'
|
||||
import { Bubble, Sender } from 'ant-design-x-vue'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import { Avatar, Refresh, CopyDocument, Delete, EditPen, CircleCheck, Loading, Setting, ArrowDown } from '@element-plus/icons-vue'
|
||||
import { useAIChat } from '@/composables/useAIChat'
|
||||
import hljs from 'highlight.js'
|
||||
import 'highlight.js/styles/github-dark.css'
|
||||
import AiApiConfig from './ai-api-config.vue'
|
||||
import { loadMarkdownCSS } from '@/utils/markdown'
|
||||
|
||||
const md = new MarkdownIt({
|
||||
html: false,
|
||||
linkify: true,
|
||||
breaks: true,
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(str, { language: lang }).value
|
||||
} catch (__) {console.warn(__)}
|
||||
}
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
const { proxy: { $message, $store } } = getCurrentInstance()
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:visible',])
|
||||
|
||||
const {
|
||||
chatList,
|
||||
loading,
|
||||
isConnecting,
|
||||
isReasoning,
|
||||
// error,
|
||||
sendMessage,
|
||||
clearChat,
|
||||
stopGeneration,
|
||||
deleteMessage,
|
||||
regenerateMessage
|
||||
} = useAIChat()
|
||||
|
||||
const aiApiConfigVisible = ref(false)
|
||||
const activeModel = ref(localStorage.getItem('activeModel') || '')
|
||||
const question = ref('') // debian设置swap为2gb的步骤
|
||||
const isDark = computed(() => $store.isDark)
|
||||
const aiConfig = computed(() => $store.aiConfig)
|
||||
const models = computed(() => aiConfig.value?.models || [])
|
||||
const hasMoreModels = computed(() => Array.isArray(models.value) && models.value.length > 1)
|
||||
const isPlusActive = computed(() => $store.isPlusActive)
|
||||
const visible = computed({
|
||||
get() {
|
||||
return props.visible
|
||||
},
|
||||
set(value) {
|
||||
emit('update:visible', value)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => models.value, (newValue) => {
|
||||
if (!newValue?.length) return
|
||||
if (!activeModel.value || !newValue.includes(activeModel.value)) {
|
||||
activeModel.value = newValue[0]
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => isDark.value, (newValue) => {
|
||||
loadMarkdownCSS(newValue)
|
||||
}, { immediate: true })
|
||||
|
||||
watch(() => chatList.value, () => {
|
||||
scrollToBottom()
|
||||
}, { deep: true })
|
||||
|
||||
watch(() => visible.value, (newValue) => {
|
||||
if (!newValue) return
|
||||
nextTick(() => {
|
||||
let input = document.querySelector('.ant-sender-input')
|
||||
setTimeout(() => {
|
||||
input.focus()
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
const handleModelChange = (model) => {
|
||||
activeModel.value = model
|
||||
localStorage.setItem('activeModel', model)
|
||||
}
|
||||
|
||||
const renderMarkdown = (content) => {
|
||||
return h('div', { class: 'markdown-body', innerHTML: md.render(content) })
|
||||
}
|
||||
|
||||
const chatListBox = ref(null)
|
||||
const shouldAutoScroll = ref(true)
|
||||
|
||||
const handleScroll = () => {
|
||||
if (!chatListBox.value) return
|
||||
const element = chatListBox.value
|
||||
const isAtBottom = Math.abs(element.scrollHeight - element.scrollTop - element.clientHeight) < 10
|
||||
shouldAutoScroll.value = isAtBottom
|
||||
}
|
||||
|
||||
const scrollToBottom = () => {
|
||||
if (!shouldAutoScroll.value || !chatListBox.value) return
|
||||
nextTick(() => {
|
||||
chatListBox.value.scrollTop = chatListBox.value.scrollHeight
|
||||
})
|
||||
}
|
||||
|
||||
const editMessage = (content) => {
|
||||
question.value = content
|
||||
}
|
||||
|
||||
const submit = async function (questionStr) {
|
||||
if (!questionStr || loading.value) return
|
||||
question.value = ''
|
||||
shouldAutoScroll.value = true
|
||||
await sendMessage(questionStr, activeModel.value)
|
||||
}
|
||||
|
||||
const copyContent = async (content) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(content)
|
||||
$message.success('复制成功')
|
||||
} catch (err) {
|
||||
$message.error('复制失败')
|
||||
}
|
||||
}
|
||||
|
||||
const handleSetting = () => {
|
||||
if (!isPlusActive.value) {
|
||||
$message.warning('请先激活Plus')
|
||||
return
|
||||
}
|
||||
aiApiConfigVisible.value = true
|
||||
}
|
||||
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
// ::-webkit-scrollbar-thumb {
|
||||
// background-color: var(--td-scrollbar-color);
|
||||
// }
|
||||
|
||||
// ::-webkit-scrollbar-thumb:horizontal:hover {
|
||||
// background-color: var(--td-scrollbar-hover-color);
|
||||
// }
|
||||
|
||||
// ::-webkit-scrollbar-track {
|
||||
// background-color: var(--td-scroll-track-color);
|
||||
// }
|
||||
|
||||
.ai_header_wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
.title {
|
||||
margin-left: 16px;
|
||||
font-size: 20px;
|
||||
color: var(--td-text-color-primary);
|
||||
font-weight: 600;
|
||||
line-height: 28px;
|
||||
}
|
||||
.setting_icon {
|
||||
cursor: pointer;
|
||||
color: var(--td-text-color-primary);
|
||||
&:hover {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
.model_dropdown {
|
||||
cursor: pointer;
|
||||
}
|
||||
.model_dropdown_link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.ai_chat_drawer {
|
||||
inset: unset !important;
|
||||
right: 0 !important;
|
||||
top: 0 !important;
|
||||
bottom: 0 !important;
|
||||
width: 30%;
|
||||
min-width: 350px;
|
||||
background-color: v-bind('isDark ? "#0d1117" : "#fff"');
|
||||
.el-drawer__header {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid v-bind('isDark ? "rgba(255, 255, 255, 0.06)" : "rgba(0, 0, 0, 0.06)"');
|
||||
}
|
||||
|
||||
.el-drawer__body {
|
||||
padding: 10px;
|
||||
|
||||
.chat_box {
|
||||
height: 100%;
|
||||
min-height: 300px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.ant-bubble-header {
|
||||
width: 100%;
|
||||
}
|
||||
.ant-bubble-content.ant-bubble-content-filled {
|
||||
background-color: transparent!important;
|
||||
border: 1px solid v-bind('isDark ? "rgba(255, 255, 255, 0.06)" : "rgba(0, 0, 0, 0.06)"');
|
||||
}
|
||||
.ant-sender {
|
||||
border-color: v-bind('isDark ? "#454242" : "#d9d9d9"');
|
||||
&:focus-within {
|
||||
border-color: #1677ff;
|
||||
}
|
||||
.ant-sender-input {
|
||||
color: v-bind('isDark ? "#bbb" : "#000"');
|
||||
}
|
||||
.ant-sender-content {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.chat_list_box {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.chat_list_item {
|
||||
position: relative;
|
||||
padding-bottom: 15px;
|
||||
.reasoning_box {
|
||||
border: 1px solid v-bind('isDark ? "rgba(255, 255, 255, 0.06)" : "rgba(0, 0, 0, 0.06)"');
|
||||
background-color: v-bind('isDark ? "inherit" : "#f0f2f5"');
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
.el-collapse {
|
||||
padding: 0 10px;
|
||||
.el-collapse-item__header {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
.el-collapse-item__header {
|
||||
background-color: transparent;
|
||||
height: 36px;
|
||||
}
|
||||
.el-collapse-item__wrap {
|
||||
background-color: transparent;
|
||||
.el-collapse-item__content {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.action_btn {
|
||||
position: absolute;
|
||||
bottom: 1px;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
&:hover .action_btn {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.clear_history_divider {
|
||||
margin-top: auto;
|
||||
.clear_history {
|
||||
margin-left: 5px;
|
||||
text-align: center;
|
||||
color: #887dfd;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sender_box {
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.model_dropdown_menu {
|
||||
max-height: 70vh;
|
||||
max-width: 375px;
|
||||
overflow: auto;
|
||||
.active {
|
||||
background-color: var(--el-dropdown-menuItem-hover-fill);
|
||||
color: var(--el-dropdown-menuItem-hover-color);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -9,20 +9,20 @@
|
||||
<MenuList />
|
||||
|
||||
<div class="aside_footer">
|
||||
<div class="theme_switch">
|
||||
<el-switch
|
||||
<div class="theme_switch">
|
||||
<el-switch
|
||||
v-model="isDark"
|
||||
inline-prompt
|
||||
:active-icon="Moon"
|
||||
:inactive-icon="Sunny"
|
||||
class="dark_switch"
|
||||
/>
|
||||
</div>
|
||||
<div class="collapse" @click="handleCollapse">
|
||||
<el-icon v-if="menuCollapse"><Expand /></el-icon>
|
||||
<el-icon v-else><Fold /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse" @click="handleCollapse">
|
||||
<el-icon v-if="menuCollapse"><Expand /></el-icon>
|
||||
<el-icon v-else><Fold /></el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -48,6 +48,7 @@ const handleCollapse = () => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.aside_container {
|
||||
overflow-x: auto;
|
||||
background-color: #fff;
|
||||
// width: 180px;
|
||||
display: flex;
|
||||
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
computed: {
|
||||
extensions() {
|
||||
let res = []
|
||||
if(this.curLang) res.push(languages[this.curLang]())
|
||||
if (this.curLang) res.push(languages[this.curLang]())
|
||||
res.push(oneDark)
|
||||
return res
|
||||
},
|
||||
@@ -113,7 +113,7 @@ export default {
|
||||
try {
|
||||
let name = String(newVal).toLowerCase()
|
||||
let suffix = getSuffix(name)
|
||||
switch(suffix) {
|
||||
switch (suffix) {
|
||||
case 'js': return this.curLang = 'javascript'
|
||||
case 'ts': return this.curLang = 'typescript'
|
||||
case 'jsx': return this.curLang = 'jsx'
|
||||
@@ -153,8 +153,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
handleSave() {
|
||||
if(this.isTips) {
|
||||
this.$messageBox.confirm( '文件已变更, 确认保存?', 'Warning', {
|
||||
if (this.isTips) {
|
||||
this.$messageBox.confirm('文件已变更, 确认保存?', 'Warning', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
@@ -172,8 +172,8 @@ export default {
|
||||
this.$emit('closed')
|
||||
},
|
||||
handleClose() {
|
||||
if(this.isTips) {
|
||||
this.$messageBox.confirm( '文件已变更, 确认丢弃?', 'Warning', {
|
||||
if (this.isTips) {
|
||||
this.$messageBox.confirm('文件已变更, 确认丢弃?', 'Warning', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
|
||||
@@ -93,7 +93,7 @@ const basicFeatures = [
|
||||
|
||||
// Plus版专属功能列表
|
||||
const plusFeatures = [
|
||||
'包含基础版全部功能',
|
||||
'AI Chat对话组件',
|
||||
'服务器跳板机功能,支持任意数量服务器的连续跳板',
|
||||
'批量修改实例配置(优化版)',
|
||||
'脚本库批量导出导入',
|
||||
@@ -102,6 +102,7 @@ const plusFeatures = [
|
||||
'通知方式无限制',
|
||||
'本地socket断开自动重连',
|
||||
'功能需求更高开发优先级',
|
||||
'后续功能优先享用',
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<h2>{{ title }}</h2>
|
||||
|
||||
<AiButton @click="handleAiClick" />
|
||||
<AiButton />
|
||||
|
||||
<el-button
|
||||
type="info"
|
||||
@@ -71,7 +71,7 @@
|
||||
<template v-if="features.length > 0 && isNew">
|
||||
<div class="version_features_title">
|
||||
<el-icon><Document /></el-icon>
|
||||
新版本更新了以下内容:
|
||||
最新版本更新了以下内容(<a href="https://github.com/chaos-zhu/easynode/blob/main/CHANGELOG.md" target="_blank">更新日志</a>):
|
||||
</div>
|
||||
<ul class="conspicuous feature_list">
|
||||
<li v-for="feature in features" :key="feature">
|
||||
@@ -116,7 +116,7 @@ import { useRouter } from 'vue-router'
|
||||
import { User, Fold, Document } from '@element-plus/icons-vue'
|
||||
import packageJson from '../../package.json'
|
||||
import MenuList from './menuList.vue'
|
||||
import AiButton from './common/ai-button.vue'
|
||||
import AiButton from './ai-chat/ai-button.vue'
|
||||
|
||||
const { proxy: { $router, $store, $api, $message } } = getCurrentInstance()
|
||||
const router = useRouter()
|
||||
@@ -236,10 +236,6 @@ const getPlusDiscount = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleAiClick = () => {
|
||||
$message({ type: 'success', message: 'AI Helper 功能开发中...', center: true })
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkFirstVisit()
|
||||
getPlusDiscount()
|
||||
@@ -338,7 +334,7 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.conspicuous {
|
||||
color: #F56C6C;
|
||||
color: #67c23a;
|
||||
font-weight: 500;
|
||||
}
|
||||
.feature_list {
|
||||
@@ -358,7 +354,7 @@ onBeforeUnmount(() => {
|
||||
transform: translateY(-50%);
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: #F56C6C;
|
||||
background: #67c23a;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
@@ -376,7 +372,7 @@ onBeforeUnmount(() => {
|
||||
.version_features_title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #F56C6C;
|
||||
color: #67c23a;
|
||||
font-weight: 500;
|
||||
margin: 15px 0 10px;
|
||||
padding-bottom: 10px;
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
import { ref, onUnmounted, computed, watch } from 'vue'
|
||||
import { AIChatService } from '@/utils/aiChatService'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import useStore from '@/store'
|
||||
|
||||
export function useAIChat() {
|
||||
const store = useStore()
|
||||
const aiService = ref(null)
|
||||
|
||||
// 从store获取配置
|
||||
const aiConfig = computed(() => store.aiConfig)
|
||||
|
||||
// 修改watch的判断逻辑
|
||||
watch(() => aiConfig.value, (newConfig) => {
|
||||
// 使用可选链操作符,确保即使是Proxy对象也能正确访问属性
|
||||
if (newConfig && typeof newConfig === 'object') {
|
||||
const { apiUrl, apiKey } = newConfig
|
||||
if (apiUrl && apiKey) {
|
||||
aiService.value = new AIChatService(apiUrl, apiKey)
|
||||
console.log('aiService created:', apiUrl)
|
||||
}
|
||||
}
|
||||
}, { immediate: true, deep: true }) // 添加deep: true以确保深层监听
|
||||
|
||||
const loadSavedChat = () => {
|
||||
const savedChat = localStorage.getItem('aiChatHistory')
|
||||
return savedChat ? JSON.parse(savedChat) : [{
|
||||
id: 1,
|
||||
content: '您好,我是小助手,有什么可以帮您的吗?',
|
||||
role: 'assistant',
|
||||
timestamp: new Date(),
|
||||
isStreaming: false,
|
||||
error: false
|
||||
},]
|
||||
}
|
||||
|
||||
const chatList = ref(loadSavedChat())
|
||||
const isConnecting = ref(false)
|
||||
const loading = ref(false)
|
||||
const error = ref(null)
|
||||
const isReasoning = ref(false)
|
||||
|
||||
const saveChat = () => {
|
||||
localStorage.setItem('aiChatHistory', JSON.stringify(chatList.value))
|
||||
}
|
||||
|
||||
const sendMessage = async (messageContent, model, options = {}) => {
|
||||
if (!aiService.value) {
|
||||
error.value = '请先配置API参数'
|
||||
ElMessage.error(error.value)
|
||||
return
|
||||
}
|
||||
|
||||
error.value = null
|
||||
loading.value = true
|
||||
isConnecting.value = true
|
||||
isReasoning.value = false
|
||||
|
||||
const userMessage = {
|
||||
id: Date.now(),
|
||||
content: messageContent,
|
||||
role: 'user',
|
||||
timestamp: new Date()
|
||||
}
|
||||
chatList.value.push(userMessage)
|
||||
|
||||
const aiMessageId = Date.now() + 1
|
||||
const aiMessage = {
|
||||
id: aiMessageId,
|
||||
content: '',
|
||||
reasoning: '',
|
||||
reasoningTime: 0,
|
||||
role: 'assistant',
|
||||
timestamp: new Date(),
|
||||
isStreaming: true
|
||||
}
|
||||
chatList.value.push(aiMessage)
|
||||
|
||||
const apiMessages = chatList.value
|
||||
.slice(1) // 排除第一条消息
|
||||
.slice(0, -1) // 排除最后一条空的AI消息
|
||||
.filter(msg => msg.role === 'user' || msg.role === 'assistant')
|
||||
.map(msg => ({
|
||||
role: msg.role,
|
||||
content: msg.content
|
||||
}))
|
||||
|
||||
try {
|
||||
await aiService.value.startChat(
|
||||
apiMessages,
|
||||
model,
|
||||
options,
|
||||
{
|
||||
onOpen: () => {
|
||||
isConnecting.value = false
|
||||
},
|
||||
onMessage: (content) => {
|
||||
const aiMessage = chatList.value.find(msg => msg.id === aiMessageId)
|
||||
if (aiMessage) {
|
||||
aiMessage.content += content
|
||||
}
|
||||
},
|
||||
onReasoning: (reasoning) => {
|
||||
isReasoning.value = true
|
||||
const aiMessage = chatList.value.find(msg => msg.id === aiMessageId)
|
||||
if (aiMessage) {
|
||||
aiMessage.reasoning += reasoning
|
||||
}
|
||||
},
|
||||
onReasoningComplete: (reasoningTime) => {
|
||||
isReasoning.value = false
|
||||
const aiMessage = chatList.value.find(msg => msg.id === aiMessageId)
|
||||
if (aiMessage) {
|
||||
aiMessage.reasoningTime = reasoningTime
|
||||
}
|
||||
},
|
||||
onError: (err) => {
|
||||
error.value = err?.message || err || '连接到 AI 服务时出错'
|
||||
loading.value = false
|
||||
const aiMessage = chatList.value.find(msg => msg.id === aiMessageId)
|
||||
if (aiMessage) {
|
||||
aiMessage.error = true
|
||||
aiMessage.isStreaming = false
|
||||
aiMessage.content = error.value // 将错误信息设置为消息内容
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
loading.value = false
|
||||
isConnecting.value = false
|
||||
isReasoning.value = false
|
||||
const aiMessage = chatList.value.find(msg => msg.id === aiMessageId)
|
||||
if (aiMessage) {
|
||||
aiMessage.isStreaming = false
|
||||
}
|
||||
saveChat() // 保存对话
|
||||
|
||||
} catch (err) {
|
||||
error.value = err?.message || err || '发送消息时出错'
|
||||
loading.value = false
|
||||
isConnecting.value = false
|
||||
isReasoning.value = false
|
||||
const aiMessage = chatList.value.find(msg => msg.id === aiMessageId)
|
||||
if (aiMessage) {
|
||||
aiMessage.error = true
|
||||
aiMessage.isStreaming = false
|
||||
aiMessage.content = error.value // 将错误信息设置为消息内容
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const clearChat = () => {
|
||||
if (loading.value) return
|
||||
chatList.value.length = 1
|
||||
error.value = null
|
||||
saveChat() // 保存清空后的状态
|
||||
ElMessage.success('清除成功')
|
||||
}
|
||||
|
||||
const stopGeneration = () => {
|
||||
aiService.value?.closeConnection()
|
||||
loading.value = false
|
||||
|
||||
const streamingMessage = chatList.value.find(msg => msg.isStreaming)
|
||||
if (streamingMessage) {
|
||||
streamingMessage.isStreaming = false
|
||||
}
|
||||
}
|
||||
|
||||
const deleteMessage = (messageId) => {
|
||||
if (loading.value) return
|
||||
const index = chatList.value.findIndex(msg => msg.id === messageId)
|
||||
if (index !== -1) {
|
||||
chatList.value.splice(index, Infinity)
|
||||
saveChat() // 保存删除后的状态
|
||||
}
|
||||
}
|
||||
|
||||
const regenerateMessage = async (messageId, model) => {
|
||||
if (loading.value) return
|
||||
const index = chatList.value.findIndex(msg => msg.id === messageId)
|
||||
if (index === -1) return
|
||||
chatList.value.splice(index + 1, Infinity) // 删除当前消息的后续消息
|
||||
const lastMessage = chatList.value[index]
|
||||
const { content, role } = lastMessage
|
||||
if (role === 'user') {
|
||||
chatList.value.pop()
|
||||
await sendMessage(content, model)
|
||||
} else if (role === 'assistant') {
|
||||
chatList.value.pop()
|
||||
const lastUserMessage = chatList.value.pop()
|
||||
await sendMessage(lastUserMessage.content, model)
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
aiService.value?.closeConnection()
|
||||
})
|
||||
|
||||
return {
|
||||
chatList,
|
||||
isConnecting,
|
||||
isReasoning,
|
||||
loading,
|
||||
error,
|
||||
sendMessage,
|
||||
clearChat,
|
||||
stopGeneration,
|
||||
deleteMessage,
|
||||
regenerateMessage
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,8 @@ const useStore = defineStore('global', {
|
||||
...(localStorage.getItem('menuSetting') ? JSON.parse(localStorage.getItem('menuSetting')) : {})
|
||||
},
|
||||
plusInfo: {},
|
||||
isPlusActive: false
|
||||
isPlusActive: false,
|
||||
aiConfig: {}
|
||||
}),
|
||||
actions: {
|
||||
async setJwtToken(token, isSession = true) {
|
||||
@@ -80,6 +81,7 @@ const useStore = defineStore('global', {
|
||||
await this.getScriptList()
|
||||
await this.getScriptGroupList()
|
||||
await this.getPlusInfo()
|
||||
await this.getAIConfig()
|
||||
this.wsClientsStatus()
|
||||
},
|
||||
async getHostList() {
|
||||
@@ -92,6 +94,10 @@ const useStore = defineStore('global', {
|
||||
this.$patch({ hostList: newHostList })
|
||||
this.HostStatusSocket?.emit('refresh_clients_data')
|
||||
},
|
||||
async getAIConfig() {
|
||||
const { data: aiConfig } = await $api.getAIConfig()
|
||||
this.$patch({ aiConfig })
|
||||
},
|
||||
async getGroupList() {
|
||||
const { data: groupList } = await $api.getGroupList()
|
||||
this.$patch({ groupList })
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
export class AIChatService {
|
||||
constructor(baseUrl, apiKey) {
|
||||
this.baseUrl = baseUrl
|
||||
this.apiKey = apiKey
|
||||
this.controller = null
|
||||
this.reasoningStartTime = null // 添加推理开始时间记录
|
||||
this.isThinking = false
|
||||
}
|
||||
|
||||
async startChat(messages, model, options = {}, callbacks) {
|
||||
this.closeConnection()
|
||||
|
||||
this.controller = new AbortController()
|
||||
|
||||
// 默认参数
|
||||
const defaultOptions = {
|
||||
stream: true,
|
||||
temperature: 0.5,
|
||||
top_p: 1,
|
||||
max_tokens: 4000,
|
||||
presence_penalty: 0,
|
||||
frequency_penalty: 0
|
||||
}
|
||||
|
||||
// 合并参数,确保必传参数存在
|
||||
const requestBody = {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
messages,
|
||||
model,
|
||||
stream: true // 强制使用流式传输
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(this.baseUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${ this.apiKey }`
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
signal: this.controller.signal
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
// 获取详细的错误信息
|
||||
let errorMessage = `HTTP error! status: ${ response.status }`
|
||||
try {
|
||||
const errorData = await response.json()
|
||||
errorMessage = errorData.error?.message || errorMessage
|
||||
} catch (e) {
|
||||
// 如果无法解析错误响应,使用默认错误信息
|
||||
}
|
||||
|
||||
if (callbacks.onError) {
|
||||
callbacks.onError(errorMessage)
|
||||
}
|
||||
return // 提前返回,不继续处理
|
||||
}
|
||||
|
||||
if (callbacks.onOpen) {
|
||||
callbacks.onOpen()
|
||||
}
|
||||
|
||||
const reader = response.body.getReader()
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
|
||||
if (done) {
|
||||
break
|
||||
}
|
||||
|
||||
const chunk = decoder.decode(value)
|
||||
const lines = chunk.split('\n').filter(line => line.trim() !== '')
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('data: ')) {
|
||||
const jsonStr = line.slice(6) // 移除 "data: " 前缀
|
||||
if (jsonStr === '[DONE]') {
|
||||
if (callbacks.onComplete) {
|
||||
callbacks.onComplete()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
const data = JSON.parse(jsonStr)
|
||||
if (callbacks.onMessage && data.choices?.[0]?.delta?.content) {
|
||||
const { content } = data.choices[0].delta
|
||||
if (content.includes('</think>')) {
|
||||
// 推理结束
|
||||
this.isThinking = false
|
||||
callbacks.onReasoning(content.replace('</think>', ''))
|
||||
if (this.reasoningStartTime) {
|
||||
const reasoningTime = Date.now() - this.reasoningStartTime
|
||||
if (callbacks.onReasoningComplete) {
|
||||
callbacks.onReasoningComplete(reasoningTime)
|
||||
}
|
||||
this.reasoningStartTime = null // 重置开始时间
|
||||
}
|
||||
} else if (content.includes('<think>') || this.isThinking) {
|
||||
// 记录推理开始时间
|
||||
this.isThinking = true
|
||||
if (!this.reasoningStartTime) {
|
||||
this.reasoningStartTime = Date.now()
|
||||
}
|
||||
callbacks.onReasoning(content.replace('<think>', ''))
|
||||
} else {
|
||||
// 非推理模型对话
|
||||
callbacks.onMessage(content)
|
||||
}
|
||||
}
|
||||
// ====== deepseek r1 推理返回的字段为 reasoning_content
|
||||
if (callbacks.onReasoning && data.choices?.[0]?.delta?.reasoning_content) {
|
||||
// 记录推理开始时间
|
||||
if (!this.reasoningStartTime) {
|
||||
this.reasoningStartTime = Date.now()
|
||||
}
|
||||
console.log(data.choices[0].delta.reasoning_content)
|
||||
callbacks.onReasoning(data.choices[0].delta.reasoning_content)
|
||||
}
|
||||
// 在推理结束时计算耗时[判断reasoning_content是否为null]
|
||||
if (this.reasoningStartTime && data.choices?.[0]?.delta?.reasoning_content === null) {
|
||||
const reasoningTime = Date.now() - this.reasoningStartTime
|
||||
if (callbacks.onReasoningComplete) {
|
||||
callbacks.onReasoningComplete(reasoningTime)
|
||||
}
|
||||
this.reasoningStartTime = null // 重置开始时间
|
||||
}
|
||||
// ======
|
||||
} catch (error) {
|
||||
console.error('解析消息失败:', error)
|
||||
if (callbacks.onError) {
|
||||
callbacks.onError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('连接错误:', error.message)
|
||||
if (error.message === 'BodyStreamBuffer was aborted') {
|
||||
callbacks.onMessage('用户取消请求')
|
||||
this.closeConnection()
|
||||
return
|
||||
}
|
||||
if (callbacks.onError) {
|
||||
callbacks.onError(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closeConnection() {
|
||||
if (this.controller) {
|
||||
this.controller.abort()
|
||||
this.controller = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export const loadMarkdownCSS = (isDark) => {
|
||||
const existingLink = document.getElementById('markdown-css')
|
||||
if (existingLink) existingLink.remove()
|
||||
const link = document.createElement('link')
|
||||
link.id = 'markdown-css'
|
||||
link.rel = 'stylesheet'
|
||||
link.href = isDark
|
||||
? 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.8.1/github-markdown-dark.min.css'
|
||||
: 'https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.8.1/github-markdown.min.css'
|
||||
document.head.appendChild(link)
|
||||
}
|
||||
@@ -50,6 +50,7 @@ onBeforeMount(async () => {
|
||||
overflow: auto;
|
||||
.router_box {
|
||||
height: calc(100% - 60px - 20px);
|
||||
overflow-y: auto;
|
||||
background-color: #fff;
|
||||
border-radius: 6px;
|
||||
margin: 10px;
|
||||
|
||||
@@ -8,14 +8,19 @@
|
||||
IP地址为包含匹配, 如输入: 192.168则匹配IP地址包含192.168的所有IP
|
||||
</div>
|
||||
</template>
|
||||
<el-icon >
|
||||
<el-icon>
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
<el-input-tag v-model="allowedIPs" tag-type="success" tag-effect="plain">
|
||||
</el-input-tag>
|
||||
<el-button style="margin-top: 6px;" type="success" :loading="btnLoading"
|
||||
@click="handleSaveAllowedIPs">保存</el-button>
|
||||
<el-input-tag v-model="allowedIPs" tag-type="success" tag-effect="plain" />
|
||||
<el-button
|
||||
style="margin-top: 6px;"
|
||||
type="success"
|
||||
:loading="btnLoading"
|
||||
@click="handleSaveAllowedIPs"
|
||||
>
|
||||
保存
|
||||
</el-button>
|
||||
</template>
|
||||
</el-alert>
|
||||
<el-table v-loading="loading" :data="loginRecordList">
|
||||
@@ -60,7 +65,7 @@ const handleLookupLoginRecord = () => {
|
||||
|
||||
const handleSaveAllowedIPs = async () => {
|
||||
btnLoading.value = true
|
||||
const ipWhiteList = [...new Set(allowedIPs.value)].filter(item => item)
|
||||
const ipWhiteList = [...new Set(allowedIPs.value),].filter(item => item)
|
||||
try {
|
||||
await $api.saveIpWhiteList({ ipWhiteList })
|
||||
handleLookupLoginRecord()
|
||||
|
||||
@@ -104,6 +104,10 @@ const handleUpdate = () => {
|
||||
try {
|
||||
loading.value = true
|
||||
let { key } = formData
|
||||
if (key.length < 15) {
|
||||
$message({ type: 'warning', center: true, message: '请输入正确的Plus Key' })
|
||||
return
|
||||
}
|
||||
await $api.updatePlusKey({ key })
|
||||
$message({ type: 'success', center: true, message: '激活成功,感谢支持' })
|
||||
localStorage.setItem('plusErrCount', 0)
|
||||
@@ -111,7 +115,7 @@ const handleUpdate = () => {
|
||||
localStorage.setItem('plusErrCount', ++errCount.value)
|
||||
if (errCount.value > 3) {
|
||||
ElMessageBox.confirm(
|
||||
'激活失败,请确认key正确(20位不规则字符串),有疑问请tg联系@chaoszhu。',
|
||||
'激活失败,请确认key正确,有疑问请tg联系作者@chaoszhu',
|
||||
'Warning',
|
||||
{
|
||||
showCancelButton : false,
|
||||
|
||||
@@ -5,6 +5,7 @@ import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
|
||||
import { AntDesignXVueResolver } from 'ant-design-x-vue/resolver'
|
||||
import viteCompression from 'vite-plugin-compression'
|
||||
import { codeInspectorPlugin } from 'code-inspector-plugin'
|
||||
|
||||
@@ -46,11 +47,13 @@ export default defineConfig({
|
||||
AutoImport({
|
||||
resolvers: [
|
||||
ElementPlusResolver(),
|
||||
AntDesignXVueResolver(),
|
||||
]
|
||||
}),
|
||||
Components({
|
||||
resolvers: [
|
||||
ElementPlusResolver(),
|
||||
AntDesignXVueResolver(),
|
||||
]
|
||||
}),
|
||||
viteCompression({
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
"@jridgewell/gen-mapping" "^0.3.5"
|
||||
"@jridgewell/trace-mapping" "^0.3.24"
|
||||
|
||||
"@ant-design/fast-color@^2.0.6":
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@ant-design/fast-color/-/fast-color-2.0.6.tgz#ab4d4455c1542c9017d367c2fa8ca3e4215d0ba2"
|
||||
integrity sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.24.7"
|
||||
|
||||
"@babel/code-frame@^7.26.2":
|
||||
version "7.26.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
|
||||
@@ -244,6 +251,13 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/runtime@^7.24.7":
|
||||
version "7.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762"
|
||||
integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/template@^7.26.9", "@babel/template@^7.27.0":
|
||||
version "7.27.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.0.tgz#b253e5406cc1df1c57dcd18f11760c2dbf40c0b4"
|
||||
@@ -584,6 +598,16 @@
|
||||
resolved "https://registry.yarnpkg.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz#1f635ad5fdd5c85ed936481525570e82b5a8307a"
|
||||
integrity sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==
|
||||
|
||||
"@emotion/hash@^0.9.2":
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b"
|
||||
integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==
|
||||
|
||||
"@emotion/unitless@^0.10.0":
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745"
|
||||
integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==
|
||||
|
||||
"@esbuild/aix-ppc64@0.25.1":
|
||||
version "0.25.1"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz#c33cf6bbee34975626b01b80451cbb72b4c6c91d"
|
||||
@@ -716,37 +740,11 @@
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@eslint-community/regexpp@^4.12.1":
|
||||
version "4.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
|
||||
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
|
||||
|
||||
"@eslint-community/regexpp@^4.6.1":
|
||||
version "4.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae"
|
||||
integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==
|
||||
|
||||
"@eslint/config-array@^0.19.2":
|
||||
version "0.19.2"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa"
|
||||
integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==
|
||||
dependencies:
|
||||
"@eslint/object-schema" "^2.1.6"
|
||||
debug "^4.3.1"
|
||||
minimatch "^3.1.2"
|
||||
|
||||
"@eslint/config-helpers@^0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.2.0.tgz#12dc8d65c31c4b6c3ebf0758db6601eb7692ce59"
|
||||
integrity sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==
|
||||
|
||||
"@eslint/core@^0.12.0":
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e"
|
||||
integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.15"
|
||||
|
||||
"@eslint/eslintrc@^2.1.4":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
|
||||
@@ -762,21 +760,6 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/eslintrc@^3.3.1":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964"
|
||||
integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==
|
||||
dependencies:
|
||||
ajv "^6.12.4"
|
||||
debug "^4.3.2"
|
||||
espree "^10.0.1"
|
||||
globals "^14.0.0"
|
||||
ignore "^5.2.0"
|
||||
import-fresh "^3.2.1"
|
||||
js-yaml "^4.1.0"
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@8.56.0":
|
||||
version "8.56.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b"
|
||||
@@ -787,24 +770,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f"
|
||||
integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
|
||||
|
||||
"@eslint/js@9.23.0":
|
||||
version "9.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.23.0.tgz#c09ded4f3dc63b40b933bcaeb853fceddb64da30"
|
||||
integrity sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==
|
||||
|
||||
"@eslint/object-schema@^2.1.6":
|
||||
version "2.1.6"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f"
|
||||
integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==
|
||||
|
||||
"@eslint/plugin-kit@^0.2.7":
|
||||
version "0.2.7"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz#9901d52c136fb8f375906a73dcc382646c3b6a27"
|
||||
integrity sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==
|
||||
dependencies:
|
||||
"@eslint/core" "^0.12.0"
|
||||
levn "^0.4.1"
|
||||
|
||||
"@floating-ui/core@^1.6.0":
|
||||
version "1.6.4"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.4.tgz#0140cf5091c8dee602bff9da5ab330840ff91df6"
|
||||
@@ -830,19 +795,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-3.0.0.tgz#f11fdf7dda62fe8e336fa7c6642d9041f30356d7"
|
||||
integrity sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==
|
||||
|
||||
"@humanfs/core@^0.19.1":
|
||||
version "0.19.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
|
||||
integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
|
||||
|
||||
"@humanfs/node@^0.16.6":
|
||||
version "0.16.6"
|
||||
resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e"
|
||||
integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
|
||||
dependencies:
|
||||
"@humanfs/core" "^0.19.1"
|
||||
"@humanwhocodes/retry" "^0.3.0"
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.13", "@humanwhocodes/config-array@^0.11.14":
|
||||
version "0.11.14"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
|
||||
@@ -862,16 +814,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
|
||||
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
|
||||
|
||||
"@humanwhocodes/retry@^0.3.0":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
|
||||
integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
|
||||
|
||||
"@humanwhocodes/retry@^0.4.2":
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161"
|
||||
integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==
|
||||
|
||||
"@isaacs/cliui@^8.0.2":
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
|
||||
@@ -1346,11 +1288,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
|
||||
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
|
||||
|
||||
"@types/estree@^1.0.6":
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8"
|
||||
integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==
|
||||
|
||||
"@types/express-serve-static-core@^4.17.33":
|
||||
version "4.19.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6"
|
||||
@@ -1388,11 +1325,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
|
||||
integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
|
||||
|
||||
"@types/json-schema@^7.0.15":
|
||||
version "7.0.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||
|
||||
"@types/keygrip@*":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.6.tgz#1749535181a2a9b02ac04a797550a8787345b740"
|
||||
@@ -1749,6 +1681,18 @@ ansi-styles@^6.1.0:
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
|
||||
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
|
||||
|
||||
ant-design-x-vue@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/ant-design-x-vue/-/ant-design-x-vue-1.0.7.tgz#1487aee17be4413cea9051c4571427c4d8b379e2"
|
||||
integrity sha512-odxMDJ2L+da+yWig/hTQbOD/ciGmsz6oN+WfnaH90FJs1fNEnpUIlvjIxwyUQDZuMX1VCcv8HkMEeRqJpnVADA==
|
||||
dependencies:
|
||||
"@ant-design/fast-color" "^2.0.6"
|
||||
"@emotion/hash" "^0.9.2"
|
||||
"@emotion/unitless" "^0.10.0"
|
||||
classnames "^2.5.1"
|
||||
csstype "^3.1.3"
|
||||
stylis "^4.3.4"
|
||||
|
||||
anymatch@~3.1.2:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
|
||||
@@ -2106,6 +2050,11 @@ chownr@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
|
||||
integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
|
||||
|
||||
classnames@^2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b"
|
||||
integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
|
||||
|
||||
clean-stack@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
|
||||
@@ -2343,7 +2292,7 @@ cross-env@^7.0.3:
|
||||
dependencies:
|
||||
cross-spawn "^7.0.1"
|
||||
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.6:
|
||||
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2:
|
||||
version "7.0.6"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
|
||||
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
|
||||
@@ -2691,7 +2640,7 @@ engine.io@~6.5.2:
|
||||
engine.io-parser "~5.2.1"
|
||||
ws "~8.17.1"
|
||||
|
||||
entities@^4.5.0:
|
||||
entities@^4.4.0, entities@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||
@@ -2866,19 +2815,21 @@ escape-string-regexp@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8"
|
||||
integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==
|
||||
|
||||
eslint-plugin-vue@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-10.0.0.tgz#42707bfb8c4490b0b1a4be6f11a416fb16c3d11c"
|
||||
integrity sha512-XKckedtajqwmaX6u1VnECmZ6xJt+YvlmMzBPZd+/sI3ub2lpYZyFnsyWo7c3nMOQKJQudeyk1lw/JxdgeKT64w==
|
||||
eslint-plugin-vue@^9.27.0:
|
||||
version "9.33.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz#de33eba8f78e1d172c59c8ec7fbfd60c6ca35c39"
|
||||
integrity sha512-174lJKuNsuDIlLpjeXc5E2Tss8P44uIimAfGD0b90k0NoirJqpG7stLuU9Vp/9ioTOrQdWVREc4mRd1BD+CvGw==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
globals "^13.24.0"
|
||||
natural-compare "^1.4.0"
|
||||
nth-check "^2.1.1"
|
||||
postcss-selector-parser "^6.0.15"
|
||||
semver "^7.6.3"
|
||||
vue-eslint-parser "^9.4.3"
|
||||
xml-name-validator "^4.0.0"
|
||||
|
||||
eslint-scope@^7.2.2:
|
||||
eslint-scope@^7.1.1, eslint-scope@^7.2.2:
|
||||
version "7.2.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
|
||||
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
|
||||
@@ -2886,24 +2837,11 @@ eslint-scope@^7.2.2:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-scope@^8.2.0, eslint-scope@^8.3.0:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.3.0.tgz#10cd3a918ffdd722f5f3f7b5b83db9b23c87340d"
|
||||
integrity sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==
|
||||
dependencies:
|
||||
esrecurse "^4.3.0"
|
||||
estraverse "^5.2.0"
|
||||
|
||||
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint-visitor-keys@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
|
||||
integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
|
||||
|
||||
eslint@8.56.0:
|
||||
version "8.56.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15"
|
||||
@@ -2992,57 +2930,7 @@ eslint@^8.56.0:
|
||||
strip-ansi "^6.0.1"
|
||||
text-table "^0.2.0"
|
||||
|
||||
eslint@^9.23.0:
|
||||
version "9.23.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.23.0.tgz#b88f3ab6dc83bcb927fdb54407c69ffe5f2441a6"
|
||||
integrity sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.2.0"
|
||||
"@eslint-community/regexpp" "^4.12.1"
|
||||
"@eslint/config-array" "^0.19.2"
|
||||
"@eslint/config-helpers" "^0.2.0"
|
||||
"@eslint/core" "^0.12.0"
|
||||
"@eslint/eslintrc" "^3.3.1"
|
||||
"@eslint/js" "9.23.0"
|
||||
"@eslint/plugin-kit" "^0.2.7"
|
||||
"@humanfs/node" "^0.16.6"
|
||||
"@humanwhocodes/module-importer" "^1.0.1"
|
||||
"@humanwhocodes/retry" "^0.4.2"
|
||||
"@types/estree" "^1.0.6"
|
||||
"@types/json-schema" "^7.0.15"
|
||||
ajv "^6.12.4"
|
||||
chalk "^4.0.0"
|
||||
cross-spawn "^7.0.6"
|
||||
debug "^4.3.2"
|
||||
escape-string-regexp "^4.0.0"
|
||||
eslint-scope "^8.3.0"
|
||||
eslint-visitor-keys "^4.2.0"
|
||||
espree "^10.3.0"
|
||||
esquery "^1.5.0"
|
||||
esutils "^2.0.2"
|
||||
fast-deep-equal "^3.1.3"
|
||||
file-entry-cache "^8.0.0"
|
||||
find-up "^5.0.0"
|
||||
glob-parent "^6.0.2"
|
||||
ignore "^5.2.0"
|
||||
imurmurhash "^0.1.4"
|
||||
is-glob "^4.0.0"
|
||||
json-stable-stringify-without-jsonify "^1.0.1"
|
||||
lodash.merge "^4.6.2"
|
||||
minimatch "^3.1.2"
|
||||
natural-compare "^1.4.0"
|
||||
optionator "^0.9.3"
|
||||
|
||||
espree@^10.0.1, espree@^10.3.0:
|
||||
version "10.3.0"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
|
||||
integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
|
||||
dependencies:
|
||||
acorn "^8.14.0"
|
||||
acorn-jsx "^5.3.2"
|
||||
eslint-visitor-keys "^4.2.0"
|
||||
|
||||
espree@^9.6.0, espree@^9.6.1:
|
||||
espree@^9.3.1, espree@^9.6.0, espree@^9.6.1:
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
|
||||
integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
|
||||
@@ -3051,7 +2939,7 @@ espree@^9.6.0, espree@^9.6.1:
|
||||
acorn-jsx "^5.3.2"
|
||||
eslint-visitor-keys "^3.4.1"
|
||||
|
||||
esquery@^1.4.2, esquery@^1.5.0, esquery@^1.6.0:
|
||||
esquery@^1.4.0, esquery@^1.4.2:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
|
||||
integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
|
||||
@@ -3162,13 +3050,6 @@ file-entry-cache@^6.0.1:
|
||||
dependencies:
|
||||
flat-cache "^3.0.4"
|
||||
|
||||
file-entry-cache@^8.0.0:
|
||||
version "8.0.0"
|
||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f"
|
||||
integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
|
||||
dependencies:
|
||||
flat-cache "^4.0.0"
|
||||
|
||||
file-type@^3.9.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
|
||||
@@ -3206,14 +3087,6 @@ flat-cache@^3.0.4:
|
||||
keyv "^4.5.3"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
flat-cache@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c"
|
||||
integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
|
||||
dependencies:
|
||||
flatted "^3.2.9"
|
||||
keyv "^4.5.4"
|
||||
|
||||
flatted@^3.2.7, flatted@^3.2.9:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
|
||||
@@ -3468,18 +3341,13 @@ globals@^11.1.0:
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
|
||||
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
|
||||
|
||||
globals@^13.19.0:
|
||||
globals@^13.19.0, globals@^13.24.0:
|
||||
version "13.24.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171"
|
||||
integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
|
||||
dependencies:
|
||||
type-fest "^0.20.2"
|
||||
|
||||
globals@^14.0.0:
|
||||
version "14.0.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
|
||||
integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
|
||||
|
||||
globalthis@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236"
|
||||
@@ -3590,6 +3458,11 @@ hexoid@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
|
||||
integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==
|
||||
|
||||
highlight.js@^11.11.1:
|
||||
version "11.11.1"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.11.1.tgz#fca06fa0e5aeecf6c4d437239135fabc15213585"
|
||||
integrity sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==
|
||||
|
||||
hookable@^5.5.3:
|
||||
version "5.5.3"
|
||||
resolved "https://registry.yarnpkg.com/hookable/-/hookable-5.5.3.tgz#6cfc358984a1ef991e2518cb9ed4a778bbd3215d"
|
||||
@@ -4135,7 +4008,7 @@ keygrip@~1.1.0:
|
||||
dependencies:
|
||||
tsscmp "1.0.6"
|
||||
|
||||
keyv@^4.5.3, keyv@^4.5.4:
|
||||
keyv@^4.5.3:
|
||||
version "4.5.4"
|
||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
|
||||
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
|
||||
@@ -4286,6 +4159,13 @@ lie@3.1.1:
|
||||
dependencies:
|
||||
immediate "~3.0.5"
|
||||
|
||||
linkify-it@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421"
|
||||
integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==
|
||||
dependencies:
|
||||
uc.micro "^2.0.0"
|
||||
|
||||
local-pkg@^1.0.0, local-pkg@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.1.tgz#f5fe74a97a3bd3c165788ee08ca9fbe998dc58dd"
|
||||
@@ -4411,11 +4291,28 @@ magic-string@^0.30.11, magic-string@^0.30.17:
|
||||
dependencies:
|
||||
"@jridgewell/sourcemap-codec" "^1.5.0"
|
||||
|
||||
markdown-it@^14.1.0:
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45"
|
||||
integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==
|
||||
dependencies:
|
||||
argparse "^2.0.1"
|
||||
entities "^4.4.0"
|
||||
linkify-it "^5.0.0"
|
||||
mdurl "^2.0.0"
|
||||
punycode.js "^2.3.1"
|
||||
uc.micro "^2.1.0"
|
||||
|
||||
math-intrinsics@^1.0.0, math-intrinsics@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
||||
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
|
||||
|
||||
mdurl@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0"
|
||||
integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==
|
||||
|
||||
media-typer@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
@@ -5057,6 +4954,11 @@ pump@^3.0.0:
|
||||
end-of-stream "^1.1.0"
|
||||
once "^1.3.1"
|
||||
|
||||
punycode.js@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7"
|
||||
integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==
|
||||
|
||||
punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
|
||||
@@ -5361,7 +5263,7 @@ semver@^7.3.5, semver@^7.5.3, semver@^7.5.4:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
|
||||
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
|
||||
|
||||
semver@^7.6.3:
|
||||
semver@^7.3.6, semver@^7.6.3:
|
||||
version "7.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f"
|
||||
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
|
||||
@@ -5764,6 +5666,11 @@ style-mod@^4.0.0, style-mod@^4.1.0:
|
||||
resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.1.2.tgz#ca238a1ad4786520f7515a8539d5a63691d7bf67"
|
||||
integrity sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==
|
||||
|
||||
stylis@^4.3.4:
|
||||
version "4.3.6"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.6.tgz#7c7b97191cb4f195f03ecab7d52f7902ed378320"
|
||||
integrity sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==
|
||||
|
||||
superjson@^2.2.1:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/superjson/-/superjson-2.2.2.tgz#9d52bf0bf6b5751a3c3472f1292e714782ba3173"
|
||||
@@ -5989,6 +5896,11 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
|
||||
|
||||
uc.micro@^2.0.0, uc.micro@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee"
|
||||
integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==
|
||||
|
||||
ufo@^1.5.4:
|
||||
version "1.5.4"
|
||||
resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754"
|
||||
@@ -6196,18 +6108,18 @@ vue-demi@*:
|
||||
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.8.tgz#00335e9317b45e4a68d3528aaf58e0cec3d5640a"
|
||||
integrity sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==
|
||||
|
||||
vue-eslint-parser@^10.1.1:
|
||||
version "10.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-10.1.1.tgz#0d56d17a8e64cda088c8601dcbfc2ea51548e3d2"
|
||||
integrity sha512-bh2Z/Au5slro9QJ3neFYLanZtb1jH+W2bKqGHXAoYD4vZgNG3KeotL7JpPv5xzY4UXUXJl7TrIsnzECH63kd3Q==
|
||||
vue-eslint-parser@^9.4.3:
|
||||
version "9.4.3"
|
||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-9.4.3.tgz#9b04b22c71401f1e8bca9be7c3e3416a4bde76a8"
|
||||
integrity sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg==
|
||||
dependencies:
|
||||
debug "^4.4.0"
|
||||
eslint-scope "^8.2.0"
|
||||
eslint-visitor-keys "^4.2.0"
|
||||
espree "^10.3.0"
|
||||
esquery "^1.6.0"
|
||||
debug "^4.3.4"
|
||||
eslint-scope "^7.1.1"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
espree "^9.3.1"
|
||||
esquery "^1.4.0"
|
||||
lodash "^4.17.21"
|
||||
semver "^7.6.3"
|
||||
semver "^7.3.6"
|
||||
|
||||
vue-router@^4.5.0:
|
||||
version "4.5.0"
|
||||
|
||||
Reference in New Issue
Block a user