AssetService.java 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193
  1. package com.izouma.nineth.service;
  2. import com.google.common.collect.Lists;
  3. import com.google.common.hash.Hashing;
  4. import com.izouma.nineth.TokenHistory;
  5. import com.izouma.nineth.config.Constants;
  6. import com.izouma.nineth.config.GeneralProperties;
  7. import com.izouma.nineth.converter.LongArrayConverter;
  8. import com.izouma.nineth.domain.Collection;
  9. import com.izouma.nineth.domain.*;
  10. import com.izouma.nineth.dto.*;
  11. import com.izouma.nineth.enums.*;
  12. import com.izouma.nineth.exception.BusinessException;
  13. import com.izouma.nineth.repo.*;
  14. import com.izouma.nineth.utils.JpaUtils;
  15. import com.izouma.nineth.utils.SecurityUtils;
  16. import com.izouma.nineth.utils.TokenUtils;
  17. import lombok.AllArgsConstructor;
  18. import lombok.extern.slf4j.Slf4j;
  19. import org.apache.commons.collections.CollectionUtils;
  20. import org.apache.commons.lang3.ObjectUtils;
  21. import org.apache.commons.lang3.RandomStringUtils;
  22. import org.apache.commons.lang3.StringUtils;
  23. import org.apache.rocketmq.spring.core.RocketMQTemplate;
  24. import org.springframework.beans.BeanUtils;
  25. import org.springframework.cache.annotation.Cacheable;
  26. import org.springframework.data.domain.Page;
  27. import org.springframework.data.domain.PageImpl;
  28. import org.springframework.data.domain.PageRequest;
  29. import org.springframework.data.domain.Pageable;
  30. import org.springframework.data.jpa.domain.Specification;
  31. import org.springframework.scheduling.annotation.Async;
  32. import org.springframework.scheduling.annotation.Scheduled;
  33. import org.springframework.security.crypto.password.PasswordEncoder;
  34. import org.springframework.stereotype.Service;
  35. import javax.persistence.criteria.Predicate;
  36. import javax.transaction.Transactional;
  37. import java.math.BigDecimal;
  38. import java.nio.charset.StandardCharsets;
  39. import java.time.Duration;
  40. import java.time.LocalDateTime;
  41. import java.time.format.DateTimeFormatter;
  42. import java.time.temporal.ChronoUnit;
  43. import java.util.*;
  44. import java.util.concurrent.ExecutionException;
  45. import java.util.concurrent.ForkJoinPool;
  46. import java.util.concurrent.atomic.AtomicInteger;
  47. import java.util.stream.Collectors;
  48. @Service
  49. @AllArgsConstructor
  50. @Slf4j
  51. public class AssetService {
  52. private AssetRepo assetRepo;
  53. private UserRepo userRepo;
  54. private CollectionRepo collectionRepo;
  55. private OrderRepo orderRepo;
  56. private TokenHistoryRepo tokenHistoryRepo;
  57. private SysConfigService sysConfigService;
  58. private RocketMQTemplate rocketMQTemplate;
  59. private GeneralProperties generalProperties;
  60. private ShowroomRepo showroomRepo;
  61. private ShowCollectionRepo showCollectionRepo;
  62. private CollectionPrivilegeRepo collectionPrivilegeRepo;
  63. private PasswordEncoder passwordEncoder;
  64. private MintActivityRepo mintActivityRepo;
  65. private DestroyRecordRepo destroyRecordRepo;
  66. private AirDropService airDropService;
  67. private HCChainService hcChainService;
  68. private RockRecordService rockRecordService;
  69. private RockRecordRepo rockRecordRepo;
  70. private AssetLockRepo assetLockRepo;
  71. private UserBalanceService userBalanceService;
  72. private PhotoAssetRepo photoAssetRepo;
  73. private NumberSeqRepo numberSeqRepo;
  74. public Page<Asset> all(PageQuery pageQuery) {
  75. Map<String, Object> query = pageQuery.getQuery();
  76. Specification<Asset> specification = JpaUtils.toSpecification(pageQuery, Asset.class);
  77. PageRequest pageRequest = JpaUtils.toPageRequest(pageQuery);
  78. if (query.containsKey("lock")) {
  79. LocalDateTime now = LocalDateTime.now();
  80. query.remove("lock");
  81. specification = specification.and((Specification<Asset>) (root, criteriaQuery, criteriaBuilder) -> {
  82. List<Predicate> and = new ArrayList<>();
  83. and.add(criteriaBuilder.greaterThan(root.get("lockTo"), now));
  84. return criteriaBuilder.and(and.toArray(new Predicate[0]));
  85. });
  86. }
  87. Page<Asset> all = assetRepo.findAll(specification, pageRequest);
  88. // Map<String, Object> query = pageQuery.getQuery();
  89. // if (query.containsKey("userId")) {
  90. // List<Long> orderId = orderRepo
  91. // .findAllByUserIdAndOpenedFalse(Convert.convert(Long.class, query.get("userId")));
  92. // return all.map(asset -> {
  93. // if (orderId.contains(asset.getOrderId())) {
  94. // asset.setOpened(false);
  95. // }
  96. // return asset;
  97. // });
  98. // }
  99. return new PageWrapper<>(all.getContent(), all.getPageable().getPageNumber(),
  100. all.getPageable().getPageSize(), all.getTotalElements()).toPage();
  101. }
  102. public List<AssetDTO> userSummary(PageQuery pageQuery) {
  103. List<AssetDTO> assetDTOs = new ArrayList<>();
  104. // 根据条件查询所有资产
  105. List<Asset> assets = assetRepo.findAll(JpaUtils.toSpecification(pageQuery, Asset.class));
  106. if (CollectionUtils.isEmpty(assets)) {
  107. return assetDTOs;
  108. }
  109. // 取出资产中未开启盲盒数据
  110. List<Asset> blindBoxClosedAssets = assets.stream()
  111. .filter(asset -> !asset.isOpened() && CollectionType.BLIND_BOX.equals(asset.getType()))
  112. .collect(Collectors.toList());
  113. if (CollectionUtils.isNotEmpty(blindBoxClosedAssets)) {
  114. blindBoxClosedAssets.forEach(asset -> {
  115. assetDTOs.add(AssetDTO.create(Lists.newArrayList(asset)));
  116. });
  117. // 移除资产中未开启盲盒数据
  118. assets.removeAll(blindBoxClosedAssets);
  119. }
  120. // 取出资产中所有未设置prefixName的值
  121. List<Asset> prefixNameIsNullAssets = assets.stream()
  122. .filter(asset -> StringUtils.isBlank(asset.getPrefixName()))
  123. .collect(Collectors.toList());
  124. if (CollectionUtils.isNotEmpty(prefixNameIsNullAssets)) {
  125. prefixNameIsNullAssets.forEach(asset -> {
  126. assetDTOs.add(AssetDTO.create(Lists.newArrayList(asset)));
  127. });
  128. assets.removeAll(prefixNameIsNullAssets);
  129. }
  130. if (CollectionUtils.isNotEmpty(assets)) {
  131. // 取出资产中所有prefixName
  132. List<String> prefixNames = assets.stream()
  133. .map(Asset::getPrefixName)
  134. .distinct()
  135. .collect(Collectors.toList());
  136. // 将资产中相同prefixName归类(除未开启盲盒和未设置prefixName)
  137. prefixNames.forEach(str -> {
  138. List<Asset> collect = assets.stream()
  139. .filter(asset -> str.equals(asset.getPrefixName()))
  140. .collect(Collectors.toList());
  141. assetDTOs.add(AssetDTO.create(collect));
  142. });
  143. }
  144. return assetDTOs;
  145. }
  146. public Asset createAsset(Collection collection, User user, Long orderId, BigDecimal price, String type,
  147. Integer number, boolean safeFlag) {
  148. if (collection.isMessNumber() && number != null) {
  149. number = getMessedNumber(collection.getId(), number, collection.getTotal());
  150. }
  151. Asset asset = Asset.create(collection, user);
  152. asset.setTokenId(TokenUtils.genTokenId());
  153. asset.setNumber(number);
  154. asset.setOasisId(collection.getOasisId());
  155. asset.setOrderId(orderId);
  156. asset.setPrice(price);
  157. asset.setPrefixName(collection.getPrefixName());
  158. asset.setTags(new HashSet<>());
  159. if (collection.getTags() != null) {
  160. asset.getTags().addAll(collection.getTags());
  161. }
  162. User fakeUser = null;
  163. if (safeFlag) {
  164. fakeUser = createFakeUser();
  165. asset.setOwner(fakeUser.getNickname());
  166. asset.setOwnerId(fakeUser.getId());
  167. asset.setOwnerAvatar(fakeUser.getAvatar());
  168. }
  169. assetRepo.saveAndFlush(asset);
  170. tokenHistoryRepo.save(TokenHistory.builder()
  171. .tokenId(asset.getTokenId())
  172. .fromUser(collection.getMinter())
  173. .fromUserId(collection.getMinterId())
  174. .fromAvatar(collection.getMinterAvatar())
  175. .toUser((safeFlag ? fakeUser : user).getNickname())
  176. .toUserId((safeFlag ? fakeUser : user).getId())
  177. .toAvatar((safeFlag ? fakeUser : user).getAvatar())
  178. .operation(type)
  179. .price(price)
  180. .companyId(asset.getCompanyId())
  181. .build());
  182. //绿洲石
  183. rockRecordService.addRock(user.getId(), price, "购买");
  184. rocketMQTemplate.syncSend(generalProperties.getMintTopic(), asset.getId());
  185. if (asset.getOasisId() != null & asset.getSource().equals(AssetSource.OFFICIAL)) {
  186. AirDrop airDrop = new AirDrop();
  187. airDrop.setName("建筑空投展厅");
  188. airDrop.setCollectionId(207012L);
  189. List<Long> userIds = new ArrayList<>();
  190. userIds.add(user.getId());
  191. List<Long> nums = new ArrayList<>();
  192. nums.add(1L);
  193. airDrop.setType(AirDropType.asset);
  194. List<DropTarget> dropTargets = new ArrayList<>();
  195. DropTarget dropTarget = new DropTarget();
  196. dropTarget.setNickname(user.getNickname());
  197. dropTarget.setNum(1);
  198. dropTarget.setPhone(user.getPhone());
  199. dropTarget.setUserId(user.getId());
  200. dropTargets.add(dropTarget);
  201. airDrop.setTargets(dropTargets);
  202. airDrop.setUserIds(userIds);
  203. airDrop.setNum(nums);
  204. airDropService.create(airDrop);
  205. }
  206. return asset;
  207. }
  208. public Asset createAsset(PhotoAsset photoAsset, User user, Long orderId, BigDecimal price, String type,
  209. Integer number, boolean safeFlag) {
  210. Asset asset = Asset.create(photoAsset, user);
  211. asset.setTokenId(TokenUtils.genTokenId());
  212. asset.setNumber(number);
  213. asset.setOrderId(orderId);
  214. asset.setPrice(price);
  215. asset.setPrefixName("星图");
  216. asset.setTags(new HashSet<>());
  217. User fakeUser = null;
  218. if (safeFlag) {
  219. fakeUser = createFakeUser();
  220. asset.setOwner(fakeUser.getNickname());
  221. asset.setOwnerId(fakeUser.getId());
  222. asset.setOwnerAvatar(fakeUser.getAvatar());
  223. }
  224. assetRepo.saveAndFlush(asset);
  225. tokenHistoryRepo.save(TokenHistory.builder()
  226. .tokenId(asset.getTokenId())
  227. .fromUser(photoAsset.getUserName())
  228. .fromUserId(photoAsset.getUserId())
  229. .fromAvatar(photoAsset.getUserAvatar())
  230. .toUser((safeFlag ? fakeUser : user).getNickname())
  231. .toUserId((safeFlag ? fakeUser : user).getId())
  232. .toAvatar((safeFlag ? fakeUser : user).getAvatar())
  233. .operation(type)
  234. .price(price)
  235. .companyId(asset.getCompanyId())
  236. .build());
  237. //绿洲石
  238. // rockRecordService.addRock(user.getId(), price, "购买");
  239. rocketMQTemplate.syncSend(generalProperties.getMintTopic(), asset.getId());
  240. return asset;
  241. }
  242. public synchronized int getMessedNumber(Long collectionId, int number, int total) {
  243. NumberSeq numberSeq = numberSeqRepo.findById(collectionId).orElse(null);
  244. if (numberSeq == null || numberSeq.getTotal() != total) {
  245. numberSeq = new NumberSeq();
  246. numberSeq.setId(collectionId);
  247. numberSeq.setTotal(total);
  248. Map<Integer, Integer> map = new HashMap<>();
  249. for (int i = 0; i < total; i++) {
  250. map.put(i, Hashing.md5().hashString(collectionId + ":" + i, StandardCharsets.UTF_8).asInt());
  251. }
  252. numberSeq.setNumbers(map.entrySet().stream()
  253. .sorted(Map.Entry.comparingByValue())
  254. .map(Map.Entry::getKey)
  255. .collect(Collectors.toList()));
  256. numberSeqRepo.save(numberSeq);
  257. }
  258. return numberSeq.getNumbers().get(number);
  259. }
  260. public Asset createAsset(BlindBoxItem winItem, User user, Long orderId, BigDecimal price, String type,
  261. Integer number, Integer holdDays, boolean safeFlag) {
  262. Collection blindBox = collectionRepo.findDetailById(winItem.getBlindBoxId())
  263. .orElseThrow(new BusinessException("盲盒不存在"));
  264. Collection collection = collectionRepo.findDetailById(winItem.getCollectionId())
  265. .orElseThrow(new BusinessException("藏品不存在"));
  266. if (collection.isMessNumber() && number != null) {
  267. number = getMessedNumber(collection.getId(), number, collection.getTotal());
  268. }
  269. winItem.setCollection(collection);
  270. Asset asset = Asset.create(winItem, user, holdDays);
  271. asset.setTokenId(TokenUtils.genTokenId());
  272. asset.setNumber(number);
  273. asset.setOasisId(winItem.getOasisId());
  274. asset.setOrderId(orderId);
  275. asset.setPrice(price);
  276. asset.setPrefixName(collection.getPrefixName());
  277. asset.setEmpower(collection.getEmpower());
  278. asset.setTags(new HashSet<>());
  279. if (blindBox.getTags() != null) {
  280. asset.getTags().addAll(blindBox.getTags());
  281. }
  282. if (collection.getTags() != null) {
  283. asset.getTags().addAll(collection.getTags());
  284. }
  285. User fakeUser = null;
  286. if (safeFlag) {
  287. fakeUser = createFakeUser();
  288. asset.setOwner(fakeUser.getNickname());
  289. asset.setOwnerId(fakeUser.getId());
  290. asset.setOwnerAvatar(fakeUser.getAvatar());
  291. }
  292. assetRepo.saveAndFlush(asset);
  293. tokenHistoryRepo.save(TokenHistory.builder()
  294. .tokenId(asset.getTokenId())
  295. .fromUser(winItem.getMinter())
  296. .fromUserId(winItem.getMinterId())
  297. .fromAvatar(winItem.getMinterAvatar())
  298. .toUser((safeFlag ? fakeUser : user).getNickname())
  299. .toUserId((safeFlag ? fakeUser : user).getId())
  300. .toAvatar((safeFlag ? fakeUser : user).getAvatar())
  301. .operation(type)
  302. .price(price)
  303. .companyId(asset.getCompanyId())
  304. .build());
  305. //绿洲石
  306. rockRecordService.addRock(user.getId(), price, "购买");
  307. rocketMQTemplate.syncSend(generalProperties.getMintTopic(), asset.getId());
  308. return asset;
  309. }
  310. public void publicShow(Long id) {
  311. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  312. if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
  313. throw new BusinessException("此藏品不属于你");
  314. }
  315. if (asset.getLockTo() != null && asset.getLockTo().isAfter(LocalDateTime.now())) {
  316. throw new BusinessException("已锁仓,不能上架展示");
  317. }
  318. if (asset.isPublicShow()) {
  319. return;
  320. }
  321. if (asset.getStatus() != AssetStatus.NORMAL) {
  322. throw new BusinessException("当前状态不可展示");
  323. }
  324. User owner = asset.isSafeFlag() ?
  325. userRepo.findById(asset.getOwnerId()).orElseThrow(new BusinessException("用户不存在"))
  326. : userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在"));
  327. Collection collection = Collection.builder()
  328. .name(asset.getName())
  329. .pic(asset.getPic())
  330. .minter(asset.getMinter())
  331. .minterId(asset.getMinterId())
  332. .minterAvatar(asset.getMinterAvatar())
  333. .owner(owner.getNickname())
  334. .oasisId(asset.getOasisId())
  335. .ownerId(owner.getId())
  336. .ownerAvatar(owner.getAvatar())
  337. .detail(asset.getDetail())
  338. .type(CollectionType.DEFAULT)
  339. .source(CollectionSource.TRANSFER)
  340. .sale(0)
  341. .stock(1)
  342. .total(1)
  343. .onShelf(true)
  344. .salable(false)
  345. .price(BigDecimal.valueOf(0))
  346. .properties(asset.getProperties())
  347. .canResale(asset.isCanResale())
  348. .royalties(asset.getRoyalties())
  349. .serviceCharge(asset.getServiceCharge())
  350. .assetId(id)
  351. .number(asset.getNumber())
  352. .tags(new HashSet<>())
  353. .prefixName(asset.getPrefixName())
  354. .companyId(asset.getCompanyId())
  355. .build();
  356. if (asset.getTags() != null) {
  357. collection.getTags().addAll(asset.getTags());
  358. }
  359. if (asset.getType().equals(CollectionType.PICTURE)) {
  360. collection.setType(CollectionType.PICTURE);
  361. }
  362. collectionRepo.save(collection);
  363. asset.setPublicShow(true);
  364. asset.setPublicCollectionId(collection.getId());
  365. assetRepo.saveAndFlush(asset);
  366. }
  367. public synchronized void consignment(Long id, BigDecimal price, String tradeCode, boolean safeFlag) {
  368. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  369. if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
  370. throw new BusinessException("此藏品不属于你");
  371. }
  372. if (asset.getType().equals(CollectionType.PICTURE)) {
  373. throw new BusinessException("星图藏品不可寄售");
  374. }
  375. if (asset.getLockTo() != null && asset.getLockTo().isAfter(LocalDateTime.now())) {
  376. throw new BusinessException("已锁仓,不能寄售");
  377. }
  378. int holdDays;
  379. if (asset.getSource() == AssetSource.GIFT) {
  380. LocalDateTime localDateTime = asset.getCreatedAt();
  381. LocalDateTime gift_change_time = LocalDateTime
  382. .parse(sysConfigService.getString("gift_change_time"), DateTimeFormatter
  383. .ofPattern("yyyy-MM-dd HH:mm:ss"));
  384. if (localDateTime.compareTo(gift_change_time) < 0) {
  385. holdDays = 20;
  386. } else {
  387. holdDays = sysConfigService.getInt("gift_days");
  388. }
  389. } else {
  390. if (ObjectUtils.isEmpty(asset.getHoldDays())) {
  391. holdDays = sysConfigService.getInt("hold_days");
  392. } else {
  393. holdDays = asset.getHoldDays();
  394. }
  395. }
  396. if (holdDays == 0 && AssetSource.OFFICIAL.equals(asset.getSource())) {
  397. BigDecimal officialConsignment = sysConfigService.getBigDecimal("OFFICIAL_CONSIGNMENT");
  398. //天转小时
  399. int hour = officialConsignment.multiply(new BigDecimal("24")).intValue();
  400. if (ChronoUnit.HOURS.between(asset.getCreatedAt(), LocalDateTime.now()) < hour) {
  401. throw new BusinessException("需持有满" + hour + "小时后才能寄售上架");
  402. }
  403. }
  404. if (ChronoUnit.DAYS.between(asset.getCreatedAt(), LocalDateTime.now()) < holdDays) {
  405. throw new BusinessException("需持有满" + holdDays + "天才能寄售上架");
  406. }
  407. User owner;
  408. if (safeFlag && !asset.isSafeFlag()) {
  409. owner = createFakeUser();
  410. asset.setOwner(owner.getNickname());
  411. asset.setOwnerId(owner.getId());
  412. asset.setOwnerAvatar(owner.getAvatar());
  413. asset.setSafeFlag(true);
  414. tokenHistoryRepo.findByTokenIdOrderByCreatedAtDesc(asset.getTokenId()).stream()
  415. .filter(t -> t.getToUserId().equals(asset.getUserId())).findFirst()
  416. .ifPresent(tokenHistory -> {
  417. tokenHistory.setToUserId(owner.getId());
  418. tokenHistory.setToUser(owner.getNickname());
  419. tokenHistory.setToAvatar(owner.getAvatar());
  420. tokenHistoryRepo.save(tokenHistory);
  421. });
  422. } else {
  423. owner = asset.isSafeFlag() ?
  424. userRepo.findById(asset.getOwnerId()).orElseThrow(new BusinessException("用户不存在"))
  425. : userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在"));
  426. }
  427. if (!passwordEncoder.matches(tradeCode, userRepo.findTradeCode(asset.getUserId()))) {
  428. throw new BusinessException("交易密码错误");
  429. }
  430. // if (StringUtils.isBlank(owner.getSettleAccountId())) {
  431. // throw new BusinessException("请先绑定银行卡");
  432. // }
  433. if (asset.isConsignment()) {
  434. throw new BusinessException("已寄售,请勿重新操作");
  435. }
  436. if (asset.getStatus() != AssetStatus.NORMAL) {
  437. throw new BusinessException("当前状态不可寄售");
  438. }
  439. if (asset.isPublicShow()) {
  440. cancelPublic(asset);
  441. }
  442. //寄售中的展厅需要先删除展厅
  443. if (CollectionType.SHOWROOM.equals(asset.getType())) {
  444. if (showroomRepo.findByAssetId(id).isPresent()) {
  445. throw new BusinessException("请先删除展厅");
  446. }
  447. }
  448. Collection collection = Collection.builder()
  449. .name(asset.getName())
  450. .pic(asset.getPic())
  451. .minter(asset.getMinter())
  452. .minterId(asset.getMinterId())
  453. .minterAvatar(asset.getMinterAvatar())
  454. .owner(owner.getNickname())
  455. .ownerId(owner.getId())
  456. .oasisId(asset.getOasisId())
  457. .ownerAvatar(owner.getAvatar())
  458. .detail(asset.getDetail())
  459. .type(CollectionType.DEFAULT)
  460. .source(CollectionSource.TRANSFER)
  461. .sale(0)
  462. .stock(1)
  463. .total(1)
  464. .onShelf(true)
  465. .salable(true)
  466. .price(price)
  467. .properties(asset.getProperties())
  468. .canResale(asset.isCanResale())
  469. .royalties(asset.getRoyalties())
  470. .serviceCharge(asset.getServiceCharge())
  471. .assetId(id)
  472. .number(asset.getNumber())
  473. .tags(new HashSet<>())
  474. .prefixName(asset.getPrefixName())
  475. .companyId(asset.getCompanyId())
  476. .build();
  477. if (asset.getTags() != null) {
  478. collection.getTags().addAll(asset.getTags());
  479. }
  480. collectionRepo.save(collection);
  481. asset.setPublicShow(true);
  482. asset.setConsignment(true);
  483. asset.setPublicCollectionId(collection.getId());
  484. asset.setSellPrice(price);
  485. assetRepo.saveAndFlush(asset);
  486. }
  487. public Asset cancelConsignmentAndStore(Long id) {
  488. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  489. if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
  490. throw new BusinessException("此藏品不属于你");
  491. }
  492. if (asset.getStatus() != AssetStatus.NORMAL) {
  493. throw new BusinessException("当前状态不可寄售");
  494. }
  495. if (asset.getPublicCollectionId() != null) {
  496. List<Order> orders = orderRepo.findByCollectionId(asset.getPublicCollectionId());
  497. if (orders.stream().anyMatch(o -> o.getStatus() != OrderStatus.CANCELLED)) {
  498. throw new BusinessException("已有订单不可取消");
  499. }
  500. collectionRepo.findById(asset.getPublicCollectionId())
  501. .ifPresent(collection -> {
  502. collection.setSalable(false);
  503. collection.setOnShelf(false);
  504. collectionRepo.save(collection);
  505. });
  506. }
  507. asset.setConsignment(false);
  508. asset.setPublicShow(false);
  509. asset.setStatus(AssetStatus.DESTROYING);
  510. return assetRepo.saveAndFlush(asset);
  511. }
  512. public void cancelConsignment(Long id) {
  513. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  514. if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
  515. throw new BusinessException("此藏品不属于你");
  516. }
  517. cancelConsignment(asset);
  518. }
  519. public void cancelConsignment(Asset asset) {
  520. if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
  521. throw new BusinessException("此藏品不属于你");
  522. }
  523. if (asset.getPublicCollectionId() != null) {
  524. List<Order> orders = orderRepo.findByCollectionId(asset.getPublicCollectionId());
  525. if (orders.stream().anyMatch(o -> o.getStatus() != OrderStatus.CANCELLED)) {
  526. throw new BusinessException("已有订单不可取消");
  527. }
  528. collectionRepo.findById(asset.getPublicCollectionId())
  529. .ifPresent(collection -> {
  530. collection.setSalable(false);
  531. collectionRepo.save(collection);
  532. });
  533. }
  534. asset.setConsignment(false);
  535. assetRepo.saveAndFlush(asset);
  536. }
  537. public void cancelPublic(Long id) {
  538. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  539. if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
  540. throw new BusinessException("此藏品不属于你");
  541. }
  542. cancelPublic(asset);
  543. }
  544. public void cancelPublic(Asset asset) {
  545. if (!asset.getUserId().equals(SecurityUtils.getAuthenticatedUser().getId())) {
  546. throw new BusinessException("此藏品不属于你");
  547. }
  548. if (!asset.isPublicShow()) {
  549. return;
  550. }
  551. if (asset.isConsignment()) {
  552. cancelConsignment(asset);
  553. }
  554. Collection collection = collectionRepo.findById(asset.getPublicCollectionId())
  555. .orElseThrow(new BusinessException("无展示记录"));
  556. collectionRepo.delete(collection);
  557. // 如果展厅有此藏品
  558. showCollectionRepo.deleteAllByCollectionId(asset.getPublicCollectionId());
  559. asset.setPublicShow(false);
  560. asset.setPublicCollectionId(null);
  561. assetRepo.saveAndFlush(asset);
  562. }
  563. public void usePrivilege(Long assetId, Long privilegeId) {
  564. Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("无记录"));
  565. asset.getPrivileges().stream().filter(p -> p.getId().equals(privilegeId)).forEach(p -> {
  566. if (!p.getName().equals("铸造")) {
  567. p.setOpened(true);
  568. p.setOpenTime(LocalDateTime.now());
  569. p.setOpenedBy(SecurityUtils.getAuthenticatedUser().getId());
  570. }
  571. });
  572. assetRepo.saveAndFlush(asset);
  573. }
  574. public void transfer(Asset asset, BigDecimal price, User toUser, TransferReason reason, Long orderId) {
  575. transfer(asset, price, toUser, reason, orderId, false);
  576. }
  577. private User createFakeUser() {
  578. String name = "0x" + RandomStringUtils.randomAlphabetic(8);
  579. return userRepo.save(User.builder()
  580. .username(name)
  581. .nickname(name)
  582. .avatar(Constants.DEFAULT_AVATAR)
  583. .isPublicShow(true)
  584. .build());
  585. }
  586. public void transfer(Asset asset, BigDecimal price, User toUser, TransferReason reason, Long orderId, boolean safeFlag) {
  587. Objects.requireNonNull(asset, "原藏品不能为空");
  588. Objects.requireNonNull(toUser, "转让人不能为空");
  589. Objects.requireNonNull(reason, "转让原因不能为空");
  590. User newOwner = toUser;
  591. if (safeFlag) {
  592. newOwner = createFakeUser();
  593. }
  594. Asset newAsset = new Asset();
  595. BeanUtils.copyProperties(asset, newAsset);
  596. newAsset.setId(null);
  597. newAsset.setUserId(toUser.getId());
  598. newAsset.setOwner(newOwner.getNickname());
  599. newAsset.setOwnerId(newOwner.getId());
  600. newAsset.setOwnerAvatar(newOwner.getAvatar());
  601. newAsset.setPublicShow(false);
  602. newAsset.setConsignment(false);
  603. newAsset.setPublicCollectionId(null);
  604. newAsset.setStatus(AssetStatus.NORMAL);
  605. newAsset.setPrice(price);
  606. newAsset.setSellPrice(null);
  607. newAsset.setOrderId(orderId);
  608. newAsset.setOasisId(asset.getOasisId());
  609. newAsset.setFromAssetId(asset.getId());
  610. newAsset.setType(CollectionType.DEFAULT);
  611. newAsset.setSource(TransferReason.GIFT == reason ? AssetSource.GIFT : AssetSource.TRANSFER);
  612. newAsset.setTags(new HashSet<>(asset.getTags()));
  613. newAsset.setSafeFlag(safeFlag);
  614. newAsset.setHoldDays(asset.getOldHoldDays());
  615. if (asset.getType().equals(CollectionType.PICTURE)) {
  616. newAsset.setType(CollectionType.PICTURE);
  617. newAsset.setHoldDays(0);
  618. }
  619. Long savedId = assetRepo.saveAndFlush(newAsset).getId();
  620. if (asset.getType().equals(CollectionType.PICTURE)) {
  621. newAsset.setType(CollectionType.PICTURE);
  622. PhotoAsset photoAsset = photoAssetRepo.findFirstByCreateAssetId(asset.getId());
  623. photoAsset.setGifted(true);
  624. photoAsset.setOwnerId(toUser.getId());
  625. photoAsset.setCreateAssetId(savedId);
  626. photoAssetRepo.save(photoAsset);
  627. }
  628. TokenHistory tokenHistory = TokenHistory.builder()
  629. .tokenId(asset.getTokenId())
  630. .fromUser(asset.getOwner())
  631. .fromUserId(asset.getOwnerId())
  632. .fromAvatar(asset.getOwnerAvatar())
  633. .toUser(newOwner.getNickname())
  634. .toUserId(newOwner.getId())
  635. .toAvatar(newOwner.getAvatar())
  636. .operation(reason.getDescription())
  637. .price(TransferReason.GIFT == reason ? null : price)
  638. .companyId(asset.getCompanyId())
  639. .build();
  640. tokenHistoryRepo.save(tokenHistory);
  641. //购买者加绿洲石
  642. if (TransferReason.TRANSFER.equals(reason) || TransferReason.AUCTION.equals(reason)) {
  643. rockRecordService.addRock(newOwner.getId(), price, "购买");
  644. }
  645. asset.setPublicShow(false);
  646. asset.setConsignment(false);
  647. asset.setPublicCollectionId(null);
  648. switch (reason) {
  649. case GIFT:
  650. asset.setStatus(AssetStatus.GIFTED);
  651. break;
  652. case AUCTION:
  653. asset.setStatus(AssetStatus.AUCTIONED);
  654. break;
  655. case TRANSFER:
  656. asset.setStatus(AssetStatus.TRANSFERRED);
  657. }
  658. asset.setOwner(newOwner.getNickname());
  659. asset.setOwnerId(newOwner.getId());
  660. asset.setOwnerAvatar(newOwner.getAvatar());
  661. assetRepo.saveAndFlush(asset);
  662. //vip权限转让
  663. CollectionPrivilege collectionPrivilege = collectionPrivilegeRepo.findByCollectionId(asset.getCollectionId());
  664. if (ObjectUtils.isNotEmpty(collectionPrivilege)) {
  665. if (collectionPrivilege.isVip()) {
  666. //更新vip信息
  667. userRepo.updateVipPurchase(toUser.getId(), 1);
  668. userRepo.updateVipPurchase(asset.getUserId(), 0);
  669. }
  670. }
  671. }
  672. public List<TokenHistory> tokenHistory(String tokenId, Long assetId) {
  673. if (tokenId == null) {
  674. if (assetId == null) return new ArrayList<>();
  675. tokenId = assetRepo.findById(assetId).map(Asset::getTokenId).orElse(null);
  676. }
  677. if (tokenId == null) return new ArrayList<>();
  678. return tokenHistoryRepo.findByTokenIdOrderByCreatedAtDesc(tokenId);
  679. }
  680. public Page<UserHistory> userHistory(Long userId, Long toUserId, Long fromUserId, Pageable pageable) {
  681. Page<TokenHistory> page;
  682. if (ObjectUtils.isNotEmpty(toUserId)) {
  683. page = tokenHistoryRepo.userHistoryTo(userId, toUserId, pageable);
  684. } else if (ObjectUtils.isNotEmpty(fromUserId)) {
  685. page = tokenHistoryRepo.userHistoryFrom(userId, fromUserId, pageable);
  686. } else {
  687. page = tokenHistoryRepo.userHistory(userId, pageable);
  688. }
  689. Set<String> tokenIds = page.stream().map(TokenHistory::getTokenId).collect(Collectors.toSet());
  690. List<Asset> assets = tokenIds.isEmpty() ? new ArrayList<>() : assetRepo.findByTokenIdIn(tokenIds);
  691. return page.map(tokenHistory -> {
  692. UserHistory userHistory = new UserHistory();
  693. BeanUtils.copyProperties(tokenHistory, userHistory);
  694. Optional<Asset> asset = assets.stream().filter(a -> a.getTokenId().equals(tokenHistory.getTokenId()))
  695. .findAny();
  696. userHistory.setAssetName(asset.map(Asset::getName).orElse(null));
  697. userHistory.setPic(asset.map(Asset::getPic).orElse(new ArrayList<>()));
  698. switch (tokenHistory.getOperation()) {
  699. case "出售":
  700. case "转让":
  701. userHistory.setDescription(tokenHistory.getToUserId().equals(userId) ? "作品交易——买入" : "作品交易——售出");
  702. break;
  703. case "转赠":
  704. userHistory.setDescription(tokenHistory.getToUserId().equals(userId) ? "他人赠送" : "作品赠送");
  705. break;
  706. default:
  707. userHistory.setDescription(tokenHistory.getOperation());
  708. }
  709. return userHistory;
  710. });
  711. }
  712. public Page<UserHistory> userHistory(Long userId, PageQuery pageQuery) {
  713. Page<TokenHistory> page = tokenHistoryRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
  714. List<Predicate> and = JpaUtils
  715. .toPredicates(pageQuery, TokenHistory.class, root, criteriaQuery, criteriaBuilder);
  716. Map<String, Object> query = pageQuery.getQuery();
  717. if (ObjectUtils.isEmpty(query.get("toUserId")) && ObjectUtils.isEmpty(query.get("fromUserId"))) {
  718. and.add(criteriaBuilder.or(criteriaBuilder.equal(root.get("toUserId"), userId), criteriaBuilder
  719. .equal(root.get("fromUserId"), userId)));
  720. } else {
  721. if (ObjectUtils.isNotEmpty(query.get("toUserId"))) {
  722. and.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("toUserId"), userId)));
  723. } else {
  724. and.add(criteriaBuilder.and(criteriaBuilder.equal(root.get("fromUserId"), userId)));
  725. }
  726. }
  727. return criteriaBuilder.and(and.toArray(new Predicate[0]));
  728. }), JpaUtils.toPageRequest(pageQuery));
  729. Set<String> tokenIds = page.stream().map(TokenHistory::getTokenId).collect(Collectors.toSet());
  730. List<Asset> assets = tokenIds.isEmpty() ? new ArrayList<>() : assetRepo.findByTokenIdIn(tokenIds);
  731. return page.map(tokenHistory -> {
  732. UserHistory userHistory = new UserHistory();
  733. BeanUtils.copyProperties(tokenHistory, userHistory);
  734. Optional<Asset> asset = assets.stream().filter(a -> a.getTokenId().equals(tokenHistory.getTokenId()))
  735. .findAny();
  736. userHistory.setAssetName(asset.map(Asset::getName).orElse(null));
  737. userHistory.setPic(asset.map(Asset::getPic).orElse(new ArrayList<>()));
  738. switch (tokenHistory.getOperation()) {
  739. case "出售":
  740. case "转让":
  741. userHistory.setDescription(tokenHistory.getToUserId().equals(userId) ? "作品交易——买入" : "作品交易——售出");
  742. break;
  743. case "转赠":
  744. userHistory.setDescription(tokenHistory.getToUserId().equals(userId) ? "他人赠送" : "作品赠送");
  745. break;
  746. default:
  747. userHistory.setDescription(tokenHistory.getOperation());
  748. }
  749. return userHistory;
  750. });
  751. }
  752. public String mint(LocalDateTime time) {
  753. if (time == null) {
  754. time = LocalDateTime.now();
  755. }
  756. for (Asset asset : assetRepo.toMint(time)) {
  757. rocketMQTemplate.syncSend(generalProperties.getMintTopic(), asset.getId());
  758. }
  759. return "ok";
  760. }
  761. @Cacheable(value = "userStat", key = "#userId")
  762. public Map<String, BigDecimal> breakdown(Long userId) {
  763. // List<TokenHistory> page = tokenHistoryRepo.userHistory(userId);
  764. // BigDecimal sale = page.stream()
  765. // .filter(th -> th.getFromUserId().equals(userId) && ObjectUtils.isNotEmpty(th.getPrice()))
  766. // .map(TokenHistory::getPrice)
  767. // .reduce(BigDecimal.ZERO, BigDecimal::add);
  768. // BigDecimal buy = page.stream()
  769. // .filter(th -> th.getToUserId().equals(userId) && ObjectUtils.isNotEmpty(th.getPrice()))
  770. // .map(TokenHistory::getPrice)
  771. // .reduce(BigDecimal.ZERO, BigDecimal::add);
  772. Map<String, BigDecimal> map = new HashMap<>();
  773. map.put("sale", tokenHistoryRepo.userSale(userId));
  774. map.put("buy", rockRecordService.getRock(userId).getRecord());
  775. return map;
  776. }
  777. public void transferCDN() throws ExecutionException, InterruptedException {
  778. ForkJoinPool customThreadPool = new ForkJoinPool(100);
  779. customThreadPool.submit(() -> {
  780. collectionRepo.selectResource().parallelStream().forEach(list -> {
  781. for (int i = 0; i < list.size(); i++) {
  782. list.set(i, replaceCDN(list.get(i)));
  783. }
  784. collectionRepo.updateCDN(Long.parseLong(list.get(0)),
  785. list.get(1),
  786. list.get(2),
  787. list.get(3),
  788. list.get(4),
  789. list.get(5));
  790. });
  791. assetRepo.selectResource().parallelStream().forEach(list -> {
  792. for (int i = 0; i < list.size(); i++) {
  793. list.set(i, replaceCDN(list.get(i)));
  794. }
  795. assetRepo.updateCDN(Long.parseLong(list.get(0)),
  796. list.get(1),
  797. list.get(2),
  798. list.get(3),
  799. list.get(4),
  800. list.get(5));
  801. });
  802. }).get();
  803. }
  804. public String replaceCDN(String url) {
  805. if (url == null) return null;
  806. return url.replaceAll("https://raex-meta\\.oss-cn-shenzhen\\.aliyuncs\\.com",
  807. "https://cdn.raex.vip");
  808. }
  809. // @Scheduled(cron = "0 0 0/1 * * ?")
  810. // public void offTheShelf() {
  811. // LocalDateTime lastTime = LocalDateTime.now().minusHours(120);
  812. // Set<Long> assetIds = collectionRepo
  813. // .findResaleCollectionPriceOver20K(BigDecimal
  814. // .valueOf(20000L), CollectionSource.TRANSFER, lastTime, true);
  815. // assetIds.forEach(this::cancelConsignmentBySystem);
  816. // }
  817. @Scheduled(cron = "0 0 0/1 * * ?")
  818. public void offTheShelfAll() {
  819. LocalDateTime lastTime = LocalDateTime.now().minusDays(10);
  820. Set<Long> assetIds = collectionRepo
  821. .findResaleCollectionOverTime(lastTime);
  822. assetIds.forEach(this::cancelConsignmentBySystem);
  823. }
  824. public void cancelConsignmentBySystem(Long id) {
  825. try {
  826. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  827. if (asset.getPublicCollectionId() != null) {
  828. List<Order> orders = orderRepo.findByCollectionId(asset.getPublicCollectionId());
  829. if (orders.stream().anyMatch(o -> o.getStatus() != OrderStatus.CANCELLED)) {
  830. throw new BusinessException("已有订单不可取消");
  831. }
  832. collectionRepo.findById(asset.getPublicCollectionId())
  833. .ifPresent(collection -> {
  834. collection.setSalable(false);
  835. collectionRepo.save(collection);
  836. });
  837. }
  838. asset.setConsignment(false);
  839. assetRepo.saveAndFlush(asset);
  840. } catch (Exception e) {
  841. log.info("自动下架报错,assetId:" + id);
  842. }
  843. }
  844. // @Cacheable(cacheNames = "fmaa", key = "#userId+'#'+#mintActivityId+'#'+#pageable.hashCode()")
  845. public PageWrapper<Asset> findMintActivityAssetsWrap(Long userId, Long mintActivityId, Long companyId, Pageable pageable) {
  846. return PageWrapper.of(findMintActivityAssets(userId, mintActivityId, companyId, pageable));
  847. }
  848. public Page<Asset> findMintActivityAssets(Long userId, Long mintActivityId, Long companyId, Pageable pageable) {
  849. MintActivity mintActivity = mintActivityRepo.findById(mintActivityId).orElse(null);
  850. if (mintActivity == null) return new PageImpl<>(Collections.emptyList());
  851. return findMintActivityAssetsCommon(userId, companyId, new CommonMatchDTO(mintActivity.getRule(),
  852. mintActivity.isAudit(), mintActivity.getCollectionName()), pageable);
  853. }
  854. public Page<Asset> findMintActivityAssetsCommon(Long userId, Long companyId, CommonMatchDTO commonMatchDTO, Pageable pageable) {
  855. if (!commonMatchDTO.isAudit()) {
  856. Set<Tag> tags = commonMatchDTO.getRule().getTags();
  857. if (tags.isEmpty()) return new PageImpl<>(Collections.emptyList());
  858. return assetRepo.findAll((Specification<Asset>) (root, query, criteriaBuilder) ->
  859. query.distinct(true).where(
  860. // where userId=some id
  861. criteriaBuilder.equal(root.get("userId"), userId),
  862. // and (lockTo is null or (lockTo is not null and lockTo < now))
  863. criteriaBuilder.or(criteriaBuilder.isNull(root.get("lockTo")),
  864. criteriaBuilder.and(criteriaBuilder.isNotNull(root.get("lockTo")),
  865. criteriaBuilder.lessThan(root.get("lockTo"), LocalDateTime.now()))),
  866. // and status = 'NORMAL'
  867. criteriaBuilder.equal(root.get("status"), AssetStatus.NORMAL),
  868. // and has some tagId
  869. root.join("tags").get("id").in(tags.stream().map(Tag::getId).toArray()))
  870. .getRestriction(), pageable);
  871. } else {
  872. return assetRepo.findByUserIdAndStatusAndCompanyIdAndNameLike(userId, AssetStatus.NORMAL, companyId,
  873. "%" + commonMatchDTO.getCollectionName() + "%", pageable);
  874. }
  875. }
  876. public void destroy(Long id, Long userId, String tradeCode, OperationSource source) {
  877. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  878. if (!asset.getUserId().equals(userId)) {
  879. throw new BusinessException("此藏品不属于你");
  880. }
  881. if (asset.getStatus() != AssetStatus.NORMAL) {
  882. throw new BusinessException("当前状态不可销毁");
  883. }
  884. if (asset.isPublicShow()) {
  885. throw new BusinessException("请先取消公开展示");
  886. // cancelPublic(asset);
  887. }
  888. User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
  889. if (StringUtils.isEmpty(user.getTradeCode())) {
  890. throw new BusinessException("未设置交易密码");
  891. }
  892. if (!passwordEncoder.matches(tradeCode, user.getTradeCode())) {
  893. throw new BusinessException("交易密码错误");
  894. }
  895. User toUser = userRepo.findById(Constants.BLACK_HOLE_USER_ID).orElseThrow(new BusinessException("无记录"));
  896. TokenHistory tokenHistory = TokenHistory.builder()
  897. .tokenId(asset.getTokenId())
  898. .fromUser(asset.getOwner())
  899. .fromUserId(asset.getOwnerId())
  900. .fromAvatar(asset.getOwnerAvatar())
  901. .toUser(toUser.getNickname())
  902. .toUserId(toUser.getId())
  903. .toAvatar(toUser.getAvatar())
  904. .operation(TransferReason.DESTROY.getDescription())
  905. .price(null)
  906. .companyId(asset.getCompanyId())
  907. .build();
  908. tokenHistoryRepo.save(tokenHistory);
  909. asset.setPublicShow(false);
  910. asset.setConsignment(false);
  911. asset.setPublicCollectionId(null);
  912. asset.setStatus(AssetStatus.DESTROYED);
  913. asset.setOwner(toUser.getNickname());
  914. asset.setOwnerId(toUser.getId());
  915. asset.setOwnerAvatar(toUser.getAvatar());
  916. assetRepo.saveAndFlush(asset);
  917. //积分记录
  918. destroyRecordRepo.save(DestroyRecord.builder()
  919. .userId(userId)
  920. .assetId(asset.getId())
  921. .name(asset.getName())
  922. .pic(asset.getPic().get(0).getUrl())
  923. .record(1)
  924. .type(RecordType.OBTAIN)
  925. .companyId(asset.getCompanyId())
  926. .source(source)
  927. .build());
  928. //加积分
  929. userRepo.addDestroyPoint(userId, 1);
  930. }
  931. @Transactional
  932. public void metaDestroyWithoutTradeCode(MetaDestroyParam metaDestroyParam, Long userId, OperationSource source) {
  933. List<Long> ids = metaDestroyParam.getIds();
  934. String remark = metaDestroyParam.getRemark();
  935. if (CollectionUtils.isEmpty(ids)) {
  936. throw new BusinessException("要销毁的藏品id为空");
  937. }
  938. ids.forEach(id -> {
  939. destroyWithoutTradeCode(id, userId, source, remark);
  940. });
  941. }
  942. public void destroyWithoutTradeCode(Long id, Long userId, OperationSource source, String remark) {
  943. Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录"));
  944. if (!asset.getUserId().equals(userId)) {
  945. throw new BusinessException("此藏品不属于该用户");
  946. }
  947. if (OperationSource.META.equals(source)) {
  948. if (asset.getStatus() != AssetStatus.NORMAL) {
  949. throw new BusinessException("当前状态不可销毁");
  950. }
  951. } else {
  952. if (asset.getStatus() != AssetStatus.DESTROYING) {
  953. throw new BusinessException("当前状态不可销毁");
  954. }
  955. }
  956. if (asset.isPublicShow()) {
  957. throw new BusinessException("请先取消公开展示");
  958. // cancelPublic(asset);
  959. }
  960. User toUser = userRepo.findById(Constants.BLACK_HOLE_USER_ID).orElseThrow(new BusinessException("无记录"));
  961. TokenHistory tokenHistory = TokenHistory.builder()
  962. .tokenId(asset.getTokenId())
  963. .fromUser(asset.getOwner())
  964. .fromUserId(asset.getOwnerId())
  965. .fromAvatar(asset.getOwnerAvatar())
  966. .toUser(toUser.getNickname())
  967. .toUserId(toUser.getId())
  968. .toAvatar(toUser.getAvatar())
  969. .operation(TransferReason.DESTROY.getDescription())
  970. .price(null)
  971. .companyId(asset.getCompanyId())
  972. .build();
  973. tokenHistoryRepo.save(tokenHistory);
  974. asset.setPublicShow(false);
  975. asset.setConsignment(false);
  976. asset.setPublicCollectionId(null);
  977. asset.setStatus(AssetStatus.DESTROYED);
  978. asset.setOwner(toUser.getNickname());
  979. asset.setOwnerId(toUser.getId());
  980. asset.setOwnerAvatar(toUser.getAvatar());
  981. assetRepo.saveAndFlush(asset);
  982. //积分记录
  983. destroyRecordRepo.save(DestroyRecord.builder()
  984. .userId(userId)
  985. .assetId(asset.getId())
  986. .name(asset.getName())
  987. .pic(asset.getPic().get(0).getUrl())
  988. .record(1)
  989. .type(RecordType.OBTAIN)
  990. .companyId(asset.getCompanyId())
  991. .source(source)
  992. .remark(remark)
  993. .build());
  994. //加积分
  995. userRepo.addDestroyPoint(userId, 1);
  996. }
  997. public double getRoyalties(Long minterId, double royalties, Long userId) {
  998. if (royalties == 2) {
  999. return 2;
  1000. }
  1001. LongArrayConverter converter = new LongArrayConverter();
  1002. String discountMinter = sysConfigService.getString("discount_minter");
  1003. List<Long> minterIds = converter.convertToEntityAttribute(discountMinter);
  1004. if (minterIds.contains(minterId)) {
  1005. String discountCollection = sysConfigService.getString("discount_collection");
  1006. List<Long> collectionIds = converter.convertToEntityAttribute(discountCollection);
  1007. Long assetId = assetRepo.findDiscount(userId, collectionIds);
  1008. if (ObjectUtils.isNotEmpty(assetId)) {
  1009. return 2;
  1010. }
  1011. }
  1012. return royalties;
  1013. }
  1014. @Async
  1015. public void hcChain() throws ExecutionException, InterruptedException {
  1016. new ForkJoinPool(1000).submit(() -> {
  1017. AtomicInteger num = new AtomicInteger();
  1018. assetRepo.findByStatus(AssetStatus.NORMAL).parallelStream()
  1019. .forEach(asset -> {
  1020. if (asset.getHcTxHash() == null) {
  1021. User user = userRepo.findById(asset.getUserId()).orElse(null);
  1022. if (user != null) {
  1023. if (user.getHcChainAddress() == null) {
  1024. user.setHcChainAddress(hcChainService.createAccount(asset.getUserId()));
  1025. }
  1026. NFT nft = hcChainService.mint(user.getHcChainAddress(), asset.getTokenId());
  1027. asset.setHcTokenId(nft.getTokenId());
  1028. asset.setHcTxHash(nft.getTxHash());
  1029. asset.setGasUsed(nft.getGasUsed());
  1030. assetRepo.saveAndFlush(asset);
  1031. }
  1032. }
  1033. log.info("hcChain:" + num.getAndIncrement());
  1034. });
  1035. }).get();
  1036. }
  1037. public void lockAsset(Long userId, Long assetId, Duration duration) {
  1038. User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
  1039. Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("藏品不存在"));
  1040. if (!asset.getUserId().equals(userId)) {
  1041. throw new BusinessException("无权限");
  1042. }
  1043. if (asset.getLockTo() != null && asset.getLockTo().isAfter(LocalDateTime.now())) {
  1044. throw new BusinessException("已是锁仓状态");
  1045. }
  1046. if (asset.getType() == CollectionType.SHOWROOM) {
  1047. throw new BusinessException("展厅不可锁定");
  1048. }
  1049. if (asset.getStatus() != AssetStatus.NORMAL) {
  1050. throw new BusinessException("当前状态不可锁定");
  1051. }
  1052. if (asset.isPublicShow() || asset.isConsignment()) {
  1053. throw new BusinessException("请先取消展示和寄售");
  1054. }
  1055. if (duration.compareTo(Duration.parse("P1D")) < 0) {
  1056. throw new BusinessException("最小锁定1天");
  1057. }
  1058. asset.setLockAt(LocalDateTime.now());
  1059. asset.setLockTo(asset.getLockAt().plus(duration));
  1060. assetRepo.saveAndFlush(asset);
  1061. assetLockRepo.save(AssetLock.builder()
  1062. .userId(userId)
  1063. .phone(user.getPhone())
  1064. .nickname(user.getNickname())
  1065. .assetId(assetId)
  1066. .name(asset.getName())
  1067. .number(asset.getNumber())
  1068. .lockAt(asset.getLockAt())
  1069. .lockTo(asset.getLockTo())
  1070. .duration(duration)
  1071. .build());
  1072. }
  1073. public List<MetaPlayerRoleClassify> metaPlayerRole(Long userId) {
  1074. List<MetaPlayerRoleClassify> metaPlayerRoleClassifies = new ArrayList<>();
  1075. metaPlayerRoleClassifies.add(buildMetaPlayerRoleClassify(userId, "艾弗森", 1L));
  1076. metaPlayerRoleClassifies.add(buildMetaPlayerRoleClassify(userId, "开拓猿", 2L));
  1077. metaPlayerRoleClassifies.add(buildMetaPlayerRoleClassify(userId, "朋克", 3L));
  1078. metaPlayerRoleClassifies.add(buildMetaPlayerRoleClassify(userId, "MUGEN", 4L));
  1079. return metaPlayerRoleClassifies;
  1080. }
  1081. private MetaPlayerRoleClassify buildMetaPlayerRoleClassify(Long userId, String name, Long id) {
  1082. MetaPlayerRoleClassify metaPlayerRoleClassify = new MetaPlayerRoleClassify();
  1083. metaPlayerRoleClassify.setClassify(name);
  1084. List<MetaPlayerRole> metaPlayerRoleList;
  1085. if ("MUGEN".equals(name)) {
  1086. metaPlayerRoleList = Arrays.asList(new MetaPlayerRole(id, "无限集团"),
  1087. new MetaPlayerRole(id + 1, "苍茫雷道"),
  1088. new MetaPlayerRole(id + 2, "炼炉天族"),
  1089. new MetaPlayerRole(id + 3, "未央宗"),
  1090. new MetaPlayerRole(id + 4, "八极门"),
  1091. new MetaPlayerRole(id + 5, "人族"),
  1092. new MetaPlayerRole(id + 6, "凤鸣寺"),
  1093. new MetaPlayerRole(id + 7, "九州岛"));
  1094. } else {
  1095. metaPlayerRoleList = Collections.singletonList(new MetaPlayerRole(id, name));
  1096. }
  1097. metaPlayerRoleClassify.setMetaPlayerRoleList(build(userId, metaPlayerRoleList));
  1098. return metaPlayerRoleClassify;
  1099. }
  1100. private List<MetaPlayerRole> build(Long userId, List<MetaPlayerRole> metaPlayerRoleList) {
  1101. metaPlayerRoleList.forEach(metaPlayerRole -> {
  1102. metaPlayerRole.setType(UserHoldTypeEnum.ASSET);
  1103. metaPlayerRole.setAddress("https://www.raex.vip/9th/productSearch?search=" + metaPlayerRole
  1104. .getName() + "&source=TRANSFER");
  1105. List<Asset> assets = assetRepo.findAllByUserIdAndStatusInAndNameLike(userId, Constants.META_NORMAL_STATUS, "%" + metaPlayerRole.getName() + "%");
  1106. metaPlayerRole.setHold(CollectionUtils.isNotEmpty(assets));
  1107. });
  1108. return metaPlayerRoleList;
  1109. }
  1110. }