const request = require('superagent'); const moment = require('moment'); const productExcluded = require('../product-excluded'); const Holiday = require('../holiday'); 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 isWorkday(date) { let workday = false; const dateString = moment(date).format('YYYY-MM-DD'); const dateInHoliday = Holiday.days.filter((d) => d.date === dateString); if (dateInHoliday.length) { if (!dateInHoliday[0].isOffDay) workday = true; // 补班 } else { const day = moment(date).day(); if (day !== 0 && day !== 6) { // 工作日 workday = true; } } return workday; } function extractBuildTime(inputString) { const pattern = /[(\(]构建时间:(.*?)[\))]/; const match = inputString.match(pattern); const buildDate = match ? moment(new Date(match[1])).format('YYYY-MM-DD HH:mm') : 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(period, 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++; } let executionStats = []; if (period === 'month') { const currentMonth = moment().format('YYYY-MM'); executionStats = executionAll.filter((item) => item.type === 'sprint' && ( moment(item.begin).format('YYYY-MM') === currentMonth || moment(item.end).format('YYYY-MM') === currentMonth )); } else { // week const currentDate = moment(); // 获取当前周的第一天(周一) const firstDayOfWeek = currentDate.clone().startOf('isoWeek'); // 获取当前周的最后一天(周日) const lastDayOfWeek = currentDate.clone().endOf('isoWeek'); executionStats = executionAll.filter((item) => { const buildTime = extractBuildTime(item.name) || item.end; const begin = moment.max(moment(item.begin), moment(firstDayOfWeek)); const end = moment.min(moment(buildTime), moment(lastDayOfWeek)); return item.type === 'sprint' && begin.isSameOrBefore(end); }); } return executionStats; } async function getOngoingProjects(ctx, next) { try { const executions = []; // 执行(未开始) const waitExecutionBaseURL = 'https://pms.anxinyun.cn/execution-all-wait-0-order_asc-0.json'; const waitExecutionStats = await getExecutionStats('month', 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('month', 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 currentDate = moment(); // 获取当前周的第一天(周一) const firstDayOfWeek = currentDate.clone().startOf('isoWeek'); // 获取当前周的最后一天(周日) const lastDayOfWeek = currentDate.clone().endOf('isoWeek'); // 执行(未开始) const waitExecutionBaseURL = 'https://pms.anxinyun.cn/execution-all-wait-0-order_asc-0.json'; const waitExecutionStats = await getExecutionStats('week', waitExecutionBaseURL, 200); // 执行(进行中) const doingExecutionBaseURL = 'https://pms.anxinyun.cn/execution-all-doing-0-order_asc-0.json'; const doingExecutionStats = await getExecutionStats('week', doingExecutionBaseURL, 200); const executionAll = waitExecutionStats.concat(doingExecutionStats); const executions = []; for (const item of executionAll) { 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.replace('&', '&'), begin, build_time: extractBuildTime(name) || end, 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; }, {}); const members = Object.entries(memberExecutions).map(([k, v]) => { const memberTasks = {}; v.forEach((item) => { const begin = moment.max(moment(item.begin), moment(firstDayOfWeek)); const end = moment.min(moment(item.build_time), moment(lastDayOfWeek)); const weekday = begin; while (weekday.isSameOrBefore(end)) { if (isWorkday(weekday)) { const weekdayEN = weekday.format('dddd').toLowerCase(); if (memberTasks[`${weekdayEN}`]) { memberTasks[`${weekdayEN}`] = `${memberTasks[`${weekdayEN}`]}、${item.name_project}`; } else { memberTasks[`${weekdayEN}`] = item.name_project; } } weekday.add(1, 'days'); } }); const initData = { name_people: k, post_people: '研发', monday: 'undefined', tuesday: 'undefined', wednesday: 'undefined', thursday: 'undefined', friday: 'undefined', saturday: 'undefined', sunday: 'undefined', }; return { ...initData, ...memberTasks }; }); ctx.status = 200; ctx.body = { total: members.length, projects: members, }; } catch (e) { ctx.status = 400; ctx.body = { name: 'FindError', message: `人员计划获取失败${e}`, }; } } router.get('/ongoing/projects', getOngoingProjects); router.get('/ongoing/persons', getOngoingPersons); }, };