AssetService.java 59 KB

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