diff --git a/.vscode/settings.json b/.vscode/settings.json index dc371b9b0..a45451b07 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -189,10 +189,7 @@ ], "github.copilot.enable": { - "*": true, - "markdown": true, - "plaintext": false, - "yaml": false + "*": false }, "cssVariables.lookupFiles": ["packages/core/base/design/src/**/*.css"], diff --git a/README.md b/README.md index 86995df85..f3da9a925 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## 🐶 新手必读 -- nodejs > 20.10.0 && pnpm > 10.14.0 (强制使用pnpm) +- nodejs > 20.12.0 && pnpm > 10.14.0 (强制使用pnpm) - 演示地址【Vue3 + element-plus】: - 演示地址【Vue3 + vben5(ant-design-vue)】: - 演示地址【Vue2 + element-ui】: @@ -21,7 +21,7 @@ **芋道**,以开发者为中心,打造中国第一流的快速开发平台,全部开源,个人与企业可 100% 免费使用。 - 采用最新 [vue-vben-admin](https://github.com/vbenjs/vue-vben-admin) v5 实现 -- 支持 [Ant Design Vue](https://www.antdv.com/) | [Element Plus](https://element-plus.org/zh-CN/) | [Naive UI](https://www.naiveui.com/) 多种免费开源的中后台模版,具备如下特性: +- 支持 [Ant Design Vue](https://www.antdv.com/) | [Element Plus](https://element-plus.org/zh-CN/) | [Naive UI](https://www.naiveui.com/) | [TDesign](https://tdesign.tencent.com/) 多种免费开源的中后台模版,具备如下特性: ![首页](.image/demo/vben.png) @@ -46,12 +46,14 @@ | [Ant Design Vue](https://www.antdv.com/) | Ant Design Vue | 4.2.6 | | [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.10.2 | | [Naive UI](https://www.naiveui.com/) | Naive UI | 2.42.0 | +| [TDesign](https://tdesign.tencent.com/) | TDesign | 1.17.1 | | [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 超集 | 5.8.3 | | [pinia](https://pinia.vuejs.org/) | Vue 存储库替代 vuex5 | 3.0.3 | | [vueuse](https://vueuse.org/) | 常用工具集 | 13.4.0 | | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 11.1.7 | | [vue-router](https://router.vuejs.org/) | Vue 路由 | 4.5.1 | | [Tailwind CSS](https://tailwindcss.com/) | 原子 CSS | 3.4.17 | +| [Iconify](https://iconify.design/) | 图标组件 | 5.0.0 | | [Iconify](https://icon-sets.iconify.design/) | 在线图标库 | 2.2.354 | | [TinyMCE](https://www.tiny.cloud/) | 富文本编辑器 | 6.1.0 | | [Echarts](https://echarts.apache.org/) | 图表库 | 5.6.0 | diff --git a/apps/web-antd/src/api/ai/chat/message/index.ts b/apps/web-antd/src/api/ai/chat/message/index.ts index 9de927023..d2677ad55 100644 --- a/apps/web-antd/src/api/ai/chat/message/index.ts +++ b/apps/web-antd/src/api/ai/chat/message/index.ts @@ -8,6 +8,7 @@ import { requestClient } from '#/api/request'; const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); const accessStore = useAccessStore(); + export namespace AiChatMessageApi { export interface ChatMessage { id: number; // 编号 @@ -18,6 +19,7 @@ export namespace AiChatMessageApi { model: number; // 模型标志 modelId: number; // 模型编号 content: string; // 聊天内容 + reasoningContent?: string; // 推理内容(深度思考) tokens: number; // 消耗 Token 数量 segmentIds?: number[]; // 段落编号 segments?: { @@ -26,10 +28,22 @@ export namespace AiChatMessageApi { documentName: string; // 文档名称 id: number; // 段落编号 }[]; + webSearchPages?: WebSearchPage[]; // 联网搜索结果 + attachmentUrls?: string[]; // 附件 URL 数组 createTime: Date; // 创建时间 roleAvatar: string; // 角色头像 userAvatar: string; // 用户头像 } + + /** 联网搜索页面接口 */ + export interface WebSearchPage { + name: string; // 网站名称 + icon: string; // 网站图标 URL + title: string; // 页面标题 + url: string; // 页面 URL + snippet: string; // 简短描述 + summary: string; // 内容摘要 + } } // 消息列表 @@ -47,9 +61,11 @@ export function sendChatMessageStream( content: string, ctrl: any, enableContext: boolean, + enableWebSearch: boolean, onMessage: any, onError: any, onClose: any, + attachmentUrls?: string[], ) { const token = accessStore.accessToken; return fetchEventSource(`${apiURL}/ai/chat/message/send-stream`, { @@ -63,6 +79,8 @@ export function sendChatMessageStream( conversationId, content, useContext: enableContext, + useSearch: enableWebSearch, + attachmentUrls: attachmentUrls || [], }), onmessage: onMessage, onerror: onError, diff --git a/apps/web-antd/src/api/ai/image/index.ts b/apps/web-antd/src/api/ai/image/index.ts index 6af33f1d0..c4c278ce6 100644 --- a/apps/web-antd/src/api/ai/image/index.ts +++ b/apps/web-antd/src/api/ai/image/index.ts @@ -9,7 +9,8 @@ export namespace AiImageApi { label: string; // Make Variations 文本 style: number; // 样式: 2(Primary)、3(Green) } - // AI 绘图 + + /** AI 绘图 */ export interface Image { id: number; // 编号 userId: number; @@ -83,6 +84,7 @@ export function deleteImageMy(id: number) { } // ================ midjourney 专属 ================ + // 【Midjourney】生成图片 export function midjourneyImagine(data: AiImageApi.ImageMidjourneyImagineReq) { return requestClient.post(`/ai/image/midjourney/imagine`, data); @@ -94,6 +96,7 @@ export function midjourneyAction(data: AiImageApi.ImageMidjourneyAction) { } // ================ 绘图管理 ================ + // 查询绘画分页 export function getImagePage(params: any) { return requestClient.get(`/ai/image/page`, { params }); diff --git a/apps/web-antd/src/api/ai/knowledge/document/index.ts b/apps/web-antd/src/api/ai/knowledge/document/index.ts index a26e80e76..6c754d53e 100644 --- a/apps/web-antd/src/api/ai/knowledge/document/index.ts +++ b/apps/web-antd/src/api/ai/knowledge/document/index.ts @@ -26,10 +26,12 @@ export function getKnowledgeDocumentPage(params: PageParam) { export function getKnowledgeDocument(id: number) { return requestClient.get(`/ai/knowledge/document/get?id=${id}`); } + // 新增知识库文档(单个) export function createKnowledge(data: any) { return requestClient.post('/ai/knowledge/document/create', data); } + // 新增知识库文档(多个) export function createKnowledgeDocumentList(data: any) { return requestClient.post('/ai/knowledge/document/create-list', data); @@ -44,6 +46,7 @@ export function updateKnowledgeDocument(data: any) { export function updateKnowledgeDocumentStatus(data: any) { return requestClient.put('/ai/knowledge/document/update-status', data); } + // 删除知识库文档 export function deleteKnowledgeDocument(id: number) { return requestClient.delete(`/ai/knowledge/document/delete?id=${id}`); diff --git a/apps/web-antd/src/api/ai/knowledge/knowledge/index.ts b/apps/web-antd/src/api/ai/knowledge/knowledge/index.ts index 7140d8b48..03f70bd9a 100644 --- a/apps/web-antd/src/api/ai/knowledge/knowledge/index.ts +++ b/apps/web-antd/src/api/ai/knowledge/knowledge/index.ts @@ -27,6 +27,7 @@ export function getKnowledge(id: number) { `/ai/knowledge/get?id=${id}`, ); } + // 新增知识库 export function createKnowledge(data: AiKnowledgeKnowledgeApi.Knowledge) { return requestClient.post('/ai/knowledge/create', data); diff --git a/apps/web-antd/src/api/ai/knowledge/segment/index.ts b/apps/web-antd/src/api/ai/knowledge/segment/index.ts index 63ea4e752..e9baf662e 100644 --- a/apps/web-antd/src/api/ai/knowledge/segment/index.ts +++ b/apps/web-antd/src/api/ai/knowledge/segment/index.ts @@ -32,6 +32,7 @@ export function getKnowledgeSegment(id: number) { `/ai/knowledge/segment/get?id=${id}`, ); } + // 新增知识库分段 export function createKnowledgeSegment( data: AiKnowledgeSegmentApi.KnowledgeSegment, @@ -47,9 +48,13 @@ export function updateKnowledgeSegment( } // 修改知识库分段状态 -export function updateKnowledgeSegmentStatus(data: any) { - return requestClient.put('/ai/knowledge/segment/update-status', data); +export function updateKnowledgeSegmentStatus(id: number, status: number) { + return requestClient.put('/ai/knowledge/segment/update-status', { + id, + status, + }); } + // 删除知识库分段 export function deleteKnowledgeSegment(id: number) { return requestClient.delete(`/ai/knowledge/segment/delete?id=${id}`); diff --git a/apps/web-antd/src/api/ai/workflow/index.ts b/apps/web-antd/src/api/ai/workflow/index.ts index a383d0cd0..676d6337c 100644 --- a/apps/web-antd/src/api/ai/workflow/index.ts +++ b/apps/web-antd/src/api/ai/workflow/index.ts @@ -2,28 +2,48 @@ import type { PageParam, PageResult } from '@vben/request'; import { requestClient } from '#/api/request'; -export function getWorkflowPage(params: PageParam) { - return requestClient.get>('/ai/workflow/page', { - params, - }); +export namespace AiWorkflowApi { + /** 工作流 */ + export interface Workflow { + id?: number; // 编号 + name: string; // 工作流名称 + code: string; // 工作流标识 + graph: string; // 工作流模型 JSON 数据 + remark?: string; // 备注 + status: number; // 状态 + createTime?: Date; // 创建时间 + } } -export const getWorkflow = (id: number | string) => { - return requestClient.get(`/ai/workflow/get?id=${id}`); -}; +/** 查询工作流管理列表 */ +export function getWorkflowPage(params: PageParam) { + return requestClient.get>( + '/ai/workflow/page', + { params }, + ); +} -export const createWorkflow = (data: any) => { +/** 查询工作流详情 */ +export function getWorkflow(id: number) { + return requestClient.get(`/ai/workflow/get?id=${id}`); +} + +/** 新增工作流 */ +export function createWorkflow(data: AiWorkflowApi.Workflow) { return requestClient.post('/ai/workflow/create', data); -}; +} -export const updateWorkflow = (data: any) => { +/** 修改工作流 */ +export function updateWorkflow(data: AiWorkflowApi.Workflow) { return requestClient.put('/ai/workflow/update', data); -}; +} -export const deleteWorkflow = (id: number | string) => { +/** 删除工作流 */ +export function deleteWorkflow(id: number) { return requestClient.delete(`/ai/workflow/delete?id=${id}`); -}; +} -export const testWorkflow = (data: any) => { +/** 测试工作流 */ +export function testWorkflow(data: any) { return requestClient.post('/ai/workflow/test', data); -}; +} diff --git a/apps/web-antd/src/api/mall/promotion/kefu/conversation/index.ts b/apps/web-antd/src/api/mall/promotion/kefu/conversation/index.ts index 6510dc0ec..497bd1a50 100644 --- a/apps/web-antd/src/api/mall/promotion/kefu/conversation/index.ts +++ b/apps/web-antd/src/api/mall/promotion/kefu/conversation/index.ts @@ -1,5 +1,3 @@ -import type { PageResult } from '@vben/request'; - import { requestClient } from '#/api/request'; export namespace MallKefuConversationApi { @@ -28,7 +26,7 @@ export namespace MallKefuConversationApi { /** 获得客服会话列表 */ export function getConversationList() { - return requestClient.get>( + return requestClient.get( '/promotion/kefu-conversation/list', ); } diff --git a/apps/web-antd/src/api/mp/account/index.ts b/apps/web-antd/src/api/mp/account/index.ts index c5ee331b0..5bd402230 100644 --- a/apps/web-antd/src/api/mp/account/index.ts +++ b/apps/web-antd/src/api/mp/account/index.ts @@ -5,18 +5,19 @@ import { requestClient } from '#/api/request'; export namespace MpAccountApi { /** 公众号账号信息 */ export interface Account { - id?: number; + id: number; name: string; - account: string; - appId: string; - appSecret: string; - token: string; + account?: string; + appId?: string; + appSecret?: string; + token?: string; aesKey?: string; qrCodeUrl?: string; remark?: string; createTime?: Date; } + // TODO @dylan:这个直接使用 Account,简化一点; export interface AccountSimple { id: number; name: string; diff --git a/apps/web-antd/src/components/table-action/icons.ts b/apps/web-antd/src/components/table-action/icons.ts index df5bf1a77..d474a6a25 100644 --- a/apps/web-antd/src/components/table-action/icons.ts +++ b/apps/web-antd/src/components/table-action/icons.ts @@ -11,4 +11,5 @@ export const ACTION_ICON = { VIEW: 'lucide:eye', COPY: 'lucide:copy', CLOSE: 'lucide:x', + BOOK: 'lucide:book', }; diff --git a/apps/web-antd/src/locales/langs/en-US/page.json b/apps/web-antd/src/locales/langs/en-US/page.json index 00a8c90b2..409137ee3 100644 --- a/apps/web-antd/src/locales/langs/en-US/page.json +++ b/apps/web-antd/src/locales/langs/en-US/page.json @@ -29,5 +29,11 @@ "tenant": { "placeholder": "Please select tenant", "success": "Switch tenant success" + }, + "mp": { + "upload": { + "invalidFormat": "Invalid {0} format!", + "maxSize": "{0} size cannot exceed {1}M!" + } } } diff --git a/apps/web-antd/src/locales/langs/zh-CN/page.json b/apps/web-antd/src/locales/langs/zh-CN/page.json index eefc4924b..f56160a6a 100644 --- a/apps/web-antd/src/locales/langs/zh-CN/page.json +++ b/apps/web-antd/src/locales/langs/zh-CN/page.json @@ -29,5 +29,11 @@ "tenant": { "placeholder": "请选择租户", "success": "切换租户成功" + }, + "mp": { + "upload": { + "invalidFormat": "上传{0}格式不对!", + "maxSize": "上传{0}大小不能超过{1}M!" + } } } diff --git a/apps/web-antd/src/plugins/form-create/index.ts b/apps/web-antd/src/plugins/form-create/index.ts index e13f1c1f7..db60c0f51 100644 --- a/apps/web-antd/src/plugins/form-create/index.ts +++ b/apps/web-antd/src/plugins/form-create/index.ts @@ -96,7 +96,6 @@ export function setupFormCreate(app: App) { components.forEach((component) => { app.component(component.name as string, component); }); - // TODO @xingyu:这里为啥 app.component('AMessage', message); 看官方是没有的; 需要额外引入 app.component('AMessage', message); formCreate.use(install); app.use(formCreate); diff --git a/apps/web-antd/src/store/mall/kefu.ts b/apps/web-antd/src/store/mall/kefu.ts index 85f4023e7..6fe0b6c25 100644 --- a/apps/web-antd/src/store/mall/kefu.ts +++ b/apps/web-antd/src/store/mall/kefu.ts @@ -5,7 +5,10 @@ import { isEmpty } from '@vben/utils'; import { acceptHMRUpdate, defineStore } from 'pinia'; -import * as KeFuConversationApi from '#/api/mall/promotion/kefu/conversation'; +import { + getConversation, + getConversationList, +} from '#/api/mall/promotion/kefu/conversation'; interface MallKefuInfoVO { conversationList: MallKefuConversationApi.Conversation[]; // 会话列表 @@ -41,9 +44,7 @@ export const useMallKefuStore = defineStore('mall-kefu', { // ======================= 会话相关 ======================= /** 加载会话缓存列表 */ async setConversationList() { - // TODO @jave:idea linter 告警,修复下; - // TODO @jave:不使用 KeFuConversationApi.,直接用 getConversationList - this.conversationList = await KeFuConversationApi.getConversationList(); + this.conversationList = await getConversationList(); this.conversationSort(); }, /** 更新会话缓存已读 */ @@ -51,8 +52,11 @@ export const useMallKefuStore = defineStore('mall-kefu', { if (isEmpty(this.conversationList)) { return; } - const conversation = this.conversationList.find( - (item) => item.id === conversationId, + const conversationList = this + .conversationList as MallKefuConversationApi.Conversation[]; + const conversation = conversationList.find( + (item: MallKefuConversationApi.Conversation) => + item.id === conversationId, ); conversation && (conversation.adminUnreadMessageCount = 0); }, @@ -62,10 +66,16 @@ export const useMallKefuStore = defineStore('mall-kefu', { return; } - const conversation = - await KeFuConversationApi.getConversation(conversationId); + const conversation = await getConversation(conversationId); this.deleteConversation(conversationId); - conversation && this.conversationList.push(conversation); + if (conversation && this.conversationList) { + const conversationList = this + .conversationList as MallKefuConversationApi.Conversation[]; + this.conversationList = [ + ...conversationList, + conversation as MallKefuConversationApi.Conversation, + ]; + } this.conversationSort(); }, /** 删除会话缓存 */ diff --git a/apps/web-antd/src/views/ai/chat/index/index.vue b/apps/web-antd/src/views/ai/chat/index/index.vue index 9e6cc2559..5f09fbc6c 100644 --- a/apps/web-antd/src/views/ai/chat/index/index.vue +++ b/apps/web-antd/src/views/ai/chat/index/index.vue @@ -1,5 +1,4 @@ diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/index.vue deleted file mode 100644 index 9b4dd5c16..000000000 --- a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/index.vue +++ /dev/null @@ -1,53 +0,0 @@ - - diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/config.ts b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/carousel/config.ts similarity index 100% rename from apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/config.ts rename to apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/carousel/config.ts diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/carousel/index.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/carousel/index.vue new file mode 100644 index 000000000..6b89b4c41 --- /dev/null +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/carousel/index.vue @@ -0,0 +1,56 @@ + + diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/carousel/property.vue similarity index 71% rename from apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/property.vue rename to apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/carousel/property.vue index 9cace5f26..bebf71f72 100644 --- a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/Carousel/property.vue +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/mobile/carousel/property.vue @@ -7,6 +7,7 @@ import { useVModel } from '@vueuse/core'; import { Form, FormItem, + InputNumber, Radio, RadioButton, RadioGroup, @@ -21,51 +22,61 @@ import { AppLinkInput, Draggable } from '#/views/mall/promotion/components'; import ComponentContainerProperty from '../../component-container-property.vue'; -// 轮播图属性面板 +/** 轮播图属性面板 */ defineOptions({ name: 'CarouselProperty' }); const props = defineProps<{ modelValue: CarouselProperty }>(); + const emit = defineEmits(['update:modelValue']); + const formData = useVModel(props, 'modelValue', emit);