企业管理

This commit is contained in:
2026-01-21 14:47:35 +08:00
parent a7f5e37aac
commit ab91458199
14 changed files with 385 additions and 261 deletions

View File

@@ -26,6 +26,7 @@
"qs": "^6.14.1", "qs": "^6.14.1",
"react": "^19.2.3", "react": "^19.2.3",
"react-dom": "^19.2.3", "react-dom": "^19.2.3",
"react-router-dom": "^6.30.3",
"valtio": "^2.3.0", "valtio": "^2.3.0",
"zustand": "^5.0.9" "zustand": "^5.0.9"
}, },

34
pnpm-lock.yaml generated
View File

@@ -29,6 +29,9 @@ importers:
react-dom: react-dom:
specifier: ^19.2.3 specifier: ^19.2.3
version: 19.2.3(react@19.2.3) version: 19.2.3(react@19.2.3)
react-router-dom:
specifier: ^6.30.3
version: 6.30.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
valtio: valtio:
specifier: ^2.3.0 specifier: ^2.3.0
version: 2.3.0(@types/react@19.2.7)(react@19.2.3) version: 2.3.0(@types/react@19.2.7)(react@19.2.3)
@@ -736,6 +739,10 @@ packages:
react: '>=16.9.0' react: '>=16.9.0'
react-dom: '>=16.9.0' react-dom: '>=16.9.0'
'@remix-run/router@1.23.2':
resolution: {integrity: sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==}
engines: {node: '>=14.0.0'}
'@rolldown/binding-android-arm64@1.0.0-beta.53': '@rolldown/binding-android-arm64@1.0.0-beta.53':
resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==} resolution: {integrity: sha512-Ok9V8o7o6YfSdTTYA/uHH30r3YtOxLD6G3wih/U9DO0ucBBFq8WPt/DslU53OgfteLRHITZny9N/qCUxMf9kjQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -1301,6 +1308,19 @@ packages:
resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
react-router-dom@6.30.3:
resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==}
engines: {node: '>=14.0.0'}
peerDependencies:
react: '>=16.8'
react-dom: '>=16.8'
react-router@6.30.3:
resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==}
engines: {node: '>=14.0.0'}
peerDependencies:
react: '>=16.8'
react@19.2.3: react@19.2.3:
resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -2178,6 +2198,8 @@ snapshots:
react: 19.2.3 react: 19.2.3
react-dom: 19.2.3(react@19.2.3) react-dom: 19.2.3(react@19.2.3)
'@remix-run/router@1.23.2': {}
'@rolldown/binding-android-arm64@1.0.0-beta.53': '@rolldown/binding-android-arm64@1.0.0-beta.53':
optional: true optional: true
@@ -2675,6 +2697,18 @@ snapshots:
react-refresh@0.18.0: {} react-refresh@0.18.0: {}
react-router-dom@6.30.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
dependencies:
'@remix-run/router': 1.23.2
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
react-router: 6.30.3(react@19.2.3)
react-router@6.30.3(react@19.2.3):
dependencies:
'@remix-run/router': 1.23.2
react: 19.2.3
react@19.2.3: {} react@19.2.3: {}
require-directory@2.1.1: {} require-directory@2.1.1: {}

View File

@@ -0,0 +1,12 @@
/**
* 企业状态
*/
export const stateObj: any = {
1: '正常',
2: '禁用',
};
export const stateOptions = [
{ label: '正常', value: '1' },
{ label: '禁用', value: '2' },
];

View File

@@ -1,9 +1,12 @@
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
import './index.css'; import './index.css';
import { HashRouter } from 'react-router-dom';
import App from './App.tsx'; import App from './App.tsx';
createRoot(document.getElementById('root')!).render( createRoot(document.getElementById('root')!).render(
// <StrictMode> // <StrictMode>
<App />, <HashRouter>
<App />,
</HashRouter>,
// </StrictMode>, // </StrictMode>,
); );

View File

