From afc6a6dd34d27ba934b52bd8df14cf6d27e4eec3 Mon Sep 17 00:00:00 2001 From: liujiangyong Date: Wed, 10 Jan 2024 17:00:24 +0800 Subject: [PATCH] =?UTF-8?q?(+)=20=E7=94=A8=E6=88=B7=E3=80=81=E6=9D=83?= =?UTF-8?q?=E9=99=90=E7=AE=A1=E7=90=86=E5=8F=8A=E6=93=8D=E4=BD=9C=E6=97=A5?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/lib/controllers/auth/index.js | 37 +++- api/app/lib/controllers/bigScreen/index .js | 18 +- .../lib/controllers/operationLogs/index.js | 49 +++++ .../lib/controllers/organization/authority.js | 102 +++++++++ api/app/lib/controllers/organization/user.js | 204 ++++++++++++++++++ api/app/lib/index.js | 29 +-- api/app/lib/models/operation_log.js | 74 +++++++ api/app/lib/models/resource.js | 43 ++++ api/app/lib/models/user.js | 9 + api/app/lib/models/user_resource.js | 51 +++++ .../{organization => bigScreen}/index.js | 0 api/app/lib/routes/operationLogs/index.js | 19 ++ api/app/lib/routes/organization/authority.js | 28 +++ api/app/lib/routes/organization/user.js | 22 ++ scripts/0.4/data/1.add_user.sql | 16 ++ scripts/0.4/data/2.add_user_resource.sql | 47 ++++ .../schema/1.create_organization_table.sql | 30 +++ scripts/0.4/schema/2.create_operation_log.sql | 22 ++ web/client/src/app.js | 4 +- .../src/layout/components/header/index.js | 15 +- .../src/sections/auth/containers/login.js | 23 +- .../bigScreen/components/basis/right_2.js | 2 +- .../components/electrity/realTimeStatus.js | 5 + .../sections/bigScreen/components/header.js | 64 ++++-- .../bigScreen/containers/systemManagement.js | 12 +- .../sections/operationLogs/actions/index.js | 7 + .../operationLogs/actions/operationLogs.js | 20 ++ .../operationLogs/containers/index.js | 5 + .../operationLogs/containers/operationLogs.js | 93 ++++++++ .../src/sections/operationLogs/index.js | 15 ++ .../src/sections/operationLogs/nav-item.js | 20 ++ .../sections/operationLogs/reducers/index.js | 5 + .../src/sections/operationLogs/routes.js | 14 ++ .../organization/actions/authority.js | 51 +++++ .../sections/organization/actions/index.js | 9 + .../src/sections/organization/actions/user.js | 66 ++++++ .../organization/components/resetPwd.js | 74 +++++++ .../organization/components/resource.js | 120 +++++++++++ .../organization/components/userModal.js | 93 ++++++++ .../organization/containers/authority.js | 109 ++++++++++ .../sections/organization/containers/index.js | 6 + .../sections/organization/containers/user.js | 186 ++++++++++++++++ web/client/src/sections/organization/index.js | 15 ++ .../src/sections/organization/nav-item.js | 28 +++ .../sections/organization/reducers/index.js | 5 + .../src/sections/organization/routes.js | 26 +++ web/client/src/utils/func.js | 22 +- web/client/src/utils/webapi.js | 20 +- 48 files changed, 1862 insertions(+), 72 deletions(-) create mode 100644 api/app/lib/controllers/operationLogs/index.js create mode 100644 api/app/lib/controllers/organization/authority.js create mode 100644 api/app/lib/controllers/organization/user.js create mode 100644 api/app/lib/models/operation_log.js create mode 100644 api/app/lib/models/resource.js create mode 100644 api/app/lib/models/user_resource.js rename api/app/lib/routes/{organization => bigScreen}/index.js (100%) create mode 100644 api/app/lib/routes/operationLogs/index.js create mode 100644 api/app/lib/routes/organization/authority.js create mode 100644 api/app/lib/routes/organization/user.js create mode 100644 scripts/0.4/data/1.add_user.sql create mode 100644 scripts/0.4/data/2.add_user_resource.sql create mode 100644 scripts/0.4/schema/1.create_organization_table.sql create mode 100644 scripts/0.4/schema/2.create_operation_log.sql create mode 100644 web/client/src/sections/operationLogs/actions/index.js create mode 100644 web/client/src/sections/operationLogs/actions/operationLogs.js create mode 100644 web/client/src/sections/operationLogs/containers/index.js create mode 100644 web/client/src/sections/operationLogs/containers/operationLogs.js create mode 100644 web/client/src/sections/operationLogs/index.js create mode 100644 web/client/src/sections/operationLogs/nav-item.js create mode 100644 web/client/src/sections/operationLogs/reducers/index.js create mode 100644 web/client/src/sections/operationLogs/routes.js create mode 100644 web/client/src/sections/organization/actions/authority.js create mode 100644 web/client/src/sections/organization/actions/index.js create mode 100644 web/client/src/sections/organization/actions/user.js create mode 100644 web/client/src/sections/organization/components/resetPwd.js create mode 100644 web/client/src/sections/organization/components/resource.js create mode 100644 web/client/src/sections/organization/components/userModal.js create mode 100644 web/client/src/sections/organization/containers/authority.js create mode 100644 web/client/src/sections/organization/containers/index.js create mode 100644 web/client/src/sections/organization/containers/user.js create mode 100644 web/client/src/sections/organization/index.js create mode 100644 web/client/src/sections/organization/nav-item.js create mode 100644 web/client/src/sections/organization/reducers/index.js create mode 100644 web/client/src/sections/organization/routes.js diff --git a/api/app/lib/controllers/auth/index.js b/api/app/lib/controllers/auth/index.js index 4ddaa8a..705cafe 100644 --- a/api/app/lib/controllers/auth/index.js +++ b/api/app/lib/controllers/auth/index.js @@ -5,7 +5,7 @@ const MD5 = require('crypto-js/md5'); const moment = require('moment'); const uuid = require('uuid'); -async function login (ctx, next) { +async function login(ctx, next) { try { // const transaction = await ctx.fs.dc.orm.transaction(); @@ -16,10 +16,13 @@ async function login (ctx, next) { where: { username: params.username, password: password, - } + }, + include: [{ + attributes: ["resourceCode"], + model: models.UserResource + }] }); - if (userRes) { const token = uuid.v4(); const userInfo = { @@ -35,6 +38,15 @@ async function login (ctx, next) { userInfo: userInfo, expired: expired }); + + await models.OperationLog.create({ + time: new Date().getTime(), + clientType: ctx.header['user-agent'], + content: '登录', + parameter: null, + userId: userInfo.id, + }) + ctx.status = 200; ctx.body = userInfo } else { @@ -54,7 +66,7 @@ async function login (ctx, next) { } } -async function varfiyCode (ctx) { +async function varfiyCode(ctx) { try { const { models } = ctx.fs.dc; const { pushBySms, pushByEmail } = ctx.app.fs.utils @@ -104,17 +116,32 @@ async function varfiyCode (ctx) { } } -async function logout (ctx) { +async function logout(ctx) { try { const models = ctx.fs.dc.models; const params = ctx.request.body; + const userInfo = await models.UserToken.findOne({ + where: { + token: params.token, + }, + attributes: ["userInfo"], + raw: true, + }); await models.UserToken.destroy({ where: { token: params.token, } }); + await models.OperationLog.create({ + time: new Date().getTime(), + clientType: ctx.header['user-agent'], + content: '登出', + parameter: null, + userId: userInfo.userInfo.id, + }) + ctx.status = 204; } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); diff --git a/api/app/lib/controllers/bigScreen/index .js b/api/app/lib/controllers/bigScreen/index .js index 0553f5b..dae060a 100644 --- a/api/app/lib/controllers/bigScreen/index .js +++ b/api/app/lib/controllers/bigScreen/index .js @@ -34,7 +34,7 @@ const getAnxinyunToken = async function (ctx) { ctx.fs.logger.error(`sechedule: laborAttendance, error: ${error}`); } } -async function axyData (ctx, next) { +async function axyData(ctx, next) { try { let { type, url, params = {} } = ctx.request.body; @@ -116,7 +116,7 @@ const getVideoUrl = async function (ctx) { } -async function getDevices (ctx, next) { +async function getDevices(ctx, next) { try { let { thingId } = ctx.query; @@ -133,7 +133,7 @@ async function getDevices (ctx, next) { } -async function getInstances (ctx, next) { +async function getInstances(ctx, next) { try { let { thingId } = ctx.query; @@ -150,13 +150,23 @@ async function getInstances (ctx, next) { } -async function getCapabilitiesInvoke (ctx, next) { +async function getCapabilitiesInvoke(ctx, next) { try { + const models = ctx.fs.dc.models; let data = ctx.query; const res = await ctx.app.iota.request.post(`/capabilities/invoke`, data) || {} + const userId = ctx.fs.api.userId; + await models.OperationLog.create({ + time: new Date().getTime(), + clientType: ctx.header['user-agent'], + content: `下发泵站控制指令`, + parameter: null, + userId, + }) + ctx.status = 200; ctx.body = res.body; } catch (err) { diff --git a/api/app/lib/controllers/operationLogs/index.js b/api/app/lib/controllers/operationLogs/index.js new file mode 100644 index 0000000..0beaebe --- /dev/null +++ b/api/app/lib/controllers/operationLogs/index.js @@ -0,0 +1,49 @@ +'use strict'; + +async function getLog(ctx, next) { + try { + const models = ctx.fs.dc.models; + const { limit, page, startTime, endTime, keyword } = ctx.query + + let findOption = { + where: {}, + order: [['time', 'DESC']], + include: [{ + model: models.User, + attributes: ["name", "username"], + }], + distinct: true + } + if (limit) { + findOption.limit = Number(limit) + } + if (page && limit) { + findOption.offset = page * limit + } + if (startTime && endTime) { + findOption.where.time = { $between: [startTime, endTime] }; + } + if (keyword) { + findOption.where['$or'] = { + clientType: { $like: `%${keyword}%` }, + content: { $like: `%${keyword}%` }, + parameter: { $like: `%${keyword}%` }, + } + } + + const res = await models.OperationLog.findAndCountAll(findOption) + + ctx.status = 200; + ctx.body = res + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { + "message": "获取操作日志失败" + } + } +} + +module.exports = { + getLog, +} \ No newline at end of file diff --git a/api/app/lib/controllers/organization/authority.js b/api/app/lib/controllers/organization/authority.js new file mode 100644 index 0000000..6960c1e --- /dev/null +++ b/api/app/lib/controllers/organization/authority.js @@ -0,0 +1,102 @@ +async function getResource(ctx, next) { + try { + const models = ctx.fs.dc.models; + + const res = await models.Resource.findAll({ + where: { parentCode: 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: ["resourceCode"], + raw: true, + where: { userId: userId } + }) + + const addRes = resCode.filter(r => !res.some(rr => rr.resourceCode == r)).map(r => { return { userId: userId, resourceCode: r } }); + const delRes = res.filter(r => !resCode.includes(r.resourceCode)).map(r => r.resourceCode); + addRes.length && await models.UserResource.bulkCreate(addRes, { transaction: transaction }); + delRes.length && await models.UserResource.destroy({ + where: { + resourceCode: { $in: delRes }, + userId: userId + }, + transaction: transaction + }) + + const operationUserId = ctx.fs.api.userId; + const user = await models.User.findOne({ + attributes: ["name"], + where: { id: userId }, + raw: true, + transaction: transaction, + }) + await models.OperationLog.create({ + time: new Date().getTime(), + clientType: ctx.header['user-agent'], + content: `修改 (${user.name}) 用户权限`, + parameter: null, + userId: operationUserId, + }, { 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 +}; \ No newline at end of file diff --git a/api/app/lib/controllers/organization/user.js b/api/app/lib/controllers/organization/user.js new file mode 100644 index 0000000..e5e469a --- /dev/null +++ b/api/app/lib/controllers/organization/user.js @@ -0,0 +1,204 @@ +'use strict'; +const Hex = require('crypto-js/enc-hex'); +const MD5 = require('crypto-js/md5'); + +async function getUser(ctx, next) { + try { + const models = ctx.fs.dc.models; + const userRes = await models.User.findAll({ + where: { + delete: false + }, + attributes: { exclude: ['password'] }, + order: [['id', 'asc']], + }) + + 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.username, + delete: false + } + }) + + if (repeatUserNameCount) { + errMsg = '已有当前用户名' + throw errMsg + } + + await models.User.create({ + name: data.name, + username: data.username, + password: Hex.stringify(MD5(data.password)), + delete: false, + }) + const userId = ctx.fs.api.userId; + await models.OperationLog.create({ + time: new Date().getTime(), + clientType: ctx.header['user-agent'], + content: `新建用户:${data.name}`, + parameter: null, + userId, + }) + + 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.findOne({ + where: { + username: data.username, + delete: false + }, + raw: true, + }) + + if (repeatUserNameCount && repeatUserNameCount.id != id) { + errMsg = '已有当前用户名' + throw errMsg + } + + await models.User.update({ + name: data.name, + username: data.username, + delete: false, + }, { + where: { id } + }); + + const userId = ctx.fs.api.userId; + await models.OperationLog.create({ + time: new Date().getTime(), + clientType: ctx.header['user-agent'], + content: `修改 (${data.name}) 用户信息`, + parameter: null, + userId, + }) + + 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(','); + const delUser = await models.User.update({ + delete: true, + }, { + where: { + id: { $in: userIds }, + }, + returning: true, + }); + + const userId = ctx.fs.api.userId; + const userName = delUser[1].map(item => item.name).join() + await models.OperationLog.create({ + time: new Date().getTime(), + clientType: ctx.header['user-agent'], + content: `删除用户:${userName}`, + parameter: null, + userId, + }) + + 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 { password } = ctx.request.body; + if (!password) { + ctx.status = 400; + ctx.body = { "message": "请输入修改密码" }; + return; + } + const userRes = await models.User.findOne({ + where: { id }, + attributes: ['id'] + }); + if (userRes) { + const updateUser = await models.User.update( + { password: Hex.stringify(MD5(password)) }, + { + where: { id }, + returning: true, + }, + ); + const userId = ctx.fs.api.userId; + await models.OperationLog.create({ + time: new Date().getTime(), + clientType: ctx.header['user-agent'], + content: `修改 (${updateUser[1][0].name}) 用户密码`, + parameter: null, + 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 = { + getUser, + creatUser, + updateUser, + deleteUser, + resetPwd, +} \ No newline at end of file diff --git a/api/app/lib/index.js b/api/app/lib/index.js index 7684a5e..82597d7 100644 --- a/api/app/lib/index.js +++ b/api/app/lib/index.js @@ -11,7 +11,7 @@ const authenticator = require('./middlewares/authenticator'); //const clickHouseClient = require('./service/clickHouseClient') const schedule = require('./schedule') // const apiLog = require('./middlewares/api-log'); - + module.exports.entry = function (app, router, opts) { app.fs.logger.log('info', '[FS-AUTH]', 'Inject auth and api mv into router.'); @@ -53,25 +53,18 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq require(`./models/${filename}`)(dc) }); - // const { Department, User, UserResource, Resource, Project, Point, PatrolPlan - // } = dc.models; - - // UserResource.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' }); - // User.hasMany(UserResource, { foreignKey: 'userId', sourceKey: 'id' }); - - // UserResource.belongsTo(Resource, { foreignKey: 'resourceId', targetKey: 'code' }); - // Resource.hasMany(UserResource, { foreignKey: 'resourceId', sourceKey: 'code' }); - // Resource.hasMany(Resource, { foreignKey: 'parentResource', sourceKey: 'code' }); + const { User, UserResource, Resource, OperationLog, } = dc.models; - // User.belongsTo(Department, { foreignKey: 'departmentId', targetKey: 'id' }); - // Department.hasMany(User, { foreignKey: 'departmentId', sourceKey: 'id' }); + User.belongsToMany(Resource, { through: UserResource, foreignKey: 'userId', otherKey: 'resourceCode' }); + Resource.belongsToMany(User, { through: UserResource, foreignKey: 'resourceCode', otherKey: 'userId' }); - // Point.belongsTo(Project, { foreignKey: 'projectId', targetKey: 'id' }); - // Project.hasMany(Point, { foreignKey: 'projectId', sourceKey: 'id' }); + UserResource.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' }); + User.hasMany(UserResource, { foreignKey: 'userId', sourceKey: 'id' }); - // PatrolPlan.belongsTo(Project, { foreignKey: 'structureId', targetKey: 'id' }); - // Project.hasMany(PatrolPlan, { foreignKey: 'structureId', sourceKey: 'id' }); + UserResource.belongsTo(Resource, { foreignKey: 'resourceCode', targetKey: 'code' }); + Resource.hasMany(UserResource, { foreignKey: 'resourceCode', sourceKey: 'code' }); + Resource.hasMany(Resource, { foreignKey: 'parentCode', sourceKey: 'code' }); - // PatrolPlan.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' }); - // User.hasMany(PatrolPlan, { foreignKey: 'userId', sourceKey: 'id' }); + OperationLog.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' }); + User.hasMany(OperationLog, { foreignKey: 'userId', sourceKey: 'id' }); }; diff --git a/api/app/lib/models/operation_log.js b/api/app/lib/models/operation_log.js new file mode 100644 index 0000000..9c4b648 --- /dev/null +++ b/api/app/lib/models/operation_log.js @@ -0,0 +1,74 @@ +/* eslint-disable*/ +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const OperationLog = sequelize.define("operationLog", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: true, + field: "id", + autoIncrement: true, + }, + time: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: null, + comment: "操作时间", + primaryKey: false, + field: "time", + autoIncrement: false + }, + clientType: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "客户端类型", + primaryKey: false, + field: "client_type", + autoIncrement: false + }, + content: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: "操作内容", + primaryKey: false, + field: "content", + autoIncrement: false + }, + parameter: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "操作参数", + primaryKey: false, + field: "parameter", + autoIncrement: false + }, + userId: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: "操作用户ID", + primaryKey: false, + field: "user_id", + autoIncrement: false, + references: { + key: "id", + model: "t_user" + } + }, + }, { + tableName: "t_operation_log", + comment: "", + indexes: [] + }); + + dc.models.OperationLog = OperationLog; + return OperationLog; +}; \ No newline at end of file diff --git a/api/app/lib/models/resource.js b/api/app/lib/models/resource.js new file mode 100644 index 0000000..f0a4764 --- /dev/null +++ b/api/app/lib/models/resource.js @@ -0,0 +1,43 @@ +/* eslint-disable*/ +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const Resource = sequelize.define("resource", { + code: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: true, + field: "code", + autoIncrement: false, + }, + name: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "name", + autoIncrement: false + }, + parentCode: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: null, + primaryKey: false, + field: "parent_code", + autoIncrement: false, + }, + }, { + tableName: "t_resource", + comment: "", + indexes: [] + }); + + dc.models.Resource = Resource; + return Resource; +}; \ No newline at end of file diff --git a/api/app/lib/models/user.js b/api/app/lib/models/user.js index a3196b9..f07f715 100644 --- a/api/app/lib/models/user.js +++ b/api/app/lib/models/user.js @@ -42,6 +42,15 @@ module.exports = dc => { field: "password", autoIncrement: false }, + delete: { + type: DataTypes.BOOLEAN, + allowNull: false, + defaultValue: false, + comment: null, + primaryKey: false, + field: "delete", + autoIncrement: false + }, }, { tableName: "t_user", comment: "", diff --git a/api/app/lib/models/user_resource.js b/api/app/lib/models/user_resource.js new file mode 100644 index 0000000..586d234 --- /dev/null +++ b/api/app/lib/models/user_resource.js @@ -0,0 +1,51 @@ +/* eslint-disable*/ +'use strict'; + +module.exports = dc => { + const DataTypes = dc.ORM; + const sequelize = dc.orm; + const UserResource = sequelize.define("userResource", { + id: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: true, + field: "id", + autoIncrement: true, + }, + userId: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "user_id", + autoIncrement: false, + references: { + key: "id", + model: "t_user" + } + }, + resourceCode: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "resource_code", + autoIncrement: false, + references: { + key: "code", + model: "t_resource" + } + } + }, { + tableName: "t_user_resource", + comment: "", + indexes: [] + }); + + dc.models.UserResource = UserResource; + return UserResource; +}; \ No newline at end of file diff --git a/api/app/lib/routes/organization/index.js b/api/app/lib/routes/bigScreen/index.js similarity index 100% rename from api/app/lib/routes/organization/index.js rename to api/app/lib/routes/bigScreen/index.js diff --git a/api/app/lib/routes/operationLogs/index.js b/api/app/lib/routes/operationLogs/index.js new file mode 100644 index 0000000..41f6c52 --- /dev/null +++ b/api/app/lib/routes/operationLogs/index.js @@ -0,0 +1,19 @@ +'use strict'; + +const operationLog = require('../../controllers/operationLogs/index'); + +module.exports = function (app, router, opts) { + + app.fs.api.logAttr['GET/operationLog'] = { content: '获取操作日志', visible: false }; + router.get('/operationLog', operationLog.getLog); + + // app.fs.api.logAttr['POST/operationLog'] = { content: '创建操作日志', visible: false }; + // router.post('/operationLog', operationLog.creatLog); + + // app.fs.api.logAttr['PUT/operationLog/:id'] = { content: '修改操作日志', visible: false }; + // router.put('/operationLog/:id', operationLog.updateLog); + + // app.fs.api.logAttr['DEL/operationLog/:ids'] = { content: '删除操作日志', visible: false }; + // router.del('/operationLog/:ids', operationLog.deleteLog); + +}; \ No newline at end of file diff --git a/api/app/lib/routes/organization/authority.js b/api/app/lib/routes/organization/authority.js new file mode 100644 index 0000000..99de6df --- /dev/null +++ b/api/app/lib/routes/organization/authority.js @@ -0,0 +1,28 @@ +'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); +}; \ No newline at end of file diff --git a/api/app/lib/routes/organization/user.js b/api/app/lib/routes/organization/user.js new file mode 100644 index 0000000..e5bf4e1 --- /dev/null +++ b/api/app/lib/routes/organization/user.js @@ -0,0 +1,22 @@ +'use strict'; + +const user = require('../../controllers/organization/user'); + +module.exports = function (app, router, opts) { + + app.fs.api.logAttr['GET/organization/user'] = { content: '获取用户信息', visible: false }; + router.get('/organization/user', user.getUser); + + app.fs.api.logAttr['POST/organization/user'] = { content: '创建用户信息', visible: false }; + router.post('/organization/user', user.creatUser); + + app.fs.api.logAttr['PUT/organization/user/:id'] = { content: '修改用户信息', visible: false }; + router.put('/organization/user/:id', user.updateUser); + + app.fs.api.logAttr['DEL/organization/user/:ids'] = { content: '删除用户信息', visible: false }; + router.del('/organization/user/:ids', user.deleteUser); + + app.fs.api.logAttr['PUT/organization/user/resetPwd/:id'] = { content: '重置用户密码', visible: false }; + router.put('/organization/user/resetPwd/:id', user.resetPwd); + +}; \ No newline at end of file diff --git a/scripts/0.4/data/1.add_user.sql b/scripts/0.4/data/1.add_user.sql new file mode 100644 index 0000000..a796963 --- /dev/null +++ b/scripts/0.4/data/1.add_user.sql @@ -0,0 +1,16 @@ +INSERT INTO + "public"."t_user" ( + "id", + "name", + "username", + "password", + "delete" + ) +VALUES + ( + default, + '超级管理员', + 'SuperAdmin', + 'e10adc3949ba59abbe56e057f20f883e', + 'f' + ); \ No newline at end of file diff --git a/scripts/0.4/data/2.add_user_resource.sql b/scripts/0.4/data/2.add_user_resource.sql new file mode 100644 index 0000000..0ca192f --- /dev/null +++ b/scripts/0.4/data/2.add_user_resource.sql @@ -0,0 +1,47 @@ +INSERT INTO "public"."t_resource" VALUES ('ORG_MANAGE', '组织管理', NULL); +INSERT INTO "public"."t_resource" VALUES ('ORG_MEMBER', '用户管理', 'ORG_MANAGE'); +INSERT INTO "public"."t_resource" VALUES ('ORG_AUTH', '权限配置', 'ORG_MANAGE'); +INSERT INTO "public"."t_resource" VALUES ('OPERATION_LOG', '操作日志', NULL); +INSERT INTO "public"."t_resource" VALUES ('OPERATION_LOG_VIEW', '操作日志查看', 'OPERATION_LOG'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_CONTROL', '泵站控制', NULL); +INSERT INTO "public"."t_resource" VALUES ('PUMP_WATER_CONTROL', '泵站水泵控制', 'PUMP_CONTROL'); +INSERT INTO "public"."t_resource" VALUES ('MONITORING_SCOPE', '泵站监测', NULL); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3569', '八月湖二站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3590', '张坊电排站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3592', '东山电排站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3593', '利用站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3594', '杨家湾站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3595', '汇仁大道补水站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3596', '河下电排站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3597', '石岐补水站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3598', '石岐电排站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3599', '三山电排站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3600', '万寿湖电排站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3601', '河外电排站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3642', '沥山电排站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3652', '象湖泵站', 'MONITORING_SCOPE'); +INSERT INTO "public"."t_resource" VALUES ('PUMP_STATION_3653', '雄溪泵站', 'MONITORING_SCOPE'); + +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'ORG_MANAGE'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'ORG_MEMBER'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'ORG_AUTH'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'OPERATION_LOG'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'OPERATION_LOG_VIEW'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_CONTROL'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_WATER_CONTROL'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'MONITORING_SCOPE'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3569'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3590'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3592'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3593'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3594'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3595'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3596'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3597'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3598'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3599'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3600'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3601'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3642'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3652'); +INSERT INTO "public"."t_user_resource" VALUES (default, 1, 'PUMP_STATION_3653'); \ No newline at end of file diff --git a/scripts/0.4/schema/1.create_organization_table.sql b/scripts/0.4/schema/1.create_organization_table.sql new file mode 100644 index 0000000..a6fd2fb --- /dev/null +++ b/scripts/0.4/schema/1.create_organization_table.sql @@ -0,0 +1,30 @@ +DROP TABLE IF EXISTS "public"."t_user"; +CREATE TABLE "public"."t_user" ( + "id" serial, + "name" varchar(64) NOT NULL, + "username" varchar(64) NOT NULL, + "password" varchar(255) NOT NULL, + "delete" bool NOT NULL DEFAULT false, + PRIMARY KEY ("id") +); +COMMENT ON COLUMN "public"."t_user"."username" IS '用户名 账号'; + + +DROP TABLE IF EXISTS "public"."t_resource"; +CREATE TABLE "public"."t_resource" ( + "code" varchar(128) NOT NULL, + "name" varchar(128) NOT NULL, + "parent_code" varchar(128), + PRIMARY KEY ("code") +); + + +DROP TABLE IF EXISTS "public"."t_user_resource"; +CREATE TABLE "public"."t_user_resource" ( + "id" serial, + "user_id" int4 NOT NULL, + "resource_code" varchar(128) NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "user_resource_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."t_user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION, + CONSTRAINT "user_resource_resource_code_fk" FOREIGN KEY ("resource_code") REFERENCES "public"."t_resource" ("code") ON DELETE NO ACTION ON UPDATE NO ACTION +); \ No newline at end of file diff --git a/scripts/0.4/schema/2.create_operation_log.sql b/scripts/0.4/schema/2.create_operation_log.sql new file mode 100644 index 0000000..57d01fb --- /dev/null +++ b/scripts/0.4/schema/2.create_operation_log.sql @@ -0,0 +1,22 @@ +DROP TABLE IF EXISTS "public"."t_operation_log"; + +CREATE TABLE "public"."t_operation_log" ( + "id" serial, + "time" timestamptz NOT NULL, + "client_type" varchar(512) NOT NULL, + "content" varchar(255) NOT NULL, + "parameter" varchar(512), + "user_id" int4 NOT NULL, + PRIMARY KEY ("id"), + CONSTRAINT "operation_log_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."t_user" ("id") ON DELETE NO ACTION ON UPDATE NO ACTION +); + +COMMENT ON COLUMN "public"."t_operation_log"."time" IS '操作时间'; + +COMMENT ON COLUMN "public"."t_operation_log"."client_type" IS '客户端类型'; + +COMMENT ON COLUMN "public"."t_operation_log"."content" IS '操作内容'; + +COMMENT ON COLUMN "public"."t_operation_log"."parameter" IS '操作参数'; + +COMMENT ON COLUMN "public"."t_operation_log"."user_id" IS '操作用户ID'; \ No newline at end of file diff --git a/web/client/src/app.js b/web/client/src/app.js index c90edf7..0cbbce7 100644 --- a/web/client/src/app.js +++ b/web/client/src/app.js @@ -4,6 +4,8 @@ import React, { useEffect } from 'react'; import Layout from './layout'; import Auth from './sections/auth'; import bigScreen from './sections/bigScreen'; +import Organization from './sections/organization'; +import OperationLog from './sections/operationLogs'; const App = props => { const { projectName } = props @@ -15,7 +17,7 @@ const App = props => { return ( ) diff --git a/web/client/src/layout/components/header/index.js b/web/client/src/layout/components/header/index.js index fd3712f..2bcb473 100644 --- a/web/client/src/layout/components/header/index.js +++ b/web/client/src/layout/components/header/index.js @@ -5,8 +5,9 @@ import { Link } from 'react-router-dom'; import { connect } from 'react-redux'; import styles from './style.css'; import { - MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, LogoutOutlined + MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined, } from '@ant-design/icons'; +import { Func } from '$utils'; const Header = props => { const { dispatch, history, user, pathname, toggleCollapsed, collapsed, actions } = props @@ -40,6 +41,12 @@ const Header = props => { {/* */} 泵站系统 + {Func.isAuthorized('MONITORING_SCOPE') && { + history.push(`/systemManagement`); + }} + >返回大屏}