mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-02-13 00:10:27 +00:00
feat: 新版webui
This commit is contained in:
84
napcat.webui/src/const/ob_api/message/group.ts
Normal file
84
napcat.webui/src/const/ob_api/message/group.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { z } from 'zod'
|
||||
import type { ZodSchema } from 'zod'
|
||||
|
||||
import { baseResponseSchema, commonResponseDataSchema } from '../response'
|
||||
import messageNodeSchema, { nodeMessage } from './node'
|
||||
|
||||
const oneBotHttpApiMessageGroup: Record<
|
||||
string,
|
||||
{
|
||||
description?: string
|
||||
request: ZodSchema
|
||||
response: ZodSchema
|
||||
}
|
||||
> = {
|
||||
'/send_group_msg': {
|
||||
description: '发送群消息',
|
||||
request: z
|
||||
.object({
|
||||
group_id: z
|
||||
.union([z.string(), z.number()])
|
||||
.describe('群号')
|
||||
.describe('群号'),
|
||||
message: z.array(messageNodeSchema).describe('消息内容')
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
const hasReply = data.message.some((item) => item.type === 'reply')
|
||||
|
||||
if (hasReply) {
|
||||
return data.message[0].type === 'reply'
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
{
|
||||
message:
|
||||
'如果 message 包含 reply 类型的消息,那么只能包含一个,而且排在最前面'
|
||||
}
|
||||
),
|
||||
response: baseResponseSchema.extend({
|
||||
data: commonResponseDataSchema
|
||||
})
|
||||
},
|
||||
'/send_group_forward_msg': {
|
||||
description: '发送群合并转发消息',
|
||||
request: z.object({
|
||||
group_id: z.union([z.string(), z.number()]).describe('群号'),
|
||||
messages: z.array(nodeMessage).describe('消息内容'),
|
||||
news: z
|
||||
.array(
|
||||
z.object({
|
||||
text: z.string()
|
||||
})
|
||||
)
|
||||
.describe('?'),
|
||||
prompt: z.string().describe('外显'),
|
||||
summary: z.string().describe('底下文本'),
|
||||
source: z.string().describe('内容')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: commonResponseDataSchema
|
||||
})
|
||||
},
|
||||
'/forward_group_single_msg': {
|
||||
description: '消息转发到群',
|
||||
request: z.object({
|
||||
group_id: z.union([z.string(), z.number()]).describe('群号'),
|
||||
message_id: z.union([z.string(), z.number()]).describe('消息 ID')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: commonResponseDataSchema
|
||||
})
|
||||
},
|
||||
'/group_poke': {
|
||||
description: '发送戳一戳',
|
||||
request: z.object({
|
||||
group_id: z.union([z.string(), z.number()]).describe('群号'),
|
||||
user_id: z.union([z.string(), z.number()]).describe('对方QQ号')
|
||||
}),
|
||||
response: baseResponseSchema
|
||||
}
|
||||
}
|
||||
|
||||
export default oneBotHttpApiMessageGroup
|
||||
269
napcat.webui/src/const/ob_api/message/index.ts
Normal file
269
napcat.webui/src/const/ob_api/message/index.ts
Normal file
@@ -0,0 +1,269 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
import { baseResponseSchema, commonResponseDataSchema } from '../response'
|
||||
import oneBotHttpApiMessageGroup from './group'
|
||||
import messageNodeSchema from './node'
|
||||
import oneBotHttpApiMessagePrivate from './private'
|
||||
|
||||
const fileSchema = z
|
||||
.object({
|
||||
file: z.string().describe('路径或链接'),
|
||||
url: z.string().describe('路径或链接'),
|
||||
file_size: z.string().describe('文件大小'),
|
||||
file_name: z.string().describe('文件名'),
|
||||
base64: z.string().describe('文件base64编码')
|
||||
})
|
||||
.describe('文件')
|
||||
const messageSchema = z
|
||||
.object({
|
||||
self_id: z.number().describe('自己QQ号'),
|
||||
user_id: z.number().describe('发送人QQ号'),
|
||||
time: z.number().describe('发送时间'),
|
||||
message_id: z.number().describe('消息ID'),
|
||||
message_seq: z.number().describe('消息序号'),
|
||||
real_id: z.number().describe('?ID'),
|
||||
message_type: z.string().describe('消息类型'),
|
||||
sender: z
|
||||
.object({
|
||||
user_id: z.number().describe('发送人QQ号'),
|
||||
nickname: z.string().describe('昵称'),
|
||||
sex: z.enum(['male', 'female', 'unknown']).describe('性别'),
|
||||
age: z.number().describe('年龄'),
|
||||
card: z.string().describe('名片'),
|
||||
role: z.enum(['owner', 'admin', 'member']).describe('角色')
|
||||
})
|
||||
.describe('发送人信息'),
|
||||
raw_message: z.string().describe('原始消息'),
|
||||
font: z.number().describe('字体'),
|
||||
sub_type: z.string().describe('子类型'),
|
||||
message: z.array(messageNodeSchema).describe('消息内容'),
|
||||
message_format: z.string().describe('消息格式'),
|
||||
post_type: z.string().describe('?'),
|
||||
message_sent_type: z.string().describe('消息发送类型'),
|
||||
group_id: z.number().describe('群号')
|
||||
})
|
||||
.describe('消息')
|
||||
|
||||
const oneBotHttpApiMessage = {
|
||||
...oneBotHttpApiMessagePrivate,
|
||||
...oneBotHttpApiMessageGroup,
|
||||
'/mark_msg_as_read': {
|
||||
description: '标记消息已读',
|
||||
request: z
|
||||
.object({
|
||||
group_id: z
|
||||
.union([z.string(), z.number()])
|
||||
.optional()
|
||||
.describe('群号,与 user_id 二选一'),
|
||||
user_id: z
|
||||
.union([z.string(), z.number()])
|
||||
.optional()
|
||||
.describe('用户QQ号,与 group_id 二选一')
|
||||
})
|
||||
.refine(
|
||||
(data) =>
|
||||
(data.group_id && !data.user_id) || (!data.group_id && data.user_id),
|
||||
{
|
||||
message: 'group_id 和 user_id 必须二选一,且不能同时存在或同时为空',
|
||||
path: ['group_id', 'user_id']
|
||||
}
|
||||
),
|
||||
response: baseResponseSchema
|
||||
},
|
||||
'/mark_group_msg_as_read': {
|
||||
description: '标记群消息已读',
|
||||
request: z.object({
|
||||
group_id: z.union([z.string(), z.number()]).describe('群号')
|
||||
}),
|
||||
response: baseResponseSchema
|
||||
},
|
||||
'/mark_private_msg_as_read': {
|
||||
description: '标记私聊消息已读',
|
||||
request: z.object({
|
||||
user_id: z.union([z.string(), z.number()]).describe('用户QQ号')
|
||||
}),
|
||||
response: baseResponseSchema
|
||||
},
|
||||
'/_mark_all_as_read': {
|
||||
description: '标记所有消息已读',
|
||||
request: z.object({}),
|
||||
response: baseResponseSchema
|
||||
},
|
||||
'/delete_msg': {
|
||||
description: '撤回消息',
|
||||
request: z.object({
|
||||
message_id: z.union([z.string(), z.number()]).describe('消息ID')
|
||||
}),
|
||||
response: baseResponseSchema
|
||||
},
|
||||
'/get_msg': {
|
||||
description: '获取消息',
|
||||
request: z.object({
|
||||
message_id: z.union([z.string(), z.number()]).describe('消息ID')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: z.object({})
|
||||
})
|
||||
},
|
||||
'/get_image': {
|
||||
description: '获取图片',
|
||||
request: z.object({
|
||||
file_id: z.string().describe('文件ID')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: fileSchema
|
||||
})
|
||||
},
|
||||
'/get_record': {
|
||||
description: '获取语音',
|
||||
request: z.object({
|
||||
file_id: z.string().describe('文件ID'),
|
||||
out_format: z
|
||||
.enum(['mp3', 'amr', 'wma', 'm4a', 'spx', 'ogg', 'wav', 'flac'])
|
||||
.describe('输出格式')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: fileSchema
|
||||
})
|
||||
},
|
||||
'/get_file': {
|
||||
description: '获取文件',
|
||||
request: z.object({
|
||||
file_id: z.string().describe('文件ID')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: fileSchema
|
||||
})
|
||||
},
|
||||
'/get_group_msg_history': {
|
||||
description: '获取群消息历史',
|
||||
request: z.object({
|
||||
group_id: z.union([z.string(), z.number()]).describe('群号'),
|
||||
message_seq: z.union([z.string(), z.number()]).describe('消息序号'),
|
||||
count: z.number().int().positive().describe('获取数量'),
|
||||
reverseOrder: z.boolean().describe('是否倒序')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: z.object({
|
||||
messages: z.array(messageSchema).describe('消息列表')
|
||||
})
|
||||
})
|
||||
},
|
||||
'/set_msg_emoji_like': {
|
||||
description: '贴表情',
|
||||
request: z.object({
|
||||
message_id: z.union([z.string(), z.number()]).describe('消息ID'),
|
||||
emoji_id: z.number().describe('表情ID'),
|
||||
set: z.boolean().describe('?')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: commonResponseDataSchema
|
||||
})
|
||||
},
|
||||
'/get_friend_msg_history': {
|
||||
description: '获取好友消息历史',
|
||||
request: z.object({
|
||||
user_id: z.union([z.string(), z.number()]).describe('用户QQ号'),
|
||||
message_seq: z.union([z.string(), z.number()]).describe('消息序号'),
|
||||
count: z.number().int().positive().describe('获取数量'),
|
||||
reverseOrder: z.boolean().describe('是否倒序')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: z.object({
|
||||
messages: z.array(messageSchema)
|
||||
})
|
||||
})
|
||||
},
|
||||
'/get_recent_contact': {
|
||||
description: '最近消息列表',
|
||||
request: z.object({
|
||||
count: z.number().int().positive().describe('获取数量')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: z.array(
|
||||
z.object({
|
||||
lastestMsg: messageSchema,
|
||||
peerUin: z.string().describe('对方QQ号'),
|
||||
remark: z.string().describe('备注'),
|
||||
msgTime: z.string().describe('消息时间'),
|
||||
chatType: z.number().describe('聊天类型'),
|
||||
msgId: z.string().describe('消息ID'),
|
||||
sendNickName: z.string().describe('发送人昵称'),
|
||||
sendMemberName: z.string().describe('发送人?昵称'),
|
||||
peerName: z.string().describe('对方昵称')
|
||||
})
|
||||
)
|
||||
})
|
||||
},
|
||||
'/fetch_emoji_like': {
|
||||
description: '获取贴表情详情',
|
||||
request: z.object({
|
||||
message_id: z.union([z.string(), z.number()]).describe('消息ID'),
|
||||
emojiId: z.string().describe('表情ID'),
|
||||
emojiType: z.string().describe('表情类型'),
|
||||
group_id: z.union([z.string(), z.number()]).optional().describe('群号'),
|
||||
user_id: z
|
||||
.union([z.string(), z.number()])
|
||||
.optional()
|
||||
.describe('用户QQ号'),
|
||||
count: z.number().int().positive().optional().describe('获取数量')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: z.object({
|
||||
result: z.number().describe('结果'),
|
||||
errMsg: z.string().describe('错误信息'),
|
||||
emojiLikesList: z
|
||||
.array(
|
||||
z
|
||||
.object({
|
||||
tinyId: z.string().describe('表情ID'),
|
||||
nickName: z.string().describe('昵称?'),
|
||||
headUrl: z.string().describe('头像?')
|
||||
})
|
||||
.describe('表情点赞列表')
|
||||
)
|
||||
.describe('表情点赞列表'),
|
||||
cookie: z.string().describe('cookie'),
|
||||
isLastPage: z.boolean().describe('是否最后一页'),
|
||||
isFirstPage: z.boolean().describe('是否第一页')
|
||||
})
|
||||
})
|
||||
},
|
||||
'/get_forward_msg': {
|
||||
description: '获取合并转发消息',
|
||||
request: z.object({
|
||||
message_id: z.union([z.string(), z.number()]).describe('消息ID')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: z.object({})
|
||||
})
|
||||
},
|
||||
'/send_forward_msg': {
|
||||
description: '发送合并转发消息',
|
||||
request: z.object({
|
||||
group_id: z.union([z.string(), z.number()]).optional().describe('群号'),
|
||||
user_id: z
|
||||
.union([z.string(), z.number()])
|
||||
.optional()
|
||||
.describe('用户QQ号'),
|
||||
messages: z.array(messageNodeSchema).describe('消息内容'),
|
||||
news: z
|
||||
.array(
|
||||
z.object({
|
||||
text: z.string()
|
||||
})
|
||||
)
|
||||
.describe('?'),
|
||||
prompt: z.string().describe('外显'),
|
||||
summary: z.string().describe('底下文字'),
|
||||
source: z.string().describe('内容')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: commonResponseDataSchema.extend({
|
||||
data: z.object({})
|
||||
})
|
||||
})
|
||||
}
|
||||
} as const
|
||||
|
||||
export default oneBotHttpApiMessage
|
||||
119
napcat.webui/src/const/ob_api/message/node.ts
Normal file
119
napcat.webui/src/const/ob_api/message/node.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import { z } from 'zod'
|
||||
|
||||
const messageNode = z.union([
|
||||
z
|
||||
.object({
|
||||
type: z.literal('text'),
|
||||
data: z.object({
|
||||
text: z.string()
|
||||
})
|
||||
})
|
||||
.describe('文本消息'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('at'),
|
||||
data: z.object({
|
||||
qq: z.string()
|
||||
})
|
||||
})
|
||||
.describe('@某人'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('image'),
|
||||
data: z.object({
|
||||
file: z.string()
|
||||
})
|
||||
})
|
||||
.describe('图片消息'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('face'),
|
||||
data: z.object({
|
||||
id: z.number()
|
||||
})
|
||||
})
|
||||
.describe('表情消息'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('json'),
|
||||
data: z.object({
|
||||
data: z.string()
|
||||
})
|
||||
})
|
||||
.describe('json 卡片消息'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('record'),
|
||||
data: z.object({
|
||||
file: z.string()
|
||||
})
|
||||
})
|
||||
.describe('语音消息'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('video'),
|
||||
data: z.object({
|
||||
file: z.string()
|
||||
})
|
||||
})
|
||||
.describe('视频消息'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('reply'),
|
||||
data: z.object({
|
||||
id: z.number()
|
||||
})
|
||||
})
|
||||
.describe('回复消息'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('music'),
|
||||
data: z.union([
|
||||
z.object({
|
||||
type: z.enum(['qq', '163']),
|
||||
id: z.string()
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal('custom'),
|
||||
url: z.string(),
|
||||
audio: z.string(),
|
||||
title: z.string(),
|
||||
image: z.string()
|
||||
})
|
||||
])
|
||||
})
|
||||
.describe('音乐消息'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('dice')
|
||||
})
|
||||
.describe('掷骰子'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('rps')
|
||||
})
|
||||
.describe('猜拳'),
|
||||
z
|
||||
.object({
|
||||
type: z.literal('file'),
|
||||
data: z.object({
|
||||
file: z.string().describe('文件路径,服务器本地或者网络文件均可')
|
||||
})
|
||||
})
|
||||
.describe('发送消息')
|
||||
])
|
||||
|
||||
export const nodeMessage = z
|
||||
.object({
|
||||
type: z.literal('node'),
|
||||
data: z.object({
|
||||
user_id: z.string(),
|
||||
nickname: z.string(),
|
||||
content: z.array(messageNode)
|
||||
})
|
||||
})
|
||||
.describe('消息节点')
|
||||
|
||||
const messageNodeSchema = z.union([messageNode, nodeMessage])
|
||||
|
||||
export default messageNodeSchema
|
||||
80
napcat.webui/src/const/ob_api/message/private.ts
Normal file
80
napcat.webui/src/const/ob_api/message/private.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { z } from 'zod'
|
||||
import type { ZodSchema } from 'zod'
|
||||
|
||||
import { baseResponseSchema, commonResponseDataSchema } from '../response'
|
||||
import messageNodeSchema, { nodeMessage } from './node'
|
||||
|
||||
const oneBotHttpApiMessagePrivate: Record<
|
||||
string,
|
||||
{
|
||||
description?: string
|
||||
request: ZodSchema
|
||||
response: ZodSchema
|
||||
}
|
||||
> = {
|
||||
'/send_private_msg': {
|
||||
description: '发送私聊消息',
|
||||
request: z
|
||||
.object({
|
||||
user_id: z.union([z.string(), z.number()]).describe('对方QQ号'),
|
||||
message: z.array(messageNodeSchema).describe('消息内容')
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
const hasReply = data.message.some((item) => item.type === 'reply')
|
||||
|
||||
if (hasReply) {
|
||||
return data.message[0].type === 'reply'
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
{
|
||||
message:
|
||||
'如果 message 包含 reply 类型的消息,那么只能包含一个,而且排在最前面'
|
||||
}
|
||||
),
|
||||
response: baseResponseSchema.extend({
|
||||
data: commonResponseDataSchema
|
||||
})
|
||||
},
|
||||
'/send_private_forward_msg': {
|
||||
description: '发送私聊合并转发消息',
|
||||
request: z.object({
|
||||
user_id: z.union([z.string(), z.number()]).describe('对方QQ号'),
|
||||
messages: z.array(nodeMessage).describe('消息内容'),
|
||||
news: z
|
||||
.array(
|
||||
z.object({
|
||||
text: z.string()
|
||||
})
|
||||
)
|
||||
.describe('?'),
|
||||
prompt: z.string().describe('外显'),
|
||||
summary: z.string().describe('底下文本'),
|
||||
source: z.string().describe('内容')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: commonResponseDataSchema
|
||||
})
|
||||
},
|
||||
'/forward_friend_single_msg': {
|
||||
description: '消息转发到私聊',
|
||||
request: z.object({
|
||||
user_id: z.union([z.string(), z.number()]).describe('对方QQ号'),
|
||||
message_id: z.union([z.string(), z.number()]).describe('消息ID')
|
||||
}),
|
||||
response: baseResponseSchema.extend({
|
||||
data: commonResponseDataSchema
|
||||
})
|
||||
},
|
||||
'/group_poke': {
|
||||
description: '发送私聊戳一戳',
|
||||
request: z.object({
|
||||
user_id: z.union([z.string(), z.number()]).describe('对方QQ号')
|
||||
}),
|
||||
response: baseResponseSchema
|
||||
}
|
||||
}
|
||||
|
||||
export default oneBotHttpApiMessagePrivate
|
||||
Reference in New Issue
Block a user