mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2026-03-02 00:30:25 +00:00
feat: 新版webui
This commit is contained in:
122
napcat.webui/src/components/onebot/display_card/message.tsx
Normal file
122
napcat.webui/src/components/onebot/display_card/message.tsx
Normal file
@@ -0,0 +1,122 @@
|
||||
import { Avatar } from '@heroui/avatar'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { isOB11GroupMessage } from '@/utils/onebot'
|
||||
|
||||
import type {
|
||||
OB11GroupMessage,
|
||||
OB11Message,
|
||||
OB11PrivateMessage
|
||||
} from '@/types/onebot'
|
||||
|
||||
import { renderMessageContent } from '../render_message'
|
||||
|
||||
export interface OneBotMessageProps {
|
||||
data: OB11Message
|
||||
}
|
||||
|
||||
export interface OneBotMessageGroupProps {
|
||||
data: OB11GroupMessage
|
||||
}
|
||||
|
||||
export interface OneBotMessagePrivateProps {
|
||||
data: OB11PrivateMessage
|
||||
}
|
||||
|
||||
const MessageContent: React.FC<{ data: OB11Message }> = ({ data }) => {
|
||||
return (
|
||||
<div className="h-full flex flex-col overflow-hidden flex-1">
|
||||
<div className="flex gap-2 items-center flex-shrink-0">
|
||||
<div className="font-bold">
|
||||
{isOB11GroupMessage(data) && data.sender.card && (
|
||||
<span className="mr-1">{data.sender.card}</span>
|
||||
)}
|
||||
<span
|
||||
className={clsx(
|
||||
isOB11GroupMessage(data) &&
|
||||
data.sender.card &&
|
||||
'text-default-400 font-normal'
|
||||
)}
|
||||
>
|
||||
{data.sender.nickname}
|
||||
</span>
|
||||
</div>
|
||||
<div>({data.sender.user_id})</div>
|
||||
<div className="text-sm">消息ID: {data.message_id}</div>
|
||||
</div>
|
||||
<Popover showArrow triggerScaleOnOpen={false}>
|
||||
<PopoverTrigger>
|
||||
<div className="flex-1 break-all overflow-hidden whitespace-pre-wrap border border-default-100 p-2 rounded-md hover:bg-content2 md:cursor-pointer transition-background relative group">
|
||||
<div className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 text-default-300">
|
||||
点击查看完整消息
|
||||
</div>
|
||||
{Array.isArray(data.message)
|
||||
? renderMessageContent(data.message, true)
|
||||
: data.raw_message}
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<div className="p-2">
|
||||
{Array.isArray(data.message)
|
||||
? renderMessageContent(data.message)
|
||||
: data.raw_message}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const OneBotMessageGroup: React.FC<OneBotMessageGroupProps> = ({ data }) => {
|
||||
return (
|
||||
<div className="h-full overflow-hidden flex flex-col w-full">
|
||||
<div className="flex items-center p-1 flex-shrink-0">
|
||||
<Avatar
|
||||
src={`https://p.qlogo.cn/gh/${data.group_id}/${data.group_id}/640/`}
|
||||
alt="群头像"
|
||||
size="sm"
|
||||
className="flex-shrink-0 mr-2"
|
||||
/>
|
||||
<div>群 {data.group_id}</div>
|
||||
</div>
|
||||
<div className="flex items-start p-1 rounded-md h-full flex-1 border border-default-100">
|
||||
<Avatar
|
||||
src={`https://q1.qlogo.cn/g?b=qq&nk=${data.sender.user_id}&s=100`}
|
||||
alt="用户头像"
|
||||
size="md"
|
||||
className="flex-shrink-0 mr-2"
|
||||
/>
|
||||
<MessageContent data={data} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const OneBotMessagePrivate: React.FC<OneBotMessagePrivateProps> = ({
|
||||
data
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex items-start p-2 rounded-md h-full flex-1">
|
||||
<Avatar
|
||||
src={`https://q1.qlogo.cn/g?b=qq&nk=${data.sender.user_id}&s=100`}
|
||||
alt="用户头像"
|
||||
size="md"
|
||||
className="flex-shrink-0 mr-2"
|
||||
/>
|
||||
<MessageContent data={data} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const OneBotMessage: React.FC<OneBotMessageProps> = ({ data }) => {
|
||||
if (data.message_type === 'group') {
|
||||
return <OneBotMessageGroup data={data} />
|
||||
} else if (data.message_type === 'private') {
|
||||
return <OneBotMessagePrivate data={data} />
|
||||
} else {
|
||||
return <div>未知消息类型</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default OneBotMessage
|
||||
60
napcat.webui/src/components/onebot/display_card/meta.tsx
Normal file
60
napcat.webui/src/components/onebot/display_card/meta.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Chip } from '@heroui/chip'
|
||||
|
||||
import { getLifecycleColor, getLifecycleName } from '@/utils/onebot'
|
||||
|
||||
import type {
|
||||
OB11Meta,
|
||||
OneBot11Heartbeat,
|
||||
OneBot11Lifecycle
|
||||
} from '@/types/onebot'
|
||||
|
||||
export interface OneBotDisplayMetaProps {
|
||||
data: OB11Meta
|
||||
}
|
||||
|
||||
export interface OneBotDisplayMetaHeartbeatProps {
|
||||
data: OneBot11Heartbeat
|
||||
}
|
||||
|
||||
export interface OneBotDisplayMetaLifecycleProps {
|
||||
data: OneBot11Lifecycle
|
||||
}
|
||||
|
||||
const OneBotDisplayMetaHeartbeat: React.FC<OneBotDisplayMetaHeartbeatProps> = ({
|
||||
data
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex gap-2">
|
||||
<Chip>心跳</Chip>
|
||||
<Chip>间隔 {data.status.interval}ms</Chip>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const OneBotDisplayMetaLifecycle: React.FC<OneBotDisplayMetaLifecycleProps> = ({
|
||||
data
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex gap-2">
|
||||
<Chip>生命周期</Chip>
|
||||
<Chip color={getLifecycleColor(data.sub_type)}>
|
||||
{getLifecycleName(data.sub_type)}
|
||||
</Chip>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const OneBotDisplayMeta: React.FC<OneBotDisplayMetaProps> = ({ data }) => {
|
||||
return (
|
||||
<div className="h-full flex items-center">
|
||||
{data.meta_event_type === 'lifecycle' && (
|
||||
<OneBotDisplayMetaLifecycle data={data} />
|
||||
)}
|
||||
{data.meta_event_type === 'heartbeat' && (
|
||||
<OneBotDisplayMetaHeartbeat data={data} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OneBotDisplayMeta
|
||||
292
napcat.webui/src/components/onebot/display_card/notice.tsx
Normal file
292
napcat.webui/src/components/onebot/display_card/notice.tsx
Normal file
@@ -0,0 +1,292 @@
|
||||
import { Chip } from '@heroui/chip'
|
||||
|
||||
import { getNoticeTypeName } from '@/utils/onebot'
|
||||
|
||||
import {
|
||||
OB11Notice,
|
||||
OB11NoticeType,
|
||||
OneBot11FriendAdd,
|
||||
OneBot11FriendRecall,
|
||||
OneBot11GroupAdmin,
|
||||
OneBot11GroupBan,
|
||||
OneBot11GroupCard,
|
||||
OneBot11GroupDecrease,
|
||||
OneBot11GroupEssence,
|
||||
OneBot11GroupIncrease,
|
||||
OneBot11GroupMessageReaction,
|
||||
OneBot11GroupRecall,
|
||||
OneBot11GroupUpload,
|
||||
OneBot11Honor,
|
||||
OneBot11LuckyKing,
|
||||
OneBot11Poke
|
||||
} from '@/types/onebot'
|
||||
|
||||
export interface OneBotNoticeProps {
|
||||
data: OB11Notice
|
||||
}
|
||||
|
||||
export interface NoticeProps<T> {
|
||||
data: T
|
||||
}
|
||||
|
||||
const GroupUploadNotice: React.FC<NoticeProps<OneBot11GroupUpload>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { group_id, user_id, file } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>文件名: {file.name}</div>
|
||||
<div>文件大小: {file.size} 字节</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const GroupAdminNotice: React.FC<NoticeProps<OneBot11GroupAdmin>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { group_id, user_id, sub_type } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>变动类型: {sub_type === 'set' ? '设置管理员' : '取消管理员'}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const GroupDecreaseNotice: React.FC<NoticeProps<OneBot11GroupDecrease>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { group_id, operator_id, user_id, sub_type } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>操作者ID: {operator_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>原因: {sub_type}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const GroupIncreaseNotice: React.FC<NoticeProps<OneBot11GroupIncrease>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { group_id, operator_id, user_id, sub_type } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>操作者ID: {operator_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>增加类型: {sub_type}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const GroupBanNotice: React.FC<NoticeProps<OneBot11GroupBan>> = ({ data }) => {
|
||||
const { group_id, operator_id, user_id, sub_type, duration } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>操作者ID: {operator_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>禁言类型: {sub_type}</div>
|
||||
<div>禁言时长: {duration} 秒</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const FriendAddNotice: React.FC<NoticeProps<OneBot11FriendAdd>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { user_id } = data
|
||||
return (
|
||||
<>
|
||||
<div>用户ID: {user_id}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const GroupRecallNotice: React.FC<NoticeProps<OneBot11GroupRecall>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { group_id, user_id, operator_id, message_id } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>操作者ID: {operator_id}</div>
|
||||
<div>消息ID: {message_id}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const FriendRecallNotice: React.FC<NoticeProps<OneBot11FriendRecall>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { user_id, message_id } = data
|
||||
return (
|
||||
<>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>消息ID: {message_id}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const PokeNotice: React.FC<NoticeProps<OneBot11Poke>> = ({ data }) => {
|
||||
const { group_id, user_id, target_id } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>目标ID: {target_id}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const LuckyKingNotice: React.FC<NoticeProps<OneBot11LuckyKing>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { group_id, user_id, target_id } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>目标ID: {target_id}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const HonorNotice: React.FC<NoticeProps<OneBot11Honor>> = ({ data }) => {
|
||||
const { group_id, user_id, honor_type } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>荣誉类型: {honor_type}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const GroupMessageReactionNotice: React.FC<
|
||||
NoticeProps<OneBot11GroupMessageReaction>
|
||||
> = ({ data }) => {
|
||||
const { group_id, user_id, message_id, likes } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>消息ID: {message_id}</div>
|
||||
<div>
|
||||
表情回应:
|
||||
{likes
|
||||
.map((like) => `表情ID: ${like.emoji_id}, 数量: ${like.count}`)
|
||||
.join(', ')}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const GroupEssenceNotice: React.FC<NoticeProps<OneBot11GroupEssence>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { group_id, message_id, sender_id, operator_id, sub_type } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>消息ID: {message_id}</div>
|
||||
<div>发送者ID: {sender_id}</div>
|
||||
<div>操作者ID: {operator_id}</div>
|
||||
<div>操作类型: {sub_type}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const GroupCardNotice: React.FC<NoticeProps<OneBot11GroupCard>> = ({
|
||||
data
|
||||
}) => {
|
||||
const { group_id, user_id, card_new, card_old } = data
|
||||
return (
|
||||
<>
|
||||
<div>群号: {group_id}</div>
|
||||
<div>用户ID: {user_id}</div>
|
||||
<div>新名片: {card_new}</div>
|
||||
<div>旧名片: {card_old}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const OneBotNotice: React.FC<OneBotNoticeProps> = ({ data }) => {
|
||||
let NoticeComponent: React.ReactNode
|
||||
switch (data.notice_type) {
|
||||
case OB11NoticeType.GroupUpload:
|
||||
NoticeComponent = <GroupUploadNotice data={data} />
|
||||
break
|
||||
case OB11NoticeType.GroupAdmin:
|
||||
NoticeComponent = <GroupAdminNotice data={data} />
|
||||
break
|
||||
case OB11NoticeType.GroupDecrease:
|
||||
NoticeComponent = <GroupDecreaseNotice data={data} />
|
||||
break
|
||||
case OB11NoticeType.GroupIncrease:
|
||||
NoticeComponent = (
|
||||
<GroupIncreaseNotice data={data as OneBot11GroupIncrease} />
|
||||
)
|
||||
break
|
||||
case OB11NoticeType.GroupBan:
|
||||
NoticeComponent = <GroupBanNotice data={data} />
|
||||
break
|
||||
case OB11NoticeType.FriendAdd:
|
||||
NoticeComponent = <FriendAddNotice data={data as OneBot11FriendAdd} />
|
||||
break
|
||||
case OB11NoticeType.GroupRecall:
|
||||
NoticeComponent = <GroupRecallNotice data={data as OneBot11GroupRecall} />
|
||||
break
|
||||
case OB11NoticeType.FriendRecall:
|
||||
NoticeComponent = (
|
||||
<FriendRecallNotice data={data as OneBot11FriendRecall} />
|
||||
)
|
||||
break
|
||||
case OB11NoticeType.Notify:
|
||||
switch (data.sub_type) {
|
||||
case 'poke':
|
||||
NoticeComponent = <PokeNotice data={data as OneBot11Poke} />
|
||||
break
|
||||
case 'lucky_king':
|
||||
NoticeComponent = <LuckyKingNotice data={data as OneBot11LuckyKing} />
|
||||
break
|
||||
case 'honor':
|
||||
NoticeComponent = <HonorNotice data={data as OneBot11Honor} />
|
||||
break
|
||||
}
|
||||
break
|
||||
case OB11NoticeType.GroupMsgEmojiLike:
|
||||
NoticeComponent = (
|
||||
<GroupMessageReactionNotice
|
||||
data={data as OneBot11GroupMessageReaction}
|
||||
/>
|
||||
)
|
||||
break
|
||||
case OB11NoticeType.GroupEssence:
|
||||
NoticeComponent = (
|
||||
<GroupEssenceNotice data={data as OneBot11GroupEssence} />
|
||||
)
|
||||
break
|
||||
case OB11NoticeType.GroupCard:
|
||||
NoticeComponent = <GroupCardNotice data={data as OneBot11GroupCard} />
|
||||
break
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex gap-2 items-center">
|
||||
<Chip color="warning" variant="flat">
|
||||
通知
|
||||
</Chip>
|
||||
<Chip>{getNoticeTypeName(data.notice_type)}</Chip>
|
||||
{NoticeComponent}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OneBotNotice
|
||||
151
napcat.webui/src/components/onebot/display_card/render.tsx
Normal file
151
napcat.webui/src/components/onebot/display_card/render.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
import { Button } from '@heroui/button'
|
||||
import { Card, CardBody, CardHeader } from '@heroui/card'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
|
||||
import { Snippet } from '@heroui/snippet'
|
||||
import { motion } from 'motion/react'
|
||||
import { IoCode } from 'react-icons/io5'
|
||||
|
||||
import OneBotDisplayMeta from '@/components/onebot/display_card/meta'
|
||||
|
||||
import { getEventName, isOB11Event } from '@/utils/onebot'
|
||||
import { timestampToDateString } from '@/utils/time'
|
||||
|
||||
import type {
|
||||
AllOB11WsResponse,
|
||||
OB11AllEvent,
|
||||
OB11Request
|
||||
} from '@/types/onebot'
|
||||
|
||||
import OneBotMessage from './message'
|
||||
import OneBotNotice from './notice'
|
||||
import OneBotDisplayResponse from './response'
|
||||
|
||||
const itemVariants = {
|
||||
hidden: { opacity: 0, scale: 0.8, y: 50 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
scale: 1,
|
||||
y: 0,
|
||||
transition: { type: 'spring', stiffness: 300, damping: 20 }
|
||||
}
|
||||
}
|
||||
|
||||
function RequestComponent({ data: _ }: { data: OB11Request }) {
|
||||
return <div>Request消息,暂未适配</div>
|
||||
}
|
||||
|
||||
export interface OneBotItemRenderProps {
|
||||
data: AllOB11WsResponse[]
|
||||
index: number
|
||||
style: React.CSSProperties
|
||||
}
|
||||
|
||||
export const getItemSize = (event: OB11AllEvent['post_type']) => {
|
||||
if (event === 'meta_event') {
|
||||
return 100
|
||||
}
|
||||
if (event === 'message') {
|
||||
return 180
|
||||
}
|
||||
if (event === 'request') {
|
||||
return 100
|
||||
}
|
||||
if (event === 'notice') {
|
||||
return 100
|
||||
}
|
||||
if (event === 'message_sent') {
|
||||
return 250
|
||||
}
|
||||
return 100
|
||||
}
|
||||
|
||||
const renderDetail = (data: AllOB11WsResponse) => {
|
||||
if (isOB11Event(data)) {
|
||||
switch (data.post_type) {
|
||||
case 'meta_event':
|
||||
return <OneBotDisplayMeta data={data} />
|
||||
case 'message':
|
||||
return <OneBotMessage data={data} />
|
||||
case 'request':
|
||||
return <RequestComponent data={data} />
|
||||
case 'notice':
|
||||
return <OneBotNotice data={data} />
|
||||
case 'message_sent':
|
||||
return <OneBotMessage data={data} />
|
||||
default:
|
||||
return <div>未知类型的消息</div>
|
||||
}
|
||||
}
|
||||
return <OneBotDisplayResponse data={data} />
|
||||
}
|
||||
|
||||
const OneBotItemRender = ({ data, index, style }: OneBotItemRenderProps) => {
|
||||
const msg = data[index]
|
||||
const isEvent = isOB11Event(msg)
|
||||
return (
|
||||
<div style={style} className="p-1 overflow-visible w-full h-full">
|
||||
<motion.div
|
||||
variants={itemVariants}
|
||||
initial="hidden"
|
||||
animate="visible"
|
||||
className="h-full px-2"
|
||||
>
|
||||
<Card className="w-full h-full py-2 bg-opacity-50 backdrop-blur-sm">
|
||||
<CardHeader className="py-0 text-default-500 flex-row gap-2">
|
||||
<div className="font-bold">
|
||||
{isEvent ? getEventName(msg.post_type) : '请求响应'}
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
{isEvent && timestampToDateString(msg.time)}
|
||||
</div>
|
||||
<div className="ml-auto">
|
||||
<Popover
|
||||
placement="left"
|
||||
showArrow
|
||||
classNames={{
|
||||
content: 'max-h-96 max-w-96 overflow-hidden p-0'
|
||||
}}
|
||||
>
|
||||
<PopoverTrigger>
|
||||
<Button
|
||||
size="sm"
|
||||
color="danger"
|
||||
variant="flat"
|
||||
radius="full"
|
||||
isIconOnly
|
||||
className="text-medium"
|
||||
>
|
||||
<IoCode />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<Snippet
|
||||
hideSymbol
|
||||
tooltipProps={{
|
||||
content: '点击复制'
|
||||
}}
|
||||
classNames={{
|
||||
copyButton: 'self-start sticky top-0 right-0'
|
||||
}}
|
||||
className="bg-content1 h-full overflow-y-scroll items-start"
|
||||
>
|
||||
{JSON.stringify(msg, null, 2)
|
||||
.split('\n')
|
||||
.map((line, i) => (
|
||||
<span key={i} className="whitespace-pre-wrap break-all">
|
||||
{line}
|
||||
</span>
|
||||
))}
|
||||
</Snippet>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardBody className="py-0">{renderDetail(msg)}</CardBody>
|
||||
</Card>
|
||||
</motion.div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OneBotItemRender
|
||||
75
napcat.webui/src/components/onebot/display_card/response.tsx
Normal file
75
napcat.webui/src/components/onebot/display_card/response.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Button } from '@heroui/button'
|
||||
import { Chip } from '@heroui/chip'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@heroui/popover'
|
||||
import { Snippet } from '@heroui/snippet'
|
||||
|
||||
import { getResponseStatusColor, getResponseStatusText } from '@/utils/onebot'
|
||||
|
||||
import { RequestResponse } from '@/types/onebot'
|
||||
|
||||
export interface OneBotDisplayResponseProps {
|
||||
data: RequestResponse
|
||||
}
|
||||
|
||||
const OneBotDisplayResponse: React.FC<OneBotDisplayResponseProps> = ({
|
||||
data
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex gap-2 items-center">
|
||||
<Chip color={getResponseStatusColor(data.status)} variant="flat">
|
||||
{getResponseStatusText(data.status)}
|
||||
</Chip>
|
||||
{data.data && (
|
||||
<Popover
|
||||
placement="right"
|
||||
showArrow
|
||||
classNames={{
|
||||
content: 'max-h-96 max-w-96 overflow-hidden p-0'
|
||||
}}
|
||||
>
|
||||
<PopoverTrigger>
|
||||
<Button
|
||||
size="sm"
|
||||
color="danger"
|
||||
variant="flat"
|
||||
radius="full"
|
||||
className="text-medium"
|
||||
>
|
||||
查看数据
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<Snippet
|
||||
hideSymbol
|
||||
tooltipProps={{
|
||||
content: '点击复制'
|
||||
}}
|
||||
classNames={{
|
||||
copyButton: 'self-start sticky top-0 right-0'
|
||||
}}
|
||||
className="bg-content1 h-full overflow-y-scroll items-start"
|
||||
>
|
||||
{JSON.stringify(data.data, null, 2)
|
||||
.split('\n')
|
||||
.map((line, i) => (
|
||||
<span key={i} className="whitespace-pre-wrap break-all">
|
||||
{line}
|
||||
</span>
|
||||
))}
|
||||
</Snippet>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)}
|
||||
{data.message && (
|
||||
<Chip className="pl-0.5" variant="flat">
|
||||
<Chip color="warning" size="sm" className="-ml-2 mr-1" variant="flat">
|
||||
返回消息
|
||||
</Chip>
|
||||
{data.message}
|
||||
</Chip>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default OneBotDisplayResponse
|
||||
Reference in New Issue
Block a user