Browse Source

能耗

master
wenlele 2 years ago
parent
commit
24a294a129
  1. 18
      api/.vscode/launch.json
  2. 67
      api/app/lib/controllers/bigScreen/index .js
  3. 87
      api/app/lib/controllers/organization/authority.js
  4. 389
      api/app/lib/controllers/organization/user.js
  5. 4
      api/app/lib/index.js
  6. 28
      api/app/lib/routes/organization/authority.js
  7. 9
      api/app/lib/routes/organization/index.js
  8. 41
      api/app/lib/routes/organization/user.js
  9. 53
      api/app/lib/schedule/clearExpiredData.js
  10. 208
      api/app/lib/schedule/hideDangerStatistic.js
  11. 64
      api/app/lib/schedule/metting.js
  12. 65
      api/config.js
  13. BIN
      web/client/assets/images/login/button-b.png
  14. BIN
      web/client/assets/images/login/icon_y.png
  15. BIN
      web/client/assets/images/login/icon_z.png
  16. BIN
      web/client/assets/images/login/input-b.png
  17. BIN
      web/client/assets/images/login/login-b.gif
  18. BIN
      web/client/assets/images/login/login_a.png
  19. BIN
      web/client/assets/images/login/login_b.png
  20. BIN
      web/client/assets/images/login/register-bg.png
  21. BIN
      web/client/assets/images/login/word.png
  22. BIN
      web/client/assets/images/monitor/ball-A.png
  23. BIN
      web/client/assets/images/monitor/ball-V.png
  24. BIN
      web/client/assets/images/monitor/bg-header.png
  25. BIN
      web/client/assets/images/monitor/headerTitle.png
  26. BIN
      web/client/assets/images/monitor/pedestal.png
  27. BIN
      web/client/assets/images/monitor/pump-head.png
  28. BIN
      web/client/assets/images/monitor/site.png
  29. BIN
      web/client/assets/images/monitor/title.png
  30. 4
      web/client/src/layout/actions/global.js
  31. 17
      web/client/src/layout/reducers/global.js
  32. 8
      web/client/src/sections/auth/actions/auth.js
  33. 60
      web/client/src/sections/auth/containers/login.js
  34. 28
      web/client/src/sections/auth/containers/login.less
  35. 51
      web/client/src/sections/bigScreen/actions/authority.js
  36. 19
      web/client/src/sections/bigScreen/actions/bigScreen.js
  37. 9
      web/client/src/sections/bigScreen/actions/index.js
  38. 113
      web/client/src/sections/bigScreen/actions/user.js
  39. 663
      web/client/src/sections/bigScreen/components/capacity.js
  40. 6
      web/client/src/sections/bigScreen/components/header.js
  41. 13
      web/client/src/sections/bigScreen/components/index.less
  42. 5
      web/client/src/sections/bigScreen/containers/systemManagement.js
  43. 2
      web/client/src/sections/bigScreen/index.js
  44. 5
      web/client/src/utils/index.js
  45. 121
      web/client/src/utils/webapi.js
  46. 59
      web/config.js
  47. 5
      web/package.json
  48. 220
      web/routes/attachment/index.js

18
api/.vscode/launch.json

@ -18,15 +18,17 @@
"-g postgres://postgres:123456@10.8.30.166:5432/XunJian", "-g postgres://postgres:123456@10.8.30.166:5432/XunJian",
// //
// "--apiEmisUrl http://10.8.30.161:1111", // "--apiEmisUrl http://10.8.30.161:1111",
"--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5", // "--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5",
"--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa", // "--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa",
"--qnbkt dev-hr", // "--qnbkt dev-hr",
// "--qndmn http://resources.anxinyun.cn", // "--qndmn http://resources.anxinyun.cn",
"--qndmn http://rjkwed13l.hn-bkt.clouddn.com", // "--qndmn http://rjkwed13l.hn-bkt.clouddn.com",
"--aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw", // "--aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw",
"--aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv", // "--aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv",
"--aliOssBucket test-c371", // "--aliOssBucket test-c371",
"--aliOssRegion oss-cn-hangzhou", // "--aliOssRegion oss-cn-hangzhou",
"--apiAnxinyunUrl https://openapi.anxinyun.cn/api/v1",
"--axyProject 1a271f12-52f2-4d16-8dad-ec0c92d3e0cc/03bzzdh/123456",
] ]
}, },
{ {

67
api/app/lib/controllers/bigScreen/index .js

@ -0,0 +1,67 @@
'use strict';
const Hex = require('crypto-js/enc-hex');
const MD5 = require('crypto-js/md5');
const moment = require('moment');
let axyTokenCache = {
token: null,
orgId: null,
expireTime: null //过期时间
}
const getAnxinyunToken = async function (ctx) {
try {
if (!axyTokenCache.token || moment() > moment(axyTokenCache.expireTime)) {
if (ctx.app.fs.opts.axyProject.split('/').length === 3) {
const dataToAxy = {
p: ctx.app.fs.opts.axyProject.split('/')[0],
username: ctx.app.fs.opts.axyProject.split('/')[1],
password: ctx.app.fs.opts.axyProject.split('/')[2],
}
const axyResponse = await ctx.app.fs.anxinyun.post('project/login', { data: dataToAxy })
if (axyResponse.authorized) {
axyTokenCache.token = axyResponse.token //放进缓存
axyTokenCache.orgId = axyResponse.orgId //放进缓存
axyTokenCache.expireTime = moment().add(20, 'hour').format('YYYY-MM-DD HH:mm:ss')
}
}
}
return axyTokenCache
} catch (error) {
ctx.fs.logger.error(`sechedule: laborAttendance, error: ${error}`);
}
}
async function axyData (ctx, next) {
try {
let { type, url, params = {} } = ctx.request.body;
let data = await getAnxinyunToken(ctx)
if (url && url.indexOf('{orgId}') != -1) {
url = url.replace(`{orgId}`, data.orgId)
}
const res = await ctx.app.fs.anxinyun[type](`${url}?token=${data.token}`, { data: params.data || {}, query: params.query || {} })
ctx.status = 200;
ctx.body = res;
} catch (err) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${err}`);
ctx.status = 400;
ctx.body = { name: 'FindError', message: '获取安心云数据失败' };
}
}
module.exports = {
axyData,
}

87
api/app/lib/controllers/organization/authority.js

@ -1,87 +0,0 @@
async function getResource(ctx, next) {
try {
const models = ctx.fs.dc.models;
const res = await models.Resource.findAll({
where: { parentResource: null },
include: [{
model: models.Resource,
}]
})
ctx.body = res;
ctx.status = 200;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "查询所有权限数据失败"
}
}
}
async function getUserResource(ctx, next) {
try {
const models = ctx.fs.dc.models;
const { userId } = ctx.query;
const res = await models.UserResource.findAll({
where: { userId: userId },
include: [{
model: models.Resource,
}]
})
ctx.body = res;
ctx.status = 200;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "查询用户权限数据失败"
}
}
}
async function updateUserRes(ctx, next) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
const { userId, resCode } = ctx.request.body;
const res = await models.UserResource.findAll({
attributes: ["resourceId"],
raw: true,
where: { userId: userId }
})
const addRes = resCode.filter(r => !res.some(rr => rr.resourceId == r)).map(r => { return { userId: userId, resourceId: r } });
const delRes = res.filter(r => !resCode.includes(r.resourceId)).map(r => r.resourceId);
addRes.length && await models.UserResource.bulkCreate(addRes, { transaction: transaction });
delRes.length && await models.UserResource.destroy({
where: {
resourceId: { $in: delRes },
userId: userId
},
transaction: transaction
})
ctx.status = 204;
await transaction.commit();
} catch (error) {
await transaction.rollback();
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "更新用户权限数据失败"
}
}
}
module.exports = {
getResource,
getUserResource,
updateUserRes
};

389
api/app/lib/controllers/organization/user.js

@ -1,389 +0,0 @@
'use strict';
const Hex = require('crypto-js/enc-hex');
const MD5 = require('crypto-js/md5');
// async function getDepMessage (ctx, next) {
// try {
// const { fs: { api: { userInfo } } } = ctx
// const models = ctx.fs.dc.models;
// let deptWhere = {}
// if (userInfo.username !== 'SuperAdmin') {
// deptWhere.id = userInfo.departmentId
// }
// let depType1 = await models.Department.findAll({
// order: [['id', 'asc']],
// // include: [{
// // model: models.User,
// // required: false,
// // where: { delete: false },
// // attributes: { exclude: ['password'] },
// // }],
// where: deptWhere,
// })
// let depRslt = []
// const getDep = async (d) => {
// let subordinate = []
// let depRes = await models.Department.findAll({
// order: [['id', 'asc']],
// // include: [{
// // model: models.User,
// // required: false,
// // where: { delete: false },
// // attributes: { exclude: ['password'] },
// // }],
// where: {
// dependence: d.id
// },
// })
// if (depRes.length)
// for (let d of depRes) {
// let dep = d.dataValues
// dep.subordinate = await getDep(d.dataValues)
// subordinate.push(dep)
// }
// return subordinate
// }
// for (let d of depType1) {
// let dep_1 = d.dataValues
// dep_1.subordinate = await getDep(d.dataValues)
// depRslt.push(dep_1)
// }
// ctx.status = 200;
// ctx.body = depRslt
// } catch (error) {
// ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
// ctx.status = 400;
// ctx.body = {
// "message": "获取部门信息失败"
// }
// }
// }
async function getDepMessage(ctx, next) {
let error = { name: 'FindError', message: '获取部门列表失败' };
let rslt = [];
try {
const models = ctx.fs.dc.models;
let list = await models.Department.findAll({});
let deptMap = []
list.filter(l => !l.dependence).map(ld => {//一级
deptMap.push({
id: ld.id,
name: ld.name,
dependence: ld.dependence,
subordinate: []
})
})
list.filter(l => l.dependence).map(ld => {//二级
let parent = deptMap.find(dm => dm.id == ld.dependence);
if (parent) {
parent.subordinate.push({
id: ld.id,
name: ld.name,
dependence: ld.dependence,
subordinate: []
})
}
})
rslt = deptMap;
error = null;
} catch (err) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${err}`);
}
if (error) {
ctx.status = 400;
ctx.body = error;
} else {
ctx.status = 200;
ctx.body = rslt;
}
}
async function createDept(ctx, next) {
const models = ctx.fs.dc.models;
try {
let rslt = ctx.request.body;
await models.Department.create(Object.assign({}, rslt, { read: 1 }))
ctx.status = 204;
ctx.body = { message: '新建部门成功' }
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '新建部门失败' }
}
}
async function updateDept(ctx, next) {
try {
const models = ctx.fs.dc.models;
const { id } = ctx.params;
const body = ctx.request.body;
await models.Department.update(
body,
{ where: { id: id } }
)
ctx.status = 204;
ctx.body = { message: '修改部门成功' }
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: '修改部门失败' }
}
}
async function delDept(ctx, next) {
let errMsg = "删除部门失败";
try {
const models = ctx.fs.dc.models;
const { id } = ctx.params;
let list = await models.Department.findAll({});
let deptIds = list.map(l => l.id);
const allUsers = await models.User.findAll({
where: {
departmentId: { $in: deptIds },
delete: false
}
})
const childrenDept = await models.Department.findAll({ where: { dependence: id } })
const childrenUser = allUsers.filter(au => au.departmentId == id);
if (childrenUser.length || childrenDept.length) {
errMsg = '请先删除部门下的用户或子部门';
throw errMsg;
}
await models.Department.destroy({ where: { id: id } });
await models.Department.destroy({ where: { dependence: id } });
ctx.status = 204;
ctx.body = { message: '删除部门成功' }
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = { message: error }
}
}
async function getUser(ctx, next) {
try {
const models = ctx.fs.dc.models;
const { depId } = ctx.params;
let userRes = null;
if (depId !== 'null') {
userRes = await models.User.findAll({
where: {
departmentId: parseInt(depId),
delete: false
},
attributes: { exclude: ['password'] },
order: [['id', 'asc']],
})
} else {
userRes = await models.User.findAll({
where: {
delete: false
},
attributes: { exclude: ['password'] },
order: [['id', 'asc']],
include: [{
required: true,
model: models.Department,
attributes: ['id', 'name'],
}]
})
}
ctx.status = 200;
ctx.body = userRes
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "获取用户信息失败"
}
}
}
async function creatUser(ctx, next) {
let errMsg = "新建用户失败"
try {
const models = ctx.fs.dc.models;
const data = ctx.request.body;
let repeatUserNameCount = await models.User.count({
where: {
username: data.phone,
delete: false
}
})
if (repeatUserNameCount) {
errMsg = '已有当前用户名'
throw errMsg
}
await models.User.create({
name: data.name,
username: data.phone,
password: Hex.stringify(MD5(data.password)),
departmentId: data.departmentId,
email: data.email,
enable: data.enable,
delete: false,
phone: data.phone,
post: data.post,
})
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": errMsg
}
}
}
async function updateUser(ctx, next) {
let errMsg = "修改用户失败"
try {
const models = ctx.fs.dc.models;
const data = ctx.request.body;
const { id } = ctx.params;
let repeatUserNameCount = await models.User.count({
where: {
username: data.username
}
})
if (repeatUserNameCount) {
errMsg = '已有当前用户名'
throw errMsg
}
await models.User.update({
name: data.name,
username: data.phone,
departmentId: data.departmentId,
email: data.email,
enable: data.enable,
delete: false,
phone: data.phone,
post: data.post,
}, {
where: {
id: id
}
});
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": errMsg
}
}
}
async function deleteUser(ctx, next) {
try {
const models = ctx.fs.dc.models;
const { ids } = ctx.params;
const userIds = ids.split(',');
await models.User.update({
delete: true,
}, {
where: {
id: { $in: userIds },
}
});
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "删除用户失败"
}
}
}
async function resetPwd(ctx, next) {
try {
const models = ctx.fs.dc.models;
const { id } = ctx.params;
const data = ctx.request.body;
await models.User.update({
password: Hex.stringify(MD5(data.password)),
}, {
where: {
id: id,
}
});
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "重置用户密码失败"
}
}
}
/**
* 修改用户密码
* @params {userId-用户Id} ctx
* @request.body {password-用户新密码} ctx
*/
async function updateUserPassword(ctx, next) {
try {
const models = ctx.fs.dc.models;
const { userId } = ctx.params;
const { password } = ctx.request.body;
if (!password) {
ctx.status = 400;
ctx.body = { "message": "请输入修改密码" };
return;
}
const userRes = await models.User.findOne({
where: {
id: userId
},
attributes: ['id']
});
if (userRes) {
await models.User.update({ password: Hex.stringify(MD5(password)) }, { where: { id: userId, } });
ctx.status = 204;
} else {
ctx.status = 400;
ctx.body = {
"message": "用户不存在"
}
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
"message": "修改用户密码失败"
}
}
}
module.exports = {
getDepMessage,
createDept,
updateDept,
delDept,
getUser,
creatUser,
updateUser,
deleteUser,
resetPwd,
updateUserPassword
}

