AssetService.java 50 KB

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