From 2fc209e6e6b3663d2b6770792ea66268af64cab9 Mon Sep 17 00:00:00 2001 From: BBIT-Kai <2911862937@qq.com> Date: Thu, 18 Sep 2025 17:11:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=89=8D=E7=AB=AF=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bbit_ai/app/llm/dataLLM.py | 139 -------- vue/apps/web-antd/package.json | 2 + vue/apps/web-antd/src/api/llm/bot.ts | 10 +- vue/apps/web-antd/src/api/llm/index.ts | 4 + vue/apps/web-antd/src/api/llm/report.ts | 55 ++++ vue/apps/web-antd/src/preferences.ts | 4 +- .../web-antd/src/router/routes/modules/cv.ts | 12 + .../web-antd/src/router/routes/modules/llm.ts | 110 ++++++- .../web-antd/src/router/routes/modules/out.ts | 13 +- .../src/views/dashboard/workspace/index.vue | 310 ++++++------------ vue/apps/web-antd/src/views/llm/bot/index.vue | 69 ++-- .../web-antd/src/views/llm/report/index.vue | 5 - .../src/en/guide/essentials/development.md | 2 - vue/docs/src/en/guide/project/dir.md | 1 - vue/docs/src/guide/essentials/development.md | 2 - vue/docs/src/guide/project/dir.md | 1 - vue/package.json | 1 - .../common-ui/src/ui/dashboard/typing.ts | 1 + .../workbench/workbench-quick-nav.vue | 65 ++-- .../src/request-client/request-client.ts | 2 +- vue/pnpm-lock.yaml | 82 +++++ vue/scripts/deploy/Dockerfile | 35 +- .../deploy/build-local-docker-image.sh | 55 ---- 23 files changed, 462 insertions(+), 518 deletions(-) delete mode 100644 bbit_ai/app/llm/dataLLM.py delete mode 100644 vue/apps/web-antd/src/views/llm/report/index.vue delete mode 100644 vue/scripts/deploy/build-local-docker-image.sh diff --git a/bbit_ai/app/llm/dataLLM.py b/bbit_ai/app/llm/dataLLM.py deleted file mode 100644 index 1370d02..0000000 --- a/bbit_ai/app/llm/dataLLM.py +++ /dev/null @@ -1,139 +0,0 @@ - -from langchain.prompts import PromptTemplate -from config.llm import llm -from config.ssDb import ssDB -from typing import Annotated -from typing_extensions import TypedDict -from langgraph.graph import StateGraph, START, END -from langgraph.graph.message import add_messages -from langchain_community.agent_toolkits import create_sql_agent -from langchain.prompts import PromptTemplate -from config.llm import llm -from config.ssDb import ssDB -from typing import Annotated -from langgraph.graph.message import add_messages -import os -from langchain_tavily import TavilySearch -from langgraph.prebuilt import ToolNode, tools_condition -from llm.chatLLM import get_chat_response -from typing import TypedDict -from langgraph.graph import StateGraph, END -from llm.summarizeLLM import getSummary - - -# -------- 定义状态 -------- -class State(TypedDict): - userInput: str # 用户输入 - source: str # 选择的数据来源:web 或 db 或 chat - infomation: str # 查询到的内容 - aiRole: str # AI 角色 - history: str # 聊天历史 - reply: str # 最终回复 - -# -------- 定义节点 -------- -# ------------------------------------------------------------------------ 路径选择 -------- - -pathSelectPrompt = PromptTemplate( - input_variables=["aiRole", "history", "userStr", "infomation"], - template = """ - 你是主干信息科技有限公司的业务员,是一家蚕桑服务公司,现在需要根据用户输入来判断应该使用哪种方式来回答用户的问题。 - 你有三种选择: - 1. 如果用户的问题涉及最新的信息,比如新闻、事件、天气等涉及时间的内容时,请选择 "web - 2. 如果用户的问题涉及具体的蚕桑业务(例如询问农户、订单、订种、租户)的数据库查询需求,请选择 "db" - 3. 如果用户的问题是一般性的聊天或咨询,请选择 "chat" - 请只返回 "web"、"db" 或 "chat" 之一,且不要添加任何其他解释。 - 用户最新输入: - {userStr} - 请做出你的选择: - """ -) -pathSelectChain = pathSelectPrompt | llm - -def decide_source(state: State, max_retry=3): - print("根据用户输入选择数据来源,用户输入:", state["userInput"]) - """根据用户输入选择数据来源""" - for _ in range(max_retry): - choice = pathSelectChain.invoke({ - "aiRole": state["aiRole"], - "history": state["history"], - "userStr": state["userInput"], - }).content.strip().lower() - if choice in ["web", "db", "chat"]: - state["source"] = choice - break - else: - # 如果连续 max_retry 次都不合法,默认走 chat - state["source"] = "chat" - print("选择的数据来源是:", state["source"]) - return state - - -# ------------------------------------------------------------------------ 上网查询 -------- -os.environ["TAVILY_API_KEY"] = "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" -tool = TavilySearch(max_results=2) - -def fetch_web(state: State): - result = tool.invoke(state["userInput"]) - state["infomation"] = result.get("content") or result - print("调用了联网工具,结果是:", state["infomation"]) - return state - -# ------------------------------------------------------------------------ 数据库查询 -------- -agent = create_sql_agent( - llm=llm, - db=ssDB, - agent_type="tool-calling", - verbose=True -) -def fetch_db(state: State): - state["infomation"] = agent.invoke({"input": state["userInput"]})["output"] - print("调用了数据库工具,结果是:", state["infomation"]) - return state - -# ------------------------------------------------------------------------ 整理结果 -------- -def summarize_ai(state: State): - """AI 总结输出""" - state["reply"] = getSummary(aiRole=state["aiRole"], history=state["history"], userInput= state["userInput"], infomation= state["infomation"]) - return state - -# ------------------------------------------------------------------------ 普通聊天 -------- -def chat(state: State): - state["reply"] = get_chat_response(aiRole=state["aiRole"],history=state["history"], userInput= state["userInput"]).content - print("直接回复") - return state - -# ------------------------------------------------------------------------ 构建有向图 -------- -workflow = StateGraph(State) -workflow.add_node("decide", decide_source) -workflow.add_node("fetch_web", fetch_web) -workflow.add_node("fetch_db", fetch_db) -workflow.add_node("chat", chat) -workflow.add_node("summarize", summarize_ai) -workflow.set_entry_point("decide") - -# 两条路径最后都汇合到 summarize -workflow.add_edge(START, "decide") -workflow.add_edge("fetch_web", "summarize") -workflow.add_edge("fetch_db", "summarize") -# 条件边:根据 source 决定走向 -workflow.add_conditional_edges( - "decide", - lambda state: state["source"], # 返回 state["source"] 的值 - { - "web": "fetch_web", - "chat": "chat", - "db": "fetch_db" - } -) -workflow.add_edge("summarize", END) -workflow.add_edge("chat", END) -graph = workflow.compile() - -# 执行函数 -def get_graph_output(aiRole:str,history: str, userInput: str) -> str: - final_state = graph.invoke({ - "aiRole":aiRole, - "history": history, - "userInput": userInput, - }) - return final_state["reply"] \ No newline at end of file diff --git a/vue/apps/web-antd/package.json b/vue/apps/web-antd/package.json index 4ebeb07..3f46a6f 100644 --- a/vue/apps/web-antd/package.json +++ b/vue/apps/web-antd/package.json @@ -26,6 +26,7 @@ "#/*": "./src/*" }, "dependencies": { + "@handsontable/vue3": "^16.0.1", "@vben/access": "workspace:*", "@vben/common-ui": "workspace:*", "@vben/constants": "workspace:*", @@ -43,6 +44,7 @@ "@vueuse/core": "catalog:", "ant-design-vue": "catalog:", "dayjs": "catalog:", + "handsontable": "^16.0.1", "js-sha256": "^0.11.0", "markdown-it": "^14.1.0", "markdown-it-container": "^4.0.0", diff --git a/vue/apps/web-antd/src/api/llm/bot.ts b/vue/apps/web-antd/src/api/llm/bot.ts index fc36901..7c0ac22 100644 --- a/vue/apps/web-antd/src/api/llm/bot.ts +++ b/vue/apps/web-antd/src/api/llm/bot.ts @@ -2,15 +2,15 @@ import { pyRequestClient } from '#/api/request'; /** * 获取AI列表 */ -export async function getAIList() { - return pyRequestClient.get('/llm/aiList'); +export async function getAIBotList() { + return pyRequestClient.get('/llm/aiListForBot'); } /** * 获取对话列表 */ export async function getSessions() { - return pyRequestClient.get('/llm/sessions'); + return pyRequestClient.get('/llm/sessionsForBot'); } /** @@ -23,12 +23,12 @@ export async function getHistory(sessionId: string) { /** * 聊天 */ -export async function chat( +export async function chatWithBot( aiId: string, sessionId: null | string, userInput: string, ) { - return pyRequestClient.post('/llm/chat', { + return pyRequestClient.post('/llm/chatForBot', { aiId, sessionId, userInput, diff --git a/vue/apps/web-antd/src/api/llm/index.ts b/vue/apps/web-antd/src/api/llm/index.ts index 859d4b8..e1f5f6f 100644 --- a/vue/apps/web-antd/src/api/llm/index.ts +++ b/vue/apps/web-antd/src/api/llm/index.ts @@ -1,2 +1,6 @@ export * from './bot'; export * from './report'; +export * from './report-bot'; +export * from './report-data'; +export * from './service'; +export * from './service-knowledge'; diff --git a/vue/apps/web-antd/src/api/llm/report.ts b/vue/apps/web-antd/src/api/llm/report.ts index e69de29..bca4707 100644 --- a/vue/apps/web-antd/src/api/llm/report.ts +++ b/vue/apps/web-antd/src/api/llm/report.ts @@ -0,0 +1,55 @@ +import { pyRequestClient } from '#/api/request'; +/** + * 获取AI列表 + */ +export async function getAIReportList() { + return pyRequestClient.get('/llm/aiListForReport'); +} + +/** + * 获取报表列表 + */ +export async function getReports() { + return pyRequestClient.get('/llm/reports'); +} + +export async function getReport(reportId: string) { + return pyRequestClient.get('/llm/report', { params: { reportId } }); +} +/** + * 保存 + */ +export async function saveReport(data: { reportId: string }) { + return pyRequestClient.post('/llm/saveReport', data); +} + +/** + * 获取 + */ +export async function getHistory1(sessionId: string) { + return pyRequestClient.get('/llm/history', { params: { sessionId } }); +} + +/** + * 聊天 + */ +export async function chatWithReport( + aiId: string, + companyId: null | string, + reportId: null | string, + userInput: string, +) { + return pyRequestClient.post('/llm/chatWithReport', { + aiId, + companyId, + reportId, + userInput, + }); +} + +/** + * 获取租户列表 + */ +export async function getCompany() { + return pyRequestClient.get('/llm/companyList'); +} diff --git a/vue/apps/web-antd/src/preferences.ts b/vue/apps/web-antd/src/preferences.ts index 7e4c379..ecc1071 100644 --- a/vue/apps/web-antd/src/preferences.ts +++ b/vue/apps/web-antd/src/preferences.ts @@ -9,10 +9,10 @@ export const overridesPreferences = defineOverridesPreferences({ // overrides app: { name: import.meta.env.VITE_APP_TITLE, - layout: 'header-sidebar-nav', // 布局方式 + layout: 'sidebar-mixed-nav', defaultHomePath: '/workspace', // 默认首页路径 enablePreferences: false, // 是否启用偏好设置 - loginExpiredMode: 'modal', // 登录过期模式 弹窗登录 + loginExpiredMode: 'page', // 登录过期模式 不用弹窗登录 跳转到页面登录,防止一些界面不会再加载 }, theme: { mode: 'light', diff --git a/vue/apps/web-antd/src/router/routes/modules/cv.ts b/vue/apps/web-antd/src/router/routes/modules/cv.ts index 5b1cf7b..00d0841 100644 --- a/vue/apps/web-antd/src/router/routes/modules/cv.ts +++ b/vue/apps/web-antd/src/router/routes/modules/cv.ts @@ -2,6 +2,7 @@ import type { RouteRecordRaw } from 'vue-router'; import { $t } from '#/locales'; +const IFrameView = () => import('@vben/layouts').then((m) => m.IFrameView); const routes: RouteRecordRaw[] = [ { meta: { @@ -47,6 +48,17 @@ const routes: RouteRecordRaw[] = [ }, component: () => import('#/views/cv/ysa/index.vue'), }, + { + name: 'CVAT', + path: '/cv/cvat', + component: IFrameView, + meta: { + icon: 'mdi:abjad-arabic', + link: 'http://171.212.101.199:13013/', + keepAlive: true, + title: '标注平台入口', + }, + }, ], }, ]; diff --git a/vue/apps/web-antd/src/router/routes/modules/llm.ts b/vue/apps/web-antd/src/router/routes/modules/llm.ts index 2347ab6..67e6f7a 100644 --- a/vue/apps/web-antd/src/router/routes/modules/llm.ts +++ b/vue/apps/web-antd/src/router/routes/modules/llm.ts @@ -6,7 +6,7 @@ const routes: RouteRecordRaw[] = [ { meta: { icon: 'ic:baseline-view-in-ar', - authority: ['bot', 'report'], + authority: ['bot', 'report', 'service'], keepAlive: false, order: 2, title: $t('大语言模型'), @@ -19,22 +19,116 @@ const routes: RouteRecordRaw[] = [ path: '/llm/bot', meta: { authority: ['bot'], - icon: 'mdi:face-woman-shimmer', - title: $t('智能体对话'), + icon: 'mdi:face-agent', + title: $t('通用智能体'), keepAlive: true, }, component: () => import('#/views/llm/bot/index.vue'), }, + // 嵌套菜单 { - name: 'SDP', - path: '/llm/report', meta: { - authority: ['report'], icon: 'mdi:hoop-house', title: $t('智农观数阁'), - keepAlive: false, + authority: ['report'], }, - component: () => import('#/views/llm/report/index.vue'), + name: 'SDP', + path: '/llm/report', + children: [ + { + name: 'SDP-chat', + path: '/llm/report/report-chat', + meta: { + authority: ['report'], + icon: 'mdi:set-center', + title: $t('报表中心'), + keepAlive: true, + }, + component: () => import('#/views/llm/report/report-chat/index.vue'), + }, + { + name: 'SDP-bot', + path: '/llm/report/report-bot', + meta: { + authority: ['report-bot'], + icon: 'mdi:face-woman-shimmer', + title: $t('智能体'), + keepAlive: true, + }, + component: () => import('#/views/llm/report/report-bot/index.vue'), + }, + { + name: 'SDP-data', + path: '/llm/report/report-data', + meta: { + authority: ['report-data'], + icon: 'ic:round-settings', + title: $t('数据源'), + keepAlive: true, + }, + component: () => import('#/views/llm/report/report-data/index.vue'), + }, + ], + }, + // 嵌套菜单 + { + meta: { + icon: 'mdi:greenhouse', + title: $t('灵思智服阁'), + authority: ['service'], + }, + name: 'CSC', + path: '/llm/service', + children: [ + { + name: 'CSC-chat', + path: '/llm/service/service-chat', + meta: { + authority: ['service'], + icon: 'mdi:android-head', + title: $t('灵思对话'), + keepAlive: true, + }, + component: () => + import('#/views/llm/service/service-chat/index.vue'), + }, + { + name: 'CSC-bot', + path: '/llm/service/service-bot', + meta: { + authority: ['service-bot'], + icon: 'mdi:face-woman', + title: $t('智能体'), + keepAlive: true, + }, + component: () => + import('#/views/llm/service/service-bot/index.vue'), + }, + { + name: 'CSC-knowledge', + path: '/llm/service/service-knowledge', + meta: { + authority: ['service-knowledge'], + icon: 'ic:round-book', + title: $t('知识库'), + keepAlive: true, + }, + component: () => + import('#/views/llm/service/service-knowledge/index.vue'), + }, + { + name: 'CSC-mem', + path: '/llm/service/service-mem', + meta: { + authority: ['service-mem'], + icon: 'mdi:brain', + title: $t('记忆库'), + keepAlive: true, + }, + component: () => + import('#/views/llm/service/service-mem/index.vue'), + }, + ], }, ], }, diff --git a/vue/apps/web-antd/src/router/routes/modules/out.ts b/vue/apps/web-antd/src/router/routes/modules/out.ts index 0816029..9dc28da 100644 --- a/vue/apps/web-antd/src/router/routes/modules/out.ts +++ b/vue/apps/web-antd/src/router/routes/modules/out.ts @@ -24,18 +24,7 @@ const routes: RouteRecordRaw[] = [ icon: 'mdi:wall-fire', iframeSrc: 'http://s1.ronsunny.cn:13010/', keepAlive: false, - title: '检索增强生成', - }, - }, - { - name: 'CVAT', - path: '/out/cvat', - component: IFrameView, - meta: { - icon: 'mdi:abjad-arabic', - link: 'http://171.212.101.199:13013/', - keepAlive: true, - title: '标注平台入口', + title: 'RAG Flow', }, }, ], diff --git a/vue/apps/web-antd/src/views/dashboard/workspace/index.vue b/vue/apps/web-antd/src/views/dashboard/workspace/index.vue index 0a44da7..b6e3d35 100644 --- a/vue/apps/web-antd/src/views/dashboard/workspace/index.vue +++ b/vue/apps/web-antd/src/views/dashboard/workspace/index.vue @@ -2,232 +2,109 @@ import type { WorkbenchProjectItem, WorkbenchQuickNavItem, - WorkbenchTodoItem, - WorkbenchTrendItem, -} from '@vben/common-ui'; +} from "@vben/common-ui"; -import { ref } from 'vue'; -import { useRouter } from 'vue-router'; - -import { WorkbenchHeader } from '@vben/common-ui'; -import { preferences } from '@vben/preferences'; -import { useUserStore } from '@vben/stores'; -import { openWindow } from '@vben/utils'; +import { useRouter } from "vue-router"; +import { WorkbenchHeader, WorkbenchQuickNav } from "@vben/common-ui"; +import { preferences } from "@vben/preferences"; +import { useUserStore } from "@vben/stores"; +import { openWindow } from "@vben/utils"; const userStore = useUserStore(); -// 这是一个示例数据,实际项目中需要根据实际情况进行调整 -// url 也可以是内部路由,在 navTo 方法中识别处理,进行内部跳转 -// 例如:url: /dashboard/workspace -const projectItems: WorkbenchProjectItem[] = [ - { - color: '', - content: '不要等待机会,而要创造机会。', - date: '2021-04-01', - group: '开源组', - icon: 'carbon:logo-github', - title: 'Github', - url: 'https://github.com', - }, - { - color: '#3fb27f', - content: '现在的你决定将来的你。', - date: '2021-04-01', - group: '算法组', - icon: 'ion:logo-vue', - title: 'Vue', - url: 'https://vuejs.org', - }, - { - color: '#e18525', - content: '没有什么才能比努力更重要。', - date: '2021-04-01', - group: '上班摸鱼', - icon: 'ion:logo-html5', - title: 'Html5', - url: 'https://developer.mozilla.org/zh-CN/docs/Web/HTML', - }, - { - color: '#bf0c2c', - content: '热情和欲望可以突破一切难关。', - date: '2021-04-01', - group: 'UI', - icon: 'ion:logo-angular', - title: 'Angular', - url: 'https://angular.io', - }, - { - color: '#00d8ff', - content: '健康的身体是实现目标的基石。', - date: '2021-04-01', - group: '技术牛', - icon: 'bx:bxl-react', - title: 'React', - url: 'https://reactjs.org', - }, - { - color: '#EBD94E', - content: '路是走出来的,而不是空想出来的。', - date: '2021-04-01', - group: '架构组', - icon: 'ion:logo-javascript', - title: 'Js', - url: 'https://developer.mozilla.org/zh-CN/docs/Web/JavaScript', - }, -]; - // 同样,这里的 url 也可以使用以 http 开头的外部链接 -const quickNavItems: WorkbenchQuickNavItem[] = [ +const cv: WorkbenchQuickNavItem[] = [ { - color: '#1fdaca', - icon: 'ion:home-outline', - title: '首页', - url: '/', + color: "#3fb27f", + authority: ['iva'], + icon: "mdi:video", + title: "视频智能分析", + url: "/cv/iva" }, { - color: '#bf0c2c', + color: "#3fb27f", + authority: ['sca'], + icon: "mdi:ice-cream", + title: "蚕茧仪评分析", + url: "/cv/sca" + }, + { + color: "#3fb27f", + authority: ['ysa'], + icon: "mdi:waveform", + title: "催青阶段分析", + url: "/cv/ysa" + }, + { + color: "#3fb27f", + icon: "ion:bar-chart-outline", + title: "标注平台入口", + authority: ['user'], + url: "http://171.212.101.199:13013/" + }, +]; +const llm: WorkbenchQuickNavItem[] = [ + { + color: "#1fdaca", + authority: ['bot'], + icon: "mdi:face-agent", + title: "通用智能体", + url: "/llm/bot" + }, + { + color: "#1fdaca", + authority: ['report'], + icon: 'mdi:set-center', + title: "智农观数阁", + url: "/llm/report/report-chat" + }, + { + color: "#1fdaca", + authority: ['service'], + icon: 'mdi:android-head', + title: "灵思智服阁", + url: "/llm/service/service-chat" + }, +]; +const common: WorkbenchQuickNavItem[] = [ + { + color: "#bf0c2c", + authority: ['remote'], + icon: "carbon:workspace", + title: "设备远程控制", + url: "/remote" + }, + { + color: "#bf0c2c", icon: 'ion:grid-outline', - title: '仪表盘', - url: '/dashboard', - }, - { - color: '#e18525', - icon: 'ion:layers-outline', - title: '组件', - url: '/demos/features/icons', - }, - { - color: '#3fb27f', - icon: 'ion:settings-outline', - title: '系统管理', - url: '/demos/features/login-expired', // 这里的 URL 是示例,实际项目中需要根据实际情况进行调整 - }, - { - color: '#4daf1bc9', - icon: 'ion:key-outline', - title: '权限管理', - url: '/demos/access/page-control', - }, - { - color: '#00d8ff', - icon: 'ion:bar-chart-outline', - title: '图表', - url: '/analytics', + title: "RAGFlow", + authority: ['user'], + url: "/out/rag" }, ]; - -const todoItems = ref([ - { - completed: false, - content: `审查最近提交到Git仓库的前端代码,确保代码质量和规范。`, - date: '2024-07-30 11:00:00', - title: '审查前端代码提交', - }, - { - completed: true, - content: `检查并优化系统性能,降低CPU使用率。`, - date: '2024-07-30 11:00:00', - title: '系统性能优化', - }, - { - completed: false, - content: `进行系统安全检查,确保没有安全漏洞或未授权的访问。 `, - date: '2024-07-30 11:00:00', - title: '安全检查', - }, - { - completed: false, - content: `更新项目中的所有npm依赖包,确保使用最新版本。`, - date: '2024-07-30 11:00:00', - title: '更新项目依赖', - }, - { - completed: false, - content: `修复用户报告的页面UI显示问题,确保在不同浏览器中显示一致。 `, - date: '2024-07-30 11:00:00', - title: '修复UI显示问题', - }, -]); -const trendItems: WorkbenchTrendItem[] = [ - { - avatar: 'svg:avatar-1', - content: `在 开源组 创建了项目 Vue`, - date: '刚刚', - title: '威廉', - }, - { - avatar: 'svg:avatar-2', - content: `关注了 威廉 `, - date: '1个小时前', - title: '艾文', - }, - { - avatar: 'svg:avatar-3', - content: `发布了 个人动态 `, - date: '1天前', - title: '克里斯', - }, - { - avatar: 'svg:avatar-4', - content: `发表文章 如何编写一个Vite插件 `, - date: '2天前', - title: 'Vben', - }, - { - avatar: 'svg:avatar-1', - content: `回复了 杰克 的问题 如何进行项目优化?`, - date: '3天前', - title: '皮特', - }, - { - avatar: 'svg:avatar-2', - content: `关闭了问题 如何运行项目 `, - date: '1周前', - title: '杰克', - }, - { - avatar: 'svg:avatar-3', - content: `发布了 个人动态 `, - date: '1周前', - title: '威廉', - }, - { - avatar: 'svg:avatar-4', - content: `推送了代码到 Github`, - date: '2021-04-01 20:00', - title: '威廉', - }, - { - avatar: 'svg:avatar-4', - content: `发表文章 如何编写使用 Admin Vben `, - date: '2021-03-01 20:00', - title: 'Vben', - }, -]; - const router = useRouter(); // 这是一个示例方法,实际项目中需要根据实际情况进行调整 -// This is a sample method, adjust according to the actual project requirements function navTo(nav: WorkbenchProjectItem | WorkbenchQuickNavItem) { - if (nav.url?.startsWith('http')) { + if (nav.url?.startsWith("http")) { openWindow(nav.url); return; } - if (nav.url?.startsWith('/')) { + if (nav.url?.startsWith("/")) { router.push(nav.url).catch((error) => { - console.error('Navigation failed:', error); + console.error("Navigation failed:", error); }); } else { console.warn(`Unknown URL for navigation item: ${nav.title} -> ${nav.url}`); } } + function getGreeting() { const hour = new Date().getHours(); - if (hour < 6) return '凌晨好'; - if (hour < 12) return '早安'; - if (hour < 18) return '下午好'; - return '晚上好'; + if (hour < 6) return "凌晨好"; + if (hour < 12) return "早安"; + if (hour < 18) return "下午好"; + return "晚上好"; } @@ -240,7 +117,38 @@ function getGreeting() { {{ getGreeting() }}, {{ userStore.userInfo?.username }}, 开始您一天的工作吧! - + + +
+
+ +
+
+
+
+ +
+
+
+
+ +
+
diff --git a/vue/apps/web-antd/src/views/llm/bot/index.vue b/vue/apps/web-antd/src/views/llm/bot/index.vue index 7c2ee55..5974a7d 100644 --- a/vue/apps/web-antd/src/views/llm/bot/index.vue +++ b/vue/apps/web-antd/src/views/llm/bot/index.vue @@ -1,40 +1,39 @@ + + diff --git a/vue/packages/effects/request/src/request-client/request-client.ts b/vue/packages/effects/request/src/request-client/request-client.ts index e581167..5e77b62 100644 --- a/vue/packages/effects/request/src/request-client/request-client.ts +++ b/vue/packages/effects/request/src/request-client/request-client.ts @@ -60,7 +60,7 @@ class RequestClient { }, responseReturn: 'raw', // 默认超时时间 - timeout: 10_000, + timeout: 30_000, }; const { ...axiosConfig } = options; const requestConfig = merge(axiosConfig, defaultConfig); diff --git a/vue/pnpm-lock.yaml b/vue/pnpm-lock.yaml index 41839bc..b155890 100644 --- a/vue/pnpm-lock.yaml +++ b/vue/pnpm-lock.yaml @@ -638,6 +638,9 @@ importers: apps/web-antd: dependencies: + '@handsontable/vue3': + specifier: ^16.0.1 + version: 16.0.1(handsontable@16.0.1)(vue@3.5.16(typescript@5.8.3)) '@vben/access': specifier: workspace:* version: link:../../packages/effects/access @@ -689,6 +692,9 @@ importers: dayjs: specifier: 'catalog:' version: 1.11.13 + handsontable: + specifier: ^16.0.1 + version: 16.0.1 js-sha256: specifier: ^0.11.0 version: 0.11.1 @@ -3394,6 +3400,15 @@ packages: '@gar/promisify@1.1.3': resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + '@handsontable/pikaday@1.0.0': + resolution: {integrity: sha512-1VN6N38t5/DcjJ7y7XUYrDx1LuzvvzlrFdBdMG90Qo1xc8+LXHqbWbsTEm5Ec5gXTEbDEO53vUT35R+2COmOyg==} + + '@handsontable/vue3@16.0.1': + resolution: {integrity: sha512-NYjL4P47+/Wb3zD89iN7BG8ihwD85kKgl2i3ds6GQhl+Fei2cG1W7Fq2mHUnTrG+rjoOf9n65vuLtNybhoVRAg==} + peerDependencies: + handsontable: '>=16.0.0' + vue: ^3.5.13 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -5049,6 +5064,9 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -5214,6 +5232,9 @@ packages: resolution: {integrity: sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==} engines: {node: '>=18.17'} + chevrotain@6.5.0: + resolution: {integrity: sha512-BwqQ/AgmKJ8jcMEjaSnfMybnKMgGTrtDKowfTP3pX4jwVy0kNjRsT/AP6h+wC3+3NC+X8X15VWBnTCQlX+wQFg==} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -5927,6 +5948,9 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + dompurify@3.2.6: + resolution: {integrity: sha512-/2GogDQlohXPZe6D6NOgQvXLPSYBqIWMnZ8zzOhn09REE4eyAzb+Hed3jhoM9OkuaJ8P6ZGTTVWQKAi8ieIzfQ==} + domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} @@ -6787,6 +6811,9 @@ packages: h3@1.15.3: resolution: {integrity: sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ==} + handsontable@16.0.1: + resolution: {integrity: sha512-YkfSYVP+5JaD8/hJfXAvVLTQhDx7flynRwCs4YFQYKGZ/Frkf1J/vCF1rvDUPGtEBJGWT+LTmJFW08cn6SsjoQ==} + happy-dom@17.5.6: resolution: {integrity: sha512-B4U6jKuiizwCJ2WP0YreQmRdeBrHKOXhpz7YUbbwdSAKfWEhdG4UfWZOZTZ5Oejs/9yJtk7xmbfp8YdVL9LVFA==} engines: {node: '>=18.0.0'} @@ -6913,6 +6940,9 @@ packages: humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + hyperformula@3.0.1: + resolution: {integrity: sha512-SFH8fOPtL7uHnYhVrd6u0g0Jp2UQyDprcRfdQh5dmLgwtCg397J3QkwGCCWuQi17WRWF1Z2+gB44WO8h+DK7dA==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -7958,6 +7988,9 @@ packages: engines: {node: '>=18'} hasBin: true + moment@2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + mpd-parser@1.3.1: resolution: {integrity: sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==} hasBin: true @@ -8123,6 +8156,9 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + numbro@2.5.0: + resolution: {integrity: sha512-xDcctDimhzko/e+y+Q2/8i3qNC9Svw1QgOkSkQoO0kIPI473tR9QRbo2KP88Ty9p8WbPy+3OpTaAIzehtuHq+A==} + nypm@0.6.0: resolution: {integrity: sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==} engines: {node: ^14.16.0 || >=16.10.0} @@ -9165,6 +9201,9 @@ packages: resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + regexp-to-ast@0.4.0: + resolution: {integrity: sha512-4qf/7IsIKfSNHQXSwial1IFmfM1Cc/whNBQqRwe0V2stPe7KmN1U0tWQiIx6JiirgSrisjE0eECdNf7Tav1Ntw==} + regexp-tree@0.1.27: resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} hasBin: true @@ -12728,6 +12767,13 @@ snapshots: '@gar/promisify@1.1.3': {} + '@handsontable/pikaday@1.0.0': {} + + '@handsontable/vue3@16.0.1(handsontable@16.0.1)(vue@3.5.16(typescript@5.8.3))': + dependencies: + handsontable: 16.0.1 + vue: 3.5.16(typescript@5.8.3) + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -14636,6 +14682,8 @@ snapshots: dependencies: is-windows: 1.0.2 + bignumber.js@9.3.1: {} + binary-extensions@2.3.0: {} bindings@1.5.0: @@ -14842,6 +14890,11 @@ snapshots: undici: 6.21.3 whatwg-mimetype: 4.0.0 + chevrotain@6.5.0: + dependencies: + regexp-to-ast: 0.4.0 + optional: true + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -15594,6 +15647,10 @@ snapshots: dependencies: domelementtype: 2.3.0 + dompurify@3.2.6: + optionalDependencies: + '@types/trusted-types': 2.0.7 + domutils@2.8.0: dependencies: dom-serializer: 1.4.1 @@ -16649,6 +16706,16 @@ snapshots: ufo: 1.6.1 uncrypto: 0.1.3 + handsontable@16.0.1: + dependencies: + '@handsontable/pikaday': 1.0.0 + core-js: 3.42.0 + dompurify: 3.2.6 + moment: 2.30.1 + numbro: 2.5.0 + optionalDependencies: + hyperformula: 3.0.1 + happy-dom@17.5.6: dependencies: webidl-conversions: 7.0.0 @@ -16796,6 +16863,12 @@ snapshots: dependencies: ms: 2.1.3 + hyperformula@3.0.1: + dependencies: + chevrotain: 6.5.0 + tiny-emitter: 2.1.0 + optional: true + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -17756,6 +17829,8 @@ snapshots: ast-module-types: 6.0.1 node-source-walk: 7.0.1 + moment@2.30.1: {} + mpd-parser@1.3.1: dependencies: '@babel/runtime': 7.27.3 @@ -17996,6 +18071,10 @@ snapshots: dependencies: boolbase: 1.0.0 + numbro@2.5.0: + dependencies: + bignumber.js: 9.3.1 + nypm@0.6.0: dependencies: citty: 0.1.6 @@ -19046,6 +19125,9 @@ snapshots: '@eslint-community/regexpp': 4.12.1 refa: 0.12.1 + regexp-to-ast@0.4.0: + optional: true + regexp-tree@0.1.27: {} regexp.prototype.flags@1.5.4: diff --git a/vue/scripts/deploy/Dockerfile b/vue/scripts/deploy/Dockerfile index 3d4ca1d..94953cf 100644 --- a/vue/scripts/deploy/Dockerfile +++ b/vue/scripts/deploy/Dockerfile @@ -1,39 +1,14 @@ -FROM node:slim AS builder - -# --max-old-space-size -ENV PNPM_HOME="/pnpm" -ENV PATH="$PNPM_HOME:$PATH" -ENV NODE_OPTIONS=--max-old-space-size=8192 -ENV TZ=Asia/Shanghai - -RUN npm i -g corepack - -WORKDIR /app - -# copy package.json and pnpm-lock.yaml to workspace -COPY . /app - -# 安装依赖 -RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile -# RUN pnpm run build --filter=\!./docs -RUN pnpm run build --filter=@vben/web-antd - - -RUN echo "Builder Success 🎉" - -FROM nginx:1.27.4-alpine AS production +FROM nginx:1.27.4-alpine # 配置 nginx RUN echo "types { application/javascript js mjs; }" > /etc/nginx/conf.d/mjs.conf \ && rm -rf /etc/nginx/conf.d/default.conf -# 复制构建产物 -COPY --from=builder /app/apps/web-antd/dist /usr/share/nginx/html - -# 复制 nginx 配置 -COPY --from=builder /app/scripts/deploy/nginx.conf /etc/nginx/nginx.conf +# 只拷贝打包好的 dist +COPY apps/web-antd/dist /usr/share/nginx/html +# 拷贝 nginx 配置 +COPY scripts/deploy/nginx.conf /etc/nginx/nginx.conf EXPOSE 8090 -# 启动 nginx CMD ["nginx", "-g", "daemon off;"] diff --git a/vue/scripts/deploy/build-local-docker-image.sh b/vue/scripts/deploy/build-local-docker-image.sh deleted file mode 100644 index 2a93b90..0000000 --- a/vue/scripts/deploy/build-local-docker-image.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) -LOG_FILE=${SCRIPT_DIR}/build-local-docker-image.log -ERROR="" -IMAGE_NAME="ce-vue" - -function stop_and_remove_container() { - # Stop and remove the existing container - docker stop ${IMAGE_NAME} >/dev/null 2>&1 - docker rm ${IMAGE_NAME} >/dev/null 2>&1 -} - -function remove_image() { - # Remove the existing image - docker rmi vben-admin-pro >/dev/null 2>&1 -} - -function install_dependencies() { - # Install all dependencies - cd ${SCRIPT_DIR} - pnpm install || ERROR="install_dependencies failed" -} - -function build_image() { - # build docker - docker build ../../ -f Dockerfile -t ${IMAGE_NAME} || ERROR="build_image failed" -} - -function log_message() { - if [[ ${ERROR} != "" ]]; - then - >&2 echo "build failed, Please check build-local-docker-image.log for more details" - >&2 echo "ERROR: ${ERROR}" - exit 1 - else - echo "docker image with tag '${IMAGE_NAME}' built sussessfully. Use below sample command to run the container" - echo "" - echo "docker run -d -p 8010:8090 --name ${IMAGE_NAME} ${IMAGE_NAME}" - fi -} - -echo "Info: Stopping and removing existing container and image" | tee ${LOG_FILE} -stop_and_remove_container -remove_image - -echo "Info: Installing dependencies" | tee -a ${LOG_FILE} -install_dependencies 1>> ${LOG_FILE} 2>> ${LOG_FILE} - -if [[ ${ERROR} == "" ]]; then - echo "Info: Building docker image" | tee -a ${LOG_FILE} - build_image 1>> ${LOG_FILE} 2>> ${LOG_FILE} -fi - -log_message | tee -a ${LOG_FILE}