4
api/app/lib/index.js

@ -6,7 +6,7 @@ const utils = require('./utils')
const routes = require('./routes'); const routes = require('./routes');
//const redisConnect = require('./service/redis') //const redisConnect = require('./service/redis')
const socketConect = require('./service/socket') const socketConect = require('./service/socket')
//const paasRequest = require('./service/paasRequest'); const paasRequest = require('./service/paasRequest');
const authenticator = require('./middlewares/authenticator'); const authenticator = require('./middlewares/authenticator');
//const clickHouseClient = require('./service/clickHouseClient') //const clickHouseClient = require('./service/clickHouseClient')
const schedule = require('./schedule') const schedule = require('./schedule')
@ -26,7 +26,7 @@ module.exports.entry = function (app, router, opts) {
socketConect(app, opts) socketConect(app, opts)
// 实例其他平台请求方法 // 实例其他平台请求方法
//paasRequest(app, opts) paasRequest(app, opts)
// clickHouse 数据库 client // clickHouse 数据库 client
//clickHouseClient(app, opts) //clickHouseClient(app, opts)

28
api/app/lib/routes/organization/authority.js

@ -1,28 +0,0 @@
'use strict';
const Authority = require('../../controllers/organization/authority');
module.exports = function (app, router, opts) {
/**
* @api {GET} resource 查询所有权限码.
* @apiVersion 1.0.0
* @apiGroup Org
*/
app.fs.api.logAttr['GET/resource'] = { content: '查询所有权限码', visible: true };
router.get('resource', Authority.getResource);
/**
* @api {GET} user/resource 查询用户权限.
* @apiVersion 1.0.0
* @apiGroup Org
*/
app.fs.api.logAttr['GET/user/resource'] = { content: '查询用户权限', visible: true };
router.get('user/resource', Authority.getUserResource);
/**
* @api {POST} user/resource 更新用户权限.
* @apiVersion 1.0.0
* @apiGroup Org
*/
app.fs.api.logAttr['POST/user/resource'] = { content: '更新用户权限', visible: true };
router.post('user/resource', Authority.updateUserRes);
};

9
api/app/lib/routes/organization/index.js

@ -0,0 +1,9 @@
'use strict';
const data = require('../../controllers/bigScreen/index ');
module.exports = function (app, router, opts) {
app.fs.api.logAttr['POST/axyData'] = { content: '获取安心云数据', visible: true };
router.post('/axyData', data.axyData);
};

41
api/app/lib/routes/organization/user.js

@ -1,41 +0,0 @@
'use strict';
const user = require('../../controllers/organization/user');
module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/organization/department'] = { content: '获取部门信息', visible: false };
router.get('/organization/department', user.getDepMessage);
app.fs.api.logAttr['POST/organization/dept/add'] = { content: '新增部门', visible: true };
router.post('/organization/dept/add', user.createDept);
app.fs.api.logAttr['PUT/organization/dept/:id/modify'] = { content: '修改部门', visible: true };
router.put('/organization/dept/:id/modify', user.updateDept);
app.fs.api.logAttr['DELETE/organization/dept/:id'] = { content: '删除部门', visible: true };
router.del('/organization/dept/:id', user.delDept);
app.fs.api.logAttr['GET/organization/department/:depId/user'] = { content: '获取部门下用户信息', visible: false };
router.get('/organization/department/:depId/user', user.getUser);
app.fs.api.logAttr['POST/organization/department/user'] = { content: '创建部门下用户信息', visible: false };
router.post('/organization/department/user', user.creatUser);
app.fs.api.logAttr['PUT/organization/department/user/:id'] = { content: '修改部门下用户信息', visible: false };
router.put('/organization/department/user/:id', user.updateUser);
app.fs.api.logAttr['DEL/organization/department/user/:ids'] = { content: '删除部门下用户信息', visible: false };
router.del('/organization/department/user/:ids', user.deleteUser);
app.fs.api.logAttr['PUT/organization/department/user/resetPwd/:id'] = { content: '重置用户密码', visible: false };
router.put('/organization/department/user/resetPwd/:id', user.resetPwd);
/**
* @api {PUT} user/password/:id 修改用户密码
* @apiVersion 1.0.0
* @apiGroup Organization
*/
app.fs.api.logAttr['PUT/user/password/:userId'] = { content: '修改用户密码', visible: false };
router.put('/user/password/:userId', user.updateUserPassword);
};

53
api/app/lib/schedule/clearExpiredData.js

@ -1,53 +0,0 @@
const moment = require('moment')
const rimraf = require('rimraf');
const fs = require("fs");
const path = require("path")
let TEST = false
// TEST = true
module.exports = function (app, opts) {
const clearExpiredData = app.fs.scheduleInit(
{
interval: '42 24 4 */3 * *',
immediate: TEST,
proRun: !TEST,
},
async () => {
try {
const { models } = app.fs.dc
const now = moment().format('YYYY-MM-DD HH:mm:ss')
await models.UserToken.destroy({
where: {
expired: { $lt: now }
}
})
await models.PhoneValidateCode.destroy({
where: {
expired: { $lt: now }
}
})
fs.readdir(path.join(__dirname, `../../downloadFiles`), function (err, files) {
if (err) {
return;
}
files.forEach((file) => {
fs.stat(path.join(__dirname, `../../downloadFiles/${file}`), (err, stats) => {
if (err) {
//return;
} else {
rimraf.sync(path.join(__dirname, `../../downloadFiles/${file}`));
}
});
});
});
} catch (error) {
app.fs.logger.error(`sechedule: clearExpiredToken, error: ${error}`);
}
}
);
return {
clearExpiredData
}
}

208
api/app/lib/schedule/hideDangerStatistic.js

@ -1,208 +0,0 @@
const fs = require('fs');
const moment = require('moment')
const path = require('path')
const OSS = require('ali-oss');
const uuid = require('uuid');
const TEST = false
// const TEST = true
module.exports = function (app, opts) {
const hideDangerStatistic = app.fs.scheduleInit(
// 按月、季度、年统计隐患整改
{
interval: '0 32 4 1 */1 *',
immediate: TEST,
proRun: !TEST,
},
async () => {
const { aliOss } = opts
const { utils: { simpleExcelDown } } = app.fs;
try {
const { models } = app.fs.dc
const today = moment()
const date = today.date()
const month = today.month() + 1
const quarter = today.quarter()
const year = today.year()
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: aliOss.region,
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
accessKeyId: aliOss.accessKey,
accessKeySecret: aliOss.secretKey,
// 填写Bucket名称,例如examplebucket。
bucket: aliOss.bucket,
});
const statistic = async (startTime, endTime, type, timeShow, typeEnglish, time) => {
const siteRectifyRes = await models.HideDangerRectifySites.findAll({
where: {},
distinct: true,
include: [{
model: models.Site,
attributes: ['id', 'name'],
}, {
model: models.HideDangerDispose,
order: [['id', 'ASC']],
// include: [{
// model: models.User,
// attributes: ['id', 'displayName'],
// }]
}, {
model: models.HideDangerRectify,
where: {
createTime: {
$between: [
startTime.format('YYYY-MM-DD HH:mm:ss'),
endTime.format('YYYY-MM-DD HH:mm:ss')
]
}
},
},]
})
let reportHeader = [{
title: "工程项目名称",
key: "siteName",
}, {
title: "整改任务名称",
key: "name",
}, {
title: "提交时间",
key: "submitTime",
}, {
title: "审批状态",
key: "state",
},]
let reportData = []
let siteMap = new Set()
let completedRectifyCount = 0
let uncompletedRectifyCount = 0
for (let s of siteRectifyRes) {
siteMap.add(s.siteId);
let sts = s.status
let stsChinese = ''
if (sts == 0) {
stsChinese = '待整改'
} else if (sts == 1) {
stsChinese = '待审批'
} else if (sts == 2) {
stsChinese = '待复审'
} else if (sts == 3 || sts == 4) {
stsChinese = '审批驳回'
} else if (sts == 5) {
stsChinese = '审批通过'
}
if (
s.hideDangerDisposes.length
&& s.hideDangerDisposes.some(sd => sd.type == 3 && sd.admit)
) {
completedRectifyCount++
} else {
uncompletedRectifyCount++
}
reportData.push({
siteName: s.dataValues.site.dataValues.name,
name: s.dataValues.hideDangerRectify.dataValues.name,
submitTime: s.dataValues.lastDisposeTime ? moment(s.dataValues.lastDisposeTime).format('YYYY-MM-DD HH:mm:ss') : '',
state: stsChinese
})
}
const fileName = `中鼎国际隐患整改数据报表-${type}-${timeShow}` + '.xlsx'
const filePath = await simpleExcelDown({
data: reportData, header: reportHeader, fileName
})
// const fileData = fs.readFileSync(filePath);
// 保存文件到云
let uploadPath = path.posix.join('hideDangerReport', uuid.v4(), fileName);
let uploadResult = await client.put(
uploadPath,
filePath,
// { contentLength: size }
);
//保存信息到数据库
const existReportRes = await models.HideDangerReport.findOne({
where: {
type: typeEnglish,
time: String(time),
}
})
const storageData = {
siteCount: siteMap.size,
rectifyCount: completedRectifyCount + uncompletedRectifyCount,
completedRectifyCount,
uncompletedRectifyCount,
report: uploadResult.name,
type: typeEnglish,
time: String(time),
}
if (existReportRes) {
await models.HideDangerReport.update(storageData, {
where: {
id: existReportRes.id
}
})
} else {
await models.HideDangerReport.create(storageData)
}
}
if (month == 1) {
// 统计一下上一年
let startTime = today.clone().subtract(1, 'year').startOf('year')
let endTime = today.clone().subtract(1, 'year').endOf('year')
await statistic(
startTime,
endTime,
'年报',
`${startTime.year()}${startTime.month() + 1}-${endTime.month() + 1}`,
'year',
startTime.year()
)
}
if ([1, 4, 7, 10].includes(month)) {
// 统计一下上季度
let startTime = today.clone().subtract(3, 'month').startOf('month')
let endTime = today.clone().subtract(1, 'month').endOf('month')
await statistic(
startTime,
endTime,
'季报',
`${startTime.year()}${startTime.month() + 1}-${endTime.month() + 1}`,
'quarter',
`${startTime.year()}-${month == 1 ? 'Q4' : month == 4 ? 'Q1' : month == 7 ? 'Q2' : 'Q3'}`
)
}
// 统计一下上个月
let startTime = today.clone().subtract(1, 'month').startOf('month')
let endTime = today.clone().subtract(1, 'month').endOf('month')
await statistic(
startTime,
endTime,
'月报',
`${startTime.year()}${startTime.month() + 1}`,
'month',
startTime.format('YYYY-MM')
)
} catch (error) {
app.fs.logger.error(`sechedule: hideDangerStatistic, error: ${error}`);
}
}
);
return {
hideDangerStatistic
}
}

