feat: 定义消息推送前端契约
This commit is contained in:
parent
25a5bc3499
commit
edb77bd67c
@ -391,4 +391,57 @@ describe('core menu api', () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('keeps every supported message-push menu name once while filtering unknown nodes', async () => {
|
||||
const messagePushNames = [
|
||||
'QqBotMessageSubscription',
|
||||
'QqBotMessageTemplate',
|
||||
'QqBotMessageSubscriptionList',
|
||||
'QqBotMessageSubscriptionCreate',
|
||||
'QqBotMessageSubscriptionUpdate',
|
||||
'QqBotMessageSubscriptionDelete',
|
||||
'QqBotMessageSubscriptionToggle',
|
||||
'QqBotMessageTemplateList',
|
||||
'QqBotMessageTemplateCreate',
|
||||
'QqBotMessageTemplateUpdate',
|
||||
'QqBotMessageTemplateDelete',
|
||||
'QqBotMessageTemplateToggle',
|
||||
'QqBotMessageTemplatePreview',
|
||||
'QqBotAccountMessagePushList',
|
||||
'QqBotAccountMessagePushCreate',
|
||||
'QqBotAccountMessagePushUpdate',
|
||||
'QqBotAccountMessagePushDelete',
|
||||
'QqBotAccountMessagePushToggle',
|
||||
];
|
||||
requestClientGet.mockResolvedValue([
|
||||
{
|
||||
name: 'QqBot',
|
||||
path: '/qqbot',
|
||||
children: [
|
||||
{
|
||||
name: 'QqBotAccount',
|
||||
path: '/qqbot/account',
|
||||
},
|
||||
...messagePushNames.map((name) => ({
|
||||
authCode: `QqBot:${name}`,
|
||||
name,
|
||||
type: 'button',
|
||||
})),
|
||||
{
|
||||
name: 'UnsupportedMessagePushNode',
|
||||
type: 'button',
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const { getAllMenusApi } = await import('./menu');
|
||||
const menus = await getAllMenusApi();
|
||||
const qqbot = menus.find((menu) => menu.name === 'QqBot');
|
||||
const retainedNames = qqbot?.children?.map((child) => child.name) ?? [];
|
||||
|
||||
expect(retainedNames).toEqual(['QqBotAccount', ...messagePushNames]);
|
||||
expect(new Set(retainedNames).size).toBe(retainedNames.length);
|
||||
expect(retainedNames).not.toContain('UnsupportedMessagePushNode');
|
||||
});
|
||||
});
|
||||
|
||||
@ -33,6 +33,11 @@ const SUPPORTED_ADMIN_MENU_NAMES = new Set([
|
||||
'QqBotAccountDelete',
|
||||
'QqBotAccountEdit',
|
||||
'QqBotAccountKick',
|
||||
'QqBotAccountMessagePushCreate',
|
||||
'QqBotAccountMessagePushDelete',
|
||||
'QqBotAccountMessagePushList',
|
||||
'QqBotAccountMessagePushToggle',
|
||||
'QqBotAccountMessagePushUpdate',
|
||||
'QqBotAccountNapcatWebui',
|
||||
'QqBotAccountRefreshLogin',
|
||||
'QqBotAccountWebUI',
|
||||
@ -45,6 +50,19 @@ const SUPPORTED_ADMIN_MENU_NAMES = new Set([
|
||||
'QqBotConversation',
|
||||
'QqBotDashboard',
|
||||
'QqBotMessage',
|
||||
'QqBotMessageSubscription',
|
||||
'QqBotMessageSubscriptionCreate',
|
||||
'QqBotMessageSubscriptionDelete',
|
||||
'QqBotMessageSubscriptionList',
|
||||
'QqBotMessageSubscriptionToggle',
|
||||
'QqBotMessageSubscriptionUpdate',
|
||||
'QqBotMessageTemplate',
|
||||
'QqBotMessageTemplateCreate',
|
||||
'QqBotMessageTemplateDelete',
|
||||
'QqBotMessageTemplateList',
|
||||
'QqBotMessageTemplatePreview',
|
||||
'QqBotMessageTemplateToggle',
|
||||
'QqBotMessageTemplateUpdate',
|
||||
'QqBotPermission',
|
||||
'QqBotPermissionCreate',
|
||||
'QqBotPermissionDelete',
|
||||
|
||||
224
apps/web-antdv-next/src/api/qqbot/message-push.spec.ts
Normal file
224
apps/web-antdv-next/src/api/qqbot/message-push.spec.ts
Normal file
@ -0,0 +1,224 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
import * as messagePushApi from './message-push';
|
||||
import {
|
||||
createAccountMessagePushBinding,
|
||||
createMessageSubscription,
|
||||
createMessageTemplate,
|
||||
deleteAccountMessagePushBinding,
|
||||
deleteMessageSubscription,
|
||||
deleteMessageTemplate,
|
||||
getAccountMessagePushBindings,
|
||||
getAccountMessagePushTargets,
|
||||
getMessagePushSourceDetail,
|
||||
getMessagePushSources,
|
||||
getMessageSubscriptionList,
|
||||
getMessageTemplateList,
|
||||
getStunMappingPortChangedOptions,
|
||||
previewMessageTemplate,
|
||||
setAccountMessagePushBindingEnabled,
|
||||
setMessageSubscriptionEnabled,
|
||||
setMessageTemplateEnabled,
|
||||
updateAccountMessagePushBinding,
|
||||
updateMessageSubscription,
|
||||
updateMessageTemplate,
|
||||
} from './message-push';
|
||||
|
||||
vi.mock('#/api/request', () => ({
|
||||
requestClient: {
|
||||
delete: vi.fn(),
|
||||
get: vi.fn(),
|
||||
post: vi.fn(),
|
||||
put: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('qqbot message push api', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('owns the exact source, subscription, and template callers', async () => {
|
||||
const sourceKey = 'network.stun/a b';
|
||||
const id = '10000000000000001';
|
||||
const previewContent = '端口 $' + '{{port}}';
|
||||
const subscriptionInput = {
|
||||
enabled: true,
|
||||
name: 'STUN 端口变更',
|
||||
sourceConfig: {
|
||||
ddnsRecordId: '10000000000000003',
|
||||
portForwardId: '10000000000000002',
|
||||
},
|
||||
sourceKey: 'network.stun.mapping-port-changed',
|
||||
};
|
||||
const templateInput = {
|
||||
content: previewContent,
|
||||
enabled: true,
|
||||
name: '端口通知',
|
||||
sourceKey: 'network.stun.mapping-port-changed',
|
||||
};
|
||||
const subscriptionQuery = {
|
||||
enabled: true,
|
||||
name: 'STUN',
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
sourceKey: 'network.stun.mapping-port-changed',
|
||||
};
|
||||
const templateQuery = {
|
||||
enabled: false,
|
||||
name: '通知',
|
||||
pageNo: 2,
|
||||
pageSize: 20,
|
||||
sourceKey: 'network.stun.mapping-port-changed',
|
||||
};
|
||||
|
||||
await getMessagePushSources();
|
||||
await getMessagePushSourceDetail(sourceKey);
|
||||
await getStunMappingPortChangedOptions();
|
||||
await getMessageSubscriptionList(subscriptionQuery);
|
||||
await createMessageSubscription(subscriptionInput);
|
||||
await updateMessageSubscription('id/a b', subscriptionInput);
|
||||
await setMessageSubscriptionEnabled(id, false);
|
||||
await deleteMessageSubscription('id/a b');
|
||||
await getMessageTemplateList(templateQuery);
|
||||
await createMessageTemplate(templateInput);
|
||||
await updateMessageTemplate('template/a b', templateInput);
|
||||
await setMessageTemplateEnabled(id, false);
|
||||
await deleteMessageTemplate('template/a b');
|
||||
await previewMessageTemplate({
|
||||
content: previewContent,
|
||||
sourceKey: 'network.stun.mapping-port-changed',
|
||||
});
|
||||
|
||||
expect(requestClient.get).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'/qqbot/message-push/sources',
|
||||
);
|
||||
expect(requestClient.get).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'/qqbot/message-push/sources/network.stun%2Fa%20b',
|
||||
);
|
||||
expect(requestClient.get).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
'/qqbot/message-push/sources/network.stun.mapping-port-changed/options',
|
||||
);
|
||||
expect(requestClient.get).toHaveBeenNthCalledWith(
|
||||
4,
|
||||
'/qqbot/message-push/subscriptions',
|
||||
{ params: subscriptionQuery },
|
||||
);
|
||||
expect(requestClient.get).toHaveBeenNthCalledWith(
|
||||
5,
|
||||
'/qqbot/message-push/templates',
|
||||
{ params: templateQuery },
|
||||
);
|
||||
expect(requestClient.post).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'/qqbot/message-push/subscriptions',
|
||||
subscriptionInput,
|
||||
);
|
||||
expect(requestClient.post).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'/qqbot/message-push/templates',
|
||||
templateInput,
|
||||
);
|
||||
expect(requestClient.post).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
'/qqbot/message-push/templates/preview',
|
||||
{
|
||||
content: previewContent,
|
||||
sourceKey: 'network.stun.mapping-port-changed',
|
||||
},
|
||||
);
|
||||
expect(requestClient.put).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'/qqbot/message-push/subscriptions/id%2Fa%20b',
|
||||
subscriptionInput,
|
||||
);
|
||||
expect(requestClient.put).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'/qqbot/message-push/subscriptions/10000000000000001/enabled',
|
||||
{ enabled: false },
|
||||
);
|
||||
expect(requestClient.put).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
'/qqbot/message-push/templates/template%2Fa%20b',
|
||||
templateInput,
|
||||
);
|
||||
expect(requestClient.put).toHaveBeenNthCalledWith(
|
||||
4,
|
||||
'/qqbot/message-push/templates/10000000000000001/enabled',
|
||||
{ enabled: false },
|
||||
);
|
||||
expect(requestClient.delete).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
'/qqbot/message-push/subscriptions/id%2Fa%20b',
|
||||
);
|
||||
expect(requestClient.delete).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
'/qqbot/message-push/templates/template%2Fa%20b',
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps account IDs as strings and encodes every account path segment', async () => {
|
||||
const selfId = '10000000000000001/a b';
|
||||
const bindingId = 'binding/a b';
|
||||
const bindingInput = {
|
||||
enabled: true,
|
||||
subscriptionId: '10000000000000002',
|
||||
targets: [
|
||||
{
|
||||
targetId: '10000000000000003',
|
||||
targetName: '测试群',
|
||||
targetType: 'group' as const,
|
||||
},
|
||||
],
|
||||
templateId: '10000000000000004',
|
||||
};
|
||||
|
||||
await getAccountMessagePushBindings(selfId);
|
||||
await createAccountMessagePushBinding(selfId, bindingInput);
|
||||
await updateAccountMessagePushBinding(selfId, bindingId, bindingInput);
|
||||
await setAccountMessagePushBindingEnabled(selfId, bindingId, false);
|
||||
await deleteAccountMessagePushBinding(selfId, bindingId);
|
||||
await getAccountMessagePushTargets(selfId);
|
||||
|
||||
const accountPath =
|
||||
'/qqbot/accounts/10000000000000001%2Fa%20b/message-push';
|
||||
expect(requestClient.get).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
`${accountPath}/bindings`,
|
||||
);
|
||||
expect(requestClient.get).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
`${accountPath}/targets`,
|
||||
);
|
||||
expect(requestClient.post).toHaveBeenCalledWith(
|
||||
`${accountPath}/bindings`,
|
||||
bindingInput,
|
||||
);
|
||||
expect(requestClient.put).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
`${accountPath}/bindings/binding%2Fa%20b`,
|
||||
bindingInput,
|
||||
);
|
||||
expect(requestClient.put).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
`${accountPath}/bindings/binding%2Fa%20b/enabled`,
|
||||
{ enabled: false },
|
||||
);
|
||||
expect(requestClient.delete).toHaveBeenCalledWith(
|
||||
`${accountPath}/bindings/binding%2Fa%20b`,
|
||||
);
|
||||
});
|
||||
|
||||
it('does not expose internal publish, event, delivery, or worker callers', () => {
|
||||
expect(Object.keys(messagePushApi)).not.toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringMatching(/delivery|event|publish|worker/i),
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
447
apps/web-antdv-next/src/api/qqbot/message-push.ts
Normal file
447
apps/web-antdv-next/src/api/qqbot/message-push.ts
Normal file
@ -0,0 +1,447 @@
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace QqbotMessagePushApi {
|
||||
export type SystemMessageScalar = boolean | null | number | string;
|
||||
|
||||
export type QqbotMessagePushTargetType = 'group' | 'private';
|
||||
|
||||
export interface SystemMessageSourceVariableDefinition {
|
||||
description: string;
|
||||
example: string;
|
||||
key: string;
|
||||
label: string;
|
||||
type: 'boolean' | 'number' | 'string';
|
||||
}
|
||||
|
||||
export interface SystemMessageSourceFieldDefinition {
|
||||
dependsOn?: string;
|
||||
key: string;
|
||||
label: string;
|
||||
optionCollection: 'ddnsRecords' | 'portForwards';
|
||||
required: true;
|
||||
type: 'select';
|
||||
}
|
||||
|
||||
export interface SystemMessageSourceDefinition {
|
||||
description: string;
|
||||
displayName: string;
|
||||
sourceKey: string;
|
||||
subscriptionFields: SystemMessageSourceFieldDefinition[];
|
||||
variables: SystemMessageSourceVariableDefinition[];
|
||||
version: 1;
|
||||
}
|
||||
|
||||
export interface StunMappingPortChangedSubscriptionConfig {
|
||||
ddnsRecordId: string;
|
||||
portForwardId: string;
|
||||
}
|
||||
|
||||
export interface StunMappingPortChangedOptionsResponse {
|
||||
ddnsRecords: Array<{
|
||||
disabledReasonCode: null | string;
|
||||
eligible: boolean;
|
||||
fqdn: string;
|
||||
id: string;
|
||||
name: string;
|
||||
portForwardId: string;
|
||||
}>;
|
||||
portForwards: Array<{
|
||||
disabledReasonCode: null | string;
|
||||
eligible: boolean;
|
||||
externalPort: number;
|
||||
id: string;
|
||||
internalPort: number;
|
||||
name: string;
|
||||
protocol: 'tcp' | 'udp';
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface MessageSubscriptionView {
|
||||
createTime: string;
|
||||
enabled: boolean;
|
||||
id: string;
|
||||
invalidReasonCode: null | string;
|
||||
name: string;
|
||||
remark: null | string;
|
||||
sourceConfig: StunMappingPortChangedSubscriptionConfig;
|
||||
sourceKey: string;
|
||||
sourceName: string;
|
||||
sourceSummary: string;
|
||||
updateTime: string;
|
||||
valid: boolean;
|
||||
}
|
||||
|
||||
export interface MessageSubscriptionListQuery {
|
||||
enabled?: boolean;
|
||||
name?: string;
|
||||
pageNo?: number;
|
||||
pageSize?: number;
|
||||
sourceKey?: string;
|
||||
}
|
||||
|
||||
export interface MessageSubscriptionInput {
|
||||
enabled: boolean;
|
||||
name: string;
|
||||
remark?: string;
|
||||
sourceConfig: Record<string, unknown>;
|
||||
sourceKey: string;
|
||||
}
|
||||
|
||||
export interface MessageTemplateView {
|
||||
content: string;
|
||||
createTime: string;
|
||||
enabled: boolean;
|
||||
id: string;
|
||||
name: string;
|
||||
referenceCount: number;
|
||||
remark: null | string;
|
||||
sourceKey: string;
|
||||
sourceName: string;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
export interface MessageTemplateListQuery {
|
||||
enabled?: boolean;
|
||||
name?: string;
|
||||
pageNo?: number;
|
||||
pageSize?: number;
|
||||
sourceKey?: string;
|
||||
}
|
||||
|
||||
export interface MessageTemplateInput {
|
||||
content: string;
|
||||
enabled: boolean;
|
||||
name: string;
|
||||
remark?: string;
|
||||
sourceKey: string;
|
||||
}
|
||||
|
||||
export interface MessageTemplatePreviewInput {
|
||||
content: string;
|
||||
sourceKey: string;
|
||||
}
|
||||
|
||||
export interface MessageTemplatePreview {
|
||||
renderedMessage: string;
|
||||
variables: Record<string, boolean | number | string>;
|
||||
}
|
||||
|
||||
export interface QqbotMessagePublishTargetInput {
|
||||
targetId: string;
|
||||
targetName?: string;
|
||||
targetType: QqbotMessagePushTargetType;
|
||||
}
|
||||
|
||||
export interface QqbotMessagePublishBindingInput {
|
||||
enabled: boolean;
|
||||
subscriptionId: string;
|
||||
targets: QqbotMessagePublishTargetInput[];
|
||||
templateId: string;
|
||||
}
|
||||
|
||||
export interface QqbotMessagePushTargetOption {
|
||||
label: string;
|
||||
targetId: string;
|
||||
targetType: QqbotMessagePushTargetType;
|
||||
}
|
||||
|
||||
export interface QqbotMessagePushTargetOptionsResponse {
|
||||
available: boolean;
|
||||
options: QqbotMessagePushTargetOption[];
|
||||
reasonCode: null | string;
|
||||
}
|
||||
|
||||
export interface QqbotMessagePublishTargetView {
|
||||
enabled: boolean;
|
||||
id: string;
|
||||
targetId: string;
|
||||
targetName: null | string;
|
||||
targetType: QqbotMessagePushTargetType;
|
||||
}
|
||||
|
||||
export interface QqbotMessagePublishBindingView {
|
||||
available: boolean;
|
||||
createTime: string;
|
||||
enabled: boolean;
|
||||
id: string;
|
||||
invalidReasonCode: null | string;
|
||||
sourceKey: string;
|
||||
sourceName: string;
|
||||
subscriptionId: string;
|
||||
subscriptionName: string;
|
||||
targets: QqbotMessagePublishTargetView[];
|
||||
templateId: string;
|
||||
templateName: string;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
export interface PageResult<T> {
|
||||
items: T[];
|
||||
total: number;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists registered system message sources available to the Admin UI.
|
||||
* @returns Public source definitions without internal adapter details.
|
||||
*/
|
||||
export function getMessagePushSources() {
|
||||
return requestClient.get<QqbotMessagePushApi.SystemMessageSourceDefinition[]>(
|
||||
'/qqbot/message-push/sources',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads one public source definition by its stable source key.
|
||||
* @param sourceKey - String source identity, encoded before becoming a URL segment.
|
||||
* @returns The requested source definition.
|
||||
*/
|
||||
export function getMessagePushSourceDetail(sourceKey: string) {
|
||||
return requestClient.get<QqbotMessagePushApi.SystemMessageSourceDefinition>(
|
||||
`/qqbot/message-push/sources/${encodeURIComponent(sourceKey)}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads server-evaluated options for the built-in STUN port-change source.
|
||||
* @returns Eligible and disabled port-forward and DDNS options.
|
||||
*/
|
||||
export function getStunMappingPortChangedOptions() {
|
||||
return requestClient.get<QqbotMessagePushApi.StunMappingPortChangedOptionsResponse>(
|
||||
'/qqbot/message-push/sources/network.stun.mapping-port-changed/options',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pages global message subscriptions using independent list filters.
|
||||
* @param params - Pagination, source, name, and enabled-state filters.
|
||||
* @returns A strict `{ items, total }` subscription page.
|
||||
*/
|
||||
export function getMessageSubscriptionList(
|
||||
params: QqbotMessagePushApi.MessageSubscriptionListQuery,
|
||||
) {
|
||||
return requestClient.get<
|
||||
QqbotMessagePushApi.PageResult<QqbotMessagePushApi.MessageSubscriptionView>
|
||||
>('/qqbot/message-push/subscriptions', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates one source-scoped global message subscription.
|
||||
* @param data - Complete subscription name, source, configuration, and enabled state.
|
||||
* @returns The persisted subscription view.
|
||||
*/
|
||||
export function createMessageSubscription(
|
||||
data: QqbotMessagePushApi.MessageSubscriptionInput,
|
||||
) {
|
||||
return requestClient.post<QqbotMessagePushApi.MessageSubscriptionView>(
|
||||
'/qqbot/message-push/subscriptions',
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces one global subscription without coercing its string ID.
|
||||
* @param id - Stable subscription ID, encoded before becoming a URL segment.
|
||||
* @param data - Complete replacement subscription input.
|
||||
* @returns The updated subscription view.
|
||||
*/
|
||||
export function updateMessageSubscription(
|
||||
id: string,
|
||||
data: QqbotMessagePushApi.MessageSubscriptionInput,
|
||||
) {
|
||||
return requestClient.put<QqbotMessagePushApi.MessageSubscriptionView>(
|
||||
`/qqbot/message-push/subscriptions/${encodeURIComponent(id)}`,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes whether a subscription matches future source events.
|
||||
* @param id - Stable subscription ID, encoded before becoming a URL segment.
|
||||
* @param enabled - Requested future enabled state.
|
||||
* @returns The updated subscription view.
|
||||
*/
|
||||
export function setMessageSubscriptionEnabled(id: string, enabled: boolean) {
|
||||
return requestClient.put<QqbotMessagePushApi.MessageSubscriptionView>(
|
||||
`/qqbot/message-push/subscriptions/${encodeURIComponent(id)}/enabled`,
|
||||
{ enabled },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft-deletes one global message subscription.
|
||||
* @param id - Stable subscription ID, encoded before becoming a URL segment.
|
||||
* @returns Whether the subscription was deleted.
|
||||
*/
|
||||
export function deleteMessageSubscription(id: string) {
|
||||
return requestClient.delete<boolean>(
|
||||
`/qqbot/message-push/subscriptions/${encodeURIComponent(id)}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pages global message templates using independent list filters.
|
||||
* @param params - Pagination, source, name, and enabled-state filters.
|
||||
* @returns A strict `{ items, total }` template page.
|
||||
*/
|
||||
export function getMessageTemplateList(
|
||||
params: QqbotMessagePushApi.MessageTemplateListQuery,
|
||||
) {
|
||||
return requestClient.get<
|
||||
QqbotMessagePushApi.PageResult<QqbotMessagePushApi.MessageTemplateView>
|
||||
>('/qqbot/message-push/templates', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates one source-scoped global message template.
|
||||
* @param data - Complete template content, source, metadata, and enabled state.
|
||||
* @returns The persisted template view.
|
||||
*/
|
||||
export function createMessageTemplate(
|
||||
data: QqbotMessagePushApi.MessageTemplateInput,
|
||||
) {
|
||||
return requestClient.post<QqbotMessagePushApi.MessageTemplateView>(
|
||||
'/qqbot/message-push/templates',
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces one global message template without coercing its string ID.
|
||||
* @param id - Stable template ID, encoded before becoming a URL segment.
|
||||
* @param data - Complete replacement template input.
|
||||
* @returns The updated template view.
|
||||
*/
|
||||
export function updateMessageTemplate(
|
||||
id: string,
|
||||
data: QqbotMessagePushApi.MessageTemplateInput,
|
||||
) {
|
||||
return requestClient.put<QqbotMessagePushApi.MessageTemplateView>(
|
||||
`/qqbot/message-push/templates/${encodeURIComponent(id)}`,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes whether a template can be selected for future bindings and events.
|
||||
* @param id - Stable template ID, encoded before becoming a URL segment.
|
||||
* @param enabled - Requested future enabled state.
|
||||
* @returns The updated template view.
|
||||
*/
|
||||
export function setMessageTemplateEnabled(id: string, enabled: boolean) {
|
||||
return requestClient.put<QqbotMessagePushApi.MessageTemplateView>(
|
||||
`/qqbot/message-push/templates/${encodeURIComponent(id)}/enabled`,
|
||||
{ enabled },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft-deletes one global message template when the backend permits it.
|
||||
* @param id - Stable template ID, encoded before becoming a URL segment.
|
||||
* @returns Whether the template was deleted.
|
||||
*/
|
||||
export function deleteMessageTemplate(id: string) {
|
||||
return requestClient.delete<boolean>(
|
||||
`/qqbot/message-push/templates/${encodeURIComponent(id)}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a source-scoped message template using server-controlled example data.
|
||||
* @param data - Template content and source identity only.
|
||||
* @returns Safe rendered text and the example variables used.
|
||||
*/
|
||||
export function previewMessageTemplate(
|
||||
data: QqbotMessagePushApi.MessageTemplatePreviewInput,
|
||||
) {
|
||||
return requestClient.post<QqbotMessagePushApi.MessageTemplatePreview>(
|
||||
'/qqbot/message-push/templates/preview',
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists message-push bindings belonging to exactly one QQBot account.
|
||||
* @param selfId - QQBot self ID kept as a string and encoded in the URL.
|
||||
* @returns Account-scoped binding views with their configured targets.
|
||||
*/
|
||||
export function getAccountMessagePushBindings(selfId: string) {
|
||||
return requestClient.get<
|
||||
QqbotMessagePushApi.QqbotMessagePublishBindingView[]
|
||||
>(`/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/bindings`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates one account-scoped binding from a global subscription and template.
|
||||
* @param selfId - QQBot self ID kept as a string and encoded in the URL.
|
||||
* @param data - Subscription, template, target, and enabled-state input.
|
||||
* @returns The persisted account binding view.
|
||||
*/
|
||||
export function createAccountMessagePushBinding(
|
||||
selfId: string,
|
||||
data: QqbotMessagePushApi.QqbotMessagePublishBindingInput,
|
||||
) {
|
||||
return requestClient.post<QqbotMessagePushApi.QqbotMessagePublishBindingView>(
|
||||
`/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/bindings`,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces one binding for exactly one QQBot account.
|
||||
* @param selfId - QQBot self ID kept as a string and encoded in the URL.
|
||||
* @param id - Stable binding ID, encoded before becoming a URL segment.
|
||||
* @param data - Subscription, template, target, and enabled-state input.
|
||||
* @returns The updated account binding view.
|
||||
*/
|
||||
export function updateAccountMessagePushBinding(
|
||||
selfId: string,
|
||||
id: string,
|
||||
data: QqbotMessagePushApi.QqbotMessagePublishBindingInput,
|
||||
) {
|
||||
return requestClient.put<QqbotMessagePushApi.QqbotMessagePublishBindingView>(
|
||||
`/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/bindings/${encodeURIComponent(id)}`,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes whether one account binding creates future delivery work.
|
||||
* @param selfId - QQBot self ID kept as a string and encoded in the URL.
|
||||
* @param id - Stable binding ID, encoded before becoming a URL segment.
|
||||
* @param enabled - Requested future enabled state.
|
||||
* @returns The updated account binding view.
|
||||
*/
|
||||
export function setAccountMessagePushBindingEnabled(
|
||||
selfId: string,
|
||||
id: string,
|
||||
enabled: boolean,
|
||||
) {
|
||||
return requestClient.put<QqbotMessagePushApi.QqbotMessagePublishBindingView>(
|
||||
`/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/bindings/${encodeURIComponent(id)}/enabled`,
|
||||
{ enabled },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft-deletes one binding from exactly one QQBot account.
|
||||
* @param selfId - QQBot self ID kept as a string and encoded in the URL.
|
||||
* @param id - Stable binding ID, encoded before becoming a URL segment.
|
||||
* @returns Whether the account binding was deleted.
|
||||
*/
|
||||
export function deleteAccountMessagePushBinding(selfId: string, id: string) {
|
||||
return requestClient.delete<boolean>(
|
||||
`/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/bindings/${encodeURIComponent(id)}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists group and private-message target choices for exactly one QQBot account.
|
||||
* @param selfId - QQBot self ID kept as a string and encoded in the URL.
|
||||
* @returns Availability state plus currently discoverable string-ID targets.
|
||||
*/
|
||||
export function getAccountMessagePushTargets(selfId: string) {
|
||||
return requestClient.get<QqbotMessagePushApi.QqbotMessagePushTargetOptionsResponse>(
|
||||
`/qqbot/accounts/${encodeURIComponent(selfId)}/message-push/targets`,
|
||||
);
|
||||
}
|
||||
34
apps/web-antdv-next/src/router/routes/modules/qqbot.spec.ts
Normal file
34
apps/web-antdv-next/src/router/routes/modules/qqbot.spec.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('qqbot routes', () => {
|
||||
it('adds two flat message-push route children without loading future pages', () => {
|
||||
const source = readFileSync(
|
||||
'apps/web-antdv-next/src/router/routes/modules/qqbot.ts',
|
||||
'utf8',
|
||||
);
|
||||
|
||||
for (const [name, path, componentPath, title] of [
|
||||
[
|
||||
'QqBotMessageSubscription',
|
||||
'/qqbot/message-subscription',
|
||||
'#/views/qqbot/message-subscription/list',
|
||||
'消息订阅',
|
||||
],
|
||||
[
|
||||
'QqBotMessageTemplate',
|
||||
'/qqbot/message-template',
|
||||
'#/views/qqbot/message-template/list',
|
||||
'消息模板',
|
||||
],
|
||||
] as const) {
|
||||
expect(source).toMatch(
|
||||
new RegExp(
|
||||
String.raw`\{\s*component: \(\) => import\('${componentPath}'\),\s*meta: \{\s*icon: 'lucide:[^']+',\s*title: '${title}',\s*\},\s*name: '${name}',\s*path: '${path}',\s*\}`,
|
||||
's',
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -112,6 +112,24 @@ const routes: RouteRecordRaw[] = [
|
||||
name: 'QqBotSendLog',
|
||||
path: '/qqbot/sendLog',
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/qqbot/message-subscription/list'),
|
||||
meta: {
|
||||
icon: 'lucide:bell-ring',
|
||||
title: '消息订阅',
|
||||
},
|
||||
name: 'QqBotMessageSubscription',
|
||||
path: '/qqbot/message-subscription',
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/qqbot/message-template/list'),
|
||||
meta: {
|
||||
icon: 'lucide:message-square-plus',
|
||||
title: '消息模板',
|
||||
},
|
||||
name: 'QqBotMessageTemplate',
|
||||
path: '/qqbot/message-template',
|
||||
},
|
||||
{
|
||||
component: () => import('#/views/qqbot/permission/list'),
|
||||
meta: {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user