xingyongchun
2 years ago
21 changed files with 957 additions and 942 deletions
@ -1,163 +1,171 @@ |
|||
/* |
|||
* @description : |
|||
* @description : |
|||
* @Date : 2021-04-07 14:39:33 |
|||
* @FilePath : \web\client\src\sections\user\components\userManagement\importUser.js |
|||
* @useStrict : use strict |
|||
*/ |
|||
|
|||
'use strict'; |
|||
import React, { useState } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { Button, Input, Card, Modal, Upload, message } from 'antd'; |
|||
import { Request } from '@peace/utils' |
|||
import request from 'superagent' |
|||
import XLSX from 'xlsx' |
|||
// import { userBulkAdd } from '../../actions'
|
|||
"use strict"; |
|||
import React, { useState } from "react"; |
|||
import { connect } from "react-redux"; |
|||
import { Button, Input, Card, Modal, Upload, message } from "antd"; |
|||
import { Request } from "@peace/utils"; |
|||
import request from "superagent"; |
|||
import XLSX from "xlsx"; |
|||
import { postInProject } from "../actions/article"; |
|||
|
|||
//TODO 下载模板和上传文件读取
|
|||
const ImportUser = props => { |
|||
const { user, dispatch, handleCancel, params,editData } = props |
|||
const [msg, setMsg] = useState('') |
|||
const [loading, setLoading] = useState('') |
|||
const [postData, setPostData] = useState([]) |
|||
const ImportUser = (props) => { |
|||
const { user, dispatch, handleCancel, params, editData } = props; |
|||
const [msg, setMsg] = useState(""); |
|||
const [loading, setLoading] = useState(""); |
|||
const [postData, setPostData] = useState([]); |
|||
|
|||
const confirm = () => { |
|||
if (postData.length) { |
|||
setLoading(true) |
|||
// dispatch(userBulkAdd(postData, params.departmentId ? params.departmentId : null)).then(res => {
|
|||
// if (res.success) {
|
|||
|
|||
// }
|
|||
// setLoading(false)
|
|||
// })
|
|||
} else { |
|||
message.warn('没有数据可以提交,请上传数据文件') |
|||
const confirm = () => { |
|||
if (postData.length) { |
|||
setLoading(true); |
|||
dispatch(postInProject(postData)).then((res) => { |
|||
console.log(res) |
|||
if (res.success) { |
|||
handleCancel(); |
|||
message.success("上传成功"); |
|||
} |
|||
setLoading(false); |
|||
}); |
|||
} else { |
|||
message.warn("没有数据可以提交,请上传数据文件"); |
|||
} |
|||
}; |
|||
|
|||
return ( |
|||
<Modal |
|||
visible={props.importVisible} |
|||
onOk={confirm} |
|||
confirmLoading={loading} |
|||
onCancel={() => { |
|||
setMsg('') |
|||
setLoading(false) |
|||
setPostData([]) |
|||
handleCancel() |
|||
}} |
|||
destroyOnClose |
|||
> |
|||
{/* <Button size="small" type='primary' onClick={() => { |
|||
return ( |
|||
<Modal |
|||
visible={props.importVisible} |
|||
onOk={confirm} |
|||
confirmLoading={loading} |
|||
onCancel={() => { |
|||
setMsg(""); |
|||
setLoading(false); |
|||
setPostData([]); |
|||
handleCancel(); |
|||
}} |
|||
destroyOnClose |
|||
> |
|||
{/* <Button size="small" type='primary' onClick={() => { |
|||
Request.get(`attachments?src=upload/files/1.jpg&filename=${encodeURIComponent('1.jpg')}&token=${user.token}`).then(res => { |
|||
|
|||
}) |
|||
}}>下载模板</Button> */} |
|||
<a href={'/_api/' + `attachments?src=files/用户信息导入模板.xlsx&filename=${encodeURIComponent('用户信息导入模板.xlsx')}&token=${user.token}`} > |
|||
<Button size="small" type='primary' >下载模板</Button> |
|||
</a> |
|||
<div style={{ marginTop: 10 }}>下载模板后填写完整后上传</div> |
|||
<div style={{ marginTop: 10 }}> |
|||
<Upload {...{ |
|||
name: 'user_d', |
|||
action: '/', |
|||
maxCount: 1, |
|||
showUploadList: { |
|||
showRemoveIcon: false |
|||
}, |
|||
beforeUpload: (file) => { |
|||
setMsg('') |
|||
setPostData([]) |
|||
const extNames = file.name.split('.'); |
|||
let isDAE = false; |
|||
if (extNames.length > 0) { |
|||
let fileType = extNames[extNames.length - 1].toLowerCase(); |
|||
isDAE = ['xlsx', 'xls'].some((f) => f == fileType); |
|||
} |
|||
if (!isDAE) { |
|||
setMsg(`只能上传 ${['xlsx', 'xls'].join()} 格式的文件!`); |
|||
return false; |
|||
} |
|||
}, |
|||
onChange(info) { |
|||
<a |
|||
href={ |
|||
"/_api/" + |
|||
`attachments?src=files/用户信息导入模板.xlsx&filename=${encodeURIComponent( |
|||
"用户信息导入模板.xlsx" |
|||
)}&token=${user.token}` |
|||
} |
|||
> |
|||
<Button size="small" type="primary"> |
|||
下载模板 |
|||
</Button> |
|||
</a> |
|||
<div style={{ marginTop: 10 }}>下载模板后填写完整后上传</div> |
|||
<div style={{ marginTop: 10 }}> |
|||
<Upload |
|||
{...{ |
|||
name: "user_d", |
|||
action: "/", |
|||
maxCount: 1, |
|||
showUploadList: { |
|||
showRemoveIcon: false, |
|||
}, |
|||
beforeUpload: (file) => { |
|||
setMsg(""); |
|||
setPostData([]); |
|||
const extNames = file.name.split("."); |
|||
let isDAE = false; |
|||
if (extNames.length > 0) { |
|||
let fileType = extNames[extNames.length - 1].toLowerCase(); |
|||
isDAE = ["xlsx", "xls"].some((f) => f == fileType); |
|||
} |
|||
if (!isDAE) { |
|||
setMsg(`只能上传 ${["xlsx", "xls"].join()} 格式的文件!`); |
|||
return false; |
|||
} |
|||
}, |
|||
onChange(info) {}, |
|||
customRequest: async (data) => { |
|||
const { file, onSuccess, onError } = data; |
|||
|
|||
}, |
|||
customRequest: async (data) => { |
|||
const { file, onSuccess, onError } = data |
|||
const reader = new FileReader(); // 使用 FileReader 读取数据
|
|||
reader.onload = function (e) { |
|||
// 数据读取完成后的回调函数
|
|||
const data = new Uint8Array(e.target.result); |
|||
const workbook = XLSX.read(data, { type: "array" }); // workbook 是 xlsx 解析 excel 后返回的对象
|
|||
|
|||
const reader = new FileReader(); // 使用 FileReader 读取数据
|
|||
reader.onload = function (e) { // 数据读取完成后的回调函数
|
|||
const data = new Uint8Array(e.target.result); |
|||
const workbook = XLSX.read(data, { type: 'array' }); // workbook 是 xlsx 解析 excel 后返回的对象
|
|||
const firstSheetName = workbook.SheetNames[0]; // 获取第一个 sheet 的名字
|
|||
const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个 sheet 的内容
|
|||
const res = XLSX.utils.sheet_to_json(worksheet); // 使用 utils 里的方法转换内容为便于使用的数组
|
|||
const error = (msg) => { |
|||
setMsg(msg); |
|||
onError({ message: msg }); |
|||
}; |
|||
if (res.length > 1000) { |
|||
error("一次性上传数据行数应小于1000行,请分批上传"); |
|||
return; |
|||
} |
|||
if (!res.length) { |
|||
error("请填写至少一行数据"); |
|||
return; |
|||
} |
|||
let postData = []; |
|||
|
|||
const firstSheetName = workbook.SheetNames[0]; // 获取第一个 sheet 的名字
|
|||
const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个 sheet 的内容
|
|||
const res = XLSX.utils.sheet_to_json(worksheet); // 使用 utils 里的方法转换内容为便于使用的数组
|
|||
const error = (msg) => { |
|||
setMsg(msg) |
|||
onError({ message: msg }) |
|||
} |
|||
if (res.length > 1000) { |
|||
error('一次性上传数据行数应小于1000行,请分批上传') |
|||
return |
|||
} |
|||
if (!res.length) { |
|||
error('请填写至少一行数据') |
|||
return |
|||
} |
|||
let postData = [] |
|||
const pattern = /^1[3|4|5|6|7|8|9]\d{9}$/ |
|||
for (let i = 0; i < res.length; i++) { |
|||
let d = res[i] |
|||
let name = String(d['姓名']).trim(); |
|||
let phone = String(d['手机号码']).trim(); |
|||
let account = String(d['账号']).trim(); |
|||
let peopleCode = d['人员编号'] && String(d['人员编号']).trim(); |
|||
if (!name || !phone || !account || !peopleCode) { |
|||
error(`第${i + 1} 行有空值,请填写后重新上传`) |
|||
return |
|||
} |
|||
if (!pattern.test(phone)) { |
|||
error(`第${i + 1} 行手机号码错误`) |
|||
return |
|||
} |
|||
if (name.length > 128 || account.length > 128) { |
|||
error(`第${i + 1} 行数据字符长度大于 128,请更改后重新上传`) |
|||
return |
|||
} |
|||
if (postData.some(p => p.account == account)) { |
|||
error(`第${i + 1} 行账号重复,请更改后重新上传`) |
|||
return |
|||
} |
|||
postData.push({ |
|||
name, phone, account, peopleCode |
|||
}) |
|||
} |
|||
if (postData.length) { |
|||
setPostData(postData) |
|||
} |
|||
let msg = '文件解析完成,点击确定按钮上传保存!' |
|||
setMsg(msg) |
|||
onSuccess({ message: msg }) |
|||
}; |
|||
reader.readAsArrayBuffer(file); // 读取数据
|
|||
}, |
|||
}}> |
|||
<Button>上传文件</Button> |
|||
</Upload> |
|||
<br /> |
|||
<span>{msg}</span> |
|||
</div> |
|||
</Modal > |
|||
) |
|||
} |
|||
for (let i = 0; i < res.length; i++) { |
|||
let d = res[i]; |
|||
let name_project = String(d["版本计划"]).trim(); |
|||
|
|||
let part_people_in = String(d["投入人力"]).trim(); |
|||
let build_time = String(d["构建时间"]).trim(); |
|||
let publish_time = String(d["发布时间"]).trim(); |
|||
let progress = String(d["目前进度"]).trim(); |
|||
if (!name_project || !part_people_in || !build_time || !publish_time||!progress) { |
|||
error(`第${i + 1} 行有空值,请填写后重新上传`); |
|||
return; |
|||
} |
|||
let part_people = part_people_in.split('、').map((i) => { |
|||
return {name_people:i} |
|||
}) |
|||
|
|||
postData.push({ |
|||
name_project, |
|||
part_people, |
|||
build_time, |
|||
publish_time,progress |
|||
}); |
|||
} |
|||
if (postData.length) { |
|||
setPostData(postData); |
|||
} |
|||
let msg = "文件解析完成,点击确定按钮上传保存!"; |
|||
setMsg(msg); |
|||
onSuccess({ message: msg }); |
|||
}; |
|||
reader.readAsArrayBuffer(file); // 读取数据
|
|||
}, |
|||
}} |
|||
> |
|||
<Button>上传文件</Button> |
|||
</Upload> |
|||
<br /> |
|||
<span>{msg}</span> |
|||
</div> |
|||
</Modal> |
|||
); |
|||
}; |
|||
|
|||
function mapStateToProps(state) { |
|||
const { auth, customizeList } = state; |
|||
return { |
|||
user: auth.user, |
|||
} |
|||
const { auth, customizeList } = state; |
|||
return { |
|||
user: auth.user, |
|||
}; |
|||
} |
|||
|
|||
|
|||
export default connect(mapStateToProps)(ImportUser); |
|||
export default connect(mapStateToProps)(ImportUser); |
|||
|
@ -1,182 +1,182 @@ |
|||
import React, { Component, useState, useEffect } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { |
|||
Card, Form, Input, Button, Row, Col, Alert, message, |
|||
} from 'antd'; |
|||
import { resetPwd, RESET_PASSWORD_SUCCESS } from '../actions/reset-pwd'; |
|||
import { sendPhoneCode, checkPhoneCode, checkPhone } from '../actions/validate-phone'; |
|||
// import React, { Component, useState, useEffect } from 'react';
|
|||
// import { connect } from 'react-redux';
|
|||
// import {
|
|||
// Card, Form, Input, Button, Row, Col, Alert, message,
|
|||
// } from 'antd';
|
|||
// import { resetPwd, RESET_PASSWORD_SUCCESS } from '../actions/reset-pwd';
|
|||
// import { sendPhoneCode, checkPhoneCode, checkPhone } from '../actions/validate-phone';
|
|||
|
|||
const FormItem = Form.Item; |
|||
// const FormItem = Form.Item;
|
|||
|
|||
function ForgetPwdContainer(props) { |
|||
const { dispatch, match: { params }, isRequesting } = props; |
|||
const [form] = Form.useForm(); |
|||
const [sleeping, setSleeping] = useState(false); |
|||
let [sleepCount, setSleepCount] = useState(60); |
|||
const [done, setDone] = useState(false); |
|||
let timer; |
|||
// function ForgetPwdContainer(props) {
|
|||
// const { dispatch, match: { params }, isRequesting } = props;
|
|||
// const [form] = Form.useForm();
|
|||
// const [sleeping, setSleeping] = useState(false);
|
|||
// let [sleepCount, setSleepCount] = useState(60);
|
|||
// const [done, setDone] = useState(false);
|
|||
// let timer;
|
|||
|
|||
const _checkPhone = async (rule, value, callback) => { |
|||
await checkPhone(value, params.domain).then((_) => { |
|||
// const _checkPhone = async (rule, value, callback) => {
|
|||
// await checkPhone(value, params.domain).then((_) => {
|
|||
|
|||
}, (err) => { |
|||
throw new Error('未发现绑定该手机的账号!'); |
|||
}); |
|||
}; |
|||
// }, (err) => {
|
|||
// throw new Error('未发现绑定该手机的账号!');
|
|||
// });
|
|||
// };
|
|||
|
|||
const fetchVCode = async () => { |
|||
const phoneObj = await form.validateFields(['phone']); |
|||
await sendPhoneCode(phoneObj.phone).then((_) => { |
|||
setSleeping(true); |
|||
timer = setInterval((_) => { |
|||
if (sleepCount == 0) { |
|||
setSleeping(false); |
|||
setSleepCount(60); |
|||
clearInterval(timer); |
|||
return; |
|||
} |
|||
setSleepCount(sleepCount--); |
|||
}, 1000); |
|||
setSleepCount(sleepCount--); |
|||
}); |
|||
}; |
|||
// const fetchVCode = async () => {
|
|||
// const phoneObj = await form.validateFields(['phone']);
|
|||
// await sendPhoneCode(phoneObj.phone).then((_) => {
|
|||
// setSleeping(true);
|
|||
// timer = setInterval((_) => {
|
|||
// if (sleepCount == 0) {
|
|||
// setSleeping(false);
|
|||
// setSleepCount(60);
|
|||
// clearInterval(timer);
|
|||
// return;
|
|||
// }
|
|||
// setSleepCount(sleepCount--);
|
|||
// }, 1000);
|
|||
// setSleepCount(sleepCount--);
|
|||
// });
|
|||
// };
|
|||
|
|||
const submit = () => { |
|||
form.validateFields().then((values) => { |
|||
checkPhoneCode(values.phone, values.code).then((_) => { |
|||
dispatch(resetPwd(params.domain, values.phone, values.code, values.password)) |
|||
.then((action) => { |
|||
if (action.type == RESET_PASSWORD_SUCCESS) { |
|||
setDone(true); |
|||
} else { |
|||
message.error(action.payload.error); |
|||
} |
|||
}); |
|||
}, (err) => { |
|||
message.error(err.response.body.message); |
|||
}); |
|||
}); |
|||
}; |
|||
// const submit = () => {
|
|||
// form.validateFields().then((values) => {
|
|||
// checkPhoneCode(values.phone, values.code).then((_) => {
|
|||
// dispatch(resetPwd(params.domain, values.phone, values.code, values.password))
|
|||
// .then((action) => {
|
|||
// if (action.type == RESET_PASSWORD_SUCCESS) {
|
|||
// setDone(true);
|
|||
// } else {
|
|||
// message.error(action.payload.error);
|
|||
// }
|
|||
// });
|
|||
// }, (err) => {
|
|||
// message.error(err.response.body.message);
|
|||
// });
|
|||
// });
|
|||
// };
|
|||
|
|||
return ( |
|||
<div> |
|||
<div style={{ textAlign: 'center', padding: '100px 0 50px 0' }}> |
|||
<img src="/assets/images/anxinyun.png" width="180px" /> |
|||
</div> |
|||
<Card style={{ width: 500, padding: 50, margin: '0 auto' }}> |
|||
<h3 style={{ |
|||
color: '#666', paddingBottom: 5, marginBottom: 30, borderBottom: '1px solid #666', |
|||
}} |
|||
> |
|||
找回密码 |
|||
</h3> |
|||
{ |
|||
done |
|||
? ( |
|||
<Alert |
|||
message="完成" |
|||
description={( |
|||
<div> |
|||
<p> |
|||
已成功验证您的手机号: |
|||
{form.getFieldValue('phone')} |
|||
, 并重置密码 |
|||
</p> |
|||
<div style={{ padding: '30px 0', fontWeight: 'bold' }}> |
|||
<a href={`/${params.domain}/signin`}>返回登录</a> |
|||
</div> |
|||
</div> |
|||
)} |
|||
type="success" |
|||
showIcon |
|||
/> |
|||
) |
|||
: ( |
|||
<div> |
|||
<Form form={form}> |
|||
<FormItem |
|||
hasFeedback |
|||
name="phone" |
|||
validateFirst |
|||
rules={[{ |
|||
pattern: /^1[3|4|5|7|8|9]\d{9}$/, message: '手机号码无效', |
|||
}, { |
|||
required: true, message: '手机号码不能为空', |
|||
}, { |
|||
validator: _checkPhone, |
|||
}, { |
|||
validateTrigger: 'onBlur', |
|||
}]} |
|||
> |
|||
<Input maxLength="11" placeholder="请输入注册时填写的手机号" /> |
|||
</FormItem> |
|||
<FormItem> |
|||
<Row> |
|||
<Col span={16}> |
|||
<FormItem |
|||
name="code" |
|||
noStyle |
|||
rules={[{ |
|||
required: true, message: '验证码不能为空', |
|||
}]} |
|||
> |
|||
<Input type="text" maxLength="8" placeholder="请输入验证码" /> |
|||
</FormItem> |
|||
// return (
|
|||
// <div>
|
|||
// <div style={{ textAlign: 'center', padding: '100px 0 50px 0' }}>
|
|||
// <img src="/assets/images/anxinyun.png" width="180px" />
|
|||
// </div>
|
|||
// <Card style={{ width: 500, padding: 50, margin: '0 auto' }}>
|
|||
// <h3 style={{
|
|||
// color: '#666', paddingBottom: 5, marginBottom: 30, borderBottom: '1px solid #666',
|
|||
// }}
|
|||
// >
|
|||
// 找回密码
|
|||
// </h3>
|
|||
// {
|
|||
// done
|
|||
// ? (
|
|||
// <Alert
|
|||
// message="完成"
|
|||
// description={(
|
|||
// <div>
|
|||
// <p>
|
|||
// 已成功验证您的手机号:
|
|||
// {form.getFieldValue('phone')}
|
|||
// , 并重置密码
|
|||
// </p>
|
|||
// <div style={{ padding: '30px 0', fontWeight: 'bold' }}>
|
|||
// <a href={`/${params.domain}/signin`}>返回登录</a>
|
|||
// </div>
|
|||
// </div>
|
|||
// )}
|
|||
// type="success"
|
|||
// showIcon
|
|||
// />
|
|||
// )
|
|||
// : (
|
|||
// <div>
|
|||
// <Form form={form}>
|
|||
// <FormItem
|
|||
// hasFeedback
|
|||
// name="phone"
|
|||
// validateFirst
|
|||
// rules={[{
|
|||
// pattern: /^1[3|4|5|7|8|9]\d{9}$/, message: '手机号码无效',
|
|||
// }, {
|
|||
// required: true, message: '手机号码不能为空',
|
|||
// }, {
|
|||
// validator: _checkPhone,
|
|||
// }, {
|
|||
// validateTrigger: 'onBlur',
|
|||
// }]}
|
|||
// >
|
|||
// <Input maxLength="11" placeholder="请输入注册时填写的手机号" />
|
|||
// </FormItem>
|
|||
// <FormItem>
|
|||
// <Row>
|
|||
// <Col span={16}>
|
|||
// <FormItem
|
|||
// name="code"
|
|||
// noStyle
|
|||
// rules={[{
|
|||
// required: true, message: '验证码不能为空',
|
|||
// }]}
|
|||
// >
|
|||
// <Input type="text" maxLength="8" placeholder="请输入验证码" />
|
|||
// </FormItem>
|
|||
|
|||
</Col> |
|||
<Col span={8}> |
|||
<Button type="primary" onClick={fetchVCode} loading={sleeping} style={{ float: 'right' }}> |
|||
{sleeping ? `${sleepCount}s后重试` : '获取验证码'} |
|||
</Button> |
|||
</Col> |
|||
</Row> |
|||
</FormItem> |
|||
<FormItem |
|||
hasFeedback |
|||
name="password" |
|||
rules={[{ |
|||
pattern: /^[a-z0-9A-Z_]{6,20}$/, message: '密码由6-20位字母、数字或_组成', |
|||
}, { |
|||
required: true, message: '密码不能为空', |
|||
}]} |
|||
> |
|||
<Input type="password" placeholder="请输入新密码" /> |
|||
</FormItem> |
|||
<FormItem |
|||
hasFeedback |
|||
name="rptpwd" |
|||
rules={[{ |
|||
required: true, message: '密码不能为空', |
|||
}, { |
|||
validator: async (rule, value) => { |
|||
if (form.getFieldValue('password') != value) { |
|||
throw new Error('两次输入的密码不一致!'); |
|||
} |
|||
}, |
|||
}]} |
|||
> |
|||
<Input type="password" placeholder="请再次输入新密码" /> |
|||
</FormItem> |
|||
<FormItem> |
|||
<Button type="primary" style={{ width: '100%' }} loading={isRequesting} onClick={submit}>重设密码</Button> |
|||
</FormItem> |
|||
</Form> |
|||
<div style={{ padding: '30px 0 0 0' }}> |
|||
<a href={`/${params.domain}/signin`}>返回登录</a> |
|||
</div> |
|||
</div> |
|||
) |
|||
} |
|||
</Card> |
|||
</div> |
|||
); |
|||
} |
|||
// </Col>
|
|||
// <Col span={8}>
|
|||
// <Button type="primary" onClick={fetchVCode} loading={sleeping} style={{ float: 'right' }}>
|
|||
// {sleeping ? `${sleepCount}s后重试` : '获取验证码'}
|
|||
// </Button>
|
|||
// </Col>
|
|||
// </Row>
|
|||
// </FormItem>
|
|||
// <FormItem
|
|||
// hasFeedback
|
|||
// name="password"
|
|||
// rules={[{
|
|||
// pattern: /^[a-z0-9A-Z_]{6,20}$/, message: '密码由6-20位字母、数字或_组成',
|
|||
// }, {
|
|||
// required: true, message: '密码不能为空',
|
|||
// }]}
|
|||
// >
|
|||
// <Input type="password" placeholder="请输入新密码" />
|
|||
// </FormItem>
|
|||
// <FormItem
|
|||
// hasFeedback
|
|||
// name="rptpwd"
|
|||
// rules={[{
|
|||
// required: true, message: '密码不能为空',
|
|||
// }, {
|
|||
// validator: async (rule, value) => {
|
|||
// if (form.getFieldValue('password') != value) {
|
|||
// throw new Error('两次输入的密码不一致!');
|
|||
// }
|
|||
// },
|
|||
// }]}
|
|||
// >
|
|||
// <Input type="password" placeholder="请再次输入新密码" />
|
|||
// </FormItem>
|
|||
// <FormItem>
|
|||
// <Button type="primary" style={{ width: '100%' }} loading={isRequesting} onClick={submit}>重设密码</Button>
|
|||
// </FormItem>
|
|||
// </Form>
|
|||
// <div style={{ padding: '30px 0 0 0' }}>
|
|||
// <a href={`/${params.domain}/signin`}>返回登录</a>
|
|||
// </div>
|
|||
// </div>
|
|||
// )
|
|||
// }
|
|||
// </Card>
|
|||
// </div>
|
|||
// );
|
|||
// }
|
|||
|
|||
function mapStateToProps(state) { |
|||
const { resetPwd } = state; |
|||
return { |
|||
isRequesting: resetPwd.isRequesting, |
|||
}; |
|||
} |
|||
// function mapStateToProps(state) {
|
|||
// const { resetPwd } = state;
|
|||
// return {
|
|||
// isRequesting: resetPwd.isRequesting,
|
|||
// };
|
|||
// }
|
|||
|
|||
export default connect(mapStateToProps)(ForgetPwdContainer); |
|||
// export default connect(mapStateToProps)(ForgetPwdContainer);
|
|||
|
@ -0,0 +1,92 @@ |
|||
import PropTypes from 'prop-types' |
|||
import React, { useEffect, useState } from "react"; |
|||
import { connect } from 'react-redux' |
|||
import { Table, message } from 'antd' |
|||
// import { getPartyMember } from '../../homePage/actions/profile'
|
|||
import { editLaborParty } from '../actions/party' |
|||
import EditParty from '../components/edit-party'; |
|||
|
|||
var request = false |
|||
export const Default = (props) => { |
|||
|
|||
const { dispatch } = props; |
|||
|
|||
const [partyLabor, setPartyLabor] = useState(); |
|||
const [showEdit, setShowEdit] = useState(false); |
|||
const [editData, setEditData] = useState(); |
|||
|
|||
useEffect(() => { |
|||
// dispatch(getPartyMember()).then(res => {
|
|||
// if (res.success) {
|
|||
// setPartyLabor(res.payload.data);
|
|||
// }
|
|||
// })
|
|||
}, [request]) |
|||
|
|||
const onEditParty = (record) => { |
|||
setShowEdit(true); |
|||
setEditData(record) |
|||
} |
|||
|
|||
const tableColumns = [ |
|||
{ |
|||
key: 'num', |
|||
dataIndex: 'num', |
|||
title: '序号', |
|||
render: () => { |
|||
return <span>1</span> |
|||
} |
|||
}, |
|||
{ |
|||
key: 'partyNumber', |
|||
dataIndex: 'partyNumber', |
|||
title: '党员人数', |
|||
}, |
|||
{ |
|||
key: 'laborUnion', |
|||
dataIndex: 'laborUnion', |
|||
title: '工会人数', |
|||
}, |
|||
{ |
|||
key: 'ation', |
|||
title: '操作', |
|||
render: (text, record) => { |
|||
return <a onClick={() => onEditParty(record)}>编辑</a> |
|||
} |
|||
} |
|||
] |
|||
|
|||
const handleOk = (values) => { |
|||
if (values) { |
|||
const { labor, party } = values |
|||
const result = { partyNumber: party, laborUnion: labor } |
|||
dispatch(editLaborParty(result)).then(res => { |
|||
if (res.success) { |
|||
message.success("编辑成功"); |
|||
request = !request; |
|||
handleCancel(); |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
const handleCancel = () => { |
|||
setShowEdit(false); |
|||
} |
|||
|
|||
return ( |
|||
<div> |
|||
<p style={{ marginBottom: 16, fontSize: 16 }}>党员、工会人数维护</p> |
|||
<Table columns={tableColumns} dataSource={partyLabor ? [partyLabor] : []} /> |
|||
<EditParty editData={editData} visible={showEdit} handleOk={handleOk} handleCancel={handleCancel} /> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
Default.propTypes = { |
|||
second: PropTypes.third |
|||
} |
|||
|
|||
const mapStateToProps = (state) => ({}) |
|||
|
|||
|
|||
export default connect(mapStateToProps)(Default) |
@ -1,163 +1,189 @@ |
|||
/* |
|||
* @description : |
|||
* @description : |
|||
* @Date : 2021-04-07 14:39:33 |
|||
* @FilePath : \web\client\src\sections\user\components\userManagement\importUser.js |
|||
* @useStrict : use strict |
|||
*/ |
|||
|
|||
'use strict'; |
|||
import React, { useState } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { Button, Input, Card, Modal, Upload, message } from 'antd'; |
|||
import { Request } from '@peace/utils' |
|||
import request from 'superagent' |
|||
import XLSX from 'xlsx' |
|||
// import { userBulkAdd } from '../../actions'
|
|||
"use strict"; |
|||
import React, { useState } from "react"; |
|||
import { connect } from "react-redux"; |
|||
import { Button, Input, Card, Modal, Upload, message } from "antd"; |
|||
import { Request } from "@peace/utils"; |
|||
import request from "superagent"; |
|||
import XLSX from "xlsx"; |
|||
import { postInPeople } from "../actions/article"; |
|||
|
|||
//TODO 下载模板和上传文件读取
|
|||
const ImportUser = props => { |
|||
const { user, dispatch, handleCancel, params,editData } = props |
|||
const [msg, setMsg] = useState('') |
|||
const [loading, setLoading] = useState('') |
|||
const [postData, setPostData] = useState([]) |
|||
const ImportUser = (props) => { |
|||
const { user, dispatch, handleCancel, params, editData } = props; |
|||
const [msg, setMsg] = useState(""); |
|||
const [loading, setLoading] = useState(""); |
|||
const [postData, setPostData] = useState([]); |
|||
|
|||
const confirm = () => { |
|||
if (postData.length) { |
|||
setLoading(true) |
|||
// dispatch(userBulkAdd(postData, params.departmentId ? params.departmentId : null)).then(res => {
|
|||
// if (res.success) {
|
|||
|
|||
// }
|
|||
// setLoading(false)
|
|||
// })
|
|||
} else { |
|||
message.warn('没有数据可以提交,请上传数据文件') |
|||
const confirm = () => { |
|||
if (postData.length) { |
|||
setLoading(true); |
|||
dispatch(postInPeople(postData)).then((res) => { |
|||
if (res.success) { |
|||
handleCancel(); |
|||
message.success("上传成功"); |
|||
} |
|||
setLoading(false); |
|||
}); |
|||
} else { |
|||
message.warn("没有数据可以提交,请上传数据文件"); |
|||
} |
|||
}; |
|||
|
|||
return ( |
|||
<Modal |
|||
visible={props.importVisible} |
|||
onOk={confirm} |
|||
confirmLoading={loading} |
|||
onCancel={() => { |
|||
setMsg('') |
|||
setLoading(false) |
|||
setPostData([]) |
|||
handleCancel() |
|||
}} |
|||
destroyOnClose |
|||
> |
|||
{/* <Button size="small" type='primary' onClick={() => { |
|||
return ( |
|||
<Modal |
|||
visible={props.importVisible} |
|||
onOk={confirm} |
|||
confirmLoading={loading} |
|||
onCancel={() => { |
|||
setMsg(""); |
|||
setLoading(false); |
|||
setPostData([]); |
|||
handleCancel(); |
|||
}} |
|||
destroyOnClose |
|||
> |
|||
{/* <Button size="small" type='primary' onClick={() => { |
|||
Request.get(`attachments?src=upload/files/1.jpg&filename=${encodeURIComponent('1.jpg')}&token=${user.token}`).then(res => { |
|||
|
|||
}) |
|||
}}>下载模板</Button> */} |
|||
<a href={'/_api/' + `attachments?src=files/用户信息导入模板.xlsx&filename=${encodeURIComponent('用户信息导入模板.xlsx')}&token=${user.token}`} > |
|||
<Button size="small" type='primary' >下载模板</Button> |
|||
</a> |
|||
<div style={{ marginTop: 10 }}>下载模板后填写完整后上传</div> |
|||
<div style={{ marginTop: 10 }}> |
|||
<Upload {...{ |
|||
name: 'user_d', |
|||
action: '/', |
|||
maxCount: 1, |
|||
showUploadList: { |
|||
showRemoveIcon: false |
|||
}, |
|||
beforeUpload: (file) => { |
|||
setMsg('') |
|||
setPostData([]) |
|||
const extNames = file.name.split('.'); |
|||
let isDAE = false; |
|||
if (extNames.length > 0) { |
|||
let fileType = extNames[extNames.length - 1].toLowerCase(); |
|||
isDAE = ['xlsx', 'xls'].some((f) => f == fileType); |
|||
} |
|||
if (!isDAE) { |
|||
setMsg(`只能上传 ${['xlsx', 'xls'].join()} 格式的文件!`); |
|||
return false; |
|||
} |
|||
}, |
|||
onChange(info) { |
|||
<a |
|||
href={ |
|||
"/_api/" + |
|||
`attachments?src=files/用户信息导入模板.xlsx&filename=${encodeURIComponent( |
|||
"用户信息导入模板.xlsx" |
|||
)}&token=${user.token}` |
|||
} |
|||
> |
|||
<Button size="small" type="primary"> |
|||
下载模板 |
|||
</Button> |
|||
</a> |
|||
<div style={{ marginTop: 10 }}>下载模板后填写完整后上传</div> |
|||
<div style={{ marginTop: 10 }}> |
|||
<Upload |
|||
{...{ |
|||
name: "user_d", |
|||
action: "/", |
|||
maxCount: 1, |
|||
showUploadList: { |
|||
showRemoveIcon: false, |
|||
}, |
|||
beforeUpload: (file) => { |
|||
setMsg(""); |
|||
setPostData([]); |
|||
const extNames = file.name.split("."); |
|||
let isDAE = false; |
|||
if (extNames.length > 0) { |
|||
let fileType = extNames[extNames.length - 1].toLowerCase(); |
|||
isDAE = ["xlsx", "xls"].some((f) => f == fileType); |
|||
} |
|||
if (!isDAE) { |
|||
setMsg(`只能上传 ${["xlsx", "xls"].join()} 格式的文件!`); |
|||
return false; |
|||
} |
|||
}, |
|||
onChange(info) {}, |
|||
customRequest: async (data) => { |
|||
const { file, onSuccess, onError } = data; |
|||
|
|||
}, |
|||
customRequest: async (data) => { |
|||
const { file, onSuccess, onError } = data |
|||
const reader = new FileReader(); // 使用 FileReader 读取数据
|
|||
reader.onload = function (e) { |
|||
// 数据读取完成后的回调函数
|
|||
const data = new Uint8Array(e.target.result); |
|||
const workbook = XLSX.read(data, { type: "array" }); // workbook 是 xlsx 解析 excel 后返回的对象
|
|||
|
|||
const reader = new FileReader(); // 使用 FileReader 读取数据
|
|||
reader.onload = function (e) { // 数据读取完成后的回调函数
|
|||
const data = new Uint8Array(e.target.result); |
|||
const workbook = XLSX.read(data, { type: 'array' }); // workbook 是 xlsx 解析 excel 后返回的对象
|
|||
const firstSheetName = workbook.SheetNames[0]; // 获取第一个 sheet 的名字
|
|||
const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个 sheet 的内容
|
|||
const res = XLSX.utils.sheet_to_json(worksheet); // 使用 utils 里的方法转换内容为便于使用的数组
|
|||
console.log(res); |
|||
const error = (msg) => { |
|||
setMsg(msg); |
|||
onError({ message: msg }); |
|||
}; |
|||
if (res.length > 1000) { |
|||
error("一次性上传数据行数应小于1000行,请分批上传"); |
|||
return; |
|||
} |
|||
if (!res.length) { |
|||
error("请填写至少一行数据"); |
|||
return; |
|||
} |
|||
let postData = []; |
|||
|
|||
const firstSheetName = workbook.SheetNames[0]; // 获取第一个 sheet 的名字
|
|||
const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个 sheet 的内容
|
|||
const res = XLSX.utils.sheet_to_json(worksheet); // 使用 utils 里的方法转换内容为便于使用的数组
|
|||
const error = (msg) => { |
|||
setMsg(msg) |
|||
onError({ message: msg }) |
|||
} |
|||
if (res.length > 1000) { |
|||
error('一次性上传数据行数应小于1000行,请分批上传') |
|||
return |
|||
} |
|||
if (!res.length) { |
|||
error('请填写至少一行数据') |
|||
return |
|||
} |
|||
let postData = [] |
|||
const pattern = /^1[3|4|5|6|7|8|9]\d{9}$/ |
|||
for (let i = 0; i < res.length; i++) { |
|||
let d = res[i] |
|||
let name = String(d['姓名']).trim(); |
|||
let phone = String(d['手机号码']).trim(); |
|||
let account = String(d['账号']).trim(); |
|||
let peopleCode = d['人员编号'] && String(d['人员编号']).trim(); |
|||
if (!name || !phone || !account || !peopleCode) { |
|||
error(`第${i + 1} 行有空值,请填写后重新上传`) |
|||
return |
|||
} |
|||
if (!pattern.test(phone)) { |
|||
error(`第${i + 1} 行手机号码错误`) |
|||
return |
|||
} |
|||
if (name.length > 128 || account.length > 128) { |
|||
error(`第${i + 1} 行数据字符长度大于 128,请更改后重新上传`) |
|||
return |
|||
} |
|||
if (postData.some(p => p.account == account)) { |
|||
error(`第${i + 1} 行账号重复,请更改后重新上传`) |
|||
return |
|||
} |
|||
postData.push({ |
|||
name, phone, account, peopleCode |
|||
}) |
|||
} |
|||
if (postData.length) { |
|||
setPostData(postData) |
|||
} |
|||
let msg = '文件解析完成,点击确定按钮上传保存!' |
|||
setMsg(msg) |
|||
onSuccess({ message: msg }) |
|||
}; |
|||
reader.readAsArrayBuffer(file); // 读取数据
|
|||
}, |
|||
}}> |
|||
<Button>上传文件</Button> |
|||
</Upload> |
|||
<br /> |
|||
<span>{msg}</span> |
|||
</div> |
|||
</Modal > |
|||
) |
|||
} |
|||
for (let i = 0; i < res.length; i++) { |
|||
let d = res[i]; |
|||
let name_people = String(d["人员姓名"]).trim(); |
|||
|
|||
let post_people = String(d["岗位"]).trim(); |
|||
let time = String(d["本周计划"]).trim(); |
|||
let project = String(d["本周任务"]).trim(); |
|||
if (!name_people || !post_people || !time || !project) { |
|||
error(`第${i + 1} 行有空值,请填写后重新上传`); |
|||
return; |
|||
} |
|||
postData.push({ |
|||
name_people, |
|||
post_people, |
|||
time, |
|||
project, |
|||
}); |
|||
} |
|||
if (postData.length) { |
|||
let newArray = postData.reduce((total, cur, index) => { |
|||
let hasValue = total.findIndex((current) => { |
|||
return current.name_people === cur.name_people; |
|||
}); |
|||
let obj = { |
|||
name_people: cur.name_people, |
|||
post_people: cur.post_people, |
|||
work: [ |
|||
{ |
|||
time: cur.time, |
|||
project: cur.project, |
|||
}, |
|||
], |
|||
}; |
|||
let obj1 = { |
|||
time: cur.time, |
|||
project: cur.project, |
|||
}; |
|||
hasValue === -1 && total.push(obj); |
|||
hasValue !== -1 && total[hasValue].work.push(obj1); |
|||
return total; |
|||
}, []); |
|||
console.log(newArray); |
|||
setPostData(newArray); |
|||
} |
|||
let msg = "文件解析完成,点击确定按钮上传保存!"; |
|||
setMsg(msg); |
|||
onSuccess({ message: msg }); |
|||
}; |
|||
reader.readAsArrayBuffer(file); // 读取数据
|
|||
}, |
|||
}} |
|||
> |
|||
<Button>上传文件</Button> |
|||
</Upload> |
|||
<br /> |
|||
<span>{msg}</span> |
|||
</div> |
|||
</Modal> |
|||
); |
|||
}; |
|||
|
|||
function mapStateToProps(state) { |
|||
const { auth, customizeList } = state; |
|||
return { |
|||
user: auth.user, |
|||
} |
|||
const { auth, customizeList } = state; |
|||
return { |
|||
user: auth.user, |
|||
}; |
|||
} |
|||
|
|||
|
|||
export default connect(mapStateToProps)(ImportUser); |
|||
export default connect(mapStateToProps)(ImportUser); |
|||
|
Loading…
Reference in new issue