Browse Source

周期计划和响应记录功能优化

dev
wenlele 1 year ago
parent
commit
fb6076bb6f
  1. 10
      api/.vscode/launch.json
  2. 30
      api/app/lib/controllers/maintenancePlan/index.js
  3. 56
      api/app/lib/controllers/record/index.js
  4. 3
      api/app/lib/index.js
  5. 176
      api/app/lib/models/maintenance_plan.js
  6. 157
      api/app/lib/models/maintenance_record.js
  7. 4
      api/app/lib/routes/record/index.js
  8. 14
      script/0.29/schema/update_maintenance_plan.sql
  9. 84
      web/client/src/sections/means/containers/devOpsStandard.jsx
  10. 60
      web/client/src/sections/means/containers/faultInformation.jsx
  11. 65
      web/client/src/sections/means/containers/projectMeans.jsx
  12. 61
      web/client/src/sections/means/containers/repairFQA.jsx
  13. 2
      web/client/src/sections/means/containers/style.less
  14. 24
      web/client/src/sections/means/nav-item.jsx
  15. 32
      web/client/src/sections/means/routes.js
  16. 4
      web/client/src/sections/means/style.less
  17. 20
      web/client/src/sections/service/actions/record.js
  18. 172
      web/client/src/sections/service/components/cycAddmodal.jsx
  19. 87
      web/client/src/sections/service/components/planAddmodal.jsx
  20. 282
      web/client/src/sections/service/components/recordModal.jsx
  21. 276
      web/client/src/sections/service/containers/cyclePlan.jsx
  22. 441
      web/client/src/sections/service/containers/maintenanceRecords.jsx
  23. 492
      web/client/src/sections/service/containers/serviceRecord.jsx
  24. 5
      web/client/src/utils/webapi.js

10
api/.vscode/launch.json

@ -42,13 +42,13 @@
// "--qndmn http://resources.anxinyun.cn",
// "--qndmn http://rhvqdivo5.hn-bkt.clouddn.com",
// click
// "--clickHouseUrl http://10.8.30.71",
// "--clickHousePort 8123",
"--clickHouseUrl http://10.8.30.71",
"--clickHousePort 30123",
// click
// "--clickHouseUrl http://10.8.30.161",
// "--clickHousePort 30123",
"--clickHouseUrl http://10.8.30.156",
"--clickHousePort 8123",
// "--clickHouseUrl http://10.8.30.156",
// "--clickHousePort 8123",
// "--clickHouseUrl https://clickhouse01.anxinyun.cn/play",
// click
@ -66,7 +66,7 @@
// "--clickHouseDataAlarm default",
// "--clickHouseIot iot",
//
"--clickHouseAnxincloud anxinyun888",
"--clickHouseAnxincloud anxinyun1",
"--clickHousePepEmis pepca8",
"--clickHouseProjectManage peppm8",
"--clickHouseVcmp video_access_dev",

30
api/app/lib/controllers/maintenancePlan/index.js

@ -2,27 +2,34 @@
//维护计划
async function getMaintenancePlan(ctx) {
async function getMaintenancePlan (ctx) {
const query = ctx.query
try {
const { models } = ctx.fs.dc
const { clickHouse } = ctx.app.fs
//console.log('11121', query)
let resCount = await models.MaintenancePlan.count({
where: { type: query.type }
})
const res = await models.MaintenancePlan.findAndCount({
let option = {
order: [['id', 'DESC']],
offset: (query.pageIndex - 1) * query.pageSize,
limit: query.pageSize,
attributes: ['id', 'missionName', 'remark', 'reason', 'planFinishTime', 'actualFinishTime', 'type', 'state'],
attributes: ['id', 'missionName', 'remark', 'reason', 'planFinishTime', 'actualFinishTime', 'type', 'state', 'recordId'],
where: { type: query.type },
include: [{
attributes: ['id', 'maintenancePlanId', 'pepUserId'],
model: models.MaintenancePlanExecuteUser
}]
})
}
if (query.pageIndex && query.pageSize) {
option.offset = (query.pageIndex - 1) * query.pageSize
option.limit = query.pageSize
}
if (query.recordId) {
option.where.recordId = { $contains: [query.recordId] }
}
const res = await models.MaintenancePlan.findAndCount(option)
//console.log('res1', res)
const arrayUserId = []
if (res.rows.length > 0) {
@ -44,6 +51,7 @@ async function getMaintenancePlan(ctx) {
actualFinishTime: item.actualFinishTime,
type: item.type,
state: item.state,
recordId: item.recordId,
maintenancePlanExecuteUsers:
item.maintenancePlanExecuteUsers.map((item1) => {
const nameArr = userRes.find((ac) => { return ac.id == item1.pepUserId })
@ -76,7 +84,7 @@ async function getMaintenancePlan(ctx) {
}
async function delMaintenancePlan(ctx) {
async function delMaintenancePlan (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const { models } = ctx.fs.dc
@ -98,7 +106,7 @@ async function delMaintenancePlan(ctx) {
}
}
async function editMaintenancePlan(ctx) {
async function editMaintenancePlan (ctx) {
const data = ctx.request.body
const transaction = await ctx.fs.dc.orm.transaction();
try {
@ -112,6 +120,7 @@ async function editMaintenancePlan(ctx) {
missionName: data.missionName,
remark: data.remark,
reason: data.reason,
recordId: data.recordId,
planFinishTime: data.planFinishTime,
state: data.state
}, { where: { id: data.id } })
@ -120,6 +129,7 @@ async function editMaintenancePlan(ctx) {
actualFinishTime: data.actualFinishTime,
missionName: data.missionName,
remark: data.remark,
recordId: data.recordId,
planFinishTime: data.planFinishTime,
state: data.state
}, { where: { id: data.id } })
@ -143,6 +153,7 @@ async function editMaintenancePlan(ctx) {
reason: data.reason,
planFinishTime: data.planFinishTime,
type: data.type,
recordId: data.recordId,
state: data.state
})
//console.log('data.manger',data.manger)
@ -159,6 +170,7 @@ async function editMaintenancePlan(ctx) {
missionName: data.missionName,
remark: data.remark,
planFinishTime: data.planFinishTime,
recordId: data.recordId,
type: data.type,
state: data.state
})

56
api/app/lib/controllers/record/index.js

@ -1,11 +1,12 @@
'use strict';
const moment = require('moment');
async function getRecord(ctx) {
async function getRecord (ctx) {
try {
const { redis } = ctx.app
const { models } = ctx.fs.dc;
const sequelize = ctx.fs.dc.ORM;
const { clickHouse } = ctx.app.fs
const { startTime, endTime, pageSize, pageIndex } = ctx.query
console.log('queryz', ctx.query)
@ -19,7 +20,7 @@ async function getRecord(ctx) {
})
let recordRes = await models.MaintenanceRecord.findAndCountAll({
order: [['id', 'DESC']],
attributes: ['id', 'sketch', 'occurrenceTime', 'solvingTime', 'interruptDuration', 'type', 'record'],
attributes: ['id', 'sketch', 'occurrenceTime', 'solvingTime', 'interruptDuration', 'type', 'record','files'],
offset: (pageIndex - 1) * pageSize,
limit: pageSize,
where: {
@ -35,7 +36,11 @@ async function getRecord(ctx) {
})
//console.log('recordRes', recordRes)
const arrayUserId = []
recordRes.rows.forEach((item) => { item.maintenanceRecordExecuteUsers.forEach((item1) => { arrayUserId.push(item1.pepUserId) }) })
const recordId = []
recordRes.rows.forEach((item) => {
recordId.push(item.id)
item.maintenanceRecordExecuteUsers.forEach((item1) => { arrayUserId.push(item1.pepUserId) })
})
const arrayUserIdCopy = [...new Set(arrayUserId)]
// console.log('(' + arrayUserIdCopy.toString() + ')', '22222')
let userRes = await redis.get('allUser')
@ -44,7 +49,12 @@ async function getRecord(ctx) {
return arrayUserIdCopy.some((children) => { return children == item.id })
})
//console.log('userRes', userRes)
const res = recordRes.rows.map((item) => {
let planList = await models.MaintenancePlan.findAll({
where: { recordId: { $overlap: recordId } },
})
const res = await recordRes.rows.map((item) => {
return {
id: item.id,
interruptDuration: item.interruptDuration,
@ -53,6 +63,8 @@ async function getRecord(ctx) {
sketch: item.sketch,
solvingTime: item.solvingTime,
type: item.type,
files: item.files || null,
planList: planList.filter(v => v.recordId && v.recordId.includes(item.id)) || [],
maintenanceRecordExecuteUsers:
item.maintenanceRecordExecuteUsers.map((item1) => {
const userArr = userRes.find((ac) => { return ac.id == item1.pepUserId })
@ -67,7 +79,7 @@ async function getRecord(ctx) {
}
)
//console.log('res1', res)
ctx.body = { count: resCount, res }
ctx.body = { count: resCount, res: res }
ctx.status = 200
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
@ -78,18 +90,18 @@ async function getRecord(ctx) {
}
}
//新增和编辑服务记录
async function addRecord(ctx) {
async function addRecord (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
const { models } = ctx.fs.dc
const params = ctx.request.body
const { solvingTime, occurrencTime, sketch, record, settler, type, id, msg } = params
const { solvingTime, occurrencTime, sketch, record, settler, type, id, msg, files } = params
const breakTime = (Date.parse(solvingTime) - Date.parse(occurrencTime)) / 1000
try {
//中断时长
//console.log('resss1', Date.parse(solvingTime), occurrencTime)
if (id) {
await models.MaintenanceRecord.update({
solvingTime, occurrenceTime: occurrencTime, sketch, record, settler, type, interruptDuration: breakTime
solvingTime, occurrenceTime: occurrencTime, sketch, record, settler, type, interruptDuration: breakTime, files: files
}, { where: { id } })
await models.MaintenanceRecordExecuteUser.destroy({ where: { maintenanceRecordId: id } })
const resArry = settler.map((item) => {
@ -99,7 +111,7 @@ async function addRecord(ctx) {
})
await models.MaintenanceRecordExecuteUser.bulkCreate(resArry)
} else {
const aa = await models.MaintenanceRecord.create({ solvingTime, occurrenceTime: occurrencTime, sketch, record, settler, type, interruptDuration: breakTime })
const aa = await models.MaintenanceRecord.create({ solvingTime, occurrenceTime: occurrencTime, sketch, record, settler, type, interruptDuration: breakTime,files: files })
const recordId = aa.id
const resArry = settler.map((item) => {
return {
@ -122,7 +134,7 @@ async function addRecord(ctx) {
}
}
//删除服务记录
async function delRecord(ctx) {
async function delRecord (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
const { models } = ctx.fs.dc
const params = ctx.params
@ -143,7 +155,29 @@ async function delRecord(ctx) {
}
async function respondRecord (ctx) {
try {
const { models } = ctx.fs.dc;
let res = await models.MaintenanceRecord.findAll({
order: [['id', 'DESC']],
attributes: ['id', 'sketch', 'occurrenceTime'],
})
ctx.body = res
ctx.status = 200
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: '获取响应记录数据失败'
}
}
}
module.exports = {
getRecord, addRecord, delRecord
getRecord,
addRecord,
delRecord,
respondRecord
};

3
api/app/lib/index.js

@ -61,7 +61,7 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
AppInspection, ProjectApp, ProjectCorrelation, AppAlarm, App, AlarmAppearRecord, AlarmConfirmLog, EmailSendLog, LatestDynamicList, AlarmPushConfig,
MaintenanceRecord, MaintenanceRecordExecuteUser, MaintenancePlanExecuteUser, MaintenancePlan, EquipmentMaintenanceRecord, EquipmentMaintenanceRecordProject,
EquipmentMaintenanceRecordExecuteUser, ServerMaintenanceRecordRepairman, ServerMaintenanceRecord,
AlarmDataContinuityType, AlarmDataContinuity
AlarmDataContinuityType, AlarmDataContinuity,
} = dc.models;
AppInspection.belongsTo(App, { foreignKey: 'projectAppId', targetKey: 'id' });
@ -112,6 +112,7 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq
MaintenanceRecordExecuteUser.belongsTo(MaintenanceRecord, { foreignKey: 'maintenanceRecordId', targetKey: 'id' })
MaintenanceRecord.hasMany(MaintenanceRecordExecuteUser, { foreignKey: 'maintenanceRecordId', targetKey: 'id' })
MaintenanceRecord.hasMany(MaintenanceRecordExecuteUser, { foreignKey: 'maintenanceRecordId', targetKey: 'id' })
MaintenancePlanExecuteUser.belongsTo(MaintenancePlan, { foreignKey: 'maintenancePlanId', targetKey: 'id' })
MaintenancePlan.hasMany(MaintenancePlanExecuteUser, { foreignKey: 'maintenancePlanId', targetKey: 'id' })

176
api/app/lib/models/maintenance_plan.js

@ -3,87 +3,97 @@
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const MaintenancePlan = sequelize.define("maintenancePlan", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "maintenance_plan_id_uindex"
},
missionName: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "任务名称",
primaryKey: false,
field: "mission_name",
autoIncrement: false
},
remark: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "备注",
primaryKey: false,
field: "remark",
autoIncrement: false
},
reason: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "操作/故障原因",
primaryKey: false,
field: "reason",
autoIncrement: false
},
planFinishTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "计划完成时间",
primaryKey: false,
field: "plan_finish_time",
autoIncrement: false
},
actualFinishTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "实际完成时间\n",
primaryKey: false,
field: "actual_finish_time",
autoIncrement: false
},
type: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "分类 period 周期 / temp 临时",
primaryKey: false,
field: "type",
autoIncrement: false
},
state: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "完成状态 unfinished 未完成 / underway 进行中 / completed 已完成 / suspend 挂起暂停 / inspected 已检查",
primaryKey: false,
field: "state",
autoIncrement: false
}
}, {
tableName: "maintenance_plan",
comment: "",
indexes: []
});
dc.models.MaintenancePlan = MaintenancePlan;
return MaintenancePlan;
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const MaintenancePlan = sequelize.define("maintenancePlan", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "maintenance_plan_id_uindex"
},
missionName: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "任务名称",
primaryKey: false,
field: "mission_name",
autoIncrement: false
},
remark: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "备注",
primaryKey: false,
field: "remark",
autoIncrement: false
},
reason: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "操作/故障原因",
primaryKey: false,
field: "reason",
autoIncrement: false
},
planFinishTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "计划完成时间",
primaryKey: false,
field: "plan_finish_time",
autoIncrement: false
},
actualFinishTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "实际完成时间\n",
primaryKey: false,
field: "actual_finish_time",
autoIncrement: false
},
type: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "分类 period 周期 / temp 临时",
primaryKey: false,
field: "type",
autoIncrement: false
},
state: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "完成状态 unfinished 未完成 / underway 进行中 / completed 已完成 / suspend 挂起暂停 / inspected 已检查",
primaryKey: false,
field: "state",
autoIncrement: false
},
recordId: {
type: DataTypes.ARRAY(DataTypes.INTEGER),
allowNull: true,
defaultValue: null,
comment: "响应记录id",
primaryKey: false,
field: "record_id",
autoIncrement: false
}
}, {
tableName: "maintenance_plan",
comment: "",
indexes: []
});
dc.models.MaintenancePlan = MaintenancePlan;
return MaintenancePlan;
};

157
api/app/lib/models/maintenance_record.js

@ -3,78 +3,87 @@
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const MaintenanceRecord = sequelize.define("maintenanceRecord", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "maintenance_record_id_uindex"
},
sketch: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "简述",
primaryKey: false,
field: "sketch",
autoIncrement: false
},
occurrenceTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "发生时间",
primaryKey: false,
field: "occurrence_time",
autoIncrement: false
},
solvingTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "解决时间",
primaryKey: false,
field: "solving_time",
autoIncrement: false
},
interruptDuration: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: "中断时长 / 秒",
primaryKey: false,
field: "interrupt_duration",
autoIncrement: false
},
type: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "故障类型",
primaryKey: false,
field: "type",
autoIncrement: false
},
record: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "故障记录",
primaryKey: false,
field: "record",
autoIncrement: false
}
}, {
tableName: "maintenance_record",
comment: "",
indexes: []
});
dc.models.MaintenanceRecord = MaintenanceRecord;
return MaintenanceRecord;
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const MaintenanceRecord = sequelize.define("maintenanceRecord", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "maintenance_record_id_uindex"
},
sketch: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "简述",
primaryKey: false,
field: "sketch",
autoIncrement: false
},
occurrenceTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "发生时间",
primaryKey: false,
field: "occurrence_time",
autoIncrement: false
},
solvingTime: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: "解决时间",
primaryKey: false,
field: "solving_time",
autoIncrement: false
},
interruptDuration: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: "中断时长 / 秒",
primaryKey: false,
field: "interrupt_duration",
autoIncrement: false
},
type: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "故障类型",
primaryKey: false,
field: "type",
autoIncrement: false
},
record: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "故障记录",
primaryKey: false,
field: "record",
autoIncrement: false
},
files: {
type: DataTypes.JSONB,
allowNull: true,
defaultValue: null,
comment: "文件",
primaryKey: false,
field: "files",
autoIncrement: false
},
}, {
tableName: "maintenance_record",
comment: "",
indexes: []
});
dc.models.MaintenanceRecord = MaintenanceRecord;
return MaintenanceRecord;
};

