@ -0,0 +1,144 @@ |
|||||
|
import React, { useState, useEffect } from 'react' |
||||
|
import Taro, { useDidShow } from '@tarojs/taro' |
||||
|
import { View, Picker, Input, Image } from '@tarojs/components' |
||||
|
import moment from 'moment' |
||||
|
import './index.scss' |
||||
|
import NoData from '@/components/no-data/noData' |
||||
|
import request from '@/services/request' |
||||
|
import { getReportList } from '@/services/api'; |
||||
|
import chevronDown from '../../static/img/patrolView/chevron-down.png' |
||||
|
import searchIcon from '../../static/img/patrolView/search.png' |
||||
|
import cardImg from '../../static/img/patrolView/card-img.png' |
||||
|
import patrolIcon from '../../static/img/patrolView/patrol.svg' |
||||
|
import patrolActiveIcon from '../../static/img/patrolView/patrol-active.svg' |
||||
|
import conserveIcon from '../../static/img/patrolView/conserve.svg' |
||||
|
import conserveActiveIcon from '../../static/img/patrolView/conserve-active.svg' |
||||
|
|
||||
|
function Index() { |
||||
|
const [isPatrol, setIsPatrol] = useState(true) |
||||
|
const [datePicker, setDatePicker] = useState(moment().format('YYYY-MM-DD')) |
||||
|
const [listData, setListData] = useState([]) |
||||
|
const [inputSite, setInputSite] = useState('') |
||||
|
const [page, setPage] = useState(0) |
||||
|
const [total, setTotal] = useState(0) |
||||
|
const [num, setNum] = useState(Math.random()) |
||||
|
const [systemInfo, setSystemInfo] = useState('') |
||||
|
|
||||
|
const userInfo = Taro.getStorageSync('userInfo') || {}; |
||||
|
|
||||
|
function dealError(error) { |
||||
|
Taro.showToast({ |
||||
|
title: error, |
||||
|
icon: 'none', |
||||
|
duration: 1500 |
||||
|
}); |
||||
|
throw new Error(error); |
||||
|
} |
||||
|
useEffect(() => { |
||||
|
request.get(getReportList(),{}, { hideErrorToast: true, hideLoading: true }).then(res => { |
||||
|
if (res.statusCode == 200) { |
||||
|
console.log(res); |
||||
|
setListData(res.data) |
||||
|
return res.data; |
||||
|
} else { |
||||
|
dealError(res.data.message || '请求出错'); |
||||
|
} |
||||
|
}, err => { |
||||
|
dealError(err.message || '请求出错'); |
||||
|
}); |
||||
|
}, []) |
||||
|
|
||||
|
useDidShow(() => { |
||||
|
let refresh = Taro.getStorageSync('refresh'); // 返回列表需要刷新 |
||||
|
if (refresh) { |
||||
|
setPage(0) |
||||
|
setNum(Math.random()) |
||||
|
Taro.removeStorageSync('refresh'); // 返回列表需要刷新 |
||||
|
} |
||||
|
Taro.getSystemInfo({ |
||||
|
success: (res) => { |
||||
|
// windows | mac为pc端 |
||||
|
// android | ios为手机端 |
||||
|
setSystemInfo(res.platform); |
||||
|
} |
||||
|
}); |
||||
|
}) |
||||
|
|
||||
|
const onTypeChange = bool => { |
||||
|
setIsPatrol(bool) |
||||
|
} |
||||
|
|
||||
|
const onDateChange = e => { |
||||
|
setDatePicker(e.detail.value); |
||||
|
} |
||||
|
|
||||
|
const handleConfirm = () => { |
||||
|
setPage(0) |
||||
|
setListData([]); |
||||
|
setTotal(0); |
||||
|
setNum(Math.random()) |
||||
|
} |
||||
|
|
||||
|
const handleInput = e => { |
||||
|
setInputSite(e.detail.value); |
||||
|
if (!e.detail.value) { |
||||
|
setPage(0) |
||||
|
setListData([]); |
||||
|
setTotal(0); |
||||
|
setNum(Math.random()) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return ( |
||||
|
<View> |
||||
|
<View className='type-box'> |
||||
|
<View className='item' onClick={() => onTypeChange(true)}> |
||||
|
<Image className='type-img' src={isPatrol ? patrolActiveIcon : patrolIcon} /> |
||||
|
<View style={{color: isPatrol ? '#346FC2': '#999999'}}>巡查</View> |
||||
|
</View> |
||||
|
<View className='line'></View> |
||||
|
<View className='item' onClick={() => onTypeChange(false)}> |
||||
|
<Image className='type-img' src={isPatrol ? conserveIcon : conserveActiveIcon} /> |
||||
|
<View style={{color: isPatrol ? '#999999': '#346FC2'}}>养护</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
<View className='filter-box'> |
||||
|
<View className='filter-item'> |
||||
|
<View style={{ float: 'left', marginLeft: '20rpx', color: '#333' }}>日期:</View> |
||||
|
<Picker className='picker' style={{ overflow: 'hidden', float: 'left' }} mode='date' end={(systemInfo == 'windows' || systemInfo == 'mac') ? moment().add(1, 'd').format('YYYY-MM-DD') : moment().format('YYYY-MM-DD')} onChange={onDateChange}> |
||||
|
<View className='filter-name'>{datePicker || '请选择'}</View> |
||||
|
<Image className='filter-img' src={chevronDown} /> |
||||
|
</Picker> |
||||
|
</View> |
||||
|
<View class='head-search'> |
||||
|
<Image className='search-img' src={searchIcon} /> |
||||
|
<Input class='heard-search-input' value={inputSite} placeholder='请输入场所名称' onConfirm={handleConfirm} onInput={handleInput} /> |
||||
|
</View> |
||||
|
</View> |
||||
|
|
||||
|
<View style={{ marginTop: '110px' }}> |
||||
|
{ |
||||
|
listData && listData.length > 0 ? listData && listData.map((e, index) => { |
||||
|
return ( |
||||
|
<View className='cardBox' key={index} onClick={() => handleDetail(index)}> |
||||
|
<View className='card-item' > |
||||
|
<Image className='card-bg' src={cardImg} /> |
||||
|
<View className='card-position'> |
||||
|
<View className='card-title'>{e.road}</View> |
||||
|
<View style={{ float: 'left', width: '100%', fontSize: '28rpx', marginTop: '16rpx' }}> |
||||
|
<View style={{ float: 'left' }}>填报人:</View> |
||||
|
<View style={{ float: 'left' }}>{e.user.name}</View> |
||||
|
</View> |
||||
|
<View className='card-date'>{moment(e.time).format('YYYY-MM-DD HH:mm:ss')}</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
</View> |
||||
|
) |
||||
|
}) : <NoData top='400rpx'></NoData> |
||||
|
} |
||||
|
</View> |
||||
|
</View> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
export default Index |
@ -0,0 +1,139 @@ |
|||||
|
page { |
||||
|
background-color: #f6f6f6; |
||||
|
|
||||
|
.type-box { |
||||
|
position: fixed; |
||||
|
top: 0px; |
||||
|
width: 100%; |
||||
|
z-index: 100; |
||||
|
background-color: #fff; |
||||
|
height: 80px; |
||||
|
display: flex; |
||||
|
justify-content: space-around; |
||||
|
align-items: center; |
||||
|
|
||||
|
.item { |
||||
|
flex-grow: 1; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
|
||||
|
.type-img { |
||||
|
width: 40px; |
||||
|
height: 40px; |
||||
|
margin: 0 10px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.line { |
||||
|
width: 1px; |
||||
|
height: 30px; |
||||
|
background-color: #f6f6f6; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.filter-box { |
||||
|
position: fixed; |
||||
|
top: 80px; |
||||
|
display: flex; |
||||
|
width: 100%; |
||||
|
z-index: 100; |
||||
|
background: #fff; |
||||
|
color: #999999; |
||||
|
font-size: 28rpx; |
||||
|
border-top: 2rpx solid #f6f6f6; |
||||
|
|
||||
|
.filter-item { |
||||
|
overflow: hidden; |
||||
|
height: 98rpx; |
||||
|
line-height: 98rpx; |
||||
|
flex: 1; |
||||
|
|
||||
|
.filter-name { |
||||
|
float: left; |
||||
|
// margin-left: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.filter-img { |
||||
|
width: 14px; |
||||
|
height: 8px; |
||||
|
float: left; |
||||
|
margin: 46rpx 20rpx 18rpx 10rpx; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.head-search { |
||||
|
width: 400rpx; |
||||
|
display: flex; |
||||
|
background: #fff; |
||||
|
padding: 10rpx 26rpx 15rpx; |
||||
|
box-sizing: border-box; |
||||
|
border-radius: 50rpx; |
||||
|
box-shadow: 0 8rpx 10rpx 0rpx #00000008; |
||||
|
border: 2rpx solid #00000011; |
||||
|
height: 68rpx; |
||||
|
line-height: 68rpx; |
||||
|
margin: 14rpx 30rpx 14rpx 0; |
||||
|
|
||||
|
.search-img { |
||||
|
width: 36rpx; |
||||
|
height: 36rpx; |
||||
|
margin-top: 5rpx; |
||||
|
} |
||||
|
|
||||
|
.heard-search-input { |
||||
|
margin-left: 26rpx; |
||||
|
font-size: 28rpx; |
||||
|
width: 100%; |
||||
|
color: #333; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.cardBox { |
||||
|
width: 690rpx; |
||||
|
margin: 40rpx auto; |
||||
|
|
||||
|
.card-item { |
||||
|
position: relative; |
||||
|
margin-bottom: 10rpx; |
||||
|
|
||||
|
.card-bg { |
||||
|
width: 100%; |
||||
|
height: 260rpx; |
||||
|
display: block; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.card-position { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
width: 88%; |
||||
|
padding: 16rpx 0 16rpx 36rpx; |
||||
|
overflow: hidden; |
||||
|
text-align: justify; |
||||
|
|
||||
|
.card-title { |
||||
|
font-size: 28rpx; |
||||
|
color: #333333; |
||||
|
float: left; |
||||
|
margin-bottom: 30rpx; |
||||
|
width: 470rpx; |
||||
|
text-overflow: ellipsis; |
||||
|
white-space: nowrap; |
||||
|
overflow: hidden; |
||||
|
margin-top: 8rpx; |
||||
|
} |
||||
|
|
||||
|
.card-date { |
||||
|
float: left; |
||||
|
font-size: 28rpx; |
||||
|
color: #999999; |
||||
|
margin-top: 30rpx; |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 174 B |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,110 @@ |
|||||
|
import React from 'react' |
||||
|
import { useEffect, useRef } from 'react'; |
||||
|
import * as echarts from 'echarts'; |
||||
|
|
||||
|
const PieChart = (props) => { |
||||
|
|
||||
|
const { width, height, data, colorList, underColorList, total, text } = props |
||||
|
|
||||
|
const chartRef = useRef(null); |
||||
|
let name = [], emptyName = [] |
||||
|
// const name = data?.map(d)
|
||||
|
data?.forEach(d => { |
||||
|
name.push(d.name) |
||||
|
emptyName.push({ |
||||
|
name: '', |
||||
|
value: d.value |
||||
|
}) |
||||
|
}) |
||||
|
useEffect(() => { |
||||
|
let chartInstance = echarts.init(chartRef.current); |
||||
|
const option = { |
||||
|
tooltip: { |
||||
|
trigger: "item", |
||||
|
}, |
||||
|
legend: { |
||||
|
orient: "vertical", |
||||
|
itemWidth: 10, |
||||
|
itemHeight: 10, |
||||
|
right: '30%', |
||||
|
top: 'center', |
||||
|
align: 'left', |
||||
|
data: name, |
||||
|
textStyle: { |
||||
|
color: "#fff", |
||||
|
}, |
||||
|
}, |
||||
|
grid: { |
||||
|
left: '10%' |
||||
|
}, |
||||
|
// title: [
|
||||
|
// {
|
||||
|
// text: text,
|
||||
|
// top: "58%",
|
||||
|
// left: '16%',
|
||||
|
// textStyle: {
|
||||
|
// color: "#E9F7FF",
|
||||
|
// fontSize: 14,
|
||||
|
// },
|
||||
|
// },
|
||||
|
// {
|
||||
|
// text: total,
|
||||
|
// top: "40%",
|
||||
|
// left: '10%',
|
||||
|
// textStyle: {
|
||||
|
// fontSize: "30",
|
||||
|
// color: "#FFFFFF",
|
||||
|
// fontFamily: "YouSheBiaoTiHei",
|
||||
|
// },
|
||||
|
// },
|
||||
|
// ],
|
||||
|
series: [ |
||||
|
{ |
||||
|
name: "底层背景", |
||||
|
type: "pie", |
||||
|
hoverAnimation: false, |
||||
|
legendHoverLink: false, |
||||
|
radius: ["60%", "72%"], |
||||
|
center: ['25%', '50%'], |
||||
|
color: underColorList, |
||||
|
label: { |
||||
|
show: false |
||||
|
}, |
||||
|
labelLine: { |
||||
|
show: false |
||||
|
}, |
||||
|
tooltip: { |
||||
|
show: false, |
||||
|
}, |
||||
|
|
||||
|
data: emptyName, |
||||
|
}, |
||||
|
{ |
||||
|
name: "已绿化里程统计", |
||||
|
type: "pie", |
||||
|
radius: ["67%", "80%"], |
||||
|
center: ['25%', '50%'], |
||||
|
color: colorList, |
||||
|
label: { |
||||
|
show: false |
||||
|
}, |
||||
|
data: data, |
||||
|
}, |
||||
|
], |
||||
|
}; |
||||
|
|
||||
|
chartInstance.setOption(option); |
||||
|
window.addEventListener('resize', () => { |
||||
|
if (chartInstance) { |
||||
|
chartInstance.resize() |
||||
|
} |
||||
|
}) |
||||
|
}, []) |
||||
|
return ( |
||||
|
<div style={{ width: width || '100%', height: height || '100%' }}> |
||||
|
<div ref={chartRef} style={{ width: '100%', height: '100%' }}></div> |
||||
|
</div> |
||||
|
|
||||
|
) |
||||
|
} |
||||
|
export default PieChart |
@ -1,8 +1,13 @@ |
|||||
import React from 'react' |
import React from 'react' |
||||
|
import Left from './left' |
||||
|
import Right from './right' |
||||
|
|
||||
const Operation = () => { |
const Operation = () => { |
||||
return ( |
return ( |
||||
<>运营</> |
<div style={{ display: 'flex', width: '100%',height: '100%',justifyContent: 'space-between' }}> |
||||
|
<Left /> |
||||
|
<Right /> |
||||
|
</div> |
||||
) |
) |
||||
} |
} |
||||
export default Operation |
export default Operation |
@ -0,0 +1,180 @@ |
|||||
|
import React, { useMemo, useState, useEffect } from 'react'; |
||||
|
import { SearchOutlined } from '@ant-design/icons'; |
||||
|
import { Col, Row, Input, Tree } from 'antd' |
||||
|
import Module from '../../public/module' |
||||
|
|
||||
|
const { Search } = Input; |
||||
|
const x = 3; |
||||
|
const y = 2; |
||||
|
const z = 1; |
||||
|
const defaultData = []; |
||||
|
|
||||
|
const generateData = (_level, _preKey, _tns) => { |
||||
|
const preKey = _preKey || '0'; |
||||
|
const tns = _tns || defaultData; |
||||
|
const children = []; |
||||
|
|
||||
|
for (let i = 0; i < x; i++) { |
||||
|
const key = `${preKey}-${i}`; |
||||
|
tns.push({ |
||||
|
title: key, |
||||
|
key, |
||||
|
}); |
||||
|
|
||||
|
if (i < y) { |
||||
|
children.push(key); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (_level < 0) { |
||||
|
return tns; |
||||
|
} |
||||
|
|
||||
|
const level = _level - 1; |
||||
|
children.forEach((key, index) => { |
||||
|
tns[index].children = []; |
||||
|
return generateData(level, key, tns[index].children); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
generateData(z); |
||||
|
const dataList = []; |
||||
|
|
||||
|
const generateList = (data) => { |
||||
|
for (let i = 0; i < data.length; i++) { |
||||
|
const node = data[i]; |
||||
|
const { key } = node; |
||||
|
dataList.push({ |
||||
|
key, |
||||
|
title: key, |
||||
|
}); |
||||
|
|
||||
|
if (node.children) { |
||||
|
generateList(node.children); |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
generateList(defaultData); |
||||
|
|
||||
|
const getParentKey = (key, tree) => { |
||||
|
let parentKey; |
||||
|
|
||||
|
for (let i = 0; i < tree.length; i++) { |
||||
|
const node = tree[i]; |
||||
|
|
||||
|
if (node.children) { |
||||
|
if (node.children.some((item) => item.key === key)) { |
||||
|
parentKey = node.key; |
||||
|
} else if (getParentKey(key, node.children)) { |
||||
|
parentKey = getParentKey(key, node.children); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return parentKey; |
||||
|
}; |
||||
|
|
||||
|
const Left = () => { |
||||
|
|
||||
|
useEffect(() => { |
||||
|
|
||||
|
}, []) |
||||
|
|
||||
|
const style = { height: "97%", marginTop: "3%" } |
||||
|
const [expandedKeys, setExpandedKeys] = useState([]); |
||||
|
const [searchValue, setSearchValue] = useState(''); |
||||
|
const [autoExpandParent, setAutoExpandParent] = useState(true); |
||||
|
|
||||
|
const onExpand = (newExpandedKeys) => { |
||||
|
setExpandedKeys(newExpandedKeys); |
||||
|
setAutoExpandParent(false); |
||||
|
}; |
||||
|
|
||||
|
const onChange = (e) => { |
||||
|
const { value } = e.target; |
||||
|
const newExpandedKeys = dataList |
||||
|
.map((item) => { |
||||
|
if (item.title.indexOf(value) > -1) { |
||||
|
return getParentKey(item.key, defaultData); |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
}) |
||||
|
.filter((item, i, self) => item && self.indexOf(item) === i); |
||||
|
setExpandedKeys(newExpandedKeys); |
||||
|
setSearchValue(value); |
||||
|
setAutoExpandParent(true); |
||||
|
}; |
||||
|
|
||||
|
const treeData = useMemo(() => { |
||||
|
const loop = (data) => |
||||
|
data.map((item) => { |
||||
|
const strTitle = item.title; |
||||
|
const index = strTitle.indexOf(searchValue); |
||||
|
const beforeStr = strTitle.substring(0, index); |
||||
|
const afterStr = strTitle.slice(index + searchValue.length); |
||||
|
const title = |
||||
|
index > -1 ? ( |
||||
|
<span> |
||||
|
{beforeStr} |
||||
|
<span className="site-tree-search-value">{searchValue}</span> |
||||
|
{afterStr} |
||||
|
</span> |
||||
|
) : ( |
||||
|
<span>{strTitle}</span> |
||||
|
); |
||||
|
|
||||
|
if (item.children) { |
||||
|
return { |
||||
|
title, |
||||
|
key: item.key, |
||||
|
children: loop(item.children), |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
title, |
||||
|
key: item.key, |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
|
return loop(defaultData); |
||||
|
}, [searchValue]); |
||||
|
return ( |
||||
|
<div style={{ display: 'flex', flexDirection: 'column', width: "23%", height: "100%", marginLeft: "1%" }}> |
||||
|
<Module style={style} title={"公交车辆信息"}> |
||||
|
<div style={{ width: '90%', height: '96', margin: '2% 5%', }}> |
||||
|
<div style={{ border: '1px solid rgba(10, 114, 255, 1)', backgroundColor: 'rgba(10, 114, 255, 0.1)' }}> |
||||
|
<img src='assets/images/quanju/search.png' style={{ width: '5%', margin: '0 1.5% 1% 3.5%' }} /> |
||||
|
<Input |
||||
|
style={{ |
||||
|
width: '90%', |
||||
|
background: 'none', |
||||
|
backgroundColor: 'none', |
||||
|
color: 'rgba(216, 240, 255, 0.8)', |
||||
|
border: 'none', |
||||
|
boxShadow: 'none', |
||||
|
}} |
||||
|
placeholder="请输入车牌号" |
||||
|
onChange={onChange} |
||||
|
/> |
||||
|
</div> |
||||
|
<Tree |
||||
|
rootStyle={{ |
||||
|
background: 'none', |
||||
|
borderColor: 'none', |
||||
|
color: 'rgba(255, 255, 255, 1)' |
||||
|
}} |
||||
|
onExpand={onExpand} |
||||
|
expandedKeys={expandedKeys} |
||||
|
autoExpandParent={autoExpandParent} |
||||
|
treeData={treeData} |
||||
|
/> |
||||
|
</div> |
||||
|
</Module> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default Left; |
@ -0,0 +1,9 @@ |
|||||
|
import React from 'react' |
||||
|
|
||||
|
const Right = () => { |
||||
|
return ( |
||||
|
<div style={{ display: 'flex', flexDirection: 'column', width: "23%", height: "100%", marginRight: "1%", }}>555555555 |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
export default Right |