巴林闲侠
2 years ago
14 changed files with 550 additions and 12 deletions
@ -0,0 +1,67 @@ |
|||||
|
{ |
||||
|
// 使用 IntelliSense 了解相关属性。 |
||||
|
// 悬停以查看现有属性的描述。 |
||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 |
||||
|
"version": "0.2.0", |
||||
|
"configurations": [ |
||||
|
{ |
||||
|
"type": "node", |
||||
|
"request": "launch", |
||||
|
"name": "启动 API", |
||||
|
"program": "${workspaceRoot}/api/server.js", |
||||
|
"env": { |
||||
|
"NODE_ENV": "development" |
||||
|
}, |
||||
|
"args": [ |
||||
|
"-p 4700", |
||||
|
"-f http://localhost:4700", |
||||
|
// 研发 |
||||
|
"-g postgres://postgres:123@10.8.30.166:5432/hr-dev", |
||||
|
"--redisHost 10.8.30.112", |
||||
|
"--redisPort 6379", |
||||
|
// "--apiEmisUrl http://10.8.30.112:14000", |
||||
|
// 测试 |
||||
|
"--apiEmisUrl http://10.8.30.161:1111", |
||||
|
"--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5", |
||||
|
"--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa", |
||||
|
"--qnbkt dev-hr", |
||||
|
// "--qndmn http://resources.anxinyun.cn", |
||||
|
"--qndmn http://rjkwed13l.hn-bkt.clouddn.com", |
||||
|
|
||||
|
// 似乎不能传空 先注释 * 2 |
||||
|
// "--clickHouseUser ", |
||||
|
// "--clickHousePassword ", |
||||
|
|
||||
|
"--clickHousePort 30123", |
||||
|
|
||||
|
// 开发 |
||||
|
// "--clickHouseUrl http://10.8.30.71", |
||||
|
// "--clickHousePepEmis pepca_dev", |
||||
|
// "--clickHouseCamworkflow camworkflow", |
||||
|
// "--clickHouseHr hr_dev", |
||||
|
|
||||
|
// 测试 |
||||
|
"--clickHouseUrl http://10.8.30.161", |
||||
|
"--clickHousePepEmis pepca8", |
||||
|
"--clickHouseCamworkflow camworkflow", |
||||
|
"--clickHouseHr hrm", |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
"type": "node", |
||||
|
"request": "launch", |
||||
|
"name": "run mocha", |
||||
|
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha", |
||||
|
"stopOnEntry": false, |
||||
|
"args": [ |
||||
|
"app/test/*.test.js", |
||||
|
"--no-timeouts" |
||||
|
], |
||||
|
"cwd": "${workspaceRoot}", |
||||
|
"runtimeExecutable": null, |
||||
|
"env": { |
||||
|
"NODE_ENV": "development" |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
'use strict'; |
||||
|
import { RouteTable, RouteRequest } from '$utils' |
||||
|
|
||||
|
export function getServiceUrl() { |
||||
|
return dispatch => { |
||||
|
return RouteRequest.get(RouteTable.getWeeklyService) |
||||
|
.then(res => { |
||||
|
return dispatch({ |
||||
|
type: "SERVER_WEEKLY_URL", |
||||
|
payload: res |
||||
|
}) |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,410 @@ |
|||||
|
import React, { useEffect, useState, useRef, useMemo } from 'react'; |
||||
|
import { connect } from 'react-redux'; |
||||
|
import { Table, Button, Pagination, Skeleton, Form, Tooltip, Banner } from '@douyinfe/semi-ui'; |
||||
|
import { IconSearch } from '@douyinfe/semi-icons'; |
||||
|
import { SkeletonScreen } from "$components"; |
||||
|
import '../style.less' |
||||
|
import { Setup } from "$components"; |
||||
|
import moment from 'moment' |
||||
|
import { getServiceUrl } from '../actions/service'; |
||||
|
|
||||
|
const WeeklyManagement = (props) => { |
||||
|
const { dispatch, actions, history, user, loading, socket, xqMembers } = props; |
||||
|
|
||||
|
const form = useRef();//表单 |
||||
|
|
||||
|
const [setup, setSetup] = useState(false);//表格设置是否显现 |
||||
|
const [setupp, setSetupp] = useState([]);//实际显示的表格列表 |
||||
|
const [lookup, setLookup] = useState({});//搜索 |
||||
|
const [query, setQuery] = useState({ limit: 10, page: 0 }); //页码信息 |
||||
|
const [order, setOrder] = useState({ orderBy: 'hiredate', orderDirection: 'DESC' }); //页码信息 |
||||
|
const [limits, setLimits] = useState(0)//每页实际条数 |
||||
|
const [downloadUrl, setDownloadUrl] = useState('')//下载pdf; |
||||
|
const [warningBanner, setWarningBanner] = useState(null); |
||||
|
const WEEKLYMANAGEMENT = "weeklyManagement"; |
||||
|
const page = useRef(query.page);//哪一页 |
||||
|
|
||||
|
let btnDisable = false; |
||||
|
const tableList = [//表格属性 |
||||
|
{ |
||||
|
title: '基础信息', |
||||
|
list: [ |
||||
|
{ name: "姓名", value: "userName" }, |
||||
|
{ name: "所属部门", value: "departmrnt" }, |
||||
|
{ name: "职位", value: "roleName" }, |
||||
|
{ name: "应提交次数", value: "idNumber" }, |
||||
|
{ name: "实际提交次述", value: "number" }, |
||||
|
{ name: "延期次数", value: "yqNumber" }, |
||||
|
{ name: "未提交次数", value: "noNumber" }, |
||||
|
{ name: "未及时审批次数", value: "noAuditNumber" }, |
||||
|
{ name: "审批人", value: "auditUser" }, |
||||
|
{ name: "操作", value: "action" } |
||||
|
] |
||||
|
} |
||||
|
]; |
||||
|
useEffect(() => { |
||||
|
localStorage.getItem(WEEKLYMANAGEMENT) == null |
||||
|
? localStorage.setItem( |
||||
|
WEEKLYMANAGEMENT, |
||||
|
JSON.stringify(['userName', 'departmrnt', 'roleName', 'idNumber', 'number', 'yqNumber', 'noNumber', 'noAuditNumber', 'auditUser', |
||||
|
'action']) |
||||
|
) |
||||
|
: ""; |
||||
|
attribute(); |
||||
|
}, []) |
||||
|
|
||||
|
useEffect(() => { |
||||
|
if (form && form.current && form.current.setValue) { |
||||
|
form.current.setValue("weeklyRange", [moment().startOf('isoWeek').format('YYYY-MM-DD'), moment().endOf('isoWeek').format('YYYY-MM-DD')]) |
||||
|
} |
||||
|
}, []) |
||||
|
|
||||
|
const columns = [ |
||||
|
{ |
||||
|
title: ( |
||||
|
<span> |
||||
|
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> 员工编号 |
||||
|
</span> |
||||
|
), |
||||
|
width: 200, |
||||
|
dataIndex: "userCode", |
||||
|
key: "userCode", |
||||
|
sorter: (a, b) => { }, |
||||
|
// sorter: (a, b) => a.name.length - b.name.length > 0 ? 1 : -1, |
||||
|
render: (_, r, index) => { |
||||
|
return (r.userCode ? r.userCode : '-'); |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
//获取表格属性设置 |
||||
|
function attribute() { |
||||
|
const arr = localStorage.getItem(WEEKLYMANAGEMENT) |
||||
|
? JSON.parse(localStorage.getItem(WEEKLYMANAGEMENT)) |
||||
|
: []; |
||||
|
|
||||
|
const column = [ |
||||
|
{ |
||||
|
title: ( |
||||
|
<div> |
||||
|
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> 姓名 |
||||
|
</div> |
||||
|
), |
||||
|
dataIndex: "userName", |
||||
|
key: "userName", |
||||
|
render: (_, r, index) => { |
||||
|
return (r.userName ? r.userName : '-'); |
||||
|
}, |
||||
|
}, { |
||||
|
title: ( |
||||
|
<div> |
||||
|
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> 所属部门 |
||||
|
</div> |
||||
|
), |
||||
|
dataIndex: "departmrnt", |
||||
|
key: "departmrnt", |
||||
|
render: (_, r, index) => { |
||||
|
return ( |
||||
|
<div style={{ display: 'flex' }}> |
||||
|
{ |
||||
|
r.departmrnt.map((ite, idx) => { |
||||
|
let departmentsArr = [] |
||||
|
for (let i = 0; i < r.departmrnt.length; i++) { |
||||
|
departmentsArr.push(r.departmrnt[i].name) |
||||
|
} |
||||
|
return ( |
||||
|
<div key={idx} style={{ display: 'flex' }}> |
||||
|
{idx == 0 ? |
||||
|
(<div style={{ padding: '0px 4px 1px 4px ', color: '#FFFFFF', fontSize: 12, background: 'rgba(0,90,189,0.8)', borderRadius: 2, marginRight: 4 }}> |
||||
|
{ite.name} |
||||
|
</div>) : ('') |
||||
|
|
||||
|
} |
||||
|
{ |
||||
|
r.departmrnt.length > 1 && idx == 1 ? ( |
||||
|
<Tooltip content={departmentsArr.join(',')} trigger="click" style={{ lineHeight: 2 }}> |
||||
|
<div style={{ padding: '0px 4px 1px 4px ', color: 'rgba(0,90,189,0.8)', fontSize: 12, marginRight: 4, cursor: "pointer", }}> |
||||
|
+{r.departmrnt.length - 1} |
||||
|
</div> |
||||
|
</Tooltip> |
||||
|
) : ('') |
||||
|
} |
||||
|
</div> |
||||
|
) |
||||
|
}) |
||||
|
} |
||||
|
</div> |
||||
|
) |
||||
|
}, |
||||
|
}, { |
||||
|
title: ( |
||||
|
<div> |
||||
|
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> 职位 |
||||
|
</div> |
||||
|
), |
||||
|
dataIndex: "roleName", |
||||
|
key: "roleName", |
||||
|
render: (_, r, index) => { |
||||
|
return ( |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
{ |
||||
|
r.role.map((ite, idx) => { |
||||
|
let roleArr = [] |
||||
|
for (let i = 0; i < r.role.length; i++) { |
||||
|
roleArr.push(r.role[i].name) |
||||
|
} |
||||
|
return ( |
||||
|
<div key={idx} style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
{idx == 0 ? |
||||
|
(ite.name) : ('') |
||||
|
} |
||||
|
{ |
||||
|
r.role.length > 1 && idx == 1 ? ( |
||||
|
<Tooltip content={roleArr.join(',')} trigger="click" style={{ lineHeight: 2 }}> |
||||
|
<div style={{ color: 'rgba(0,90,189,0.8)', fontSize: 12, marginRight: 4, cursor: "pointer", }}> |
||||
|
+{r.role.length - 1} |
||||
|
</div> |
||||
|
</Tooltip> |
||||
|
) : ('') |
||||
|
} |
||||
|
</div> |
||||
|
) |
||||
|
}) |
||||
|
} |
||||
|
</div>); |
||||
|
}, |
||||
|
}, { |
||||
|
title: '应提交次数', |
||||
|
dataIndex: "idNumber", |
||||
|
key: "idNumber", |
||||
|
render: (_, r, index) => { |
||||
|
return (r.idNumber ? r.idNumber : '-'); |
||||
|
}, |
||||
|
}, { |
||||
|
title: '实际提交次述', |
||||
|
dataIndex: "number", |
||||
|
key: "number", |
||||
|
render: (_, r, index) => { |
||||
|
return (r.gender ? r.gender : '-'); |
||||
|
}, |
||||
|
}, { |
||||
|
title: '延期次数', |
||||
|
dataIndex: "yqNumber", |
||||
|
key: "yqNumber", |
||||
|
render: (_, r, index) => { |
||||
|
return (r.nativePlace ? r.nativePlace : '-'); |
||||
|
}, |
||||
|
}, { |
||||
|
title: '未提交次数', |
||||
|
dataIndex: "noNumber", |
||||
|
key: "noNumber", |
||||
|
render: (_, r, index) => { |
||||
|
return (r.birthday ? r.birthday : '-'); |
||||
|
}, |
||||
|
}, { |
||||
|
title: '未及时审批次数', |
||||
|
dataIndex: "noAuditNumber", |
||||
|
key: "noAuditNumber", |
||||
|
render: (_, r, index) => { |
||||
|
return (r.marital ? r.marital : '-'); |
||||
|
}, |
||||
|
}, { |
||||
|
title: '审批人', |
||||
|
dataIndex: "auditUser", |
||||
|
key: "auditUser", |
||||
|
render: (_, r, index) => { |
||||
|
return (r.politicsStatus ? r.politicsStatus : '-'); |
||||
|
}, |
||||
|
}, { |
||||
|
title: '操作', |
||||
|
dataIndex: "action", |
||||
|
key: "action", |
||||
|
render: (_, r, index) => { |
||||
|
return (r.vitae ? <a href={`/_file-server/${r.vitae}`} style={{ color: '#005ABD' }}>下载</a> : '-') |
||||
|
}, |
||||
|
}, |
||||
|
]; |
||||
|
for (let i = 0; i < arr.length; i++) { |
||||
|
let colum = column.filter((item) => { |
||||
|
return item.key === arr[i]; |
||||
|
}); |
||||
|
columns.splice(i + 2, 0, colum[0]); |
||||
|
} |
||||
|
setSetupp(columns); |
||||
|
} |
||||
|
function handleRow(record, index) {//斑马条纹 |
||||
|
// 给偶数行设置斑马纹 |
||||
|
if (index % 2 === 0) { |
||||
|
return { |
||||
|
style: { |
||||
|
background: '#FAFCFF', |
||||
|
} |
||||
|
}; |
||||
|
} else { |
||||
|
return {}; |
||||
|
} |
||||
|
} |
||||
|
const scroll = useMemo(() => ({}), []); |
||||
|
|
||||
|
return ( |
||||
|
<> |
||||
|
<div style={{ padding: '0px 12px' }}> |
||||
|
<div style={{ display: 'flex' }}> |
||||
|
<div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14 }}>人事管理</div> |
||||
|
<div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14, margin: '0px 8px' }}>/</div> |
||||
|
<div style={{ color: 'rgba(0,0,0,0.45)', fontSize: 14 }}>基本动作</div> |
||||
|
<div style={{ color: '#033C9A', fontSize: 14, margin: '0px 8px' }}>/</div> |
||||
|
<div style={{ color: '#033C9A', fontSize: 14 }}>周报管理</div> |
||||
|
</div> |
||||
|
<div style={{ background: '#FFFFFF', boxShadow: '0px 0px 12px 2px rgba(220,222,224,0.2)', borderRadius: 2, padding: '20px 0px 20px 19px ', marginTop: 12 }}> |
||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> |
||||
|
<div style={{ display: 'flex', alignItems: 'baseline' }}> |
||||
|
<div style={{ width: 0, height: 20, borderLeft: '3px solid #0F7EFB', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div> |
||||
|
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#033C9A', marginLeft: 8 }}>周报管理</div> |
||||
|
<div style={{ marginLeft: 6, fontSize: 12, color: '#969799', fontFamily: "DINExp", }}>WEEKLY MANAGEMENT</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style={{ marginRight: 20, marginTop: 18 }}> |
||||
|
<Form |
||||
|
labelPosition="left" |
||||
|
labelAlign="right" |
||||
|
labelWidth="80px" |
||||
|
getFormApi={(formApi) => (form.current = formApi)} |
||||
|
> |
||||
|
<div> |
||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}> |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
<Form.DatePicker |
||||
|
label='查询时间:' |
||||
|
field='weeklyRange' type="dateRange" density="compact" showClear style={{ width: 370, color: "#F9F9F9" }} /> |
||||
|
</div> |
||||
|
<div style={{ display: 'flex', alignItems: 'center' }}> |
||||
|
<div style={{ width: 20, height: 20, cursor: "pointer", marginRight: 15 }} |
||||
|
> |
||||
|
|
||||
|
{/* <img src="/assets/images/hrImg/export.png" alt="" style={{ width: '100%', height: '100%' }} /> */} |
||||
|
{ |
||||
|
downloadUrl ? <iframe src={`/_api/${downloadUrl}`} style={{ display: 'none' }} /> : '' |
||||
|
} |
||||
|
</div> |
||||
|
<img src="/assets/images/hrImg/newsetup.png" alt="" style={{ width: 20, height: 20, cursor: "pointer", marginRight: 15 }} |
||||
|
onClick={() => setSetup(true)} |
||||
|
/> |
||||
|
<Button theme='solid' |
||||
|
type='primary' |
||||
|
style={{ width: 80, borderRadius: 2, height: 32, background: '#DBECFF', color: '#005ABD' }} |
||||
|
// disable={btnDisable} |
||||
|
onClick={() => { |
||||
|
const weeklyRange = form.current.getValue("weeklyRange"); |
||||
|
if (weeklyRange && weeklyRange.length == 2) { |
||||
|
dispatch(getServiceUrl()).then(res => { |
||||
|
const { payload } = res; |
||||
|
if (payload && payload.url) { |
||||
|
|
||||
|
let url = `${payload.url}/week_report/week`; |
||||
|
if (weeklyRange && weeklyRange.length == 2) { |
||||
|
url += `?start=${moment(weeklyRange[0]).format('YYYY-MM-DD HH:mm:ss')}&end=${moment(weeklyRange[1]).format('YYYY-MM-DD HH:mm:ss')}` |
||||
|
} |
||||
|
console.log(url); |
||||
|
setDownloadUrl(url); |
||||
|
} else { |
||||
|
setWarningBanner("导出地址有误,导出失败"); |
||||
|
} |
||||
|
}) |
||||
|
} else { |
||||
|
setWarningBanner("请选择查询时间范围"); |
||||
|
} |
||||
|
}}>导出</Button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</Form> |
||||
|
{ |
||||
|
warningBanner && |
||||
|
(<Banner |
||||
|
type="danger" |
||||
|
description={warningBanner} |
||||
|
onClose={() => setWarningBanner(null)} |
||||
|
/>)} |
||||
|
<div style={{ border: '1px solid #C7E1FF', background: '#F4F8FF', borderRadius: 2, height: 32, width: 669, padding: '8px 0px 7px 12px', display: 'flex', alignItems: 'center', color: '#0F7EFB', fontSize: 12 }}> |
||||
|
<img src="/assets/images/hrImg/!.png" alt="" style={{ width: 14, height: 14, marginRight: 8 }} /> |
||||
|
表格中带有认证标识" |
||||
|
<img src="/assets/images/hrImg/V.png" alt="" style={{ width: 14, height: 14 }} /> |
||||
|
"信息的为系统基础数据,来源于项企PEP系统,不支持修改和导入变更 |
||||
|
</div> |
||||
|
<div style={{ marginTop: 20 }}> |
||||
|
<Skeleton |
||||
|
// loading={loading} |
||||
|
loading={false} |
||||
|
active={true} |
||||
|
placeholder={SkeletonScreen()} |
||||
|
> |
||||
|
<Table |
||||
|
columns={setupp.filter((s) => s)} |
||||
|
dataSource={[]} |
||||
|
bordered={false} |
||||
|
empty="暂无数据" |
||||
|
pagination={false} |
||||
|
onRow={handleRow} |
||||
|
scroll={scroll} |
||||
|
/> |
||||
|
</Skeleton> |
||||
|
<div |
||||
|
style={{ |
||||
|
display: "flex", |
||||
|
justifyContent: "space-between", |
||||
|
padding: "20px 20px", |
||||
|
}} |
||||
|
> |
||||
|
<div> |
||||
|
</div> |
||||
|
<div style={{ display: 'flex', }}> |
||||
|
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}> |
||||
|
共{limits}条信息 |
||||
|
</span> |
||||
|
<Pagination |
||||
|
className="22" |
||||
|
total={limits} |
||||
|
showSizeChanger |
||||
|
currentPage={query.page + 1} |
||||
|
pageSizeOpts={[10, 20, 30, 40]} |
||||
|
onChange={(currentPage, pageSize) => { |
||||
|
setQuery({ limit: pageSize, page: currentPage - 1 }); |
||||
|
page.current = currentPage - 1 |
||||
|
}} |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{setup ? ( |
||||
|
<Setup |
||||
|
tableType={WEEKLYMANAGEMENT} |
||||
|
tableList={tableList} |
||||
|
length={10} |
||||
|
close={() => { |
||||
|
setSetup(false); |
||||
|
attribute(); |
||||
|
}} |
||||
|
/> |
||||
|
) : ( |
||||
|
"" |
||||
|
)} |
||||
|
|
||||
|
</> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
function mapStateToProps(state) { |
||||
|
const { auth, global, MemberSearch, webSocket } = state; |
||||
|
return { |
||||
|
// loading: members.isRequesting, |
||||
|
user: auth.user, |
||||
|
actions: global.actions, |
||||
|
xqMembers: MemberSearch.data, |
||||
|
// socket: webSocket.socket |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
export default connect(mapStateToProps)(WeeklyManagement); |
@ -0,0 +1,18 @@ |
|||||
|
'use strict'; |
||||
|
// const request = require('superagent');
|
||||
|
|
||||
|
module.exports = { |
||||
|
entry: function (app, router, opts) { |
||||
|
|
||||
|
const getWeeklyService = async function (ctx) { |
||||
|
const { service } = opts; |
||||
|
|
||||
|
ctx.status = 200; |
||||
|
ctx.body = { |
||||
|
url: service.weekly, |
||||
|
}; |
||||
|
}; |
||||
|
|
||||
|
router.get('/_service/weekly', getWeeklyService); |
||||
|
} |
||||
|
}; |
Loading…
Reference in new issue