wenlele 2 years ago
parent
commit
7f585c6366
  1. 1
      .gitignore
  2. 7
      api/.vscode/launch.json
  3. 13
      api/Dockerfilenew
  4. 16
      api/app/lib/controllers/auth/index.js
  5. 17
      api/app/lib/controllers/data/index.js
  6. 91
      api/app/lib/controllers/data/task.js
  7. 4
      api/app/lib/controllers/organization/user.js
  8. 35
      api/app/lib/controllers/report/index.js
  9. 8
      api/app/lib/index.js
  10. 20
      api/app/lib/models/report.js
  11. 87
      api/app/lib/models/task_manage.js
  12. 8
      api/app/lib/models/user.js
  13. 10
      api/app/lib/routes/data/index.js
  14. 5
      api/app/lib/routes/report/index.js
  15. 15
      api/log/development.log
  16. 22
      jenkinsfilenew_api
  17. 25
      jenkinsfilenew_web
  18. 2
      scripts/1.2.0/data/1.alter_user.sql
  19. 16
      scripts/1.2.0/data/2.create_task_manage.sql
  20. 9
      scripts/1.2.1/schema/1update_report.sql
  21. 7
      weapp/project.config.json
  22. 6
      weapp/project.private.config.json
  23. 12
      weapp/src/components/uploads/index.js
  24. 4
      weapp/src/config.js
  25. 127
      weapp/src/packages/patrol/index.jsx
  26. 52
      weapp/src/packages/patrolView/index.jsx
  27. 2
      weapp/src/packages/patrolView/index.scss
  28. 34
      weapp/src/pages/home/index.jsx
  29. 10
      weapp/src/pages/home/index.scss
  30. 26
      weapp/src/pages/user/index.jsx
  31. 49
      weapp/src/static/img/home/fill-anomaly.svg
  32. 218
      weapp/src/static/img/home/fill-bg.svg
  33. 49
      weapp/src/static/img/home/fill-road.svg
  34. 1
      web/Dockerfile
  35. 17
      web/Dockerfilenew
  36. BIN
      web/client/assets/images/jiekou.png
  37. BIN
      web/client/assets/images/tiptop.png
  38. 2
      web/client/src/app.js
  39. 7
      web/client/src/layout/containers/layout/index.js
  40. 4
      web/client/src/sections/auth/containers/login.js
  41. 11
      web/client/src/sections/fillion/actions/patrol.js
  42. 35
      web/client/src/sections/fillion/actions/task.js
  43. 180
      web/client/src/sections/fillion/components/datajuji.js
  44. 211
      web/client/src/sections/fillion/components/editGuanlang.js
  45. 20
      web/client/src/sections/fillion/components/inforTable.js
  46. 112
      web/client/src/sections/fillion/components/patrolTable.js
  47. 152
      web/client/src/sections/fillion/components/task/addTaskModal.js
  48. 4
      web/client/src/sections/fillion/containers/index.js
  49. 9
      web/client/src/sections/fillion/containers/jiekouguanli.js
  50. 16
      web/client/src/sections/fillion/containers/patrol.js
  51. 186
      web/client/src/sections/fillion/containers/task.js
  52. 261
      web/client/src/sections/fillion/containers/videois.js
  53. 12
      web/client/src/sections/fillion/nav-item.js
  54. 27
      web/client/src/sections/fillion/routes.js
  55. 8
      web/client/src/sections/organization/components/userModal.js
  56. 30
      web/client/src/sections/organization/containers/user.js
  57. 1
      web/client/src/sections/quanju/containers/footer/build/Leftbottom.js
  58. 6
      web/client/src/utils/webapi.js
  59. 2
      web/package-lock.json
  60. 2
      web/package.json

1
.gitignore

@ -142,3 +142,4 @@ dist
web/client/assets/color.less
package-lock.json
development.text
web/package-lock.json

7
api/.vscode/launch.json

