Browse Source

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

dev
wenlele 1 year ago
parent
commit
fb6076bb6f
  1. 10
      api/.vscode/launch.json
  2. 24
      api/app/lib/controllers/maintenancePlan/index.js
  3. 50
      api/app/lib/controllers/record/index.js
  4. 3
      api/app/lib/index.js
  5. 10
      api/app/lib/models/maintenance_plan.js
  6. 11
      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. 61
      web/client/src/sections/means/containers/projectMeans.jsx
  12. 61
      web/client/src/sections/means/containers/repairFQA.jsx
  13. 24
      web/client/src/sections/means/nav-item.jsx
  14. 32
      web/client/src/sections/means/routes.js
  15. 2
      web/client/src/sections/means/style.less
  16. 18
      web/client/src/sections/service/actions/record.js
  17. 34
      web/client/src/sections/service/components/cycAddmodal.jsx
  18. 87
      web/client/src/sections/service/components/planAddmodal.jsx
  19. 58
      web/client/src/sections/service/components/recordModal.jsx
  20. 8
      web/client/src/sections/service/containers/cyclePlan.jsx
  21. 3
      web/client/src/sections/service/containers/maintenanceRecords.jsx
  22. 126
      web/client/src/sections/service/containers/serviceRecord.jsx
  23. 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",

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

@ -5,24 +5,31 @@
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 })
@ -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
})

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

