18 changed files with 1026 additions and 121 deletions
-
2package.json
-
79pnpm-lock.yaml
-
105src/api/client.ts
-
7src/api/services/index.ts
-
44src/api/services/transactionService.ts
-
58src/api/services/userService.ts
-
39src/api/types.ts
-
1src/app/home/assets/components/AssetListCard.tsx
-
1src/app/home/assets/components/ResourceCard.tsx
-
35src/app/home/assets/components/TransferCard.tsx
-
57src/app/home/assets/components/VoteCard.tsx
-
162src/app/home/assets/components/WalletCard.tsx
-
14src/app/home/assets/page.tsx
-
43src/app/home/components/HeaderMenu/api.ts
-
206src/app/home/components/HeaderMenu/groupManager.tsx
-
261src/app/home/components/HeaderMenu/index.tsx
-
2src/app/home/layout.tsx
-
31src/store/userAtoms.ts
@ -0,0 +1,105 @@ |
|||||
|
import axios, { AxiosInstance, AxiosRequestConfig } from "axios"; |
||||
|
|
||||
|
/** |
||||
|
* API客户端类 |
||||
|
* 封装了基于axios的HTTP请求方法,提供统一的接口调用方式 |
||||
|
*/ |
||||
|
export class ApiClient { |
||||
|
private client: AxiosInstance; |
||||
|
|
||||
|
// constructor(baseURL: string = process.env.NEXT_PUBLIC_API_BASE_URL || 'https://api.example.com') {
|
||||
|
constructor(baseURL: string = " http://192.168.31.65:6600") { |
||||
|
this.client = axios.create({ |
||||
|
baseURL, |
||||
|
timeout: 10000, // 请求超时时间:10秒
|
||||
|
headers: { |
||||
|
"Content-Type": "application/json", |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
// 请求拦截器
|
||||
|
this.client.interceptors.request.use( |
||||
|
(config) => { |
||||
|
// 在这里添加认证token
|
||||
|
const token = localStorage.getItem("token"); |
||||
|
if (token) { |
||||
|
config.headers.Authorization = `Bearer ${token}`; |
||||
|
} |
||||
|
return config; |
||||
|
}, |
||||
|
(error) => { |
||||
|
return Promise.reject(error); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
// 响应拦截器
|
||||
|
this.client.interceptors.response.use( |
||||
|
(response) => response, |
||||
|
(error) => { |
||||
|
// 在这里处理常见错误
|
||||
|
if (error.response?.status === 401) { |
||||
|
// 处理未授权访问
|
||||
|
console.error("未授权访问"); |
||||
|
} |
||||
|
return Promise.reject(error); |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 发送GET请求 |
||||
|
* @param url 请求地址 |
||||
|
* @param config 请求配置 |
||||
|
* @returns 返回请求数据 |
||||
|
*/ |
||||
|
async get<T>(url: string, config?: AxiosRequestConfig): Promise<T> { |
||||
|
const response = await this.client.get<T>(url, config); |
||||
|
return response.data; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 发送POST请求 |
||||
|
* @param url 请求地址 |
||||
|
* @param data 请求数据 |
||||
|
* @param config 请求配置 |
||||
|
* @returns 返回请求数据 |
||||
|
*/ |
||||
|
async post<T>( |
||||
|
url: string, |
||||
|
data?: any, |
||||
|
config?: AxiosRequestConfig, |
||||
|
): Promise<T> { |
||||
|
const response = await this.client.post<T>(url, data, config); |
||||
|
return response.data; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 发送PUT请求 |
||||
|
* @param url 请求地址 |
||||
|
* @param data 请求数据 |
||||
|
* @param config 请求配置 |
||||
|
* @returns 返回请求数据 |
||||
|
*/ |
||||
|
async put<T>( |
||||
|
url: string, |
||||
|
data?: any, |
||||
|
config?: AxiosRequestConfig, |
||||
|
): Promise<T> { |
||||
|
const response = await this.client.put<T>(url, data, config); |
||||
|
return response.data; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 发送DELETE请求 |
||||
|
* @param url 请求地址 |
||||
|
* @param config 请求配置 |
||||
|
* @returns 返回请求数据 |
||||
|
*/ |
||||
|
async delete<T>(url: string, config?: AxiosRequestConfig): Promise<T> { |
||||
|
const response = await this.client.delete<T>(url, config); |
||||
|
return response.data; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 导出API客户端实例
|
||||
|
export const apiClient = new ApiClient(); |
@ -0,0 +1,7 @@ |
|||||
|
/** |
||||
|
* 服务模块导出文件 |
||||
|
* 统一导出所有服务类,方便其他模块引用 |
||||
|
*/ |
||||
|
|
||||
|
export * from './userService'; |
||||
|
export * from './transactionService'; |
@ -0,0 +1,44 @@ |
|||||
|
import { apiClient } from '../client'; |
||||
|
import { ApiResponse, Transaction, CreateTransactionRequest } from '../types'; |
||||
|
|
||||
|
/** |
||||
|
* 交易服务类 - 处理所有与交易相关的API请求 |
||||
|
*/ |
||||
|
export class TransactionService { |
||||
|
// 交易API的基础路径
|
||||
|
private static readonly BASE_PATH = '/transactions'; |
||||
|
|
||||
|
/** |
||||
|
* 创建新交易 |
||||
|
* @param data 创建交易所需的数据 |
||||
|
* @returns 返回创建的交易信息 |
||||
|
*/ |
||||
|
static async createTransaction(data: CreateTransactionRequest): Promise<ApiResponse<Transaction>> { |
||||
|
return apiClient.post<ApiResponse<Transaction>>(this.BASE_PATH, data); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取指定ID的交易详情 |
||||
|
* @param id 交易ID |
||||
|
* @returns 返回交易详细信息 |
||||
|
*/ |
||||
|
static async getTransaction(id: string): Promise<ApiResponse<Transaction>> { |
||||
|
return apiClient.get<ApiResponse<Transaction>>(`${this.BASE_PATH}/${id}`); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取交易列表 |
||||
|
* @param params 查询参数对象 |
||||
|
* @param params.page 页码 |
||||
|
* @param params.limit 每页数量 |
||||
|
* @param params.status 交易状态过滤 |
||||
|
* @returns 返回交易列表数据 |
||||
|
*/ |
||||
|
static async listTransactions(params?: { |
||||
|
page?: number; |
||||
|
limit?: number; |
||||
|
status?: Transaction['status']; |
||||
|
}): Promise<ApiResponse<Transaction[]>> { |
||||
|
return apiClient.get<ApiResponse<Transaction[]>>(this.BASE_PATH, { params }); |
||||
|
} |
||||
|
} |
@ -0,0 +1,58 @@ |
|||||
|
import { apiClient } from '../client'; |
||||
|
import { ApiResponse, LoginRequest, LoginResponse, User } from '../types'; |
||||
|
|
||||
|
/** |
||||
|
* 用户服务类 - 处理所有与用户相关的API请求 |
||||
|
*/ |
||||
|
export class UserService { |
||||
|
// 用户API的基础路径
|
||||
|
private static readonly BASE_PATH = '/users'; |
||||
|
|
||||
|
/** |
||||
|
* 用户登录 |
||||
|
* @param credentials 登录凭证,包含邮箱和密码 |
||||
|
* @returns 返回登录响应,包含用户token和用户信息 |
||||
|
*/ |
||||
|
static async login(credentials: LoginRequest): Promise<ApiResponse<LoginResponse>> { |
||||
|
return apiClient.post<ApiResponse<LoginResponse>>(`${this.BASE_PATH}/login`, credentials); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取当前登录用户信息 |
||||
|
* @returns 返回当前用户的详细信息 |
||||
|
*/ |
||||
|
static async getCurrentUser(): Promise<ApiResponse<User>> { |
||||
|
return apiClient.get<ApiResponse<User>>(`${this.BASE_PATH}/me`); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 更新用户资料 |
||||
|
* @param userId 用户ID |
||||
|
* @param data 需要更新的用户数据 |
||||
|
* @returns 返回更新后的用户信息 |
||||
|
*/ |
||||
|
static async updateProfile(userId: string, data: Partial<User>): Promise<ApiResponse<User>> { |
||||
|
return apiClient.put<ApiResponse<User>>(`${this.BASE_PATH}/${userId}`, data); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 使用示例:
|
||||
|
/* |
||||
|
try { |
||||
|
// 尝试用户登录
|
||||
|
const response = await UserService.login({ |
||||
|
email: 'user@example.com', |
||||
|
password: 'password123' |
||||
|
}); |
||||
|
|
||||
|
if (response.success) { |
||||
|
const { token, user } = response.data; |
||||
|
// 将token存储在localStorage中
|
||||
|
localStorage.setItem('token', token); |
||||
|
// 处理用户数据
|
||||
|
console.log('登录用户:', user); |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('登录失败:', error); |
||||
|
} |
||||
|
*/ |
@ -0,0 +1,39 @@ |
|||||
|
// Common API response wrapper
|
||||
|
export interface ApiResponse<T> { |
||||
|
success: boolean; |
||||
|
data: T; |
||||
|
message?: string; |
||||
|
} |
||||
|
|
||||
|
// User related types
|
||||
|
export interface User { |
||||
|
id: string; |
||||
|
username: string; |
||||
|
email: string; |
||||
|
createdAt: string; |
||||
|
} |
||||
|
|
||||
|
export interface LoginRequest { |
||||
|
email: string; |
||||
|
password: string; |
||||
|
} |
||||
|
|
||||
|
export interface LoginResponse { |
||||
|
token: string; |
||||
|
user: User; |
||||
|
} |
||||
|
|
||||
|
// Transaction related types
|
||||
|
export interface Transaction { |
||||
|
id: string; |
||||
|
amount: number; |
||||
|
currency: string; |
||||
|
status: 'pending' | 'completed' | 'failed'; |
||||
|
timestamp: string; |
||||
|
} |
||||
|
|
||||
|
export interface CreateTransactionRequest { |
||||
|
amount: number; |
||||
|
currency: string; |
||||
|
recipientAddress: string; |
||||
|
} |
@ -1,28 +1,150 @@ |
|||||
import React from "react"; |
|
||||
import { Card, Space, Typography } from "antd"; |
|
||||
import { WalletOutlined } from "@ant-design/icons"; |
|
||||
|
import React, { useState } from "react"; |
||||
|
import { |
||||
|
Card, |
||||
|
Space, |
||||
|
Typography, |
||||
|
Modal, |
||||
|
Input, |
||||
|
Select, |
||||
|
Button, |
||||
|
QRCode, |
||||
|
message, |
||||
|
} from "antd"; |
||||
|
import { |
||||
|
WalletOutlined, |
||||
|
QrcodeOutlined, |
||||
|
TransactionOutlined, |
||||
|
} from "@ant-design/icons"; |
||||
|
|
||||
const { Title } = Typography; |
const { Title } = Typography; |
||||
|
const { TextArea } = Input; |
||||
|
|
||||
const WalletCard: React.FC = () => { |
const WalletCard: React.FC = () => { |
||||
|
const [isTransferModalOpen, setIsTransferModalOpen] = useState(false); |
||||
|
const [isReceiveModalOpen, setIsReceiveModalOpen] = useState(false); |
||||
|
const [receiverAddress, setReceiverAddress] = useState(""); |
||||
|
const [selectedToken, setSelectedToken] = useState("TRX"); |
||||
|
const [transferNote, setTransferNote] = useState(""); |
||||
|
|
||||
|
// 示例钱包地址
|
||||
|
const walletAddress = "TRx1234567890abcdefghijklmnopqrstuvwxyz"; |
||||
|
|
||||
|
const handleTransfer = () => { |
||||
|
if (!receiverAddress) { |
||||
|
message.error("请输入接收账户地址"); |
||||
|
return; |
||||
|
} |
||||
|
// 这里添加转账逻辑
|
||||
|
message.success("转账请求已提交"); |
||||
|
setIsTransferModalOpen(false); |
||||
|
// 重置表单
|
||||
|
setReceiverAddress(""); |
||||
|
setSelectedToken("TRX"); |
||||
|
setTransferNote(""); |
||||
|
}; |
||||
|
|
||||
|
const handleSaveQRCode = () => { |
||||
|
message.success("二维码已保存"); |
||||
|
}; |
||||
|
|
||||
return ( |
return ( |
||||
<Card |
|
||||
title={ |
|
||||
<> |
|
||||
<WalletOutlined /> 钱包资产 |
|
||||
</> |
|
||||
} |
|
||||
hoverable |
|
||||
> |
|
||||
<div className="text-center"> |
|
||||
<Title level={3}>0.00 TRX</Title> |
|
||||
<p>总资产价值</p> |
|
||||
</div> |
|
||||
<Space> |
|
||||
<button>转账</button> |
|
||||
<button>收款</button> |
|
||||
</Space> |
|
||||
</Card> |
|
||||
|
<> |
||||
|
<Card |
||||
|
title={ |
||||
|
<> |
||||
|
<WalletOutlined /> 钱包资产 |
||||
|
</> |
||||
|
} |
||||
|
hoverable |
||||
|
style={{ minHeight: "240px" }} |
||||
|
> |
||||
|
<div className="text-center"> |
||||
|
<Title level={3}>0.00 TRX</Title> |
||||
|
<p>总资产价值</p> |
||||
|
</div> |
||||
|
<Space> |
||||
|
<Button |
||||
|
type="primary" |
||||
|
icon={<TransactionOutlined />} |
||||
|
onClick={() => setIsTransferModalOpen(true)} |
||||
|
> |
||||
|
转账 |
||||
|
</Button> |
||||
|
<Button |
||||
|
icon={<QrcodeOutlined />} |
||||
|
onClick={() => setIsReceiveModalOpen(true)} |
||||
|
> |
||||
|
收款 |
||||
|
</Button> |
||||
|
</Space> |
||||
|
</Card> |
||||
|
|
||||
|
{/* 转账弹窗 */} |
||||
|
<Modal |
||||
|
title="转账" |
||||
|
open={isTransferModalOpen} |
||||
|
onOk={handleTransfer} |
||||
|
onCancel={() => setIsTransferModalOpen(false)} |
||||
|
centered |
||||
|
> |
||||
|
<Space direction="vertical" style={{ width: "100%" }} size="large"> |
||||
|
<div> |
||||
|
<p>接收账户</p> |
||||
|
<Input |
||||
|
placeholder="请输入接收账户地址" |
||||
|
value={receiverAddress} |
||||
|
onChange={(e) => setReceiverAddress(e.target.value)} |
||||
|
/> |
||||
|
</div> |
||||
|
<div> |
||||
|
<p>选择通证</p> |
||||
|
<Select |
||||
|
style={{ width: "100%" }} |
||||
|
value={selectedToken} |
||||
|
onChange={setSelectedToken} |
||||
|
options={[ |
||||
|
{ value: "TRX", label: "TRX" }, |
||||
|
{ value: "USDT", label: "USDT" }, |
||||
|
]} |
||||
|
/> |
||||
|
</div> |
||||
|
<div> |
||||
|
<p>转账备注</p> |
||||
|
<TextArea |
||||
|
rows={4} |
||||
|
placeholder="请输入转账备注" |
||||
|
value={transferNote} |
||||
|
onChange={(e) => setTransferNote(e.target.value)} |
||||
|
/> |
||||
|
</div> |
||||
|
</Space> |
||||
|
</Modal> |
||||
|
|
||||
|
{/* 收款弹窗 */} |
||||
|
<Modal |
||||
|
title="收款" |
||||
|
open={isReceiveModalOpen} |
||||
|
onCancel={() => setIsReceiveModalOpen(false)} |
||||
|
footer={[ |
||||
|
<Button key="save" type="primary" onClick={handleSaveQRCode}> |
||||
|
保存二维码 |
||||
|
</Button>, |
||||
|
]} |
||||
|
centered |
||||
|
> |
||||
|
<Space |
||||
|
direction="vertical" |
||||
|
style={{ width: "100%", alignItems: "center" }} |
||||
|
size="large" |
||||
|
> |
||||
|
<div style={{ wordBreak: "break-all", textAlign: "center" }}> |
||||
|
<p>钱包地址</p> |
||||
|
<p>{walletAddress}</p> |
||||
|
</div> |
||||
|
<QRCode value={walletAddress} size={200} /> |
||||
|
</Space> |
||||
|
</Modal> |
||||
|
</> |
||||
); |
); |
||||
}; |
}; |
||||
|
|
||||
|
@ -0,0 +1,43 @@ |
|||||
|
import { apiClient } from "@/api/client"; |
||||
|
|
||||
|
export class Api { |
||||
|
private static readonly BASE_PATH = "/transactions"; |
||||
|
|
||||
|
//http://192.168.31.65:6600/api/v1/group/add
|
||||
|
static async addGroupArr(data: any) { |
||||
|
return apiClient.post("/api/v1/group/add", data); |
||||
|
} |
||||
|
|
||||
|
//http://192.168.31.65:6600/api/v1/group/list
|
||||
|
static async getGroupArr() { |
||||
|
return apiClient.get("/api/v1/group/list"); |
||||
|
} |
||||
|
//http://192.168.31.65:6600/api/v1/group/update
|
||||
|
static async updateGroupArr(data: any) { |
||||
|
return apiClient.put("/api/v1/group/update", data); |
||||
|
} |
||||
|
//http://192.168.31.65:6600/api/v1/group/{id}
|
||||
|
static async deleteGroupArr(id: string) { |
||||
|
return apiClient.delete(`/api/v1/group/${id}`); |
||||
|
} |
||||
|
|
||||
|
//http://192.168.31.65:6600/api/v1/address/add
|
||||
|
static async addAddressArr(data: any) { |
||||
|
return apiClient.post("/api/v1/address/add", data); |
||||
|
} |
||||
|
|
||||
|
//http://192.168.31.65:6600/api/v1/address/list
|
||||
|
static async getAddressArr() { |
||||
|
return apiClient.get("/api/v1/address/list"); |
||||
|
} |
||||
|
|
||||
|
//http://192.168.31.65:6600/api/v1/address/update
|
||||
|
static async updateAddressArr(data: any) { |
||||
|
return apiClient.put("/api/v1/address/update", data); |
||||
|
} |
||||
|
|
||||
|
//http://192.168.31.65:6600/api/v1/address/{id}
|
||||
|
static async deleteAddressArr(id: string) { |
||||
|
return apiClient.delete(`/api/v1/address/${id}`); |
||||
|
} |
||||
|
} |
@ -0,0 +1,206 @@ |
|||||
|
"use client"; |
||||
|
|
||||
|
import React, { useEffect, useState } from "react"; |
||||
|
import { Button, Form, Modal, Space, Table, Typography } from "antd"; |
||||
|
import { BetaSchemaForm } from "@ant-design/pro-components"; |
||||
|
import { Api } from "./api"; |
||||
|
const { Link } = Typography; |
||||
|
|
||||
|
interface GroupManagerProps { |
||||
|
modalOpen: boolean; |
||||
|
setModalOpen: React.Dispatch<React.SetStateAction<boolean>>; |
||||
|
dataSource: any[]; |
||||
|
setDataSource: React.Dispatch<React.SetStateAction<any[]>>; |
||||
|
getGroupArr: Function; |
||||
|
} |
||||
|
|
||||
|
const GroupManager: React.FC<GroupManagerProps> = ({ |
||||
|
modalOpen, |
||||
|
setModalOpen, |
||||
|
dataSource, |
||||
|
setDataSource, |
||||
|
getGroupArr, |
||||
|
}) => { |
||||
|
const [createOpen, setCreate] = useState(false); |
||||
|
const [editorOpen, setEditorOpen] = useState(false); |
||||
|
const [createForm] = Form.useForm(); // 只取 Form 实例
|
||||
|
const [editForm] = Form.useForm(); // 只取 Form 实例
|
||||
|
|
||||
|
const onCancel = () => { |
||||
|
setModalOpen(false); |
||||
|
}; |
||||
|
|
||||
|
const openCreateForm = () => { |
||||
|
createForm.resetFields(); |
||||
|
setCreate(true); |
||||
|
}; |
||||
|
|
||||
|
const openEditForm = (record: any) => { |
||||
|
editForm.setFieldsValue(record); |
||||
|
setEditorOpen(true); |
||||
|
}; |
||||
|
|
||||
|
const closeCreateForm = () => { |
||||
|
setCreate(false); |
||||
|
}; |
||||
|
const closeEditForm = () => { |
||||
|
setEditorOpen(false); |
||||
|
}; |
||||
|
|
||||
|
//============================================通信====================================================
|
||||
|
|
||||
|
const handleAdd = async () => { |
||||
|
const reqData = createForm.getFieldsValue(); |
||||
|
await Api.addGroupArr(reqData); |
||||
|
getGroupArr(); |
||||
|
closeCreateForm(); |
||||
|
}; |
||||
|
const subDelect = async (id: string) => { |
||||
|
await Api.deleteGroupArr(id); |
||||
|
getGroupArr(); |
||||
|
}; |
||||
|
const subEdit = async () => { |
||||
|
const reqData = editForm.getFieldsValue(); |
||||
|
await Api.updateGroupArr(reqData); |
||||
|
getGroupArr(); |
||||
|
closeEditForm(); |
||||
|
}; |
||||
|
//===================================================================================================
|
||||
|
|
||||
|
const columns = [ |
||||
|
{ |
||||
|
title: "ID", |
||||
|
dataIndex: "id", |
||||
|
key: "id", |
||||
|
formItemProps: { |
||||
|
hidden: true, |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: "分组名称", |
||||
|
dataIndex: "name", |
||||
|
key: "name", |
||||
|
formItemProps: { |
||||
|
rules: [{ required: true, message: "必填项" }], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: "排序", |
||||
|
dataIndex: "sort", |
||||
|
key: "sort", |
||||
|
formItemProps: { |
||||
|
rules: [{ required: true, message: "必填项" }], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: "操作", |
||||
|
hideInForm: true, |
||||
|
render: (_: any, record: any) => { |
||||
|
return ( |
||||
|
<Space> |
||||
|
<a onClick={() => openEditForm(record)}>编辑</a> |
||||
|
<a onClick={() => subDelect(record.id)}>删除</a> |
||||
|
</Space> |
||||
|
); |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
<Modal |
||||
|
title="分组管理" |
||||
|
open={modalOpen} |
||||
|
onCancel={onCancel} |
||||
|
footer={null} |
||||
|
width={1000} |
||||
|
height={1000} |
||||
|
> |
||||
|
<Button |
||||
|
onClick={() => { |
||||
|
openCreateForm(); |
||||
|
}} |
||||
|
type="primary" |
||||
|
style={{ marginBottom: 16 }} |
||||
|
> |
||||
|
增加分组 |
||||
|
</Button> |
||||
|
<Table |
||||
|
columns={columns as []} |
||||
|
dataSource={dataSource} |
||||
|
bordered |
||||
|
scroll={{ x: 600, y: 600 }} |
||||
|
/> |
||||
|
</Modal> |
||||
|
|
||||
|
<Modal |
||||
|
title="添加" |
||||
|
open={createOpen} |
||||
|
onCancel={closeCreateForm} |
||||
|
footer={null} |
||||
|
> |
||||
|
<BetaSchemaForm |
||||
|
form={createForm} |
||||
|
layoutType="Form" |
||||
|
onFinish={handleAdd} |
||||
|
columns={columns as any[]} |
||||
|
submitter={{ |
||||
|
render: (props) => { |
||||
|
return [ |
||||
|
<Button |
||||
|
key="submit" |
||||
|
type="primary" |
||||
|
onClick={() => props.submit()} |
||||
|
> |
||||
|
提交 |
||||
|
</Button>, |
||||
|
<Button |
||||
|
key="cancel" |
||||
|
onClick={closeCreateForm} |
||||
|
style={{ marginLeft: 8 }} |
||||
|
> |
||||
|
取消 |
||||
|
</Button>, |
||||
|
]; |
||||
|
}, |
||||
|
}} |
||||
|
/> |
||||
|
</Modal> |
||||
|
<Modal |
||||
|
title="编辑" |
||||
|
open={editorOpen} |
||||
|
onCancel={closeEditForm} |
||||
|
footer={null} |
||||
|
> |
||||
|
<BetaSchemaForm |
||||
|
form={editForm} |
||||
|
layoutType="Form" |
||||
|
onFinish={subEdit} |
||||
|
columns={columns as any[]} |
||||
|
submitter={{ |
||||
|
render: (props) => { |
||||
|
return [ |
||||
|
<Button |
||||
|
key="submit" |
||||
|
type="primary" |
||||
|
onClick={() => props.submit()} |
||||
|
> |
||||
|
提交 |
||||
|
</Button>, |
||||
|
<Button |
||||
|
key="cancel" |
||||
|
onClick={closeEditForm} |
||||
|
style={{ marginLeft: 8 }} |
||||
|
> |
||||
|
取消 |
||||
|
</Button>, |
||||
|
]; |
||||
|
}, |
||||
|
}} |
||||
|
/> |
||||
|
</Modal> |
||||
|
</> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default GroupManager; |
@ -0,0 +1,31 @@ |
|||||
|
import { atom } from "jotai"; |
||||
|
|
||||
|
interface UserInfo { |
||||
|
address: string; |
||||
|
} |
||||
|
|
||||
|
// 创建初始用户信息
|
||||
|
const initialUserInfo: UserInfo = { |
||||
|
address: "AAAAAAAAAAAAAAAAAAA", |
||||
|
}; |
||||
|
|
||||
|
// 用户信息 atom
|
||||
|
export const userInfoAtom = atom<UserInfo>(initialUserInfo); |
||||
|
|
||||
|
// 登录状态 atom
|
||||
|
export const isLoggedInAtom = atom<boolean>(false); |
||||
|
|
||||
|
// 派生的 atom,用于更新用户信息
|
||||
|
export const userInfoActionsAtom = atom( |
||||
|
(get) => get(userInfoAtom), |
||||
|
(get, set, updates: Partial<UserInfo>) => { |
||||
|
const currentInfo = get(userInfoAtom); |
||||
|
set(userInfoAtom, { ...currentInfo, ...updates }); |
||||
|
}, |
||||
|
); |
||||
|
|
||||
|
// 清除用户信息的 atom
|
||||
|
export const clearUserInfoAtom = atom(null, (get, set) => { |
||||
|
set(userInfoAtom, initialUserInfo); |
||||
|
set(isLoggedInAtom, false); |
||||
|
}); |
Write
Preview
Loading…
Cancel
Save
Reference in new issue