package com.yeejoin.equipmanage.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.util.StringUtil;
import com.google.common.collect.Lists;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.interceptors.PermissionInterceptorContext;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.biz.common.utils.RedisUtils;
import com.yeejoin.amos.component.feign.config.InnerInvokException;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.privilege.Privilege;
import com.yeejoin.amos.feign.privilege.model.AgencyUserModel;
import com.yeejoin.amos.feign.privilege.model.CompanyModel;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.equipmanage.common.datasync.entity.FireVehicle;
import com.yeejoin.equipmanage.common.dto.CarFusionDto;
import com.yeejoin.equipmanage.common.dto.CarInfoDto;
import com.yeejoin.equipmanage.common.dto.CarStatusInfoDto;
import com.yeejoin.equipmanage.common.entity.*;
import com.yeejoin.equipmanage.common.entity.dto.CarDto;
import com.yeejoin.equipmanage.common.entity.dto.CarEquipAlarmInfoDto;
import com.yeejoin.equipmanage.common.entity.dto.CarEquipStateInfoDto;
import com.yeejoin.equipmanage.common.entity.publics.BaseEntity;
import com.yeejoin.equipmanage.common.entity.vo.CarIndexVo;
import com.yeejoin.equipmanage.common.entity.vo.CarPropertyVo;
import com.yeejoin.equipmanage.common.entity.vo.EquipmentSpecificVo;
import com.yeejoin.equipmanage.common.enums.*;
import com.yeejoin.equipmanage.common.exception.CommonException;
import com.yeejoin.equipmanage.common.utils.*;
import com.yeejoin.equipmanage.common.vo.*;
import com.yeejoin.equipmanage.dto.*;
import com.yeejoin.equipmanage.mapper.*;
import com.yeejoin.equipmanage.remote.RemoteSecurityService;
import com.yeejoin.equipmanage.service.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.ContentType;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.Collator;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 消防车信息 服务实现类
 *
 * @author wujiang
 * @date 2020-07-07
 */
@Service
public class CarServiceImpl extends ServiceImpl<CarMapper, Car> implements ICarService {

	private final String CAR_START_INDEX_KEY = "FireCar_Start";
	@Autowired
	protected HttpServletRequest request;
	@Autowired
	EquipmentSpecificMapper equipmentSpecificMapper;
	@Autowired
	WlCarSpeedWaringRecordMapper wlCarSpeedWaringRecordMapper;
	@Autowired
	ISyncDataService syncDataService;
	@Autowired
	private EquipmentCategoryMapper equipmentCategoryMapper;
	private List<Consumer<LossParams>> lossHandlers;
	private List<Consumer<LoadingParams>> loadingHandlers;
	@Autowired
	private CarInfoMapper carInfoMapper;
	@Autowired
	private ISystemDicService iSystemDicService;
	@Autowired
	private StockDetailMapper stockDetailMapper;
	@Autowired
	private SystemDicMapper systemDicMapper;
	@Autowired
	private IEquipmentQrcodeService iEquipmentQrcodeService;
	@Autowired
	private ExtinguishantOnCarMapper extinguishantOnCarMapper;
	@Autowired
	private CarMapper carMapper;
	@Autowired
	private WastageBillMapper wastageBillMapper;
	@Autowired
	private EquipmentDetailMapper equipmentDetailMapper;
	@Autowired
	private WastageBillDetailMapper wastageBillDetailMapper;
	@Autowired
	private JournalMapper journalMapper;
	@Autowired
	private ICarPropertyService iCarPropertyService;
	@Autowired
	private StockMapper stockMapper;
	@Autowired
	private UnitMapper unitMapper;
	@Autowired
	private RedisUtils redisUtils;
	@Autowired
	private EquipmentOnCarMapper equipmentOnCarMapper;
	@Autowired
	private WarehouseStructureMapper warehouseStructureMapper;
	@Autowired
	private IEquipmentService iEquipmentService;
	@Autowired
	private IUploadFileService iUploadFileService;
	@Autowired
	private IUnitService iUnitService;
	@Autowired
	@Lazy
	private IEquipmentIndexService equipmentIndexService;
	@Autowired
	private IManufacturerInfoService iManufacturerInfoService;
	@Autowired
	private IJournalService journalService;
	@Autowired
	private RemoteSecurityService remoteSecurityService;
	@Autowired
	private ICarPropertyService carPropertyService;
	@Autowired
	private IEquipmentDetailService iEquipmentDetailService;
	@Autowired
	private IEquipmentCategoryService iEquipmentCategoryService;
	@Autowired
	private CarPropertyMapper carPropertyMapper;
	@Value("${equip.dict.car-state}")
	private String carState;
	@Value("${equip.dict.name-key}")
	private String nameKeys;
	@Value("${systemctl.sync.switch}")
	private Boolean syncSwitch;
	@Value("${equip.car.alarmBattery}")
	private Integer carEquipAlarmBatteryNumber;
	@Value("${equip.car.maxTravel}")
	private Double carMaxTravel;
	@Autowired
	@Lazy
	private IWlCarMileageService iWlCarMileageService;
	@Value("${car.max.speed:100}")
	private Integer CAR_MAX_SPEED;

	@Value("${auth-key-auth-enabled:}")
	private String authKey;

	/**
	 * 当前登录用户信息
	 */
	protected ReginParams getSelectedOrgInfo() {
		return JSONObject.parseObject(redisUtils.get(buildKey(getUserId(), getToken())).toString(), ReginParams.class);
	}

	protected String getUserId() {
		String userId = null;
		if (getUser() != null) {
			userId = getUser().getUserId();
		}
		return userId;
	}

	// redi缓存选择的用户信息
	private String buildKey(String userId, String token) {
		return RedisKey.buildReginKey(userId, token);

	}

	protected AgencyUserModel getUser() {
		AgencyUserModel userModel = null;
		if (getToken() != null) {
			RequestContext.setToken(getToken());
			RequestContext.setProduct(getProduct());
			RequestContext.setAppKey(getAppKey());
			FeignClientResult<?> feignClientResult;
			try {
				feignClientResult = Privilege.agencyUserClient.getme();
				userModel = (AgencyUserModel) feignClientResult.getResult();

			} catch (InnerInvokException e) {
				throw new RuntimeException(e.getMessage());
			}

		}
		return userModel;
	}

	protected String getToken() {
		String authToken = request.getHeader("token");
		if (authToken == null) {
			authToken = request.getHeader("X-Access-Token");
		}
		return authToken;
	}

	protected String getProduct() {
		String authToken = request.getHeader("product");
		if (authToken == null) {
			authToken = request.getParameter("product");
		}
		return authToken;
	}

	protected String getAppKey() {
		String authToken = request.getHeader("appKey");
		if (authToken == null) {
			authToken = request.getParameter("appKey");
		}
		return authToken;
	}

	protected String getChannelType() {
		String channelType = request.getHeader("channelType");
		if (channelType == null) {
			channelType = request.getParameter("channelType");
		}
		return channelType;
	}

	@Override
	public List<EquipmentCategory> getCarCategory() {
		List<EquipmentCategory> results = new ArrayList<>();
		Map<String, Object> columnMap = new HashMap<String, Object>();
		columnMap.put("name", "消防车");
		columnMap.put("industry_code", IndustryEnum.EQUIP.getCode());
		List<EquipmentCategory> equipmentCategory = equipmentCategoryMapper.selectByMap(columnMap);
		if (ObjectUtils.isEmpty(equipmentCategory)) {
			return results;
		}
		List<Map<String, Object>> lists = equipmentCategoryMapper
				.getEquipCategoryListByParentId(equipmentCategory.get(0).getId());
		for (Map<String, Object> map : lists) {
			EquipmentCategory instance = new EquipmentCategory();
			instance.setId(Long.parseLong(map.get("id").toString()));
			instance.setCode(map.get("code").toString());
			if (map.get("parentId") != null && StringUtil.isNotEmpty(map.get("parentId").toString())) {
				instance.setParentId(Long.parseLong(map.get("parentId").toString()));
			}
			instance.setName(map.get("name").toString());
			instance.setIsConsumptive(Boolean.valueOf(map.get("isConsumptive").toString()));
			instance.setLevel(String.valueOf(map.get("curLevel").toString()));
			results.add(instance);
		}
		return results;
	}

	@Override
	public Car saveCar(AgencyUserModel user, Car car, CarInfo carInfo, Set<CarProperty> carpList) {
		Car carInstance = saveCarInstance(user, car);
		if (carInstance == null) {
			throw new CommonException(0, "车辆信息保存失败");
		}
		Long carId = carInstance.getId();
		if (carInfo != null) {
			carInfo.setCarId(carId);
			carInfoMapper.insert(carInfo); // 保存车辆信息
		}
		if (carpList != null && !carpList.isEmpty()) {
			saveCarProperty(carpList, carInstance); // 保存性能指标
		}
		return carInstance;
	}

	private Car saveCarInstance(AgencyUserModel user, Car car) {
		if (car.getEquipmentId() == null) {
			throw new CommonException(0, "请选择车辆定义");
		}
		if (car.getCountry() == null) {
			throw new CommonException(0, "请填写国别");
		}
		if (car.getCarNum() == null) {
			throw new CommonException(0, "请填写车牌号");
		}
		QueryWrapper<Car> queryWrapper = new QueryWrapper<Car>();
		queryWrapper.lambda().eq(Car::getCarNum, car.getCarNum());
		List<Car> ifExistList = this.list(queryWrapper);
		if (car.getId() == null) {
			if (ifExistList != null && !ifExistList.isEmpty()) {
				throw new CommonException(0, "录入的车牌号已存在");
			}
		} else {
			List<Long> ids = new ArrayList<Long>();
			ifExistList.forEach(action -> ids.add(action.getId()));
			if (ifExistList != null && !ids.isEmpty() && !ids.contains(car.getId())) {
				throw new CommonException(0, "录入的车牌号已存在");
			}
		}

		if (car.getCarState() == null) {
//			SystemDic carState = iSystemDicService.findByTypeAndCode(SystemDicTypeEum.carState.getType(),
//					CarStatusEnum.ZW.getCode());
			car.setCarState(CarStatusEnum.ZW.getCode());
		}

		if (car.getId() != null) {
			Car oldcar = this.getById(car.getId());
			// 更新图片或者视频 删除远程服务器的文件
			// if (FtpUtil.isFastdfs&&oldcar!=null) {
			// if (StringUtil.isNotEmpty(oldcar.getImg()) &&
			// !oldcar.getImg().equals(car.getImg())) {
			// FtpUtil.ftpDeleteFileFastdfs(oldcar.getImg());
			// }
			// if (StringUtil.isNotEmpty(oldcar.getFilm()) &&
			// !oldcar.getFilm().equals(car.getFilm())) {
			// FtpUtil.ftpDeleteFileFastdfs(oldcar.getFilm());
			// }
			// }
		}
		this.save(car);
		saveCarQRCode(car);
		return car;
	}

