AssetService.java 50 KB

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