AssetService.java 53 KB

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