	private void saveCarQRCode(Car car) {
		QueryWrapper<EquipmentQrcode> queryWrapper = new QueryWrapper<EquipmentQrcode>();
		queryWrapper.lambda().eq(EquipmentQrcode::getCarId, car.getId());
		List<EquipmentQrcode> equipmentQRCodeList = iEquipmentQrcodeService.getBaseMapper().selectList(queryWrapper);
		if (equipmentQRCodeList == null || equipmentQRCodeList.isEmpty()) {
			EquipmentQrcode equipmentQRCode = new EquipmentQrcode();
			equipmentQRCode.setCarId(car.getId());
			equipmentQRCode.setIsSingleUsed(true);
			iEquipmentQrcodeService.save(equipmentQRCode);
			if (StringUtils.isBlank(car.getQrCode())) {
				equipmentQRCode.setQRCode(QRCodeUtil.generateQRCode());
				car.setQrCode(equipmentQRCode.getQRCode());
			} else {
				equipmentQRCode.setQRCode(car.getQrCode());
			}
			this.save(car);
			iEquipmentQrcodeService.save(equipmentQRCode);
		} else {
			if (!StringUtil.isNotEmpty(car.getQrCode())) {
				car.setQrCode(equipmentQRCodeList.get(0).getQRCode());
				this.save(car);
			}
		}
	}

	private void saveCarProperty(Set<CarProperty> carpList, Car car) {
		carpList.forEach(action -> {
			if (action.getCarId() == null) {
				if (action.getValue() != null) {
					CarProperty carPro = new CarProperty();
					carPro.setCarId(car.getId());
					// carPro.setPerfQuotaDefinitionId(action.getPerfQuotaDefinitionId());
					carPro.setValue(action.getValue());
					carPro.setRemark(action.getRemark());
					iCarPropertyService.save(carPro);
				}
			} else {
				iCarPropertyService.save(action);
			}
		});
	}

	// 消耗灭火药剂
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, String> lossExtinguishants(Long carId, List<ExtinguishantLossRequest> extinguishants) {
		LossParams params = new LossParams(carId, extinguishants);
		lossHandlers.forEach(handler -> handler.accept(params));
		Map<String, String> result = new HashMap<>();
		result.put("person", getUser().getRealName());
		result.put("time", DateUtils.getNowStrLong());
		result.put("number", params.getBill().getBillCode());
		return result;
	}

	@PostConstruct
	public void init() {
		if (null == loadingHandlers) {
			loadingHandlers = new ArrayList<Consumer<LoadingParams>>();

			loadingHandlers.add((p) -> {
				p.setCar(carMapper.selectById(p.getCarId()));

				List<Long> stockDetailIds = p.getExtinguishants().stream().map(ExtinguishantRequeset::getStockDetailId)
						.collect(Collectors.toList());

				Map<Long, StockDetail> details = new HashMap<>();
				stockDetailMapper.findByIdInAndStatus(stockDetailIds, EquipStatusEnum.REPERTORY.getCode())
						.forEach(s -> details.put(s.getId(), s));

				p.setDetails(details);

				Map<String, Object> columnMap = new HashMap<String, Object>();
				columnMap.put("type", "JournalType");
				columnMap.put("code", JournalTypeEnum.CZ.getCode());
				List<SystemDic> listd = systemDicMapper.selectByMap(columnMap);
				p.setLoadingId(listd.get(0).getCode());
			});

			loadingHandlers.add(this::destocking);

//			loadingHandlers.add((p) ->
//				AsynUtils.run(p.getStockDetailIds(), iRemoteSearchServer::updateStockDetails));
		}
		if (null == lossHandlers) {
			lossHandlers = new ArrayList<Consumer<LossParams>>();
			lossHandlers.add(p -> {
				p.setCar(carMapper.selectById(p.getCarId()));
				Map<String, Object> columnMap = new HashMap<String, Object>();
				columnMap.put("car_id", p.getCarId());
				List<ExtinguishantOnCar> extinguishantOnCar = extinguishantOnCarMapper.selectByMap(columnMap);
				p.setExtinguishantOnCar(extinguishantOnCar);
				List<Long> stockDetailIds = p.getExtinguishantOnCar().stream().map(ExtinguishantOnCar::getStockDetailId)
						.collect(Collectors.toList());
				Map<Long, StockDetail> details = new HashMap<>();
				stockDetailMapper.findByIdInAndStatus(stockDetailIds, EquipStatusEnum.ONCAR.getCode())
						.forEach(s -> details.put(s.getId(), s));
				p.setDetails(details);
				columnMap.clear();
				columnMap.put("type", "JournalType");
				columnMap.put("code", JournalTypeEnum.SH.getCode());
				List<SystemDic> listd = systemDicMapper.selectByMap(columnMap);
				p.setLossStateId(listd.get(0).getId());
			});
			lossHandlers.add(this::loss);

			// 同步搜索
			/*
			 * lossHandlers.add((p) -> AsynUtils.run(p.getStockDetailIds(),
			 * iRemoteSearchServer::updateStockDetails));
			 */
		}
	}

	@Transactional(rollbackFor = RuntimeException.class)
	void destocking(LoadingParams params) {
		try {
			params.getExtinguishants().forEach(r -> {
				// 去库存
				StockDetail detail = params.getDetailById(r.getStockDetailId());
				detail.setAmount(detail.getAmount() - r.getAmount());
				stockDetailMapper.updateById(detail);
				params.addStockDetailId(r.getStockDetailId());

				StockDetail detailOnCar = new StockDetail();
				BeanUtils.copyProperties(detail, detailOnCar);
				// 新增车载记录
//                detail_onCar = detail.clone();
				detailOnCar.setId(null);
				detailOnCar.setAmount(r.getAmount());
				detailOnCar.setStatus(EquipStatusEnum.ONCAR.getCode().toString());
				stockDetailMapper.insert(detailOnCar);
				params.addStockDetailId(detailOnCar.getId());

				// 装车
				extinguishantOnCarMapper.insert(params.create(r, detailOnCar));

				// 流水
				journalMapper.insert(params.createJournal(r, detailOnCar.getId()));

			});
		} catch (Exception e) {
			throw new RuntimeException("系统异常！");
		}
	}

