Browse Source

提交后台

master
xingyongchun 2 years ago
parent
commit
7a174d8bbe
  1. 18
      web/client/src/layout/components/header/index.js
  2. 116
      web/client/src/sections/article/actions/article.js
  3. 284
      web/client/src/sections/article/components/import_model.js
  4. 2
      web/client/src/sections/article/components/modeal.js
  5. 25
      web/client/src/sections/article/containers/index.js
  6. 344
      web/client/src/sections/auth/containers/forget-pwd.js
  7. 2
      web/client/src/sections/auth/containers/login.js
  8. 8
      web/client/src/sections/auth/reducers/domain.js
  9. 8
      web/client/src/sections/auth/reducers/reset-pwd.js
  10. 196
      web/client/src/sections/homePage/actions/profile.js
  11. 48
      web/client/src/sections/homePage/containers/index.js
  12. 2
      web/client/src/sections/homePage/containers/particulars.js
  13. 92
      web/client/src/sections/party/containers/index.js
  14. 116
      web/client/src/sections/personnel/actions/article.js
  15. 302
      web/client/src/sections/personnel/components/import_model.js
  16. 116
      web/client/src/sections/personnel/components/modeal.js
  17. 48
      web/client/src/sections/personnel/containers/index.js
  18. 2
      web/client/src/sections/personnel/nav-item.js
  19. 156
      web/client/src/utils/webapi.js
  20. 2
      web/package.json
  21. 2
      web/readme.md

18
web/client/src/layout/components/header/index.js

