YuJian920
3 years ago
14 changed files with 204 additions and 133 deletions
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
import React from "react"; |
||||
import { Select } from "antd"; |
||||
|
||||
const { Option } = Select; |
||||
|
||||
type SelectProps = React.ComponentProps<typeof Select>; |
||||
|
||||
interface IdSelectProps |
||||
extends Omit<SelectProps, "value" | "onChange" | "options"> { |
||||
value: number | string | null | undefined; |
||||
onChange: (value?: number) => void; |
||||
defaultOptionName?: string; |
||||
options?: { name: string; id: number }[]; |
||||
} |
||||
|
||||
const toNumber = (value: unknown) => (isNaN(Number(value)) ? 0 : Number(value)); |
||||
|
||||
const IdSelect = (props: IdSelectProps) => { |
||||
const { value, onChange, defaultOptionName, options, ...restProps } = props; |
||||
return ( |
||||
<Select |
||||
value={options?.length ? toNumber(value) : 0} |
||||
onChange={(value) => onChange(toNumber(value) || undefined)} |
||||
{...restProps} |
||||
> |
||||
{defaultOptionName ? ( |
||||
<Option value={0}>{defaultOptionName}</Option> |
||||
) : null} |
||||
{options?.map((option) => ( |
||||
<Option value={option.id} key={option.id}>{option.name}</Option> |
||||
))} |
||||
</Select> |
||||
); |
||||
}; |
||||
|
||||
export default React.memo(IdSelect); |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
import React from "react"; |
||||
import { Rate } from "antd"; |
||||
|
||||
interface PinProps extends React.ComponentProps<typeof Rate> { |
||||
checked: boolean; |
||||
onCheckedChange?: (checked: boolean) => void; |
||||
} |
||||
|
||||
const Pin = ({ checked, onCheckedChange, ...restProps }: PinProps) => { |
||||
return ( |
||||
<Rate |
||||
count={1} |
||||
value={checked ? 1 : 0} |
||||
onChange={(num) => onCheckedChange?.(!!num)} |
||||
{...restProps} |
||||
/> |
||||
); |
||||
}; |
||||
|
||||
export default Pin; |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
import React from "react"; |
||||
import useUser from "../hook/useUsers"; |
||||
import IdSelect from "./IdSelect"; |
||||
|
||||
const UserSelect = (props: React.ComponentProps<typeof IdSelect>) => { |
||||
const { data: users } = useUser(); |
||||
return <IdSelect options={users || []} {...props} />; |
||||
}; |
||||
|
||||
export default React.memo(UserSelect); |
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
import { useMemo } from "react"; |
||||
import useUrlQueryParams from "./useUrlQueryParams"; |
||||
|
||||
const useProjectsSearchParams = () => { |
||||
const [param, setParam] = useUrlQueryParams(["name", "personId"]); |
||||
// 转换 URL 中的字符串参数
|
||||
return [ |
||||
useMemo(() => ({ ...param, personId: Number(param.personId) || undefined }), [param]), |
||||
setParam, |
||||
] as const; |
||||
}; |
||||
|
||||
export default useProjectsSearchParams; |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
import { useAuth } from "../context/auth-context"; |
||||
import { request } from "../utils/request"; |
||||
|
||||
const useRequest = () => { |
||||
const { user } = useAuth(); |
||||
return (...[endpoint, config]: Parameters<typeof request>) => request(endpoint, { ...config, token: user?.token }); |
||||
}; |
||||
|
||||
export default useRequest; |
@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
|
||||
export interface User { |
||||
id: number; |
||||
name: string; |
||||
email: string; |
||||
title: string; |
||||
organization: string; |
||||
token: string; |
||||
} |
||||
|
||||
export interface Project { |
||||
id: number; |
||||
name: string; |
||||
personId: number; |
||||
pin: boolean; |
||||
organization: string; |
||||
created: number; |
||||
} |
@ -1,39 +1,44 @@
@@ -1,39 +1,44 @@
|
||||
import qs from 'qs' |
||||
import { logout } from './token' |
||||
import { useAuth } from '../context/auth-context' |
||||
import qs from "qs"; |
||||
import { logout } from "./token"; |
||||
import { message } from "antd"; |
||||
|
||||
const baseURL = process.env.REACT_APP_API_URL |
||||
const baseURL = process.env.REACT_APP_API_URL; |
||||
|
||||
interface Config extends RequestInit { |
||||
data?: object, |
||||
token?: string |
||||
data?: object; |
||||
token?: string; |
||||
} |
||||
|
||||
export const request = async (endpoint: string, { data, token, headers, ...customConfig }: Config) => { |
||||
export const request = async ( |
||||
endpoint: string, |
||||
{ data, token, headers, ...customConfig }: Config |
||||
) => { |
||||
const config = { |
||||
method: 'GET', |
||||
method: "GET", |
||||
headers: { |
||||
Authorization: token ? `Bearer ${token}` : '', |
||||
'Content-Type': data ? 'application/json' : '' |
||||
Authorization: token ? `Bearer ${token}` : "", |
||||
"Content-Type": data ? "application/json" : "", |
||||
}, |
||||
...customConfig |
||||
} |
||||
if (config.method.toUpperCase() === 'GET') endpoint += `?${qs.stringify(data)}` |
||||
else config.body = JSON.stringify(data || {}) |
||||
...customConfig, |
||||
}; |
||||
if (config.method.toUpperCase() === "GET") |
||||
endpoint += `?${qs.stringify(data)}`; |
||||
else config.body = JSON.stringify(data || {}); |
||||
|
||||
return window.fetch(`${baseURL}${endpoint}`, config).then(async (response) => { |
||||
if (response.status === 401) { |
||||
await logout() |
||||
window.location.reload() |
||||
return Promise.reject({ message: "请重新登录" }) |
||||
} |
||||
const data = await response.json() |
||||
if (response.ok) return data |
||||
else return Promise.reject(data) |
||||
}) |
||||
} |
||||
|
||||
export const useRequest = () => { |
||||
const { user } = useAuth() |
||||
return (...[endpoint, config]: Parameters<typeof request>) => request(endpoint, { ...config, token: user?.token }) |
||||
} |
||||
return window |
||||
.fetch(`${baseURL}${endpoint}`, config) |
||||
.then(async (response) => { |
||||
if (response.status === 401) { |
||||
await logout(); |
||||
window.location.reload(); |
||||
return Promise.reject({ message: "请重新登录" }); |
||||
} |
||||
const data = await response.json(); |
||||
if (response.ok) return data; |
||||
else return Promise.reject(data); |
||||
}) |
||||
.catch((error) => { |
||||
message.error("请求异常"); |
||||
return Promise.reject(error); |
||||
}); |
||||
}; |
||||
|
Loading…
Reference in new issue