4
api/app/lib/routes/record/index.js

@ -12,4 +12,8 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['DEL/record/:id'] = { content: '删除服务记录', visible: true };
router.del('/record/:id', record.delRecord);
app.fs.api.logAttr['GET/respond-record'] = { content: '获取响应记录数据', visible: true };
router.get('/respond-record', record.respondRecord);
};

14
script/0.29/schema/update_maintenance_plan.sql

@ -0,0 +1,14 @@
alter table maintenance_plan
add record_id integer[];
comment on column maintenance_plan.record_id is '响应记录id';
alter table maintenance_record
add files jsonb;
comment on column maintenance_record.files is '文件';

84
web/client/src/sections/means/containers/devOpsStandard.jsx

@ -3,12 +3,15 @@ import { connect } from 'react-redux';
import { Input, Button, Tree, Modal, Table, Upload, Pagination, Popconfirm } from '@douyinfe/semi-ui';
import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle, IconSearch } from '@douyinfe/semi-icons';
import SimpleBar from 'simplebar-react';
import PerfectScrollbar from "perfect-scrollbar";
import FileModal from '../components/fileModal';
import moment from 'moment';
import './style.less'
let itemList
let folderList
let tableList
const Rest = (props) => {
const { dispatch, actions, user, qiniu, loading, clientHeight, overallProjectId, apiRoot } = props
const { install, means } = actions
@ -44,8 +47,42 @@ const Rest = (props) => {
}))
// setPepProjectId(data[0]?.pepProjectId)
fileList(null)
const domItem = document.getElementById("itemList");
if (domItem) {
itemList = new PerfectScrollbar("#itemList", {
suppressScrollX: true,
});
}
const domFolder = document.getElementById("folderList");
if (domFolder) {
folderList = new PerfectScrollbar("#folderList", {
suppressScrollX: true,
});
}
const domTable = document.getElementById("tableList");
if (domTable) {
tableList = new PerfectScrollbar("#tableList", {
suppressScrollX: true,
});
}
}, [])
useEffect(() => {
const domItem = document.getElementById("itemList");
if (domItem && itemList) {
itemList.update();
}
const domFolder = document.getElementById("folderList");
if (domFolder && folderList) {
folderList.update();
}
const domTable = document.getElementById("tableList");
if (domTable && tableList) {
tableList.update();
}
})
useEffect(() => {
let data
if (overallProjectId) {
@ -236,29 +273,6 @@ const Rest = (props) => {
}
},
]
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
tags: ['nice', 'developer'],
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
tags: ['loser'],
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sydney No. 1 Lake Park',
tags: ['cool', 'teacher'],
},
];
const preview = (url) => {
let link = encodeURI(`${qiniu}/${url}`)
@ -278,7 +292,8 @@ const Rest = (props) => {
<div style={{ width: 200, height: '100%', padding: '16px 10px', boxShadow: '0 0 4px 2px #0000000d' }}>
<Input placeholder='请输入项目名称' value={projectSearch} onChange={v => setProjectSearch(v)} />
<SimpleBar style={{ height: 'calc(100% - 24px', }} forceVisible="y" >
{/* <SimpleBar style={{ height: 'calc(100% - 24px', }} forceVisible="y" > */}
<div id='itemList' style={{ height: 'calc(100% - 24px', }}>
<div style={{ cursor: 'pointer', background: pepProjectId == null ? 'rgb(15 126 251 / 16%)' : '', width: 180, height: 30, display: 'flex', alignItems: 'center' }}
onClick={() => {
setPepProjectId(null)
@ -302,7 +317,9 @@ const Rest = (props) => {
</div>
})}
</SimpleBar>
</div>
{/* </SimpleBar> */}
</div>
<div style={{ height: '100%', display: 'flex', flex: 1 }}>
@ -330,7 +347,8 @@ const Rest = (props) => {
}}
/> : ""
}
<SimpleBar style={{ height: 'calc(100% - 70px' }} forceVisible='y' >
{/* <SimpleBar style={{ height: 'calc(100% - 70px' }} forceVisible='y' > */}
<div id='folderList' style={{ height: 'calc(100% - 70px', }}>
<Tree
treeData={treeData}
defaultExpandAll
@ -341,7 +359,10 @@ const Rest = (props) => {
setFileSearch('')
}}
/>
</SimpleBar>
</div>
{/* </SimpleBar> */}
</div>
{/* 表格 */}
@ -428,7 +449,9 @@ const Rest = (props) => {
}
</div>
<SimpleBar style={{ height: 'calc(100% - 100px' }} forceVisible='y' >
{/* <SimpleBar style={{ height: 'calc(100% - 100px' }} forceVisible='y' > */}
<div id='tableList' style={{ height: 'calc(100% - 100px', }}>
<Table
style={{ width: 'calc(100% - 10px)', marginLeft: 10 }}
columns={column}
@ -463,7 +486,8 @@ const Rest = (props) => {
// },
// }}
/>
</SimpleBar>
</div>
{/* </SimpleBar> */}
{count > 0 ? <div style={{ display: 'flex', width: '100%', justifyContent: 'flex-end', alignItems: 'center', marginTop: 12 }}>
<span style={{ lineHeight: "30px", fontSize: 13 }}>

60
web/client/src/sections/means/containers/faultInformation.jsx

@ -3,12 +3,15 @@ import { connect } from 'react-redux';
import { Input, Button, Tree, Modal, Table, Upload, Pagination, Popconfirm } from '@douyinfe/semi-ui';
import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle, IconSearch } from '@douyinfe/semi-icons';
import SimpleBar from 'simplebar-react';
import PerfectScrollbar from "perfect-scrollbar";
import FileModal from '../components/fileModal';
import moment from 'moment';
import './style.less'
let itemList
let folderList
let tableList
const Rest = (props) => {
const { dispatch, actions, user, qiniu, loading, clientHeight, overallProjectId, apiRoot } = props
const { install, means } = actions
@ -43,8 +46,42 @@ const Rest = (props) => {
}))
// setPepProjectId(data[0]?.pepProjectId)
fileList(null)
const domItem = document.getElementById("itemList");
if (domItem) {
itemList = new PerfectScrollbar("#itemList", {
suppressScrollX: true,
});
}
const domFolder = document.getElementById("folderList");
if (domFolder) {
folderList = new PerfectScrollbar("#folderList", {
suppressScrollX: true,
});
}
const domTable = document.getElementById("tableList");
if (domTable) {
tableList = new PerfectScrollbar("#tableList", {
suppressScrollX: true,
});
}
}, [])
useEffect(() => {
const domItem = document.getElementById("itemList");
if (domItem && itemList) {
itemList.update();
}
const domFolder = document.getElementById("folderList");
if (domFolder && folderList) {
folderList.update();
}
const domTable = document.getElementById("tableList");
if (domTable && tableList) {
tableList.update();
}
})
useEffect(() => {
let data
if (overallProjectId) {
@ -277,7 +314,9 @@ const Rest = (props) => {
<div style={{ width: 200, height: '100%', padding: '16px 10px', boxShadow: '0 0 4px 2px #0000000d' }}>
<Input placeholder='请输入项目名称' value={projectSearch} onChange={v => setProjectSearch(v)} />
<SimpleBar style={{ height: 'calc(100% - 24px', }} forceVisible="y" >
{/* <SimpleBar style={{ height: 'calc(100% - 24px', }} forceVisible="y" > */}
<div id='itemList' style={{ height: 'calc(100% - 24px', }}>
<div style={{ cursor: 'pointer', background: pepProjectId == null ? 'rgb(15 126 251 / 16%)' : '', width: 180, height: 30, display: 'flex', alignItems: 'center' }}
onClick={() => {
setPepProjectId(null)
@ -301,7 +340,8 @@ const Rest = (props) => {
</div>
})}
</SimpleBar>
{/* </SimpleBar> */}
</div>
</div>
<div style={{ height: '100%', display: 'flex', flex: 1 }}>
@ -329,7 +369,9 @@ const Rest = (props) => {
}}
/> : ""
}
<SimpleBar style={{ height: 'calc(100% - 70px' }} forceVisible='y' >
{/* <SimpleBar style={{ height: 'calc(100% - 70px' }} forceVisible='y' > */}
<div id='folderList' style={{ height: 'calc(100% - 70px', }}>
<Tree
treeData={treeData}
defaultExpandAll
@ -340,8 +382,9 @@ const Rest = (props) => {
setFileSearch('')
}}
/>
</SimpleBar>
{/* </SimpleBar> */}
</div>
</div>
{/* 表格 */}
<div style={{
@ -427,7 +470,9 @@ const Rest = (props) => {
}
</div>
<SimpleBar style={{ height: 'calc(100% - 100px' }} forceVisible='y' >
{/* <SimpleBar style={{ height: 'calc(100% - 100px' }} forceVisible='y' > */}
<div id='tableList' style={{ height: 'calc(100% - 100px', }}>
<Table
style={{ width: 'calc(100% - 10px)', marginLeft: 10 }}
columns={column}
@ -462,7 +507,8 @@ const Rest = (props) => {
// },
// }}
/>
</SimpleBar>
{/* </SimpleBar> */}
</div>
{count > 0 ? <div style={{ display: 'flex', width: '100%', justifyContent: 'flex-end', alignItems: 'center', marginTop: 12 }}>
<span style={{ lineHeight: "30px", fontSize: 13 }}>

65
web/client/src/sections/means/containers/projectMeans.jsx

@ -3,14 +3,17 @@ import { connect } from 'react-redux';
import { Input, Button, Tree, Modal, Table, Upload, Pagination, Popconfirm } from '@douyinfe/semi-ui';
import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle, IconSearch } from '@douyinfe/semi-icons';
import SimpleBar from 'simplebar-react';
import PerfectScrollbar from "perfect-scrollbar";
import FileModal from '../components/fileModal';
import moment from 'moment';
import './style.less'
let itemList
let folderList
let tableList
const Rest = (props) => {
const { dispatch, actions, user, qiniu, loading, clientHeight, overallProjectId ,apiRoot} = props
const { dispatch, actions, user, qiniu, loading, clientHeight, overallProjectId, apiRoot } = props
const { install, means } = actions
const [pomsList, setPomsList] = useState([]); //
const [showPomsList, setShowPomsList] = useState([]); //
@ -44,8 +47,43 @@ const Rest = (props) => {
}
}))
fileList(null)
const domItem = document.getElementById("itemList");
if (domItem) {
itemList = new PerfectScrollbar("#itemList", {
suppressScrollX: true,
});
}
const domFolder = document.getElementById("folderList");
if (domFolder) {
folderList = new PerfectScrollbar("#folderList", {
suppressScrollX: true,
});
}
const domTable = document.getElementById("tableList");
if (domTable) {
tableList = new PerfectScrollbar("#tableList", {
suppressScrollX: true,
});
}
}, [])
useEffect(() => {
const domItem = document.getElementById("itemList");
if (domItem && itemList) {
itemList.update();
}
const domFolder = document.getElementById("folderList");
if (domFolder && folderList) {
folderList.update();
}
const domTable = document.getElementById("tableList");
if (domTable && tableList) {
tableList.update();
}
})
useEffect(() => {
let data
if (overallProjectId) {
@ -278,7 +316,8 @@ const Rest = (props) => {
<div style={{ width: 200, height: '100%', padding: '16px 10px', boxShadow: '0 0 4px 2px #0000000d' }}>
<Input placeholder='请输入项目名称' value={projectSearch} onChange={v => setProjectSearch(v)} />
<SimpleBar style={{ height: 'calc(100% - 24px', }} forceVisible="y" >
{/* <SimpleBar style={{ height: 'calc(100% - 24px', }} forceVisible="y" > */}
<div id='itemList' style={{ height: 'calc(100% - 24px', }}>
{showPomsList?.map(v => {
return <div key={'pepProjectId' + v.pepProjectId} title={v.pepProjectName} style={{ cursor: 'pointer', background: v.pepProjectId == pepProjectId ? 'rgb(15 126 251 / 16%)' : '', width: 180, height: 30, display: 'flex', alignItems: 'center' }}
onClick={() => {
@ -292,7 +331,8 @@ const Rest = (props) => {
</div>
})}
</SimpleBar>
{/* </SimpleBar> */}
</div>
</div>
<div style={{ height: '100%', display: 'flex', flex: 1 }}>
@ -320,7 +360,9 @@ const Rest = (props) => {
}}
/> : ""
}
<SimpleBar style={{ height: 'calc(100% - 70px' }} forceVisible='y' >
{/* <SimpleBar style={{ height: 'calc(100% - 70px' }} forceVisible='y' > */}
<div id='folderList' style={{ height: 'calc(100% - 70px', }}>
<Tree
treeData={treeData}
defaultExpandAll
@ -331,8 +373,8 @@ const Rest = (props) => {
setFileSearch('')
}}
/>
</SimpleBar>
{/* </SimpleBar> */}
</div>
</div>
{/* 表格 */}
<div style={{
@ -418,7 +460,9 @@ const Rest = (props) => {
}
</div>
<SimpleBar style={{ height: 'calc(100% - 100px' }} forceVisible='y' >
{/* <SimpleBar className='SimpleBar' style={{ height: 'calc(100% - 100px', border: 0 }} forceVisible='y' > */}
<div id='tableList' style={{ height: 'calc(100% - 100px', border: 0 }}>
<Table
style={{ width: 'calc(100% - 10px)', marginLeft: 10 }}
columns={column}
@ -453,7 +497,8 @@ const Rest = (props) => {
// },
// }}
/>
</SimpleBar>
</div>
{/* </SimpleBar> */}
{count > 0 ? <div style={{ display: 'flex', width: '100%', justifyContent: 'flex-end', alignItems: 'center', marginTop: 12 }}>
<span style={{ lineHeight: "30px", fontSize: 13 }}>
@ -559,7 +604,7 @@ function mapStateToProps (state) {
// socket: webSocket.socket
clientHeight: global.clientHeight,
qiniu: global.qiniu?.domain,
apiRoot:global.apiRoot
apiRoot: global.apiRoot
};
}

61
web/client/src/sections/means/containers/repairFQA.jsx

@ -3,12 +3,15 @@ import { connect } from 'react-redux';
import { Input, Button, Tree, Modal, Table, Upload, Pagination, Popconfirm } from '@douyinfe/semi-ui';
import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle, IconSearch } from '@douyinfe/semi-icons';
import SimpleBar from 'simplebar-react';
import PerfectScrollbar from "perfect-scrollbar";
import FileModal from '../components/fileModal';
import moment from 'moment';
import './style.less'
let itemList
let folderList
let tableList
const Rest = (props) => {
const { dispatch, actions, user, qiniu, loading, clientHeight, overallProjectId, apiRoot } = props
const { install, means } = actions
@ -43,8 +46,42 @@ const Rest = (props) => {
}))
// setPepProjectId(data[0]?.pepProjectId)
fileList(null)
const domItem = document.getElementById("itemList");
if (domItem) {
itemList = new PerfectScrollbar("#itemList", {
suppressScrollX: true,
});
}
const domFolder = document.getElementById("folderList");
if (domFolder) {
folderList = new PerfectScrollbar("#folderList", {
suppressScrollX: true,
});
}
const domTable = document.getElementById("tableList");
if (domTable) {
tableList = new PerfectScrollbar("#tableList", {
suppressScrollX: true,
});
}
}, [])
useEffect(() => {
const domItem = document.getElementById("itemList");
if (domItem && itemList) {
itemList.update();
}
const domFolder = document.getElementById("folderList");
if (domFolder && folderList) {
folderList.update();
}
const domTable = document.getElementById("tableList");
if (domTable && tableList) {
tableList.update();
}
})
useEffect(() => {
let data
if (overallProjectId) {
@ -277,7 +314,9 @@ const Rest = (props) => {
<div style={{ width: 200, height: '100%', padding: '16px 10px', boxShadow: '0 0 4px 2px #0000000d' }}>
<Input placeholder='请输入项目名称' value={projectSearch} onChange={v => setProjectSearch(v)} />
<SimpleBar style={{ height: 'calc(100% - 24px', }} forceVisible="y" >
{/* <SimpleBar style={{ height: 'calc(100% - 24px', }} forceVisible="y" > */}
<div id='itemList' style={{ height: 'calc(100% - 24px', }}>
<div style={{ cursor: 'pointer', background: pepProjectId == null ? 'rgb(15 126 251 / 16%)' : '', width: 180, height: 30, display: 'flex', alignItems: 'center' }}
onClick={() => {
setPepProjectId(null)
@ -302,7 +341,8 @@ const Rest = (props) => {
</div>
})}
</SimpleBar>
{/* </SimpleBar> */}
</div>
</div>
<div style={{ height: '100%', display: 'flex', flex: 1 }}>
@ -330,7 +370,9 @@ const Rest = (props) => {
}}
/> : ""
}
<SimpleBar style={{ height: 'calc(100% - 70px' }} forceVisible='y' >
{/* <SimpleBar style={{ height: 'calc(100% - 70px' }} forceVisible='y' > */}
<div id='folderList' style={{ height: 'calc(100% - 70px', }}>
<Tree
treeData={treeData}
defaultExpandAll
@ -341,8 +383,8 @@ const Rest = (props) => {
setFileSearch('')
}}
/>
</SimpleBar>
{/* </SimpleBar> */}
</div>
</div>
{/* 表格 */}
<div style={{
@ -428,7 +470,9 @@ const Rest = (props) => {
}
</div>
<SimpleBar style={{ height: 'calc(100% - 100px' }} forceVisible='y' >
{/* <SimpleBar style={{ height: 'calc(100% - 100px' }} forceVisible='y' > */}
<div id='tableList' style={{ height: 'calc(100% - 100px', }}>
<Table
style={{ width: 'calc(100% - 10px)', marginLeft: 10 }}
columns={column}
@ -463,7 +507,8 @@ const Rest = (props) => {
// },
// }}
/>
</SimpleBar>
</div>
{/* </SimpleBar> */}
{count > 0 ? <div style={{ display: 'flex', width: '100%', justifyContent: 'flex-end', alignItems: 'center', marginTop: 12 }}>
<span style={{ lineHeight: "30px", fontSize: 13 }}>

2
web/client/src/sections/means/containers/style.less

@ -6,4 +6,4 @@
.tip{
display: inline-block;
}
}
}

24
web/client/src/sections/means/nav-item.jsx

@ -10,36 +10,36 @@ export function getNavItem (user, dispatch) {
icon: <IconCode />,
items: [
{
itemKey: 'projectMeans',
itemKey: 'project',
text: '项目资料',
icon: <iconpark-icon style={{ width: 20, height: 20 }} name="iconjianshezhong"></iconpark-icon>,
to: '/means/projectMeans/projectMeans1',
to: '/means/project/projectMeans',
items: [{
itemKey: 'projectMeans1', to: '/means/projectMeans/projectMeans1', text: '项目资料'
itemKey: 'projectMeans', to: '/means/project/projectMeans', text: '项目资料'
}]
}, {
itemKey: 'repairFQA',
itemKey: 'repair',
text: '维修FAQ',
icon: <iconpark-icon style={{ width: 20, height: 20 }} name="iconjianshezhong"></iconpark-icon>,
to: '/means/repairFQA/repairFQA1',
to: '/means/repair/repairFQA',
items: [{
itemKey: 'repairFQA1', to: '/means/repairFQA/repairFQA1', text: '维修FAQ'
itemKey: 'repairFQA', to: '/means/repair/repairFQA', text: '维修FAQ'
}]
}, {
itemKey: 'faultInformation',
itemKey: 'fault',
text: '故障资料',
icon: <iconpark-icon style={{ width: 20, height: 20 }} name="iconjianshezhong"></iconpark-icon>,
to: '/means/faultInformation/faultInformation1',
to: '/means/fault/faultInformation',
items: [{
itemKey: 'faultInformation1', to: '/means/faultInformation/faultInformation1', text: '故障资料'
itemKey: 'faultInformation', to: '/means/fault/faultInformation', text: '故障资料'
}]
}, {
itemKey: 'devOpsStandard',
itemKey: 'standard',
text: '运维规范',
icon: <iconpark-icon style={{ width: 20, height: 20 }} name="iconjianshezhong"></iconpark-icon>,
to: '/means/devOpsStandard/devOpsStandard1',
to: '/means/standard/devOpsStandard',
items: [{
itemKey: 'devOpsStandard1', to: '/means/devOpsStandard/devOpsStandard1', text: '运维规范'
itemKey: 'devOpsStandard', to: '/means/standard/devOpsStandard', text: '运维规范'
}]
}
]

32
web/client/src/sections/means/routes.js

@ -8,42 +8,42 @@ export default [{
breadcrumb: '资料',
// 不设置 component 则面包屑禁止跳转
childRoutes: [{
path: '/projectMeans',
key: 'projectMeans',
path: '/project',
key: 'project',
breadcrumb: '项目资料',
childRoutes: [{
path: '/projectMeans1',
key: 'projectMeans1',
path: '/projectMeans',
key: 'projectMeans',
component: ProjectMeans,
breadcrumb: '项目资料',
}]
}, {
path: '/repairFQA',
key: 'repairFQA',
path: '/repair',
key: 'repair',
breadcrumb: '维修FAQ',
childRoutes: [{
path: '/repairFQA1',
key: 'repairFQA1',
path: '/repairFQA',
key: 'repairFQA',
component: RepairFQA,
breadcrumb: '维修FAQ',
}]
}, {
path: '/faultInformation',
key: 'faultInformation',
path: '/fault',
key: 'fault',
breadcrumb: '故障资料',
childRoutes: [{
path: '/faultInformation1',
key: 'faultInformation1',
path: '/faultInformation',
key: 'faultInformation',
component: FaultInformation,
breadcrumb: '故障资料',
}]
}, {
path: '/devOpsStandard',
key: 'devOpsStandard',
path: '/standard',
key: 'standard',
breadcrumb: '运维规范',
childRoutes: [{
path: '/devOpsStandard1',
key: 'devOpsStandard1',
path: '/devOpsStandard',
key: 'devOpsStandard',
component: DevOpsStandard,
breadcrumb: '运维规范',
}]

4
web/client/src/sections/means/style.less

@ -4,4 +4,6 @@
#example:hover {
color: yellowgreen;
}
}

20
web/client/src/sections/service/actions/record.js

@ -17,6 +17,16 @@ export function getRecord(query) { //获取服务记录
});
}
export function respondRecord() { //获取服务记录
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_RESPOND_RECORD',
url: `${ApiTable.respondRecord}`,
msg: { option: '获取响应记录数据' },
});
}
export function addRecord(query) { //新增服务记录和编辑
let msg = ''
@ -29,8 +39,11 @@ export function addRecord(query) { //新增服务记录和编辑
data: query,
actionType: 'ADD_RECORD',
url: `${ApiTable.addRecord}`,
msg: { option: msg }
msg: { option: msg },
reducer: {
name: "addRecord",
params: { noClear: true }
}
});
}
export function calculability(query) {//计算系统可用性
@ -59,4 +72,5 @@ export function delRecord(query) {//删除服务记录
});
}
}

172
web/client/src/sections/service/components/cycAddmodal.jsx

@ -1,89 +1,107 @@
import React,{useState,useEffect,useRef} from 'react'
import React, { useState, useEffect, useRef } from 'react'
import { connect } from 'react-redux';
import { Button,Table,Modal,Form } from '@douyinfe/semi-ui';
import moment from 'moment'
import { Button, Table, Modal, Form } from '@douyinfe/semi-ui';
const AddModal=(props)=>{
const {visible,onClose,recordRow,pepList,actions,dispatch}=props
const{service}=actions
const api = useRef();
useEffect(()=>{
},[])
//
const okHandler=()=>{
//api.current.setValues({'manger':recordRow?.maintenancePlanExecuteUsers.map((item)=>{return item.id})},)
api.current.validate().then((res)=>{
res.manger
recordRow?.maintenancePlanExecuteUsers
const query={
id:recordRow?.id,
actualFinishTime:res.realityTime,
planFinishTime:res.planTime,
remark:res.notes,
state:res.status,
type:'period',
missionName:res.taskName,
manger:res.manger,
msg:recordRow?'编辑周期性计划':'添加周期性计划'
}
dispatch(service.editMaintenancePlan(query)).then((res)=>{
if(res.success) onClose() ; api.current.reset()
const AddModal = (props) => {
const { visible, onClose, recordRow, pepList, actions, dispatch, respondRecordData } = props
const { service } = actions
const api = useRef();
const [selectValue, setSelectValue] = useState([])
})
})
}
return (<div>
<Modal visible={visible} onCancel={()=>{onClose()}} title={recordRow?'周期性计划编辑':'周期性计划添加'}
onOk={okHandler}
>
<Form
initValues={{'taskName':recordRow?.missionName,
'manger':recordRow?.maintenancePlanExecuteUsers.map((item)=>{return item.pepUserId}),
'reason':recordRow?.reason,
'status':recordRow?.state,
'notes':recordRow?.remark,
'planTime':recordRow?.planFinishTime,
'realityTime':recordRow?.actualFinishTime}}
useEffect(() => {
}, [])
//
const okHandler = () => {
api.current.validate().then((res) => {
console.log(111, res, respondRecordData?.map(v => ({ value: v.id, label: v.sketch })));
const query = {
id: recordRow?.id,
actualFinishTime: res.realityTime,
planFinishTime: res.planTime,
remark: res.notes,
state: res.status,
type: 'period',
missionName: res.taskName,
manger: res.manger,
recordId: res.recordId,
msg: recordRow ? '编辑周期性计划' : '添加周期性计划'
}
dispatch(service.editMaintenancePlan(query)).then((res) => {
if (res.success) onClose(); api.current.reset()
getFormApi={formApi => api.current = formApi}
labelCol={{ span: 6 }}
labelPosition='left'
>
<Form.Input field='taskName' label='任务名称:' maxLength={30} rules={[
{ required: true, message: '请输入任务名称' },
]} ></Form.Input>
<Form.Select field='manger' label='责任人' rules={[{ required: true, message: '请输入责任人' }]} trigger='blur' style={{ width:'100%' }}
multiple filter>
{pepList?.map((item)=>{return ( <Form.Select.OptGroup label={item.name}>
{item.users.map((item1)=>{
return <Form.Select.Option value={item1.id} label={item1.name}></Form.Select.Option>
})}
</Form.Select.OptGroup> )})}
</Form.Select>
<Form.Select label='完成情况'style={{ width: 200 }} field='status'>
<Form.Select.Option value='未完成'>未完成</Form.Select.Option>
<Form.Select.Option value='进行中'>进行中</Form.Select.Option>
<Form.Select.Option value='已完成'>已完成</Form.Select.Option>
<Form.Select.Option value='挂起'>挂起</Form.Select.Option>
</Form.Select>
<Form.TextArea label='备注' field='notes' placeholder='故障发生原因及解决方案'></Form.TextArea>
<Form.DatePicker label='计划完成时间:' field='planTime' rules={[{ required: true, message: '请选择计划完成时间' },]}></Form.DatePicker>
<Form.DatePicker label='实际完成时间:' field='realityTime'></Form.DatePicker>
</Form>
</Modal>
})
</div>)
})
}
return (<div>
<Modal visible={visible} onCancel={() => { onClose() }} title={recordRow ? '周期性计划编辑' : '周期性计划添加'}
onOk={okHandler}
>
<Form
initValues={{
'taskName': recordRow?.missionName,
'manger': recordRow?.maintenancePlanExecuteUsers.map((item) => { return item.pepUserId }),
'reason': recordRow?.reason,
'status': recordRow?.state,
'notes': recordRow?.remark,
'planTime': recordRow?.planFinishTime,
'realityTime': recordRow?.actualFinishTime,
'recordId': recordRow?.recordId || [],
}}
getFormApi={formApi => api.current = formApi}
labelCol={{ span: 6 }}
labelPosition='left'
>
<Form.Input field='taskName' label='任务名称:' maxLength={30} rules={[
{ required: true, message: '请输入任务名称' },
]} ></Form.Input>
<Form.Select field='manger' label='责任人' rules={[{ required: true, message: '请输入责任人' }]} trigger='blur' style={{ width: '100%' }}
multiple filter>
{pepList?.map((item) => {
return (<Form.Select.OptGroup label={item.name}>
{item.users.map((item1) => {
return <Form.Select.Option value={item1.id} label={item1.name}></Form.Select.Option>
})}
</Form.Select.OptGroup>)
})}
</Form.Select>
<Form.Select label='完成情况' style={{ width: 200 }} field='status'>
<Form.Select.Option value='未完成'>未完成</Form.Select.Option>
<Form.Select.Option value='进行中'>进行中</Form.Select.Option>
<Form.Select.Option value='已完成'>已完成</Form.Select.Option>
<Form.Select.Option value='挂起'>挂起</Form.Select.Option>
</Form.Select>
<Form.TextArea label='备注' field='notes' placeholder='故障发生原因及解决方案'></Form.TextArea>
<Form.DatePicker label='计划完成时间:' field='planTime' rules={[{ required: true, message: '请选择计划完成时间' },]}></Form.DatePicker>
<Form.DatePicker label='实际完成时间:' field='realityTime'></Form.DatePicker>
<Form.Select field='recordId' label='响应关联:' style={{ width: '100%' }}
dropdownStyle={{ width: 400 }}
// optionList={respondRecordData.map(v => ({ value: v.id, label: `${v.sketch} / ${moment(v.occurrenceTime).format('YYYY-MM-DD')}` }))}
multiple filter
>
{respondRecordData?.map((v) => {
return <Form.Select.Option value={v.id} label={`${v.sketch} / ${moment(v.occurrenceTime).format('YYYY-MM-DD')}`}>
</Form.Select.Option>
})}
</Form.Select>
</Form>
</Modal>
</div>)
}
function mapStateToProps (state) {
const { global } = state;
return {
actions: global.actions,
};
}
const { global } = state;
return {
actions: global.actions,
};
}
export default connect(mapStateToProps)(AddModal)

87
web/client/src/sections/service/components/planAddmodal.jsx

@ -0,0 +1,87 @@
import React, { useState, useEffect, useRef } from 'react'
import { connect } from 'react-redux';
import moment from 'moment'
import { Button, Table, Modal, Form } from '@douyinfe/semi-ui';
const PlanAddmodal = (props) => {
const { visible, onClose, recordRow, actions, dispatch } = props
const { service, install } = actions
const [pepList, setPepList] = useState([])//
const api = useRef();
const [selectValue, setSelectValue] = useState([])
useEffect(() => {
dispatch(install.getOrganizationDeps()).then((res) => {//(PEP)
setPepList(res.payload.data)
})
}, [])
//
const okHandler = () => {
api.current.validate().then((res) => {
const query = {
actualFinishTime: res.realityTime,
planFinishTime: res.planTime,
remark: res.notes,
state: res.status,
type: 'period',
missionName: res.taskName,
manger: res.manger,
recordId: [recordRow.id],
msg: '添加周期性计划'
}
dispatch(service.editMaintenancePlan(query)).then((res) => {
if (res.success) onClose(); api.current.reset()
})
})
}
return (<div>
<Modal visible={visible} onCancel={() => { onClose() }} title={'添加周期性计划'}
onOk={okHandler}
>
<Form
getFormApi={formApi => api.current = formApi}
labelCol={{ span: 6 }}
labelPosition='left'
>
<Form.Input field='taskName' label='任务名称:' maxLength={30} rules={[
{ required: true, message: '请输入任务名称' },
]} ></Form.Input>
<Form.Select field='manger' label='责任人' rules={[{ required: true, message: '请输入责任人' }]} trigger='blur' style={{ width: '100%' }}
multiple filter>
{pepList?.map((item) => {
return (<Form.Select.OptGroup label={item.name}>
{item.users.map((item1) => {
return <Form.Select.Option value={item1.id} label={item1.name}></Form.Select.Option>
})}
</Form.Select.OptGroup>)
})}
</Form.Select>
<Form.Select label='完成情况' style={{ width: 200 }} field='status'>
<Form.Select.Option value='未完成'>未完成</Form.Select.Option>
<Form.Select.Option value='进行中'>进行中</Form.Select.Option>
<Form.Select.Option value='已完成'>已完成</Form.Select.Option>
<Form.Select.Option value='挂起'>挂起</Form.Select.Option>
</Form.Select>
<Form.TextArea label='备注' field='notes' placeholder='故障发生原因及解决方案'></Form.TextArea>
<Form.DatePicker label='计划完成时间:' field='planTime' rules={[{ required: true, message: '请选择计划完成时间' },]}></Form.DatePicker>
<Form.DatePicker label='实际完成时间:' field='realityTime'></Form.DatePicker>
</Form>
</Modal>
</div>)
}
function mapStateToProps (state) {
const { global } = state;
return {
actions: global.actions,
};
}
export default connect(mapStateToProps)(PlanAddmodal)

282
web/client/src/sections/service/components/recordModal.jsx

@ -1,144 +1,178 @@
'use strict';
import React, { useEffect,useState,useRef } from 'react';
import { Modal,Form,DatePicker,useFormApi,actions,Button } from '@douyinfe/semi-ui';
import React, { useEffect, useState, useRef } from 'react';
import { Modal, Form, DatePicker, Upload, actions, Button } from '@douyinfe/semi-ui';
import { connect } from 'react-redux';
import moment from 'moment'
import { IconDeleteStroked, IconEditStroked, IconUpload, IconAlertCircle, IconSearch } from '@douyinfe/semi-icons';
const RecordModal =(props)=>{
const{visible,onClose,dispatch,recordRow,pepList,actions}=props
const [startTime,setStartTime]=useState('')
const [endTime,setEndTime]=useState('')
const FormApi = useRef();
const{service} =actions
// let t=0//
// let h=0//
// let s=0//
const RecordModal = (props) => {
const { visible, onClose, dispatch, recordRow, pepList, actions, addRecord, qiniu, apiRoot } = props
const [startTime, setStartTime] = useState('')
const [endTime, setEndTime] = useState('')
const [uploadData, setUploadData] = useState({})
const FormApi = useRef();
const { service } = actions
// let t=0//
// let h=0//
// let s=0//
// console.log('endTimex',endTime)
useEffect(()=>{
setEndTime(recordRow?.solvingTime)
setStartTime(recordRow?.occurrenceTime)
console.log('recordRow',recordRow)
useEffect(() => {
setEndTime(recordRow?.solvingTime)
setStartTime(recordRow?.occurrenceTime)
console.log('recordRow', recordRow)
},[recordRow])
const cancelHandler=()=>{
onClose()
setStartTime('')
setEndTime('')
}, [recordRow])
const cancelHandler = () => {
onClose()
setStartTime('')
setEndTime('')
}
const okHandler=()=>{
FormApi.current.validate().then((res)=>{
console.log('recordRow',res)
const editVal={
id:recordRow?.id,
solvingTime:res.endTime,
occurrencTime:res.startTime,
sketch:res.name,
record:res.record,
settler:res.settler,
type:res.type,
msg:recordRow?'编辑服务记录':'添加服务记录'
}
dispatch(service.addRecord(editVal)).then(res => {
}
const okHandler = () => {
FormApi.current.validate().then((res) => {
console.log('recordRow', res)
const editVal = {
id: recordRow?.id,
solvingTime: res.endTime,
occurrencTime: res.startTime,
sketch: res.name,
record: res.record,
settler: res.settler,
type: res.type,
msg: recordRow ? '编辑响应记录' : '添加响应记录',
files: [{ ...uploadData }]
}
dispatch(service.addRecord(editVal)).then(res => {
if (res.success) {
onClose()
FormApi.current.reset()
setStartTime('');setEndTime('')
onClose()
FormApi.current.reset()
setStartTime(''); setEndTime('')
}
})
})
}
return <Modal
title={recordRow?'编辑响应记录':'添加响应记录'}
visible={visible}
footer={
//recordRow?<Button onClick={cancelHandler}></Button>:
<div>
<Button onClick={cancelHandler}>取消</Button>
<Button theme='solid' type='primary' onClick={okHandler}>确定</Button>
</div>}
onCancel={cancelHandler}
onOk={okHandler}
>
<Form wrapperCol={{ span: 20 }}
initValues={{'name':recordRow?.sketch,
'startTime':recordRow?.occurrenceTime,
'endTime':recordRow?.solvingTime,
'settler':recordRow?.maintenanceRecordExecuteUsers.map((item)=>{return item.pepUserId}),
'type':recordRow?.type,
'record':recordRow?.record,
'breakTime':recordRow?parseInt(recordRow.interruptDuration/60/60/24)+'天'+
parseInt(recordRow.interruptDuration/60/60%24)+'时'+
parseInt(recordRow.interruptDuration/60%60)+'分':'0天0时0秒'
})
})
}
return <Modal
title={recordRow ? '编辑响应记录' : '添加响应记录'}
visible={visible}
footer={
//recordRow?<Button onClick={cancelHandler}></Button>:
<div>
<Button onClick={cancelHandler}>取消</Button>
<Button loading={addRecord} theme='solid' type='primary' onClick={okHandler}>确定</Button>
</div>}
onCancel={cancelHandler}
// onOk={okHandler}
>
<Form wrapperCol={{ span: 20 }}
initValues={{
'name': recordRow?.sketch,
'startTime': recordRow?.occurrenceTime,
'endTime': recordRow?.solvingTime,
'settler': recordRow?.maintenanceRecordExecuteUsers.map((item) => { return item.pepUserId }),
'type': recordRow?.type,
'record': recordRow?.record,
'breakTime': recordRow ? parseInt(recordRow.interruptDuration / 60 / 60 / 24) + '天' +
parseInt(recordRow.interruptDuration / 60 / 60 % 24) + '时' +
parseInt(recordRow.interruptDuration / 60 % 60) + '分' : '0天0时0秒'
}}
getFormApi={formApi => FormApi.current = formApi}
labelPosition='left'
labelAlign='right'>
<Form.Input field='name' label='故障简述:' trigger='blur'
placeholder='请输入故障简述' rules={[{ required: true, message: '请输入故障简述' }]} maxLength={30} />
<Form.DatePicker field='startTime' label='发生时间:' rules={[{ required: true, message: '请输入发生时间' }]}
type="dateTime" onChange={(e) => {
const seconds = (moment(endTime).format('x') - moment(e).format('x')) / 1000//
const tdd = e && endTime ? parseInt(seconds / 60 / 60 / 24) : 0//
const tdh = e && endTime ? parseInt(seconds / 60 / 60 % 24) : 0//
const tds = e && endTime ? parseInt(seconds / 60 % 60) : 0//
setStartTime(e)
FormApi.current.setValue('breakTime', `${tdd}${tdh}${tds}`)
}}
getFormApi={formApi => FormApi.current = formApi}
labelPosition='left'
labelAlign='right'>
<Form.Input field='name' label='故障简述:' trigger='blur'
placeholder='请输入故障简述' rules={[{ required: true, message:'请输入故障简述' }]} maxLength={30}/>
<Form.DatePicker field='startTime' label='发生时间:' rules={[{ required: true, message:'请输入发生时间' }]}
type="dateTime" onChange={(e)=>{
const seconds=(moment(endTime).format('x')-moment(e).format('x'))/1000//
const tdd=e&&endTime?parseInt(seconds/60/60/24):0//
const tdh=e&&endTime?parseInt(seconds/60/60%24):0//
const tds=e&&endTime?parseInt(seconds/60%60):0//
setStartTime(e)
FormApi.current.setValue('breakTime',`${tdd}${tdh}${tds}`)
}}
/>
<Form.DatePicker field='endTime' label='解决时间:' initValue={endTime} rules={[{ required: true, message:'请输入解决时间' }]}
type="dateTime" onChange={(e)=>{
const seconds=(moment(e).format('x')-moment(startTime).format('x'))/1000//
const tdd=e&&startTime?parseInt(seconds/60/60/24):0//
const tdh=e&&startTime?parseInt(seconds/60/60%24):0//
const tds=e&&startTime?parseInt(seconds/60%60):0//
setEndTime(e);//console.log('sss',moment(endTime-startTime).format('DDhhmm'))
FormApi.current.setValue('breakTime',`${tdd}${tdh}${tds}`)
/>
<Form.DatePicker field='endTime' label='解决时间:' initValue={endTime} rules={[{ required: true, message: '请输入解决时间' }]}
type="dateTime" onChange={(e) => {
const seconds = (moment(e).format('x') - moment(startTime).format('x')) / 1000//
const tdd = e && startTime ? parseInt(seconds / 60 / 60 / 24) : 0//
const tdh = e && startTime ? parseInt(seconds / 60 / 60 % 24) : 0//
const tds = e && startTime ? parseInt(seconds / 60 % 60) : 0//
setEndTime(e);//console.log('sss',moment(endTime-startTime).format('DDhhmm'))
FormApi.current.setValue('breakTime', `${tdd}${tdh}${tds}`)
}} />
<Form.Input field='breakTime' label='中断时间:' disabled/>
{/* 中断时间:{endTime&&startTime? <span style={{marginLeft:30}}>{`${tdd}天${tdh}时${tds}分`}</span>:recordRow?.interruptDuration} */}
<Form.Select field='settler' label='解决者:' trigger='blur' style={{ width:'100%' }}
filter
rules={[{ required: true, message:'请输入解决者' }]} multiple>
{pepList?.map((item)=>{return ( <Form.Select.OptGroup label={item.name}>
{item.users.map((item1)=>{
return <Form.Select.Option value={item1.id} label={item1.name}></Form.Select.Option>
}} />
<Form.Input field='breakTime' label='中断时间:' disabled />
{/* 中断时间:{endTime&&startTime? <span style={{marginLeft:30}}>{`${tdd}天${tdh}时${tds}分`}</span>:recordRow?.interruptDuration} */}
<Form.Select field='settler' label='解决者:' trigger='blur' style={{ width: '100%' }}
filter
rules={[{ required: true, message: '请输入解决者' }]} multiple>
{pepList?.map((item) => {
return (<Form.Select.OptGroup label={item.name}>
{item.users.map((item1) => {
return <Form.Select.Option value={item1.id} label={item1.name}></Form.Select.Option>
})}
</Form.Select.OptGroup> )})}
</Form.Select>
<Form.Select field="type" label={{ text: '故障类型'}} style={{ width: 200 }} rules={[{ required: true, message:'请输入故障类型' }]}>
<Form.Select.Option value="es异常">es异常</Form.Select.Option>
<Form.Select.Option value="数据库异常">数据库异常</Form.Select.Option>
<Form.Select.Option value="应用异常">应用异常</Form.Select.Option>
<Form.Select.Option value="kafka异常">kafka异常</Form.Select.Option>
<Form.Select.Option value="服务器异常">服务器异常</Form.Select.Option>
<Form.Select.Option value="DAC进程异常">DAC进程异常</Form.Select.Option>
<Form.Select.Option value="K8S集群异常">K8S集群异常</Form.Select.Option>
<Form.Select.Option value="redis服务异常">redis服务异常</Form.Select.Option>
<Form.Select.Option value="其他">其他</Form.Select.Option>
</Form.Select>
<Form.TextArea field="record" label={{text:'故障记录'}} rules={[{ required: true, message:'请输入故障记录' }]}>
</Form.TextArea>
</Form>
})}
</Form.Select.OptGroup>)
})}
</Form.Select>
<Form.Select field="type" label={{ text: '故障类型' }} style={{ width: 200 }} rules={[{ required: true, message: '请输入故障类型' }]}>
<Form.Select.Option value="es异常">es异常</Form.Select.Option>
<Form.Select.Option value="数据库异常">数据库异常</Form.Select.Option>
<Form.Select.Option value="应用异常">应用异常</Form.Select.Option>
<Form.Select.Option value="kafka异常">kafka异常</Form.Select.Option>
<Form.Select.Option value="服务器异常">服务器异常</Form.Select.Option>
<Form.Select.Option value="DAC进程异常">DAC进程异常</Form.Select.Option>
<Form.Select.Option value="K8S集群异常">K8S集群异常</Form.Select.Option>
<Form.Select.Option value="redis服务异常">redis服务异常</Form.Select.Option>
<Form.Select.Option value="其他">其他</Form.Select.Option>
</Form.Select>
<Form.TextArea field="record" label={{ text: '故障记录' }} rules={[{ required: true, message: '请输入故障记录' }]}>
</Form.TextArea>
<div style={{ display: 'flex', marginLeft: 30 }}>
<div style={{ marginTop: 6 }}>文件</div>
<Upload
style={{ display: 'inline-block' }}
action={`${apiRoot}/attachments/p`}
accept={'.txt, .doc, .docx, .xls, .xlsx, .pdf, .png, .jpg, .rar, .zip'}
limit={1}
maxSize={51200}
onRemove={() => {
setUploadData({})
}}
onSuccess={(responseBody, file) => {
setUploadData({
name: file.name,
size: file.size,
url: responseBody?.uploaded,
uploadTime: moment().format("YYYY-MM-DD HH:mm:ss")
})
}}
>
<Button icon={<IconUpload />} theme="light">
文件上传
</Button>
</Upload>
</div>
</Form>
</Modal>
</Modal>
}
function mapStateToProps (state) {
const { auth, global, members, webSocket } = state;
return {
// loading: members.isRequesting,
// user: auth.user,
actions: global.actions,
// members: members.data,
// socket: webSocket.socket
};
}
const { auth, global, members, webSocket, addRecord } = state;
console.log(addRecord);
return {
addRecord: addRecord.isRequesting,
// user: auth.user,
actions: global.actions,
qiniu: global.qiniu?.domain,
apiRoot: global.apiRoot
};
}
export default connect(mapStateToProps)(RecordModal);

276
web/client/src/sections/service/containers/cyclePlan.jsx

@ -1,156 +1,162 @@
import React, { useEffect,useState} from 'react';
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Button,Table,Popconfirm,Pagination } from '@douyinfe/semi-ui';
import { Button, Table, Popconfirm, Pagination } from '@douyinfe/semi-ui';
import Addmodal from '../components/cycAddmodal'
import moment from 'moment'
const Server = (props) => {
const { dispatch, actions, user, loading, socket } = props
const{service,install}=actions
const [addVis,setAddVis]=useState(false)
const [cycPlan,setCysPlan]=useState([])
const [recordRow,setRecordRow]=useState(null)
const { service, install } = actions
const [addVis, setAddVis] = useState(false)
const [cycPlan, setCysPlan] = useState([])
const [recordRow, setRecordRow] = useState(null)
const [pepList, setPepList] = useState([])//
const [pageSize,setPageSize]=useState(10)
const [pageIndex,setPageIndex]=useState(1)
const [total,setTotal]=useState()
const [pageSize, setPageSize] = useState(10)
const [pageIndex, setPageIndex] = useState(1)
const [total, setTotal] = useState()
const [respondRecordData, setRespondRecordData] = useState([])
const getCycPlan=(query={type:'period',msg:'获取周期性计划',pageIndex,pageSize})=>{
dispatch(service.getMaintenancePlan(query)).then((res)=>{
setCysPlan(res?.payload.data.responseRes)
setTotal(res?.payload.data.count)
})
}
useEffect(()=>{
getCycPlan()
dispatch(install.getOrganizationDeps()).then((res) => {//(PEP)
setPepList(res.payload.data)
})
},[])
const delHandler=(record)=>{
const query={
responseId:record.id,
msg:'删除周期性计划'
}
dispatch(service.delMaintenancePlan(query)).then((res)=>{
if(res.success) getCycPlan({type:'period',msg:'获取周期性计划',pageIndex:1,pageSize});setPageIndex(1)
})
}
//
// const pagination={
// total:total,
// defaultCurrent: 1,
// pageSize:pageSize,
// showSizeChanger: true,
// currentPage:pageIndex,
// showQuickJumper: true,
// pageSizeOpts: ["5", "10", "15"],
// showTotal: function () {
// return `${total}`
// },
// onChange:(pageIndex,pageSize)=>{
// console.log('pageIndex1',pageIndex,pageSize)
// setPageIndex(pageIndex)
// setPageSize(pageSize)
// const query={
// pageIndex,pageSize,type:'temp',msg:''
// }
// getCycPlan(query)
// }
// }
//console.log('cycPlan',cycPlan)
const getCycPlan = (query = { type: 'period', msg: '获取周期性计划', pageIndex, pageSize }) => {
dispatch(service.getMaintenancePlan(query)).then((res) => {
setCysPlan(res?.payload.data.responseRes)
setTotal(res?.payload.data.count)
})
}
useEffect(() => {
getCycPlan()
dispatch(install.getOrganizationDeps()).then((res) => {//(PEP)
setPepList(res.payload.data)
})
dispatch(service.respondRecord({})).then((res) => {
if (res.success) {
setRespondRecordData(res?.payload.data)
}
});
}, [])
const delHandler = (record) => {
const query = {
responseId: record.id,
msg: '删除周期性计划'
}
dispatch(service.delMaintenancePlan(query)).then((res) => {
if (res.success) getCycPlan({ type: 'period', msg: '获取周期性计划', pageIndex: 1, pageSize }); setPageIndex(1)
})
}
//
// const pagination={
// total:total,
// defaultCurrent: 1,
// pageSize:pageSize,
// showSizeChanger: true,
// currentPage:pageIndex,
// showQuickJumper: true,
// pageSizeOpts: ["5", "10", "15"],
// showTotal: function () {
// return `${total}`
// },
// onChange:(pageIndex,pageSize)=>{
// console.log('pageIndex1',pageIndex,pageSize)
// setPageIndex(pageIndex)
// setPageSize(pageSize)
// const query={
// pageIndex,pageSize,type:'temp',msg:''
// }
// getCycPlan(query)
// }
// }
//console.log('cycPlan',cycPlan)
const columns = [
{
title: '序号',
render:(t, r, i) => {
{
title: '序号',
render: (t, r, i) => {
return i + 1
}
},
{
title: '任务名称',
dataIndex: 'missionName',
},
{
title: '责任人',
render:(record)=>{
return <span>
{record?.maintenancePlanExecuteUsers.map((item)=>{
return item.name
}).toString()
}
</span>
}
},
{
title: '完成情况',
dataIndex: 'state',
},
{
title: '备注',
dataIndex: 'remark',
},
{
title: '计划完成时间',
render:(record)=>{
}
},
{
title: '任务名称',
dataIndex: 'missionName',
},
{
title: '责任人',
render: (record) => {
return <span>
{record?.maintenancePlanExecuteUsers.map((item) => {
return item.name
}).toString()
}
</span>
}
},
{
title: '完成情况',
dataIndex: 'state',
},
{
title: '备注',
dataIndex: 'remark',
},
{
title: '计划完成时间',
render: (record) => {
return <span>{moment(record.planFinishTime).format('YYYY-MM-DD')}</span>
},
},
{
title: '实际完成时间',
render:(record)=>{
return record.actualFinishTime?<span>{moment(record.actualFinishTime).format('YYYY-MM-DD')}</span>:''
},
},
{
title: '操作',
render:(record)=>{
return (<div>
<Button onClick={()=>{setAddVis(true);setRecordRow(record)}} style={{marginRight:10}}>编辑</Button>
<Popconfirm title="确定是否删除?" onConfirm={()=>{delHandler(record)}}><Button type='danger'> 删除</Button></Popconfirm>
</div>)
}
},
},
},
{
title: '实际完成时间',
render: (record) => {
return record.actualFinishTime ? <span>{moment(record.actualFinishTime).format('YYYY-MM-DD')}</span> : ''
},
},
{
title: '操作',
render: (record) => {
return (<div>
<Button onClick={() => { setAddVis(true); setRecordRow(record) }} style={{ marginRight: 10 }}>编辑</Button>
<Popconfirm title="确定是否删除?" onConfirm={() => { delHandler(record) }}><Button type='danger'> 删除</Button></Popconfirm>
</div>)
}
},
];
return (
<div style={{background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px'}}>
<div style={{marginBottom:20}}>
<Button theme='solid' type='secondary' onClick={()=>{setAddVis(true)}}>新增</Button>
{/* <Button theme='solid' type='secondary' style={{marginLeft:50}}>导入</Button> */}
</div>
<div>
<Table columns={columns} dataSource={cycPlan} pagination={false}></Table>
</div>
<div style={{ display: 'flex',justifyContent:'flex-end' ,margin:'10px 0 0 0'}}>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{total}条信息
</span>
<Pagination total={total}
showSizeChanger
pageSize={pageSize}
currentPage={pageIndex}
pageSizeOpts={[10, 20, 30]}
onChange={(pageIndex,pageSize)=>{
console.log('pageIndex1',pageIndex,pageSize)
setPageIndex(pageIndex)
setPageSize(pageSize)
const query={
pageIndex,pageSize,type:'period',msg:'获取周期性计划'
}
getCycPlan(query)
}}></Pagination>
<div style={{ background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px' }}>
<div style={{ marginBottom: 20 }}>
<Button theme='solid' type='secondary' onClick={() => { setAddVis(true) }}>新增</Button>
{/* <Button theme='solid' type='secondary' style={{marginLeft:50}}>导入</Button> */}
</div>
<div>
<Table columns={columns} dataSource={cycPlan} pagination={false}></Table>
</div>
<div style={{ display: 'flex', justifyContent: 'flex-end', margin: '10px 0 0 0' }}>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{total}条信息
</span>
<Pagination total={total}
showSizeChanger
pageSize={pageSize}
currentPage={pageIndex}
pageSizeOpts={[10, 20, 30]}
onChange={(pageIndex, pageSize) => {
console.log('pageIndex1', pageIndex, pageSize)
setPageIndex(pageIndex)
setPageSize(pageSize)
const query = {
pageIndex, pageSize, type: 'period', msg: '获取周期性计划'
}
getCycPlan(query)
}}></Pagination>
</div>
<Addmodal visible={addVis} respondRecordData={respondRecordData} onClose={() => { setAddVis(false); setRecordRow(null); getCycPlan() }} recordRow={recordRow} pepList={pepList}></Addmodal>
</div>
<Addmodal visible={addVis} onClose={()=>{setAddVis(false);setRecordRow(null);getCycPlan()}} recordRow={recordRow} pepList={pepList}></Addmodal>
</div>
)
}
function mapStateToProps (state) {
const { global } = state;
return {
actions: global.actions,
};
}
function mapStateToProps (state) {
const { global } = state;
return {
actions: global.actions,
};
}
export default connect(mapStateToProps)(Server);

441
web/client/src/sections/service/containers/maintenanceRecords.jsx

@ -5,236 +5,237 @@ import MaintenanceRecordModal from '../components/maintenanceRecordModal';
import moment from 'moment';
const MaintenanceRecords = (props) => {
const { dispatch, actions, user, loading, socket, projectList } = props;
const [addVis, setAddVis] = useState(false);
const [recordRow, setRecordRow] = useState(null);
const [equipmentList, setEquipmentList] = useState([]);
const [pepList, setPepList] = useState([]);
const [pageSize, setPageSize] = useState(10);
const [pageIndex, setPageIndex] = useState(1);
const [startTime, setStartTime] = useState('1970-1-1');
const [endTime, setEndTime] = useState('2099-1-1');
const { install, service } = actions;
const [total,setTotal]=useState()
const [projectId,setProjectId]=useState(null)
const getEquipment = (query = { startTime, endTime, pageIndex, pageSize }) => {
dispatch(service.getEquipment(query)).then((res) => {
// console.log()
if (res.success) setEquipmentList(res?.payload.data.result); setTotal(res?.payload.data.resCount)
const { dispatch, actions, user, loading, socket, projectList } = props;
const [addVis, setAddVis] = useState(false);
const [recordRow, setRecordRow] = useState(null);
const [equipmentList, setEquipmentList] = useState([]);
const [pepList, setPepList] = useState([]);
const [pageSize, setPageSize] = useState(10);
const [pageIndex, setPageIndex] = useState(1);
const [startTime, setStartTime] = useState('1970-1-1');
const [endTime, setEndTime] = useState('2099-1-1');
const { install, service } = actions;
const [total, setTotal] = useState()
const [projectId, setProjectId] = useState(null)
});
};
const getEquipment = (query = { startTime, endTime, pageIndex, pageSize }) => {
dispatch(service.getEquipment(query)).then((res) => {
// console.log()
if (res.success) setEquipmentList(res?.payload.data.result); setTotal(res?.payload.data.resCount)
});
};
// console.log('equipmentList', equipmentList);
const findHandler=()=>{
const query={
pageIndex,pageSize,msg:'获取维护记录',startTime, endTime,projectId
}
console.log('canshu',projectId,startTime, endTime)
getEquipment(query)
}
const timeHandler=(e)=>{
setEndTime(e[1]+'')
setStartTime(e[0]+'')
}
useEffect(() => {
dispatch(install.getOrganizationDeps()).then((res) => {
//(PEP)
setPepList(res.payload.data);
});
getEquipment();
}, [])
const delHandler=(record)=>{
dispatch(service.delEquipment(record.id)).then((res)=>{
if(res.success) getEquipment({
pageIndex:1,pageSize,msg:'获取维护记录',startTime, endTime,projectId
});setPageIndex(1)
})
}
const columns = [
{
title: '序号',
render: (t, r, i) => {
return i + 1;
}
},
{
title: '项目名称',
render: (record) => {
const currentId = record.equipmentMaintenanceRecordProjects?.map((item1) => {
return item1.projectId;
})[0];
//const currnetObj = projectList?.find((item) => item.id === record?.equipmentMaintenanceRecordProjects?.projectId)||{};
const currnetObj = projectList?.find((item) => item.id === currentId)||{};
const projectName = currnetObj.name ? currnetObj.name : currnetObj.pepProjectName;
return projectName?.length > 15 ? (
<Tooltip content={<div>{projectName}</div>}>
<div style={{}}>{projectName?.length > 15 ? `${projectName?.substr(0, 15)}...` : projectName}</div>
</Tooltip>
) : (
projectName
);
}
},
{
title: '设备类型',
dataIndex: 'equipmentCategory'
},
{
title: '设备型号',
dataIndex: 'equipmentType'
},
{
title: '维修原因',
dataIndex: 'maintenanceReason'
},
{
title: '解决方案',
dataIndex: 'solution'
},
{
title: '维修人',
render: (record) => {
return (
<span>
{record?.equipmentMaintenanceRecordExecuteUsers
.map((item) => {
return item.name;
})
.toString()}
</span>
);
}
},
{
title: '上报时间',
render: (record) => {
return <span>{moment(record.reportTime).format('YYYY-MM-DD HH:mm:ss')}</span>;
}
},
{
title: '维修完成时间',
render: (record) => {
//('record',record.completedTime)
return (record.completedTime?(<span>{moment(record.reportTime).format('YYYY-MM-DD HH:mm:ss')}</span>):'')
}
},
{
title: '状态',
dataIndex: 'status'
},
{
title: '操作',
render: (record) => {
return (
<div>
<Button
style={{marginRight:10}}
onClick={() => {
setAddVis(true);
setRecordRow(record);
}}
>
编辑
</Button>
<Popconfirm
title='确定是否删除?'
onConfirm={() => {
delHandler(record);
}}
>
<Button type='danger' > 删除</Button>
</Popconfirm>
</div>
);
}
}
];
const findHandler = () => {
const query = {
pageIndex, pageSize, msg: '获取维护记录', startTime, endTime, projectId
}
console.log('canshu', projectId, startTime, endTime)
getEquipment(query)
}
const timeHandler = (e) => {
setEndTime(e[1] + '')
setStartTime(e[0] + '')
}
useEffect(() => {
dispatch(install.getOrganizationDeps()).then((res) => {
//(PEP)
setPepList(res.payload.data);
});
getEquipment();
}, [])
const delHandler = (record) => {
dispatch(service.delEquipment(record.id)).then((res) => {
if (res.success) getEquipment({
pageIndex: 1, pageSize, msg: '获取维护记录', startTime, endTime, projectId
}); setPageIndex(1)
})
}
const columns = [
{
title: '序号',
render: (t, r, i) => {
return i + 1;
}
},
{
title: '项目名称',
render: (record) => {
const currentId = record.equipmentMaintenanceRecordProjects?.map((item1) => {
return item1.projectId;
})[0];
//const currnetObj = projectList?.find((item) => item.id === record?.equipmentMaintenanceRecordProjects?.projectId)||{};
const currnetObj = projectList?.find((item) => item.id === currentId) || {};
const projectName = currnetObj.name ? currnetObj.name : currnetObj.pepProjectName;
return projectName?.length > 15 ? (
<Tooltip content={<div>{projectName}</div>}>
<div style={{}}>{projectName?.length > 15 ? `${projectName?.substr(0, 15)}...` : projectName}</div>
</Tooltip>
) : (
projectName
);
}
},
{
title: '设备类型',
dataIndex: 'equipmentCategory'
},
{
title: '设备型号',
dataIndex: 'equipmentType'
},
{
title: '维修原因',
dataIndex: 'maintenanceReason'
},
{
title: '解决方案',
dataIndex: 'solution'
},
{
title: '维修人',
render: (record) => {
return (
<span>
{record?.equipmentMaintenanceRecordExecuteUsers
.map((item) => {
return item.name;
})
.toString()}
</span>
);
}
},
{
title: '上报时间',
render: (record) => {
return <span>{moment(record.reportTime).format('YYYY-MM-DD HH:mm:ss')}</span>;
}
},
{
title: '维修完成时间',
render: (record) => {
//('record',record.completedTime)
return (record.completedTime ? (<span>{moment(record.reportTime).format('YYYY-MM-DD HH:mm:ss')}</span>) : '')
}
},
{
title: '状态',
dataIndex: 'status'
},
{
title: '操作',
render: (record) => {
return (
<div>
<Button
style={{ marginRight: 10 }}
onClick={() => {
setAddVis(true);
setRecordRow(record);
}}
>
编辑
</Button>
<Popconfirm
title='确定是否删除?'
onConfirm={() => {
delHandler(record);
}}
>
<Button type='danger' > 删除</Button>
</Popconfirm>
</div>
);
}
}
];
return (
<div style={{ background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px' }}>
<div style={{ display: 'flex', marginBottom: 20, alignItems: 'baseline' }}>
<div style={{ marginRight: 100 }}>
{' '}
<Button
theme='solid'
type='secondary'
onClick={() => {
setAddVis(true);
}}
>
新增
</Button>
</div>
<div style={{ marginRight: 200 }}>
{' '}
<span style={{ marginRight: 10 }}>项目名称</span>
<Select
showClear
onChange={(e)=>{setProjectId(e)}}
onClear={()=>{setProjectId(null)}}
style={{ width: 150 }}
optionList={projectList?.map((item) => {
return { value: item.id, label: item.pepProjectName||item.name }
})}
></Select>
</div>
<div style={{ marginRight: 20, display: 'flex', alignItems: 'baseline' }}>
<span style={{ marginRight: 10 }}>上报时间</span>
<DatePicker type='dateTimeRange' onChange={(e)=>{timeHandler(e)}} onClear={()=>{setStartTime('1970-1-1');setEndTime('2099-12-31')}}></DatePicker>
</div>
<div>
<Button theme='solid' type="primary" onClick={findHandler}>查询</Button>
</div>
return (
<div style={{ background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px' }}>
<div style={{ display: 'flex', marginBottom: 20, alignItems: 'baseline' }}>
<div style={{ marginRight: 100 }}>
{' '}
<Button
theme='solid'
type='secondary'
onClick={() => {
setAddVis(true);
}}
>
新增
</Button>
</div>
<div style={{ marginRight: 200 }}>
{' '}
<span style={{ marginRight: 10 }}>项目名称</span>
<Select
showClear
onChange={(e) => { setProjectId(e) }}
onClear={() => { setProjectId(null) }}
style={{ width: 150 }}
optionList={projectList?.map((item) => {
return { value: item.id, label: item.pepProjectName || item.name }
})}
></Select>
</div>
<div style={{ marginRight: 20, display: 'flex', alignItems: 'baseline' }}>
<span style={{ marginRight: 10 }}>上报时间</span>
<DatePicker type='dateTimeRange' onChange={(e) => { timeHandler(e) }} onClear={() => { setStartTime('1970-1-1'); setEndTime('2099-12-31') }}></DatePicker>
</div>
<div>
<Table columns={columns} dataSource={equipmentList} pagination={false}></Table>
<Button theme='solid' type="primary" onClick={findHandler}>查询</Button>
</div>
<div style={{ display: 'flex',justifyContent:'flex-end' ,margin:'10px 0 0 0'}}>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{total}条信息
</span>
<Pagination total={total}
showSizeChanger
pageSize={pageSize}
currentPage={pageIndex}
pageSizeOpts={[10, 20, 30]}
onChange={(pageIndex,pageSize)=>{
//console.log('pageIndex1',pageIndex,pageSize)
setPageIndex(pageIndex)
setPageSize(pageSize)
const query={
pageIndex,pageSize,msg:'获取维护记录',startTime, endTime,projectId
}
getEquipment(query)
}}></Pagination>
</div>
<div>
<Table columns={columns} dataSource={equipmentList} pagination={false}></Table>
</div>
<div style={{ display: 'flex', justifyContent: 'flex-end', margin: '10px 0 0 0' }}>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{total}条信息
</span>
<Pagination total={total}
showSizeChanger
pageSize={pageSize}
currentPage={pageIndex}
pageSizeOpts={[10, 20, 30]}
onChange={(pageIndex, pageSize) => {
//console.log('pageIndex1',pageIndex,pageSize)
setPageIndex(pageIndex)
setPageSize(pageSize)
const query = {
pageIndex, pageSize, msg: '获取维护记录', startTime, endTime, projectId
}
getEquipment(query)
}}></Pagination>
</div>
<MaintenanceRecordModal
visible={addVis}
onClose={() => {
setAddVis(false);
setRecordRow(null);
//getEquipment();
findHandler()
}}
recordRow={recordRow}
pepList={pepList}
projectList={projectList}
></MaintenanceRecordModal>
</div>
<MaintenanceRecordModal
visible={addVis}
onClose={() => {
setAddVis(false);
setRecordRow(null);
//getEquipment();
findHandler()
}}
recordRow={recordRow}
pepList={pepList}
projectList={projectList}
></MaintenanceRecordModal>
</div>
);
);
};
function mapStateToProps(state) {
const { auth, global, members, webSocket, ProjectPoms } = state;
return {
// loading: members.isRequesting,
// user: auth.user,
actions: global.actions,
// members: members.data,
// socket: webSocket.socket
projectList: ProjectPoms.data?.rows
};
function mapStateToProps (state) {
const { auth, global, members, webSocket, ProjectPoms } = state;
return {
// loading: members.isRequesting,
// user: auth.user,
actions: global.actions,
// members: members.data,
// socket: webSocket.socket
projectList: ProjectPoms.data?.rows
};
}
export default connect(mapStateToProps)(MaintenanceRecords);

492
web/client/src/sections/service/containers/serviceRecord.jsx

@ -1,248 +1,362 @@
'use strict';
import React, { useEffect,useState,useMemo } from 'react';
import { Calendar,DatePicker,RadioGroup, Radio,Button,Table,Modal,Tooltip,Pagination, Popconfirm } from '@douyinfe/semi-ui';
import React, { useEffect, useState, useMemo } from 'react';
import { Calendar, DatePicker, RadioGroup, Radio, Button, Table, Modal, Tooltip, Pagination, Popconfirm } from '@douyinfe/semi-ui';
import moment from 'moment'
import { connect } from 'react-redux';
import RecordModal from '../components/recordModal'
import PlanAddmodal from '../components/planAddmodal'
const Server = (props) => {
const { dispatch, actions, user, loading, socket } = props
//console.log('actions',actions)
const {install,service}=actions
const [dateValue,setDateValue]=useState([])
const [mode,setMode]=useState('month')
const [modalVis,setModalVis]=useState(false)
const [recordRow,setRecordRow]=useState(null)
const [recordList,setRecordList]=useState([])
const { install, service } = actions
const [dateValue, setDateValue] = useState([])
const [mode, setMode] = useState('month')
const [modalVis, setModalVis] = useState(false)
const [recordRow, setRecordRow] = useState(null)
const [recordList, setRecordList] = useState([])
const [pepList, setPepList] = useState([])//
const [startTime,setStartTime]=useState('1970-1-1' )
const [endTime,setEndTime]=useState('2099-1-1')
const [sTime,setStime]=useState(moment().startOf('month').format('YYYY-MM-DD HH:mm:ss'))
const [eTime,setEtime]=useState(moment().endOf('month').format('YYYY-MM-DD HH:mm:ss'))
const [calculability,setCalculability]=useState('')
const [pageSize,setPageSize]=useState(10)
const [pageIndex,setPageIndex]=useState(1)
const [total,setTotal]=useState()
const getRecordList=(query={
startTime,endTime,pageIndex,pageSize
})=>{
dispatch(service.getRecord(query)).then((res)=>{
console.log('res1',res)
const [startTime, setStartTime] = useState('1970-1-1')
const [endTime, setEndTime] = useState('2099-1-1')
const [sTime, setStime] = useState(moment().startOf('month').format('YYYY-MM-DD HH:mm:ss'))
const [eTime, setEtime] = useState(moment().endOf('month').format('YYYY-MM-DD HH:mm:ss'))
const [calculability, setCalculability] = useState('')
const [pageSize, setPageSize] = useState(10)
const [pageIndex, setPageIndex] = useState(1)
const [total, setTotal] = useState()
const [addVis, setAddVis] = useState(false)
const [cycPlan, setCysPlan] = useState([])
const [visible, setVisible] = useState(false)
const getRecordList = (query = {
startTime, endTime, pageIndex, pageSize
}) => {
dispatch(service.getRecord(query)).then((res) => {
// console.log('res1',res)
setRecordList(res?.payload.data.res)
setTotal(res?.payload.data.count)
})
}
//('endTime',endTime)
//('endTime',endTime)
useEffect(() => {
getRecordList()
dispatch(install.getOrganizationDeps()).then((res) => {//(PEP)
if(res.success) setPepList(res.payload.data)
})
if (res.success) setPepList(res.payload.data)
})
}, [])
const delHandler=(id)=>{
dispatch(service.delRecord(id)).then((res)=>{
if(res.success) {
getRecordList({startTime,endTime,pageIndex:1,pageSize})
const delHandler = (id) => {
dispatch(service.delRecord(id)).then((res) => {
if (res.success) {
getRecordList({ startTime, endTime, pageIndex: 1, pageSize })
setPageIndex(1)
}
})
}
const getCycPlan = (recordId) => {
dispatch(service.getMaintenancePlan({ type: 'period', msg: '获取周期性计划', recordId: recordId })).then((res) => {
setCysPlan(res?.payload.data.responseRes)
})
}
useEffect(() => {
const query={
const query = {
sTime, eTime
}
console.log('sTime',sTime,eTime)
dispatch(service.calculability(query)).then((res)=>{
if(res.success) setCalculability((Math.round(res.payload.data * 10000)) / 100 + '%'); // console.log(res.payload.data,'dateee')
}
console.log('sTime', sTime, eTime)
dispatch(service.calculability(query)).then((res) => {
if (res.success) setCalculability((Math.round(res.payload.data * 10000)) / 100 + '%'); // console.log(res.payload.data,'dateee')
})
}, [sTime,eTime])
}, [sTime, eTime])
const pagination = {
const pagination={
}
}
//console.log(recordList,'11111111')
const columns = [
{
title: '序号',
render:(t, r, i) => {
return i + 1
}
},
{
title: '故障描述',
dataIndex: 'sketch',
},
{
title: '发生时间',
render:(record)=>{
const columns = [
{
title: '序号',
render: (t, r, i) => {
return i + 1
}
},
{
title: '故障描述',
dataIndex: 'sketch',
},
{
title: '发生时间',
render: (record) => {
return <span>{moment(record.occurrenceTime).format('YYYY-MM-DD HH:mm:ss')}</span>
},
},
{
title: '解决时间',
render:(record)=>{
return <span>{moment(record.solvingTime).format('YYYY-MM-DD HH:mm:ss')}</span>
},
},
{
title: '恢复时间',
render:(record)=>{
const tdd=parseInt((moment(record.solvingTime).format('x')-moment(record.occurrenceTime).format('x'))/1000/60/60/24)//
const tdh=parseInt((moment(record.solvingTime).format('x')-moment(record.occurrenceTime).format('x'))/1000/60/60%24)//
const tds=parseInt((moment(record.solvingTime).format('x')-moment(record.occurrenceTime).format('x'))/1000/60%60)//
return <span>{`${tdd}${tdh}${tds}`}</span>
}
},
{
},
},
{
title: '解决时间',
render: (record) => {
return <span>{moment(record.solvingTime).format('YYYY-MM-DD HH:mm:ss')}</span>
},
},
{
title: '恢复时间',
render: (record) => {
const tdd = parseInt((moment(record.solvingTime).format('x') - moment(record.occurrenceTime).format('x')) / 1000 / 60 / 60 / 24)//
const tdh = parseInt((moment(record.solvingTime).format('x') - moment(record.occurrenceTime).format('x')) / 1000 / 60 / 60 % 24)//
const tds = parseInt((moment(record.solvingTime).format('x') - moment(record.occurrenceTime).format('x')) / 1000 / 60 % 60)//
return <span>{`${tdd}${tdh}${tds}`}</span>
}
},
{
title: '故障类型',
dataIndex: 'type',
},
{
title: '解决者',
//width:20,
render:(record)=>{
// console.log('ressss',record)
return <span>
{record?.maintenanceRecordExecuteUsers.map((item)=>{
return item.name
}).toString()
}
},
{
title: '解决者',
//width:20,
render: (record) => {
// console.log('ressss',record)
return <span>
{record?.maintenanceRecordExecuteUsers.map((item) => {
return item.name
}).toString()
}
</span>
}
},
{
title: '操作',
render:(record)=>{
return <div>
<Button
style={{marginRight:10}}
onClick={() => {
setModalVis(true);setRecordRow(record)
}}
>
编辑
</Button>
<Popconfirm
title='确定是否删除?'
onConfirm={() => {
delHandler(record.id);
}}
>
<Button type='danger' > 删除</Button>
</Popconfirm>
</div>
},
},
];
const onChangeDate=(e)=> {
console.log('zzzz',e[0],e[1])
</span>
}
},
{
title: '文件',
render: (record) => {
return record.files?.length > 0 && <a style={{ color: 'blue' }} href={`/_file-server/${record.files[0]?.url + '?filename=' + encodeURIComponent(record.files[0]?.name)}`}>
{record.files[0]?.name}
</a> || '--'
},
},
{
title: '操作',
render: (record) => {
return <div style={{ width: 294 }}>
<Button
style={{ marginRight: 10 }}
onClick={() => {
setModalVis(true); setRecordRow(record)
}}
>
编辑
</Button>
<Popconfirm
title='确定是否删除?'
onConfirm={() => {
delHandler(record.id);
}}
>
<Button type='danger' > 删除</Button>
</Popconfirm>
<Button
style={{ marginRight: 10 }}
onClick={() => {
setRecordRow(record)
setAddVis(true)
}}
>
添加计划
</Button>
{record.planList?.length > 0 && <Button
style={{ marginRight: 10 }}
onClick={() => {
getCycPlan(record.id);
setVisible(true)
}}
>
查看计划
</Button>}
</div>
},
},
];
const onChangeDate = (e) => {
setMode('')
setDateValue(e)
setStime(moment(e[0]).format('YYYY-MM-DD HH:mm:ss'))
setEtime(moment(e[1]).format('YYYY-MM-DD HH:mm:ss'))
const query={
const query = {
sTime, eTime
}
//console.log('sTime',sTime,eTime)
dispatch(service.calculability(query)).then((res)=>{
if(res.success) setCalculability((Math.round(res.payload.data * 10000)) / 100 + '%'); // console.log(res.payload.data,'dateee')
}
//console.log('sTime',sTime,eTime)
dispatch(service.calculability(query)).then((res) => {
if (res.success) setCalculability((Math.round(res.payload.data * 10000)) / 100 + '%'); // console.log(res.payload.data,'dateee')
})
}
const clearHandler=()=>{
}
const addHandler=()=>{
setModalVis(true)
}
}
const clearHandler = () => {
}
const addHandler = () => {
setModalVis(true)
}
const onSelect=(e)=> {
if(e.target.value==='month'){
setStime(moment().startOf('month').format('YYYY-MM-DD HH:mm:ss'));
setEtime(moment().endOf('month').format('YYYY-MM-DD HH:mm:ss'))
const onSelect = (e) => {
if (e.target.value === 'month') {
setStime(moment().startOf('month').format('YYYY-MM-DD HH:mm:ss'));
setEtime(moment().endOf('month').format('YYYY-MM-DD HH:mm:ss'))
}else{
setStime(moment().startOf('year').format("YYYY-MM-DD HH:mm:ss"))
setEtime(moment().endOf('year').format('YYYY-MM-DD HH:mm:ss'))
} else {
setStime(moment().startOf('year').format("YYYY-MM-DD HH:mm:ss"))
setEtime(moment().endOf('year').format('YYYY-MM-DD HH:mm:ss'))
}
setMode(e.target.value)
setDateValue([])
}
console.log('11111',moment().startOf('year').format('YYYY-MM-DD HH:mm:ss'))
setMode(e.target.value)
setDateValue([])
}
const column = [
{
title: '序号',
render: (t, r, i) => {
return i + 1
}
},
{
title: '任务名称',
dataIndex: 'missionName',
},
{
title: '责任人',
render: (record) => {
return <span>
{record?.maintenancePlanExecuteUsers.map((item) => {
return item.name
}).toString()
}
</span>
}
},
{
title: '完成情况',
dataIndex: 'state',
render: (t, record) => t || '--'
},
{
title: '备注',
dataIndex: 'remark',
render: (t, record) => t || '--'
},
{
title: '计划完成时间',
render: (record) => {
return <span>{moment(record.planFinishTime).format('YYYY-MM-DD')}</span>
},
},
{
title: '实际完成时间',
render: (record) => {
return record.actualFinishTime ? <span>{moment(record.actualFinishTime).format('YYYY-MM-DD')}</span> : '--'
},
},
];
return (
<div style={{background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px'}}>
<div style={{display:'flex',marginTop:20,alignItems:'flex-end'}}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>系统可用性</div>
<div style={{marginLeft:350}}>
<RadioGroup onChange={e => onSelect(e)} value={mode} type="button">
<Radio value={'month'} checked>本月</Radio>
<Radio value={'year'}>全年</Radio>
</RadioGroup>
<DatePicker type="dateTimeRange"
onChange={e => onChangeDate(e) }
density="compact"
style={{ width: 400 }}
value={dateValue}
onClear={()=>{clearHandler()}}
<div style={{ background: '#FFFFFF', margin: '8px 12px', padding: '20px 20px 0px 20px' }}>
<div style={{ display: 'flex', marginTop: 20, alignItems: 'flex-end' }}>
<div style={{ width: 0, height: 20, borderLeft: '3px solid #005ABD', borderTop: '3px solid transparent', borderBottom: '3px solid transparent' }}></div>
<div style={{ fontFamily: "YouSheBiaoTiHei", fontSize: 24, color: '#101531', marginLeft: 8 }}>系统可用性</div>
<div style={{ marginLeft: 350 }}>
<RadioGroup onChange={e => onSelect(e)} value={mode} type="button">
<Radio value={'month'} checked>本月</Radio>
<Radio value={'year'}>全年</Radio>
</RadioGroup>
<DatePicker type="dateTimeRange"
onChange={e => onChangeDate(e)}
density="compact"
style={{ width: 400 }}
value={dateValue}
onClear={() => { clearHandler() }}
/>
</div>
</div>
<div style={{marginLeft:20,marginTop:50,display:'flex',alignItems:'flex-end'}}>
<span style={{width:340}}>{`系统可用性=(平均故障间隔MTBF)/(平均故障间隔MTBF+故障恢复时间MTTR)*100%`}</span>
<span style={{fontSize:48,color: '#D9001B',marginLeft:150}}>{calculability}</span>
</div>
<div style={{display:'flex',marginTop:20}}>
</div>
<div style={{ marginLeft: 20, marginTop: 50, display: 'flex', alignItems: 'flex-end' }}>
<span style={{ width: 340 }}>{`系统可用性=(平均故障间隔MTBF)/(平均故障间隔MTBF+故障恢复时间MTTR)*100%`}</span>
<span style={{ fontSize: 48, color: '#D9001B', marginLeft: 150 }}>{calculability}</span>
</div>
<div style={{ display: 'flex', marginTop: 20 }}>
<Button theme='solid' type='secondary' onClick={addHandler}>新增</Button>
<div style={{display:'flex',alignItems:'baseline',marginLeft:700}}>
<div style={{ display: 'flex', alignItems: 'baseline', marginLeft: 700 }}>
<span >产生时间</span>
<DatePicker type="dateRange" insetInput style={{ width: 280,marginLeft:10 }} onChange={(e)=>{
setStartTime((e[0])+'');setEndTime(e[1]+'') }}
onClear={()=>{setStartTime('1970-1-1');setEndTime('2099-12-31')}} />
<Button theme='solid' type="primary" style={{ marginLeft:20 }} onClick={()=>{
setPageIndex(1);setPageSize(10)
getRecordList({ startTime,endTime,pageIndex:1,pageSize:10});
<DatePicker type="dateRange" insetInput style={{ width: 280, marginLeft: 10 }} onChange={(e) => {
setStartTime((e[0]) + ''); setEndTime(e[1] + '')
}}
onClear={() => { setStartTime('1970-1-1'); setEndTime('2099-12-31') }} />
<Button theme='solid' type="primary" style={{ marginLeft: 20 }} onClick={() => {
setPageIndex(1); setPageSize(10)
getRecordList({ startTime, endTime, pageIndex: 1, pageSize: 10 });
//console.log('setStartTime',startTime,'setEndTime',endTime)
}}>查询</Button>
</div>
</div>
<div style={{marginTop:10}}>
<Table columns={columns} dataSource={recordList} pagination={false} onHeaderRow={()=>{
</div>
<div style={{ marginTop: 10 }}>
<Table columns={columns} dataSource={recordList} pagination={false} onHeaderRow={() => {
return {
background:'#000000',
background: '#000000',
}
}}/>
}} />
</div>
<div style={{ display: 'flex',justifyContent:'flex-end' ,margin:'10px 0 0 0'}}>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{total}条信息
</span>
<Pagination total={total}
showSizeChanger
pageSize={pageSize}
currentPage={pageIndex}
pageSizeOpts={[10, 20, 30]}
onChange={(pageIndex,pageSize)=>{
setPageIndex(pageIndex)
setPageSize(pageSize)
const query={
startTime,endTime,pageIndex,pageSize
}
getRecordList(query)
}}></Pagination>
</div>
<RecordModal visible={modalVis} onClose={() => { setModalVis(false);getRecordList();setRecordRow(null)}} recordRow={recordRow} pepList={pepList}></RecordModal>
<div style={{ display: 'flex', justifyContent: 'flex-end', margin: '10px 0 0 0' }}>
<span style={{ lineHeight: "30px", fontSize: 13, color: 'rgba(0,90,189,0.8)' }}>
{total}条信息
</span>
<Pagination total={total}
showSizeChanger
pageSize={pageSize}
currentPage={pageIndex}
pageSizeOpts={[10, 20, 30]}
onChange={(pageIndex, pageSize) => {
setPageIndex(pageIndex)
setPageSize(pageSize)
const query = {
startTime, endTime, pageIndex, pageSize
}
getRecordList(query)
}}></Pagination>
</div>
<RecordModal
visible={modalVis}
onClose={() => { setModalVis(false); getRecordList(); setRecordRow(null) }}
recordRow={recordRow} pepList={pepList}></RecordModal>
<PlanAddmodal
visible={addVis}
onClose={() => {
setAddVis(false);
getRecordList()
setRecordRow(null)
}}
recordRow={recordRow} />
<Modal
visible={visible}
title={'查看周期计划'}
width={800}
footer={null}
onOk={() => {
setVisible(false)
}}
onCancel={() => {
setVisible(false)
}}
>
<Table style={{ marginBottom: 20 }} columns={column} dataSource={cycPlan} pagination={false} onHeaderRow={() => {
return {
background: '#000000',
}
}} />
</Modal>
</div>
)
}
@ -251,7 +365,7 @@ function mapStateToProps (state) {
return {
// loading: members.isRequesting,
// user: auth.user,
actions: global.actions,
actions: global.actions,
// members: members.data,
// socket: webSocket.socket
};

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

@ -129,7 +129,10 @@ export const ApiTable = {
//获取设备类型
getEquipmentCategory: 'equipmentCategory',
//获取状态数据
getMaintenanceStatus: 'maintenanceStatus'
getMaintenanceStatus: 'maintenanceStatus',
respondRecord: 'respond-record',
};
// 项企的接口

Loading…
Cancel
Save