Initial commit
BIN
src/assets/background.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
src/assets/blue.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/blueBorder.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/blueTitle.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/assets/cardBorder.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
src/assets/chain.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/countBorder.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/green.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/greenBorder.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/greyBorder.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/header.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
src/assets/indigoBorder.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
src/assets/light.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/numberBorder.png
Normal file
|
After Width: | Height: | Size: 433 B |
BIN
src/assets/redTitle.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
src/assets/search.png
Normal file
|
After Width: | Height: | Size: 540 B |
BIN
src/assets/searchWhite.png
Normal file
|
After Width: | Height: | Size: 607 B |
BIN
src/assets/shape/car.png
Normal file
|
After Width: | Height: | Size: 563 B |
BIN
src/assets/shape/electricCars.png
Normal file
|
After Width: | Height: | Size: 372 B |
BIN
src/assets/shape/inSchool.png
Normal file
|
After Width: | Height: | Size: 701 B |
BIN
src/assets/shape/other.png
Normal file
|
After Width: | Height: | Size: 404 B |
BIN
src/assets/shape/outSchool.png
Normal file
|
After Width: | Height: | Size: 714 B |
BIN
src/assets/show.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/assets/time_box.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/assets/title.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
src/assets/titleBorder.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
src/assets/titleBorder2.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
src/assets/titleBorder3.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
src/assets/titleBorder4.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
src/assets/yellow.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/yellowTitle.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
380
src/components/CarModalPage/index.jsx
Normal file
@@ -0,0 +1,380 @@
|
||||
import style from "./index.less";
|
||||
import {ScrollBoard} from "@jiaminghi/data-view-react";
|
||||
import {forwardRef, useEffect, useImperativeHandle, useState} from "react";
|
||||
import modalApi from "@/https/apis/modalApi";
|
||||
import rightPageApi from "@/https/apis/rightPageApi";
|
||||
import {ConfigProvider} from 'antd';
|
||||
import zh_CN from 'antd/es/locale/zh_CN';
|
||||
import dayjs from "dayjs";
|
||||
import DatePicker from "@/components/DatePicker/index";
|
||||
const {RangePicker} = DatePicker;
|
||||
const CarModalPage = ({}, ref) => {
|
||||
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [carVisible, setCarVisible] = useState(true)
|
||||
const [illegalTypeList, setIllegalTypeList] = useState([])
|
||||
//轮播表
|
||||
const [illegalList, setIllegalList] = useState([])
|
||||
const [illegalLists, setIllegalLists] = useState([])
|
||||
//图片列表
|
||||
const [imgList, setImgList] = useState([])
|
||||
//详情弹框的显示
|
||||
const [detailVisible, setDetailVisible] = useState(false);
|
||||
//查询参数
|
||||
const [illegalParams, setIllegalParams] = useState({
|
||||
vehicleTypeId: "", ruleId: ""
|
||||
})
|
||||
//违规的学院
|
||||
const [collegeList, setCollegeList] = useState([])
|
||||
const [searchText, setSearchText] = useState('')
|
||||
const [configDetails, setConfigDetails] = useState({})
|
||||
|
||||
useEffect(() => {
|
||||
carTypeList()
|
||||
getCollegeList()
|
||||
whereClick()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
console.log(illegalParams)
|
||||
getIllegalList(illegalParams)
|
||||
getIllegalType(illegalParams.vehicleTypeId)
|
||||
}, [illegalParams])
|
||||
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
showModal
|
||||
}))
|
||||
|
||||
///////////////////////////////////// 逻辑方法
|
||||
|
||||
/**
|
||||
* 显示弹窗
|
||||
*/
|
||||
const showModal = (params, date) => {
|
||||
setVisible(true);
|
||||
whereClick(params, date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断从哪里点
|
||||
* @param params
|
||||
* @param date
|
||||
*/
|
||||
const whereClick = (params, date) => {
|
||||
setCarVisible(true)
|
||||
date = dayjs()
|
||||
let tempDate = {
|
||||
startTime: dayjs(),
|
||||
endTime: dayjs()
|
||||
}
|
||||
//圆饼图
|
||||
if (params?.illegalType) {
|
||||
setIllegalParams({
|
||||
...params,
|
||||
ruleId: params.id,
|
||||
startTime: tempDate.startTime.add(-7, 'day').format('YYYY-MM-DD'),
|
||||
endTime: tempDate.endTime.format('YYYY-MM-DD')
|
||||
})
|
||||
return
|
||||
}
|
||||
//柱状图
|
||||
if (params?.type) {
|
||||
setIllegalParams({...params, startTime: '2022-' + params.type, endTime: '2022-' + params.type})
|
||||
}
|
||||
//横向图
|
||||
if (params?.collegeNo) {
|
||||
setIllegalParams({
|
||||
...params,
|
||||
no: params.collegeNo,
|
||||
startTime: date.format('YYYY-MM') + '-01',
|
||||
endTime: date.add(1, 'month').format('YYYY-MM') + '-01'
|
||||
})
|
||||
}
|
||||
if (params?.detail) {
|
||||
console.log(params)
|
||||
setDetailVisible(true)
|
||||
setCarVisible(false)
|
||||
let tempData = {
|
||||
headerHeight: 50,
|
||||
headerBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
oddRowBGC: 'rgba(0,0,0,0)',
|
||||
evenRowBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
columnWidth: [150, 145, 155, 155, 50],
|
||||
index: true,
|
||||
align: ["center"],
|
||||
rowNum: 1,
|
||||
header: [
|
||||
"<span style='color: #BDFF79;'>车牌号</span>",
|
||||
"<span style='color: #BDFF79;'>车主</span>",
|
||||
"<span style='color: #BDFF79;'>执行人</span>",
|
||||
"<span style='color: #BDFF79;'>扣分</span>",
|
||||
],
|
||||
data: [
|
||||
[
|
||||
params.name.row[0],
|
||||
params.name.row[3]?.replace(/<[^>]*>/g, ""),
|
||||
params.name.row[4]?.replace(/<[^>]*>/g, ""),
|
||||
params.name.row[2],
|
||||
],
|
||||
],
|
||||
}
|
||||
setConfigDetails(tempData)
|
||||
setImgList([
|
||||
params.name.row[5]?.replace(/<[^>]*>/g, ""),
|
||||
])
|
||||
}
|
||||
//车辆类型
|
||||
if (params?.vehicleTypeId) {
|
||||
setIllegalParams({...params})
|
||||
}
|
||||
//日期
|
||||
if (params?.title === '今日') {
|
||||
tempDate.startTime = tempDate.startTime.format('YYYY-MM-DD')
|
||||
tempDate.endTime = tempDate.startTime
|
||||
setIllegalParams({...params, startTime: tempDate.startTime, endTime: tempDate.endTime})
|
||||
} else if (params?.title === '昨日') {
|
||||
tempDate.startTime = tempDate.startTime.add(-1, 'day').format('YYYY-MM-DD')
|
||||
tempDate.endTime = tempDate.startTime
|
||||
setIllegalParams({...params, startTime: tempDate.startTime, endTime: tempDate.endTime})
|
||||
} else if (params?.title === '上月') {
|
||||
tempDate.startTime = tempDate.startTime.add(-1, 'month').format('YYYY-MM') + '-01'
|
||||
tempDate.endTime = tempDate.endTime.format('YYYY-MM') + '-01'
|
||||
setIllegalParams({...params, startTime: tempDate.startTime, endTime: tempDate.endTime})
|
||||
} else if (params?.title === '本月') {
|
||||
tempDate.startTime = tempDate.startTime.format('YYYY-MM') + '-01'
|
||||
tempDate.endTime = tempDate.endTime.add(1, 'month').format('YYYY-MM') + '-01'
|
||||
setIllegalParams({...params, startTime: tempDate.startTime, endTime: tempDate.endTime})
|
||||
}
|
||||
}
|
||||
|
||||
const getIllegalList = () => {
|
||||
modalApi.illegalList({
|
||||
...illegalParams,
|
||||
keyword: searchText,
|
||||
startTime: illegalParams?.startTime,
|
||||
endTime: illegalParams?.endTime
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
setIllegalList(res.data.map(it => {
|
||||
return [
|
||||
`<span>${it.vehicleType}</span>`,
|
||||
`<span style='margin-right:50px'>${it.plateNo}</span>`,
|
||||
`<span>   ${it.ruleName}</span>`,
|
||||
`<span>   ${"  " + it.score}</span>`,
|
||||
`<span style='display:none'>${it.userName}</span>`,
|
||||
`<span style='display:none'>${it.reportUserName}</span>`,
|
||||
`<span style='display:none'>${it.imgs}</span>`,
|
||||
]
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 点击获取详情
|
||||
* @param val
|
||||
*/
|
||||
const detailClick = (val) => {
|
||||
console.log(val)
|
||||
setDetailVisible(true)
|
||||
let tempData = {
|
||||
...config, data: [
|
||||
[
|
||||
val.row[2],
|
||||
val.row[5]?.replace(/<[^>]*>/g, ""),
|
||||
val.row[6]?.replace(/<[^>]*>/g, ""),
|
||||
val.row[4],
|
||||
],
|
||||
],
|
||||
rowNum: 1,
|
||||
header: [
|
||||
"<span style='color: #BDFF79;'>车牌号</span>",
|
||||
"<span style='color: #BDFF79;'>车主</span>",
|
||||
"<span style='color: #BDFF79;'>执行人</span>",
|
||||
"<span style='color: #BDFF79;'>扣分</span>",
|
||||
],
|
||||
}
|
||||
setImgList([
|
||||
val.row[7]?.replace(/<[^>]*>/g, ""),
|
||||
val?.row[8]?.replace(/<[^>]*>/g, ""),
|
||||
])
|
||||
setConfigDetails(tempData)
|
||||
}
|
||||
|
||||
/**
|
||||
* 车辆类型列表
|
||||
* @param key
|
||||
*/
|
||||
const carTypeList = (key) => {
|
||||
modalApi.carTypeList(key).then(res => {
|
||||
if (res.code === 200) {
|
||||
setIllegalTypeList(res.data.map(it => {
|
||||
return {
|
||||
name: it.name,
|
||||
value: it.id,
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 违规类型列表
|
||||
* @param key
|
||||
*/
|
||||
const getIllegalType = (key) => {
|
||||
modalApi.illegalTypeList(key).then(res => {
|
||||
if (res.code === 200) {
|
||||
setIllegalLists(res.data.map(it => {
|
||||
return {
|
||||
name: it.name,
|
||||
value: it.id,
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getCollegeList = () => {
|
||||
rightPageApi.collegeCount('2022-03-01').then(res => {
|
||||
if (res.code == 200) {
|
||||
setCollegeList(res.data.map(it => {
|
||||
return {
|
||||
name: it.collegeName,
|
||||
value: it.collegeNo,
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//////////////////////////////// 页面渲染
|
||||
|
||||
if (!visible) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
let config = {
|
||||
rowNum: 6, //表格行数
|
||||
headerHeight: 50,
|
||||
headerBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
oddRowBGC: 'rgba(0,0,0,0)',
|
||||
evenRowBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
columnWidth: [150, 145, 155, 155, 50],
|
||||
index: true,
|
||||
align: ["center"],
|
||||
header: [
|
||||
"<span style='color: #BDFF79;'>车型</span>",
|
||||
"<span style='color: #BDFF79;'>车牌</span>",
|
||||
"<span style='color: #BDFF79;'>违规</span>",
|
||||
"<span style='color: #BDFF79;'>扣分</span>",
|
||||
],
|
||||
data: illegalList,
|
||||
}
|
||||
//
|
||||
return (
|
||||
<div>
|
||||
{/*搜索弹框*/}
|
||||
{carVisible &&
|
||||
<div className={style.modal_box}>
|
||||
<div className={style.modal_title}>
|
||||
<span className={style.title_box}>车辆违规-查询</span>
|
||||
<span style={{position: 'absolute', right: 10, cursor: 'pointer'}}
|
||||
onClick={() => {
|
||||
setIllegalParams({})
|
||||
setVisible(false)
|
||||
}}>×</span>
|
||||
</div>
|
||||
<div className={style.modal_body}>
|
||||
<select className={style.text} type="text" id="carType" value={illegalParams.vehicleTypeId}
|
||||
onChange={(e) =>
|
||||
setIllegalParams({...illegalParams, vehicleTypeId: e.target.value})}>
|
||||
<option value="" style={{display: 'none'}}>违规车型</option>
|
||||
{illegalTypeList.map(it => {
|
||||
return (<option key={it.value} value={it.value}>{it.name}</option>)
|
||||
})}
|
||||
</select>
|
||||
<img src={require("@/assets/chain.png")} alt=""/>
|
||||
<select className={style.text} value={illegalParams.ruleId}
|
||||
onChange={(e) =>
|
||||
setIllegalParams({...illegalParams, ruleId: e.target.value})}
|
||||
>
|
||||
<option value="" style={{display: 'none'}}>违规类型</option>
|
||||
{illegalLists.map(it => {
|
||||
return (<option key={it.value} value={it.value}>{it.name}</option>)
|
||||
})}
|
||||
</select>
|
||||
<img src={require("@/assets/chain.png")} alt=""/>
|
||||
|
||||
<input className={style.text} placeholder="输入车牌" type="search"
|
||||
onChange={e => setSearchText(e.target.value)}/>
|
||||
<div className={style.search_btn}>
|
||||
<img style={{position: "absolute", left: '25%', top: '25%', width: 25, height: 25}}
|
||||
src={require("@/assets/searchWhite.png")} onClick={() => getIllegalList()}/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={style.modal_body} style={{height: '5%', marginBottom: 20}}>
|
||||
<img src={require("@/assets/chain.png")} alt=""/>
|
||||
|
||||
<ConfigProvider locale={zh_CN}>
|
||||
<RangePicker className={style.dataPicker} locale={zh_CN} allowClear={false} onChange={(e) => {
|
||||
setIllegalParams({
|
||||
...illegalParams,
|
||||
startTime: e[0].format('YYYY-MM-DD'),
|
||||
endTime: e[1].format('YYYY-MM-DD'),
|
||||
})
|
||||
}}
|
||||
value={[illegalParams.startTime ? dayjs(illegalParams.startTime) : '', illegalParams.endTime ? dayjs(illegalParams.endTime) : '']}
|
||||
/>
|
||||
</ConfigProvider>
|
||||
<img src={require("@/assets/chain.png")} alt=""/>
|
||||
|
||||
<select className={style.text} style={{width: '34%'}} id="carType" value={illegalParams.no}
|
||||
onChange={(e) =>
|
||||
setIllegalParams({...illegalParams, no: e.target.value})}>
|
||||
<option value="" style={{display: 'none'}}>违规学院</option>
|
||||
{collegeList.map(it => {
|
||||
return (<option key={it.value} value={it.value}>{it.name}</option>)
|
||||
})}
|
||||
</select>
|
||||
<img src={require("@/assets/chain.png")} alt=""/>
|
||||
|
||||
</div>
|
||||
{/* 轮播表 */}
|
||||
{illegalList && <div style={{cursor: 'pointer'}}>
|
||||
<ScrollBoard onClick={(e) => detailClick(e)} config={config} style={{width: '100%', height: '300px'}}/>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
}
|
||||
{/* 详情弹框 */}
|
||||
{
|
||||
detailVisible &&
|
||||
<div className={style.modal_box} style={{width: 769, height: 420}}>
|
||||
<div className={style.modal_title}>
|
||||
<span className={style.title_box}>车辆违规-详情</span>
|
||||
<span style={{position: 'absolute', right: 10, cursor: 'pointer'}}
|
||||
onClick={() => setDetailVisible(false)}>×</span>
|
||||
</div>
|
||||
<div className={style.middleDetails}>
|
||||
{imgList[0] && <div className={style.pic}>
|
||||
<img src={imgList[0]} alt="" style={{width: '100%', height: '100%'}}/>
|
||||
</div>}
|
||||
{imgList[1] &&
|
||||
<div className={style.pic}>
|
||||
<img src={imgList[1]} alt="" style={{width: '100%', height: '100%'}}/>
|
||||
</div>}
|
||||
</div>
|
||||
<div>
|
||||
<ScrollBoard config={configDetails} style={{height: 100}}/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default forwardRef(CarModalPage)
|
||||
118
src/components/CarModalPage/index.less
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
.modal_box {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -75%);
|
||||
width: 769px;
|
||||
height: 500px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border: 2px solid #10FDF2;
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
.dataPicker {
|
||||
height: 45px;
|
||||
width: 40%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border-radius: 22px;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #14FDF7;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #FFFFFF;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
padding-left: 15px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
|
||||
}
|
||||
|
||||
.modal_title {
|
||||
line-height: 36px;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
//text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
//background: linear-gradient(180deg, #10FDF2 0%, rgba(16, 253, 242, 0.5) 100%);
|
||||
//box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.25);
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
}
|
||||
|
||||
.modal_body {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 24%;
|
||||
color: #40a9ff;
|
||||
//background-color: #40a9ff;
|
||||
|
||||
.text {
|
||||
height: 45px;
|
||||
width: 25%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border-radius: 22px;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #14FDF7;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #D5D8E2;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
padding-left: 10px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.title_box {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
background-color: #10FDF2;
|
||||
padding: 0 8px 5px 8px;
|
||||
}
|
||||
|
||||
.search_btn {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
width: 43px;
|
||||
height: 43px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
cursor: pointer;
|
||||
background: #14FDF7;
|
||||
}
|
||||
|
||||
option {
|
||||
font-size: 14px;
|
||||
// background: rgba(47, 253, 239, 0.1);
|
||||
background-color: rgb(0, 52, 73);
|
||||
color: #D5D8E2;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 2px solid #24A7A4;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.middleDetails {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 68%;
|
||||
|
||||
.pic {
|
||||
width: 45%;
|
||||
height: 200px;
|
||||
border: 1px solid #14FDF7;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
8
src/components/DatePicker/index.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Dayjs } from 'dayjs';
|
||||
import dayjsGenerateConfig from 'rc-picker/es/generate/dayjs';
|
||||
import generatePicker from 'antd/es/date-picker/generatePicker';
|
||||
import 'antd/es/date-picker/style/index';
|
||||
|
||||
const DatePicker = generatePicker<Dayjs>(dayjsGenerateConfig);
|
||||
|
||||
export default DatePicker;
|
||||
20
src/components/Flex/index.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface IFlexProps {
|
||||
direction?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
|
||||
wrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
|
||||
justify?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around';
|
||||
alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch';
|
||||
|
||||
itemSelf?: 'auto' | 'flex-start' | 'flex-end' | 'center' | 'stretch';
|
||||
itemOrder?: number;
|
||||
itemGrow?: number;
|
||||
|
||||
style?: object;
|
||||
className?: string;
|
||||
|
||||
onClick?: any,
|
||||
}
|
||||
|
||||
export default class Flex extends React.Component<IFlexProps, any> {
|
||||
}
|
||||
56
src/components/Flex/index.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import React, {memo} from "react";
|
||||
import styles from './index.less';
|
||||
|
||||
const Index = memo((props) => {
|
||||
|
||||
const {
|
||||
direction, wrap, justify, alignItems,
|
||||
itemOrder, itemSelf, itemGrow, onClick,
|
||||
className, style, ...other
|
||||
} = props;
|
||||
|
||||
let newStyle = {};
|
||||
if (direction) {
|
||||
newStyle['flexDirection'] = direction;
|
||||
newStyle['WebkitFlexDirection'] = direction;
|
||||
}
|
||||
if (wrap) {
|
||||
newStyle['flexWrap'] = wrap;
|
||||
newStyle['WebkitFlexWrap'] = wrap;
|
||||
}
|
||||
if (justify) {
|
||||
newStyle['justifyContent'] = justify;
|
||||
newStyle['WebkitJustifyContent'] = justify;
|
||||
}
|
||||
if (alignItems) {
|
||||
newStyle['alignItems'] = alignItems;
|
||||
newStyle['WebkitAlignItems'] = alignItems;
|
||||
}
|
||||
if (itemSelf) {
|
||||
newStyle['alignSelf'] = itemSelf;
|
||||
newStyle['WebkitAlignSelf'] = itemSelf;
|
||||
}
|
||||
if (itemOrder) {
|
||||
newStyle['order'] = itemOrder;
|
||||
}
|
||||
|
||||
if (itemGrow) {
|
||||
newStyle['flexGrow'] = itemGrow;
|
||||
newStyle['WebkitFlexGrow'] = itemGrow;
|
||||
}
|
||||
|
||||
let clazz = styles.flex;
|
||||
if (className) {
|
||||
clazz = clazz + ' ' + className;
|
||||
}
|
||||
|
||||
return <div
|
||||
{...other} className={clazz} style={{...newStyle, ...style}} onClick={onClick}
|
||||
>{props.children}</div>
|
||||
});
|
||||
|
||||
const Flex = (props) => {
|
||||
return <Index {...props} />
|
||||
};
|
||||
|
||||
export default Flex;
|
||||
15
src/components/Flex/index.less
Normal file
@@ -0,0 +1,15 @@
|
||||
.flex {
|
||||
display: -webkit-flex; /* Safari */
|
||||
display: flex;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
|
||||
word-break: break-all;
|
||||
white-space: normal;
|
||||
|
||||
flex-shrink: 0;
|
||||
-webkit-flex-shrink: 0;
|
||||
|
||||
}
|
||||
114
src/components/FlipView/Flipper.js
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 翻牌数字
|
||||
* @author: 兔子先生
|
||||
* @createDate: 2019-11-24
|
||||
*/
|
||||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import './flipper.css'
|
||||
|
||||
class Flipper extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
isFlipping: false,
|
||||
flipType: 'down',
|
||||
frontTextFromData: 0,
|
||||
backTextFromData: 1
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {isFlipping, flipType, frontTextFromData, backTextFromData} = this.state
|
||||
return (
|
||||
<div className={['M-Flipper', flipType, isFlipping ? 'go' : null].join(' ')}>
|
||||
<div className={'digital front ' + this._textClass(frontTextFromData)}/>
|
||||
<div className={'digital back ' + this._textClass(backTextFromData)}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// componentDidMount() {
|
||||
// this.props.onRef(this)
|
||||
// }
|
||||
test() {
|
||||
console.log('test')
|
||||
}
|
||||
|
||||
_textClass(number) {
|
||||
return 'number' + number
|
||||
}
|
||||
|
||||
_flip(type, front, back) {
|
||||
// 如果处于翻转中,则不执行
|
||||
if (this.isFlipping) {
|
||||
return false
|
||||
}
|
||||
this.setState({
|
||||
frontTextFromData: front,
|
||||
backTextFromData: back,
|
||||
// 根据传递过来的type设置翻转方向
|
||||
flipType: type,
|
||||
// 设置翻转状态为true
|
||||
isFlipping: true
|
||||
})
|
||||
setTimeout(() => {
|
||||
this.setState({
|
||||
frontTextFromData: back,
|
||||
isFlipping: false
|
||||
})
|
||||
}, this.props.duration)
|
||||
}
|
||||
|
||||
// 下翻牌
|
||||
flipDown(front, back) {
|
||||
this._flip('down', front, back)
|
||||
}
|
||||
|
||||
// 上翻牌
|
||||
flipUp(front, back) {
|
||||
this._flip('up', front, back)
|
||||
}
|
||||
|
||||
// 设置前牌文字
|
||||
setFront(text) {
|
||||
this.setState({
|
||||
frontTextFromData: text
|
||||
})
|
||||
}
|
||||
|
||||
// 设置后牌文字
|
||||
setBack(text) {
|
||||
this.setState({
|
||||
backTextFromData: text
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// props类型校验
|
||||
Flipper.propTypes = {
|
||||
frontText: PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.string
|
||||
]),
|
||||
backText: PropTypes.oneOfType([
|
||||
PropTypes.number,
|
||||
PropTypes.string
|
||||
]),
|
||||
duration: PropTypes.number
|
||||
}
|
||||
|
||||
// props默认值
|
||||
Flipper.defaultProps = {
|
||||
// front paper text
|
||||
// 前牌文字
|
||||
frontText: 0,
|
||||
// back paper text
|
||||
// 后牌文字
|
||||
backText: 1,
|
||||
// flipping duration, please be consistent with the CSS animation-duration value.
|
||||
// 翻牌动画时间,与CSS中设置的animation-duration保持一致
|
||||
duration: 600
|
||||
}
|
||||
|
||||
export default Flipper
|
||||
186
src/components/FlipView/flipper.css
Normal file
@@ -0,0 +1,186 @@
|
||||
.M-Flipper {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 40px;
|
||||
margin: 2px;
|
||||
height: 70px;
|
||||
line-height: 70px;
|
||||
border: solid 1px #000;
|
||||
border-radius: 10px;
|
||||
background: #666666;
|
||||
font-size: 60px;
|
||||
color: #fff;
|
||||
box-shadow: 0 0 6px rgba(0, 0, 0, 0.5);
|
||||
text-align: center;
|
||||
font-family: 'Helvetica Neue';
|
||||
}
|
||||
|
||||
.M-Flipper .digital:before,
|
||||
.M-Flipper .digital:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background: #000 url("../../assets/numberBorder.png");
|
||||
|
||||
}
|
||||
|
||||
.M-Flipper .digital:before {
|
||||
top: 0;
|
||||
bottom: 50%;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border-bottom: solid 1px #666;
|
||||
}
|
||||
|
||||
.M-Flipper .digital:after {
|
||||
top: 50%;
|
||||
bottom: 0;
|
||||
border-radius: 0 0 10px 10px;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
/*向下翻*/
|
||||
.M-Flipper.down .front:before {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.M-Flipper.down .back:after {
|
||||
z-index: 2;
|
||||
transform-origin: 50% 0%;
|
||||
transform: perspective(160px) rotateX(180deg);
|
||||
}
|
||||
|
||||
.M-Flipper.down .front:after,
|
||||
.M-Flipper.down .back:before {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.M-Flipper.down.go .front:before {
|
||||
transform-origin: 50% 100%;
|
||||
animation: frontFlipDown 0.6s ease-in-out both;
|
||||
box-shadow: 0 -2px 6px rgba(255, 255, 255, 0.3);
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.M-Flipper.down.go .back:after {
|
||||
animation: backFlipDown 0.6s ease-in-out both;
|
||||
}
|
||||
|
||||
/*向上翻*/
|
||||
.M-Flipper.up .front:after {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.M-Flipper.up .back:before {
|
||||
z-index: 2;
|
||||
transform-origin: 50% 100%;
|
||||
transform: perspective(160px) rotateX(-180deg);
|
||||
}
|
||||
|
||||
.M-Flipper.up .front:before,
|
||||
.M-Flipper.up .back:after {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.M-Flipper.up.go .front:after {
|
||||
transform-origin: 50% 0;
|
||||
animation: frontFlipUp 0.6s ease-in-out both;
|
||||
box-shadow: 0 2px 6px rgba(255, 255, 255, 0.3);
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
.M-Flipper.up.go .back:before {
|
||||
animation: backFlipUp 0.6s ease-in-out both;
|
||||
}
|
||||
|
||||
@keyframes frontFlipDown {
|
||||
0% {
|
||||
transform: perspective(160px) rotateX(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(160px) rotateX(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes backFlipDown {
|
||||
0% {
|
||||
transform: perspective(160px) rotateX(180deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(160px) rotateX(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes frontFlipUp {
|
||||
0% {
|
||||
transform: perspective(160px) rotateX(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(160px) rotateX(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes backFlipUp {
|
||||
0% {
|
||||
transform: perspective(160px) rotateX(-180deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(160px) rotateX(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
.M-Flipper .number0:before,
|
||||
.M-Flipper .number0:after {
|
||||
content: '0';
|
||||
}
|
||||
|
||||
.M-Flipper .number1:before,
|
||||
.M-Flipper .number1:after {
|
||||
content: '1';
|
||||
}
|
||||
|
||||
.M-Flipper .number2:before,
|
||||
.M-Flipper .number2:after {
|
||||
content: '2';
|
||||
}
|
||||
|
||||
.M-Flipper .number3:before,
|
||||
.M-Flipper .number3:after {
|
||||
content: '3';
|
||||
}
|
||||
|
||||
.M-Flipper .number4:before,
|
||||
.M-Flipper .number4:after {
|
||||
content: '4';
|
||||
}
|
||||
|
||||
.M-Flipper .number5:before,
|
||||
.M-Flipper .number5:after {
|
||||
content: '5';
|
||||
}
|
||||
|
||||
.M-Flipper .number6:before,
|
||||
.M-Flipper .number6:after {
|
||||
content: '6';
|
||||
}
|
||||
|
||||
.M-Flipper .number7:before,
|
||||
.M-Flipper .number7:after {
|
||||
content: '7';
|
||||
}
|
||||
|
||||
.M-Flipper .number8:before,
|
||||
.M-Flipper .number8:after {
|
||||
content: '8';
|
||||
}
|
||||
|
||||
.M-Flipper .number9:before,
|
||||
.M-Flipper .number9:after {
|
||||
content: '9';
|
||||
}
|
||||
65
src/components/FlipView/index.jsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React, {Fragment, useState, useRef, useEffect} from 'react'
|
||||
import Flipper from './Flipper'
|
||||
import './flipper.css'
|
||||
|
||||
const FlipView = ({number = '0'}) => {
|
||||
|
||||
const [lastArray, setLastArray] = useState(['0', '0', '0', '0', '0', '0']);
|
||||
const flipper0 = useRef();
|
||||
const flipper1 = useRef();
|
||||
const flipper2 = useRef();
|
||||
const flipper3 = useRef();
|
||||
const flipper4 = useRef();
|
||||
const flipper5 = useRef();
|
||||
const flipper6 = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
run();
|
||||
}, [number]);
|
||||
|
||||
///////////////////////////////////////// 逻辑方法
|
||||
|
||||
/**
|
||||
* 开始翻牌
|
||||
*/
|
||||
const run = () => {
|
||||
let tempArray = new Array(6 - number.length);
|
||||
let array = tempArray.concat([...number.split('')]);
|
||||
|
||||
const flipDown = (front, back, ref) => {
|
||||
front = front || "0";
|
||||
back = back || "0";
|
||||
if (front != back) {
|
||||
ref && ref.current.flipDown(back, front);
|
||||
}
|
||||
};
|
||||
|
||||
flipDown(array[0], lastArray[0], flipper1);
|
||||
flipDown(array[1], lastArray[1], flipper2);
|
||||
flipDown(array[2], lastArray[2], flipper3);
|
||||
flipDown(array[3], lastArray[3], flipper4);
|
||||
flipDown(array[4], lastArray[4], flipper5);
|
||||
flipDown(array[5], lastArray[5], flipper6);
|
||||
|
||||
setLastArray(array);
|
||||
|
||||
};
|
||||
|
||||
///////////////////////////////////////// 页面渲染
|
||||
|
||||
return <Fragment>
|
||||
<Flipper ref={flipper0}/>
|
||||
<em style={{fontSize: 36, margin: '0 5px'}}>,</em>
|
||||
<Flipper ref={flipper1}/>
|
||||
<Flipper ref={flipper2}/>
|
||||
<Flipper ref={flipper3}/>
|
||||
<em style={{fontSize: 36, margin: '0 5px'}}>,</em>
|
||||
<Flipper ref={flipper4}/>
|
||||
<Flipper ref={flipper5}/>
|
||||
<Flipper ref={flipper6}/>
|
||||
</Fragment>
|
||||
|
||||
};
|
||||
|
||||
|
||||
export default FlipView;
|
||||
270
src/components/LeftPage/index.jsx
Normal file
@@ -0,0 +1,270 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import style from './index.less'
|
||||
import {ScrollBoard} from "@jiaminghi/data-view-react";
|
||||
import leftPageApi from "@/https/apis/leftPageApi";
|
||||
|
||||
import yellowPng from '@/assets/yellow.png';
|
||||
import Flex from "@/components/Flex";
|
||||
import TitleView from "@/components/TitleView";
|
||||
import FlipView from "@/components/FlipView";
|
||||
|
||||
|
||||
const border = [require('@/assets/blueBorder.png'), require('@/assets/greenBorder.png'), require('@/assets/indigoBorder.png')]
|
||||
const typeCount = [require('@/assets/shape/car.png'), require('@/assets/shape/electricCars.png'), require('@/assets/shape/other.png')]
|
||||
|
||||
|
||||
const LeftPage = ({onCarIllegalClick, onUserIllegalClick}) => {
|
||||
|
||||
const {bottom_box, title_box2} = style;
|
||||
|
||||
const [carType, setCarType] = useState([])
|
||||
const [currentMonth, setCurrentMonth] = useState([])
|
||||
const [lastMonth, setLastMonth] = useState([])
|
||||
const [currentDay, setCurrentDay] = useState([])
|
||||
const [lastDay, setLastDay] = useState([])
|
||||
const [illegalList, setIllegalList] = useState([])
|
||||
//查询参数
|
||||
const [searchText, setSearchText] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
getCountType()
|
||||
getMonthCount()
|
||||
getLastMonthCount()
|
||||
getDayCount()
|
||||
getLastCount()
|
||||
getIllegalList()
|
||||
}, [])
|
||||
|
||||
///////////////////////////////////////// 逻辑方法
|
||||
|
||||
const getCountType = () => {
|
||||
leftPageApi.countType().then(res => {
|
||||
if (res.code === 200) {
|
||||
res.data.forEach((it, index) => {
|
||||
it.icon = typeCount[index];
|
||||
it.border = border[index];
|
||||
});
|
||||
setCarType(res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getMonthCount = () => {
|
||||
leftPageApi.monthCount().then(res => {
|
||||
if (res.code == 200) {
|
||||
setCurrentMonth(res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getLastMonthCount = () => {
|
||||
leftPageApi.lastMonthCount().then(res => {
|
||||
if (res.code == 200) {
|
||||
setLastMonth(res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getDayCount = () => {
|
||||
leftPageApi.dayCount().then(res => {
|
||||
if (res.code == 200) {
|
||||
setCurrentDay(res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getLastCount = () => {
|
||||
leftPageApi.lastDay().then(res => {
|
||||
if (res.code == 200) {
|
||||
setLastDay(res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const getIllegalList = () => {
|
||||
leftPageApi.illegalList().then(res => {
|
||||
if (res.code == 200) {
|
||||
// console.log(res.data)
|
||||
setIllegalList(res.data.map(it => {
|
||||
return [it.plateNo, it.ruleName, it.score,
|
||||
`<span style='display:none'>${it.userName}</span>`,
|
||||
`<span style='display:none'>${it.reportUserName}</span>`,
|
||||
`<span style='display:none'>${it.imgs}</span>`
|
||||
]
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
///////////////////////////////////////// 数据常量
|
||||
|
||||
let config = {
|
||||
headerBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
headerHeight: 36,
|
||||
oddRowBGC: 'rgba(0, 0, 0, 0)',
|
||||
evenRowBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
columnWidth: [180, 85, 50],
|
||||
header: [
|
||||
"<span style='color: #BDFF79;'>车牌号</span>",
|
||||
"<span style='color: #BDFF79;'>违规</span>",
|
||||
"<span style='color: #BDFF79;'>扣分</span>",
|
||||
],
|
||||
data: illegalList
|
||||
};
|
||||
|
||||
let counts = [
|
||||
{
|
||||
title: '昨日',
|
||||
count: lastDay,
|
||||
imgSrc: yellowPng,
|
||||
},
|
||||
{
|
||||
title: '今日',
|
||||
count: currentDay,
|
||||
imgSrc: "./imgs/blue.png",
|
||||
},
|
||||
{
|
||||
title: '本月',
|
||||
count: currentMonth,
|
||||
imgSrc: require('@/assets/light.png'),
|
||||
},
|
||||
{
|
||||
title: '上月',
|
||||
count: lastMonth,
|
||||
imgSrc: require('@/assets/green.png'),
|
||||
},
|
||||
];
|
||||
|
||||
return <Flex
|
||||
direction={"column"} className={style.container} justify={"center"} alignItems={"center"}
|
||||
>
|
||||
|
||||
<Flex className={style.carCount} direction={"column"}>
|
||||
|
||||
<TitleView
|
||||
title={'车辆统计管理'} bgUrl={'./imgs/titleBorder.png'} bgStyle={{width: 176, height: 53}}
|
||||
extra={<Flex
|
||||
itemGrow={1} style={{width: 0}} alignItems={"center"} justify={"flex-end"}
|
||||
className={style.title_box}
|
||||
>
|
||||
<input
|
||||
className={style.text} placeholder="人员查询" type="search"
|
||||
onChange={e => setSearchText(e.target.value)}
|
||||
/>
|
||||
<div className={style.search_btn} onClick={onUserIllegalClick}>
|
||||
<img
|
||||
alt={''} style={{position: "absolute", left: '25%', top: '25%', width: 25, height: 25}}
|
||||
src={require("@/assets/searchWhite.png")}
|
||||
/>
|
||||
</div>
|
||||
</Flex>}
|
||||
/>
|
||||
|
||||
|
||||
<Flex className={style.inoutCar} justify={"space-between"}>
|
||||
|
||||
<Flex style={{width: 187, marginRight: 6}}>
|
||||
<Flex itemGrow={1} style={{width: 0}}>
|
||||
<img alt={''} style={{position: 'absolute'}} src={require("@/assets/countBorder.png")}/>
|
||||
<img alt={''} style={{position: 'absolute', top: 20, left: 26}}
|
||||
src={require("@/assets/shape/inSchool.png")}/>
|
||||
<img alt={''} style={{position: 'absolute', top: 10, left: 10}} src={require("@/assets/show.png")}/>
|
||||
</Flex>
|
||||
<Flex direction={"column"} justify={"center"} alignItems={"center"} style={{marginRight: 12}}>
|
||||
<Flex style={{fontSize: 18, fontWeight: 500, color: '#E9CC7C'}}>156</Flex>
|
||||
<Flex style={{fontSize: 14}}>进校车辆</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Flex style={{width: 187, marginLeft: 6}}>
|
||||
<Flex itemGrow={1} style={{width: 0}}>
|
||||
<img alt={''} style={{position: 'absolute'}} src={require("@/assets/countBorder.png")}/>
|
||||
<img alt={''} style={{position: 'absolute', top: 20, left: 26}}
|
||||
src={require("@/assets/shape/outSchool.png")}/>
|
||||
<img alt={''} style={{position: 'absolute', top: 10, left: 10}} src={require("@/assets/show.png")}/>
|
||||
</Flex>
|
||||
<Flex direction={"column"} justify={"center"} alignItems={"center"} style={{marginRight: 12}}>
|
||||
<Flex style={{fontSize: 18, fontWeight: 500, color: '#E9CC7C'}}>143</Flex>
|
||||
<Flex style={{fontSize: 14}}>出校车辆</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
</Flex>
|
||||
|
||||
<Flex className={style.carType} justify={"space-between"}>
|
||||
{carType.map((it, index) => {
|
||||
return <Flex
|
||||
key={index} className={style.carBox} direction={"column"} justify={"center"} alignItems={"center"}
|
||||
onClick={() => onCarIllegalClick(it)}
|
||||
>
|
||||
<img alt={''} style={{position: 'absolute', zIndex: 0, left: 0}} src={it.border}/>
|
||||
<img alt='' style={{zIndex: 1}} src={it.icon}/>
|
||||
<Flex style={{zIndex: 1, fontSize: 18, fontWeight: 500, color: '#E9CC7C'}}>{it.count}</Flex>
|
||||
<Flex style={{zIndex: 1, fontSize: 14}}>{it.vehicleType}</Flex>
|
||||
</Flex>
|
||||
})}
|
||||
</Flex>
|
||||
|
||||
<Flex className={style.carEvent} justify={"space-between"}>
|
||||
<Flex
|
||||
className={style.body_box_down} alignItems={"center"}
|
||||
onClick={() => onCarIllegalClick()}
|
||||
>
|
||||
<img alt={''} style={{position: 'absolute'}} src={require("@/assets/cardBorder.png")}/>
|
||||
<span style={{paddingLeft: 22}}>车辆违规</span>
|
||||
<img alt={''} className={style.img_search} src={require("@/assets/search.png")}/>
|
||||
</Flex>
|
||||
|
||||
<Flex className={style.body_box_down} alignItems={"center"}>
|
||||
<img alt={''} style={{position: 'absolute'}} src={require("@/assets/greyBorder.png")}/>
|
||||
<span style={{paddingLeft: 28}}>事件上报</span>
|
||||
</Flex>
|
||||
|
||||
<Flex className={style.body_box_down} alignItems={"center"}>
|
||||
<img alt={''} style={{position: 'absolute'}} src={require("@/assets/greyBorder.png")}/>
|
||||
<span style={{paddingLeft: 28}}>扣分记录</span>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
{/*轮播表*/}
|
||||
<Flex itemGrow={1} style={{height: 0, marginBottom: 20}}>
|
||||
<ScrollBoard
|
||||
config={config} onClick={e => onCarIllegalClick({name: e, detail: true})}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
{/*底部盒子*/}
|
||||
<Flex className={style.bottom_box} direction={"column"}>
|
||||
|
||||
<TitleView
|
||||
bgUrl={'./imgs/titleBorder2.png'} title={'违规总数统计'} bgStyle={{width: 176, height: 53}}
|
||||
/>
|
||||
|
||||
{/* 翻牌器 */}
|
||||
<Flex style={{margin: '10px 0', width: '100%'}} justify={"center"}>
|
||||
<FlipView number={'112'}/>
|
||||
</Flex>
|
||||
|
||||
{/* 违规数统计 */}
|
||||
<Flex className={style.dayStat} wrap={"wrap"} justify={"space-around"}>
|
||||
{counts.map((it, index) => {
|
||||
return (
|
||||
<Flex
|
||||
key={index} className={style.down_body_box} alignItems={"center"} justify={"center"}
|
||||
onClick={(e) => onCarIllegalClick(it)}
|
||||
>
|
||||
<img alt={''} src={it.imgSrc} style={{position: "absolute", zIndex: 0}}/>
|
||||
<span style={{zIndex: 1, fontSize: 32, lineHeight: 1}}>{it.count}</span>
|
||||
<span style={{zIndex: 1, fontSize: 14}}>{it.title}</span>
|
||||
</Flex>
|
||||
)
|
||||
})}
|
||||
</Flex>
|
||||
|
||||
</Flex>
|
||||
|
||||
</Flex>
|
||||
}
|
||||
|
||||
export default LeftPage
|
||||
244
src/components/LeftPage/index.less
Normal file
@@ -0,0 +1,244 @@
|
||||
.container {
|
||||
width: 400px;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
|
||||
|
||||
.carCount {
|
||||
width: 100%;
|
||||
|
||||
.title_box {
|
||||
height: 80px;
|
||||
font-size: 18px;
|
||||
|
||||
.titleBg {
|
||||
width: 176px;
|
||||
height: 53px;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.text {
|
||||
height: 45px;
|
||||
width: 160px;
|
||||
border-radius: 22px;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #14FDF7;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #D5D8E2;
|
||||
line-height: 20px;
|
||||
padding-left: 20px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.search_btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 43px;
|
||||
height: 43px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
cursor: pointer;
|
||||
background: #14FDF7;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.inoutCar {
|
||||
height: 75px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.carType {
|
||||
height: 75px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.carBox {
|
||||
width: 120px;
|
||||
height: 75px;
|
||||
font-size: 16px;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.carEvent {
|
||||
height: 50px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
.body_box_down {
|
||||
width: 120px;
|
||||
height: 50px;
|
||||
font-size: 15px;
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.img_search {
|
||||
margin-top: 8px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.bottom_box {
|
||||
color: white;
|
||||
|
||||
.title_box2 {
|
||||
height: 30%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.drawNumber {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.dayStat {
|
||||
|
||||
.down_body_box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 170px;
|
||||
height: 70px;
|
||||
cursor: pointer;
|
||||
margin-bottom: 20px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
&:nth-child(1) {
|
||||
color: rgb(255, 236, 142);
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
color: rgb(75, 242, 255);
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
color: rgb(119, 255, 229);
|
||||
}
|
||||
|
||||
&:nth-child(4) {
|
||||
color: rgb(106, 255, 125);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.modal_box {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 29%;
|
||||
transform: translate(78%, 0);
|
||||
width: 769px;
|
||||
height: 430px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border: 2px solid #10FDF2;
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
.modal_title {
|
||||
transform: translateY(5%);
|
||||
height: 8%;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #FFFFFF;
|
||||
line-height: 25px;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.modal_body {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 22%;
|
||||
|
||||
.text {
|
||||
height: 45px;
|
||||
width: 25%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border-radius: 22px;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #14FDF7;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #D5D8E2;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
padding-left: 10px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
|
||||
&:nth-child(1) {
|
||||
//transform: translateX(55px);
|
||||
}
|
||||
}
|
||||
|
||||
.title_box {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
background-color: #10FDF2;
|
||||
padding: 0 8px 5px 8px;
|
||||
}
|
||||
|
||||
.search_btn {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
width: 43px;
|
||||
height: 43px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
cursor: pointer;
|
||||
background: #14FDF7;
|
||||
}
|
||||
|
||||
option {
|
||||
font-size: 14px;
|
||||
// background: rgba(47, 253, 239, 0.1);
|
||||
background-color: rgb(0, 52, 73);
|
||||
color: #D5D8E2;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 2px solid #24A7A4;
|
||||
}
|
||||
}
|
||||
|
||||
.middleDetails {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 55%;
|
||||
|
||||
.pic {
|
||||
width: 35%;
|
||||
height: 205px;
|
||||
border: 1px solid #14FDF7;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
.board_box {
|
||||
height: 200px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/components/MiddlePage/index.jsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import style from './index.less'
|
||||
|
||||
const middlePage = () => {
|
||||
return (
|
||||
<div className={style.container}>
|
||||
<div className={style.title_box}>
|
||||
<img style={{position:"absolute"}} src={require('@/assets/title.png')}/>
|
||||
<span >异常分部预览</span>
|
||||
</div>
|
||||
<div className={style.type_title}>
|
||||
<img style={{position:"absolute"}} src={require('@/assets/redTitle.png')}/>
|
||||
<span>汽车超速</span>
|
||||
</div>
|
||||
<div className={style.type_title}>
|
||||
<img style={{position:"absolute"}} src={require('@/assets/yellowTitle.png')}/>
|
||||
<span>汽车超载</span>
|
||||
</div>
|
||||
<div className={style.type_title}>
|
||||
<img style={{position:"absolute"}} src={require('@/assets/blueTitle.png')}/>
|
||||
<span>汽车违停</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default middlePage
|
||||
39
src/components/MiddlePage/index.less
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
width: 800px;
|
||||
color: #ffffff;
|
||||
margin-left: 100px;
|
||||
//background-color: chocolate;
|
||||
|
||||
.title_box {
|
||||
position: relative;
|
||||
width: 273px;
|
||||
height: 53px;
|
||||
font-size: 18px;
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
left: 75px;
|
||||
}
|
||||
}
|
||||
|
||||
.type_title {
|
||||
position: relative;
|
||||
width: 168px;
|
||||
height: 32px;
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
font-family: PingFangSC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
top: 5px;
|
||||
left: 42px;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/components/RightPage/BarChart/index.jsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import rightPageApi from "@/https/apis/rightPageApi";
|
||||
|
||||
const {Bar} = window.charts;
|
||||
|
||||
const DemoBar = ({requestDate,onClick}) => {
|
||||
|
||||
|
||||
|
||||
const [list,setList] = useState([])
|
||||
const pieRef = useRef();
|
||||
|
||||
useEffect(()=>{
|
||||
getCollegeCount()
|
||||
clickPie(pieRef?.current?.getChart())
|
||||
},[requestDate])
|
||||
|
||||
const getCollegeCount = () => {
|
||||
rightPageApi.collegeCount(requestDate.format("YYYY-MM-DD")).then(res=>{
|
||||
if(res.code == 200){
|
||||
setList(res.data.map(it => {
|
||||
return {collegeName:it.collegeName.substr(0,10), sales: parseInt(it.count,10),collegeNo:it.collegeNo}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const clickPie = (plot) => {
|
||||
plot.off("plot:click");
|
||||
plot.on('plot:click', (...args) => {
|
||||
onClick && onClick(args[0]?.data?.data,requestDate.format('YYYY-MM'))
|
||||
})
|
||||
}
|
||||
|
||||
const data = list
|
||||
const config = {
|
||||
data,
|
||||
xField: 'sales',
|
||||
yField: 'collegeName',
|
||||
color: '#3B90FF',
|
||||
xAxis:{
|
||||
label:{
|
||||
style:{
|
||||
fill:'#F2F2F2'
|
||||
}
|
||||
}
|
||||
},
|
||||
barStyle: {
|
||||
fill: 'l(180) 0:#3B90FF 1:rgba(47, 253, 239, 0)',
|
||||
},
|
||||
yAxis:{
|
||||
label:{
|
||||
style:{
|
||||
fill:'#F2F2F2'
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
collegeName: {
|
||||
alias: '类别',
|
||||
},
|
||||
sales: {
|
||||
alias: '违规总数',
|
||||
},
|
||||
no:{
|
||||
alias:'编号'
|
||||
}
|
||||
},
|
||||
minBarWidth: 25,
|
||||
maxBarWidth: 25,
|
||||
};
|
||||
return <Bar ref={pieRef} {...config}/>;
|
||||
};
|
||||
|
||||
export default DemoBar
|
||||
|
||||
77
src/components/RightPage/ColumnChart/index.jsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import rightPageApi from "@/https/apis/rightPageApi";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
const { Column } = window.charts;
|
||||
|
||||
const DemoColumn = ({onClick}) => {
|
||||
|
||||
const [dataCount,setDataCount] = useState([])
|
||||
|
||||
useEffect(()=>{
|
||||
getSevenCount()
|
||||
},[])
|
||||
|
||||
const getSevenCount = () => {
|
||||
rightPageApi.sevenCount().then(res=>{
|
||||
if(res.code == 200){
|
||||
setDataCount(res.data.map(it=>{
|
||||
return {type:it.week.substr(5,5),sales:parseInt(it.count,10)}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const clickColumn = (plot) => {
|
||||
plot.on('plot:click', (...args) => {
|
||||
onClick && onClick(args[0]?.data?.data)
|
||||
})
|
||||
}
|
||||
|
||||
const data = dataCount;
|
||||
const config = {
|
||||
data,
|
||||
xField: 'type',
|
||||
yField: 'sales',
|
||||
color: '#4AE7E0',
|
||||
label: {
|
||||
// 可手动配置 label 数据标签位置
|
||||
position: 'middle',
|
||||
// 'top', 'bottom', 'middle',
|
||||
// 配置样式
|
||||
style: {
|
||||
fill: '#F2F2F2',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
name:'type',
|
||||
label: {
|
||||
autoHide: true,
|
||||
autoRotate: false,
|
||||
style: {
|
||||
fill: '#F2F2F2'
|
||||
}
|
||||
},
|
||||
},
|
||||
barStyle: {
|
||||
fill: 'red',
|
||||
},
|
||||
yAxis:{
|
||||
label:{
|
||||
style:{
|
||||
fill:'#F2F2F2'
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
type: {
|
||||
alias: '类别',
|
||||
},
|
||||
sales: {
|
||||
alias: '违规数',
|
||||
},
|
||||
},
|
||||
};
|
||||
return <Column {...config} onReady={clickColumn}/>;
|
||||
};
|
||||
|
||||
export default DemoColumn
|
||||
82
src/components/RightPage/PieChart/index.jsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import rightPageApi from "@/https/apis/rightPageApi";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
const {Pie, G2} = window.charts;
|
||||
const G = G2.getEngine('canvas');
|
||||
const cfg = {
|
||||
appendPadding: 10,
|
||||
data: [],
|
||||
angleField: 'count',
|
||||
colorField: 'type',
|
||||
radius: 0.75,
|
||||
legend: false,
|
||||
label: {
|
||||
type: 'spider',
|
||||
labelHeight: 40,
|
||||
formatter: (data, mappingData) => {
|
||||
const group = new G.Group({});
|
||||
group.addShape({
|
||||
type: 'circle',
|
||||
attrs: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 40,
|
||||
height: 50,
|
||||
r: 5,
|
||||
fill: mappingData.color,
|
||||
},
|
||||
});
|
||||
group.addShape({
|
||||
type: 'text',
|
||||
attrs: {
|
||||
x: 10,
|
||||
y: 8,
|
||||
text: `${data.type}`,
|
||||
fill: mappingData.color,
|
||||
},
|
||||
});
|
||||
return group;
|
||||
},
|
||||
},
|
||||
interactions: [
|
||||
{
|
||||
type: 'element-selected',
|
||||
},
|
||||
{
|
||||
type: 'element-active',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const DemoPie = ({onClick}) => {
|
||||
|
||||
useEffect(() => {
|
||||
getSevenType()
|
||||
}, [])
|
||||
|
||||
const [dataCount, setDataCount] = useState([])
|
||||
|
||||
const clickPie = (plot) => {
|
||||
plot.on('plot:click', (...args) => {
|
||||
console.log(args[0]?.data?.data)
|
||||
onClick && onClick(args[0]?.data?.data)
|
||||
})
|
||||
}
|
||||
|
||||
const getSevenType = () => {
|
||||
rightPageApi.sevenType().then(res => {
|
||||
if (res.code === 200) {
|
||||
console.log(res.data)
|
||||
setDataCount(res.data
|
||||
.map(it => (
|
||||
{...it, illegalType: it.type, count: parseInt(it.count, 10)}
|
||||
))
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return <Pie {...cfg} data={dataCount} onReady={clickPie}/>;
|
||||
};
|
||||
|
||||
export default DemoPie
|
||||
72
src/components/RightPage/index.jsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import style from './index.less'
|
||||
import BarChart from './BarChart'
|
||||
import ColumnChart from './ColumnChart'
|
||||
import PieChart from './PieChart'
|
||||
import dayjs from "dayjs";
|
||||
import Flex from "@/components/Flex";
|
||||
|
||||
const monthList = []
|
||||
for (let i = 1; i < 13; i++) {
|
||||
monthList.push({
|
||||
name: i + '月',
|
||||
value: i
|
||||
})
|
||||
}
|
||||
|
||||
const rightPage = ({onPieClick}) => {
|
||||
|
||||
const [dateNum, setDate] = useState(dayjs())
|
||||
const [copyDate, setCopyDate] = useState(dayjs())
|
||||
const [dataBoxVisible, setDataBoxVisible] = useState(false)
|
||||
|
||||
const {middle_box, bottom_box, title_box} = style;
|
||||
|
||||
|
||||
///////////////////////////////////////// 页面渲染
|
||||
|
||||
return <Flex direction={"column"} className={style.container}>
|
||||
<div className={style.top_box}>
|
||||
<div className={style.title_box}>
|
||||
<img style={{left: 10, height: '56px', position: 'absolute'}}
|
||||
src={require('@/assets/titleBorder3.png')}/>
|
||||
<span style={{position: "absolute", left: '4vh', top: 12, fontSize: '18px'}}>学院违章排行</span>
|
||||
<div onClick={() => setDataBoxVisible(!dataBoxVisible)} className={style.time_box}>{copyDate.format("YYYY-MM")}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{height: 300}}><BarChart requestDate={copyDate} onClick={onPieClick}/></div>
|
||||
</div>
|
||||
<div className={middle_box}>
|
||||
<div className={title_box}>
|
||||
<img style={{left: 20, width: '178px', height: '56px', position: 'absolute'}}
|
||||
src={require('@/assets/titleBorder4.png')}/>
|
||||
<span style={{position: "absolute", left: '4.5vh', top: 14, fontSize: '18px'}}>车辆违规统计</span>
|
||||
</div>
|
||||
<div style={{height: 300}}><ColumnChart onClick={(args) => onPieClick(args)}/></div>
|
||||
</div>
|
||||
<div className={bottom_box} style={{height: 300}}><PieChart onClick={(args) => onPieClick(args)}/></div>
|
||||
{
|
||||
dataBoxVisible && <div className={style.dataBox}>
|
||||
<div className={style.data_title}>
|
||||
<span style={{fontSize: 26, cursor: 'pointer'}}
|
||||
onClick={() => setDate(dateNum.add(-1, 'year'))}>«</span>
|
||||
<span style={{lineHeight: 2.5}}>{dateNum.format('YYYY')}</span>
|
||||
<span style={{fontSize: 26, cursor: 'pointer'}}
|
||||
onClick={() => setDate(dateNum.add(1, 'year'))}>»</span>
|
||||
</div>
|
||||
<div className={style.data_body}>
|
||||
{
|
||||
monthList.map(it => {
|
||||
return <div className={style.data_box} onClick={(e) => {
|
||||
setDataBoxVisible(false)
|
||||
setCopyDate(dayjs(dateNum.format("YYYY-") + it.value + "-01"));
|
||||
}} key={it.value}>{it.name}</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</Flex>
|
||||
}
|
||||
|
||||
export default rightPage
|
||||
213
src/components/RightPage/index.less
Normal file
@@ -0,0 +1,213 @@
|
||||
.container {
|
||||
width: 400px;
|
||||
height: 100%;
|
||||
color:#fff;
|
||||
font-size:16px;
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
|
||||
.top_box {
|
||||
width: 100%;
|
||||
height: 35%;
|
||||
padding: 18px;
|
||||
|
||||
.title_box {
|
||||
position: relative;
|
||||
height:18%;
|
||||
overflow: hidden;
|
||||
|
||||
.time_box {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
padding: 1px 8px 1.5px 8px;
|
||||
font-size: 16px;
|
||||
overflow: hidden;
|
||||
transform: translateY(10px);
|
||||
background-size: 100%;
|
||||
background: url("../../assets/time_box.png") no-repeat;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: rgba(169,169,169,.2);
|
||||
transition: all 0.2s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.middle_box {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 35%;
|
||||
padding: 18px;
|
||||
//background-color: white;
|
||||
|
||||
.title_box {
|
||||
position: relative;
|
||||
height:18%;
|
||||
|
||||
.time_box {
|
||||
position: absolute;
|
||||
width:80px;
|
||||
height:30px;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.middle_box {
|
||||
height: 20%;
|
||||
background-color: chocolate;
|
||||
}
|
||||
|
||||
//background-color: saddlebrown;
|
||||
}
|
||||
.bottom_box {
|
||||
width: 100%;
|
||||
height: 30%;
|
||||
//background-color: crimson;
|
||||
padding: 18px;
|
||||
|
||||
}
|
||||
@keyframes fadeInDown {
|
||||
0% {
|
||||
-webkit-transform: matrix3d(.7, 0, 0, 0, 0, .7, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.7, 0, 0, 0, 0, .7, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
opacity: 0
|
||||
}
|
||||
3.4% {
|
||||
-webkit-transform: matrix3d(.795, 0, 0, 0, 0, .822, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.795, 0, 0, 0, 0, .822, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
4.7% {
|
||||
-webkit-transform: matrix3d(.835, 0, 0, 0, 0, .88, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.835, 0, 0, 0, 0, .88, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
6.81% {
|
||||
-webkit-transform: matrix3d(.898, 0, 0, 0, 0, .968, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.898, 0, 0, 0, 0, .968, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
9.41% {
|
||||
-webkit-transform: matrix3d(.965, 0, 0, 0, 0, 1.05, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.965, 0, 0, 0, 0, 1.05, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
10.21% {
|
||||
-webkit-transform: matrix3d(.982, 0, 0, 0, 0, 1.068, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.982, 0, 0, 0, 0, 1.068, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
13.61% {
|
||||
-webkit-transform: matrix3d(1.037, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.037, 0, 0, 0, 0, 1.1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
14.11% {
|
||||
-webkit-transform: matrix3d(1.042, 0, 0, 0, 0, 1.099, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.042, 0, 0, 0, 0, 1.099, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
17.52% {
|
||||
-webkit-transform: matrix3d(1.062, 0, 0, 0, 0, 1.072, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.062, 0, 0, 0, 0, 1.072, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
18.72% {
|
||||
-webkit-transform: matrix3d(1.064, 0, 0, 0, 0, 1.056, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.064, 0, 0, 0, 0, 1.056, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
21.32% {
|
||||
-webkit-transform: matrix3d(1.059, 0, 0, 0, 0, 1.021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.059, 0, 0, 0, 0, 1.021, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
24.32% {
|
||||
-webkit-transform: matrix3d(1.045, 0, 0, 0, 0, .988, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.045, 0, 0, 0, 0, .988, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
25.23% {
|
||||
-webkit-transform: matrix3d(1.04, 0, 0, 0, 0, .981, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.04, 0, 0, 0, 0, .981, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
29.03% {
|
||||
-webkit-transform: matrix3d(1.019, 0, 0, 0, 0, .969, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.019, 0, 0, 0, 0, .969, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
29.93% {
|
||||
-webkit-transform: matrix3d(1.014, 0, 0, 0, 0, .97, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.014, 0, 0, 0, 0, .97, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
35.54% {
|
||||
-webkit-transform: matrix3d(.994, 0, 0, 0, 0, .989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.994, 0, 0, 0, 0, .989, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
36.74% {
|
||||
-webkit-transform: matrix3d(.991, 0, 0, 0, 0, .994, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.991, 0, 0, 0, 0, .994, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
41.04% {
|
||||
-webkit-transform: matrix3d(.988, 0, 0, 0, 0, 1.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.988, 0, 0, 0, 0, 1.007, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
44.44% {
|
||||
-webkit-transform: matrix3d(.99, 0, 0, 0, 0, 1.01, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.99, 0, 0, 0, 0, 1.01, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
52.15% {
|
||||
-webkit-transform: matrix3d(.997, 0, 0, 0, 0, 1.002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(.997, 0, 0, 0, 0, 1.002, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
opacity: 1
|
||||
}
|
||||
59.86% {
|
||||
-webkit-transform: matrix3d(1.002, 0, 0, 0, 0, .997, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.002, 0, 0, 0, 0, .997, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
63.26% {
|
||||
-webkit-transform: matrix3d(1.002, 0, 0, 0, 0, .998, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1.002, 0, 0, 0, 0, .998, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
75.28% {
|
||||
-webkit-transform: matrix3d(1, 0, 0, 0, 0, 1.001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1, 0, 0, 0, 0, 1.001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
85.49%,
|
||||
90.69%,
|
||||
100% {
|
||||
-webkit-transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
|
||||
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
|
||||
}
|
||||
100% {
|
||||
opacity: 1
|
||||
}
|
||||
|
||||
}
|
||||
.dataBox {
|
||||
top: 58px;
|
||||
right: 32px;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
background-color: rgba(0,0,0,.9);
|
||||
border-radius: 15px;
|
||||
animation: fadeInDown .3s;
|
||||
|
||||
.data_title {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
font-size: 18px;
|
||||
margin: 10px 0;
|
||||
border-bottom: 1px solid grey;
|
||||
}
|
||||
.data_body {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.data_box {
|
||||
text-align: center;
|
||||
width: 45px;
|
||||
height: 40px;
|
||||
margin: 5px;
|
||||
line-height: 40px;
|
||||
cursor: pointer;
|
||||
vertical-align: center;
|
||||
&:hover {
|
||||
color: black;
|
||||
background-color: grey;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/components/TitleView/index.jsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import Flex from "@/components/Flex";
|
||||
import less from './index.less';
|
||||
|
||||
|
||||
/**
|
||||
* 标题视图
|
||||
* @constructor
|
||||
*/
|
||||
const TitleView = ({bgUrl, bgStyle = {}, title = "", extra}) => {
|
||||
|
||||
|
||||
///////////////////////////////////////// 页面渲染
|
||||
|
||||
return <Flex justify={"space-between"} alignItems={"center"}>
|
||||
<Flex
|
||||
className={less.titleBg} justify={"center"} alignItems={"center"}
|
||||
style={{...bgStyle, backgroundImage: `url(${bgUrl})`}}
|
||||
>
|
||||
<Flex>{title}</Flex>
|
||||
</Flex>
|
||||
|
||||
{extra}
|
||||
</Flex>
|
||||
|
||||
};
|
||||
|
||||
export default TitleView;
|
||||
6
src/components/TitleView/index.less
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
.titleBg {
|
||||
font-size: 18px;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
206
src/components/UserModalPage/index.jsx
Normal file
@@ -0,0 +1,206 @@
|
||||
import style from "./index.less";
|
||||
import {ScrollBoard} from "@jiaminghi/data-view-react";
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import leftPageApi from "@/https/apis/leftPageApi";
|
||||
import modalApi from "@/https/apis/modalApi";
|
||||
|
||||
|
||||
const modalPage = ({onCloseUser}) => {
|
||||
//用户弹框的轮播表
|
||||
const [userVehicleList, setUserVehicleList] = useState([])
|
||||
|
||||
const [imgUrl, setImgUrl] = useState('')
|
||||
|
||||
const [detailVisible, setDetailVisible] = useState(false);
|
||||
//获取车辆类型
|
||||
const [illegalTypeList, setIllegalTypeList] = useState([])
|
||||
|
||||
//获取身份列表
|
||||
const [idTypeList, setIdTypeList] = useState([])
|
||||
//人员详情
|
||||
const [configDetails, setConfigDetails] = useState({})
|
||||
|
||||
const [searchText, setSearchText] = useState('')
|
||||
const [userListParams, setUserListParams] = useState({
|
||||
vehicleTypeId: "", userType: ""
|
||||
})
|
||||
|
||||
const scrollTable = useRef()
|
||||
|
||||
useEffect(() => {
|
||||
getUserVehicleList()
|
||||
}, [userListParams])
|
||||
|
||||
useEffect(() => {
|
||||
getUserVehicleList()
|
||||
carTypeList()
|
||||
getIdTypeList()
|
||||
}, [])
|
||||
|
||||
/**
|
||||
* 获取人员车辆列表
|
||||
*/
|
||||
const getUserVehicleList = () => {
|
||||
leftPageApi.userVehicleList({...userListParams, keyword: searchText}).then(res => {
|
||||
if (res.code == 200) {
|
||||
setUserVehicleList(res.data.map(it => {
|
||||
return [it.name, it.no, it.sex == '1' ? '男' : '女', it.organName, it.vehicleCount, `<span style='display: none'>${it.id}</span>`]
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 获取车辆类型
|
||||
* @param key
|
||||
*/
|
||||
const carTypeList = (key) => {
|
||||
modalApi.carTypeList(key).then(res => {
|
||||
if (res.code === 200) {
|
||||
setIllegalTypeList(res.data.map(it => {
|
||||
return {
|
||||
name: it.name,
|
||||
value: it.id,
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
const getIdTypeList = () => {
|
||||
leftPageApi.idTypeList().then(res => {
|
||||
if (res.code == 200) {
|
||||
setIdTypeList(res.data.map(it => {
|
||||
return {
|
||||
name: it.name,
|
||||
value: it.id
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击轮播表获取详情事件
|
||||
* @param userId
|
||||
* @param vehicleTypeId
|
||||
*/
|
||||
const detailClick = (userId, vehicleTypeId) => {
|
||||
leftPageApi.userVehicleDetails(vehicleTypeId, userId).then(res => {
|
||||
if (res.code == 200) {
|
||||
setImgUrl(res.data[0].imgs)
|
||||
console.log(res.data)
|
||||
setConfigDetails(res.data.map(it => {
|
||||
return [it.name, it.type, it.plateNo, it.status, `<span style="display: none">${it.imgs}</span>`]
|
||||
}))
|
||||
}
|
||||
})
|
||||
setDetailVisible(true)
|
||||
}
|
||||
|
||||
//用户轮播图
|
||||
let userConfig = {
|
||||
index: true,
|
||||
headerBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
headerHeight: 65,
|
||||
oddRowBGC: 'rgba(0, 0, 0, 0)',
|
||||
evenRowBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
columnWidth: [60, 120, 140, 120, 200],
|
||||
rowNum: 5,
|
||||
header: [
|
||||
"<span style='color: #BDFF79;'>姓名</span>",
|
||||
"<span style='color: #BDFF79;'>ID</span>",
|
||||
"<span style='color: #BDFF79;'>性别</span>",
|
||||
"<span style='color: #BDFF79;'>部门</span>",
|
||||
"<span style='color: #BDFF79;'>车辆</span>",
|
||||
],
|
||||
data: userVehicleList
|
||||
}
|
||||
//用户详情
|
||||
let userDetailConfig = {
|
||||
index: true,
|
||||
headerBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
headerHeight: 60,
|
||||
oddRowBGC: 'rgba(0, 0, 0, 0)',
|
||||
evenRowBGC: 'rgba(47, 253, 239, 0.1)',
|
||||
columnWidth: [150, 150, 150, 150],
|
||||
rowNum: configDetails.length,
|
||||
header: [
|
||||
"<span style='color: #BDFF79;'>姓名</span>",
|
||||
"<span style='color: #BDFF79;'>车辆类型</span>",
|
||||
"<span style='color: #BDFF79;'>车牌号</span>",
|
||||
"<span style='color: #BDFF79;'>车辆状态</span>",
|
||||
],
|
||||
data: configDetails
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* 人员列表弹框*/}
|
||||
{
|
||||
<div className={style.modal_box}>
|
||||
<div className={style.modal_title}>
|
||||
<span className={style.title_box}>人员车辆-查询</span>
|
||||
<span style={{position: 'absolute', right: 10, cursor: 'pointer'}}
|
||||
onClick={onCloseUser}>×</span>
|
||||
</div>
|
||||
<div className={style.modal_body}>
|
||||
<select className={style.text} type="text" id="carType"
|
||||
onChange={(e) => setUserListParams({...userListParams, vehicleTypeId: e.target.value})}
|
||||
>
|
||||
<option value="" style={{display: 'none'}}>车辆类型</option>
|
||||
{illegalTypeList.map(it => {
|
||||
return (
|
||||
<option key={it.value} value={it.value}>{it.name}</option>
|
||||
)
|
||||
})}
|
||||
</select>
|
||||
<img src={require("@/assets/chain.png")} alt=""/>
|
||||
<select className={style.text}
|
||||
onChange={(e) => setUserListParams({...userListParams, userType: e.target.value})}>
|
||||
<option value="" style={{display: 'none'}}>身份筛选</option>
|
||||
<option key={''} value={''}>全部</option>
|
||||
{idTypeList.map(it => {
|
||||
return (<option key={it.value} value={it.value}>{it.name}</option>)
|
||||
})}
|
||||
</select>
|
||||
<input className={style.text} placeholder="搜索" type="search"
|
||||
onChange={e => setSearchText(e.target.value)}/>
|
||||
<div className={style.search_btn}>
|
||||
<img style={{position: "absolute", left: '25%', top: '25%', width: 25, height: 25}}
|
||||
src={require("@/assets/searchWhite.png")} onClick={() => getUserVehicleList()}/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{cursor: 'pointer', width: '100%',height:'100%',overflow:'auto'}}>
|
||||
<ScrollBoard config={userConfig} style={{width: '100%', height: '300px'}}
|
||||
onClick={(e) => detailClick(e.row[6]?.replace(/<[^>]*>/g, ""), userListParams.vehicleTypeId)}
|
||||
/>
|
||||
</div>
|
||||
</div>}
|
||||
{/* 详情弹框*/}
|
||||
{
|
||||
detailVisible &&
|
||||
<div className={style.modal_box} style={{width: 769, height: 458}}>
|
||||
<div className={style.modal_title}>
|
||||
<span className={style.title_box}>人员车辆-详情</span>
|
||||
<span style={{position: 'absolute', right: 10, cursor: 'pointer'}}
|
||||
onClick={() => {
|
||||
setDetailVisible(false)
|
||||
setImgUrl('')
|
||||
}}>×</span>
|
||||
</div>
|
||||
<div className={style.middleDetails}>
|
||||
{imgUrl && <div className={style.pic}>
|
||||
<img src={imgUrl} alt="" style={{width: '100%', height: '100%'}}/>
|
||||
</div>}
|
||||
</div>
|
||||
<div className={style.board_box}>
|
||||
<ScrollBoard config={userDetailConfig} style={{height: 170}} ref={scrollTable}
|
||||
onClick={(e) => setImgUrl(e.row[5].replace(/<[^>]*>/g, ""))}/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default modalPage
|
||||
103
src/components/UserModalPage/index.less
Normal file
@@ -0,0 +1,103 @@
|
||||
.modal_box {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%,-75%);
|
||||
width: 769px;
|
||||
height: 430px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border: 2px solid #10FDF2;
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
.modal_title {
|
||||
transform: translateY(5%);
|
||||
height: 8%;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #FFFFFF;
|
||||
line-height: 25px;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.userTable {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
.modal_body {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 22%;
|
||||
.text {
|
||||
height: 45px;
|
||||
width: 25%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border-radius: 22px;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #14FDF7;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #D5D8E2;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
padding-left: 10px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
|
||||
|
||||
&:nth-child(1){
|
||||
//transform: translateX(55px);
|
||||
}
|
||||
}
|
||||
|
||||
.title_box {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
background-color: #10FDF2;
|
||||
padding: 0 8px 5px 8px;
|
||||
}
|
||||
|
||||
.search_btn {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
width: 43px;
|
||||
height: 43px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
cursor: pointer;
|
||||
background: #14FDF7;
|
||||
}
|
||||
option {
|
||||
font-size: 14px;
|
||||
// background: rgba(47, 253, 239, 0.1);
|
||||
background-color: rgb(0, 52, 73);
|
||||
color: #D5D8E2;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 2px solid #24A7A4;
|
||||
}
|
||||
}
|
||||
.middleDetails {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 55%;
|
||||
.pic {
|
||||
width: 35%;
|
||||
height: 205px;
|
||||
border: 1px solid #14FDF7;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
.row-item {
|
||||
height: 47px;
|
||||
}
|
||||
|
||||
.board_box {
|
||||
height: 200px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
}
|
||||
}
|
||||
}
|
||||
84
src/global.less
Normal file
@@ -0,0 +1,84 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
}
|
||||
|
||||
@primary-color: #14FDF7; // 全局主色
|
||||
|
||||
.ant-picker-panel-container {
|
||||
background: black !important;
|
||||
}
|
||||
|
||||
.ant-picker-header {
|
||||
color: #14FDF7;
|
||||
border-bottom: 1px solid #bfbfbf80;
|
||||
}
|
||||
|
||||
.ant-picker-content th {
|
||||
color: #14FDF7;
|
||||
}
|
||||
|
||||
.ant-picker-content th:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
// 其他月
|
||||
.ant-picker-cell {
|
||||
color: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.ant-picker-cell:hover {
|
||||
color: #000;
|
||||
background-color: black;
|
||||
|
||||
.ant-picker-cell-inner {
|
||||
background-color: #ffffff80 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 本月
|
||||
.ant-picker-cell-in-view {
|
||||
color: #14FDF7;
|
||||
}
|
||||
|
||||
.ant-picker-cell-in-view:hover {
|
||||
color: black;
|
||||
|
||||
}
|
||||
|
||||
.ant-picker-cell-in-view:hover {
|
||||
.ant-picker-cell-inner {
|
||||
background: #ffffff80 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-picker-panel .ant-picker-footer {
|
||||
border-bottom: 1px solid #bfbfbf80;
|
||||
border-top: 1px solid #bfbfbf80;
|
||||
}
|
||||
|
||||
.ant-picker-panel {
|
||||
border-bottom: 1px solid #bfbfbf80;
|
||||
}
|
||||
|
||||
.ant-picker-header > button {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ant-picker-header > button:hover {
|
||||
color: #14FDF7;
|
||||
}
|
||||
|
||||
.ant-picker-range-arrow {
|
||||
display: none;
|
||||
background-color: #ffffff80 !important;
|
||||
|
||||
}
|
||||
|
||||
.ant-picker-input > input {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.ant-picker-cell .ant-picker-cell-inner {
|
||||
}
|
||||
80
src/https/apis/leftPageApi.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import request from "@/https/request";
|
||||
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 获取车辆类型的数量
|
||||
* @param data
|
||||
*/
|
||||
countType: async (data) => {
|
||||
return request('/vehicle/manager/visual/management/illegal/count/type', {method: 'GET', data})
|
||||
},
|
||||
/**
|
||||
* 获取本月违规数
|
||||
*/
|
||||
monthCount: async () => {
|
||||
return request('/vehicle/manager/visual/management/illegal/current/month')
|
||||
},
|
||||
/**
|
||||
* 获取上月违规数
|
||||
*/
|
||||
lastMonthCount: async () => {
|
||||
return request('/vehicle/manager/visual/management/illegal/last/month')
|
||||
},
|
||||
/**
|
||||
* 获取当日的违规数
|
||||
*/
|
||||
dayCount: async () => {
|
||||
return request('/vehicle/manager/visual/management/illegal/today')
|
||||
},
|
||||
/**
|
||||
* 获取昨日
|
||||
*/
|
||||
lastDay: async () => {
|
||||
return request('/vehicle/manager/visual/management/illegal/yesterday')
|
||||
},
|
||||
/**
|
||||
* 获取违规列表
|
||||
* @return {Promise<any>}
|
||||
*/
|
||||
illegalList: async () => {
|
||||
return request('/vehicle/manager/visual/management/illegal/page')
|
||||
},
|
||||
/**
|
||||
* 获取违规总数
|
||||
*/
|
||||
illegalCount: async () => {
|
||||
return request('/vehicle/manager/visual/management/illegal/count')
|
||||
},
|
||||
/**
|
||||
* 获取人员车辆列表
|
||||
*/
|
||||
userVehicleList: async ({vehicleTypeId, userType, keyword}) => {
|
||||
return request('/vehicle/manager/visual/management/illegal/user/vehicle', {
|
||||
method: 'GET', params: {
|
||||
vehicleTypeId,
|
||||
userType,
|
||||
keyword
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取身份表
|
||||
*/
|
||||
idTypeList:async () => {
|
||||
return request('/vehicle/manager/user/enum/page',{
|
||||
method:'GET'
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 获取人员车辆详情
|
||||
*/
|
||||
userVehicleDetails:async(vehicleTypeId, userId)=> {
|
||||
return request('/vehicle/manager/visual/management/illegal/user/vehicle/detail',{
|
||||
method:'GET',params:{
|
||||
vehicleTypeId,
|
||||
userId,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
46
src/https/apis/modalApi.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import request from "@/https/request";
|
||||
|
||||
export default {
|
||||
|
||||
/**
|
||||
* 获取学院违规统计
|
||||
*/
|
||||
getCollegeList: async (data) => {
|
||||
return request("/vehicle/manager/visual/management/illegal/college/count", {method: 'GET', data});
|
||||
},
|
||||
/**
|
||||
* 车辆类型列表
|
||||
*/
|
||||
carTypeList: async (data) => {
|
||||
return request("/vehicle/manager/vehicle/type/page", {method: 'GET', data});
|
||||
},
|
||||
/**
|
||||
* 违规类型列表
|
||||
* @param vehicleTypeId
|
||||
* @return {Promise<any>}
|
||||
*/
|
||||
illegalTypeList:async (vehicleTypeId) => {
|
||||
return request('/vehicle/manager/score/rule/page',{method:'GET',params:{vehicleTypeId}})
|
||||
},
|
||||
/**
|
||||
* 车辆违规列表
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @param no 学院编号
|
||||
* @param vehicleTypeId 车辆类型
|
||||
* @param ruleId 违规类型
|
||||
* @param keyword 关键词
|
||||
*/
|
||||
illegalList: async ({vehicleTypeId, ruleId, keyword,startTime='',endTime='',no}) => {
|
||||
return request("/vehicle/manager/visual/management/illegal/page", {
|
||||
method: 'GET', params: {
|
||||
vehicleTypeId,
|
||||
ruleId,
|
||||
keyword,
|
||||
startTime,
|
||||
endTime,
|
||||
no,
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
23
src/https/apis/rightPageApi.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import request from "@/https/request";
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 学院违规统计
|
||||
*/
|
||||
collegeCount:async (data) => {
|
||||
return request('/vehicle/manager/visual/management/illegal/college/count', {params: {dateTime: data}})
|
||||
},
|
||||
/**
|
||||
* 近七天的违规类型统计
|
||||
* @return {Promise<any>}
|
||||
*/
|
||||
sevenType:async () => {
|
||||
return request('/vehicle/manager/visual/management/illegal/in/seven/type')
|
||||
},
|
||||
/**
|
||||
* 近七天每天的违规量
|
||||
*/
|
||||
sevenCount:async () => {
|
||||
return request('/vehicle/manager/visual/management/illegal/in/seven/days')
|
||||
}
|
||||
}
|
||||
99
src/https/request.js
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* request 网络请求工具
|
||||
* 更详细的 api 文档: https://github.com/umijs/umi-request
|
||||
*/
|
||||
import {extend} from 'umi-request';
|
||||
import Common from "@/utils/Common";
|
||||
|
||||
const codeMessage = {
|
||||
200: '服务器成功返回请求的数据。',
|
||||
201: '新建或修改数据成功。',
|
||||
202: '一个请求已经进入后台排队(异步任务)。',
|
||||
204: '删除数据成功。',
|
||||
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
|
||||
401: '用户没有权限(令牌、用户名、密码错误)。',
|
||||
403: '用户得到授权,但是访问是被禁止的。',
|
||||
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
|
||||
406: '请求的格式不可得。',
|
||||
410: '请求的资源被永久删除,且不会再得到的。',
|
||||
422: '当创建一个对象时,发生一个验证错误。',
|
||||
500: '服务器发生错误,请检查服务器。',
|
||||
502: '网关错误。',
|
||||
503: '服务不可用,服务器暂时过载或维护。',
|
||||
504: '网关超时。',
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存用户登录信息
|
||||
*/
|
||||
export const saveLoginInfo = (data) => {
|
||||
sessionStorage.setItem('token', data.token);
|
||||
sessionStorage.setItem('nickName', data.user.nickName);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 异常处理程序
|
||||
*/
|
||||
const errorHandler = error => {
|
||||
const {response} = error;
|
||||
let res = {
|
||||
code: -1,
|
||||
message: '请求初始化时出错或者服务器没有响应返回'
|
||||
};
|
||||
|
||||
if (!Common.isEmpty(response)) {
|
||||
res.code = response.status;
|
||||
res.message = codeMessage[response.status] || response.statusText;
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
/**
|
||||
* 配置request请求时的默认参数
|
||||
*/
|
||||
|
||||
const request = extend({
|
||||
errorHandler,
|
||||
// 默认错误处理
|
||||
credentials: 'include', // 默认请求是否带上cookie
|
||||
requestType: "json", // 表单提交post请求
|
||||
});
|
||||
|
||||
request.use((async (ctx, next) => {
|
||||
const {options} = ctx.req;
|
||||
|
||||
options.headers = {...options.headers, token: sessionStorage.getItem('token')};
|
||||
|
||||
// 存在分页器的时候
|
||||
if (options.params?.pagination) {
|
||||
options.params.length = options.params.pagination.pageSize;
|
||||
options.params.start = options.params?.length * (options.params.pagination.current - 1);
|
||||
delete options.params['pagination'];
|
||||
}
|
||||
if (options.data?.pagination) {
|
||||
options.data.length = options.data.pagination.pageSize;
|
||||
options.data.start = options.data.length * (options.data.pagination.current - 1);
|
||||
delete options.data['pagination'];
|
||||
}
|
||||
|
||||
// equals 处理
|
||||
if (options.params && options.params.equals) {
|
||||
let ids = [];
|
||||
let equalsObj = options.params.equals;
|
||||
Object.keys(equalsObj).map(key => {
|
||||
if (!Common.isEmpty(equalsObj[key])) {
|
||||
ids.push(key + "=" + equalsObj[key]);
|
||||
}
|
||||
});
|
||||
options.params.equals = ids.join(",");
|
||||
}
|
||||
|
||||
// 增加通用参数
|
||||
|
||||
await next();
|
||||
|
||||
}));
|
||||
|
||||
|
||||
export default request;
|
||||
179
src/pages/document.ejs
Normal file
@@ -0,0 +1,179 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0">
|
||||
<script crossorigin src="./react.production.min.js"></script>
|
||||
<script crossorigin src="./react-dom.production.min.js"></script>
|
||||
<script crossorigin src="./charts.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>Out-of-the-box mid-stage front/design solution!</noscript>
|
||||
<div id="root">
|
||||
<style>html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.page-loading-warp {
|
||||
padding: 24px 98px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ant-spin {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 14px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1.5;
|
||||
list-style: none;
|
||||
-webkit-font-feature-settings: 'tnum';
|
||||
font-feature-settings: 'tnum';
|
||||
position: absolute;
|
||||
display: none;
|
||||
color: #1890ff;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
opacity: 0;
|
||||
-webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
|
||||
-webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
|
||||
}
|
||||
|
||||
.ant-spin-spinning {
|
||||
position: static;
|
||||
display: inline-block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ant-spin-dot {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
background-color: #1296db;
|
||||
border-radius: 100%;
|
||||
-webkit-transform: scale(0.75);
|
||||
-ms-transform: scale(0.75);
|
||||
transform: scale(0.75);
|
||||
-webkit-transform-origin: 50% 50%;
|
||||
-ms-transform-origin: 50% 50%;
|
||||
transform-origin: 50% 50%;
|
||||
opacity: 0.3;
|
||||
-webkit-animation: antSpinMove 1s infinite linear alternate;
|
||||
animation: antSpinMove 1s infinite linear alternate;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(1) {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(2) {
|
||||
top: 0;
|
||||
right: 0;
|
||||
-webkit-animation-delay: 0.4s;
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(3) {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
-webkit-animation-delay: 0.8s;
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-item:nth-child(4) {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
-webkit-animation-delay: 1.2s;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
.ant-spin-dot-spin {
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
-webkit-animation: antRotate 1.2s infinite linear;
|
||||
animation: antRotate 1.2s infinite linear;
|
||||
}
|
||||
|
||||
.ant-spin-lg .ant-spin-dot {
|
||||
font-size: 32px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.ant-spin-lg .ant-spin-dot i {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
||||
.ant-spin-blur {
|
||||
background: #fff;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antRotate {
|
||||
to {
|
||||
-webkit-transform: rotate(405deg);
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antRotate {
|
||||
to {
|
||||
-webkit-transform: rotate(405deg);
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}</style>
|
||||
|
||||
<div
|
||||
style="display: flex;justify-content: center;align-items: center;flex-direction: column;min-height: 420px;height: 100%;">
|
||||
<div class="page-loading-warp">
|
||||
<div class="ant-spin ant-spin-lg ant-spin-spinning">
|
||||
<span class="ant-spin-dot ant-spin-dot-spin">
|
||||
<i class="ant-spin-dot-item"></i>
|
||||
<i class="ant-spin-dot-item"></i>
|
||||
<i class="ant-spin-dot-item"></i>
|
||||
<i class="ant-spin-dot-item"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
36
src/pages/index.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React, {useRef, useState} from "react";
|
||||
import less from './index.less'
|
||||
import LeftPage from '../components/LeftPage'
|
||||
import RightPage from '../components/RightPage'
|
||||
import MiddlePage from '../components/MiddlePage'
|
||||
import {BorderBox6} from "@jiaminghi/data-view-react";
|
||||
import CarModalPage from "@/components/CarModalPage";
|
||||
import ModalPage from "@/components/UserModalPage";
|
||||
import Flex from "@/components/Flex";
|
||||
|
||||
const width = 2120, height = 1295;
|
||||
const bgUrl = window.sessionStorage.getItem('core_3d_map_bg');
|
||||
|
||||
export default () => {
|
||||
|
||||
const carModalPageRef = useRef();
|
||||
|
||||
|
||||
///////////////////////////////////////// 页面渲染
|
||||
|
||||
return <Flex className={less.body} style={{backgroundImage: `url(${bgUrl})`}}>
|
||||
|
||||
<LeftPage/>
|
||||
|
||||
<Flex itemGrow={1} style={{width: 0}}>
|
||||
|
||||
</Flex>
|
||||
|
||||
<Flex>
|
||||
<RightPage/>
|
||||
</Flex>
|
||||
|
||||
|
||||
</Flex>
|
||||
|
||||
}
|
||||
129
src/pages/index.less
Normal file
@@ -0,0 +1,129 @@
|
||||
.body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 5px 15px;
|
||||
//background-image: url("../assets/map.png") ;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.containerBody {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 88%;
|
||||
}
|
||||
|
||||
.left_box {
|
||||
width: 20%;
|
||||
//height: 95%;
|
||||
//min-width: 900px;
|
||||
//background-color: aqua;
|
||||
}
|
||||
|
||||
.middle_box {
|
||||
width: 60%;
|
||||
//background-color: saddlebrown;
|
||||
}
|
||||
|
||||
.right_box {
|
||||
width: 20%;
|
||||
//background-color: greenyellow;
|
||||
}
|
||||
|
||||
.modal_box {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -75%);
|
||||
width: 769px;
|
||||
height: 430px;
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border: 2px solid #10FDF2;
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
.modal_title {
|
||||
transform: translateY(5%);
|
||||
height: 8%;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #FFFFFF;
|
||||
line-height: 25px;
|
||||
text-align: center;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.modal_body {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 22%;
|
||||
|
||||
.text {
|
||||
height: 45px;
|
||||
width: 25%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
border-radius: 22px;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
border: 1px solid #14FDF7;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #D5D8E2;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
padding-left: 10px;
|
||||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
|
||||
|
||||
&:nth-child(1) {
|
||||
//transform: translateX(55px);
|
||||
}
|
||||
}
|
||||
|
||||
.title_box {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
background-color: #10FDF2;
|
||||
padding: 0 8px 5px 8px;
|
||||
}
|
||||
|
||||
.search_btn {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
width: 43px;
|
||||
height: 43px;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
cursor: pointer;
|
||||
background: #14FDF7;
|
||||
}
|
||||
|
||||
option {
|
||||
font-size: 14px;
|
||||
// background: rgba(47, 253, 239, 0.1);
|
||||
background-color: rgb(0, 52, 73);
|
||||
color: #D5D8E2;
|
||||
backdrop-filter: blur(10px);
|
||||
border: 2px solid #24A7A4;
|
||||
}
|
||||
}
|
||||
|
||||
.middleDetails {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: 69%;
|
||||
|
||||
.pic {
|
||||
width: 45%;
|
||||
height: 200px;
|
||||
border: 1px solid #14FDF7;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/utils/AppCommon.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import request from '@/https/request';
|
||||
import AppHelper from '@/utils/AppHelper';
|
||||
import {stringify} from 'qs';
|
||||
|
||||
export default {
|
||||
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
* @param url
|
||||
* @param params
|
||||
*/
|
||||
downloadFile: (url, params) => {
|
||||
return request(url, {method: 'POST', data: {...params}}).then(res => {
|
||||
if (res.code === 200) {
|
||||
window.location.href = res.data;
|
||||
} else {
|
||||
AppHelper.showRespError(res);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 直接下载文件
|
||||
* @param url
|
||||
* @param params
|
||||
*/
|
||||
downloadByWindow: (url, params) => {
|
||||
let query = {token: sessionStorage.getItem('token'), ...params};
|
||||
window.location.href = url + '?' + stringify(query);
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
70
src/utils/AppHelper.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import {message} from "antd";
|
||||
import {history} from 'umi';
|
||||
import Common from "@/utils/Common";
|
||||
|
||||
/**
|
||||
* 显示提示消息
|
||||
* @param msg
|
||||
* @param type
|
||||
* @param callback
|
||||
*/
|
||||
const showToast = (msg, type = 'success', callback) => {
|
||||
message[type](msg, 3, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* 显示网络请求错误
|
||||
* @param res
|
||||
*/
|
||||
const showRespError = (res) => {
|
||||
if (res && res.code !== 200) {
|
||||
message.destroy();
|
||||
message['error'](res.message, 3, () => {
|
||||
if (res.code == 110) {
|
||||
routerPush('/login');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 显示加载框
|
||||
* @param msg
|
||||
*/
|
||||
const showLoading = (msg = '数据处理中,请稍等') => {
|
||||
message.loading(msg, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* 隐藏message组件
|
||||
*/
|
||||
const hideMessage = () => {
|
||||
message.destroy();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 返回上一级
|
||||
*/
|
||||
const routerBack = () => {
|
||||
history.goBack();
|
||||
};
|
||||
|
||||
/**
|
||||
* 跳转指定目录
|
||||
* @param pathname
|
||||
* @param query
|
||||
*/
|
||||
const routerPush = (pathname, query) => {
|
||||
if (Common.isEmpty(query)) {
|
||||
history.push(pathname);
|
||||
} else {
|
||||
history.push({pathname, query: {...query}});
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
showToast, showRespError, showLoading,
|
||||
hideMessage, routerBack, routerPush
|
||||
}
|
||||
140
src/utils/Common.js
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* 获取Url中的参数
|
||||
*/
|
||||
const getParamFormUrl = (key, host) => {
|
||||
let arr;
|
||||
let reg = new RegExp('(^|&)' + key + '=([^&]*)(&|$)');
|
||||
try {
|
||||
let testHost = window.location.href;
|
||||
if (host) {
|
||||
testHost = host;
|
||||
}
|
||||
if ((arr = testHost.split('?')[1].match(reg))) {
|
||||
return decodeURI(arr[2]);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断是否开始
|
||||
* @param value
|
||||
* @param start
|
||||
*/
|
||||
const startWidth = (value, start = '') => {
|
||||
return initValue(value, '').substr(0, start.length) === start;
|
||||
};
|
||||
|
||||
/**
|
||||
* 是否为空
|
||||
* @param value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
const isEmpty = (value) => {
|
||||
return value == undefined || value == null || value == '';
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置默认值
|
||||
* @param value
|
||||
* @param def
|
||||
*/
|
||||
const initValue = (value, def) => {
|
||||
return isEmpty(value) ? def : value;
|
||||
};
|
||||
|
||||
/**
|
||||
* 转换为json
|
||||
* @param value
|
||||
* @param def = {}
|
||||
*/
|
||||
const parseJSON = (value, def) => {
|
||||
let obj;
|
||||
try {
|
||||
obj = JSON.parse(value);
|
||||
} catch (e) {
|
||||
}
|
||||
if (!obj) {
|
||||
obj = def;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 将array中的某个key用sep连接起来
|
||||
* @param array
|
||||
* @param key
|
||||
* @param sep
|
||||
*/
|
||||
const arrayKeys = (array = [], key = 'id', sep = ',') => {
|
||||
let result = '';
|
||||
array.forEach(item => {
|
||||
if (typeof item == 'object') {
|
||||
result = result + item[key];
|
||||
} else {
|
||||
result = result + item;
|
||||
}
|
||||
result = result + sep;
|
||||
});
|
||||
result = result.substring(0, result.length - sep.length);
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 分割对象
|
||||
* @param obj
|
||||
* @param sep
|
||||
*/
|
||||
const splitObj = (obj, sep = ',') => {
|
||||
if (obj) {
|
||||
return obj.split(sep);
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 字符串长度
|
||||
* @param val
|
||||
* @returns {number}
|
||||
*/
|
||||
const length = (val = '') => {
|
||||
return isEmpty(val) ? 0 : val.length;
|
||||
};
|
||||
|
||||
|
||||
const arraySet = (array = [], key) => {
|
||||
let obj = {};
|
||||
array.forEach(item => {
|
||||
obj[item[key]] = item;
|
||||
});
|
||||
return Object.keys(obj).map(k => (obj[k]));
|
||||
};
|
||||
|
||||
/**
|
||||
* 上传图片
|
||||
*/
|
||||
const uploadFile = (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let fileData = new FormData();
|
||||
fileData.append('file', file);
|
||||
let request = new XMLHttpRequest();
|
||||
request.open("POST", "/tools/file/whole_upload");
|
||||
request.onreadystatechange = ev => {
|
||||
if (ev.currentTarget.readyState === 4) {
|
||||
let res = JSON.parse(ev.currentTarget.responseText);
|
||||
resolve(res);
|
||||
}
|
||||
};
|
||||
request.send(fileData);
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
getParamFormUrl, isEmpty, initValue, startWidth, arraySet,
|
||||
parseJSON, arrayKeys, splitObj, length, uploadFile
|
||||
}
|
||||
|
||||
|
||||