64
api/app/lib/schedule/metting.js

@ -1,64 +0,0 @@
const moment = require('moment')
const TEST = false
// const TEST = true
module.exports = function (app, opts) {
const mettingGenerate = app.fs.scheduleInit(
{
interval: '0 0 0 */1 * *',
immediate: TEST,
proRun: !TEST,
},
async () => {
try {
const { models } = app.fs.dc
const today = moment()
const date = today.date()
const dateFormat = moment().format('YYYY-MM-DD')
let sites = await models.Site.findAll({
where: { del: false },
attributes: ['id', 'name']
});
let datasM = [], datasB = [], datasD = [], datas6 = []
sites.map(s => {
datasM.push({
siteId: s.id,
type: '月度安全例会',
date: dateFormat
});
datasB.push({
siteId: s.id,
type: '班前会',
date: dateFormat
});
datasD.push({
siteId: s.id,
type: '日调度会',
date: dateFormat
});
datas6.push({
siteId: s.id,
type: '逢六教育培训',
date: dateFormat
})
})
if (date == 1) {
await models.Metting.bulkCreate(datasM)
}
await models.Metting.bulkCreate(datasB)
await models.Metting.bulkCreate(datasD)
if (parseInt(date) % 10 == 6) {
await models.Metting.bulkCreate(datas6)
}
} catch (error) {
app.fs.logger.error(`sechedule: mettingGenerate, error: ${error}`);
}
}
);
return {
mettingGenerate
}
}

65
api/config.js

@ -11,34 +11,18 @@ const dev = process.env.NODE_ENV == 'development';
args.option(['p', 'port'], '启动端口'); args.option(['p', 'port'], '启动端口');
args.option(['g', 'pg'], 'postgre 服务 URL'); args.option(['g', 'pg'], 'postgre 服务 URL');
// 七牛云存储参数 args.option('apiAnxinyunUrl', "安心云api");
args.option('qnak', 'qiniuAccessKey'); args.option('axyProject', '安心云泵站项目信息');
args.option('qnsk', 'qiniuSecretKey');
args.option('qnbkt', 'qiniuBucket');
args.option('qndmn', 'qiniuDomain');
args.option('aliOssAccessKey', '阿里OSS AccessKey');
args.option('aliOssSecretKey', '阿里OSS SecretKey');
args.option('aliOssBucket', '阿里OSS Bucket');
args.option('aliOssRegion', '阿里OSS Region');
const flags = args.parse(process.argv); const flags = args.parse(process.argv);
const XUNJIAN_DB = process.env.XUNJIAN_DB || flags.pg; const XUNJIAN_DB = process.env.XUNJIAN_DB || flags.pg;
const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.apiAnxinyunUrl
const AXY_BZ_PROJECT = process.env.AXY_BZ_PROJECT || flags.axyProject
// 七牛云存储参数
const QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || flags.qndmn;
const QINIU_BUCKET_RESOURCE = process.env.ANXINCLOUD_QINIU_BUCKET_RESOURCE || flags.qnbkt;
const QINIU_AK = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak;
const QINIU_SK = process.env.ANXINCLOUD_QINIU_SECRETKEY || flags.qnsk;
//阿里OSS
const ALI_OSS_ACCESSKEY = process.env.ALI_OSS_ACCESSKEY || flags.aliOssAccessKey;
const ALI_OSS_SECRETKET = process.env.ALI_OSS_SECRETKET || flags.aliOssSecretKey;
const ALI_OSS_BUCKET = process.env.ALI_OSS_BUCKET || flags.aliOssBucket;
const ALI_OSS_REGION = process.env.ALI_OSS_REGION || flags.aliOssRegion;
if (!XUNJIAN_DB || !API_ANXINYUN_URL || !AXY_BZ_PROJECT) {
if (!XUNJIAN_DB || !QINIU_DOMAIN_QNDMN_RESOURCE || !QINIU_BUCKET_RESOURCE || !QINIU_AK || !QINIU_SK) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');
args.showHelp(); args.showHelp();
process.exit(-1); process.exit(-1);
@ -51,12 +35,6 @@ const product = {
{ {
entry: require('@fs/attachment').entry, entry: require('@fs/attachment').entry,
opts: { opts: {
qiniu: {
domain: QINIU_DOMAIN_QNDMN_RESOURCE,
bucket: QINIU_BUCKET_RESOURCE,
accessKey: QINIU_AK,
secretKey: QINIU_SK
},
maxSize: 104857600, // 100M maxSize: 104857600, // 100M
} }
}, { }, {
@ -66,33 +44,12 @@ const product = {
exclude: [ exclude: [
// "*" // "*"
], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由 ], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由
qiniu: { // apiAnxinyunUrl: API_ANXINYUN_URL,
domain: QINIU_DOMAIN_QNDMN_RESOURCE, axyProject: AXY_BZ_PROJECT,
bucket: QINIU_BUCKET_RESOURCE, pssaRequest: [{// name 会作为一个 request 出现在 ctx.app.fs
accessKey: QINIU_AK, name: 'anxinyun',
secretKey: QINIU_SK root: API_ANXINYUN_URL
}, }],
aliOss: {
accessKey: ALI_OSS_ACCESSKEY,
secretKey: ALI_OSS_SECRETKET,
bucket: ALI_OSS_BUCKET,
region: ALI_OSS_REGION
},
sms: {
///阿里云-安心云
accessKey: 'LTAI5tAFdjz7j38aNF2C9Qe8',
accessSecret: '1trYkmiqfBtvZL6BxkNH2uQcQQPs0S'
},
email: {
enabled: true,
host: 'smtp.exmail.qq.com',
port: 465,
sender: {
name: '中鼎服务',
address: 'fsiot@free-sun.com.cn',
password: 'Fs2689'
}
},
} }
} }
], ],

BIN
web/client/assets/images/login/button-b.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
web/client/assets/images/login/icon_y.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
web/client/assets/images/login/icon_z.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
web/client/assets/images/login/input-b.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
web/client/assets/images/login/login-b.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

BIN
web/client/assets/images/login/login_a.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

BIN
web/client/assets/images/login/login_b.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

BIN
web/client/assets/images/login/register-bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

BIN
web/client/assets/images/login/word.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
web/client/assets/images/monitor/ball-A.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
web/client/assets/images/monitor/ball-V.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
web/client/assets/images/monitor/bg-header.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 297 KiB

BIN
web/client/assets/images/monitor/headerTitle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
web/client/assets/images/monitor/pedestal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
web/client/assets/images/monitor/pump-head.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
web/client/assets/images/monitor/site.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
web/client/assets/images/monitor/title.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

4
web/client/src/layout/actions/global.js

@ -36,7 +36,9 @@ export function initApiRoot () {
dispatch({ dispatch({
type: INIT_API_ROOT, type: INIT_API_ROOT,
payload: { payload: {
apiRoot: res.root apiRoot: res.root,
axyApi: res.axyApi,
axyProject: res.axyProject,
} }
}) })
}); });

17
web/client/src/layout/reducers/global.js

