zhaobing
9 months ago
17 changed files with 1402 additions and 34 deletions
@ -0,0 +1,78 @@ |
|||
'use strict'; |
|||
|
|||
const moment = require("moment") |
|||
|
|||
|
|||
|
|||
async function countIssueByState(ctx, next) { |
|||
const sequelize = ctx.fs.dc.orm |
|||
const { projectId } = ctx.query |
|||
try { |
|||
const rslt = await sequelize.query(` |
|||
SELECT COUNT(CASE WHEN prih.state=4 THEN 1 END) AS waitingRepair, |
|||
COUNT(CASE WHEN prih.state=1 THEN 1 END) AS waitingPlan, |
|||
COUNT(CASE WHEN prih.state=5 THEN 1 END) AS waitingCheck, |
|||
COUNT(CASE WHEN prih.state=2 THEN 1 END) AS waitingExamine |
|||
FROM patrol_record rd |
|||
INNER JOIN patrol_record_issue_handle prih |
|||
ON rd.id = prih.patrol_record_id |
|||
WHERE rd.project_id in (${projectId}) |
|||
`)
|
|||
ctx.status = 200 |
|||
ctx.body = rslt[0][0] |
|||
|
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
|||
ctx.status = 400; |
|||
ctx.body = { message: '根据状态分类查询问题处理失败' } |
|||
} |
|||
|
|||
} |
|||
//近30天的问题统计
|
|||
async function countDayIssue(ctx, next) { |
|||
const sequelize = ctx.fs.dc.orm |
|||
const { projectId } = ctx.query |
|||
try { |
|||
const rslt = await sequelize.query(` |
|||
SELECT |
|||
date_sequence::DATE AS date, |
|||
COALESCE(COUNT(patrol_record.inspection_time), 0) AS count |
|||
FROM |
|||
generate_series(CURRENT_DATE - INTERVAL '29 days', CURRENT_DATE, '1 day'::interval) date_sequence |
|||
LEFT JOIN patrol_record |
|||
ON date_sequence::DATE = DATE(patrol_record.inspection_time) |
|||
AND patrol_record.project_id in (:projectId) |
|||
AND patrol_record.alarm='true' |
|||
GROUP BY date |
|||
ORDER BY date; |
|||
`, {
|
|||
replacements: { |
|||
projectId: projectId, |
|||
}, |
|||
type: sequelize.QueryTypes.SELECT, |
|||
}) |
|||
ctx.status = 200 |
|||
ctx.body = rslt |
|||
|
|||
} catch (error) { |
|||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
|||
ctx.status = 400; |
|||
ctx.body = { message: '近30天的问题统计查询失败' } |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
module.exports = { |
|||
countIssueByState, |
|||
countDayIssue |
|||
} |
@ -0,0 +1,13 @@ |
|||
'use strict'; |
|||
const error = require('../../controllers/bigScreen/error'); |
|||
|
|||
module.exports = function (app, router, opts) { |
|||
|
|||
|
|||
app.fs.api.logAttr['GET/bigScreen/patrolRecordIssue'] = { content: '', visible: false }; |
|||
router.get('/bigScreen/patrolRecordIssue',error.countIssueByState) |
|||
|
|||
app.fs.api.logAttr['GET/bigScreen/patrolRecordDayIssue'] = { content: '', visible: false }; |
|||
router.get('/bigScreen/patrolRecordDayIssue',error.countDayIssue) |
|||
|
|||
} |
After Width: | Height: | Size: 67 KiB |
@ -0,0 +1,85 @@ |
|||
'use strict'; |
|||
|
|||
import { basicAction } from '@peace/utils' |
|||
import { ApiTable } from '$utils' |
|||
|
|||
|
|||
export function addPatrolRecordIssueHandle(params) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'post', |
|||
data: params, |
|||
dispatch, |
|||
actionType: 'ADD_PatrolRecordIssueHandle_REPORT', |
|||
url: ApiTable.addPatrolRecordIssueHandle, |
|||
msg: { |
|||
option: '维修计划新增', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
export function modifyPatrolRecordIssueHandle(id, params, msg) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'put', |
|||
data: params, |
|||
dispatch, |
|||
actionType: 'MODIFY_PatrolRecordIssueHandle_REPORT', |
|||
url: ApiTable.modifyPatrolRecordIssueHandle.replace('{id}', id), |
|||
msg: { |
|||
option: msg || '维修计划审批', |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
|
|||
export const GET_PATROL_RECORD_LIST = 'GET_PATROL_RECORD_LIST'; |
|||
export const GET_PATROL_RECORD_LIST_SUCCESS = 'GET_PATROL_RECORD_LIST_SUCCESS'; |
|||
export const GET_PATROL_RECORD_LIST_ERROR = 'GET_PATROL_RECORD_LIST_ERROR'; |
|||
export function getRecords(url) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'get', |
|||
dispatch, |
|||
actionType: GET_PATROL_RECORD_LIST, |
|||
url: url, |
|||
msg: { error: '获取巡检记录失败', }, |
|||
reducer: { name: 'record' } |
|||
}); |
|||
} |
|||
|
|||
export function countIssueByState(query) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'get', |
|||
dispatch, |
|||
query, |
|||
actionType: 'COUNT_ISSUE_BY_STATE', |
|||
url: ApiTable.countIssueByState, |
|||
msg: { |
|||
option: '根据问题状态统计', |
|||
}, |
|||
reducer: { name: 'issues' } |
|||
}); |
|||
} |
|||
|
|||
|
|||
export function countDayIssue(query) { |
|||
return (dispatch) => basicAction({ |
|||
type: 'get', |
|||
dispatch, |
|||
query, |
|||
actionType: 'COUNT_DAY_ISSUE', |
|||
url: ApiTable.countDayIssue, |
|||
msg: { |
|||
option: '近三十天问题统计', |
|||
}, |
|||
reducer: { name: 'dayIssues' } |
|||
}); |
|||
} |
|||
|
|||
|
|||
|
|||
export default{ |
|||
getRecords, |
|||
modifyPatrolRecordIssueHandle, |
|||
addPatrolRecordIssueHandle, |
|||
countIssueByState, |
|||
countDayIssue |
|||
} |
@ -1,7 +1,8 @@ |
|||
'use strict'; |
|||
import leader from './leader' |
|||
import run from './run' |
|||
import error from './error' |
|||
export default { |
|||
...leader,...run |
|||
...leader,...run,...error |
|||
|
|||
} |
@ -0,0 +1,429 @@ |
|||
import React, { useState, useRef } from 'react'; |
|||
import { Button, Form, Row, Col, Table, Popconfirm, Input, message } from 'antd'; |
|||
import { |
|||
ModalForm, |
|||
ProFormText, |
|||
ProFormSelect, |
|||
ProFormTextArea, |
|||
ProFormDatePicker, |
|||
ProFormDateRangePicker, |
|||
ProFormDependency |
|||
} from '@ant-design/pro-form'; |
|||
import Uploads from '$components/Uploads'; |
|||
import moment from 'moment'; |
|||
const FormItem = Form.Item; |
|||
//state: 1下发未上报 2已上报待审批 3整改完成 上报结果result: status 0 已上报未审批 1 审批通过 2 审批驳回
|
|||
export default (props) => { |
|||
const { title, triggerRender, editData = null, onFinish, readOnly, structsUsers, user } = props; |
|||
const users = structsUsers?.find(s => s.id == editData?.points?.project?.id)?.users?.map(v => { return { value: v.id, label: v.name, ...v } }) |
|||
const formItemLayout = { labelCol: { span: 7 }, wrapperCol: { span: 16 } }; |
|||
const formRef = useRef(); |
|||
|
|||
const initialValues = editData ? { |
|||
...editData, |
|||
...editData?.patrolRecordIssueHandles[0], |
|||
approvePerson: editData?.patrolRecordIssueHandles[0]?.approvePerson?.name || '', |
|||
approveDate: editData?.patrolRecordIssueHandles[0]?.approveDate ? moment(editData?.patrolRecordIssueHandles[0]?.approveDate).format('YYYY-MM-DD HH:mm:ss') : "", |
|||
repairPerson: users?.find(s => s.value == editData?.patrolRecordIssueHandles[0]?.repairPerson?.id) ? editData?.patrolRecordIssueHandles[0]?.repairPerson?.id : null, |
|||
checkPerson: users?.find(s => s.value == editData?.patrolRecordIssueHandles[0]?.checkPerson?.id) ? editData?.patrolRecordIssueHandles[0]?.checkPerson?.id : null, |
|||
} : {}; |
|||
if (editData?.patrolRecordIssueHandles?.length > 0) { |
|||
initialValues.dateRange = [editData?.patrolRecordIssueHandles[0]?.startTime, editData?.patrolRecordIssueHandles[0]?.endTime] |
|||
} |
|||
const [approve, setApprove] = useState('') |
|||
|
|||
const approveHandle = async (values) => { |
|||
onFinish && await onFinish({ |
|||
msg: approve ? '计划同意' : '计划驳回', |
|||
state: approve ? 4 : 3, |
|||
approveOpinion: values?.approveOpinion, |
|||
approvePerson: user, |
|||
approveDate: moment() |
|||
}, editData) |
|||
} |
|||
|
|||
const renderPlanInfo = () => { |
|||
return <> |
|||
{/* <Card title={'巡检信息'}> */} |
|||
<div className="item-title">{"巡检信息"}</div> |
|||
<Form> |
|||
<Row> |
|||
<Col span={12}> |
|||
<Form.Item label="结构物名称:" {...formItemLayout}> |
|||
<Input value={editData?.points?.project?.name} readOnly /> |
|||
</Form.Item> |
|||
<Form.Item label="巡检人:" {...formItemLayout}> |
|||
<Input value={editData?.points?.user?.name} readOnly /> |
|||
</Form.Item> |
|||
</Col> |
|||
<Col span={12}> |
|||
<Form.Item label="巡检单位:" {...formItemLayout}> |
|||
<Input value={editData?.points?.user?.department?.name} readOnly title={222} /> |
|||
</Form.Item> |
|||
|
|||
<Form.Item label="巡检时间:" {...formItemLayout}> |
|||
<Input value={editData?.inspectionTime && moment(editData?.inspectionTime).format('YYYY-MM-DD HH:mm:ss')} readOnly /> |
|||
</Form.Item> |
|||
</Col> |
|||
</Row> |
|||
</Form> |
|||
|
|||
<div className="item-title">{"问题详情"}</div> |
|||
<Row> |
|||
<Col span={12}> |
|||
<Form.Item label="点位名称:" {...formItemLayout}> |
|||
<Input value={editData?.points?.itemData?.name} readOnly /> |
|||
</Form.Item> |
|||
</Col> |
|||
</Row> |
|||
<Row> |
|||
<Col span={24}> |
|||
{ |
|||
editData?.points?.inspectContent && Array.isArray(editData?.points?.inspectContent) && |
|||
editData?.points?.inspectContent?.map(s => { |
|||
if (s?.alarm == true) { |
|||
return <> |
|||
{s?.deviceName && <Col span={12}> |
|||
<Form.Item label="设备名称:" {...formItemLayout}> |
|||
<Input value={s?.deviceName} readOnly /> |
|||
</Form.Item> |
|||
</Col>} |
|||
{ |
|||
s?.checkItems?.map(k => { |
|||
return <Row style={{ marginBottom: 15 }}> |
|||
<Col span={12}> |
|||
<Form.Item label="检查项:" {...formItemLayout}> |
|||
<Input value={k.name} readOnly /> |
|||
</Form.Item> |
|||
<Form.Item label="异常等级:" {...formItemLayout}> |
|||
<Input value={k?.level} readOnly /> |
|||
</Form.Item> |
|||
</Col> |
|||
<Col span={12}> |
|||
<Form.Item label="问题描述:" {...formItemLayout}> |
|||
<Input value={k?.msgInp} readOnly title={222} /> |
|||
</Form.Item> |
|||
|
|||
<Form.Item label="现场图片:" {...formItemLayout}> |
|||
<Uploads |
|||
listType='picture-card' |
|||
uploadType='project' |
|||
maxFilesNum={1} |
|||
maxFileSize={10} |
|||
isQiniu={true} |
|||
disabled={true} |
|||
fileTypes={["png", "jpg"]} |
|||
defaultValue={ |
|||
(() => { |
|||
let nextV = [] |
|||
for (let s of (k.imgs || [])) { |
|||
if (s) { |
|||
nextV.push({ |
|||
storageUrl: s |
|||
}) |
|||
} |
|||
} |
|||
return nextV |
|||
})() |
|||
} |
|||
/> |
|||
|
|||
</Form.Item> |
|||
</Col> |
|||
</Row> |
|||
}) |
|||
} |
|||
</> |
|||
|
|||
|
|||
} |
|||
}) |
|||
} |
|||
</Col> |
|||
</Row></> |
|||
} |
|||
|
|||
const renderRepairInfo = () => { |
|||
return <> |
|||
<div className="item-title">{"维修处理"}</div> |
|||
|
|||
<ProFormTextArea |
|||
name="repairDesc" |
|||
label="维修情况描述:" |
|||
disabled={true} |
|||
/> |
|||
|
|||
<Form.Item label="完工图片:"> |
|||
<Uploads |
|||
listType='picture-card' |
|||
uploadType='project' |
|||
maxFilesNum={1} |
|||
maxFileSize={10} |
|||
isQiniu={true} |
|||
disabled={true} |
|||
fileTypes={["png", "jpg"]} |
|||
defaultValue={ |
|||
(() => { |
|||
let nextV = [] |
|||
for (let s of (editData?.patrolRecordIssueHandles[0]?.repairImage || [])) { |
|||
if (s) { |
|||
nextV.push({ |
|||
storageUrl: s |
|||
}) |
|||
} |
|||
} |
|||
return nextV |
|||
})() |
|||
} |
|||
/> |
|||
|
|||
</Form.Item> |
|||
|
|||
</> |
|||
} |
|||
|
|||
const renderCheckInfo = () => { |
|||
return <> |
|||
<div className="item-title">{"质检验收"}</div> |
|||
|
|||
<ProFormTextArea |
|||
name="checkPerson1" |
|||
label="验收人:" |
|||
disabled={true} |
|||
value={editData?.patrolRecordIssueHandles[0]?.checkPerson?.name} |
|||
/> |
|||
|
|||
<ProFormText |
|||
name="checkPerson1" |
|||
label="成本(元):" |
|||
disabled={true} |
|||
value={editData?.patrolRecordIssueHandles[0]?.cost} |
|||
/> |
|||
|
|||
<Form.Item label="完工图片:"> |
|||
<Uploads |
|||
listType='picture-card' |
|||
uploadType='project' |
|||
maxFilesNum={1} |
|||
maxFileSize={10} |
|||
isQiniu={true} |
|||
disabled={true} |
|||
fileTypes={["png", "jpg"]} |
|||
defaultValue={ |
|||
(() => { |
|||
let nextV = [] |
|||
for (let s of (editData?.patrolRecordIssueHandles[0]?.checkImage || [])) { |
|||
if (s) { |
|||
nextV.push({ |
|||
storageUrl: s |
|||
}) |
|||
} |
|||
} |
|||
return nextV |
|||
})() |
|||
} |
|||
/> |
|||
</Form.Item> |
|||
|
|||
<ProFormTextArea |
|||
name="checkOpinion" |
|||
label="验收意见:" |
|||
disabled={true} |
|||
/> |
|||
|
|||
<ProFormTextArea |
|||
name="checkState" |
|||
label="验收结果:" |
|||
disabled={true} |
|||
value={editData?.patrolRecordIssueHandles[0]?.state == 6 ? '验收通过' : '验收不通过'} |
|||
/> |
|||
</> |
|||
} |
|||
return ( |
|||
<ModalForm |
|||
formRef={formRef} |
|||
title={title || ''} |
|||
initialValues={initialValues} |
|||
trigger={ |
|||
triggerRender ? triggerRender : <Button type="primary" > |
|||
{title || ''} |
|||
</Button> |
|||
} |
|||
width={1300} |
|||
layout="horizontal" |
|||
// grid={true}
|
|||
{...formItemLayout} |
|||
modalProps={{ |
|||
destroyOnClose: true, |
|||
// onCancel: () => { },
|
|||
bodyStyle: { height: 620, overflowY: 'auto' } |
|||
}} |
|||
onFinish={async (values) => { |
|||
if (editData?.patrolRecordIssueHandles[0]?.state === 2 && title == '审核') { |
|||
approveHandle(values) |
|||
return true; |
|||
} else { |
|||
values.repairUnit = values?.repairUnits; |
|||
values.startTime = values?.dateRange[0]; |
|||
values.endTime = values?.dateRange[1]; |
|||
values.repairPerson = { id: users?.find(s => s.value == values.repairPerson)?.value, name: users?.find(s => s.id == values.repairPerson)?.label } |
|||
values.checkPerson = { id: users?.find(s => s.value == values.checkPerson)?.value, name: users?.find(s => s.id == values.checkPerson)?.label } |
|||
onFinish && await onFinish(values, editData) |
|||
//message.success('提交成功');
|
|||
return true; |
|||
} |
|||
}} |
|||
|
|||
submitter={editData?.patrolRecordIssueHandles[0]?.state === 2 && title != '修改计划' && title != '查看详情' ? { |
|||
render: (props, defaultDoms) => { |
|||
return [ |
|||
<Button onClick={() => { |
|||
setApprove(1) |
|||
props.submit(); |
|||
}} type='primary'>确定</Button>, |
|||
<Button onClick={() => { |
|||
setApprove(0) |
|||
props.submit(); |
|||
}}>驳回</Button> |
|||
]; |
|||
} |
|||
} : (!readOnly)} |
|||
> |
|||
<div> |
|||
{/*问题记录信息*/} |
|||
{renderPlanInfo()} |
|||
|
|||
{/*问题处理计划表单*/} |
|||
{ |
|||
((editData?.patrolRecordIssueHandles[0]?.state == 1 && title != '查看详情') || editData?.patrolRecordIssueHandles[0]?.state > 1) && |
|||
<> |
|||
<div className="item-title">{"维修计划信息"}</div> |
|||
<Row> |
|||
<Col span={12}> |
|||
{!readOnly ? <ProFormSelect |
|||
rules={[{ required: true, message: '请选择维修人' }]} |
|||
options={users || []} |
|||
disabled={readOnly} |
|||
name="repairPerson" |
|||
label="维修人" |
|||
fieldProps={{ |
|||
showSearch: true |
|||
}} |
|||
/> : |
|||
<ProFormText |
|||
name="repairPerson1" |
|||
label="维修人:" |
|||
disabled={true} |
|||
value={editData?.patrolRecordIssueHandles[0]?.repairPerson?.name} |
|||
/> |
|||
} |
|||
</Col> |
|||
<Col span={12}> |
|||
<ProFormDependency name={['repairPerson']}> |
|||
{({ repairPerson }) => { |
|||
const department = users?.find(s => s.id == repairPerson)?.department?.name |
|||
|
|||
return ( |
|||
<ProFormText |
|||
disabled={true} |
|||
name="repairUnits" |
|||
label="维修单位" |
|||
placeholder="" |
|||
fieldProps={{ |
|||
showSearch: true |
|||
}} |
|||
colProps={{ |
|||
span: 12, |
|||
}} |
|||
value={department} |
|||
/> |
|||
); |
|||
}} |
|||
</ProFormDependency> |
|||
|
|||
</Col> |
|||
|
|||
<Col span={12}> |
|||
<ProFormDateRangePicker |
|||
disabled={readOnly} |
|||
name="dateRange" |
|||
label="计划开始时间~结束时间:" |
|||
rules={[{ required: true, message: '请选择计划时间范围' }]} |
|||
/> |
|||
</Col> |
|||
<Col span={12}> |
|||
{!readOnly ? <ProFormSelect |
|||
rules={[{ required: true, message: '请选择质检人' }]} |
|||
options={users || []} |
|||
disabled={readOnly} |
|||
name="checkPerson" |
|||
label="质检人" |
|||
fieldProps={{ |
|||
showSearch: true |
|||
}} |
|||
/> : <ProFormText |
|||
name="checkPerson1" |
|||
label="质检人:" |
|||
disabled={true} |
|||
value={editData?.patrolRecordIssueHandles[0]?.checkPerson?.name} |
|||
/>} |
|||
</Col> |
|||
<Col span={12}> |
|||
<ProFormTextArea |
|||
name="repairAsk" |
|||
label="维修要求:" |
|||
disabled={readOnly} |
|||
rules={[ |
|||
{ |
|||
max: 200, message: '维修要求长度不能大于200个字符' |
|||
}, |
|||
{ |
|||
whitespace: true, message: '请勿输入空格' |
|||
}]} |
|||
placeholder="" |
|||
/></Col> |
|||
{editData?.patrolRecordIssueHandles[0]?.state && editData?.patrolRecordIssueHandles[0]?.state > 3 && <Col span={12}> |
|||
<ProFormText |
|||
name="approvePerson" |
|||
label="制定人:" |
|||
disabled={true} |
|||
/> |
|||
<ProFormText |
|||
name="approveDate" |
|||
label="制定时间:" |
|||
disabled={true} |
|||
/> |
|||
</Col>} |
|||
</Row> |
|||
</> |
|||
} |
|||
|
|||
{ |
|||
((editData?.patrolRecordIssueHandles[0]?.state > 2) || title == '审核') && |
|||
<> |
|||
<div className="item-title">{"维修计划审批"}</div> |
|||
<div> |
|||
<ProFormTextArea |
|||
name="approveOpinion" |
|||
label="审批意见:" |
|||
disabled={title != '审核'} |
|||
rules={[ |
|||
{ required: true, message: '请输入审批意见' }, |
|||
{ |
|||
max: 200, message: '审批意见长度不能大于200个字符' |
|||
}, |
|||
{ |
|||
whitespace: true, message: '请勿输入空格' |
|||
}]} |
|||
placeholder="请输入审批意见" |
|||
/> |
|||
</div> |
|||
</> |
|||
} |
|||
|
|||
{(editData?.patrolRecordIssueHandles[0]?.state && editData?.patrolRecordIssueHandles[0]?.state > 4) && renderRepairInfo()} |
|||
{(editData?.patrolRecordIssueHandles[0]?.state && editData?.patrolRecordIssueHandles[0]?.state > 5) && renderCheckInfo()} |
|||
</div> |
|||
</ ModalForm> |
|||
); |
|||
}; |
Loading…
Reference in new issue