-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
247 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
'use client'; | ||
|
||
import React from 'react'; | ||
import { | ||
Row, Col, Form, Input, | ||
} from 'antd'; | ||
import { | ||
UserFormRule, usernameRule, emailRule, passwordRule, | ||
} from '@/zod/user'; | ||
import withActionForm from '@/components/with-action-form'; | ||
import DebounceSelect from '@/components/debounce-select'; | ||
|
||
const InternalUserForm: React.FC<WithFormProps> = ({ mode, data }) => { | ||
const { roleOptions } = data; | ||
return ( | ||
<Row gutter={[15, 0]}> | ||
<Form.Item name="id"> | ||
<Input name="id" hidden /> | ||
</Form.Item> | ||
<Col span={12}> | ||
<Form.Item | ||
name="username" | ||
label="用户名" | ||
validateDebounce={300} | ||
rules={[usernameRule]} | ||
required | ||
> | ||
<Input placeholder="用户登录名称" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item | ||
name="nickname" | ||
label="用户昵称" | ||
validateDebounce={300} | ||
> | ||
<Input placeholder="用户昵称" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item name="realname" label="真实姓名"> | ||
<Input placeholder="用户真实姓名" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item name="gender" label="性别"> | ||
<Input placeholder="性别" /> | ||
</Form.Item> | ||
</Col> | ||
|
||
{mode === 'create' && ( | ||
<> | ||
<Col span={12}> | ||
<Form.Item label="登录密码" name="password" rules={[passwordRule]} required> | ||
<Input.Password placeholder="登录密码" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item label="密码确认" name="confirmPassword" dependencies={['password']} rules={[passwordRule]} required> | ||
<Input.Password placeholder="密码确认" /> | ||
</Form.Item> | ||
</Col> | ||
</> | ||
)} | ||
|
||
<Col span={12}> | ||
<Form.Item label="用户邮箱" name="email" validateDebounce={300} rules={[emailRule]} required> | ||
<Input placeholder="邮箱" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item label="手机号码" name="mobile"> | ||
<Input placeholder="用户手机号码" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item label="角色" name="roles"> | ||
<DebounceSelect options={roleOptions} mode="multiple" placeholder="请选择" /> | ||
</Form.Item> | ||
</Col> | ||
</Row> | ||
); | ||
}; | ||
|
||
export default withActionForm(InternalUserForm); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +1,20 @@ | ||
'use client'; | ||
import React, { ComponentProps } from 'react'; | ||
import { RoleModel } from '@/models'; | ||
import InternalUserForm from './form'; | ||
|
||
import React from 'react'; | ||
import { | ||
Row, Col, Form, Input, | ||
} from 'antd'; | ||
import { CreateUserFormRule, UserPasswordRule } from '@/zod/user'; | ||
import withActionForm from '@/components/with-action-form'; | ||
|
||
const UserForm: React.FC<WithFormProps> = ({ mode }) => { | ||
console.log('mode', mode); | ||
const UserForm: React.FC<ComponentProps<typeof InternalUserForm>> = async (props) => { | ||
const roleOptions = await RoleModel.findAll({ | ||
raw: true, | ||
attributes: [['id', 'value'], ['name', 'label']], | ||
}); | ||
return ( | ||
<Row gutter={[15, 0]}> | ||
<Col span={12}> | ||
<Form.Item | ||
name="username" | ||
label="用户名" | ||
validateDebounce={300} | ||
rules={[CreateUserFormRule]} | ||
required | ||
> | ||
<Input placeholder="用户登录名称" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item | ||
name="nickname" | ||
label="用户昵称" | ||
validateDebounce={300} | ||
> | ||
<Input placeholder="用户昵称" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item name="realname" label="真实姓名"> | ||
<Input placeholder="用户真实姓名" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item name="gender" label="性别"> | ||
<Input placeholder="性别" /> | ||
</Form.Item> | ||
</Col> | ||
|
||
{mode === 'create' && ( | ||
<> | ||
<Col span={12}> | ||
<Form.Item label="登录密码" name="password" rules={[UserPasswordRule]}> | ||
<Input.Password placeholder="登录密码" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item label="密码确认" name="confirmPassword" dependencies={['password']} rules={[UserPasswordRule]}> | ||
<Input.Password placeholder="密码确认" /> | ||
</Form.Item> | ||
</Col> | ||
</> | ||
)} | ||
|
||
<Col span={12}> | ||
<Form.Item label="用户邮箱" name="email" validateDebounce={300} rules={[CreateUserFormRule]}> | ||
<Input placeholder="邮箱" /> | ||
</Form.Item> | ||
</Col> | ||
<Col span={12}> | ||
<Form.Item label="手机号码" name="mobile"> | ||
<Input placeholder="用户手机号码" /> | ||
</Form.Item> | ||
</Col> | ||
</Row> | ||
<InternalUserForm | ||
{...props} | ||
data={{ | ||
roleOptions, | ||
}} | ||
/> | ||
); | ||
}; | ||
|
||
export default withActionForm(UserForm); | ||
export default UserForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import React, { useMemo, useRef, useState } from 'react'; | ||
import debounce from 'lodash/debounce'; | ||
import { Select, Spin } from 'antd'; | ||
import type { SelectProps } from 'antd/es/select'; | ||
|
||
export interface DebounceSelectProps<ValueType = any> | ||
extends Omit<SelectProps<ValueType | ValueType[]>, 'children'> { | ||
fetcher?: (search: string) => Promise<ValueType[]>; | ||
delay?: number; | ||
} | ||
|
||
interface SelectValueType { | ||
key?: string; | ||
label: React.ReactNode; | ||
value: string | number; | ||
} | ||
|
||
function DebounceSelect<ValueType extends SelectValueType = any>({ | ||
fetcher, | ||
delay = 300, | ||
options: InternalOptions = [], | ||
...props | ||
}: DebounceSelectProps<ValueType>) { | ||
const [fetching, setFetching] = useState(false); | ||
const [options, setOptions] = useState(InternalOptions); | ||
const fetchRef = useRef(0); | ||
|
||
const onSearch = useMemo(() => { | ||
if (!fetcher) { | ||
return; | ||
} | ||
const search = (value: string) => { | ||
fetchRef.current += 1; | ||
const fetchId = fetchRef.current; | ||
// setOptions([]); | ||
setFetching(true); | ||
|
||
fetcher(value).then((newOptions) => { | ||
if (fetchId !== fetchRef.current) { | ||
// for fetch callback order | ||
return; | ||
} | ||
|
||
setOptions(newOptions); | ||
setFetching(false); | ||
}); | ||
}; | ||
|
||
return debounce(search, delay); | ||
}, [fetcher, delay]); | ||
|
||
console.log('options', options); | ||
return ( | ||
<Select | ||
labelInValue | ||
filterOption={false} | ||
onSearch={onSearch} | ||
notFoundContent={fetching ? <Spin size="small" /> : null} | ||
{...props} | ||
options={options} | ||
/> | ||
); | ||
} | ||
|
||
export default DebounceSelect; |
Oops, something went wrong.