修复:保险支持5张图片

This commit is contained in:
2025-06-15 00:43:58 +08:00
parent 47b6a3d8de
commit 6a700e9d4b
7 changed files with 350 additions and 69 deletions

View File

@@ -18,8 +18,10 @@ const BestSellers = (props: any) => {
return ( return (
<div key={index} className={'flex bg-white rounded-lg w-full p-3 mb-3'} <div key={index} className={'flex bg-white rounded-lg w-full p-3 mb-3'}
onClick={() => Taro.navigateTo({url: '/hjm/query?id=' + item.code})}> onClick={() => Taro.navigateTo({url: '/hjm/query?id=' + item.code})}>
<Image src={item.image} mode={'scaleToFill'} { item.image && (
<Image src={JSON.parse(item.image)[0].url} mode={'scaleToFill'}
radius="10%" width="80" height="80"/> radius="10%" width="80" height="80"/>
)}
<div className={'mx-3 flex flex-col'}> <div className={'mx-3 flex flex-col'}>
<Space direction={'vertical'}> <Space direction={'vertical'}>
<div className={'car-no text-lg font-bold'}>{item.code}</div> <div className={'car-no text-lg font-bold'}>{item.code}</div>

View File

@@ -29,6 +29,7 @@ function BxAdd() {
const [bxFiled2, setBxFiled2] = useState<CmsWebsiteField>() const [bxFiled2, setBxFiled2] = useState<CmsWebsiteField>()
const [carInfo, setCarInfo] = useState<HjmCar | null>(null) const [carInfo, setCarInfo] = useState<HjmCar | null>(null)
const [fileList, setFileList] = useState<any[]>([]) // 图片文件列表 const [fileList, setFileList] = useState<any[]>([]) // 图片文件列表
const [lastSubmitTime, setLastSubmitTime] = useState<number>(0) // 最后提交时间
const [formData, setFormData] = useState<HjmBxLog>({ const [formData, setFormData] = useState<HjmBxLog>({
carId: undefined, carId: undefined,
accidentType: undefined, accidentType: undefined,
@@ -64,7 +65,6 @@ function BxAdd() {
}) })
pageHjmCar({driverId: Taro.getStorageSync('UserId')}).then(res => { pageHjmCar({driverId: Taro.getStorageSync('UserId')}).then(res => {
const car = res?.list[0]; const car = res?.list[0];
setLoading(true)
if (car) { if (car) {
setCarInfo(car) setCarInfo(car)
setFormData(prev => ({ setFormData(prev => ({
@@ -217,6 +217,26 @@ function BxAdd() {
// 提交表单 // 提交表单
const handleSubmit = async () => { const handleSubmit = async () => {
// 防止重复提交 - 检查loading状态
if (loading) {
Taro.showToast({
title: '正在提交中,请稍候...',
icon: 'loading'
})
return
}
// 防止快速连续点击 - 2秒内不允许重复提交
const now = Date.now()
if (now - lastSubmitTime < 2000) {
Taro.showToast({
title: '请勿频繁提交',
icon: 'none'
})
return
}
setLastSubmitTime(now)
// 表单验证 // 表单验证
if (!formData.carId) { if (!formData.carId) {
Taro.showToast({ Taro.showToast({
@@ -278,6 +298,8 @@ function BxAdd() {
icon: 'success' icon: 'success'
}) })
formData.image = ''
setTimeout(() => { setTimeout(() => {
Taro.navigateBack() Taro.navigateBack()
}, 2000) }, 2000)
@@ -513,9 +535,11 @@ function BxAdd() {
<Button <Button
type="primary" type="primary"
block block
loading={loading}
disabled={loading}
onClick={handleSubmit} onClick={handleSubmit}
> >
{loading ? '提交中...' : '提交报险申请'}
</Button> </Button>
</div> </div>
</div> </div>

View File

@@ -13,6 +13,7 @@ import Taro from '@tarojs/taro'
import {pageHjmBxLog} from "@/api/hjm/hjmBxLog"; import {pageHjmBxLog} from "@/api/hjm/hjmBxLog";
import {HjmBxLog} from "@/api/hjm/hjmBxLog/model"; import {HjmBxLog} from "@/api/hjm/hjmBxLog/model";
/** /**
* 报险记录列表页面 * 报险记录列表页面
*/ */
@@ -45,7 +46,12 @@ const Bx: React.FC = () => {
keywords: keywords.trim() keywords: keywords.trim()
}) })
setList(res?.list || []) setList(res?.list.map(d => {
console.log(d,'ddd')
d.image = JSON.parse(d.image);
console.log(d)
return d;
}) || [])
} catch (error) { } catch (error) {
console.error('获取报险记录失败:', error) console.error('获取报险记录失败:', error)
Taro.showToast({ Taro.showToast({
@@ -227,14 +233,16 @@ const Bx: React.FC = () => {
{/* 事故照片预览 */} {/* 事故照片预览 */}
{item.image && ( {item.image && (
<div style={{marginBottom: '12px'}}> <div style={{marginBottom: '12px'}} className={'flex gap-2'}>
{item.image.map((image) => (
<Image <Image
src={item.image} src={image.url}
width="60" width="60"
height="60" height="60"
radius="6px" radius="6px"
mode="aspectFill" mode="aspectFill"
/> />
))}
</div> </div>
)} )}
@@ -262,27 +270,20 @@ const Bx: React.FC = () => {
</div> </div>
{/* 浮动添加按钮 */} {/* 浮动添加按钮 */}
<div style={{ {/*<div style={{*/}
position: 'fixed', {/* position: 'fixed',*/}
bottom: '20px', {/* bottom: '20px',*/}
right: '20px', {/* right: '20px',*/}
zIndex: 30 {/* zIndex: 30*/}
}}> {/*}}>*/}
<Button {/* <Button*/}
type="primary" {/* type="primary"*/}
shape="round" {/* size="large"*/}
size="large" {/* onClick={onAddInsurance}*/}
onClick={onAddInsurance} {/* >*/}
style={{ {/* 一键报险*/}
width: '56px', {/* </Button>*/}
height: '56px', {/*</div>*/}
borderRadius: '28px',
boxShadow: '0 4px 12px rgba(0,0,0,0.15)'
}}
>
+
</Button>
</div>
</> </>
) )
} }

View File

@@ -3,7 +3,7 @@ import {Map} from '@tarojs/components'
import {Search} from '@nutui/icons-react-taro' import {Search} from '@nutui/icons-react-taro'
import {Button, Input} from '@nutui/nutui-react-taro' import {Button, Input} from '@nutui/nutui-react-taro'
import {useRouter} from '@tarojs/taro' import {useRouter} from '@tarojs/taro'
import {getHjmCar, getHjmCarByCode} from "@/api/hjm/hjmCar"; import {getHjmCarByCode} from "@/api/hjm/hjmCar";
import {HjmCar} from "@/api/hjm/hjmCar/model"; import {HjmCar} from "@/api/hjm/hjmCar/model";
import './location.scss' import './location.scss'
@@ -50,7 +50,7 @@ const Location = () => {
} }
const reload = () => { const reload = () => {
const id = Number(params.id); const code = params.id;
setScale(14) setScale(14)
// 执行搜索 // 执行搜索
if (keywords) { if (keywords) {
@@ -74,8 +74,8 @@ const Location = () => {
return false; return false;
} }
// 获取车辆信息 // 获取车辆信息
if (id) { if (code) {
getHjmCar(id).then(data => { getHjmCarByCode(code).then(data => {
setItem(data) setItem(data)
setLatitude(data.latitude) setLatitude(data.latitude)
setLongitude(data.longitude) setLongitude(data.longitude)

View File

@@ -2,7 +2,8 @@ import {useEffect, useState} from "react";
import Taro, {useRouter} from '@tarojs/taro' import Taro, {useRouter} from '@tarojs/taro'
import {getHjmCarByCode, pageHjmCar, updateHjmCar} from "@/api/hjm/hjmCar"; import {getHjmCarByCode, pageHjmCar, updateHjmCar} from "@/api/hjm/hjmCar";
import {HjmCar} from "@/api/hjm/hjmCar/model"; import {HjmCar} from "@/api/hjm/hjmCar/model";
import './location.scss' import './location.scss';
import { Swiper } from '@nutui/nutui-react-taro'
import {copyText} from "@/utils/common"; import {copyText} from "@/utils/common";
import {View} from '@tarojs/components' import {View} from '@tarojs/components'
import { import {
@@ -13,11 +14,21 @@ import {
Cell, Cell,
Image Image
} from '@nutui/nutui-react-taro' } from '@nutui/nutui-react-taro'
import { ImagePreview } from '@nutui/nutui-react-taro'
import {Scan} from '@nutui/icons-react-taro' import {Scan} from '@nutui/icons-react-taro'
import {pageDictData} from "@/api/system/dict-data"; import {pageDictData} from "@/api/system/dict-data";
import {DictData} from "@/api/system/dict-data/model"; import {DictData} from "@/api/system/dict-data/model";
import {myUserVerify} from "@/api/system/userVerify"; import {myUserVerify} from "@/api/system/userVerify";
import {uploadFile} from "@/api/system/file";
// 图片数据接口
interface UploadedImageData {
url?: string;
src?: string;
name?: string;
uid?: string;
message?: string;
type?: string;
}
/** /**
* 文章终极列表 * 文章终极列表
@@ -28,6 +39,8 @@ const Query = () => {
const [keywords, setKeywords] = useState<string>() const [keywords, setKeywords] = useState<string>()
const [dict, setDict] = useState<DictData[]>([]) const [dict, setDict] = useState<DictData[]>([])
const [adminId, setAdminId] = useState<number>() const [adminId, setAdminId] = useState<number>()
const [showPreview, setShowPreview] = useState(false)
const [fileList, setFileList] = useState<UploadedImageData[]>([]) // 图片文件列表
const [FormData, setFormData] = useState<HjmCar>( const [FormData, setFormData] = useState<HjmCar>(
{ {
// 自增ID // 自增ID
@@ -135,25 +148,133 @@ const Query = () => {
}); });
} }
// 拍照上传功能 // 选择并上传图片
const takePhoto = () => { const handleChooseImage = () => {
uploadFile().then(res => { if (fileList.length >= 5) {
setFormData({ Taro.showToast({
...FormData, title: '最多只能上传5张图片',
image: res.url 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 removeImage = (index: number) => { const uploadSingleImage = (filePath: string, index: number) => {
// const newImages = uploadedImages.filter((_, i) => i !== index); const TenantId = Taro.getStorageSync('TenantId')
// setUploadedImages(newImages);
// setFormData({ Taro.uploadFile({
// ...FormData, url: 'https://server.gxwebsoft.com/api/oss/upload',
// image: newImages.join(',') 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 () => { // const chooseLocation = async () => {
@@ -197,6 +318,29 @@ const Query = () => {
if(data){ if(data){
setFormData(data) setFormData(data)
setKeywords(data.code) 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) { if (data.status == 0) {
Taro.setNavigationBarTitle({ Taro.setNavigationBarTitle({
title: '安装设备' title: '安装设备'
@@ -326,11 +470,90 @@ const Query = () => {
name="image" name="image"
required required
rules={[{message: '请上传照片'}]} rules={[{message: '请上传照片'}]}
onClick={takePhoto}
> >
<div style={{display: 'flex', flexDirection: 'column', gap: '10px'}}> <div style={{
<Image src={FormData.image} mode={'scaleToFill'} display: 'flex',
radius="10%" width="80" height="80"/> 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> </div>
</Form.Item> </Form.Item>
@@ -349,7 +572,36 @@ const Query = () => {
{/* 已安装 */} {/* 已安装 */}
{FormData?.status == 1 ? ( {FormData?.status == 1 ? (
<div className={'car-info w-full bg-white'}> <div className={'car-info w-full bg-white'}>
<Image src={FormData?.image} mode={'aspectFit'} width={'100%'} height={'300px'}/> {/* 显示多张图片 */}
<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'}> <div className={'px-2'}>
<Cell className={'car-info-item-title'} onClick={() => copyText(`${FormData?.code}`)}> <Cell className={'car-info-item-title'} onClick={() => copyText(`${FormData?.code}`)}>
{FormData?.code} {FormData?.code}
@@ -372,11 +624,11 @@ const Query = () => {
<Cell className={'car-info-item-content'}> <Cell className={'car-info-item-content'}>
{FormData.fenceName} {FormData.fenceName}
</Cell> </Cell>
<div className={'flex justify-around'}> <div className={'flex justify-around py-4'}>
<Button nativeType="submit" type="info" onClick={ <Button nativeType="submit" type="info" onClick={
() => { () => {
Taro.navigateTo({ Taro.navigateTo({
url: `/hjm/location?id=${FormData?.id}` url: `/hjm/location?id=${FormData?.code}`
}) })
} }
}> }>
@@ -385,7 +637,7 @@ const Query = () => {
<Button nativeType="submit" type="warning" onClick={ <Button nativeType="submit" type="warning" onClick={
() => { () => {
Taro.navigateTo({ Taro.navigateTo({
url: `/hjm/trajectory/trajectory?id=${FormData?.id}` url: `/hjm/trajectory/trajectory?id=${FormData?.code}`
}) })
} }
}> }>

View File

@@ -2,7 +2,7 @@ import {useEffect, useState} from "react";
import {Map} from '@tarojs/components' import {Map} from '@tarojs/components'
import Taro, {useRouter} from '@tarojs/taro' import Taro, {useRouter} from '@tarojs/taro'
import {DatePicker, Button, type PickerOption} from '@nutui/nutui-react-taro' import {DatePicker, Button, type PickerOption} from '@nutui/nutui-react-taro'
import {getHjmCar, getHjmCarByCode} from "@/api/hjm/hjmCar"; import {getHjmCarByCode} from "@/api/hjm/hjmCar";
import {HjmCar} from "@/api/hjm/hjmCar/model"; 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";
@@ -119,7 +119,7 @@ const Location = () => {
} }
const reload = () => { const reload = () => {
const id = Number(params.id); const code = params.id;
setScale(16) setScale(16)
// 执行搜索 // 执行搜索
if (keywords) { if (keywords) {
@@ -144,8 +144,8 @@ const Location = () => {
return false; return false;
} }
// 获取车辆信息 // 获取车辆信息
if (id) { if (code) {
getHjmCar(id).then(data => { getHjmCarByCode(code).then(data => {
setItem(data) setItem(data)
setLatitude(data.latitude) setLatitude(data.latitude)
setLongitude(data.longitude) setLongitude(data.longitude)

View File

@@ -17,9 +17,11 @@ const BestSellers = (props: any) => {
{props.data?.map((item, index) => { {props.data?.map((item, index) => {
return ( return (
<div key={index} className={'flex bg-white rounded-lg w-full p-3 mb-3'} <div key={index} className={'flex bg-white rounded-lg w-full p-3 mb-3'}
onClick={() => Taro.navigateTo({url: '/hjm/query?id=' + item.id})}> onClick={() => Taro.navigateTo({url: '/hjm/query?id=' + item.code})}>
<Image src={item.image} mode={'scaleToFill'} {item.image && (
<Image src={JSON.parse(item.image)[0].url} mode={'scaleToFill'}
radius="10%" width="80" height="80"/> radius="10%" width="80" height="80"/>
)}
<div className={'mx-3 flex flex-col'}> <div className={'mx-3 flex flex-col'}>
<Space direction={'vertical'}> <Space direction={'vertical'}>
<div className={'car-no text-lg font-bold'}>{item.code}</div> <div className={'car-no text-lg font-bold'}>{item.code}</div>