	@Override
	@Transactional(rollbackFor = RuntimeException.class)
	public void loss(Object o) {
		LossParams params = (LossParams) o;
		// 生成损耗单
		WastageBill bill = new WastageBill();
		// 生成损耗单据编号
		List<Map<String, Object>> wastage = wastageBillMapper.getOneByIdDesc();
		String billCode = "";
		if (null == wastage || wastage.size() < 1) {
			billCode = getCurrentPrefix() + "0001";
		} else {
			String str = (wastage.get(0).get("bill_code")).toString().substring(2);
			Long value = Long.valueOf(str) + 1L;
			billCode = BillCodeManagerUtil.LOSS + value.toString();
		}
		String code2 = BillCodeManagerUtil.checkCoding(BillCodeManagerUtil.LOSS, billCode);
		bill.setBillCode(code2);
		Map<String, Object> columnMap = new HashMap<String, Object>();
		columnMap.put("type", "StockBillType");
		columnMap.put("code", StockBillTypeEnum.SHCK.getValue());
		List<SystemDic> listd = systemDicMapper.selectByMap(columnMap);
		bill.setBillType(StockBillTypeEnum.SHCK.getValue());
		bill.setCreatorId(Long.valueOf(getUser().getUserId()));
		bill.setCreatorName(getUser().getRealName());
		bill.setOrgCode("");
		// bill.setOrgCode(user.getCompany().getCompCode());
		wastageBillMapper.insert(bill);
		wastageBillMapper.updateById(bill);
		params.setBill(bill);

		params.getExtinguishants().forEach(r -> {
			try {
				// 减车载
				Double lossCount = r.getTotal() - r.getAmount();
				if (0 >= lossCount) {
					throw new IllegalArgumentException("消耗量不能为0或者小于0！");
				}
				List<ExtinguishantOnCar> list = ArrayUtil.filter(params.getExtinguishantOnCar(),
						e -> e.getEquipmentDetailId().longValue() == r.getEquipmentDetailId().longValue());
				for (ExtinguishantOnCar e : list) {

					// 车载记录总和 大于等于 消耗量
					if (r.getTotal().doubleValue() == lossCount.doubleValue()) {
						lossCount = params.equalLossCountHandler(e, lossCount);
						break;
					} else if (r.getTotal().doubleValue() > lossCount.doubleValue()) {

						lossCount = params.greaterThanLossCountHandler(e, lossCount);
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException("系统异常！");
			}
		});
	}

	/**
	 * 获取单据编码前缀
	 *
	 * @return
	 */
	private String getCurrentPrefix() {
		return BillCodeManagerUtil.LOSS + DateUtils.get(Calendar.YEAR) + DateUtils.get(Calendar.MONTH)
				+ DateUtils.get(Calendar.DAY_OF_MONTH);
	}

	@Override
	public Map<String, String> loadingExtinguishants(Long carId, List<ExtinguishantRequeset> extinguishants) {
		Car car = this.getById(carId);
		if (car.getCarState().equals(CarStatusEnum.WX.getCode())
				|| car.getCarState().equals(CarStatusEnum.BF.getCode())) {
			throw new RuntimeException("报废维修车辆不能装载");
		}
		LoadingParams params = new LoadingParams(carId, extinguishants);
		loadingHandlers.forEach(handler -> handler.accept(params));
		Map<String, String> result = new HashMap<>();
		result.put("person", getUser().getRealName());
		result.put("time", DateUtils.getNowStrLong());
		result.put("number", null);
		return result;
	}

	@Override
	public void loadingEquipment(OnBoardEquipment equipment, AgencyUserModel user) {
		List<Equip> eqs = generate(equipment);
		try {
			eqs.forEach(eq -> {
				StockDetail detail = getEligibleStockDetail(eq);
				if (null == detail) {
					throw new RuntimeException("二维码为【" + eq.getQrCode() + "】的装备库存量不足！");
				}
				updateStockDetail(detail, equipment.getType(), null, null);
				loading(detail, eq);
				generateJournal(detail, eq, equipment.getType(), user, null);
			});
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}

	}

	private void loading(StockDetail detail, Equip eq) {
		QueryWrapper queryWrapper = new QueryWrapper();
		queryWrapper.eq("qr_code", detail.getQrCode());
		EquipmentSpecific equipmentSpecific = equipmentSpecificMapper.selectOne(queryWrapper);
		EquipmentOnCar equipmentOnCar = new EquipmentOnCar();
		equipmentOnCar.setCarId(eq.getCarId());
		equipmentOnCar.setStockDetailId(detail.getId());
		equipmentOnCar.setAmount(eq.getAmount());
		equipmentOnCar.setEquipmentDetailId(eq.getEquipmentDetailId());
		if (equipmentSpecific != null) {
			equipmentOnCar.setEquipmentSpecificId(equipmentSpecific.getId());
		}
		equipmentOnCarMapper.insert(equipmentOnCar);
	}

	private void generateJournal(StockDetail detail, Equip eq, String type, AgencyUserModel user, Long shelfCellId) {
		OnBoardEquipmentEnum typeEnum = OnBoardEquipmentEnum.getEnum(type);
		Journal journal = new Journal();
		journal.setUserId(Long.valueOf(user.getUserId()));
		journal.setEquipmentDetailId(eq.getEquipmentDetailId());
		journal.setAmount(eq.getAmount());
		journal.setOrgCode(getSelectedOrgInfo().getCompany().getOrgCode());
		journal.setStockDetailId(detail.getId());

		Car car = carMapper.selectById(eq.getCarId());
		if (null == car) {
			throw new RuntimeException("车辆不存在！");
		}
		EquipmentDetail equipmentDetail = equipmentDetailMapper.selectById(eq.getEquipmentDetailId());
		if (typeEnum == OnBoardEquipmentEnum.LOAD) {

			// 查询装备状态
			Map<String, Object> columnMap = new HashMap<String, Object>();
			columnMap.put("type", "JournalType");
			columnMap.put("code", JournalTypeEnum.CZ.getCode());
			List<SystemDic> list = systemDicMapper.selectByMap(columnMap);
			ParsePropertyUtil.setting(journal::setState, () -> list.get(0).getId().toString());

			journal.setRemark(
					user.getRealName() + "将" + equipmentDetail.getName() + "装备装载到车牌号为【" + car.getCarNum() + "】的车辆上。");
			journal.setWarehouseStructureId(detail.getWarehouseStructureId());
			journal.setCarId(eq.getCarId());
		} else if (typeEnum == OnBoardEquipmentEnum.UNLOAD) {
			journal.setRemark(
					user.getRealName() + "从车牌号为【" + car.getCarNum() + "】的车辆上卸载了" + equipmentDetail.getName() + "装备。");
			journal.setWarehouseStructureId(shelfCellId);
			journal.setCarId(eq.getCarId());
		}
		journalMapper.insert(journal);
	}

	private List<Equip> generate(OnBoardEquipment equipment) {
		return equipment.getEquipments().parallelStream().map(eq -> {
			eq.setWarehouseId(equipment.getWarehouseId());
			return eq;
		}).collect(Collectors.toList());
	}

	private StockDetail getEligibleStockDetail(Equip eq) {
		QueryWrapper queryWrapper = new QueryWrapper();
		queryWrapper.eq("qr_code", eq.getQrCode());
		queryWrapper.eq("warehouse_id", eq.getWarehouseId());
		queryWrapper.gt("amount", 0d);
		List<StockDetail> details = stockDetailMapper.selectList(queryWrapper);

		return details.isEmpty() ? null : details.get(0);
	}

	private void updateStock(StockDetail detail, double amount) {
		Stock stock = stockMapper.selectById(detail.getStockId());
		stock.setAmount(stock.getAmount() + amount);
		stockMapper.updateById(stock);
	}

	private Stock changeStock(Long warehouseId, Long equipmentDetailId, String orgCode) {
		// Stock stock =
		// iStockDao.findByEquipmentDetailIdAndWarehouseId(equipmentDetailId,
		// warehouseId);
		Map<String, Object> columnMap = new HashMap<String, Object>();
		columnMap.put("equipment_detail_id", equipmentDetailId);
		columnMap.put("warehouse_id", warehouseId);
		List<Stock> stock = stockMapper.selectByMap(columnMap);
		Stock stock1 = new Stock();
		if (null == stock && stock.size() > 0) {
			stock1.setAmount(0d);
			stock1.setEquipmentDetailId(equipmentDetailId);
			stock1.setWarehouseId(warehouseId);
			stock1.setOrgCode(orgCode);
			stockMapper.insert(stock1);
		}
		return stock1;
	}

	private void updateStockDetail(StockDetail detail, String type, Long warehouseId, Long shelfCellId) {
		OnBoardEquipmentEnum typeEnum = OnBoardEquipmentEnum.getEnum(type);
		if (typeEnum == OnBoardEquipmentEnum.LOAD) {
			// TODO 更新为自己去反，之前为减去1，这样在设备管理方式为批量管理时，就不对了
			updateStock(detail, detail.getAmount() * -1);
			detail.setAmount(0.0);
			detail.setStatus(EquipStatusEnum.ONCAR.getCode().toString());
		} else if (typeEnum == OnBoardEquipmentEnum.UNLOAD) {
			if (null != shelfCellId) {
				// 更换仓库id，就需要更换该stockDetail对应的stock
				if (warehouseId != null && warehouseId.longValue() != detail.getWarehouseId()) {
					Stock stock = changeStock(warehouseId, detail.getEquipmentDetailId(), detail.getOrgCode());
					detail.setStockId(stock.getId());
				}
				detail.setWarehouseId(warehouseId);
				detail.setWarehouseStructureId(shelfCellId);
			}
			detail.setStatus(EquipStatusEnum.REPERTORY.getCode().toString());
			// 卸载将卸载的数量恢复
			updateStock(detail, detail.getAmount());
		}
		stockDetailMapper.updateById(detail);
	}

	@Override
	public void unloadEquipment(OnBoardEquipment equipment, AgencyUserModel user) {
		List<Equip> eqs = generate(equipment);
		String area = equipment.getArea();
		// TODO: 是否返回原始位置：true-是 false -否 ，equipment.getShelfCellCode()
		// 为空或者为null，代表，装备的卸载是，放回原位
		boolean isOriPosition = StringUtil.isEmpty(equipment.getShelfCellCode());
		// 新存放的货位id,不放回原位使用
		Long shelfCellId = null;
		// TODO: 不放回原位，查询存放位置(正常逻辑，应该是前端返回操作类型及货位id,后端不需要进行查询)
		if (!isOriPosition && equipment.getWarehouseId() != null) {
			shelfCellId = queryShelfCellId(equipment);
		}
		try {
			Long finalShelfCellId = shelfCellId;
			eqs.forEach(eq -> {
				EquipmentOnCar equipmentOnCar = checkEquipment(eq);
				if (null == equipmentOnCar) {
					throw new RuntimeException("二维码为【" + eq.getQrCode() + "】的装备未装备在车上，不用卸载!");
				}
				StockDetail detail = stockDetailMapper.selectById(equipmentOnCar.getStockDetailId());
				if (null == detail) {
					throw new RuntimeException("二维码为【" + eq.getQrCode() + "】的装备未记录在库!");
				}
				// 卸载将转载的数量回复回去
				if (finalShelfCellId != null) {
					iEquipmentDetailService.update(
							new UpdateWrapper<EquipmentDetail>().eq("id", eq.getEquipmentDetailId()).set("area", area));
				}
				detail.setAmount(equipmentOnCar.getAmount());
				unLoad(equipmentOnCar);
				updateStockDetail(detail, equipment.getType(), equipment.getWarehouseId(), finalShelfCellId);
				generateJournal(detail, eq, equipment.getType(), user, finalShelfCellId);
			});
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}

	}

	private void unLoad(EquipmentOnCar equipmentOnCar) {
		equipmentOnCarMapper.deleteById(equipmentOnCar.getId());

	}

	private EquipmentOnCar checkEquipment(Equip eq) {

		Map<String, Object> columnMap = new HashMap<String, Object>();
		columnMap.put("qr_code", eq.getQrCode());
		List<EquipmentOnCar> list2 = null;
		List<StockDetail> list = stockDetailMapper.selectByMap(columnMap);
		if (list != null && list.size() > 0) {
			columnMap.clear();
			columnMap.put("equipment_detail_id", eq.getEquipmentDetailId());
			columnMap.put("car_id", eq.getCarId());
			columnMap.put("stock_detail_id", list.get(0).getId());
			list2 = equipmentOnCarMapper.selectByMap(columnMap);
		}
		if (list2 != null && list2.size() > 0) {
			return list2.get(0);
		}
		return null;
	}

	private Long queryShelfCellId(OnBoardEquipment equipment) {
		// 存放到其他位置
		Map<String, Object> columnMap = new HashMap<String, Object>();
		columnMap.put("warehouse_id", equipment.getWarehouseId());
		columnMap.put("code", equipment.getShelfCellCode());
		List<WarehouseStructure> shelfCell = warehouseStructureMapper.selectByMap(columnMap);
		if (shelfCell.isEmpty()) {
			throw new RuntimeException("货位信息获取失败!");
		}
		return shelfCell.get(0).getId();

	}

	@Override
	public IPage<Car> getCarList(String ercode, String orgcode, Car car, Page<Car> pageBean) {
		QueryWrapper<Car> queryWrapper = new QueryWrapper<>();
		List<Equipment> equipmentList = iEquipmentService.list(new QueryWrapper<Equipment>().likeRight("code", ercode));
		List<Long> idList = new ArrayList<Long>();
		for (Equipment equipment : equipmentList) {
			idList.add(equipment.getId());
		}
		if (!StringUtil.isEmpty(car.getStandard())) {
			queryWrapper.eq("standard", car.getStandard());
		}
		if (car.getCarState() != null) {
			queryWrapper.eq("car_state_id", car.getCarState());
		}
		if (!StringUtil.isEmpty(car.getBrand())) {
			queryWrapper.eq("brand", car.getBrand());
		}
		if (!StringUtil.isEmpty(orgcode)) {
			queryWrapper.eq("org_code", orgcode);
		}
		if (idList != null) {
			queryWrapper.in("equipment_id", idList);
		}
		IPage<Car> page = this.page(pageBean, queryWrapper);
		for (Car carOne : page.getRecords()) {
			Equipment equipment = iEquipmentService.getById(carOne.getEquipmentId());
			String utilName = carMapper.getUtilName(equipment.getUnitId());
			carOne.setUnitName(utilName);
			equipment.setImg(equipment.getImg());
			carOne.setEquipment(equipment);
			carOne.setCarState(CarStatusEnum.getEnum(carOne.getCarState().toString()).getName());
		}
		return page;
	}

	@Override
	public Car saveOne(Car car) {
		// 如果没有状态默认状态在位
		if (StringUtils.isEmpty(car.getCarState())) {
			car.setCarState(CarStatusEnum.ZW.getCode());
		}
		String orgCode = remoteSecurityService.getAgencyUser().getCompanys().get(0).getOrgCode();
		car.setOrgCode(orgCode);
		boolean save = this.save(car);
		// AST数据同步
		if (save && syncSwitch) {
			FireVehicle fireVehicle = getFireVehicleDetailById(car.getId());
			syncDataService.syncCreatedFireVehicle(fireVehicle);
		}
		List<CarProperty> carPropertyList = car.getCarPropertyList();
		if (carPropertyList != null) {
			for (CarProperty carProperty : carPropertyList) {
				carProperty.setCarId(car.getId());
			}
			boolean saveBatch = iCarPropertyService.saveBatch(carPropertyList);
			// AST数据同步
			if (saveBatch && syncSwitch) {
				dataSyncSaveOrUpdate(car);
			}
		}
		List<UploadFile> fileList = new ArrayList<UploadFile>();
		fileList.addAll(fillFileList(car.getImg(), car.getId(), FileTypeEnum.image.toString()));
		fileList.addAll(fillFileList(car.getVideo(), car.getId(), FileTypeEnum.video.toString()));
		fileList.addAll(fillFileList(car.getCertification(), car.getId(), FileTypeEnum.certificate.toString()));
		fileList.addAll(fillFileList(car.getInstruction(), car.getId(), FileTypeEnum.instruction.toString()));
		iUploadFileService.saveBatch(fileList);
		syncDataService.saveOrUpdateEquipIotCodeRedisData(null);
		return car;
	}

	@Override
	@Async("equipAsyncExecutor")
	public FireVehicle getFireVehicleDetailById(Long id) {
		return carMapper.getFireVehicleDetailById(id);
	}

	@Override
	public List<CarInfoDto> carInfoList(Long teamId, String name) {
		LambdaQueryWrapper<Car> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(teamId != null, Car::getTeamId, teamId);
		wrapper.like(!StringUtil.isEmpty(name), Car::getName, name);
		wrapper.in(Car::getCarState, "1", "2");
		wrapper.orderByDesc(BaseEntity::getCreateDate);
		List<Car> carList = this.list(wrapper);
		List<Equipment> equipmentList = iEquipmentService.list();
		/* 统一车辆图片使用装备定义图片 2021-10-27 陈召 */
		equipmentList.stream().filter(e -> e.getName().contains("车")).forEach(e -> {
			carList.forEach(car -> {
				if (e.getId().equals(car.getEquipmentId())) {
					List<UploadFile> objects = new ArrayList<>();
					UploadFile uploadFile = new UploadFile();
					uploadFile.setUrl(e.getImg());
					objects.add(uploadFile);
					car.setImg(objects);
				}
			});
		});
		/* 统一车辆图片使用装备定义图片 2021-10-27 陈召 */
		Map<Long, Equipment> keyMap = equipmentList.stream()
				.collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
		List<EquipmentCategory> categoryList = iEquipmentCategoryService.list();
		Map<Long, String> categoryMap = categoryList.stream()
				.collect(Collectors.toMap(BaseEntity::getId, EquipmentCategory::getName));
		List<UploadFile> fileList = iUploadFileService.list(new LambdaQueryWrapper<UploadFile>()
				.eq(UploadFile::getObjectType, "car").eq(UploadFile::getFileType, "image"));

		// 车载装备
		List<Map<String, Object>> carResourceMapList = this.baseMapper.getCarResourceMapList(null);
		Map<String, List<Map<String, Object>>> carResourceMap = carResourceMapList.stream()
				.collect(Collectors.groupingBy(car -> car.get("carId").toString()));
		return carList.stream().map(car -> {
			CarInfoDto carInfoVo = new CarInfoDto();
			Bean.copyExistPropertis(car, carInfoVo);
			Equipment equipment = keyMap.get(carInfoVo.getEquipmentId());
			carInfoVo.setCarStateDesc(this.getCarStateDesc(car));
			carInfoVo.setEquipmentName(equipment != null ? equipment.getName() : "");
			carInfoVo.setCategoryId(equipment != null ? equipment.getCategoryId() : null);
			carInfoVo.setCategoryName(categoryMap.get(carInfoVo.getCategoryId()));
			carInfoVo.setName(car.getName());
			if (car.getImg() != null) {

				List<String> img = new ArrayList<>();
				img.add(car.getImg().get(0).getUrl());
				carInfoVo.setImage(img);
			}
			carInfoVo.setResourceList(carResourceMap.get(car.getId().toString()));
			return carInfoVo;
		}).collect(Collectors.toList());
	}

	@Override
	public List<Map<String, Object>> teamCarList() {
		return this.baseMapper.getCarNumGroupByTeamId();
	}

	private String getCarStateDesc(Car car) {
		CarStatusEnum carStatusEnum = CarStatusEnum.getEnum(car.getCarState());
		if (carStatusEnum != null) {
			return carStatusEnum.getName();
		}
		return "";
	}

	@Async("equipAsyncExecutor")
	void dataSyncSaveOrUpdate(Car car) {
		CarIndexVo carIndexVo = new CarIndexVo();
		carIndexVo.setId(car.getId());
		List<CarPropertyVo> propertyList = carPropertyService.getCarPropertyList(carIndexVo);
		List<CarPropertyVo> fireVehicleInfoList = propertyList.stream().filter(propertyVo -> 0 == propertyVo.getIsIot())
				.collect(Collectors.toList());
		List<CarPropertyVo> fireVehicleMeasurementList = propertyList.stream()
				.filter(propertyVo -> propertyVo.getIsIot() != null && 1 == propertyVo.getIsIot())
				.collect(Collectors.toList());
		syncDataService.syncCreatedFireVehicleInfo(fireVehicleInfoList);
		syncDataService.syncCreatedFireVehicleMeasurement(fireVehicleMeasurementList);
	}

	@Override
	public void dataSyncDeletedIds(List<Long> carIds) {
		List<CarPropertyVo> propertyList = carPropertyService.getCarPropertyListByCarIds(carIds);
		List<Long> fireVehicleInfoList = propertyList.stream().filter(propertyVo -> 0 == propertyVo.getIsIot())
				.map(CarPropertyVo::getId).collect(Collectors.toList());
		List<Long> fireVehicleMeasurementList = propertyList.stream()
				.filter(propertyVo -> propertyVo.getIsIot() != null && 1 == propertyVo.getIsIot())
				.map(CarPropertyVo::getId).collect(Collectors.toList());
		syncDataService.syncDeletedFireVehicleInfo(fireVehicleInfoList);
		syncDataService.syncDeletedFireVehicleMeasurement(fireVehicleMeasurementList);
	}

	private List<UploadFile> fillFileList(List<UploadFile> list, Long id, String type) {
		if (list == null) {
			return new ArrayList<UploadFile>();
		}
		list.forEach(item -> {
			item.setUrl(item.getUrl());
			item.setFileType(type);
			item.setObjectType(BillContentEnum.CL.getKey());
			item.setObjectId(id);
		});
		return list;
	}

	@Override
	public Car updateOneById(Car car) {
		String orgCode = remoteSecurityService.getAgencyUser().getCompanys().get(0).getOrgCode();
		car.setOrgCode(orgCode);
		// @TableField(updateStrategy = FieldStrategy.IGNORED) 置空不生效 为空单独设置 by kongfm
		// 2021-09-09
		this.update(new LambdaUpdateWrapper<Car>().set(Car::getAgencyId, car.getAgencyId())
				.set(Car::getTeamId, car.getTeamId()).eq(Car::getId, car.getId()));
		boolean update = this.updateById(car);
		// AST数据同步
		if (update && syncSwitch) {
			FireVehicle fireVehicle = getFireVehicleDetailById(car.getId());
			syncDataService.syncCreatedFireVehicle(fireVehicle);
		}
		List<CarProperty> carPropertyList = car.getCarPropertyList();
		if (carPropertyList.size() > 0) {
			carPropertyList.forEach(x -> {
				if ("state".equals(x.getNameKey())) {
					if ("是".equals(x.getValue())) {
						x.setValue(TrueOrFalseEnum.real.value);
					} else {
						x.setValue(TrueOrFalseEnum.fake.value);
					}
				}
			});
			carPropertyList.forEach(x -> x.setCarId(car.getId()));
			iCarPropertyService.remove(new QueryWrapper<CarProperty>().lambda().eq(CarProperty::getCarId, car.getId()));
			boolean saveBatch = iCarPropertyService.saveBatch(carPropertyList);
			// AST数据同步
			if (saveBatch && syncSwitch) {
				dataSyncSaveOrUpdate(car);
			}
		}
		iUploadFileService.remove(new QueryWrapper<UploadFile>().eq("object_type", BillContentEnum.CL.getKey())
				.eq("object_id", car.getId()));
		List<UploadFile> fileList = new ArrayList<UploadFile>();
		fileList.addAll(fillFileList(car.getImg(), car.getId(), FileTypeEnum.image.toString()));
		fileList.addAll(fillFileList(car.getVideo(), car.getId(), FileTypeEnum.video.toString()));
		fileList.addAll(fillFileList(car.getCertification(), car.getId(), FileTypeEnum.certificate.toString()));
		fileList.addAll(fillFileList(car.getInstruction(), car.getId(), FileTypeEnum.instruction.toString()));
		iUploadFileService.saveBatch(fileList);
		syncDataService.saveOrUpdateEquipIotCodeRedisData(null);
		return car;
	}

	@Override
	public Car selectOneById(Long id) {
		Car car = this.getById(id);
		car.setQrCode("03#" + car.getQrCode());
		List<CarProperty> carPropertyList = iCarPropertyService.list(new QueryWrapper<CarProperty>().eq("car_id", id));
		for (CarProperty carProperty : carPropertyList) {
			EquipmentIndex perfQuota = equipmentIndexService.getById(carProperty.getEquipmentIndexId());
			if (perfQuota != null) {
				carProperty.setPerfQuotaName(perfQuota.getPerfQuotaName());
				carProperty.setGroupName(perfQuota.getGroupName());
				carProperty.setUnitName(perfQuota.getUnitName());
				carProperty.setNameKey(perfQuota.getPerfQuotaDefinitionId());
			}
		}
		carPropertyList.forEach(x -> {
			if ("state".equals(x.getNameKey())) {
				if (TrueOrFalseEnum.real.value.equals(x.getValue())) {
					x.setValue("是");
				} else {
					x.setValue("否");
				}
			}
			if ("labels".equals(x.getNameKey())) {
				List<String> newLabels = new ArrayList();
				String eqList = x.getValue();
				if (StringUtil.isNotEmpty(eqList)) {
					String regex = "[\\[\\]]";
					eqList = eqList.replaceAll(regex, "").replaceAll("\"", "");
					String strings[] = eqList.split(",");
					List<String> list = Arrays.asList(strings);
					for (String str : list) {
						EquipmentSpecificVo equipmentSpecific = equipmentSpecificMapper.getEquipmentNameByIotCode(str);
						if (null != equipmentSpecific) {
							newLabels.add(equipmentSpecific.getName());
						}
					}
					String newLabelValue = "";
					if (newLabels.size() > 0) {
						newLabelValue = newLabels.toString().replaceAll(regex, "");
					}
					x.setValue(newLabelValue);
				}
			}
			if (!StringUtil.isNotEmpty(x.getGroupName())) {
				x.setGroupName("其他");
			}
		});
		car.setCarPropertyList(carPropertyList);

		ManufacturerInfo manufacturerInfo = iManufacturerInfoService.getById(car.getManufacturerId());
		manufacturerInfo.setImg(manufacturerInfo.getImg());
		car.setManufacturerInfo(manufacturerInfo);
		car.setImg(getCarFileList(id, FileTypeEnum.image.toString()));
		car.setVideo(getCarFileList(id, FileTypeEnum.video.toString()));
		car.setCertification(getCarFileList(id, FileTypeEnum.certificate.toString()));
		car.setInstruction(getCarFileList(id, FileTypeEnum.instruction.toString()));
		Equipment equipment = iEquipmentService.getById(car.getEquipmentId());
		if (!ObjectUtils.isEmpty(equipment.getCategoryId())) {
			equipment.setEquipmentCategory(equipmentCategoryMapper.selectById(equipment.getCategoryId()));
		}
		car.setEquipment(equipment);
		if (car.getCountry() != null) {
			car.setCountryName(
					iSystemDicService.getOne(new QueryWrapper<SystemDic>().eq("id", car.getCountry())).getName());
		}
		if (!ObjectUtils.isEmpty(car.getChassisCountry())) {
			car.setChassisCountryName(iSystemDicService
					.getOne(new QueryWrapper<SystemDic>().eq("id", car.getChassisCountry())).getName());
		}
		car.setJournals(
				journalService.list(new QueryWrapper<Journal>().eq("car_id", car.getId()).orderByAsc("create_date")));
		car.setEquipmentsOnCar(this.baseMapper.selectEquipmentOnCarAppList(car.getId()));
		List<Equipment> equipment1 = iEquipmentService.listByCategoryId(equipment.getCategoryId());
		car.setUnit(equipment1.get(0).getUnit());
		car.setCategoryId(equipment.getCategoryId());
		if (car.getIsImport() != null) {
			car.setImportStr(car.getIsImport() ? "进口" : "国产");
		}

		if (!ObjectUtils.isEmpty(car.getIotCode())) {
			Double monthTravel = 0.0;
			Double totalTravel = 0.0;
			String currentYearAndMonth = DateUtil.format(new Date(), "yyyy-MM");
			LambdaQueryWrapper<WlCarMileage> wrapper = new LambdaQueryWrapper<WlCarMileage>();
			wrapper.eq(WlCarMileage::getIotCode, car.getIotCode());
			wrapper.ge(WlCarMileage::getTravel, 0.5);
			wrapper.isNotNull(WlCarMileage::getEndTime);
			wrapper.isNotNull(WlCarMileage::getStartTime);
//            .ge("travel", 0.5)
			List<WlCarMileage> list = iWlCarMileageService.list(wrapper);
			for (WlCarMileage wl : list) {
				// 判断当前车辆全程是否异常,如果时速小于阈值 则对数据进行返回 否则不予返回
				if (!ObjectUtils.isEmpty(wl.getTakeTime()) && !ObjectUtils.isEmpty(wl.getTravel())
						&& ((wl.getTravel() / (wl.getTakeTime() / 3600000.0)) < CAR_MAX_SPEED)) {
					totalTravel += wl.getTravel();
					if (DateUtil.format(wl.getStartTime(), "yyyy-MM").equals(currentYearAndMonth)) {
						monthTravel += wl.getTravel();
					}
				}
			}
			car.setTotalTravel(Double.valueOf(String.format("%.1f", totalTravel)));
			car.setMonthTravel(Double.valueOf(String.format("%.1f", monthTravel)));
			WlCarMileage last = iWlCarMileageService
					.getOne(new LambdaQueryWrapper<WlCarMileage>().eq(WlCarMileage::getIotCode, car.getIotCode())
							.orderByDesc(WlCarMileage::getEndTime).last("limit 1"));
			car.setSpeed(last != null ? last.getEndSpeed() : null);
			// 产品 和 设备 各8位
			if (car.getIotCode().length() >= 16) {
				car.setIotMeasurement(car.getIotCode().substring(0, 8));
				car.setIotDeviceName(car.getIotCode().substring(8, car.getIotCode().length()));
			}
		}
		return car;
	}

	@Override
	public Car getCarDetailById(Long id) {
		Car car = this.getById(id);
		if (car != null) {
			List<CarIndexVo> carVoList = this.baseMapper.getCarIndexs(id);
			Map<String, List<CarIndexVo>> map = carVoList.stream().collect(Collectors.groupingBy(vo -> vo.getName()));
			car.setExt(JSONObject.toJSONString(map));
			ManufacturerInfo manufacturerInfo = iManufacturerInfoService.getById(car.getManufacturerId());
			manufacturerInfo.setImg(manufacturerInfo.getImg());
			car.setManufacturerInfo(manufacturerInfo);
			car.setImg(getCarFileList(id, FileTypeEnum.image.toString()));
			Equipment equipment = iEquipmentService.getById(car.getEquipmentId());
			if (!ObjectUtils.isEmpty(equipment.getCategoryId())) {
				equipment.setEquipmentCategory(equipmentCategoryMapper.selectById(equipment.getCategoryId()));
			}
			car.setCarState(CarStatusEnum.getNameByCode(car.getCarState()));
			car.setCountry(iSystemDicService.getByIdforAll(Long.valueOf(car.getCountry())).getName());
			car.setUnitName(iUnitService.getById(equipment.getUnitId()).getName());
			car.setEquipment(equipment);
			car.setFullQrCode("03#" + car.getQrCode());
		}
		return car;
	}

	@Override
	public Car getCarDetailByCarNum(String carNum, String orgCode) {
		QueryWrapper<Car> carQueryWrapper = new QueryWrapper<>();
		carQueryWrapper.eq("car_num", carNum);
		Car car = carMapper.selectOne(carQueryWrapper);

		List<CarIndexVo> carVoList = getCarsInfoByOrgCode(orgCode);
		List<CarProperty> propertyList = new ArrayList<>();
		Map<String, List<CarIndexVo>> map = carVoList.stream().collect(Collectors.groupingBy(vo -> vo.getName()));
		car.setExt(JSONObject.toJSONString(map));
		ManufacturerInfo manufacturerInfo = iManufacturerInfoService.getById(car.getManufacturerId());
		manufacturerInfo.setImg(manufacturerInfo.getImg());
		car.setManufacturerInfo(manufacturerInfo);
		car.setImg(getCarFileList(car.getId(), FileTypeEnum.image.toString()));
		Equipment equipment = iEquipmentService.getById(car.getEquipmentId());
		if (!ObjectUtils.isEmpty(equipment.getCategoryId())) {
			equipment.setEquipmentCategory(equipmentCategoryMapper.selectById(equipment.getCategoryId()));
		}
		car.setEquipment(equipment);
		return car;
	}

	public List<CarIndexVo> getCarsInfoByOrgCode(String orgCode) {
		return carMapper.getCarsInfoByOrgCode(orgCode);
	}

	private List<UploadFile> getCarFileList(Long id, String type) {
		List<UploadFile> list = iUploadFileService.list(new QueryWrapper<UploadFile>().eq("object_id", id)
				.eq("object_type", BillContentEnum.CL.getKey()).eq("file_type", type));
		list.forEach(item -> {
			item.setUrl(item.getUrl());
		});
		return list;
	}

	@Override
	public boolean removeOneByIds(List<Long> idList) {
		iCarPropertyService.remove(new QueryWrapper<CarProperty>().in("car_id", idList));
		boolean b = this.removeByIds(idList);
		if (b && syncSwitch) {
			syncDataService.syncDeletedFireVehicle(idList);
		}
		return b;
	}

	@Override
	public Page<Car> page(Page<Car> pageBean, Car car) {
		List<Car> list = carMapper.page(pageBean.offset(), pageBean.getSize(), car);
		int count = carMapper.count(car);
		pageBean.setRecords(list);
		pageBean.setTotal(count);
		return pageBean;
	}

	@Override
	public List<CarIndexVo> getCarsIotInfo(String orgCode) {
		return carMapper.getCarsIotInfo(orgCode);
	}

	@Override
	public List<EquipStateOnCarVo> getCarEquipmentsById(Long id) {
		List<EquipStateOnCarVo> list = carMapper.getCarEquipmentStateByCarId(id);
		List<EquipStateOnCarVo> result = new ArrayList<>();
		StringBuilder sb = new StringBuilder("equipmentOnCar_");
		if (list.size() > 0) {
			for (EquipStateOnCarVo carVo : list) {
				String key = sb.append(carVo.getIotCode()).toString();
				if (!ObjectUtils.isEmpty(redisUtils.get(key))) {
					carVo.setState(TrueOrFalseEnum.real.value);
				} else {
					carVo.setState(TrueOrFalseEnum.fake.value);
				}
				result.add(carVo);
			}
		}
		return result;
	}

	@Override
	@Transactional
	public Boolean updateCarStatus(List<CarStatusInfoDto> cars) {
		try {
			if (!ValidationUtil.isEmpty(cars)) {
				List<String> carIdList = Lists.transform(cars, CarStatusInfoDto::getSequenceNbr);
				List<Car> carList = carMapper.selectBatchIds(carIdList);
				Map<String, String> carStatusMap = cars.stream()
						.collect(Collectors.toMap(CarStatusInfoDto::getSequenceNbr, CarStatusInfoDto::getStatus));
				carList.forEach(car -> {
					String carStatusCode = carStatusMap.get(car.getId().toString());
					// 可进行更新操作
					if (CarStatusEnum.getEnum(car.getCarState()).getAllowedOp().contains(carStatusCode)) {
						// 更新车辆状态
						car.setCarState(carStatusCode);
					}
				});
				this.updateBatchById(carList);
			}
		} catch (Exception e) {
			throw new RuntimeException("操作失败！");
		}

		return true;
	}

	@Override
	public List<CarDto> getTeamCarList(String sequenceNbr, Long id, Double longitude, Double latitude) {
		List<CarDto> list = carMapper.getTeamCarList(sequenceNbr, id, carState);
		if (!CollectionUtils.isEmpty(list)) {
			if (longitude != null && latitude != null) {
				List<Long> idList = list.stream().map(CarDto::getSequenceNbr).collect(Collectors.toList());
				List<CarPropertyVo> propertyList = getCarPropertyList(idList, null, nameKeys, 1);
				if (!CollectionUtils.isEmpty(propertyList)) {
					list.stream().forEach(x -> {
						List<CarPropertyVo> collect = propertyList.stream()
								.filter(y -> y.getCarId().equals(x.getSequenceNbr())).collect(Collectors.toList());
						final Double[] longitudeVal = { null };
						final Double[] latitudeVal = { null };
						collect.stream().forEach(z -> {
							String nameKey = z.getNameKey();
							String value = z.getValue();
							switch (nameKey) {
							case "FireCar_GDLongitude":
								if (StringUtils.isNotBlank(value)) {
									longitudeVal[0] = Double.parseDouble(value);
									x.setLongitude(String.valueOf(longitudeVal[0]));
								}
								break;
							case "FireCar_GDLatitude":
								if (StringUtils.isNotBlank(value)) {
									latitudeVal[0] = Double.parseDouble(value);
									x.setLatitude(String.valueOf(latitudeVal[0]));
								}
								break;
							}
						});
						if (longitudeVal[0] != null && latitudeVal[0] != null) {
							GlobalCoordinates source = new GlobalCoordinates(longitudeVal[0], latitudeVal[0]);
							GlobalCoordinates target = new GlobalCoordinates(longitude, latitude);
							double distance = new GeodeticCalculator()
									.calculateGeodeticCurve(Ellipsoid.Sphere, source, target).getEllipsoidalDistance();
							BigDecimal decimal = new BigDecimal(distance / 1000);
							x.setDistance(decimal.setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue());
						}
					});
				}
			}
			return list;
		}
		return Lists.newArrayList();
	}

	@Override
	public List<CarPropertyVo> getCarPropertyList(List<Long> idList, Long teamId, String nameKeys, Integer isIot) {
		// 权限处理
		PermissionInterceptorContext.setDataAuthRule(authKey);
		List<CarPropertyVo> list = carMapper.getCarPropertyList(idList, teamId, nameKeys, isIot);
		if (!CollectionUtils.isEmpty(list)) {
			return list;
		}
		return Lists.newArrayList();
	}

	@Override
	public Car querySimpleInfoById(Long carId) {
		return this.getById(carId);
	}

	@Override
	public Object getCarStateInfoByCarNum(String carNum) {
		// TODO Auto-generated method stub
		return carMapper.getCarStateInfoByCarNum(carNum);
	}

	@Override
	public CarForUE4VO getCarDetailByCarNumToThreeDimensional(Long carId, String orgCode) {
		CarForUE4VO carForUE4VO = new CarForUE4VO();
		QueryWrapper<Car> carQueryWrapper = new QueryWrapper<>();
		carQueryWrapper.eq("id", carId);
		Car car = carMapper.selectOne(carQueryWrapper);
		carForUE4VO.setId(carId);
		carForUE4VO.setCarNum(car.getCarNum());
		Equipment equipment = iEquipmentService.getById(car.getEquipmentId());
		if (!ObjectUtils.isEmpty(equipment.getCategoryId())) {
			equipment.setEquipmentCategory(equipmentCategoryMapper.selectById(equipment.getCategoryId()));
		}
		carForUE4VO.setCarType(equipment.getEquipmentCategory().getName());

		// 数据库字段（is_import 0->国产， 1->进口）
		carForUE4VO.setIsImport(
				Boolean.TRUE.equals(car.getIsImport()) ? TrueOrFalseEnum.real.desc : TrueOrFalseEnum.fake.desc);
		carForUE4VO.setBrand(car.getBrand());
		QueryWrapper<SystemDic> countryQueryWrapper = new QueryWrapper<>();
		countryQueryWrapper.eq("id", car.getCountry());
		SystemDic systemDic = iSystemDicService.getBaseMapper().selectOne(countryQueryWrapper);
		carForUE4VO.setCountry(systemDic.getName());
		carForUE4VO.setStandard(car.getStandard());
		ManufacturerInfo manufacturerInfo = iManufacturerInfoService.getById(car.getManufacturerId());
		carForUE4VO.setManufacturerName(manufacturerInfo.getName());
		carForUE4VO.setCccAuth(
				Boolean.TRUE.equals(car.getCccAuth()) ? TrueOrFalseEnum.real.flag : TrueOrFalseEnum.fake.flag);
		QueryWrapper<SystemDic> chassisCountryQueryWrapper = new QueryWrapper<>();
		chassisCountryQueryWrapper.eq("id", car.getChassisCountry());
		SystemDic dic = iSystemDicService.getBaseMapper().selectOne(chassisCountryQueryWrapper);
		carForUE4VO.setChassisCountry(dic.getName());
		carForUE4VO.setChassisBrand(car.getChassisBrand());
		return carForUE4VO;
	}

	@Override
	public Page<CarInfoDto> equipmentCarList(Page<CarInfoDto> pag, Long teamId, String name, String code, Long id,
			Boolean isNo) {

		List<Car> carList = carMapper.equipmentCarList(pag.offset(), pag.getSize(), teamId, name, code, id, isNo);
		int num = carMapper.equipmentCarListcount(teamId, name, code, id, isNo);

		List<Equipment> equipmentList = iEquipmentService.list();
		Map<Long, Equipment> keyMap = equipmentList.stream()
				.collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
		List<EquipmentCategory> categoryList = iEquipmentCategoryService.list();
		Map<Long, String> categoryMap = categoryList.stream()
				.collect(Collectors.toMap(BaseEntity::getId, EquipmentCategory::getName));
		List<UploadFile> fileList = iUploadFileService.list(new LambdaQueryWrapper<UploadFile>()
				.eq(UploadFile::getObjectType, "car").eq(UploadFile::getFileType, "image"));

		// 车载装备
		List<Map<String, Object>> carResourceMapList = this.baseMapper.getCarResourceMapList(null);
		Map<String, List<Map<String, Object>>> carResourceMap = carResourceMapList.stream()
				.collect(Collectors.groupingBy(car -> car.get("carId").toString()));
		List<CarInfoDto> CarInfoDtoList = carList.stream().map(car -> {
			CarInfoDto carInfoVo = new CarInfoDto();
			Bean.copyExistPropertis(car, carInfoVo);
			Equipment equipment = keyMap.get(carInfoVo.getEquipmentId());
			carInfoVo.setCarStateDesc(this.getCarStateDesc(car));
			carInfoVo.setEquipmentName(equipment != null ? equipment.getName() : "");
			carInfoVo.setCategoryId(equipment != null ? equipment.getCategoryId() : null);
			carInfoVo.setCategoryName(categoryMap.get(carInfoVo.getCategoryId()));

			carInfoVo.setImage(fileList.stream().filter(f -> f.getObjectId().equals(car.getId()))
					.map(UploadFile::getUrl).collect(Collectors.toList()));

			if (equipment.getImg() != null) {
				List<String> img = new ArrayList<>();
				img.add(equipment.getImg());
				carInfoVo.setImage(img);
			}

			carInfoVo.setResourceList(carResourceMap.get(car.getId().toString()));
			return carInfoVo;
		}).collect(Collectors.toList());

		pag.setTotal(num);
		pag.setRecords(CarInfoDtoList);
		return pag;
	}

	@Override
	public List<CarFusionDto> getCarFusionList() {
		List<CarFusionDto> carFusionDtos = this.baseMapper.selectCarAndCarProperty();
		return carFusionDtos;
	}

	@Override
	public void refreshStaData() {
		List<Map<String, Object>> result = this.baseMapper.queryCompanyCarStaData();
		result.forEach(m -> redisUtils.set((buildKey(m)), m.get("total"), 86400));
		iotrefreshStaData();
	}

	@Override
	public void iotrefreshStaData() {
		List<Map<String, Object>> result = this.baseMapper.queryCompanyIotStaData();
		result.forEach(m -> redisUtils.set((iotbuildKey(m)), m.get("total"), 86400));

	}

	private String buildKey(Map<String, Object> row) {
		return SourcesStatisticsImpl.PREFIX_CATEGORY_COUNT + row.get("bizOrgCode").toString() + "_"
				+ SourceTypeEnum.CAR.getCode() + "_" + row.get("categoryCode").toString();
	}

	private String iotbuildKey(Map<String, Object> row) {
		return SourcesStatisticsImpl.PREFIX_CATEGORY_COUNT + row.get("bizOrgCode").toString() + "_"
				+ SourceTypeEnum.IOT.getCode() + "_" + row.get("categoryCode").toString();
	}

	@Override
	public IPage getQRCode(Long id) {
		Car car = this.getById(id);
		if (car == null) {
			return null;
		}
		String url = "";
		JSONObject jsonObject = new JSONObject();
		byte[] bytes = QRCodeUtil.generateQRCodeImageByteData(car.getQrCode(), 200);
		InputStream inputStream = new ByteArrayInputStream(bytes);
		try {
			MultipartFile file = new MockMultipartFile(car.getQrCode() + ".jpg", car.getQrCode() + ".jpg",
					ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
			FeignClientResult<Map<String, String>> date = Systemctl.fileStorageClient.updateCommonFileFree(file,
					"jxiop/qrcode");
			if (date != null) {
				Map<String, String> map = date.getResult();
				Iterator<String> it = map.keySet().iterator();
				String urlString = it.next();
				jsonObject.put("fileUrl", urlString);
				jsonObject.put("fileName", car.getQrCode());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		List list = new ArrayList();
		list.add(jsonObject);
		IPage page = new Page(1, 100);
		page.setRecords(list);
		return page;
	}

	@Override
	public List<Car> location(String orgCode) {
		List<Car> list = this.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode));
		return list;
	}

	@Override
	public Map<String, Integer> getCountOfCar(String orgCode) {
		Map<String, Integer> map = new HashMap<>();
		map.put("countofCar", this
				.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode).groupBy(Car::getId)).size());
		return map;
	}

	@Override
	public Map<String, Integer> getCountOfCarBelongCompany(String orgCode) {
		Map<String, Integer> map = new HashMap<>();
		map.put("countofCompany", this
				.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode).groupBy(Car::getBizOrgCode))
				.size());
		return map;
	}

	@Override
	public List<ChartIntegerDto> getCarCategoryInfo(String orgCode) {
		List<ChartIntegerDto> list1 = new ArrayList<>();
		List<EquipmentCategory> list = equipmentCategoryMapper
				.selectList(new QueryWrapper<EquipmentCategory>().isNotNull("parent_id"));
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				ChartIntegerDto chartIntegerDto = new ChartIntegerDto();
				Integer count = carMapper.getCarCategoryCountByCategoryID(list.get(i).getId(), orgCode);
				chartIntegerDto.setName(list.get(i).getName());
				chartIntegerDto.setValue(count);
				list1.add(chartIntegerDto);
			}
		}
		return list1;
	}

	@Override
	public Page<CarEquipStateInfoDto> getCarEquipStateInfo(String keyWord, String orgCode) {
//        BasicTableDataDto basicTableDataDto = new BasicTableDataDto();
//        List<ColModel> colModels = new ArrayList<>();
//        colModels.add(new ColModel("carNum","车牌号"));
//        colModels.add(new ColModel("bizOrgName","所属单位"));
//        colModels.add(new ColModel("equipState","设备状态"));
//        colModels.add(new ColModel("extra2","设备电量"));
		Page<CarEquipStateInfoDto> page = new Page<>();
		List<CarEquipStateInfoDto> result = new ArrayList<>();
		List<Car> list = this.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode));
		if ((!ObjectUtils.isEmpty(keyWord)) && StringUtils.isNotEmpty(keyWord)) {
			list = list.stream().filter(car -> car.getBizOrgName().contains(keyWord)).collect(Collectors.toList());
		}
		list = list.stream().filter(car -> !ObjectUtils.isEmpty(car.getExtra2()))
				.sorted(Comparator.comparing(Car::getExtra2, Comparator.comparingDouble(Double::valueOf)).reversed())
				.collect(Collectors.toList());
		for (int i = 0; i < list.size(); i++) {
			Car car = list.get(i);
			CarEquipStateInfoDto carEquipStateInfoDto = new CarEquipStateInfoDto();
			carEquipStateInfoDto.setCarNum(car.getCarNum());
			carEquipStateInfoDto.setBizOrgName(car.getBizOrgName());
			if (car.getExtra2() != null) {
				carEquipStateInfoDto.setEquipState("开机");
				carEquipStateInfoDto.setExtra2(car.getExtra2() + "%");
			} else {
				carEquipStateInfoDto.setEquipState("关机");
				carEquipStateInfoDto.setExtra2("未上报");
			}
			result.add(carEquipStateInfoDto);
		}
