Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 添加消息互动功能 #21

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions components/fb/channel-group.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!-- 频道分组。 -->

<script lang="ts" setup>
import { Channel } from 'fanbook-api-node-sdk';

export interface Props {
/** 展示的频道分组。 */
channel: Channel;
/** 在分组下的频道。 */
children: Channel[];
}

defineProps<Props>();
</script>

<template>
<ACollapseItem :key='channel.channel_id' :header='channel.name' :show-expand-icon='!!children.length'>
<FbChannelInfo v-for='item in children' :channel='item' />
</ACollapseItem>
</template>

<style lang="postcss" scoped>
:deep() .arco-collapse-item-content-box {
@apply flex flex-col;
}
</style>
24 changes: 24 additions & 0 deletions components/fb/channel-info.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- 聊天简略信息。 -->

<script lang="ts" setup>
import { Channel } from 'fanbook-api-node-sdk';

export interface Props {
/** 展示的聊天信息。 */
channel: Channel;
}

const props = defineProps<Props>();
const image = computed(() => {
const { type } = props.channel;
if (SupportedChannelType.includes(type)) return `/icon/channel/${type}.svg`;
return '/icon/channel/unknown.svg';
})
</script>

<template>
<ASpace class='h-[30px] overflow-visible' direction='horizontal'>
<img class='w-4' :src='image' />
{{ channel.name }}
</ASpace>
</template>
49 changes: 49 additions & 0 deletions components/fb/channel-list.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!-- 频道列表。 -->

<script lang="ts" setup>
import { Channel, ChannelType } from 'fanbook-api-node-sdk';

export interface Props {
/** 频道列表。 */
channels: Channel[];
}

const props = defineProps<Props>();

const channelsGrouped = computed(() => {
const ret: Array<Channel | Channel[]> = [];
for (const channel of props.channels) { // 放入未分类的频道
if (channel.type === ChannelType.ClassChannel) break;
ret.push(channel);
}
for (let i = ret.length; i < props.channels.length; ++i) { // 放入分类的频道
if (props.channels[i].type === ChannelType.ClassChannel) { // 新的分类
ret.push([props.channels[i]]);
} else { // 分类下的频道
(ret.at(-1) as Channel[]).push(props.channels[i]);
}
}
return ret;
});
</script>

<template>
<ACollapse>
<template v-for='channel in channelsGrouped'>
<FbChannelGroup
v-if='Array.isArray(channel)'
:channel='channel[0]'
:children='channel.slice(1)'
/>
<FbChannelInfo v-else class='unclassed-channel' :channel='channel' />
</template>
</ACollapse>
</template>

<style lang="postcss" scoped>
.unclassed-channel {
border-bottom: 1px solid var(--color-border-2);
@apply flex h-10 !important;
@apply px-4 my-[2px];
}
</style>
4 changes: 3 additions & 1 deletion components/fb/guild-picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ async function handleChange(v: bigint) {
if (!botId) botId = (await getCurrentBot().getMe()).id; // 无缓存,先获取缓存
input.value = { status: 'validating' };
try {
selected.value = await getCurrentBot().getGuild(v, botId);
const guild = await getCurrentBot().getGuild(v, botId);
if (guild.name) selected.value = guild; // name 为空表示非服务器
else throw new FanbookApiError(-1); // 所以要特判
input.value = { status: 'success' };
} catch (e) {
input.value.status = 'error';
Expand Down
17 changes: 17 additions & 0 deletions components/fb/guild-view.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!-- 服务器视图。 -->

<script lang="ts" setup>
import { Channel } from 'fanbook-api-node-sdk';

export interface Props {
/** 服务器频道。 */
channels: Channel[];
}

defineProps<Props>();
</script>

<template>
<FbChannelList v-if='channels.length' :channels='channels' />
<AEmpty v-else>没有频道</AEmpty>
</template>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"@vitejs/plugin-legacy": "^4.1.1",
"@vueuse/core": "^10.3.0",
"@vueuse/nuxt": "^10.3.0",
"fanbook-api-node-sdk": "^0.3.0",
"fanbook-api-node-sdk": "^0.4.2",
"husky": "^8.0.3",
"lodash-es": "^4.17.9",
"nprogress": "^0.2.0",
Expand Down
62 changes: 62 additions & 0 deletions pages/feature/message.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script lang="ts" setup>
import { promiseTimeout } from '@vueuse/core';
import { Message } from '@arco-design/web-vue';
import { Bot, Channel } from 'fanbook-api-node-sdk';

definePageMeta({
title: '消息互动',
middleware: ['require-bot'],
});

const bot = getCurrentBot();
let bus: Awaited<ReturnType<Bot['listen']>> | undefined;
const guildPickerOpen = ref(false);
const channels: Ref<Channel[]> = ref([]);
let unmounting = false;

async function connect() {
bus = await bot.listen();
bus.on('push', handlePush);
bus.on('error', handleError);
bus.on('close', handleClose);
}

function handlePush() {
}
function handleError(err: unknown) {
}
async function handleClose() {
if (unmounting) return; // 离开页面导致的连接关闭,不重连
while (true) {
const { close } = Message.loading({
content: '连接中断,正在重连',
duration: -Infinity,
});
try {
await connect();
close();
break;
} catch (err) {
console.error('Failed to reconnect', err);
await promiseTimeout(3000); // 3s 后再次尝试重连
}
close();
}
Message.success('重连成功');
}

// onMounted(() => connect().catch(handleClose));
onBeforeUnmount(() => {
unmounting = true;
if (bus) bus.emit('close');
});
</script>

<template>
<FbGuildPicker
v-model:visible='guildPickerOpen'
@ok='(v) => channels = toOrderedChannels(v)'
/>
<AButton @click='() => guildPickerOpen = true'>选择服务器</AButton>
<FbGuildView :channels='channels' />
</template>
Loading