@@ -0,0 +1,139 @@
import { Button, DatePicker, Form, Input, notification, Select } from 'antd';
import TextArea from 'antd/lib/input/TextArea';
import dayjs from 'dayjs';
import { stringify } from 'qs';
import type React from 'react';
import { useImperativeHandle, useState } from 'react';
import ModalPlugin from '@/components/ModalPlugin';
import { stateOptions } from '@/configs/usersConfig';
import { CompanyServices } from '@/services/CompanyServices';
import type { IRef } from '@/utils/type';
import { useRequest } from '@/utils/useRequest';
interface IProps extends IRef {
onCallback?: () => void;
}
export type ICompanyEditModalType = {
show: (data?: any) => void;
};
export const CompanyEditModal: React.FC<IProps> = (props) => {
const [open, setOpen] = useState(false);
const [title, setTitle] = useState('');
const [form] = Form.useForm();
const [data, setData] = useState<any>(null);
// 请求成功回调
const success = (res: any) => {
if (res.err_code === 0) {
notification.success({ message: '保存成功' });
props.onCallback?.();
setOpen(false);
form.resetFields(); // 提交成功重置表单
}
};
//const { loading: addLoading, request: addRequest } = useRequest(CompanyServices.add, { onSuccess: success });
const { loading: editLoading, request: editRequest } = useRequest(CompanyServices.edit, { onSuccess: success });
const save = async () => {
try {
const values = await form.validateFields();
const [eff_date, exp_date] = values.date_range || [];
values.eff_date = eff_date?.format('YYYY-MM-DD') || null;
values.exp_date = exp_date?.format('YYYY-MM-DD') || null;
delete values.date_range;
// 编辑场景带上主键
if (data?.company_id) {
values.company_id = data.company_id;
editRequest(stringify(values));
} else {
//addRequest(stringify(values));
}
} catch (error) {
console.log('表单验证未通过', error);
}
};
useImperativeHandle(props.ref, () => ({
show: (data?: any) => {
setTitle(data ? `${data.company_name} 编辑` : '新增');
setOpen(true);
setData(data);
if (data) {
// 编辑场景初始化表单
form.setFieldsValue({
company_name: data.company_name,
company_address: data.company_address,
erp_name: data.erp_name,
date_range: data.eff_date && data.exp_date ? [dayjs(data.eff_date), dayjs(data.exp_date)] : undefined,
company_state: String(data.company_state),
});
} else {
form.resetFields();
}
},
}));
return (
<ModalPlugin
open={open}
onCancel={() => setOpen(false)}
title={title}
footer={[
<Button key='cancel' onClick={() => setOpen(false)}>
</Button>,
<Button key='save' type='primary' loading={editLoading} onClick={save}>
</Button>,
]}
>
<Form form={form} labelCol={{ style: { width: window?.dfConfig?.language === 'zh-cn' ? 80 : 120 } }}>
<Form.Item
label='企业'
name='company_name'
required
rules={[
{ required: true, message: '请输入企业' },
{ min: 2, message: '最少2字符' },
{ max: 20, message: '最多20字符' },
]}
>
<Input allowClear placeholder='请填写企业' maxLength={20} showCount />
</Form.Item>
<Form.Item
label='ERP'
name='erp_name'
rules={[
{ min: 2, message: '最少2字符' },
{ max: 20, message: '最多20字符' },
]}
>
<Input allowClear placeholder='请填写ERP' maxLength={20} showCount />
</Form.Item>
<Form.Item label='地址' name='company_address'>
<Input allowClear placeholder='请填写地址' maxLength={20} showCount />
</Form.Item>
<Form.Item label={'状态'} name='company_state'>
<Select options={stateOptions} placeholder='请选择状态' />
</Form.Item>
<Form.Item label='简介' name='company_desc'>
<TextArea allowClear maxLength={200} showCount />
</Form.Item>
<Form.Item label='有效期' name='date_range'>
<DatePicker.RangePicker style={{ width: '100%' }} format='YYYY-MM-DD' allowClear />
</Form.Item>
</Form>
</ModalPlugin>
);
};

View File