@ -1,8 +1,8 @@
'use strict'; 'use strict';
import Immutable from 'immutable'; import Immutable from 'immutable';
import { INIT_LAYOUT, RESIZE } from '../actions/global'; import { INIT_LAYOUT, RESIZE,INIT_API_ROOT } from '../actions/global';
import { SET_GLOBAL_SITE_LIST, CLEAR_GLOBAL_SITE_LIST } from '../actions/site' import { SET_GLOBAL_SITE_LIST, CLEAR_GLOBAL_SITE_LIST } from '../actions/site'
function global(state = { function global (state = {
title: '', title: '',
copyright: '', copyright: '',
sections: [], sections: [],
@ -10,7 +10,9 @@ function global(state = {
plugins: {}, plugins: {},
clientHeight: 768, clientHeight: 768,
clientWidth: 1024, clientWidth: 1024,
sites: [] sites: [],
axyApi: '',
axyProject: ''
}, action) { }, action) {
const payload = action.payload; const payload = action.payload;
switch (action.type) { switch (action.type) {
@ -28,8 +30,15 @@ function global(state = {
plugins: payload.plugins, plugins: payload.plugins,
clientHeight: state.clientHeight, clientHeight: state.clientHeight,
detailsComponent: null, detailsComponent: null,
sites: [] sites: [],
axyApi: payload.axyApi,
axyProject: payload.axyProject,
}; };
case INIT_API_ROOT:
return Immutable.fromJS(state).merge({
axyApi: payload.axyApi,
axyProject: payload.axyProject,
}).toJS();
// case INIT_RESOURCE_ROOT: // case INIT_RESOURCE_ROOT:
// return Immutable.fromJS(state).merge(payload).toJS(); // return Immutable.fromJS(state).merge(payload).toJS();
// case INIT_PAGE_HEADER_DETAILS: // case INIT_PAGE_HEADER_DETAILS:

8
web/client/src/sections/auth/actions/auth.js

@ -1,7 +1,9 @@
'use strict'; 'use strict';
import { ApiTable } from '$utils' import { ApiTable, AxyRequest, AxyApiTable } from '$utils'
import { Request } from '@peace/utils' import { Request } from '@peace/utils'
import superagent from "superagent"
// import config from "../../../../../config"
export const INIT_AUTH = 'INIT_AUTH'; export const INIT_AUTH = 'INIT_AUTH';
export function initAuth () { export function initAuth () {
@ -14,10 +16,11 @@ export function initAuth () {
}; };
} }
export const REQUEST_LOGIN = 'REQUEST_LOGIN'; export const REQUEST_LOGIN = 'REQUEST_LOGIN';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_ERROR = 'LOGIN_ERROR'; export const LOGIN_ERROR = 'LOGIN_ERROR';
export function login ({ username, password, phone, code }) { export function login ({ username, password, phone, code, axyApi, axyProject }) {
return dispatch => { return dispatch => {
dispatch({ type: REQUEST_LOGIN }); dispatch({ type: REQUEST_LOGIN });
@ -50,6 +53,7 @@ export function logout (user) {
Request.put(url, { Request.put(url, {
token: token token: token
}); });
return { return {
type: LOGOUT type: LOGOUT
}; };

60
web/client/src/sections/auth/containers/login.js

@ -11,7 +11,7 @@ import { login, LOGIN_ERROR } from '../actions/auth';
import { ExclamationCircleOutlined } from '@ant-design/icons'; import { ExclamationCircleOutlined } from '@ant-design/icons';
import { Uploads } from '$components' import { Uploads } from '$components'
import { LockOutlined, UserOutlined } from '@ant-design/icons'; import { LockOutlined, UserOutlined } from '@ant-design/icons';
import '../style.less'; import './login.less';
const FormItem = Form.Item; const FormItem = Form.Item;
@ -74,7 +74,7 @@ const Login = props => {
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
color: 'aliceblue', color: 'aliceblue',
backgroundImage: 'url(/assets/images/login/login_b.png)', backgroundImage: 'url(/assets/images/login/login-b.gif)',
backgroundSize: 'cover', backgroundSize: 'cover',
position: 'relative', position: 'relative',
}} }}
@ -82,22 +82,29 @@ const Login = props => {
{/* <img src='/assets/images/logo.png' style={{ height: 42, borderRadius: 4, position: 'fixed', top: 32, left: 32 }} /> */} {/* <img src='/assets/images/logo.png' style={{ height: 42, borderRadius: 4, position: 'fixed', top: 32, left: 32 }} /> */}
<div style={{ <div style={{
width: 556, height: 434, backgroundColor: '#rgba(255,255,255,0.50)', width: 556, height: 554, display: 'flex', flexDirection: 'column', justifyContent: 'space-between',
borderRadius: '2px 2px 0 0', boxShadow: 'inset 0 0 8px 0 rgba(50,131,255,0.25)', borderRadius: '2px 2px 0 0', position: 'absolute', right: 150, top: 'calc(50% - 217px)'
display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'absolute', right: 150, top: 'calc(50% - 217px)'
}}> }}>
<img src={'/assets/images/login/word.png'} style={{ width: '100%', height: 80, dispatch: 'inline-block' }} />
<div className='login' style={{ width: 556, height: 434, background: 'url(/assets/images/login/register-bg.png)', backgroundSize: '100% 100%', backgroundPosition: 'center', }}>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', margin: '22px 10px' }}>
<img src={'/assets/images/login/icon_z.png'} style={{ width: 26, height: 14 }} />
<div style={{ color: '#C5E0FF', fontSize: 24 }}>系统登录</div>
<img src={'/assets/images/login/icon_y.png'} style={{ width: 26, height: 14 }} />
</div>
<div style={{ <div style={{
width: 410, // width: 410,
height: 322, // height: 322,
backgroundColor: ''
}}> }}>
<img src={'/assets/images/login/login_a.png'} style={{ width: 124, height: 37, display: 'inline-block', marginBottom: 40 }} />
<Form <Form
form={form} form={form}
onFinish={r => { onFinish={r => {
form.validateFields().then(r => { form.validateFields().then(r => {
dispatch(login({ username: r.username, password: r.password })); dispatch(login({ username: r.username, password: r.password}));
}) })
.catch(err => { .catch(err => {
dispatch({ dispatch({
@ -107,21 +114,29 @@ const Login = props => {
}) })
}} }}
style={{ width: '100%', height: 400, display: 'flex', alignItems: 'center', flexDirection: 'column' }}
> >
<Form.Item label='' name="username" rules={[{ required: true, message: '请输入用户名' },]}> <Form.Item label='' name="username" rules={[{ required: true, message: '请输入账户' },]} style={{ marginTop: 50 }}>
<Input prefix={<UserOutlined className="site-form-item-icon" />} placeholder="用户名" /> <Input prefix={<>
<UserOutlined style={{ marginLeft: 20, color: 'white', fontSize: 18 }} />
<span style={{ color: 'white' }}>账户</span>
<span style={{ color: 'white', marginRight: 10, height: 18, borderRight: '1px solid white' }}></span>
</>} style={{ width: 380, margin: '6px 0px 6px 0' }} placeholder="" />
</Form.Item> </Form.Item>
<Form.Item label='' name="password" rules={[{ required: true, message: '请输入密码' },]}> <Form.Item label='' name="password" rules={[{ required: true, message: '请输入密码' },]}>
<Input.Password prefix={<LockOutlined className="site-form-item-icon" />} placeholder="密码" /> <Input.Password prefix={<>
<LockOutlined style={{ marginLeft: 20, color: 'white', fontSize: 18 }} />
<span style={{ color: 'white' }}>密码</span>
<span style={{ color: 'white', marginRight: 10, height: 18, borderRight: '1px solid white' }}></span>
</>} style={{ width: 380, margin: '6px 0' }} placeholder="" />
</Form.Item> </Form.Item>
<Tooltip title='请联系管理员'>
<a style={{ position: 'relative', left: 348, top: -17 }}>忘记密码</a>
</Tooltip>
<Form.Item <Form.Item
> >
<Button type="primary" htmlType="submit" style={{ width: 410, height: 50 }}> <Button type="primary" htmlType="submit" style={{ width: 300, height: 50, marginRight: 6, fontSize: 18, border: 0, background: 'url(/assets/images/login/button-b.png)', backgroundSize: '100% 100%', backgroundPosition: 'center', }}>
登录 立即登录
</Button> </Button>
</Form.Item> </Form.Item>
</Form> </Form>
@ -132,16 +147,21 @@ const Login = props => {
</div> </div>
</div> </div>
</div>
</div > </div >
); );
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { auth } = state; const { auth, global } = state;
console.log(global);
return { return {
user: auth.user, user: auth.user,
error: auth.error, error: auth.error,
isRequesting: auth.isRequesting isRequesting: auth.isRequesting,
} }
} }

28
web/client/src/sections/auth/containers/login.less

@ -0,0 +1,28 @@
.login {
.ant-form-item-control-input {
background: url(/assets/images/login/input-b.png);
background-size: 100% 108%;
background-position: center;
.ant-input-affix-wrapper,
.ant-input-affix-wrapper-status-success,
.ant-input-affix-wrapper-status-error {
background: transparent;
border: 0;
#username,#password {
background: transparent;
color: white;
}
}
.ant-input-affix-wrapper-status-error:not(
.ant-input-affix-wrapper-disabled
):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper,
.ant-input-affix-wrapper-status-error:not(
.ant-input-affix-wrapper-disabled
):not(.ant-input-affix-wrapper-borderless).ant-input-affix-wrapper:hover {
background: transparent;
}
.ant-input-password-icon{
color: white;
}
}
}

51
web/client/src/sections/bigScreen/actions/authority.js

@ -1,51 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getAuthority(orgId) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_MEMBERS',
url: `${ApiTable.getEnterprisesMembers.replace('{enterpriseId}', orgId)}`,
msg: { error: '获取用户列表失败' },
reducer: { name: 'members' }
});
}
export function getResource(userId) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_RESOURCE',
url: `${ApiTable.getResource}`,
msg: { error: '获取权限失败' },
reducer: { name: 'resource' }
});
}
export function getUserResource(userId) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_USER_RESOURCE',
url: `${ApiTable.getUserResource}?userId=${userId}`,
msg: { error: '获取用户权限失败' },
reducer: { name: 'userResource' }
});
}
export function postUserRes(body) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
actionType: 'UPDATE_USER_RESOURCE',
url: `${ApiTable.postUserRes}`,
data: body,
msg: { success: '更新用户权限' }
});
}
export default {
getAuthority,
getResource,
getUserResource,
postUserRes
}

19
web/client/src/sections/bigScreen/actions/bigScreen.js

@ -0,0 +1,19 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function axyData (data = {}) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
actionType: 'POST_AXY_DATA',
url: `${ApiTable.axyData}`,
data: data,
msg: { success: '' }
});
}
export default {
axyData
}

9
web/client/src/sections/bigScreen/actions/index.js

@ -1,11 +1,8 @@
'use strict'; 'use strict';
import * as authority from './authority' import * as bigScreen from './bigScreen'
import { getDepMessage, getDepUser, createUser } from './user'
export default { export default {
...authority, ...bigScreen
getDepMessage,
getDepUser,
createUser,
} }

113
web/client/src/sections/bigScreen/actions/user.js

@ -1,113 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getDepMessage() {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_DEPARTMENT_MESSAGE',
url: ApiTable.getDepMessage,
msg: { error: '获取部门信息失败' },
reducer: { name: 'depMessage' }
});
}
//新建部门
export function createDept(data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'CREATE_DEPT',
url: ApiTable.createDept,
msg: { option: '新建部门' },
});
}
//修改部门
export function updateDept(id, data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'UPDATE_DEPT',
url: ApiTable.updateDept.replace('{id}', id),
msg: { option: '修改部门' },
});
}
//删除部门
export function delDept(id) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_DEPT',
url: ApiTable.delDept.replace('{id}', id),
msg: { option: '删除部门' },
});
}
export function getDepUser(depId) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_DEPARTMENT_USER',
url: ApiTable.getDepUser.replace('{depId}', depId),
msg: { error: '获取部门下用户信息失败' },
reducer: { name: 'depUser' }
});
}
export function createUser(data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'CREATE_DEPARTMENT_USER',
url: ApiTable.createUser,
msg: { option: '新建用户' },
});
}
export function updateUser(id, data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'UPDATE_DEPARTMENT_USER',
url: ApiTable.updateUser.replace('{id}', id),
msg: { option: '修改用户' },
});
}
export function delUser(ids) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_DEPARTMENT_USER',
url: ApiTable.delUser.replace('{ids}', ids),
msg: { option: '删除用户' },
});
}
export function resetPwd(id, data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'CREATE_DEPARTMENT_USER',
url: ApiTable.resetPwd.replace('{id}', id),
msg: { option: '重置用户密码' },
});
}
export default {
getDepMessage,
getDepUser,
createUser,
updateUser,
delUser,
resetPwd
}

663
web/client/src/sections/bigScreen/components/capacity.js

