Julin
1 year ago
5 changed files with 536 additions and 228 deletions
@ -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开发', |
|||
'上位机开发', |
|||
|
|||
// 测试部
|
|||
'测试部门', |
|||
|
|||
// 硬件研发部项目型任务
|
|||
'硬件研发部任务', |
|||
|
|||
// 软件共性技术研究
|
|||
'共性技术', |
|||
]; |
@ -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('&', '&'), |
|||
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…
Reference in new issue