@ -13,9 +13,10 @@
"NODE_ENV": "development"
},
"args": [
"-p 14000",
"-f http://localhost:14000",
"-g postgres://postgres:123@10.8.30.32:5432/highways4good",
"-p 13400",
"-f http://localhost:13400",
// "-g postgres://postgres:123@10.8.30.32:5432/highways4good",
"-g postgres://FashionAdmin:123456@10.8.30.156:5432/highway4goodn0728",
"--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5",
"--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa",
"--qnbkt dev-highways4good",

13
api/Dockerfilenew

@ -0,0 +1,13 @@
FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12-dev as builder
COPY . /var/app
WORKDIR /var/app
EXPOSE 8080
RUN npm config set registry=https://nexus.ngaiot.com/repository/fs-npm/
RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json
RUN npm cache clean -f
RUN rm -rf package-lock.json
RUN npm install --registry https://nexus.ngaiot.com/repository/fs-npm/
FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12
COPY --from=builder --chown=node /var/app /home/node/app
WORKDIR /home/node/app
CMD ["node", "server.js"]

16
api/app/lib/controllers/auth/index.js

@ -9,18 +9,26 @@ async function login (ctx, next) {
try {
const models = ctx.fs.dc.models;
const params = ctx.request.body;
console.log('params.username', params)
let password = Hex.stringify(MD5(params.password));
const userRes = await models.User.findOne({
where: {
username: params.username,
$or: [{ username: params.username },
{ phone: params.username }
],
password: password,
delete: false,
},
attributes: { exclude: ['password', 'delete'] },
});
if (!userRes) {
console.log('userRes', userRes)
if (!userRes.isAdmin) {
ctx.status = 400;
ctx.body = {
"message": "不是管理员,禁止登录"
}
}
else if (!userRes) {
ctx.status = 400;
ctx.body = {
"message": "账号或密码错误"

17
api/app/lib/controllers/data/index.js

@ -8,7 +8,8 @@ async function dataExport (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId } = ctx.fs.api
const { exp, ids, roadLevel, municipalType } = ctx.query;
const { exp, ids, roadLevel, municipalType,
patrolType } = ctx.query;
if (!exp) {
throw '参数错误';
@ -89,11 +90,23 @@ async function dataExport (ctx) {
const tableAttributes = models[modalOption.tableName].tableAttributes
let header = []
for (let k in tableAttributes) {
const comment = tableAttributes[k].comment
let comment = tableAttributes[k].comment
if (k != 'id' && comment) {
if (comment == '品名' && municipalType == '出租车') {
continue
}
if (patrolType) {
if (patrolType == 'road') {
} else if (patrolType == 'anomaly') {
} else {
// 正常的之前的巡查内容
if (comment == '工程名称') {
continue
}
}
}
header.push({
title: comment || '-',
key: k,

91
api/app/lib/controllers/data/task.js

@ -0,0 +1,91 @@
'use strict';
async function getTask(ctx) {
try {
const models = ctx.fs.dc.models
const query = ctx.query
const whereopt = {
isdanger: query.isdanger
}
const whereRoadOpt = {
id: query.id
}
const taskRes = await models.TaskManage.findAndCountAll({
order: [['id', 'DESC']],
attributes: ['id', 'dangerDescription', 'isdanger', 'issuanceTime', 'reportTime'],
include: [
{
attributes: ['id', 'routeName', 'routeCode'],
model: models.Road,
where: query.id == undefined ? {} : whereRoadOpt
},
{
attributes: ['id', 'name'],
model: models.User
}
],
where: query.isdanger == undefined ? {} : whereopt
})
ctx.body = taskRes
ctx.status = 200
}
catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: '获取失败'
}
}
}
//删除任务
async function delTask(ctx) {
try {
const models = ctx.fs.dc.models
const { id } = ctx.params
await models.TaskManage.destroy({ where: { id: id } })
ctx.status = 204
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: '删除失败'
}
}
}
//编辑任务
async function editTask(ctx) {
//const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models
const params = ctx.request.body
const road = await models.Road.findOne({ where: { id: params.routeId } })
const user = await models.User.findOne({ where: { id: params.userId } })
if (!params.id) {
await models.TaskManage.create({
roadid: road.id, userid: user.id, dangerDescription: params.dangerDescription.trim()
})
} else {
await models.TaskManage.update({
roadid: road.id, userid: user.id, dangerDescription: params.dangerDescription.trim()
}, { where: { id: params.id } })
}
ctx.status = 204
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: '新增失败'
}
}
}
module.exports = {
getTask, delTask, editTask
};

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

@ -52,7 +52,7 @@ async function creatUser (ctx, next) {
try {
const models = ctx.fs.dc.models;
const data = ctx.request.body;
console.log('data', data)
let repeatUserNameCount = await models.User.count({
where: {
phone: data.phone,
@ -74,6 +74,7 @@ async function creatUser (ctx, next) {
delete: false,
phone: data.phone,
remark: 'th',
isAdmin: data.isAdmin
})
ctx.status = 204;
@ -114,6 +115,7 @@ async function updateUser (ctx, next) {
enable: data.enable,
delete: false,
phone: data.phone,
isAdmin: data.isAdmin
}, {
where: {
id: userId

35
api/app/lib/controllers/report/index.js

@ -9,7 +9,7 @@ async function reportList (ctx) {
where: {
},
attributes: ['id', 'road', 'time', 'projectType', 'roadSectionStart', 'roadSectionEnd', 'reportType', 'content', 'longitude', 'latitude'],
attributes: ['id', 'road', 'time', 'projectType', 'roadSectionStart', 'roadSectionEnd', 'reportType', 'content', 'longitude', 'latitude', 'projectName', 'handleState'],
include: [{
model: models.User,
attributes: ['name']
@ -30,10 +30,16 @@ async function reportList (ctx) {
}
}
if (keyword) {
if (reportType == 'road') {
findOption.where.projectName = {
'$like': `%${keyword}%`
}
} else {
findOption.where.road = {
'$like': `%${keyword}%`
}
}
}
if (userId) {
findOption.where.userId = userId
}
@ -133,6 +139,31 @@ async function reportDetail (ctx) {
}
}
async function reportHandle (ctx) {
try {
const { models } = ctx.fs.dc;
const { reportId } = ctx.params
const { handleState } = ctx.request.body
await models.Report.update({
handleState: handleState
}, {
where: {
id: reportId
}
})
ctx.status = 200;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function createReport (ctx) {
try {
const { userId } = ctx.fs.api
@ -181,5 +212,5 @@ async function deleteReport (ctx) {
module.exports = {
reportList,
reportPosition,
reportDetail, createReport, deleteReport,
reportDetail, createReport, deleteReport, reportHandle
};

8
api/app/lib/index.js

@ -26,7 +26,7 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
require(`./models/${filename}`)(dc)
});
const { User, Department, Report, FileType, Road, Files, FileRoad } = dc.models;
const { User, Department, Report, FileType, Road, Files, FileRoad, TaskManage } = dc.models;
// 定义外键
User.belongsTo(Department, { foreignKey: 'departmentId', targetKey: 'id' });
Department.hasMany(User, { foreignKey: 'departmentId', sourceKey: 'id' });
@ -40,4 +40,10 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
// Files.belongsTo(Road, { foreignKey: 'roadId', targetKey: 'id' });
// Road.hasMany(Files, { foreignKey: 'roadId', targetKey: 'id' });
//定义外键
TaskManage.belongsTo(User, { foreignKey: 'userid', targetKey: 'id' })
User.hasMany(TaskManage, { foreignKey: 'userid', targetKey: 'id' })
//
TaskManage.belongsTo(Road, { foreignKey: 'roadid', targetKey: 'id' })
Road.hasMany(TaskManage, { foreignKey: 'roadid', targetKey: 'id' })
};

20
api/app/lib/models/report.js

@ -166,6 +166,26 @@ module.exports = dc => {
field: "address",
autoIncrement: false
},
projectName: {
index: 17,
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "工程名称",
primaryKey: false,
field: "project_name",
autoIncrement: false
},
handleState: {
index: 18,
type: DataTypes.STRING,
allowNull: false,
defaultValue: "已处理",
// comment: "处理状态",
primaryKey: false,
field: "handle_state",
autoIncrement: false
},
}, {
tableName: "report",
comment: "",

87
api/app/lib/models/task_manage.js

@ -0,0 +1,87 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const TaskManage = sequelize.define("taskManage", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: "id",
primaryKey: true,
field: "id",
autoIncrement: true
},
roadid: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: "道路id",
primaryKey: false,
field: "roadid",
autoIncrement: false,
references: {
key: "id",
model: "road"
}
},
dangerDescription: {
type: DataTypes.CHAR,
allowNull: true,
defaultValue: null,
comment: "隐患说明",
primaryKey: false,
field: "danger_description",
autoIncrement: false
},
issuanceTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "下发时间",
primaryKey: false,
field: "issuance_time",
autoIncrement: false
},
userid: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: "用户id",
primaryKey: false,
field: "userid",
autoIncrement: false,
references: {
key: "id",
model: "user"
}
},
isdanger: {
type: DataTypes.BOOLEAN,
allowNull: true,
defaultValue: null,
comment: "是否存在安全隐患,flase(不存在)",
primaryKey: false,
field: "isdanger",
autoIncrement: false
},
reportTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "上报时间",
primaryKey: false,
field: "report_time",
autoIncrement: false
}
}, {
tableName: "task_manage",
comment: "",
indexes: []
});
dc.models.TaskManage = TaskManage;
return TaskManage;
};

8
api/app/lib/models/user.js

@ -14,6 +14,14 @@ module.exports = dc => {
field: "id",
autoIncrement: true
},
isAdmin: {
type: DataTypes.BOOLEAN,
defaultValue: null,
comment: null,
primaryKey: false,
field: "isadmin",
autoIncrement: false
},
name: {
type: DataTypes.STRING,
allowNull: false,

10
api/app/lib/routes/data/index.js

@ -8,7 +8,7 @@ const overspeed = require('../../controllers/data/overspeed');
const bus = require('../../controllers/data/bus');
const publicity = require('../../controllers/data/publicity');
const dataIndex = require('../../controllers/data/index');
const task = require('../../controllers/data/task')
module.exports = function (app, router, opts) {
// 数据导出
@ -172,4 +172,12 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['DEL/publicity/:publicityId'] = { content: '删除宣传数据', visible: false };
router.del('/publicity/:publicityId', publicity.publicityDel);
//publicity END
// task
app.fs.api.logAttr['GET/task'] = { content: '获取任务列表', visible: false };
router.get('/task', task.getTask);
app.fs.api.logAttr['DEL/task/:id'] = { content: '删除任务', visible: false };
router.del('/task/:id', task.delTask);
app.fs.api.logAttr['PUT/task'] = { content: '编辑任务', visible: false };
router.put('/task', task.editTask);
//task END
};

5
api/app/lib/routes/report/index.js

@ -10,7 +10,10 @@ module.exports = function (app, router, opts) {
router.get('/report/position', report.reportPosition);
app.fs.api.logAttr['GET/report/:reportId/detail'] = { content: '获取上报详情', visible: false };
router.get('/report/:reportId//detail', report.reportDetail);
router.get('/report/:reportId/detail', report.reportDetail);
app.fs.api.logAttr['GET/report/:reportId/handle'] = { content: '处理上报详情', visible: false };
router.post('/report/:reportId/handle', report.reportHandle);
app.fs.api.logAttr['POST/report'] = { content: '创建上报', visible: false };
router.post('/report', report.createReport);

15
api/log/development.log

@ -11203,3 +11203,18 @@ headers: {}
2022-09-05 15:40:10.680 - debug: [FS-LOGGER] Init.
2022-09-05 15:40:11.273 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2022-09-05 15:40:11.273 - info: [FS-AUTH] Inject auth and api mv into router.
2023-06-27 15:28:45.497 - debug: [FS-LOGGER] Init.
2023-06-27 15:28:46.411 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-06-27 15:28:46.411 - info: [FS-AUTH] Inject auth and api mv into router.
2023-06-27 15:56:55.756 - debug: [FS-LOGGER] Init.
2023-06-27 15:56:56.357 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-06-27 15:56:56.358 - info: [FS-AUTH] Inject auth and api mv into router.
2023-06-27 16:32:17.216 - debug: [FS-LOGGER] Init.
2023-06-27 16:32:17.767 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-06-27 16:32:17.768 - info: [FS-AUTH] Inject auth and api mv into router.
2023-06-27 18:48:13.296 - debug: [FS-LOGGER] Init.
2023-06-27 18:48:13.664 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-06-27 18:48:13.664 - info: [FS-AUTH] Inject auth and api mv into router.
2023-06-27 20:02:06.352 - debug: [FS-LOGGER] Init.
2023-06-27 20:02:06.794 - info: [FS-ATTACHMENT] Inject attachment mw into router.
2023-06-27 20:02:06.795 - info: [FS-AUTH] Inject auth and api mv into router.

22
jenkinsfilenew_api

@ -0,0 +1,22 @@
podTemplate {
node('pod-templ-jenkins-slave-common') {
env.IMAGE_NAME = "${IOT_IMAGES_REGISTRY}/${IOT}/${JOB_NAME}"
env.IMAGE_NAME_SHORT = "${IOT}/${JOB_NAME}"
env.CODE_ADDR = "${GIT_ADDRESS}/free-sun/Highways4Good.git"
stage('Run shell') {
git branch: 'dev', credentialsId: 'gitea-builder', url: "${CODE_ADDR}"
container('image-builder') {
sh'''
find . -depth -name '.svn' -type d -exec rm -rf {} +
/kaniko/executor --context=${BUILD_WORKSPACE} --dockerfile=./api/Dockerfilenew --destination=${IMAGE_NAME}:${IMAGE_VERSION} --cache=false --cleanup
'''
}
buildName "${IMAGE_NAME_SHORT}:${IMAGE_VERSION}"
buildDescription "${IMAGE_NAME}:${IMAGE_VERSION}"
}
}
}

25
jenkinsfilenew_web

@ -0,0 +1,25 @@
podTemplate {
node('pod-templ-jenkins-slave-common') {
env.IMAGE_NAME = "${IOT_IMAGES_REGISTRY}/${IOT}/${JOB_NAME}"
env.IMAGE_NAME_SHORT = "${IOT}/${JOB_NAME}"
env.CODE_ADDR = "${GIT_ADDRESS}/free-sun/Highways4Good.git"
stage('Run shell') {
git branch: 'dev', credentialsId: 'gitea-builder', url: "${CODE_ADDR}"
container('image-builder') {
sh'''
pwd
ls -al
/kaniko/executor --context=${BUILD_WORKSPACE} --dockerfile=./web/Dockerfilenew --destination=${IMAGE_NAME}:${IMAGE_VERSION} --cache=false --cleanup
'''
}
buildName "${IMAGE_NAME_SHORT}:${IMAGE_VERSION}"
buildDescription "${IMAGE_NAME}:${IMAGE_VERSION}"
}
}
}

2
scripts/1.2.0/data/1.alter_user.sql

@ -0,0 +1,2 @@
ALTER TABLE public."user"
ADD COLUMN isadmin boolean;

16
scripts/1.2.0/data/2.create_task_manage.sql

@ -0,0 +1,16 @@
create table public.task_manage(
id SERIAL PRIMARY KEY ,
roadId integer not null references public.road(id),
danger_description char(300),
issuance_time timestamp,
userId integer NOT NULL references public.user(id),
isdanger boolean,
report_time timestamp
);
comment on column public.task_manage.id is 'id';
comment on column public.task_manage.roadId is '道路id';
comment on column public.task_manage.danger_description is '隐患说明';
comment on column public.task_manage.issuance_time is '下发时间';
comment on column public.task_manage.userId is '用户id';
comment on column public.task_manage.isdanger is '是否存在安全隐患,flase(不存在)';
comment on column public.task_manage.report_time is '上报时间';

9
scripts/1.2.1/schema/1update_report.sql

@ -0,0 +1,9 @@
alter table report
add project_name varchar(512);
alter table report alter column project_type drop not null;
alter table report
add handle_state varchar(32) default '已处理' not null;
comment on column report.handle_state is '待处理 / 已处理 / 不处理';

7
weapp/project.config.json

@ -2,7 +2,7 @@
"miniprogramRoot": "dist/",
"projectname": "四好公路",
"description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"appid": "wx3c0c46dcf49a85be",
"appid": "wx79ff58f03d17f24d",
"setting": {
"urlCheck": false,
"es6": false,
@ -14,7 +14,7 @@
"autoAudits": false,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"enhance": true,
"enhance": false,
"showShadowRootInWxmlPanel": true,
"packNpmManually": false,
"packNpmRelationList": [],
@ -29,7 +29,8 @@
},
"disableUseStrict": false,
"useCompilerPlugins": false,
"minifyWXML": true
"minifyWXML": true,
"condition": false
},
"compileType": "miniprogram",
"libVersion": "2.25.1",

6
weapp/project.private.config.json

@ -1,7 +1,9 @@
{
"projectname": "%E5%9B%9B%E5%A5%BD%E5%85%AC%E8%B7%AF",
"setting": {
"compileHotReLoad": true
"compileHotReLoad": true,
"bigPackageSizeSupport": true
},
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html"
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"libVersion": "2.32.2"
}

12
weapp/src/components/uploads/index.js

@ -0,0 +1,12 @@
import React, { useState, useEffect } from 'react';
import Taro, { useRouter } from '@tarojs/taro';
import { View, RadioGroup, Radio, Image, Input, Picker } from '@tarojs/components';
const Index = () => {
return(
<View>123</View>
)
}
export default Index

4
weapp/src/config.js

@ -1,5 +1,5 @@
let DEV = false;
// DEV = true; //使用测试环境
DEV = true; //使用测试环境
const baseConfig = {
errorHandle: false, //是否启用全局异常处理‌‍‍‌‍​‌‌‍​‌‌‌‌‌​‌‌‍‌​‍‌‌‌‌​‍‍‍‍‌​‌‍‍‌‍​‌‌‍​‍‍‍‌‌​‍‌‌‌‌​‍‌‍‌​‍‌‌‌O
@ -8,7 +8,7 @@ const baseConfig = {
};
const development = {
baseUrl: 'http://221.230.55.29:31919',
baseUrl: 'http://10.8.30.112:13400',
// baseUrl: 'https://d763-117-90-37-10.ap.ngrok.io',
// webUrl: 'https://smartwater.anxinyun.cn',
// pcode: 'fce4afe2-5b6a-408a-ab18-a2afa7fa027c',

127
weapp/src/packages/patrol/index.jsx

@ -1,8 +1,9 @@
import React, { useState, useEffect } from 'react';
import Taro, { useRouter } from '@tarojs/taro';
import { View, RadioGroup, Radio, Image, Input, Picker } from '@tarojs/components';
import { View, RadioGroup, Radio, Image, Input, Picker, Video } from '@tarojs/components';
import { AtButton, AtTextarea, AtImagePicker } from 'taro-ui';
import InputPicker from '../components/inputPicker';
import VideoUpload from '../../components/uploads'
import request from '@/services/request';
import environment from '../../config';
import { getState } from '../../store/globalState';
@ -17,11 +18,16 @@ const Index = () => {
const isSuperAdmin = userInfo && userInfo.username === 'SuperAdmin' ? true : false
const router = useRouter()
const { params: { type } } = router
const { params: { type, kind } } = router
const isView = type === 'view' ? true : false
const isPatrol = kind === 'patrol' ? true : false
const isRoad = kind === 'road' ? true : false
const isAnomaly = kind === 'anomaly' ? true : false
const [reportType, setReportType] = useState('patrol') //
const [projectType, setProjectType] = useState('') //
const [projectName, setProjectName] = useState('') //
const [road, setRoad] = useState('') //
const [roadSectionStart, setRoadSectionStart] = useState('') // Start
const [roadSectionEnd, setRoadSectionEnd] = useState('') // End
@ -69,6 +75,12 @@ const Index = () => {
])
useEffect(() => {
if (isRoad) {
Taro.setNavigationBarTitle({ title: '在建道路' })
} if (isAnomaly) {
Taro.setNavigationBarTitle({ title: '异常反馈' })
}
if (isView) { //
Taro.showLoading({ title: '加载中' })
request.get(getReportDetail(router.params.id)).then(res => {
@ -84,6 +96,7 @@ const Index = () => {
}
setReportType(data.reportType)
setProjectType(showPrjType || data.projectType)
setProjectName(data.projectName)
setRoad(data.road)
setRoadSectionStart(data.roadSectionStart)
setRoadSectionEnd(data.roadSectionEnd)
@ -111,8 +124,9 @@ const Index = () => {
url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${res.latitude},${res.longitude}&key=${key}`,
success: function (res) {
// res
let addresscity = res.data.result.address_component.province + res.data.result.address_component.city + res.data.result.address_component.district
setAddress(addresscity + res.data.result.address_component.street_number)
// let addresscity = res.data.result.address_component.province + res.data.result.address_component.city + res.data.result.address_component.district
// console.log(res, 'res')
setAddress(res.data.result.formatted_addresses.standard_address)
}
})
}
@ -163,11 +177,15 @@ const Index = () => {
function report () {
if (!canReport) { return }
if (!projectType || !road) {
if (
(isPatrol && (!projectType || !road))
|| (isAnomaly && !road)
) {
Taro.showToast({ title: '请完善必填信息', icon: 'none' })
return
}
if (prjTypeSelector.indexOf(projectType) === -1) {
if (isPatrol && prjTypeSelector.indexOf(projectType) === -1) {
Taro.showToast({ title: '工程类型错误', icon: 'none' })
return
}
@ -175,10 +193,14 @@ const Index = () => {
Taro.showToast({ title: '内容字数不能超过50', icon: 'none' })
return
}
const reportProjectType = prjType[prjTypeSelector.indexOf(projectType)].value
if (isRoad && !projectName) {
Taro.showToast({ title: '请完善项目名称', icon: 'none' })
return
}
const reportProjectType = prjType[prjTypeSelector.indexOf(projectType)]?.value || ''
let data = {
reportType,
reportType: isPatrol ? reportType : kind,
projectType: reportProjectType,
road,
roadSectionStart,
@ -186,7 +208,9 @@ const Index = () => {
address,
content,
longitude,
latitude
latitude,
projectName,
handleState: isAnomaly ? '待处理' : undefined,
}
if (reportType === 'patrol') {
data['scenePic'] = sceneImg
@ -276,6 +300,10 @@ const Index = () => {
break;
case 'content':
setContent(value)
break;
case "projectName":
setProjectName(value)
break;
default:
break;
}
@ -385,7 +413,9 @@ const Index = () => {
return (
<View className='patrol'>
{
(!isSuperAdmin || isView) &&
(!isSuperAdmin || isView)
&& !isRoad && !isAnomaly
&&
<View className='report-type'>
<View className='text'>上报类型</View>
<RadioGroup onChange={handleTypeChange}>
@ -408,6 +438,9 @@ const Index = () => {
</RadioGroup>
</View>
}
{
isPatrol ?
<InputPicker
title='工程类型:'
placeholder='请选择工程类型'
@ -415,7 +448,26 @@ const Index = () => {
onInput={setProjectType}
selector={prjTypeSelector}
isView={isView}
/> : ''
}
{
isRoad ?
<View className='address'>
<View className='title'>项目名称</View>
<Input
className='input'
type='text'
placeholder={isView ? '' : '请输入项目名称'}
value={projectName}
onInput={e => handleInput(e, 'projectName')}
disabled={isView}
/>
</View> : ''
}
{
isPatrol || isAnomaly ?
<InputPicker
key={sourceRoadSel} // keyselector
title='所在道路:'
@ -424,8 +476,11 @@ const Index = () => {
onInput={setRoad}
selector={sourceRoadSel}
isView={isView}
/>
/> : ''
}
{
isPatrol || isAnomaly ?
<View className='road-section'>
<View className='title'>所属路段</View>
<Input
@ -467,7 +522,8 @@ const Index = () => {
<Image src={arrowIcon} className='img-r' />
</Picker>
}
</View>
</View> : ''
}
<View className='address'>
<View className='title'>具体位置</View>
@ -490,7 +546,7 @@ const Index = () => {
maxLength={50}
/>
{
reportType === 'patrol' ?
reportType === 'patrol' || isRoad || isAnomaly ?
<View className='patrol-img'>
现场图片
{
@ -509,6 +565,46 @@ const Index = () => {
onImageClick={handleImgClick}
/>
}
{/* <Video
id='video'
src='https://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400'
poster='../../static/img/date.png'
initialTime={0}
controls={true}
autoplay={false}
loop={false}
muted={false}
/> */}
{/* <AtButton onClick={() => {
Taro.chooseMedia({
sourceType: ['album', 'camera'], mediaType: ['image', 'video'],
camera: 'back',
success: function (res) {
console.log(res.tempFilePath)
Taro.showLoading({ title: '上传中' })
const tempFilePaths = res.tempFilePath
let token = getState('token') || Taro.getStorageSync('token')
Taro.uploadFile({
url: `${baseUrl}${postImage()}?token=${token}`,
filePath: tempFilePaths,
name: 'file',
success: (res) => {
console.log(res);
Taro.hideLoading();
if (res.statusCode == 200) {
// setImg(true, JSON.parse(res.data).key)
} else {
Taro.showToast({ title: '上传失败,请重试', icon: 'error' })
}
}
});
}
})
}}>
添加视频
</AtButton> */}
</View> :
<View className='conserve-img'>
养护图片:
@ -532,6 +628,7 @@ const Index = () => {
onImageClick={handleImgClick}
/>
}
<View className='horizontal-line hl-two'>
<View className='circle c-two'></View>
<View className='text t-two'>养护中</View>
@ -577,7 +674,9 @@ const Index = () => {
}
{
isView ?
isSuperAdmin && <AtButton type='primary' className='del-btn' onClick={deleteReport}>删除</AtButton> :
isSuperAdmin &&
<AtButton type='primary' className='del-btn' onClick={deleteReport}>删除</AtButton>
:
<AtButton type='primary' className='sub-btn' onClick={report}>上报</AtButton>
}
</View>

52
weapp/src/packages/patrolView/index.jsx

@ -17,9 +17,13 @@ import conserveActiveIcon from '../../static/img/patrolView/conserve-active.svg'
function Index () {
const userInfo = Taro.getStorageSync('userInfo') || {};
const router = useRouter()
const { params: { filter } } = router
const { params: { filter, kind } } = router
const [isPatrol, setIsPatrol] = useState(true)
const isPatrol = kind === 'patrol' ? true : false
const isRoad = kind === 'road' ? true : false
const isAnomaly = kind === 'anomaly' ? true : false
const [reportType, setReportType] = useState(kind || 'patrol')
const [datePicker, setDatePicker] = useState('')
const [listData, setListData] = useState([])
const [filterText, setFilterText] = useState('')
@ -29,10 +33,18 @@ function Index() {
const limit = 10
useEffect(() => {
if (isRoad) {
Taro.setNavigationBarTitle({ title: '在建道路' })
} if (isAnomaly) {
Taro.setNavigationBarTitle({ title: '异常反馈' })
}
}, [])
useEffect(() => {
setPage(0)
setNum(Math.random())
}, [isPatrol, datePicker])
}, [reportType, datePicker])
useEffect(() => {
getList(page == 0 ? true : false)
@ -54,7 +66,7 @@ function Index() {
startTime: datePicker ? datePicker + ' 00:00:00' : '',
endTime: datePicker ? datePicker + ' 23:59:59' : '',
keyword: filterText,
reportType: isPatrol ? 'patrol' : 'conserve',
reportType: reportType,
userId: filter === 'my' ? userInfo.id : '',
}
request.get(getReportList(), data).then(res => {
@ -99,10 +111,6 @@ function Index() {
});
})
const onTypeChange = bool => {
setIsPatrol(bool)
}
const onDateChange = e => {
setDatePicker(e.detail.value);
}
@ -121,23 +129,28 @@ function Index() {
}
const handleDetail = index => {
Taro.navigateTo({ url: `/packages/patrol/index?type=view&id=${listData[index].id}` })
Taro.navigateTo({ url: `/packages/patrol/index?type=view&id=${listData[index].id}&kind=${kind}` })
}
return (
<View>
{
isPatrol ?
<View className='type-box'>
<View className='item' onClick={() => onTypeChange(true)}>
<Image className='type-img' src={isPatrol ? patrolActiveIcon : patrolIcon} />
<View style={{ color: isPatrol ? '#346FC2' : '#999999' }}>巡查</View>
<View className='item' onClick={() => setReportType('patrol')}>
<Image className='type-img' src={reportType == 'patrol' ? patrolActiveIcon : patrolIcon} />
<View style={{ color: reportType == 'patrol' ? '#346FC2' : '#999999' }}>巡查</View>
</View>
<View className='line'></View>
<View className='item' onClick={() => onTypeChange(false)}>
<Image className='type-img' src={isPatrol ? conserveIcon : conserveActiveIcon} />
<View style={{ color: isPatrol ? '#999999' : '#346FC2' }}>养护</View>
<View className='item' onClick={() => setReportType('conserve')}>
<Image className='type-img' src={reportType == 'conserve' ? conserveActiveIcon : conserveIcon} />
<View style={{ color: reportType == 'conserve' ? '#346FC2' : '#999999' }}>养护</View>
</View>
</View>
<View className='filter-box'>
: ""
}
<View className='filter-box' style={{ top: isPatrol ? "40px" : '0' }}>
<View className='filter-item'>
<View style={{ float: 'left', marginLeft: '20rpx', color: '#333' }}>日期</View>
<Picker
@ -154,11 +167,12 @@ function Index() {
</View>
<View class='head-search'>
<Image className='search-img' src={searchIcon} />
<Input class='heard-search-input' value={filterText} placeholder='请输入道路名称' onConfirm={handleConfirm} onInput={handleInput} />
<Input class='heard-search-input' value={filterText} placeholder={
isRoad ? '请输入项目名称' : '请输入道路名称'} onConfirm={handleConfirm} onInput={handleInput} />
</View>
</View>
<View style={{ marginTop: '110px' }}>
<View style={{ marginTop: isPatrol ? '110px' : "80px" }}>
{
listData && listData.length > 0 ? listData && listData.map((e, index) => {
return (
@ -166,7 +180,7 @@ function Index() {
<View className='card-item' >
<Image className='card-bg' src={cardImg} />
<View className='card-position'>
<View className='card-title'>{e.road}</View>
<View className='card-title'>{e.road || e.projectName}</View>
<View style={{ float: 'left', width: '100%', fontSize: '28rpx', marginTop: '16rpx' }}>
<View style={{ float: 'left' }}>填报人</View>
<View style={{ float: 'left' }}>{e.user && e.user.name}</View>

2
weapp/src/packages/patrolView/index.scss

@ -34,7 +34,7 @@ page {
.filter-box {
position: fixed;
top: 80px;
// top: 80px;
display: flex;
width: 100%;
z-index: 100;

34
weapp/src/pages/home/index.jsx

@ -26,14 +26,14 @@ const Index = () => {
}
}, [])
function toPatrol() {
function toPatrol (kind) {
Taro.navigateTo({
url: '/packages/patrol/index?type=edit'
url: `/packages/patrol/index?type=edit&kind=${kind}`
})
}
function toPatrolView() {
function toPatrolView (kind) {
Taro.navigateTo({
url: '/packages/patrolView/index'
url: `/packages/patrolView/index?kind=${kind}`
})
}
@ -47,7 +47,31 @@ const Index = () => {
<View className='page'>
<View className='card fill'>
<View className='title'> </View>
<View className='btn' onClick={isSuperAdmin ? toPatrolView : toPatrol}>
<View className='btn' onClick={
isSuperAdmin ?
() => toPatrolView('patrol')
: () => toPatrol('patrol')
}>
{isSuperAdmin ? '查看' : '填报'}
</View>
</View>
<View className='card fill_road'>
<View className='title'> </View>
<View className='btn' onClick={
isSuperAdmin ?
() => toPatrolView('road')
: () => toPatrol('road')
}>
{isSuperAdmin ? '查看' : '填报'}
</View>
</View>
<View className='card fill_anomaly'>
<View className='title'> </View>
<View className='btn' onClick={
isSuperAdmin ?
() => toPatrolView('anomaly')
: () => toPatrol('anomaly')
}>
{isSuperAdmin ? '查看' : '填报'}
</View>
</View>

10
weapp/src/pages/home/index.scss

@ -7,13 +7,21 @@
margin-top: 30px;
padding: 10px;
width: 94%;
height: 360px;
height: 280px;
}
.fill {
background: url('../../static/img/home/fill-bg.svg') no-repeat;
background-size: 100% 100%;
}
.fill_road {
background: url('../../static/img/home/fill-road.svg') no-repeat;
background-size: 100% 100%;
}
.fill_anomaly {
background: url('../../static/img/home/fill-anomaly.svg') no-repeat;
background-size: 100% 100%;
}
.video {
background: url('../../static/img/home/video-bg.svg') no-repeat;

26
weapp/src/pages/user/index.jsx

@ -23,15 +23,15 @@ const Index = ({ ...props }) => {
Taro.navigateTo({ url: '/packages/changePassword/index' })
}
const toMyReport = () => {
const toMyReport = (kind) => {
Taro.navigateTo({
url: '/packages/patrolView/index?filter=my'
url: `/packages/patrolView/index?filter=my&kind=${kind}`
})
}
const toPatrolReport = () => {
const toPatrolReport = (kind) => {
Taro.navigateTo({
url: '/packages/patrol/index?type=edit'
url: `/packages/patrol/index?type=edit&kind=${kind}`
})
}
@ -64,7 +64,7 @@ const Index = ({ ...props }) => {
</View>
</View>
<View className='box' onClick={isSuperAdmin ? toPatrolReport : toMyReport}>
<View className='box' onClick={isSuperAdmin ? () => toPatrolReport('patrol') : () => toMyReport('patrol')}>
<Image className='box-img' src={reportImg} />
<View className='box-txt'>
{isSuperAdmin ? '巡查上报' : '我的上报'}
@ -72,6 +72,22 @@ const Index = ({ ...props }) => {
<Image className='img' src={moreImg} />
</View>
<View className='box' onClick={isSuperAdmin ? () => toPatrolReport('road') : () => toMyReport('road')}>
<Image className='box-img' src={reportImg} />
<View className='box-txt'>
{isSuperAdmin ? '在建道路上报' : '在建道路'}
</View>
<Image className='img' src={moreImg} />
</View>
<View className='box' onClick={isSuperAdmin ? () => toPatrolReport('anomaly') : () => toMyReport('anomaly')}>
<Image className='box-img' src={reportImg} />
<View className='box-txt'>
{isSuperAdmin ? '异常反馈上报' : '异常反馈'}
</View>
<Image className='img' src={moreImg} />
</View>
<View className='box' onClick={changePassword} style={{ marginTop: '2rpx' }}>
<Image className='box-img' src={pswdImg} />
<View className='box-txt'>修改密码</View>

49
weapp/src/static/img/home/fill-anomaly.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

218
weapp/src/static/img/home/fill-bg.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 38 KiB

49
weapp/src/static/img/home/fill-road.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

1
web/Dockerfile

@ -9,6 +9,7 @@ RUN npm install --registry http://10.8.30.22:7000
RUN npm run build
RUN rm -rf client/src
RUN rm -rf node_modules
RUN rm -rf package-lock.json
RUN npm install --production --force --registry http://10.8.30.22:7000
FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node-16:7.22-06-20
COPY --from=builder --chown=node /var/app /home/node/app

17
web/Dockerfilenew

@ -0,0 +1,17 @@
FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12-dev as builder
COPY . /var/app
WORKDIR /var/app
EXPOSE 8080
RUN npm config set registry=https://nexus.ngaiot.com/repository/fs-npm/
RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json
RUN npm cache clean -f
RUN rm -rf package-lock.json
RUN npm install --registry https://nexus.ngaiot.com/repository/fs-npm/
RUN npm run build
RUN rm -rf client/src
RUN rm -rf node_modules
RUN npm install --production --force --registry https://nexus.ngaiot.com/repository/fs-npm/
FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node-16:7.22-06-20
COPY --from=builder --chown=node /var/app /home/node/app
WORKDIR /home/node/app
CMD ["node", "server.js"]

BIN
web/client/assets/images/jiekou.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
web/client/assets/images/tiptop.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

2
web/client/src/app.js

@ -1,4 +1,4 @@
'use strict';
'use strict'
import React, { useEffect } from 'react';
import Layout from './layout';

7
web/client/src/layout/containers/layout/index.js

@ -46,10 +46,11 @@ const LayoutContainer = props => {
));
}
useEffect(() => {
if (user && user.authorized)
dispatch(getDepMessage()).then((res) => {
setDepMessage(res)
})
}, [true])
}, [user])
useEffect(() => {
scrollbar = new PerfectScrollbar('#page-content', { suppressScrollX: true });
}, [])
@ -74,9 +75,7 @@ const LayoutContainer = props => {
dom.scrollTop = 0;
}
})
// if (depMessage) {
// console.log(depMessage);
// }
let contentStyle = {
position: 'relative',
margin: '12px 12px 0px',

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

@ -50,7 +50,7 @@ const Login = props => {
return
}
setInputChanged(false)
dispatch(login("12345678912564589", "123456789"))
dispatch(login(username, password))
}
@ -69,6 +69,7 @@ const Login = props => {
value={username}
maxlength={11}
onChange={e => {
console.log('e.target.value', e.target.value)
setUserName(e.target.value)
setInputChanged(true)
}}
@ -82,6 +83,7 @@ const Login = props => {
value={password}
onChange={e => {
console.log('setPassword', e.target.value)
setPassword(e.target.value)
setInputChanged(true)
}}

11
web/client/src/sections/fillion/actions/patrol.js

@ -36,3 +36,14 @@ export function getUserList(query) {
reducer: { name: 'userList' }
});
}
export function handleReport (reportId, data) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
actionType: 'HANDLE_REPORT',
url: ApiTable.handleReport.replace("{reportId}", reportId),
data: data,
msg: { option: '处理数据' },
});
}

35
web/client/src/sections/fillion/actions/task.js

@ -0,0 +1,35 @@
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getTask(query) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query: query,
actionType: 'GET_TASK',
url: ApiTable.getTask,
msg: { error: '获取任务信息' },
reducer: { name: 'task' }
});
}
export function delTask(query) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_TASK',
url: ApiTable.delTask.replace("{taskId}", query?.id),
msg: { option: '删除任务信息' },
});
}
export function editTask(query) {
return dispatch => basicAction({
type: 'put',
dispatch: dispatch,
data: query,
actionType: 'PUT_TASK',
url: ApiTable.editTask,
msg: { option: '编辑或新增任务信息' },
});
}

180
web/client/src/sections/fillion/components/datajuji.js

@ -0,0 +1,180 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Select, DatePicker, AutoComplete, Col, Button, Row } from 'antd';
import { MinusCircleOutlined, PlusOutlined, PlusCircleOutlined } from '@ant-design/icons';
const Search = Input.Search
const { TextArea } = Input;
import moment from 'moment';
const EditGuanlang = (props) => {
const { visible, onCancel, editData, handleSaveScore, readOnly, companys, searchCompany, applyState } = props;
const [form] = Form.useForm();
const [replyFiles, setReplyFiles] = useState([]);
const [companyOpts, setCompanyOpts] = useState([]);
const [stationItem, setStationItem] = useState(null);
const [deviceList, setDeviceList] = useState([]);
useEffect(() => {
if (!visible) {
form.resetFields()
}
}, [visible])
useEffect(() => {
if (editData) {
let revertData = Object.assign({}, editData);
Object.keys(editData).forEach(key => {
if (key == 'accidentTime') {
revertData[key] = editData[key] && moment(editData[key]);
}
if (key == 'images') {
// const list = (editData[key] || '').split(',') || []
if (editData[key]) {
revertData[key] = JSON.parse(editData[key]);
}
}
});
form.setFieldsValue({ ...revertData });
}
}, [editData])
useEffect(() => {
if (companys && companys.length) {
let list = [];
companys.forEach(item => {
list.push({ label: item.company, value: item.company })
})
setCompanyOpts(list);
}
}, [companys])
useEffect(() => {
if (editData && companys && companys.length) {
handleSelectCompany(null, { value: editData.companyName })
let list = ((editData || {}).accidentStations || []).map(item => item.stationId)
form.setFieldsValue({ stations: list })
}
}, [companys, editData])
const handleSave = () => {
const data = form.getFieldsValue(true);
console.log(data, 'data')
handleSaveScore();
}
const onFileUploaded = (fileList) => {
setReplyFiles(fileList);
}
const handleSelectCompany = (v, opt) => {
const { value } = opt;
const target = companys.filter(c => c.company == value);
setDeviceList(target[0]?.deviceInfos || []);
}
const data1 = [
{ label: '2021年12月', value: '2021年12月' },
{ label: '2021年11月', value: '2021年11月' },
{ label: '2021年10月', value: '2021年10月' },
{ label: '2021年9月', value: '2021年9月' },
{ label: '2021年8月', value: '2021年8月' },
{ label: '2021年7月', value: '2021年7月' },
{ label: '2021年6月', value: '2021年6月' },
{ label: '2021年5月', value: '2021年5月' },
{ label: '2021年4月', value: '2021年4月' },
{ label: '2021年3月', value: '2021年3月' },
{ label: '2021年2月', value: '2021年2月' },
{ label: '2021年1月', value: '2021年1月' }]
const data2 = [
{ label: '噪声传感器', value: '噪声传感器' },
{ label: '导轮式固定测斜仪', value: '导轮式固定测斜仪' },
{ label: '闭合式磁通量传感器', value: '闭合式磁通量传感器' },
{ label: '扬尘监测系统', value: '扬尘监测系统' },
{ label: '空气质量监测系统', value: '空气质量监测系统' },
{ label: '车辆动态称重系统', value: '车辆动态称重系统' },
{ label: '多通道振动采集仪', value: '多通道振动采集仪' },
{ label: '应急照明控制器', value: '应急照明控制器' },
{ label: '钢筋计', value: '钢筋计' },
{ label: '噪声传感器', value: '噪声传感器' },
{ label: '风速风向仪', value: '风速风向仪' },
{ label: '静力水准仪', value: '静力水准仪' },
{ label: '表面式应变计', value: '表面式应变计' },
{ label: '光纤光栅锚索计', value: '光纤光栅锚索计' },
{ label: '加速度计', value: '加速度计' },
{ label: '闭合式磁通量传感器', value: '闭合式磁通量传感器' },
{ label: '开环式磁通量传感器', value: '开环式磁通量传感器' },
{ label: '压差式变形测量传感器', value: '压差式变形测量传感器' },
{ label: '多通道振动采集仪', value: '多通道振动采集仪' },
{ label: '压电式传感器', value: '压电式传感器' },
{ label: '钢筋计', value: '钢筋计' },
{ label: '盒式固定测斜仪', value: '盒式固定测斜仪' },
{ label: '拉线位移传感器', value: '拉线位移传感器' },
{ label: '表面式应变计', value: '表面式应变计' },
{ label: '芯型土压力计', value: '芯型土压力计' },
{ label: '芯型锚索计', value: '芯型锚索计' },
{ label: '收敛仪', value: '收敛仪' },
{ label: '激光测距仪 ', value: '激光测距仪 ' },
{ label: '磁电式传感器', value: '磁电式传感器' },
{ label: '压电式传感器', value: '压电式传感器' },
{ label: '锚索计', value: '锚索计' },
{ label: '静力水准仪 ', value: '静力水准仪 ' },
{ label: '移动测斜仪 ', value: '移动测斜仪 ' }
]
return (
<Modal
title="数据汇集"
visible={visible}
destroyOnClose
width={600}
// onOk={handleSave}
onCancel={onCancel}
footer={null}
>
<Form form={form} labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} onFinish={handleSave}>
<Row>
<Col span={20}>
<Form.Item
label={'历史数据'}
name={'startposition'}>
<Select options={data1} defaultValue="2021年12月" mode="multiple"></Select>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={20}>
<Form.Item
label={'传感器设备'}
name={'endposition'}>
<Select options={data2} defaultValue="噪声传感器" mode="multiple"></Select>
</Form.Item>
</Col>
</Row>
<Form.Item wrapperCol={{ span: 12, offset: 6 }}>
<Col span={24} style={{ display: 'flex', justifyContent: 'space-around' }}>
<Button htmlType="submit" onClick={() => {
onCancel()
}}>
取消
</Button>
<Button type="primary" onClick={() => {
onCancel()
}}>
确定
</Button>
</Col>
</Form.Item>
</Form>
*汇集历史数据接入物联网监测数据实现大数据的接入解算
</Modal >
)
}
export default EditGuanlang;

211
web/client/src/sections/fillion/components/editGuanlang.js

@ -0,0 +1,211 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Select, DatePicker, AutoComplete, Col, Button,Row } from 'antd';
import { MinusCircleOutlined, PlusOutlined,PlusCircleOutlined } from '@ant-design/icons';
const Search = Input.Search
const { TextArea } = Input;
import moment from 'moment';
const EditGuanlang = (props) => {
const { visible, onCancel, editData, handleSaveScore, readOnly, companys, searchCompany, applyState } = props;
const [form] = Form.useForm();
const [replyFiles, setReplyFiles] = useState([]);
const [companyOpts, setCompanyOpts] = useState([]);
const [stationItem, setStationItem] = useState(null);
const [deviceList, setDeviceList] = useState([]);
useEffect(() => {
if (!visible) {
form.resetFields()
}
}, [visible])
useEffect(() => {
if (editData) {
let revertData = Object.assign({}, editData);
Object.keys(editData).forEach(key => {
if (key == 'accidentTime') {
revertData[key] = editData[key] && moment(editData[key]);
}
if (key == 'images') {
// const list = (editData[key] || '').split(',') || []
if (editData[key]) {
revertData[key] = JSON.parse(editData[key]);
}
}
});
form.setFieldsValue({ ...revertData });
}
}, [editData])
useEffect(() => {
if (companys && companys.length) {
let list = [];
companys.forEach(item => {
list.push({ label: item.company, value: item.company })
})
setCompanyOpts(list);
}
}, [companys])
useEffect(() => {
if (editData && companys && companys.length) {
handleSelectCompany(null, { value: editData.companyName })
let list = ((editData || {}).accidentStations || []).map(item => item.stationId)
form.setFieldsValue({ stations: list })
}
}, [companys, editData])
const handleSave = () => {
const data = form.getFieldsValue(true);
console.log(data,'data')
handleSaveScore();
}
const onFileUploaded = (fileList) => {
setReplyFiles(fileList);
}
const handleSelectCompany = (v, opt) => {
const { value } = opt;
const target = companys.filter(c => c.company == value);
setDeviceList(target[0]?.deviceInfos || []);
}
return (
<Modal
title="新增摄像头"
visible={visible}
destroyOnClose
width={1000}
// onOk={handleSave}
onCancel={onCancel}
footer={null}
>
<Form form={form} labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} onFinish={handleSave}>
<img src='/assets/images/tiptop.png' style={{width:'100%'}}></img>
<Row style={{marginBottom:'20px'}}>
<Col span={20}> <a>配置属性</a> </Col>
<Col span={2}> <Button>视频格式转换</Button> </Col>
{/* <Col span={2}> <Button>测试</Button> </Col> */}
</Row>
<Row>
<Col span={12}>
<Form.Item
// style={{ width: 'calc(45% - 4px' }}
label={'设备名称'}
rules={[{ required: true, message: '设备名称为必填项' }]}
name={'guanlangname'}>
<Input placeholder="请输入设备名称、常用项目或者位置定义"/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label={'云台支持'}
name={'roadnamee'}
rules={[{ required: true, message: '所在道路名称不能为空' }]}
>
<Select options={[{label:'支持',value:'支持'},{label:'不支持',value:'不支持'}]} defaultValue="支持"></Select>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={12}>
<Form.Item
label={'高清切换'}
name={'startposition'}>
<Select options={[{label:'支持',value:'支持'},{label:'不支持',value:'不支持'}]} defaultValue="支持"></Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label={'语音支持'}
name={'endposition'}>
<Select options={[{label:'支持',value:'支持'},{label:'不支持',value:'不支持'}]} defaultValue="支持"></Select>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={12}>
<Form.Item
style={{ width: 'calc(45%-4px' }}
label={'内存'}
name={'guanlangmaterial'}
rules={[{ required: true, message: '管廊材质不能为空' }]}>
<Select options={[{label:'8g',value:'8g'},{label:'16g',value:'16g'},{label:'32g',value:'32g'}
,{label:'64g',value:'64g'},{label:'128g',value:'128g'},{label:'256g',value:'256g'},{label:'>256g',value:'>256g'}]} defaultValue="未安装"></Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label={'序列设备号'}
name={'guanlanglayer'}
rules={[{ required: true, message: '序列设备号不能为空' }]}>
<Input placeholder="请输入序列设备号"/>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={12}>
<Form.Item
style={{ width: 'calc(45%-4px' }}
label={'安装位置'}
name={'guanlanglength'}
rules={[{ required: true, message: '安装位置不能为空' }]}>
<Input placeholder="请输入高德经纬度坐标"/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label={'通道号'}
name={'manageunit'}
rules={[{ required: true, message: '通道号不能为空' }]}>
<Col span={24} style={{ display: 'flex', justifyContent: 'space-around' }}>
<Input/>
</Col>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={12}>
<Form.Item
label={'设备类型'}
name={'startposition'}>
<Select options={[{label:'枪机',value:'枪机'},{label:'球机',value:'球机'},{label:'其他',value:'其他'}]} placeholder="请选择摄像头类型"></Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label={'设备能力'}
name={'endposition'}>
<Select options={[{label:'普通摄像头',value:'普通摄像头'},{label:'人流量计数',value:'人流量计数'},{label:'热成像',value:'热成像'},{label:'AI摄像头',value:'AI摄像头'},{label:'其他',value:'其他'}]} placeholder="请选择能力"></Select>
</Form.Item>
</Col>
</Row>
<Form.Item wrapperCol={{ span: 12, offset: 6 }}>
<Col span={24} style={{ display: 'flex', justifyContent: 'space-around' }}>
<Button htmlType="submit" onClick={()=>{
onCancel()
}}>
取消
</Button>
<Button type="primary" htmlType="submit">
确定
</Button>
</Col>
</Form.Item>
</Form>
</Modal >
)
}
export default EditGuanlang;

20
web/client/src/sections/fillion/components/inforTable.js

@ -6,7 +6,7 @@ import './protable.less'
import moment from 'moment';
import { getPurchase, delPurchase } from "../actions/infor"
import UserModal from './infor/details';
import Datajuji from './datajuji'
const InForTable = (props) => {
const { dispatch, user, depData, depMessage, depLoading } = props
const [rowSelected, setRowSelected] = useState([])
@ -23,6 +23,7 @@ const InForTable = (props) => {
const [overrunRateUpper, setOverrunRateUpper] = useState()//超限率上限
const [overrunRateFloor, setOverrunRateFloor] = useState()//超限率下限
const [testTime, setTestTime] = useState()//超限率下限
const [datajuji, setdatajuji] = useState() //数据聚集弹窗
const ref = useRef()
useEffect(() => { ref.current.reload() }, [monitor, delet])
//打开弹窗
@ -381,6 +382,13 @@ const InForTable = (props) => {
>
新增
</Button>
{/* <Button
type='primary'
onClick={() => { setdatajuji(true)}} style={{ marginLeft: 15 }}
>
数据汇集
</Button> */}
{/* <Button
type="primary"
style={{ width: "100px", marginLeft: 20 }}
@ -477,6 +485,16 @@ const InForTable = (props) => {
// sitename={sitename}
setRecortd={setRecortd}
/> : ''}
{datajuji ? <Datajuji
visible={datajuji}
onCancel={() => { setdatajuji(false) }}
// handleSaveScore={handleSaveScore}
// searchCompany={searchCompany}
// companys={companys}
// editData={modalRecord}
// readOnly={readOnly}
// applyState={applyState}
></Datajuji> : ''}
</Spin >
)
}

112
web/client/src/sections/fillion/components/patrolTable.js

@ -2,7 +2,7 @@ import { connect } from 'react-redux';
import './protable.less'
import { Card, Button, Popconfirm, Badge, Col, Row, DatePicker, Input, Modal, Spin, Image, message, Popover } from 'antd';
import ProTable from '@ant-design/pro-table';
import { getReportList, getReportDetail } from '../actions/patrol';
import { getReportList, getReportDetail, handleReport } from '../actions/patrol';
import React, { useEffect, useState } from 'react';
import { httpDel } from '@peace/utils'
import { PinyinHelper } from '@peace/utils';
@ -12,12 +12,15 @@ import styles from './protable.less';
import moment from 'moment';
const DetailForm = (props) => {
const { visible, data, handleClose, loading } = props;
const { visible, data, handleClose, loading, isAnomaly, isRoad, isPatrol } = props;
const [qndmn] = useState(localStorage.getItem('qndmn'));
const keyList = [
// { key: '编号', name: 'id' },
{ key: '工程类型', name: 'projectType' },
{ key: '所在路段', name: 'road' },
{ key: '工程类型', name: 'projectType', skip: !isPatrol },
{ key: '工程名称', name: 'projectName', skip: !isRoad },
{ key: '所在路段', name: 'road', skip: isRoad },
{ key: '具体位置', name: 'address' },
{ key: '巡查内容', name: 'content' },
{ key: '现场照片', name: 'scenePic' },
@ -29,7 +32,9 @@ const DetailForm = (props) => {
// })
return keyList.map(obj => {
return <div style={{ display: 'flex', width: '100%', justifyContent: 'space-between', margin: '12px 0' }}>
return (
obj.skip ? null :
<div style={{ display: 'flex', width: '100%', justifyContent: 'space-between', margin: '12px 0' }}>
<span style={{ fontSize: 16, color: 'gray', minWidth: '26%' }}>{obj.key}</span>
{
obj.name != 'scenePic' ?
@ -47,6 +52,7 @@ const DetailForm = (props) => {
}
</div>
)
})
} else {
return '暂无数据'
@ -58,7 +64,11 @@ const DetailForm = (props) => {
visible={visible}
footer={null}
onCancel={handleClose}
title={'巡查管理详情'}
title={
isPatrol ?
'巡查管理详情' :
isRoad ? '建设上报详情' : '异常反馈详情'
}
>
<Spin spinning={loading}>
{renderContent(data)}
@ -68,9 +78,13 @@ const DetailForm = (props) => {
}
const DetailList = (props) => {
const { reportList, loading, dispatch, handleOpen, handelRefresh } = props;
const { reportList, loading, dispatch, handleOpen, handelRefresh, isAnomaly, isRoad, isPatrol, queryData } = props;
const [visible, setVisible] = useState(false)
const [selectRecord, setSelectRecord] = useState();
const [noProcessingPopVisible, setNoProcessingPopVisible] = useState(false);
const [noProcessingSelectRecord, setNoProcessingSelectRecord] = useState();
const checkDetail = (record) => {
dispatch(getReportDetail(record.id))
}
@ -95,7 +109,7 @@ const DetailList = (props) => {
let counter = 0;
const columns = [
{
isPatrol ? {
title: '编号',
key: 'id',
dataIndex: 'id',
@ -113,7 +127,8 @@ const DetailList = (props) => {
}
return moment(record.time).format("YYYYMMDD") * 10000 + counter;
}
},
} : '',
isPatrol ?
{
title: '工程类型',
key: 'projectType',
@ -128,13 +143,23 @@ const DetailList = (props) => {
default: return text;
}
}
},
} : '',
isRoad ?
{
title: '工程名称',
key: 'projectName',
dataIndex: 'projectName',
align: 'center',
} : '',
isPatrol || isAnomaly ?
{
title: '所属道路',
key: 'road',
dataIndex: 'road',
align: 'center'
}, {
} : '',
isPatrol || isAnomaly ?
{
title: '所在路段',
key: 'address',
dataIndex: 'address',
@ -142,7 +167,7 @@ const DetailList = (props) => {
render: (text, record) => {
return `${record.roadSectionStart || ''}-${record.roadSectionEnd || ''}`
}
},
} : '',
{
title: '具体内容',
key: 'content',
@ -150,7 +175,7 @@ const DetailList = (props) => {
align: 'center'
},
{
title: '巡查人',
title: isRoad ? '上报人' : '巡查人',
width: 100,
key: 'userName',
dataIndex: 'userName',
@ -175,6 +200,29 @@ const DetailList = (props) => {
<Button
onClick={() => { checkDetail(record); handleOpen(); }}
style={{ marginRight: 10 }}>查看</Button>,
isAnomaly && record.handleState != '已处理' ? <Button>指派</Button> : null,
isAnomaly && record.handleState != '已处理' ?
<Popover
content={[
<div style={{ width: '100%', height: 30 }}>
<Button onClick={() => setNoProcessingPopVisible(false)} style={{ float: "right" }} ></Button>
<Button type="primary" onClick={() => dispatch(handleReport(record.id, { handleState: '已处理' })).then(res => {
if (res.success) {
setNoProcessingPopVisible(false)
setNoProcessingSelectRecord(null)
handelRefresh()
}
})} style={{ marginRight: 8, float: "right" }} ></Button>
</div>
]}
visible={noProcessingSelectRecord == record.id && noProcessingPopVisible}
trigger="click"
onClick={() => setNoProcessingSelectRecord(record.id)}
title="是否不处理该记录?"
onVisibleChange={(newVisible) => setNoProcessingPopVisible(newVisible)}
>
<Button>不处理</Button>
</Popover> : null,
<Popover
content={[
<div style={{ width: '100%', height: 30 }}>
@ -193,7 +241,7 @@ const DetailList = (props) => {
]
}
},
];
].filter(s => s);
return (
<ProTable
columns={columns}
@ -280,7 +328,6 @@ const PatrolNameList = (props) => {
return {
onClick: () => {
if (record) {
// console.log('record:', record)
let id = record.id
if (selectRoad == record.id) {
id = null
@ -299,7 +346,7 @@ const PatrolNameList = (props) => {
const PatrolTable = (props) => {
const { userList, reportList, dispatch, reportListLoading, reportDetail, reportDetailLoading, userLoading, exports } = props;
const { userList, reportList, dispatch, reportListLoading, reportDetail, reportDetailLoading, userLoading, exports, pathname } = props;
const [record, setRecord] = useState();
const [dateRange, setDateRange] = useState();
const [detailVisible, setDetailVisible] = useState(false)
@ -307,6 +354,11 @@ const PatrolTable = (props) => {
const { RangePicker } = DatePicker;
const isRoad = pathname.includes('road')
const isAnomaly = pathname.includes('anomaly')
const isPatrol = !isRoad && !isAnomaly
const reportType = isRoad ? 'road' : isAnomaly ? 'anomaly' : 'patrol';
useEffect(() => {
if (userList && userList instanceof Array) {
setRecord(userList[0]);
@ -320,7 +372,7 @@ const PatrolTable = (props) => {
}, [record, dateRange])
const queryData = () => {
let query = { userId: record.id, reportType: 'patrol', asc: true }
let query = { userId: record.id, reportType: reportType, asc: true }
if ((dateRange && dateRange instanceof Array && dateRange[0] != '')) {
query.startTime = moment(dateRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss')
query.endTime = moment(dateRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
@ -337,7 +389,7 @@ const PatrolTable = (props) => {
}, [activeTabKey1])
const handelRefresh = () => {
let query = { userId: record.id, reportType: 'patrol', asc: true }
let query = { userId: record.id, reportType: reportType, asc: true }
dispatch(getReportList(query));
}
@ -358,11 +410,16 @@ const PatrolTable = (props) => {
},
];
const contentList = {
tab1: [<div>
tab1: [
<div>
<Card style={{ flex: 1 }}>
<DetailList reportList={reportList} record={record} loading={reportListLoading} dispatch={dispatch} handleOpen={handleOpen} handelRefresh={handelRefresh} />
<DetailList
reportList={reportList} record={record} loading={reportListLoading} dispatch={dispatch} handleOpen={handleOpen} handelRefresh={handelRefresh}
isPatrol={isPatrol} isRoad={isRoad} isAnomaly={isAnomaly} queryData={queryData}
/>
</Card>
</div>],
</div>
],
tab2: <PatrolGis userId={(record || {}).id} dispatch={dispatch} reportList={reportList} />
};
const onTab1Change = (key) => {
@ -380,7 +437,7 @@ const PatrolTable = (props) => {
const handleExport = () => {
if (reportList && reportList instanceof Array && reportList.length) {
let ids = reportList.map(item => item.id);
exports(ids);
exports(ids, reportType);
}
}
@ -396,17 +453,18 @@ const PatrolTable = (props) => {
</Card>
<Card
style={{ flex: 1 }}
tabList={tabList}
tabList={isPatrol ? tabList : undefined}
activeTabKey={activeTabKey1}
onTabChange={(key) => {
onTab1Change(key);
}}
>
{
activeTabKey1 == 'tab1' ? <div style={{ marginBottom: 20 }}>
activeTabKey1 == 'tab1' ?
<div style={{ marginBottom: 20 }}>
<RangePicker onChange={(date, dateString) => { setDateRange(dateString) }} />
<Button style={{ marginLeft: 20 }}>查询</Button>
<Button style={{ marginLeft: 20 }} onClick={handleExport} >导出</Button>
{/* <Button style={{ marginLeft: 20 }} onClick={handleExport} >导出</Button> */}
</div> : ''
}
{contentList[activeTabKey1]}
@ -414,7 +472,9 @@ const PatrolTable = (props) => {
visible={detailVisible}
handleClose={handleClose}
data={reportDetail}
loading={reportDetailLoading} />
loading={reportDetailLoading}
isPatrol={isPatrol} isRoad={isRoad} isAnomaly={isAnomaly}
/>
</Card>
</div>

152
web/client/src/sections/fillion/components/task/addTaskModal.js

@ -0,0 +1,152 @@
import React, { useState, useEffect, useRef } from 'react';
import { Modal, Form, Input, Select, Button } from 'antd';
import { connect } from 'react-redux';
import { getRoadway } from '../../actions/infor'
import { getUserList } from '../../actions/patrol';
import { editTask } from '../../actions/task';
const AddModal = (props) => {
const { dispatch, recordRow, visible, onClose, user, lookVal } = props
const { TextArea } = Input
const [form] = Form.useForm()
const [inputVal, setIputVal] = useState(undefined)
const [selectVal, setSelectVal] = useState('')
const [roadRes, setRoadRes] = useState([])//路线列表
const [userList, setUserList] = useState([])//用户列表
useEffect(async () => {
const res = await dispatch(getUserList())
setUserList(res?.payload.data)
}, [true])
const onChange = () => {
form.resetFields(['code'])//清空具体某个表单的值
}
useEffect(() => {
form.setFieldsValue(recordRow ? { 'name': recordRow?.road.id, 'code': recordRow?.road.id, 'danger': recordRow?.dangerDescription, 'user': recordRow?.user.id } : {})
}, [recordRow])
useEffect(async () => {
const res = await dispatch(getRoadway({}))
setRoadRes(res?.payload.data)
}, [])
//新增和修改
const handleSaveUpdate = () => {
form.validateFields().then((values) => {
//console.log('values', recordRow)
//console.log('values', values)
const val = {
dangerDescription: values.danger,
userId: values.user,
routeId: values.name,
id: recordRow?.id
}
dispatch(editTask(val)).then(res => {
if (res.success) {
onClose()
form.resetFields()
}
})
})
}
return (
<Modal visible={visible}
title={lookVal ? '查看' : recordRow ? '编辑任务' : '新增数据'}
onCancel={() => {
onClose()
form.resetFields()//清空所有个表单的值
setSelectVal('')//置空路线代码的选择
}}
onOk={
handleSaveUpdate
}
footer={
lookVal ? null : [
<Button onClick={() => { onClose(); form.resetFields(); setSelectVal('') }}>取消</Button>,
<Button type='primary' onClick={handleSaveUpdate}>确认</Button>
]
}
>
<Form form={form}>
<Form.Item
label="路线名称"
name="name"
//initialValues={recordRow?.road.routeName}
rules={[{ required: true, message: '路线名称' }]} >
<Select
disabled={lookVal ? true : false}
allowClear='true'
showSearch
placeholder="请输入关键词"
onChange={(value) => {
onChange()
setSelectVal(value)
}}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={roadRes?.map((item) => ({
label: item.routeName,
value: item.id
})
)}
/>
</Form.Item>
<Form.Item
label="路线代码"
name="code"
rules={[{ required: true, message: '路线代码' }]}>
<Select
disabled={lookVal ? true : false}
placeholder="请输入关键词"
value={selectVal}
>
<Select.Option key={selectVal}>{selectVal}</Select.Option>
</Select>
</Form.Item>
<Form.Item
label="隐患说明"
name="danger"
rules={[{ required: true, message: '隐患说明' }]}>
<TextArea disabled={lookVal ? true : false} />
</Form.Item>
<Form.Item
label="责任人"
name="user"
rules={[{ required: true, message: '责任人' }]}>
<Select
disabled={lookVal ? true : false}
allowClear='true'
showSearch
placeholder="请输入负责人"
options={userList?.map((item) => ({
label: item.name,
value: item.id
})
)}
/>
</Form.Item>
{lookVal ? <Form.Item
label="下发时间"
name="issuanceTime"
>
<Input disabled={lookVal ? true : false} />
</Form.Item> : ''}
{lookVal ? <Form.Item
label="图片说明"
name="picture"
>
<Input disabled={lookVal ? true : false} />
</Form.Item> : ''}
</Form>
</Modal >
)
}
function mapStateToProps(state) {
const { auth } = state
return {
user: auth.user,
}
}
export default connect(mapStateToProps)(AddModal)

4
web/client/src/sections/fillion/containers/index.js

@ -12,4 +12,6 @@ import PromoTional from './promotional';
import Maintenance from './maintenance';
import Patrol from './patrol';
import File from './file';
export { Infor,transportation,BridgeTable,HigHways,OperaTional,Enforce,Public,Videois,PromoTional,Maintenance,Patrol,File};
import Jiekouguanli from './jiekouguanli';
import Task from './task'
export { Infor, transportation, BridgeTable, HigHways, OperaTional, Enforce, Public, Videois, PromoTional, Maintenance, Patrol, File, Jiekouguanli, Task };

9
web/client/src/sections/fillion/containers/jiekouguanli.js

@ -0,0 +1,9 @@
import React from 'react'
export default function Jiekouguanli() {
return (
<div>
<img src='/assets/images/jiekou.png' style={{width:'100%'}}></img>
</div>
)
}

16
web/client/src/sections/fillion/containers/patrol.js

@ -4,13 +4,12 @@ import '../style.less';
import { getDepMessage, getReportStatistic } from "../actions/infor"
import { getUserList } from '../actions/patrol';
import PatrolTable from '../components/patrolTable';
const superagent = require('superagent');
const patrol = (props) => {
const { dispatch, user } = props
const { dispatch, user, location: { pathname } } = props
const [data, setData] = useState()
useEffect(() => {
// dispatch(getDepMessage())
setData(props)
}, []);
@ -18,18 +17,19 @@ const patrol = (props) => {
dispatch(getUserList())
}, [true])
//批量导出
const exports = (ids, counts) => {
// console.log(user);
const exports = (ids, reportType) => {
let reportIds = ids.toString();
window.open(
'/_api/' +
`data/export?exp=patrol&ids=${reportIds}&token=${user.token}`)
`data/export?exp=patrol&ids=${reportIds}&token=${user.token}&patrolType=${reportType}`)
}
return (
<> <PatrolTable data={data} exports={exports} />
<>
<PatrolTable data={data} exports={exports} pathname={pathname} />
</>
)
}
function mapStateToProps (state) {
const { auth } = state
return {

186
web/client/src/sections/fillion/containers/task.js

@ -0,0 +1,186 @@
'use strict';
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { Button, Table, Spin, Select, Divider, Popconfirm } from 'antd';
import moment from 'moment';
import { debounce } from 'lodash'
import AddModal from '../components/task/addTaskModal';
import { getRoadway } from '../actions/infor'
import { getTask } from '../actions/task'
import { delTask } from '../actions/task'
const Task = (props) => {
const { dispatch } = props
const [addModalVis, setAddModalVis] = useState(false)
const [roadRes, setRoadRes] = useState([])//路线列表
const [selectVal, setSelectVal] = useState('all')//选择框得值
const [inputVal, setIputVal] = useState(undefined)
const [taskRes, setTaskRes] = useState([])
const [recordRow, setRecordRow] = useState(null)
const [lookVal, setLookval] = useState('')
useEffect(async () => {
const res = await dispatch(getRoadway({}))
setRoadRes(res.payload.data)
}, [])
const getData = async (querySelect = { id: inputVal, isdanger: selectVal === 'all' ? undefined : selectVal === 'y' ? true : false }) => {
const task = await dispatch(getTask(querySelect))
setTaskRes(task.payload?.data)
}
useEffect(async () => {
getData()
}, [])
//搜索道路名称
const searchRoadName = async (value) => {
const task = await dispatch(getTask({ id: value, isdanger: selectVal === 'all' ? undefined : selectVal === 'y' ? true : false }))
setTaskRes(task.payload?.data)
setIputVal(value)
}
//选择安全是否消除
const changeSelect = async (value) => {
console.log('value', value)
const task1 = await dispatch(getTask({ id: inputVal, isdanger: value === 'all' ? undefined : value === 'y' ? true : false }))
setTaskRes(task1.payload?.data)
setSelectVal(value)
}
//刪除task
const delTaskHandler = async (record) => {
const res = await dispatch(delTask({ id: record.id }))
if (res.success) {
getData()
}
}
//查看
const look = (record) => {
setAddModalVis(true)
setLookval(record)
setRecordRow(record);
}
//配置表格列
const columns = [{
title: '路线名称',
render: (_, record) => {
return <div>{record.road.routeName}</div>
}
},
{
title: '路线代码',
render: (_, record) => {
return <div>{record.road.routeCode}</div>
}
},
{
title: '隐患说明',
dataIndex: 'dangerDescription',
//with: 20,
// textWrap: 'word-break',
// ellipsis: true
},
{
title: '下发时间',
render: (_, record) => {
return <div>{record.issuanceTime ? moment(record?.issuanceTime).format('YYYY-MM-DD HH:mm:ss') : ''}</div>
}
},
{
title: '责任人',
//with: 20,
render: (_, record) => {
return <div>{record.user.name}</div>
}
},
{
title: '是否消除隐患',
render: (_, record) => {
return <div>{record.isdanger === null ? '' : record.isdanger === 'true' ? '是' : '否'}</div>
}
},
{
title: '上报时间',
render: (_, record) => {
return <div>{record.reportTime ? moment(record.reportTime).format('YYYY-MM-DD HH:mm:ss') : ''}</div>
}
},
{
title: '操作',
render: (dom, record) => {
return <div>
{record.reportTime ? '' : <Button type='link' onClick={() => {
setRecordRow(record);
setAddModalVis(true)
}}>编辑</Button>}
<Popconfirm title='确定要删除吗?' onConfirm={() => { delTaskHandler(record) }}><Button type='link'>刪除</Button></Popconfirm>
<Button type='link' onClick={() => { look(record) }}>查看</Button>
</div>
}
},
]
//配置分页
const paginationOpt = {
defaultCurrent: 1,
defaultPageSize: 5,
total: taskRes?.count,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: ["5", "10", "15"],
showTotal: function () {
return `共有${taskRes?.count}`
}
}
return (<div className='taskMenu'>
<div style={{ display: 'flex', flexWrap: ' nowrap', justifyContent: 'space-between' }}>
<div style={{ marginLeft: 20 }}>
路线名称: <Select
allowClear='true'
showSearch
placeholder="请输入关键词"
//optionFilterProp="children"
onChange={(value) => { searchRoadName(value) }}
//onSearch={(value) => { console.log('11111', value) }}
filterOption={(input, option) =>
(option?.label ?? '').toLowerCase().includes(input.toLowerCase())
}
options={roadRes?.map((item) => ({
label: item.routeName,
value: item.id
})
)}
/>
</div>
<div>
是否存在安全隐患: <Select placeholder='请输入关键词'
options={[{ value: 'all', label: '全部' }, { value: 'y', label: '是' }, { value: 'n', label: '否' }]}
onChange={(value) => { changeSelect(value) }}>
</Select>
</div>
<div >
<Button type='primary' onClick={() => { setRecordRow(null); setAddModalVis(true) }}>新增</Button>
</div>
</div>
<Divider style={{ marginTop: 10 }} />
<Table columns={columns} dataSource={taskRes?.rows} size="small" pagination={paginationOpt}>
</Table>
<AddModal visible={addModalVis} onClose={() => { setAddModalVis(false); getData(); setRecordRow(null); setLookval(null) }} recordRow={recordRow}
lookVal={lookVal}
></AddModal>
</div >)
}
function mapStateToProps(state) {
//const { task } = state;
return {
//isRequesting: task.isRequesting,
}
}
export default connect(mapStateToProps)(Task);

261
web/client/src/sections/fillion/containers/videois.js

@ -1,42 +1,243 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Input, Table, Button, Select, message, Popconfirm } from 'antd';
// import { getAccidentInfo, createAccidentInfo, deleteAccidentInfo, editAccidentInfo, getAllCompany } from '../actions/device';
// import EditAccidentModal from '../components/editAccidentModal';
import EditGuanlang from '../components/editGuanlang';
import '../style.less';
import { getDepMessage, getReportStatistic } from "../actions/infor"
import VideoTable from '../components/videoTable';
const superagent = require('superagent');
const Videois = (props) => {
const { dispatch, user } = props
const [data, setData] = useState()
import { Func } from '$utils';
import moment from 'moment';
var recordId = null;
const Guanlang = (props) => {
const { dispatch, user, totalPage, companys, creditScore } = props
const [data, setData] = useState([])
const [modalVisible, setModalVisible] = useState(false);
const [modalRecord, setModalRecord] = useState();
const [companyName, setCompanyName] = useState(null)
const [creditCode, setCreditCode] = useState(null)
const [pageSize, setPageSize] = useState(10);
const [currentPage, setCurrentPage] = useState(1);
const [applyStatus, setApplyStatus] = useState(null);
const [applyState, setApplyState] = useState('check'); // check 查看;create 新增; apply 初审; approve 复审
const [editModal, setEditModal] = useState(false);
const [readOnly, setReadOnly] = useState(false);
const accidentInfo= []
// const initial = (params, search = false) => {
// dispatch(getAccidentInfo(params)).then(() => { if (search) setCurrentPage(1) })
// }
useEffect(() => {
// dispatch(getDepMessage())
setData(props)
}, []);
//批量导出
const exports = (ids, counts) => {
// console.log(user);
let reportIds = [];
if (ids.length)
reportIds = ids
else
reportIds = (counts || {}).ids || [];
superagent.post('/_report/http')
.send({ id: reportIds.map(i => Number(i)) }).end((err, res) => {
const resTextIs = res.text.split('/').pop()
window.open(
'/_api/' +
`attachments?src=files/${resTextIs}&filename=${encodeURIComponent(resTextIs)}&token=${user.token}`)
})
const params = { limit: pageSize, offset: currentPage }
// initial(params)
}, [true])
const openModal = (record, state) => {
if (state == 'check') {
setReadOnly(true)
} else {
setReadOnly(false)
}
searchCompany(record.companyName)
setApplyState(state);
setModalVisible(true);
setModalRecord(record);
}
const search = () => {
const params = { company: companyName, applyStatus, limit: pageSize, offset: 1 }
// initial(params, true)
}
const clearSearch = () => {
setCompanyName(null)
setCreditCode(null)
const params = { limit: pageSize, offset: currentPage }
// initial(params)
}
const columns = [
{
title: '序号',
dataIndex: 'companyName',
key: 'companyName',
},
{
title: '设备名称',
dataIndex: 'accidentTime',
key: 'accidentTime',
render: (text) => {
return moment(text).format('YYYY-MM-DD')
}
},
{
title: '设备状态',
dataIndex: 'stationName',
key: 'stationName',
render: (v, t) => {
let list = t.accidentStations.map(item => item.stationName);
return list.join(',');
}
},
{
title: '接入类型',
dataIndex: 'stationName',
key: 'stationName',
render: (v, t) => {
let list = t.accidentStations.map(item => item.stationName);
return list.join(',');
}
},
{
title: '设备厂家',
dataIndex: 'stationName',
key: 'stationName',
render: (v, t) => {
let list = t.accidentStations.map(item => item.stationName);
return list.join(',');
}
},
{
title: '操作',
render: (record) => {
return (
<span>
<a onClick={() => openModal(record, 'check')}>查看&nbsp;&nbsp;</a>
<a onClick={() => openModal(record, 'edit')}>编辑&nbsp;&nbsp;</a>
<Popconfirm
title="确认删除"
onConfirm={() => {
// console.log(record)
// dispatch(deleteAccidentInfo(record.id)).then((res) => {
// if (res.success) {
// message.success('删除记录成功');
// search();
// }
// }
// )
}
}
>
<a>删除&nbsp;&nbsp;</a>
</Popconfirm>
</span>
)
}
}
];
const handleSaveScore = (data) => {
console.log('执行了')
setModalVisible(false);
// if (applyState == 'create')
// dispatch(createAccidentInfo(data)).then(res => {
// if (res.success) {
// message.success('事故资讯添加成功');
// setModalVisible(false);
// search();
// }
// })
// else if (applyState == 'edit') {
// dispatch(editAccidentInfo(data)).then(res => {
// if (res.success) {
// message.success('事故资讯编辑成功');
// setModalVisible(false);
// search();
// }
// })
// }
}
var timer = null;
const searchCompany = (companyName) => {
if (timer) {
clearTimeout(timer)
} else {
timer = setTimeout(() => {
// dispatch(getAllCompany({ companyName }));
}, 400);
}
}
const spanStyle = { diplay: 'inline-block', marginLeft: 10 }
const inputStyle = { width: 200 }
return (
<> <VideoTable data={data} exports={exports} />
</>
<div style={{ margin: 5 }}>
<div style={{ marginBottom: 10 }}>
<span style={spanStyle}>
设备搜索
<Input style={inputStyle} placeholder='请输入' value={companyName} onChange={(v) => setCompanyName(v.target.value)}></Input>
</span>
<span style={{...spanStyle,marginLeft: 40}}>
接入类型
<Input style={inputStyle} placeholder='请输入' value={companyName} onChange={(v) => setCompanyName(v.target.value)}></Input>
</span>
<span style={{...spanStyle,marginLeft: 40}}>
厂家筛选
<Input style={inputStyle} placeholder='请输入' value={companyName} onChange={(v) => setCompanyName(v.target.value)}></Input>
</span>
<span style={{...spanStyle,marginLeft: 40}}>
查询状态
<Input style={inputStyle} placeholder='请输入' value={companyName} onChange={(v) => setCompanyName(v.target.value)}></Input>
</span>
<Button type='primary' onClick={() => search()} style={{ marginLeft: 15 }}>查询</Button>
<Button onClick={() => { setModalVisible(true); setApplyState('create'); setReadOnly(false); setModalRecord(null) }} style={{ marginLeft: 15 }}>新增</Button>
</div>
<div>
<Table
rowKey='id'
columns={columns}
dataSource={accidentInfo}
pagination={{
total: totalPage,
showSizeChanger: true,
showQuickJumper: true,
current: currentPage,
showTotal: (total) => {
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / pageSize)}页,${total}`}</span>
},
onShowSizeChange: (currentPage, pageSize) => {
setCurrentPage(currentPage);
setPageSize(pageSize);
const params = { company: companyName, creditCode, limit: pageSize, offset: currentPage }
// initial(params)
},
onChange: (page, pageSize) => {
setCurrentPage(page);
setPageSize(pageSize);
const params = { company: companyName, creditCode, limit: pageSize, offset: page }
// initial(params)
}
}}
/>
{modalVisible ? <EditGuanlang
visible={modalVisible}
onCancel={() => { setModalVisible(false) }}
handleSaveScore={handleSaveScore}
// searchCompany={searchCompany}
companys={companys}
editData={modalRecord}
readOnly={readOnly}
applyState={applyState}
></EditGuanlang> : ''}
</div>
</div>
)
}
function mapStateToProps(state) {
const { auth } = state
const { auth, accidentInfo, allCompany } = state
return {
user: auth.user,
// user: auth?.user,
// accidentInfo: accidentInfo?.data && accidentInfo?.data.rows || [],
// totalPage: accidentInfo.data && accidentInfo.data.count,
// companys: allCompany.data && allCompany.data.rows || []
}
}
export default connect(mapStateToProps)(Videois);
export default connect(mapStateToProps)(Guanlang);

12
web/client/src/sections/fillion/nav-item.js

@ -9,6 +9,9 @@ export function getNavItem(user, dispatch) {
<Menu.Item key="fillioninfor">
<Link to="/fillion/infor">治超管理</Link>
</Menu.Item>
{/* <Menu.Item key="filliontask">
<Link to="/fillion/task">任务管理</Link>
</Menu.Item> */}
<Menu.Item key="filliontransportation">
<Link to="/fillion/transportation">道路管理</Link>
</Menu.Item><Menu.Item key="fillionbridge">
@ -38,9 +41,18 @@ export function getNavItem(user, dispatch) {
{/* <Menu.Item key="fillionvideois">
<Link to="/fillion/videois">视频管理</Link>
</Menu.Item> */}
{/* <Menu.Item key="jiekouguanli">
<Link to="/fillion/jiekouguanli">接口管理</Link>
</Menu.Item> */}
<Menu.Item key="fillionpromotional">
<Link to="/fillion/promotional">宣传视频</Link>
</Menu.Item>
<Menu.Item key="fillionpatrolanomaly">
<Link to="/fillion/patrol_anomaly">异常反馈</Link>
</Menu.Item>
<Menu.Item key="fillionpatrolroad">
<Link to="/fillion/patrol_road">建设上报</Link>
</Menu.Item>
</SubMenu>
);
}

27
web/client/src/sections/fillion/routes.js

@ -11,6 +11,8 @@ import { PromoTional } from './containers';
import { Maintenance } from './containers'
import { Patrol } from './containers'
import { File } from './containers';
import { Jiekouguanli } from './containers'
import { Task } from './containers'
export default [{
type: 'inner',
route: {
@ -25,6 +27,12 @@ export default [{
menuSelectKeys: ['fillioninfor'],
component: Infor,
breadcrumb: '治超管理',
}, {
path: '/task',
key: 'filliontask',
menuSelectKeys: ['filliontask'],
component: Task,
breadcrumb: '任务管理',
}, {
path: '/transportation',
key: 'filliontransportation',
@ -69,6 +77,18 @@ export default [{
menuSelectKeys: ['fillionpatrol'],
component: Patrol,
breadcrumb: '巡查管理',
}, {
path: '/patrol_anomaly',
key: 'fillionpatrolanomaly',
menuSelectKeys: ['fillionpatrolanomaly'],
component: Patrol,
breadcrumb: '异常反馈',
}, {
path: '/patrol_road',
key: 'fillionpatrolroad',
menuSelectKeys: ['fillionpatrolroad'],
component: Patrol,
breadcrumb: '建设上报',
}, {
path: '/public',
key: 'fillionpublic',
@ -89,6 +109,13 @@ export default [{
menuSelectKeys: ['fillionvideois'],
component: Videois,
breadcrumb: '视频管理',
},
{
path: '/jiekouguanli',
key: 'jiekouguanli',
menuSelectKeys: ['jiekouguanli'],
component: Jiekouguanli,
breadcrumb: '接口管理',
}
, {
path: '/promotional',

8
web/client/src/sections/organization/components/userModal.js

@ -153,6 +153,14 @@ const UserModal = (props) => {
// defaultChecked
valuePropName="checked"
/>
<ProFormSwitch
name={['contract', 'isAdmin']}
width="md"
label="是否管理员"
placeholder="请选择"
// defaultChecked
valuePropName="checked"
/>
</ProForm.Group>
</ModalForm>
</Spin>

30
web/client/src/sections/organization/containers/user.js

@ -11,7 +11,7 @@ import DepModal from '../components/depModal';
const TreeNode = Tree.TreeNode;
const UserManage = (props) => {
const { dispatch, loading, depMessage, depUser, clientHeight } = props
const { dispatch, loading, depMessage, depUser, clientHeight, user } = props
const [modalVisible, setModalVisible] = useState(false);
const [modalType, setModalType] = useState();
const [modalRecord, setModalRecord] = useState();
@ -23,12 +23,17 @@ const UserManage = (props) => {
const [depModalRecord, setDepModalRecord] = useState();
const [selectedTree, setSelectedTree] = useState();
const [depCrumbs, setDepCrumbs] = useState([]);
const [depUserCopy, setDepUserCopy] = useState([])//用于存放除了自己的管理的数组,即自己不能调整自己是否为管理员
useEffect(() => {
dispatch(getDepMessage())
}, [])
}, [])
useEffect(() => {
const copy = depUser.filter((item) => {
return item.name !== user//把自己筛选出去
})
setDepUserCopy(copy)
}, [depUser])
useEffect(() => {
if (depMessage.length) {
setDepSelectedKeys([depMessage[0].id])
@ -60,7 +65,15 @@ const UserManage = (props) => {
render: (_, r) => {
return <Switch checkedChildren="启用" unCheckedChildren="禁用" disabled defaultChecked={r.enable} />
}
}, {
},
{
title: '是否管理员',
dataIndex: 'isadmin',
render: (_, r) => {
return <div>{r.isAdmin ? '是' : '否'}</div>
}
},
{
title: '操作',
dataIndex: 'action',
render: (dom, record) => {
@ -307,7 +320,7 @@ const UserManage = (props) => {
</Breadcrumb>
<ProTable
columns={columns}
dataSource={depUser}
dataSource={depUserCopy}
style={{ width: "100% ", height: clientHeight - 95, overflow: "auto" }}
rowSelection={{
selectedRowKeys: rowSelected,
@ -373,13 +386,14 @@ const UserManage = (props) => {
}
function mapStateToProps(state) {
const { depMessage, depUser, global } = state;
const { depMessage, depUser, global, auth } = state;
// console.log(state);
return {
clientHeight: global.clientHeight,
loading: depMessage.isRequesting,
depMessage: depMessage.data || [],
depUser: depUser.data || []
depUser: depUser.data || [],
user: auth?.user?.name
};
}

1
web/client/src/sections/quanju/containers/footer/build/Leftbottom.js

@ -284,4 +284,5 @@ legend: {
</div>
);
}
export default Leftbottom

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

@ -148,6 +148,7 @@ export const ApiTable = {
compileReportRectifyDetail: 'report/rectify/detail',
getReportList: 'report/list',
getReportDetail: 'report/{reportId}/detail',
handleReport:'report/{reportId}/handle',
getUsers: 'user',
@ -278,7 +279,10 @@ export const ApiTable = {
getCustodyunit: '/road/maintenance',
postCustodyunit: '/road/maintenance',
//养护费用
getMaintenance:'/road/maintenance/cost/nanchang/query'
getMaintenance: '/road/maintenance/cost/nanchang/query',
//任务信息
getTask: 'task', delTask: 'task/{taskId}', editTask: 'task'
};

2
web/package-lock.json

@ -3163,7 +3163,7 @@
"strip-css-comments": {
"version": "4.1.0",
"resolved": "http://10.8.30.22:7000/strip-css-comments/-/strip-css-comments-4.1.0.tgz",
"integrity": "sha1-ynmOPmtxkp8LNU4L1y53WbLqF+A=",
"integrity": "sha512-azjRwrqk7nK21LU7QuL7DpDyPjvRROQvqPrNyyz6emdzbOh6fsNTvkSvUiThBLzC6+MN90rFu296VbPb/KV+3A==",
"requires": {
"is-regexp": "^2.1.0"
}

2
web/package.json

@ -6,7 +6,7 @@
"scripts": {
"test": "mocha",
"start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5000 -u http://localhost:14000 --qndmn http://rfkimpwbb.hn-bkt.clouddn.com",
"start-params": "node server -p 5000 -u http://localhost:13400 --qndmn http://rfkimpwbb.hn-bkt.clouddn.com",
"deploy": "export NODE_ENV=production&&npm run color && npm run build && node server",
"build-dev": "export NODE_ENV=development&&webpack --config webpack.config.js",
"build": "export NODE_ENV=production&&webpack --config webpack.config.prod.js",

Loading…
Cancel
Save