@ -1,47 +1,672 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { Spin, Card, Modal, TreeSelect, message } from 'antd'; import { Spin, Card, Modal, Select, Carousel, Progress } from 'antd';
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form'; import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form';
import Title from 'antd/lib/skeleton/Title'; import moment from 'moment'
import ReactECharts from 'echarts-for-react';
import './index.less'
const Capacity = ({ user, }) => { const Capacity = ({ actions, dispatch, user, }) => {
const { bigScreen } = actions
const [pageLeft, setPageLeft] = useState(0) //左边翻页
const [pageRight, setPageRight] = useState(0) //左边翻页
const [siteList, setSiteList] = useState([]) //站点列表
const [strucId, setStrucId] = useState() //站点ID
const [pumpData, setPumpData] = useState([]) //水泵数据
const [cabinetData, setCabinetData] = useState([]) //进线柜数据
const [centreData, setCentreData] = useState({}) //中间数据
useEffect(() => {
dispatch(bigScreen.axyData({ type: 'get', url: `organizations/{orgId}/structures` })).then(res => {
// console.log(res);
if (res.success) {
setSiteList(res.payload.data?.map(v => ({ value: v.id, label: v.name })) || [])
setStrucId(res.payload.data[0]?.id)
}
})
}, [])
useEffect(async () => {
let pump = []
let cabinetSun = []
let pumpSun = []
let sun = {}
if (strucId) {
await dispatch(bigScreen.axyData({ type: 'get', url: `structures/${strucId}/factors` })).then(async r => {
if (r.success) {
//水泵信息
let waterId = r.payload.data?.find(v => v.name == '泵站水泵')?.id
if (waterId) {
await dispatch(bigScreen.axyData({
type: 'get', url: `structures/${strucId}/stations`,
params: { query: { factorId: waterId } }
})).then(async p => {
if (p.success) {
let dataId = []
p.payload.data?.map(v => {
v.groups?.map(s => {
s.stations?.map(f => {
dataId.push(f.id)
})
})
})
if (dataId.length) {
let sameDay //当天最新一条数据
let beforeDay //前一天最新一条数据
let month //上个月最新一条数据
let year //去年最新一条数据
// 当前时间
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().startOf('day').format('YYYY:MM:DD HH:mm:ss'),
endTime: moment().endOf('day').format('YYYY:MM:DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
pump = d.payload.data?.stations || []
sameDay = d.payload.data?.stations || []
}
})
// 昨天最后一条数据
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().day(moment().day() - 7).startOf('day').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().day(moment().day() - 1).endOf('day').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
beforeDay = d.payload.data?.stations || []
}
})
// 上月最后一条数据
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().month(moment().month() - 1).startOf('month').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().month(moment().month() - 1).endOf('month').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
month = d.payload.data?.stations || []
}
})
//去年最后一条数据
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().year(moment().year() - 1).month(moment().month() - 1).startOf('year').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().year(moment().year() - 1).month(moment().month() - 1).endOf('year').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
year = d.payload.data?.stations || []
}
})
sameDay?.map(u => {
let find1 = beforeDay?.find(c => c.id == u.id)
let find2 = month?.find(c => c.id == u.id)
let find3 = year?.find(c => c.id == u.id)
return <div style={{ width: '100%', height: 'calc(100% - 160px)' }}> // console.log(find1);
pumpSun.push({
today: u?.data[0]?.eMotor_EQ && find1?.data[0]?.eMotor_EQ ? (u?.data[0]?.eMotor_EQ - find1?.data[0]?.eMotor_EQ) : '--',
sameMonth: u?.data[0]?.eMotor_EQ && find2?.data[0]?.eMotor_EQ ? (u?.data[0]?.eMotor_EQ - find2?.data[0]?.eMotor_EQ) : '--',
thisYear: u?.data[0]?.eMotor_EQ && find3?.data[0]?.eMotor_EQ ? (u?.data[0]?.eMotor_EQ - find3?.data[0]?.eMotor_EQ) : '--',
eMotor_EQ: u?.data[0]?.eMotor_EQ,
id: u.id,
name: u.name,
})
})
}
}
})
}
//进线柜
let wireCabinetId = r.payload.data?.find(v => v.name == '泵站进线柜')?.id
if (wireCabinetId) {
await dispatch(bigScreen.axyData({
type: 'get', url: `structures/${strucId}/stations`,
params: { query: { factorId: wireCabinetId } }
})).then(async p => {
if (p.success) {
let dataId = []
p.payload.data?.map(v => {
v.groups?.map(s => {
s.stations?.map(f => {
dataId.push(f.id)
})
})
})
if (dataId.length) {
let sameDay //当天最新一条数据
let beforeDay //前一天最新一条数据
let month //上个月最新一条数据
let year //去年最新一条数据
// 当前时间
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().startOf('day').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
sameDay = d.payload.data?.stations || []
}
})
// 昨天最后一条数据
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().day(moment().day() - 7).startOf('day').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().day(moment().day() - 1).endOf('day').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
beforeDay = d.payload.data?.stations || []
}
})
// 上月最后一条数据
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().month(moment().month() - 1).startOf('month').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().month(moment().month() - 1).endOf('month').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
month = d.payload.data?.stations || []
}
})
//去年最后一条数据
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().year(moment().year() - 1).month(moment().month() - 1).startOf('year').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().year(moment().year() - 1).month(moment().month() - 1).endOf('year').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
year = d.payload.data?.stations || []
}
})
sameDay?.map(u => {
let find1 = beforeDay?.find(c => c.id == u.id)
let find2 = month?.find(c => c.id == u.id)
let find3 = year?.find(c => c.id == u.id)
// console.log(find1);
cabinetSun.push({
today: u?.data[0]?.eQF_EQ && find1?.data[0]?.eQF_EQ ? (u?.data[0]?.eQF_EQ - find1?.data[0]?.eQF_EQ) : '--',
sameMonth: u?.data[0]?.eQF_EQ && find2?.data[0]?.eQF_EQ ? (u?.data[0]?.eQF_EQ - find2?.data[0]?.eQF_EQ) : '--',
thisYear: u?.data[0]?.eQF_EQ && find3?.data[0]?.eQF_EQ ? (u?.data[0]?.eQF_EQ - find3?.data[0]?.eQF_EQ) : '--',
eQF_EQ: u?.data[0]?.eQF_EQ,
id: u.id,
name: u.name,
sQF_CLOSING: u?.data[0]?.sQF_CLOSING
})
})
}
}
})
}
//泵站信息
let informationId = r.payload.data?.find(v => v.name == '泵站信息')?.id
if (informationId) {
await dispatch(bigScreen.axyData({
type: 'get', url: `structures/${strucId}/stations`,
params: { query: { factorId: informationId } }
})).then(async p => {
if (p.success) {
let dataId = []
p.payload.data?.map(v => {
v.groups?.map(s => {
s.stations?.map(f => {
dataId.push(f.id)
})
})
})
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: dataId.join(),
startTime: moment().startOf('day').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
sun.sHumidity = d.payload.data?.stations[0]?.data[0]?.sHumidity
sun.sTEMP = d.payload.data?.stations[0]?.data[0]?.sTEMP
sun.sGrille_level = d.payload.data?.stations[0]?.data[0]?.sGrille_level
}
})
}
})
}
}
})
}
await dispatch(bigScreen.axyData({
type: 'get', url: `stations/theme/data`, params: {
query: {
stations: 56643,
startTime: moment().startOf('day').format('YYYY-MM-DD HH:mm:ss'),
endTime: moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'),
limit: 1
}
}
})).then(d => {
if (d.success) {
}
})
setPumpData(pump)
setCabinetData(cabinetSun)
//计算各个阶段的总点电量
let day1 = 0
let day30 = 0
let day365 = 0
let daySun = 0
pumpSun?.map(h => {
if (!isNaN(h.today)) day1 += h.today
if (!isNaN(h.sameMonth)) day30 += h.sameMonth
if (!isNaN(h.thisYear)) day365 += h.thisYear
if (!isNaN(h.eQF_EQ)) daySun += h.eQF_EQ
})
cabinetSun?.map(h => {
if (!isNaN(h.today)) day1 += h.today
if (!isNaN(h.sameMonth)) day30 += h.sameMonth
if (!isNaN(h.thisYear)) day365 += h.thisYear
if (!isNaN(h.eQF_EQ)) daySun += h.eQF_EQ
})
sun.day1 = day1
sun.day30 = day30
sun.day365 = day365
sun.daySun = daySun
setCentreData(sun)
}, [strucId])
return <div style={{ width: '100%', height: 'calc(100% - 160px)', position: "absolute", top: 160, right: 0 }}>
<div style={{ width: '100%', height: 'calc(60%)', display: 'flex', }}> <div style={{ width: '100%', height: 'calc(60%)', display: 'flex', }}>
{/* 水泵 */}
<div style={{
width: '30%', height: '100%', display: 'flex', justifyContent: 'center',
}}>
<div style={{ width: '80%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', }}>
{pumpData.length > 0 && <>
<img style={{ width: 36, height: 36 }} src="/assets/images/monitor/left.png"
onClick={() => {
if (pageLeft > 0) setPageLeft(pageLeft - 1)
}} />
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
{
pumpData?.slice(pageLeft * 2, (pageLeft + 1) * 2)?.map((v, index) => {
return <div key={'waterPump' + index} style={{ width: 250, height: 200 }}>
<div style={{
width: '100%', height: 38,
backgroundImage: 'url(/assets/images/monitor/pump-head.png)',
backgroundSize: '100% 100%',
backgroundPosition: 'center', display: 'flex', justifyContent: 'space-between', alignItems: 'center'
}}>
<div style={{ fontSize: 18, fontWeight: 400, marginLeft: 46, color: '#FFFFFF' }}>{v.name}</div>
<div style={{
width: 50, height: 26, background: '#a7110033', border: '1px solid #A71100', cursor: "pointer",
borderRadius: 4, color: ' #E83E2B', textAlign: 'center', lineHeight: '22px', marginRight: 10
}}>{[1, 3, 5].includes(v.data[0]?.sMotor_RunMode) ? '启动' : [2, 4, 7].includes(v.data[0]?.sMotor_RunMode) ? '停止' : v.data[0]?.sMotor_RunMode == 7 ? '故障' : '无状态'}</div>
</div>
<div style={{ background: 'linear-gradient(180deg, #000e28e6 1%, #021f48cc 100%)' }}>
<Carousel style={{ width: '100%', height: 66 }} autoplay>
<div style={{ width: '100%', height: '100%', }}>
<div style={{
width: '100%', height: '100%', display: 'flex', justifyContent: 'space-around'
}}>
<div style={{ width: '40%', height: '100%', display: 'flex', justifyContent: 'space-between', }}>
<img style={{ width: 40, height: 40 }} src='/assets/images/monitor/ball-A.png' />
<div style={{ display: 'flex', flexDirection: 'column', color: 'white', fontSize: 14 }}>
<div>{v.data[0]?.eMotor_A_A} A</div>
<div>A相电流</div>
</div>
</div>
<div style={{ width: '40%', height: '100%', display: 'flex', justifyContent: 'space-between', }}>
<img style={{ width: 40, height: 40 }} src='/assets/images/monitor/ball-V.png' />
<div style={{ display: 'flex', flexDirection: 'column', color: 'white', fontSize: 14 }}>
<div>{v.data[0]?.eMotor_A_V} V</div>
<div>A相电压</div>
</div>
</div>
</div>
</div>
<div style={{ width: '100%', height: '100%', }}>
<div style={{
width: '100%', height: '100%', display: 'flex', justifyContent: 'space-around'
}}>
<div style={{ width: '40%', height: '100%', display: 'flex', justifyContent: 'space-between', }}>
<img style={{ width: 40, height: 40 }} src='/assets/images/monitor/ball-A.png' />
<div style={{ display: 'flex', flexDirection: 'column', color: 'white', fontSize: 14 }}>
<div>{v.data[0]?.eMotor_B_A} A</div>
<div>B相电流</div>
</div>
</div>
<div style={{ width: '40%', height: '100%', display: 'flex', justifyContent: 'space-between', }}>
<img style={{ width: 40, height: 40 }} src='/assets/images/monitor/ball-V.png' />
<div style={{ display: 'flex', flexDirection: 'column', color: 'white', fontSize: 14 }}>
<div>{v.data[0]?.eMotor_B_V} V</div>
<div>B相电压</div>
</div>
</div>
</div>
</div>
<div style={{ width: '100%', height: '100%', }}>
<div style={{ <div style={{
width: '30%', height: '100%', borderRight: '1px solid white', display: 'flex', justifyContent: 'center', width: '100%', height: '100%', display: 'flex', justifyContent: 'space-around'
}}> }}>
<div style={{ width: '80%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}> <div style={{ width: '40%', height: '100%', display: 'flex', justifyContent: 'space-between', }}>
<img style={{ width: 36, height: 36 }} src="/assets/images/monitor/left.png" /> <img style={{ width: 40, height: 40 }} src='/assets/images/monitor/ball-A.png' />
<div style={{ display: 'flex', }}> <div style={{ display: 'flex', flexDirection: 'column', color: 'white', fontSize: 14 }}>
<div> <div>{v.data[0]?.eMotor_C_A} A</div>
<div>C相电流</div>
</div>
</div>
<div style={{ width: '40%', height: '100%', display: 'flex', justifyContent: 'space-between', }}>
<img style={{ width: 40, height: 40 }} src='/assets/images/monitor/ball-V.png' />
<div style={{ display: 'flex', flexDirection: 'column', color: 'white', fontSize: 14 }}>
<div>{v.data[0]?.eMotor_C_V} V</div>
<div>C相电压</div>
</div>
</div>
</div>
</div>
</Carousel>
<div style={{ width: "100%", height: 90, padding: '10px 25px', display: 'flex', flexDirection: 'column', justifyContent: 'space-around', color: 'white' }}>
<div style={{ display: 'flex' }}>
<div style={{ width: 90, textAlign: 'end' }}>总用电量:</div>
<div style={{ width: 90, textAlign: 'end', color: '#FFCB00' }}>{v.data[0]?.eMotor_EQ} kwh</div>
</div>
<div style={{ display: 'flex' }}>
<div style={{ width: 90, textAlign: 'end' }}>单次运行时间:</div>
<div style={{ width: 90, textAlign: 'end', color: '#FFCB00' }}>{v.data[0]?.dPump_T_S} min</div>
</div>
<div style={{ display: 'flex' }}>
<div style={{ width: 90, textAlign: 'end' }}>总积累时间:</div>
<div style={{ width: 90, textAlign: 'end', color: '#FFCB00' }}>{v.data[0]?.dPump_T_T} h</div>
</div>
</div> </div>
</div> </div>
<img style={{ width: 36, height: 36 }} src="/assets/images/monitor/right.png" /> </div>
})
}
</div>
<img style={{ width: 36, height: 36 }} src="/assets/images/monitor/right.png"
onClick={() => {
if (pageLeft + 1 < Math.ceil(pumpData.length / 2)) setPageLeft(pageLeft + 1)
}} />
</>}
</div> </div>
</div> </div>
{/* 中间位置 */}
<div style={{ <div style={{
width: '40%', height: '100%', borderRight: '1px solid white', width: '40%', height: '100%',
backgroundImage: 'url(/assets/images/monitor/pillar.png)', backgroundImage: 'url(/assets/images/monitor/pillar.png)',
backgroundSize: '80% 80%', backgroundSize: '80% 80%',
backgroundPosition: 'center', backgroundPosition: 'center',
backgroundRepeat: 'no-repeat', backgroundRepeat: 'no-repeat',
position: 'relative'
}}>
<div style={{
backgroundImage: 'url(/assets/images/monitor/pedestal.png)',
backgroundSize: '100% 100%', backgroundPosition: 'center', backgroundRepeat: 'no-repeat',
color: '#00FFF8', fontSize: 20, width: 160, height: 160, textAlign: 'center',
position: 'absolute', top: '6%', left: 10,
}}>
<div style={{ fontSize: 20, color: '#E2F8FF', fontWeight: 600 }}>
湿度</div>{centreData?.sHumidity} %
</div>
<div style={{ color: '#00FFF8', fontSize: 20, position: 'absolute', top: '15%', left: "calc(50% - 90px)", display: 'inline-block' }}>
<span style={{ fontSize: 20, color: '#E2F8FF', fontWeight: 600 }}>
总用量</span>{centreData?.daySun} kWh
</div>
<div style={{
backgroundImage: 'url(/assets/images/monitor/pedestal.png)',
backgroundSize: '100% 100%', backgroundPosition: 'center', backgroundRepeat: 'no-repeat',
color: '#00FFF8', fontSize: 20, width: 160, height: 160, textAlign: 'center',
position: 'absolute', top: '6%', right: -10,
}}> }}>
<div style={{ fontSize: 20, color: '#E2F8FF', fontWeight: 600 }}>
温度</div>{centreData?.sTEMP}
</div>
<div style={{
backgroundImage: 'linear-gradient(180deg, #0F3977 0%, #07327b9c 53%, #002B7E 100%)',
color: '#4CA1FF', fontSize: 20, width: 160, height: 60, textAlign: 'center',
position: 'absolute', top: '35%', left: -60,
}}>
<div style={{ fontSize: 20, color: '#E2F8FF', fontWeight: 600 }}>
今年用电</div>{centreData?.day365?.toFixed(2) || '--'}
</div>
<div style={{
backgroundImage: 'linear-gradient(180deg, #0F3977 0%, #07327b9c 53%, #002B7E 100%)',
color: '#4CA1FF', fontSize: 20, width: 160, height: 60, textAlign: 'center',
position: 'absolute', top: '54%', left: 0,
}}>
<div style={{ fontSize: 20, color: '#E2F8FF', fontWeight: 600 }}>
当月用电</div>{centreData?.day30?.toFixed(2) || '--'}
</div>
<div style={{
backgroundImage: ' linear-gradient(180deg, #0F3977 0%, #07327b9c 53%, #002B7E 100%)',
color: '#4CA1FF', fontSize: 20, width: 160, height: 60, textAlign: 'center',
position: 'absolute', top: '67%', left: 'calc(50% - 80px)',
}}>
<div style={{ fontSize: 20, color: '#E2F8FF', fontWeight: 600 }}>
当日用电</div>{centreData?.day1?.toFixed(2) || '--'}
</div>
<div style={{
backgroundImage: 'linear-gradient(180deg, #0F3977 0%, #07327b9c 53%, #002B7E 100%)',
height: 130, width: 180, position: 'absolute', top: '37%', right: 0,
display: 'flex', flexDirection: 'column', alignItems: 'center'
}}>
<div style={{ fontSize: 18, fontWeight: 600, color: "#E2F8FF", width: 160, marginBottom: 18 }}>集水池液位</div>
<div style={{ height: 160, width: 116, }}>
<Progress type="dashboard" percent={75} strokeColor={'#10D2E9'} gapDegree={180}
format={() => <div style={{ color: '#4CA1FF', fontSize: 20 }}>{centreData?.sGrille_level?.toFixed(2) || 0} m</div>}
/>
</div>
</div> </div>
<div style={{ width: '30%', height: '100%', }}></div>
<div className='site' style={{
display: 'flex', justifyContent: 'center', alignItems: 'center',
width: '100%', tpo: '80%', position: 'absolute', top: '80%'
}}>
<img style={{ width: 67, height: 68, marginLeft: 94 }} src='/assets/images/monitor/site.png' />
<div style={{
width: 180, height: 41, backgroundImage: 'url(/assets/images/monitor/title.png)',
backgroundSize: '100% 100%', backgroundPosition: 'center', backgroundRepeat: 'no-repeat',
textAlign: 'center', lineHeight: '41px', fontSize: 20, color: '#FFF', fontStyle: "italic"
}}>{siteList?.filter(v => v.value == strucId)[0]?.label}</div>
<Select
showSearch
placeholder="请选择站点"
value={strucId}
style={{ width: 155 }}
optionFilterProp="children"
onChange={() => {
}}
onSearch={() => {
}}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={siteList}
/>
</div>
</div>
{/* 进线柜 */}
<div style={{ width: '30%', height: '100%', display: 'flex', justifyContent: 'center', }}>
<div style={{ width: '80%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', }}>
{cabinetData.length > 0 && <>
<img style={{ width: 36, height: 36 }} src="/assets/images/monitor/left.png"
onClick={() => {
if (pageRight > 0) setPageRight(pageRight - 1)
}} />
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
{
cabinetData?.slice(pageRight * 2, (pageRight + 1) * 2)?.map((v, index) => {
return <div key={'waterPump' + index} style={{ width: 250, height: 200 }}>
<div style={{
width: '100%', height: 38,
backgroundImage: 'url(/assets/images/monitor/pump-head.png)',
backgroundSize: '100% 100%',
backgroundPosition: 'center', display: 'flex', justifyContent: 'space-between', alignItems: 'center'
}}>
<div style={{ fontSize: 18, fontWeight: 400, marginLeft: 46, color: '#FFFFFF' }}>{v.name}</div>
<div style={{
width: 50, height: 26, background: '#a7110033', border: '1px solid #A71100', cursor: "pointer",
borderRadius: 4, color: ' #E83E2B', textAlign: 'center', lineHeight: '22px', marginRight: 10
}}>{v.sQF_CLOSING ? '合闸' : '分闸'}</div>
</div>
<div style={{ background: 'linear-gradient(180deg, #000e28e6 1%, #021f48cc 100%)' }}>
<div style={{ width: "100%", height: 160, padding: '10px 25px', display: 'flex', flexDirection: 'column', justifyContent: 'space-around', color: 'white' }}>
<div style={{ display: 'flex' }}>
<div style={{ width: 90, textAlign: 'end' }}>当日用电:</div>
<div style={{ width: 90, textAlign: 'end', color: '#FFCB00' }}>{isNaN(v.today) ? v.today : v.today?.toFixed(2)} kwh</div>
</div>
<div style={{ display: 'flex' }}>
<div style={{ width: 90, textAlign: 'end' }}>当月用电:</div>
<div style={{ width: 90, textAlign: 'end', color: '#FFCB00' }}>{isNaN(v.sameMonth) ? v.sameMonth : v.sameMonth?.toFixed(2)} min</div>
</div>
<div style={{ display: 'flex' }}>
<div style={{ width: 90, textAlign: 'end' }}>今年用电:</div>
<div style={{ width: 90, textAlign: 'end', color: '#FFCB00' }}>{isNaN(v.thisYear) ? v.thisYear : v.thisYear?.toFixed(2)} h</div>
</div>
<div style={{ display: 'flex' }}>
<div style={{ width: 90, textAlign: 'end' }}>总用电量:</div>
<div style={{ width: 90, textAlign: 'end', color: '#FFCB00' }}>{v.eQF_EQ?.toFixed(2) || '--'} h</div>
</div>
</div>
</div>
</div>
})
}
</div>
<img style={{ width: 36, height: 36 }} src="/assets/images/monitor/right.png"
onClick={() => {
if (pageRight + 1 < Math.ceil(cabinetData.length / 2)) setPageRight(pageRight + 1)
}} /></>}
</div>
</div>
</div >
<div style={{ width: '100%', height: 'calc(36% )', display: 'flex', justifyContent: 'space-between' }}>
<div style={{
backgroundImage: 'url(/assets/images/monitor/headerTitle.png)',
backgroundSize: '100% 36px',
backgroundPosition: '0 0',
backgroundRepeat: 'no-repeat',
width: '31%', height: '100%',
}}>
<div className='site' style={{ display: 'flex' }}>
<div style={{ lineHeight: "36px", color: '#E2F8FF', fontSize: 20., textIndent: 20 }}>液位趋势</div>
<Select
showSearch
placeholder="请选择站点"
value={strucId}
style={{ width: 155,height:20 }}
optionFilterProp="children"
onChange={() => {
}}
onSearch={() => {
}}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={siteList}
/>
</div>
</div>
<div style={{
backgroundImage: 'url(/assets/images/monitor/headerTitle.png)',
backgroundSize: '100% 36px',
backgroundPosition: '0 0',
backgroundRepeat: 'no-repeat',
width: '31%', height: '100%',
}}>
<div style={{ lineHeight: "36px", color: '#E2F8FF', fontSize: 20., textIndent: 20 }}>电流趋势</div>
</div>
<div style={{
backgroundImage: 'url(/assets/images/monitor/headerTitle.png)',
backgroundSize: '100% 36px',
backgroundPosition: '0 0',
backgroundRepeat: 'no-repeat',
width: '31%', height: '100%',
}}>
<div style={{ lineHeight: "36px", color: '#E2F8FF', fontSize: 20., textIndent: 20 }}>用电趋势</div>
</div> </div>
<div style={{ width: '100%', height: 'calc(40% - 1px)', borderTop: '1px solid white', display: 'flex', }}>
<div style={{ width: '33%', height: '100%', borderRight: '1px solid white' }}></div>
<div style={{ width: '33%', height: '100%', borderRight: '1px solid white' }}></div>
<div style={{ width: '33%', height: '100%', }}></div>
</div> </div>
</div > </div >
} }
@ -51,7 +676,7 @@ function mapStateToProps (state) {
return { return {
user: auth.user, user: auth.user,
clientHeight: global.clientHeight, clientHeight: global.clientHeight,
actions: global.actions,
}; };
} }
export default connect(mapStateToProps)(Capacity)
export default connect(mapStateToProps)(Capacity);

