Browse Source

Merge branch 'dev' of https://gitea.anxinyun.cn/gao.zhiyuan/Highways4Good into dev

release_0.0.4
wangyue 2 years ago
parent
commit
a561e62bd3
  1. 5
      api/.vscode/launch.json
  2. 19
      api/Dockerfile
  3. 15
      api/app/lib/controllers/data/bridge.js
  4. 36
      api/app/lib/controllers/data/index.js
  5. 77
      api/app/lib/controllers/data/publicity.js
  6. 81
      api/app/lib/controllers/data/road.js
  7. 36
      api/app/lib/controllers/data/vehicle.js
  8. 36
      api/app/lib/controllers/overview/building.js
  9. 8
      api/app/lib/controllers/overview/conserve.js
  10. 12
      api/app/lib/controllers/overview/management.js
  11. 2
      api/app/lib/controllers/report/index.js
  12. 2
      api/app/lib/models/bridge.js
  13. 52
      api/app/lib/models/publicity.js
  14. 2
      api/app/lib/models/report.js
  15. 20
      api/app/lib/routes/data/index.js
  16. 27
      api/config.js
  17. 1253
      api/log/development.log
  18. 2
      api/sequelize-automate.config.js
  19. 77
      api/utils/xlsxDownload.js
  20. 19
      jenkinsfile_api
  21. 19
      jenkinsfile_web
  22. 2
      scripts/0.0.1/data/2_update_statistic_data.sql
  23. 17
      scripts/0.0.1/data/3_init_report_pic_data/.vscode/launch.json
  24. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/1-1.jpg
  25. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/1-2.jpg
  26. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/10-1.jpg
  27. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/11-1.jpg
  28. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/12-1.jpg
  29. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/13-1.jpg
  30. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/14-1.jpg
  31. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/15-1.jpg
  32. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/16-1.jpg
  33. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/17-1.jpg
  34. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/18-1.jpg
  35. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/19-1.jpg
  36. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/2-1.jpg
  37. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/2-2.jpg
  38. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/20-1.jpg
  39. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/21-1.jpg
  40. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/22-1.jpg
  41. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/23-1.jpg
  42. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/24-1.jpg
  43. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/25-1.jpg
  44. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/26-1.jpg
  45. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/27-1.jpg
  46. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/28-1.jpg
  47. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/29-1.jpg
  48. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/3-1.jpg
  49. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/30-1.jpg
  50. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/31-1.jpg
  51. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/32-1.jpg
  52. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/33-1.jpg
  53. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/34-1.jpg
  54. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/35-1.jpg
  55. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/36-1.jpg
  56. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/37-1.jpg
  57. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/38-1.jpg
  58. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/39-1.jpg
  59. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/4-1.jpg
  60. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/40-1.jpg
  61. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/41-1.jpg
  62. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/42-1.jpg
  63. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/43-1.jpg
  64. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/5-1.jpg
  65. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/6-1.jpg
  66. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/7-1.jpg
  67. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/8-1.jpg
  68. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/pic/9-1.jpg
  69. BIN
      scripts/0.0.1/data/3_init_report_pic_data/data/work.xlsx
  70. 132
      scripts/0.0.1/data/3_init_report_pic_data/index.js
  71. 20
      scripts/0.0.1/data/3_init_report_pic_data/package.json
  72. 46
      scripts/0.0.1/data/工具脚本(无需执行)/dataIn.js
  73. 4
      scripts/0.0.1/data/工具脚本(无需执行)/桥梁_数据脚本对应.sql
  74. 56597
      scripts/0.0.1/schema/1.init_table.sql
  75. 7
      weapp/src/app.config.js
  76. 3
      weapp/src/packages/changePassword/index.config.js
  77. 64
      weapp/src/packages/changePassword/index.jsx
  78. 35
      weapp/src/packages/changePassword/index.scss
  79. 3
      weapp/src/packages/changePassword/success/index.config.js
  80. 24
      weapp/src/packages/changePassword/success/index.jsx
  81. 26
      weapp/src/packages/changePassword/success/index.scss
  82. 52
      weapp/src/packages/components/inputPicker/index.jsx
  83. 30
      weapp/src/packages/components/inputPicker/index.scss
  84. 578
      weapp/src/packages/patrol/index.jsx
  85. 63
      weapp/src/packages/patrol/index.scss
  86. 83
      weapp/src/packages/patrolView/index.jsx
  87. 4
      weapp/src/pages/auth/login/login.jsx
  88. 2
      weapp/src/pages/home/index.jsx
  89. 46
      weapp/src/pages/user/index.jsx
  90. 26
      weapp/src/services/api.js
  91. 15
      weapp/src/static/img/changePassword/success.svg
  92. 20
      web/Dockerfile
  93. 27
      web/client/assets/color.less
  94. BIN
      web/client/assets/images/quanju/busVideo.png
  95. BIN
      web/client/assets/images/quanju/theBus.png
  96. BIN
      web/client/assets/images/worker.png
  97. 6
      web/client/index.ejs
  98. 66
      web/client/index.html
  99. 2
      web/client/src/index.js
  100. 83
      web/client/src/layout/components/header/index.js

5
api/.vscode/launch.json

