Files
template-10519/src/hjm/query.tsx

697 lines
20 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {useEffect, useState} from "react";
import Taro, {useRouter} from '@tarojs/taro'
import {getHjmCarByCode, pageHjmCar, updateHjmCar} from "@/api/hjm/hjmCar";
import {HjmCar} from "@/api/hjm/hjmCar/model";
import './location.scss';
import { Swiper } from '@nutui/nutui-react-taro'
import {copyText} from "@/utils/common";
import {View} from '@tarojs/components'
import {
Form,
Button,
Input,
Radio,
Cell,
Image
} from '@nutui/nutui-react-taro'
import { ImagePreview } from '@nutui/nutui-react-taro'
import {Scan} from '@nutui/icons-react-taro'
import {pageDictData} from "@/api/system/dict-data";
import {DictData} from "@/api/system/dict-data/model";
import {myUserVerify} from "@/api/system/userVerify";
import {listUserRole, updateUserRole} from "@/api/system/userRole";
import {UserRole} from "@/api/system/userRole/model";
import {updateUser} from "@/api/system/user";
// 图片数据接口
interface UploadedImageData {
url?: string;
src?: string;
name?: string;
uid?: string;
message?: string;
type?: string;
}
/**
* 文章终极列表
* @constructor
*/
const Query = () => {
const {params} = useRouter();
const [keywords, setKeywords] = useState<string>()
const [dict, setDict] = useState<DictData[]>([])
const [adminId, setAdminId] = useState<number>()
const [showPreview, setShowPreview] = useState(false)
const [userRole, setUserRole] = useState<UserRole>()
const [fileList, setFileList] = useState<UploadedImageData[]>([]) // 图片文件列表
const [FormData, setFormData] = useState<HjmCar>(
{
// 自增ID
id: undefined,
// 车辆名称
name: undefined,
// 车辆图片
image: undefined,
// 类型 0汽车 1其他车
type: undefined,
// 快递公司
kuaidi: undefined,
// 管理负责人
kuaidiAdmin: undefined,
organization: undefined,
organizationParentId: undefined,
parentOrganization: undefined,
parentOrganizationAdmin: undefined,
// 车辆编号
code: undefined,
// 操作员
driver: undefined,
// 保险状态
insuranceStatus: undefined,
// GPS设备编号
gpsNo: undefined,
// 电子围栏ID
fenceId: undefined,
// 电子围栏名称
fenceName: undefined,
// 电子围栏
fence: undefined,
// 位置
location: undefined,
// 经度
longitude: undefined,
// 纬度
latitude: undefined,
// 地址
address: undefined,
// 用户ID
userId: undefined,
// 排序(数字越小越靠前)
sortNumber: undefined,
// 备注
comments: undefined,
// 状态, 0正常, 1冻结
status: undefined,
// 是否删除, 0否, 1是
deleted: undefined,
// 租户id
tenantId: undefined,
// 创建时间
createTime: undefined,
// 更新时间
updateTime: undefined,
}
)
// 提交表单
const submitSucceed = (values: any) => {
console.log(values)
if(FormData.image == '[]' || !FormData.image){
Taro.showToast({
title: '请上传车辆图片',
icon: 'error'
});
return false
}
if(!FormData.gpsNo){
Taro.showToast({
title: '请绑定GPS',
icon: 'error'
});
return false
}
// 升级为快递员
if(userRole){
updateHjmCar({
...FormData,
status: 1,
driverId: adminId,
driverName: Taro.getStorageSync('RealName')
}).then(() => {
userRole.roleId = 1738;
updateUserRole(userRole).then(() => {
Taro.showToast({title: `绑定成功`, icon: 'success'})
})
updateUser({
userId: Taro.getStorageSync('UserId'),
organizationId: FormData.organizationId
}).then(() => {})
setTimeout(() => {
reload();
return Taro.navigateBack()
}, 1000)
}).catch(() => {
Taro.showToast({
title: '绑定失败',
icon: 'error'
});
})
}
}
const submitFailed = (error: any) => {
console.log(error, 'err...')
}
const saveGpsNo = () => {
Taro.scanCode({
onlyFromCamera: true,
scanType: ['barCode', 'qrCode'],
success: (res) => {
// 更新表单数据
setFormData({
...FormData,
gpsNo: res.result
});
Taro.showToast({
title: '扫码成功' + res.result,
icon: 'success',
duration: 2000
});
},
fail: (err) => {
console.log('扫码失败', err);
Taro.showToast({
title: '扫码失败',
icon: 'error',
duration: 2000
});
}
});
}
// 选择并上传图片
const handleChooseImage = () => {
if (fileList.length >= 5) {
Taro.showToast({
title: '最多只能上传5张图片',
icon: 'none'
})
return
}
Taro.chooseImage({
count: 5 - fileList.length, // 剩余可选择的数量
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
console.log('选择图片成功:', res)
// 逐个上传选中的图片
res.tempFilePaths.forEach((filePath, index) => {
uploadSingleImage(filePath, index)
})
},
fail: (err) => {
console.log('选择图片失败:', err)
Taro.showToast({
title: '选择图片失败',
icon: 'error'
})
}
})
}
// 上传单张图片
const uploadSingleImage = (filePath: string, index: number) => {
const TenantId = Taro.getStorageSync('TenantId')
Taro.uploadFile({
url: 'https://server.gxwebsoft.com/api/oss/upload',
filePath: filePath,
name: 'file',
header: {
'content-type': 'application/json',
TenantId
},
success: (res) => {
try {
const data = JSON.parse(res.data);
console.log('上传成功', data)
if (data.code === 0) {
// 更新文件列表
const newFile = {
name: `图片${Date.now()}_${index}`,
url: data.data.url,
status: 'success',
message: '上传成功',
type: 'image',
uid: `${Date.now()}_${index}`,
}
setFileList(prev => {
const newList = [...prev, newFile]
// 同时更新表单数据 - 使用JSON格式存储
const imageData: UploadedImageData[] = newList.map(f => ({
url: f.url,
name: f.name,
uid: f.uid
}))
setFormData(prevForm => ({
...prevForm,
image: JSON.stringify(imageData)
}))
return newList
})
Taro.showToast({
title: '上传成功',
icon: 'success'
})
} else {
Taro.showToast({
title: data.message || '上传失败',
icon: 'error'
})
}
} catch (error) {
console.error('解析响应失败:', error)
Taro.showToast({
title: '上传失败',
icon: 'error'
})
}
},
fail: (err) => {
console.log('上传请求失败', err);
Taro.showToast({
title: '上传失败',
icon: 'error'
})
}
})
}
// 处理文件删除
const handleFileRemove = (file: any) => {
console.log('删除文件:', file)
const newFileList = fileList.filter(f => f.uid !== file.uid)
setFileList(newFileList)
// 更新表单数据 - 使用JSON格式存储
if (newFileList.length === 0) {
setFormData(prev => ({
...prev,
image: undefined
}))
} else {
const imageData: UploadedImageData[] = newFileList.map(f => ({
url: f.url,
src: f.url,
name: f.name,
uid: f.uid
}))
setFormData(prev => ({
...prev,
image: JSON.stringify(imageData)
}))
}
}
// 打开地图选择位置
// const chooseLocation = async () => {
// try {
// const res = await Taro.chooseLocation({
// latitude, // 默认纬度
// longitude // 默认经度
// })
// console.log('选择的位置:', res);
// } catch (err) {
// console.error('选择位置失败:', err);
// }
// }
const reload = () => {
const code = params.id;
// 获取数据字典
pageDictData({dictCode: 'InsuranceStatus'}).then(res => {
setDict(res?.list || [])
})
// 查询角色
listUserRole({userId: Taro.getStorageSync('UserId')}).then(res => {
if(res.length > 0){
setUserRole(res[0])
}
})
// 检查是否已实名
myUserVerify({status: 1}).then(data => {
if (!data) {
Taro.showToast({
title: '未实名认证',
icon: 'error'
})
setTimeout(() => {
Taro.navigateTo({
url: '/user/userVerify/index'
})
}, 1000)
return false
}
if(data){
setAdminId(data.userId);
}
})
// 获取车辆信息
if (code) {
getHjmCarByCode(code).then(data => {
if(data){
setFormData(data)
setKeywords(data.code)
// 解析图片数据
if (data.image) {
try {
const parsedImages: UploadedImageData[] = JSON.parse(data.image)
setFileList(parsedImages.map((img) => ({
url: img.url,
src: img.url
})))
} catch (error) {
// 如果解析失败可能是旧格式的单个URL
if (typeof data.image === 'string' && data.image.trim()) {
setFileList([{
src: data.image,
url: data.image,
message: '上传成功',
type: 'image',
uid: `legacy_${Date.now()}`,
}])
}
}
}
if (data.status == 0) {
Taro.setNavigationBarTitle({
title: '安装设备'
})
setFormData({...data, driver: Taro.getStorageSync('RealName')})
}
}
})
}
// 执行搜索
if (keywords) {
pageHjmCar({keywords}).then(res => {
if (res?.list && res?.list?.length > 0) {
const data = res?.list[0];
// setFormData(data)
setKeywords(data.code)
}
})
return false;
}
}
useEffect(() => {
reload()
}, [])
return (
<>
{/* 未安装 */}
{FormData?.status == 0 ? (
<div className={'car-info w-full bg-white'}>
<div className={'px-0'}>
<Form
divider
initialValues={FormData}
labelPosition="left"
onFinish={(values) => submitSucceed(values)}
onFinishFailed={(errors) => submitFailed(errors)}
footer={
<div
style={{
display: 'flex',
justifyContent: 'center',
width: '100%'
}}
>
<Button nativeType="submit" block type="info">
</Button>
</div>
}
>
<Form.Item
label={'车辆编号'}
name="code"
rules={[{message: '请输入车辆编号'}]}
>
<View onClick={() => copyText(`${FormData?.code}`)}>{FormData?.code}</View>
</Form.Item>
<Form.Item
label={'快递公司品牌'}
name="parentOrganization"
rules={[{message: '快递公司品牌'}]}
>
<Input placeholder="快递公司品牌" disabled type="text"/>
</Form.Item>
<Form.Item
label={'管理责任人'}
name="parentOrganizationAdmin"
rules={[{message: '管理责任人'}]}
>
<Input placeholder="管理责任人" disabled type="text"/>
</Form.Item>
<Form.Item
label={'电子围栏'}
name="fenceName"
rules={[{message: '电子围栏'}]}
>
<Input placeholder="电子围栏" type="text"/>
</Form.Item>
<Form.Item
label="保险状态"
name="insuranceStatus"
rules={[
{message: '保险状态'}
]}
>
<Radio.Group value={FormData.insuranceStatus} disabled direction="horizontal">
{
dict?.map((item, index) => (
<Radio key={index} value={item.dictDataCode}>
{item.dictDataName}
</Radio>
))
}
</Radio.Group>
</Form.Item>
<Form.Item
label={'GPS编号'}
name="gpsNo"
required
rules={[{message: 'GPS编号'}]}
>
<div
style={{
display: 'flex',
alignItems: 'center',
background: '#fff',
}}
>
<Input
placeholder="请填入GPS设备编号"
value={FormData.gpsNo}
onChange={(value) => setFormData({...FormData, gpsNo: value})}
/>
<div
className="right"
style={{display: 'flex', alignItems: 'center'}}
>
<Scan onClick={saveGpsNo}/>
</div>
</div>
</Form.Item>
<Form.Item
label={'拍照上传'}
name="image"
required
rules={[{message: '请上传照片'}]}
>
<div style={{
display: 'flex',
flexWrap: 'wrap',
gap: '12px',
padding: '8px 0'
}}>
{/* 显示已上传的图片 */}
{fileList.map((file) => (
<div key={file.uid} style={{
position: 'relative',
width: '80px',
height: '80px',
borderRadius: '8px',
overflow: 'hidden',
border: '1px solid #d9d9d9'
}}>
<img
src={file.url}
alt={file.name}
style={{
width: '100%',
height: '100%',
objectFit: 'cover'
}}
/>
<Button
size="small"
type="default"
style={{
position: 'absolute',
top: '-8px',
right: '-8px',
width: '20px',
height: '20px',
borderRadius: '10px',
fontSize: '12px',
minWidth: '20px',
padding: 0,
lineHeight: '20px'
}}
onClick={() => handleFileRemove(file)}
>
×
</Button>
</div>
))}
{/* 添加图片按钮 */}
{fileList.length < 5 && (
<div
onClick={handleChooseImage}
style={{
width: '80px',
height: '80px',
borderRadius: '8px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
border: '2px dashed #d9d9d9',
backgroundColor: '#fafafa',
cursor: 'pointer'
}}
>
<span style={{fontSize: '20px', color: '#d9d9d9'}}>+</span>
<span style={{fontSize: '10px', marginTop: '2px', color: '#666'}}>
</span>
</div>
)}
{/* 显示上传数量提示 */}
{fileList.length > 0 && (
<div style={{
width: '100%',
fontSize: '12px',
color: '#52c41a',
textAlign: 'center',
marginTop: '4px'
}}>
{fileList.length}5
</div>
)}
</div>
</Form.Item>
<Form.Item
label={'操作员'}
name="driver"
rules={[{message: '操作员'}]}
>
<Input placeholder="操作员" type="text"/>
</Form.Item>
</Form>
</div>
</div>
) : ''}
{/* 已安装 */}
{FormData?.status == 1 ? (
<div className={'car-info w-full bg-white'}>
{/* 显示多张图片 */}
<div style={{
display: 'flex',
flexWrap: 'wrap',
gap: '8px',
padding: '16px',
justifyContent: 'center'
}}>
<ImagePreview
autoPlay
// @ts-ignore
images={fileList}
visible={showPreview}
onClose={() => setShowPreview(false)}
/>
<Swiper defaultValue={1} autoPlay indicator>
{fileList.map((item) => (
// @ts-ignore
<Swiper.Item key={item}>
<Image
width="100%"
height="100%"
mode={'aspectFit'}
onClick={() => setShowPreview(true)}
src={item.url}
/>
</Swiper.Item>
))}
</Swiper>
</div>
<div className={'px-2'}>
<Cell className={'car-info-item-title'} onClick={() => copyText(`${FormData?.code}`)}>
{FormData?.code}
</Cell>
<Cell className={'car-info-item-title'}>
{FormData?.parentOrganization}
</Cell>
<Cell className={'car-info-item-title'}>
{FormData?.organization}
</Cell>
<Cell className={'car-info-item-title'}>
{FormData?.parentOrganizationAdmin}
</Cell>
<Cell className={'car-info-item-content'}>
{FormData?.driver}
</Cell>
<Cell className={'car-info-item-content'}>
{FormData?.insuranceStatus}
</Cell>
<Cell className={'car-info-item-content'}>
GPS编号{FormData?.gpsNo}
</Cell>
<Cell className={'car-info-item-content'}>
{FormData.fenceName}
</Cell>
<div className={'flex justify-around py-4'}>
<Button nativeType="submit" type="info" onClick={
() => {
Taro.navigateTo({
url: `/hjm/location?id=${FormData?.code}`
})
}
}>
</Button>
<Button nativeType="submit" type="warning" onClick={
() => {
Taro.navigateTo({
url: `/hjm/trajectory/trajectory?id=${FormData?.code}`
})
}
}>
</Button>
</div>
</div>
</div>
) : ''}
</>
)
}
// @ts-ignore
export default Query