6
web/client/src/sections/bigScreen/components/header.js

@ -17,10 +17,6 @@ const Header = ({ dispatch, actions, user, module, setModule, history }) => {
alignItems: 'center' alignItems: 'center'
}}> }}>
<div style={{ width: 200, color: 'white', }}>天气</div> <div style={{ width: 200, color: 'white', }}>天气</div>
<div style={{
lineHeight: '136px', fontFamily: 'YouSheBiaoTiHei',
fontSize: 48, color: '#E2F8FF', letterSpacing: 4,
}}>泵站自动化控制系统</div>
<div style={{ width: 200, color: 'white', display: 'flex', alignItems: 'center' }}> <div style={{ width: 200, color: 'white', display: 'flex', alignItems: 'center' }}>
<div style={{ <div style={{
width: 130, height: 52, width: 130, height: 52,
@ -58,7 +54,7 @@ const Header = ({ dispatch, actions, user, module, setModule, history }) => {
backgroundSize: '100% 100%', backgroundSize: '100% 100%',
backgroundPosition: '100% 100%', backgroundPosition: '100% 100%',
backgroundRepeat: 'no-repeat', backgroundRepeat: 'no-repeat',
color: 'white', color: 'white',cursor: "pointer"
}} onClick={() => setModule(v.key)}>{v.title}</div> }} onClick={() => setModule(v.key)}>{v.title}</div>
})} })}
</div> </div>

