package com.lqkj.link.module.zone.service; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.lqkj.link.module.authority.domain.UserInfo; import com.lqkj.link.module.authority.repository.UserInfoRepository; import com.lqkj.link.module.bulletin.domain.NoticeInfo; import com.lqkj.link.module.bulletin.repository.NoticeInfoRepository; import com.lqkj.link.module.zone.domain.*; import com.lqkj.link.module.zone.repository.*; import com.lqkj.link.util.AliOSSUtils; import com.lqkj.link.util.PhoneUtils; import com.lqkj.link.util.Unzipper; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.aspectj.weaver.ast.Var; import org.checkerframework.checker.units.qual.A; import org.aspectj.weaver.ast.Var; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.*; import java.util.stream.Collectors; @Service public class ZoneInfoService { private final ZoneInfoRepository zoneInfoRepository; private final UserInfoRepository userInfoRepository; private final GeomInfoRepository geomInfoRepository; private final ModelInfoRepository modelInfoRepository; @Autowired private AliOSSUtils aliOSSUtils; private static final Long ONEDAY = 24 * 60 * 60 * 1000L; @Autowired private LikesInfoRepository likesInfoRepository; @Autowired private NoticeInfoRepository noticeInfoRepository; @Autowired private ShareInfoRepository shareInfoRepository; public ZoneInfoService(ZoneInfoRepository zoneInfoRepository, UserInfoRepository userInfoRepository, GeomInfoRepository geomInfoRepository, ModelInfoRepository modelInfoRepository) { this.zoneInfoRepository = zoneInfoRepository; this.userInfoRepository = userInfoRepository; this.geomInfoRepository = geomInfoRepository; this.modelInfoRepository = modelInfoRepository; } public Page pageQueryTemplate(String zoneName, Integer page, Integer pageSize) { Pageable pageable = PageRequest.of(page, pageSize); return zoneInfoRepository.pageQueryTemplate(zoneName, pageable); } @Transactional public Map saveTemplate(ZoneInfo zoneInfo) { Map result = new HashMap<>(); if ((zoneInfo.getZoneId() != null && zoneInfoRepository.hasSameTemplateNameWithoutOne(zoneInfo.getZoneName(), zoneInfo.getZoneId())) || (zoneInfo.getZoneId() == null && zoneInfoRepository.hasSameTemplateName(zoneInfo.getZoneName()))) { result.put("msg", "模板名称不能重复!"); return result; } zoneInfo.setUpdateTime(new Date()); boolean isUpdated = true; if (zoneInfo.getZoneId() == null) { zoneInfo.setShareCount(0); zoneInfo.setViewCount(0); zoneInfo.setTemplateUse(0); }else { ZoneInfo oldZoneInfo = zoneInfoRepository.findById(zoneInfo.getZoneId()).get(); isUpdated = !oldZoneInfo.getTemplateFilePath().equals(zoneInfo.getTemplateFilePath()); } ZoneInfo zoneInfo1 = zoneInfoRepository.save(zoneInfo); if (StringUtils.isNotBlank(zoneInfo.getTemplateFilePath()) && isUpdated) { // 清除元素与模型 geomInfoRepository.deleteAllByZoneId(zoneInfo1.getZoneId()); modelInfoRepository.deleteAllByTemplateIds(Collections.singletonList(zoneInfo1.getZoneId())); // 解压压缩文件 // 文件目录格式: // --geom.json // --models // ----model1.fbx 模型1文件 // ----model2.fbx 模型2文件 // ----model1.json 模型1材质 // ----model2.json 模型2材质 // // geom.json文件总json格式: // { // "init": { // "rotation": { // "x": 0, // "y": 0, // "z": 0, // "w": 0 // }, // "translation": { // "x": 0, // "y": 0, // "z": 0 // }, // "scale3D": { // "x": 0, // "y": 0, // "z": 0 // } // }, // "models": [ // { // "modelPath": "model1.fbx", // "location": [ // { // "rotation": { // "x": 0, // "y": 0, // "z": 0, // "w": 0 // }, // "translation": { // "x": 0, // "y": 0, // "z": 0 // }, // "scale3D": { // "x": 0, // "y": 0, // "z": 0 // } // } // ] // } // ] // } String geomJsonString = null; try { Unzipper.unZipFiles(new File("." + zoneInfo.getTemplateFilePath()), "./upload/template/" + zoneInfo1.getZoneId() + "/"); geomJsonString = Files.readString(Paths.get("./upload/template/" + zoneInfo1.getZoneId() + "/geom.json")); } catch (IOException e) { modelInfoRepository.deleteAllByTemplateIds(Collections.singletonList(zoneInfo1.getZoneId())); zoneInfoRepository.delete(zoneInfo1); result.put("msg", "模板压缩文件解压失败!"); return result; } TemplateGeom templateGeom = JSON.parseObject(geomJsonString, TemplateGeom.class); zoneInfo1.setInitLocation(templateGeom.getInit()); zoneInfoRepository.save(zoneInfo1); List templateInfoList = templateGeom.getModels(); List list = new ArrayList<>(); if (zoneInfo1.getTypeNumber() == 1){ String modelFolderPath = "./upload/template/" + zoneInfo1.getZoneId() + "/models"; File modelFolder = new File(modelFolderPath); File[] models = modelFolder.listFiles(); assert models != null; for (File model : models) { if (model.isFile()) { String modelFileName = model.getName(); if (modelFileName.endsWith(".fbx")) { String modelPath = aliOSSUtils.upload(model); list.add(new ModelInfo(null, null, modelFileName.substring(0, modelFileName.lastIndexOf(".")).toLowerCase(), null, null, null, modelPath, zoneInfo1.getThumbnail(), null, zoneInfo1.getZoneId(), 1)); } } } }else { String directoryPath = "./upload/template/" + zoneInfo1.getZoneId(); File directory = new File(directoryPath); // 获取目录下的所有文件 File[] files = directory.listFiles((dir, name) -> name.endsWith(".pak")); assert files != null; String pakPath = aliOSSUtils.upload(files[0]); zoneInfo1.setPakPath(pakPath); zoneInfoRepository.save(zoneInfo1); for (TemplateInfo templateInfo : templateInfoList) { list.add(new ModelInfo(null, null, templateInfo.getModelPath().substring(templateInfo.getModelPath().lastIndexOf(".") + 1), null, null, null, templateInfo.getModelPath(), zoneInfo1.getThumbnail(), null, zoneInfo1.getZoneId(), 2)); } } List modelInfoList = modelInfoRepository.saveAll(list); Map modelPathIdMap = modelInfoList .stream() .collect(Collectors.toMap(ModelInfo::getOriginalPath, ModelInfo -> ModelInfo)); List geomInfoList = new ArrayList<>(); GeometryFactory geometryFactory = new GeometryFactory(); int j = 1; for (TemplateInfo templateInfo : templateInfoList) { String modelName = templateInfo.getModelPath(); ModelInfo modelInfo = modelPathIdMap.get(modelName); for (int i = 0; i < templateInfo.getLocation().size(); i++) { JSONObject trans = templateInfo.getLocation().get(i); GeomInfo geomInfo = new GeomInfo(); geomInfo.setGeomId(zoneInfo1.getZoneId() + "_" + j); geomInfo.setModelId(modelInfo.getModelId()); geomInfo.setGeomName(modelInfo.getModelName()); geomInfo.setZoneId(zoneInfo1.getZoneId()); geomInfo.setLocking(false); geomInfo.setTrans(trans); JSONObject pointObject = trans.getJSONObject("translation"); geomInfo.setGeom(geometryFactory.createPoint(new Coordinate( Double.parseDouble(pointObject.get("x").toString()), Double.parseDouble(pointObject.get("y").toString()), Double.parseDouble(pointObject.get("z").toString())))); j++; geomInfoList.add(geomInfo); } } geomInfoRepository.saveAll(geomInfoList); } result.put("zone", zoneInfo1); return result; } @Transactional public void deleteTemplate(List zoneIds) { zoneInfoRepository.deleteAllByIdInBatch(zoneIds); modelInfoRepository.deleteAllByTemplateIds(zoneIds); } public List autoCompleteMyWork(String userCode, String keyword) { return zoneInfoRepository .autoCompleteMyWork(userCode, keyword) .stream() .map(v -> (String) v.get("name")) .toList(); } public List autoCompleteResource(String keyword, Integer searchType) { return zoneInfoRepository .autoCompleteResource(keyword, searchType) .stream() .map(v -> (String) v.get("name")) .toList(); } public List autoCompleteAudit(String keyword, Integer searchType) { return zoneInfoRepository .autoCompleteAudit(keyword, searchType) .stream() .map(v -> (String) v.get("name")) .toList(); } public Page myWork(String userCode, String name, Integer page, Integer pageSize) { Pageable pageable = PageRequest.of(page, pageSize); return zoneInfoRepository.pageQueryMyWork(userCode, name, pageable); } public Page> resourceCenter(String name, Integer searchType, Integer page, Integer pageSize, Integer orderType, String userCode) { Pageable pageable = PageRequest.of(page, pageSize); Page> maps = zoneInfoRepository.pageQueryResourceCenter(name, searchType, pageable, orderType); List> result = new ArrayList<>(); maps.getContent().forEach(map -> { Integer zoneId = (Integer) map.get("zoneId"); UserInfo userInfo = userInfoRepository.findByUserCode(userCode); boolean isLiked = likesInfoRepository.isLiked(zoneId, userInfo.getUserId()); HashMap zoneInfo = new HashMap<>(map); if (isLiked) { zoneInfo.put("isLiked", true); } else { zoneInfo.put("isLiked", false); } result.add(zoneInfo); }); return new PageImpl<>(result, PageRequest.of(page, pageSize), maps.getTotalElements()); } public Page> auditCenter(String name, Integer searchType, Integer page, Integer pageSize) { Pageable pageable = PageRequest.of(page, pageSize); return zoneInfoRepository.auditCenter(name, searchType, pageable); } @Transactional public String share(Integer zoneId, String userCode, String shareUserCode, Integer shareType) { UserInfo shareUserInfo = userInfoRepository.findByUserCode(shareUserCode); if (Objects.isNull(shareUserInfo)) throw new RuntimeException("未能找到与该手机号码相关的账户,请确认号码无误"); String shareCode = UUID.randomUUID().toString(); List shareInfoList = shareInfoRepository.findByZoneIdAndSharedUserId(zoneId, shareUserInfo.getUserId()); if (shareInfoList.size() > 0 && (shareTime(shareInfoList.get(0)) > System.currentTimeMillis())) throw new RuntimeException("该账户已分享过该作品"); else if (shareInfoList.size() > 0 && (shareTime(shareInfoList.get(0)) < System.currentTimeMillis())) { shareInfoRepository.updateShareTime(zoneId, shareUserInfo.getUserId(), shareType); }else { zoneInfoRepository.share(zoneId, userCode, shareCode, shareUserInfo.getUserId(), shareType); } UserInfo userInfo = userInfoRepository.findByUserCode(userCode); NoticeInfo noticeInfo = new NoticeInfo(); noticeInfo.setUserId(shareUserInfo.getUserId()); noticeInfo.setType(4); noticeInfo.setContent(PhoneUtils.encryptPhoneNumber(userInfo.getUserCode()) + "邀请你参加作品协作,与他(她)共建场景。"); noticeInfo.setHasView(false); noticeInfo.setCreateTime(new Date()); noticeInfo.setZoneId(zoneId); noticeInfoRepository.save(noticeInfo); return shareCode; } private Long shareTime(ShareInfo shareInfo){ return shareInfo.getShareTime().getTime() + shareInfo.getCanUse() * ONEDAY; } @Transactional public void view(Integer zoneId, String userCode) { zoneInfoRepository.view(zoneId, userCode); } @Transactional public String rename(Integer zoneId, String newName, String userCode) { if (zoneInfoRepository.hasSameNameWithUser(newName, userCode, zoneId)) { return "不能与已有作品重名!"; } zoneInfoRepository.rename(newName, zoneId); return null; } @Transactional public String deleteWork(Integer zoneId, String userCode) { if(!zoneInfoRepository.existsById(zoneId)){ return "该作品不存在!"; } if (!zoneInfoRepository.isAuthor(zoneId, userCode)) { return "您不是该作品的作者!"; } if (!zoneInfoRepository.canBeDeleteWithAuthStatus(zoneId)) { return "不能删除正在审核的作品!"; } notifySharer(zoneId); shareInfoRepository.deleteByZoneId(zoneId); zoneInfoRepository.deleteById(zoneId); return null; } /** * 通知分享者 * @param zoneId */ private void notifySharer(Integer zoneId) { List noticeInfos = new ArrayList<>(); ZoneInfo zoneInfo = zoneInfoRepository.findById(zoneId).get(); shareInfoRepository.findByZoneId(zoneId).forEach(shareInfo -> { NoticeInfo noticeInfo = new NoticeInfo(); noticeInfo.setUserId(shareInfo.getSharedUserId()); noticeInfo.setType(6); noticeInfo.setContent("经决定对" + zoneInfo.getZoneName() + "团队进行调整。很遗憾地通知您,您将不再作为该项目的协作者。我们感谢您到目前为止的贡献。"); noticeInfo.setHasView(false); noticeInfo.setCreateTime(new Date()); noticeInfo.setZoneId(zoneId); noticeInfos.add(noticeInfo); }); noticeInfoRepository.saveAll(noticeInfos); } @Transactional public Map create(String name, Integer templateId, String userCode) { Map result = new HashMap<>(); UserInfo userInfo = userInfoRepository.findByUserCode(userCode); if (zoneInfoRepository.existsByZoneNameAndUserId(name, userInfo.getUserId())) { result.put("msg", "不能与已有作品重名!"); return result; } ZoneInfo template = null; if (templateId != null) { template = zoneInfoRepository.findById(templateId).get(); } ZoneInfo zoneInfo = new ZoneInfo(null, userInfo.getUserId(), name, template == null ? new JSONObject(JSON.parseObject("{\"rotation\":{\"x\":0,\"y\":0.4383658766746521,\"z\":0,\"w\":0.8987966179847717},\"translation\":{\"x\":-820.947265625,\"y\":0,\"z\":955.6719360351563},\"scale3D\":{\"x\":1,\"y\":1,\"z\":1}}")) : template.getInitLocation(), template == null ? null : template.getThumbnail(), 0, new Date(), 0, 0, null, null, 0,0, null, template == null ? 1 : template.getTypeNumber(), template == null ? null : template.getPakPath()); ZoneInfo newInfo = zoneInfoRepository.save(zoneInfo); GeometryFactory geometryFactory = new GeometryFactory(); if (templateId != null) { if (geomInfoRepository.hasGeom(templateId)) { List geomInfoList = geomInfoRepository.findAllByZoneId(templateId); List list = new ArrayList<>(); for (GeomInfo geomInfo : geomInfoList) { String geomId = geomInfo.getGeomId(); String newId = newInfo.getZoneId() + "_" + geomId.split("_")[1]; GeomInfo newGeom = JSON.parseObject(JSON.toJSONString(geomInfo), GeomInfo.class); newGeom.setGeomId(newId); newGeom.setZoneId(newInfo.getZoneId()); newGeom.setTrans(geomInfo.getLocation()); JSONObject pointObject = geomInfo.getLocation().getJSONObject("translation"); newGeom.setGeom(geometryFactory.createPoint(new Coordinate( Double.parseDouble(pointObject.get("x").toString()), Double.parseDouble(pointObject.get("y").toString()), Double.parseDouble(pointObject.get("z").toString())))); newGeom.setLocking(false); list.add(newGeom); } geomInfoRepository.saveAll(list); } // 模板使用次数+1 zoneInfoRepository.addTemplateUse(templateId); }else { GeomInfo geomInfo = new GeomInfo(); geomInfo.setZoneId(newInfo.getZoneId()); geomInfo.setGeomId(newInfo.getZoneId() + "_1"); geomInfo.setModelId(10000); geomInfo.setGeomName("地板"); geomInfo.setLocking(false); geomInfo.setTrans(new JSONObject(JSON.parseObject("{\"rotation\":{\"x\":0,\"y\":0,\"z\":0,\"w\":1},\"translation\":{\"x\":0,\"y\":0,\"z\":20},\"scale3D\":{\"x\":1,\"y\":1,\"z\":1}}"))); geomInfo.setGeom(geometryFactory.createPoint(new Coordinate(0, 0, 0))); geomInfo.setTypeNumber(0); geomInfoRepository.save(geomInfo); } result.put("zone", newInfo); return result; } public void saveThumbnail(Integer zoneId, String thumbnailPath) { ZoneInfo zoneInfo = zoneInfoRepository.findById(zoneId).get(); zoneInfo.setThumbnail(thumbnailPath); // zoneInfo.setUpdateTime(new Date()); zoneInfoRepository.save(zoneInfo); } public JSONObject readTrans(Integer zoneId) { return zoneInfoRepository.findById(zoneId).get().getInitLocation(); } /** * 检查分享状态 * @param zoneId * @param userId * @return */ public boolean checkShareStatus(Integer zoneId, Integer userId) { List shareInfos = shareInfoRepository.findByZoneIdAndSharedUserId(zoneId, userId); if (shareInfos.size() < 1) return false; return shareTime(shareInfos.get(0)) > System.currentTimeMillis(); } /** * 获取分享中心数据 * @param name * @param userId * @param page * @param pageSize * @return */ public Page> shareCenter(String name, Integer userId, Integer page, Integer pageSize) { Pageable pageable = PageRequest.of(page, pageSize); Page> maps = zoneInfoRepository.pageQueryshareCenter(name, userId, pageable); List> result = new ArrayList<>(); maps.getContent().forEach(map -> { String update_time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(map.get("update_time")); HashMap resultMap = new HashMap<>(map); resultMap.put("update_time", update_time); result.add(resultMap); }); return new PageImpl<>(result, PageRequest.of(page, pageSize), maps.getTotalElements()); } /** * 分享中心自动补全接口 * @param keyword * @param userId * @return */ public List autoCompleteShare(String keyword, Integer userId) { return zoneInfoRepository.autoCompleteShare(keyword, userId); } /** * 接受分享 * @param zoneId * @param userId */ @Transactional public void acceptShare(Integer zoneId, Integer userId, Boolean acceptStatus) { zoneInfoRepository.acceptShare(zoneId, userId, acceptStatus); if (!acceptStatus) { UserInfo userInfo = userInfoRepository.findById(userId).get(); ShareInfo shareInfo = shareInfoRepository.findByZoneIdAndSharedUserId(zoneId, userId).get(0); NoticeInfo noticeInfo = new NoticeInfo(); noticeInfo.setAcceptStatus(false); noticeInfo.setCreateTime(new Date()); noticeInfo.setHasView(false); noticeInfo.setUserId(shareInfo.getUserId()); noticeInfo.setType(5); noticeInfo.setContent("手机号为" + PhoneUtils.encryptPhoneNumber(userInfo.getUserCode()) + "的用户拒绝参加您的作品协作!"); noticeInfo.setZoneId(zoneId); noticeInfoRepository.save(noticeInfo); } } /** * 查看分享用户 * @param zoneId * @return */ public List> viewShareUser(Integer zoneId) { return userInfoRepository.viewShareUser(zoneId); } public List> getSpawnPointList(Integer zoneId) { List> spawnPointList = zoneInfoRepository.getSpawnPointList(zoneId); ArrayList> maps = new ArrayList<>(); for (Map map : spawnPointList) { HashMap stringObjectHashMap = new HashMap<>(); stringObjectHashMap.put("id", map.get("id")); stringObjectHashMap.put("zone_id", map.get("zone_id")); stringObjectHashMap.put("name", map.get("name")); stringObjectHashMap.put("init_location", JSONObject.parse(map.get("init_location").toString())); maps.add(stringObjectHashMap); } return maps; } public void save(ZoneInfo zoneInfo) { zoneInfoRepository.save(zoneInfo); } public ZoneInfo zoneDetails(Integer zoneId) { return zoneInfoRepository.findById(zoneId).get(); } @Transactional public void updateShareType(Integer zoneId, Integer shareType, Integer sharedUserId) { shareInfoRepository.updateShareType(zoneId, shareType, sharedUserId); } }