Skip to content

Commit

Permalink
chore: wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kaikaibenkai committed Nov 22, 2023
1 parent 9adbdaa commit b3a5fee
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 36 deletions.
4 changes: 2 additions & 2 deletions components/fb/bot-token-picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const input = ref<{
}>({
token: '',
});
const selected: ShallowRef<Bot | undefined> = shallowRef();
const selected: Ref<Bot | undefined> = shallowRef();
async function handleChange(v: string) {
input.value = { token: v, help: '', status: 'validating' };
Expand Down Expand Up @@ -95,7 +95,7 @@ function handleClose() {
:closable='showCancel'
:ok-button-props='{ disabled: !selected }'
:esc-to-close='false'
@update:visible='(v) => emit("update:visible", v)'
@update:visible='(v: boolean) => emit("update:visible", v)'
@ok='() => emit("ok", selected!)'
@cancel='() => emit("cancel")'
@close='handleClose'
Expand Down
6 changes: 3 additions & 3 deletions components/fb/credit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ function handleRemoveSlotRow() {
class='mb-2 w-full'
:slot='slot'
:editable='editable'
@edit-value='(value) => emit("edit-slot-value", row, index, value)'
@edit-label='(label) => emit("edit-slot-label", row, index, label)'
@edit-image='(url) => emit("edit-slot-image", row, index, url)'
@edit-value='(value: string) => emit("edit-slot-value", row, index, value)'
@edit-label='(label: string) => emit("edit-slot-label", row, index, label)'
@edit-image='(url: string) => emit("edit-slot-image", row, index, url)'
/>
<div v-if='editable' class='flex flex-col'>
<ADivider direction='vertical' />
Expand Down
12 changes: 6 additions & 6 deletions components/fb/guild-picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ export interface Props {
/** 是否隐藏取消按钮。 @default true */
showCancel?: boolean;
}
export type Events = {
'update:visible': [value: boolean];
export interface Events {
(ev: 'update:visible', value: boolean): void;
/** 关闭选择器。 */
close: [];
(ev: 'close'): void;
/** 确认选择。 */
ok: [value: Guild];
(ev: 'ok', value: Guild): void;
/** 取消选择。 */
cancel: [];
(ev: 'cancel'): void;
}
withDefaults(defineProps<Props>(), {
Expand Down Expand Up @@ -78,7 +78,7 @@ function handleBadInput() {
:closable='showCancel'
:ok-button-props='{ disabled: !selected }'
:esc-to-close='false'
@update:visible='(v) => emit("update:visible", v)'
@update:visible='(v: boolean) => emit("update:visible", v)'
@ok='() => emit("ok", selected!)'
@cancel='() => emit("cancel")'
@close='handleClose'
Expand Down
40 changes: 40 additions & 0 deletions components/fb/user-input.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<script lang="ts" setup>
import { User } from 'fanbook-api-node-sdk';
export interface Props {
modelValue: User[];
/** 所属服务器。 */
guild?: bigint;
/** 最大选择人数。 @default 1 */
max?: number;
/** 最大显示人数。 @default 1 */
maxShow?: number;
}
export type Events = {
'update:model-value': [value: User[]];
};
const props = withDefaults(defineProps<Props>(), {
max: 1,
maxShow: 1,
});
const emit = defineEmits<Events>();
const adding = ref(false);
</script>

<template>
<ASpace>
<AAvatarGroup :max-count='maxShow'>
<AAvatar v-for='item in modelValue'>
{{ item.first_name }}
</AAvatar>
</AAvatarGroup>
<AButton v-if='modelValue.length < max' shape='round' @click='() => adding = !adding'>
<template #icon><IconPlus /></template>
</AButton>
<AInputNumber v-if='adding' hide-button :min='0' :precision='0'>
<template #prefix>#</template>
</AInputNumber>
</ASpace>
</template>
68 changes: 45 additions & 23 deletions pages/feature/credit.vue
Original file line number Diff line number Diff line change
@@ -1,35 +1,57 @@
<script lang='ts' setup>
import { GuildCredit } from 'fanbook-api-node-sdk';
import { ChatMember, Guild } from 'fanbook-api-node-sdk';
import { selectUser } from '~/utils/biz/user-selector';
definePageMeta({
title: '成员荣誉',
middleware: ['require-bot'],
});
const credit: Ref<GuildCredit> = ref({
authority: {
icon: 'https://fb-cdn.fanbook.mobi/fanbook/app/files/chatroom/image/ddf60a18da9f51be0255af8a115007ea.png',
name: '机器人工具',
},
slots: [
[{
img: 'https://fb-cdn.fanbook.mobi/fanbook/app/files/chatroom/image/643162c237f9fbe8c9c09a5a6b409b77.png',
value: 'Collaborator',
}],
[{
label: '头衔介绍',
value: '为项目捉虫和引路的志愿者',
}],
],
title: {
img: 'https://fb-cdn.fanbook.mobi/fanbook/app/files/chatroom/image/643162c237f9fbe8c9c09a5a6b409b77.png',
},
const LAST_PAGE = 2;
const page = ref(1);
const title = computed(() => {
switch (page.value) {
case 1: return '输入用户信息';
case 2: return `@${input.value.user?.user.first_name} 的荣誉列表`;
}
});
interface Input {
guild?: Guild;
user?: ChatMember;
}
const input: Ref<Input> = ref({});
const pickingGuild = ref(false);
</script>

<template>
<FbCredit :credit='credit' editable />
<TechnologyInfo title='data'>
{{ credit }}
</TechnologyInfo>
<FbGuildPicker v-model:visible='pickingGuild' @ok='(v) => input.guild = v' />
<FeatureWrapper>
<ACard class='card' :title='title'>
<AForm v-if='page === 1' :model='input' auto-label-width>
<AFormItem field='guild' label='所在服务器' required>
<ASpace direction='vertical'>
<AButton @click='() => pickingGuild = true'>选择服务器</AButton>
<template v-if='input.guild'>已选择:{{ input.guild.name }}</template>
</ASpace>
</AFormItem>
<AFormItem field='user' label='用户 ID' required>
<AButton @click='() => selectUser().then((v) => input.user = v)'>选择</AButton>
{{ input.user }}
</AFormItem>
</AForm>
<template v-else></template>
<ASpace>
<AButton v-if='page !== LAST_PAGE' type='primary' @click='() => ++page'>下一步</AButton>
<AButton v-if='page !== 1' @click='() => --page'>上一步</AButton>
</ASpace>
</ACard>
</FeatureWrapper>
</template>

<style lang="postcss" scoped>
.card:deep() > .arco-card-body {
@apply flex flex-col justify-items-end !important;
}
</style>
3 changes: 1 addition & 2 deletions utils/biz/image-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface SelectImageOptions {
export function selectImage(options?: SelectImageOptions): Promise<string | undefined> {
return new Promise((resolve) => {
const input = ref('');
const status: Ref<undefined | 'error'> = ref(undefined);
const status: Ref<'error' | undefined> = ref(undefined);

function handleInput() {
if (VALIDATE_REGEXP.test(input.value)) status.value = undefined;
Expand All @@ -25,7 +25,6 @@ export function selectImage(options?: SelectImageOptions): Promise<string | unde

Modal.open({
title: options?.title ?? '选择图片',
//@ts-ignore
content: () => (
<FormItem
label='图片链接'
Expand Down
60 changes: 60 additions & 0 deletions utils/biz/user-selector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Button, FormItem, InputNumber, Modal } from '@arco-design/web-vue';
import { ChatMember, Guild } from 'fanbook-api-node-sdk';
import FbGuildPicker from '~/components/fb/guild-picker.vue';

export interface SelectUserOptions {
/** 弹窗标题。 */
title?: string;
/** 默认的服务器。 */
defaultGuild?: Guild;
/** 是否隐藏服务器选择器。 */
hideGuild?: boolean;
}

export function selectUser(options?: SelectUserOptions): Promise<ChatMember | undefined> {
return new Promise((resolve) => {
const guild = ref(options?.defaultGuild);
const selectingGuild = ref(false);
const id: Ref<number | undefined> = ref();
const user: Ref<ChatMember | undefined> = ref();

async function handleIdChange(value?: number) {
if (!value || !guild.value) {
user.value = undefined;
return;
}
[user.value] = await getCurrentBot().getMembersByShortIds(
BigInt(guild.value.guild_id),
[value],
);
}

Modal.open({
title: options?.title ?? '选择用户',
content: () => (<>
{!options?.hideGuild && <FormItem label='所在服务器' required v-slot={{
help: () => guild ? `已选择:${guild.value?.name}` : '',
}}>
<FbGuildPicker visible={selectingGuild.value} onOk={(v: Guild) => guild.value = v} onClose={() => selectingGuild.value = false} />
<Button type={guild.value ? 'secondary' : 'outline'} onClick={() => selectingGuild.value = true}>
选择服务器
</Button>
</FormItem>}
<FormItem label='用户 ID' required>
<InputNumber
v-model={id.value}
hideButton
min={0}
precision={0}
onChange={handleIdChange}
v-slot={{
prefix: () => '#',
}}
/>
</FormItem>
</>),
onOk: () => resolve(user.value),
onCancel: () => resolve(undefined),
});
});
}

0 comments on commit b3a5fee

Please sign in to comment.