@ -16,6 +16,11 @@
"-p 14000",
"-f http://localhost:14000",
"-g postgres://postgres:123@10.8.30.32:5432/highways4good",
"--qnak XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5",
"--qnsk yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa",
"--qnbkt dev-highways4good",
// "--qndmn http://resources.anxinyun.cn",
"--qndmn http://rfkimpwbb.hn-bkt.clouddn.com",
]
},
{

19
api/Dockerfile

@ -1,7 +1,4 @@
FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2
MAINTAINER liuxinyi "liu.xinyi@free-sun.com.cn"
FROM repository.anxinyun.cn/devops/node:12-dev as builder
COPY . /var/app
@ -9,6 +6,16 @@ WORKDIR /var/app
EXPOSE 8080
CMD ["-g", "postgres://FashionAdmin:123456@iota-m1:5433/SmartRiver", "--qnak", "5XrM4wEB9YU6RQwT64sPzzE6cYFKZgssdP5Kj3uu", "--qnsk", "w6j2ixR_i-aelc6I7S3HotKIX-ukMzcKmDfH6-M5", "--qnbkt", "anxinyun-test", "--qndmn", "http://test.resources.anxinyun.cn"]
RUN npm config set registry=http://10.8.30.22:7000
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 http://10.8.30.22:7000
FROM registry.cn-hangzhou.aliyuncs.com/fs-devops/node:12
COPY --from=builder --chown=node /var/app /home/node/app
WORKDIR /home/node/app
ENTRYPOINT [ "node", "server.js" ]
CMD ["node", "server.js"]

15
api/app/lib/controllers/data/bridge.js

@ -3,10 +3,21 @@
async function bridgeGet (ctx) {
try {
const models = ctx.fs.dc.models;
const { bridgeName } = ctx.query;
const roadRes = await models.Bridge.findAll({
let findOption = {
where: {
},
order: [['id', 'DESC']]
})
}
if (bridgeName) {
findOption.where.bridgeName = {
$like: `%${bridgeName}%`
}
}
const roadRes = await models.Bridge.findAll(findOption)
ctx.status = 200;
ctx.body = roadRes

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

@ -0,0 +1,36 @@
'use strict';
const { simpleExcelDown } = require('../../../../utils/xlsxDownload');
async function dataExport (ctx) {
try {
// const models = ctx.fs.dc.models;
// const { userId } = ctx.fs.api
// const { ids } = ctx.query;
// const exportData = await models.BusCar.destroy({
// where: {
// id: { $in: ids.split(',') }
// }
// })
// const fileName = `摄像头信息列表_${userId}_${moment().format('YYYYMMDDHHmmss')}` + '.csv'
// const filePath = await simpleExcelDown({ data: exportData, header, fileName: fileName })
// const fileData = fs.readFileSync(filePath);
// ctx.status = 200;
// ctx.set('Content-Type', 'application/x-xls');
// ctx.set('Content-disposition', 'attachment; filename=' + encodeURI(fileName));
// ctx.body = fileData;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
module.exports = {
dataExport
};

77
api/app/lib/controllers/data/publicity.js

@ -0,0 +1,77 @@
'use strict';
async function publicityGet (ctx) {
try {
const models = ctx.fs.dc.models;
const { enable } = ctx.query;
let findOption = {
where: {},
order: [['id', 'DESC']]
}
if (enable) {
findOption.where.enable = true
}
const roadRes = await models.Publicity.findAll(findOption)
ctx.status = 200;
ctx.body = roadRes
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function publicityEdit (ctx) {
try {
const models = ctx.fs.dc.models;
const data = ctx.request.body;
if (!data.publicityId) {
await models.Publicity.create(data)
} else {
await models.Publicity.update(
data, {
where: {
id: data.publicityId
}
})
}
ctx.status = 204
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function publicityDel (ctx) {
try {
const models = ctx.fs.dc.models;
const { publicityId } = ctx.params;
await models.Publicity.destroy({
where: {
id: publicityId
}
})
ctx.status = 204
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
module.exports = {
publicityGet, publicityEdit, publicityDel,
};

81
api/app/lib/controllers/data/road.js

@ -5,7 +5,7 @@ async function importIn (ctx) {
// 数据导入
try {
const models = ctx.fs.dc.models;
const { level } = ctx.query;
const { level, } = ctx.query;
const data = ctx.request.body;
const roadRes = await models.Road.findAll({
@ -35,14 +35,80 @@ async function importIn (ctx) {
async function get (ctx) {
try {
const models = ctx.fs.dc.models;
const { level } = ctx.query;
const { level, road, sectionStart, sectionEnd } = ctx.query;
const roadRes = await models.Road.findAll({
where: {
level
},
let findOption = {
where: {},
order: [['id', 'DESC']]
})
}
if (level) {
findOption.where.level = level
}
if (road || sectionStart || sectionEnd) {
findOption.where['$or'] = {}
if (road) {
findOption.where['$or'].push = {
routeName: { $like: `%${road}%` }
}
}
if (sectionStart) {
findOption.where['$or'].
startingPlaceName = { $like: `%${sectionStart}%` }
}
if (sectionEnd) {
findOption.where['$or'].
stopPlaceName = { $like: `%${sectionEnd}%` }
}
}
const roadRes = await models.Road.findAll(findOption)
ctx.status = 200;
ctx.body = roadRes
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
async function getRoadSection (ctx) {
try {
const models = ctx.fs.dc.models;
const { level, road, sectionStart, sectionEnd } = ctx.query;
let findOption = {
where: {},
order: [['id', 'DESC']],
attributes: ['id', 'routeName', 'startingPlaceName', 'stopPlaceName']
}
if (level) {
findOption.where.level = level
}
if (road || sectionStart || sectionEnd) {
findOption.where['$or'] = {}
if (road) {
findOption.where['$or'].push = {
routeName: { $like: `%${road}%` }
}
}
if (sectionStart) {
findOption.where['$or'].
startingPlaceName = { $like: `%${sectionStart}%` }
}
if (sectionEnd) {
findOption.where['$or'].
stopPlaceName = { $like: `%${sectionEnd}%` }
}
}
const roadRes = await models.Road.findAll(findOption)
ctx.status = 200;
ctx.body = roadRes
@ -104,5 +170,6 @@ async function del (ctx) {
module.exports = {
importIn,
getRoadSection,
get, edit, del,
};

36
api/app/lib/controllers/data/vehicle.js

@ -4,12 +4,19 @@ async function get (ctx) {
try {
const models = ctx.fs.dc.models;
const { type } = ctx.request.body;
const { name } = ctx.query;
const vehicleRes = await models.Statistic.findAll({
let findOption = {
where: {
type
}
})
}
if (name) {
findOption.where.name = {
$like: `%${name}%`
}
}
const vehicleRes = await models.Statistic.findAll(findOption)
ctx.status = 200;
ctx.body = vehicleRes
@ -76,12 +83,20 @@ async function specificGet (ctx) {
try {
const models = ctx.fs.dc.models;
const { type } = ctx.query;
const { nameOfBusinessOwner } = ctx.query;
const vehicleRes = await models.MunicipalVehicle.findAll({
let findOption = {
where: {
type
}
})
}
if (nameOfBusinessOwner) {
findOption.where.nameOfBusinessOwner = {
$like: `%${nameOfBusinessOwner}%`
}
}
const vehicleRes = await models.MunicipalVehicle.findAll(findOption)
ctx.status = 200;
ctx.body = vehicleRes
@ -143,8 +158,19 @@ async function specificDel (ctx) {
async function businessGet (ctx) {
try {
const models = ctx.fs.dc.models;
const { nameOfBusinessOwner } = ctx.query;
const businessRes = await models.MunicipalBusiness.findAll()
let findOption = {
where:{
}
}
if (nameOfBusinessOwner) {
findOption.where.nameOfBusinessOwner = {
$like: `%${nameOfBusinessOwner}%`
}
}
const businessRes = await models.MunicipalBusiness.findAll(findOption)
ctx.status = 200;
ctx.body = businessRes

36
api/app/lib/controllers/overview/building.js

@ -37,7 +37,7 @@ async function roadState (ctx) {
type: 'road',
})
const bridgeCount = await models.Bridge.count({})
const bridgeRes = await models.Bridge.findAll({})
let constructionYear = []
for (let i = 0; constructionYear.length < 4; i++) {
@ -51,7 +51,7 @@ async function roadState (ctx) {
// 已建数量
buildedRoad: 0,
// 桥梁数量
bridgeCount: bridgeCount,
bridgeCount: bridgeRes.length,
// 涵洞数量
culvertCount: 0,
// 施工统计
@ -64,6 +64,18 @@ async function roadState (ctx) {
// 乡镇统计
townRoad: {
},
// 县乡村涵洞 个数
townCulvert: {
'县': 0,
'乡': 0,
'村': 0,
},
// 桥大小
bridgeSize: {
'大桥': 0,
'中桥': 0,
'小桥': 0,
},
// 类型统计
roadType: {
@ -134,6 +146,8 @@ async function roadState (ctx) {
roadState.roadType[r.level] = (roadState.roadType[r.level] || 0) + (Number(r.chainageMileage) || 0)
roadState.townCulvert[r.level] = (roadState.townCulvert[r.level] || 0) + (Number(r.numberOfCulverts) || 0)
if (roadState.roadLevel[r.technicalLevel]) {
roadState.roadLevel[r.technicalLevel] += 1
} else {
@ -170,11 +184,19 @@ async function roadState (ctx) {
}
}
let townName = p.buildUnit.replace('人民政府', '').replace('南昌县', '').replace('管委会', '')
if (roadState.townProject[townName]) {
roadState.townProject[townName] += 1
} else {
roadState.townProject[townName] = 1
if (p.buildUnit) {
let townName = p.buildUnit.replace('人民政府', '').replace('南昌县', '').replace('管委会', '')
if (roadState.townProject[townName]) {
roadState.townProject[townName] += 1
} else {
roadState.townProject[townName] = 1
}
}
}
for (let { dataValues: b } of bridgeRes) {
if (roadState.bridgeSize[b.bridgeClassification] || roadState.bridgeSize[b.bridgeClassification] == 0) {
roadState.bridgeSize[b.bridgeClassification] += 1
}
}

8
api/app/lib/controllers/overview/conserve.js

@ -22,10 +22,18 @@ async function statistic (ctx) {
}
const reportRes = await await models.Report.findAll(findOption)
const reportCount = await models.Report.count({
attributes: ['projectType'],
group: ['projectType'],
where: {
reportType: 'conserve',
},
})
ctx.status = 200
ctx.body = {
processed: reportRes.length,
reportCount: reportCount,
reportList: reportRes,
}
} catch (error) {

12
api/app/lib/controllers/overview/management.js

@ -4,15 +4,23 @@ async function overSpeedList (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId } = ctx.fs.api;
const { limit } = ctx.query;
const overSpeedRes = await models.Overspeed.findAll({
attributes: ['id', 'licensePlate', 'overrunRate', 'deductPoints', 'fine', 'processingTime'],
attributes: ['id', 'licensePlate', 'overrunRate', 'deductPoints', 'fine', 'processingTime', 'testTime'],
order: [['testTime', 'DESC']],
limit: limit || 120,
})
const overSpeedProcessedCount = await models.Overspeed.count({
where: {
processingTime: { $ne: null }
}
})
ctx.status = 200
ctx.body = {
processed: overSpeedRes.filter(s => s.processingTime).length,
processed: overSpeedProcessedCount,
overSpeedList: overSpeedRes,
}
} catch (error) {

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

@ -9,7 +9,7 @@ async function reportList (ctx) {
where: {
},
attributes: ['id', 'road', 'time', 'projectType', 'roadSectionStart', 'roadSectionEnd'],
attributes: ['id', 'road', 'time', 'projectType', 'roadSectionStart', 'roadSectionEnd', 'reportType', 'content', 'longitude','latitude'],
include: [{
model: models.User,
attributes: ['name']

2
api/app/lib/models/bridge.js

@ -579,7 +579,7 @@ module.exports = dc => {
defaultValue: null,
comment: "工程性质",
primaryKey: false,
field: "engineering_properties_",
field: "engineering_properties",
autoIncrement: false
},
reconstructionPart: {

52
api/app/lib/models/publicity.js

@ -0,0 +1,52 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const Publicity = sequelize.define("publicity", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "publicity_id_uindex"
},
name: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "name",
autoIncrement: false
},
video: {
type: DataTypes.ARRAY(DataTypes.INTEGER),
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "video",
autoIncrement: false
},
enable: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true,
comment: null,
primaryKey: false,
field: "enable",
autoIncrement: false
}
}, {
tableName: "publicity",
comment: "",
indexes: []
});
dc.models.Publicity = Publicity;
return Publicity;
};

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

@ -125,7 +125,7 @@ module.exports = dc => {
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,

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

@ -6,9 +6,15 @@ const bridge = require('../../controllers/data/bridge');
const project = require('../../controllers/data/project');
const overspeed = require('../../controllers/data/overspeed');
const bus = require('../../controllers/data/bus');
const publicity = require('../../controllers/data/publicity');
const data = require('../../controllers/data');
module.exports = function (app, router, opts) {
// 数据导出
app.fs.api.logAttr['GET/data/export'] = { content: '导出数据', visible: true };
router.get('/data/export', data.dataExport);
// 运政
//客运车
async function setVehicleType (ctx, next) {
@ -72,6 +78,9 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/road'] = { content: '获取道路数据', visible: true };
router.get('/road', road.get);
app.fs.api.logAttr['GET/road/section'] = { content: '获取道路路段数据', visible: true };
router.get('/road/section', road.getRoadSection);
app.fs.api.logAttr['put/road'] = { content: '编辑道路数据', visible: true };
router.put('/road', road.edit);
@ -131,4 +140,15 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['DEL/bus/car/:carId'] = { content: '删除公交车辆数据', visible: false };
router.del('/bus/car/:carId', bus.carDel);
//bus END
//publicity
app.fs.api.logAttr['GET/publicity'] = { content: '获取宣传数据', visible: true };
router.get('/publicity', publicity.publicityGet);
app.fs.api.logAttr['PUT/publicity'] = { content: '编辑宣传数据', visible: true };
router.put('/publicity', publicity.publicityEdit);
app.fs.api.logAttr['DEL/publicity/:publicityId'] = { content: '删除宣传数据', visible: false };
router.del('/publicity/:publicityId', publicity.publicityDel);
//publicity END
};

27
api/config.js

@ -11,11 +11,22 @@ const dev = process.env.NODE_ENV == 'development';
args.option(['p', 'port'], '启动端口');
args.option(['g', 'pg'], 'postgre服务URL');
args.option(['f', 'fileHost'], '文件中心本地化存储: WebApi 服务器地址(必填), 该服务器提供文件上传Web服务');
// 七牛云存储参数
args.option('qnak', 'qiniuAccessKey');
args.option('qnsk', 'qiniuSecretKey');
args.option('qnbkt', 'qiniuBucket');
args.option('qndmn', 'qiniuDomain');
//
const flags = args.parse(process.argv);
const FS_UNIAPP_DB = process.env.FS_UNIAPP_DB || flags.pg;
const FS_UNIAPP_FC_LOCAL_SVR_ORIGIN = process.env.FS_UNIAPP_FC_LOCAL_SVR_ORIGIN || flags.fileHost;
// const LOCAL_SVR_ORIGIN = process.env.LOCAL_SVR_ORIGIN || flags.fileHost;
const QINIU_DOMAIN_QNDMN_RESOURCE = process.env.ANXINCLOUD_QINIU_DOMAIN_QNDMN_RESOURC || flags.qndmn;
const QINIU_BUCKET_RESOURCE = process.env.ANXINCLOUD_QINIU_BUCKET_RESOURCE || flags.qnbkt;
const QINIU_AK = process.env.ANXINCLOUD_QINIU_ACCESSKEY || flags.qnak;
const QINIU_SK = process.env.ANXINCLOUD_QINIU_SECRETKEY || flags.qnsk;
if (!FS_UNIAPP_DB) {
console.log('缺少启动参数,异常退出');
@ -30,10 +41,16 @@ const product = {
{
entry: require('@fs/attachment').entry,
opts: {
local: {
origin: FS_UNIAPP_FC_LOCAL_SVR_ORIGIN || `http://localhost:${flags.port || 8080}`,
rootPath: 'static',
childPath: 'upload',
// local: {
// origin: LOCAL_SVR_ORIGIN || `http://localhost:${flags.port || 8080}`,
// rootPath: 'static',
// childPath: 'upload',
// },
qiniu: {
domain: QINIU_DOMAIN_QNDMN_RESOURCE,
bucket: QINIU_BUCKET_RESOURCE,
accessKey: QINIU_AK,
secretKey: QINIU_SK
},
maxSize: 104857600, // 100M
}

1253
api/log/development.log

File diff suppressed because it is too large

2
api/sequelize-automate.config.js

@ -27,7 +27,7 @@ module.exports = {
typesDir: 'models', // 指定输出 TypeScript 类型定义的文件目录,只有 TypeScript / Midway 等会有类型定义
emptyDir: false, // !!! 谨慎操作 生成 models 之前是否清空 `dir` 以及 `typesDir`
tables: null, // 指定生成哪些表的 models,如 ['user', 'user_post'];如果为 null,则忽略改属性
skipTables: ['report'], // 指定跳过哪些表的 models,如 ['user'];如果为 null,则忽略改属性
skipTables: ['report', 'publicity'], // 指定跳过哪些表的 models,如 ['user'];如果为 null,则忽略改属性
tsNoCheck: false, // 是否添加 `@ts-nocheck` 注释到 models 文件中
ignorePrefix: [], // 生成的模型名称忽略的前缀,因为 项目中有以下表名是以 t_ 开头的,在实际模型中不需要, 可以添加多个 [ 't_data_', 't_',] ,长度较长的 前缀放前面
attrLength: false, // 在生成模型的字段中 是否生成 如 var(128)这种格式,公司一般使用 String ,则配置为 false

77
api/utils/xlsxDownload.js

@ -0,0 +1,77 @@
'use strict';
const fs = require('fs');
const xlsx = require('better-xlsx');
const path = require('path')
const moment = require('moment')
//递归创建目录 同步方法
async function makeDir (dir) {
if (!fs.existsSync(dir)) {
makeDir(path.dirname(dir))
fs.mkdirSync(dir, function (err) {
if (err) {
throw err
}
});
}
}
async function simpleExcelDown ({ data = [], header = [], fileName = moment().format('YYYY-MM-DD HH:mm:ss') } = {}) {
const fileDirPath = path.join(__dirname, `../../downloadFiles`)
makeDir(fileDirPath)
const file = new xlsx.File();
const sheet_1 = file.addSheet('sheet_1');
// header
const headerStyle = new xlsx.Style();
headerStyle.align.h = 'center';
headerStyle.align.v = 'center';
headerStyle.border.right = 'thin';
headerStyle.border.rightColor = '#000000';
headerStyle.border.bottom = 'thin';
headerStyle.border.bottomColor = '#000000';
const headerRow = sheet_1.addRow();
const indexCell = headerRow.addCell();
indexCell.value = '序号'
indexCell.style = headerStyle
for (let h of header) {
const cell = headerRow.addCell();
cell.value = h.title;
cell.style = headerStyle
}
// data
const style = new xlsx.Style();
style.align.h = 'left';
style.align.v = 'center';
style.border.right = 'thin';
style.border.rightColor = '#000000';
style.border.bottom = 'thin';
style.border.bottomColor = '#000000';
for (let i = 0; i < data.length; i++) {
const row = sheet_1.addRow();
const indexCell = row.addCell();
indexCell.value = i + 1
indexCell.style = headerStyle
for (let h of header) {
const cell = row.addCell();
cell.value = data[i][h.key];
cell.style = style
}
}
const savePath = path.join(fileDirPath, fileName)
await new Promise(function (resolve, reject) {
file.saveAs()
.pipe(fs.createWriteStream(savePath))
.on('finish', () => {
resolve()
});
})
return savePath
}
module.exports = {
simpleExcelDown,
makeDir
}

19
jenkinsfile_api

@ -0,0 +1,19 @@
pipeline {
agent {
node{
label 'jnlp-slave'
}
}
stages {
stage('Highways4Good Api ......') {
steps {
sh 'switch-auth.sh anxinyun'
buildName "#${BUILD_NUMBER} ~/fs-cloud/${JOB_NAME}:${IMAGE_VERSION}"
buildDescription "registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}"
sh 'docker build -t registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION} ./api'
sh 'docker push registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}'
}
}
}
}

19
jenkinsfile_web

@ -0,0 +1,19 @@
pipeline {
agent {
node{
label 'jnlp-slave'
}
}
stages {
stage('Highways4Good Web......') {
steps {
sh 'switch-auth.sh anxinyun'
buildName "#${BUILD_NUMBER} ~/fs-cloud/${JOB_NAME}:${IMAGE_VERSION}"
buildDescription "registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}"
sh 'docker build -t registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION} ./web'
sh 'docker push registry.cn-hangzhou.aliyuncs.com/${CLOUD}/${JOB_NAME}:${IMAGE_VERSION}'
}
}
}
}

2
scripts/0.0.1/data/1_update_statistic_data.sql → scripts/0.0.1/data/2_update_statistic_data.sql

@ -5,5 +5,5 @@ INSERT INTO statistic (name, count, type) values ('标志牌', 0, 'road_manage')
INSERT INTO statistic (name, count, type) values ('防护栏', 0, 'road_manage');
INSERT INTO statistic (name, count, type) values ('检查井', 0, 'road_manage');
INSERT INTO statistic (name, count, type) values ('雨水口', 0, 'road_manage');
INSERT INTO statistic (name, count, type) values ('', 0, 'road_manage');
INSERT INTO statistic (name, count, type) values ('', 0, 'road_manage');
INSERT INTO statistic (name, count, type) values ('养护责任牌', 0, 'road_manage');

17
scripts/0.0.1/data/3_init_report_pic_data/.vscode/launch.json

@ -0,0 +1,17 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\index.js"
}
]
}

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/1-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/1-2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/10-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/11-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/12-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/13-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/14-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 895 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/15-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/16-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/17-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/18-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/19-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/2-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/2-2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/20-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/21-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/22-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/23-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/24-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/25-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/26-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/27-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/28-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/29-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/3-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/30-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/31-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/32-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/33-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/34-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/35-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/36-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/37-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/38-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/39-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/4-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/40-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/41-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/42-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/43-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/5-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/6-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/7-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/8-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/pic/9-1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 KiB

BIN
scripts/0.0.1/data/3_init_report_pic_data/data/work.xlsx

Binary file not shown.

132
scripts/0.0.1/data/3_init_report_pic_data/index.js

@ -0,0 +1,132 @@
try {
const { Pool, Client } = require('pg')
const request = require('superagent');
const Hex = require('crypto-js/enc-hex');
const MD5 = require('crypto-js/md5');
const XLSX = require('xlsx')
const path = require('path')
const fs = require("fs");
const qiniu = require('qiniu');
const uuidv4 = require('uuid/v4');
// 连接数据库
const pool = new Pool({
user: 'postgres',
host: '10.8.30.32',
database: 'highways4good',
password: '123',
port: 5432,
})
// 7niu 验证
const accessKey = 'XuDgkao6cL0HidoMAPnA5OB10Mc_Ew08mpIfRJK5'
const secretKey = 'yewcieZLzKZuDfig0wLZ9if9jKp2P_1jd3CMJPSa'
const bucket = 'dev-highways4good'
const fun = async () => {
// note: we don't try/catch this because if connecting throws an exception
// we don't need to dispose of the client (it will be undefined)
const client = await pool.connect()
try {
await client.query('BEGIN')
console.log(`开始`);
const upload7niu =
async (filePath, filename) => {
return new Promise((resolve, reject) => {
try {
const uploadPath = 'images'
// 7niu 鉴权
const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);
const config = {
scope: bucket,
// expires: 3600,
returnBody: '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}'
}
var putPolicy = new qiniu.rs.PutPolicy(config);
var uploadToken = putPolicy.uploadToken(mac);
// 上传文件
var formUploader = new qiniu.form_up.FormUploader(config);
var putExtra = new qiniu.form_up.PutExtra();
let key = path.posix.join(uploadPath, uuidv4(), filename);
formUploader.putFile(uploadToken, key, filePath, putExtra, function (respErr,
respBody, respInfo) {
if (respErr) {
reject(respErr);
throw respErr;
}
if (respInfo.statusCode == 200) {
console.log(respBody);
let qnkey = respBody.key;
resolve({ key: qnkey, url: `${qnkey}` });
} else {
console.log(respInfo.statusCode);
console.log(respBody);
reject(new Error('failed to upload.'));
}
});
} catch (err) {
reject(err);
}
});
}
// 读取数据文件
let workbook = XLSX.readFile(path.join(__dirname, './data/work.xlsx'));
let firstSheetName = workbook.SheetNames[0];
let worksheet = workbook.Sheets[firstSheetName];
let res = XLSX.utils.sheet_to_json(worksheet, {
defval: ''
});
// console.log(res);
res.sort((a, b) => { return Date.parse(a['时间']) - Date.parse(b['时间']) });
// 读取全部图片
let pic = [];
fs.readdirSync(path.join(__dirname, '/data/pic')).forEach((filename) => {
pic.push({
path: `./data/pic/${filename}`,
name: filename
})
});
for (let r of res) {
console.log(r);
let picList = pic.filter(p => {
const { name } = p
const no = name.split('-')[0]
return no == r['编号']
})
console.log(picList);
// 将图片上传至 7niu
let upPicUrl = [];
for (let p of picList) {
const upRes = await upload7niu(path.join(__dirname, p.path), p.name)
console.log(upRes);
upPicUrl.push(upRes.url)
}
const roadSectionArr = r['路段'] ? r['路段'].split('至') : null
const roadSection = roadSectionArr && roadSectionArr.length > 1 ? roadSectionArr : [null, null]
await client.query(`INSERT INTO report (report_type, project_type, road, road_section_start, road_section_end,time,content,conserve_underway_pic) VALUES($1, $2, $3, $4, $5, $6, $7, $8) `, ['conserve', 'road', r['道路'], roadSection[0], roadSection[1], r['时间'], r['内容'], upPicUrl])
// break
}
// await client.query('ROLLBACK')
await client.query('COMMIT')
console.log('执行完毕~')
} catch (e) {
await client.query('ROLLBACK')
console.log('执行错误~')
throw e
} finally {
client.release();
}
}
fun()
} catch (error) {
console.error(error)
}

20
scripts/0.0.1/data/3_init_report_pic_data/package.json

@ -0,0 +1,20 @@
{
"name": "appkey-generator",
"version": "1.0.0",
"description": "tool",
"main": "index.js",
"scripts": {
"test": "mocha",
"start": "set NODE_ENV=development&&node index"
},
"author": "liu",
"license": "ISC",
"dependencies": {
"crypto-js": "^4.1.1",
"pg": "^7.18.2",
"qiniu": "^7.7.0",
"superagent": "^8.0.0",
"uuid": "3.1.0",
"xlsx": "^0.17.1"
}
}

46
scripts/0.0.1/data/工具脚本(无需执行)/dataIn.js

@ -12,6 +12,7 @@ try {
user: 'postgres',
host: '10.8.30.32',
database: 'highways4good',
// database: 'highways4good_initdata',
password: '123',
port: 5432,
})
@ -46,6 +47,11 @@ try {
// defaultValue: ['乡'],
// },
// {
// path: ['./data/桥梁/桥第三方.xls'],
// n: '桥梁',
// tableName: 'bridge'
// },
// {
// path: (() => {
// let p = [];
// fs.readdirSync(path.join(__dirname, '/data/运政/车辆/出租车')).forEach((filename) => {
@ -71,26 +77,26 @@ try {
// defaultKey: ['type'],
// defaultValue: ['危货'],
// },
{
path: ['./data/运政/业户/出租车/事业发展中心巡游出租业户信息表.xlsx'],
n: '运政业户',
tableName: 'municipal_business',
defaultKey: ['type'],
defaultValue: ['出租车'],
},
{
path: (() => {
let p = [];
fs.readdirSync(path.join(__dirname, '/data/运政/业户/危货')).forEach((filename) => {
p.push(`./data/运政/业户/危货/${filename}`)
});
return p;
})(),
n: '运政业户',
tableName: 'municipal_business',
defaultKey: ['type'],
defaultValue: ['危货'],
},
// {
// path: ['./data/运政/业户/出租车/事业发展中心巡游出租业户信息表.xlsx'],
// n: '运政业户',
// tableName: 'municipal_business',
// defaultKey: ['type'],
// defaultValue: ['出租车'],
// },
// {
// path: (() => {
// let p = [];
// fs.readdirSync(path.join(__dirname, '/data/运政/业户/危货')).forEach((filename) => {
// p.push(`./data/运政/业户/危货/${filename}`)
// });
// return p;
// })(),
// n: '运政业户',
// tableName: 'municipal_business',
// defaultKey: ['type'],
// defaultValue: ['危货'],
// },
// {
// path: ['./data/工程一览/道路.xls'],
// n: '工程一览',

4
scripts/0.0.1/data/工具脚本(无需执行)/桥梁_数据脚本对应.sql

@ -65,8 +65,8 @@ ON column bridge.Nature_Of_Management_And_Maintenance_Unit is '管养单位性
ON column bridge.Management_And_Maintenance_Unit is '管养单位'; alter TABLE bridge add Supervision_Unit varchar(1024); comment
ON column bridge.Supervision_Unit is '监管单位'; alter TABLE bridge add Reconstruction_Construction_Unit varchar(1024); comment
ON column bridge.Reconstruction_Construction_Unit is '改造施工单位'; alter TABLE bridge add Whether_It_Is_A_Subsidy_Project_Of_The_Ministry varchar(1024); comment
ON column bridge.Whether_It_Is_A_Subsidy_Project_Of_The_Ministry is '是否部补助项目'; alter TABLE bridge add Engineering_Properties_ varchar(1024); comment
ON column bridge.Engineering_Properties_ is '工程性质'; alter TABLE bridge add Reconstruction_Part varchar(1024); comment
ON column bridge.Whether_It_Is_A_Subsidy_Project_Of_The_Ministry is '是否部补助项目'; alter TABLE bridge add Engineering_Properties varchar(1024); comment
ON column bridge.Engineering_Properties is '工程性质'; alter TABLE bridge add Reconstruction_Part varchar(1024); comment
ON column bridge.Reconstruction_Part is '改造部位'; alter TABLE bridge add Modification_Completion_Date varchar(1024); comment
ON column bridge.Modification_Completion_Date is '改造完工日期'; alter TABLE bridge add Year_1 varchar(1024); comment
ON column bridge.Year_1 is '年份1'; alter TABLE bridge add Span_Combination_1 varchar(1024); comment

56597
scripts/0.0.1/schema/1.init_table.sql

File diff suppressed because it is too large

7
weapp/src/app.config.js

@ -8,7 +8,9 @@ export default {
'root': 'packages/',
'pages': [
'patrol/index',
'patrolView/index'
'patrolView/index',
'changePassword/index',
'changePassword/success/index'
]
}],
permission: {
@ -16,6 +18,9 @@ export default {
"desc": '需要获取您的地理位置'
}
},
requiredPrivateInfos: [
'getLocation',
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: "#2C66F3",

3
weapp/src/packages/changePassword/index.config.js

@ -0,0 +1,3 @@
export default {
navigationBarTitleText: '修改密码'
}

64
weapp/src/packages/changePassword/index.jsx

@ -0,0 +1,64 @@
import React, { useState } from 'react'
import Taro from '@tarojs/taro'
import { View, Input } from '@tarojs/components'
import { AtButton } from 'taro-ui'
import request from '@/services/request'
import { putPassword } from '@/services/api'
import './index.scss'
function Index() {
const userInfo = Taro.getStorageSync('userInfo') || null;
const [phone, setPhone] = useState(userInfo.phone)
const [password, setPassword] = useState('')
const [password2, setPassword2] = useState('')
function confirm() {
if (!password) {
Taro.showToast({ title: '请输入密码' })
return
} else if (password !== password2) {
Taro.showToast({ title: '两次输入的密码不一致' })
return
} else {
Taro.showModal({
title: '提示',
content: '确定修改吗',
success: function (res) {
if (res.confirm) {
Taro.showLoading({
title: '修改中'
})
request.put(putPassword(userInfo.id), { password }).then(res => {
Taro.hideLoading()
if (res.statusCode == 200 || res.statusCode == 204) {
Taro.removeStorageSync('token')
Taro.removeStorageSync('userInfo')
Taro.reLaunch({ url: '/packages/changePassword/success/index' })
}
})
}
}
})
}
}
return (
<View className='page'>
<View className='phone'>
<View className='title'>手机号码</View>
<Input value={phone} disabled={true} />
</View>
<View className='pswd'>
<View className='title'>新的密码</View>
<Input value={password} onInput={e => setPassword(e.detail.value)} />
</View>
<View className='pswd'>
<View className='title'>再次输入新的密码</View>
<Input value={password2} onInput={e => setPassword2(e.detail.value)} />
</View>
<AtButton className='btn' type='primary' onClick={confirm}>确认</AtButton>
</View>
)
}
export default Index

35
weapp/src/packages/changePassword/index.scss

@ -0,0 +1,35 @@
page {
background-color: #f6f6f6;
font-size: 28px;
.phone {
height: 96px;
background-color: #fff;
margin: 20px auto;
display: flex;
justify-content: left;
align-items: center;
.title {
margin-left: 30px;
}
}
.pswd {
height: 96px;
background-color: #fff;
margin-bottom: 5px;
display: flex;
justify-content: left;
align-items: center;
.title {
margin-left: 30px;
}
}
.btn {
width: 70%;
margin: 80px auto;
}
}

3
weapp/src/packages/changePassword/success/index.config.js

@ -0,0 +1,3 @@
export default {
navigationBarTitleText: '修改密码'
}

24
weapp/src/packages/changePassword/success/index.jsx

@ -0,0 +1,24 @@
import React from 'react'
import Taro from '@tarojs/taro'
import { View, Image } from '@tarojs/components'
import { AtButton } from 'taro-ui'
import './index.scss'
import successIcon from '../../../static/img/changePassword/success.svg'
function Index() {
function handleClick() {
Taro.reLaunch({ url: '/pages/auth/login/login' })
}
return (
<View>
<View className='box'>
<Image className='img' src={successIcon} />
<View className='text'>修改成功</View>
</View>
<AtButton className='btn' type='primary' onClick={handleClick}>返回登录</AtButton>
</View>
)
}
export default Index

26
weapp/src/packages/changePassword/success/index.scss

@ -0,0 +1,26 @@
page {
background-color: #f6f6f6;
.box {
background-color: #fff;
height: 360px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.img {
width: 160px;
height: 160px;
}
.text {
margin-top: 32px;
}
}
.btn {
width: 70%;
margin: 80px auto;
}
}

52
weapp/src/packages/components/inputPicker/index.jsx

@ -0,0 +1,52 @@
/*
* 输入框筛选选择器
*/
import React, { useState, useEffect } from 'react'
import { View, Picker, Image, Input, Text } from '@tarojs/components'
import arrowIcon from '../../../static/img/patrol/arrow-down.svg'
import './index.scss'
export default function InputPicker(props) {
const { title, placeholder, selector, value, onInput, isView } = props
const [curSelector, setCurSelector] = useState([])
useEffect(() => {
setCurSelector(selector)
}, [])
function handleInput({ detail: { value: v } }) {
onInput(v)
if (v) {
setCurSelector(selector.filter(item => item && item.includes(v)))
} else {
setCurSelector(selector)
}
}
const handlePickerChange = (e) => {
onInput(curSelector[e.detail.value])
}
return (
<View className='input-picker'>
<View className='input-box'>
<View className='title'><Text style={{ color: 'red' }}>*&nbsp;</Text>{title}</View>
<Input
className='input'
type='text'
placeholder={placeholder}
border={false}
value={value}
onInput={handleInput}
disabled={isView}
/>
</View>
{
!isView &&
<Picker mode='selector' range={curSelector} onChange={handlePickerChange}>
<Image src={arrowIcon} className='img' />
</Picker>
}
</View>
)
}

30
weapp/src/packages/components/inputPicker/index.scss

@ -0,0 +1,30 @@
.input-picker {
display: flex;
justify-content: space-between;
height: 96px;
align-items: center;
background-color: #fff;
margin-bottom: 5px;
.input-box {
padding: 12px 0;
flex-grow: 1;
display: flex;
align-items: center;
.title {
margin-left: 12px;
}
.input {
margin-left: 20px;
flex-grow: 1;
}
}
.img {
width: 24px;
height: 14px;
margin: 0 30px;
}
}

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

@ -1,245 +1,485 @@
import React, { useState, useEffect } from 'react';
import Taro from '@tarojs/taro';
import {
View,
RadioGroup,
Radio,
Button,
Image,
Input,
Textarea,
Picker
} from '@tarojs/components';
import { AtForm, AtInput, AtButton, AtTextarea, AtImagePicker, AtTimeline } from 'taro-ui';
// import InputPicker from '../components/inputPicker';
import Taro, { useRouter } from '@tarojs/taro';
import { View, RadioGroup, Radio, Image, Input, Picker } from '@tarojs/components';
import { AtButton, AtTextarea, AtImagePicker } from 'taro-ui';
import InputPicker from '../components/inputPicker';
import request from '@/services/request';
import { postReport, getReportDetail, delReport, getRoadSection } from '@/services/api';
import './index.scss';
import arrowIcon from '../../static/img/patrol/arrow-down.svg';
const Index = () => {
const [isPatrol, setIsPatrol] = useState(true) // or
const [prjTypeSelector, setPrjTypeSelector] = useState([])
const [roadSelector, setRoadSelector] = useState([])
const [projectType, setProjectType] = useState('')
const [road, setRoad] = useState('')
const userInfo = Taro.getStorageSync('userInfo') || {};
const isSuperAdmin = userInfo && userInfo.username === 'SuperAdmin' ? true : false
const [images, setimages] = useState([])
const router = useRouter()
const { params: { type } } = router
const isView = type === 'view' ? true : false
const reportType = [
const [reportType, setReportType] = useState('patrol') //
const [projectType, setProjectType] = useState('') //
const [road, setRoad] = useState('') //
const [roadSectionStart, setRoadSectionStart] = useState('') // Start
const [roadSectionEnd, setRoadSectionEnd] = useState('') // End
const [address, setAddress] = useState('') //
const [content, setContent] = useState('') //
const [scenePic, setScenePic] = useState([]) //
const [conserveBeforePic, setConserveBeforePic] = useState([]) //
const [conserveUnderwayPic, setConserveUnderwayPic] = useState([]) //
const [conserveAfterPic, setConserveAfterPic] = useState([]) //
const [longitude, setLongitude] = useState(0) //
const [latitude, setLatitude] = useState(0) //
const [sourceRoadSel, setSourceRoadSel] = useState([])
const [sourceRoadStartSel, setSourceRoadStartSel] = useState([])
const [sourceRoadEndSel, setSourceRoadEndSel] = useState([])
const prjTypeSelector = ['道路', '桥梁', '涵洞', '其他']
const [roadStartSel, setRoadStartSel] = useState([])
const [roadEndSel, setRoadEndSel] = useState([])
const [canReport, setCanReport] = useState(true)
const [typeList, setTypeList] = useState([
{
value: '巡查',
value: 'patrol',
text: '巡查',
checked: true
},
{
value: '养护',
value: 'conserve',
text: '养护',
checked: false
}
]
])
useEffect(() => {
const prjTypeSelector = ['道路', '桥梁', '涵洞', '其他']
const roadSelector = ['富山一路', '金沙大道', '玉湖路']
setPrjTypeSelector(prjTypeSelector)
setRoadSelector(roadSelector)
if (isView) { //
Taro.showLoading({ title: '加载中' })
request.get(getReportDetail(router.params.id)).then(res => {
Taro.hideLoading()
if (res.statusCode == 200 || res.statusCode == 204) {
const { data } = res
setReportType(data.reportType)
setProjectType(data.projectType)
setRoad(data.road)
setRoadSectionStart(data.roadSectionStart)
setRoadSectionEnd(data.roadSectionEnd)
setAddress(data.address)
setContent(data.content)
setScenePic(data.scenePic ? data.scenePic.map(item => ({ url: item })) : [])
setConserveBeforePic(data.conserveBeforePic ? data.conserveBeforePic.map(item => ({ url: item })) : [])
setConserveUnderwayPic(data.conserveUnderwayPic ? data.conserveUnderwayPic.map(item => ({ url: item })) : [])
setConserveAfterPic(data.conserveAfterPic ? data.conserveAfterPic.map(item => ({ url: item })) : [])
} else {
Taro.showToast({ title: res.data.message || '请求出错', icon: 'none' })
}
}, err => {
Taro.showToast({ title: err.message || '请求出错', icon: 'none' })
})
} else { //
Taro.showLoading({ title: '加载中' })
let key = 'ODQBZ-3FZAU-6VIVL-2XXNM-F7CP7-WVFCY' // key
Taro.getLocation({
type: 'wgs84',
success: function (res) {
setLongitude(res.longitude)
setLatitude(res.latitude)
Taro.request({
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)
}
})
}
})
request.get(getRoadSection()).then(res => {
Taro.hideLoading()
if (res.statusCode == 200 || res.statusCode == 204) {
const { data } = res
let nextSourceRoadSel = []
let nextSourceRoadStartSel = []
let nextSourceRoadEndSel = []
data.map(item => {
nextSourceRoadSel.push(item.routeName)
nextSourceRoadStartSel.push(item.startingPlaceName)
nextSourceRoadEndSel.push(item.stopPlaceName)
})
setSourceRoadSel(nextSourceRoadSel)
setSourceRoadStartSel(nextSourceRoadStartSel)
setSourceRoadEndSel(nextSourceRoadEndSel)
} else {
Taro.showToast({ title: res.data.message || '请求出错', icon: 'none' })
}
}, err => {
Taro.showToast({ title: err.message || '请求出错', icon: 'none' })
})
}
}, [])
useEffect(() => {
setRoadStartSel(sourceRoadStartSel)
setRoadEndSel(sourceRoadEndSel)
}, [sourceRoadStartSel, sourceRoadEndSel])
useEffect(() => {
if (projectType) {
setPrjTypeSelector(prjTypeSelector.filter(s => s.includes(projectType)))
setTypeList([
{
value: 'patrol',
text: '巡查',
checked: reportType === 'patrol' ? true : false
},
{
value: 'conserve',
text: '养护',
checked: reportType === 'conserve' ? true : false
}
])
}, [reportType])
function report() {
if (!canReport) { return }
if (!projectType || !road) {
Taro.showToast({ title: '请完善必填信息', icon: 'none' })
return
}
if (prjTypeSelector.indexOf(projectType) === -1) {
Taro.showToast({ title: '工程类型错误', icon: 'none' })
return
}
}, [projectType])
// useEffect(() => {
// if (projectType) {
// setPrjTypeSelector(prjTypeSelector.filter(s => s.includes(projectType)))
// }
// }, [projectType])
function onTypeChange(e) {
if (e.detail.value === '巡查') {
setIsPatrol(true)
let data = {
reportType,
projectType,
road,
roadSectionStart,
roadSectionEnd,
address,
content,
longitude,
latitude
}
if (reportType === 'patrol') {
data['scenePic'] = scenePic.length > 0 ? scenePic.map(item => item.url) : null
} else {
setIsPatrol(false)
data['conserveBeforePic'] = conserveBeforePic.length > 0 ? conserveBeforePic.map(item => item.url) : null
data['conserveUnderwayPic'] = conserveUnderwayPic.length > 0 ? conserveUnderwayPic.map(item => item.url) : null
data['conserveAfterPic'] = conserveAfterPic.length > 0 ? conserveAfterPic.map(item => item.url) : null
}
Taro.showModal({
title: '提示',
content: '您要进行信息上报么?',
success: function (res) {
if (res.confirm) {
setCanReport(false)
setTimeout(() => {
setCanReport(true)
}, 3000) // 3
Taro.showLoading({
title: '上报中'
})
request.post(postReport(), data).then(res => {
Taro.hideLoading()
if (res.statusCode == 200 || res.statusCode == 204) {
Taro.showToast({ title: '上报成功', icon: 'none', duration: 1500 })
setTimeout(() => {
Taro.reLaunch({
url: '/pages/home/index'
});
}, 1500)
} else {
Taro.showToast({ title: res.data.message || '请求出错', icon: 'none' })
}
}, err => {
Taro.showToast({ title: err.message || '请求出错', icon: 'none' })
})
}
}
})
}
function onPrjTypeChange(e) {
setProjectType(selector[e.detail.value])
function deleteReport() {
Taro.showModal({
title: '提示',
content: '确定删除吗?',
success: function (res) {
if (res.confirm) {
Taro.showLoading({
title: '删除中'
})
request.del(delReport(router.params.id)).then(res => {
Taro.hideLoading()
if (res.statusCode == 200 || res.statusCode == 204) {
Taro.showToast({ title: '删除成功', icon: 'none', duration: 1500 })
setTimeout(() => {
Taro.navigateBack()
}, 1000)
} else {
Taro.showToast({ title: res.data.message || '请求出错', icon: 'none' })
}
}, err => {
Taro.showToast({ title: err.message || '请求出错', icon: 'none' })
})
}
}
})
}
function onImgPickerChange(files) {
setimages(files)
function handleInput({ detail: { value } }, type) {
switch (type) {
case 'roadSectionStart':
setRoadSectionStart(value)
if (value) {
setRoadStartSel(sourceRoadStartSel.filter(item => item && item.includes(value)))
} else {
setRoadStartSel(sourceRoadStartSel)
}
break;
case 'roadSectionEnd':
setRoadSectionEnd(value)
if (value) {
setRoadEndSel(sourceRoadEndSel.filter(item => item && item.includes(value)))
} else {
setRoadEndSel(sourceRoadEndSel)
}
break;
case 'address':
setAddress(value)
break;
case 'content':
setContent(value)
default:
break;
}
}
function onImageClick(index, file) {
function handleTypeChange(e) {
setReportType(e.detail.value)
}
function handleImgChange(files, type) {
switch (type) {
case 'scenePic':
setScenePic(files)
break;
case 'conserveBeforePic':
setConserveBeforePic(files)
break;
case 'conserveUnderwayPic':
setConserveUnderwayPic(files)
break;
case 'conserveAfterPic':
setConserveAfterPic(files)
break;
default:
break;
}
}
function handleImgClick(index, file) {
Taro.previewImage({
urls: [file.url] // http
})
}
useEffect(() => {
console.log(images);
}, [images])
return (
<View>
<View className='report-type'>
<View className='text'>上报类型</View>
<RadioGroup onChange={onTypeChange}>
{
reportType.map((item, i) => {
return (
<Radio
key={i}
value={item.value}
checked={item.checked}
className='radio'
color='#346FC2'
>
{item.text}
</Radio>
)
})
}
</RadioGroup>
</View>
<View className='input-picker'>
<AtInput
className='input'
title='工程类型:'
type='text'
placeholder='请选择工程类型'
border={false}
value={projectType}
onChange={value => setProjectType(value)}
/>
<Picker mode='selector' range={prjTypeSelector} onChange={onPrjTypeChange}>
<Image src={arrowIcon} className='img-r' />
</Picker>
</View>
<View className='input-picker'>
<AtInput
className='input'
title='所在道路:'
type='text'
placeholder='请选择您所在的道路'
border={false}
value={road}
onChange={value => setRoad(value)}
/>
<Picker mode='selector' range={roadSelector} onChange={onPrjTypeChange}>
<Image src={arrowIcon} className='img-r' />
</Picker>
</View>
{/* <InputPicker
className='input-picker'
<View className='patrol'>
{
!isSuperAdmin &&
<View className='report-type'>
<View className='text'>上报类型</View>
<RadioGroup onChange={handleTypeChange}>
{
typeList.map((item, i) => {
return (
<Radio
key={i}
value={item.value}
checked={item.checked}
className='radio'
color='#346FC2'
disabled={isView}
>
{item.text}
</Radio>
)
})
}
</RadioGroup>
</View>
}
<InputPicker
title='工程类型:'
placeholder='请选择工程类型'
value={projectType}
onChange={setProjectType}
onInput={setProjectType}
selector={prjTypeSelector}
isView={isView}
/>
<InputPicker
className='input-picker'
<InputPicker
key={sourceRoadSel} // keyselector
title='所在道路:'
placeholder='请选择您所在的道路'
placeholder='请选择或输入您所在的道路'
value={road}
onChange={setRoad}
selector={roadSelector}
/> */}
onInput={setRoad}
selector={sourceRoadSel}
isView={isView}
/>
<View className='input-picker'>
<AtInput
<View className='road-section'>
<View className='title'>所属路段</View>
<Input
className='input'
title='所属路段:'
type='text'
placeholder='路段名称'
placeholder={isView ? '' : '路段名称'}
border={false}
// value={this.state.value}
// onChange={this.handleChange.bind(this, 'value')}
value={roadSectionStart}
onInput={e => handleInput(e, 'roadSectionStart')}
disabled={isView}
/>
<Picker mode='selector' range={roadSelector} onChange={onPrjTypeChange}>
<Image src={arrowIcon} className='img-l' />
</Picker>
<AtInput
{
!isView &&
<Picker
mode='selector'
range={roadStartSel}
onChange={e => setRoadSectionStart(roadStartSel[e.detail.value])}
>
<Image src={arrowIcon} className='img-l' />
</Picker>
}
<View>&nbsp;</View>
<Input
className='input'
type='text'
placeholder='路段名称'
placeholder={isView ? '' : '路段名称'}
border={false}
// value={this.state.value}
// onChange={this.handleChange.bind(this, 'value')}
value={roadSectionEnd}
onInput={e => handleInput(e, 'roadSectionEnd')}
disabled={isView}
/>
{
!isView &&
<Picker
mode='selector'
range={roadEndSel}
onChange={e => setRoadSectionEnd(roadEndSel[e.detail.value])}
>
<Image src={arrowIcon} className='img-r' />
</Picker>
}
</View>
<View className='address'>
<View className='title'>具体位置</View>
<Input
className='input'
type='text'
placeholder={isView ? '' : '根据定位自动获取,可手动修改'}
value={address}
onInput={e => handleInput(e, 'address')}
disabled={isView}
/>
<Picker mode='selector' range={roadSelector} onChange={onPrjTypeChange}>
<Image src={arrowIcon} className='img-r' />
</Picker>
</View>
<AtTextarea
count={false}
title='具体位置:'
placeholder='具体位置:根据定位自动获取,可手动修改'
// value={this.state.value}
// onChange={this.handleChange.bind(this, 'value')}
/>
<AtTextarea
count={false}
title='巡查内容:'
placeholder='请输入巡查内容'
// value={this.state.value}
// onChange={this.handleChange.bind(this, 'value')}
placeholder={isView ? '' : '请输入巡查内容'}
value={content}
onChange={(v, e) => handleInput(e, 'content')}
disabled={isView}
maxLength={50}
/>
{
isPatrol ?
<View className='patrol-picker'>
reportType === 'patrol' ?
<View className='patrol-img'>
现场图片
<AtImagePicker
className='img-picker'
count={3 - images.length}
showAddBtn={images.length >= 3 ? false : true}
files={images}
onChange={onImgPickerChange}
onImageClick={onImageClick}
/>
{
isView ?
<View className='img-box'>
{scenePic.map(item => (
<Image className='img' src={item.url} onClick={() => handleImgClick(undefined, item)} />
))}
</View> :
<AtImagePicker
className='img-picker'
count={3 - scenePic.length}
showAddBtn={scenePic.length >= 3 ? false : true}
files={scenePic}
onChange={files => handleImgChange(files, 'scenePic')}
onImageClick={handleImgClick}
/>
}
</View> :
<View className='conserve-picker'>
<View className='conserve-img'>
养护图片:
<View className='horizontal-line hl-one'>
<View className='circle c-one'></View>
<View className='text t-one'>养护前</View>
</View>
<AtImagePicker
className='img-picker'
count={3}
files={images}
onChange={onImgPickerChange}
/>
{
isView ?
<View className='img-box'>
{conserveBeforePic.map(item => (
<Image className='img' src={item.url} onClick={() => handleImgClick(undefined, item)} />
))}
</View> :
<AtImagePicker
className='img-picker'
count={3 - conserveBeforePic.length}
showAddBtn={conserveBeforePic.length >= 3 ? false : true}
files={conserveBeforePic}
onChange={files => handleImgChange(files, 'conserveBeforePic')}
onImageClick={handleImgClick}
/>
}
<View className='horizontal-line hl-two'>
<View className='circle c-two'></View>
<View className='text t-two'>养护中</View>
</View>
<AtImagePicker
className='img-picker'
count={3}
files={images}
onChange={onImgPickerChange}
/>
{
isView ?
<View className='img-box'>
{conserveUnderwayPic.map(item => (
<Image className='img' src={item.url} onClick={() => handleImgClick(undefined, item)} />
))}
</View> :
<AtImagePicker
className='img-picker'
count={3 - conserveUnderwayPic.length}
showAddBtn={conserveUnderwayPic.length >= 3 ? false : true}
files={conserveUnderwayPic}
onChange={files => handleImgChange(files, 'conserveUnderwayPic')}
onImageClick={handleImgClick}
/>
}
<View className='horizontal-line hl-three'>
<View className='circle c-three'></View>
<View className='text t-three'>养护后</View>
</View>
<AtImagePicker
className='img-picker'
count={3}
files={images}
onChange={onImgPickerChange}
/>
{
isView ?
<View className='img-box'>
{conserveAfterPic.map(item => (
<Image className='img' src={item.url} onClick={() => handleImgClick(undefined, item)} />
))}
</View> :
<AtImagePicker
className='img-picker'
count={3 - conserveAfterPic.length}
showAddBtn={conserveAfterPic.length >= 3 ? false : true}
files={conserveAfterPic}
onChange={files => handleImgChange(files, 'conserveAfterPic')}
onImageClick={handleImgClick}
/>
}
</View>
}
<AtButton formType='submit' type='primary' className='sub-btn'>上报</AtButton>
{
isView ?
<AtButton type='primary' className='del-btn' onClick={deleteReport}>删除</AtButton> :
<AtButton type='primary' className='sub-btn' onClick={report}>上报</AtButton>
}
</View>
)
}

63
weapp/src/packages/patrol/index.scss

@ -3,6 +3,10 @@ page {
width: 100vw;
background-color: #f6f6f6;
.patrol {
font-size: 28px;
}
.report-type {
height: 96px;
background-color: #fff;
@ -20,32 +24,58 @@ page {
}
}
.input-picker {
.road-section {
display: flex;
justify-content: space-between;
justify-content: left;
height: 96px;
align-items: center;
background-color: #fff;
margin-bottom: 5px;
.title {
margin-left: 30px;
}
.input {
width: 200px;
margin: 0 10px;
}
.img-r {
width: 24px;
height: 14px;
margin-right: 30px;
// margin-left: 10px;
margin: 0 10px;
}
.img-l {
width: 24px;
height: 14px;
margin: 0 10px;
}
}
.patrol-picker {
.address {
background-color: #fff;
padding: 20px;
display: flex;
align-items: center;
height: 96px;
margin-bottom: 5px;
.title {
margin-left: 30px;
}
.input {
margin-left: 20px;
flex-grow: 1;
}
}
.patrol-img {
background-color: #fff;
padding: 20px;
}
.conserve-picker {
.conserve-img {
background-color: #fff;
padding: 20px;
@ -53,6 +83,7 @@ page {
height: 30px;
width: 100%;
border-radius: 5px;
margin-top: 10px;
display: flex;
justify-content: left;
align-items: center;
@ -109,8 +140,26 @@ page {
}
}
.img-box {
display: flex;
flex-wrap: wrap;
.img {
width: 170px;
height: 170px;
margin: 10px 0 0 10px;
}
}
.sub-btn {
width: 70%;
margin: 80px auto;
}
.del-btn {
width: 70%;
margin: 80px auto;
background-color: #C23434;
border-color: #C23434;
}
}

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

@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react'
import Taro, { useDidShow } from '@tarojs/taro'
import Taro, { useDidShow, useRouter } from '@tarojs/taro'
import { View, Picker, Input, Image } from '@tarojs/components'
import moment from 'moment'
import './index.scss'
@ -15,16 +15,24 @@ import conserveIcon from '../../static/img/patrolView/conserve.svg'
import conserveActiveIcon from '../../static/img/patrolView/conserve-active.svg'
function Index() {
const userInfo = Taro.getStorageSync('userInfo') || {};
const router = useRouter()
const { params: { limit } } = router
const [isPatrol, setIsPatrol] = useState(true)
const [datePicker, setDatePicker] = useState(moment().format('YYYY-MM-DD'))
const [listData, setListData] = useState([])
const [inputSite, setInputSite] = useState('')
const [page, setPage] = useState(0)
const [total, setTotal] = useState(0)
const [num, setNum] = useState(Math.random())
const [showListData, setShowListData] = useState([])
const [filterText, setFilterText] = useState('')
const [systemInfo, setSystemInfo] = useState('')
const userInfo = Taro.getStorageSync('userInfo') || {};
useEffect(() => {
getList()
}, [datePicker])
useEffect(() => {
setShowListData(listData.filter(item => isPatrol ? item.reportType === 'patrol' : item.reportType === 'conserve'))
}, [isPatrol])
function dealError(error) {
Taro.showToast({
@ -34,25 +42,32 @@ function Index() {
});
throw new Error(error);
}
useEffect(() => {
request.get(getReportList(),{}, { hideErrorToast: true, hideLoading: true }).then(res => {
const getList = () => {
Taro.showLoading({ title: '加载中' })
request.get(
getReportList(),
{ startTime: datePicker + ' 00:00:00', endTime: datePicker + ' 23:59:59' }
).then(res => {
Taro.hideLoading()
if (res.statusCode == 200) {
console.log(res);
setListData(res.data)
return res.data;
let { data } = res
if (limit === 'my') {
data = data.filter(item => item.user.name === userInfo.name)
}
setListData(data)
setShowListData(data.filter(item => isPatrol ? item.reportType === 'patrol' : item.reportType === 'conserve'))
return data;
} else {
dealError(res.data.message || '请求出错');
}
}, err => {
dealError(err.message || '请求出错');
});
}, [])
}
useDidShow(() => {
let refresh = Taro.getStorageSync('refresh'); //
if (refresh) {
setPage(0)
setNum(Math.random())
Taro.removeStorageSync('refresh'); //
}
Taro.getSystemInfo({
@ -72,53 +87,60 @@ function Index() {
setDatePicker(e.detail.value);
}
const handleConfirm = () => {
setPage(0)
setListData([]);
setTotal(0);
setNum(Math.random())
const handleConfirm = e => {
let nextList = listData.filter(item => isPatrol ? item.reportType === 'patrol' : item.reportType === 'conserve')
nextList = nextList.filter(item => item.road.includes(e.detail.value))
setShowListData(nextList)
}
const handleInput = e => {
setInputSite(e.detail.value);
setFilterText(e.detail.value);
if (!e.detail.value) {
setPage(0)
setListData([]);
setTotal(0);
setNum(Math.random())
setShowListData(listData.filter(item => isPatrol ? item.reportType === 'patrol' : item.reportType === 'conserve'));
}
}
const handleDetail = index => {
Taro.navigateTo({ url: `/packages/patrol/index?type=view&id=${showListData[index].id}` })
}
return (
<View>
<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 style={{ color: isPatrol ? '#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 style={{ color: isPatrol ? '#999999' : '#346FC2' }}>养护</View>
</View>
</View>
<View className='filter-box'>
<View className='filter-item'>
<View style={{ float: 'left', marginLeft: '20rpx', color: '#333' }}>日期</View>
<Picker className='picker' style={{ overflow: 'hidden', float: 'left' }} mode='date' end={(systemInfo == 'windows' || systemInfo == 'mac') ? moment().add(1, 'd').format('YYYY-MM-DD') : moment().format('YYYY-MM-DD')} onChange={onDateChange}>
<Picker
className='picker'
style={{ overflow: 'hidden', float: 'left' }}
mode='date'
end={(systemInfo == 'windows' || systemInfo == 'mac')
? moment().add(1, 'd').format('YYYY-MM-DD')
: moment().format('YYYY-MM-DD')} onChange={onDateChange}
>
<View className='filter-name'>{datePicker || '请选择'}</View>
<Image className='filter-img' src={chevronDown} />
</Picker>
</View>
<View class='head-search'>
<Image className='search-img' src={searchIcon} />
<Input class='heard-search-input' value={inputSite} placeholder='请输入场所名称' onConfirm={handleConfirm} onInput={handleInput} />
<Input class='heard-search-input' value={filterText} placeholder='请输入道路名称' onConfirm={handleConfirm} onInput={handleInput} />
</View>
</View>
<View style={{ marginTop: '110px' }}>
{
listData && listData.length > 0 ? listData && listData.map((e, index) => {
showListData && showListData.length > 0 ? showListData && showListData.map((e, index) => {
return (
<View className='cardBox' key={index} onClick={() => handleDetail(index)}>
<View className='card-item' >
@ -127,7 +149,7 @@ function Index() {
<View className='card-title'>{e.road}</View>
<View style={{ float: 'left', width: '100%', fontSize: '28rpx', marginTop: '16rpx' }}>
<View style={{ float: 'left' }}>填报人</View>
<View style={{ float: 'left' }}>{e.user.name}</View>
<View style={{ float: 'left' }}>{e.user && e.user.name}</View>
</View>
<View className='card-date'>{moment(e.time).format('YYYY-MM-DD HH:mm:ss')}</View>
</View>
@ -140,5 +162,4 @@ function Index() {
</View>
)
}
export default Index

4
weapp/src/pages/auth/login/login.jsx

@ -18,6 +18,10 @@ const LoginPage = (props) => {
const [password, setPassword] = useState('');
const doLogin = () => {
if (!username || !password) {
Taro.showToast({ title: '请输入账号和密码', icon: 'none' })
return
}
login(getLoginUrl(), { phone: username, password }).then(res => {
Taro.reLaunch({
url: '/pages/home/index'

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

@ -10,7 +10,7 @@ const Index = () => {
function toPatrol() {
Taro.navigateTo({
url: '/packages/patrol/index'
url: '/packages/patrol/index?type=edit'
})
}
function toPatrolView() {

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

@ -16,20 +16,40 @@ const { webUrl } = cfg;
const Index = ({ ...props }) => {
const userInfo = Taro.getStorageSync('userInfo') || {};
const isSuperAdmin = userInfo && userInfo.username === 'SuperAdmin' ? true : false
const goRedirect = () => {
const changePassword = () => {
Taro.navigateTo({ url: '/packages/changePassword/index' })
}
const toMyReport = () => {
Taro.navigateTo({
url: '/packages/patrolView/index?limit=my'
})
}
const onLogout = () => {
logout(getLogoutUrl()).then(() => {
Taro.reLaunch({
url: '/pages/auth/login/login'
});
});
const toPatrolReport = () => {
Taro.navigateTo({
url: '/packages/patrol/index?type=edit'
})
}
const onLogout = () => {
Taro.showModal({
title: '提示',
content: '确定退出登录吗',
success: function (res) {
if (res.confirm) {
logout(getLogoutUrl()).then(() => {
Taro.reLaunch({
url: '/pages/auth/login/login'
});
});
}
}
})
}
return (
<View className='page'>
<View className='myBox'>
@ -42,18 +62,20 @@ const Index = ({ ...props }) => {
</View>
</View>
<View className='box' onClick={() => goRedirect(1)}>
<View className='box' onClick={isSuperAdmin ? toPatrolReport : toMyReport}>
<Image className='box-img' src={reportImg} />
<View className='box-txt'>我的填报</View>
<View className='box-txt'>
{isSuperAdmin ? '巡查上报' : '我的上报'}
</View>
<Image className='img' src={moreImg} />
</View>
<View className='box' onClick={() => goRedirect(2)} style={{ marginTop: '2rpx' }}>
<View className='box' onClick={changePassword} style={{ marginTop: '2rpx' }}>
<Image className='box-img' src={pswdImg} />
<View className='box-txt'>修改密码</View>
<Image className='img' src={moreImg} />
</View>
<View className='logout' onClick={onLogout}>退出登录</View>
</View>

26
weapp/src/services/api.js

@ -7,10 +7,36 @@ export const getLogoutUrl = () => {
return `/logout`;
};
// 巡查上报
export const postReport = () => {
return `/report`;
};
// 获取上报列表
export const getReportList = () => {
return `/report/list`;
};
// 获取上报详情
export const getReportDetail = id => {
return `/report/${id}/detail`;
};
// 删除上报
export const delReport = id => {
return `/report/${id}`;
};
// 修改密码
export const putPassword = id => {
return `/department/user/${id}/password`;
};
// 获取道路路段
export const getRoadSection = () => {
return `/road/section`;
};
//行业查询
export const getIndustryUrl = () => {
return `/elec/business/industry`

15
weapp/src/static/img/changePassword/success.svg

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="80px" height="80px" viewBox="0 0 80 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>切片</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="首页_我的修改密码-1" transform="translate(-148.000000, -99.000000)">
<g id="5.反馈/6.Progress进度条/进度圈/成功" transform="translate(148.000000, 99.000000)">
<path d="M40,0 C62.09139,0 80,17.90861 80,40 C80,62.09139 62.09139,80 40,80 C17.90861,80 0,62.09139 0,40 C0,17.90861 17.90861,0 40,0 Z M40,4 C20.117749,4 4,20.117749 4,40 C4,59.882251 20.117749,76 40,76 C59.882251,76 76,59.882251 76,40 C76,20.117749 59.882251,4 40,4 Z" id="Progress" fill="#52C41A"></path>
<g id="check" transform="translate(14.000000, 15.000000)">
<rect id="矩形" fill="#000000" fill-rule="nonzero" opacity="0" x="0" y="0" width="48" height="48"></rect>
<path d="M42.75,8.90625 L39.4734375,8.90625 C39.0140625,8.90625 38.578125,9.1171875 38.296875,9.478125 L18.9703125,33.9609375 L9.703125,22.21875 C9.4171875,21.8578125 8.9859375,21.646875 8.5265625,21.646875 L5.25,21.646875 C4.9359375,21.646875 4.7625,22.0078125 4.9546875,22.2515625 L17.79375,38.5171875 C18.39375,39.2765625 19.546875,39.2765625 20.1515625,38.5171875 L43.0453125,9.50625 C43.2375,9.2671875 43.0640625,8.90625 42.75,8.90625 Z" id="路径" fill="#52C41A"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

20
web/Dockerfile

@ -1,5 +1,4 @@
FROM repository.anxinyun.cn/base-images/nodejs12:20.10.12.2
FROM repository.anxinyun.cn/devops/node:12-dev as builder
COPY . /var/app
@ -7,6 +6,19 @@ WORKDIR /var/app
EXPOSE 8080
CMD ["-u", "http://localhost:8088"]
RUN npm config set registry=http://10.8.30.22:7000
RUN echo "{\"time\":\"$BUILD_TIMESTAMP\",\"build\": \"$BUILD_NUMBER\",\"revision\": \"$SVN_REVISION_1\",\"URL\":\"$SVN_URL_1\"}" > version.json
RUN npm cache clean -f
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 npm install --production --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
WORKDIR /home/node/app
ENTRYPOINT [ "node", "server.js" ]
CMD ["node", "server.js"]

27
web/client/assets/color.less

@ -1149,10 +1149,11 @@ tr > .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child::afte
.ant-mentions-dropdown-menu-item-active {background-color: @item-hover-bg;}
.ant-menu-item-danger.ant-menu-item {color: #ff4d4f;}
.ant-menu-item-danger.ant-menu-item:hover, .ant-menu-item-danger.ant-menu-item-active {color: #ff4d4f;}
.ant-menu-item-danger.ant-menu-item:active {background: #fff1f0;}
.ant-menu-item-danger.ant-menu-item:active {background: color(~`colorPalette("@{modal-header-border-color-split}", 1)`);}
.ant-menu-item-danger.ant-menu-item-selected {color: #ff4d4f;}
.ant-menu-item-danger.ant-menu-item-selected > a, .ant-menu-item-danger.ant-menu-item-selected > a:hover {color: #ff4d4f;}
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-danger.ant-menu-item-selected {background-color: #fff1f0;}
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-danger.ant-menu-item-selected {background-color: color(~`colorPalette("@{modal-header-border-color-split}", 1)`);}
.ant-menu-inline .ant-menu-item-danger.ant-menu-item::after {border-right-color: #ff4d4f;}
.ant-menu-dark .ant-menu-item-danger.ant-menu-item, .ant-menu-dark .ant-menu-item-danger.ant-menu-item:hover, .ant-menu-dark .ant-menu-item-danger.ant-menu-item > a {color: #ff4d4f;}
.ant-menu-dark.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-danger.ant-menu-item-selected {color: #fff;background-color: #ff4d4f;}
@ -1722,11 +1723,22 @@ tr.ant-table-expanded-row:hover > td {background: @table-expanded-row-bg;}
.ant-tag-checkable:active, .ant-tag-checkable-checked {color: #fff;}
.ant-tag-checkable-checked {background-color: @primary-color;}
.ant-tag-checkable:active {background-color: color(~`colorPalette("@{primary-color}", 7)`);}
.ant-tag-pink {color: #c41d7f;background: color(~`colorPalette("@{component-background}", 1)`);border-color: #ffadd2;}
.ant-tag-pink {color: #c41d7f;background: #fff0f6;border-color: #ffadd2;}
.ant-tag-pink-inverse {color: #fff;background: #eb2f96;border-color: #eb2f96;}
.ant-tag-magenta {color: #c41d7f;background: color(~`colorPalette("@{component-background}", 1)`);border-color: #ffadd2;}
.ant-tag-magenta-inverse {color: #fff;background: #eb2f96;border-color: #eb2f96;}
.ant-tag-red {color: #cf1322;background: #fff1f0;border-color: #ffa39e;}
.ant-tag-pink {color: #c41d7f;background: color(~`colorPalette("@{success-color-deprecated-bg}", 1)`);border-color: #ffadd2;}
.ant-tag-pink-inverse {color: #fff;background: #eb2f96;border-color: #eb2f96;}
.ant-tag-magenta {color: #c41d7f;background: color(~`colorPalette("@{success-color-deprecated-bg}", 1)`);border-color: #ffadd2;}
.ant-tag-magenta-inverse {color: #fff;background: #eb2f96;border-color: #eb2f96;}
.ant-tag-red {color: #cf1322;background: color(~`colorPalette("@{modal-header-border-color-split}", 1)`);border-color: #ffa39e;}
.ant-tag-red-inverse {color: #fff;background: #f5222d;border-color: #f5222d;}
.ant-tag-volcano {color: #d4380d;background: #fff2e8;border-color: #ffbb96;}
.ant-tag-volcano-inverse {color: #fff;background: #fa541c;border-color: #fa541c;}
@ -1742,9 +1754,16 @@ tr.ant-table-expanded-row:hover > td {background: @table-expanded-row-bg;}
.ant-tag-lime-inverse {color: #fff;background: #a0d911;border-color: #a0d911;}
.ant-tag-green {color: #389e0d;background: #f6ffed;border-color: #b7eb8f;}
.ant-tag-green-inverse {color: #fff;background: #52c41a;border-color: #52c41a;}
.ant-tag-blue {color: #096dd9;background: #e6f7ff;border-color: #91d5ff;}
.ant-tag-blue-inverse {color: #fff;background: #1890ff;border-color: #1890ff;}
.ant-tag-geekblue {color: #1d39c4;background: color(~`colorPalette("@{btn-primary-bg}", 1)`);border-color: #adc6ff;}
.ant-tag-blue {color: #096dd9;background: #e6f7ff;border-color: color(~`colorPalette("@{alert-info-border-color}", 5)`);}
.ant-tag-blue-inverse {color: #fff;background: #1890ff;border-color: #1890ff;}
.ant-tag-geekblue {color: #1d39c4;background: color(~`colorPalette("@{tree-bg}", 1)`);border-color: #adc6ff;}
.ant-tag-geekblue-inverse {color: #fff;background: #2f54eb;border-color: #2f54eb;}
.ant-tag-purple {color: #531dab;background: #f9f0ff;border-color: #d3adf7;}
.ant-tag-purple-inverse {color: #fff;background: #722ed1;border-color: #722ed1;}
@ -1984,7 +2003,11 @@ a.ant-typography.ant-typography-disabled:hover, .ant-typography a.ant-typography
.ant-upload-list-picture .ant-upload-list-item-error, .ant-upload-list-picture-card .ant-upload-list-item-error {border-color: #ff4d4f;}
.ant-upload-list-picture .ant-upload-list-item:hover .ant-upload-list-item-info, .ant-upload-list-picture-card .ant-upload-list-item:hover .ant-upload-list-item-info {background: transparent;}
.ant-upload-list-picture .ant-upload-list-item-uploading, .ant-upload-list-picture-card .ant-upload-list-item-uploading {border-style: dashed;}
.ant-upload-list-picture .ant-upload-list-item-error .ant-upload-list-item-thumbnail .anticon svg path[fill='#e6f7ff'], .ant-upload-list-picture-card .ant-upload-list-item-error .ant-upload-list-item-thumbnail .anticon svg path[fill='#e6f7ff'] {fill: @error-color-deprecated-bg;}
.ant-upload-list-picture .ant-upload-list-item-error .ant-upload-list-item-thumbnail .anticon svg path[fill='#e6f7ff'], .ant-upload-list-picture-card .ant-upload-list-item-error .ant-upload-list-item-thumbnail .anticon svg path[fill='#e6f7ff'] {fill: @error-color-deprecated-bg;}
.ant-upload-list-picture .ant-upload-list-item-error .ant-upload-list-item-thumbnail .anticon svg path[fill='#1890ff'], .ant-upload-list-picture-card .ant-upload-list-item-error .ant-upload-list-item-thumbnail .anticon svg path[fill='#1890ff'] {fill: #ff4d4f;}
.ant-upload-list-picture-card .ant-upload-list-item-info::before {background-color: rgba(0, 0, 0, 0.5);}
.ant-upload-list-picture-card .ant-upload-list-item-actions .anticon-eye, .ant-upload-list-picture-card .ant-upload-list-item-actions .anticon-download, .ant-upload-list-picture-card .ant-upload-list-item-actions .anticon-delete {color: rgba(255, 255, 255, 0.85);}

BIN
web/client/assets/images/quanju/busVideo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 KiB

BIN
web/client/assets/images/quanju/theBus.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

6
web/client/index.ejs

@ -9,6 +9,12 @@
type="text/css"
href="/assets/font_sc/iconfont.css"
/>
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: 'e955cd5ddfc3a752aa27d1e1c67d182d',
}
</script>
<script src="https://webapi.amap.com/maps?v=2.0&key=00f9a29dedcdbd8befec3dfe0cef5003&plugin=AMap.Adaptor,AMap.Scale,AMap.ToolBar,AMap.DistrictSearch,AMap.Geocoder,AMap.CustomLayer,Map3D,ElasticMarker"></script>
</head>
<body style="background: transparent">

66
web/client/index.html

@ -1,37 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title></title>
<link rel="shortcut icon" href="/assets/images/favicon.ico" />
<link
rel="stylesheet"
type="text/css"
href="/assets/font_sc/iconfont.css"
/>
<link rel="stylesheet" href="/assets/fontziti/font.css" />
</head>
<body>
<link
rel="stylesheet/less"
type="text/css"
href="/assets/color.less"
rel="external nofollow"
/>
<script>
window.less = {
async: false,
env: "production",
};
</script>
<script
type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"
></script>
<div id="App"></div>
<script
type="text/javascript"
src="http://localhost:5001/client/build/app.js"
></script>
</body>
</html>
<head>
<meta charset="UTF-8" />
<title></title>
<link rel="shortcut icon" href="/assets/images/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/assets/font_sc/iconfont.css" />
<link rel="stylesheet" href="/assets/fontziti/font.css" />
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode: 'e955cd5ddfc3a752aa27d1e1c67d182d',
}
</script>
<script
src="https://webapi.amap.com/maps?v=2.0&key=00f9a29dedcdbd8befec3dfe0cef5003&plugin=AMap.Adaptor,AMap.Scale,AMap.ToolBar,AMap.DistrictSearch,AMap.Geocoder,AMap.CustomLayer,Map3D,ElasticMarker"></script>
<script src="https://webapi.amap.com/loca?v=2.0.0&key=00f9a29dedcdbd8befec3dfe0cef5003"></script>
</head>
<body>
<link rel="stylesheet/less" type="text/css" href="/assets/color.less" rel="external nofollow" />
<script>
window.less = {
async: false,
env: "production",
};
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script>
<div id="App"></div>
<script type="text/javascript" src="http://localhost:5001/client/build/app.js"></script>
</body>
</html>

2
web/client/src/index.js

@ -4,4 +4,4 @@ import React from 'react';
import { render } from 'react-dom';
import App from './app';
render((<App projectName="智慧应急" />), document.getElementById('App'));
render((<App projectName="南昌县智慧交通监管系统" />), document.getElementById('App'));

83
web/client/src/layout/components/header/index.js

@ -18,30 +18,15 @@ const themeMap = {
}
const Header = props => {
const { dispatch, changeTheme, history, user, pathname, toggleCollapsed, collapsed, actions } = props
const changeTheme_ = (themeKey) => {
localStorage.setItem("theme-name", themeKey);
window.less.modifyVars(themeMap[themeKey]).catch(error => {
message.error(`Failed to reset theme`);
});
changeTheme(themeKey)
}
const { dispatch, history, user, pathname, toggleCollapsed, collapsed, actions } = props
const handelClick = item => {
if (item.key == 'logout') {
dispatch(actions.auth.logout(user));
history.push(`/signin`);
} else if (item.key == 'themeLight') {
changeTheme_('light')
} else if (item.key == 'themeDark') {
changeTheme_('dark')
} else if (item.key == 'themeExample') {
changeTheme_('example')
}
}
let current = pathname;
console.log(pathname);
if (pathname == '/' || pathname == '') {
@ -56,56 +41,48 @@ const Header = props => {
return (
<div className={styles.header}>
{/* <div className={styles['header-fold']}>
<div className={styles['header-fold']}>
<span onClick={toggleCollapsed} style={{ marginRight: 20 }}>
{collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
</span>
<div className={styles['header-title']} style={{}}>
智慧应急 */}
{/* <span>{user.orgName}</span> */}
{/* </div>
南昌县智慧交通监管系统
</div>
</div>
<div id="nav" className={styles['header-nav']}> */}
{/* <Menu
<div id="nav" className={styles['header-nav']}>
<Menu
mode='horizontal'
selectedKeys={[current]} style={{ border: 0 }}
onClick={handelClick}
> */}
{/* <Menu.SubMenu key="theme" title={<div style={{ margin: '0 8px' }}></div>} >
<Menu.Item key="themeLight" >
<span>亮色风格</span>
</Menu.Item>
<Menu.Item key="themeDark" >
<span>暗色风格</span>
>
<div style={{ display: 'inline-block', cursor: "pointer" }} onClick={() => history.push(`/quanju`)}>进入大屏</div>
<Menu.SubMenu key="user" title={
<div style={{
margin: '0 8px'
}}>
<div
className={styles['header-nav-user-img-wrapper']}
>
<UserOutlined />
</div>
<div style={{ display: 'inline-block' }}>{user.name}</div>
</div>}
>
{/* <Menu.Item key="profile" icon={<UserOutlined />}>
<Link to="/profile">个人设置</Link>
</Menu.Item> */}
<Menu.Item key="logout" icon={<LogoutOutlined />}>
<span>退出</span>
</Menu.Item>
<Menu.Item key="themeExample" >
<span>示例风格</span>
</Menu.Item>
</Menu.SubMenu> */}
{/* <Menu.SubMenu key="user" title={
<div style={{
margin: '0 8px'
}}>
<div className={styles['header-nav-user-img-wrapper']}>
<UserOutlined />
</div>
<div style={{ display: 'inline-block' }}>{user.name}</div>
</div>}
> */}
{/* <Menu.Item key="profile" icon={<UserOutlined />}>
<Link to="/profile">个人设置</Link>
</Menu.Item> */}
{/* <Menu.Item key="logout" icon={<LogoutOutlined />}>
<span>退出</span>
</Menu.Item>
</Menu.SubMenu> */}
{/* </Menu> */}
{/* </div> */}
</Menu.SubMenu>
</Menu>
</div>
</div>
);
};
function mapStateToProps(state) {
function mapStateToProps (state) {
const { global, auth } = state;
return {
actions: global.actions,

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save