From 01743cfc184f725b9458c4dfcb163f25dc695999 Mon Sep 17 00:00:00 2001 From: sunlei Date: Sun, 7 Jun 2026 21:32:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B4=A6=E5=8F=B7=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=8E=A5=E5=85=A5KtTable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/ktTable/KtTable.tsx | 3 +- .../ktTable/hooks/useKtTableActions.tsx | 15 ++ .../src/components/ktTable/types.ts | 3 + .../account/components/AccountConfigPanel.tsx | 210 ++++++++---------- .../src/views/qqbot/account/config.scss | 30 ++- .../src/views/qqbot/account/config.tsx | 2 +- 6 files changed, 140 insertions(+), 123 deletions(-) diff --git a/apps/web-antdv-next/src/components/ktTable/KtTable.tsx b/apps/web-antdv-next/src/components/ktTable/KtTable.tsx index 316d038..bbb4d13 100644 --- a/apps/web-antdv-next/src/components/ktTable/KtTable.tsx +++ b/apps/web-antdv-next/src/components/ktTable/KtTable.tsx @@ -175,6 +175,7 @@ export default defineComponent({ const permissions = useKtTablePermission(context); const { formButtons, + getVisibleRowActions, headerButtons, renderButton, renderRowAction, @@ -720,7 +721,7 @@ export default defineComponent({ */ const renderActionCell = (record: KtTableRecord) => { const { inlineActions, overflowActions } = splitRowActions( - rowActions.value, + getVisibleRowActions(record), ); return ( diff --git a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.tsx b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.tsx index f348626..587c2d1 100644 --- a/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.tsx +++ b/apps/web-antdv-next/src/components/ktTable/hooks/useKtTableActions.tsx @@ -167,6 +167,20 @@ export function useKtTableActions(options: UseKtTableActionsOptions) { await runHook('onAfterAction', action, result, context); } + /** + * 按当前行过滤行操作,支持同一列按行状态展示不同按钮。 + * + * @param row 当前行数据。 + */ + function getVisibleRowActions(row: KtTableRecord) { + return rowActions.value.filter((action) => { + const { rowVisible } = action; + if (typeof rowVisible === 'function') return rowVisible(row, context); + if (typeof rowVisible === 'boolean') return rowVisible; + return true; + }); + } + /** * 按配置决定是否弹出确认框后再执行行操作。 * @@ -239,6 +253,7 @@ export function useKtTableActions(options: UseKtTableActionsOptions) { return { formButtons, + getVisibleRowActions, headerButtons, renderButton, renderRowAction: renderRowAction as ( diff --git a/apps/web-antdv-next/src/components/ktTable/types.ts b/apps/web-antdv-next/src/components/ktTable/types.ts index 49625c6..dcc68db 100644 --- a/apps/web-antdv-next/src/components/ktTable/types.ts +++ b/apps/web-antdv-next/src/components/ktTable/types.ts @@ -104,6 +104,9 @@ export interface KtTableRowAction< row: Row, context: KtTableContext, ) => Promise | void; + rowVisible?: + | ((row: Row, context: KtTableContext) => boolean) + | boolean; } export interface KtTableStatistic< diff --git a/apps/web-antdv-next/src/views/qqbot/account/components/AccountConfigPanel.tsx b/apps/web-antdv-next/src/views/qqbot/account/components/AccountConfigPanel.tsx index f4b8213..6689074 100644 --- a/apps/web-antdv-next/src/views/qqbot/account/components/AccountConfigPanel.tsx +++ b/apps/web-antdv-next/src/views/qqbot/account/components/AccountConfigPanel.tsx @@ -1,18 +1,13 @@ +import type { TableColumnType } from 'antdv-next'; + import type { PropType } from 'vue'; import type { QqbotApi } from '#/api/qqbot'; +import type { KtTableRowAction } from '#/components/ktTable'; import { computed, defineComponent, ref, watch } from 'vue'; -import { - Button, - message, - Popconfirm, - Space, - Table, - Tabs, - Tag, -} from 'antdv-next'; +import { message, Spin, Tabs, Tag } from 'antdv-next'; import { bindQqbotAccountCommand, @@ -25,6 +20,7 @@ import { unbindQqbotAccountRule, unbindQqbotEventPlugin, } from '#/api/qqbot'; +import { KtTable } from '#/components/ktTable'; import { getOptionLabel, @@ -32,10 +28,8 @@ import { qqbotRuleTargetOptions, } from '../../modules/options'; -const AButton = Button as any; -const APopconfirm = Popconfirm as any; -const ASpace = Space as any; -const ATable = Table as any; +const AKtTable = KtTable as any; +const ASpin = Spin as any; const ATabs = Tabs as any; export default defineComponent({ @@ -69,7 +63,7 @@ export default defineComponent({ mergeById(ruleTemplates.value, boundRules.value), ); - const commandColumns = [ + const commandColumns: Array> = [ { dataIndex: 'name', key: 'name', title: '命令模板', width: 160 }, { dataIndex: 'code', key: 'code', title: '命令编码', width: 140 }, { dataIndex: 'aliases', key: 'aliases', title: '别名', width: 200 }, @@ -82,15 +76,24 @@ export default defineComponent({ }, { dataIndex: 'enabled', key: 'enabled', title: '模板状态', width: 100 }, { dataIndex: 'bound', key: 'bound', title: '绑定状态', width: 100 }, + ]; + const commandRowActions: Array> = [ { - dataIndex: 'action', - fixed: 'right', - key: 'action', - title: '操作', - width: 100, + key: 'bind', + label: '绑定', + onClick: async (row) => handleCommandBind(row), + rowVisible: (row) => !boundCommandIds.value.has(row.id), + }, + { + confirm: (row) => `确认从当前账号解绑「${row.name || row.code}」吗?`, + danger: true, + key: 'unbind', + label: '解绑', + onClick: async (row) => handleCommandUnbind(row), + rowVisible: (row) => boundCommandIds.value.has(row.id), }, ]; - const eventColumns = [ + const eventColumns: Array> = [ { dataIndex: 'name', key: 'name', title: '插件模板', width: 160 }, { dataIndex: 'key', key: 'key', title: '插件 Key', width: 160 }, { @@ -106,15 +109,24 @@ export default defineComponent({ width: 320, }, { dataIndex: 'bound', key: 'bound', title: '绑定状态', width: 100 }, + ]; + const eventRowActions: Array> = [ { - dataIndex: 'action', - fixed: 'right', - key: 'action', - title: '操作', - width: 100, + key: 'bind', + label: '绑定', + onClick: async (row) => handleEventBind(row), + rowVisible: (row) => !row.bound, + }, + { + confirm: (row) => `确认从当前账号解绑「${row.name}」吗?`, + danger: true, + key: 'unbind', + label: '解绑', + onClick: async (row) => handleEventUnbind(row), + rowVisible: (row) => row.bound, }, ]; - const ruleColumns = [ + const ruleColumns: Array> = [ { dataIndex: 'name', key: 'name', title: '规则模板', width: 160 }, { dataIndex: 'keyword', key: 'keyword', title: '关键词', width: 180 }, { @@ -137,12 +149,22 @@ export default defineComponent({ }, { dataIndex: 'enabled', key: 'enabled', title: '模板状态', width: 100 }, { dataIndex: 'bound', key: 'bound', title: '绑定状态', width: 100 }, + ]; + const ruleRowActions: Array> = [ { - dataIndex: 'action', - fixed: 'right', - key: 'action', - title: '操作', - width: 100, + key: 'bind', + label: '绑定', + onClick: async (row) => handleRuleBind(row), + rowVisible: (row) => !boundRuleIds.value.has(row.id), + }, + { + confirm: (row) => + `确认从当前账号解绑「${row.name || row.keyword}」吗?`, + danger: true, + key: 'unbind', + label: '解绑', + onClick: async (row) => handleRuleUnbind(row), + rowVisible: (row) => boundRuleIds.value.has(row.id), }, ]; @@ -161,7 +183,6 @@ export default defineComponent({ }, { immediate: true }, ); - async function refreshAll() { loading.value = true; try { @@ -282,32 +303,6 @@ export default defineComponent({ return [...map.values()]; } - const renderBindAction = (options: { - bound: boolean; - name: string; - onBind: () => Promise; - onUnbind: () => Promise; - }) => { - if (!options.bound) { - return ( - - 绑定 - - ); - } - - return ( - - - 解绑 - - - ); - }; - const renderBoundTag = (bound: boolean) => { return ( @@ -326,13 +321,18 @@ export default defineComponent({ const renderCommandTable = () => { return ( -