Browse Source

小程序巡查养护上报修改

dev
liujiangyong 1 year ago
parent
commit
0cc65ee485
  1. 5
      api/app/lib/controllers/report/index.js
  2. 6
      weapp/src/packages/components/inputPicker/index.jsx
  3. 415
      weapp/src/packages/patrol/index.jsx
  4. 119
      weapp/src/packages/patrol/index.scss

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

@ -4,7 +4,7 @@ const moment = require('moment')
async function reportList (ctx) {
try {
const models = ctx.fs.dc.models;
const { limit, page, startTime, endTime, keyword, userId, reportType, isTop, asc, projectType, handleState = '', performerId = '' } = ctx.query
const { limit, page, startTime, endTime, keyword, userId, reportType, isTop, asc, projectType, handleState = '', performerId = '', codeRoad } = ctx.query
const { userInfo } = ctx.fs.api
const sequelize = ctx.fs.dc.orm;
@ -96,6 +96,9 @@ async function reportList (ctx) {
if (handleState) {
findOption.where.handleState = handleState
}
if (codeRoad) {
findOption.where.codeRoad = codeRoad
}
let reportRes = null;

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

@ -7,7 +7,7 @@ import arrowIcon from '../../../static/img/patrol/arrow-down.svg'
import './index.scss'
export default function InputPicker(props) {
const { title, placeholder, selector, value, onInput, isView, onlySelect } = props
const { title, placeholder, selector, value, onInput, isView, onlySelect, width, star = true } = props
const [curSelector, setCurSelector] = useState([])
useEffect(() => {
@ -31,9 +31,9 @@ export default function InputPicker (props) {
onInput(curSelector[e.detail.value])
}
return (
<View className='input-picker'>
<View className='input-picker' style={{ width: width || 'auto' }}>
<View className='input-box'>
<View className='title'><Text style={{ color: 'red' }}>*&nbsp;</Text>{title}</View>
<View className='title'>{star ? <Text style={{ color: 'red' }}>*&nbsp;</Text> : null}{title}</View>
<Input
className='input'
type='text'

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

@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import Taro, { useRouter } from '@tarojs/taro';
import { View, RadioGroup, Radio, Image, Input, Picker, Video } from '@tarojs/components';
import { View, RadioGroup, Radio, Image, Input, Picker, Video, Text, CheckboxGroup, Checkbox, Textarea } from '@tarojs/components';
import { AtButton, AtTextarea, AtImagePicker, AtMessage, AtIcon } from 'taro-ui';
import InputPicker from '../components/inputPicker';
import InputPickers from '../components/inputPickers';
@ -8,7 +8,7 @@ import VideoUpload from '../../components/uploads'
import request from '@/services/request';
import environment from '../../config';
import { getState } from '../../store/globalState';
import { postReport, getReportDetail, delReport, getRoadSection, postImage, getProject, postHandle } from '@/services/api';
import { postReport, getReportList, getReportDetail, delReport, getRoadSection, postImage, getProject, postHandle } from '@/services/api';
import './index.scss';
import arrowIcon from '../../static/img/patrol/arrow-down.svg';
@ -61,6 +61,143 @@ const Index = () => {
const [videoqn, setVideoqn] = useState([])
const [handleType, setHandleType] = useState('')
const [roadCodeHead, setRoadCodeHead] = useState('X')
const [roadCodeEnd, setRoadCodeEnd] = useState('')
const [otherType, setOtherType] = useState('') // -
const [patrolContentEdit, setPatrolContentEdit] = useState(false) //
const [patrolContent, setPatrolContent] = useState({
inspectionNoException: {
label: '巡查结果无异常',
selected: false,
value: '',
},
roadDamage: {
label: '路面损坏',
selected: false,
value: '',
},
securityDamage: {
label: '安防损坏',
selected: false,
value: '',
},
bridgeDamage: {
label: '桥梁损坏',
selected: false,
value: '',
},
culvertDamage: {
label: '涵洞损坏',
selected: false,
value: '',
},
securityDeficiency: {
label: '安防缺失',
selected: false,
value: '',
},
encounteredEnvironment: {
label: '路域环境',
selected: false,
value: '',
},
otherDescription: {
label: '其他',
selected: false,
value: '',
},
})
const [conserveInfo, setConserveInfo] = useState({
roadType: {
label: '路面类型',
value: '',
unit: '',
},
roadWidth: {
label: '路面宽度',
value: '',
unit: '米',
},
wrongLane: {
label: '错车道',
value: '',
unit: '个',
},
roadsideTrees: {
label: '行道树',
value: '',
unit: '棵',
},
roadsideDitch: {
label: '边沟',
value: '',
unit: '米',
},
guardrail: {
label: '护栏',
value: '',
unit: '米',
},
roadMarking: {
label: '标线',
value: '',
unit: '米',
},
})
const [conserveContent, setConserveContent] = useState({
maintenanceStaffCount: {
label: '本次养护共安排养护人员',
value: '',
unit: '人',
},
shoulderRepair: {
label: '整修路肩、边坡',
value: '',
unit: '平米',
},
ditchCleaning: {
label: '开挖、清理边坡',
value: '',
unit: '米',
},
asphaltRepair: {
label: '修补沥青路面',
value: '',
unit: '平米',
},
concreteRepair: {
label: '修补水泥路面',
value: '',
unit: '平米',
},
grassMowing: {
label: '除草',
value: '',
unit: '米',
},
treeWhitening: {
label: '行道树刷白',
value: '',
unit: '株/公里',
},
pileWhitening: {
label: '公里桩/百米桩刷漆',
value: '',
unit: '个',
},
guardrailMaintenance: {
label: '维修护栏',
value: '',
unit: '米',
},
endHeadRepair: {
label: '修复端头',
value: '',
unit: '块',
},
})
const prjType =
isAnomaly ?
[
@ -70,10 +207,11 @@ const Index = () => {
]
:
[
{ text: '无', value: '' },
{ text: '道路', value: 'road', onlyView: true },
{ text: '县道', value: 'countyRoad' },
{ text: '乡道', value: 'villageRoad' },
{ text: '村道', value: 'rusticRoad' },
{ text: '县道', value: 'countyRoad', onlyView: true },
{ text: '乡道', value: 'villageRoad', onlyView: true },
{ text: '村道', value: 'rusticRoad', onlyView: true },
{ text: '桥梁', value: 'bridge' },
{ text: '涵洞', value: 'culvert' },
{ text: '其他', value: 'other' },
@ -149,6 +287,30 @@ const Index = () => {
setConserveAfterPic(data.conserveAfterPic ? data.conserveAfterPic.map(item => ({ url: imgUrl + item })) : [])
setHandleId(data.id)
setVideo(data.videoUrl[0] ? imgUrl + data.videoUrl[0] : '')
setRoadCodeHead(data.codeRoad ? data.codeRoad.slice(0, 1) : '')
setRoadCodeEnd(data.codeRoad ? data.codeRoad.slice(1) : '')
if (data.reportType === 'patrol') {
let next = { ...patrolContent }
next.inspectionNoException.selected = data.inspectionNoException
Object.keys(patrolContent).forEach(key => {
if (data[key]) {
next[key].selected = true
next[key].value = data[key]
}
})
setPatrolContent(next)
} else if (data.reportType === 'conserve') {
let nextInfo = { ...conserveInfo }
Object.keys(conserveInfo).forEach(key => {
if (data[key]) nextInfo[key].value = data[key]
})
setConserveInfo(nextInfo)
let nextContent = { ...conserveContent }
Object.keys(conserveContent).forEach(key => {
if (data[key]) nextContent[key].value = data[key]
})
setConserveContent(nextContent)
}
if (data.handleContent) {
setHandleCenter(data.handleContent)
}
@ -159,6 +321,7 @@ const Index = () => {
Taro.showToast({ title: err.message || '请求出错', icon: 'none' })
})
} else { //
if (isPatrol) setProjectType('县道')
Taro.showLoading({ title: '加载中' })
let key = 'ODQBZ-3FZAU-6VIVL-2XXNM-F7CP7-WVFCY' // key
Taro.getLocation({
@ -258,14 +421,18 @@ const Index = () => {
function report() {
if (!canReport) { return }
if (
(isPatrol && (!projectType || !road))
(isPatrol && (!projectType || !road || !roadCodeEnd))
|| (isAnomaly && !road)
|| (kind === 'patrol' && Object.values(patrolContent).every(c => c.value.trim() === '') && !patrolContent.巡查结果无异常.selected)
|| (kind === 'conserve'
&& (Object.values(conserveInfo).every(c => c.value.trim() === '')
|| Object.values(conserveContent).every(c => c.value.trim() === '')))
) {
Taro.showToast({ title: '请完善必填信息', icon: 'none' })
return
}
if ((isPatrol || isAnomaly) && prjTypeSelector.indexOf(projectType) === -1) {
if (isAnomaly && prjTypeSelector.indexOf(projectType) === -1) {
Taro.showToast({ title: isAnomaly ? '反馈类型错误' : '工程类型错误', icon: 'none' })
return
}
@ -279,7 +446,6 @@ const Index = () => {
}
const reportProjectType = prjType.find(p => p.text == projectType)?.value || ''
let data = {
reportType: isPatrol ? reportType : kind,
projectType: reportProjectType,
@ -302,6 +468,24 @@ const Index = () => {
data['conserveUnderwayPic'] = conserveUnderwayImg
data['conserveAfterPic'] = conserveAfterImg
}
if (isPatrol) {
data.codeRoad = roadCodeHead + roadCodeEnd
if (otherType) data.projectType = otherType
if (kind === 'patrol') {
Object.keys(patrolContent).forEach(key => {
data[key] = patrolContent[key].value
})
data.inspectionNoException = patrolContent.inspectionNoException.selected
} else if (kind === 'conserve') {
Object.keys(conserveInfo).forEach(key => {
data[key] = key === 'roadType' ? conserveInfo[key].value : Number(conserveInfo[key].value)
})
Object.keys(conserveContent).forEach(key => {
data[key] = Number(conserveContent[key].value)
})
}
}
Taro.showModal({
title: '提示',
content: '您要进行信息上报么?',
@ -359,7 +543,7 @@ const Index = () => {
})
}
function handleInput({ detail: { value } }, type) {
function handleInput({ detail: { value } }, type, key) {
switch (type) {
case 'roadSectionStart':
setRoadSectionStart(value)
@ -389,6 +573,64 @@ const Index = () => {
case "wait":
setHandleCenter(value)
break;
case "roadCodeEnd":
setRoadCodeEnd(value)
if (value.length >= 9) {
for (const r of roadList) {
if (r.routeCode === roadCodeHead + value) {
setRoad(r.routeName)
setRoadSectionStart(r.startingPlaceName)
setRoadSectionEnd(r.stopPlaceName)
request.get(getReportList(), { limit: 1, page: 0, codeRoad: r.routeCode }).then(res => {
if (res.statusCode === 200 && res.data.length) {
request.get(getReportDetail(res.data[0].id)).then(detailRes => {
if (res.statusCode === 200) {
let nextInfo = { ...conserveInfo }
Object.keys(conserveInfo).forEach(key => {
if (detailRes.data[key]) nextInfo[key].value = detailRes.data[key]
})
setConserveInfo(nextInfo)
setPatrolContentEdit(false)
} else {
setPatrolContentEdit(true)
}
})
} else {
setPatrolContentEdit(true)
}
})
break;
}
}
}
break;
case "conserveInfo":
let nextInfo = { ...conserveInfo }
nextInfo[key].value = value
setConserveInfo(nextInfo)
break;
case "conserveContent":
let nextContent = { ...conserveContent }
nextContent[key].value = value
setConserveContent(nextContent)
break;
case "contentCheck":
let nextCheck = { ...patrolContent }
Object.keys(patrolContent).forEach(key => {
if (value.indexOf(key) !== -1) {
nextCheck[key].selected = true
} else {
nextCheck[key].selected = false
}
})
setPatrolContent(nextCheck)
break;
case "patrolContent":
let nextPatrolContent = { ...patrolContent }
nextPatrolContent[key].value = value
if (value) nextPatrolContent[key].selected = true
setPatrolContent(nextPatrolContent)
break;
default:
break;
}
@ -647,15 +889,56 @@ const Index = () => {
} */}
{
isPatrol ?
isPatrol ? <>
<View className='code-choice'>
<Text style={{ color: 'red' }}>*&nbsp;</Text>线路编码
<RadioGroup onChange={(e) => {
setRoadCodeHead(e.detail.value[0]);
setProjectType(e.detail.value[0] === 'X' ? '县道' : e.detail.value[0] === 'Y' ? '乡道' : '村道');
}}>
<Radio value='X' checked={roadCodeHead === 'X'} color='#0080EE' className='radio' disabled={isView}>X</Radio>
<Radio value='Y' checked={roadCodeHead === 'Y'} color='#0080EE' className='radio' disabled={isView}>Y</Radio>
<Radio value='C' checked={roadCodeHead === 'C'} color='#0080EE' className='radio' disabled={isView}>C</Radio>
</RadioGroup>
<Input
type='text'
placeholder={isView ? '' : '请输入线路编号'}
value={roadCodeEnd}
onInput={e => handleInput(e, 'roadCodeEnd')}
disabled={isView}
/>
</View>
<View className='code-choice'>
<Text style={{ color: 'red' }}>*&nbsp;</Text>道路类型
<Input
style={{ width: '30%' }}
type='text'
value={roadCodeHead === 'X' ? '县道' : roadCodeHead === 'Y' ? '乡道' : '村道'}
onInput={() => { }}
disabled={true}
/>
<Text>其他</Text>
<InputPicker
title='道路类型:'
placeholder='请选择道路类型'
value={projectType}
onInput={setProjectType}
width='30%'
star={false}
onlySelect
title=''
placeholder=''
value={otherType}
onInput={(value) => setOtherType(value === '无' ? '' : value)}
selector={prjTypeSelector}
isView={isView}
/> : ''
/>
</View>
<InputPicker
title='路线名称:'
placeholder='请输入路线名称'
value={road}
onInput={setRoad}
selector={sourceRoadSel}
isView={isView}
/>
</> : ''
}
{
@ -699,7 +982,7 @@ const Index = () => {
}
{
isPatrol || isAnomaly ?
isAnomaly ?
<InputPicker
key={123} // keyselector
title='所在道路:'
@ -711,7 +994,7 @@ const Index = () => {
/> : ''
}
{
isPatrol || isAnomaly ?
isAnomaly ?
<InputPickers
key={456} // keyselector
title='线路编码:'
@ -779,15 +1062,103 @@ const Index = () => {
disabled={isView}
/>
</View>
<AtTextarea
{
kind === 'patrol' && <View className='patrol-content'>
<View className='title'>
<View><Text style={{ color: 'red' }}>*&nbsp;</Text>巡查内容</View>
</View>
<View className='cell-box'>
<CheckboxGroup onChange={e => handleInput(e, 'contentCheck')}>
{
Object.keys(patrolContent).map(key => <View className='item'>
<Checkbox color='#0080EE' value={key} checked={patrolContent[key].selected} disabled={isView} />
<Text style={{ width: patrolContent[key].label === '巡查结果无异常' ? '100%' : '75px' }}>{patrolContent[key].label + (patrolContent[key].label !== '巡查结果无异常' ? ':' : '')}</Text>
{patrolContent[key].label !== '巡查结果无异常' && <Textarea
autoHeight
className='input'
placeholder={'具体内容'}
value={patrolContent[key].value}
onInput={e => handleInput(e, 'patrolContent', key)}
disabled={isView}
/>}
</View>)
}
</CheckboxGroup>
</View>
</View >
}
{
kind === 'conserve' && <View>
<View className='conserve-info'>
<View className='title'>
<View><Text style={{ color: 'red' }}>*&nbsp;</Text>养护基本信息</View>
{
(!patrolContentEdit && !isView) && <View style={{ color: '#0080EE' }} onClick={() => {
Taro.showModal({
title: '提示',
content: '是否要进行信息修改?',
success: function (res) {
if (res.confirm) {
setPatrolContentEdit(true)
} else if (res.cancel) {
}
}
})
}}>修改</View>
}
</View>
<View>
<View className='grid-box'>
{
Object.keys(conserveInfo).map(key => <View className='item'>
<Text className='label'>{conserveInfo[key].label}</Text>
<Input
className='input'
type={key === 'roadType' ? 'text' : 'digit'}
placeholder={patrolContentEdit ? '请输入' : ''}
value={conserveInfo[key].value}
onInput={e => handleInput(e, 'conserveInfo', key)}
disabled={isView || !patrolContentEdit}
/>
<Text>{conserveInfo[key].unit}</Text>
</View>)
}
</View>
</View>
</View>
<View className='conserve-content'>
<View className='title'>
<View><Text style={{ color: 'red' }}>*&nbsp;</Text>养护作业内容</View>
</View>
<View className='cell-box'>
{
Object.keys(conserveContent).map(key => <View className='item'>
<Text className='label'>{conserveContent[key].label}</Text>
<Input
className='input'
type='digit'
placeholder={'请输入'}
value={conserveContent[key].value}
onInput={e => handleInput(e, 'conserveContent', key)}
disabled={isView}
/>
<Text>{conserveContent[key].unit}</Text>
</View>)
}
</View>
</View>
</View>
}
{
!isPatrol ? <AtTextarea
title='巡查内容:'
placeholder={isView ? '' : '请输入具体内容'}
value={content}
onChange={(v, e) => handleInput(e, 'content')}
disabled={isView}
maxLength={50}
/>
/> : null
}
{
reportType === 'patrol' || isRoad || isAnomaly ?
<View className='patrol-img'>
@ -870,7 +1241,7 @@ const Index = () => {
/>
}
<View className='horizontal-line hl-two'>
{/* <View className='horizontal-line hl-two'>
<View className='circle c-two'></View>
<View className='text t-two'>养护中</View>
</View>
@ -889,7 +1260,7 @@ const Index = () => {
onChange={(files, operationType, index) => handleImgChange(files, operationType, index, 'conserveUnderwayPic')}
onImageClick={handleImgClick}
/>
}
} */}
<View className='horizontal-line hl-three'>
<View className='circle c-three'></View>

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

@ -5,6 +5,7 @@ page {
.patrol {
font-size: 28px;
padding-bottom: 50px;
}
.report-type {
@ -46,6 +47,7 @@ page {
height: 14px;
margin: 0 10px;
}
.img-l {
width: 24px;
height: 14px;
@ -101,6 +103,7 @@ page {
font-size: 24px;
}
}
.hl-one {
background-color: #DFDFDF;
@ -112,6 +115,7 @@ page {
color: #999999;
}
}
.hl-two {
background-color: #f7d3a5;
@ -123,6 +127,7 @@ page {
color: #FE9B1C;
}
}
.hl-three {
background-color: #a0f3a4;
@ -162,4 +167,118 @@ page {
background-color: #C23434;
border-color: #C23434;
}
.code-choice {
height: 96px;
background-color: #fff;
display: flex;
justify-content: start;
align-items: center;
margin-bottom: 5px;
padding-left: 12px;
.radio {
margin-right: 10px;
}
}
.patrol-content {
background-color: #fff;
margin-bottom: 5px;
padding: 0 12px;
.title {
display: flex;
justify-content: space-between;
align-items: center;
height: 60px;
}
.cell-box {
width: 100%;
.item {
min-height: 60px;
display: flex;
justify-content: start;
align-items: center;
margin-left: 12px;
.input {
width: 70%;
}
}
}
}
.conserve-info {
background-color: #fff;
margin-bottom: 5px;
padding: 0 12px;
.title {
display: flex;
justify-content: space-between;
align-items: center;
height: 60px;
}
.grid-box {
display: flex;
justify-content: start;
align-items: center;
flex-wrap: wrap;
width: 100%;
.item {
width: 45%;
height: 60px;
display: flex;
justify-content: start;
align-items: center;
margin-left: 12px;
.label {
width: 140px;
}
.input {
width: 140px;
}
}
}
}
.conserve-content {
background-color: #fff;
margin-bottom: 5px;
padding: 0 12px;
.title {
display: flex;
justify-content: space-between;
align-items: center;
height: 60px;
}
.cell-box {
width: 100%;
.item {
height: 60px;
display: flex;
justify-content: start;
align-items: center;
margin-left: 12px;
.label {
width: 60%;
}
.input {
width: 140px;
}
}
}
}
}
Loading…
Cancel
Save