//        List<CarEquipStateInfoDto> list = carMapper.getCarEquipStateInfo();
////        if (list.size() > 0) {
////            list.forEach(carEquipStateInfoDto -> {
////                if (carEquipStateInfoDto.getExtra2() != null) {
////                    carEquipStateInfoDto.setEquipState("开机");
////                    carEquipStateInfoDto.setExtra2(carEquipStateInfoDto.getExtra2() + "%");
////                } else {
////                    carEquipStateInfoDto.setEquipState("关机");
////                    carEquipStateInfoDto.setExtra2("未上报");
////                }
////            });
////        }
		page.setRecords(result);
		page.setTotal(list.size());
		page.setCurrent(1);
		page.setSize(10);
//        page.setPagination(true);
//        page.setTotal((list.size()/page.getPageSize()));
//        basicTableDataDto.setDataGridMock(page);
//        basicTableDataDto.setColModel(colModels);
		return page;
	}

	@Override
	public Page<CarEquipAlarmInfoDto> getCarEquipAlarmInfoDto(String keyWord, String orgCode) {
		Page<CarEquipAlarmInfoDto> page = new Page<>();
		List<Car> list = this.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode)).stream()
				.filter(car -> Integer.valueOf(car.getExtra2()) < carEquipAlarmBatteryNumber)
				.collect(Collectors.toList());
		if (StringUtils.isNotEmpty(keyWord)) {
			list = list.stream().filter(car -> car.getBizOrgName().contains(keyWord)).collect(Collectors.toList());
		}
		List<CarEquipAlarmInfoDto> carEquipAlarmInfoDtoList = new ArrayList<>();
		for (int i = 0; i < list.size(); i++) {
			CarEquipAlarmInfoDto carEquipAlarmInfoDto = new CarEquipAlarmInfoDto();
			carEquipAlarmInfoDto.setCarNum(list.get(i).getCarNum());
			carEquipAlarmInfoDto.setNo(i + 1);
			carEquipAlarmInfoDto.setAlarmMessage("该设备电量低于" + carEquipAlarmBatteryNumber + "%!");
			carEquipAlarmInfoDtoList.add(carEquipAlarmInfoDto);
		}
		page.setRecords(carEquipAlarmInfoDtoList);
		page.setTotal(list.size());
		page.setCurrent(1);
		page.setSize(10);
		return page;
	}

	@Override
	public List<ChartIntegerDto> getCarBelongAreaInfo(String orgCode) {
		List<ChartIntegerDto> list = new ArrayList<>();
		FeignClientResult<java.util.Collection<CompanyModel>> de = Privilege.companyClient.queryAgencyTree(null);
		// 如果是公司则获取所有片区
		CompanyModel[] companyModelList = de.getResult().toArray(new CompanyModel[0]);
		if (companyModelList.length == 1 && companyModelList[0].getLevel().equals("headquarter")) {
			List<CompanyModel> companyModels = new ArrayList<CompanyModel>(companyModelList[0].getChildren());
			for (int i = 0; i < companyModels.size(); i++) {
				ChartIntegerDto chartIntegerDto = new ChartIntegerDto();
				CompanyModel companyModel1 = JSON.parseObject(JSON.toJSONString(companyModels.get(i)),
						CompanyModel.class);
				Integer count = this.count(new QueryWrapper<Car>().like("biz_org_code", companyModel1.getOrgCode())
						.likeRight("biz_org_code", orgCode));
				chartIntegerDto.setName(companyModel1.getCompanyName());
				chartIntegerDto.setCompanyId(companyModel1.getSequenceNbr());
				chartIntegerDto.setValue(count);
				list.add(chartIntegerDto);
			}
		}
		return list;
	}

	@Override
	public Page<CarAreaInfoDto> getCarAreaInfo(String areaName, String orgCode) {
		Page<CarAreaInfoDto> page = new Page<>();
		List<CarAreaInfoDto> list = new ArrayList<>();
		CompanyModel companyModelArea = Privilege.companyClient.queryByCompanyName(areaName).getResult();
		if (companyModelArea != null) {
			FeignClientResult<java.util.Collection<CompanyModel>> de = Privilege.companyClient
					.querySubAgencyTree(companyModelArea.getSequenceNbr());
			// 如果是公司则获取所有片区
			ArrayList<CompanyModel> companyModels = (ArrayList<CompanyModel>) de.getResult();
			if (companyModels.size() > 0) {
				for (int i = 0; i < companyModels.size(); i++) {
					CompanyModel companyModel = companyModels.get(i);
					CarAreaInfoDto carAreaInfoDto = new CarAreaInfoDto();
					Integer count = this.count(new QueryWrapper<Car>().like("biz_org_code", companyModel.getOrgCode())
							.likeRight("biz_org_code", orgCode));
					carAreaInfoDto.setNo(i + 1);
					carAreaInfoDto.setName(companyModel.getCompanyName());
					carAreaInfoDto.setCountOfCar(count);
					list.add(carAreaInfoDto);
				}
			}
		}
		page.setRecords(list);
		page.setTotal(list.size());
		page.setCurrent(1);
		page.setSize(10);
		return page;
	}

	@Override
	public BasicTableDataDto getCarMileageInfoByMoth(String date, Integer current, Integer pageSize, String keyWord,
			String orgCode) {
		BasicTableDataDto basicTableDataDto = new BasicTableDataDto();
		List<ColModel> colModels = new ArrayList<>();
		colModels.add(new ColModel("carNum", "车牌号"));
		colModels.add(new ColModel("carCode", "编号"));
		colModels.add(new ColModel("bizOrgName", "所属单位"));
		colModels.add(new ColModel("total", "当月里程"));
		List<MileageDto> mileageDtoList = new ArrayList<>();
		List<Car> list = this.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode));
		if (StringUtils.isNotEmpty(keyWord)) {
			list = list.stream().filter(car -> car.getBizOrgName().contains(keyWord)).collect(Collectors.toList());
		}
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				MileageDto mileageDto = new MileageDto();
				Car car = list.get(i);
				Double totalTravel = iWlCarMileageService.getTotalTravelByIotCodeAndDate(date, car.getIotCode());
				mileageDto.setCarNum(car.getCarNum());
				mileageDto.setCarCode(car.getRemark());
				mileageDto.setBizOrgName(car.getBizOrgName());
				mileageDto.setIotCode(date + "::" + car.getIotCode());
				if (totalTravel != null) {
//                    mileageDto.setTotalTravel((totalTravel / carMaxTravel) * 100);
					mileageDto.setTotalTravel(totalTravel);
				} else {
					totalTravel = 0.0;
					mileageDto.setTotalTravel(totalTravel);
				}
				mileageDto.setTotal(String.format("%.1f", totalTravel) + "KM");
				mileageDtoList.add(mileageDto);
			}
		}
		mileageDtoList = mileageDtoList.stream().sorted(Comparator.comparing(MileageDto::getTotalTravel).reversed())
				.collect(Collectors.toList());
		Integer from = (current - 1) * pageSize > mileageDtoList.size() ? mileageDtoList.size()
				: (current - 1) * pageSize;
		Integer to = current * pageSize > mileageDtoList.size() ? mileageDtoList.size() : current * pageSize;
		DataGridMock mypageDto = new DataGridMock(current, mileageDtoList.size(), true, current,
				mileageDtoList.subList(from, to));
		basicTableDataDto.setDataGridMock(mypageDto);
		basicTableDataDto.setColModel(colModels);
		return basicTableDataDto;
	}

	@Override
	public List<CarExportDto> exportCarMileageInfoByMoth(String date, String keyWord, String orgCode) {
		List<CarExportDto> carExportDtos = new ArrayList<>();
		List<Car> list = this.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode));
		if (StringUtils.isNotEmpty(keyWord)) {
			list = list.stream().filter(car -> car.getBizOrgName().contains(keyWord)).collect(Collectors.toList());
		}
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				CarExportDto carExportDto = new CarExportDto();
				Car car = list.get(i);
				Double totalTravel = iWlCarMileageService.getTotalTravelByIotCodeAndDate(date, car.getIotCode());
				carExportDto.setCode(car.getRemark());
				carExportDto.setCarNumber(car.getCarNum());
				carExportDto.setDriver(car.getDriver());
				carExportDto.setPhone(car.getPhone());
				carExportDto.setOrgName(car.getBizOrgName());
				carExportDto.setStandard(car.getStandard());
				carExportDto.setDisplacement(car.getDisplacement());
				if (totalTravel != null) {
					carExportDto.setTotalTravel(String.format("%.1f", totalTravel) + "KM");
					carExportDto.setTotalTravelValue(String.format("%.1f", totalTravel));
				} else {
					carExportDto.setTotalTravel("0KM");
					carExportDto.setTotalTravelValue("0.0");
				}
				carExportDtos.add(carExportDto);
			}
		}
		Collections.sort(carExportDtos, (e1, e2) -> Double.valueOf(e2.getTotalTravelValue())
				.compareTo(Double.valueOf(e1.getTotalTravelValue())));
		return carExportDtos;
	}

	@Override
	public ZZChartsDto getCarMileageInfoByMothOFDay(String iotCode) {
		ZZChartsDto zzChartsDto = new ZZChartsDto();
		// X轴数据
		List<String> x = new ArrayList<>();
		// Y轴数据
		List<Double> y = new ArrayList<>();
		String[] datas = iotCode.split("::");
		TreeMap<String, Double> map = new TreeMap<>();
		String[] dates = datas[0].split("-");
		Calendar calendar = Calendar.getInstance(Locale.CHINA);
		calendar.set(Calendar.YEAR, Integer.parseInt(dates[0]));
		calendar.set(Calendar.MONTH, Integer.parseInt(dates[1]));
		for (int i = 0; i < calendar.getActualMaximum(Calendar.DATE); i++) {
			String dateStr = i < 9 ? dates[1] + "-0" + (i + 1) : dates[1] + "-" + (i + 1);
			Double totalTravel = iWlCarMileageService.getTotalTravelByIotCodeAndDate(dateStr, datas[1]);
			if (totalTravel == null) {
				totalTravel = 0.0;
			}
			x.add(dateStr);
			y.add(totalTravel);
		}
		zzChartsDto.setAxisData(x);
		zzChartsDto.setSeriesData(y);
		return zzChartsDto;
	}

	@Override
	public Page<CarExceptionDto> getCarExcepitonTrack(Integer type, String keyWord, String orgCode) {
		Page<CarExceptionDto> page = new Page<>();
		List<CarExceptionDto> carExceptionDtos = new ArrayList<>();
		LocalDate localDate = LocalDate.now(ZoneId.of("+8"));
		String endDate = localDate.toString();
		String startDate = localDate.plusDays((0 - type)).toString();
		List<Car> list = carMapper.selectList(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode));
		if (StringUtils.isNotEmpty(keyWord)) {
			list = list.stream().filter(car -> car.getBizOrgName().contains(keyWord)).collect(Collectors.toList());
		}
		if (list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				CarExceptionDto carExceptionDto = new CarExceptionDto();
				Car car = list.get(i);
				Double totalTravel = iWlCarMileageService.getTotalTravelByIotCodeAndDateProd(startDate, endDate,
						list.get(i).getIotCode());
				if (totalTravel <= 0.0) {
					carExceptionDto.setCarId(String.valueOf(car.getId()));
					carExceptionDto.setCarNumber(car.getCarNum());
					carExceptionDto.setBelongStation(car.getBizOrgName());
					carExceptionDtos.add(carExceptionDto);
				}
			}
		}
		page.setRecords(carExceptionDtos);
		page.setTotal(carExceptionDtos.size());
		page.setCurrent(1);
		page.setSize(10);
		return page;
	}

	@Override
	public BasicTableDataDto getCarWarningRecord(String keyWord, Integer current, Integer pageSize, String orgCode) {
		BasicTableDataDto basicTableDataDto = new BasicTableDataDto();
		Page<CarSpeedWarningRecord> carSpeedWarningRecordPage = new Page<>();
		List<ColModel> colModels = new ArrayList<>();
		colModels.add(new ColModel("carNum", "车牌号"));
		colModels.add(new ColModel("bizOrgName", "所属单位"));
		colModels.add(new ColModel("waringDate", "超速时间"));
		colModels.add(new ColModel("overSpeed", "超速值（Km/h）"));
		QueryWrapper queryWrapper = new QueryWrapper<CarSpeedWarningRecord>();
		if (StringUtils.isNotEmpty(keyWord)) {
			queryWrapper.like("biz_org_name", keyWord);
		}
		queryWrapper.ge("over_speed_count",5);
		queryWrapper.orderByDesc("waring_date");
		// 过滤车牌
		List<Car> clist = this.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode));
		List<String> carnums = clist.stream().map(i -> i.getCarNum()).collect(Collectors.toList());
		if (carnums.size() > 0) {
			queryWrapper.in("car_num", carnums);
		}
		Integer count = wlCarSpeedWaringRecordMapper.selectCount(queryWrapper);
		queryWrapper.last("limit " + (current - 1) * pageSize + "," +  pageSize);
		List<CarSpeedWarningRecord> list = wlCarSpeedWaringRecordMapper.selectList(queryWrapper);
        Integer totalPage = (count+pageSize-1)/pageSize;
		DataGridMock dataGridMock = new DataGridMock(current,count, true,
				totalPage, list);
		basicTableDataDto.setDataGridMock(dataGridMock);
		basicTableDataDto.setColModel(colModels);
		return basicTableDataDto;
	}

	@Override
	public List<Map<String, String>> getBizOrgName(String orgCode) {
		List<Map<String, String>> result = new ArrayList<>();
		List<Car> cars = this
				.list(new LambdaQueryWrapper<Car>().likeRight(Car::getBizOrgCode, orgCode).groupBy(Car::getBizOrgCode));
		List<String> orgNames = cars.stream().map(car -> car.getBizOrgName()).collect(Collectors.toList());
		Comparator comparator = Collator.getInstance(Locale.CHINA);
		Collections.sort(orgNames, (p1, p2) -> comparator.compare(p1, p2));
		for (int i = 0; i < orgNames.size(); i++) {
			Map<String, String> item = new HashMap<>();
			item.put("text", orgNames.get(i));
			item.put("value", orgNames.get(i));
			result.add(item);
		}
		return result;
	}

	@Override
	public List<Map<String, String>> updateCarStartStatus() {
		return carPropertyMapper.selectIndexByTime(CAR_START_INDEX_KEY);
	}

	@Override
	public void updateCarQrCode(List<Map<String, String>> mapList, String status) {
		if (!CollectionUtils.isEmpty(mapList)) {
			List<String> carIds = mapList.stream().map(m -> m.get("sourceId")).filter(Objects::nonNull)
					.collect(Collectors.toList());
			carMapper.updateStatusByIds(carIds, status);
		}
	}

	class LossParams {
		private Long carId;

		private Long lossStateId;

		private List<ExtinguishantLossRequest> extinguishants;

		private Car car;

		private Map<Long, StockDetail> details;

		private List<ExtinguishantOnCar> extinguishantOnCar;

		/**
		 * 记录明细账id,用户更新搜索
		 */
		private Set<Long> stockDetailIds;

		/**
		 * 损耗单
		 */
		private WastageBill bill;

		public LossParams(Long carId, List<ExtinguishantLossRequest> extinguishants) {
			this.carId = carId;
			this.extinguishants = extinguishants;
			setStockDetailIds(new HashSet<>());
		}

		public StockDetail getDetailById(Long id) {
			return details.get(id);
		}

		public Long getCarId() {
			return carId;
		}

		public void setCarId(Long carId) {
			this.carId = carId;
		}

		public List<ExtinguishantLossRequest> getExtinguishants() {
			return extinguishants;
		}

		public void setExtinguishants(List<ExtinguishantLossRequest> extinguishants) {
			this.extinguishants = extinguishants;
		}

		public Car getCar() {
			return car;
		}

		public void setCar(Car car) {
			this.car = car;
		}

		public Map<Long, StockDetail> getDetails() {
			return details;
		}

		public void setDetails(Map<Long, StockDetail> details) {
			this.details = details;
		}

		public List<ExtinguishantOnCar> getExtinguishantOnCar() {
			return extinguishantOnCar;
		}

		public void setExtinguishantOnCar(List<ExtinguishantOnCar> extinguishantOnCar) {
			this.extinguishantOnCar = extinguishantOnCar;
		}

		public WastageBill getBill() {
			return bill;
		}

		public void setBill(WastageBill bill) {
			this.bill = bill;
		}

		private Double equalLossCountHandler(ExtinguishantOnCar ex, Double lossCount) throws Exception {
			try {
				StockDetail stockDetail = getDetailById(ex.getStockDetailId());
				stockDetail.setStatus(EquipStatusEnum.LOSS.getCode().toString());
				stockDetail.setId(null);
				stockDetailMapper.insert(stockDetail);
				addStockDetailId(stockDetail.getId());
				// 查询库存
				Stock stock = stockMapper.selectById(stockDetail.getStockId());
				stock.setAmount(stock.getAmount() - lossCount);
				stockMapper.updateById(stock);
				// 删除
				extinguishantOnCarMapper.deleteById(ex.getId());
				// 损耗清单详情
				WastageBillDetail detail = new WastageBillDetail();
				detail.setAmount(BigDecimal.valueOf(lossCount));
				detail.setStockDetailId(stockDetail.getId());
				detail.setWastageBillId(bill.getId());
				wastageBillDetailMapper.insert(detail);
				journalMapper.insert(createJournal(ex, stockDetail.getId(), null));
				return 0d;
			} catch (Exception e) {
				throw e;
			}
		}

		private Double greaterThanLossCountHandler(ExtinguishantOnCar ex, Double lossCount) throws Exception {
			try {
				StockDetail stockDetail = getDetailById(ex.getStockDetailId());
				if (stockDetail == null) {
					return 0d;
				}
				stockDetail.setAmount(stockDetail.getAmount() - lossCount);
				stockDetailMapper.updateById(stockDetail);
				addStockDetailId(stockDetail.getId());

				StockDetail stockDetailClone = new StockDetail();
				BeanUtils.copyProperties(stockDetail, stockDetailClone);
				stockDetailClone.setId(null);
				stockDetailClone.setAmount(lossCount);
				stockDetailClone.setStatus(EquipStatusEnum.LOSS.getCode().toString());
				stockDetailMapper.insert(stockDetailClone);
				addStockDetailId(stockDetailClone.getId());
				Stock stock = stockMapper.selectById(stockDetail.getStockId());
				stock.setAmount(stock.getAmount() - lossCount);
				stockMapper.updateById(stock);
				ex.setAmount(ex.getAmount() - lossCount);
				extinguishantOnCarMapper.updateById(ex);

				// 损耗清单详情
				WastageBillDetail detail = new WastageBillDetail();
				detail.setAmount(BigDecimal.valueOf(lossCount));
				detail.setStockDetailId(stockDetailClone.getId());
				detail.setWastageBillId(bill.getId());
				wastageBillDetailMapper.insert(detail);
				journalMapper.insert(createJournal(ex, stockDetailClone.getId(), lossCount));
				return 0d;
			} catch (Exception e) {
				e.printStackTrace();
				throw e;
			}
		}

		public Journal createJournal(ExtinguishantOnCar e, Long stockDetailId, Double amount) {
			Journal journal = new Journal();
			Double lossAmount = (null != amount) ? amount : e.getAmount();
			Long lossStockDetailId = (null != stockDetailId) ? stockDetailId : e.getStockDetailId();
			journal.setAmount(lossAmount);
			journal.setCarId(getCarId());
			journal.setEquipmentDetailId(e.getEquipmentDetailId());
			journal.setUserId(Long.valueOf(getUser().getUserId()));
			// 查询EquipmentDetail
			EquipmentDetail equipmentDetail = equipmentDetailMapper
					.selectById(getDetailById(e.getStockDetailId()).getEquipmentDetailId());
			Equipment equipment = iEquipmentService.getById(equipmentDetail.getEquipmentId());
			Unit unit = unitMapper.selectById(equipment.getUnitId());
			journal.setRemark(String.format("【%s】在车牌号为【%s】的车辆上，损耗了【%.2f】%s【%s】", getUser().getRealName(),
					getCar().getCarNum(), lossAmount, unit.getName(), equipmentDetail.getName()));
			journal.setOrgCode(getCar().getOrgCode());
			journal.setStockDetailId(lossStockDetailId);
			journal.setState(getLossStateId().toString());

			return journal;
		}

		public Set<Long> getStockDetailIds() {
			return stockDetailIds;
		}

		public void setStockDetailIds(Set<Long> stockDetailIds) {
			this.stockDetailIds = stockDetailIds;
		}

		public void addStockDetailId(Long id) {
			stockDetailIds.add(id);
		}

		public Long getLossStateId() {
			return lossStateId;
		}

		public void setLossStateId(Long lossStateId) {
			this.lossStateId = lossStateId;
		}
	}

	class LoadingParams {
		private Long carId;

		private String loadingId;

		private List<ExtinguishantRequeset> extinguishants;

		private Car car;

		private Map<Long, StockDetail> details;

		private Set<Long> stockDetailIds;

		public LoadingParams(Long carId, List<ExtinguishantRequeset> extinguishants) {
			this.carId = carId;
			this.extinguishants = extinguishants;
			setStockDetailIds(new HashSet<>());
		}

		public ExtinguishantOnCar create(ExtinguishantRequeset r, StockDetail detail) {
			ExtinguishantOnCar extinguishantOnCar = new ExtinguishantOnCar();
			extinguishantOnCar.setCarId(carId);
			extinguishantOnCar.setAmount(r.getAmount());
			extinguishantOnCar.setStockDetailId(detail.getId());
			extinguishantOnCar.setEquipmentDetailId(getDetailById(r.getStockDetailId()).getEquipmentDetailId());
			return extinguishantOnCar;
		}

		public Journal createJournal(ExtinguishantRequeset r, Long stockDetailId) {
			// 查询EquipmentDetail
			EquipmentDetail equipmentDetail = equipmentDetailMapper
					.selectById(getDetailById(r.getStockDetailId()).getEquipmentDetailId());
			Equipment equipment = iEquipmentService.getById(equipmentDetail.getEquipmentId());
			Unit unit = unitMapper.selectById(equipment.getUnitId());
			Journal journal = new Journal();
			journal.setAmount(r.getAmount());
			journal.setCarId(getCarId());
			journal.setEquipmentDetailId(getDetailById(r.getStockDetailId()).getEquipmentDetailId());
			journal.setUserId(Long.valueOf(getUser().getUserId()));
			journal.setWarehouseStructureId(getDetailById(r.getStockDetailId()).getWarehouseStructureId());

			journal.setRemark(String.format("【%s】向车牌号为【%s】的车辆上，装载了【%.2f】%s【%s】", getUser().getRealName(),
					getCar().getCarNum(), r.getAmount(), unit.getName(), equipmentDetail.getName()));
			journal.setOrgCode(getCar().getOrgCode());
			journal.setStockDetailId(stockDetailId);
			journal.setState(getLoadingId());

			return journal;
		}

		public StockDetail getDetailById(Long id) {
			return details.get(id);
		}

		public Long getCarId() {
			return carId;
		}

		public void setCarId(Long carId) {
			this.carId = carId;
		}

		public List<ExtinguishantRequeset> getExtinguishants() {
			return extinguishants;
		}

		public void setExtinguishants(List<ExtinguishantRequeset> extinguishants) {
			this.extinguishants = extinguishants;
		}

		public Car getCar() {
			return car;
		}

		public void setCar(Car car) {
			this.car = car;
		}

		public Map<Long, StockDetail> getDetails() {
			return details;
		}

		public void setDetails(Map<Long, StockDetail> details) {
			this.details = details;
		}

		public Set<Long> getStockDetailIds() {
			return stockDetailIds;
		}

		public void setStockDetailIds(Set<Long> stockDetailIds) {
			this.stockDetailIds = stockDetailIds;
		}

		public void addStockDetailId(Long id) {
			stockDetailIds.add(id);
		}

		public String getLoadingId() {
			return loadingId;
		}

		public void setLoadingId(String loadingId) {
			this.loadingId = loadingId;
		}
	}
}
