my-kaiqiuwang/src/components/BindKaiqiuAccount.tsx
kyuuseiryuu 2774037012 feat(app): add push notification support and event management logic
- Introduce PermissionControlPanel in UserCenter for managing notification permissions.
- Update Service Worker (sw.ts) to handle background push notifications via Firebase Cloud Messaging.
- Implement EventSubscribeService logic to fetch active events, filter expired ones, and clean up subscriptions.
- Refactor KaiqiuService and parsing utilities to include eventId in event details.
- Remove deprecated ScheduleService and inline sendNotification logic.
- Update utility functions to support new types and notification checks.
- Add VAPI public key configuration and update Firebase exports.
2026-03-24 17:21:50 +09:00

91 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useRequest } from "ahooks";
import { useAuthHeaders } from "../hooks/useAuthHeaders";
import { Alert, App, Button, Drawer, Flex, Form, Input, Spin, Typography } from "antd";
import { ExportOutlined, LinkOutlined } from "@ant-design/icons";
import { useCallback, useState } from "react";
import { useNavigate } from "react-router";
export const BindKaiqiuAccount = () => {
const headers = useAuthHeaders();
const isBindReq = useRequest<{
isBinded: boolean;
uid?: string;
}, []>(async () => {
return fetch('/api/account/bind', { headers }).then(res => res.json());
}, { manual: false, debounceWait: 300, refreshDeps: [headers] });
const [open, setOpen] = useState(false);
const [form] = Form.useForm<{ password: string, username: string }>();
const { modal, message } = App.useApp();
const bindRequest = useRequest(async (data) => {
const result = await fetch('/api/account/bind', {
method: 'PUT',
body: JSON.stringify(data),
headers,
}).then(res => res.json());
return result;
}, { manual: true, refreshDeps: [headers] });
const handleBind = useCallback(async () => {
const data = await form.validateFields().catch(() => Promise.reject());
const result = await bindRequest.runAsync(data);
if (!result.success) {
message.error(result.message);
return;
}
await isBindReq.runAsync();
message.success('绑定成功');
setOpen(false);
}, [form, headers, isBindReq, message]);
const handleForgotPass = useCallback(() => {
modal.info({
title: '忘记密码',
content: (
<div>
- - - -
</div>
),
});
}, [modal]);
const navigate = useNavigate();
if (isBindReq.data?.isBinded === undefined) return null;
if (isBindReq.data?.isBinded) {
return (
<Flex gap={8} onClick={() => navigate(`/profile/${isBindReq.data?.uid}`)}>
<Typography.Text type="secondary">UID: {isBindReq.data?.uid ?? '-'}</Typography.Text>
<ExportOutlined />
</Flex>
);
}
return (
<>
<Button
icon={<LinkOutlined />}
onClick={() => setOpen(true)}
>
</Button>
<Drawer
title="绑定开球网账号"
placement="bottom"
size={500}
open={open}
onClose={() => setOpen(false)}
>
<Flex gap={12} vertical>
<Alert type='success' description="后台不会存储账号密码,仅用于登录开球网获取数据。绑定后修改密码不影响绑定结果" />
<Spin spinning={bindRequest.loading}>
<Form form={form}>
<Form.Item rules={[{ required: true, message: '' }]} label="开球网用户名" name={'username'}>
<Input />
</Form.Item>
<Form.Item rules={[{ required: true, message: '' }]} label="开球网密码" name={'password'}>
<Input.Password />
</Form.Item>
</Form>
</Spin>
<Button block type="primary" loading={bindRequest.loading} onClick={handleBind}></Button>
<Button block type="link" onClick={handleForgotPass}></Button>
</Flex>
</Drawer>
</>
);
}