diff --git a/web/client/src/app.js b/web/client/src/app.js index 6aace3a..1c45a61 100644 --- a/web/client/src/app.js +++ b/web/client/src/app.js @@ -1,6 +1,6 @@ import React, { useEffect } from 'react'; import { - Auth, AlarmConfure, Article, Party, Personnel + Auth, AlarmConfure, Article, Wait, Personnel } from './sections'; import Layout from './layout'; @@ -19,7 +19,7 @@ function App(props) { return ( ); } diff --git a/web/client/src/layout/containers/layout/index.js b/web/client/src/layout/containers/layout/index.js index 4a3e190..6891c52 100644 --- a/web/client/src/layout/containers/layout/index.js +++ b/web/client/src/layout/containers/layout/index.js @@ -230,4 +230,4 @@ function mapStateToProps(state) { export default connect(mapStateToProps)(LayoutContainer); -var pathList = ["/article", "/party", "/organization", "/personnel"]; +var pathList = ["/article", "/wait", "/organization", "/personnel"]; diff --git a/web/client/src/sections/homePage/actions/profile.js b/web/client/src/sections/homePage/actions/profile.js index abf34e2..8db83fe 100644 --- a/web/client/src/sections/homePage/actions/profile.js +++ b/web/client/src/sections/homePage/actions/profile.js @@ -99,7 +99,7 @@ export function getProject() { type: "post", dispatch: dispatch, actionType: "PROJECT", - url: ApiTable.projectUrl, + url: ApiTable.getProjectUrl, msg: { option: "获取本周在研项目" }, reducer: { name: "project", @@ -113,7 +113,7 @@ export function getPeople() { type: "post", dispatch: dispatch, actionType: "PEOPLE", - url: ApiTable.peopleUrl, + url: ApiTable.getPeopleUrl, msg: { option: "获取人员情况" }, reducer: { name: "people", @@ -127,7 +127,7 @@ export function getWait() { type: "post", dispatch: dispatch, actionType: "WAIT", - url: ApiTable.waitUrl, + url: ApiTable.getWaitUrl, msg: { option: "获取待研发项目" }, reducer: { name: "wait", diff --git a/web/client/src/sections/index.js b/web/client/src/sections/index.js index 5eceed5..e1177fb 100644 --- a/web/client/src/sections/index.js +++ b/web/client/src/sections/index.js @@ -1,9 +1,9 @@ import Auth from './auth'; import AlarmConfure from './homePage'; import Article from './article' -import Party from './party' +import Wait from './wait' import Personnel from './personnel' export { - Auth, AlarmConfure, Article, Party, Personnel + Auth, AlarmConfure, Article, Wait, Personnel }; diff --git a/web/client/src/sections/party/actions/index.js b/web/client/src/sections/party/actions/index.js deleted file mode 100644 index 1e6b011..0000000 --- a/web/client/src/sections/party/actions/index.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; -import { editLaborParty } from './party' - -export default { - editLaborParty -} \ No newline at end of file diff --git a/web/client/src/sections/party/actions/party.js b/web/client/src/sections/party/actions/party.js deleted file mode 100644 index d7d87fc..0000000 --- a/web/client/src/sections/party/actions/party.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; -import { ApiTable } from '$utils' -import { Request } from '@peace/utils' -import { basicAction } from '@peace/utils' - - -export function editLaborParty(obj) { - return dispatch => basicAction({ - type: 'put', - dispatch: dispatch, - data: obj, - actionType: 'EDIT_PARTY', - url: `${ApiTable.getpartyMember}`, - msg: { error: '编辑党员工会人数失败' }, - reducer: { name: 'editLaborParty' } - }); -} - diff --git a/web/client/src/sections/party/components/edit-party.js b/web/client/src/sections/party/components/edit-party.js deleted file mode 100644 index 9439fed..0000000 --- a/web/client/src/sections/party/components/edit-party.js +++ /dev/null @@ -1,82 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { Modal, Form, InputNumber, Button } from 'antd' -import { useEffect } from 'react' - -const EditParty = props => { - const { visible, handleOk, handleCancel, editData } = props - const [form] = Form.useForm(); - - useEffect(() => { - if (editData && visible) { - form.setFieldsValue({ - party: editData.partyNumber, - labor: editData.laborUnion - }) - } - }, [editData, visible]) - - return ( - -
- - - - - - - -
- - -
-
- -
-
- ) -} - -EditParty.propTypes = { - visible: PropTypes.bool, - handleCancel: PropTypes.func, - handleOk: PropTypes.func, - editData: PropTypes.object -} - -export default EditParty \ No newline at end of file diff --git a/web/client/src/sections/party/containers/index.js b/web/client/src/sections/party/containers/index.js deleted file mode 100644 index fbbd356..0000000 --- a/web/client/src/sections/party/containers/index.js +++ /dev/null @@ -1,92 +0,0 @@ -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 1 - } - }, - { - key: 'partyNumber', - dataIndex: 'partyNumber', - title: '党员人数', - }, - { - key: 'laborUnion', - dataIndex: 'laborUnion', - title: '工会人数', - }, - { - key: 'ation', - title: '操作', - render: (text, record) => { - return onEditParty(record)}>编辑 - } - } - ] - - 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 ( -
-

党员、工会人数维护

- - - - ) -} - -Default.propTypes = { - second: PropTypes.third -} - -const mapStateToProps = (state) => ({}) - - -export default connect(mapStateToProps)(Default) \ No newline at end of file diff --git a/web/client/src/sections/wait/actions/article.js b/web/client/src/sections/wait/actions/article.js new file mode 100644 index 0000000..cdada0d --- /dev/null +++ b/web/client/src/sections/wait/actions/article.js @@ -0,0 +1,64 @@ +"use strict"; +import { ApiTable } from "$utils"; +import { Request } from "@peace/utils"; +import { basicAction } from "@peace/utils"; + +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 } }); + }; +} diff --git a/web/client/src/sections/wait/actions/index.js b/web/client/src/sections/wait/actions/index.js new file mode 100644 index 0000000..5995a74 --- /dev/null +++ b/web/client/src/sections/wait/actions/index.js @@ -0,0 +1,9 @@ +"use strict"; +import { addArticle, editArticle, getDataList, delDataList } from "./article"; + +export default { + addArticle, + editArticle, + getDataList, + delDataList, +}; diff --git a/web/client/src/sections/wait/components/import_model.js b/web/client/src/sections/wait/components/import_model.js new file mode 100644 index 0000000..41098a5 --- /dev/null +++ b/web/client/src/sections/wait/components/import_model.js @@ -0,0 +1,163 @@ +/* + * @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' + +//TODO 下载模板和上传文件读取 +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('没有数据可以提交,请上传数据文件') + } + } + + return ( + { + setMsg('') + setLoading(false) + setPostData([]) + handleCancel() + }} + destroyOnClose + > + {/* */} + + + +
下载模板后填写完整后上传
+
+ { + 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 + + 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 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); // 读取数据 + }, + }}> + + +
+ {msg} +
+
+ ) +} + +function mapStateToProps(state) { + const { auth, customizeList } = state; + return { + user: auth.user, + } +} + + +export default connect(mapStateToProps)(ImportUser); \ No newline at end of file diff --git a/web/client/src/sections/wait/components/modeal.js b/web/client/src/sections/wait/components/modeal.js new file mode 100644 index 0000000..53e5c41 --- /dev/null +++ b/web/client/src/sections/wait/components/modeal.js @@ -0,0 +1,96 @@ +import React,{useState,useEffect} from 'react' +import { Modal, Form, Input, Button,DatePicker,Select } from 'antd' +import dayjs from 'dayjs'; +function modeal(props) { + const [form] = Form.useForm(); + const { visible, handleOk, handleCancel, editData } = props + console.log(editData) + useEffect(() => { + if (editData && visible) { + form.setFieldsValue({ + name_project: editData.name_project, + part_people: editData.part_people, + build_time: dayjs(editData?.build_time), + publish_time: dayjs(editData.publish_time), + progress:editData.progress + }) + } + }, [editData, visible]) + return ( + +
+ + + + + + + + + + + + + + + + +
+ + +
+
+ + +
+ ) +} + +export default modeal \ No newline at end of file diff --git a/web/client/src/sections/wait/containers/index.js b/web/client/src/sections/wait/containers/index.js new file mode 100644 index 0000000..647d8dc --- /dev/null +++ b/web/client/src/sections/wait/containers/index.js @@ -0,0 +1,192 @@ +import PropTypes from "prop-types"; +import React, { useEffect, useState, useRef } from "react"; +import { connect } from "react-redux"; +import { Button, Popconfirm } from "antd"; +import ProTable from "@ant-design/pro-table"; +import Action from "../actions/index"; +import moment from "moment"; +import { push } from "react-router-redux"; +import { Scroller } from "$components"; +import ProjectModeal from '../components/modeal' +import ImportModeal from '../components/import_model' + +export const Default = (props) => { + const { dispatch } = props; + const [heading, setHeading] = useState(); //标题 + const [state, setState] = useState(); //状态 + const [day, setDay] = useState(); //发布时间 + const [counts, setCounts] = useState(); //数据 + const [visible, setVisible] = useState(false); //弹窗 + const [editData, setEditData] = useState(); //数据 + const [importVisible, setImportVisible] = useState(false); //弹窗 + + const tableActionRef = useRef(); + const dataSore = [{ name_project: '企服v1.0.1', part_people: '投入研发3、测试1', build_time: new Date(), publish_time: new Date(), progress: '研发中' }] + const columns = [ + { + title: "项目", + dataIndex: "name_project", + key: "name_project", + hideInSearch: true, + render: (dom, record) => { + return record.name_project; + }, + }, + { + title: "需求来源", + key: "from_project", + dataIndex: "from_project", + hideInSearch: true, + render: (dom, record) => { + return record.part_people + }, + }, + { + title: "对接人", + key: "contacts", + dataIndex: "contacts", + hideInSearch: true, + render: (dom, record) => { + return moment(record.build_time).format('YYYY-MM-DD') + }, + }, + { + title: '处理进度', + dataIndex: 'progress', + key: 'progress', + align: 'center' + }, + { + title: "操作", + key: "since", + dataIndex: "createdAt", + valueType: "dateTime", + hideInSearch: true, + render: (dom, record) => { + return ( +
+ { + editor(record); + }} + > + 编辑 + + { + delDataList(record.id); + }} + > + + +
+ ) + + }, + }, + { + key: "direction", + hideInTable: true, + dataIndex: "direction", + order: 6, + renderFormItem: (item, { type, defaultRender, ...rest }, form) => { + return ( + + ); + }, + }, + ]; + const handleCancel = () => { + setVisible(false) + } + const handOk = () => { + + } + const importHandleCancel = () => { + setImportVisible(false) + } + //删除资讯 + const delDataList = (ids, type) => { + dispatch(Action.delDataList(ids)).then((res) => { + if (res.success) { + // 刷新 + tableActionRef.current.reload(); + } + }); + }; + //编辑 + const editor = (record) => { + setVisible(true) + setEditData(record) + }; + return ( +
+ + { + let query = { + type: -1, + searchValue: heading, + 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 { + ...res, + total: res.payload.data ? res.payload.data.total : 0, + }; + }} + rowKey="id" + pagination={{ + showSizeChanger: true, + }} + /> + + + +
+ ); +}; + +Default.propTypes = { + second: PropTypes.third, +}; + +const mapStateToProps = (state) => ({}); + +export default connect(mapStateToProps)(Default); + + +const data = [ + { name: 'yongchu', age: '18', 任务1: 'v1', 计划1: 'time1' }, + { name: 'yongchu', age: '18', 任务1: 'v1', 计划1: 'time1' }, + { name: 'yongchu', age: '18', 任务1: 'v1', 计划1: 'time1' }, + { name: '大王', age: '18', 任务1: 'v1', 计划1: 'time1' }, + { name: '大王', age: '18', 任务1: 'v1', 计划1: 'time1' } +] \ No newline at end of file diff --git a/web/client/src/sections/party/index.js b/web/client/src/sections/wait/index.js similarity index 84% rename from web/client/src/sections/party/index.js rename to web/client/src/sections/wait/index.js index 7f880ad..a56bf27 100644 --- a/web/client/src/sections/party/index.js +++ b/web/client/src/sections/wait/index.js @@ -4,8 +4,8 @@ import actions from './actions'; import nativeItem from './nav-item'; export default { - key: 'party', - name: '工会管理', + key: 'wait', + name: '排队项目', reducers, routes, actions, diff --git a/web/client/src/sections/party/nav-item.js b/web/client/src/sections/wait/nav-item.js similarity index 71% rename from web/client/src/sections/party/nav-item.js rename to web/client/src/sections/wait/nav-item.js index cda3481..5927b02 100644 --- a/web/client/src/sections/party/nav-item.js +++ b/web/client/src/sections/wait/nav-item.js @@ -5,8 +5,8 @@ import { BarChartOutlined } from '@ant-design/icons'; export function getNavItem() { return ( - }> - 工会管理 + }> + 排队项目 ); } diff --git a/web/client/src/sections/party/reducers/index.js b/web/client/src/sections/wait/reducers/index.js similarity index 100% rename from web/client/src/sections/party/reducers/index.js rename to web/client/src/sections/wait/reducers/index.js diff --git a/web/client/src/sections/party/routes.js b/web/client/src/sections/wait/routes.js similarity index 75% rename from web/client/src/sections/party/routes.js rename to web/client/src/sections/wait/routes.js index afcbab4..1551026 100644 --- a/web/client/src/sections/party/routes.js +++ b/web/client/src/sections/wait/routes.js @@ -3,8 +3,8 @@ export default [ { type: 'inner', route: { - path: '/party', - key: 'party', + path: '/wait', + key: 'wait', component: Container, } } diff --git a/web/client/src/utils/webapi.js b/web/client/src/utils/webapi.js index 09bf6bd..53bbd3d 100644 --- a/web/client/src/utils/webapi.js +++ b/web/client/src/utils/webapi.js @@ -3,9 +3,9 @@ import noCache from "superagent-no-cache"; export const ApiTable = { /* 研发看板 */ - projectUrl: "outProject", // 在研项目 - peopleUrl: "outPeople", // 人员情况 - waitUrl: "outWait", // 待研项目 + getProjectUrl: "outProject", // 在研项目 + getPeopleUrl: "outPeople", // 人员情况 + getWaitUrl: "outWait", // 待研项目 getDataList: "article/management", //全部资讯 delDataList: "article/management", //删除资讯