'use strict'; const { QueryTypes } = require('sequelize'); const moment = require('moment'); const xlsxDownload = require('../../../../utils/xlsxDownload.js'); const fs = require('fs'); const data = require('../../routes/data/index.js'); async function reportList (ctx) { try { const models = ctx.fs.dc.models; const { limit, page, startTime, endTime, keyword, userId, reportType, isTop, asc, projectType, handleState = '', performerId = '', codeRoad } = ctx.query const { userInfo } = ctx.fs.api const sequelize = ctx.fs.dc.orm; let findUsers = [] if ( userInfo.loginSource == 'wx' && userInfo.isAdmin && userInfo.phone != 'SuperAdmin' && (!performerId && !handleState) ) { // 是管理员但不是超管 查自己部门及下级部门的所有用户的信息 const sqlStr = ` WITH RECURSIVE sub_departments AS ( SELECT id, dependence FROM department WHERE id = ${userInfo.departmentId} UNION ALL SELECT d.id, d.dependence FROM sub_departments sd JOIN department d ON sd.id = d.dependence ) SELECT u.id FROM "user" AS u JOIN sub_departments sd ON u.department_id = sd.id WHERE u.delete = false; ` const res = await sequelize.query(sqlStr, { type: QueryTypes.SELECT }) findUsers = res.map(item => { return item.id }) findUsers.push(-1) } let findOption = { where: { }, attributes: ['id', 'road', 'time', 'projectType', 'roadSectionStart', 'performerId', 'roadSectionEnd', 'reportType', 'address', 'content', 'longitude', 'latitude', 'projectName', 'handleState', 'codeRoad', 'handleContent', 'handlePic', 'videoUrl', 'scenePic'], include: [{ model: models.User, attributes: ['name'] }], //order: [['time', asc ? 'ASC' : 'DESC']], order: [['time', 'DESC']], } if (limit) { findOption.limit = limit } if (page && limit) { findOption.offset = page * limit } if (startTime && endTime) { findOption.where = { time: { '$between': [startTime, endTime] } } } if (keyword) { if (reportType == 'road') { findOption.where.projectName = { '$like': `%${keyword}%` } } else { findOption.where.road = { '$like': `%${keyword}%` } } } if (userId) { findOption.where.userId = { $in: userId.split(',').map(Number) } } if (findUsers.length) { findOption.where.userId = { $in: findUsers } } if (reportType) { findOption.where.reportType = reportType } if (projectType) { findOption.where.projectType = projectType } if (performerId) { let performerIds = performerId.split(',') findOption.where.performerId = { $in: performerIds } } if (handleState) { let handleStates = handleState.split(',') findOption.where.handleState = { $in: handleStates } } if (codeRoad) { findOption.where.codeRoad = codeRoad } let reportRes = null; if (isTop) { const sqlStr = ` select NR.*, "user".name as user_name from (SELECT R.*, "row_number"() OVER (PARTITION BY R.user_id ORDER BY R."time" DESC) AS NEWINDEX FROM report AS R ${reportType ? ` where report_type = '${reportType}' `: '' } ) AS NR left join "user" on "user".id = NR.user_id WHERE NEWINDEX = 1 order by id desc; ` reportRes = await sequelize.query(sqlStr, { type: QueryTypes.SELECT }); if (reportType == 'road') { const projectNameArr = reportRes.map(item => item.project_name).filter(item => item) const projectRes = projectNameArr.length ? await models.Project.findAll({ where: { entryName: { $in: projectNameArr } } }) : [] for (let r of reportRes) { let corProject = projectRes.find(item => item.entryName == r.project_name) if (corProject) { r.project = corProject.dataValues } } } } else { reportRes = await models.Report.findAll(findOption) } ctx.status = 200; ctx.body = reportRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function reportPosition (ctx) { try { const models = ctx.fs.dc.models; const { startTime, endTime, userId, reportType } = ctx.query const sequelize = ctx.fs.dc.ORM; let findMxTimeOption = { attributes: [ 'userId', [sequelize.fn('MAX', sequelize.col('time')), 'maxTime'], ], where: { }, group: ['report.user_id'], } if (startTime && endTime) { findMxTimeOption.where = { time: { '$between': [startTime, endTime] } } } if (userId) { findMxTimeOption.where.userId = userId } if (reportType) { findMxTimeOption.where.reportType = reportType } const reportMaxTimeRes = await models.Report.findAll(findMxTimeOption) const timeArr = reportMaxTimeRes.map(item => item.dataValues.maxTime) const reportRes = await models.Report.findAll({ where: { time: { '$in': timeArr } } }) ctx.status = 200; ctx.body = reportRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function reportDetail (ctx) { try { const models = ctx.fs.dc.models; const { reportId } = ctx.params const reportRes = await models.Report.findOne({ where: { id: reportId }, include: [{ model: models.Road, // where: { // del: false // }, as: 'road_', }], }) ctx.status = 200; ctx.body = reportRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function reportHandle (ctx) { try { const { models } = ctx.fs.dc; const { reportId } = ctx.params const { handleState } = ctx.request.body const data = ctx.request.body /** * data = { * handleState, * handleContent, * handlePic * } */ await models.Report.update(data, { where: { id: reportId } }) ctx.status = 200; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function createReport (ctx) { try { const { userId } = ctx.fs.api const models = ctx.fs.dc.models; const data = ctx.request.body; await models.Report.create({ ...data, userId, time: new Date(), }) ctx.status = 204 } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function deleteReport (ctx) { try { const models = ctx.fs.dc.models; const { reportId } = ctx.params; await models.Report.destroy({ where: { id: reportId } }) ctx.status = 204 } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } // TODO 小程序填写道路名称的时候的道路筛选 是一起都返回 还是不断传关键字搜索返回 async function spotPrepare (ctx) { try { const { models } = ctx.fs.dc; const sequelize = ctx.fs.dc.orm; const { percentage } = ctx.request.body; const departmentIdRes = await models.Department.findAll({ attributes: ['id', 'name'], where: { dependence: null, delete: false, } }) let lukyDepartment = '' if (departmentIdRes.length) { lukyDepartment = departmentIdRes[(Math.round(Math.random() * departmentIdRes.length) || 1) - 1] } else { throw `暂无乡镇信息` } const sqlStr = ` WITH RECURSIVE sub_departments AS ( SELECT id, dependence FROM department WHERE id = ${lukyDepartment.id} UNION ALL SELECT d.id, d.dependence FROM sub_departments sd JOIN department d ON sd.id = d.dependence ) SELECT u.id FROM "user" AS u JOIN sub_departments sd ON u.department_id = sd.id WHERE u.delete = false; ` const userRes = await sequelize.query(sqlStr, { type: QueryTypes.SELECT }) let findUsers = [] findUsers = userRes.map(item => { return item.id }) const reportCount = findUsers.length ? await models.Report.count({ where: { reportType: 'conserve', userId: { $in: findUsers } } }) : 0 const previewRes = await models.ReportSpotCheckPreview.create({ percentage: percentage, departmentId: lukyDepartment.id, date: moment().format(), reportCount: reportCount, checked: false, }) ctx.status = 200; ctx.body = { lukyDepartment, reportCount, previewId: previewRes.id } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function spotCheck (ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const { models } = ctx.fs.dc; const sequelize = ctx.fs.dc.orm; const { previewId } = ctx.query if (!previewId) { throw '参数错误' } const prepareRes = await models.ReportSpotCheckPreview.findOne({ where: { id: previewId } }) const sqlStr = ` WITH RECURSIVE sub_departments AS ( SELECT id, dependence FROM department WHERE id = ${prepareRes.departmentId} UNION ALL SELECT d.id, d.dependence FROM sub_departments sd JOIN department d ON sd.id = d.dependence ) SELECT u.id FROM "user" AS u JOIN sub_departments sd ON u.department_id = sd.id WHERE u.delete = false; ` const userRes = await sequelize.query(sqlStr, { type: QueryTypes.SELECT }) let findUsers = [] findUsers = userRes.map(item => { return item.id }) let checkCount = Math.ceil(prepareRes.reportCount * (prepareRes.percentage / 100)) const reportRes = await findUsers.length && checkCount ? await models.Report.findAll({ where: { reportType: 'conserve', userId: { $in: findUsers }, }, include: [{ model: models.User, attributes: ['name'] }], order: sequelize.random(), // 随机排序 limit: checkCount, // 限制返回的记录数 }) : [] await models.ReportSpotCheckPreview.update({ checked: true }, { where: { id: previewId } }) if (reportRes.length) { let spotDate = moment().format('YYYY-MM-DD') await models.ReportSpotCheck.bulkCreate(reportRes.map(r => { return { reportId: r.id, spotDate: spotDate, prepareId: previewId } })) } const rslt = findUsers.length && checkCount ? await models.ReportSpotCheckPreview.findAll({ where: { checked: 'true', id: previewId }, include: [{ model: models.Department, attributes: ['name'] }, { model: models.ReportSpotCheck, include: [{ model: models.Report, include: [{ model: models.User, attributes: ['name'] }], }] } ], }) : [] await transaction.commit(); ctx.status = 200; ctx.body = rslt } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function spotCheckDetail (ctx) { const { models } = ctx.fs.dc const { startTime, endTime } = ctx.query try { const res = await models.ReportSpotCheckPreview.findAll({ where: { checked: 'true' }, order: [['date', 'DESC']], include: [{ model: models.Department, attributes: ['name'] }, { model: models.ReportSpotCheck, where: { spotDate: { $between: [moment(startTime).format('YYYY-MM-DD'), moment(endTime).format('YYYY-MM-DD')] } }, order: [['spot_date', 'DESC']], include: [{ model: models.Report, order: [['date', 'DESC']], include: [{ model: models.User, attributes: ['name'] }], }] } ], }) ctx.body = res ctx.status = 200 } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) ctx.status = 400 ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function roadSpotPrepare (ctx) { try { const { models } = ctx.fs.dc; const sequelize = ctx.fs.dc.orm; const { countyPercentage } = ctx.request.body; const lastSpotRes = await models.RoadSpotCheckPreview.findOne({ where: { checked: true }, // attributes: ['id', 'countyPercentage', 'date',], order: [['date', 'DESC']], // include: [{ // model: models.RoadSpotCheck, // include: [{ // model: models.Road, // // attributes: ['id', 'name'] // }] // }] }) let lastCountyPercentage = 0 // 最后一次的县道百分比 let lastCountyRoadIds = [] // 上次查得的县道id let lastTownRoadIds = [] // 上次查得的乡镇道id let lastVillageRoadRoadIds = [] // 上次查得的村道id let lastVillageIds = [] let gather = [] //汇总 if (lastSpotRes) { lastCountyPercentage = lastSpotRes.countyPercentage lastCountyRoadIds = lastSpotRes.countyRoadId || [] let lastCounty = await models.RoadSpotCheckPreview.findAll({ where: { checked: true, id: { $lte: lastSpotRes.id } }, limit: 3, order: [['date', 'DESC']], }) if (lastCounty) { lastCounty.forEach(d => { lastTownRoadIds = lastTownRoadIds.concat(d.townshipRoadId) || [] }) } let lastVillage = await models.RoadSpotCheckPreview.findAll({ where: { checked: true, id: { $lte: lastSpotRes.id } }, limit: 9, order: [['date', 'DESC']], }) if (lastVillage) { lastVillage.forEach(d => { lastVillageRoadRoadIds = lastVillageRoadRoadIds.concat(d.villageRoadId) || [] lastVillageIds = lastVillageIds.concat(d.villageId) || [] }) } // lastTownRoadIds = lastSpotRes.townshipRoadId || [] // lastVillageRoadRoadIds = lastSpotRes.villageRoadId || [] // lastVillageIds = lastSpotRes.villageId || [] } // 先查上次没查的范围内的 然后比较百分比 如果重叠 再查上次查过的 let keyMap = { '县': `route_code LIKE 'X%'`, '乡': `route_code LIKE 'Y%'`, '村': `route_code LIKE 'C%'` } async function getRoadTotalMileage (key, otherWhere = [], spot) { let res = await sequelize.query(` SELECT SUM(COALESCE(CAST(chainage_mileage AS DOUBLE PRECISION), 0)) AS total_mileage FROM road WHERE del = false AND spot = ${spot} AND ${keyMap[key]} ${otherWhere.length ? `AND ${otherWhere.join(' AND ')}` : ''} `) return res[0][0].total_mileage || 0 } async function getRoadSpot (key, lastRoadIds = [], inOrNot, otherWhere = []) { if (!lastRoadIds.length && !inOrNot) { return [] } return await sequelize.query(` SELECT id, chainage_mileage FROM road WHERE del = false AND spot = true AND ${keyMap[key]} ${lastRoadIds.length ? `AND id ${inOrNot ? 'IN' : 'NOT IN'} ( ${lastRoadIds.map(item => `'${item}'`).join(',')},-1 )` : '' } AND chainage_mileage IS NOT NULL ${otherWhere.length ? `AND ${otherWhere.join(' AND ')}` : ''} ORDER BY RANDOM() `, { type: QueryTypes.SELECT }); } async function spotRoadId (key, lastRoadIds, targetMileage, otherWhere = [], villageIdList = []) { let spotRoadIds = [] let accumulationMileage = 0 async function filterRoad (otherWhere, getRepeat = true) { if (key == '村' && getRepeat == true) { } else { let roadUnSpotedRes = await getRoadSpot(key, lastRoadIds, false, otherWhere) for (let r of roadUnSpotedRes) { spotRoadIds.push(r.id) accumulationMileage += parseFloat(r.chainage_mileage) if (accumulationMileage >= targetMileage) { break; } } } if (accumulationMileage < targetMileage && getRepeat) { // 还小于 说明没取够 let roadUnSpotedRepeatRes = await getRoadSpot( key, lastRoadIds, true, otherWhere ) for (let r of roadUnSpotedRepeatRes) { spotRoadIds.push(r.id) accumulationMileage += parseFloat(r.chainage_mileage) if (accumulationMileage >= targetMileage) { break; } } } } if (key == '村') { for await (let villageId of villageIdList) { await filterRoad([ ...otherWhere, `village_id=${villageId}` ], false) spotVillageIds.push(villageId) if (accumulationMileage >= targetMileage) { break; } } if (accumulationMileage < targetMileage) { // 还小于 说明没取够 await filterRoad(otherWhere, true) } } else { await filterRoad(otherWhere, true) } return [spotRoadIds, accumulationMileage] } let villageMil = 0, townMil = 0, countryMil = 0; // 抽县 const countryRoadTotalMileage = await getRoadTotalMileage('县', '', true) const countryRoadHide = await getRoadTotalMileage('县', '', false) const countryRoadNeedMileage = countryRoadTotalMileage * countyPercentage / 100 let spotCountyRoadIdsArr = await spotRoadId('县', lastCountyRoadIds, countryRoadNeedMileage, []) let spotCountyRoadIds = spotCountyRoadIdsArr[0] let countryMil_ = spotCountyRoadIdsArr[1] || 0 if (countryMil_) countryMil += countryMil_; gather.push({ name: '南昌县交通运输局', county: countryRoadTotalMileage + countryRoadHide, countyParticipate: countryRoadTotalMileage, countyPresent: countryMil_, countyDifferenceValue: countryMil_ - countryRoadNeedMileage }) let town = await models.Town.findAll() || [] // 抽乡 const allTownCodeRes = await sequelize.query(` SELECT DISTINCT township_code FROM road WHERE del = false AND spot = true AND township_code IS NOT NULL `, { type: QueryTypes.SELECT }); let spotTownRoadIds = [] let spotVillageRoadIds = [] let spotVillageIds = [] let allTownCodeResTown = [] for await (let t of allTownCodeRes) { // 遍历每个乡镇并抽取 let otherWhere = [`township_code='${t.township_code}'`] const townRoadTotalMileage = await getRoadTotalMileage('乡', otherWhere, true) const townRoadHide = await getRoadTotalMileage('乡', otherWhere, false) const townRoadNeedMileage = townRoadTotalMileage * (countyPercentage == 75 ? 50 : 25) / 100 let spotTownRoadIdsArr = await spotRoadId('乡', lastTownRoadIds, townRoadNeedMileage, otherWhere) let spotTownRoadIds_ = spotTownRoadIdsArr[0] let townMil_ = spotTownRoadIdsArr[1] spotTownRoadIds = spotTownRoadIds.concat(spotTownRoadIds_) if (townMil_) townMil += townMil_ // 抽村 const villageRoadTotalMileage = await getRoadTotalMileage('村', otherWhere, true) const villageRoadTotalHide = await getRoadTotalMileage('村', otherWhere, false) const villageRoadNeedMileage = villageRoadTotalMileage * (countyPercentage == 75 ? 20 : 10) / 100 let spotFirstVillageId = -1 // 随机选取一个不在上次查过的村 let villageRes = await sequelize.query(` SELECT id FROM village WHERE township_code = '${t.township_code}' ${lastVillageIds.length ? `AND id NOT IN ( ${lastVillageIds.map(item => `'${item}'`).join(',')},-1 )`: ''} ORDER BY RANDOM() LIMIT 1 `, { type: QueryTypes.SELECT }); if (!villageRes.length) { // 没有村了,随机选一个 villageRes = await sequelize.query(` SELECT id FROM village WHERE township_code = '${t.township_code}' ORDER BY RANDOM() LIMIT 1 `, { type: QueryTypes.SELECT }); } if (villageRes.length) { spotVillageIds.push(villageRes[0].id) spotFirstVillageId = villageRes[0].id } else { allTownCodeResTown.push({ code: t.township_code, township: townRoadTotalMileage + townRoadHide, townshipParticipate: townRoadTotalMileage, townshipPresent: townMil_, townshipDifferenceValue: townMil_ - townRoadNeedMileage, village: villageRoadTotalMileage + villageRoadTotalHide, villageParticipate: villageRoadTotalMileage, villagePresent: 0, villageDifferenceValue: 0 }) continue; } const villageNearRes = await sequelize.query(` SELECT id,calc_village,distance FROM village_distance WHERE origin_village = ${spotFirstVillageId} ORDER BY distance ASC `, { type: QueryTypes.SELECT }) let villageCheckIdList = villageNearRes.map(item => item.calc_village) villageCheckIdList.unshift(spotFirstVillageId) villageCheckIdList = [...(new Set(villageCheckIdList))] let spotVillageRoadIdsArr = await spotRoadId('村', lastVillageRoadRoadIds, villageRoadNeedMileage, otherWhere, villageCheckIdList) let spotVillageRoadIds_ = spotVillageRoadIdsArr[0] let villageMil_ = spotVillageRoadIdsArr[1] spotVillageRoadIds = spotVillageRoadIds.concat(spotVillageRoadIds_) if (villageMil_) villageMil += villageMil_ allTownCodeResTown.push({ code: t.township_code, township: townRoadTotalMileage + townRoadHide, townshipParticipate: townRoadTotalMileage, townshipPresent: townMil_, townshipDifferenceValue: townMil_ - townRoadNeedMileage, village: villageRoadTotalMileage + villageRoadTotalHide, villageParticipate: villageRoadTotalMileage, villagePresent: villageMil_, villageDifferenceValue: villageMil_ - villageRoadNeedMileage }) } for (let index = 0; index < town.length; index++) { let d = town[index] if (allTownCodeResTown.find(c => c.code == d.code)) { gather.push({ ...(allTownCodeResTown.find(c => c.code == d.code) || {}), name: d.name }) } else { let where = [`township_code='${d.code}'`] let township = await getRoadTotalMileage('乡', where, false) let village = await getRoadTotalMileage('村', where, false) gather.push({ name: d.name, code: d.code, township: township, townshipParticipate: 0, townshipPresent: 0, townshipDifferenceValue: 0, village: village, villageParticipate: 0, villagePresent: 0, villageDifferenceValue: 0 }) } } const previewRes = await models.RoadSpotCheckPreview.create({ countyPercentage: countyPercentage, date: moment().format(), countyRoadId: spotCountyRoadIds, townshipRoadId: spotTownRoadIds, villageRoadId: spotVillageRoadIds, villageId: spotVillageIds, checked: false, villageMil, townMil, countryMil, gather }) ctx.status = 200; ctx.body = { previewId: previewRes.id, spotCountyRoadCount: spotCountyRoadIds.length, spotTownRoadCount: spotTownRoadIds.length, spotVillageRoadCount: spotVillageRoadIds.length, villageMil, townMil, countryMil } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function confirmRoadSpot (ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const { models } = ctx.fs.dc; const sequelize = ctx.fs.dc.orm; const { previewId } = ctx.request.body const prepareRes = await models.RoadSpotCheckPreview.findOne({ where: { id: previewId } }) let spotedRoadIds = [] spotedRoadIds = spotedRoadIds.concat(prepareRes.dataValues.countyRoadId) spotedRoadIds = spotedRoadIds.concat(prepareRes.dataValues.townshipRoadId) spotedRoadIds = spotedRoadIds.concat(prepareRes.dataValues.villageRoadId) const conserveCountRes = await sequelize.query(` SELECT road_id, COUNT(road_id) as count FROM report WHERE road_id IN ( ${spotedRoadIds.map(item => item).join(',')} ) AND report_type = 'conserve' GROUP BY road_id `, { type: QueryTypes.SELECT }) let spotRslt = [] for await (let item of spotedRoadIds) { let corConserveCount = conserveCountRes.find(cc => cc.road_id == item) spotRslt.push({ roadId: item, maintenanceCount: corConserveCount ? corConserveCount.count : 0, prepareId: previewId }) } await models.RoadSpotCheck.bulkCreate(spotRslt, { transaction }) await models.RoadSpotCheckPreview.update({ checked: true }, { where: { id: previewId }, transaction }) await transaction.commit(); ctx.status = 204; } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function roadSpotList (ctx) { try { const { models } = ctx.fs.dc; const { startTime, endTime, page, limit } = ctx.query let findOpt = { order: [['id', 'DESC']], where: { checked: true } } if (startTime && endTime) { findOpt.where.date = { $between: [moment(startTime).startOf('day').format(), moment(endTime).endOf('day').format()] } } if (page && limit) { findOpt.offset = (page - 1) * limit findOpt.limit = limit } const listRes = await models.RoadSpotCheckPreview.findAll(findOpt) ctx.status = 200; ctx.body = listRes.map(item => { return { id: item.id, date: item.date, countyPercentage: item.countyPercentage, spotCountyRoadCount: item.countyRoadId ? item.countyRoadId.length : 0, spotTownRoadCount: item.townshipRoadId ? item.townshipRoadId.length : 0, spotVillageRoadCount: item.villageRoadId ? item.villageRoadId.length : 0, countyRoadId: item.countyRoadId, townshipRoadId: item.townshipRoadId, villageRoadId: item.villageRoadId, villageMil: item.villageMil, townMil: item.townMil, countryMil: item.countryMil } }) } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function roadSpotDetail (ctx) { try { const { models } = ctx.fs.dc; const { previewId, keyword } = ctx.query const listRes = await models.RoadSpotCheck.findAll({ where: { prepareId: previewId, }, include: [{ model: models.Road, where: { ...(keyword ? { routeName: { $ilike: `%${keyword}%` } } : {}), del: false, }, }, { model: models.RoadSpotCheckPreview, attributes: ['id'], include: [{ model: models.RoadSpotCheckChangeLog, attributes: ['id', 'changeRoadId'], }] }] }) ctx.status = 200; ctx.body = listRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function roadSpotChange (ctx) { const transaction = await ctx.fs.dc.orm.transaction(); try { const { models } = ctx.fs.dc; const sequelize = ctx.fs.dc.orm; const { originRoadId, changeRoadId, previewId } = ctx.request.body if (originRoadId == changeRoadId) { throw '原路段与目标路段不能相同' } const previewRes = await models.RoadSpotCheckPreview.findOne({ where: { id: previewId } }) if (!previewRes) { throw '预览数据不存在' } let previewUpdated = false async function updatePreview (key) { if (previewUpdated) return if (previewRes[key] && previewRes[key].includes(originRoadId)) { let originRoadIds = previewRes.dataValues[key] let originRoadIdIndex = originRoadIds.indexOf(originRoadId) originRoadIds.splice(originRoadIdIndex, 1, changeRoadId) await models.RoadSpotCheckPreview.update({ [key]: originRoadIds }, { where: { id: previewId }, transaction }) previewUpdated = true } } await updatePreview('countyRoadId') await updatePreview('townshipRoadId') await updatePreview('villageRoadId') if (!previewUpdated) { throw '更改路段不在抽查范围内' } const roadRes = await models.Road.findAll({ where: { id: { $in: [originRoadId, changeRoadId] }, del: false, } }) if (roadRes.length != 2) { throw '路段不存在' } let content = '' let curOriginRoad = roadRes.find(item => item.id == originRoadId) let curChangeRoad = roadRes.find(item => item.id == changeRoadId) const level = curChangeRoad.level; let milData = {} let differenceValue = (parseFloat(curChangeRoad.chainageMileage) - parseFloat(curOriginRoad.chainageMileage)) || 0 if (level == '县') { previewRes.gather && previewRes.gather.forEach(d => { if (!d.code) { d.countyPresent = d.countyPresent + differenceValue d.countyDifferenceValue = d.countyDifferenceValue + differenceValue } }) milData = { countryMil: previewRes.countryMil + differenceValue, gather: previewRes.gather } } else if (level == '乡') { previewRes.gather && previewRes.gather.forEach(d => { if (d.code == curOriginRoad.townshipCode) { d.townshipPresent = d.townshipPresent - parseFloat(curOriginRoad.chainageMileage) d.townshipDifferenceValue = d.townshipDifferenceValue - parseFloat(curOriginRoad.chainageMileage) } if (d.code == curOriginRoad.curChangeRoad) { d.villagePresent = d.villagePresent + parseFloat(curChangeRoad.chainageMileage) d.townshipDifferenceValue = d.townshipDifferenceValue + parseFloat(curChangeRoad.chainageMileage) } }) || [] milData = { townMil: previewRes.townMil + differenceValue, gather: previewRes.gather } } else if (level == '村') { previewRes.gather && previewRes.gather.forEach(d => { if (d.code == curOriginRoad.townshipCode) { d.villageParticipate = d.villageParticipate - parseFloat(curOriginRoad.chainageMileage) d.villageDifferenceValue = d.villageDifferenceValue - parseFloat(curOriginRoad.chainageMileage) } if (d.code == curOriginRoad.curChangeRoad) { d.villageParticipate = d.villageParticipate + parseFloat(curChangeRoad.chainageMileage) d.villageDifferenceValue = d.villageDifferenceValue + parseFloat(curChangeRoad.chainageMileage) } }) || [] milData = { villageMil: previewRes.villageMil + differenceValue, gather: previewRes.gather } } await models.RoadSpotCheckPreview.update({ ...milData }, { where: { id: previewId }, transaction }) content = `将${curOriginRoad.routeName}从${curOriginRoad.startingPlaceName}到${curOriginRoad.stopPlaceName}改为${curChangeRoad.routeName}从${curChangeRoad.startingPlaceName}到${curChangeRoad.stopPlaceName}` const maintenanceCount = await sequelize.query(` SELECT COUNT(id) as count FROM report WHERE report_type = 'conserve' AND road_id=${changeRoadId} `, { type: QueryTypes.SELECT }) await models.RoadSpotCheck.update({ roadId: changeRoadId, maintenanceCount: maintenanceCount[0].count }, { where: { roadId: originRoadId, prepareId: previewId }, transaction }) await models.RoadSpotCheckChangeLog.create({ userId: ctx.fs.api.userId, time: moment().format(), originRoadId: originRoadId, changeRoadId: changeRoadId, content: content, prepareId: previewId }, { transaction }) await transaction.commit(); ctx.status = 204; } catch (error) { await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function roadSpotChangList (ctx) { try { const { models } = ctx.fs.dc; const { startTime, endTime, page, limit } = ctx.query let findOptPreview = { where: { checked: true, }, attributes: ['id', 'date'] } if (startTime && endTime) { findOptPreview.where = { date: { $between: [moment(startTime).startOf('day').format(), moment(endTime).endOf('day').format()] } } } let findOpt = { order: [['id', 'DESC']], where: { }, include: [{ model: models.RoadSpotCheckPreview, ...findOptPreview, required: true, }, { model: models.User, attributes: ['name'] }] } if (page && limit) { findOpt.offset = (page - 1) * limit findOpt.limit = limit } const listRes = await models.RoadSpotCheckChangeLog.findAll(findOpt) ctx.status = 200; ctx.body = listRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } async function exportSpotRode (ctx) { try { const { models } = ctx.fs.dc; const { previewId } = ctx.query const previewRes = await models.RoadSpotCheckPreview.findOne({ where: { id: previewId } }) const listRes = await models.RoadSpotCheck.findAll({ where: { prepareId: previewId }, include: [{ model: models.Road, // required: false, where: { del: false, } }] }) let town = await models.Town.findAll({}) || [] let village = await models.Village.findAll({ attributes: ['id', 'name'] }) || [] const header = [{ key: 'townshipCode', title: '所属乡镇', }, { key: 'villageId', title: '所属行政村', }, { key: 'routeName', title: '道路名称', }, { key: 'routeCode', title: '道路代码', }, { key: 'startStation', title: '起点桩号', }, { key: 'stopStation', title: '止点桩号', }, { key: 'technicalLevel', title: '技术等级', }, { key: 'pavementType', title: '路面类型', }, { key: 'pavementWidth', title: '路面宽度', }, { key: 'subgradeWidth', title: '路基宽度', }, { key: 'chainageMileage', title: '桩号里程', }, { key: 'maintenanceCount', title: '养护次数(次)', },] // function judgeLevel (routeCode) { // if (routeCode) { // if (routeCode.startsWith('X')) { // return '县道' // } else if (routeCode.startsWith('Y')) { // return '乡道' // } else if (routeCode.startsWith('C')) { // return '村道' // } // return '' // } else { // return '' // } // } let exportData = listRes.map(({ dataValues: item }) => { let road = item.road && item.road.dataValues || {} return { townshipCode: (town.find(d => d.code == road.townshipCode) || {}).name || '--', villageId: (village.find(d => road.villageId == d.id) || {}).name || '--', routeName: road.routeName, routeCode: road.routeCode, startStation: road.startStation || 0, stopStation: road.stopStation || 0, technicalLevel: road.technicalLevel, pavementType: road.pavementType, pavementWidth: road.pavementWidth || 0, subgradeWidth: road.subgradeWidth || 0, chainageMileage: road.chainageMileage || 0, maintenanceCount: item.maintenanceCount, } }) const fileName = `${moment(previewRes.date).format('YYYY年MM月DD日HH时mm分')}道路抽查记录` + '.csv' const filePath = await xlsxDownload.simpleExcelDown({ // data: exportData, header, fileName: fileName data: exportData, header, fileName: fileName, gather: { data: previewRes.gather || [] } }) const fileData = fs.readFileSync(filePath); ctx.status = 200; ctx.set('Content-Type', 'application/x-xls'); ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName)); ctx.body = fileData } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { message: typeof error == 'string' ? error : undefined } } } module.exports = { reportList, reportPosition, reportDetail, createReport, deleteReport, reportHandle, spotPrepare, spotCheck, spotCheckDetail, roadSpotPrepare, confirmRoadSpot, roadSpotList, roadSpotDetail, roadSpotChange, roadSpotChangList, exportSpotRode };