@@ -0,0 +1,62 @@
import { Select } from 'antd';
import type { InputStatus } from 'antd/es/_util/statusUtils';
import type React from 'react';
import { useEffect, useState } from 'react';
import { CompanyServices } from '@/services/CompanyServices';
import { isArray } from '@/utils/common';
import { useRequest } from '@/utils/useRequest';
interface IProps {
status?: InputStatus;
value?: string | number;
onChange?: (value: string | number) => void;
onBlur?: React.FocusEventHandler<HTMLElement> | undefined;
allowClear?: boolean;
}
const CompanySelect: React.FC<IProps> = (props) => {
const [list, setList] = useState<any[]>([]);
const { request } = useRequest(CompanyServices.getCompanyAjaxList, {
onSuccess: (res) => {
const arr: any[] = [];
if (res.err_code == 0 && isArray(res.data)) {
res.data.forEach((item: any) => {
arr.push({
label: item.company_name,
value: item.company_id,
});
});
}
setList(arr);
},
});
useEffect(() => {
request();
}, []);
return (
<Select
status={props.status}
showSearch={{
// 搜索时使用 option.label 属性匹配
optionFilterProp: 'label',
// 下拉排序,可选
filterSort: (optionA, optionB) =>
(optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase()),
}}
allowClear={props.allowClear}
//value={props.value}
value={props.value !== undefined && props.value != null && props.value !== '' ? Number(props.value) : undefined}
onChange={(value) => {
props.onChange?.(value);
}}
onBlur={(event) => {
props.onBlur?.(event);
}}
options={list}
popupRender={(menu) => <>{menu}</>}
/>
);
};
export default CompanySelect;

View File

@@ -1,168 +0,0 @@
import { Button, Form, Input, notification, Select } from 'antd';
import TextArea from 'antd/lib/input/TextArea';
import { stringify } from 'qs';
import type React from 'react';
import { useImperativeHandle, useState } from 'react';
import ModalPlugin from '@/components/ModalPlugin';
import { stateOptions, userSexOptions } from '@/configs/usersConfig';
import { UserServices } from '@/services/UserServices';
import type { IRef } from '@/utils/type';
import { useRequest } from '@/utils/useRequest';
interface IProps extends IRef {
onCallback?: () => void;
}
export type IUserEditModalType = {
show: (data?: any) => void;
};
export const UserEditModal: React.FC<IProps> = (props) => {
const [open, setOpen] = useState(false);
const [title, setTitle] = useState('');
const [form] = Form.useForm();
const [data, setData] = useState<any>(null);
// 请求成功回调
const success = (res: any) => {
if (res.err_code === 0) {
notification.success({ message: '保存成功' });
props.onCallback?.();
setOpen(false);
form.resetFields(); // 提交成功重置表单
}
};
const { loading: addLoading, request: addRequest } = useRequest(UserServices.add, { onSuccess: success });
const { loading: editLoading, request: editRequest } = useRequest(UserServices.edit, { onSuccess: success });
const save = async () => {
try {
const values = await form.validateFields();
// 编辑场景带上主键
if (data?.user_id) {
values.user_id = data.user_id;
editRequest(stringify(values));
} else {
addRequest(stringify(values));
}
} catch (error) {
console.log('表单验证未通过', error);
}
};
useImperativeHandle(props.ref, () => ({
show: (data?: any) => {
setTitle(data ? `${data.login_name} 编辑` : '新增');
setOpen(true);
setData(data);
if (data) {
// 编辑场景初始化表单
form.setFieldsValue({
login_name: data.login_name,
user_phone: data.user_phone,
user_mail: data.user_mail,
nick_name: data.nick_name,
password: '', // 密码编辑可选
comments: data.comments,
user_sex: String(data.user_sex),
state: String(data.state),
});
} else {
form.resetFields();
form.setFieldsValue({
user_sex: '1',
state: '1',
});
}
},
}));
return (
<ModalPlugin
open={open}
onCancel={() => setOpen(false)}
title={title}
footer={[
<Button key='cancel' onClick={() => setOpen(false)}>
</Button>,
<Button key='save' type='primary' loading={addLoading || editLoading} onClick={save}>
</Button>,
]}
>
<Form form={form} labelCol={{ style: { width: window?.dfConfig?.language === 'zh-cn' ? 80 : 120 } }}>
<Form.Item
label='用户名'
name='login_name'
required
rules={[
{ required: true, message: '请输入用户名' },
{ min: 2, message: '最少2字符' },
{ max: 20, message: '最多20字符' },
]}
>
<Input allowClear placeholder='请填写用户名' maxLength={20} showCount />
</Form.Item>
<Form.Item
label='昵称'
name='nick_name'
rules={[
{ min: 2, message: '最少2字符' },
{ max: 20, message: '最多20字符' },
]}
>
<Input allowClear placeholder='请填写昵称' maxLength={20} showCount />
</Form.Item>
<Form.Item
label='手机号'
name='user_phone'
required
rules={[
{ required: true, message: '请输入手机号' },
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确' },
]}
>
<Input allowClear placeholder='请填写手机号' maxLength={11} showCount />
</Form.Item>
<Form.Item label='邮箱' name='user_mail' rules={[{ type: 'email', message: '邮箱格式不正确' }]}>
<Input allowClear placeholder='请填写邮箱' />
</Form.Item>
<Form.Item label='密码' name='password' rules={[{ min: 6, max: 18, message: '密码需6~18位' }]}>
<Input.Password allowClear placeholder={data ? '不修改请留空' : '请填写密码'} />
</Form.Item>
{!data?.user_id && (
<Form.Item
label='企业名'
name='company_name'
rules={[
{ min: 2, message: '最少2字符' },
{ max: 20, message: '最多20字符' },
]}
>
<Input allowClear placeholder='请填写企业名' />
</Form.Item>
)}
<Form.Item label={'性别'} name='user_sex'>
<Select options={userSexOptions} placeholder='请选择性别' />
</Form.Item>
<Form.Item label={'状态'} name='state'>
<Select options={stateOptions} placeholder='请选择状态' />
</Form.Item>
<Form.Item label='备注' name='comments'>
<TextArea allowClear maxLength={200} showCount />
</Form.Item>
</Form>
</ModalPlugin>
);
};

