Compare commits
11 Commits
954c4ac296
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 07894f63a2 | |||
| 96b75c6cab | |||
| c250f2ae5e | |||
| 7df71448c9 | |||
| 6bf4799789 | |||
| 7b78a39b52 | |||
| 7c0c367041 | |||
| 3c61f2db3b | |||
| 4157f9804c | |||
| 52d2d7c773 | |||
| 164cb594fa |
@@ -1,4 +1,4 @@
|
|||||||
import type { PageParam } from '@/api';
|
import type { PageParam } from '@/api/index';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表单设计表
|
* 表单设计表
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ export interface HjmViolation {
|
|||||||
id?: number;
|
id?: number;
|
||||||
// 车辆编号
|
// 车辆编号
|
||||||
code?: string;
|
code?: string;
|
||||||
|
// 车辆图片
|
||||||
|
image?: string;
|
||||||
// 标题
|
// 标题
|
||||||
title?: string;
|
title?: string;
|
||||||
// 文章分类ID
|
// 文章分类ID
|
||||||
|
|||||||
@@ -41,4 +41,5 @@ export interface OrganizationParam extends PageParam {
|
|||||||
keywords?: string;
|
keywords?: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
parentId?: number;
|
parentId?: number;
|
||||||
|
organizationIds?: any;
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/components/FixedButton.tsx
Normal file
38
src/components/FixedButton.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {View} from '@tarojs/components';
|
||||||
|
import {Button} from '@nutui/nutui-react-taro'
|
||||||
|
|
||||||
|
interface FixedButtonProps {
|
||||||
|
text?: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
disabled?: boolean;
|
||||||
|
background?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function FixedButton({text, onClick, icon, disabled, background}: FixedButtonProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* 底部安全区域占位 */}
|
||||||
|
<View className="h-20 w-full"></View>
|
||||||
|
<View
|
||||||
|
className="fixed z-50 bottom-0 left-0 right-0 bg-white border-t border-gray-200 px-4 py-3 safe-area-bottom">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
style={{
|
||||||
|
background
|
||||||
|
}}
|
||||||
|
size="large"
|
||||||
|
block
|
||||||
|
icon={icon}
|
||||||
|
disabled={disabled}
|
||||||
|
className="px-6"
|
||||||
|
onClick={onClick}>
|
||||||
|
{text || '新增'}
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FixedButton;
|
||||||
@@ -8,6 +8,8 @@ import './location.scss'
|
|||||||
import {HjmFence} from "@/api/hjm/hjmFence/model";
|
import {HjmFence} from "@/api/hjm/hjmFence/model";
|
||||||
import {getHjmFence} from "@/api/hjm/hjmFence";
|
import {getHjmFence} from "@/api/hjm/hjmFence";
|
||||||
import {Market} from "../pages/index";
|
import {Market} from "../pages/index";
|
||||||
|
// 导入GPS坐标转换工具
|
||||||
|
import GPS from '@/utils/gpsUtil.js';
|
||||||
interface Where {
|
interface Where {
|
||||||
latitude?: number;
|
latitude?: number;
|
||||||
longitude?: number;
|
longitude?: number;
|
||||||
@@ -42,9 +44,30 @@ const Location = () => {
|
|||||||
// 转为多边形点数组
|
// 转为多边形点数组
|
||||||
const points = coordPairs.map(coord => {
|
const points = coordPairs.map(coord => {
|
||||||
const [lat, lng] = coord.split(',');
|
const [lat, lng] = coord.split(',');
|
||||||
|
const latitude = parseFloat(lat);
|
||||||
|
const longitude = parseFloat(lng);
|
||||||
|
|
||||||
|
// 确保解析后的坐标是有效数字
|
||||||
|
if (isNaN(latitude) || isNaN(longitude)) {
|
||||||
|
throw new Error(`无效坐标: ${lat}, ${lng}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换WGS84坐标到GCJ02坐标
|
||||||
|
try {
|
||||||
|
const transformed = GPS.gcj_encrypt(latitude, longitude);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
return {
|
||||||
|
latitude: transformed.lat,
|
||||||
|
longitude: transformed.lng
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('围栏坐标转换错误:', error);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
latitude: parseFloat(lat),
|
latitude: latitude,
|
||||||
longitude: parseFloat(lng)
|
longitude: longitude
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log(points,'pointspointspoints')
|
console.log(points,'pointspointspoints')
|
||||||
@@ -57,30 +80,66 @@ const Location = () => {
|
|||||||
|
|
||||||
const reload = () => {
|
const reload = () => {
|
||||||
setScale(11)
|
setScale(11)
|
||||||
setLongitude(108.355702)
|
|
||||||
setLatitude(22.857968)
|
// 设置初始坐标(需要转换)
|
||||||
|
const initialLat = 22.857968;
|
||||||
|
const initialLng = 108.355702;
|
||||||
|
try {
|
||||||
|
const transformed = GPS.gcj_encrypt(initialLat, initialLng);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
setLongitude(transformed.lng);
|
||||||
|
setLatitude(transformed.lat);
|
||||||
|
} else {
|
||||||
|
setLongitude(initialLng);
|
||||||
|
setLatitude(initialLat);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始坐标转换错误:', error);
|
||||||
|
setLongitude(initialLng);
|
||||||
|
setLatitude(initialLat);
|
||||||
|
}
|
||||||
|
|
||||||
getHjmFence(4).then(data => {
|
getHjmFence(4).then(data => {
|
||||||
setFence(data)
|
setFence(data)
|
||||||
const coordStr = data.points || '';
|
const coordStr = data.points || '';
|
||||||
|
|
||||||
// 使用通用函数解析坐标字符串
|
// 使用通用函数解析坐标字符串(已包含坐标转换)
|
||||||
const {points} = parseCoordinateString(coordStr);
|
const {points} = parseCoordinateString(coordStr);
|
||||||
console.log('解析结果 - 多边形点:', points);
|
console.log('解析结果 - 多边形点:', points);
|
||||||
setPoints(points);
|
setPoints(points);
|
||||||
setShowCircles(true)
|
setShowCircles(true)
|
||||||
console.log(fence,'fencefencefence')
|
console.log(fence,'fencefencefence')
|
||||||
})
|
})
|
||||||
|
|
||||||
const where: Where = {}
|
const where: Where = {}
|
||||||
|
// 使用转换后的坐标
|
||||||
where.latitude = latitude
|
where.latitude = latitude
|
||||||
where.longitude = longitude
|
where.longitude = longitude
|
||||||
|
|
||||||
pageByQQMap(where).then(res => {
|
pageByQQMap(where).then(res => {
|
||||||
if (res?.count == 0) {
|
if (res?.count == 0) {
|
||||||
const arr = []
|
const arr = []
|
||||||
|
// 转换默认位置坐标
|
||||||
|
const defaultLat = 22.813371;
|
||||||
|
const defaultLng = 108.323885;
|
||||||
|
let markerLat = defaultLat;
|
||||||
|
let markerLng = defaultLng;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const transformed = GPS.gcj_encrypt(defaultLat, defaultLng);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
markerLat = transformed.lat;
|
||||||
|
markerLng = transformed.lng;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('默认位置坐标转换错误:', error);
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
arr.push({
|
arr.push({
|
||||||
id: 10001,
|
id: 10001,
|
||||||
latitude: 22.813371,
|
latitude: markerLat,
|
||||||
longitude: 108.323885,
|
longitude: markerLng,
|
||||||
title: '当前位置',
|
title: '当前位置',
|
||||||
name: '当前位置'
|
name: '当前位置'
|
||||||
})
|
})
|
||||||
@@ -91,11 +150,31 @@ const Location = () => {
|
|||||||
const data = res?.list;
|
const data = res?.list;
|
||||||
const arr = []
|
const arr = []
|
||||||
data?.map((item: HjmCar) => {
|
data?.map((item: HjmCar) => {
|
||||||
|
// 转换WGS84坐标到GCJ02坐标
|
||||||
|
let markerLat = item.latitude;
|
||||||
|
let markerLng = item.longitude;
|
||||||
|
|
||||||
|
if (item.latitude && item.longitude) {
|
||||||
|
try {
|
||||||
|
const lat = Number(item.latitude);
|
||||||
|
const lng = Number(item.longitude);
|
||||||
|
if (!isNaN(lat) && !isNaN(lng) && isFinite(lat) && isFinite(lng)) {
|
||||||
|
const transformed = GPS.gcj_encrypt(lat, lng);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
markerLat = transformed.lat;
|
||||||
|
markerLng = transformed.lng;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('车辆坐标转换错误:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
arr.push({
|
arr.push({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
latitude: item.latitude,
|
latitude: markerLat,
|
||||||
longitude: item.longitude,
|
longitude: markerLng,
|
||||||
label: {
|
label: {
|
||||||
content: `${item?.code}`,
|
content: `${item?.code}`,
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ const List = () => {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
where.driverId = user.userId;
|
where.driverId = user.userId;
|
||||||
}
|
}
|
||||||
if(roleCode == 'zhandian'){
|
if(roleCode == 'zhandian' && user.merchants == null){
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
where.organizationId = user.organizationId;
|
where.organizationId = user.organizationId;
|
||||||
}
|
}
|
||||||
@@ -59,6 +59,10 @@ const List = () => {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
where.installerId = user.userId;
|
where.installerId = user.userId;
|
||||||
}
|
}
|
||||||
|
if(user.merchants != null){
|
||||||
|
// @ts-ignore
|
||||||
|
where.organizationIds = user.merchants;
|
||||||
|
}
|
||||||
if(roleCode == 'user'){
|
if(roleCode == 'user'){
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import {HjmCar} from "@/api/hjm/hjmCar/model";
|
|||||||
import './trajectory.scss'
|
import './trajectory.scss'
|
||||||
import {pageHjmGpsLog} from "@/api/hjm/hjmGpsLog";
|
import {pageHjmGpsLog} from "@/api/hjm/hjmGpsLog";
|
||||||
import {formatCurrentDate, getCurrentHour} from "@/utils/time";
|
import {formatCurrentDate, getCurrentHour} from "@/utils/time";
|
||||||
|
// 导入GPS坐标转换工具
|
||||||
|
import GPS from '@/utils/gpsUtil.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文章终极列表
|
* 文章终极列表
|
||||||
@@ -102,14 +104,33 @@ const Location = () => {
|
|||||||
Taro.showLoading({title: '加载中...'});
|
Taro.showLoading({title: '加载中...'});
|
||||||
pageHjmGpsLog(where).then(res => {
|
pageHjmGpsLog(where).then(res => {
|
||||||
console.log(res?.list, 'list')
|
console.log(res?.list, 'list')
|
||||||
// setPoints(res?.list.map(item => {
|
// 转换轨迹点坐标
|
||||||
// console.log(item, 'item.')
|
const transformedPoints = (res?.list || []).map(item => {
|
||||||
// return {
|
// 转换WGS84坐标到GCJ02坐标
|
||||||
// latitude: item.latitude,
|
const lat = Number(item.latitude);
|
||||||
// longitude: item.longitude
|
const lng = Number(item.longitude);
|
||||||
// }
|
|
||||||
// }) || [])
|
if (item.latitude && item.longitude &&
|
||||||
setHjmGpsLog(res?.list || []);
|
!isNaN(lat) &&
|
||||||
|
!isNaN(lng) &&
|
||||||
|
isFinite(lat) &&
|
||||||
|
isFinite(lng)) {
|
||||||
|
try {
|
||||||
|
const transformed = GPS.gcj_encrypt(lat, lng);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
latitude: transformed.lat,
|
||||||
|
longitude: transformed.lng
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('轨迹点坐标转换错误:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
setHjmGpsLog(transformedPoints);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
Taro.hideLoading();
|
Taro.hideLoading();
|
||||||
})
|
})
|
||||||
@@ -123,8 +144,34 @@ const Location = () => {
|
|||||||
getHjmCarByCode(keywords).then(data => {
|
getHjmCarByCode(keywords).then(data => {
|
||||||
console.log('执行搜索', data)
|
console.log('执行搜索', data)
|
||||||
setItem(data)
|
setItem(data)
|
||||||
setLatitude(data.latitude)
|
|
||||||
setLongitude(data.longitude)
|
// 转换WGS84坐标到GCJ02坐标
|
||||||
|
if (data.latitude && data.longitude &&
|
||||||
|
!isNaN(data.latitude) &&
|
||||||
|
!isNaN(data.longitude) &&
|
||||||
|
isFinite(data.latitude) &&
|
||||||
|
isFinite(data.longitude)) {
|
||||||
|
try {
|
||||||
|
const lat = Number(data.latitude);
|
||||||
|
const lng = Number(data.longitude);
|
||||||
|
const transformed = GPS.gcj_encrypt(lat, lng);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
setLatitude(transformed.lat);
|
||||||
|
setLongitude(transformed.lng);
|
||||||
|
} else {
|
||||||
|
setLatitude(data.latitude);
|
||||||
|
setLongitude(data.longitude);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('坐标转换错误:', error);
|
||||||
|
setLatitude(data.latitude);
|
||||||
|
setLongitude(data.longitude);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setLatitude(data.latitude);
|
||||||
|
setLongitude(data.longitude);
|
||||||
|
}
|
||||||
|
|
||||||
setKeywords(data.code)
|
setKeywords(data.code)
|
||||||
// 获取车辆轨迹信息
|
// 获取车辆轨迹信息
|
||||||
getLocationRecord(data);
|
getLocationRecord(data);
|
||||||
@@ -144,8 +191,34 @@ const Location = () => {
|
|||||||
if (code) {
|
if (code) {
|
||||||
getHjmCarByCode(code).then(data => {
|
getHjmCarByCode(code).then(data => {
|
||||||
setItem(data)
|
setItem(data)
|
||||||
setLatitude(data.latitude)
|
|
||||||
setLongitude(data.longitude)
|
// 转换WGS84坐标到GCJ02坐标
|
||||||
|
if (data.latitude && data.longitude &&
|
||||||
|
!isNaN(data.latitude) &&
|
||||||
|
!isNaN(data.longitude) &&
|
||||||
|
isFinite(data.latitude) &&
|
||||||
|
isFinite(data.longitude)) {
|
||||||
|
try {
|
||||||
|
const lat = Number(data.latitude);
|
||||||
|
const lng = Number(data.longitude);
|
||||||
|
const transformed = GPS.gcj_encrypt(lat, lng);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
setLatitude(transformed.lat);
|
||||||
|
setLongitude(transformed.lng);
|
||||||
|
} else {
|
||||||
|
setLatitude(data.latitude);
|
||||||
|
setLongitude(data.longitude);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('坐标转换错误:', error);
|
||||||
|
setLatitude(data.latitude);
|
||||||
|
setLongitude(data.longitude);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setLatitude(data.latitude);
|
||||||
|
setLongitude(data.longitude);
|
||||||
|
}
|
||||||
|
|
||||||
setKeywords(data.code)
|
setKeywords(data.code)
|
||||||
// 获取车辆轨迹信息
|
// 获取车辆轨迹信息
|
||||||
getLocationRecord(data);
|
getLocationRecord(data);
|
||||||
@@ -220,7 +293,6 @@ const Location = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/*<Map polyline={{hjmGpsLog}}></Map>*/}
|
|
||||||
<Map
|
<Map
|
||||||
id="map"
|
id="map"
|
||||||
longitude={longitude}
|
longitude={longitude}
|
||||||
|
|||||||
59
src/hjm/violation/Items.tsx
Normal file
59
src/hjm/violation/Items.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import {useEffect} from "react";
|
||||||
|
import {Image, Space,Button} from '@nutui/nutui-react-taro'
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import {View} from '@tarojs/components'
|
||||||
|
import {HjmViolation} from "@/api/hjm/hjmViolation/model";
|
||||||
|
import navTo from "@/utils/common";
|
||||||
|
|
||||||
|
interface BestSellersProps {
|
||||||
|
data: HjmViolation[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const BestSellers = (props: BestSellersProps) => {
|
||||||
|
const reload = () => {
|
||||||
|
// 可以在这里添加重新加载逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reload()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View className={'px-2 mb-4'}>
|
||||||
|
<View className={'flex flex-col justify-between items-center rounded-lg px-3'}>
|
||||||
|
{props.data?.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<View key={item.id || index} className={'flex bg-white rounded-lg w-full p-3 mb-3'}
|
||||||
|
onClick={() => navTo(`/hjm/violation/detail?id=${item.code}`)}>
|
||||||
|
<View className={'flex flex-col'}>
|
||||||
|
<Image src={item.image && JSON.parse(item.image).length > 0 && JSON.parse(item.image)[0].url} mode={'scaleToFill'}
|
||||||
|
radius="10%" width="70" height="70" className={'mb-1'}/>
|
||||||
|
{item.userId == Taro.getStorageSync('UserId') && (
|
||||||
|
<Button type={'default'} size="small" onClick={() => navTo(`/hjm/violation/add?id=${item.id}`)}>修改</Button>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<View className={'mx-3 flex flex-col'}>
|
||||||
|
<Space direction={'vertical'}>
|
||||||
|
<View className={'car-no text-lg font-bold'}>{item.title}</View>
|
||||||
|
<View className={'flex text-xs text-gray-500'}>车辆编号:<span
|
||||||
|
className={'text-gray-700'}>{item.code}</span></View>
|
||||||
|
<View className={'flex text-xs text-gray-500'}>违章描述:<span
|
||||||
|
className={'text-gray-700'}>{item.comments}</span></View>
|
||||||
|
<View className={'flex text-xs text-gray-500'}>创建时间:<span
|
||||||
|
className={'text-gray-700'}>{item.createTime}</span></View>
|
||||||
|
</Space>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
{(!props.data || props.data.length === 0) && (
|
||||||
|
<View className={'flex justify-center items-center py-10'}>
|
||||||
|
<View className={'text-gray-500 text-sm'}>暂无数据</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<View style={{height: '170px'}}></View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default BestSellers
|
||||||
@@ -274,19 +274,19 @@ function Add() {
|
|||||||
} style={{padding: '12px 16px'}}>
|
} style={{padding: '12px 16px'}}>
|
||||||
|
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell title="处理状态" description={'请选择'} extra={
|
{/*<Cell title="处理状态" description={'请选择'} extra={*/}
|
||||||
<div style={{
|
{/* <div style={{*/}
|
||||||
display: 'flex',
|
{/* display: 'flex',*/}
|
||||||
alignItems: 'center',
|
{/* alignItems: 'center',*/}
|
||||||
justifyContent: 'flex-end',
|
{/* justifyContent: 'flex-end',*/}
|
||||||
height: '24px'
|
{/* height: '24px'*/}
|
||||||
}}>
|
{/* }}>*/}
|
||||||
<span style={{color: '#333', fontSize: '14px'}}>
|
{/* <span style={{color: '#333', fontSize: '14px'}}>*/}
|
||||||
{statusOptions.find(option => option.value === formData.status)?.text || '请选择'}
|
{/* {statusOptions.find(option => option.value === formData.status)?.text || '请选择'}*/}
|
||||||
</span>
|
{/* </span>*/}
|
||||||
</div>
|
{/* </div>*/}
|
||||||
} style={{padding: '12px 16px'}} onClick={() => setIsPickerVisible(true)}>
|
{/*} style={{padding: '12px 16px'}} onClick={() => setIsPickerVisible(true)}>*/}
|
||||||
</Cell>
|
{/*</Cell>*/}
|
||||||
</Cell.Group>
|
</Cell.Group>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,390 +1,178 @@
|
|||||||
import React, {useEffect, useState} from "react";
|
import {useEffect, useState, CSSProperties} from "react";
|
||||||
import {
|
import {Search} from '@nutui/icons-react-taro'
|
||||||
Loading,
|
import {Button, Input, InfiniteLoading} from '@nutui/nutui-react-taro'
|
||||||
Empty,
|
|
||||||
Button,
|
|
||||||
Input,
|
|
||||||
Tag,
|
|
||||||
Space,
|
|
||||||
Pagination
|
|
||||||
} from '@nutui/nutui-react-taro'
|
|
||||||
import {useRouter} from '@tarojs/taro'
|
|
||||||
import {Search, Calendar, Truck, File, AddCircle} from '@nutui/icons-react-taro'
|
|
||||||
import Taro, {useDidShow} from '@tarojs/taro'
|
|
||||||
import {pageHjmViolation} from "@/api/hjm/hjmViolation";
|
import {pageHjmViolation} from "@/api/hjm/hjmViolation";
|
||||||
import {HjmViolation} from "@/api/hjm/hjmViolation/model";
|
import {HjmViolation} from "@/api/hjm/hjmViolation/model";
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import Items from "./Items";
|
||||||
|
import {useRouter} from '@tarojs/taro'
|
||||||
|
import {getUserInfo} from "@/api/layout";
|
||||||
|
import navTo from "@/utils/common";
|
||||||
|
import FixedButton from "@/components/FixedButton";
|
||||||
|
|
||||||
|
const InfiniteUlStyle: CSSProperties = {
|
||||||
|
height: '80vh',
|
||||||
|
width: '100%',
|
||||||
|
padding: '0',
|
||||||
|
overflowY: 'auto',
|
||||||
|
overflowX: 'hidden',
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 报险记录列表页面
|
* 文章终极列表
|
||||||
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const List: React.FC = () => {
|
const ViolationList = () => {
|
||||||
const {params} = useRouter();
|
const {params} = useRouter();
|
||||||
const [list, setList] = useState<HjmViolation[]>([])
|
|
||||||
const [loading, setLoading] = useState<boolean>(false)
|
|
||||||
const [keywords, setKeywords] = useState<string>('')
|
const [keywords, setKeywords] = useState<string>('')
|
||||||
const [refreshing, setRefreshing] = useState<boolean>(false)
|
const [list, setList] = useState<HjmViolation[]>([])
|
||||||
const [page, setPage] = useState<number>(1)
|
const [page, setPage] = useState(1)
|
||||||
const [limit, setLimit] = useState<number>(10)
|
const [hasMore, setHasMore] = useState(true)
|
||||||
const [total, setTotal] = useState<number>(0)
|
const [loading, setLoading] = useState(false)
|
||||||
const [needRefresh, setNeedRefresh] = useState<boolean>(false) // 修改默认值为false,避免初始加载时的重复
|
|
||||||
const [isLoadingRef, setIsLoadingRef] = useState<boolean>(false) // 防止并发加载
|
|
||||||
|
|
||||||
console.log(refreshing)
|
const onKeywords = (keywords: string) => {
|
||||||
// 获取状态显示
|
setKeywords(keywords)
|
||||||
const getStatusDisplay = (status?: number) => {
|
|
||||||
switch (status) {
|
|
||||||
case 0:
|
|
||||||
return {text: '未处理', color: '#faad14', bgColor: '#fffbe6'}
|
|
||||||
case 1:
|
|
||||||
return {text: '已处理', color: '#52c41a', bgColor: '#f6ffed'}
|
|
||||||
case 2:
|
|
||||||
return {text: '已驳回', color: '#ff4d4f', bgColor: '#fff2f0'}
|
|
||||||
default:
|
|
||||||
return {text: '未知', color: '#8c8c8c', bgColor: '#f5f5f5'}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const reload = async (showLoading = true) => {
|
const loadList = async (isRefresh = false) => {
|
||||||
// 防止并发请求,如果正在加载则直接返回
|
if (loading) return;
|
||||||
if (isLoadingRef) {
|
|
||||||
console.log('正在加载中,跳过本次请求')
|
setLoading(true)
|
||||||
return
|
|
||||||
|
// 搜索条件
|
||||||
|
const where: any = {
|
||||||
|
keywords: keywords.trim(),
|
||||||
|
page,
|
||||||
|
limit: 10, // 直接使用10,不通过state
|
||||||
}
|
}
|
||||||
|
|
||||||
setLimit(10)
|
// 读取用户信息
|
||||||
try {
|
const user = await getUserInfo();
|
||||||
setIsLoadingRef(true) // 设置加载标记
|
|
||||||
if (showLoading) setLoading(true)
|
|
||||||
setRefreshing(true)
|
|
||||||
|
|
||||||
const where: any = {
|
// 判断身份
|
||||||
keywords: keywords.trim(),
|
const roleCode = Taro.getStorageSync('RoleCode');
|
||||||
page,
|
if(roleCode == 'kuaidiyuan'){
|
||||||
limit,
|
// @ts-ignore
|
||||||
}
|
where.driverId = user.userId;
|
||||||
|
}
|
||||||
const roleCode = Taro.getStorageSync('RoleCode');
|
if(roleCode == 'zhandian'){
|
||||||
if (roleCode == 'kuaidi') {
|
// @ts-ignore
|
||||||
if (Taro.getStorageSync('OrganizationParentId') == 0) {
|
where.organizationId = user.organizationId;
|
||||||
// @ts-ignore
|
}
|
||||||
where.organizationParentId = Taro.getStorageSync('OrganizationId');
|
if(roleCode == 'kuaidi'){
|
||||||
} else {
|
// @ts-ignore
|
||||||
// @ts-ignore
|
where.organizationParentId = user.organizationId;
|
||||||
where.organizationId = Taro.getStorageSync('OrganizationId');
|
}
|
||||||
}
|
if(roleCode == 'Installer'){
|
||||||
}
|
// @ts-ignore
|
||||||
if(params.id){
|
where.installerId = user.userId;
|
||||||
where.code = params.id;
|
}
|
||||||
}
|
if(roleCode == 'user'){
|
||||||
|
|
||||||
console.log('开始请求数据, where:', where)
|
|
||||||
const res = await pageHjmViolation(where)
|
|
||||||
console.log('请求成功,获取到', res?.list?.length, '条数据')
|
|
||||||
|
|
||||||
// 确保数据被替换而不是追加
|
|
||||||
setList(res?.list || [])
|
|
||||||
setTotal(res?.count || 0)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取报险记录失败:', error)
|
|
||||||
Taro.showToast({
|
|
||||||
title: '获取报险记录失败',
|
|
||||||
icon: 'error'
|
|
||||||
})
|
|
||||||
} finally {
|
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
setRefreshing(false)
|
return false;
|
||||||
setIsLoadingRef(false) // 清除加载标记
|
}
|
||||||
|
if(params.id){
|
||||||
|
where.code = params.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取车辆列表
|
||||||
|
try {
|
||||||
|
const res = await pageHjmViolation(where);
|
||||||
|
if (res?.list && res?.list.length > 0) {
|
||||||
|
if (isRefresh) {
|
||||||
|
setList(res.list);
|
||||||
|
} else {
|
||||||
|
setList(prevList => [...prevList, ...res.list]);
|
||||||
|
}
|
||||||
|
setHasMore(res.list.length >= 10); // 如果返回的数据少于10条,说明没有更多了
|
||||||
|
} else {
|
||||||
|
if (isRefresh) {
|
||||||
|
setList([]);
|
||||||
|
}
|
||||||
|
setHasMore(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取车辆列表失败:', error);
|
||||||
|
if (isRefresh) {
|
||||||
|
setList([]);
|
||||||
|
}
|
||||||
|
setHasMore(false);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSearch = () => {
|
const reload = async () => {
|
||||||
reload()
|
setPage(1);
|
||||||
|
await loadList(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onKeywordsChange = (value: string) => {
|
const loadMore = async () => {
|
||||||
setKeywords(value)
|
if (!hasMore || loading) return;
|
||||||
|
const nextPage = page + 1;
|
||||||
|
setPage(nextPage);
|
||||||
|
await loadList();
|
||||||
}
|
}
|
||||||
|
|
||||||
const onAddInsurance = () => {
|
|
||||||
Taro.navigateTo({
|
|
||||||
url: '/hjm/violation/add'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 页面显示时触发,包括从其他页面返回
|
|
||||||
useDidShow(() => {
|
|
||||||
console.log('useDidShow 触发, needRefresh:', needRefresh)
|
|
||||||
if (needRefresh) {
|
|
||||||
console.log('执行 reload 由于 needRefresh=true')
|
|
||||||
reload(false)
|
|
||||||
setNeedRefresh(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
//
|
|
||||||
// useEffect(() => {
|
|
||||||
// // 监听刷新事件
|
|
||||||
// const handleRefresh = () => {
|
|
||||||
// console.log('接收到 violationListRefresh 事件')
|
|
||||||
// // 只设置标记,不直接调用reload,由useDidShow处理
|
|
||||||
// setNeedRefresh(true)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Taro.eventCenter.on('violationListRefresh', handleRefresh)
|
|
||||||
//
|
|
||||||
// // 初始加载数据 - 只在组件首次挂载时执行
|
|
||||||
// console.log('组件初始化,执行初始 reload')
|
|
||||||
// reload().then()
|
|
||||||
//
|
|
||||||
// // 清理事件监听器
|
|
||||||
// return () => {
|
|
||||||
// Taro.eventCenter.off('violationListRefresh', handleRefresh)
|
|
||||||
// }
|
|
||||||
// }, []) // 移除page和limit依赖,避免不必要的重新加载
|
|
||||||
|
|
||||||
// 单独处理分页变化
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (page > 1 || limit !== 10) { // 只有当分页参数真正改变时才重新加载
|
reload().then()
|
||||||
console.log('分页参数变化,执行 reload, page:', page, 'limit:', limit)
|
}, [])
|
||||||
reload().then()
|
|
||||||
}
|
|
||||||
}, [page, limit])
|
|
||||||
|
|
||||||
const onPageChange = (current: number) => {
|
// 页面显示时刷新列表(从添加页返回时触发)
|
||||||
setPage(current)
|
Taro.useDidShow(() => {
|
||||||
}
|
reload()
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* 搜索栏 */}
|
<div className={'fixed z-20 top-5 left-0 w-full'}>
|
||||||
<div style={{
|
<div className={'px-4'}>
|
||||||
position: 'fixed',
|
|
||||||
top: '20px',
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
display: "none",
|
|
||||||
zIndex: 20,
|
|
||||||
padding: '0 16px',
|
|
||||||
backgroundColor: '#f5f5f5'
|
|
||||||
}}>
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
padding: '8px 12px',
|
|
||||||
borderRadius: '20px',
|
|
||||||
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
|
|
||||||
}}>
|
|
||||||
<Search size={16} color="#999"/>
|
|
||||||
<Input
|
|
||||||
placeholder="搜索报险记录"
|
|
||||||
value={keywords}
|
|
||||||
onChange={onKeywordsChange}
|
|
||||||
onConfirm={onSearch}
|
|
||||||
style={{
|
|
||||||
border: 'none',
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
flex: 1,
|
|
||||||
marginLeft: '8px'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
onClick={onSearch}
|
|
||||||
loading={loading}
|
|
||||||
>
|
|
||||||
搜索
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 报险记录列表 */}
|
|
||||||
<div style={{
|
|
||||||
marginTop: '10px',
|
|
||||||
paddingBottom: '80px'
|
|
||||||
}}>
|
|
||||||
{loading && list.length === 0 ? (
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
height: '200px'
|
|
||||||
}}>
|
|
||||||
<Loading type="spinner">加载中...</Loading>
|
|
||||||
</div>
|
|
||||||
) : list.length === 0 ? (
|
|
||||||
<Empty description="暂无违章记录">
|
|
||||||
</Empty>
|
|
||||||
) : (
|
|
||||||
<div style={{padding: '0 16px'}}>
|
|
||||||
{list.map((item) => {
|
|
||||||
const statusDisplay = getStatusDisplay(item.status)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
key={item.id || item.code} // 使用唯一ID而不是index
|
|
||||||
style={{
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
borderRadius: '12px',
|
|
||||||
padding: '16px',
|
|
||||||
marginBottom: '12px',
|
|
||||||
boxShadow: '0 2px 8px rgba(0,0,0,0.06)',
|
|
||||||
border: '1px solid #f0f0f0'
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
|
||||||
Taro.navigateTo({
|
|
||||||
url: `/hjm/violation/detail?id=${item.code}`
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'flex-start',
|
|
||||||
marginBottom: '12px'
|
|
||||||
}}>
|
|
||||||
<div style={{flex: 1}}>
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '8px',
|
|
||||||
marginBottom: '8px'
|
|
||||||
}}>
|
|
||||||
<File size={16} color="#1890ff"/>
|
|
||||||
<span style={{
|
|
||||||
fontSize: '16px',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: '#262626'
|
|
||||||
}}>
|
|
||||||
{item.title}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Space direction="vertical">
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '8px'
|
|
||||||
}}>
|
|
||||||
<Truck size={14} color="#8c8c8c"/>
|
|
||||||
<span style={{fontSize: '13px', color: '#8c8c8c'}}>
|
|
||||||
车辆编号:{item.code}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '8px'
|
|
||||||
}}>
|
|
||||||
<Calendar size={14} color="#8c8c8c"/>
|
|
||||||
<span style={{fontSize: '13px', color: '#8c8c8c'}}>
|
|
||||||
创建时间:{item.createTime}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Tag
|
|
||||||
color={statusDisplay.color}
|
|
||||||
style={{
|
|
||||||
backgroundColor: statusDisplay.bgColor,
|
|
||||||
border: `1px solid ${statusDisplay.color}`,
|
|
||||||
fontSize: '12px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{statusDisplay.text}
|
|
||||||
</Tag>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 备注信息 */}
|
|
||||||
{item.comments && (
|
|
||||||
<div style={{
|
|
||||||
backgroundColor: '#f8f9fa',
|
|
||||||
padding: '8px 12px',
|
|
||||||
borderRadius: '6px',
|
|
||||||
fontSize: '13px',
|
|
||||||
color: '#595959',
|
|
||||||
lineHeight: '1.4'
|
|
||||||
}}>
|
|
||||||
{item.comments.length > 50
|
|
||||||
? `${item.comments.substring(0, 50)}...`
|
|
||||||
: item.comments
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{item.userId == Taro.getStorageSync('UserId') && (
|
|
||||||
<div className={'flex justify-end mt-4'}>
|
|
||||||
<Space>
|
|
||||||
<Button type="default" onClick={(event: any) => {
|
|
||||||
event.stopPropagation()
|
|
||||||
Taro.navigateTo({
|
|
||||||
url: `/hjm/violation/add?id=${item.id}`
|
|
||||||
})
|
|
||||||
}}>修改</Button>
|
|
||||||
{/*<Button type="primary" onClick={(event: any) => {*/}
|
|
||||||
{/* event.stopPropagation()*/}
|
|
||||||
{/* removeHjmViolation(item.id).then(() => {*/}
|
|
||||||
{/* Taro.showToast({*/}
|
|
||||||
{/* title: '删除成功',*/}
|
|
||||||
{/* icon: 'success'*/}
|
|
||||||
{/* })*/}
|
|
||||||
{/* // 删除成功后重新加载列表*/}
|
|
||||||
{/* reload(false)*/}
|
|
||||||
{/* }).catch((error) => {*/}
|
|
||||||
{/* Taro.showToast({*/}
|
|
||||||
{/* title: error.message || '删除失败',*/}
|
|
||||||
{/* icon: 'error'*/}
|
|
||||||
{/* })*/}
|
|
||||||
{/* })*/}
|
|
||||||
{/*}}>删除</Button>*/}
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{
|
|
||||||
Taro.getStorageSync('RoleCode') == 'jiaojing' && (
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'fixed',
|
display: 'flex',
|
||||||
bottom: '20px',
|
alignItems: 'center',
|
||||||
right: '20px',
|
background: '#fff',
|
||||||
zIndex: 30,
|
padding: '0 10px',
|
||||||
padding: '8px',
|
borderRadius: '20px'
|
||||||
borderRadius: '20px',
|
}}
|
||||||
overflow: "hidden",
|
>
|
||||||
backgroundColor: '#ff0000',
|
<Search/>
|
||||||
}}>
|
<Input
|
||||||
<AddCircle size={28} color={'#ffffff'} onClick={onAddInsurance}/>
|
placeholder="车辆编号"
|
||||||
|
value={keywords}
|
||||||
|
onChange={onKeywords}
|
||||||
|
onConfirm={reload}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={'flex items-center'}
|
||||||
|
>
|
||||||
|
<Button type="warning" onClick={reload}>
|
||||||
|
查询
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={InfiniteUlStyle} id="scroll">
|
||||||
|
<InfiniteLoading
|
||||||
|
target="scroll"
|
||||||
|
className={'w-full fixed left-0 top-20'}
|
||||||
|
hasMore={hasMore}
|
||||||
|
onLoadMore={loadMore}
|
||||||
|
loadingText="加载中..."
|
||||||
|
loadMoreText="没有更多了"
|
||||||
|
>
|
||||||
|
<Items data={list}/>
|
||||||
|
</InfiniteLoading>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
Taro.getStorageSync('RoleCode') == 'jiaojing' && (
|
||||||
|
<>
|
||||||
|
<FixedButton onClick={() => navTo(`/hjm/violation/add`)} />
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
{/* 分页 */}
|
|
||||||
{list.length > 0 && (
|
|
||||||
<div style={{
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
padding: '20px 0',
|
|
||||||
backgroundColor: '#f5f5f5'
|
|
||||||
}}>
|
|
||||||
<Pagination
|
|
||||||
value={page}
|
|
||||||
total={total}
|
|
||||||
pageSize={limit}
|
|
||||||
onChange={onPageChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
export default ViolationList
|
||||||
export default List
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import {getSiteInfo, getUserInfo, getWxOpenId} from "@/api/layout";
|
|||||||
import Login from "./Login";
|
import Login from "./Login";
|
||||||
import {pageByQQMap, pageHjmCar} from "@/api/hjm/hjmCar";
|
import {pageByQQMap, pageHjmCar} from "@/api/hjm/hjmCar";
|
||||||
import {HjmCar} from "@/api/hjm/hjmCar/model";
|
import {HjmCar} from "@/api/hjm/hjmCar/model";
|
||||||
|
// 导入GPS坐标转换工具
|
||||||
|
import GPS from '@/utils/gpsUtil.js';
|
||||||
|
|
||||||
export interface Market {
|
export interface Market {
|
||||||
// 自增ID
|
// 自增ID
|
||||||
@@ -108,14 +110,36 @@ function Home() {
|
|||||||
const getLocation = async () => {
|
const getLocation = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await Taro.getLocation({
|
const res = await Taro.getLocation({
|
||||||
type: 'gcj02' //返回可以用于wx.openLocation的经纬度
|
type: 'wgs84' // 使用WGS84坐标系,然后手动转换为GCJ02
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.latitude) {
|
// 转换WGS84坐标到GCJ02坐标
|
||||||
setLatitude(res.latitude)
|
if (res.latitude && res.longitude &&
|
||||||
}
|
!isNaN(res.latitude) &&
|
||||||
if (res.longitude) {
|
!isNaN(res.longitude) &&
|
||||||
setLongitude(res.longitude)
|
isFinite(res.latitude) &&
|
||||||
|
isFinite(res.longitude)) {
|
||||||
|
try {
|
||||||
|
const lat = Number(res.latitude);
|
||||||
|
const lng = Number(res.longitude);
|
||||||
|
const transformed = GPS.gcj_encrypt(lat, lng);
|
||||||
|
// 确保转换结果有效
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
setLatitude(transformed.lat);
|
||||||
|
setLongitude(transformed.lng);
|
||||||
|
} else {
|
||||||
|
// 如果转换结果无效,使用原始坐标
|
||||||
|
setLatitude(res.latitude);
|
||||||
|
setLongitude(res.longitude);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('坐标转换错误:', error);
|
||||||
|
setLatitude(res.latitude);
|
||||||
|
setLongitude(res.longitude);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setLatitude(res.latitude);
|
||||||
|
setLongitude(res.longitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已认证用户
|
// 已认证用户
|
||||||
@@ -185,11 +209,33 @@ function Home() {
|
|||||||
const data = res?.list;
|
const data = res?.list;
|
||||||
const arr = []
|
const arr = []
|
||||||
data?.map((item: HjmCar) => {
|
data?.map((item: HjmCar) => {
|
||||||
|
// 转换WGS84坐标到GCJ02坐标
|
||||||
|
let markerLat = item.latitude;
|
||||||
|
let markerLng = item.longitude;
|
||||||
|
|
||||||
|
if (item.latitude && item.longitude &&
|
||||||
|
!isNaN(item.latitude) &&
|
||||||
|
!isNaN(item.longitude) &&
|
||||||
|
isFinite(item.latitude) &&
|
||||||
|
isFinite(item.longitude)) {
|
||||||
|
try {
|
||||||
|
const lat = Number(item.latitude);
|
||||||
|
const lng = Number(item.longitude);
|
||||||
|
const transformed = GPS.gcj_encrypt(lat, lng);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
markerLat = transformed.lat;
|
||||||
|
markerLng = transformed.lng;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('标记点坐标转换错误:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
arr.push({
|
arr.push({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
latitude: item.latitude,
|
latitude: markerLat,
|
||||||
longitude: item.longitude,
|
longitude: markerLng,
|
||||||
label: {
|
label: {
|
||||||
content: `${item?.code}`,
|
content: `${item?.code}`,
|
||||||
color: '#000000',
|
color: '#000000',
|
||||||
@@ -232,13 +278,36 @@ function Home() {
|
|||||||
setList(res?.list || [])
|
setList(res?.list || [])
|
||||||
if (res?.list && res?.list.length > 0) {
|
if (res?.list && res?.list.length > 0) {
|
||||||
const data = res?.list[0];
|
const data = res?.list[0];
|
||||||
setLongitude(data?.longitude)
|
|
||||||
setLatitude(data?.latitude)
|
// 转换WGS84坐标到GCJ02坐标
|
||||||
|
let displayLat = data.latitude;
|
||||||
|
let displayLng = data.longitude;
|
||||||
|
|
||||||
|
if (data.latitude && data.longitude &&
|
||||||
|
!isNaN(data.latitude) &&
|
||||||
|
!isNaN(data.longitude) &&
|
||||||
|
isFinite(data.latitude) &&
|
||||||
|
isFinite(data.longitude)) {
|
||||||
|
try {
|
||||||
|
const lat = Number(data.latitude);
|
||||||
|
const lng = Number(data.longitude);
|
||||||
|
const transformed = GPS.gcj_encrypt(lat, lng);
|
||||||
|
if (transformed && !isNaN(transformed.lat) && !isNaN(transformed.lng)) {
|
||||||
|
displayLat = transformed.lat;
|
||||||
|
displayLng = transformed.lng;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('搜索结果坐标转换错误:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLongitude(displayLng)
|
||||||
|
setLatitude(displayLat)
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
setMarkers([{
|
setMarkers([{
|
||||||
id: data.id,
|
id: data.id,
|
||||||
latitude: data.latitude,
|
latitude: displayLat,
|
||||||
longitude: data.longitude,
|
longitude: displayLng,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
label: {
|
label: {
|
||||||
content: `${data?.code}`,
|
content: `${data?.code}`,
|
||||||
|
|||||||
@@ -35,29 +35,29 @@ const Login = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送短信验证码
|
// 发送短信验证码
|
||||||
const handleSendSmsCode = async () => {
|
// const handleSendSmsCode = async () => {
|
||||||
if (!phone) {
|
// if (!phone) {
|
||||||
Taro.showToast({
|
// Taro.showToast({
|
||||||
title: '请输入手机号',
|
// title: '请输入手机号',
|
||||||
icon: 'error'
|
// icon: 'error'
|
||||||
})
|
// })
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 验证手机号格式
|
// // 验证手机号格式
|
||||||
const phoneReg = /^1[3-9]\d{9}$/
|
// const phoneReg = /^1[3-9]\d{9}$/
|
||||||
if (!phoneReg.test(phone)) {
|
// if (!phoneReg.test(phone)) {
|
||||||
Taro.showToast({
|
// Taro.showToast({
|
||||||
title: '手机号格式不正确',
|
// title: '手机号格式不正确',
|
||||||
icon: 'error'
|
// icon: 'error'
|
||||||
})
|
// })
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// 显示图形验证码弹窗
|
// // 显示图形验证码弹窗
|
||||||
fetchCaptcha()
|
// fetchCaptcha()
|
||||||
setShowCaptchaModal(true)
|
// setShowCaptchaModal(true)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 确认发送短信验证码
|
// 确认发送短信验证码
|
||||||
const confirmSendSmsCode = async () => {
|
const confirmSendSmsCode = async () => {
|
||||||
@@ -96,21 +96,21 @@ const Login = () => {
|
|||||||
const handleSmsLogin = async () => {
|
const handleSmsLogin = async () => {
|
||||||
if (!phone) {
|
if (!phone) {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: '请输入手机号',
|
title: '请输入账号',
|
||||||
icon: 'error'
|
icon: 'error'
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证手机号格式
|
// 验证手机号格式
|
||||||
const phoneReg = /^1[3-9]\d{9}$/
|
// const phoneReg = /^1[3-9]\d{9}$/
|
||||||
if (!phoneReg.test(phone)) {
|
// if (!phoneReg.test(phone)) {
|
||||||
Taro.showToast({
|
// Taro.showToast({
|
||||||
title: '手机号格式不正确',
|
// title: '手机号格式不正确',
|
||||||
icon: 'error'
|
// icon: 'error'
|
||||||
})
|
// })
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (!smsCode) {
|
if (!smsCode) {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
@@ -123,7 +123,7 @@ const Login = () => {
|
|||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
// 短信登录时传入手机号和短信验证码
|
// 短信登录时传入手机号和短信验证码
|
||||||
const res = await loginBySms({ phone, code: smsCode })
|
const res = await loginBySms({ phone, code:smsCode })
|
||||||
|
|
||||||
console.log(res,'.......')
|
console.log(res,'.......')
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
@@ -232,8 +232,7 @@ const Login = () => {
|
|||||||
}}>
|
}}>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="手机号"
|
placeholder="请输入账号"
|
||||||
maxLength={11}
|
|
||||||
value={phone}
|
value={phone}
|
||||||
onChange={(val) => setPhone(val)}
|
onChange={(val) => setPhone(val)}
|
||||||
style={{
|
style={{
|
||||||
@@ -258,9 +257,8 @@ const Login = () => {
|
|||||||
borderRadius: '8px'
|
borderRadius: '8px'
|
||||||
}}>
|
}}>
|
||||||
<Input
|
<Input
|
||||||
type="text"
|
type="password"
|
||||||
placeholder="短信验证码"
|
placeholder="请输入密码"
|
||||||
maxLength={6}
|
|
||||||
value={smsCode}
|
value={smsCode}
|
||||||
onChange={(val) => setSmsCode(val)}
|
onChange={(val) => setSmsCode(val)}
|
||||||
style={{
|
style={{
|
||||||
@@ -269,18 +267,6 @@ const Login = () => {
|
|||||||
padding: '10px'
|
padding: '10px'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Button
|
|
||||||
type="info"
|
|
||||||
size="small"
|
|
||||||
disabled={countdown > 0}
|
|
||||||
onClick={handleSendSmsCode}
|
|
||||||
style={{
|
|
||||||
borderRadius: '0 8px 8px 0',
|
|
||||||
height: '40px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{countdown > 0 ? `${countdown}秒后重发` : '获取验证码'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -317,7 +303,7 @@ const Login = () => {
|
|||||||
checked={isAgree}
|
checked={isAgree}
|
||||||
onClick={() => setIsAgree(!isAgree)}
|
onClick={() => setIsAgree(!isAgree)}
|
||||||
/>
|
/>
|
||||||
<span style={{color: '#999', marginLeft: '5px'}} onClick={() => setIsAgree(!isAgree)}>勾选表示您已阅读并同意</span>
|
<span style={{color: '#999', marginLeft: '5px'}} onClick={() => setIsAgree(!isAgree)}>已阅读并同意</span>
|
||||||
<a
|
<a
|
||||||
onClick={() => Taro.navigateTo({url: '/passport/agreement'})}
|
onClick={() => Taro.navigateTo({url: '/passport/agreement'})}
|
||||||
style={{color: '#1890ff'}}
|
style={{color: '#1890ff'}}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const UserVerifyAdmin: React.FC = () => {
|
|||||||
const [keywords, setKeywords] = useState<string>('')
|
const [keywords, setKeywords] = useState<string>('')
|
||||||
// const [showTextArea, setShowTextArea] = useState<boolean>(false)
|
// const [showTextArea, setShowTextArea] = useState<boolean>(false)
|
||||||
const [refreshing, setRefreshing] = useState<boolean>(false)
|
const [refreshing, setRefreshing] = useState<boolean>(false)
|
||||||
const {user} = useUser()
|
const {user, fetchUserInfo} = useUser()
|
||||||
console.log(refreshing)
|
console.log(refreshing)
|
||||||
|
|
||||||
// 获取状态显示
|
// 获取状态显示
|
||||||
@@ -52,25 +52,66 @@ const UserVerifyAdmin: React.FC = () => {
|
|||||||
keywords: keywords.trim(),
|
keywords: keywords.trim(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (Taro.getStorageSync('RoleCode') == 'zhandian') {
|
// 如果当前登录用户可管理商户存在,则直接按商户ID过滤
|
||||||
// @ts-ignore
|
const normalizeOrganizationIds = (value: any): any[] | undefined => {
|
||||||
// where.organizationId = Taro.getStorageSync('OrganizationId')
|
if (value == null) return undefined
|
||||||
// }
|
if (Array.isArray(value)) return value
|
||||||
// if (Taro.getStorageSync('RoleCode') == 'kuaidi') {
|
if (typeof value === 'string') {
|
||||||
// @ts-ignore
|
const trimmed = value.trim()
|
||||||
// where.OrganizationParentId = Taro.getStorageSync('OrganizationParentId')
|
if (!trimmed) return []
|
||||||
// }
|
try {
|
||||||
|
const parsed = JSON.parse(trimmed)
|
||||||
|
if (Array.isArray(parsed)) return parsed
|
||||||
|
} catch (_e) {}
|
||||||
|
return trimmed
|
||||||
|
.split(',')
|
||||||
|
.map(s => s.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
}
|
||||||
|
return [value]
|
||||||
|
}
|
||||||
|
|
||||||
const organizations = await listOrganizations({
|
let merchants = user?.merchants
|
||||||
parentId: Taro.getStorageSync('OrganizationId')
|
if (merchants == null) {
|
||||||
})
|
const storedUser = Taro.getStorageSync('User')
|
||||||
const organizationIds = organizations.map(item => item.organizationId)
|
if (storedUser) {
|
||||||
// 把Taro.getStorageSync('OrganizationId')也放入数组
|
if (typeof storedUser === 'string') {
|
||||||
organizationIds.push(Taro.getStorageSync('OrganizationId'))
|
try {
|
||||||
|
merchants = JSON.parse(storedUser)?.merchants
|
||||||
|
} catch (_e) {}
|
||||||
|
} else {
|
||||||
|
merchants = storedUser?.merchants
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 本地没有拿到 merchants 时,尝试从接口刷新一次用户信息
|
||||||
|
if (merchants == null && user?.userId) {
|
||||||
|
const latestUser = await fetchUserInfo()
|
||||||
|
merchants = latestUser?.merchants
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询机构列表:如果 merchants 存在,则用 organizationIds=merchants 来查
|
||||||
|
const organizationIdsParam = normalizeOrganizationIds(merchants)
|
||||||
|
const hasMerchants = Boolean(organizationIdsParam && organizationIdsParam.length > 0)
|
||||||
|
|
||||||
|
const organizations = await listOrganizations(
|
||||||
|
hasMerchants
|
||||||
|
? // @ts-ignore
|
||||||
|
{ organizationIds: organizationIdsParam }
|
||||||
|
: { parentId: Taro.getStorageSync('OrganizationId') }
|
||||||
|
)
|
||||||
|
|
||||||
|
const organizationIds = organizations.map(item => item.organizationId).filter(Boolean) as any[]
|
||||||
|
// 把 merchants/当前机构 也放入数组
|
||||||
|
if (hasMerchants) {
|
||||||
|
organizationIds.push(...(organizationIdsParam as any[]))
|
||||||
|
} else {
|
||||||
|
organizationIds.push(Taro.getStorageSync('OrganizationId'))
|
||||||
|
}
|
||||||
|
|
||||||
console.log(organizationIds,'organizationIds')
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
where.organizationIds = organizationIds;
|
where.organizationIds = Array.from(new Set(organizationIds))
|
||||||
|
|
||||||
const res = await pageUserVerify(where)
|
const res = await pageUserVerify(where)
|
||||||
|
|
||||||
@@ -98,57 +139,79 @@ const UserVerifyAdmin: React.FC = () => {
|
|||||||
// 检查是否有特定角色
|
// 检查是否有特定角色
|
||||||
const hasRole = (roleCode: string) => {
|
const hasRole = (roleCode: string) => {
|
||||||
if (!user || !user.roles) {
|
if (!user || !user.roles) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
return user.roles.some(role => role.roleCode === roleCode);
|
return user.roles.some(role => role.roleCode === roleCode)
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
const onPass = async (item: UserVerify) => {
|
const onPass = async (item: UserVerify) => {
|
||||||
const role = await listUserRole({roleId: 1701,userId: item.userId})
|
try {
|
||||||
const userRole = role[0];
|
const role = await listUserRole({roleId: 1701, userId: item.userId})
|
||||||
// 审核通过
|
const userRole = role[0]
|
||||||
updateUserVerify({
|
|
||||||
...item,
|
// 审核通过 - 先更新实名认证状态
|
||||||
status: 1
|
await updateUserVerify({
|
||||||
}).then(() => {
|
...item,
|
||||||
if(userRole){
|
status: 1
|
||||||
updateUserRole({
|
})
|
||||||
...userRole,
|
|
||||||
roleId: 1738
|
// 再更新用户角色(如果存在对应角色)
|
||||||
})
|
if (userRole) {
|
||||||
}
|
await updateUserRole({
|
||||||
Taro.showToast({
|
...userRole,
|
||||||
title: '操作成功',
|
roleId: 1738
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
reload().then()
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
Taro.showToast({
|
||||||
|
title: '操作成功',
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
await reload(false)
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('审核通过失败:', error)
|
||||||
|
Taro.showToast({
|
||||||
|
title: error?.message || '操作失败',
|
||||||
|
icon: 'error'
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onReject = async (item: UserVerify) => {
|
const onReject = async (item: UserVerify) => {
|
||||||
const role = await listUserRole({roleId: 1738,userId: item.userId})
|
try {
|
||||||
const userRole = role[0];
|
const role = await listUserRole({roleId: 1738, userId: item.userId})
|
||||||
if(userRole){
|
const userRole = role[0]
|
||||||
userRole.roleId = 1701;
|
|
||||||
updateUserRole(userRole).then(() => {
|
// 审核驳回 - 先恢复用户角色(如果存在)
|
||||||
updateUserVerify({
|
if (userRole) {
|
||||||
...item,
|
userRole.roleId = 1701
|
||||||
status: 2
|
await updateUserRole(userRole)
|
||||||
}).then(() => {
|
}
|
||||||
Taro.showToast({
|
|
||||||
title: '操作成功',
|
await updateUserVerify({
|
||||||
icon: 'success'
|
...item,
|
||||||
})
|
status: 2
|
||||||
reload().then()
|
})
|
||||||
})
|
|
||||||
|
Taro.showToast({
|
||||||
|
title: '操作成功',
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
await reload(false)
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('审核驳回失败:', error)
|
||||||
|
Taro.showToast({
|
||||||
|
title: error?.message || '操作失败',
|
||||||
|
icon: 'error'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!user?.userId) return
|
||||||
reload().then()
|
reload().then()
|
||||||
}, [])
|
}, [user?.userId])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -297,7 +360,7 @@ const UserVerifyAdmin: React.FC = () => {
|
|||||||
fontSize: '12px'
|
fontSize: '12px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item.statusText}
|
{item.statusText || statusDisplay.text}
|
||||||
</Tag>
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -317,7 +380,7 @@ const UserVerifyAdmin: React.FC = () => {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{Taro.getStorageSync('kuaidi') && (
|
{(hasRole('admin') || hasRole('kuaidi') || hasRole('zhandian')) && (
|
||||||
<Space className={'pt-4 flex justify-end'}>
|
<Space className={'pt-4 flex justify-end'}>
|
||||||
<Button type="success" onClick={() => onPass(item)}>通过</Button>
|
<Button type="success" onClick={() => onPass(item)}>通过</Button>
|
||||||
<Button type="warning" onClick={() => onReject(item)}>驳回</Button>
|
<Button type="warning" onClick={() => onReject(item)}>驳回</Button>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {BaseUrl, TenantId} from "@/utils/config";
|
|||||||
let baseUrl = BaseUrl
|
let baseUrl = BaseUrl
|
||||||
|
|
||||||
if(process.env.NODE_ENV === 'development'){
|
if(process.env.NODE_ENV === 'development'){
|
||||||
baseUrl = 'http://localhost:9200/api'
|
// baseUrl = 'http://localhost:9200/api'
|
||||||
}
|
}
|
||||||
export function request<T>(options:any) {
|
export function request<T>(options:any) {
|
||||||
const token = Taro.getStorageSync('access_token');
|
const token = Taro.getStorageSync('access_token');
|
||||||
|
|||||||
Reference in New Issue
Block a user