AssetService.java 60 KB

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