@ -18,9 +18,9 @@ function Header(props) {
dispatch, history, user, pathname, toggleCollapsed, collapsed, actions, profile, onChangeTheme, dispatch, history, user, pathname, toggleCollapsed, collapsed, actions, profile, onChangeTheme,
} = props; } = props;
useEffect(() => { // useEffect(() => {
user?.id && actions?.profile?.getProfile && dispatch(actions.profile.getProfile(user?.id)); // user?.id && actions?.profile?.getProfile && dispatch(actions.profile.getProfile(user?.id));
}, []); // }, []);
const changeTheme = (themeKey) => { const changeTheme = (themeKey) => {
localStorage.setItem('theme-name', themeKey); localStorage.setItem('theme-name', themeKey);
@ -33,8 +33,8 @@ function Header(props) {
const handelClick = (item) => { const handelClick = (item) => {
if (item.key === 'logout') { if (item.key === 'logout') {
dispatch(actions.auth.logout(user)); // dispatch(actions.auth.logout(user));
sessionStorage.removeItem('selectedKeys'); // sessionStorage.removeItem('selectedKeys');
history.push('/brief'); history.push('/brief');
} }
// else if (item.key === 'themeLight') { // else if (item.key === 'themeLight') {
@ -91,7 +91,7 @@ function Header(props) {
<Link to="/profile">个人设置</Link> <Link to="/profile">个人设置</Link>
</Menu.Item> */} </Menu.Item> */}
<Menu.Item key="logout" icon={<LogoutOutlined />}> <Menu.Item key="logout" icon={<LogoutOutlined />}>
<span>退出</span> <span >退出</span>
</Menu.Item> </Menu.Item>
</Menu.SubMenu> </Menu.SubMenu>
</Menu> </Menu>
@ -103,9 +103,9 @@ function Header(props) {
function mapStateToProps(state) { function mapStateToProps(state) {
const { global, auth, profile } = state; const { global, auth, profile } = state;
return { return {
actions: global.actions, // actions: global.actions,
user: auth.user, // user: auth.user,
profile: profile.data || {}, // profile: profile.data || {},
}; };
} }

116
web/client/src/sections/article/actions/article.js

@ -3,62 +3,86 @@ import { ApiTable } from "$utils";
import { Request } from "@peace/utils"; import { Request } from "@peace/utils";
import { basicAction } from "@peace/utils"; import { basicAction } from "@peace/utils";
export function addArticle(articleObj) { // export function addArticle(articleObj) {
// return (dispatch) =>
// basicAction({
// type: "post",
// dispatch: dispatch,
// data: articleObj,
// actionType: "ADD_ARTICLE",
// url: `${ApiTable.addArticle}`,
// msg: { error: "新增文章失败" },
// reducer: { name: "articleInsertInfo" },
// });
// }
// export function editArticle(articleObj) {
// return (dispatch) =>
// basicAction({
// type: "put",
// dispatch: dispatch,
// data: articleObj,
// actionType: "EDIT_ARTICLE",
// url: `${ApiTable.addArticle}`,
// msg: { error: "编辑文章失败" },
// reducer: { name: "articleInsertInfo" },
// });
// }
// export function getDataList(query) {
// return (dispatch) =>
// basicAction({
// type: "get",
// dispatch: dispatch,
// actionType: "GET_DATALIST",
// url: ApiTable.getDataList,
// query: query,
// msg: { error: "获取文章信息失败" },
// reducer: {
// name: "articlesfrom",
// },
// });
// }
// export function delDataList(id) {
// return (dispatch) =>
// basicAction({
// type: "del",
// dispatch: dispatch,
// actionType: "DEL_DATALIST11",
// url: ApiTable.delDataList + `?id=${id}`,
// query: { id: id },
// msg: { error: "删除文章信息失败" },
// });
// }
// export const MODIFYARTICAL = {
// REQUEST_SUCCESS: "MODIFY_ARTICAL_SUCCESS",
// };
// export function setModifyData(data) {
// return (dispatch) => {
// dispatch({ type: MODIFYARTICAL.REQUEST_SUCCESS, payload: { data } });
// };
// }
export function postProject(articleObj) {
return (dispatch) => return (dispatch) =>
basicAction({ basicAction({
type: "post", type: "post",
dispatch: dispatch, dispatch: dispatch,
data: articleObj, data: articleObj,
actionType: "ADD_ARTICLE", actionType: "POST_PROJECT",
url: `${ApiTable.addArticle}`, url: `${ApiTable.projectUrl}`,
msg: { error: "新增文章失败" }, msg: { error: "获取项目信息失败" },
reducer: { name: "articleInsertInfo" }, // reducer: { name: "articleInsertInfo" },
}); });
} }
export function postInProject(articleObj) {
export function editArticle(articleObj) {
return (dispatch) => return (dispatch) =>
basicAction({ basicAction({
type: "put", type: "post",
dispatch: dispatch, dispatch: dispatch,
data: articleObj, data: articleObj,
actionType: "EDIT_ARTICLE", actionType: "POST_IN_PROJECT",
url: `${ApiTable.addArticle}`, url: `${ApiTable.postInProject}`,
msg: { error: "编辑文章失败" }, msg: { error: "上传项目信息失败" },
reducer: { name: "articleInsertInfo" }, // reducer: { name: "articleInsertInfo" },
});
}
export function getDataList(query) {
return (dispatch) =>
basicAction({
type: "get",
dispatch: dispatch,
actionType: "GET_DATALIST",
url: ApiTable.getDataList,
query: query,
msg: { error: "获取文章信息失败" },
reducer: {
name: "articlesfrom",
},
});
}
export function delDataList(id) {
return (dispatch) =>
basicAction({
type: "del",
dispatch: dispatch,
actionType: "DEL_DATALIST11",
url: ApiTable.delDataList + `?id=${id}`,
query: { id: id },
msg: { error: "删除文章信息失败" },
}); });
} }
export const MODIFYARTICAL = {
REQUEST_SUCCESS: "MODIFY_ARTICAL_SUCCESS",
};
export function setModifyData(data) {
return (dispatch) => {
dispatch({ type: MODIFYARTICAL.REQUEST_SUCCESS, payload: { data } });
};
}

284
web/client/src/sections/article/components/import_model.js

@ -5,159 +5,167 @@
* @useStrict : use strict * @useStrict : use strict
*/ */
'use strict'; "use strict";
import React, { useState } from 'react'; import React, { useState } from "react";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { Button, Input, Card, Modal, Upload, message } from 'antd'; import { Button, Input, Card, Modal, Upload, message } from "antd";
import { Request } from '@peace/utils' import { Request } from "@peace/utils";
import request from 'superagent' import request from "superagent";
import XLSX from 'xlsx' import XLSX from "xlsx";
// import { userBulkAdd } from '../../actions' import { postInProject } from "../actions/article";
//TODO 下载模板和上传文件读取 //TODO 下载模板和上传文件读取
const ImportUser = props => { const ImportUser = (props) => {
const { user, dispatch, handleCancel, params,editData } = props const { user, dispatch, handleCancel, params, editData } = props;
const [msg, setMsg] = useState('') const [msg, setMsg] = useState("");
const [loading, setLoading] = useState('') const [loading, setLoading] = useState("");
const [postData, setPostData] = useState([]) const [postData, setPostData] = useState([]);
const confirm = () => { const confirm = () => {
if (postData.length) { if (postData.length) {
setLoading(true) setLoading(true);
// dispatch(userBulkAdd(postData, params.departmentId ? params.departmentId : null)).then(res => { dispatch(postInProject(postData)).then((res) => {
// if (res.success) { console.log(res)
if (res.success) {
// } handleCancel();
// setLoading(false) message.success("上传成功");
// })
} else {
message.warn('没有数据可以提交,请上传数据文件')
} }
setLoading(false);
});
} else {
message.warn("没有数据可以提交,请上传数据文件");
} }
};
return ( return (
<Modal <Modal
visible={props.importVisible} visible={props.importVisible}
onOk={confirm} onOk={confirm}
confirmLoading={loading} confirmLoading={loading}
onCancel={() => { onCancel={() => {
setMsg('') setMsg("");
setLoading(false) setLoading(false);
setPostData([]) setPostData([]);
handleCancel() handleCancel();
}} }}
destroyOnClose destroyOnClose
> >
{/* <Button size="small" type='primary' onClick={() => { {/* <Button size="small" type='primary' onClick={() => {
Request.get(`attachments?src=upload/files/1.jpg&filename=${encodeURIComponent('1.jpg')}&token=${user.token}`).then(res => { Request.get(`attachments?src=upload/files/1.jpg&filename=${encodeURIComponent('1.jpg')}&token=${user.token}`).then(res => {
}) })
}}>下载模板</Button> */} }}>下载模板</Button> */}
<a href={'/_api/' + `attachments?src=files/用户信息导入模板.xlsx&filename=${encodeURIComponent('用户信息导入模板.xlsx')}&token=${user.token}`} > <a
<Button size="small" type='primary' >下载模板</Button> href={
</a> "/_api/" +
<div style={{ marginTop: 10 }}>下载模板后填写完整后上传</div> `attachments?src=files/用户信息导入模板.xlsx&filename=${encodeURIComponent(
<div style={{ marginTop: 10 }}> "用户信息导入模板.xlsx"
<Upload {...{ )}&token=${user.token}`
name: 'user_d', }
action: '/', >
maxCount: 1, <Button size="small" type="primary">
showUploadList: { 下载模板
showRemoveIcon: false </Button>
}, </a>
beforeUpload: (file) => { <div style={{ marginTop: 10 }}>下载模板后填写完整后上传</div>
setMsg('') <div style={{ marginTop: 10 }}>
setPostData([]) <Upload
const extNames = file.name.split('.'); {...{
let isDAE = false; name: "user_d",
if (extNames.length > 0) { action: "/",
let fileType = extNames[extNames.length - 1].toLowerCase(); maxCount: 1,
isDAE = ['xlsx', 'xls'].some((f) => f == fileType); showUploadList: {
} showRemoveIcon: false,
if (!isDAE) { },
setMsg(`只能上传 ${['xlsx', 'xls'].join()} 格式的文件!`); beforeUpload: (file) => {
return false; setMsg("");
} setPostData([]);
}, const extNames = file.name.split(".");
onChange(info) { 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;
}, const reader = new FileReader(); // 使用 FileReader 读取数据
customRequest: async (data) => { reader.onload = function (e) {
const { file, onSuccess, onError } = data // 数据读取完成后的回调函数
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: "array" }); // workbook 是 xlsx 解析 excel 后返回的对象
const reader = new FileReader(); // 使用 FileReader 读取数据 const firstSheetName = workbook.SheetNames[0]; // 获取第一个 sheet 的名字
reader.onload = function (e) { // 数据读取完成后的回调函数 const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个 sheet 的内容
const data = new Uint8Array(e.target.result); const res = XLSX.utils.sheet_to_json(worksheet); // 使用 utils 里的方法转换内容为便于使用的数组
const workbook = XLSX.read(data, { type: 'array' }); // workbook 是 xlsx 解析 excel 后返回的对象 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 的名字 for (let i = 0; i < res.length; i++) {
const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个 sheet 的内容 let d = res[i];
const res = XLSX.utils.sheet_to_json(worksheet); // 使用 utils 里的方法转换内容为便于使用的数组 let name_project = String(d["版本计划"]).trim();
const error = (msg) => {
setMsg(msg) let part_people_in = String(d["投入人力"]).trim();
onError({ message: msg }) let build_time = String(d["构建时间"]).trim();
} let publish_time = String(d["发布时间"]).trim();
if (res.length > 1000) { let progress = String(d["目前进度"]).trim();
error('一次性上传数据行数应小于1000行,请分批上传') if (!name_project || !part_people_in || !build_time || !publish_time||!progress) {
return error(`${i + 1} 行有空值,请填写后重新上传`);
} return;
if (!res.length) { }
error('请填写至少一行数据') let part_people = part_people_in.split('、').map((i) => {
return return {name_people:i}
} })
let postData = []
const pattern = /^1[3|4|5|6|7|8|9]\d{9}$/ postData.push({
for (let i = 0; i < res.length; i++) { name_project,
let d = res[i] part_people,
let name = String(d['姓名']).trim(); build_time,
let phone = String(d['手机号码']).trim(); publish_time,progress
let account = String(d['账号']).trim(); });
let peopleCode = d['人员编号'] && String(d['人员编号']).trim(); }
if (!name || !phone || !account || !peopleCode) { if (postData.length) {
error(`${i + 1} 行有空值,请填写后重新上传`) setPostData(postData);
return }
} let msg = "文件解析完成,点击确定按钮上传保存!";
if (!pattern.test(phone)) { setMsg(msg);
error(`${i + 1} 行手机号码错误`) onSuccess({ message: msg });
return };
} reader.readAsArrayBuffer(file); // 读取数据
if (name.length > 128 || account.length > 128) { },
error(`${i + 1} 行数据字符长度大于 128,请更改后重新上传`) }}
return >
} <Button>上传文件</Button>
if (postData.some(p => p.account == account)) { </Upload>
error(`${i + 1} 行账号重复,请更改后重新上传`) <br />
return <span>{msg}</span>
} </div>
postData.push({ </Modal>
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 >
)
}
function mapStateToProps(state) { function mapStateToProps(state) {
const { auth, customizeList } = state; const { auth, customizeList } = state;
return { return {
user: auth.user, user: auth.user,
} };
} }
export default connect(mapStateToProps)(ImportUser); export default connect(mapStateToProps)(ImportUser);

2
web/client/src/sections/article/components/modeal.js

@ -9,7 +9,7 @@ function modeal(props) {
if (editData && visible) { if (editData && visible) {
form.setFieldsValue({ form.setFieldsValue({
name_project: editData.name_project, name_project: editData.name_project,
part_people: editData.part_people, part_people: editData.part_people.map((i)=>i.name_people),
build_time: dayjs(editData?.build_time), build_time: dayjs(editData?.build_time),
publish_time: dayjs(editData.publish_time), publish_time: dayjs(editData.publish_time),
progress:editData.progress progress:editData.progress

25
web/client/src/sections/article/containers/index.js

@ -3,7 +3,7 @@ import React, { useEffect, useState, useRef } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Button, Popconfirm } from "antd"; import { Button, Popconfirm } from "antd";
import ProTable from "@ant-design/pro-table"; import ProTable from "@ant-design/pro-table";
import Action from "../actions/index"; import {postProject} from "../actions/article";
import moment from "moment"; import moment from "moment";
import { push } from "react-router-redux"; import { push } from "react-router-redux";
import { Scroller } from "$components"; import { Scroller } from "$components";
@ -38,7 +38,7 @@ export const Default = (props) => {
dataIndex: "part_people", dataIndex: "part_people",
hideInSearch: true, hideInSearch: true,
render: (dom, record) => { render: (dom, record) => {
return record.part_people return <div>{record.part_people.map((i, index) => record.part_people.length == 1 ? <span>{i.name_people}</span> : <span>{i.name_people}{index < record.part_people.length-1 ? '':'' }</span>) }</div>
}, },
}, },
{ {
@ -147,28 +147,15 @@ export const Default = (props) => {
actionRef={tableActionRef} actionRef={tableActionRef}
columns={columns} columns={columns}
options={false} options={false}
dataSource={dataSore} dataSource={counts||[]}
search={{ search={{
optionRender: false, optionRender: false,
collapsed: false, collapsed: false,
}} }}
request={async (params) => { request={async (params) => {
let query = { const res = await dispatch(postProject());
type: -1, console.log(res)
searchValue: heading, setCounts(res.payload.data.projects);
status: state,
page: params.current,
limit: params.pageSize,
publishTime:
day && day.length && day[0].trim() != ""
? JSON.stringify([
moment(day[0]).startOf("day"),
moment(day[1]).endOf("day"),
])
: null,
};
const res = await dispatch(Action.getDataList(query));
setCounts(res.payload.data);
return { return {
...res, ...res,
total: res.payload.data ? res.payload.data.total : 0, total: res.payload.data ? res.payload.data.total : 0,

344
web/client/src/sections/auth/containers/forget-pwd.js

@ -1,182 +1,182 @@
import React, { Component, useState, useEffect } from 'react'; // import React, { Component, useState, useEffect } from 'react';
import { connect } from 'react-redux'; // import { connect } from 'react-redux';
import { // import {
Card, Form, Input, Button, Row, Col, Alert, message, // Card, Form, Input, Button, Row, Col, Alert, message,
} from 'antd'; // } from 'antd';
import { resetPwd, RESET_PASSWORD_SUCCESS } from '../actions/reset-pwd'; // import { resetPwd, RESET_PASSWORD_SUCCESS } from '../actions/reset-pwd';
import { sendPhoneCode, checkPhoneCode, checkPhone } from '../actions/validate-phone'; // import { sendPhoneCode, checkPhoneCode, checkPhone } from '../actions/validate-phone';
const FormItem = Form.Item; // const FormItem = Form.Item;
function ForgetPwdContainer(props) { // function ForgetPwdContainer(props) {
const { dispatch, match: { params }, isRequesting } = props; // const { dispatch, match: { params }, isRequesting } = props;
const [form] = Form.useForm(); // const [form] = Form.useForm();
const [sleeping, setSleeping] = useState(false); // const [sleeping, setSleeping] = useState(false);
let [sleepCount, setSleepCount] = useState(60); // let [sleepCount, setSleepCount] = useState(60);
const [done, setDone] = useState(false); // const [done, setDone] = useState(false);
let timer; // let timer;
const _checkPhone = async (rule, value, callback) => { // const _checkPhone = async (rule, value, callback) => {
await checkPhone(value, params.domain).then((_) => { // await checkPhone(value, params.domain).then((_) => {
}, (err) => { // }, (err) => {
throw new Error('未发现绑定该手机的账号!'); // throw new Error('未发现绑定该手机的账号!');
}); // });
}; // };
const fetchVCode = async () => { // const fetchVCode = async () => {
const phoneObj = await form.validateFields(['phone']); // const phoneObj = await form.validateFields(['phone']);
await sendPhoneCode(phoneObj.phone).then((_) => { // await sendPhoneCode(phoneObj.phone).then((_) => {
setSleeping(true); // setSleeping(true);
timer = setInterval((_) => { // timer = setInterval((_) => {
if (sleepCount == 0) { // if (sleepCount == 0) {
setSleeping(false); // setSleeping(false);
setSleepCount(60); // setSleepCount(60);
clearInterval(timer); // clearInterval(timer);
return; // return;
} // }
setSleepCount(sleepCount--); // setSleepCount(sleepCount--);
}, 1000); // }, 1000);
setSleepCount(sleepCount--); // setSleepCount(sleepCount--);
}); // });
}; // };
const submit = () => { // const submit = () => {
form.validateFields().then((values) => { // form.validateFields().then((values) => {
checkPhoneCode(values.phone, values.code).then((_) => { // checkPhoneCode(values.phone, values.code).then((_) => {
dispatch(resetPwd(params.domain, values.phone, values.code, values.password)) // dispatch(resetPwd(params.domain, values.phone, values.code, values.password))
.then((action) => { // .then((action) => {
if (action.type == RESET_PASSWORD_SUCCESS) { // if (action.type == RESET_PASSWORD_SUCCESS) {
setDone(true); // setDone(true);
} else { // } else {
message.error(action.payload.error); // message.error(action.payload.error);
} // }
}); // });
}, (err) => { // }, (err) => {
message.error(err.response.body.message); // message.error(err.response.body.message);
}); // });
}); // });
}; // };
return ( // return (
<div> // <div>
<div style={{ textAlign: 'center', padding: '100px 0 50px 0' }}> // <div style={{ textAlign: 'center', padding: '100px 0 50px 0' }}>
<img src="/assets/images/anxinyun.png" width="180px" /> // <img src="/assets/images/anxinyun.png" width="180px" />
</div> // </div>
<Card style={{ width: 500, padding: 50, margin: '0 auto' }}> // <Card style={{ width: 500, padding: 50, margin: '0 auto' }}>
<h3 style={{ // <h3 style={{
color: '#666', paddingBottom: 5, marginBottom: 30, borderBottom: '1px solid #666', // color: '#666', paddingBottom: 5, marginBottom: 30, borderBottom: '1px solid #666',
}} // }}
> // >
找回密码 // 找回密码
</h3> // </h3>
{ // {
done // done
? ( // ? (
<Alert // <Alert
message="完成" // message="完成"
description={( // description={(
<div> // <div>
<p> // <p>
已成功验证您的手机号 // 已成功验证您的手机号:
{form.getFieldValue('phone')} // {form.getFieldValue('phone')}
, 并重置密码 // , 并重置密码
</p> // </p>
<div style={{ padding: '30px 0', fontWeight: 'bold' }}> // <div style={{ padding: '30px 0', fontWeight: 'bold' }}>
<a href={`/${params.domain}/signin`}>返回登录</a> // <a href={`/${params.domain}/signin`}>返回登录</a>
</div> // </div>
</div> // </div>
)} // )}
type="success" // type="success"
showIcon // showIcon
/> // />
) // )
: ( // : (
<div> // <div>
<Form form={form}> // <Form form={form}>
<FormItem // <FormItem
hasFeedback // hasFeedback
name="phone" // name="phone"
validateFirst // validateFirst
rules={[{ // rules={[{
pattern: /^1[3|4|5|7|8|9]\d{9}$/, message: '手机号码无效', // pattern: /^1[3|4|5|7|8|9]\d{9}$/, message: '手机号码无效',
}, { // }, {
required: true, message: '手机号码不能为空', // required: true, message: '手机号码不能为空',
}, { // }, {
validator: _checkPhone, // validator: _checkPhone,
}, { // }, {
validateTrigger: 'onBlur', // validateTrigger: 'onBlur',
}]} // }]}
> // >
<Input maxLength="11" placeholder="请输入注册时填写的手机号" /> // <Input maxLength="11" placeholder="请输入注册时填写的手机号" />
</FormItem> // </FormItem>
<FormItem> // <FormItem>
<Row> // <Row>
<Col span={16}> // <Col span={16}>
<FormItem // <FormItem
name="code" // name="code"
noStyle // noStyle
rules={[{ // rules={[{
required: true, message: '验证码不能为空', // required: true, message: '验证码不能为空',
}]} // }]}
> // >
<Input type="text" maxLength="8" placeholder="请输入验证码" /> // <Input type="text" maxLength="8" placeholder="请输入验证码" />
</FormItem> // </FormItem>
</Col> // </Col>
<Col span={8}> // <Col span={8}>
<Button type="primary" onClick={fetchVCode} loading={sleeping} style={{ float: 'right' }}> // <Button type="primary" onClick={fetchVCode} loading={sleeping} style={{ float: 'right' }}>
{sleeping ? `${sleepCount}s后重试` : '获取验证码'} // {sleeping ? `${sleepCount}s后重试` : '获取验证码'}
</Button> // </Button>
</Col> // </Col>
</Row> // </Row>
</FormItem> // </FormItem>
<FormItem // <FormItem
hasFeedback // hasFeedback
name="password" // name="password"
rules={[{ // rules={[{
pattern: /^[a-z0-9A-Z_]{6,20}$/, message: '密码由6-20位字母、数字或_组成', // pattern: /^[a-z0-9A-Z_]{6,20}$/, message: '密码由6-20位字母、数字或_组成',
}, { // }, {
required: true, message: '密码不能为空', // required: true, message: '密码不能为空',
}]} // }]}
> // >
<Input type="password" placeholder="请输入新密码" /> // <Input type="password" placeholder="请输入新密码" />
</FormItem> // </FormItem>
<FormItem // <FormItem
hasFeedback // hasFeedback
name="rptpwd" // name="rptpwd"
rules={[{ // rules={[{
required: true, message: '密码不能为空', // required: true, message: '密码不能为空',
}, { // }, {
validator: async (rule, value) => { // validator: async (rule, value) => {
if (form.getFieldValue('password') != value) { // if (form.getFieldValue('password') != value) {
throw new Error('两次输入的密码不一致!'); // throw new Error('两次输入的密码不一致!');
} // }
}, // },
}]} // }]}
> // >
<Input type="password" placeholder="请再次输入新密码" /> // <Input type="password" placeholder="请再次输入新密码" />
</FormItem> // </FormItem>
<FormItem> // <FormItem>
<Button type="primary" style={{ width: '100%' }} loading={isRequesting} onClick={submit}>重设密码</Button> // <Button type="primary" style={{ width: '100%' }} loading={isRequesting} onClick={submit}>重设密码</Button>
</FormItem> // </FormItem>
</Form> // </Form>
<div style={{ padding: '30px 0 0 0' }}> // <div style={{ padding: '30px 0 0 0' }}>
<a href={`/${params.domain}/signin`}>返回登录</a> // <a href={`/${params.domain}/signin`}>返回登录</a>
</div> // </div>
</div> // </div>
) // )
} // }
</Card> // </Card>
</div> // </div>
); // );
} // }
function mapStateToProps(state) { // function mapStateToProps(state) {
const { resetPwd } = state; // const { resetPwd } = state;
return { // return {
isRequesting: resetPwd.isRequesting, // isRequesting: resetPwd.isRequesting,
}; // };
} // }
export default connect(mapStateToProps)(ForgetPwdContainer); // export default connect(mapStateToProps)(ForgetPwdContainer);

2
web/client/src/sections/auth/containers/login.js

@ -117,7 +117,7 @@ function mapStateToProps(state) {
return { return {
user: auth.user, user: auth.user,
error: auth.error, error: auth.error,
isRequesting: auth.isRequesting, // isRequesting: auth.isRequesting,
}; };
} }

8
web/client/src/sections/auth/reducers/domain.js

@ -3,7 +3,7 @@ import * as actionTypes from '../actions/domain';
const initState = { const initState = {
domain: null, domain: null,
isRequesting: false, // isRequesting: false,
error: null, error: null,
}; };
@ -12,17 +12,17 @@ function domain(state = initState, action) {
switch (action.type) { switch (action.type) {
case actionTypes.REQUEST_DOMAIN: case actionTypes.REQUEST_DOMAIN:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
isRequesting: true, // isRequesting: true,
error: null, error: null,
}).toJS(); }).toJS();
case actionTypes.GET_DOMAIN_SUCCESS: case actionTypes.GET_DOMAIN_SUCCESS:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
isRequesting: false, // isRequesting: false,
domain: payload.domain, domain: payload.domain,
}).toJS(); }).toJS();
case actionTypes.GET_DOMAIN_ERROR: case actionTypes.GET_DOMAIN_ERROR:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
isRequesting: false, // isRequesting: false,
error: payload.error, error: payload.error,
}).toJS(); }).toJS();
default: default:

8
web/client/src/sections/auth/reducers/reset-pwd.js

@ -2,7 +2,7 @@ import Immutable from 'immutable';
import * as actionTypes from '../actions/reset-pwd'; import * as actionTypes from '../actions/reset-pwd';
const initState = { const initState = {
isRequesting: false, // isRequesting: false,
error: null, error: null,
}; };
@ -11,16 +11,16 @@ function resetPwd(state = initState, action) {
switch (action.type) { switch (action.type) {
case actionTypes.REQUEST_RESET_PASSWORD: case actionTypes.REQUEST_RESET_PASSWORD:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
isRequesting: true, // isRequesting: true,
error: null, error: null,
}).toJS(); }).toJS();
case actionTypes.RESET_PASSWORD_SUCCESS: case actionTypes.RESET_PASSWORD_SUCCESS:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
isRequesting: false, // isRequesting: false,
}).toJS(); }).toJS();
case actionTypes.RESET_PASSWORD_ERROR: case actionTypes.RESET_PASSWORD_ERROR:
return Immutable.fromJS(state).merge({ return Immutable.fromJS(state).merge({
isRequesting: false, // isRequesting: false,
error: payload.error, error: payload.error,
}).toJS(); }).toJS();
default: default:

196
web/client/src/sections/homePage/actions/profile.js

@ -1,97 +1,97 @@
import { basicAction } from "@peace/utils"; import { basicAction } from "@peace/utils";
import { ApiTable } from "$utils"; import { ApiTable } from "$utils";
export function getProfile(userId) { // export function getProfile(userId) {
return (dispatch) => // return (dispatch) =>
basicAction({ // basicAction({
type: "get", // type: "get",
dispatch: dispatch, // dispatch: dispatch,
actionType: "GET_PROFILE", // actionType: "GET_PROFILE",
url: ApiTable.getUserInfo.replace("{userId}", userId), // url: ApiTable.getUserInfo.replace("{userId}", userId),
msg: { error: "获取用户信息失败" }, // msg: { error: "获取用户信息失败" },
reducer: { // reducer: {
name: "profile", // name: "profile",
}, // },
}); // });
} // }
export function getDataList({ type, page, limit, status }) { // export function getDataList({ type, page, limit, status }) {
return (dispatch) => // return (dispatch) =>
basicAction({ // basicAction({
type: "get", // type: "get",
dispatch: dispatch, // dispatch: dispatch,
actionType: "GET_DATALIST", // actionType: "GET_DATALIST",
url: ApiTable.getDataList, // url: ApiTable.getDataList,
query: { type, page, limit, status }, // query: { type, page, limit, status },
msg: { error: "获取文章信息失败" }, // msg: { error: "获取文章信息失败" },
reducer: { // reducer: {
name: "articlesfrom", // name: "articlesfrom",
}, // },
}); // });
} // }
export function editProfile(userId, params, type) { // export function editProfile(userId, params, type) {
return (dispatch) => // return (dispatch) =>
basicAction({ // basicAction({
type: "put", // type: "put",
data: params, // data: params,
dispatch: dispatch, // dispatch: dispatch,
actionType: "EDIT_PROFILE", // actionType: "EDIT_PROFILE",
url: ApiTable.modifyUserInfo // url: ApiTable.modifyUserInfo
.replace("{userId}", userId) // .replace("{userId}", userId)
.replace("{type}", type || "phone"), // .replace("{type}", type || "phone"),
msg: { option: "更新个人信息" }, // msg: { option: "更新个人信息" },
}); // });
} // }
export function editpassword(userId, params) { // export function editpassword(userId, params) {
return (dispatch) => // return (dispatch) =>
basicAction({ // basicAction({
type: "put", // type: "put",
data: params, // data: params,
dispatch: dispatch, // dispatch: dispatch,
actionType: "EDIT_PASSWORD", // actionType: "EDIT_PASSWORD",
url: ApiTable.modifyPassWord.replace("{userId}", userId), // url: ApiTable.modifyPassWord.replace("{userId}", userId),
msg: { option: "更新密码" }, // msg: { option: "更新密码" },
}); // });
} // }
export function editName(userId, params) { // export function editName(userId, params) {
return (dispatch) => // return (dispatch) =>
basicAction({ // basicAction({
type: "put", // type: "put",
data: params, // data: params,
dispatch: dispatch, // dispatch: dispatch,
actionType: "EDIT_NAME", // actionType: "EDIT_NAME",
url: ApiTable.modifyName.replace("{userId}", userId), // url: ApiTable.modifyName.replace("{userId}", userId),
msg: { option: "修改姓名" }, // msg: { option: "修改姓名" },
}); // });
} // }
export function getText(id) { // export function getText(id) {
return (dispatch) => // return (dispatch) =>
basicAction({ // basicAction({
type: "get", // type: "get",
dispatch: dispatch, // dispatch: dispatch,
actionType: "GET_TEXT", // actionType: "GET_TEXT",
url: ApiTable.getText, // url: ApiTable.getText,
query: { id }, // query: { id },
msg: { error: "获取文章信息失败" }, // msg: { error: "获取文章信息失败" },
reducer: { // reducer: {
name: "wen", // name: "wen",
}, // },
}); // });
} // }
export function getPartyMember() { // export function getPartyMember() {
return (dispatch) => // return (dispatch) =>
basicAction({ // basicAction({
type: "get", // type: "get",
dispatch: dispatch, // dispatch: dispatch,
actionType: "PARTY_MEMBER", // actionType: "PARTY_MEMBER",
url: ApiTable.getpartyMember, // url: ApiTable.getpartyMember,
msg: { option: "获取工会人数" }, // msg: { option: "获取工会人数" },
reducer: { // reducer: {
name: "party", // name: "party",
}, // },
}); // });
} // }
export function getProject() { export function getProject() {
return (dispatch) => return (dispatch) =>
@ -136,10 +136,16 @@ export function getWait() {
} }
export default { export default {
getProfile, // getProfile,
editProfile, // editProfile,
editpassword, // editpassword,
editName, // editName,
getText, // getText,
getPartyMember, // modifyEmailEnable,
// modifyEmailDisable,
// modifySmsEnable,
// modifySmsDisable,
// midifyDndEnable,
// modifyDndDisable,
// getPartyMember,
}; };

48
web/client/src/sections/homePage/containers/index.js

@ -133,46 +133,9 @@ function Management(props) {
}, },
]; ];
useEffect(() => { // useEffect(() => {
dispatch(getProject()).then((res) => { // dispatch(getPartyMember()).then((res) => {});
if (res.success) { // }, []);
const nextData = res.payload?.data?.projects?.map((d, i) => ({
...d,
key: i,
build_time: moment(d.build_time).format("YYYY/MM/DD"),
publish_time: moment(d.publish_time).format("YYYY/MM/DD"),
part_people: d.part_people?.map(p => p.name_people).join(),
}));
setProjectData(nextData)
}
})
dispatch(getPeople()).then((res) => {
console.log(res, 'getPeople')
})
dispatch(getWait()).then((res) => {
if (res.success) {
const nextData = res.payload?.data?.projects?.map((d, i) => ({
...d,
key: i,
}));
setWaitData(nextData)
}
})
let nextData = []
for (let i = 1; i <= 34; i++) {
nextData.push({
key: i,
name: i,
age: 32,
address: '西湖区湖底公园1号',
})
}
setDataSource(nextData)
}, []);
return ( return (
<> <>
@ -231,8 +194,9 @@ function Management(props) {
function mapStateToProps(state) { function mapStateToProps(state) {
const { auth, global } = state; const { auth, global } = state;
return { return {
user: auth.user, // loding: party.isRequesting,
actions: global.actions, // user: auth.user,
// actions: global.actions,
}; };
} }
export default connect(mapStateToProps)(Management); export default connect(mapStateToProps)(Management);

2
web/client/src/sections/homePage/containers/particulars.js

@ -123,7 +123,7 @@ function Particulars(props) {
function mapStateToProps(state) { function mapStateToProps(state) {
const { auth, global, party, wen } = state; const { auth, global, party, wen } = state;
return { return {
loding: wen.isRequesting, // loding: wen.isRequesting,
user: auth.user, user: auth.user,
actions: global.actions, actions: global.actions,
party: party, party: party,

92
web/client/src/sections/party/containers/index.js

@ -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)

116
web/client/src/sections/personnel/actions/article.js

@ -3,62 +3,86 @@ import { ApiTable } from "$utils";
import { Request } from "@peace/utils"; import { Request } from "@peace/utils";
import { basicAction } from "@peace/utils"; import { basicAction } from "@peace/utils";
export function addArticle(articleObj) { // export function addArticle(articleObj) {
// return (dispatch) =>
// basicAction({
// type: "post",
// dispatch: dispatch,
// data: articleObj,
// actionType: "ADD_ARTICLE",
// url: `${ApiTable.addArticle}`,
// msg: { error: "新增文章失败" },
// reducer: { name: "articleInsertInfo" },
// });
// }
// export function editArticle(articleObj) {
// return (dispatch) =>
// basicAction({
// type: "put",
// dispatch: dispatch,
// data: articleObj,
// actionType: "EDIT_ARTICLE",
// url: `${ApiTable.addArticle}`,
// msg: { error: "编辑文章失败" },
// reducer: { name: "articleInsertInfo" },
// });
// }
// export function getDataList(query) {
// return (dispatch) =>
// basicAction({
// type: "get",
// dispatch: dispatch,
// actionType: "GET_DATALIST",
// url: ApiTable.getDataList,
// query: query,
// msg: { error: "获取文章信息失败" },
// reducer: {
// name: "articlesfrom",
// },
// });
// }
// export function delDataList(id) {
// return (dispatch) =>
// basicAction({
// type: "del",
// dispatch: dispatch,
// actionType: "DEL_DATALIST11",
// url: ApiTable.delDataList + `?id=${id}`,
// query: { id: id },
// msg: { error: "删除文章信息失败" },
// });
// }
// export const MODIFYARTICAL = {
// REQUEST_SUCCESS: "MODIFY_ARTICAL_SUCCESS",
// };
// export function setModifyData(data) {
// return (dispatch) => {
// dispatch({ type: MODIFYARTICAL.REQUEST_SUCCESS, payload: { data } });
// };
// }
export function postOutPeople(articleObj) {
return (dispatch) => return (dispatch) =>
basicAction({ basicAction({
type: "post", type: "post",
dispatch: dispatch, dispatch: dispatch,
data: articleObj, data: articleObj,
actionType: "ADD_ARTICLE", actionType: "POST_OUTPEOPLE",
url: `${ApiTable.addArticle}`, url: `${ApiTable.peopleUrl}`,
msg: { error: "新增文章失败" }, msg: { error: "获取人员信息失败" },
reducer: { name: "articleInsertInfo" }, // reducer: { name: "articleInsertInfo" },
}); });
} }
export function postInPeople(articleObj) {
export function editArticle(articleObj) {
return (dispatch) => return (dispatch) =>
basicAction({ basicAction({
type: "put", type: "post",
dispatch: dispatch, dispatch: dispatch,
data: articleObj, data: articleObj,
actionType: "EDIT_ARTICLE", actionType: "POST_OUTPEOPLE",
url: `${ApiTable.addArticle}`, url: `${ApiTable.postInPeople}`,
msg: { error: "编辑文章失败" }, msg: { error: "上传人员信息失败" },
reducer: { name: "articleInsertInfo" }, // reducer: { name: "articleInsertInfo" },
});
}
export function getDataList(query) {
return (dispatch) =>
basicAction({
type: "get",
dispatch: dispatch,
actionType: "GET_DATALIST",
url: ApiTable.getDataList,
query: query,
msg: { error: "获取文章信息失败" },
reducer: {
name: "articlesfrom",
},
});
}
export function delDataList(id) {
return (dispatch) =>
basicAction({
type: "del",
dispatch: dispatch,
actionType: "DEL_DATALIST11",
url: ApiTable.delDataList + `?id=${id}`,
query: { id: id },
msg: { error: "删除文章信息失败" },
}); });
} }
export const MODIFYARTICAL = {
REQUEST_SUCCESS: "MODIFY_ARTICAL_SUCCESS",
};
export function setModifyData(data) {
return (dispatch) => {
dispatch({ type: MODIFYARTICAL.REQUEST_SUCCESS, payload: { data } });
};
}

302
web/client/src/sections/personnel/components/import_model.js

@ -5,159 +5,185 @@
* @useStrict : use strict * @useStrict : use strict
*/ */
'use strict'; "use strict";
import React, { useState } from 'react'; import React, { useState } from "react";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { Button, Input, Card, Modal, Upload, message } from 'antd'; import { Button, Input, Card, Modal, Upload, message } from "antd";
import { Request } from '@peace/utils' import { Request } from "@peace/utils";
import request from 'superagent' import request from "superagent";
import XLSX from 'xlsx' import XLSX from "xlsx";
// import { userBulkAdd } from '../../actions' import { postInPeople } from "../actions/article";
//TODO 下载模板和上传文件读取 //TODO 下载模板和上传文件读取
const ImportUser = props => { const ImportUser = (props) => {
const { user, dispatch, handleCancel, params,editData } = props const { user, dispatch, handleCancel, params, editData } = props;
const [msg, setMsg] = useState('') const [msg, setMsg] = useState("");
const [loading, setLoading] = useState('') const [loading, setLoading] = useState("");
const [postData, setPostData] = useState([]) const [postData, setPostData] = useState([]);
const confirm = () => { const confirm = () => {
if (postData.length) { if (postData.length) {
setLoading(true) setLoading(true);
// dispatch(userBulkAdd(postData, params.departmentId ? params.departmentId : null)).then(res => { dispatch(postInPeople(postData)).then((res) => {
// if (res.success) { if (res.success) {
handleCancel();
// } message.success("上传成功");
// setLoading(false)
// })
} else {
message.warn('没有数据可以提交,请上传数据文件')
} }
setLoading(false);
});
} else {
message.warn("没有数据可以提交,请上传数据文件");
} }
};
return ( return (
<Modal <Modal
visible={props.importVisible} visible={props.importVisible}
onOk={confirm} onOk={confirm}
confirmLoading={loading} confirmLoading={loading}
onCancel={() => { onCancel={() => {
setMsg('') setMsg("");
setLoading(false) setLoading(false);
setPostData([]) setPostData([]);
handleCancel() handleCancel();
}} }}
destroyOnClose destroyOnClose
> >
{/* <Button size="small" type='primary' onClick={() => { {/* <Button size="small" type='primary' onClick={() => {
Request.get(`attachments?src=upload/files/1.jpg&filename=${encodeURIComponent('1.jpg')}&token=${user.token}`).then(res => { Request.get(`attachments?src=upload/files/1.jpg&filename=${encodeURIComponent('1.jpg')}&token=${user.token}`).then(res => {
}) })
}}>下载模板</Button> */} }}>下载模板</Button> */}
<a href={'/_api/' + `attachments?src=files/用户信息导入模板.xlsx&filename=${encodeURIComponent('用户信息导入模板.xlsx')}&token=${user.token}`} > <a
<Button size="small" type='primary' >下载模板</Button> href={
</a> "/_api/" +
<div style={{ marginTop: 10 }}>下载模板后填写完整后上传</div> `attachments?src=files/用户信息导入模板.xlsx&filename=${encodeURIComponent(
<div style={{ marginTop: 10 }}> "用户信息导入模板.xlsx"
<Upload {...{ )}&token=${user.token}`
name: 'user_d', }
action: '/', >
maxCount: 1, <Button size="small" type="primary">
showUploadList: { 下载模板
showRemoveIcon: false </Button>
}, </a>
beforeUpload: (file) => { <div style={{ marginTop: 10 }}>下载模板后填写完整后上传</div>
setMsg('') <div style={{ marginTop: 10 }}>
setPostData([]) <Upload
const extNames = file.name.split('.'); {...{
let isDAE = false; name: "user_d",
if (extNames.length > 0) { action: "/",
let fileType = extNames[extNames.length - 1].toLowerCase(); maxCount: 1,
isDAE = ['xlsx', 'xls'].some((f) => f == fileType); showUploadList: {
} showRemoveIcon: false,
if (!isDAE) { },
setMsg(`只能上传 ${['xlsx', 'xls'].join()} 格式的文件!`); beforeUpload: (file) => {
return false; setMsg("");
} setPostData([]);
}, const extNames = file.name.split(".");
onChange(info) { 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;
}, const reader = new FileReader(); // 使用 FileReader 读取数据
customRequest: async (data) => { reader.onload = function (e) {
const { file, onSuccess, onError } = data // 数据读取完成后的回调函数
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: "array" }); // workbook 是 xlsx 解析 excel 后返回的对象
const reader = new FileReader(); // 使用 FileReader 读取数据 const firstSheetName = workbook.SheetNames[0]; // 获取第一个 sheet 的名字
reader.onload = function (e) { // 数据读取完成后的回调函数 const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个 sheet 的内容
const data = new Uint8Array(e.target.result); const res = XLSX.utils.sheet_to_json(worksheet); // 使用 utils 里的方法转换内容为便于使用的数组
const workbook = XLSX.read(data, { type: 'array' }); // workbook 是 xlsx 解析 excel 后返回的对象 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 的名字 for (let i = 0; i < res.length; i++) {
const worksheet = workbook.Sheets[firstSheetName]; // 获取第一个 sheet 的内容 let d = res[i];
const res = XLSX.utils.sheet_to_json(worksheet); // 使用 utils 里的方法转换内容为便于使用的数组 let name_people = String(d["人员姓名"]).trim();
const error = (msg) => {
setMsg(msg) let post_people = String(d["岗位"]).trim();
onError({ message: msg }) let time = String(d["本周计划"]).trim();
} let project = String(d["本周任务"]).trim();
if (res.length > 1000) { if (!name_people || !post_people || !time || !project) {
error('一次性上传数据行数应小于1000行,请分批上传') error(`${i + 1} 行有空值,请填写后重新上传`);
return return;
} }
if (!res.length) { postData.push({
error('请填写至少一行数据') name_people,
return post_people,
} time,
let postData = [] project,
const pattern = /^1[3|4|5|6|7|8|9]\d{9}$/ });
for (let i = 0; i < res.length; i++) { }
let d = res[i] if (postData.length) {
let name = String(d['姓名']).trim(); let newArray = postData.reduce((total, cur, index) => {
let phone = String(d['手机号码']).trim(); let hasValue = total.findIndex((current) => {
let account = String(d['账号']).trim(); return current.name_people === cur.name_people;
let peopleCode = d['人员编号'] && String(d['人员编号']).trim(); });
if (!name || !phone || !account || !peopleCode) { let obj = {
error(`${i + 1} 行有空值,请填写后重新上传`) name_people: cur.name_people,
return post_people: cur.post_people,
} work: [
if (!pattern.test(phone)) { {
error(`${i + 1} 行手机号码错误`) time: cur.time,
return project: cur.project,
} },
if (name.length > 128 || account.length > 128) { ],
error(`${i + 1} 行数据字符长度大于 128,请更改后重新上传`) };
return let obj1 = {
} time: cur.time,
if (postData.some(p => p.account == account)) { project: cur.project,
error(`${i + 1} 行账号重复,请更改后重新上传`) };
return hasValue === -1 && total.push(obj);
} hasValue !== -1 && total[hasValue].work.push(obj1);
postData.push({ return total;
name, phone, account, peopleCode }, []);
}) console.log(newArray);
} setPostData(newArray);
if (postData.length) { }
setPostData(postData) let msg = "文件解析完成,点击确定按钮上传保存!";
} setMsg(msg);
let msg = '文件解析完成,点击确定按钮上传保存!' onSuccess({ message: msg });
setMsg(msg) };
onSuccess({ message: msg }) reader.readAsArrayBuffer(file); // 读取数据
}; },
reader.readAsArrayBuffer(file); // 读取数据 }}
}, >
}}> <Button>上传文件</Button>
<Button>上传文件</Button> </Upload>
</Upload> <br />
<br /> <span>{msg}</span>
<span>{msg}</span> </div>
</div> </Modal>
</Modal > );
) };
}
function mapStateToProps(state) { function mapStateToProps(state) {
const { auth, customizeList } = state; const { auth, customizeList } = state;
return { return {
user: auth.user, user: auth.user,
} };
} }
export default connect(mapStateToProps)(ImportUser); export default connect(mapStateToProps)(ImportUser);

116
web/client/src/sections/personnel/components/modeal.js

@ -1,5 +1,6 @@
import React,{useState,useEffect} from 'react' import React,{useState,useEffect} from 'react'
import { Modal, Form, Input, Button,DatePicker,Select } from 'antd' import { Modal, Form, Input, Button, DatePicker, Space } from 'antd'
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
function modeal(props) { function modeal(props) {
const [form] = Form.useForm(); const [form] = Form.useForm();
@ -8,11 +9,12 @@ function modeal(props) {
useEffect(() => { useEffect(() => {
if (editData && visible) { if (editData && visible) {
form.setFieldsValue({ form.setFieldsValue({
name_project: editData.name_project, name_people: editData.name_people,
part_people: editData.part_people, post_people: editData.post_people,
build_time: dayjs(editData?.build_time), progress: editData.progress,
publish_time: dayjs(editData.publish_time), time:editData.work.map((i)=>i.time),
progress:editData.progress project:editData.work.map((i)=>i.project)
}) })
} }
}, [editData, visible]) }, [editData, visible])
@ -21,7 +23,7 @@ function modeal(props) {
visible={visible} visible={visible}
onCancel={handleCancel} onCancel={handleCancel}
footer={null} footer={null}
title="研发看板项目编辑" title="研发看板人员编辑"
> >
<Form <Form
name="basic" name="basic"
@ -31,44 +33,80 @@ function modeal(props) {
autoComplete="off" autoComplete="off"
> >
<Form.Item <Form.Item
label="项目计划" label="人员姓名"
name="name_project" name="name_people"
rules={[{ required: true, message: '请输入项目计划' }]} rules={[{ required: true, message: '请输入人员姓名' }]}
> >
<Input/> <Input/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="投入人力" label="岗位"
name="part_people" name="post_people"
rules={[{ required: true, message: '请输入人员姓名' }]} rules={[{ required: true, message: '请输入岗位' }]}
> >
<Input/> <Input/>
</Form.Item> </Form.Item>
<Form.Item {/* {editData?.work.map(() => {
label="构建时间" return <> <Form.Item
name="build_time" label="本周计划"
rules={[{ required: true, message: '请选择时间' }]} name="time"
> rules={[{ required: true, message: '请填写工作计划' }]}
<DatePicker /> >
</Form.Item> <Input/>
<Form.Item </Form.Item>
label="发布时间" <Form.Item
name="publish_time" label="本周任务"
rules={[{ required: true, message: '请选择时间' }]} name="project"
> rules={[{ required: true, message: '请填写工作计划' }]}
<DatePicker /> >
</Form.Item> <Input/>
<Form.Item </Form.Item></>
label="目前进度" })} */}
name="progress" <Form.List name="users">
rules={[{ required: true, message: '请选择进度' }]} {(fields, { add, remove }) => (
> <>
<Select><Select.Option value="需求评审中">需求评审中</Select.Option> {editData?.work.map(({ key, name, ...restField }) => (
<Select.Option value="研发中">研发中</Select.Option> <Space
<Select.Option value="测试中">测试中</Select.Option> key={key}
<Select.Option value="已发布">已发布</Select.Option> style={{
</Select> display: 'flex',
</Form.Item> marginBottom: 8,
}}
align="baseline"
>
<Form.Item
{...restField}
name={[name, 'first']}
rules={[
{
required: true,
message: 'Missing first name',
},
]}
>
<Input placeholder="First Name" />
</Form.Item>
<Form.Item
{...restField}
name={[name, 'last']}
rules={[
{
required: true,
message: 'Missing last name',
},
]}
>
<Input placeholder="Last Name" />
</Form.Item>
</Space>
))}
<Form.Item>
</Form.Item>
</>
)}
</Form.List>
<Form.Item noStyle={true}> <Form.Item noStyle={true}>
<div style={{ <div style={{
padding: '12px 0', padding: '12px 0',

48
web/client/src/sections/personnel/containers/index.js

@ -3,7 +3,7 @@ import React, { useEffect, useState, useRef } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Button, Popconfirm } from "antd"; import { Button, Popconfirm } from "antd";
import ProTable from "@ant-design/pro-table"; import ProTable from "@ant-design/pro-table";
import Action from "../actions/index"; import {postOutPeople} from "../actions/article";
import moment from "moment"; import moment from "moment";
import { push } from "react-router-redux"; import { push } from "react-router-redux";
import { Scroller } from "$components"; import { Scroller } from "$components";
@ -25,29 +25,31 @@ export const Default = (props) => {
const columns = [ const columns = [
{ {
title: "人员姓名", title: "人员姓名",
dataIndex: "name_project", dataIndex: "name_people",
key: "name_project", key: "name_people",
hideInSearch: true, hideInSearch: true,
render: (dom, record) => { render: (dom, record) => {
return record.name_project; return record.name_people;
}, },
}, },
{ {
title: "岗位", title: "岗位",
key: "category", key: "post_people",
dataIndex: "part_people", dataIndex: "post_people",
hideInSearch: true, hideInSearch: true,
render: (dom, record) => { render: (dom, record) => {
return record.part_people return record.post_people
}, },
}, },
{ {
title: "本周工作计划", title: "本周工作计划",
key: "build_time", key: "work",
dataIndex: "build_time", dataIndex: "work",
hideInSearch: true, hideInSearch: true,
render: (dom, record) => { render: (dom, record) => {
return moment(record.build_time).format('YYYY-MM-DD') return <div>{record?.work?.map((item) => {
return <div><span>{item.time}</span><span>{item.project }</span></div>
})}</div>
}, },
}, },
{ {
@ -125,32 +127,20 @@ export const Default = (props) => {
return ( return (
<div style={{ height: "100%" }}> <div style={{ height: "100%" }}>
<Scroller containerId={"article-container-query"} height={"100%"}> <Scroller containerId={"article-container-query"} height={"100%"}>
<ProTable <ProTable
actionRef={tableActionRef} actionRef={tableActionRef}
columns={columns} columns={columns}
options={false} options={false}
dataSource={dataSore} dataSource={counts||[]}
search={{ search={{
optionRender: false, optionRender: false,
collapsed: false, collapsed: false,
}} }}
request={async (params) => { request={async(params) => {
let query = { console.log(params)
type: -1, const res = await dispatch(postOutPeople());
searchValue: heading,
status: state, setCounts(res.payload.data.projects);
page: params.current,
limit: params.pageSize,
publishTime:
day && day.length && day[0].trim() != ""
? JSON.stringify([
moment(day[0]).startOf("day"),
moment(day[1]).endOf("day"),
])
: null,
};
const res = await dispatch(Action.getDataList(query));
setCounts(res.payload.data);
return { return {
...res, ...res,
total: res.payload.data ? res.payload.data.total : 0, total: res.payload.data ? res.payload.data.total : 0,

2
web/client/src/sections/personnel/nav-item.js

@ -6,7 +6,7 @@ import { BarChartOutlined } from '@ant-design/icons';
export function getNavItem() { export function getNavItem() {
return ( return (
<Menu.Item key="personnel" icon={<BarChartOutlined />}> <Menu.Item key="personnel" icon={<BarChartOutlined />}>
<Link to="/personnel">项目信息</Link> <Link to="/personnel">人员任务</Link>
</Menu.Item> </Menu.Item>
); );
} }

156
web/client/src/utils/webapi.js

@ -2,156 +2,12 @@ import request from "superagent";
import noCache from "superagent-no-cache"; import noCache from "superagent-no-cache";
export const ApiTable = { export const ApiTable = {
/* 研发看板 */ /* 研发看板 */
getProjectUrl: "outProject", // 在研项目 projectUrl: "outProject", // 在研项目
getPeopleUrl: "outPeople", // 人员情况 peopleUrl: "outPeople", // 人员情况
getWaitUrl: "outWait", // 待研项目 waitUrl: "outWait", // 待研项目
postInProject:'inProject', // 增加项目
getDataList: "article/management", //全部资讯 postInPeople:'inPeople',//增加人员任务
delDataList: "article/management", //删除资讯
addArticle: "article/management",
checkDomain: "domain/{domain}",
resetPwd: "reset/password",
phoneVCode: "validate/phone",
checkPhone: "check/phone",
checkRegcode: "validate/regcode",
login: "login",
logout: "logout",
/* 个人设置 */
getUserInfo: "users/{userId}/details",
modifyUserInfo: "users/{userId}/{type}",
modifyEmail: "users/{userId}/email",
modifyAvator: "user/{userId}/avator",
modifySmsEnable: "users/{userId}/sms-notification/enable",
modifyEmailEnable: "users/{userId}/email-notification/enable",
modifySmsDisable: "users/{userId}/sms-notification/disable",
modifyEmailDisable: "users/{userId}/email-notification/disable",
modifyWxEnable: "/users/{userId}/wx-notification/enable",
modifyWxDisable: "/users/{userId}/wx-notification/disable",
midifyDndEnable: "users/{userId}/dnd/enable",
modifyDndDisable: "users/{userId}/dnd/disable",
modifyPassWord: "users/{userId}/password",
modifyName: "users/{userId}/name",
/* 企业 */
getEnterprisesDetails: "users/{userId}/enterprises/details",
getEnterprisesMembers: "enterprises/{enterpriseId}/members",
getEnterprisesRoles: "enterprises/{enterpriseId}/roles",
getPostsUrl: "posts",
addDepartment: "enterprises/{enterpriseId}/departments",
deleteDepartment: "departments/{departmentId}",
modifyDepartment: "departments/{departmentId}/rename",
sortDepartment: "departments/sort",
sortDepartmentUsers: "department/users/sort",
enableMember: "members/{memberId}/enable",
disableMember: "members/{memberId}/disable",
addMember: "members",
deleteMember: "members/{memberId}",
modifyMember: "members/{memberId}",
modifyEnterprise: "enterprises/{enterpriseId}",
/* 权限 */
getAuthorList: "org/{orgId}/resources",
getProejectAuthorList: "org/{orgId}/project/resources",
getAuthorByRoleId: "role/{roleId}/resources",
modifyAuthor: "role/{roleId}/resources",
modifyRoleUsers: "role/{roleId}/users",
modifyRoleStructures: "role/{roleId}/structures",
modifyDepartmentUsers: "department/{depId}/users",
deleteRoleUsers: "role/{roleId}/users/remove",
getDepartmentResources: "orgs/{orgId}/department/resources?platform=true",
modifyDepartmentResources: "department/{departmentId}/resources",
addGroupRoleUrl: "group/role",
groupRoleUrlById: "group/{groupId}/role",
addRoleUrl: "role",
roleUrlById: "role/{roleId}",
/* 项目 */
getProjects: "users/{userId}/projects",
addProject: "users/{userId}/projects",
editProject: "projects/{projectId}",
deleteProject: "projects/{projectId}",
editProjectAdmin: "projects/{projectId}/admin",
editProjectUrl: "projects/{projectId}/url",
applyProject: "projects/{projectId}/apply",
reviewedProject: "projects/{projectId}/reviewed",
publishProject: "projects/{projectId}/publish",
generateReviewReport: "reports/review/immediately",
getReviewReport: "reports/review",
changeProjectEventState: "projects/{projectId}/evnetState",
/* 结构物管理 */
getStructsList: "organizations/{organizationId}/structures",
getStructsListWithoutIOTA:
"organizations/{organizationId}/withoutiota/structures",
// 系统日志
getSystemLog: "/log",
// 大屏
getCarstatisticsUrl: "statistics/cars",
getAlarmsUrl: "alarms",
getDevicesUrl: "devices",
getVideoToken: "video/accessToken",
getVideoList: "video/list",
getLastDataUrl: "last-data/{structId}",
// 隧道配置
getTunnels: "tunnels",
getTunnelSystems: "tunnel/systems",
createTunnel: "tunnel",
modifyTunnel: "tunnel/{tunnelId}",
// 设备配置
getDevices: "devices",
getDeviceTypes: "device/types",
createDevice: "device",
modifyDevice: "device/{deviceId}",
getDeviceStatistics: "devices/statistics/{key}",
getDeviceStatusRecords: "devices/status-records",
// 广播系统
getBroadcastLogin: "control/20140901/infs/login.json",
getBroadcastEmployee: "control/api_v2.2.5/employee/query/queryAll.json",
getBroadcastTask: "control/api_v2.2.5/broad/query/all.json",
getPhoneRecords: "control/20210628/infs/getAllCdrs.json",
getBroadcastAlarms: "control/api_v2.2.5/alarm/query/queryAll.json",
// 视频模块
getTunnelVideos: "tunnel/{id}/videos",
ptzsControl: "tunnel/{id}/ptzsControl",
getTrafficFlow: "traffic/{id}",
getVideoUrls: "video/{id}/urls",
getTerminals: "tunnel/{id}/terminals",
getTerminalDetail: "terminal/{id}/detail",
getTunnelVideosById: "tunnel/{id}/videos",
getRobotRequest: "tunnel/{id}/robot",
// 操作日志配置
getLogs: "logs",
createLog: "log",
modifyLog: "log/{logId}",
// 积水健康监测
fsLoginUrl: "login",
getSensorsStations: "structures/{structureId}/sensors-stations",
getFactorDevice: "structures/{structureId}/factors/{factorId}/devices",
getStationsData:
"structures/{structureId}/factors/{factorId}/stations/data?startTime={startTime}&endTime={endTime}",
getBatchThreshold:
"structures/{structId}/factors/{factorId}/threshold/batches",
getStationThemesData: "stations/theme/data",
getStations: "structures/{structureId}/stations",
// 告警管理
getAlarms: "users/{userId}/alarms",
modifyAlarmChecked: "alarms/check",
// 机器人
robotRequest: "tunnel/{id}/robot",
//党员工会人数统计接口
getpartyMember: "laborUnion/count",
// 文章获取
getText: "article/management/query",
//支委会人员信息 //支委会人员信息
getCommittee: "partyOrganizations", //获取支委会人员 getCommittee: "partyOrganizations", //获取支委会人员
postCommittee: "partyOrganization", //新增 postCommittee: "partyOrganization", //新增

2
web/package.json

@ -6,7 +6,7 @@
"scripts": { "scripts": {
"test": "mocha", "test": "mocha",
"start": "cross-env NODE_ENV=development npm run start-params", "start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "npm run color && node server -p 5002 -u http://127.0.0.1:3000", "start-params": "npm run color && node server -p 5002 -u http://localhost:8080",
"deploy": "export NODE_ENV=production&&npm run color && npm run build && node server", "deploy": "export NODE_ENV=production&&npm run color && npm run build && node server",
"build-dev": "export NODE_ENV=development&&webpack --config webpack.config.js", "build-dev": "export NODE_ENV=development&&webpack --config webpack.config.js",
"build": "export NODE_ENV=production&&npm run color&&webpack --config webpack.config.prod.js", "build": "export NODE_ENV=production&&npm run color&&webpack --config webpack.config.prod.js",

2
web/readme.md

@ -203,7 +203,7 @@
function mapStateToProps(state) { function mapStateToProps(state) {
const { auth, global, members } = state; const { auth, global, members } = state;
return { return {
loading: members.isRequesting, <!-- loading: members.isRequesting, -->
user: auth.user, user: auth.user,
actions: global.actions, actions: global.actions,
members: members.data, members: members.data,

Loading…
Cancel
Save