13
web/client/src/sections/bigScreen/components/index.less

@ -0,0 +1,13 @@
.site {
.ant-select:not(.ant-select-customize-input) .ant-select-selector {
border: 0.5px solid #89bdef66;
background-image: linear-gradient(180deg, #6187e400 30%, #6187e480 100%);
color: #fff;
}
.ant-select:not(.ant-select-customize-input) .ant-select-selector {
background-color: transparent;
}
.ant-select-arrow {
color: #fff;
}
}

5
web/client/src/sections/bigScreen/containers/systemManagement.js

@ -3,20 +3,19 @@ import { connect } from 'react-redux';
import { FormOutlined, DeleteOutlined } from '@ant-design/icons'; import { FormOutlined, DeleteOutlined } from '@ant-design/icons';
import { Spin, Tooltip, Button, Popconfirm, Row, Col, Tree, Card, Switch } from 'antd'; import { Spin, Tooltip, Button, Popconfirm, Row, Col, Tree, Card, Switch } from 'antd';
import ProTable from '@ant-design/pro-table'; 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 Header from '../components/header';
import Basis from '../components/basis'; import Basis from '../components/basis';
import Capacity from '../components/capacity'; import Capacity from '../components/capacity';
import Electrical from '../components/electrical'; import Electrical from '../components/electrical';
import RealTime from '../components/realTime'; import RealTime from '../components/realTime';
import Amap from '../components/AMap'; import Amap from '../components/amap';
import './style.less'; import './style.less';
const TreeNode = Tree.TreeNode; const TreeNode = Tree.TreeNode;
const SystemManagement = ({ clientHeight, user, history }) => { const SystemManagement = ({ clientHeight, user, history }) => {
const [module, setModule] = useState('basis') const [module, setModule] = useState('capacity')
useEffect(() => { useEffect(() => {
}, []) }, [])

2
web/client/src/sections/bigScreen/index.js

@ -6,7 +6,7 @@ import actions from './actions';
import { getNavItem } from './nav-item'; import { getNavItem } from './nav-item';
export default { export default {
key: 'organization', key: 'bigScreen',
name: '', name: '',
reducers: reducers, reducers: reducers,
routes: routes, routes: routes,

5
web/client/src/utils/index.js

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import { AuthorizationCode } from './authCode'; import { AuthorizationCode } from './authCode';
import { ApiTable, RouteTable } from './webapi' import { ApiTable, RouteTable, AxyRequest, AxyApiTable } from './webapi'
import Func from './func'; import Func from './func';
import { useFsRequest } from './hooks'; import { useFsRequest } from './hooks';
@ -10,5 +10,6 @@ export {
Func, Func,
ApiTable, RouteTable, ApiTable, RouteTable,
Constans, Constans,
useFsRequest useFsRequest,
AxyRequest, AxyApiTable
} }

121
web/client/src/utils/webapi.js

@ -1,120 +1,37 @@
'use strict'; 'use strict';
import request from 'superagent'; import request from 'superagent';
import { ProxyRequest, customWebUtils } from "@peace/utils";
export const ApiTable = {
login: 'login',
logout: 'logout',
validatePhone: 'validate/phone',
getUserSiteList: 'user/site/list',
// 组织管理-用户管理
getDepMessage: 'organization/department',
createDept: '/organization/dept/add',
updateDept: '/organization/dept/{id}/modify',
delDept: '/organization/dept/{id}',
getDepUser: 'organization/department/{depId}/user',
createUser: 'organization/department/user',
updateUser: 'organization/department/user/{id}',
delUser: 'organization/department/user/{ids}',
resetPwd: '/organization/department/user/resetPwd/{id}',
// 巡检计划
patrolPlan: 'patrolPlan', // 增改查
delPatrolPlan: 'patrolPlan/{id}',
// 巡检记录
patrolRecord: 'patrolRecord/:patrolPlanId/:startTime/:endTime/:alarm/:pointId',
// 用户权限
getResource: 'resource',
getUserResource: 'user/resource',
postUserRes: 'user/resource',
//安全风险预报 const userKey = "axyUser";
getSiteWeekRegiste: 'sites/report',
getRiskReportList: 'risk/report',
modifyRiskReport: 'risk/report/{riskId}',
riskExport: 'risk/export',
getEnterprisesMembers: 'enterprises/{enterpriseId}/members',
//工程交底 export const AxyRequest = new ProxyRequest("_axy", userKey);
getProjectDisclosureList: 'project/disclosure',
addProjectDisclosure: 'project/disclosure',
editProjectDisclosure: 'project/disclosure/{id}',
delProjectDisclosure: 'project/disclosure/{id}',
//安全巡检 export const webUtils = new customWebUtils({
getCheckTask: '/getcheckTask', userKey: userKey
addCheckTask: '/addcheckTask', });
editCheckTask: '/editcheckTask', const { basicAction, RouteRequest } = webUtils
delCheckTask: '/delcheckTask/:id',
//协调申请 export {
getCoordinateList: 'risk/coordinate', basicAction, RouteRequest
addCoordinate: 'risk/coordinate', }
delCoordinate: 'risk/coordinate/{id}',
editCoordinate: 'risk/coordinate/{id}',
//会议 export const ApiTable = {
mettingList: 'metting/list', login: 'login',
editMetting: 'metting', logout: 'logout',
//隐患整改
getRectifyList: 'rectify/list',
addRectify: 'rectify',
editRectify: 'rectify/{id}',
delRectify: 'rectify/{id}',
disposeRectify: 'rectify/dispose',
rectifyReport: 'rectify/report',
//问题上报
problemReport: 'report/problem',
//查阅人员
problemReportConsult: 'report/problem/consult',
//花名册管理
getWorkerList: 'get/worker/list',
addWorker: 'add/worker',
editWorker: 'worker/{id}',
delWorker: 'worker/{id}',
getWorkerIdcards: 'worker/idcards',
//安全管理
getTring: 'training/list/:siteid',
postTring: 'training',
putTring: 'training',
delTring: 'training/:id',
//考情信息 axyData: 'axyData', //安心云数据
getChcekList: 'get/worker/attendance/list',
addCheck: 'add/worker/attendance',
editCheck: 'worker/attendance/:id',
delCheck: 'worker/attendance/:id',
verifyWoker: 'verify/worker/exist',
//首页-我的待办
getDealTodoList: 'user/deal/list',
addDealTodo: 'user/deal',
//结构物 };
getProjectList: 'projectList',
postAddProject: 'addProject',
delProject: 'delProject/{id}',
//点位
position: 'position',
delPosition: 'delPosition/{id}',
qrCodeShow: 'qrCodeShow',
q:'q',
//视频接入配置 // 安心云的接口
siteList: 'siteList', export const AxyApiTable = {
addCamera: 'camera', login: 'project/login'
delCamera: 'camera/{id}',
//项目状态配置 }
editProjectStatus: 'project/status',
};
export const RouteTable = { export const RouteTable = {
apiRoot: '/api/root', apiRoot: '/api/root',

59
web/config.js

@ -15,29 +15,21 @@ dev && console.log('\x1B[33m%s\x1b[0m', '请遵循并及时更新 readme.md,
// // 启动参数 // // 启动参数
args.option(['p', 'port'], '启动端口'); args.option(['p', 'port'], '启动端口');
args.option(['u', 'api-url'], 'webapi的URL'); args.option(['u', 'api-url'], 'webapi的URL');
args.option('qnak', 'qiniuAccessKey'); args.option('apiAnxinyunUrl', "安心云api");
args.option('qnsk', 'qiniuSecretKey'); args.option('axyProject', '安心云泵站项目信息');
args.option('qnbkt', 'qiniuBucket');
args.option('qndmn', 'qiniuDomain');
args.option('aliOssAccessKey', '阿里OSS AccessKey');
args.option('aliOssSecretKey', '阿里OSS SecretKey');
args.option('aliOssBucket', '阿里OSS Bucket');
args.option('aliOssRegion', '阿里OSS Region');
const flags = args.parse(process.argv); const flags = args.parse(process.argv);
const FS_UNIAPP_API = process.env.FS_UNIAPP_API || flags.apiUrl; const FS_UNIAPP_API = process.env.FS_UNIAPP_API || flags.apiUrl;
const ANXINCLOUD_QINIU_ACCESSKEY = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak; const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.apiAnxinyunUrl
const ANXINCLOUD_QINIU_SECRETKEY = process.env.ANXINCLOUD_QINIU_SECRETKEY || flags.qnsk; const AXY_BZ_PROJECT = process.env.AXY_BZ_PROJECT || flags.axyProject
const ANXINCLOUD_QINIU_BUCKET_RESOURCE = process.env.ANXINCLOUD_QINIU_BUCKET_RESOURCE || flags.qnbkt;
const ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE || flags.qndmn;
//阿里OSS
const ALI_OSS_ACCESSKEY = process.env.ALI_OSS_ACCESSKEY || flags.aliOssAccessKey;
const ALI_OSS_SECRETKET = process.env.ALI_OSS_SECRETKET || flags.aliOssSecretKey;
const ALI_OSS_BUCKET = process.env.ALI_OSS_BUCKET || flags.aliOssBucket;
const ALI_OSS_REGION = process.env.ALI_OSS_REGION || flags.aliOssRegion;
if (!FS_UNIAPP_API || !ANXINCLOUD_QINIU_ACCESSKEY || !ANXINCLOUD_QINIU_SECRETKEY || !ANXINCLOUD_QINIU_BUCKET_RESOURCE || !ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE) { if (
!FS_UNIAPP_API
|| !API_ANXINYUN_URL
) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');
args.showHelp(); args.showHelp();
process.exit(-1); process.exit(-1);
@ -52,38 +44,29 @@ const product = {
host: FS_UNIAPP_API, host: FS_UNIAPP_API,
match: /^\/_api\//, match: /^\/_api\//,
} }
}, {
entry: require('./middlewares/proxy').entry,
opts: {
host: API_ANXINYUN_URL,
match: /^\/_axy\//,
}
}, { }, {
entry: require('./middlewares/attachment').entry, entry: require('./middlewares/attachment').entry,
opts: { opts: {
qiniu: {
accessKey: ANXINCLOUD_QINIU_ACCESSKEY,
secretKey: ANXINCLOUD_QINIU_SECRETKEY,
bucket: ANXINCLOUD_QINIU_BUCKET_RESOURCE,
domain: ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE
},
maxSize: 104857600, // 100M maxSize: 104857600, // 100M
uploadPath: 'other' uploadPath: 'other'
} }
}, { }, {
entry: require('./routes').entry, entry: require('./routes').entry,
opts: { opts: {
apiUrl: FS_UNIAPP_API, axyApi: API_ANXINYUN_URL,
staticRoot: './client', axyProject: AXY_BZ_PROJECT
qiniu: {
fetchUrl: '/_file-server',
domain: ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURCE
},
aliOss: {
fetchUrl: '/_file-ali-server',
accessKey: ALI_OSS_ACCESSKEY,
secretKey: ALI_OSS_SECRETKET,
bucket: ALI_OSS_BUCKET,
region: ALI_OSS_REGION
}
} }
}, { }, {
entry: require('./client').entry,// 静态信息 entry: require('./client').entry,// 静态信息
opts: {} opts: {
}
}], }],
logger: { logger: {
level: 'debug', level: 'debug',

5
web/package.json

@ -6,7 +6,7 @@
"scripts": { "scripts": {
"test": "mocha", "test": "mocha",
"start": "cross-env NODE_ENV=development npm run start-params", "start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5900 -u http://127.0.0.1:4900 --qnak 5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu --qnsk w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5 --qnbkt anxinyun-test --qndmn http://test.resources.anxinyun.cn --aliOssAccessKey LTAI5tNDfn7UhStYQcn3JBtw --aliOssSecretKey rnoXtDWQA1djJ5Xqcdn1OSEol0lVyv --aliOssBucket test-c371 --aliOssRegion oss-cn-hangzhou", "start-params": "node server -p 5900 -u http://127.0.0.1:4900 --apiAnxinyunUrl https://openapi.anxinyun.cn/api/v1 --axyProject 1a271f12-52f2-4d16-8dad-ec0c92d3e0cc/03bzzdh/123456",
"deploy": "export NODE_ENV=production && npm run build && node server", "deploy": "export NODE_ENV=production && npm run build && node server",
"build-dev": "export NODE_ENV=development&&webpack --config webpack.config.js", "build-dev": "export NODE_ENV=development&&webpack --config webpack.config.js",
"build": "export NODE_ENV=production&&webpack --config webpack.config.prod.js" "build": "export NODE_ENV=production&&webpack --config webpack.config.prod.js"
@ -68,7 +68,7 @@
"@antv/g6": "^4.2.5", "@antv/g6": "^4.2.5",
"@fs/attachment": "^1.0.0", "@fs/attachment": "^1.0.0",
"@peace/components": "0.0.35", "@peace/components": "0.0.35",
"@peace/utils": "0.0.37", "@peace/utils": "0.0.66",
"ahooks": "^3.7.4", "ahooks": "^3.7.4",
"ali-oss": "^6.17.1", "ali-oss": "^6.17.1",
"antd": "^4.24.5", "antd": "^4.24.5",
@ -82,6 +82,7 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"echarts": "^5.4.1", "echarts": "^5.4.1",
"echarts-for-react": "^3.0.2",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"form-data": "^3.0.0", "form-data": "^3.0.0",
"fs-attachment": "^1.0.0", "fs-attachment": "^1.0.0",

220
web/routes/attachment/index.js

@ -27,225 +27,27 @@ const ext = {
module.exports = { module.exports = {
entry: function (app, router, opts) { entry: function (app, router, opts) {
let download_ = async function (ctx, next) {
const { fetchUrl } = opts.qiniu;
const { fetchUrl: aliFetchUrl, bucket, region } = opts.aliOss
if (ctx.path && ctx.path.includes(fetchUrl)) {
try {
const { filename } = ctx.request.query;
const fkey = decodeURI(ctx.path.slice(fetchUrl.length + 1)).replace(/\.json$/, '.js');
if (ctx.path) {
const extNames = ctx.path.split('.');
app.fs.logger.log('info', 'extNames', extNames);
if (extNames.length > 0) {
let fileType = extNames[extNames.length - 1].toLowerCase();
if (fileType === 'pdf') {
ctx.type = 'application/pdf';
app.fs.logger.log('info', 'application/pdf', fileType);
}
}
}
const publicDownloadUrl = await app.fs.attachment.download(fkey);
ctx.status = 200;
if (filename) ctx.attachment(filename);
ctx.body = request.get(publicDownloadUrl);
} catch (err) {
ctx.fs.logger.error(err);
ctx.status = 404;
ctx.body = { error: 'file not found.' };
}
} else if (ctx.path && ctx.path.includes(aliFetchUrl)) {
const { filename } = ctx.request.query;
const fkey = decodeURI(ctx.path.slice(aliFetchUrl.length + 1)).replace(/\.json$/, '.js');
if (ctx.path) {
const extNames = ctx.path.split('.');
app.fs.logger.log('info', 'extNames', extNames);
if (extNames.length > 0) {
let fileType = extNames[extNames.length - 1].toLowerCase();
if (fileType === 'pdf') {
ctx.type = 'application/pdf';
app.fs.logger.log('info', 'application/pdf', fileType);
}
}
}
const publicDownloadUrl = `http://${bucket}.${region}.aliyuncs.com/${encodeURIComponent(fkey)}`
ctx.status = 200;
ctx.body = request.get(publicDownloadUrl);
} else {
await next();
}
};
const getApiRoot = async function (ctx) { const getApiRoot = async function (ctx) {
const { apiUrl, qiniu } = opts; const { apiUrl, axyApi, axyProject } = opts;
const { bucket, region } = opts.aliOss
ctx.status = 200; ctx.status = 200;
ctx.body = { ctx.body = {
root: apiUrl, root: apiUrl,
qiniu: qiniu.domain, axyApi: axyApi,
aliAdmin: `http://${bucket}.${region}.aliyuncs.com` axyProject: axyProject
}; };
}; };
let upload = async function (ctx, next) {
try {
const { files } = await parse(ctx.req);
const file = files[0];
const extname = path.extname(file.filename).toLowerCase();
const fileType = ctx.query.type || "image";
const fileFolder = ctx.query.fileFolder || 'common';
if (ext[fileType].indexOf(extname) < 0) {
ctx.status = 400;
ctx.body = JSON.stringify({ name: 'UploadFailed', message: '文件格式无效' });
return;
}
const date = new Date().toLocaleDateString();
const time = new Date().getTime();
let fileName = time + '_' + file.filename;
let saveFile = path.join(__dirname, '../../', `/client/assets/files/${fileFolder}`, fileName);
const pathUrl = `./client/assets/files/${fileFolder}`;
const res1 = fs.existsSync(`./client/assets/files/${fileFolder}`);
!res1 && fs.mkdirSync(`./client/assets/files/${fileFolder}`);
const res = fs.existsSync(pathUrl);
!res && fs.mkdirSync(pathUrl);
let stream = fs.createWriteStream(saveFile);
fs.createReadStream(file.path).pipe(stream);
stream.on('error', function (err) {
app.fs.logger.log('error', '[Upload Heatmap]', err);
});
ctx.status = 200;
ctx.body = { filename: path.join(`/assets/files/${fileFolder}`, fileName), name: 'UploadSuccess', message: '上传成功' };
} catch (err) {
ctx.status = 500;
ctx.fs.logger.error(err);
ctx.body = { err: 'upload error.' };
}
}
let remove = async function (ctx, next) {
try {
const fkeys = ctx.request.body;
let removeUrl = path.join(__dirname, '../../', './client', fkeys.url);
const res = fs.existsSync(removeUrl);
if (!res) {
ctx.status = 400;
ctx.body = JSON.stringify({ name: 'DeleteFailed', message: '文件地址不存在' });
return;
}
fs.unlink(removeUrl, function (error) {
if (error) {
console.log(error);
}
})
ctx.status = 200;
ctx.body = { name: 'DeleteSuccess.', message: '删除成功' };
} catch (err) {
ctx.status = 500;
ctx.fs.logger.error(err);
ctx.body = { err: 'upload cleanup error.' };
}
}
let upload_ = async function (ctx, next) {
let fkey = null;
try {
const { p } = ctx.params;
const { files } = await parse(ctx.req);
const file = files[0];
const extname = path.extname(file.filename).toLowerCase();
if (!UploadPath[p]) {
ctx.status = 400;
ctx.body = JSON.stringify({ error: '附件存放的文件夹名称无效' });
return;
} else if (UploadPath[p].indexOf(extname) < 0) {
ctx.status = 400;
ctx.body = JSON.stringify({ error: '文件格式无效' });
return;
} else {
const fileInfo = await ctx.app.fs.attachment.upload(file, { uploadPath: p });
fkey = fileInfo.key;
ctx.body = { uploaded: fkey };
}
} catch (err) {
ctx.status = 500;
ctx.fs.logger.error(err);
ctx.body = { err: 'upload error.' };
}
}
const uploadAliOSS = async (ctx,) => {
// 这个是上传到阿里
try {
const { aliOss } = opts
const { p = 'default' } = ctx.params;
const { files } = await parse(ctx.req);
const file = files[0];
const filename = file.filename || path.basename(file);
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: aliOss.region,
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
accessKeyId: aliOss.accessKey,
accessKeySecret: aliOss.secretKey,
// 填写Bucket名称,例如examplebucket。
bucket: aliOss.bucket,
});
let uploadPath = path.posix.join(p, uuid.v4(), filename);
let result = await client.putStream(
uploadPath,
file,
// { contentLength: size }
);
ctx.status = 200;
ctx.body = {
key: result.name,
uploaded: result.name,
url: result.url,
};
} catch (error) {
ctx.status = 400;
ctx.fs.logger.error(error);
ctx.body = { err: 'upload error.' };
}
}
const downloadFromAli = async (ctx) => {
try {
const { aliOss } = opts
const { path, filename } = ctx.query
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: aliOss.region,
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
accessKeyId: aliOss.accessKey,
accessKeySecret: aliOss.secretKey,
// 填写Bucket名称,例如examplebucket。
bucket: aliOss.bucket,
});
const filename_ = filename || path.split('/').pop()
const result = await client.get(path);
ctx.status = 200;
ctx.set('Content-Type', 'application/x-xls');
ctx.set('Content-disposition', 'attachment; filename=' + filename_);
ctx.body = result.content;
} catch (error) {
ctx.status = 400;
ctx.fs.logger.error(error);
ctx.body = { err: 'download error.' };
}
}
router.use(download_); // router.use(download_);
router.get('/api/root', getApiRoot); router.get('/api/root', getApiRoot);
router.post('/_upload/new', upload); // router.post('/_upload/new', upload);
router.delete('/_upload/cleanup', remove); // router.delete('/_upload/cleanup', remove);
router.post('/_upload/attachments/ali/:p', uploadAliOSS); // router.post('/_upload/attachments/ali/:p', uploadAliOSS);
router.get('/_download/attachments/ali', downloadFromAli); // router.get('/_download/attachments/ali', downloadFromAli);
router.post('/_upload/attachments/:p', upload_); // router.post('/_upload/attachments/:p', upload_);
} }
}; };

Loading…
Cancel
Save