View File

@@ -1,30 +1,28 @@
import { Button, DatePicker, Input, Select } from 'antd'; import { Button, DatePicker, Input, Select } from 'antd';
import { stringify } from 'qs'; import { stringify } from 'qs';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { FormItemPlugin, FormPlugin } from '@/components/FormPlugin'; import { FormItemPlugin, FormPlugin } from '@/components/FormPlugin';
import { GapBox } from '@/components/GapBox'; import { GapBox } from '@/components/GapBox';
import PageContainerPlugin from '@/components/PageContainer/PageContainerPlugin'; import PageContainerPlugin from '@/components/PageContainer/PageContainerPlugin';
import { FooterPagination, HeaderPagination } from '@/components/PaginationPlugin'; import { FooterPagination, HeaderPagination } from '@/components/PaginationPlugin';
import { MoreSearchButton, SearchButton } from '@/components/SearchButton'; import { SearchButton } from '@/components/SearchButton';
import type { ColumnsTypeUltra } from '@/components/TableColumnsFilterPlugin'; import type { ColumnsTypeUltra } from '@/components/TableColumnsFilterPlugin';
import { TablePlugin } from '@/components/TablePlugin'; import { TablePlugin } from '@/components/TablePlugin';
import { staffType } from '@/configs/staffsConfig'; import { stateObj, stateOptions } from '@/configs/companyConfig';
import { stateOptions, userSex, userState } from '@/configs/usersConfig';
import type { IAjaxDataBase, IParamsBase } from '@/interfaces/common'; import type { IAjaxDataBase, IParamsBase } from '@/interfaces/common';
import { type IUserEditModalType, UserEditModal } from '@/pages/User/List/components/UserEditModal'; import { CompanyServices } from '@/services/CompanyServices';
import { UserServices } from '@/services/UserServices';
import { useAuthStore } from '@/store/AuthStore'; import { useAuthStore } from '@/store/AuthStore';
import { tableFixedByPhone, toArray } from '@/utils/common'; import { tableFixedByPhone, toArray } from '@/utils/common';
import { useRequest } from '@/utils/useRequest'; import { useRequest } from '@/utils/useRequest';
import { CompanyEditModal, type ICompanyEditModalType } from './components/CompanyEditModal';
interface IAjaxData extends IAjaxDataBase { interface IAjaxData extends IAjaxDataBase {
data: any[]; data: any[];
} }
type IParams = IParamsBase & { type IParams = IParamsBase & {
login_name?: string; company_name?: string;
nick_name?: string; company_state?: number;
user_phone?: string;
state?: number;
create_dateL?: string; create_dateL?: string;
create_dateU?: string; create_dateU?: string;
}; };
@@ -35,9 +33,10 @@ const CompanyListForm: React.FC = () => {
const [params, setParams] = useState<IParams>({ curr_page: 1, page_count: 20 }); const [params, setParams] = useState<IParams>({ curr_page: 1, page_count: 20 });
const [ajaxData, setAjaxData] = useState<IAjaxData>({ count: 0, data: [] }); const [ajaxData, setAjaxData] = useState<IAjaxData>({ count: 0, data: [] });
const [showMoreSearch, setShowMoreSearch] = useState(false); const [showMoreSearch, setShowMoreSearch] = useState(false);
const UserEditModalRef = useRef<IUserEditModalType>(null); const CompanyEditModalRef = useRef<ICompanyEditModalType>(null);
const nav = useNavigate();
const { loading: userLoading, request: userRequest } = useRequest(UserServices.getUserList, { const { loading: userLoading, request: userRequest } = useRequest(CompanyServices.getCompanyList, {
onSuccessCodeZero: (res) => { onSuccessCodeZero: (res) => {
setAjaxData({ setAjaxData({
count: res.count || 0, count: res.count || 0,
@@ -49,43 +48,52 @@ const CompanyListForm: React.FC = () => {
const columns: ColumnsTypeUltra<any> = [ const columns: ColumnsTypeUltra<any> = [
{ {
title: '操作', title: '操作',
width: 50, width: 120,
fixed: tableFixedByPhone('left'), fixed: tableFixedByPhone('left'),
render: (_, item) => ( render: (_, item) => (
<GapBox> <GapBox>
<Button <Button
type='primary' type='primary'
onClick={() => { onClick={() => {
UserEditModalRef.current?.show(item); CompanyEditModalRef.current?.show(item);
}} }}
> >
</Button> </Button>
{auth.SF_ERP_USER_EDIT && ( <Button
<Button type='text'
type='primary' onClick={() => {
onClick={() => { //nav(`user/list?company_id=${item.company_id}`);
UserEditModalRef.current?.show(item); location.href = `#/user/list?company_id=${item.company_id}`;
}} }}
> >
</Button> </Button>
)}
</GapBox> </GapBox>
), ),
}, },
{ title: '用户名', dataIndex: 'login_name', width: 120 }, { title: '企业', dataIndex: 'company_name', width: 80 },
{ title: '企业名称', dataIndex: 'company_name', width: 120 }, { title: 'ERP', dataIndex: 'erp_name', width: 80 },
{ title: '类型', dataIndex: 'staff_type', width: 60, render: (value) => staffType[value] }, { title: '状态', dataIndex: 'company_state', width: 60, ellipsis: true, render: (value) => stateObj[value] },
{ title: '昵称', dataIndex: 'nick_name', width: 120 },
{ title: '手机', dataIndex: 'user_phone', width: 120 },
{ title: '性别', dataIndex: 'user_sex', width: 60, render: (value) => userSex[value] },
{ title: '状态', dataIndex: 'state', width: 60, ellipsis: true, render: (value) => userState[value] },
{ {
title: '备注', title: '地址',
dataIndex: 'comments', dataIndex: 'company_address',
width: 300, width: 300,
}, },
{
title: '简介',
dataIndex: 'company_desc',
width: 300,
},
{
title: '有效期',
dataIndex: 'eff_date',
width: 190,
render: (_, record) => {
return record.eff_date ? `${record.eff_date || ''}${record.exp_date || ''}` : '';
},
},
{ {
title: '创建时间', title: '创建时间',
width: window.dfConfig.isPhone ? 160 : 160, width: window.dfConfig.isPhone ? 160 : 160,
@@ -109,37 +117,35 @@ const CompanyListForm: React.FC = () => {
return ( return (
<> <>
<FormPlugin gutter={16}> <FormPlugin gutter={16}>
<FormItemPlugin label={'用户名'}> <FormItemPlugin label={'企业'}>
<Input <Input
allowClear allowClear
defaultValue={params.login_name} defaultValue={params.company_name}
placeholder='用户名' placeholder='企业'
onChange={(e) => { onChange={(e) => {
params.login_name = e.target.value.trim() || undefined; params.company_name = e.target.value.trim() || undefined;
}} }}
onPressEnter={() => page(1)} onPressEnter={() => page(1)}
/> />
</FormItemPlugin> </FormItemPlugin>
<FormItemPlugin label={'昵称'}> <FormItemPlugin label={'状态'}>
<Input <Select
allowClear allowClear
defaultValue={params.nick_name} value={params.company_state}
placeholder='昵称' options={stateOptions}
onChange={(e) => { onChange={(value) => {
params.nick_name = e.target.value.trim() || undefined; params.company_state = value || undefined;
setParams({ ...params });
}} }}
onPressEnter={() => page(1)}
/> />
</FormItemPlugin> </FormItemPlugin>
<FormItemPlugin label={'手机号'}> <FormItemPlugin label={'创建日期'}>
<Input <DatePicker.RangePicker
allowClear style={{ width: '100%' }}
defaultValue={params.user_phone} onChange={(_values, dates) => {
placeholder='手机号' params.create_dateL = dates?.[0] || undefined;
onChange={(e) => { params.create_dateU = dates?.[1] || undefined;
params.user_phone = e.target.value.trim() || undefined;
}} }}
onPressEnter={() => page(1)}
/> />
</FormItemPlugin> </FormItemPlugin>
@@ -158,24 +164,24 @@ const CompanyListForm: React.FC = () => {
page(1); page(1);
}} }}
/> />
<MoreSearchButton {/* <MoreSearchButton
show={showMoreSearch} show={showMoreSearch}
onClick={() => { onClick={() => {
setShowMoreSearch((v) => !v); setShowMoreSearch((v) => !v);
}} }}
/> /> */}
</div> </div>
</FormItemPlugin> </FormItemPlugin>
</FormPlugin> </FormPlugin>
<FormPlugin style={{ display: showMoreSearch ? 'flex' : 'none' }} gutter={16}> {/* <FormPlugin style={{ display: showMoreSearch ? 'flex' : 'none' }} gutter={16}>
<FormItemPlugin label={'状态'}> <FormItemPlugin label={'状态'}>
<Select <Select
allowClear allowClear
value={params.state} value={params.company_state}
options={stateOptions} options={stateOptions}
onChange={(value) => { onChange={(value) => {
params.state = value || undefined; params.company_state = value || undefined;
setParams({ ...params }); setParams({ ...params });
}} }}
/> />
@@ -189,27 +195,15 @@ const CompanyListForm: React.FC = () => {
}} }}
/> />
</FormItemPlugin> </FormItemPlugin>
</FormPlugin> </FormPlugin> */}
<GapBox style={{ marginBottom: 12, justifyContent: 'space-between' }}> <HeaderPagination
<GapBox> style={{ marginBottom: 12, marginRight: 12 }}
<Button current={params.curr_page}
type='primary' pageSize={params.page_count}
onClick={() => { total={ajaxData.count}
UserEditModalRef.current?.show(); onChange={page}
}} />
>
</Button>
</GapBox>
<HeaderPagination
style={{ marginBottom: 0, marginRight: 12 }}
current={params.curr_page}
pageSize={params.page_count}
total={ajaxData.count}
onChange={page}
/>
</GapBox>
<TablePlugin <TablePlugin
loading={userLoading} loading={userLoading}
@@ -219,7 +213,7 @@ const CompanyListForm: React.FC = () => {
dataSource={ajaxData.data} dataSource={ajaxData.data}
columns={columns} columns={columns}
scroll={{ x: true }} scroll={{ x: true }}
rowKey={'user_id'} rowKey={'company_id'}
/> />
<FooterPagination <FooterPagination
@@ -232,7 +226,7 @@ const CompanyListForm: React.FC = () => {
}} }}
/> />
<UserEditModal ref={UserEditModalRef} onCallback={() => page(1)} /> <CompanyEditModal ref={CompanyEditModalRef} onCallback={() => page(1)} />
</> </>
); );
}; };

View File

@@ -148,7 +148,13 @@ const AdminSysLogForm: React.FC = () => {
<FormItemPlugin label='权限'> <FormItemPlugin label='权限'>
<Select <Select
showSearch showSearch={{
// 搜索时使用 option.label 属性匹配
optionFilterProp: 'label',
// 下拉排序,可选
filterSort: (optionA, optionB) =>
(optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase()),
}}
allowClear allowClear
placeholder='请选择权限' placeholder='请选择权限'
disabled={!params.menu_id} disabled={!params.menu_id}

View File

@@ -229,15 +229,26 @@ export const AdminGrpEditModal: React.FC<IProps> = (props) => {
<Button onClick={expandAll}></Button> <Button onClick={expandAll}></Button>
<Button onClick={collapseAll}></Button> <Button onClick={collapseAll}></Button>
</Space> </Space>
<Tree <div
checkable style={{
checkStrictly={false} // 父子联动 maxHeight: 360,
treeData={menuTree} overflow: 'auto',
checkedKeys={checkedKeys} border: '1px solid #d9d9d9',
expandedKeys={expandedKeys} borderRadius: 6,
onExpand={(keys) => setExpandedKeys(keys)} padding: 8,
onCheck={(keys) => setCheckedKeys(keys as React.Key[])} background: '#fff',
/> }}
>
<Tree
checkable
checkStrictly={false} // 父子联动
treeData={menuTree}
checkedKeys={checkedKeys}
expandedKeys={expandedKeys}
onExpand={(keys) => setExpandedKeys(keys)}
onCheck={(keys) => setCheckedKeys(keys as React.Key[])}
/>
</div>
</Form.Item> </Form.Item>
</Form> </Form>
</ModalPlugin> </ModalPlugin>

View File

@@ -38,7 +38,13 @@ const AdminGrpSelect: React.FC<IProps> = (props) => {
return ( return (
<Select <Select
status={props.status} status={props.status}
showSearch showSearch={{
// 搜索时使用 option.label 属性匹配
optionFilterProp: 'label',
// 下拉排序,可选
filterSort: (optionA, optionB) =>
(optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase()),
}}
allowClear={props.allowClear} allowClear={props.allowClear}
value={props.value} value={props.value}
onChange={(value) => { onChange={(value) => {

View File

@@ -38,7 +38,13 @@ const AdminDepSelect: React.FC<IProps> = (props) => {
return ( return (
<Select <Select
status={props.status} status={props.status}
showSearch showSearch={{
// 搜索时使用 option.label 属性匹配
optionFilterProp: 'label',
// 下拉排序,可选
filterSort: (optionA, optionB) =>
(optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase()),
}}
allowClear={props.allowClear} allowClear={props.allowClear}
value={props.value} value={props.value}
onChange={(value) => { onChange={(value) => {

View File

@@ -1,6 +1,7 @@
import { Button, DatePicker, Input, Select } from 'antd'; import { Button, DatePicker, Input, Select } from 'antd';
import { stringify } from 'qs'; import { stringify } from 'qs';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { FormItemPlugin, FormPlugin } from '@/components/FormPlugin'; import { FormItemPlugin, FormPlugin } from '@/components/FormPlugin';
import { GapBox } from '@/components/GapBox'; import { GapBox } from '@/components/GapBox';
import PageContainerPlugin from '@/components/PageContainer/PageContainerPlugin'; import PageContainerPlugin from '@/components/PageContainer/PageContainerPlugin';
@@ -11,6 +12,7 @@ import { TablePlugin } from '@/components/TablePlugin';
import { staffType } from '@/configs/staffsConfig'; import { staffType } from '@/configs/staffsConfig';
import { stateOptions, userSex, userState } from '@/configs/usersConfig'; import { stateOptions, userSex, userState } from '@/configs/usersConfig';
import type { IAjaxDataBase, IParamsBase } from '@/interfaces/common'; import type { IAjaxDataBase, IParamsBase } from '@/interfaces/common';
import CompanySelect from '@/pages/Company/List/components/CompanySelect';
import { type IUserEditModalType, UserEditModal } from '@/pages/User/List/components/UserEditModal'; import { type IUserEditModalType, UserEditModal } from '@/pages/User/List/components/UserEditModal';
import { UserServices } from '@/services/UserServices'; import { UserServices } from '@/services/UserServices';
import { useAuthStore } from '@/store/AuthStore'; import { useAuthStore } from '@/store/AuthStore';
@@ -25,6 +27,7 @@ type IParams = IParamsBase & {
nick_name?: string; nick_name?: string;
user_phone?: string; user_phone?: string;
state?: number; state?: number;
company_id?: any;
create_dateL?: string; create_dateL?: string;
create_dateU?: string; create_dateU?: string;
}; };
@@ -32,10 +35,13 @@ type IParams = IParamsBase & {
/** 用户列表页面 */ /** 用户列表页面 */
const UserListForm: React.FC = () => { const UserListForm: React.FC = () => {
const auth = useAuthStore().auth; const auth = useAuthStore().auth;
const [params, setParams] = useState<IParams>({ curr_page: 1, page_count: 20 });
const [ajaxData, setAjaxData] = useState<IAjaxData>({ count: 0, data: [] }); const [ajaxData, setAjaxData] = useState<IAjaxData>({ count: 0, data: [] });
const [showMoreSearch, setShowMoreSearch] = useState(false); const [showMoreSearch, setShowMoreSearch] = useState(false);
const UserEditModalRef = useRef<IUserEditModalType>(null); const UserEditModalRef = useRef<IUserEditModalType>(null);
const [searchParams] = useSearchParams();
const company_id = searchParams.get('company_id');
const [params, setParams] = useState<IParams>({ curr_page: 1, page_count: 20, company_id });
const { loading: userLoading, request: userRequest } = useRequest(UserServices.getUserList, { const { loading: userLoading, request: userRequest } = useRequest(UserServices.getUserList, {
onSuccessCodeZero: (res) => { onSuccessCodeZero: (res) => {
@@ -75,7 +81,7 @@ const UserListForm: React.FC = () => {
), ),
}, },
{ title: '用户名', dataIndex: 'login_name', width: 120 }, { title: '用户名', dataIndex: 'login_name', width: 120 },
{ title: '企业名称', dataIndex: 'company_name', width: 120 }, { title: '企业', dataIndex: 'company_name', width: 120 },
{ title: '类型', dataIndex: 'staff_type', width: 60, render: (value) => staffType[value] }, { title: '类型', dataIndex: 'staff_type', width: 60, render: (value) => staffType[value] },
{ title: '昵称', dataIndex: 'nick_name', width: 120 }, { title: '昵称', dataIndex: 'nick_name', width: 120 },
{ title: '手机', dataIndex: 'user_phone', width: 120 }, { title: '手机', dataIndex: 'user_phone', width: 120 },
@@ -180,6 +186,16 @@ const UserListForm: React.FC = () => {
}} }}
/> />
</FormItemPlugin> </FormItemPlugin>
<FormItemPlugin label={'企业'}>
<CompanySelect
allowClear
value={params.company_id} //
onChange={(value) => {
params.company_id = value || undefined;
setParams({ ...params });
}}
/>
</FormItemPlugin>
<FormItemPlugin label={'创建日期'}> <FormItemPlugin label={'创建日期'}>
<DatePicker.RangePicker <DatePicker.RangePicker
style={{ width: '100%' }} style={{ width: '100%' }}

View File

@@ -1,3 +1,5 @@
export const CompanyServices = { export const CompanyServices = {
getCompanyList: '/Company/getCompanyList', getCompanyList: '/Company/getCompanyList',
getCompanyAjaxList: '/Company/getCompanyAjaxList',
edit: '/Company/edit',
} as const; } as const;