Browse Source

“本月在研项目”数据源改为“禅道”。

master
Julin 1 year ago
parent
commit
5d566b70c6
  1. 61
      web/client/src/layout/index.js
  2. 326
      web/client/src/sections/homePage/containers/index.js
  3. 83
      web/config-product-excluded.js
  4. 3
      web/package.json
  5. 225
      web/routes/missionboard/index.js

61
web/client/src/layout/index.js

@ -1,18 +1,18 @@
import React, { useEffect, useState } from "react";
import moment from "moment";
import { Provider } from "react-redux";
import { createBrowserHistory } from "history";
import { ConnectedRouter } from "connected-react-router";
import { Switch, Route } from "react-router-dom";
import { ConfigProvider } from "antd";
import zhCN from "antd/lib/locale/zh_CN";
import { basicReducer } from "@peace/utils";
import * as layoutActions from "./actions/global";
import { Layout, NoMatch } from "./containers";
import configStore from "./store";
import "moment/locale/zh-cn";
import React, { useEffect, useState } from 'react';
import moment from 'moment';
import { Provider } from 'react-redux';
import { createBrowserHistory } from 'history';
import { ConnectedRouter } from 'connected-react-router';
import { Switch, Route } from 'react-router-dom';
import { ConfigProvider } from 'antd';
import zhCN from 'antd/lib/locale/zh_CN';
import { basicReducer } from '@peace/utils';
import * as layoutActions from './actions/global';
import { Layout, NoMatch } from './containers';
import configStore from './store';
import 'moment/locale/zh-cn';
moment.locale("zh-cn");
moment.locale('zh-cn');
const { initLayout, initApiRoot } = layoutActions;
@ -33,22 +33,22 @@ function Root(props) {
path: route.path,
breadcrumb: route.breadcrumb,
component: route.component || null,
authCode: route.authCode || "",
authCode: route.authCode || '',
key: route.key,
};
if (!route.path.startsWith("/")) {
if (!route.path.startsWith('/')) {
console.error(`路由配置需以 "/" 开始:${route.path}`);
}
if (route.path.length > 1 && route.path[route.path.length] == "/") {
if (route.path.length > 1 && route.path[route.path.length] == '/') {
console.error(`除根路由路由配置不可以以 "/" 结束:${route.path}`);
}
if (parentRoute && parentRoute != "/") {
if (parentRoute && parentRoute != '/') {
obj.path = parentRoute + route.path;
}
if (route.exact === false) {
obj.exact = false;
}
if (route.hasOwnProperty("childRoutes")) {
if (route.hasOwnProperty('childRoutes')) {
combineRoutes.push(obj);
flat(route.childRoutes, obj.path);
} else {
@ -90,12 +90,11 @@ function Root(props) {
};
for (const s of sections) {
if (!s.key)
console.warn(`请给你的section添加一个key值,section name:${s.name}`);
if (!s.key) { console.warn(`请给你的section添加一个key值,section name:${s.name}`); }
for (const r of s.routes) {
if (r.type == "inner" || r.type == "home") {
if (r.type == 'inner' || r.type == 'home') {
inners.push(r.route);
} else if (r.type == "outer") {
} else if (r.type == 'outer') {
outers.push(r.route);
}
}
@ -104,14 +103,14 @@ function Root(props) {
}
if (s.actions) {
actions = { ...actions, [s.key]: s.actions };
if (s.key != "auth") {
if (s.key != 'auth') {
for (const ak in s.actions) {
const actions = s.actions[ak];
if (actions && typeof actions === "object") {
if (actions && typeof actions === 'object') {
for (const actionName in actions) {
initReducer(reducers, actionName, actions[actionName]);
}
} else if (typeof actions === "function") {
} else if (typeof actions === 'function') {
initReducer(reducers, ak, actions);
}
}
@ -123,7 +122,7 @@ function Root(props) {
const store = configStore(reducers, history);
store.dispatch(initLayout(title, copyright, sections, actions));
store.dispatch(actions.auth.initAuth());
store.dispatch(initApiRoot());
// store.dispatch(initApiRoot());
const newCombineRoutes = flatRoutes(inners);
@ -138,21 +137,21 @@ function Root(props) {
path={route.path}
component={route.component}
/>
))
)),
);
setCombineRoutes(
newCombineRoutes.map((route) => (
<Route
key={route.key}
exact={
Object.prototype.hasOwnProperty.call(route, "exact")
Object.prototype.hasOwnProperty.call(route, 'exact')
? route.exact
: true
}
path={route.path}
component={route.component}
/>
))
)),
);
}, []);
@ -173,7 +172,7 @@ function Root(props) {
</Provider>
</ConfigProvider>
) : (
""
''
);
}

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

@ -1,57 +1,82 @@
/* eslint-disable react-hooks/exhaustive-deps */
import React, { useState, useEffect,useRef } from "react";
import { connect } from "react-redux";
import { Spin, Tabs, Table } from "antd";
import classnames from "classnames/bind";
import styles from "./index.less";
import { push } from "react-router-redux";
import moment from "moment";
import { getProject, getPeople, getWait,postKeySearch } from "../actions/profile";
import { Scroller } from "$components";
import ProTable from "@ant-design/pro-table";
import React, { useState, useEffect, useRef } from 'react';
import { connect } from 'react-redux';
import { Spin, Table } from 'antd';
import classnames from 'classnames/bind';
import { push } from 'react-router-redux';
import moment from 'moment';
import request from 'superagent';
import ProTable from '@ant-design/pro-table';
import { Scroller } from '$components';
import {
getPeople, getWait, postKeySearch,
} from '../actions/profile';
import styles from './index.less';
const schedule = require('node-schedule');
const CX = classnames.bind(styles);
const topImg = "/assets/images/top.png";
const pointImg = "/assets/images/point.png";
const topImg = '/assets/images/top.png';
const pointImg = '/assets/images/point.png';
function Management(props) {
const { dispatch, user } = props
const height = document.body.clientHeight
const width=document.body.clientWidth
const [dataSource, setDataSource] = useState([])
const [name, setName] = useState()//名字查询
const [ajob, setAjob] = useState()//岗位查询
const [projectData, setProjectData] = useState([])
const [peopleData, setPeopleData] = useState([])
const [waitData, setWaitData] = useState([])
const [counts,setCounts]=useState()
const { dispatch, user } = props;
const [name, setName] = useState();// 名字查询
const [ajob, setAjob] = useState();// 岗位查询
const [projectData, setProjectData] = useState([]);
const [peopleData, setPeopleData] = useState([]);
const [waitData, setWaitData] = useState([]);
const ref = useRef();
function getOngoingProjects() {
request.get('/ongoing/projects').then((res) => {
setProjectData(res?.body?.projects);
});
}
useEffect(() => {
dispatch(getProject()).then((res) => {
setProjectData(res?.payload.data?.projects)
})
getOngoingProjects();
schedule.scheduleJob('0 0 7,18 * * ?', () => { // 每天 7时、18时 定时更新
getOngoingProjects();
});
dispatch(getPeople()).then((res) => {
setPeopleData(res.payload.data.projects)
})
setPeopleData(res?.payload.data?.projects);
});
dispatch(getWait()).then((res) => {
setWaitData(res.payload.data.projects)
})
},[])
setWaitData(res?.payload.data?.projects);
});
}, []);
const projectCol = [
{
title: '执行ID',
dataIndex: 'execution_id',
key: 'execution_id',
align: 'center',
},
{
title: '项目名称',
dataIndex: 'name_project',
key: 'name_project',
align: 'center'
align: 'center',
},
{
title: '投入人力',
dataIndex: 'part_people',
key: 'part_people',
align: 'center',
render: (dom, record) => {
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>
},
render: (dom, record) => (
<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>
),
},
{
title: '构建时间',
@ -62,45 +87,39 @@ function Management(props) {
// sortOrder:'descend' ,
sorter: {
compare: (a, b) => {
const one = moment(a.build_time).format('YYYYMMDD')
const two=moment(b.build_time).format('YYYYMMDD')
return one - two
},
const one = moment(a.build_time).format('YYYYMMDD');
const two = moment(b.build_time).format('YYYYMMDD');
return one - two;
},
render: (dom, record) => {
return <>{moment(record.build_time).format('YYYY-MM-DD')=='1999-01-01'?'待定':moment(record.build_time).format('YYYY-MM-DD')}</>
},
render: (dom, record) => <>{record.build_time ? moment(record.build_time).format('YYYY-MM-DD') : '待定'}</>,
},
{
title: '发布时间',
dataIndex: 'publish_time',
key: 'publish_time',
align: 'center',
render: (dom, record) => {
return moment(record.publish_time).format('YYYY-MM-DD')
},
render: (dom, record) => moment(record.publish_time).format('YYYY-MM-DD'),
},
{
title: '进度',
dataIndex: 'progress',
key: 'progress',
align: 'center'
align: 'center',
},
{
title: '状态',
dataIndex: 'deferred_payment',
key: 'deferred_payment',
align: 'center',
render: (dom, record) => {
const current = new Date()
return <>
render: (dom, record) => (
<>
{
((record.progress == '研发中' && Number(moment(current).format('YYYYMMDD')) > Number(moment(record.build_time).format('YYYYMMDD'))) && moment(record.build_time).format('YYYY-MM-DD') !== '1999-01-01')
|| ((record.progress == '测试中' && Number(moment(current).format('YYYYMMDD')) > Number(moment(record.publish_time).format('YYYYMMDD'))) && moment(record.build_time).format('YYYY-MM-DD') !== '1999-01-01')
|| ((record.progress == '需求评审中' && Number(moment(current).format('YYYYMMDD')) > Number(moment(record.build_time).format('YYYYMMDD'))) && moment(record.build_time).format('YYYY-MM-DD') !== '1999-01-01') ?
<div style={{ color: '#fb3838' }}>已延期</div> : <div style={{ color: '#23d96e' }}></div>}
record.publish_time && moment().isAfter(moment(record.publish_time))
? <div style={{ color: '#fb3838' }}>已延期</div> : <div style={{ color: '#23d96e' }}></div>
}
</>
},
),
},
];
@ -112,15 +131,13 @@ function Management(props) {
ellipsis: true,
hideInSearch: true,
width: 100,
render: (dom, record) => {
return record.name_people;
},
render: (dom, record) => record.name_people,
}, {
title: '岗位',
key: 'post_people',
dataIndex: 'post_people',
valueType: "select",
valueType: 'select',
initialValue: null,
fieldProps: {
onChange: (value, cs) => {
@ -128,99 +145,79 @@ function Management(props) {
},
options: [
{
label: "全部岗位",
label: '全部岗位',
value: null,
},
{
label: "研发",
label: '研发',
value: '研发',
},
{
label: "测试",
label: '测试',
value: '测试',
},
{
label: "UI",
label: 'UI',
value: 'UI',
},
],
},
render: (dom, record) => {
return record.post_people;
},
render: (dom, record) => record.post_people,
},
{
title: "周一",
key: "md",
dataIndex: "md",
title: '周一',
key: 'md',
dataIndex: 'md',
hideInSearch: true,
render: (dom, record) => {
return <div>{record.md=='undefined'?'--' :record.md}</div>;
},
render: (dom, record) => <div>{record.md == 'undefined' ? '--' : record.md}</div>,
},
{
title: "周二",
key: "td",
dataIndex: "td",
title: '周二',
key: 'td',
dataIndex: 'td',
hideInSearch: true,
render: (dom, record) => {
return <div>{record.td=='undefined'?'--' :record.td}</div>;
},
render: (dom, record) => <div>{record.td == 'undefined' ? '--' : record.td}</div>,
},
{
title: "周三",
key: "wd",
dataIndex: "wd",
title: '周三',
key: 'wd',
dataIndex: 'wd',
hideInSearch: true,
render: (dom, record) => {
return <div>{record.wd=='undefined'?'--' :record.wd}</div>;
},
render: (dom, record) => <div>{record.wd == 'undefined' ? '--' : record.wd}</div>,
},
{
title: "周四",
key: "thd ",
dataIndex: "thd ",
title: '周四',
key: 'thd ',
dataIndex: 'thd ',
hideInSearch: true,
render: (dom, record) => {
return <div>{record.thd=='undefined'?'--' :record.thd}</div>;
},
render: (dom, record) => <div>{record.thd == 'undefined' ? '--' : record.thd}</div>,
},
{
title: "周五",
key: "fd",
dataIndex: "fd",
title: '周五',
key: 'fd',
dataIndex: 'fd',
hideInSearch: true,
render: (dom, record) => {
return <div>{record.fd=='undefined'?'--' :record.fd}</div>;
},
render: (dom, record) => <div>{record.fd == 'undefined' ? '--' : record.fd}</div>,
},
{
title: "周六",
key: "sd",
dataIndex: "sd",
title: '周六',
key: 'sd',
dataIndex: 'sd',
hideInSearch: true,
render: (dom, record) => {
return <div>{record.sd=='undefined'?'--' :record.sd}</div>;
},
render: (dom, record) => <div>{record.sd == 'undefined' ? '--' : record.sd}</div>,
},
{
title: "周日",
key: "ssd",
dataIndex: "ssd",
title: '周日',
key: 'ssd',
dataIndex: 'ssd',
hideInSearch: true,
render: (dom, record) => {
return <div>{record.ssd=='undefined'?'--' :record.ssd}</div>;
},
render: (dom, record) => <div>{record.ssd == 'undefined' ? '--' : record.ssd}</div>,
},
{title: "关键字搜索",
key: "direction",
{
title: '关键字搜索',
key: 'direction',
hideInTable: true,
dataIndex: "direction",
dataIndex: 'direction',
order: 6,
fieldProps: {
onChange: (value, cs) => {
@ -229,9 +226,7 @@ function Management(props) {
placeholder: '请输入关键字进行搜索',
getPopupContainer: (triggerNode) => triggerNode.parentNode,
},
}
},
];
const waitCol = [
@ -239,115 +234,120 @@ function Management(props) {
title: '项目',
dataIndex: 'name_project',
key: 'name_project',
align: 'center'
align: 'center',
},
{
title: '需求来源',
dataIndex: 'from_project',
key: 'from_project',
align: 'center'
align: 'center',
},
{
title: '对接人',
dataIndex: 'contacts',
key: 'contacts',
align: 'center'
},{
align: 'center',
}, {
title: '评估工时',
dataIndex: 'consum_time',
key: 'consum_time',
align: 'center'
align: 'center',
},
{
title: '处理进度',
dataIndex: 'progress',
key: 'progress',
align: 'center'
align: 'center',
},
];
return (
<>
<div className={CX("index")} >
<img className={CX("index-img")} src={topImg} />
<div className={CX("index-main")} >
<div className={CX("index-main-box")} >
<img className={CX("index-main-box-point")} src={pointImg} />
<div className={CX("index-main-box-title")}>本周在研项目</div>
<div className={CX("index-main-box-en")}>/Research project this week</div>
<div className={CX('index')}>
<img className={CX('index-img')} src={topImg} />
<div className={CX('index-main')}>
<div className={CX('index-main-box')}>
<img className={CX('index-main-box-point')} src={pointImg} />
<div className={CX('index-main-box-title')}>本月在研项目</div>
<div className={CX('index-main-box-en')}>/Research project this week</div>
<Spin spinning={false}>
<Table dataSource={projectData} columns={projectCol} size="small" pagination={false} scroll={{ y: '32vh' }}/>
<Table dataSource={projectData} columns={projectCol} size="small" pagination={false} scroll={{ y: '32vh' }} />
</Spin>
</div>
<div className={CX("index-main-box")} >
<img className={CX("index-main-box-point")} src={pointImg} />
<div className={CX("index-main-box-title")}>待研发项目</div>
<div className={CX("index-main-box-en")}>/Project to be developed</div>
<Table dataSource={waitData} columns={waitCol} size="small" pagination={false} scroll={{ y: '32vh' }}/>
<div className={CX('index-main-box')}>
<img className={CX('index-main-box-point')} src={pointImg} />
<div className={CX('index-main-box-title')}>待研发项目</div>
<div className={CX('index-main-box-en')}>/Project to be developed</div>
<Table dataSource={waitData} columns={waitCol} size="small" pagination={false} scroll={{ y: '32vh' }} />
</div>
</div>
<div className={CX("index-main-box")} style={{width:'90%',margin:'0 auto',marginTop:'2.8rem',height:'42.5vh'}}>
<img className={CX("index-main-box-point")} src={pointImg} />
<div className={CX("index-main-box-title")}>人员情况</div>
<div className={CX("index-main-box-en")}>/Information on Personnel</div>
<div
className={CX('index-main-box')}
style={{
width: '90%', margin: '0 auto', marginTop: '2.8rem', height: '42.5vh',
}}
>
<img className={CX('index-main-box-point')} src={pointImg} />
<div className={CX('index-main-box-title')}>人员情况</div>
<div className={CX('index-main-box-en')}>/Information on Personnel</div>
{/* <Scroller containerId={"article-container-query"} height={"80%"}> */}
<ProTable options={false} actionRef={ref} dataSource={peopleData} columns={peopleCol} size="small" pagination={false} scroll={{ y: '20vh' }}
<ProTable
options={false}
actionRef={ref}
dataSource={peopleData}
columns={peopleCol}
size="small"
pagination={false}
scroll={{ y: '20vh' }}
request={async () => {
if (name || ajob) {
const query = {
value1:name,
value2:ajob,
}
value1: name,
value2: ajob,
};
const res = await dispatch(postKeySearch(query));
setPeopleData(res?.payload.data.projects);
return {
...res,
// total: res.payload.data.data ? res.payload.data.total : 0,
};
} else {
}
const res = await dispatch(getPeople());
console.log(res)
setPeopleData(res?.payload.data.projects);
return {
...res,
// total: res.payload.data.data ? res.payload.data.total : 0,
};
}
}}
onReset={(v) => {
setName(null)
setAjob(null)
setName(null);
setAjob(null);
}}
/>
{/* </Scroller> */}
</div>
</div>
<a
style={{
fontSize: "16px",
position: "absolute",
color: "#000",
right: "40px",
top: "20px",
fontSize: '16px',
position: 'absolute',
color: '#000',
right: '40px',
top: '20px',
zIndex: 10000,
}}
onClick={() => {
if (
user &&
user.authorized &&
JSON.parse(sessionStorage.getItem("user"))
user
&& user.authorized
&& JSON.parse(sessionStorage.getItem('user'))
) {
dispatch(push("/article"));
dispatch(push('/article'));
} else {
dispatch(push("/login"));
dispatch(push('/login'));
}
}}
>

83
web/config-product-excluded.js

@ -0,0 +1,83 @@
module.exports = [
// 硬件产品化系列
'分布式数据采集节点',
'称重采集仪',
'振动采集仪',
'云振动采集仪',
'地灾产品',
'模块化动态采集模块',
'光电扰度仪',
'移动测斜仪',
'光纤光栅解调仪',
'塔吊监测',
'水质在线监测',
'扬尘在线监测',
'分布式数据采集系统网关\\/节点',
'静力水准仪',
'振弦采集仪',
'分布式GPRS节点',
'一体化振动\\/测斜',
'磁通量产品',
'振弦类传感器',
'盒式固定测斜仪',
'导轮式固定测斜仪',
'外购传感器',
'多功能静态数据采集仪',
'激光测距仪',
'DTU-通讯设备',
'分布式振弦数据采集模块',
'加速度计',
'聚醚管&聚安酯管',
'硬件机械辅材设计',
'地质灾害监测预警监测设备-一体式倾角/加速度/裂缝计(FS-YTZD-QJ/JS/LF)',
'微型应变计',
'FS-RTU-P4',
'水利RTU FS-SL-RTU',
'国产化MCU替代',
'智能空气净化器(FS-KJ02)',
'模块化-多功能静态数据采集仪(FS-M24)',
'微型振弦采集仪(FS-iVW)',
'分布式节点',
'无线倾角传感器',
'高支模监测系统V3.00',
'振弦式温度计',
'高精度渗压计',
'高精度渗压计开发项目',
'智芯系列振弦产品开发项目',
'一体化水位传感器',
'分布式采集节点(FS-LPWAN02-LORA/4G/NB)',
// 第三方检定
'UI设计',
'第三方检定',
'第三方检定支撑',
// 测试部
'测试部',
// 软件研发部项目集
'软件研发部日常工作',
// 外场故障
'外场故障',
// ci-cd
'Jenkins集成',
'禅道',
'研发看板系统',
// 硬件研发--嵌入式开发
'固件库开发',
'单片机开发',
'linux开发',
'上位机开发',
// 测试部
'测试部门',
// 硬件研发部项目型任务
'硬件研发部任务',
// 软件共性技术研究
'共性技术',
];

3
web/package.json

@ -82,7 +82,7 @@
"ahooks": "^3.1.14",
"antd": "^4.14.1",
"antd-theme-generator": "^1.2.8",
"args": "^5.0.1",
"args": "^3.0.7",
"array-move": "^3.0.1",
"braft-editor": "^2.3.9",
"classnames": "^2.3.1",
@ -107,6 +107,7 @@
"leva": "^0.9.23",
"mini-dynamic-antd-theme": "^0.5.3",
"moment": "^2.22.0",
"node-schedule": "^2.1.1",
"npm": "^7.20.6",
"perfect-scrollbar": "^1.5.5",
"postprocessing": "^6.24.1",

225
web/routes/missionboard/index.js

@ -0,0 +1,225 @@
const request = require('superagent');
const moment = require('moment');
const productExcluded = require('../../config-product-excluded');
module.exports = {
entry(app, router, opts) {
async function auth() {
const session = await request.get('https://pms.anxinyun.cn/api-getSessionID.json');
const sessionData = JSON.parse(session.text).data;
const { sessionName, sessionID } = JSON.parse(sessionData);
const loginInfo = await request
.post('https://pms.anxinyun.cn/user-login.json')
.set({ 'Content-Type': 'application/x-www-form-urlencoded' })
.query({ [`${sessionName}`]: sessionID })
.send({ account: 'admin', password: 'Fashion123' });
app.fs = app.fs || {};
app.fs.session = { sessionName, sessionID };
}
(async function () {
await auth();
setInterval(async () => {
await auth();
}, 1200000); // 每 20分钟 刷新一次
}());
function extractBuildTime(inputString) {
const pattern = /[(\(]构建时间:(.*?)[\))]/;
const match = inputString.match(pattern);
const buildDate = match ? match[1] : null;
return buildDate;
}
async function getExecutionDetail(executionId) {
const { sessionName, sessionID } = app.fs.session;
const executionDetailRes = await request
.get(`https://pms.anxinyun.cn/execution-view-${executionId}.json`)
.set('Cookie', `${sessionName}=${sessionID}`);
const executionDetailText = JSON.parse(executionDetailRes.text);
const executionDetailData = JSON.parse(executionDetailText.data);
const executionTeamRDs = [];
const executionTeamMembers = executionDetailData.teamMembers;
for (const member of Object.values(executionTeamMembers)) {
if (member.role === '研发') executionTeamRDs.push({ name_people: member.realname });
}
const executionProducts = Object.values(executionDetailData.products).map((product) => product.name);
return { executionTeamRDs, executionProducts };
}
async function getExecutionProgress(executionId) {
const { sessionName, sessionID } = app.fs.session;
const testTaskRes = await request
.get(`https://pms.anxinyun.cn/execution-testtask-${executionId}.json`)
.set('Cookie', `${sessionName}=${sessionID}`);
const testTaskText = JSON.parse(testTaskRes.text);
const progress = Object.keys(JSON.parse(testTaskText.data).tasks).length ? '测试中' : '研发中';
return progress;
}
async function getExecutionStats(baseURL, recPerPage) {
const { sessionName, sessionID } = app.fs.session;
const executionRes = await request
.get(baseURL)
.set('Cookie', `${sessionName}=${sessionID}; pagerExecutionAll=${recPerPage || 10}`);
const executionText = JSON.parse(executionRes.text);
const executionData = JSON.parse(executionText.data);
let executionAll = executionData.executionStats;
const pg = executionData.pager;
let pid = pg.pageID;
while (pid < pg.pageTotal) {
const res = await request
.get(baseURL.replace('.json', `-${pg.recTotal}-${pg.recPerPage}-${pid + 1}.json`))
.set('Cookie', `${sessionName}=${sessionID}`);
const resText = JSON.parse(res.text);
const resData = JSON.parse(resText.data);
executionAll = executionAll.concat(resData.executionStats);
pid++;
}
const currentMonth = moment().format('YYYY-MM');
const executionStats = executionAll.filter((item) => item.type === 'sprint' && (
moment(item.begin).format('YYYY-MM') === currentMonth
|| moment(item.end).format('YYYY-MM') === currentMonth
));
return executionStats;
}
async function getOngoingProjects(ctx, next) {
try {
const { sessionName, sessionID } = app.fs.session;
const executions = [];
const currentMonth = moment().format('YYYY-MM');
// 执行(未开始)
const waitExecutionBaseURL = 'https://pms.anxinyun.cn/execution-all-wait-0-order_asc-0.json';
const waitExecutionStats = await getExecutionStats(waitExecutionBaseURL, 200);
for (const item of waitExecutionStats) {
const { id, name, end } = item;
const { executionTeamRDs, executionProducts } = await getExecutionDetail(id);
if (executionProducts.some((p) => productExcluded.includes(p))) continue;
executions.push({
execution_id: id,
name_project: name,
build_time: extractBuildTime(name),
publish_time: end,
part_people: executionTeamRDs,
progress: '需求评审中',
});
}
// 执行(进行中)
const doingExecutionBaseURL = 'https://pms.anxinyun.cn/execution-all-doing-0-order_asc-0.json';
const doingExecutionStats = await getExecutionStats(doingExecutionBaseURL, 200);
for (const item of doingExecutionStats) {
const { id, name, end } = item;
const { executionTeamRDs, executionProducts } = await getExecutionDetail(id);
if (executionProducts.some((p) => productExcluded.includes(p))) continue;
const executionProgress = await getExecutionProgress(id);
executions.push({
execution_id: id,
name_project: name.replace('&amp;', '&'),
build_time: extractBuildTime(name),
publish_time: end,
part_people: executionTeamRDs,
progress: executionProgress,
});
}
ctx.status = 200;
ctx.body = {
total: executions.length,
projects: executions,
};
} catch (e) {
ctx.status = 400;
ctx.body = {
name: 'FindError',
message: `版本计划获取失败${e}`,
};
}
}
async function getOngoingPersons(ctx, next) {
try {
const { sessionName, sessionID } = app.fs.session;
const executions = [];
const currentDate = moment();
// 获取当前周的第一天(周一)
const firstDayOfWeek = currentDate.clone().startOf('isoWeek');
// 获取当前周的最后一天(周日)
const lastDayOfWeek = currentDate.clone().endOf('isoWeek');
// 执行(未开始)
const waitExecutionRes = await request
.get('https://pms.anxinyun.cn/execution-all-wait-0-order_asc-0.json')
.set('Cookie', `${sessionName}=${sessionID}`);
const waitExecutionText = JSON.parse(waitExecutionRes.text);
const waitExecutionStats = JSON.parse(waitExecutionText.data).executionStats
.filter((item) => item.type === 'sprint' && (
moment(item.begin).isBetween(firstDayOfWeek, lastDayOfWeek, undefined, '[]')
|| moment(item.end).isBetween(firstDayOfWeek, lastDayOfWeek, undefined, '[]')
));
for (const item of waitExecutionStats) {
const {
id, name, begin, end,
} = item;
const { executionTeamRDs, executionProducts } = await getExecutionDetail(id);
if (executionProducts.some((p) => productExcluded.includes(p))) continue;
executions.push({
name_project: name,
begin,
build_time: extractBuildTime(name),
end,
part_people: executionTeamRDs,
});
}
const memberExecutions = executions.reduce((p, c) => {
const { part_people, ...rest } = c;
part_people.forEach((member) => {
if (p[member.name_people]) {
p[member.name_people].push(rest);
} else {
p[member.name_people] = [rest];
}
});
return p;
}, {});
ctx.status = 200;
ctx.body = {
total: Object.keys(memberExecutions).length,
projects: memberExecutions,
};
} catch (e) {
ctx.status = 400;
ctx.body = {
name: 'FindError',
message: `人员计划获取失败${e}`,
};
}
}
router.get('/ongoing/projects', getOngoingProjects);
router.get('/ongoing/persons', getOngoingPersons);
},
};
Loading…
Cancel
Save