@ -1,122 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
async function getPatrolPlan(ctx, next) { | 
				
			|||
    try { | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const { limit, page } = ctx.query; | 
				
			|||
        let options = { | 
				
			|||
            include: [{ | 
				
			|||
                required: true, | 
				
			|||
                model: models.User, | 
				
			|||
                attributes: ['id', 'name'], | 
				
			|||
                include: [{ | 
				
			|||
                    required: true, | 
				
			|||
                    model: models.Department, | 
				
			|||
                    attributes: ['id', 'name'], | 
				
			|||
                }] | 
				
			|||
            }, { | 
				
			|||
                required: true, | 
				
			|||
                model: models.Project, | 
				
			|||
                attributes: ['id', 'name'], | 
				
			|||
            }] | 
				
			|||
        }; | 
				
			|||
        if (limit) { | 
				
			|||
            options.limit = Number(limit); | 
				
			|||
        } | 
				
			|||
        if (page && limit) { | 
				
			|||
            options.offset = Number(page) * Number(limit); | 
				
			|||
        } | 
				
			|||
        let res = await models.PatrolPlan.findAndCountAll(options); | 
				
			|||
        ctx.status = 200; | 
				
			|||
        ctx.body = res; | 
				
			|||
    } catch (error) { | 
				
			|||
        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
        ctx.status = 400; | 
				
			|||
        ctx.body = { | 
				
			|||
            "message": "获取巡检计划失败" | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function createPatrolPlan(ctx, next) { | 
				
			|||
    try { | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const data = ctx.request.body; | 
				
			|||
        const { name, way, structureId, startTime, endTime, frequency, points, userId } = data; | 
				
			|||
 | 
				
			|||
        let plan = { name, way, structureId, startTime, endTime, frequency, points, userId }; | 
				
			|||
 | 
				
			|||
        await models.PatrolPlan.create(plan); | 
				
			|||
 | 
				
			|||
        ctx.status = 204; | 
				
			|||
    } catch (error) { | 
				
			|||
        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
        ctx.status = 400; | 
				
			|||
        ctx.body = { | 
				
			|||
            "message": '新增巡检计划失败' | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function updatePatrolPlan(ctx, next) { | 
				
			|||
    try { | 
				
			|||
        let errMsg = '修改巡检计划失败'; | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const data = ctx.request.body; | 
				
			|||
        const { name, way, structureId, startTime, endTime, frequency, points, userId } = data; | 
				
			|||
 | 
				
			|||
        let plan = { name, way, structureId, startTime, endTime, frequency, points, userId }; | 
				
			|||
 | 
				
			|||
        if (data && data.id) { | 
				
			|||
            await models.PatrolPlan.update(plan, { | 
				
			|||
                where: { id: data.id } | 
				
			|||
            }) | 
				
			|||
        } else { | 
				
			|||
            errMsg = '请传入巡检计划id'; | 
				
			|||
            throw errMsg; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        ctx.status = 204; | 
				
			|||
    } catch (error) { | 
				
			|||
        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
        ctx.status = 400; | 
				
			|||
        ctx.body = { | 
				
			|||
            "message": errMsg | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function delPatrolPlan(ctx, next) { | 
				
			|||
    try { | 
				
			|||
        let errMsg = '删除巡检计划失败'; | 
				
			|||
 | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const { id } = ctx.params; | 
				
			|||
 | 
				
			|||
        const record = await models.PatrolRecord.findOne({ | 
				
			|||
            where: { patrolPlanId: id } | 
				
			|||
        }); | 
				
			|||
 | 
				
			|||
        if (record) { | 
				
			|||
            errMsg = '不能删除有巡检记录的计划'; | 
				
			|||
            throw errMsg; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        await models.PatrolPlan.destroy({ | 
				
			|||
            where: { id } | 
				
			|||
        }) | 
				
			|||
 | 
				
			|||
        ctx.status = 204; | 
				
			|||
    } catch (error) { | 
				
			|||
        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
        ctx.status = 400; | 
				
			|||
        ctx.body = { message: error } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
module.exports = { | 
				
			|||
    getPatrolPlan, | 
				
			|||
    createPatrolPlan, | 
				
			|||
    updatePatrolPlan, | 
				
			|||
    delPatrolPlan, | 
				
			|||
} | 
				
			|||
@ -1,113 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
async function findPatrolRecord(ctx, next) { | 
				
			|||
    let rslt = []; | 
				
			|||
    let error = { name: 'FindError', message: '获取巡检记录失败' }; | 
				
			|||
    try { | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const { startTime, endTime, alarm, patrolPlanId, pointId } = ctx.params; | 
				
			|||
        // patrolPlanId传all查所有
 | 
				
			|||
        if (patrolPlanId == 'all') { | 
				
			|||
            /* 如果有startTime && endTime,查询所有符合条件的数据 */ | 
				
			|||
            if (startTime !== 'null' && endTime !== 'null') { | 
				
			|||
                if (pointId !== 'null') { | 
				
			|||
                    if (alarm == 'null') { | 
				
			|||
                        rslt = await models.PatrolRecord.findAll({ | 
				
			|||
                            where: { inspectionTime: { $between: [startTime, endTime] }, pointId: { $in: pointId.split(',') } }, | 
				
			|||
                        }); | 
				
			|||
                    } else { | 
				
			|||
                        rslt = await models.PatrolRecord.findAll({ | 
				
			|||
                            where: { alarm, inspectionTime: { $between: [startTime, endTime] }, pointId: { $in: pointId.split(',') } }, | 
				
			|||
                        }); | 
				
			|||
                    } | 
				
			|||
                } else { | 
				
			|||
                    if (alarm == 'null') { | 
				
			|||
                        rslt = await models.PatrolRecord.findAll({ | 
				
			|||
                            where: { inspectionTime: { $between: [startTime, endTime] } }, | 
				
			|||
                        }); | 
				
			|||
                    } else { | 
				
			|||
                        rslt = await models.PatrolRecord.findAll({ | 
				
			|||
                            where: { alarm, inspectionTime: { $between: [startTime, endTime] } }, | 
				
			|||
                        }); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
            } else { | 
				
			|||
                /* 如果没有startTime && endTime,查询每个点位最新一条符合条件的数据 */ | 
				
			|||
                let a = [] | 
				
			|||
                if (pointId !== 'null') { | 
				
			|||
                    a = await models.PatrolRecord.findAll({ | 
				
			|||
                        where: { pointId: { $in: pointId.split(',') } }, | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
                rslt = pointId.split(',').map(i => { | 
				
			|||
                    return a.filter(t => t.pointId == i).sort((a, b) => b.id - a.id)[0] || null | 
				
			|||
                }) | 
				
			|||
            } | 
				
			|||
        } else { | 
				
			|||
            if (startTime !== 'null' && endTime !== 'null') { | 
				
			|||
                if (pointId !== 'null') { | 
				
			|||
                    rslt = await models.PatrolRecord.findAll({ | 
				
			|||
                        where: { patrolPlanId: { $in: patrolPlanId.split(',') }, alarm, inspectionTime: { $between: [startTime, endTime] }, pointId: { $in: pointId.split(',') } }, | 
				
			|||
                    }); | 
				
			|||
                } else { | 
				
			|||
                    rslt = await models.PatrolRecord.findAll({ | 
				
			|||
                        where: { patrolPlanId: { $in: patrolPlanId.split(',') }, alarm, inspectionTime: { $between: [startTime, endTime] } }, | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
 | 
				
			|||
            } else { | 
				
			|||
                let a = [] | 
				
			|||
                /* 如果没有startTime && endTime,查询每个点位最新一条符合条件的数据 */ | 
				
			|||
                if (pointId !== 'null') { | 
				
			|||
                    a = await models.PatrolRecord.findAll({ | 
				
			|||
                        where: { patrolPlanId: { $in: patrolPlanId.split(',') }, pointId: { $in: pointId.split(',') } }, | 
				
			|||
                    }); | 
				
			|||
                } else { | 
				
			|||
                    a = await models.PatrolRecord.findAll({ | 
				
			|||
                        where: { patrolPlanId: { $in: patrolPlanId.split(',') } }, | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
 | 
				
			|||
                rslt = pointId.split(',').map(i => { | 
				
			|||
                    return a.filter(t => t.pointId == i).sort((a, b) => b.id - a.id)[0] || null | 
				
			|||
                }) | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        ctx.status = 200; | 
				
			|||
        ctx.body = rslt; | 
				
			|||
        error = null | 
				
			|||
    } catch (error) { | 
				
			|||
        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
        ctx.status = 400; | 
				
			|||
        ctx.body = { | 
				
			|||
            "message": "获取巡检记录失败" | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function addPatrolRecord(ctx, next) { | 
				
			|||
    let error = { name: 'addError', message: '新增巡检记录失败' }; | 
				
			|||
    try { | 
				
			|||
        const models = ctx.fs.dc.models; | 
				
			|||
        const data = ctx.request.body; | 
				
			|||
        let { patrolPlanId, lastInspectionTime, inspectionTime, points, alarm, pointId } = data | 
				
			|||
        let record = { patrolPlanId, lastInspectionTime, inspectionTime, points, alarm, pointId } | 
				
			|||
 | 
				
			|||
        await models.PatrolRecord.create(record); | 
				
			|||
 | 
				
			|||
        ctx.status = 204; | 
				
			|||
        error = null | 
				
			|||
    } catch (error) { | 
				
			|||
        ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
        ctx.status = 400; | 
				
			|||
        ctx.body = { | 
				
			|||
            "message": '新增巡检计划失败' | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
module.exports = { | 
				
			|||
    findPatrolRecord, | 
				
			|||
    addPatrolRecord, | 
				
			|||
} | 
				
			|||
@ -1,431 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
 | 
				
			|||
async function projectList (ctx, next) { | 
				
			|||
   try { | 
				
			|||
      const models = ctx.fs.dc.models; | 
				
			|||
      let userInfo = ctx.fs.api.userInfo; | 
				
			|||
      const { limit, page, name, justStructure } = ctx.query; | 
				
			|||
 | 
				
			|||
      let options = { | 
				
			|||
         where: { | 
				
			|||
 | 
				
			|||
         }, | 
				
			|||
         // include: [{
 | 
				
			|||
         //    as: 'company',
 | 
				
			|||
         //    model: models.Company,
 | 
				
			|||
         //    attributes: ['id', 'name'],
 | 
				
			|||
         // },],
 | 
				
			|||
      } | 
				
			|||
      if (limit) { | 
				
			|||
         options.limit = Number(limit) | 
				
			|||
      } | 
				
			|||
      if (page && limit) { | 
				
			|||
         options.offset = Number(page) * Number(limit) | 
				
			|||
      } | 
				
			|||
      if (name) { | 
				
			|||
         options.where.name = { $like: `%${name}%` } | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
      let res = [] | 
				
			|||
      if (justStructure) { | 
				
			|||
         res = await models.Project.findAndCountAll({ | 
				
			|||
            attributes: ['id', 'name'], | 
				
			|||
         }) | 
				
			|||
      } else { | 
				
			|||
         res = await models.Project.findAndCountAll(options) | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
      ctx.status = 200; | 
				
			|||
      ctx.body = res | 
				
			|||
   } catch (error) { | 
				
			|||
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
      ctx.status = 400; | 
				
			|||
      ctx.body = { | 
				
			|||
         "message": "获取结构列表失败" | 
				
			|||
      } | 
				
			|||
   } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
async function postAddProject (ctx, next) { | 
				
			|||
   try { | 
				
			|||
      const models = ctx.fs.dc.models; | 
				
			|||
      let userInfo = ctx.fs.api.userInfo; | 
				
			|||
      const data = ctx.request.body; | 
				
			|||
      const { img, longitude, latitude, name, type, describe } = data | 
				
			|||
 | 
				
			|||
      let errMsg = data.id ? '结构物编辑失败' : '结构物新增失败' | 
				
			|||
      let project = { img, longitude, latitude, name, type, describe, userId: userInfo.id } | 
				
			|||
 | 
				
			|||
      const alikeProject = await models.Project.findOne({ | 
				
			|||
         where: { | 
				
			|||
            name: name, | 
				
			|||
         } | 
				
			|||
      }) | 
				
			|||
 | 
				
			|||
      if ((!data.id && alikeProject) || (alikeProject && alikeProject.id !== data.id)) { | 
				
			|||
         errMsg = '已有相同结构物名称' | 
				
			|||
         throw errMsg | 
				
			|||
      } | 
				
			|||
      if (data && data.id) { | 
				
			|||
         await models.Project.update(project, { | 
				
			|||
            where: { | 
				
			|||
               id: data.id | 
				
			|||
            } | 
				
			|||
         }) | 
				
			|||
      } else { | 
				
			|||
         await models.Project.create(project) | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
 | 
				
			|||
      ctx.status = 204; | 
				
			|||
   } catch (error) { | 
				
			|||
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) | 
				
			|||
      ctx.status = 400; | 
				
			|||
      ctx.body = { | 
				
			|||
         "message": errMsg | 
				
			|||
      } | 
				
			|||
   } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function delProject (ctx, next) { | 
				
			|||
   try { | 
				
			|||
      const models = ctx.fs.dc.models; | 
				
			|||
      let userInfo = ctx.fs.api.userInfo; | 
				
			|||
      const { id } = ctx.params | 
				
			|||
 | 
				
			|||
      //删除结构物
 | 
				
			|||
      await models.Project.destroy({ | 
				
			|||
         where: { | 
				
			|||
            id, | 
				
			|||
         } | 
				
			|||
      }) | 
				
			|||
      const pointId = [] | 
				
			|||
      const pointLIst = await models.Point.findAll({ | 
				
			|||
         where: { | 
				
			|||
            projectId: id, | 
				
			|||
         }, | 
				
			|||
         attributes: ['id'], | 
				
			|||
      }) | 
				
			|||
      pointLIst.map(v => pointId.push(v.id)) | 
				
			|||
 | 
				
			|||
      //点位
 | 
				
			|||
      await models.Point.destroy({ | 
				
			|||
         where: { | 
				
			|||
            projectId: id | 
				
			|||
         } | 
				
			|||
      }) | 
				
			|||
 | 
				
			|||
 | 
				
			|||
      //巡检计划
 | 
				
			|||
      const planId = [] | 
				
			|||
      const planLIst = await models.PatrolPlan.findAll({ | 
				
			|||
         where: { | 
				
			|||
            structureId: id, | 
				
			|||
         }, | 
				
			|||
         attributes: ['id'], | 
				
			|||
      }) | 
				
			|||
      planLIst.map(v => planId.push(v.id)) | 
				
			|||
      await models.PatrolPlan.destroy({ | 
				
			|||
         where: { | 
				
			|||
            structureId: id | 
				
			|||
         } | 
				
			|||
      }) | 
				
			|||
 | 
				
			|||
      //巡检记录
 | 
				
			|||
      await models.PatrolRecord.destroy({ | 
				
			|||
         where: { | 
				
			|||
            pointId: { $in: pointId }, | 
				
			|||
            patrolPlanId: { $in: planId } | 
				
			|||
         } | 
				
			|||
      }) | 
				
			|||
 | 
				
			|||
 | 
				
			|||
      ctx.status = 204; | 
				
			|||
   } catch (error) { | 
				
			|||
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) | 
				
			|||
      ctx.status = 400; | 
				
			|||
      ctx.body = { | 
				
			|||
         "message": '删除结构物失败' | 
				
			|||
      } | 
				
			|||
   } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function addPosition (ctx, next) { | 
				
			|||
   try { | 
				
			|||
      const models = ctx.fs.dc.models; | 
				
			|||
      let userInfo = ctx.fs.api.userInfo; | 
				
			|||
      const data = ctx.request.body; | 
				
			|||
      const { longitude, latitude, name, describe, qrCode, projectId, } = data | 
				
			|||
 | 
				
			|||
      let errMsg = data.id ? '点位编辑失败' : '点位新增失败' | 
				
			|||
      let pointData = { longitude, latitude, name, describe, qrCode, projectId } | 
				
			|||
 | 
				
			|||
      const alikeProject = await models.Point.findOne({ | 
				
			|||
         where: { | 
				
			|||
            id: data.id, | 
				
			|||
         } | 
				
			|||
      }) | 
				
			|||
 | 
				
			|||
      if (data && data.id) { | 
				
			|||
         if (qrCode) { | 
				
			|||
            await models.Point.update({ ...alikeProject, qrCode }, { | 
				
			|||
               where: { | 
				
			|||
                  id: data.id, | 
				
			|||
               } | 
				
			|||
            }) | 
				
			|||
         } else { | 
				
			|||
            await models.Point.update({ pointData }, { | 
				
			|||
               where: { | 
				
			|||
                  id: data.id, | 
				
			|||
               } | 
				
			|||
            }) | 
				
			|||
         } | 
				
			|||
 | 
				
			|||
      } else { | 
				
			|||
         await models.Point.create(pointData) | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
 | 
				
			|||
      ctx.status = 204; | 
				
			|||
   } catch (error) { | 
				
			|||
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) | 
				
			|||
      ctx.status = 400; | 
				
			|||
      ctx.body = { | 
				
			|||
         "message": errMsg | 
				
			|||
      } | 
				
			|||
   } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function position (ctx, next) { | 
				
			|||
   try { | 
				
			|||
      const models = ctx.fs.dc.models; | 
				
			|||
      let userInfo = ctx.fs.api.userInfo; | 
				
			|||
      const { limit, page, projectId } = ctx.query; | 
				
			|||
 | 
				
			|||
      let options = { | 
				
			|||
         where: { | 
				
			|||
            id: projectId | 
				
			|||
         }, | 
				
			|||
         include: [{ | 
				
			|||
            model: models.Point, | 
				
			|||
         },], | 
				
			|||
      } | 
				
			|||
      if (limit) { | 
				
			|||
         options.limit = Number(limit) | 
				
			|||
      } | 
				
			|||
      if (page && limit) { | 
				
			|||
         options.offset = Number(page) * Number(limit) | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
      let res = await models.Project.findAndCountAll(options) | 
				
			|||
      ctx.status = 200; | 
				
			|||
      ctx.body = res | 
				
			|||
   } catch (error) { | 
				
			|||
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
      ctx.status = 400; | 
				
			|||
      ctx.body = { | 
				
			|||
         "message": "获取结构列表失败" | 
				
			|||
      } | 
				
			|||
   } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
async function delPosition (ctx, next) { | 
				
			|||
   try { | 
				
			|||
      const models = ctx.fs.dc.models; | 
				
			|||
      let userInfo = ctx.fs.api.userInfo; | 
				
			|||
      const { id } = ctx.params | 
				
			|||
 | 
				
			|||
      const pointOne = await models.Point.findOne({ | 
				
			|||
         where: { | 
				
			|||
            id | 
				
			|||
         }, | 
				
			|||
         attributes: ['projectId'], | 
				
			|||
      }) | 
				
			|||
      if (pointOne) { | 
				
			|||
         const patrolPlanLIst = await models.PatrolPlan.findAll({ | 
				
			|||
            where: { | 
				
			|||
               structureId: pointOne.projectId, | 
				
			|||
            }, | 
				
			|||
         }) | 
				
			|||
 | 
				
			|||
         for (var u of patrolPlanLIst) { | 
				
			|||
            const points = [] | 
				
			|||
            u.points.map(r => { | 
				
			|||
               if (r.id == id) { | 
				
			|||
               } else { | 
				
			|||
                  points.push(r) | 
				
			|||
               } | 
				
			|||
            }) | 
				
			|||
            u.points = points | 
				
			|||
 | 
				
			|||
            await models.PatrolRecord.destroy({ | 
				
			|||
               where: { | 
				
			|||
                  pointId: id, | 
				
			|||
                  patrolPlanId: u.id | 
				
			|||
               } | 
				
			|||
            }) | 
				
			|||
 | 
				
			|||
            if (points.length > 0) { | 
				
			|||
               let data = { | 
				
			|||
                  name: u.dataValues.name, | 
				
			|||
                  way: u.dataValues.way, | 
				
			|||
                  structureId: u.dataValues.structureId, | 
				
			|||
                  startTime: u.dataValues.startTime, | 
				
			|||
                  endTime: u.dataValues.endTime, | 
				
			|||
                  frequency: u.dataValues.frequency, | 
				
			|||
                  points: u.dataValues.points, | 
				
			|||
                  userId: u.dataValues.userId, | 
				
			|||
                  patrolCount: u.dataValues.patrolCount | 
				
			|||
               } | 
				
			|||
               await models.PatrolPlan.update(data,{ | 
				
			|||
                  where: { | 
				
			|||
                     id: u.dataValues.id | 
				
			|||
                  } | 
				
			|||
               }) | 
				
			|||
            } else { | 
				
			|||
               await models.PatrolPlan.destroy({ | 
				
			|||
                  where: { | 
				
			|||
                     id: u.id | 
				
			|||
                  } | 
				
			|||
               }) | 
				
			|||
            } | 
				
			|||
         } | 
				
			|||
 | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
      await models.Point.destroy({ | 
				
			|||
         where: { | 
				
			|||
            id, | 
				
			|||
         } | 
				
			|||
      }) | 
				
			|||
 | 
				
			|||
 | 
				
			|||
      ctx.status = 204; | 
				
			|||
   } catch (error) { | 
				
			|||
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`) | 
				
			|||
      ctx.status = 400; | 
				
			|||
      ctx.body = { | 
				
			|||
         "message": '删除点位失败' | 
				
			|||
      } | 
				
			|||
   } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
async function qrCodeShow (ctx, next) { | 
				
			|||
   try { | 
				
			|||
      const models = ctx.fs.dc.models; | 
				
			|||
      let userInfo = ctx.fs.api.userInfo; | 
				
			|||
      const { projectId, name } = ctx.query; | 
				
			|||
 | 
				
			|||
      let options = { | 
				
			|||
         where: { | 
				
			|||
            qrCode: { $ne: null } | 
				
			|||
         }, | 
				
			|||
      } | 
				
			|||
      if (projectId) { | 
				
			|||
         options.where.projectId = projectId | 
				
			|||
      } | 
				
			|||
      if (name) { | 
				
			|||
         options.where.name = { $like: `%${name}%` } | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
      let res = await models.Point.findAndCountAll(options) | 
				
			|||
      ctx.status = 200; | 
				
			|||
      ctx.body = res | 
				
			|||
   } catch (error) { | 
				
			|||
      ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); | 
				
			|||
      ctx.status = 400; | 
				
			|||
      ctx.body = { | 
				
			|||
         "message": "获取二维码列表失败" | 
				
			|||
      } | 
				
			|||
   } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
async function q (ctx) { | 
				
			|||
   // let error = {
 | 
				
			|||
   //     name: 'FindError',
 | 
				
			|||
   //     message: "获取失败!"
 | 
				
			|||
   // };
 | 
				
			|||
   // const models = ctx.fs.dc.models;
 | 
				
			|||
   // const { devices } = ctx.request.body
 | 
				
			|||
   // const attachment = ctx.app.fs.qn_attachment
 | 
				
			|||
 | 
				
			|||
   // try {
 | 
				
			|||
 | 
				
			|||
   //     if (!Array.isArray(devices)) {
 | 
				
			|||
   //         error = { name: 'paramsError', message: '参数不能为空' };
 | 
				
			|||
   //         ctx.throw(400);
 | 
				
			|||
   //     }
 | 
				
			|||
   //     const devicesArr = await models.Device.findAll({
 | 
				
			|||
   //         attributes: ['deviceNo', 'periodCode', 'qrSrc'],
 | 
				
			|||
   //         where: { deviceNo: { $in: devices } }
 | 
				
			|||
   //     })
 | 
				
			|||
 | 
				
			|||
   //     let ids = [], idsMap = {}, qnImages = []
 | 
				
			|||
   //     devicesArr.forEach(d => {
 | 
				
			|||
   //         const qrSrc = d.qrSrc
 | 
				
			|||
   //         const deviceNo = d.deviceNo
 | 
				
			|||
   //         const periodCode = d.periodCode
 | 
				
			|||
   //         if (qrSrc) {
 | 
				
			|||
   //             if (/^\d+$/.test(qrSrc)) {
 | 
				
			|||
   //                 ids.push(qrSrc)
 | 
				
			|||
   //                 idsMap[qrSrc] = { deviceNo, periodCode }
 | 
				
			|||
   //             } else {
 | 
				
			|||
   //                 let domain = globalCache.getQnDomain()
 | 
				
			|||
   //                 let imgUrl = `${domain}/${qrSrc}`
 | 
				
			|||
   //                 qnImages.push({ src: imgUrl, deviceNo, periodCode })
 | 
				
			|||
   //             }
 | 
				
			|||
   //         }
 | 
				
			|||
   //     })
 | 
				
			|||
 | 
				
			|||
   //     const docs = await models.QrcodePng.findAll({
 | 
				
			|||
   //         where: {
 | 
				
			|||
   //             id: { $in: ids }
 | 
				
			|||
   //         },
 | 
				
			|||
   //         attributes: ["id", "base64"]
 | 
				
			|||
   //     })
 | 
				
			|||
 | 
				
			|||
   //     let pics = []
 | 
				
			|||
 | 
				
			|||
   //     if (docs.length > 0) {
 | 
				
			|||
   //         pics = docs.map((d) => {
 | 
				
			|||
   //             let { deviceNo, periodCode } = idsMap[d.id] || {}
 | 
				
			|||
   //             let base64 = d.base64.replace(/^data:image\/\w+;base64,/, '')
 | 
				
			|||
   //             return {
 | 
				
			|||
   //                 url: Buffer.from(base64, 'base64'),
 | 
				
			|||
   //                 name: deviceNo,
 | 
				
			|||
   //                 periodCode
 | 
				
			|||
   //             }
 | 
				
			|||
   //         })
 | 
				
			|||
   //     }
 | 
				
			|||
 | 
				
			|||
   //     if (qnImages.length > 0) {
 | 
				
			|||
   //         let qns = await downloadImgsAsBase64(qnImages)
 | 
				
			|||
   //         pics = pics.concat(qns)
 | 
				
			|||
   //     }
 | 
				
			|||
 | 
				
			|||
   //     let fileUrl = await downLoadImageBiz(pics, { zipName: "二维码_" + moment().format("YYYY-MM-DD-HH-mm-ss"), attachment })
 | 
				
			|||
   //     add2CleanCache(fileUrl, attachment)
 | 
				
			|||
   //     ctx.status = 200
 | 
				
			|||
   //     ctx.body = { fileUrl }
 | 
				
			|||
 | 
				
			|||
   // } catch (err) {
 | 
				
			|||
   //     ctx.fs.logger.error(err);
 | 
				
			|||
   //     ctx.status = 400;
 | 
				
			|||
   //     ctx.body = error;
 | 
				
			|||
   // }
 | 
				
			|||
} | 
				
			|||
 | 
				
			|||
module.exports = { | 
				
			|||
   projectList, | 
				
			|||
   postAddProject, | 
				
			|||
   delProject, | 
				
			|||
   addPosition, | 
				
			|||
   position, | 
				
			|||
   delPosition, | 
				
			|||
   qrCodeShow, | 
				
			|||
   q | 
				
			|||
} | 
				
			|||
@ -1,17 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
const patrolPlan = require('../../controllers/patrolPlan/patrolPlan'); | 
				
			|||
 | 
				
			|||
module.exports = function (app, router, opts) { | 
				
			|||
    app.fs.api.logAttr['GET/patrolPlan'] = { content: '获取巡检计划', visible: false }; | 
				
			|||
    router.get('/patrolPlan', patrolPlan.getPatrolPlan); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['POST/patrolPlan'] = { content: '新增巡检计划', visible: true }; | 
				
			|||
    router.post('/patrolPlan', patrolPlan.createPatrolPlan); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['PUT/patrolPlan'] = { content: '修改巡检计划', visible: true }; | 
				
			|||
    router.put('/patrolPlan', patrolPlan.updatePatrolPlan); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['DELETE/patrolPlan/:id'] = { content: '删除巡检计划', visible: true }; | 
				
			|||
    router.del('/patrolPlan/:id', patrolPlan.delPatrolPlan); | 
				
			|||
}; | 
				
			|||
@ -1,12 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
const patrolRecord = require('../../controllers/patrolRecord/patrolRecord'); | 
				
			|||
 | 
				
			|||
module.exports = function (app, router, opts) { | 
				
			|||
    app.fs.api.logAttr['GET/patrolRecord/:patrolPlanId/:startTime/:endTime/:alarm/:pointId'] = { content: '获取巡检记录', visible: true }; | 
				
			|||
    // web端、小程序端查数据:patrolPlanId为all,不需要传pointId
 | 
				
			|||
    // 小程序端查点位最新一条数据:startTime、endTime、alarm不传
 | 
				
			|||
    router.get('/patrolRecord/:patrolPlanId/:startTime/:endTime/:alarm/:pointId', patrolRecord.findPatrolRecord); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['POST/patrolRecord/add'] = { content: '新增巡检记录', visible: true } | 
				
			|||
    router.post('/patrolRecord/add', patrolRecord.addPatrolRecord); | 
				
			|||
}; | 
				
			|||
@ -1,31 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
const projectSituation = require('../../controllers/projectRegime/projectSituation'); | 
				
			|||
 | 
				
			|||
module.exports = function (app, router, opts) { | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['GET/projectList'] = { content: '获取结构物列表', visible: false }; | 
				
			|||
    router.get('/projectList', projectSituation.projectList); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['POST/addProject'] = { content: '新增修改结构物', visible: false }; | 
				
			|||
    router.post('/addProject', projectSituation.postAddProject); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['DEL/delProject/:id'] = { content: '删除结构物', visible: false }; | 
				
			|||
    router.del('/delProject/:id', projectSituation.delProject); | 
				
			|||
    | 
				
			|||
    app.fs.api.logAttr['POST/position'] = { content: '新增修改点位', visible: false }; | 
				
			|||
    router.post('/position', projectSituation.addPosition); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['GET/position'] = { content: '获取点位列表', visible: false }; | 
				
			|||
    router.get('/position', projectSituation.position); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['DEL/delPosition/:id'] = { content: '删除点位', visible: false }; | 
				
			|||
    router.del('/delPosition/:id', projectSituation.delPosition); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['GET/qrCodeShow'] = { content: '获取二维码列表', visible: false }; | 
				
			|||
    router.get('/qrCodeShow', projectSituation.qrCodeShow); | 
				
			|||
 | 
				
			|||
    app.fs.api.logAttr['GET/q'] = { content: '获取二维码列表', visible: false }; | 
				
			|||
    router.get('/q', projectSituation.q); | 
				
			|||
 | 
				
			|||
} | 
				
			|||
| 
		 Before Width: | Height: | Size: 22 KiB  | 
| 
		 Before Width: | Height: | Size: 21 KiB  | 
| 
		 Before Width: | Height: | Size: 20 KiB  | 
| 
		 Before Width: | Height: | Size: 21 KiB  | 
| 
		 Before Width: | Height: | Size: 21 KiB  | 
| 
		 Before Width: | Height: | Size: 22 KiB  | 
| 
		 Before Width: | Height: | Size: 20 KiB  | 
| 
		 Before Width: | Height: | Size: 22 KiB  | 
| 
		 Before Width: | Height: | Size: 20 KiB  | 
| 
		 Before Width: | Height: | Size: 22 KiB  | 
| 
		 Before Width: | Height: | Size: 22 KiB  | 
| 
		 Before Width: | Height: | Size: 21 KiB  | 
| 
		 Before Width: | Height: | Size: 202 KiB  | 
| 
		 Before Width: | Height: | Size: 725 B  | 
| 
		 Before Width: | Height: | Size: 24 KiB  | 
| 
		 Before Width: | Height: | Size: 169 KiB  | 
| 
		 Before Width: | Height: | Size: 8.7 KiB  | 
| 
		 Before Width: | Height: | Size: 3.2 KiB  | 
| 
		 Before Width: | Height: | Size: 2.0 KiB  | 
| 
		 Before Width: | Height: | Size: 2.3 KiB  | 
| 
		 Before Width: | Height: | Size: 2.6 KiB  | 
| 
		 Before Width: | Height: | Size: 2.0 KiB  | 
| 
		 Before Width: | Height: | Size: 2.7 KiB  | 
| 
		 Before Width: | Height: | Size: 2.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.5 KiB  | 
| 
		 Before Width: | Height: | Size: 524 B  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 873 B  | 
| 
		 Before Width: | Height: | Size: 206 KiB  | 
| 
		 Before Width: | Height: | Size: 150 B  | 
| 
		 Before Width: | Height: | Size: 950 B  | 
| 
		 Before Width: | Height: | Size: 873 B  | 
| 
		 Before Width: | Height: | Size: 815 B  | 
| 
		 Before Width: | Height: | Size: 193 B  | 
| 
		 Before Width: | Height: | Size: 147 B  | 
| 
		 Before Width: | Height: | Size: 999 B  | 
| 
		 Before Width: | Height: | Size: 648 B  | 
| 
		 Before Width: | Height: | Size: 932 B  | 
| 
		 Before Width: | Height: | Size: 646 KiB  | 
| 
		 Before Width: | Height: | Size: 200 KiB  | 
| 
		 Before Width: | Height: | Size: 7.8 KiB  | 
| 
		 After Width: | Height: | Size: 21 KiB  | 
| 
		 After Width: | Height: | Size: 234 KiB  | 
| 
		 After Width: | Height: | Size: 22 KiB  | 
| 
		 After Width: | Height: | Size: 1.5 MiB  | 
| 
		 After Width: | Height: | Size: 76 KiB  | 
| 
		 After Width: | Height: | Size: 23 KiB  | 
@ -1,316 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import React, { Component } from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Upload, message, Modal, Card, Button } from 'antd'; | 
				
			|||
import moment from 'moment'; | 
				
			|||
import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; | 
				
			|||
 | 
				
			|||
class Uploads extends Component { | 
				
			|||
    constructor(props) { | 
				
			|||
        super(props); | 
				
			|||
        this.ApiRoot = localStorage.getItem('tyApiRoot') | 
				
			|||
        this.state = { | 
				
			|||
            fileUploading: false, | 
				
			|||
            fileList: [], | 
				
			|||
            curPreviewPic: '', | 
				
			|||
            delPicIng: false, | 
				
			|||
            removeFilesList: [] | 
				
			|||
        }; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    dealName = (uploaded) => { | 
				
			|||
        let realName = uploaded.split('/')[2] | 
				
			|||
        let x1 = realName.split('.') | 
				
			|||
        let x2 = x1[0].split('_') | 
				
			|||
        let showName = `${x2[0]}.${x1[1]}` | 
				
			|||
        return showName | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    // setFileList = (value) => {
 | 
				
			|||
    //     let defaultFileList = [];
 | 
				
			|||
    //     defaultFileList = value.map((u, index) => {
 | 
				
			|||
    //         let fileUrl = `${this.ApiRoot}/${u.url}`;
 | 
				
			|||
    //         return {
 | 
				
			|||
    //             uid: -index - 1,
 | 
				
			|||
    //             name: this.dealName(u.url),
 | 
				
			|||
    //             status: 'done',
 | 
				
			|||
    //             storageUrl: u.url,
 | 
				
			|||
    //             url: fileUrl
 | 
				
			|||
    //         };
 | 
				
			|||
    //     });
 | 
				
			|||
    //     onChange(defaultFileList)
 | 
				
			|||
    //     this.setState({
 | 
				
			|||
    //         fileList: defaultFileList
 | 
				
			|||
    //     });
 | 
				
			|||
    // };
 | 
				
			|||
 | 
				
			|||
    componentDidMount() { | 
				
			|||
        const { value } = this.props; | 
				
			|||
        if (value) { | 
				
			|||
            this.setState(value); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    componentWillReceiveProps(np) { | 
				
			|||
        const { dispatch, value: thisEditData, onChange } = this.props; | 
				
			|||
        const { value: nextEditData } = np; | 
				
			|||
 | 
				
			|||
        const setFileList = () => { | 
				
			|||
            let defaultFileList = []; | 
				
			|||
            defaultFileList = nextEditData.map((u, index) => { | 
				
			|||
                let fileUrl = `${this.ApiRoot}/${u.storageUrl}`; | 
				
			|||
                return { | 
				
			|||
                    uid: -index - 1, | 
				
			|||
                    name: this.dealName(u.storageUrl), | 
				
			|||
                    status: 'done', | 
				
			|||
                    storageUrl: u.storageUrl, | 
				
			|||
                    url: fileUrl, | 
				
			|||
                    size: u.size || -1 | 
				
			|||
                }; | 
				
			|||
            }); | 
				
			|||
            this.setState({ | 
				
			|||
                fileList: defaultFileList | 
				
			|||
            }); | 
				
			|||
        }; | 
				
			|||
 | 
				
			|||
        if (nextEditData && nextEditData.length) { | 
				
			|||
            if (!thisEditData || !this.state.fileList.length) { | 
				
			|||
                setFileList(); | 
				
			|||
            } else if (nextEditData.length != thisEditData.length) { | 
				
			|||
                setFileList(); | 
				
			|||
            } else { | 
				
			|||
                let repeat = true; | 
				
			|||
                for (let i = 0; i < thisEditData.length; i++) { | 
				
			|||
                    if (thisEditData[i] != nextEditData[i]) { | 
				
			|||
                        repeat = false; | 
				
			|||
                        break; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                if (!repeat) { | 
				
			|||
                    setFileList(); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
        // else{
 | 
				
			|||
        //     this.setState({
 | 
				
			|||
        //         fileList:[],
 | 
				
			|||
        //     })
 | 
				
			|||
        // }
 | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    render() { | 
				
			|||
        const UploadPath = { | 
				
			|||
            project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'png', 'jpg', 'rar', 'zip'], | 
				
			|||
            report: ['doc', 'docx', 'xls', 'xlsx', 'pdf'], | 
				
			|||
            data: ['txt', 'xls', 'xlsx'], | 
				
			|||
            image: ['png', 'jpg', 'svg', 'jpeg'], | 
				
			|||
            three: ['js'], | 
				
			|||
            video: ['mp4'] | 
				
			|||
        }; | 
				
			|||
        /** | 
				
			|||
         * uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project; | 
				
			|||
         * disabled 【boolean】 上传是否可用 | 
				
			|||
         * maxFilesNum 【number】 最大上传数量 | 
				
			|||
         * fileTypes 【array[string]】 可允许上传的文件类型; | 
				
			|||
         * maxFileSize 【number】 单个文件最大大小 M | 
				
			|||
         * listType 【antd】 upload 组件的属性 | 
				
			|||
         * onChange 【function】 文件数量变化时候回调 返回文件 | 
				
			|||
         * value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}] | 
				
			|||
         * onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false } | 
				
			|||
         */ | 
				
			|||
        const { | 
				
			|||
            uploadType, | 
				
			|||
            disabled, | 
				
			|||
            maxFilesNum, | 
				
			|||
            fileTypes, | 
				
			|||
            maxFileSize, | 
				
			|||
            listType, | 
				
			|||
            onChange, | 
				
			|||
            value, | 
				
			|||
            showUploadList, | 
				
			|||
            onStateChange | 
				
			|||
        } = this.props; | 
				
			|||
        const { fileList, curPreviewPic, delPicIng, removeFilesList } = this.state; | 
				
			|||
        const that = this; | 
				
			|||
        let uploadType_ = uploadType || 'project'; | 
				
			|||
        let maxFilesNum_ = maxFilesNum || 1; | 
				
			|||
        let defaultFileTypes = fileTypes || UploadPath[uploadType_]; | 
				
			|||
        const uploadProps = { | 
				
			|||
            name: 'checkFile_', | 
				
			|||
            multiple: false, | 
				
			|||
            showUploadList: showUploadList || true, | 
				
			|||
            action: `${this.ApiRoot}/attachments/${uploadType_}`, | 
				
			|||
            listType: listType || 'text', | 
				
			|||
            disabled: disabled, | 
				
			|||
            beforeUpload: (file) => { | 
				
			|||
                if (fileList.length >= maxFilesNum_) { | 
				
			|||
                    message.warning(`最多选择${maxFilesNum_}个文件上传`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                if (file.name.length > 60) { | 
				
			|||
                    message.warning(`文件名过长(大于60字符),请修改后上传`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                const extNames = file.name.split('.'); | 
				
			|||
                var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/; | 
				
			|||
                if (!reg.exec(file.name)) { | 
				
			|||
                    message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                let isDAE = false; | 
				
			|||
                if (extNames.length > 0) { | 
				
			|||
                    let fileType = extNames[extNames.length - 1].toLowerCase(); | 
				
			|||
                    isDAE = defaultFileTypes.some((f) => f == fileType); | 
				
			|||
                } | 
				
			|||
                if (!isDAE) { | 
				
			|||
                    message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                const isLt = file.size / 1024 / 1024 < (maxFileSize || 3); | 
				
			|||
                if (!isLt) { | 
				
			|||
                    message.error(`文件必须小于${maxFileSize || 3}MB!`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                this.setState({ | 
				
			|||
                    fileUploading: true | 
				
			|||
                }); | 
				
			|||
                if (onStateChange) { | 
				
			|||
                    onStateChange({ uploading: true }); | 
				
			|||
                } | 
				
			|||
            }, | 
				
			|||
            onChange(info) { | 
				
			|||
                const status = info.file.status; | 
				
			|||
                if (status === 'uploading') { | 
				
			|||
                    that.setState({ | 
				
			|||
                        fileList: info.fileList | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
                if (status === 'done') { | 
				
			|||
                    let { uploaded, url } = info.file.response; | 
				
			|||
                    let size = info.file.size; | 
				
			|||
                    let nextFileList = fileList; | 
				
			|||
                    nextFileList[nextFileList.length - 1] = { | 
				
			|||
                        uid: -moment().unix(), | 
				
			|||
                        name: that.dealName(uploaded), | 
				
			|||
                        status: 'done', | 
				
			|||
                        storageUrl: uploaded, | 
				
			|||
                        url: url, | 
				
			|||
                        size: size | 
				
			|||
                    }; | 
				
			|||
                    onChange(nextFileList); | 
				
			|||
                    that.setState({ | 
				
			|||
                        fileUploading: false, | 
				
			|||
                        fileList: nextFileList | 
				
			|||
                    }); | 
				
			|||
                    if (onStateChange) { | 
				
			|||
                        onStateChange({ uploading: false }); | 
				
			|||
                    } | 
				
			|||
                } else if (status === 'error') { | 
				
			|||
                    that.setState({ | 
				
			|||
                        fileUploading: false | 
				
			|||
                    }); | 
				
			|||
                    message.error(`${info.file.name} 上传失败,请重试`); | 
				
			|||
                    if (onStateChange) { | 
				
			|||
                        onStateChange({ uploading: false }); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
            }, | 
				
			|||
            onRemove(file) { | 
				
			|||
                let nextFileList = []; | 
				
			|||
                fileList.map((f, i) => { | 
				
			|||
                    if (f.uid != file.uid) { | 
				
			|||
                        nextFileList.push(f); | 
				
			|||
                    } | 
				
			|||
                }); | 
				
			|||
                let nextRemoveFiles = removeFilesList.concat([file.storageUrl]); | 
				
			|||
                if (curPreviewPic == file.url) { | 
				
			|||
                    that.setState({ | 
				
			|||
                        curPreviewPic: '' | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
                onChange(nextFileList); | 
				
			|||
                that.setState({ | 
				
			|||
                    fileList: nextFileList, | 
				
			|||
                    removeFilesList: nextRemoveFiles | 
				
			|||
                }); | 
				
			|||
            }, | 
				
			|||
            onPreview(file) { | 
				
			|||
                let filePostfix = file.url.split('.').pop(); | 
				
			|||
                filePostfix = filePostfix.toLowerCase(); | 
				
			|||
                if (UploadPath.image.some((img) => img == filePostfix)) { | 
				
			|||
                    that.setState({ | 
				
			|||
                        curPreviewPic: file.url | 
				
			|||
                    }); | 
				
			|||
                } else { | 
				
			|||
                    message.warn('仅支持图片预览'); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        }; | 
				
			|||
 | 
				
			|||
        let fileList_ = fileList | 
				
			|||
        // .map(f => {
 | 
				
			|||
        //     if (f.storageUrl) {
 | 
				
			|||
        //         let realName = f.storageUrl.split('/').pop()
 | 
				
			|||
        //         if (f.name != realName) {
 | 
				
			|||
        //             f.name = realName
 | 
				
			|||
        //         }
 | 
				
			|||
        //     }
 | 
				
			|||
        //     return f
 | 
				
			|||
        // })
 | 
				
			|||
 | 
				
			|||
        return ( | 
				
			|||
            <div> | 
				
			|||
                <Spin spinning={delPicIng}> | 
				
			|||
                    <Upload {...uploadProps} fileList={fileList_}> | 
				
			|||
                        { | 
				
			|||
                            disabled ? ( | 
				
			|||
                                '' | 
				
			|||
                            ) : | 
				
			|||
                                listType == 'picture-card' ? | 
				
			|||
                                    ( | 
				
			|||
                                        fileList.length >= maxFilesNum_ ? null : ( | 
				
			|||
                                            <div style={{}}> | 
				
			|||
                                                <PlusOutlined /> | 
				
			|||
                                                <div>上传图片</div> | 
				
			|||
                                            </div> | 
				
			|||
                                        ) | 
				
			|||
                                    ) : ( | 
				
			|||
                                        <Button disabled={fileList.length >= maxFilesNum_} icon={<UploadOutlined />}>  文件上传 </Button> | 
				
			|||
                                    ) | 
				
			|||
                        } | 
				
			|||
                    </Upload> | 
				
			|||
                    { | 
				
			|||
                        curPreviewPic ? ( | 
				
			|||
                            <Card | 
				
			|||
                                bodyStyle={{ | 
				
			|||
                                    padding: 8 | 
				
			|||
                                }} | 
				
			|||
                            > | 
				
			|||
                                <div style={{ marginBottom: 8 }} > | 
				
			|||
                                    <span>文件预览</span> | 
				
			|||
                                    <span | 
				
			|||
                                        style={{ float: 'right' }} | 
				
			|||
                                        onClick={() => { this.setState({ curPreviewPic: '' }); }} | 
				
			|||
                                    > | 
				
			|||
                                        <CloseOutlined style={{ fontSize: 20 }} /> | 
				
			|||
                                    </span> | 
				
			|||
                                </div> | 
				
			|||
                                <img style={{ width: '100%' }} src={curPreviewPic}></img> | 
				
			|||
                            </Card> | 
				
			|||
                        ) : '' | 
				
			|||
                    } | 
				
			|||
                </Spin> | 
				
			|||
            </div> | 
				
			|||
        ); | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps(state) { | 
				
			|||
    const { auth } = state | 
				
			|||
    return { | 
				
			|||
        user: auth.user | 
				
			|||
    }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(Uploads); | 
				
			|||
@ -1,389 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import React, { Component } from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Upload, message, Modal, Card, Button } from 'antd'; | 
				
			|||
import moment from 'moment'; | 
				
			|||
import { PlusOutlined, UploadOutlined, CloseOutlined } from '@ant-design/icons'; | 
				
			|||
 | 
				
			|||
class Uploads extends Component { | 
				
			|||
    constructor(props) { | 
				
			|||
        super(props); | 
				
			|||
        this.ApiRoot = localStorage.getItem('tyApiRoot') | 
				
			|||
        this.qnDomain = localStorage.getItem('qnDomain'); | 
				
			|||
        this.aliAdmin = localStorage.getItem('aliAdmin'); | 
				
			|||
        this.state = { | 
				
			|||
            fileUploading: false, | 
				
			|||
            fileList: [], | 
				
			|||
            curPreviewPic: '', | 
				
			|||
            curPreviewVideo: '', | 
				
			|||
            delPicIng: false, | 
				
			|||
            removeFilesList: [] | 
				
			|||
        }; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    dealName = (uploaded) => { | 
				
			|||
        let realName = uploaded.split('/')[2] | 
				
			|||
        // let x1 = realName.split('.')
 | 
				
			|||
        // let postfix = x1.pop()
 | 
				
			|||
        // let allName = x1.join('.')
 | 
				
			|||
        // let x2 = allName.split('_')
 | 
				
			|||
        // let showName = `${x2[0]}.${postfix}`
 | 
				
			|||
        return realName | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    // setFileList = (value) => {
 | 
				
			|||
    //     let defaultFileList = [];
 | 
				
			|||
    //     defaultFileList = value.map((u, index) => {
 | 
				
			|||
    //         let fileUrl = `${this.ApiRoot}/${u.url}`;
 | 
				
			|||
    //         return {
 | 
				
			|||
    //             uid: -index - 1,
 | 
				
			|||
    //             name: this.dealName(u.url),
 | 
				
			|||
    //             status: 'done',
 | 
				
			|||
    //             storageUrl: u.url,
 | 
				
			|||
    //             url: fileUrl
 | 
				
			|||
    //         };
 | 
				
			|||
    //     });
 | 
				
			|||
    //     onChange(defaultFileList)
 | 
				
			|||
    //     this.setState({
 | 
				
			|||
    //         fileList: defaultFileList
 | 
				
			|||
    //     });
 | 
				
			|||
    // };
 | 
				
			|||
 | 
				
			|||
    setFileList = (nextEditData, isQiniu, isAli) => { | 
				
			|||
        let defaultFileList = []; | 
				
			|||
        defaultFileList = nextEditData.map((u, index) => { | 
				
			|||
            let fileUrl = | 
				
			|||
                isQiniu ? `/_file-server/${u.storageUrl}` | 
				
			|||
                    : isAli ? `/_file-ali-server/${u.storageUrl}` | 
				
			|||
                        : `${this.ApiRoot}/${u.storageUrl}`; | 
				
			|||
 | 
				
			|||
            return { | 
				
			|||
                uid: -index - 1, | 
				
			|||
                name: this.dealName(u.storageUrl), | 
				
			|||
                status: 'done', | 
				
			|||
                storageUrl: u.storageUrl, | 
				
			|||
                url: fileUrl, | 
				
			|||
                size: u.size || -1 | 
				
			|||
            }; | 
				
			|||
        }); | 
				
			|||
        this.setState({ | 
				
			|||
            fileList: defaultFileList | 
				
			|||
        }); | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    componentDidMount() { | 
				
			|||
        const { value, defaultValue, isQiniu, isAli } = this.props; | 
				
			|||
        if (defaultValue) { | 
				
			|||
            this.setFileList(defaultValue, isQiniu, isAli) | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    UNSAFE_componentWillReceiveProps(np) { | 
				
			|||
        const { dispatch, value: thisEditData, onChange } = this.props; | 
				
			|||
        const { value: nextEditData, isQiniu, isAli } = np; | 
				
			|||
        // this.setFileList(nextEditData, isQiniu)
 | 
				
			|||
        // const setFileList = () => {
 | 
				
			|||
        //     let defaultFileList = [];
 | 
				
			|||
        //     defaultFileList = nextEditData.map((u, index) => {
 | 
				
			|||
        //         let fileUrl = isQiniu ? `/_file-server/${u.storageUrl}` : `${this.ApiRoot}/${u.storageUrl}`;
 | 
				
			|||
        //         return {
 | 
				
			|||
        //             uid: -index - 1,
 | 
				
			|||
        //             name: this.dealName(u.storageUrl),
 | 
				
			|||
        //             status: 'done',
 | 
				
			|||
        //             storageUrl: u.storageUrl,
 | 
				
			|||
        //             url: fileUrl,
 | 
				
			|||
        //             size: u.size || -1
 | 
				
			|||
        //         };
 | 
				
			|||
        //     });
 | 
				
			|||
        //     this.setState({
 | 
				
			|||
        //         fileList: defaultFileList
 | 
				
			|||
        //     });
 | 
				
			|||
        // };
 | 
				
			|||
        if (nextEditData && nextEditData.length) { | 
				
			|||
            if (!thisEditData || !this.state.fileList.length) { | 
				
			|||
                this.setFileList(nextEditData, isQiniu, isAli); | 
				
			|||
            } else if (nextEditData.length != thisEditData.length) { | 
				
			|||
                this.setFileList(nextEditData, isQiniu, isAli); | 
				
			|||
            } else { | 
				
			|||
                let repeat = true; | 
				
			|||
                for (let i = 0; i < thisEditData.length; i++) { | 
				
			|||
                    if (thisEditData[i] != nextEditData[i]) { | 
				
			|||
                        repeat = false; | 
				
			|||
                        break; | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
                if (!repeat) { | 
				
			|||
                    this.setFileList(nextEditData, isQiniu, isAli); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
        // else{
 | 
				
			|||
        //     this.setState({
 | 
				
			|||
        //         fileList:[],
 | 
				
			|||
        //     })
 | 
				
			|||
        // }
 | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    render() { | 
				
			|||
        const UploadPath = { | 
				
			|||
            project: ['txt', 'dwg', 'doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf', 'pptx', 'png', 'jpg', 'svg', 'jpeg', 'rar', 'zip', 'jpeg', 'mp4'], | 
				
			|||
            report: ['doc', 'docx', 'xls', 'xlsx', 'csv', 'pdf'], | 
				
			|||
            data: ['txt', 'xls', 'xlsx', 'csv'], | 
				
			|||
            image: ['png', 'jpg', 'svg', 'jpeg'], | 
				
			|||
            three: ['js'], | 
				
			|||
            video: ['mp4'] | 
				
			|||
        }; | 
				
			|||
        /** | 
				
			|||
         * uploadType 【string】 主要区别文件上传路径 以及类型 以 web/routes/attachment/index.js 中 UploadPath 的 key 值为准;默认 project; | 
				
			|||
         * disabled 【boolean】 上传是否可用 | 
				
			|||
         * maxFilesNum 【number】 最大上传数量 | 
				
			|||
         * fileTypes 【array[string]】 可允许上传的文件类型; | 
				
			|||
         * maxFileSize 【number】 单个文件最大大小 M | 
				
			|||
         * listType 【antd】 upload 组件的属性 | 
				
			|||
         * onChange 【function】 文件数量变化时候回调 返回文件 | 
				
			|||
         * value 【array[obj]】 编辑数据 [{url:'xxx', [size:999]}] | 
				
			|||
         * onStateChange 【function】 文件状态改变回调函数 上传中 return { uploading:true/false } | 
				
			|||
         */ | 
				
			|||
        const { | 
				
			|||
            uploadType, | 
				
			|||
            disabled, | 
				
			|||
            maxFilesNum, | 
				
			|||
            fileTypes, | 
				
			|||
            maxFileSize, | 
				
			|||
            listType, | 
				
			|||
            onChange = () => { }, | 
				
			|||
            value, | 
				
			|||
            showUploadList, | 
				
			|||
            onStateChange, | 
				
			|||
            isQiniu, | 
				
			|||
            isAli, | 
				
			|||
        } = this.props; | 
				
			|||
        const { fileList, curPreviewPic, curPreviewVideo, delPicIng, removeFilesList } = this.state; | 
				
			|||
        const that = this; | 
				
			|||
        let uploadType_ = uploadType || 'project'; | 
				
			|||
        let maxFilesNum_ = maxFilesNum || 1; | 
				
			|||
        let defaultFileTypes = fileTypes || UploadPath[uploadType_]; | 
				
			|||
        // debugger
 | 
				
			|||
        const uploadProps = { | 
				
			|||
            name: 'checkFile_', | 
				
			|||
            multiple: false, | 
				
			|||
            showUploadList: showUploadList || true, | 
				
			|||
            action: | 
				
			|||
                isQiniu ? `/_upload/attachments/${uploadType_}` | 
				
			|||
                    : isAli ? `/_upload/attachments/ali/${uploadType_}` | 
				
			|||
                        : `${this.ApiRoot}/attachments/${uploadType_}`, | 
				
			|||
            listType: listType || 'text', | 
				
			|||
            disabled: disabled, | 
				
			|||
            beforeUpload: (file) => { | 
				
			|||
                if (fileList.length >= maxFilesNum_) { | 
				
			|||
                    message.warning(`最多选择${maxFilesNum_}个文件上传`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                if (file.name.length > 60) { | 
				
			|||
                    message.warning(`文件名过长(大于60字符),请修改后上传`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                const extNames = file.name.split('.'); | 
				
			|||
                // var reg = /^[\.\s\u4e00-\u9fa5a-zA-Z0-9_-]{0,}$/;
 | 
				
			|||
                // if (!reg.exec(file.name)) {
 | 
				
			|||
                //     message.warning(`文件名包含除字母、汉字、数字、中划线、下划线之外的字符,请修改后上传`);
 | 
				
			|||
                //     return false;
 | 
				
			|||
                // }
 | 
				
			|||
                let isDAE = false; | 
				
			|||
                if (extNames.length > 0) { | 
				
			|||
                    let fileType = extNames[extNames.length - 1].toLowerCase(); | 
				
			|||
                    isDAE = defaultFileTypes.some((f) => f == fileType); | 
				
			|||
                } | 
				
			|||
                if (!isDAE) { | 
				
			|||
                    message.error(`只能上传 ${defaultFileTypes.join()} 格式的文件!`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                const isLt = file.size / 1024 / 1024 < (maxFileSize || 3); | 
				
			|||
                if (!isLt) { | 
				
			|||
                    message.error(`文件必须小于${maxFileSize || 3}MB!`); | 
				
			|||
                    return false; | 
				
			|||
                } | 
				
			|||
                this.setState({ | 
				
			|||
                    fileUploading: true | 
				
			|||
                }); | 
				
			|||
                if (onStateChange) { | 
				
			|||
                    onStateChange({ uploading: true }); | 
				
			|||
                } | 
				
			|||
            }, | 
				
			|||
            onChange(info) { | 
				
			|||
                const status = info.file.status; | 
				
			|||
                if (status === 'uploading') { | 
				
			|||
                    that.setState({ | 
				
			|||
                        fileList: info.fileList | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
                if (status === 'done') { | 
				
			|||
                    let { uploaded, url } = info.file.response; | 
				
			|||
                    let size = info.file.size; | 
				
			|||
                    let nextFileList = fileList; | 
				
			|||
                    nextFileList[nextFileList.length - 1] = { | 
				
			|||
                        uid: -moment().unix(), | 
				
			|||
                        name: that.dealName(uploaded), | 
				
			|||
                        status: 'done', | 
				
			|||
                        storageUrl: uploaded, | 
				
			|||
                        url: | 
				
			|||
                            isQiniu ? '/_file-server/' + uploaded : | 
				
			|||
                                isAli ? `/_file-ali-server/${uploaded}` : | 
				
			|||
                                    url, | 
				
			|||
                        size: size | 
				
			|||
                    }; | 
				
			|||
                    onChange(nextFileList); | 
				
			|||
                    that.setState({ | 
				
			|||
                        fileUploading: false, | 
				
			|||
                        fileList: nextFileList | 
				
			|||
                    }); | 
				
			|||
                    if (onStateChange) { | 
				
			|||
                        onStateChange({ uploading: false }); | 
				
			|||
                    } | 
				
			|||
                } else if (status === 'error') { | 
				
			|||
                    that.setState({ | 
				
			|||
                        fileUploading: false | 
				
			|||
                    }); | 
				
			|||
                    message.error(`${info.file.name} 上传失败,请重试`); | 
				
			|||
                    if (onStateChange) { | 
				
			|||
                        onStateChange({ uploading: false }); | 
				
			|||
                    } | 
				
			|||
                } | 
				
			|||
            }, | 
				
			|||
            onRemove(file) { | 
				
			|||
                let nextFileList = []; | 
				
			|||
                fileList.map((f, i) => { | 
				
			|||
                    if (f.uid != file.uid) { | 
				
			|||
                        nextFileList.push(f); | 
				
			|||
                    } | 
				
			|||
                }); | 
				
			|||
                let nextRemoveFiles = removeFilesList.concat([file.storageUrl]); | 
				
			|||
                if (curPreviewPic == file.url) { | 
				
			|||
                    that.setState({ | 
				
			|||
                        curPreviewPic: '' | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
                if (curPreviewVideo == file.url) { | 
				
			|||
                    that.setState({ | 
				
			|||
                        curPreviewVideo: '' | 
				
			|||
                    }); | 
				
			|||
                } | 
				
			|||
                onChange(nextFileList); | 
				
			|||
                that.setState({ | 
				
			|||
                    fileList: nextFileList, | 
				
			|||
                    removeFilesList: nextRemoveFiles | 
				
			|||
                }); | 
				
			|||
            }, | 
				
			|||
            onPreview(file) { | 
				
			|||
                let filePostfix = file.url.split('.').pop(); | 
				
			|||
                filePostfix = filePostfix.toLowerCase(); | 
				
			|||
                if (UploadPath.image.some((img) => img == filePostfix)) { | 
				
			|||
                    that.setState({ | 
				
			|||
                        curPreviewPic: file.url | 
				
			|||
                    }); | 
				
			|||
                } else if (UploadPath.video.some((img) => img == filePostfix)) { | 
				
			|||
                    that.setState({ | 
				
			|||
                        curPreviewVideo: file.url | 
				
			|||
                    }); | 
				
			|||
                } else { | 
				
			|||
                    //message.warn('仅支持图片预览');
 | 
				
			|||
                    preview(file.storageUrl) | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        }; | 
				
			|||
 | 
				
			|||
        const preview = (url) => { | 
				
			|||
            let link = isQiniu ? encodeURI(`${this.qnDomain}/${url}`) : | 
				
			|||
                isAli ? encodeURI(`${this.aliAdmin}/${url}`) : '' | 
				
			|||
            if (link) | 
				
			|||
                if (url.indexOf("pdf") !== -1 || url.indexOf("csv") !== -1) { | 
				
			|||
                    window.open(link) | 
				
			|||
                } else { | 
				
			|||
                    window.open(`https://view.officeapps.live.com/op/view.aspx?src=${link}`) | 
				
			|||
                } | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        let fileList_ = fileList | 
				
			|||
        // .map(f => {
 | 
				
			|||
        //     if (f.storageUrl) {
 | 
				
			|||
        //         let realName = f.storageUrl.split('/').pop()
 | 
				
			|||
        //         if (f.name != realName) {
 | 
				
			|||
        //             f.name = realName
 | 
				
			|||
        //         }
 | 
				
			|||
        //     }
 | 
				
			|||
        //     return f
 | 
				
			|||
        // })
 | 
				
			|||
        //下载文件
 | 
				
			|||
        const handleDownload = (file) => { | 
				
			|||
            saveAs(file) | 
				
			|||
        }; | 
				
			|||
        const saveAs = (file) => { | 
				
			|||
            const link = document.createElement('a'); | 
				
			|||
            link.href = file.url; | 
				
			|||
            link.download = file.name; | 
				
			|||
            link.style.display = 'none'; | 
				
			|||
            link.click(); | 
				
			|||
        } | 
				
			|||
        //自定义下载
 | 
				
			|||
        return ( | 
				
			|||
            <div> | 
				
			|||
                <Spin spinning={delPicIng}> | 
				
			|||
                    <Upload {...uploadProps} fileList={fileList_} showUploadList={{ showDownloadIcon: true }} onDownload={handleDownload}> | 
				
			|||
                        { | 
				
			|||
                            disabled ? ( | 
				
			|||
                                '' | 
				
			|||
                            ) : | 
				
			|||
                                listType == 'picture-card' ? | 
				
			|||
                                    ( | 
				
			|||
                                        fileList.length >= maxFilesNum_ ? null : ( | 
				
			|||
                                            <div style={{}}> | 
				
			|||
                                                <PlusOutlined /> | 
				
			|||
                                                <div>添加附件</div> | 
				
			|||
                                            </div> | 
				
			|||
                                        ) | 
				
			|||
                                    ) : ( | 
				
			|||
                                        <Button disabled={fileList.length >= maxFilesNum_} icon={<UploadOutlined />}>  文件上传 </Button> | 
				
			|||
                                    ) | 
				
			|||
                        } | 
				
			|||
                    </Upload> | 
				
			|||
                    { | 
				
			|||
                        curPreviewPic ? ( | 
				
			|||
                            <Card bodyStyle={{ padding: 8 }}> | 
				
			|||
                                <div style={{ marginBottom: 8 }} > | 
				
			|||
                                    <span>图片预览</span> | 
				
			|||
                                    <span style={{ float: 'right' }} onClick={() => { this.setState({ curPreviewPic: '' }) }}> | 
				
			|||
                                        <CloseOutlined style={{ fontSize: 20 }} /> | 
				
			|||
                                    </span> | 
				
			|||
                                </div> | 
				
			|||
                                <img style={{ width: '100%' }} src={curPreviewPic} /> | 
				
			|||
                            </Card> | 
				
			|||
                        ) : '' | 
				
			|||
                    } | 
				
			|||
                    { | 
				
			|||
                        curPreviewVideo ? (<Card bodyStyle={{ padding: 8 }}> | 
				
			|||
                            <div style={{ marginBottom: 8 }} > | 
				
			|||
                                <span>视频预览</span> | 
				
			|||
                                <span style={{ float: 'right' }} onClick={() => { this.setState({ curPreviewVideo: '' }) }}> | 
				
			|||
                                    <CloseOutlined style={{ fontSize: 20 }} /> | 
				
			|||
                                </span> | 
				
			|||
                            </div> | 
				
			|||
                            <video controls style={{ width: '100%' }}> | 
				
			|||
                                <source src={curPreviewVideo} type="video/mp4"></source> | 
				
			|||
                            </video> | 
				
			|||
                        </Card>) : '' | 
				
			|||
                    } | 
				
			|||
                </Spin> | 
				
			|||
            </div> | 
				
			|||
        ); | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps(state) { | 
				
			|||
    const { auth } = state | 
				
			|||
    return { | 
				
			|||
        user: auth.user | 
				
			|||
    }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(Uploads); | 
				
			|||
@ -1,683 +0,0 @@ | 
				
			|||
/** | 
				
			|||
 * Created by Xumeng 2020/04/22. | 
				
			|||
 */ | 
				
			|||
 | 
				
			|||
import React, { useState, useEffect } from 'react'; | 
				
			|||
import PropTypes from 'prop-types'; | 
				
			|||
import { | 
				
			|||
  Row, Col, Space, Button, message, notification, Form, Input, Tooltip, Menu, Dropdown, | 
				
			|||
} from 'antd'; | 
				
			|||
import moment from 'moment'; | 
				
			|||
import XLSX from 'xlsx'; | 
				
			|||
import { fromJS } from 'immutable'; | 
				
			|||
import { Request } from '@peace/utils'; | 
				
			|||
import FileSaver from 'file-saver'; | 
				
			|||
import './index.less'; | 
				
			|||
 | 
				
			|||
// 通用前端导入导出组件  使用方法查看底部propTypes
 | 
				
			|||
function ExportAndImport(props) { | 
				
			|||
  const [form] = Form.useForm(); | 
				
			|||
  const [exportLoading, setExportLoading] = useState(false); | 
				
			|||
  const [importLoading, setImportLoading] = useState(false); | 
				
			|||
  const { | 
				
			|||
    importDataCallback, onImportSucess, handelData, importMethod = 'post', | 
				
			|||
  } = props; | 
				
			|||
 | 
				
			|||
  useEffect(() => () => { | 
				
			|||
    // 只有unmount 时调用
 | 
				
			|||
    notification.close('import-notification'); | 
				
			|||
  }); | 
				
			|||
  const importExcel = (file, type) => { | 
				
			|||
    setImportLoading(true); | 
				
			|||
    // 获取上传的文件对象
 | 
				
			|||
    const { files } = file.target; | 
				
			|||
    // 判断xls、xlsx格式
 | 
				
			|||
    if (files[0].type.indexOf('sheet') > -1 || files[0].type.indexOf('ms-excel') > -1) { | 
				
			|||
      // 通过FileReader对象读取文件
 | 
				
			|||
      const fileReader = new FileReader(); | 
				
			|||
      fileReader.onload = (event) => { | 
				
			|||
        try { | 
				
			|||
          const { importRequest = true, importUrl, importQuery } = props; | 
				
			|||
          if (importRequest && !importUrl) { | 
				
			|||
            message.error('获取导入接口失败!'); | 
				
			|||
            form.resetFields(); | 
				
			|||
            return; | 
				
			|||
          } | 
				
			|||
          const { result } = event.target; | 
				
			|||
          // 以二进制流方式读取得到整份excel表格对象
 | 
				
			|||
          const workbook = XLSX.read(result, { type: 'binary', cellDates: true }); | 
				
			|||
          let data = []; // 存储获取到的数据
 | 
				
			|||
          // 遍历每张工作表进行读取(这里默认只读取第一张表)
 | 
				
			|||
          for (const sheet in workbook.Sheets) { | 
				
			|||
            if (workbook.Sheets.hasOwnProperty(sheet)) { | 
				
			|||
              // 利用 sheet_to_json 方法将 excel 转成 json 数据
 | 
				
			|||
              data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet])); | 
				
			|||
              break; // 如果只取第一张表,就取消注释这行
 | 
				
			|||
            } | 
				
			|||
          } | 
				
			|||
          if (data.length > 10000) { | 
				
			|||
            message.error('一次最多导入10000条数据,请分批导入!'); | 
				
			|||
            form.resetFields(); | 
				
			|||
            setImportLoading(false); | 
				
			|||
            return; | 
				
			|||
          } | 
				
			|||
          if (importRequest) { | 
				
			|||
            message.success('获取文件数据成功,开始处理导入...'); | 
				
			|||
            const importData = handelData ? handelData(data) : data; | 
				
			|||
            Request[importMethod](importUrl, { data: importData }, importQuery || {}).then((res) => { | 
				
			|||
              message.success('导入数据成功'); | 
				
			|||
              form.resetFields(); | 
				
			|||
              notification.close('import-notification'); | 
				
			|||
              setImportLoading(false); | 
				
			|||
              onImportSucess && onImportSucess(); | 
				
			|||
            }, (err) => { | 
				
			|||
              if (err.status === 500) { | 
				
			|||
                message.error('数据导入出错,导入失败'); | 
				
			|||
              } else if (err.status === 400) { | 
				
			|||
                message.error(err.body.message || '数据验证出错,请检查数据格式是否正确'); | 
				
			|||
              } else { | 
				
			|||
                message.error('导入失败'); | 
				
			|||
              } | 
				
			|||
              form.resetFields(); | 
				
			|||
              setImportLoading(false); | 
				
			|||
            }); | 
				
			|||
          } else { | 
				
			|||
            form.resetFields(); | 
				
			|||
            setImportLoading(false); | 
				
			|||
            importDataCallback && importDataCallback(data, type); | 
				
			|||
            notification.close('import-notification'); | 
				
			|||
          } | 
				
			|||
        } catch (e) { | 
				
			|||
          console.log(e); | 
				
			|||
          // 这里可以抛出文件类型错误不正确的相关提示
 | 
				
			|||
          message.error('文件格式不正确!'); | 
				
			|||
          setImportLoading(false); | 
				
			|||
          form.resetFields(); | 
				
			|||
        } | 
				
			|||
      }; | 
				
			|||
      // fileReader.onloadend = (event) => {
 | 
				
			|||
      //     console.log(event)
 | 
				
			|||
      // }
 | 
				
			|||
      // 以二进制方式打开文件
 | 
				
			|||
      fileReader.readAsBinaryString(files[0]); | 
				
			|||
    } else { | 
				
			|||
      message.error('文件格式不正确!'); | 
				
			|||
      form.resetFields(); | 
				
			|||
      setImportLoading(false); | 
				
			|||
    } | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const loop = (data, keypath, values) => { // deal with array
 | 
				
			|||
    const dkey = keypath.slice(0, 1)[0]; | 
				
			|||
    console.log(dkey); | 
				
			|||
    if (dkey) { | 
				
			|||
      const dvalue = data[dkey]; | 
				
			|||
      const otherKeypath = keypath.slice(1); | 
				
			|||
      if (Array.isArray(dvalue)) { | 
				
			|||
        if (otherKeypath.length) { | 
				
			|||
          const immutableData = fromJS(data); | 
				
			|||
          for (let index = 0; index < dvalue.length; index++) { | 
				
			|||
            const tmp = immutableData.getIn([dkey, index]).toJS(); | 
				
			|||
            loop(tmp, otherKeypath, values); | 
				
			|||
          } | 
				
			|||
        } | 
				
			|||
      } else { | 
				
			|||
        values.push(dvalue); | 
				
			|||
      } | 
				
			|||
    } | 
				
			|||
    return values; | 
				
			|||
  }; | 
				
			|||
  const getColumnData = (opts) => { | 
				
			|||
    const { | 
				
			|||
      data, keypath, render, spliter, rawdata, | 
				
			|||
    } = opts; | 
				
			|||
    let v = null; | 
				
			|||
    const outer = data[keypath[0]]; | 
				
			|||
 | 
				
			|||
    if (Array.isArray(outer)) { | 
				
			|||
      const values = loop(data, keypath, []); | 
				
			|||
      v = rawdata ? values : values.join(spliter || ','); | 
				
			|||
    } else { | 
				
			|||
      v = fromJS(data).getIn(keypath); | 
				
			|||
    } | 
				
			|||
    // 处理render
 | 
				
			|||
    if (render && typeof render === 'function') { | 
				
			|||
      v = render(outer, data); | 
				
			|||
    } | 
				
			|||
    return v; | 
				
			|||
  }; | 
				
			|||
  const getDataSource = (attrs, filterData) => { | 
				
			|||
    // let token = JSON.parse(sessionStorage.getItem('user')).token;
 | 
				
			|||
    const dataSource = filterData.map((item) => { | 
				
			|||
      const record = {}; | 
				
			|||
      attrs.forEach((attr) => { | 
				
			|||
        const { | 
				
			|||
          key, dataIndex, render, child, | 
				
			|||
        } = attr; | 
				
			|||
        if (child) { | 
				
			|||
          record[key] = getDataSource(child, item[key]); | 
				
			|||
        } else { | 
				
			|||
          const v = getColumnData({ | 
				
			|||
            data: item, | 
				
			|||
            keypath: dataIndex || [key], | 
				
			|||
            render: render || null, | 
				
			|||
          }); | 
				
			|||
          record[key] = v; | 
				
			|||
        } | 
				
			|||
      }); | 
				
			|||
 | 
				
			|||
      return record; | 
				
			|||
    }); | 
				
			|||
    return dataSource; | 
				
			|||
  }; | 
				
			|||
  // 暂时只处理两层
 | 
				
			|||
  const getFlatData = (attrs, filterData, dataToAoa, deep = 0) => { | 
				
			|||
    filterData.map((item) => { | 
				
			|||
      let cur = dataToAoa[deep]; | 
				
			|||
      if (!cur) { | 
				
			|||
        cur = dataToAoa[deep] = []; | 
				
			|||
      } | 
				
			|||
      attrs.map((attr, index) => { | 
				
			|||
        const { key, child } = attr; | 
				
			|||
        if (child) { | 
				
			|||
          if (Array.isArray(item[key])) { | 
				
			|||
            // getFlatData(child,item[key],dataToAoa,deep)
 | 
				
			|||
 | 
				
			|||
            item[key].map((s, i) => { | 
				
			|||
              if (i == 0) { | 
				
			|||
                child.map((c) => { | 
				
			|||
                  cur.push(s[c.key]); | 
				
			|||
                }); | 
				
			|||
              } else { | 
				
			|||
                deep++; | 
				
			|||
                const childCur = dataToAoa[deep] = []; | 
				
			|||
                pushNull(childCur, index); | 
				
			|||
                child.map((c) => { | 
				
			|||
                  childCur.push(s[c.key]); | 
				
			|||
                }); | 
				
			|||
              } | 
				
			|||
            }); | 
				
			|||
          } | 
				
			|||
        } else { | 
				
			|||
          cur.push(item[key]); | 
				
			|||
        } | 
				
			|||
      }); | 
				
			|||
      deep++; | 
				
			|||
    }); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const getHeader = (headers, excelHeader, deep, perOffset) => { | 
				
			|||
    let offset = 0; | 
				
			|||
    let cur = excelHeader[deep]; | 
				
			|||
    if (!cur) { | 
				
			|||
      cur = excelHeader[deep] = []; | 
				
			|||
    } | 
				
			|||
    pushNull(cur, perOffset - cur.length); | 
				
			|||
    for (let i = 0; i < headers.length; i++) { | 
				
			|||
      const head = headers[i]; | 
				
			|||
      cur.push(head.name); | 
				
			|||
      if (head.hasOwnProperty('child') && Array.isArray(head.child) && head.child.length > 0) { | 
				
			|||
        const childOffset = getHeader(head.child, excelHeader, deep + 1, cur.length - 1); | 
				
			|||
        pushNull(cur, childOffset - 1); | 
				
			|||
        offset += childOffset; | 
				
			|||
      } else { | 
				
			|||
        offset++; | 
				
			|||
      } | 
				
			|||
    } | 
				
			|||
    return offset; | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const pushNull = (arr, count) => { | 
				
			|||
    for (let i = 0; i < count; i++) { | 
				
			|||
      arr.push(null); | 
				
			|||
    } | 
				
			|||
  }; | 
				
			|||
  const fillNull = (arr) => { | 
				
			|||
    const max = Math.max(...(arr.map((a) => a.length))); | 
				
			|||
    arr.filter((e) => e.length < max).forEach((e) => pushNull(e, max - e.length)); | 
				
			|||
  }; | 
				
			|||
  const doMerges = (arr) => { | 
				
			|||
    // 要么横向合并 要么纵向合并
 | 
				
			|||
    const deep = arr.length; | 
				
			|||
    const merges = []; | 
				
			|||
    for (let y = 0; y < deep; y++) { | 
				
			|||
      // 先处理横向合并
 | 
				
			|||
      const row = arr[y]; | 
				
			|||
      let colSpan = 0; | 
				
			|||
      for (let x = 0; x < row.length; x++) { | 
				
			|||
        if (row[x] === null) { | 
				
			|||
          colSpan++; | 
				
			|||
          if (((x + 1) === row.length) && (colSpan > 0 && x > colSpan)) { | 
				
			|||
            merges.push({ s: { r: y, c: x - colSpan }, e: { r: y, c: x } }); | 
				
			|||
          } | 
				
			|||
        } else if (colSpan > 0 && x > colSpan) { | 
				
			|||
          merges.push({ s: { r: y, c: x - colSpan - 1 }, e: { r: y, c: x - 1 } }); | 
				
			|||
          colSpan = 0; | 
				
			|||
        } else { | 
				
			|||
          colSpan = 0; | 
				
			|||
        } | 
				
			|||
      } | 
				
			|||
    } | 
				
			|||
    // 再处理纵向合并
 | 
				
			|||
    const colLength = arr[0].length; | 
				
			|||
    for (let x = 0; x < colLength; x++) { | 
				
			|||
      let rowSpan = 0; | 
				
			|||
      for (let y = 0; y < deep; y++) { | 
				
			|||
        if (arr[y][x] != null) { | 
				
			|||
          rowSpan = 0; | 
				
			|||
        } else { | 
				
			|||
          rowSpan++; | 
				
			|||
        } | 
				
			|||
      } | 
				
			|||
      if (rowSpan > 0) { | 
				
			|||
        merges.push({ s: { r: deep - rowSpan - 1, c: x }, e: { r: deep - 1, c: x } }); | 
				
			|||
      } | 
				
			|||
    } | 
				
			|||
    return merges; | 
				
			|||
  }; | 
				
			|||
  // 内容暂只出了纵向合并
 | 
				
			|||
  const doContetMerges = (arr, headerLength) => { | 
				
			|||
    const deep = arr.length; | 
				
			|||
    const merges = []; | 
				
			|||
    // 处理纵向合并
 | 
				
			|||
    const colLength = arr[0].length; | 
				
			|||
    for (let x = 0; x < colLength; x++) { | 
				
			|||
      let rowSpan = 0; | 
				
			|||
      const mergY = 0; | 
				
			|||
      for (let y = 0; y < deep; y++) { | 
				
			|||
        if (rowSpan > 0) { | 
				
			|||
          // 如果还有null 继续加
 | 
				
			|||
          if (arr[y][x] === null) { | 
				
			|||
            rowSpan += 1; | 
				
			|||
          } else { | 
				
			|||
            // 不为null 增加merge
 | 
				
			|||
            merges.push({ s: { r: headerLength + (y - rowSpan - 1), c: x }, e: { r: headerLength + y - 1, c: x } }); | 
				
			|||
            rowSpan = 0; | 
				
			|||
          } | 
				
			|||
        } else if (arr[y][x] === null) { | 
				
			|||
          rowSpan += 1; | 
				
			|||
        } | 
				
			|||
      } | 
				
			|||
      if (rowSpan > 0) { | 
				
			|||
        merges.push({ s: { r: headerLength + (deep - rowSpan - 1), c: x }, e: { r: headerLength + deep - 1, c: x } }); | 
				
			|||
        rowSpan = 0; | 
				
			|||
      } | 
				
			|||
    } | 
				
			|||
    return merges; | 
				
			|||
  }; | 
				
			|||
  const exportMergeExcel = async () => { | 
				
			|||
    setExportLoading(true); | 
				
			|||
    const { | 
				
			|||
      column, data, fileName, exportUrl, exportQuery, exportBody, requestType, header, showYearMouth, | 
				
			|||
    } = props || {}; | 
				
			|||
 | 
				
			|||
    let resultData = []; | 
				
			|||
    if (exportUrl) { | 
				
			|||
      resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { | 
				
			|||
        // 数据接口返回的结果 如果是对象 必须把返回数组放入rows
 | 
				
			|||
        if (typeof data === 'object' && data.rows) { | 
				
			|||
          return data.rows; | 
				
			|||
        } | 
				
			|||
        return data; | 
				
			|||
      }, (err) => { | 
				
			|||
        message.error('获取数据失败,导出失败!'); | 
				
			|||
      }) : await Request.get(exportUrl, exportQuery || {}).then((data) => { | 
				
			|||
        if (typeof data === 'object' && data.rows) { | 
				
			|||
          return data.rows; | 
				
			|||
        } | 
				
			|||
        return data; | 
				
			|||
      }, (err) => { | 
				
			|||
        message.error('获取数据失败,导出失败!'); | 
				
			|||
      }); | 
				
			|||
      if (!resultData) { | 
				
			|||
        return; | 
				
			|||
      } | 
				
			|||
    } else { | 
				
			|||
      resultData = data; | 
				
			|||
    } | 
				
			|||
    const excelHeader = []; | 
				
			|||
    getHeader(column, excelHeader, 0, 0); | 
				
			|||
    fillNull(excelHeader); | 
				
			|||
 | 
				
			|||
    // console.log(excelHeader);
 | 
				
			|||
 | 
				
			|||
    const loopData = getDataSource(column, resultData); | 
				
			|||
    // console.log(loopData)
 | 
				
			|||
 | 
				
			|||
    const dataToAoa = []; | 
				
			|||
    getFlatData(column, loopData, dataToAoa, 0); | 
				
			|||
    fillNull(dataToAoa); | 
				
			|||
    // console.log(dataToAoa);
 | 
				
			|||
 | 
				
			|||
    const aoa = [].concat(excelHeader, dataToAoa); | 
				
			|||
    // console.log(aoa)
 | 
				
			|||
 | 
				
			|||
    const headerMerges = doMerges(excelHeader); | 
				
			|||
    const contentMerages = doContetMerges(dataToAoa, excelHeader.length); | 
				
			|||
    const merges = [].concat(headerMerges, contentMerages); | 
				
			|||
    // console.log(contentMerages)
 | 
				
			|||
 | 
				
			|||
    // let opts = {
 | 
				
			|||
    //     defaultCellStyle: {
 | 
				
			|||
    //         font: { name: "宋体", sz: 11, color: { auto: 1 } },
 | 
				
			|||
    //         border: {
 | 
				
			|||
    //             color: { auto: 1 }
 | 
				
			|||
    //         },
 | 
				
			|||
    //         alignment: {
 | 
				
			|||
    //             /// 自动换行
 | 
				
			|||
    //             wrapText: 1,
 | 
				
			|||
    //             // 居中
 | 
				
			|||
    //             horizontal: "center",
 | 
				
			|||
    //             vertical: "center",
 | 
				
			|||
    //             indent: 0
 | 
				
			|||
    //         }
 | 
				
			|||
    //    }
 | 
				
			|||
    // }
 | 
				
			|||
    const sheet = XLSX.utils.aoa_to_sheet(aoa); | 
				
			|||
    // let newSheet = {};
 | 
				
			|||
    // for (let [key, value] of Object.entries(sheet)) {
 | 
				
			|||
    //     if(key == '!ref'){
 | 
				
			|||
    //         newSheet[key] = value
 | 
				
			|||
    //     }else if(typeof value === 'object'){
 | 
				
			|||
    //         newSheet[key] = {
 | 
				
			|||
    //             ...value,
 | 
				
			|||
    //             s: opts.defaultCellStyle
 | 
				
			|||
    //         }
 | 
				
			|||
    //     }
 | 
				
			|||
    // }
 | 
				
			|||
    const wpx = column.map((c) => ({ | 
				
			|||
      wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, | 
				
			|||
    })); | 
				
			|||
    sheet['!cols'] = wpx; | 
				
			|||
    sheet['!merges'] = merges; | 
				
			|||
 | 
				
			|||
    // 构建 workbook 对象
 | 
				
			|||
    const workbook = XLSX.utils.book_new(); | 
				
			|||
 | 
				
			|||
    const time = moment().format('YYYY-MM-DD'); | 
				
			|||
 | 
				
			|||
    XLSX.utils.book_append_sheet(workbook, sheet, 'mySheet'); | 
				
			|||
    // 导出 Excel
 | 
				
			|||
    XLSX.writeFile(workbook, fileName ? `${fileName}-${time}.xlsx` : '导出数据.xlsx'); | 
				
			|||
    setExportLoading(false); | 
				
			|||
    // message.success(`成功导出了 ${loopData.length || 0} 条数据`);
 | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const exportProExcel = async () => { | 
				
			|||
    setExportLoading(true); | 
				
			|||
    const { | 
				
			|||
      column, data, fileName, exportUrl, exportQuery, exportBody, requestType, showYearMouth, | 
				
			|||
    } = props || {}; | 
				
			|||
    let resultData = []; | 
				
			|||
    if (exportUrl) { | 
				
			|||
      resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { | 
				
			|||
        // 数据接口返回的结果 如果是对象 必须把返回数组放入rows
 | 
				
			|||
        if (typeof data === 'object') { | 
				
			|||
          return data.data ? data.data : data.rows; | 
				
			|||
        } | 
				
			|||
        return data; | 
				
			|||
      }, (err) => { | 
				
			|||
        message.error('获取数据失败,导出失败!'); | 
				
			|||
      }) : await Request.get(exportUrl, exportQuery || {}).then((data) => { | 
				
			|||
        if (showYearMouth) { | 
				
			|||
 | 
				
			|||
        } | 
				
			|||
        if (typeof data === 'object' && data.rows) { | 
				
			|||
          return data.rows; | 
				
			|||
        } | 
				
			|||
        return data; | 
				
			|||
      }, (err) => { | 
				
			|||
        message.error('获取数据失败,导出失败!'); | 
				
			|||
      }); | 
				
			|||
      if (!resultData) { | 
				
			|||
        return; | 
				
			|||
      } | 
				
			|||
    } else { | 
				
			|||
      resultData = data; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    const loopData = getDataSource(column, resultData); | 
				
			|||
 | 
				
			|||
    let content = ''; | 
				
			|||
    let header = '<tr>'; | 
				
			|||
    // header += `<th><div>序号</div></th>`;
 | 
				
			|||
    column.map((colum) => { | 
				
			|||
      header += `<th><div>${colum.name}</div></th>`; | 
				
			|||
    }); | 
				
			|||
    header += '</tr>'; | 
				
			|||
    loopData.map((data) => { | 
				
			|||
      content += '<tr>'; | 
				
			|||
      column.map((c) => { | 
				
			|||
        if (c.style) { | 
				
			|||
          content += `<th style="${c.style}"><div>${data[c.dataIndex || c.key]}</div></th>`; | 
				
			|||
        } else { | 
				
			|||
          content += `<th><div>${data[c.dataIndex || c.key]}</div></th>`; | 
				
			|||
        } | 
				
			|||
      }); | 
				
			|||
      content += '</tr>'; | 
				
			|||
    }); | 
				
			|||
 | 
				
			|||
    const exportTable = `\uFEFF
 | 
				
			|||
                <table style='text-alagin:center' border="1"> | 
				
			|||
                    ${header} | 
				
			|||
                    ${content} | 
				
			|||
                </table> | 
				
			|||
            `;
 | 
				
			|||
    const time = moment().format('YYYY-MM-DD'); | 
				
			|||
    const tempStrs = new Blob([exportTable], { type: 'text/xls' }); | 
				
			|||
    FileSaver.saveAs(tempStrs, fileName ? `${fileName}-${time}.xls` : '导出数据.xls'); | 
				
			|||
    setExportLoading(false); | 
				
			|||
    // message.success(`成功导出了 ${loopData.length || 0} 条数据`);
 | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const exportExcel = async () => { | 
				
			|||
    setExportLoading(true); | 
				
			|||
    const { | 
				
			|||
      column, data, fileName, exportUrl, exportQuery, exportBody, requestType, | 
				
			|||
    } = props || {}; | 
				
			|||
    const _headers = column | 
				
			|||
      .map((item, i) => ({ key: item.key, title: item.name, position: String.fromCharCode(65 + i) + 1 })) | 
				
			|||
      .reduce((prev, next) => ({ ...prev, [next.position]: { key: next.key, v: next.title } }), {}); | 
				
			|||
    let resultData = []; | 
				
			|||
    if (exportUrl) { | 
				
			|||
      resultData = requestType == 'post' ? await Request.post(exportUrl, exportBody || {}, exportQuery || {}).then((data) => { | 
				
			|||
        // 数据接口返回的结果 如果是对象 必须把返回数组放入rows
 | 
				
			|||
 | 
				
			|||
        if (typeof data === 'object' && (data.rows || data.data)) { | 
				
			|||
          return data.data ? data.data : data.rows; | 
				
			|||
        } | 
				
			|||
        return data; | 
				
			|||
      }, (err) => { | 
				
			|||
        message.error('获取数据失败,导出失败!'); | 
				
			|||
      }) : await Request.get(exportUrl, exportQuery || {}).then((data) => { | 
				
			|||
        if (typeof data === 'object' && data.rows) { | 
				
			|||
          return data.rows; | 
				
			|||
        } | 
				
			|||
        return data; | 
				
			|||
      }, (err) => { | 
				
			|||
        message.error('获取数据失败,导出失败!'); | 
				
			|||
      }); | 
				
			|||
      if (!resultData) { | 
				
			|||
        return; | 
				
			|||
      } | 
				
			|||
    } else { | 
				
			|||
      resultData = data; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    const loopDate = getDataSource(column, resultData); | 
				
			|||
 | 
				
			|||
    const wpx = column.map((c) => ({ | 
				
			|||
      wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, | 
				
			|||
    })); | 
				
			|||
    if (!(loopDate.length > 0)) { | 
				
			|||
      setExportLoading(false); | 
				
			|||
      return; | 
				
			|||
    } | 
				
			|||
    const _data = loopDate | 
				
			|||
      .map((item, i) => column.map((key, j) => ({ content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) }))) | 
				
			|||
      // 对刚才的结果进行降维处理(二维数组变成一维数组)
 | 
				
			|||
      .reduce((prev, next) => prev.concat(next)) | 
				
			|||
      // 转换成 worksheet 需要的结构
 | 
				
			|||
      .reduce((prev, next) => ({ ...prev, [next.position]: { v: next.content } }), {}); | 
				
			|||
 | 
				
			|||
    // 合并 column 和 data
 | 
				
			|||
    const output = { ..._headers, ..._data }; | 
				
			|||
    // 获取所有单元格的位置
 | 
				
			|||
    const outputPos = Object.keys(output); | 
				
			|||
    // 计算出范围 ,["A1",..., "H2"]
 | 
				
			|||
    const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`; | 
				
			|||
 | 
				
			|||
    // 构建 workbook 对象
 | 
				
			|||
    const workbook = { | 
				
			|||
      SheetNames: ['mySheet'], | 
				
			|||
      Sheets: { | 
				
			|||
        mySheet: { | 
				
			|||
 | 
				
			|||
          ...output, | 
				
			|||
          '!ref': ref, | 
				
			|||
          '!cols': wpx, | 
				
			|||
        }, | 
				
			|||
      }, | 
				
			|||
    }; | 
				
			|||
    const time = moment().format('YYYY-MM-DD'); | 
				
			|||
    // 导出 Excel
 | 
				
			|||
    XLSX.writeFile(workbook, fileName ? `${fileName}-${time}.xlsx` : '导出数据.xlsx'); | 
				
			|||
    setExportLoading(false); | 
				
			|||
    // message.success(`成功导出了 ${loopDate.length || 0} 条数据`);
 | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  const exportTemplete = async () => { | 
				
			|||
    const { importTemColumn, importTemData, fileName } = props || {}; | 
				
			|||
    const _headers = importTemColumn | 
				
			|||
      .map((item, i) => { | 
				
			|||
        let group = 0; // 用于处理Z1的时候,重计算AA1
 | 
				
			|||
        if (parseInt(i / 26) > group) { | 
				
			|||
          group = parseInt(i / 26); | 
				
			|||
        } | 
				
			|||
        if (group > 0) { // AA1 BA1 CA1
 | 
				
			|||
          const position = String.fromCharCode(65 + (group - 1)); | 
				
			|||
          return { key: item.key, title: item.name, position: position + String.fromCharCode(65 + (i % 26)) + 1 }; | 
				
			|||
        } return { key: item.key, title: item.name, position: String.fromCharCode(65 + i) + 1 }; | 
				
			|||
      }) | 
				
			|||
      .reduce((prev, next) => ({ ...prev, [next.position]: { key: next.key, v: next.title } }), {}); | 
				
			|||
 | 
				
			|||
    const loopDate = getDataSource(importTemColumn, importTemData); | 
				
			|||
 | 
				
			|||
    const wpx = importTemColumn.map((c) => ({ | 
				
			|||
      wpx: Number.parseInt(c.wpx) ? Number.parseInt(c.wpx) : 100, | 
				
			|||
    })); | 
				
			|||
    const _data = loopDate.length ? loopDate | 
				
			|||
      .map((item, i) => importTemColumn.map((key, j) => ({ content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) }))) | 
				
			|||
      // 对刚才的结果进行降维处理(二维数组变成一维数组)
 | 
				
			|||
      .reduce((prev, next) => prev.concat(next)) | 
				
			|||
      // 转换成 worksheet 需要的结构
 | 
				
			|||
      .reduce((prev, next) => ({ ...prev, [next.position]: { v: next.content } }), {}) : []; | 
				
			|||
    // 合并 column 和 data
 | 
				
			|||
    const output = { ..._headers, ..._data }; | 
				
			|||
    // 获取所有单元格的位置
 | 
				
			|||
    const outputPos = Object.keys(output); | 
				
			|||
    // 计算出范围 ,["A1",..., "H2"]
 | 
				
			|||
    const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`; | 
				
			|||
 | 
				
			|||
    // 构建 workbook 对象
 | 
				
			|||
    const workbook = { | 
				
			|||
      SheetNames: ['mySheet'], | 
				
			|||
      Sheets: { | 
				
			|||
        mySheet: { | 
				
			|||
 | 
				
			|||
          ...output, | 
				
			|||
          '!ref': ref, | 
				
			|||
          '!cols': wpx, | 
				
			|||
        }, | 
				
			|||
      }, | 
				
			|||
    }; | 
				
			|||
    // 导出 Excel
 | 
				
			|||
    XLSX.writeFile(workbook, fileName ? `${fileName}-导入模板.xlsx` : '导入模板.xlsx'); | 
				
			|||
  }; | 
				
			|||
  const tips = (type) => { | 
				
			|||
    const { tips, templeteBth = true } = props; | 
				
			|||
    const description = ( | 
				
			|||
      <div className="export-import"> | 
				
			|||
        {tips && tips} | 
				
			|||
        <Row gutter={16}> | 
				
			|||
          <Col span={12}> | 
				
			|||
            <Form form={form} initialValues={{}}> | 
				
			|||
              <Form.Item name="import-file"> | 
				
			|||
                <Input className="file-uploader" type="file" accept=".xlsx, .xls" onChange={(e) => importExcel(e, type)} /> | 
				
			|||
                <Button style={props.btnStyle} className={props.btnClass} loading={importLoading}> | 
				
			|||
                  选择文件 | 
				
			|||
                </Button> | 
				
			|||
              </Form.Item> | 
				
			|||
            </Form> | 
				
			|||
          </Col> | 
				
			|||
          {templeteBth && ( | 
				
			|||
            <Col span={12}> | 
				
			|||
              <Button style={props.btnStyle} className={props.btnClass} onClick={exportTemplete}> | 
				
			|||
                模板下载 | 
				
			|||
              </Button> | 
				
			|||
            </Col> | 
				
			|||
          )} | 
				
			|||
        </Row> | 
				
			|||
      </div> | 
				
			|||
    ); | 
				
			|||
 | 
				
			|||
    notification.info({ | 
				
			|||
      message: '支持 .xlsx、.xls 格式的文件', | 
				
			|||
      description, | 
				
			|||
      key: 'import-notification', | 
				
			|||
      duration: null, | 
				
			|||
    }); | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  return ( | 
				
			|||
    <Space> | 
				
			|||
      { | 
				
			|||
        props.import && ( | 
				
			|||
          <Button style={props.btnStyle} className={props.btnClass} loading={importLoading} onClick={tips}> | 
				
			|||
            {props.importBtnName || '导入'} | 
				
			|||
          </Button> | 
				
			|||
        ) | 
				
			|||
      } | 
				
			|||
      { | 
				
			|||
        props.export && ( | 
				
			|||
          <Tooltip placement="top" title={props.exportBtnTips || '默认导出所有数据'}> | 
				
			|||
            <Button style={props.btnStyle} className={props.btnClass} loading={exportLoading} onClick={props.exportType === 'pro' ? exportProExcel : exportExcel}> | 
				
			|||
              {props.exportBtnName || '导出'} | 
				
			|||
            </Button> | 
				
			|||
          </Tooltip> | 
				
			|||
        ) | 
				
			|||
      } | 
				
			|||
    </Space> | 
				
			|||
  ); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
ExportAndImport.propTypes = { | 
				
			|||
  export: PropTypes.bool, // 是否显示导出按钮
 | 
				
			|||
  exportBtnName: PropTypes.string, // 导出按钮文字
 | 
				
			|||
  importBtnName: PropTypes.string, // 导入按钮文字
 | 
				
			|||
  import: PropTypes.bool, // 是否显示导入按钮
 | 
				
			|||
  variedImport: PropTypes.bool, // 是否显示多样导入
 | 
				
			|||
  variedImportDisable: PropTypes.bool, // 多样导入禁用
 | 
				
			|||
  variedImportBtnName: PropTypes.string, // 多样导入文字
 | 
				
			|||
  column: PropTypes.array, // 导出显示的header数组 兼容antd column 可直接拿table的column使用  注:column每列的属性wpx设置导出的execl每列的宽度值 默认 100
 | 
				
			|||
  data: PropTypes.array, // 导出的数据 兼容antd table 数组嵌套处理
 | 
				
			|||
  exportUrl: PropTypes.string, // 导出数据从接口获取的url地址   返回的数据1、数组必须支持column的设置 ,2、如果是对象,数组需放在rows属性上
 | 
				
			|||
  exportBody: PropTypes.object, // 导出数据接口body参数
 | 
				
			|||
  exportQuery: PropTypes.object, // 导出数据从接口获取的url地址上的参数
 | 
				
			|||
  exportBtnTips: PropTypes.string, // 导出按钮tips文字提示
 | 
				
			|||
  importUrl: PropTypes.string, // 导入接口url
 | 
				
			|||
  importQuery: PropTypes.object, // 导入接口url地址上的参数
 | 
				
			|||
  btnClass: PropTypes.string, // 按钮className
 | 
				
			|||
  btnStyle: PropTypes.object, // 按钮style
 | 
				
			|||
  tips: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), // 上传文件提示的信息
 | 
				
			|||
  onImportSucess: PropTypes.func, // 上传成功后 返回处理函数
 | 
				
			|||
  importTemColumn: PropTypes.array, // 导入模板设置 头部字段数组
 | 
				
			|||
  importTemData: PropTypes.array, // 导入模板默认数据
 | 
				
			|||
  requestType: PropTypes.string, // 请求类型
 | 
				
			|||
  importDataCallback: PropTypes.func, // 上传后数据返回
 | 
				
			|||
  templeteBth: PropTypes.bool, // 模板按钮
 | 
				
			|||
  importRequest: PropTypes.bool, // 请求导入接口,false时搭配importDataCallback,
 | 
				
			|||
  exportType: PropTypes.string, // 导出执行的函数名
 | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
export default ExportAndImport; | 
				
			|||
@ -1,13 +0,0 @@ | 
				
			|||
.export-import { | 
				
			|||
    .file-uploader { | 
				
			|||
      position: absolute; | 
				
			|||
      width: 100%; | 
				
			|||
      height: 100%; | 
				
			|||
      top: 0; | 
				
			|||
      left: 0; | 
				
			|||
      outline: none; | 
				
			|||
      opacity: 0; | 
				
			|||
      background-color: transparent; | 
				
			|||
      z-index: 10; | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
@ -1,74 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
import React, { Component } from 'react'; | 
				
			|||
import { Table } from 'antd'; | 
				
			|||
import './index.less'; | 
				
			|||
import moment from 'moment'; | 
				
			|||
 | 
				
			|||
class FlowRecordTable extends Component { | 
				
			|||
    constructor(props) { | 
				
			|||
        super(props); | 
				
			|||
        this.state = { | 
				
			|||
            isRequesting: false, | 
				
			|||
            pagination: { | 
				
			|||
                showTotal: total => `共${total}条`, | 
				
			|||
                responsive: true, | 
				
			|||
                defaultPageSize: 10, | 
				
			|||
            }, | 
				
			|||
            data: [] | 
				
			|||
        } | 
				
			|||
        this.token = JSON.parse(sessionStorage.getItem('user')).token; | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
 | 
				
			|||
    getPagination = () => { | 
				
			|||
        const { pagination, data } = this.state; | 
				
			|||
        const { actiPage } = this.props; | 
				
			|||
        pagination.total = data.length > 0 ? data.length : 0; | 
				
			|||
        pagination.current = actiPage; | 
				
			|||
        return pagination; | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    onTableChange = (pagination, filters, sorter) => { | 
				
			|||
        this.props.onPageChange(pagination.current) | 
				
			|||
    } | 
				
			|||
    componentDidMount() { | 
				
			|||
    } | 
				
			|||
    render() { | 
				
			|||
        const { flowRecord } = this.props; | 
				
			|||
        const tableColumnAttrs = [ | 
				
			|||
            { | 
				
			|||
                title: '序号', | 
				
			|||
                dataIndex: 'id', | 
				
			|||
                width: '12%', | 
				
			|||
                render: (text, record, index) => { return index + 1 } | 
				
			|||
            }, | 
				
			|||
            { | 
				
			|||
                title: '操作人', | 
				
			|||
                dataIndex: 'processBy', | 
				
			|||
                width: '25%', | 
				
			|||
            }, | 
				
			|||
            { | 
				
			|||
                title: '操作时间', | 
				
			|||
                dataIndex: 'processAt', | 
				
			|||
                width: '25%', | 
				
			|||
                render: (text, record, index) => { return moment(text).format('YYYY-MM-DD HH:mm') } | 
				
			|||
            }, { | 
				
			|||
                title: '操作内容', | 
				
			|||
                dataIndex: 'processContent', | 
				
			|||
                width: '38%', | 
				
			|||
            }, | 
				
			|||
        ]; | 
				
			|||
        return ( | 
				
			|||
            <Table | 
				
			|||
                rowKey="id" | 
				
			|||
                className={'fs-table'} | 
				
			|||
                dataSource={flowRecord} | 
				
			|||
                columns={tableColumnAttrs} | 
				
			|||
                onChange={this.onTableChange} | 
				
			|||
                pagination={this.getPagination()} | 
				
			|||
            /> | 
				
			|||
        ); | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default FlowRecordTable; | 
				
			|||
@ -1,27 +1,10 @@ | 
				
			|||
 | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import Upload from './Upload'; | 
				
			|||
import Uploads from './Uploads'; | 
				
			|||
import NoResource from './no-resource'; | 
				
			|||
import LimitTextArea from './limit-textarea'; | 
				
			|||
// import ProcessForm from './process_form'
 | 
				
			|||
import FlowRecordTable from './flowRecordTable' | 
				
			|||
import Table from './table' | 
				
			|||
import Search from './search' | 
				
			|||
import SketchColor from './sketchColor' | 
				
			|||
import ExportAndImport from './export' | 
				
			|||
// import Upload from './Upload';
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
export { | 
				
			|||
    Upload, | 
				
			|||
    Uploads, | 
				
			|||
    NoResource, | 
				
			|||
    LimitTextArea, | 
				
			|||
   //  ProcessForm,
 | 
				
			|||
    FlowRecordTable, | 
				
			|||
    Table, | 
				
			|||
    Search, | 
				
			|||
    SketchColor, | 
				
			|||
    ExportAndImport, | 
				
			|||
    | 
				
			|||
    | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
@ -1,70 +0,0 @@ | 
				
			|||
import React, { PureComponent } from 'react'; | 
				
			|||
import { Input } from 'antd'; | 
				
			|||
const { TextArea } = Input; | 
				
			|||
import './index.less'; | 
				
			|||
 | 
				
			|||
/*** | 
				
			|||
 * 显示最大输入字符数 | 
				
			|||
 * maxLength:300(默认) | 
				
			|||
 */ | 
				
			|||
class LimitTextArea extends PureComponent { | 
				
			|||
 | 
				
			|||
  constructor(props) { | 
				
			|||
    super(props) | 
				
			|||
    this.state = { | 
				
			|||
      len: 0, | 
				
			|||
      maxLength: 300, | 
				
			|||
      isvalid: true, // 是否显示最大字符数
 | 
				
			|||
    } | 
				
			|||
    // 若需要覆盖onChange时,value必填
 | 
				
			|||
    if (props.onChange && !props.hasOwnProperty('value')) { | 
				
			|||
      this.state.isvalid = false | 
				
			|||
      console.warn('LimitTextArea:绑定onChange时,value属性必填,否则显示最大输入字符数将失效!') | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  // 若外部定义了onChange事件,handleChange将会被覆盖
 | 
				
			|||
  handleChange = (e) => { | 
				
			|||
    const { sep } = this.props | 
				
			|||
    const val = e.target.value | 
				
			|||
    const arr = (val || '').split(sep) | 
				
			|||
    this.setState({ | 
				
			|||
      len: arr.length | 
				
			|||
    }) | 
				
			|||
  } | 
				
			|||
 | 
				
			|||
  render () { | 
				
			|||
    const { maxLength: defaultMax, isvalid } = this.state | 
				
			|||
    const { sep, maxLength, value, ...restProps } = this.props | 
				
			|||
    const max = maxLength > 0 ? maxLength : defaultMax | 
				
			|||
    /** form组件中,value有值 */ | 
				
			|||
    const arr = (value || '').split(sep) | 
				
			|||
    let len = value ? arr.length : this.state.len | 
				
			|||
    len = len > max ? max : len | 
				
			|||
    /**截取最大字符串 */ | 
				
			|||
    const val = arr.slice(0, len).join(sep) | 
				
			|||
    const n = val ? len : 0 | 
				
			|||
    const suffix = `${n}/${max}` | 
				
			|||
 | 
				
			|||
    return isvalid ? ( | 
				
			|||
      <div className={'block'}> | 
				
			|||
        <TextArea  | 
				
			|||
          onChange={ e => this.handleChange(e) }  | 
				
			|||
          value={val} | 
				
			|||
          { ...restProps } | 
				
			|||
        /> | 
				
			|||
        <span className={'counter'}>{suffix}</span> | 
				
			|||
      </div> | 
				
			|||
    ) : <TextArea { ...this.props } /> | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
LimitTextArea.defaultProps = { | 
				
			|||
  /** 分割符 | 
				
			|||
   * 可以是个字符串,如:'\n' | 
				
			|||
   * 也可以是个正则表达式,如:/\n\r/ | 
				
			|||
   */ | 
				
			|||
  sep: '' | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default LimitTextArea; | 
				
			|||
@ -1,10 +0,0 @@ | 
				
			|||
.block { | 
				
			|||
    position: relative; | 
				
			|||
    .counter { | 
				
			|||
      position: absolute; | 
				
			|||
      bottom: 5px; | 
				
			|||
      right: 15px; | 
				
			|||
      color: #adadad; | 
				
			|||
      z-index: 2; | 
				
			|||
    } | 
				
			|||
  } | 
				
			|||
@ -1,21 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import React from 'react'; | 
				
			|||
import { Result} from 'antd'; | 
				
			|||
import { MehOutlined } from '@ant-design/icons'; | 
				
			|||
class NoResource extends React.Component { | 
				
			|||
    constructor(props) { | 
				
			|||
        super(props); | 
				
			|||
    } | 
				
			|||
    render() { | 
				
			|||
        const title = this.props.title ? this.props.title : "抱歉,没有可访问的资源!" | 
				
			|||
        return ( | 
				
			|||
            <Result | 
				
			|||
            icon={<MehOutlined />} | 
				
			|||
            title={title} | 
				
			|||
            /> | 
				
			|||
        ); | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default NoResource; | 
				
			|||
@ -1,217 +0,0 @@ | 
				
			|||
/** | 
				
			|||
 * Created by Xumeng 2020/04/01. | 
				
			|||
 */ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import React, { useState } from 'react'; | 
				
			|||
import PropTypes from 'prop-types'; | 
				
			|||
import { Space, Row, Col, Form, DatePicker, Input, Select, Button } from 'antd'; | 
				
			|||
import { DownOutlined, UpOutlined } from '@ant-design/icons'; | 
				
			|||
//import { fromJS } from 'immutable';
 | 
				
			|||
import { Constans } from '$utils'; | 
				
			|||
import moment from 'moment'; | 
				
			|||
import './index.less'; | 
				
			|||
const FormItem = Form.Item; | 
				
			|||
const { RangePicker } = DatePicker; | 
				
			|||
 | 
				
			|||
//通用搜索栏组件  使用方法查看底部propTypes
 | 
				
			|||
 | 
				
			|||
const Search = (props) => { | 
				
			|||
    const [expand, setExpand] = useState(false); | 
				
			|||
    const [form] = Form.useForm(); | 
				
			|||
    const { colSpan } = props; | 
				
			|||
    //初始化表单数据
 | 
				
			|||
    const getinitialValues = () => { | 
				
			|||
        const { formList } = props; | 
				
			|||
        let obj = {}; | 
				
			|||
        formList.forEach((v) => { | 
				
			|||
            const { field, initialValue } = v; | 
				
			|||
            if (initialValue) { | 
				
			|||
                obj[field] = initialValue; | 
				
			|||
            } | 
				
			|||
        }); | 
				
			|||
 | 
				
			|||
        return obj; | 
				
			|||
    }; | 
				
			|||
    //获取表单项
 | 
				
			|||
    const getFields = () => { | 
				
			|||
        const formItemList = []; | 
				
			|||
        const { formList, showNumber, offset } = props; | 
				
			|||
        let showNum = showNumber ? showNumber : 3; | 
				
			|||
        let offsetNum = offset ? offset : 0; | 
				
			|||
        const span = Number.parseInt((24 - offsetNum) / showNum); | 
				
			|||
        if (formList && formList.length > 0) { | 
				
			|||
            formList.forEach((item, index) => { | 
				
			|||
                const { label, field, type, placeholder, style, labelSpan, showTime, optionName, list, rules, itemProps } = item; | 
				
			|||
                let num = 0; | 
				
			|||
                if (index === 0 && offsetNum) { | 
				
			|||
                    num = offsetNum; | 
				
			|||
                } | 
				
			|||
                switch (type) { | 
				
			|||
                    case 'TIME': | 
				
			|||
                        const TIMES = ( | 
				
			|||
                            <Col offset={num} span={labelSpan || span} key={`${field}-${index}`}> | 
				
			|||
                                <FormItem label={label || '选择日期'} name={field} rules={rules}> | 
				
			|||
                                    <DatePicker | 
				
			|||
                                        getPopupContainer={(triggerNode) => triggerNode.parentNode} | 
				
			|||
                                        //showTime={showTime ? showTime : false}
 | 
				
			|||
                                        style={style ? style : {}} | 
				
			|||
                                        placeholder={placeholder || '选择日期'} | 
				
			|||
                                        format='YYYY-MM-DD' | 
				
			|||
                                        {...itemProps} | 
				
			|||
                                    /> | 
				
			|||
                                </FormItem> | 
				
			|||
                            </Col> | 
				
			|||
                        ); | 
				
			|||
                        formItemList.push(TIMES); | 
				
			|||
                        break; | 
				
			|||
                    case 'RANGETIME': | 
				
			|||
                        const RANGETIMES = ( | 
				
			|||
                            <Col offset={num} span={labelSpan || span} key={`${field}-${index}`}> | 
				
			|||
                                <FormItem label={label || '选择日期时间段'} name={field} rules={rules}> | 
				
			|||
                                    <RangePicker | 
				
			|||
                                        getPopupContainer={(triggerNode) => triggerNode.parentNode} | 
				
			|||
                                        showTime={showTime ? showTime : false} | 
				
			|||
                                        style={style ? style : {}} | 
				
			|||
                                        //placeholder={placeholder || '选择日期时间段'}
 | 
				
			|||
                                        format={showTime ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'} | 
				
			|||
                                        {...itemProps} | 
				
			|||
                                    /> | 
				
			|||
                                </FormItem> | 
				
			|||
                            </Col> | 
				
			|||
                        ); | 
				
			|||
                        formItemList.push(RANGETIMES); | 
				
			|||
                        break; | 
				
			|||
                    case 'SELECT': | 
				
			|||
                        const SELECT = ( | 
				
			|||
                            <Col offset={num} span={labelSpan || span} key={`${field}-${index}`}> | 
				
			|||
                                <FormItem label={label || '请选择'} name={field} rules={rules}> | 
				
			|||
                                    <Select | 
				
			|||
                                        style={style ? style : {}} | 
				
			|||
                                        getPopupContainer={(triggerNode) => triggerNode.parentNode} | 
				
			|||
                                        placeholder={placeholder || '请选择'} | 
				
			|||
                                        {...itemProps} | 
				
			|||
                                    > | 
				
			|||
                                        {getOptionList(list, optionName)} | 
				
			|||
                                    </Select> | 
				
			|||
                                </FormItem> | 
				
			|||
                            </Col> | 
				
			|||
                        ); | 
				
			|||
                        formItemList.push(SELECT); | 
				
			|||
                        break; | 
				
			|||
                    default: | 
				
			|||
                        const INPUT = ( | 
				
			|||
                            <Col offset={num} span={labelSpan || span} key={`${field}-${index}`}> | 
				
			|||
                                <FormItem label={label || '关键字'} name={field} rules={rules}> | 
				
			|||
                                    <Input style={style ? style : {}} placeholder={placeholder || '请输入关键字'} {...itemProps} /> | 
				
			|||
                                </FormItem> | 
				
			|||
                            </Col> | 
				
			|||
                        ); | 
				
			|||
                        formItemList.push(INPUT); | 
				
			|||
                        break; | 
				
			|||
                } | 
				
			|||
            }); | 
				
			|||
        } | 
				
			|||
        //默认显示个数处理
 | 
				
			|||
        return expand ? formItemList : formItemList.slice(0, showNum); | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    const onFinish = (values) => { | 
				
			|||
        const { formList } = props; | 
				
			|||
        let obj = Object.assign({}, values); | 
				
			|||
        //处理时间
 | 
				
			|||
        formList.forEach((v) => { | 
				
			|||
            if (v.type == 'TIME' && obj.hasOwnProperty(v.field)) { | 
				
			|||
                if (obj[v.field]) { | 
				
			|||
                    obj[v.field] = [ | 
				
			|||
                        moment(obj[v.field]).startOf('day').format('YYYY-MM-DD HH:mm:ss'), | 
				
			|||
                        moment(obj[v.field]).endOf('day').format('YYYY-MM-DD HH:mm:ss') | 
				
			|||
                    ]; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
            if (v.type == 'RANGETIME' && obj.hasOwnProperty(v.field)) { | 
				
			|||
                if (Array.isArray(obj[v.field])) { | 
				
			|||
                    obj[v.field] = v.showTime | 
				
			|||
                        ? [moment(obj[v.field][0]).format('YYYY-MM-DD HH:mm:ss'), moment(obj[v.field][1]).format('YYYY-MM-DD HH:mm:ss')] | 
				
			|||
                        : [ | 
				
			|||
                              moment(obj[v.field][0]).startOf('day').format('YYYY-MM-DD HH:mm:ss'), | 
				
			|||
                              moment(obj[v.field][1]).endOf('day').format('YYYY-MM-DD HH:mm:ss') | 
				
			|||
                          ]; | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
            //处理undefind
 | 
				
			|||
            if (obj[v.field] === undefined) { | 
				
			|||
                obj[v.field] = null; | 
				
			|||
            } | 
				
			|||
        }); | 
				
			|||
 | 
				
			|||
        props.onSearch(obj); | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    const getOptionList = (data, name) => { | 
				
			|||
        if (!data) { | 
				
			|||
            return []; | 
				
			|||
        } | 
				
			|||
        return data.map((item) => ( | 
				
			|||
            <Select.Option disabled={item.disabled || false} value={item.value} key={item.key || item.value}> | 
				
			|||
                {item[`${name}`]} | 
				
			|||
            </Select.Option> | 
				
			|||
        )); | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    return ( | 
				
			|||
        <Form | 
				
			|||
            form={form} | 
				
			|||
            name='smart_seal_search' | 
				
			|||
            className='smart-seal-search-form' | 
				
			|||
            onFinish={onFinish} | 
				
			|||
            initialValues={getinitialValues()} | 
				
			|||
            validateMessages={Constans.defaultValidateMessages} | 
				
			|||
        > | 
				
			|||
            <Row gutter={16}> | 
				
			|||
                <Col span={colSpan ? colSpan.label : 18}> | 
				
			|||
                    <Row gutter={16}>{getFields()}</Row> | 
				
			|||
                </Col> | 
				
			|||
                <Col span={colSpan ? colSpan.button : 6}> | 
				
			|||
                    <Space> | 
				
			|||
                        <Button htmlType='submit' className='smart-seal-default-btn'> | 
				
			|||
                            查询 | 
				
			|||
                        </Button> | 
				
			|||
                        {props.showRest && ( | 
				
			|||
                            <Button | 
				
			|||
                                onClick={() => { | 
				
			|||
                                    form.resetFields(); | 
				
			|||
                                }} | 
				
			|||
                                className='smart-seal-default-btn' | 
				
			|||
                            > | 
				
			|||
                                重置 | 
				
			|||
                            </Button> | 
				
			|||
                        )} | 
				
			|||
                        {props.formList.length > props.showNumber && ( | 
				
			|||
                            <a | 
				
			|||
                                style={{ marginLeft: 8, fontSize: 12 }} | 
				
			|||
                                onClick={() => { | 
				
			|||
                                    setExpand(!expand); | 
				
			|||
                                }} | 
				
			|||
                            > | 
				
			|||
                                {expand ? <UpOutlined /> : <DownOutlined />} {expand ? '收起' : '展开'} | 
				
			|||
                            </a> | 
				
			|||
                        )} | 
				
			|||
                    </Space> | 
				
			|||
                </Col> | 
				
			|||
            </Row> | 
				
			|||
        </Form> | 
				
			|||
    ); | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
Search.propTypes = { | 
				
			|||
    //查询配置数组 [{label, field, type[TIME,RANGETIME,SELECT,INPUT], initialValue, placeholder, width, list(select使用) optionName(select使用) , showTime(是否显示时间) }]
 | 
				
			|||
    formList: PropTypes.array.isRequired, | 
				
			|||
    showNumber: PropTypes.number, //默认展示几个item ,其余展开按钮控制
 | 
				
			|||
    offset: PropTypes.number, //设置第一个item的偏移值
 | 
				
			|||
    onSearch: PropTypes.func.isRequired, //查询提交函数
 | 
				
			|||
    showRest: PropTypes.bool, //是否显示重置按钮
 | 
				
			|||
    colSpan: PropTypes.object // 搜索栏整体布局  默认 {label: 18 : button: 6}
 | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
export default Search; | 
				
			|||
@ -1,3 +0,0 @@ | 
				
			|||
.ant-form-horizontal .ant-form-item-control { | 
				
			|||
    flex: 1 1 0%; | 
				
			|||
} | 
				
			|||
@ -1,82 +0,0 @@ | 
				
			|||
'use strict' | 
				
			|||
import React from 'react'; | 
				
			|||
import { SketchPicker } from 'react-color'; | 
				
			|||
 | 
				
			|||
class SketchColor extends React.Component { | 
				
			|||
    constructor(props) { | 
				
			|||
        super(props); | 
				
			|||
        this.state = { | 
				
			|||
            displayColorPicker: false, | 
				
			|||
            color: "#fff", | 
				
			|||
        }; | 
				
			|||
         | 
				
			|||
    } | 
				
			|||
    componentDidMount() { | 
				
			|||
      const { color } = this.props; | 
				
			|||
       | 
				
			|||
      color && this.setState({ | 
				
			|||
        color: color | 
				
			|||
      }) | 
				
			|||
 | 
				
			|||
   } | 
				
			|||
  handleClick = () => { | 
				
			|||
    this.setState({ displayColorPicker: !this.state.displayColorPicker }) | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  handleClose = () => { | 
				
			|||
    this.setState({ displayColorPicker: false }) | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  handleChange = (color) => { | 
				
			|||
    const {onChangeComplete} = this.props; | 
				
			|||
    this.setState({ color: color.hex }); | 
				
			|||
    onChangeComplete && onChangeComplete(color) | 
				
			|||
  }; | 
				
			|||
 | 
				
			|||
  render() { | 
				
			|||
    const { color } = this.state; | 
				
			|||
    const styles = { | 
				
			|||
        color: { | 
				
			|||
          width: '36px', | 
				
			|||
          height: '14px', | 
				
			|||
          borderRadius: '2px', | 
				
			|||
          background: color, | 
				
			|||
        }, | 
				
			|||
        swatch: { | 
				
			|||
          padding: '5px', | 
				
			|||
          background: '#fff', | 
				
			|||
          borderRadius: '1px', | 
				
			|||
          boxShadow: '0 0 0 1px rgba(0,0,0,.1)', | 
				
			|||
          display: 'inline-block', | 
				
			|||
          cursor: 'pointer', | 
				
			|||
        }, | 
				
			|||
        popover: { | 
				
			|||
          position: 'absolute', | 
				
			|||
          zIndex: '2', | 
				
			|||
        }, | 
				
			|||
        cover: { | 
				
			|||
          position: 'fixed', | 
				
			|||
          top: '0px', | 
				
			|||
          right: '0px', | 
				
			|||
          bottom: '0px', | 
				
			|||
          left: '0px', | 
				
			|||
        }, | 
				
			|||
       | 
				
			|||
    }; | 
				
			|||
     | 
				
			|||
    return ( | 
				
			|||
      <div> | 
				
			|||
        <div style={ styles.swatch } onClick={ this.handleClick }> | 
				
			|||
          <div style={ styles.color } /> | 
				
			|||
        </div> | 
				
			|||
        { this.state.displayColorPicker ? <div style={ styles.popover }> | 
				
			|||
          <div style={ styles.cover } onClick={ this.handleClose }/> | 
				
			|||
          <SketchPicker width={300} color={ color } onChange={ this.handleChange } /> | 
				
			|||
        </div> : null } | 
				
			|||
 | 
				
			|||
      </div> | 
				
			|||
    ) | 
				
			|||
  } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default SketchColor | 
				
			|||
@ -1,259 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
import React, { Component } from 'react'; | 
				
			|||
import PropTypes from 'prop-types'; | 
				
			|||
import { Table as AntdTable, Divider, Dropdown, Menu, Spin, Popconfirm } from 'antd'; | 
				
			|||
import { DownOutlined } from '@ant-design/icons'; | 
				
			|||
import { fromJS } from 'immutable'; | 
				
			|||
import './index.less'; | 
				
			|||
 | 
				
			|||
const loop = (data, keypath, values) => { | 
				
			|||
    // deal with array
 | 
				
			|||
    let dkey = keypath.slice(0, 1)[0]; | 
				
			|||
    if (dkey) { | 
				
			|||
        let dvalue = data[dkey]; | 
				
			|||
        let otherKeypath = keypath.slice(1); | 
				
			|||
        if (Array.isArray(dvalue)) { | 
				
			|||
            if (otherKeypath.length) { | 
				
			|||
                let immutableData = fromJS(data); | 
				
			|||
                for (let index = 0; index < dvalue.length; index++) { | 
				
			|||
                    let tmp = immutableData.getIn([dkey, index]).toJS(); | 
				
			|||
                    loop(tmp, otherKeypath, values); | 
				
			|||
                } | 
				
			|||
            } | 
				
			|||
        } else { | 
				
			|||
            values.push(dvalue); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
    return values; | 
				
			|||
}; | 
				
			|||
 | 
				
			|||
//通用table组件 使用方法查看底部propTypes
 | 
				
			|||
class Table extends Component { | 
				
			|||
    constructor(props) { | 
				
			|||
        super(props); | 
				
			|||
        this.state = { | 
				
			|||
            selectedRowKeys: [], | 
				
			|||
            pagination: { | 
				
			|||
                showTotal: (total) => `共${total}条`, | 
				
			|||
                showSizeChanger: true, | 
				
			|||
                showQuickJumper: true, | 
				
			|||
                responsive: true, | 
				
			|||
                pageSizeOptions: ['10', '20', '30', '40'], | 
				
			|||
                defaultPageSize: 10 | 
				
			|||
            }, | 
				
			|||
            visible: {}, | 
				
			|||
            current: 1 | 
				
			|||
        }; | 
				
			|||
        this.token = JSON.parse(sessionStorage.getItem('user')).token; | 
				
			|||
    } | 
				
			|||
    handleMenuClick = (e) => { | 
				
			|||
        //TODO 点击删除
 | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    UNSAFE_componentWillReceiveProps() { | 
				
			|||
        this.setState({ | 
				
			|||
            visible: {} | 
				
			|||
        }); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    handleVisibleChange = (flag, key) => { | 
				
			|||
        let visible = this.state.visible; | 
				
			|||
        visible[key] = flag; | 
				
			|||
        this.setState({ visible }); | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    getColumns = () => { | 
				
			|||
        let columns = this.props.attrs.map((attr) => { | 
				
			|||
            const { dataIndex, key, name, render, width, ellipsis, fixed } = attr; | 
				
			|||
            let obj = { | 
				
			|||
                title: name, | 
				
			|||
                dataIndex: dataIndex || key, | 
				
			|||
                key: key, | 
				
			|||
                ellipsis: ellipsis == undefined ? true : ellipsis, | 
				
			|||
                width: width | 
				
			|||
            }; | 
				
			|||
            if (render) { | 
				
			|||
                obj.render = render; | 
				
			|||
            } | 
				
			|||
            if (fixed) { | 
				
			|||
                obj.fixed = fixed; | 
				
			|||
            } | 
				
			|||
            return obj; | 
				
			|||
        }); | 
				
			|||
 | 
				
			|||
        if (!this.props.actions) { | 
				
			|||
            return columns; | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
        columns.push({ | 
				
			|||
            title: '操作', | 
				
			|||
            key: 'action', | 
				
			|||
            className: 'fs-table-column-action', | 
				
			|||
            render: (text, record) => { | 
				
			|||
                let actions = this.props.actions; | 
				
			|||
                if (record && record.actions) actions = actions.filter((act) => record.actions.includes(act.key)); | 
				
			|||
 | 
				
			|||
                return ( | 
				
			|||
                    <span style={{ whiteSpace: 'normal' }}> | 
				
			|||
                        {actions.reduce((p, c, i) => { | 
				
			|||
                            const { key, name, handler, dom, style, dropdown, hidden, popconfirm, getPopTitleFun, definedTitle } = c; | 
				
			|||
                            if (typeof hidden === 'function') { | 
				
			|||
                                let unVisiable = hidden(record); | 
				
			|||
                                if (unVisiable) return p; | 
				
			|||
                            } | 
				
			|||
 | 
				
			|||
                            if (dropdown && Array.isArray(dropdown)) { | 
				
			|||
                                // 操作按钮 下拉菜单处理
 | 
				
			|||
                                const menus = ( | 
				
			|||
                                    <Menu onClick={this.handleMenuClick}> | 
				
			|||
                                        {dropdown.map((m) => { | 
				
			|||
                                            if (m.popconfirm) { | 
				
			|||
                                                return ( | 
				
			|||
                                                    <Menu.Item key={m.key}> | 
				
			|||
                                                        <Popconfirm | 
				
			|||
                                                            placement='left' | 
				
			|||
                                                            title={m.title ? m.title : `确认${m.name}?`} | 
				
			|||
                                                            onConfirm={() => { | 
				
			|||
                                                                m.handler && m.handler(record); | 
				
			|||
                                                            }} | 
				
			|||
                                                        > | 
				
			|||
                                                            <a onClick={(e) => e.preventDefault()}>{m.name}</a> | 
				
			|||
                                                        </Popconfirm> | 
				
			|||
                                                    </Menu.Item> | 
				
			|||
                                                ); | 
				
			|||
                                            } else { | 
				
			|||
                                                return ( | 
				
			|||
                                                    <Menu.Item key={m.key}> | 
				
			|||
                                                        <a onClick={(e) => m.handler && m.handler(record)}>{m.name}</a> | 
				
			|||
                                                    </Menu.Item> | 
				
			|||
                                                ); | 
				
			|||
                                            } | 
				
			|||
                                        })} | 
				
			|||
                                    </Menu> | 
				
			|||
                                ); | 
				
			|||
                                p.push( | 
				
			|||
                                    <Dropdown | 
				
			|||
                                        overlay={menus} | 
				
			|||
                                        onVisibleChange={(e) => this.handleVisibleChange(e, text.id)} | 
				
			|||
                                        visible={this.state.visible ? this.state.visible[text.id] : false} | 
				
			|||
                                        key={key} | 
				
			|||
                                    > | 
				
			|||
                                        <a style={style ? style : { display: 'inline-block' }} onClick={(e) => e.preventDefault()}> | 
				
			|||
                                            {name} <DownOutlined /> | 
				
			|||
                                        </a> | 
				
			|||
                                    </Dropdown> | 
				
			|||
                                ); | 
				
			|||
                            } else { | 
				
			|||
                                if (dom) { | 
				
			|||
                                    popconfirm | 
				
			|||
                                        ? p.push( | 
				
			|||
                                            <Popconfirm placement='left' title={`确认${name}吗?`} onConfirm={() => handler(record)} key={key}> | 
				
			|||
                                                <span | 
				
			|||
                                                    style={style ? style : { display: 'inline-block' }} | 
				
			|||
                                                    key={key} | 
				
			|||
                                                    onClick={(e) => e.preventDefault()} | 
				
			|||
                                                > | 
				
			|||
                                                    {dom} | 
				
			|||
                                                </span> | 
				
			|||
                                            </Popconfirm> | 
				
			|||
                                        ) | 
				
			|||
                                        : p.push( | 
				
			|||
                                            <span style={style ? style : { display: 'inline-block' }} key={key} onClick={(e) => handler(record)}> | 
				
			|||
                                                {dom} | 
				
			|||
                                            </span> | 
				
			|||
                                        ); | 
				
			|||
                                } else { | 
				
			|||
                                    popconfirm | 
				
			|||
                                        ? p.push( | 
				
			|||
                                            <Popconfirm placement='left' title={definedTitle && getPopTitleFun ? getPopTitleFun(record) : `确认${name}吗?`} onConfirm={() => handler(record)} key={key}> | 
				
			|||
                                                <a | 
				
			|||
                                                    style={style ? style : { display: 'inline-block' }} | 
				
			|||
                                                    key={key} | 
				
			|||
                                                    onClick={(e) => e.preventDefault()} | 
				
			|||
                                                > | 
				
			|||
                                                    {name} | 
				
			|||
                                                </a> | 
				
			|||
                                            </Popconfirm> | 
				
			|||
                                        ) | 
				
			|||
                                        : p.push( | 
				
			|||
                                            <a style={style ? style : { display: 'inline-block' }} key={key} onClick={(e) => handler(record)}> | 
				
			|||
                                                {name} | 
				
			|||
                                            </a> | 
				
			|||
                                        ); | 
				
			|||
                                } | 
				
			|||
                            } | 
				
			|||
 | 
				
			|||
                            if (i < actions.length - 1) p.push(<Divider key={`divider${i}`} type='vertical' />); | 
				
			|||
                            return p; | 
				
			|||
                        }, [])} | 
				
			|||
                    </span> | 
				
			|||
                ); | 
				
			|||
            } | 
				
			|||
        }); | 
				
			|||
 | 
				
			|||
        return columns; | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    getColumnData = (opts) => { | 
				
			|||
        const { data, keypath, spliter, rawdata } = opts; | 
				
			|||
        let v = null; | 
				
			|||
        let outer = data[keypath[0]]; | 
				
			|||
        if (Array.isArray(outer)) { | 
				
			|||
            let values = loop(data, keypath, []); | 
				
			|||
            v = rawdata ? values : values.join(spliter || ','); | 
				
			|||
        } else { | 
				
			|||
            v = fromJS(data).getIn(keypath); | 
				
			|||
        } | 
				
			|||
        return v; | 
				
			|||
    }; | 
				
			|||
 | 
				
			|||
    getPagination = () => { | 
				
			|||
        const { total, curpage } = this.props; | 
				
			|||
        const { pagination, current } = this.state; | 
				
			|||
        pagination.total = total ? total : 0; | 
				
			|||
        pagination.current = curpage ? curpage : current; | 
				
			|||
        return pagination; | 
				
			|||
    }; | 
				
			|||
    //暂时只支持分页远程处理
 | 
				
			|||
    handleTableChange = (pagination, filters, sorter) => { | 
				
			|||
        this.setState({ | 
				
			|||
            current: pagination.current | 
				
			|||
        }); | 
				
			|||
        if (this.props.onTableChange) { | 
				
			|||
            let limit = Number.parseInt(pagination.pageSize); | 
				
			|||
            let offset = limit * (Number.parseInt(pagination.current) - 1); | 
				
			|||
            this.props.onTableChange(limit, offset, pagination.current); | 
				
			|||
        } | 
				
			|||
    }; | 
				
			|||
    render() { | 
				
			|||
        const { scroll, rowSelection, data, isRequesting, showHeader, noShowPagination, rowKey } = this.props; | 
				
			|||
        return ( | 
				
			|||
            <AntdTable | 
				
			|||
                className={'fs-table'} | 
				
			|||
                id='fs-smart-seal-table' | 
				
			|||
                dataSource={data} | 
				
			|||
                loading={isRequesting} | 
				
			|||
                showHeader={showHeader} | 
				
			|||
                scroll={scroll ? scroll : {}} | 
				
			|||
                rowKey={rowKey ? rowKey : 'id'} | 
				
			|||
                rowSelection={rowSelection ? rowSelection : null} | 
				
			|||
                columns={this.getColumns()} | 
				
			|||
                onChange={this.handleTableChange} | 
				
			|||
                pagination={noShowPagination ? false : this.getPagination()} | 
				
			|||
            /> | 
				
			|||
        ); | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
Table.propTypes = { | 
				
			|||
    data: PropTypes.array.isRequired, //数据资源
 | 
				
			|||
    attrs: PropTypes.array.isRequired, //属性数组用于colums {key,name,|render|isImg|nullable}
 | 
				
			|||
    actions: PropTypes.array, //操作栏数组  { key,name,style,handler,dropdown,dom}
 | 
				
			|||
    scroll: PropTypes.object, //同antd 用法
 | 
				
			|||
    rowSelection: PropTypes.object, //表格行是否可选择 配置项同antd
 | 
				
			|||
    onTableChange: PropTypes.func, //onChange触发函数
 | 
				
			|||
    showHeader: PropTypes.bool, //是否显示表头
 | 
				
			|||
    noShowPagination: PropTypes.bool, //是否显示分页器,
 | 
				
			|||
    showLessItems: PropTypes.bool, //是否显示较少页面内容,
 | 
				
			|||
    rowKey: PropTypes.string//表格记录的key
 | 
				
			|||
}; | 
				
			|||
export default Table; | 
				
			|||
@ -1,34 +0,0 @@ | 
				
			|||
//宽度小于1920px | 
				
			|||
@media screen and (max-width:1920px) { | 
				
			|||
    .fs-table :global(.ant-table tbody > tr > td) { | 
				
			|||
        border: none; | 
				
			|||
        font-size: 14px; | 
				
			|||
        font-weight: 400; | 
				
			|||
        color: #666; | 
				
			|||
    } | 
				
			|||
    .fs-table :global(.ant-table thead > tr > th) { | 
				
			|||
        border: none; | 
				
			|||
        font-size: 14px; | 
				
			|||
        font-weight: 600; | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
//宽度大于等于1920px | 
				
			|||
@media screen and (min-width:1920px) { | 
				
			|||
    .fs-table :global(.ant-table tbody > tr > td) { | 
				
			|||
        border: none; | 
				
			|||
        font-size: 14px; | 
				
			|||
        font-weight: 400; | 
				
			|||
        color: #666; | 
				
			|||
    } | 
				
			|||
    .fs-table :global(.ant-table thead > tr > th) { | 
				
			|||
        border: none; | 
				
			|||
        font-size: 16px; | 
				
			|||
        font-weight: 600; | 
				
			|||
    } | 
				
			|||
} | 
				
			|||
 | 
				
			|||
 | 
				
			|||
// .fs-table :global(.fs-table-column-action) { | 
				
			|||
//     font-size: 16px; | 
				
			|||
// } | 
				
			|||
@ -0,0 +1,26 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Card, Modal, TreeSelect, message } from 'antd'; | 
				
			|||
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form'; | 
				
			|||
 | 
				
			|||
const Basis = ({ user, module, setModule }) => { | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
   return <div style={{ width: '100%', heigh: '100%' }}> | 
				
			|||
    基础信息 | 
				
			|||
 | 
				
			|||
   </div > | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps (state) { | 
				
			|||
   const { auth, global } = state; | 
				
			|||
   return { | 
				
			|||
      user: auth.user, | 
				
			|||
      clientHeight: global.clientHeight, | 
				
			|||
   }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(Basis); | 
				
			|||
@ -0,0 +1,26 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Card, Modal, TreeSelect, message } from 'antd'; | 
				
			|||
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form'; | 
				
			|||
import Title from 'antd/lib/skeleton/Title'; | 
				
			|||
 | 
				
			|||
const Capacity = ({ user,  }) => { | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
   return <div style={{ width: '100%', heigh: '100%' }}> | 
				
			|||
     能耗监测 | 
				
			|||
   </div > | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps (state) { | 
				
			|||
   const { auth, global } = state; | 
				
			|||
   return { | 
				
			|||
      user: auth.user, | 
				
			|||
      clientHeight: global.clientHeight, | 
				
			|||
   }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(Capacity); | 
				
			|||
@ -0,0 +1,27 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Card, Modal, TreeSelect, message } from 'antd'; | 
				
			|||
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form'; | 
				
			|||
import Title from 'antd/lib/skeleton/Title'; | 
				
			|||
 | 
				
			|||
const Electrical = ({ user, module, setModule }) => { | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
   return <div style={{ width: '100%', heigh: '100%' }}> | 
				
			|||
      电排远控 | 
				
			|||
 | 
				
			|||
   </div > | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps (state) { | 
				
			|||
   const { auth, global } = state; | 
				
			|||
   return { | 
				
			|||
      user: auth.user, | 
				
			|||
      clientHeight: global.clientHeight, | 
				
			|||
   }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(Electrical); | 
				
			|||
@ -0,0 +1,75 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Card, Modal, TreeSelect, message } from 'antd'; | 
				
			|||
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form'; | 
				
			|||
import Title from 'antd/lib/skeleton/Title'; | 
				
			|||
 | 
				
			|||
const Header = ({ user, module, setModule }) => { | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
   return <div style={{ width: '100%', heigh: '100%' }}> | 
				
			|||
      <div style={{ | 
				
			|||
         width: '100%', height: 130, | 
				
			|||
         backgroundImage: 'url(/assets/images/monitor/header-bg.png)', | 
				
			|||
         backgroundSize: 'cover', | 
				
			|||
         backgroundPosition: 'center', | 
				
			|||
         display: 'flex', | 
				
			|||
         justifyContent: 'space-between', | 
				
			|||
      }}> | 
				
			|||
         <div style={{ width: 140 }}>天气</div> | 
				
			|||
         <div style={{ | 
				
			|||
            width: 424, lineHeight: '136px', | 
				
			|||
            fontFamily: 'YouSheBiaoTiHei', fontSize: 43, color: '#E2F8FF', letterSpacing: 4, fontWeight: 600 | 
				
			|||
         }}>泵站自动化控制系统</div> | 
				
			|||
         <div> | 
				
			|||
            <div style={{ | 
				
			|||
               width: 140, height: 52, | 
				
			|||
               backgroundImage: 'url(/assets/images/monitor/user.png)', | 
				
			|||
               backgroundSize: 'cover', | 
				
			|||
               backgroundPosition: 'center' | 
				
			|||
            }}>{user?.name} | 
				
			|||
            </div> | 
				
			|||
         </div> | 
				
			|||
 | 
				
			|||
      </div> | 
				
			|||
      <div style={{ display: 'flex', justifyContent: 'center' }}> | 
				
			|||
         <div style={{ | 
				
			|||
            width: '45%', height: 44, textAlign: 'center', | 
				
			|||
            backgroundImage: 'url(/assets/images/monitor/strip.png)', | 
				
			|||
            backgroundSize: '100% 25%', | 
				
			|||
            backgroundPosition: 'center', | 
				
			|||
            backgroundRepeat: 'no-repeat', | 
				
			|||
            display: 'flex', | 
				
			|||
            alignItems: 'flex-end', justifyContent: 'space-around', | 
				
			|||
         }}> | 
				
			|||
            {[{ title: '基础信息', key: 'basis' }, | 
				
			|||
            { title: '能耗监测', key: 'capacity' }, | 
				
			|||
            { title: '电排远控', key: 'electrical ' }, | 
				
			|||
            { title: '实时监测', key: 'realTime' },].map(v => { | 
				
			|||
               return <div key={v.key} style={{ | 
				
			|||
                  width: 80, height: 30, lineHeight: '30px', | 
				
			|||
                  backgroundImage: `url(/assets/images/monitor/${module == v.key ? 'pitch-on' : 'chose-none'}.png)`, | 
				
			|||
                  backgroundSize: 'center', | 
				
			|||
                  backgroundPosition: 'center', | 
				
			|||
                  color: 'white', | 
				
			|||
               }} onClick={() => setModule(v.key)}>{v.title}</div> | 
				
			|||
            })} | 
				
			|||
 | 
				
			|||
         </div> | 
				
			|||
      </div> | 
				
			|||
 | 
				
			|||
   </div > | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps (state) { | 
				
			|||
   const { auth, global } = state; | 
				
			|||
   return { | 
				
			|||
      user: auth.user, | 
				
			|||
      clientHeight: global.clientHeight, | 
				
			|||
   }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(Header); | 
				
			|||
@ -0,0 +1,26 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Card, Modal, TreeSelect, message } from 'antd'; | 
				
			|||
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form'; | 
				
			|||
import Title from 'antd/lib/skeleton/Title'; | 
				
			|||
 | 
				
			|||
const RealTime = ({ user, module, setModule }) => { | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
   return <div style={{ width: '100%', heigh: '100%' }}> | 
				
			|||
    实时监测 | 
				
			|||
   </div > | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps (state) { | 
				
			|||
   const { auth, global } = state; | 
				
			|||
   return { | 
				
			|||
      user: auth.user, | 
				
			|||
      clientHeight: global.clientHeight, | 
				
			|||
   }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(RealTime); | 
				
			|||
@ -0,0 +1,5 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import SystemManagement from './systemManagement'; | 
				
			|||
 | 
				
			|||
export { SystemManagement }; | 
				
			|||
@ -0,0 +1,50 @@ | 
				
			|||
import React, { useEffect, useState } from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { FormOutlined, DeleteOutlined } from '@ant-design/icons'; | 
				
			|||
import { Spin, Tooltip, Button, Popconfirm, Row, Col, Tree, Card, Switch } from 'antd'; | 
				
			|||
import ProTable from '@ant-design/pro-table'; | 
				
			|||
import { getDepMessage, getDepUser, createUser, updateUser, delUser, resetPwd, createDept, updateDept, delDept } from '../actions/user'; | 
				
			|||
import Header from '../components/header'; | 
				
			|||
import Basis from '../components/basis'; | 
				
			|||
import Capacity from '../components/capacity'; | 
				
			|||
import Electrical from '../components/electrical'; | 
				
			|||
import RealTime from '../components/realTime'; | 
				
			|||
 | 
				
			|||
const TreeNode = Tree.TreeNode; | 
				
			|||
 | 
				
			|||
const SystemManagement = ({ clientHeight, user }) => { | 
				
			|||
 | 
				
			|||
   const [module, setModule] = useState('basis') | 
				
			|||
   useEffect(() => { | 
				
			|||
 | 
				
			|||
   }, []) | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
 | 
				
			|||
   return ( | 
				
			|||
      <div style={{ | 
				
			|||
         width: '100vw', height: '100vh', | 
				
			|||
         backgroundImage: 'url(/assets/images/monitor/screen-bg.png)', | 
				
			|||
         backgroundSize: 'cover', | 
				
			|||
         backgroundPosition: 'center' | 
				
			|||
      }}> | 
				
			|||
         <Header module={module} setModule={setModule} /> | 
				
			|||
         {module == 'basis' ? <Basis /> : ""} | 
				
			|||
         {module == 'capacity' ? <Capacity /> : ""} | 
				
			|||
         {module == 'electrical' ? <Electrical /> : ""} | 
				
			|||
         {module == 'realTime' ? <RealTime /> : ""} | 
				
			|||
      </div> | 
				
			|||
   ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps (state) { | 
				
			|||
   const { auth, global } = state; | 
				
			|||
   return { | 
				
			|||
      user: auth.user, | 
				
			|||
      clientHeight: global.clientHeight, | 
				
			|||
   }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(SystemManagement); | 
				
			|||
@ -0,0 +1,22 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { Link } from 'react-router-dom'; | 
				
			|||
import { Menu } from 'antd'; | 
				
			|||
import { SettingOutlined } from '@ant-design/icons'; | 
				
			|||
 | 
				
			|||
const SubMenu = Menu.SubMenu; | 
				
			|||
 | 
				
			|||
export function getNavItem(user, dispatch) { | 
				
			|||
    // if (!Func.isAuthorized("ORG_MANAGE")) {
 | 
				
			|||
    //     return null
 | 
				
			|||
    // }
 | 
				
			|||
    return (<></> | 
				
			|||
      //   <SubMenu key="organization" icon={<SettingOutlined />} title={'组织管理'}>
 | 
				
			|||
      //       <Menu.Item key="userManage">
 | 
				
			|||
      //           <Link to="/organization/user">部门成员</Link>
 | 
				
			|||
      //       </Menu.Item>
 | 
				
			|||
      //       <Menu.Item key="authority">
 | 
				
			|||
      //           <Link to="/organization/authority">权限配置</Link>
 | 
				
			|||
      //       </Menu.Item>
 | 
				
			|||
      //   </SubMenu>
 | 
				
			|||
    ); | 
				
			|||
} | 
				
			|||
@ -0,0 +1,27 @@ | 
				
			|||
'use strict'; | 
				
			|||
import { SystemManagement } from './containers'; | 
				
			|||
 | 
				
			|||
export default [{ | 
				
			|||
    type: 'outer', | 
				
			|||
    route: { | 
				
			|||
        path: '/systemManagement', | 
				
			|||
        key: 'systemManagement', | 
				
			|||
        breadcrumb: '泵站大屏', | 
				
			|||
        component: SystemManagement, | 
				
			|||
      //   menuSelectKeys: ['userManage'],
 | 
				
			|||
      //   menuOpenKeys: ['organization'],
 | 
				
			|||
      //   childRoutes: [{
 | 
				
			|||
      //       path: '/user',
 | 
				
			|||
      //       key: 'userManage',
 | 
				
			|||
      //       menuSelectKeys: ['userManage'],
 | 
				
			|||
      //       component: UserManage,
 | 
				
			|||
      //       breadcrumb: '部门成员',
 | 
				
			|||
      //   }, {
 | 
				
			|||
      //       path: '/authority',
 | 
				
			|||
      //       key: 'authority',
 | 
				
			|||
      //       component: Authority,
 | 
				
			|||
      //       menuSelectKeys: ['authority'],
 | 
				
			|||
      //       breadcrumb: '权限配置',
 | 
				
			|||
      //   }]
 | 
				
			|||
    } | 
				
			|||
}]; | 
				
			|||
@ -1,88 +0,0 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { ProFormText, ModalForm, ProFormSelect } from '@ant-design/pro-form'; | 
				
			|||
 | 
				
			|||
const DeptModal = (props) => { | 
				
			|||
    const { visible, modalType, onVisibleChange, onConfirm, editData, depts } = props | 
				
			|||
    let deptOptions = [], sonArr = []; | 
				
			|||
    depts.map(d => { | 
				
			|||
        deptOptions.push({ | 
				
			|||
            value: d.id, | 
				
			|||
            label: d.name | 
				
			|||
        }); | 
				
			|||
 | 
				
			|||
        d.subordinate.map(ds => { | 
				
			|||
            sonArr.push({ | 
				
			|||
                value: ds.id, | 
				
			|||
                label: ds.name | 
				
			|||
            }) | 
				
			|||
        }) | 
				
			|||
    }) | 
				
			|||
    const onFinish = (values) => { | 
				
			|||
        if (onConfirm) { | 
				
			|||
            if (modalType === 'edit') { | 
				
			|||
                values.contract.parentDeptId = values.contract.parentDeptId || null | 
				
			|||
                onConfirm(values) | 
				
			|||
            } else { | 
				
			|||
                onConfirm(values); | 
				
			|||
            } | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    const checkName = (rule, value, callback) => { | 
				
			|||
        const list = modalType == 'edit' ? deptOptions.concat(sonArr).filter(g => g.value != editData.id) : deptOptions.concat(sonArr) | 
				
			|||
        if (list.filter(s => s.label == value).length) { | 
				
			|||
            callback('该名称已存在'); | 
				
			|||
        } else { | 
				
			|||
            callback(); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    return ( | 
				
			|||
        <ModalForm | 
				
			|||
            width={400} | 
				
			|||
            title={modalType == 'edit' ? '编辑部门' : '新建部门'} | 
				
			|||
            visible={visible} | 
				
			|||
            onVisibleChange={onVisibleChange} | 
				
			|||
            onFinish={onFinish} | 
				
			|||
            destroyOnClose | 
				
			|||
            initialValues={ | 
				
			|||
                modalType == 'edit' ? | 
				
			|||
                    { | 
				
			|||
                        contract: editData | 
				
			|||
                    } : | 
				
			|||
                    { | 
				
			|||
                        contract: { | 
				
			|||
                            enable: true | 
				
			|||
                        } | 
				
			|||
                    } | 
				
			|||
            } | 
				
			|||
        > | 
				
			|||
            <ProFormText | 
				
			|||
                name={['contract', 'name']} | 
				
			|||
                maxLength={24} | 
				
			|||
                width="md" | 
				
			|||
                label="部门名称" | 
				
			|||
                required | 
				
			|||
                placeholder="请输入部门名称" | 
				
			|||
                rules={[{ required: true, message: '请输入部门名称' }, { validator: checkName }]} | 
				
			|||
            /> | 
				
			|||
            <ProFormSelect | 
				
			|||
                name={['contract', 'dependence']} | 
				
			|||
                label="上级部门" | 
				
			|||
                request={async () => { | 
				
			|||
                    let t = modalType === 'edit' ? deptOptions.filter(i => i.value !== editData.id) : deptOptions | 
				
			|||
                    return t | 
				
			|||
                }} | 
				
			|||
                disabled={modalType === 'edit' ? editData.subordinate?.length === 0 ? false : true : false} | 
				
			|||
            /> | 
				
			|||
        </ModalForm> | 
				
			|||
    ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps(state) { | 
				
			|||
    return { | 
				
			|||
    }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(DeptModal); | 
				
			|||
@ -1,74 +0,0 @@ | 
				
			|||
import React, { useRef, useState } from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Card, Modal, TreeSelect } from 'antd'; | 
				
			|||
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form'; | 
				
			|||
 | 
				
			|||
const ResetPwd = (props) => { | 
				
			|||
    const { visible, onVisibleChange, onConfirm } = props; | 
				
			|||
    const formRef = useRef(); | 
				
			|||
 | 
				
			|||
    const onFinish = (values) => { | 
				
			|||
        if (onConfirm) { | 
				
			|||
            onConfirm(values); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    return ( | 
				
			|||
        <Spin spinning={false}> | 
				
			|||
            <ModalForm | 
				
			|||
                title={'重置密码'} | 
				
			|||
                visible={visible} | 
				
			|||
                onVisibleChange={onVisibleChange} | 
				
			|||
                onFinish={onFinish} | 
				
			|||
                formRef={formRef} | 
				
			|||
                destroyOnClose | 
				
			|||
            > | 
				
			|||
                <ProFormText.Password | 
				
			|||
                    name={['password']} | 
				
			|||
                    width="md" | 
				
			|||
                    label="新密码" | 
				
			|||
                    required | 
				
			|||
                    placeholder="请输入密码" | 
				
			|||
                    fieldProps={{ | 
				
			|||
                        autocomplete: 'new-password' | 
				
			|||
                    }} | 
				
			|||
                    rules={[ | 
				
			|||
                        { required: true, message: '请填写密码' }, | 
				
			|||
                        { min: 6, message: '请填写至少6位密码' }, | 
				
			|||
                    ]} | 
				
			|||
                /> | 
				
			|||
                <ProFormText.Password | 
				
			|||
                    name={['checkPassword']} | 
				
			|||
                    width="md" | 
				
			|||
                    label="确认密码" | 
				
			|||
                    required | 
				
			|||
                    autocomplete='off' | 
				
			|||
                    placeholder="请输入密码" | 
				
			|||
                    rules={[ | 
				
			|||
                        { required: true, message: '请再次填写密码' }, | 
				
			|||
                        { min: 6, message: '请填写至少6位密码' }, | 
				
			|||
                        { | 
				
			|||
                            validator: (rule, value, callback) => { | 
				
			|||
                                const pwd = formRef.current.getFieldValue('password'); | 
				
			|||
                                if (!value) { | 
				
			|||
                                    callback(); | 
				
			|||
                                } | 
				
			|||
                                if (pwd == value) { | 
				
			|||
                                    callback(); | 
				
			|||
                                } else { | 
				
			|||
                                    callback('两次输入的密码不一致'); | 
				
			|||
                                } | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                    ]} | 
				
			|||
                /> | 
				
			|||
            </ModalForm> | 
				
			|||
        </Spin> | 
				
			|||
    ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps(state) { | 
				
			|||
    return {}; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(ResetPwd); | 
				
			|||
@ -1,121 +0,0 @@ | 
				
			|||
import React, { useEffect } from 'react'; | 
				
			|||
import { Checkbox, Table } from 'antd'; | 
				
			|||
import { useState } from 'react'; | 
				
			|||
 | 
				
			|||
const CheckboxGroup = Checkbox.Group; | 
				
			|||
 | 
				
			|||
const Resource = props => { | 
				
			|||
    const { roleData, userRole, userSelected, setResCode, userType } = props; | 
				
			|||
    const [indeterminate, setIndeterminate] = useState({}); | 
				
			|||
    const [roleCheck, setRoleCheck] = useState({});//一级权限码
 | 
				
			|||
    const [parentRoleCheck, setParentRoleCheck] = useState({}); //二级权限码
 | 
				
			|||
 | 
				
			|||
    const roleDatas=roleData.slice(0) | 
				
			|||
    useEffect(() => { | 
				
			|||
        const check = {} | 
				
			|||
        const parentCheck = {} | 
				
			|||
        const initInd = {} | 
				
			|||
        roleData && roleData.map && roleData.map(r => { | 
				
			|||
            let currentInd = false; | 
				
			|||
            let sum = 0; | 
				
			|||
            if (r.resources) { | 
				
			|||
                check[r.code] = [] | 
				
			|||
                r.resources.map(child => { | 
				
			|||
                    if (userRole.find(code => code.resourceId == child.code)) { | 
				
			|||
                        currentInd = true; | 
				
			|||
                        sum++; | 
				
			|||
                        check[r.code].push(child.code); | 
				
			|||
                    } | 
				
			|||
                }) | 
				
			|||
            } | 
				
			|||
            parentCheck[r.code] = r.resources.length === sum | 
				
			|||
            initInd[r.code] = parentCheck[r.code] ? false : currentInd | 
				
			|||
        }); | 
				
			|||
        setParentRoleCheck(parentCheck) | 
				
			|||
        setRoleCheck(check); | 
				
			|||
        setIndeterminate(initInd); | 
				
			|||
    }, [userRole]); | 
				
			|||
 | 
				
			|||
    const setResData = (role) => { | 
				
			|||
        let codes = []; | 
				
			|||
        // Object.keys(partRole).map(r => {
 | 
				
			|||
        //     if (partRole[r]) codes.push(r)
 | 
				
			|||
        // })
 | 
				
			|||
        Object.keys(role).map(r => { | 
				
			|||
            if (role[r].length) { | 
				
			|||
                codes.push(r); | 
				
			|||
            } | 
				
			|||
            codes = codes.concat(role[r]) | 
				
			|||
        }) | 
				
			|||
        setResCode(codes) | 
				
			|||
    } | 
				
			|||
    return ( | 
				
			|||
        <Table | 
				
			|||
            bordered | 
				
			|||
            pagination={false} | 
				
			|||
            dataSource={roleDatas} | 
				
			|||
            columns={[{ | 
				
			|||
                title: '功能', | 
				
			|||
                key: 'name', | 
				
			|||
                dataIndex: 'name', | 
				
			|||
                render: (text, record) => { | 
				
			|||
                    const parentCode = record.code | 
				
			|||
                    return <Checkbox | 
				
			|||
                     | 
				
			|||
                        indeterminate={indeterminate[parentCode]} | 
				
			|||
                        onChange={(e) => { | 
				
			|||
                            const currentParCheck = JSON.parse(JSON.stringify(parentRoleCheck)); | 
				
			|||
                            currentParCheck[parentCode] = e.target.checked; | 
				
			|||
                            const currentCode = JSON.parse(JSON.stringify(roleCheck)); | 
				
			|||
                            currentCode[parentCode] = e.target.checked ? roleData.find(r => r.code == parentCode).resources.map(r => r.code) : [] | 
				
			|||
                            const currentInd = JSON.parse(JSON.stringify(indeterminate)); | 
				
			|||
                            currentInd[parentCode] = false; | 
				
			|||
 | 
				
			|||
                            setParentRoleCheck(currentParCheck); | 
				
			|||
                            setRoleCheck(currentCode); | 
				
			|||
                            setIndeterminate(currentInd); | 
				
			|||
                            setResData(currentCode) | 
				
			|||
                        }} | 
				
			|||
                        checked={parentRoleCheck[parentCode] || false} | 
				
			|||
                        disabled={userSelected === "SuperAdmin" || userType === 4} | 
				
			|||
                        options={''} | 
				
			|||
                    > | 
				
			|||
                        {text} | 
				
			|||
                    </Checkbox> | 
				
			|||
                } | 
				
			|||
            }, { | 
				
			|||
                title: '列表', | 
				
			|||
                key: 'resources', | 
				
			|||
                dataIndex: 'resources', | 
				
			|||
                render: (text, record) => { | 
				
			|||
                    let data = []; | 
				
			|||
                    console.log() | 
				
			|||
                    text.map(s => { s.name !== "整治汇总编辑" ? data.push({ label: s.name, value: s.code }) : '' }) | 
				
			|||
                    let parentCode = record.code; | 
				
			|||
 | 
				
			|||
                    return <CheckboxGroup | 
				
			|||
                        disabled={userSelected === "SuperAdmin" || userType === 4} | 
				
			|||
                        options={data} | 
				
			|||
                        value={roleCheck[parentCode] || []} | 
				
			|||
                        onChange={value => { | 
				
			|||
                            const checkArr = JSON.parse(JSON.stringify(roleCheck)); | 
				
			|||
                            const parentCheck = JSON.parse(JSON.stringify(parentRoleCheck)); | 
				
			|||
                            const ind = JSON.parse(JSON.stringify(indeterminate)); | 
				
			|||
                            const currentCode = roleData.find(r => r.code == parentCode) || {} | 
				
			|||
 | 
				
			|||
                            checkArr[parentCode] = value; | 
				
			|||
                            ind[parentCode] = !!value.length && value.length < currentCode.resources.length | 
				
			|||
                            parentCheck[parentCode] = value.length === currentCode.resources.length | 
				
			|||
 | 
				
			|||
                            setRoleCheck(checkArr); | 
				
			|||
                            setIndeterminate(ind); | 
				
			|||
                            setParentRoleCheck(parentCheck); | 
				
			|||
                            setResData(checkArr) | 
				
			|||
                        }} | 
				
			|||
                    /> | 
				
			|||
                } | 
				
			|||
            }]} | 
				
			|||
        ></Table > | 
				
			|||
    ) | 
				
			|||
} | 
				
			|||
export default Resource | 
				
			|||
@ -1,171 +0,0 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Card, Modal, TreeSelect, message } from 'antd'; | 
				
			|||
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form'; | 
				
			|||
 | 
				
			|||
const UserModal = (props) => { | 
				
			|||
    const { visible, modalType, depData, onVisibleChange, onConfirm, editData } = props | 
				
			|||
    const reg_tel = /^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$/; | 
				
			|||
    const onFinish = (values) => { | 
				
			|||
        if (onConfirm) { | 
				
			|||
            onConfirm(values); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
    const mobile = (value) => { | 
				
			|||
        if (reg_tel.test(value)) { | 
				
			|||
            return | 
				
			|||
        } | 
				
			|||
        return message('请输入姓名') | 
				
			|||
    } | 
				
			|||
    return ( | 
				
			|||
        <Spin spinning={false}> | 
				
			|||
            <ModalForm | 
				
			|||
                title={modalType == 'edit' ? '编辑用户' : '新建用户'} | 
				
			|||
                visible={visible} | 
				
			|||
                onVisibleChange={onVisibleChange} | 
				
			|||
                onFinish={onFinish} | 
				
			|||
                destroyOnClose | 
				
			|||
                initialValues={ | 
				
			|||
                    modalType == 'edit' ? | 
				
			|||
                        { | 
				
			|||
                            contract: editData | 
				
			|||
                        } : | 
				
			|||
                        { | 
				
			|||
                            contract: { | 
				
			|||
                                enable: true | 
				
			|||
                            } | 
				
			|||
                        } | 
				
			|||
                } | 
				
			|||
            > | 
				
			|||
                <ProForm.Group> | 
				
			|||
                    <ProFormText | 
				
			|||
                        name={['contract', 'name']} | 
				
			|||
                        maxLength={24} | 
				
			|||
                        width="md" | 
				
			|||
                        label="姓名" | 
				
			|||
                        required | 
				
			|||
                        placeholder="请输入姓名" | 
				
			|||
                        rules={[{ required: true, message: '请输入姓名' }]} | 
				
			|||
                    /> | 
				
			|||
                    <ProFormText | 
				
			|||
                        name={['contract', 'phone']} | 
				
			|||
                        width="md" | 
				
			|||
                        label="用户名(手机号)" | 
				
			|||
                        required | 
				
			|||
                        fieldProps={{ | 
				
			|||
                            maxLength: 11, | 
				
			|||
                        }} | 
				
			|||
                        getValueFromEvent={(event) => { | 
				
			|||
                            return event.target.value.replace(/\D/g, '') | 
				
			|||
                        }} | 
				
			|||
                        placeholder="请输入用户名(手机号)" | 
				
			|||
                        rules={[ | 
				
			|||
                            { required: true, valueType: Number, max: 11 }, { pattern: /^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$/, message: "请输入正确的手机号" } | 
				
			|||
                        ]} | 
				
			|||
                    /> | 
				
			|||
                </ProForm.Group> | 
				
			|||
                <ProForm.Group> | 
				
			|||
                    <ProFormTreeSelect | 
				
			|||
                        name={['contract', 'departmentId']} | 
				
			|||
                        placeholder="请选择所属部门" | 
				
			|||
                        width="md" | 
				
			|||
                        label="所属部门" | 
				
			|||
                        required | 
				
			|||
                        fieldNames={{ | 
				
			|||
                            title: 'name', | 
				
			|||
                            key: 'id', | 
				
			|||
                            children: 'subordinate' | 
				
			|||
                        }} | 
				
			|||
                        onSelect={(selectedKeys, { selected, selectedNodes }) => { | 
				
			|||
                            if (selected) { | 
				
			|||
                                setDepSelectedKeys(selectedKeys) | 
				
			|||
                                setDepSelected(selectedNodes[0].name || "") | 
				
			|||
                                dispatch(getDepUser(selectedKeys[0])) | 
				
			|||
                            } | 
				
			|||
                        }} | 
				
			|||
                        fieldProps={{ | 
				
			|||
                            fieldNames: { | 
				
			|||
                                label: 'title', | 
				
			|||
                            }, | 
				
			|||
                            treeDefaultExpandAll: false, | 
				
			|||
                        }} | 
				
			|||
                        rules={[{ required: true, message: '请选择所属部门' }]} | 
				
			|||
                        request={async () => { | 
				
			|||
                            console.log(depData); | 
				
			|||
                            return depData | 
				
			|||
                        }} | 
				
			|||
                        expandedKeys={["title"]} | 
				
			|||
                    /> | 
				
			|||
                    < ProFormText | 
				
			|||
                        name={['contract', 'post']} | 
				
			|||
                        width="md" | 
				
			|||
                        label="职位" | 
				
			|||
                        // required
 | 
				
			|||
                        placeholder="请输入职位" | 
				
			|||
                    /> | 
				
			|||
                </ProForm.Group> | 
				
			|||
                <ProForm.Group> | 
				
			|||
                    <ProFormText | 
				
			|||
                        name={['contract', 'email']} | 
				
			|||
                        width="md" | 
				
			|||
                        label="邮箱" | 
				
			|||
                        // required
 | 
				
			|||
                        placeholder="请输入邮箱" | 
				
			|||
                        rules={[ | 
				
			|||
                            // { required: true, message: '请输入邮箱' },
 | 
				
			|||
                            { type: 'email', message: '请输入正确格式的邮箱' }, | 
				
			|||
                        ]} | 
				
			|||
                    /> | 
				
			|||
                    {modalType == 'edit' ? null : <ProFormText.Password | 
				
			|||
                        name={['contract', 'password']} | 
				
			|||
                        width="md" | 
				
			|||
                        label="密码" | 
				
			|||
                        required | 
				
			|||
                        placeholder="请输入密码" | 
				
			|||
                        fieldProps={{ | 
				
			|||
                            autocomplete: 'new-password' | 
				
			|||
                        }} | 
				
			|||
                        rules={[ | 
				
			|||
                            { required: true, message: '请填写密码' }, | 
				
			|||
                            { min: 6, message: '请填写至少6位密码' }, | 
				
			|||
                        ]} | 
				
			|||
                    />} | 
				
			|||
                </ProForm.Group> | 
				
			|||
                <ProForm.Group> | 
				
			|||
                    <ProFormSwitch | 
				
			|||
                        name={['contract', 'enable']} | 
				
			|||
                        width="md" | 
				
			|||
                        label="是否启用" | 
				
			|||
                        placeholder="请选择" | 
				
			|||
                        // defaultChecked
 | 
				
			|||
                        valuePropName="checked" | 
				
			|||
                    /> | 
				
			|||
                </ProForm.Group> | 
				
			|||
            </ModalForm> | 
				
			|||
        </Spin> | 
				
			|||
    ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps(state) { | 
				
			|||
    const { depMessage } = state; | 
				
			|||
 | 
				
			|||
    const pakData = (dep) => { | 
				
			|||
        // console.log(dep);
 | 
				
			|||
        return dep.map((d) => { | 
				
			|||
            return { | 
				
			|||
                title: d.name, | 
				
			|||
                value: d.id, | 
				
			|||
                // key: d.id,
 | 
				
			|||
                children: pakData(d.subordinate) | 
				
			|||
            } | 
				
			|||
        }) | 
				
			|||
    } | 
				
			|||
    let depData = pakData(depMessage.data || []) | 
				
			|||
 | 
				
			|||
    return { | 
				
			|||
        loading: depMessage.isRequesting, | 
				
			|||
        depData, | 
				
			|||
    }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(UserModal); | 
				
			|||
@ -1,149 +0,0 @@ | 
				
			|||
import React, { useEffect, useState } from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { Spin, Row, Col, Card, Button, Tree, Empty } from 'antd'; | 
				
			|||
import { getDepMessage, getDepUser } from '../actions/user'; | 
				
			|||
import { getResource, getUserResource, postUserRes } from '../actions/authority'; | 
				
			|||
import Resource from '../components/resource'; | 
				
			|||
 | 
				
			|||
const Authority = (props) => { | 
				
			|||
   const { dispatch, loading, depMessage, depUser, resource, userResource, clientHeight } = props | 
				
			|||
   const [depSelectedKeys, setDepSelectedKeys] = useState([]) | 
				
			|||
   const [userSelectedKeys, setUserSelectedKeys] = useState([]) | 
				
			|||
   const [depSelected, setDepSelected] = useState() | 
				
			|||
   const [userSelected, setUserSelected] = useState() | 
				
			|||
   const [resCode, setResCode] = useState({}) | 
				
			|||
   const [useName, setUseName] = useState()// 选中名字
 | 
				
			|||
   const [userType, setUserType] = useState() | 
				
			|||
   console.log(resource) | 
				
			|||
   useEffect(() => { | 
				
			|||
      dispatch(getResource()) | 
				
			|||
      if (!(depMessage && depMessage.length)) { | 
				
			|||
         dispatch(getDepMessage()) | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
   }, []) | 
				
			|||
   useEffect(() => { | 
				
			|||
      if (depMessage.length) { | 
				
			|||
         setDepSelectedKeys([depMessage[0].id]) | 
				
			|||
         setDepSelected([depMessage[0].name]) | 
				
			|||
         dispatch(getDepUser(depMessage[0].id)) | 
				
			|||
      } | 
				
			|||
 | 
				
			|||
   }, [depMessage]) | 
				
			|||
   useEffect(() => { | 
				
			|||
      if (depUser.length) { | 
				
			|||
         setUserSelectedKeys([depUser[0].id]) | 
				
			|||
         setUserSelected(depUser[0].username) | 
				
			|||
         dispatch(getUserResource(depUser[0].id)) | 
				
			|||
         setUseName(depUser[0].name) | 
				
			|||
      } | 
				
			|||
      console.log(depUser, 'depUser') | 
				
			|||
   }, [depUser]) | 
				
			|||
 | 
				
			|||
   const handleSave = () => { | 
				
			|||
      dispatch(postUserRes({ userId: userSelectedKeys[0], resCode: resCode })).then(res => { | 
				
			|||
         if (res.success) { | 
				
			|||
            dispatch(getUserResource(userSelectedKeys[0])) | 
				
			|||
         } | 
				
			|||
      }) | 
				
			|||
   } | 
				
			|||
   return ( | 
				
			|||
      <Spin spinning={loading}> | 
				
			|||
         <Row gutter={16}> | 
				
			|||
            <Col span={4} style={{ height: '100%' }}> | 
				
			|||
               <Card title="部门" bordered={false} bodyStyle={{ padding: 8, paddingTop: 24 }}> | 
				
			|||
                  { | 
				
			|||
                     depMessage.length ? | 
				
			|||
                        <Tree | 
				
			|||
                           height={clientHeight - 100} | 
				
			|||
                           defaultExpandedKeys={[depMessage[0].id]} | 
				
			|||
                           selectedKeys={depSelectedKeys} | 
				
			|||
                           onSelect={(selectedKeys, { selected, selectedNodes, node }) => { | 
				
			|||
                              setUserType(selectedNodes[0].type) | 
				
			|||
                              if (selected) { | 
				
			|||
                                 setDepSelectedKeys(selectedKeys) | 
				
			|||
                                 setDepSelected(selectedNodes[0].name || "") | 
				
			|||
                                 dispatch(getDepUser(selectedKeys[0])) | 
				
			|||
                              } | 
				
			|||
 | 
				
			|||
                           }} | 
				
			|||
                           treeData={depMessage} | 
				
			|||
                           fieldNames={{ | 
				
			|||
                              title: 'name', | 
				
			|||
                              key: 'id', | 
				
			|||
                              children: 'subordinate' | 
				
			|||
                           }} | 
				
			|||
                        /> : '' | 
				
			|||
                  } | 
				
			|||
               </Card> | 
				
			|||
            </Col> | 
				
			|||
            <Col span={4} style={{ height: '100%', }}> | 
				
			|||
               <Card title={(depSelected ? `[${depSelected}]` : "") + '用户列表'} bordered={false} bodyStyle={{ padding: 8, paddingTop: 24 }}> | 
				
			|||
                  { | 
				
			|||
                     depUser.length ? | 
				
			|||
                        <Tree | 
				
			|||
                           height={clientHeight - 100} | 
				
			|||
                           defaultSelectedKeys={[depUser[0].id]} | 
				
			|||
                           selectedKeys={userSelectedKeys} | 
				
			|||
                           onSelect={(selectedKeys, { selected, selectedNodes, node, event }) => { | 
				
			|||
                              const name = node.name | 
				
			|||
                              setUseName(name) | 
				
			|||
 | 
				
			|||
                              if (selected) { | 
				
			|||
                                 setUserSelectedKeys(selectedKeys) | 
				
			|||
                                 setUserSelected(selectedNodes[0].username || '') | 
				
			|||
                                 dispatch(getUserResource(selectedKeys[0])) | 
				
			|||
                              } | 
				
			|||
 | 
				
			|||
                           }} | 
				
			|||
                           treeData={depUser} | 
				
			|||
                           fieldNames={{ | 
				
			|||
                              title: 'name', | 
				
			|||
                              key: 'id' | 
				
			|||
                           }} | 
				
			|||
                        /> : <Empty /> | 
				
			|||
                  } | 
				
			|||
               </Card> | 
				
			|||
            </Col> | 
				
			|||
            <Col span={16} style={{ height: '100%', }}> | 
				
			|||
               {depUser.length ? | 
				
			|||
                  <Card title={`[${useName ? useName : '管理员'}] 功能范围`} bordered={false} bodyStyle={{ padding: 8, paddingTop: 24 }}> | 
				
			|||
                     <Resource | 
				
			|||
                        userSelected={userSelected} | 
				
			|||
                        roleData={resource} | 
				
			|||
                        userRole={userResource} | 
				
			|||
                        setResCode={setResCode} | 
				
			|||
                        userType={userType} | 
				
			|||
                     /> | 
				
			|||
                     <Row type="flex" justify="center" style={{ marginBottom: 16, marginTop: 16, textAlign: 'center' }}> | 
				
			|||
                        <Col span="24"> | 
				
			|||
                           <Button | 
				
			|||
                              disabled={userSelected === "SuperAdmin" || userType === 4} | 
				
			|||
                              onClick={handleSave} | 
				
			|||
                              style={{ width: '60%' }} | 
				
			|||
                              type='primary'>保存修改</Button> | 
				
			|||
                        </Col></Row> | 
				
			|||
                  </Card> | 
				
			|||
                  : <Card title={`[]功能范围`} bordered={false} bodyStyle={{ padding: 8, paddingTop: 24 }}> | 
				
			|||
                     <Empty /> | 
				
			|||
                  </Card> | 
				
			|||
               } | 
				
			|||
            </Col> | 
				
			|||
         </Row> | 
				
			|||
      </Spin > | 
				
			|||
   ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps (state) { | 
				
			|||
   const { userResource, resource, depMessage, depUser, global } = state; | 
				
			|||
   return { | 
				
			|||
      clientHeight: global.clientHeight, | 
				
			|||
      loading: depMessage.isRequesting || depUser.isRequesting || resource.isRequesting, | 
				
			|||
      userResource: userResource.data || [], | 
				
			|||
      resource: resource.data || [], | 
				
			|||
      depMessage: depMessage.data || [], | 
				
			|||
      depUser: depUser.data || [] | 
				
			|||
   }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(Authority); | 
				
			|||
@ -1,6 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import Authority from './authority'; | 
				
			|||
import UserManage from './user'; | 
				
			|||
 | 
				
			|||
export { Authority, UserManage }; | 
				
			|||
@ -1,332 +0,0 @@ | 
				
			|||
import React, { useEffect, useState } from 'react'; | 
				
			|||
import { connect } from 'react-redux'; | 
				
			|||
import { FormOutlined, DeleteOutlined } from '@ant-design/icons'; | 
				
			|||
import { Spin, Tooltip, Button, Popconfirm, Row, Col, Tree, Card, Switch } from 'antd'; | 
				
			|||
import ProTable from '@ant-design/pro-table'; | 
				
			|||
import { getDepMessage, getDepUser, createUser, updateUser, delUser, resetPwd, createDept, updateDept, delDept } from '../actions/user'; | 
				
			|||
import UserModal from '../components/userModal'; | 
				
			|||
import ResetPwd from '../components/resetPwd'; | 
				
			|||
import DeptModal from '../components/deptModal'; | 
				
			|||
 | 
				
			|||
const TreeNode = Tree.TreeNode; | 
				
			|||
 | 
				
			|||
const UserManage = (props) => { | 
				
			|||
    const user = JSON.parse(sessionStorage.getItem('user')); | 
				
			|||
 | 
				
			|||
    const { dispatch, loading, depMessage, depUser, clientHeight } = props; | 
				
			|||
    // 部门
 | 
				
			|||
    const [deptModalVisible, setDeptModalVisible] = useState(false); | 
				
			|||
    const [deptModalType, setDeptModalType] = useState(); | 
				
			|||
    const [deptModalRecord, setDeptModalRecord] = useState(); | 
				
			|||
 | 
				
			|||
    // 成员
 | 
				
			|||
    const [modalVisible, setModalVisible] = useState(false); | 
				
			|||
    const [modalType, setModalType] = useState(); | 
				
			|||
    const [modalRecord, setModalRecord] = useState(); | 
				
			|||
    const [pwdModalVisible, setPwdModalVisible] = useState(false); | 
				
			|||
    const [depSelectedKeys, setDepSelectedKeys] = useState([]) | 
				
			|||
    const [rowSelected, setRowSelected] = useState([]) | 
				
			|||
 | 
				
			|||
    useEffect(() => { | 
				
			|||
        dispatch(getDepMessage()) | 
				
			|||
    }, []) | 
				
			|||
 | 
				
			|||
    useEffect(() => { | 
				
			|||
        if (depMessage.length) { | 
				
			|||
            setDepSelectedKeys([depMessage[0].id]) | 
				
			|||
            dispatch(getDepUser(depMessage[0].id)) | 
				
			|||
        } | 
				
			|||
    }, [depMessage]) | 
				
			|||
 | 
				
			|||
    const columns = [ | 
				
			|||
        { | 
				
			|||
            title: '姓名', | 
				
			|||
            dataIndex: 'name', | 
				
			|||
        }, { | 
				
			|||
            title: '用户名(手机号)', | 
				
			|||
            dataIndex: 'username', | 
				
			|||
        }, | 
				
			|||
        { | 
				
			|||
            title: '职位', | 
				
			|||
            dataIndex: 'post', | 
				
			|||
        }, { | 
				
			|||
            title: '邮箱', | 
				
			|||
            dataIndex: 'email', | 
				
			|||
        }, { | 
				
			|||
            title: '启用状态', | 
				
			|||
            dataIndex: 'enable', | 
				
			|||
            render: (_, r) => { | 
				
			|||
                return <Switch checkedChildren="启用" unCheckedChildren="禁用" disabled defaultChecked={r.enable} /> | 
				
			|||
            } | 
				
			|||
        }, { | 
				
			|||
            title: '操作', | 
				
			|||
            dataIndex: 'action', | 
				
			|||
            render: (dom, record) => { | 
				
			|||
 | 
				
			|||
                return record.username == 'SuperAdmin' ? '' : [ | 
				
			|||
                    <Button type="link" onClick={() => { openModal('edit', record) }}>编辑</Button>, | 
				
			|||
                    <Popconfirm | 
				
			|||
                        title="确认删除?" | 
				
			|||
                        onConfirm={() => { | 
				
			|||
                            delUsers([record.id]) | 
				
			|||
                        }} | 
				
			|||
                    > | 
				
			|||
                        <Button type="link">删除</Button> | 
				
			|||
                    </Popconfirm>, | 
				
			|||
                    <Button | 
				
			|||
                        type="link" | 
				
			|||
                        onClick={() => { | 
				
			|||
                            setModalRecord(record); | 
				
			|||
                            setPwdModalVisible(true); | 
				
			|||
                        }} | 
				
			|||
                    >重置密码</Button> | 
				
			|||
                ] | 
				
			|||
            }, | 
				
			|||
        }, | 
				
			|||
    ]; | 
				
			|||
 | 
				
			|||
    //弹窗确认
 | 
				
			|||
    const onConfirm = (values) => { | 
				
			|||
        if (modalType == 'edit') { | 
				
			|||
            dispatch(updateUser(modalRecord.id, values.contract)).then(res => { | 
				
			|||
                if (res.success) { | 
				
			|||
                    setModalVisible(false); | 
				
			|||
                    dispatch(getDepUser(depSelectedKeys[0])); | 
				
			|||
                } | 
				
			|||
            }); | 
				
			|||
        } else { | 
				
			|||
            dispatch(createUser(values.contract)).then(res => { | 
				
			|||
                if (res.success) { | 
				
			|||
                    setModalVisible(false); | 
				
			|||
                    dispatch(getDepUser(depSelectedKeys[0])); | 
				
			|||
                } | 
				
			|||
            }); | 
				
			|||
        } | 
				
			|||
 | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    //打开弹窗
 | 
				
			|||
    const openModal = (type, record) => { | 
				
			|||
        setModalVisible(true); | 
				
			|||
        setModalType(type); | 
				
			|||
        if (type == 'edit') { | 
				
			|||
            setModalRecord(record); | 
				
			|||
        } else { | 
				
			|||
            setModalRecord(null); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    //删除用户
 | 
				
			|||
    const delUsers = (ids, type) => { | 
				
			|||
        dispatch(delUser(ids)).then(res => { | 
				
			|||
            dispatch(getDepUser(depSelectedKeys[0])); | 
				
			|||
            if (type == 'batch') { | 
				
			|||
                setRowSelected([]); | 
				
			|||
            } | 
				
			|||
        }); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    //重置密码
 | 
				
			|||
    const onPwdConfirm = (values) => { | 
				
			|||
        dispatch(resetPwd(modalRecord.id, { password: values.password })).then(res => { | 
				
			|||
            if (res.success) { | 
				
			|||
                setPwdModalVisible(false); | 
				
			|||
                dispatch(getDepUser(depSelectedKeys[0])); | 
				
			|||
            } | 
				
			|||
        }); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    const openDeptModal = (type, record) => { | 
				
			|||
        console.log(type, record, 'type, record') | 
				
			|||
 | 
				
			|||
        setDeptModalVisible(true); | 
				
			|||
        setDeptModalType(type); | 
				
			|||
        if (type === 'edit') { | 
				
			|||
            setDeptModalRecord(record); | 
				
			|||
        } else { | 
				
			|||
            setDeptModalRecord(null); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
    const onDeptConfirm = (values) => { | 
				
			|||
        if (deptModalType === 'edit') { | 
				
			|||
            dispatch(updateDept(deptModalRecord.id, values.contract)).then(res => { | 
				
			|||
                if (res.success) { | 
				
			|||
                    setDeptModalVisible(false); | 
				
			|||
                    dispatch(getDepMessage()) | 
				
			|||
                } | 
				
			|||
            }); | 
				
			|||
        } else { | 
				
			|||
            dispatch(createDept(values.contract)).then(res => { | 
				
			|||
                if (res.success) { | 
				
			|||
                    setDeptModalVisible(false); | 
				
			|||
                    dispatch(getDepMessage()) | 
				
			|||
                } | 
				
			|||
            }); | 
				
			|||
        } | 
				
			|||
    } | 
				
			|||
    const delDepartment = (id) => { | 
				
			|||
        dispatch(delDept(id)).then(res => { | 
				
			|||
            if (res.success) { | 
				
			|||
                dispatch(getDepMessage()) | 
				
			|||
            } | 
				
			|||
        }); | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    const renderTree = (item, id) => { | 
				
			|||
        // let cannotDel = item.users.length || item.subordinate?.filter(is => is.users.length).length;//自己下面有成员 或者下级部门下有成员 不能删除
 | 
				
			|||
        return <div style={{ display: 'flex', width: '6vw', justifyContent: 'space-between' }}> | 
				
			|||
            <Tooltip title={item.name}> | 
				
			|||
                <div style={{ width: '70%', textOverflow: 'ellipsis', whiteSpace: 'nowrap', overflow: 'hidden' }}>{item.name}</div> | 
				
			|||
            </Tooltip> | 
				
			|||
            <div style={{ width: '30%' }} > | 
				
			|||
                { | 
				
			|||
                    depSelectedKeys == id && user.username === "SuperAdmin" ? | 
				
			|||
                        <> | 
				
			|||
                            <FormOutlined onClick={() => { | 
				
			|||
                                setDeptModalRecord(item) | 
				
			|||
                                setDeptModalVisible(true) | 
				
			|||
                                setDeptModalType('edit') | 
				
			|||
                            }} /> | 
				
			|||
                            { | 
				
			|||
                                <Popconfirm title='是否确认删除?' onConfirm={() => { delDepartment(id) }}> | 
				
			|||
                                    <DeleteOutlined style={{ marginLeft: 5 }} /> | 
				
			|||
                                </Popconfirm> | 
				
			|||
                            } | 
				
			|||
                        </> : null | 
				
			|||
                } | 
				
			|||
            </div> | 
				
			|||
        </div> | 
				
			|||
    } | 
				
			|||
 | 
				
			|||
    return (<div > | 
				
			|||
        <Spin spinning={loading} /* style={{ height: "calc(100vh - 70px)" }} */> | 
				
			|||
            <Row gutter={16} /* style={{ overflow: "scroll" }} */> | 
				
			|||
                <Col flex="260px" style={{ height: '100%' }}> | 
				
			|||
                    <Card title="部门" bordered={false} bodyStyle={{ padding: 8, paddingTop: 24, }}> | 
				
			|||
                        { | 
				
			|||
                            user.username === "SuperAdmin" && <Button | 
				
			|||
                                type="primary" | 
				
			|||
                                key="primary" | 
				
			|||
                                style={{ margin: '16px 0px' }} | 
				
			|||
                                onClick={() => openDeptModal('create')} | 
				
			|||
                            >新建部门</Button> | 
				
			|||
                        } | 
				
			|||
                        { | 
				
			|||
                            depMessage.length ? | 
				
			|||
                                <Tree | 
				
			|||
                                    height={clientHeight - 95} | 
				
			|||
                                    defaultExpandedKeys={[depMessage[0].id]} | 
				
			|||
                                    selectedKeys={depSelectedKeys} | 
				
			|||
                                    onSelect={(selectedKeys, e) => { | 
				
			|||
                                        if (e.selected) { | 
				
			|||
                                            setDepSelectedKeys(selectedKeys) | 
				
			|||
                                            dispatch(getDepUser(selectedKeys[0])) | 
				
			|||
                                        } | 
				
			|||
                                    }} | 
				
			|||
                                // treeData={depMessage}
 | 
				
			|||
                                // fieldNames={{
 | 
				
			|||
                                //     title: 'name',
 | 
				
			|||
                                //     key: 'id',
 | 
				
			|||
                                //     children: 'subordinate'
 | 
				
			|||
                                // }}
 | 
				
			|||
                                > | 
				
			|||
                                    { | 
				
			|||
                                        depMessage.map((s, index) => { | 
				
			|||
                                            return <TreeNode title={renderTree(s, s.id)} key={s.id} > | 
				
			|||
                                                { | 
				
			|||
                                                    s.subordinate.map(k => { | 
				
			|||
                                                        return <TreeNode title={renderTree(k, k.id)} key={k.id} onMouseOver={() => { setIShowIcon(k.id) }} onMouseOut={() => { setIShowIcon(null) }}> | 
				
			|||
                                                        </TreeNode> | 
				
			|||
                                                    }) | 
				
			|||
                                                } | 
				
			|||
                                            </TreeNode> | 
				
			|||
                                        }) | 
				
			|||
                                    } | 
				
			|||
                                </Tree> : '' | 
				
			|||
                        } | 
				
			|||
                    </Card> | 
				
			|||
                </Col> | 
				
			|||
 | 
				
			|||
                <Col /* flex="auto" */ style={{ width: "calc(100% - 260px)", height: '100%', display: "black" }}> | 
				
			|||
                    <Card title="用户" bordered={false} height={clientHeight} bodyStyle={{ padding: 8, paddingTop: 24, overflow: "hidden", width: "100%" }}> | 
				
			|||
                        <ProTable | 
				
			|||
                            columns={columns} | 
				
			|||
                            dataSource={depUser} | 
				
			|||
                            style={{ width: "100% ", height: clientHeight - 95, overflow: "auto" }} | 
				
			|||
                            rowSelection={{ | 
				
			|||
                                selectedRowKeys: rowSelected, | 
				
			|||
                                onChange: (selectedRowKeys) => { | 
				
			|||
                                    setRowSelected(selectedRowKeys); | 
				
			|||
 | 
				
			|||
                                }, | 
				
			|||
                                getCheckboxProps: (record) => { | 
				
			|||
                                    return { | 
				
			|||
                                        disabled: record.username === 'SuperAdmin', | 
				
			|||
                                    } | 
				
			|||
                                }, | 
				
			|||
                            }} | 
				
			|||
                            options={false} | 
				
			|||
                            search={false} | 
				
			|||
                            rowKey="id" | 
				
			|||
                            toolBarRender={() => [ | 
				
			|||
                                <span> | 
				
			|||
                                    <Button | 
				
			|||
                                        type="primary" | 
				
			|||
                                        key="primary" | 
				
			|||
                                        style={{ marginRight: 10 }} | 
				
			|||
                                        onClick={() => openModal('create')} | 
				
			|||
                                    >新建用户</Button> | 
				
			|||
                                    <Button style={{ marginRight: 10 }} onClick={() => { dispatch(getDepUser(depSelectedKeys[0])); }}>刷新</Button> | 
				
			|||
                                    <Popconfirm title="确认删除?" onConfirm={() => { delUsers(rowSelected, 'batch') }}> | 
				
			|||
                                        <Button>批量删除</Button> | 
				
			|||
                                    </Popconfirm> | 
				
			|||
                                </span> | 
				
			|||
                            ]} | 
				
			|||
                        /> | 
				
			|||
                    </Card> | 
				
			|||
                    { | 
				
			|||
                        deptModalVisible ? | 
				
			|||
                            <DeptModal | 
				
			|||
                                visible={deptModalVisible} | 
				
			|||
                                onVisibleChange={setDeptModalVisible} | 
				
			|||
                                modalType={deptModalType} | 
				
			|||
                                onConfirm={onDeptConfirm} | 
				
			|||
                                editData={deptModalRecord} | 
				
			|||
                                depts={depMessage} | 
				
			|||
                            /> | 
				
			|||
                            : '' | 
				
			|||
                    } | 
				
			|||
                    { | 
				
			|||
                        depMessage.length && modalVisible ? | 
				
			|||
                            <UserModal | 
				
			|||
                                visible={modalVisible} | 
				
			|||
                                onVisibleChange={setModalVisible} | 
				
			|||
                                modalType={modalType} | 
				
			|||
                                onConfirm={onConfirm} | 
				
			|||
                                editData={modalRecord} | 
				
			|||
                            /> | 
				
			|||
                            : '' | 
				
			|||
                    } | 
				
			|||
                    {pwdModalVisible ? <ResetPwd visible={pwdModalVisible} | 
				
			|||
                        onVisibleChange={setPwdModalVisible} | 
				
			|||
                        onConfirm={onPwdConfirm} /> : ''} | 
				
			|||
 | 
				
			|||
                </Col> | 
				
			|||
            </Row> | 
				
			|||
        </Spin> | 
				
			|||
    </div> | 
				
			|||
 | 
				
			|||
    ) | 
				
			|||
} | 
				
			|||
 | 
				
			|||
function mapStateToProps(state) { | 
				
			|||
    const { depMessage, depUser, global } = state; | 
				
			|||
    return { | 
				
			|||
        clientHeight: global.clientHeight, | 
				
			|||
        loading: depMessage.isRequesting, | 
				
			|||
        depMessage: depMessage.data || [], | 
				
			|||
        depUser: depUser.data || [] | 
				
			|||
    }; | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export default connect(mapStateToProps)(UserManage); | 
				
			|||
@ -1,22 +0,0 @@ | 
				
			|||
import React from 'react'; | 
				
			|||
import { Link } from 'react-router-dom'; | 
				
			|||
import { Menu } from 'antd'; | 
				
			|||
import { SettingOutlined } from '@ant-design/icons'; | 
				
			|||
 | 
				
			|||
const SubMenu = Menu.SubMenu; | 
				
			|||
 | 
				
			|||
export function getNavItem(user, dispatch) { | 
				
			|||
    // if (!Func.isAuthorized("ORG_MANAGE")) {
 | 
				
			|||
    //     return null
 | 
				
			|||
    // }
 | 
				
			|||
    return ( | 
				
			|||
        <SubMenu key="organization" icon={<SettingOutlined />} title={'组织管理'}> | 
				
			|||
            <Menu.Item key="userManage"> | 
				
			|||
                <Link to="/organization/user">部门成员</Link> | 
				
			|||
            </Menu.Item> | 
				
			|||
            <Menu.Item key="authority"> | 
				
			|||
                <Link to="/organization/authority">权限配置</Link> | 
				
			|||
            </Menu.Item> | 
				
			|||
        </SubMenu> | 
				
			|||
    ); | 
				
			|||
} | 
				
			|||
@ -1,26 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
import { UserManage, Authority } from './containers'; | 
				
			|||
 | 
				
			|||
export default [{ | 
				
			|||
    type: 'inner', | 
				
			|||
    route: { | 
				
			|||
        path: '/organization', | 
				
			|||
        key: 'organization', | 
				
			|||
        breadcrumb: '组织管理', | 
				
			|||
        menuSelectKeys: ['userManage'], | 
				
			|||
        menuOpenKeys: ['organization'], | 
				
			|||
        childRoutes: [{ | 
				
			|||
            path: '/user', | 
				
			|||
            key: 'userManage', | 
				
			|||
            menuSelectKeys: ['userManage'], | 
				
			|||
            component: UserManage, | 
				
			|||
            breadcrumb: '部门成员', | 
				
			|||
        }, { | 
				
			|||
            path: '/authority', | 
				
			|||
            key: 'authority', | 
				
			|||
            component: Authority, | 
				
			|||
            menuSelectKeys: ['authority'], | 
				
			|||
            breadcrumb: '权限配置', | 
				
			|||
        }] | 
				
			|||
    } | 
				
			|||
}]; | 
				
			|||
@ -1,9 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import * as plan from './plan' | 
				
			|||
import * as record from './record' | 
				
			|||
 | 
				
			|||
export default { | 
				
			|||
    ...plan, | 
				
			|||
    ...record, | 
				
			|||
} | 
				
			|||
@ -1,80 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import { basicAction } from '@peace/utils' | 
				
			|||
import { ApiTable } from '$utils' | 
				
			|||
 | 
				
			|||
export function getPatrolPlan() { | 
				
			|||
    return dispatch => basicAction({ | 
				
			|||
        type: 'get', | 
				
			|||
        dispatch: dispatch, | 
				
			|||
        actionType: 'GET_PATROL_PLAN', | 
				
			|||
        url: ApiTable.patrolPlan, | 
				
			|||
        msg: { error: '获取巡检计划失败' }, | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export function createPatrolPlan(data) { | 
				
			|||
    return dispatch => basicAction({ | 
				
			|||
        type: 'post', | 
				
			|||
        data, | 
				
			|||
        dispatch: dispatch, | 
				
			|||
        actionType: 'CREATE_PATROL_PLAN', | 
				
			|||
        url: ApiTable.patrolPlan, | 
				
			|||
        msg: { error: '新增巡检计划失败' }, | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export function delPatrolPlan(id) { | 
				
			|||
    return dispatch => basicAction({ | 
				
			|||
        type: 'del', | 
				
			|||
        dispatch: dispatch, | 
				
			|||
        actionType: 'DEL_PATROL_PLAN', | 
				
			|||
        url: ApiTable.delPatrolPlan.replace('{id}', id), | 
				
			|||
        msg: { error: '删除巡检计划失败' }, | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export function updatePatrolPlan(data) { | 
				
			|||
    return dispatch => basicAction({ | 
				
			|||
        type: 'put', | 
				
			|||
        data, | 
				
			|||
        dispatch: dispatch, | 
				
			|||
        actionType: 'UPDATE_PATROL_PLAN', | 
				
			|||
        url: ApiTable.patrolPlan, | 
				
			|||
        msg: { error: '修改巡检计划失败' }, | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export function getUserList() { | 
				
			|||
    return dispatch => basicAction({ | 
				
			|||
        type: 'get', | 
				
			|||
        dispatch: dispatch, | 
				
			|||
        actionType: 'GET_USER_LIST', | 
				
			|||
        url: ApiTable.getDepUser.replace('{depId}', null), | 
				
			|||
        msg: { error: '获取人员列表失败' }, | 
				
			|||
        reducer: { name: 'userList' } | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export function getProjectList(query) { | 
				
			|||
    return (dispatch) => basicAction({ | 
				
			|||
        type: 'get', | 
				
			|||
        query, | 
				
			|||
        dispatch, | 
				
			|||
        actionType: 'GET_PROJEECT_LIST', | 
				
			|||
        url: ApiTable.getProjectList, | 
				
			|||
        msg: { error: '获取结构物列表失败', }, | 
				
			|||
        reducer: { name: 'structureList' } | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
 | 
				
			|||
export function positionList(query) { | 
				
			|||
    return (dispatch) => basicAction({ | 
				
			|||
        type: 'get', | 
				
			|||
        query, | 
				
			|||
        dispatch, | 
				
			|||
        actionType: 'POSITION_LIST', | 
				
			|||
        url: ApiTable.position, | 
				
			|||
        msg: { error: '获取点位列表失败', }, | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||
@ -1,17 +0,0 @@ | 
				
			|||
'use strict'; | 
				
			|||
 | 
				
			|||
import { basicAction } from '@peace/utils' | 
				
			|||
 | 
				
			|||
export const GET_PATROL_RECORD_LIST = 'GET_PATROL_RECORD_LIST'; | 
				
			|||
export const GET_PATROL_RECORD_LIST_SUCCESS = 'GET_PATROL_RECORD_LIST_SUCCESS'; | 
				
			|||
export const GET_PATROL_RECORD_LIST_ERROR = 'GET_PATROL_RECORD_LIST_ERROR'; | 
				
			|||
export function records(url) { | 
				
			|||
    return (dispatch) => basicAction({ | 
				
			|||
        type: 'get', | 
				
			|||
        dispatch, | 
				
			|||
        actionType: GET_PATROL_RECORD_LIST, | 
				
			|||
        url: url, | 
				
			|||
        msg: { error: '获取巡检记录失败', }, | 
				
			|||
        reducer: { name: 'record' } | 
				
			|||
    }); | 
				
			|||
} | 
				
			|||