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/.env.development b/apps/web-antd/.env.development index cff255764..fe07e867c 100644 --- a/apps/web-antd/.env.development +++ b/apps/web-antd/.env.development @@ -4,9 +4,9 @@ VITE_PORT=5666 VITE_BASE=/ # 请求路径 -VITE_BASE_URL=http://127.0.0.1:48080 +VITE_BASE_URL=http://47.103.66.220:48080 # 接口地址 -VITE_GLOB_API_URL=/admin-api +VITE_GLOB_API_URL=http://47.103.66.220:48080/admin-api # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持S3服务 VITE_UPLOAD_TYPE=server # 是否打开 devtools,true 为打开,false 为关闭 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/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/knowledge/document/data.ts b/apps/web-antd/src/views/ai/knowledge/document/data.ts index a6433040a..14c088e26 100644 --- a/apps/web-antd/src/views/ai/knowledge/document/data.ts +++ b/apps/web-antd/src/views/ai/knowledge/document/data.ts @@ -1,11 +1,13 @@ import type { VbenFormSchema } from '#/adapter/form'; import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { AiKnowledgeDocumentApi } from '#/api/ai/knowledge/document'; import { AiModelTypeEnum, CommonStatusEnum, DICT_TYPE } from '@vben/constants'; import { getDictOptions } from '@vben/hooks'; import { z } from '#/adapter/form'; import { getModelSimpleList } from '#/api/ai/model/model'; + /** 新增/修改的表单 */ export function useFormSchema(): VbenFormSchema[] { return [ @@ -92,12 +94,17 @@ export function useGridFormSchema(): VbenFormSchema[] { fieldName: 'name', label: '文件名称', component: 'Input', + componentProps: { + placeholder: '请输入文件名称', + allowClear: true, + }, }, { fieldName: 'status', label: '是否启用', component: 'Select', componentProps: { + placeholder: '请选择是否启用', allowClear: true, options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), }, @@ -106,45 +113,66 @@ export function useGridFormSchema(): VbenFormSchema[] { } /** 列表的字段 */ -export function useGridColumns(): VxeTableGridOptions['columns'] { +export function useGridColumns( + onStatusChange?: ( + newStatus: number, + row: AiKnowledgeDocumentApi.KnowledgeDocument, + ) => PromiseLike, +): VxeTableGridOptions['columns'] { return [ { field: 'id', title: '文档编号', + minWidth: 100, }, { field: 'name', title: '文件名称', + minWidth: 200, }, { field: 'contentLength', title: '字符数', + minWidth: 100, }, { field: 'tokens', title: 'Token 数', + minWidth: 100, }, { field: 'segmentMaxTokens', title: '分片最大 Token 数', + minWidth: 150, }, { field: 'retrievalCount', title: '召回次数', + minWidth: 100, }, { field: 'status', title: '是否启用', - slots: { default: 'status' }, + minWidth: 100, + align: 'center', + cellRender: { + attrs: { beforeChange: onStatusChange }, + name: 'CellSwitch', + props: { + checkedValue: CommonStatusEnum.ENABLE, + unCheckedValue: CommonStatusEnum.DISABLE, + }, + }, }, { field: 'createTime', title: '上传时间', + minWidth: 180, formatter: 'formatDateTime', }, { title: '操作', - width: 150, + minWidth: 150, fixed: 'right', slots: { default: 'actions' }, }, diff --git a/apps/web-antd/src/views/ai/knowledge/document/form/index.vue b/apps/web-antd/src/views/ai/knowledge/document/form/index.vue index 4e0bf6de2..83f53806b 100644 --- a/apps/web-antd/src/views/ai/knowledge/document/form/index.vue +++ b/apps/web-antd/src/views/ai/knowledge/document/form/index.vue @@ -16,14 +16,13 @@ import { Card } from 'ant-design-vue'; import { getKnowledgeDocument } from '#/api/ai/knowledge/document'; -import ProcessStep from './ProcessStep.vue'; -import SplitStep from './SplitStep.vue'; -import UploadStep from './UploadStep.vue'; +import ProcessStep from './modules/process-step.vue'; +import SplitStep from './modules/split-step.vue'; +import UploadStep from './modules/upload-step.vue'; const route = useRoute(); const router = useRouter(); -// 组件引用 const uploadDocumentRef = ref(); const documentSegmentRef = ref(); const processCompleteRef = ref(); @@ -59,9 +58,9 @@ const tabs = useTabs(); function handleBack() { // 关闭当前页签 tabs.closeCurrentTab(); - // 跳转到列表页,使用路径, 目前后端的路由 name: 'name'+ menuId + // 跳转到列表页 router.push({ - path: `/ai/knowledge/document`, + name: 'AiKnowledgeDocument', query: { knowledgeId: route.query.knowledgeId, }, @@ -92,6 +91,7 @@ async function initData() { goToNextStep(); } } + /** 切换到下一步 */ function goToNextStep() { if (currentStep.value < steps.length - 1) { @@ -106,11 +106,6 @@ function goToPrevStep() { } } -/** 初始化 */ -onMounted(async () => { - await initData(); -}); - /** 添加组件卸载前的清理代码 */ onBeforeUnmount(() => { // 清理所有的引用 @@ -118,12 +113,18 @@ onBeforeUnmount(() => { documentSegmentRef.value = null; processCompleteRef.value = null; }); + /** 暴露方法给子组件使用 */ defineExpose({ goToNextStep, goToPrevStep, handleBack, }); + +/** 初始化 */ +onMounted(async () => { + await initData(); +}); - diff --git a/apps/web-antd/src/views/ai/knowledge/knowledge/retrieval/index.vue b/apps/web-antd/src/views/ai/knowledge/knowledge/retrieval/index.vue index a9c9d2aef..f7b4e4fab 100644 --- a/apps/web-antd/src/views/ai/knowledge/knowledge/retrieval/index.vue +++ b/apps/web-antd/src/views/ai/knowledge/knowledge/retrieval/index.vue @@ -17,7 +17,7 @@ import { import { getKnowledge } from '#/api/ai/knowledge/knowledge'; import { searchKnowledgeSegment } from '#/api/ai/knowledge/segment'; -/** 文档召回测试 */ +/** 知识库文档召回测试 */ defineOptions({ name: 'KnowledgeDocumentRetrieval' }); const route = useRoute(); @@ -32,7 +32,7 @@ const queryParams = reactive({ similarityThreshold: 0.5, }); -/** 调用文档召回测试接口 */ +/** 执行召回测试 */ async function getRetrievalResult() { if (!queryParams.content) { message.warning('请输入查询文本'); @@ -50,19 +50,17 @@ async function getRetrievalResult() { similarityThreshold: queryParams.similarityThreshold, }); segments.value = data || []; - } catch (error) { - console.error(error); } finally { loading.value = false; } } -/** 展开/收起段落内容 */ +/** 切换段落展开状态 */ function toggleExpand(segment: any) { segment.expanded = !segment.expanded; } -/** 获取知识库信息 */ +/** 获取知识库配置信息 */ async function getKnowledgeInfo(id: number) { try { const knowledge = await getKnowledge(id); @@ -157,43 +155,44 @@ onMounted(() => {
-
+
分段({{ segment.id }}) · {{ segment.contentLength }} 字符数 · {{ segment.tokens }} Token score: {{ segment.score }}
{{ segment.content }}
-
-
- +
+
+ {{ segment.documentName || '未知文档' }}
diff --git a/apps/web-antd/src/views/ai/knowledge/segment/data.ts b/apps/web-antd/src/views/ai/knowledge/segment/data.ts index 0f4a8cdbe..109adda2c 100644 --- a/apps/web-antd/src/views/ai/knowledge/segment/data.ts +++ b/apps/web-antd/src/views/ai/knowledge/segment/data.ts @@ -1,7 +1,8 @@ import type { VbenFormSchema } from '#/adapter/form'; import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { AiKnowledgeSegmentApi } from '#/api/ai/knowledge/segment'; -import { DICT_TYPE } from '@vben/constants'; +import { CommonStatusEnum, DICT_TYPE } from '@vben/constants'; import { getDictOptions } from '@vben/hooks'; /** 新增/修改的表单 */ @@ -43,12 +44,17 @@ export function useGridFormSchema(): VbenFormSchema[] { fieldName: 'documentId', label: '文档编号', component: 'Input', + componentProps: { + placeholder: '请输入文档编号', + allowClear: true, + }, }, { fieldName: 'status', label: '是否启用', component: 'Select', componentProps: { + placeholder: '请选择是否启用', allowClear: true, options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'), }, @@ -57,11 +63,17 @@ export function useGridFormSchema(): VbenFormSchema[] { } /** 列表的字段 */ -export function useGridColumns(): VxeTableGridOptions['columns'] { +export function useGridColumns( + onStatusChange?: ( + newStatus: number, + row: AiKnowledgeSegmentApi.KnowledgeSegment, + ) => PromiseLike, +): VxeTableGridOptions['columns'] { return [ { field: 'id', title: '分段编号', + minWidth: 100, }, { type: 'expand', @@ -76,23 +88,36 @@ export function useGridColumns(): VxeTableGridOptions['columns'] { { field: 'contentLength', title: '字符数', + minWidth: 100, }, { field: 'tokens', title: 'token 数量', + minWidth: 120, }, { field: 'retrievalCount', title: '召回次数', + minWidth: 100, }, { field: 'status', - title: '是否启用', - slots: { default: 'status' }, + title: '状态', + minWidth: 100, + align: 'center', + cellRender: { + attrs: { beforeChange: onStatusChange }, + name: 'CellSwitch', + props: { + checkedValue: CommonStatusEnum.ENABLE, + unCheckedValue: CommonStatusEnum.DISABLE, + }, + }, }, { field: 'createTime', title: '创建时间', + minWidth: 180, formatter: 'formatDateTime', }, { diff --git a/apps/web-antd/src/views/ai/knowledge/segment/index.vue b/apps/web-antd/src/views/ai/knowledge/segment/index.vue index e5797dce8..4533882cf 100644 --- a/apps/web-antd/src/views/ai/knowledge/segment/index.vue +++ b/apps/web-antd/src/views/ai/knowledge/segment/index.vue @@ -5,11 +5,11 @@ import type { AiKnowledgeSegmentApi } from '#/api/ai/knowledge/segment'; import { onMounted } from 'vue'; import { useRoute } from 'vue-router'; -import { useAccess } from '@vben/access'; import { confirm, Page, useVbenModal } from '@vben/common-ui'; -import { CommonStatusEnum } from '@vben/constants'; +import { DICT_TYPE } from '@vben/constants'; +import { getDictLabel } from '@vben/hooks'; -import { message, Switch } from 'ant-design-vue'; +import { message } from 'ant-design-vue'; import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; import { @@ -23,7 +23,7 @@ import { useGridColumns, useGridFormSchema } from './data'; import Form from './modules/form.vue'; const route = useRoute(); -const { hasAccessByCodes } = useAccess(); + const [FormModal, formModalApi] = useVbenModal({ connectedComponent: Form, destroyOnClose: true, @@ -34,17 +34,17 @@ function handleRefresh() { gridApi.query(); } -/** 创建 */ +/** 创建知识库片段 */ function handleCreate() { formModalApi.setData({ documentId: route.query.documentId }).open(); } -/** 编辑 */ +/** 编辑知识库片段 */ function handleEdit(row: AiKnowledgeSegmentApi.KnowledgeSegment) { formModalApi.setData(row).open(); } -/** 删除 */ +/** 删除知识库片段 */ async function handleDelete(row: AiKnowledgeSegmentApi.KnowledgeSegment) { const hideLoading = message.loading({ content: $t('ui.actionMessage.deleting', [row.id]), @@ -52,21 +52,41 @@ async function handleDelete(row: AiKnowledgeSegmentApi.KnowledgeSegment) { }); try { await deleteKnowledgeSegment(row.id as number); - message.success({ - content: $t('ui.actionMessage.deleteSuccess', [row.id]), - }); + message.success($t('ui.actionMessage.deleteSuccess', [row.id])); handleRefresh(); } finally { hideLoading(); } } +/** 更新知识库片段状态 */ +async function handleStatusChange( + newStatus: number, + row: AiKnowledgeSegmentApi.KnowledgeSegment, +): Promise { + return new Promise((resolve, reject) => { + confirm({ + content: `你要将片段 ${row.id} 的状态切换为【${getDictLabel(DICT_TYPE.COMMON_STATUS, newStatus)}】吗?`, + }) + .then(async () => { + // 更新片段状态 + await updateKnowledgeSegmentStatus(row.id!, newStatus); + // 提示并返回成功 + message.success($t('ui.actionMessage.operationSuccess')); + resolve(true); + }) + .catch(() => { + reject(new Error('取消操作')); + }); + }); +} + const [Grid, gridApi] = useVbenVxeGrid({ formOptions: { schema: useGridFormSchema(), }, gridOptions: { - columns: useGridColumns(), + columns: useGridColumns(handleStatusChange), height: 'auto', keepSource: true, proxyConfig: { @@ -82,6 +102,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ }, rowConfig: { keyField: 'id', + isHover: true, }, toolbarConfig: { refresh: true, @@ -90,26 +111,7 @@ const [Grid, gridApi] = useVbenVxeGrid({ } as VxeTableGridOptions, }); -/** 修改是否发布 */ -async function handleStatusChange(row: AiKnowledgeSegmentApi.KnowledgeSegment) { - try { - // 修改状态的二次确认 - const text = row.status ? '启用' : '禁用'; - await confirm(`确认要"${text}"该分段吗?`).then(async () => { - await updateKnowledgeSegmentStatus({ - id: row.id, - status: row.status, - }); - gridApi.reload(); - }); - } catch { - row.status = - row.status === CommonStatusEnum.ENABLE - ? CommonStatusEnum.DISABLE - : CommonStatusEnum.ENABLE; - } -} - +/** 初始化 */ onMounted(() => { gridApi.formApi.setFieldValue('documentId', route.query.documentId); }); @@ -132,15 +134,6 @@ onMounted(() => { ]" /> - + diff --git a/apps/web-antd/src/views/mall/promotion/components/app-link-input/app-link-select-dialog.vue b/apps/web-antd/src/views/mall/promotion/components/app-link-input/select-dialog.vue similarity index 87% rename from apps/web-antd/src/views/mall/promotion/components/app-link-input/app-link-select-dialog.vue rename to apps/web-antd/src/views/mall/promotion/components/app-link-input/select-dialog.vue index 949087212..27405557b 100644 --- a/apps/web-antd/src/views/mall/promotion/components/app-link-input/app-link-select-dialog.vue +++ b/apps/web-antd/src/views/mall/promotion/components/app-link-input/select-dialog.vue @@ -3,11 +3,12 @@ import type { AppLink } from './data'; import { nextTick, ref } from 'vue'; +import { useVbenModal } from '@vben/common-ui'; import { getUrlNumberValue } from '@vben/utils'; -import { Button, Form, FormItem, Modal, Tooltip } from 'ant-design-vue'; +import { Button, Form, FormItem, Tooltip } from 'ant-design-vue'; -import ProductCategorySelect from '#/views/mall/product/category/components/product-category-select.vue'; +import { ProductCategorySelect } from '#/views/mall/product/category/components/'; import { APP_LINK_GROUP_LIST, APP_LINK_TYPE_ENUM } from './data'; @@ -30,21 +31,31 @@ const groupBtnRefs = ref([]); // 分组引用列表 const detailSelectDialog = ref<{ id?: number; type?: APP_LINK_TYPE_ENUM; - visible: boolean; }>({ - visible: false, id: undefined, type: undefined, }); // 详情选择对话框 -const dialogVisible = ref(false); +const [Modal, modalApi] = useVbenModal({ + onConfirm() { + emit('change', activeAppLink.value.path); + emit('appLinkChange', activeAppLink.value); + modalApi.close(); + }, +}); + +const [DetailSelectModal, detailSelectModalApi] = useVbenModal({ + onConfirm() { + detailSelectModalApi.close(); + }, +}); defineExpose({ open }); /** 打开弹窗 */ async function open(link: string) { activeAppLink.value.path = link; - dialogVisible.value = true; + modalApi.open(); // 滚动到当前的链接 const group = APP_LINK_GROUP_LIST.find((group) => group.links.some((linkItem) => { @@ -76,7 +87,7 @@ function handleAppLinkSelected(appLink: AppLink) { 'id', `http://127.0.0.1${activeAppLink.value.path}`, ) || undefined; - detailSelectDialog.value.visible = true; + detailSelectModalApi.open(); break; } default: { @@ -85,13 +96,6 @@ function handleAppLinkSelected(appLink: AppLink) { } } -/** 处理确认提交 */ -function handleSubmit() { - emit('change', activeAppLink.value.path); - emit('appLinkChange', activeAppLink.value); - dialogVisible.value = false; -} - /** * 处理右侧链接列表滚动 * @@ -138,7 +142,7 @@ function scrollToGroupBtn(group: string) { /** 是否为相同的链接(不比较参数,只比较链接) */ function isSameLink(link1: string, link2: string) { - return link2 ? link1.split('?')[0] === link2.split('?')[0] : false; + return link2 ? link1?.split('?')[0] === link2.split('?')[0] : false; } /** 处理详情选择 */ @@ -149,17 +153,12 @@ function handleProductCategorySelected(id: number) { activeAppLink.value.path = `${url.pathname}${url.search}`; // 关闭对话框,并重置 id - detailSelectDialog.value.visible = false; + detailSelectModalApi.close(); detailSelectDialog.value.id = undefined; } - - diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container-property.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container-property.vue index 38c475f75..37cc1ac46 100644 --- a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container-property.vue +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container-property.vue @@ -133,11 +133,16 @@ function handleSliderChange(prop: string) { +

组件样式:

- + 纯色 图片 @@ -146,11 +151,17 @@ function handleSliderChange(prop: string) { - + - + - + - - diff --git a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container.vue b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container.vue index 6f05d921a..26fac3f7c 100644 --- a/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container.vue +++ b/apps/web-antd/src/views/mall/promotion/components/diy-editor/components/component-container.vue @@ -49,6 +49,7 @@ const emits = defineEmits<{ type DiyComponentWithStyle = DiyComponent & { property: { style?: ComponentStyle }; }; + /** 组件样式 */ const style = computed(() => { const componentStyle = props.component.property.style; @@ -108,6 +109,8 @@ const handleDeleteComponent = () => { class="component-toolbar" v-if="showToolbar && component.name && active" > + +
+ 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);