feat: 账号配置表格头部接入KtTable

This commit is contained in:
sunlei 2026-06-07 22:57:34 +08:00
parent 01743cfc18
commit 5af4b4d297
3 changed files with 143 additions and 169 deletions

View File

@ -32,6 +32,14 @@ const AKtTable = KtTable as any;
const ASpin = Spin as any;
const ATabs = Tabs as any;
const configTabItems = [
{ key: 'command', label: '在线命令' },
{ key: 'event', label: '事件触发' },
{ key: 'rule', label: '自动回复规则' },
] as const;
type ConfigTabKey = (typeof configTabItems)[number]['key'];
export default defineComponent({
name: 'QqBotAccountConfigPanel',
props: {
@ -41,7 +49,7 @@ export default defineComponent({
},
},
setup(props) {
const activeTab = ref('command');
const activeTab = ref<ConfigTabKey>('command');
const boundCommands = ref<QqbotApi.Command[]>([]);
const boundRules = ref<QqbotApi.Rule[]>([]);
const commandTemplates = ref<QqbotApi.Command[]>([]);
@ -167,6 +175,28 @@ export default defineComponent({
rowVisible: (row) => boundRuleIds.value.has(row.id),
},
];
const activeColumns = computed(() => {
if (activeTab.value === 'event') return eventColumns;
if (activeTab.value === 'rule') return ruleColumns;
return commandColumns;
});
const activeRows = computed(() => {
if (activeTab.value === 'event') return eventPlugins.value;
if (activeTab.value === 'rule') return mergedRuleTemplates.value;
return mergedCommandTemplates.value;
});
const activeRowActions = computed(() => {
if (activeTab.value === 'event') return eventRowActions;
if (activeTab.value === 'rule') return ruleRowActions;
return commandRowActions;
});
const activeRowKey = computed(() => {
if (activeTab.value === 'event') {
return (row: QqbotApi.EventPlugin) =>
`${currentSelfId.value}:${row.key}`;
}
return 'id';
});
watch(
currentSelfId,
@ -319,149 +349,106 @@ export default defineComponent({
);
};
const renderCommandTable = () => {
const renderTableTitle = () => {
return (
<AKtTable
class="qqbot-account-config-panel__table"
columns={commandColumns}
dataSource={mergedCommandTemplates.value}
rowActions={commandRowActions}
rowKey="id"
showDefaultButtons={false}
showFooter={false}
showHeader={false}
showIndex={false}
showPagination={false}
showTableSetting={false}
size="small"
v-slots={{
bodyCell: ({ column, record }: any) => {
const row = record as QqbotApi.Command;
const bound = boundCommandIds.value.has(row.id);
if (column.key === 'aliases') {
return row.aliases?.join(' / ') || '-';
}
if (column.key === 'targetType') {
return getOptionLabel(qqbotRuleTargetOptions, row.targetType);
}
if (column.key === 'enabled') {
return renderEnabledTag(row.enabled);
}
if (column.key === 'bound') {
return renderBoundTag(bound);
}
return undefined;
},
}}
/>
<div class="qqbot-account-config-panel__table-title">
<span></span>
<Tag color="processing">{`Self ID${currentSelfId.value || '-'}`}</Tag>
{props.account?.name ? <Tag>{props.account.name}</Tag> : null}
</div>
);
};
const renderEventTable = () => {
const renderHeaderControls = () => {
return (
<AKtTable
class="qqbot-account-config-panel__table"
columns={eventColumns}
dataSource={eventPlugins.value}
rowActions={eventRowActions}
rowKey={(row: QqbotApi.EventPlugin) =>
`${currentSelfId.value}:${row.key}`
}
showDefaultButtons={false}
showFooter={false}
showHeader={false}
showIndex={false}
showPagination={false}
showTableSetting={false}
size="small"
v-slots={{
bodyCell: ({ column, record }: any) => {
const row = record as QqbotApi.EventPlugin;
if (column.key === 'triggerType') {
return row.triggerType === 'message'
? '消息事件'
: row.triggerType;
}
if (column.key === 'bound') {
return renderBoundTag(row.bound);
}
return undefined;
},
}}
/>
<div class="kt-table__header-control-group">
<ATabs
class="kt-table__header-tabs"
items={[...configTabItems]}
v-model:activeKey={activeTab.value}
/>
</div>
);
};
const renderRuleTable = () => {
return (
<AKtTable
class="qqbot-account-config-panel__table"
columns={ruleColumns}
dataSource={mergedRuleTemplates.value}
rowActions={ruleRowActions}
rowKey="id"
showDefaultButtons={false}
showFooter={false}
showHeader={false}
showIndex={false}
showPagination={false}
showTableSetting={false}
size="small"
v-slots={{
bodyCell: ({ column, record }: any) => {
const row = record as QqbotApi.Rule;
const bound = boundRuleIds.value.has(row.id);
if (column.key === 'matchType') {
return getOptionLabel(qqbotRuleMatchOptions, row.matchType);
}
if (column.key === 'targetType') {
return getOptionLabel(qqbotRuleTargetOptions, row.targetType);
}
if (column.key === 'replyContent') {
return (
<span class="qqbot-account-config-panel__ellipsis">
{row.replyContent || '-'}
</span>
);
}
if (column.key === 'enabled') {
return renderEnabledTag(row.enabled);
}
if (column.key === 'bound') {
return renderBoundTag(bound);
}
return undefined;
},
}}
/>
);
const renderBodyCell = ({ column, record }: any) => {
if (activeTab.value === 'event') {
const row = record as QqbotApi.EventPlugin;
if (column.key === 'triggerType') {
return row.triggerType === 'message' ? '消息事件' : row.triggerType;
}
if (column.key === 'bound') {
return renderBoundTag(row.bound);
}
return undefined;
}
if (activeTab.value === 'rule') {
const row = record as QqbotApi.Rule;
const bound = boundRuleIds.value.has(row.id);
if (column.key === 'matchType') {
return getOptionLabel(qqbotRuleMatchOptions, row.matchType);
}
if (column.key === 'targetType') {
return getOptionLabel(qqbotRuleTargetOptions, row.targetType);
}
if (column.key === 'replyContent') {
return (
<span class="qqbot-account-config-panel__ellipsis">
{row.replyContent || '-'}
</span>
);
}
if (column.key === 'enabled') {
return renderEnabledTag(row.enabled);
}
if (column.key === 'bound') {
return renderBoundTag(bound);
}
return undefined;
}
const row = record as QqbotApi.Command;
const bound = boundCommandIds.value.has(row.id);
if (column.key === 'aliases') {
return row.aliases?.join(' / ') || '-';
}
if (column.key === 'targetType') {
return getOptionLabel(qqbotRuleTargetOptions, row.targetType);
}
if (column.key === 'enabled') {
return renderEnabledTag(row.enabled);
}
if (column.key === 'bound') {
return renderBoundTag(bound);
}
return undefined;
};
return () => (
<div class="qqbot-account-config-panel">
<div class="qqbot-account-config-panel__account">
<Tag color="processing">Self ID{currentSelfId.value || '-'}</Tag>
{props.account?.name ? <Tag>{props.account.name}</Tag> : null}
<div class="qqbot-account-config-panel__spin">
<ASpin spinning={loading.value}>
<AKtTable
class="qqbot-account-config-panel__table"
columns={activeColumns.value}
dataSource={activeRows.value}
rowActions={activeRowActions.value}
rowKey={activeRowKey.value}
showDefaultButtons={false}
showFooter={false}
showIndex={false}
showPagination={false}
showTableSetting={false}
size="small"
v-slots={{
bodyCell: renderBodyCell,
headerControls: renderHeaderControls,
title: renderTableTitle,
}}
/>
</ASpin>
</div>
<ATabs
class="qqbot-account-config-panel__tabs"
items={[
{ key: 'command', label: '在线命令' },
{ key: 'event', label: '事件触发' },
{ key: 'rule', label: '自动回复规则' },
]}
v-model:activeKey={activeTab.value}
/>
<ASpin
class="qqbot-account-config-panel__spin"
spinning={loading.value}
>
<div class="qqbot-account-config-panel__content">
{activeTab.value === 'command' ? renderCommandTable() : null}
{activeTab.value === 'event' ? renderEventTable() : null}
{activeTab.value === 'rule' ? renderRuleTable() : null}
</div>
</ASpin>
</div>
);
},

View File

@ -33,24 +33,14 @@
font-weight: 600;
}
&__card {
&__content {
flex: 1;
min-height: 0;
}
&__card,
&__card > .ant-card-body {
display: flex;
flex-direction: column;
min-height: 0;
}
&__card > .ant-card-body {
flex: 1;
}
&__card .ant-spin-nested-loading,
&__card .ant-spin-container {
&__content,
&__content > .ant-spin-nested-loading,
&__content > .ant-spin-nested-loading > .ant-spin-container {
display: flex;
flex: 1 1 0;
flex-direction: column;
@ -65,19 +55,9 @@
flex-direction: column;
min-height: 0;
&__account {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 10px;
}
&__tabs {
flex: none;
}
&__spin,
&__spin > .ant-spin-container {
&__spin > .ant-spin-nested-loading,
&__spin > .ant-spin-nested-loading > .ant-spin-container {
display: flex;
flex: 1 1 0;
flex-direction: column;
@ -85,19 +65,19 @@
min-height: 0;
}
&__content {
display: flex;
flex: 1;
min-width: 0;
min-height: 0;
overflow: hidden;
}
&__table {
flex: 1 1 0;
width: 100%;
min-width: 0;
min-height: 0;
.kt-table__header {
margin-bottom: 8px;
}
.kt-table__main-content {
padding: 12px;
}
}
&__ellipsis {
@ -108,4 +88,12 @@
vertical-align: bottom;
white-space: nowrap;
}
&__table-title {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
min-width: 0;
}
}

View File

@ -6,7 +6,7 @@ import { useRoute, useRouter } from 'vue-router';
import { Page } from '@vben/common-ui';
import { ArrowLeft } from '@vben/icons';
import { Alert, Button, Card, Spin, Tag } from 'antdv-next';
import { Alert, Button, Spin, Tag } from 'antdv-next';
import { getQqbotAccountList } from '#/api/qqbot';
@ -15,7 +15,6 @@ import AccountConfigPanel from './components/AccountConfigPanel';
import './config.scss';
const AButton = Button as any;
const ACard = Card as any;
const ASpin = Spin as any;
export default defineComponent({
@ -112,7 +111,7 @@ export default defineComponent({
</div>
</div>
<ACard class="qqbot-account-config__card" variant="borderless">
<div class="qqbot-account-config__content">
<ASpin spinning={loading.value}>
{errorMessage.value ? (
<Alert message={errorMessage.value} showIcon type="warning" />
@ -120,7 +119,7 @@ export default defineComponent({
<AccountConfigPanel account={account.value} />
)}
</ASpin>
</ACard>
</div>
</div>
</Page>
);