@ -6,6 +6,7 @@ async function getRecord(ctx) {
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}`);
@ -82,14 +94,14 @@ 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 {
@ -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' })

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

@ -78,7 +78,17 @@ module.exports = dc => {
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: "",

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

@ -69,7 +69,16 @@ module.exports = dc => {
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: "",

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,9 +382,10 @@ const Rest = (props) => {
setFileSearch('')
}}
/>
</SimpleBar>
{/* </SimpleBar> */}
</div>
</div>
{/* 表格 */}
<div style={{
flex: 1, height: '100%',
@ -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 }}>

61
web/client/src/sections/means/containers/projectMeans.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,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 }}>

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 }}>

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: '运维规范',
}]

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

@ -5,3 +5,5 @@
#example:hover {
color: yellowgreen;
}

18
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) {//计算系统可用性
@ -60,3 +73,4 @@ export function delRecord(query) {//删除服务记录
});
}

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

@ -1,20 +1,21 @@
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 AddModal = (props) => {
const {visible,onClose,recordRow,pepList,actions,dispatch}=props
const { visible, onClose, recordRow, pepList, actions, dispatch, respondRecordData } = props
const { service } = actions
const api = useRef();
const [selectValue, setSelectValue] = useState([])
useEffect(() => {
}, [])
//
const okHandler = () => {
//api.current.setValues({'manger':recordRow?.maintenancePlanExecuteUsers.map((item)=>{return item.id})},)
api.current.validate().then((res) => {
res.manger
recordRow?.maintenancePlanExecuteUsers
console.log(111, res, respondRecordData?.map(v => ({ value: v.id, label: v.sketch })));
const query = {
id: recordRow?.id,
actualFinishTime: res.realityTime,
@ -24,6 +25,7 @@ const okHandler=()=>{
type: 'period',
missionName: res.taskName,
manger: res.manger,
recordId: res.recordId,
msg: recordRow ? '编辑周期性计划' : '添加周期性计划'
}
dispatch(service.editMaintenancePlan(query)).then((res) => {
@ -40,13 +42,16 @@ const okHandler=()=>{
>
<Form
initValues={{'taskName':recordRow?.missionName,
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}}
'realityTime': recordRow?.actualFinishTime,
'recordId': recordRow?.recordId || [],
}}
getFormApi={formApi => api.current = formApi}
labelCol={{ span: 6 }}
@ -57,11 +62,13 @@ const okHandler=()=>{
]} ></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}>
{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.OptGroup>)
})}
</Form.Select>
<Form.Select label='完成情况' style={{ width: 200 }} field='status'>
<Form.Select.Option value='未完成'>未完成</Form.Select.Option>
@ -73,6 +80,17 @@ const okHandler=()=>{
<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>

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)

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

@ -1,14 +1,16 @@
'use strict';
import React, { useEffect, useState, useRef } from 'react';
import { Modal,Form,DatePicker,useFormApi,actions,Button } from '@douyinfe/semi-ui';
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 { 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//
@ -38,8 +40,10 @@ const okHandler=()=>{
record: res.record,
settler: res.settler,
type: res.type,
msg:recordRow?'编辑服务记录':'添加服务记录'
msg: recordRow ? '编辑响应记录' : '添加响应记录',
files: [{ ...uploadData }]
}
dispatch(service.addRecord(editVal)).then(res => {
if (res.success) {
onClose()
@ -56,13 +60,14 @@ const okHandler=()=>{
//recordRow?<Button onClick={cancelHandler}></Button>:
<div>
<Button onClick={cancelHandler}>取消</Button>
<Button theme='solid' type='primary' onClick={okHandler}>确定</Button>
<Button loading={addRecord} theme='solid' type='primary' onClick={okHandler}>确定</Button>
</div>}
onCancel={cancelHandler}
onOk={okHandler}
// onOk={okHandler}
>
<Form wrapperCol={{ span: 20 }}
initValues={{'name':recordRow?.sketch,
initValues={{
'name': recordRow?.sketch,
'startTime': recordRow?.occurrenceTime,
'endTime': recordRow?.solvingTime,
'settler': recordRow?.maintenanceRecordExecuteUsers.map((item) => { return item.pepUserId }),
@ -103,12 +108,14 @@ const okHandler=()=>{
<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}>
{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.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>
@ -124,6 +131,32 @@ const okHandler=()=>{
<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>
@ -131,13 +164,14 @@ const okHandler=()=>{
</Modal>
}
function mapStateToProps (state) {
const { auth, global, members, webSocket } = state;
const { auth, global, members, webSocket, addRecord } = state;
console.log(addRecord);
return {
// loading: members.isRequesting,
addRecord: addRecord.isRequesting,
// user: auth.user,
actions: global.actions,
// members: members.data,
// socket: webSocket.socket
qiniu: global.qiniu?.domain,
apiRoot: global.apiRoot
};
}

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

@ -15,6 +15,7 @@ const Server = (props) => {
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) => {
@ -27,6 +28,11 @@ const Server = (props) => {
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 = {
@ -140,7 +146,7 @@ const Server = (props) => {
getCycPlan(query)
}}></Pagination>
</div>
<Addmodal visible={addVis} onClose={()=>{setAddVis(false);setRecordRow(null);getCycPlan()}} recordRow={recordRow} pepList={pepList}></Addmodal>
<Addmodal visible={addVis} respondRecordData={respondRecordData} onClose={() => { setAddVis(false); setRecordRow(null); getCycPlan() }} recordRow={recordRow} pepList={pepList}></Addmodal>
</div>
)

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

@ -17,12 +17,13 @@ const MaintenanceRecords = (props) => {
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);

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

@ -5,6 +5,7 @@ import { Calendar,DatePicker,RadioGroup, Radio,Button,Table,Modal,Tooltip,Pagina
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
@ -24,11 +25,16 @@ const Server = (props) => {
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)
// console.log('res1',res)
setRecordList(res?.payload.data.res)
setTotal(res?.payload.data.count)
})
@ -39,6 +45,7 @@ const Server = (props) => {
dispatch(install.getOrganizationDeps()).then((res) => {//(PEP)
if (res.success) setPepList(res.payload.data)
})
}, [])
const delHandler = (id) => {
dispatch(service.delRecord(id)).then((res) => {
@ -48,6 +55,12 @@ const Server = (props) => {
}
})
}
const getCycPlan = (recordId) => {
dispatch(service.getMaintenancePlan({ type: 'period', msg: '获取周期性计划', recordId: recordId })).then((res) => {
setCysPlan(res?.payload.data.responseRes)
})
}
useEffect(() => {
const query = {
sTime, eTime
@ -114,10 +127,18 @@ const Server = (props) => {
</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>
return <div style={{ width: 294 }}>
<Button
style={{ marginRight: 10 }}
onClick={() => {
@ -135,13 +156,31 @@ const Server = (props) => {
>
<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) => {
console.log('zzzz',e[0],e[1])
setMode('')
setDateValue(e)
setStime(moment(e[0]).format('YYYY-MM-DD HH:mm:ss'))
@ -172,11 +211,56 @@ const addHandler=()=>{
setEtime(moment().endOf('year').format('YYYY-MM-DD HH:mm:ss'))
}
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' }}>
@ -206,7 +290,8 @@ const addHandler=()=>{
<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]+'') }}
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)
@ -240,7 +325,36 @@ const addHandler=()=>{
getRecordList(query)
}}></Pagination>
</div>
<RecordModal visible={modalVis} onClose={() => { setModalVis(false);getRecordList();setRecordRow(null)}} recordRow={recordRow} pepList={pepList}></RecordModal>
<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>
)

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