Commit 3cf7752f authored by 张子雨's avatar 张子雨

feat: 员工管理开发

parent ec155464
......@@ -292,12 +292,12 @@ export default {
name: 'StoreManagement',
component: './StoreManagement',
},
// {
// title: '商户管理后台-商家资料',
// path: '/EmployeeManagement',
// name: 'EmployeeManagement',
// component: './EmployeeManagement',
// },
{
title: '商户管理后台-员工员工管理',
path: '/EmployeeManagement',
name: 'EmployeeManagement',
component: './EmployeeManagement',
},
{
component: './404',
},
......
const isProduction = process.env.NODE_ENV === 'production';
const isPre = process.env.PRE_ENV === 'pre';
const environment = 'yxm2';
const environment = 'xyqb';
const envAPi = {
api: `https://security-${environment}.liangkebang.net`, //'https://security-xyqb.liangkebang.net',
kdspOpApi: `https://sc-merchant-api-${environment}.liangkebang.net`,
......
import React, { useState } from 'react';
import { Modal, Form, Radio, Input, Button, Upload, message, Select } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import { apiDepartmentSave, apiDepartmentExcel } from '../service';
const { Item } = Form;
const layout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const DepartmentModal = ({ visible, onClose, enterpriseList }) => {
const [form] = Form.useForm();
const [importMode, setImportMode] = useState(false);
const handleCancel = val => {
form.resetFields();
setImportMode(false);
onClose(val);
};
const handleImportChange = info => {
if (info.file.status === 'done') {
message.success('文件上传成功');
} else if (info.file.status === 'error') {
message.error('文件上传失败');
}
};
const getDepartmentSave = async values => {
const params = {
name: values.name,
enterpriseId: values.enterpriseId,
};
const res = await apiDepartmentSave(params);
if (res.businessCode === '0000') {
message.success('保存成功');
handleCancel(true);
}
};
const getDepartmentExcel = async values => {
const params = {
name: values.name,
file: values.file,
};
const res = await apiDepartmentExcel(params);
if (res.businessCode === '0000') {
message.success('保存成功');
handleCancel(true);
}
};
const handleSave = () => {
form.validateFields().then(values => {
if (importMode) {
getDepartmentExcel(values);
return;
}
getDepartmentSave(values);
});
};
return (
<Modal
title="创建部门"
visible={visible}
onCancel={() => handleCancel(false)}
footer={[
<Button key="cancel" onClick={onClose}>
取消
</Button>,
<Button key="save" type="primary" onClick={() => handleSave()}>
保存
</Button>,
]}
initialValue={{ configMode: 0 }}
>
<Form form={form} {...layout}>
<Item
label="选择企业"
name="enterpriseId"
rules={[{ required: true, message: '请选择企业' }]}
>
<Select
placeholder="请选择企业"
allowClear
showSearch
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={enterpriseList}
/>
</Item>
<Item
label="配置方式"
name="configMode"
rules={[{ required: true, message: '请选择配置方式' }]}
initialValue={0}
>
<Radio.Group>
<Radio value={0} onChange={() => setImportMode(false)}>
单个添加
</Radio>
<Radio value={1} onChange={() => setImportMode(true)}>
批量导入
</Radio>
</Radio.Group>
</Item>
{importMode ? (
<Item
label="上传文件"
name="file"
rules={[
{ required: true, message: '请上传文件' },
{
// eslint-disable-next-line no-confusing-arrow
validator: (_, value) =>
value && value.fileList.length > 0
? Promise.resolve()
: // eslint-disable-next-line prefer-promise-reject-errors
Promise.reject('请上传文件'),
},
]}
>
<Upload beforeUpload={() => false} onChange={handleImportChange}>
<Button icon={<UploadOutlined />}>点击上传</Button>
</Upload>
</Item>
) : (
<Item
label="部门名称"
name="name"
rules={[{ required: true, message: '请输入部门名称' }]}
>
<Input />
</Item>
)}
</Form>
</Modal>
);
};
export default DepartmentModal;
import React, { useState } from 'react';
import { Modal, Form, Input, Button, Select, message } from 'antd';
import { apiStaffSave } from '../service';
const { Option } = Select;
const layout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const NewEmployeeModal = props => {
const { departmentList, visible, onClose, enterpriseList, getDepartmentList } = props;
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const handleSave = () => {
form.validateFields().then(async values => {
setLoading(true);
const res = await apiStaffSave(values);
if (res.businessCode === '0000') {
setLoading(false);
message.success('保存成功');
onClose(true);
}
});
};
const validatePhone = (_, value) => {
const phoneRegex = /^[1-9]\d{9}$/;
if (!value || phoneRegex.test(value)) {
return Promise.resolve();
}
// eslint-disable-next-line prefer-promise-reject-errors
return Promise.reject('请输入有效的手机号码');
};
const onChange = value => {
getDepartmentList(value);
};
return (
<Modal
visible={visible}
title="添加新员工"
onCancel={onClose}
footer={[
<Button key="cancel" onClick={onClose}>
取消
</Button>,
<Button key="save" type="primary" loading={loading} onClick={handleSave}>
保存
</Button>,
]}
>
<Form form={form} {...layout}>
<Form.Item
name="enterpriseId"
label="企业"
rules={[
{
required: true,
message: '请选择企业',
},
]}
>
<Select
onChange={onChange}
placeholder="请选择企业"
allowClear
showSearch
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={enterpriseList}
/>
</Form.Item>
<Form.Item
name="departmentId"
label="部门"
rules={[
{
required: true,
message: '请选择部门',
},
]}
>
<Select
placeholder="请选择部门"
allowClear
showSearch
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={departmentList}
/>
</Form.Item>
<Form.Item
name="staffNo"
label="员工ID"
rules={[
{
required: true,
message: '请输入员工ID',
},
]}
>
<Input />
</Form.Item>
<Form.Item
name="staffName"
label="员工姓名"
rules={[
{
required: true,
message: '请输入员工姓名',
},
]}
>
<Input />
</Form.Item>
<Form.Item
name="mobile"
label="员工手机号"
rules={[
{
required: true,
message: '请输入员工手机号',
},
{
validator: validatePhone,
},
]}
>
<Input />
</Form.Item>
</Form>
</Modal>
);
};
export default NewEmployeeModal;
import React, { useState } from 'react';
import { Modal, Form, Input, Button, Table, Space, Row, Col, Select } from 'antd';
import { apiDepartmentList } from '../service';
const { Item } = Form;
const ViewDepartmentModal = ({ visible, onClose, enterpriseList }) => {
const [form] = Form.useForm();
const [dataSource, setDataSource] = useState([]);
const [value, setValue] = useState('');
const [pagination, setPagination] = useState({
page: 1,
size: 10,
});
const handleCancel = () => {
form.resetFields();
onClose();
};
const handleSearch = async values => {
setPagination({ ...pagination, page: 1 });
setValue(value);
const res = await apiDepartmentList({ value, ...pagination });
if (res.businessCode === '0000' && res.data?.records?.length) {
const list = res.data.records;
const optionData = list.map(item => ({
value: item.id,
label: item.name,
}));
setDataSource(optionData);
}
};
const handleTableChange = (pag, filters, sorter) => {
setPagination(pag);
handleSearch();
};
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
},
{
title: '部门',
dataIndex: 'department',
key: 'department',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
},
{
title: '创建人',
dataIndex: 'creator',
key: 'creator',
},
{
title: '操作',
dataIndex: 'operation',
key: 'operation',
render: (_, record) => (
<Space>
<Button type="link">修改部门名称</Button>
</Space>
),
},
];
return (
<Modal visible={visible} onCancel={handleCancel} width={800} footer={null} title="查看部门">
<Form form={form} onFinish={handleSearch}>
<Row gutter={16}>
<Col span={10}>
<Item name="id" style={{ width: '300px' }}>
<Select
placeholder="请选择企业"
allowClear
showSearch
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={enterpriseList}
/>
</Item>
</Col>
<Col>
<Item>
<Button type="primary" htmlType="submit">
搜索
</Button>
</Item>
</Col>
</Row>
</Form>
<Table
dataSource={dataSource}
columns={columns}
pagination={pagination}
onChange={handleTableChange}
bordered
/>
</Modal>
);
};
export default ViewDepartmentModal;
import React from 'react';
import { Image as ImageComponent, Button, Switch } from 'antd';
import { FormOutlined } from '@ant-design/icons';
export const repastTypeList = [
{
value: 0,
label: '拉黑',
},
{
value: 1,
label: '正常',
},
];
export const columns = props => [
{
title: '部门名称',
key: 'departmentName',
dataIndex: 'departmentName',
align: 'center',
},
{
title: '员工姓名',
key: 'staffName',
dataIndex: 'staffName',
align: 'center',
},
{
title: '员工手机号',
key: 'mobile',
dataIndex: 'mobile',
align: 'center',
},
{
title: '员工状态',
key: 'isBlack',
dataIndex: 'isBlack',
align: 'center',
render: _ => (_ ? '拉黑' : '正常'),
},
{
title: '余额/券状态',
key: 'balanceBackFlag',
dataIndex: 'balanceBackFlag',
align: 'center',
render: _ => (_ ? '' : ''),
},
{
title: '是否消费限额',
key: 'balance',
dataIndex: 'balance',
align: 'center',
render: _ => (
<>
{' '}
<Switch defaultChecked /> {_ ? '已开启' : '已关闭'}
</>
),
},
{
title: '员工企业余额',
key: 'balanceBackFlag',
dataIndex: 'balanceBackFlag',
align: 'center',
},
{
title: '有效餐券张数',
key: 'couponCount',
dataIndex: 'couponCount',
align: 'center',
},
{
title: '操作',
dataIndex: 'option',
valueType: 'option',
align: 'center',
key: 'option',
render: (_, row) => [
<Button type="link">余额充值明细</Button>,
<Button type="link" disabled={!row?.isBlack} onClick={() => props.delShop(row)}>
删除
</Button>,
],
},
];
import React, { useState, useRef, forwardRef, useEffect } from 'react';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Modal, Form, Select, Table, Card, Row, Col, Input, Button, message, Upload } from 'antd';
import { columns, repastTypeList } from './data';
import styles from './index.less';
import { apiStaffList, apiEnterpriseList, apiDepartmentList, apiStaffExcel } from './service.js';
import NewEmployeeModal from './components/newEmployeeModal';
import DepartmentModal from './components/departmentModal';
import ViewDepartmentModal from './components/ViewDepartmentModal';
const { confirm } = Modal;
const StoreManagement = () => {
const [modalVisible, setModalVisible] = useState(false);
const [departmentVisible, setDepartmentVisible] = useState(false);
const [viewDepartmentVisible, setViewDepartmentVisible] = useState(false);
const [staffList, setStaffList] = useState([]);
const [enterpriseList, setEnterpriseList] = useState([]);
const [firstEnterprise, setFirstEnterprise] = useState();
const [departmentList, setDepartmentList] = useState([]);
const [page, setPage] = useState({
page: 1,
size: 10,
});
const [searchForm, setSearchForm] = useState({});
const formRef = useRef(null);
const [editVisible, setEditVisible] = useState(false);
const [addVisible, setAddVisible] = useState(false);
const [repastType, setRepastType] = useState([]);
const [repastId, setRepastId] = useState(null);
const data = [
{
enterpriseId: '企业id',
id: '1',
shopId: 'shopId',
shopName: '店铺名称',
mealType: '到店',
pickselfName: '',
updatedBy: '修改人名称',
amount: '2023/03/21 14:06:11',
isBlack: 0,
},
{
enterpriseId: '企业id',
id: '2',
shopId: 'shopId',
shopName: '店铺名称',
mealType: '到店',
pickselfName: '取餐点',
updatedBy: '修改人名称',
isBlack: 1,
},
];
const shopList = async () => {
const res = await apiStaffList({ ...page, data: searchForm });
if (res.businessCode === '0000' && res.data?.records?.length) {
const list = res.data.records;
setStaffList(list);
}
};
// 上传文件
const handleUpload = async info => {
if (info.file.status === 'done') {
console.log(info.file);
const res = await apiStaffExcel(info.file);
if (res.businessCode === '0000') {
message.success('上传成功');
shopList();
}
} else if (info.file.status === 'error') {
console.log('File upload failed:', info.file.error);
}
};
// 关闭弹框
const handleCloseModal = val => {
setModalVisible(false);
setDepartmentVisible(false);
setViewDepartmentVisible(false);
if (val) {
shopList();
}
};
// 部门查询
const getDepartmentList = async id => {
const res = await apiDepartmentList({ id, page: 1, size: 10000 });
if (res.businessCode === '0000' && res.data?.records?.length) {
const list = res.data.records;
const optionData = list.map(item => ({
value: item.id,
label: item.name,
}));
setDepartmentList(optionData);
return;
}
setDepartmentList([]);
};
// 企业查询
const getEnterpriseList = async () => {
const res = await apiEnterpriseList();
if (res.businessCode === '0000' && res.data?.records?.length) {
const list = res.data.records;
const firstOption = list[0].id;
const optionData = list.map(item => ({
value: item.id,
label: item.name,
}));
setFirstEnterprise(firstOption);
setEnterpriseList(optionData);
getDepartmentList(firstOption);
shopList();
}
};
useEffect(() => {
getEnterpriseList();
}, []);
const setMealTypeList = async () => {
// const res = await mealTypeList({ id: repastId });
// if (res.businessCode === '0000') {
// setRepastType(res.data);
setEditVisible(true);
// }
};
// 修改餐饮类型
const editRepastType = ({ id }) => {
setRepastId(id);
setMealTypeList();
};
// 删除
const deleteShop = async id => {
// const res = await setShopDelete({ id });
// if (res.businessCode === '0000') {
// message.success('删除成功!');
// shopList();
// }
};
// 删除
const delShop = ({ staffName, id }) => {
confirm({
title: `确认删除企业员工#${staffName || ''}#?`,
onOk() {
deleteShop(id);
},
onCancel() {
console.log('Cancel');
},
});
};
// 添加商户
const addShop = () => {
setAddVisible(true);
};
// 搜索
const onFinish = values => {
setSearchForm(values);
setPage({ current: 1, pageSize: 10 });
shopList();
};
// 重置
const onReset = () => {
formRef.current.resetFields();
shopList();
};
// 分页
const handleTableChange = val => {
setPage(val);
};
const res = {
editRepastType,
delShop,
};
return (
<PageHeaderWrapper>
<Card className={styles.card}>
<Form ref={formRef} onFinish={onFinish} initialValue={{ enterpriseId: firstEnterprise }}>
<Row gutter={24}>
<Col span={8}>
<Form.Item
label="企业名称"
name="enterpriseId"
wrapperCol={{ span: 16 }}
rules={[{ required: true }]}
>
<Select
allowClear
showSearch
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={enterpriseList}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="部门查询" name="departmentId" wrapperCol={{ span: 16 }}>
<Select
allowClear
showSearch
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={departmentList}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="员工手机号" name="mobile" wrapperCol={{ span: 16 }}>
<Input maxLength="11" allowClear />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="员工id" name="staffNo" wrapperCol={{ span: 16 }}>
<Input allowClear />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="员工状态" name="mealType" wrapperCol={{ span: 16 }}>
<Select
allowClear
showSearch
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={[
{
value: 0,
label: '正常',
},
{
value: 1,
label: '拉黑',
},
]}
placeholder="全部"
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="员工姓名" name="staffName" wrapperCol={{ span: 16 }}>
<Input maxLength="8" allowClear />
</Form.Item>
</Col>
<Col>
<Form.Item>
<Button type="primary" htmlType="submit">
搜索
</Button>
<Button htmlType="button" onClick={onReset} className={styles.left}>
重置
</Button>
</Form.Item>
</Col>
</Row>
</Form>
<div className={styles.addBtn}>
<Upload onChange={handleUpload} accept=".xls,.xlsx" maxCount={1} showUploadList={false}>
<Button type="primary">初始化数据上传Excel</Button>
</Upload>
<Button type="primary" className={styles.left}>
设置员工黑名单
</Button>
<Button
type="primary"
className={styles.left}
onClick={() => {
setModalVisible(true);
}}
>
添加新员工
</Button>
<Button
type="primary"
className={styles.left}
onClick={() => {
setDepartmentVisible(true);
}}
>
创建部门
</Button>
<Button
type="primary"
className={styles.left}
onClick={() => {
setViewDepartmentVisible(true);
}}
>
查看部门
</Button>
</div>
</Card>
<Table
columns={columns(res)}
dataSource={staffList}
rowKey={r => r.appealNo}
bordered
onChange={handleTableChange}
/>
<NewEmployeeModal
visible={modalVisible}
enterpriseList={enterpriseList}
departmentList={departmentList}
onClose={handleCloseModal}
getDepartmentList={getDepartmentList}
/>
<DepartmentModal
visible={departmentVisible}
enterpriseList={enterpriseList}
onClose={handleCloseModal}
/>
<ViewDepartmentModal
visible={viewDepartmentVisible}
enterpriseList={enterpriseList}
onClose={handleCloseModal}
/>
</PageHeaderWrapper>
);
};
export default StoreManagement;
.tip {
padding-top: 5px;
color: #ff8c00;
font-size: 12px;
}
.card {
margin-bottom: 16px;
}
.btn {
position: absolute;
right: 0;
bottom: 0;
display: flex;
}
.left {
margin-left: 20px;
}
.editShop {
margin-bottom: 10px;
}
.addBtn {
display: flex;
align-items: center;
justify-content: flex-end;
}
import request from '@/utils/request';
import config from '../../../config/env.config';
import { stringify } from 'qs';
import _ from 'lodash';
const { goodsApi } = config;
// [企业员工]-列表查询
// http://yapi.quantgroups.com/project/389/interface/api/65359
export const apiStaffList = async params => {
const data = await request.post('/api/consoles/enterprise/staff/pageList', {
prefix: goodsApi,
data: params,
});
return data;
};
// [企业客户]-列表查询
// http://yapi.quantgroups.com/project/389/interface/api/65324
export const apiEnterpriseList = async () => {
const data = await request.post('/api/consoles/enterprise/pageList', {
prefix: goodsApi,
data: {
page: 1,
size: 10000,
},
});
return data;
};
// [企业部门]-列表查询
// http://yapi.quantgroups.com/project/389/interface/api/65344
export const apiDepartmentList = async params => {
const data = await request.post('/api/consoles/enterprise/department/pageList', {
prefix: goodsApi,
data: params,
});
return data;
};
// [企业员工]-添加员工
// http://yapi.quantgroups.com/project/389/interface/api/65364
export const apiStaffSave = async params => {
const data = await request.post('/api/consoles/enterprise/staff/save', {
prefix: goodsApi,
data: params,
});
return data;
};
// [企业员工]-导入员工
// http://yapi.quantgroups.com/project/389/interface/api/65384
export const apiStaffExcel = async file => {
const params = new FormData();
params.append('file', file);
const data = await request.post('/api/consoles/enterprise/staff/excel', {
prefix: goodsApi,
data: params,
});
return data;
};
// [企业部门]-新增企业部门
// http://yapi.quantgroups.com/project/389/interface/api/65349
export const apiDepartmentSave = async params => {
const data = await request.post('/api/consoles/enterprise/department/save', {
prefix: goodsApi,
data: params,
});
return data;
};
// [企业部门]-导入企业部门
// http://yapi.quantgroups.com/project/389/interface/api/65354
export const apiDepartmentExcel = async file => {
const params = new FormData();
params.append('file', file.file);
params.append('enterpriseId', file.enterpriseId);
const data = await request.post('/api/consoles/enterprise/department/excel', {
prefix: goodsApi,
data: params,
});
return data;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment