Przeglądaj źródła

Merge branch 'master' of http://git.izouma.com/xiongzhu/9th

panhui 4 lat temu
rodzic
commit
45b78763a7
26 zmienionych plików z 2725 dodań i 912 usunięć
  1. 1060 0
      src/main/contract/9th.sol
  2. BIN
      src/main/contract/alipay-solc-0.6.4.tgz
  3. 1 8
      src/main/java/com/izouma/nineth/event/CreateAssetEvent.java
  4. 78 89
      src/main/java/com/izouma/nineth/service/AssetService.java
  5. 53 1
      src/main/java/com/izouma/nineth/service/NFTService.java
  6. 16 22
      src/main/java/com/izouma/nineth/service/OrderService.java
  7. 18 4
      src/main/java/com/izouma/nineth/web/OrderNotifyController.java
  8. 1 1
      src/main/java/com/izouma/nineth/web/OrderPayController.java
  9. 1 0
      src/main/nine-space/package.json
  10. 3 0
      src/main/nine-space/src/main.js
  11. 10 0
      src/main/nine-space/src/router/index.js
  12. 2 2
      src/main/nine-space/src/views/Mine.vue
  13. 93 0
      src/main/nine-space/src/views/account/Authentication.vue
  14. 3 12
      src/main/nine-space/src/views/account/Verified.vue
  15. 440 0
      src/main/nine-space/src/views/account/VerifiedSucs.vue
  16. 32 4
      src/main/nine-space/src/views/asset/Consignment.vue
  17. 4 2
      src/main/nine-space/src/views/asset/Detail.vue
  18. 41 2
      src/main/nine-space/yarn.lock
  19. 1 1
      src/main/pc-space/src/views/user/CollectionOrder.vue
  20. 38 29
      src/main/pc-space/src/views/user/EnterpriseAuthentication.vue
  21. 1 1
      src/main/pc-space/src/views/user/PayRecord.vue
  22. 3 3
      src/main/pc-space/src/views/user/TransactionOrdes.vue
  23. 92 90
      src/main/vue/package-lock.json
  24. 2 2
      src/main/vue/package.json
  25. 726 636
      src/main/vue/yarn.lock
  26. 6 3
      src/test/java/com/izouma/nineth/service/NFTServiceTest.java

+ 1060 - 0
src/main/contract/9th.sol

@@ -0,0 +1,1060 @@
+pragma solidity ^0.6.3;
+
+library Strings {
+    function toString(uint256 value) internal pure returns (string memory) {
+        // Inspired by OraclizeAPI's implementation - MIT licence
+        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
+
+        if (value == 0) {
+            return "0";
+        }
+        uint256 temp = value;
+        uint256 digits;
+        while (temp != 0) {
+            digits++;
+            temp /= 10;
+        }
+        bytes memory buffer = new bytes(digits);
+        uint256 index = digits - 1;
+        temp = value;
+        while (temp != 0) {
+            buffer[index--] = bytes1(uint8(48 + (temp % 10)));
+            temp /= 10;
+        }
+        return string(buffer);
+    }
+}
+
+library EnumerableMap {
+    struct MapEntry {
+        bytes32 _key;
+        bytes32 _value;
+    }
+
+    struct Map {
+        // Storage of map keys and values
+        MapEntry[] _entries;
+        // Position of the entry defined by a key in the `entries` array, plus 1
+        // because index 0 means a key is not in the map.
+        mapping(bytes32 => uint256) _indexes;
+    }
+
+    function _set(
+        Map storage map,
+        bytes32 key,
+        bytes32 value
+    ) private returns (bool) {
+        // We read and store the key's index to prevent multiple reads from the same storage slot
+        uint256 keyIndex = map._indexes[key];
+
+        if (keyIndex == 0) {
+            // Equivalent to !contains(map, key)
+            map._entries.push(MapEntry({_key: key, _value: value}));
+            // The entry is stored at length-1, but we add 1 to all indexes
+            // and use 0 as a sentinel value
+            map._indexes[key] = map._entries.length;
+            return true;
+        } else {
+            map._entries[keyIndex - 1]._value = value;
+            return false;
+        }
+    }
+
+    function _remove(Map storage map, bytes32 key) private returns (bool) {
+        // We read and store the key's index to prevent multiple reads from the same storage slot
+        uint256 keyIndex = map._indexes[key];
+
+        if (keyIndex != 0) {
+            // Equivalent to contains(map, key)
+            // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
+            // in the array, and then remove the last entry (sometimes called as 'swap and pop').
+            // This modifies the order of the array, as noted in {at}.
+
+            uint256 toDeleteIndex = keyIndex - 1;
+            uint256 lastIndex = map._entries.length - 1;
+
+            // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
+            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
+
+            MapEntry storage lastEntry = map._entries[lastIndex];
+
+            // Move the last entry to the index where the entry to delete is
+            map._entries[toDeleteIndex] = lastEntry;
+            // Update the index for the moved entry
+            map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based
+
+            // Delete the slot where the moved entry was stored
+            map._entries.pop();
+
+            // Delete the index for the deleted slot
+            delete map._indexes[key];
+
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    function _contains(Map storage map, bytes32 key)
+        private
+        view
+        returns (bool)
+    {
+        return map._indexes[key] != 0;
+    }
+
+    function _length(Map storage map) private view returns (uint256) {
+        return map._entries.length;
+    }
+
+    function _at(Map storage map, uint256 index)
+        private
+        view
+        returns (bytes32, bytes32)
+    {
+        require(
+            map._entries.length > index,
+            "EnumerableMap: index out of bounds"
+        );
+
+        MapEntry storage entry = map._entries[index];
+        return (entry._key, entry._value);
+    }
+
+    function _tryGet(Map storage map, bytes32 key)
+        private
+        view
+        returns (bool, bytes32)
+    {
+        uint256 keyIndex = map._indexes[key];
+        if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
+        return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
+    }
+
+    function _get(Map storage map, bytes32 key) private view returns (bytes32) {
+        uint256 keyIndex = map._indexes[key];
+        require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
+        return map._entries[keyIndex - 1]._value; // All indexes are 1-based
+    }
+
+    function _get(
+        Map storage map,
+        bytes32 key,
+        string memory errorMessage
+    ) private view returns (bytes32) {
+        uint256 keyIndex = map._indexes[key];
+        require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
+        return map._entries[keyIndex - 1]._value; // All indexes are 1-based
+    }
+
+    // UintToAddressMap
+
+    struct UintToAddressMap {
+        Map _inner;
+    }
+
+    function set(
+        UintToAddressMap storage map,
+        uint256 key,
+        identity value
+    ) internal returns (bool) {
+        return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
+    }
+
+    function remove(UintToAddressMap storage map, uint256 key)
+        internal
+        returns (bool)
+    {
+        return _remove(map._inner, bytes32(key));
+    }
+
+    function contains(UintToAddressMap storage map, uint256 key)
+        internal
+        view
+        returns (bool)
+    {
+        return _contains(map._inner, bytes32(key));
+    }
+
+    function length(UintToAddressMap storage map)
+        internal
+        view
+        returns (uint256)
+    {
+        return _length(map._inner);
+    }
+
+    function at(UintToAddressMap storage map, uint256 index)
+        internal
+        view
+        returns (uint256, identity)
+    {
+        (bytes32 key, bytes32 value) = _at(map._inner, index);
+        return (uint256(key), identity(uint160(uint256(value))));
+    }
+
+    function tryGet(UintToAddressMap storage map, uint256 key)
+        internal
+        view
+        returns (bool, identity)
+    {
+        (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
+        return (success, identity(uint160(uint256(value))));
+    }
+
+    function get(UintToAddressMap storage map, uint256 key)
+        internal
+        view
+        returns (identity)
+    {
+        return identity(uint160(uint256(_get(map._inner, bytes32(key)))));
+    }
+
+    function get(
+        UintToAddressMap storage map,
+        uint256 key,
+        string memory errorMessage
+    ) internal view returns (identity) {
+        return
+            identity(
+                uint160(uint256(_get(map._inner, bytes32(key), errorMessage)))
+            );
+    }
+}
+
+library EnumerableSet {
+
+    struct Set {
+        bytes32[] _values;
+
+        mapping (bytes32 => uint256) _indexes;
+    }
+
+    function _add(Set storage set, bytes32 value) private returns (bool) {
+        if (!_contains(set, value)) {
+            set._values.push(value);
+            set._indexes[value] = set._values.length;
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    function _remove(Set storage set, bytes32 value) private returns (bool) {
+        uint256 valueIndex = set._indexes[value];
+
+        if (valueIndex != 0) {
+
+            uint256 toDeleteIndex = valueIndex - 1;
+            uint256 lastIndex = set._values.length - 1;
+
+            bytes32 lastvalue = set._values[lastIndex];
+
+            set._values[toDeleteIndex] = lastvalue;
+            set._indexes[lastvalue] = toDeleteIndex + 1;
+
+            set._values.pop();
+
+            delete set._indexes[value];
+
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    function _contains(Set storage set, bytes32 value) private view returns (bool) {
+        return set._indexes[value] != 0;
+    }
+
+    function _length(Set storage set) private view returns (uint256) {
+        return set._values.length;
+    }
+
+    function _at(Set storage set, uint256 index) private view returns (bytes32) {
+        require(set._values.length > index, "EnumerableSet: index out of bounds");
+        return set._values[index];
+    }
+
+
+    struct Bytes32Set {
+        Set _inner;
+    }
+
+    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
+        return _add(set._inner, value);
+    }
+
+    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
+        return _remove(set._inner, value);
+    }
+
+    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
+        return _contains(set._inner, value);
+    }
+
+    function length(Bytes32Set storage set) internal view returns (uint256) {
+        return _length(set._inner);
+    }
+
+    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
+        return _at(set._inner, index);
+    }
+
+    struct AddressSet {
+        Set _inner;
+    }
+
+    function add(AddressSet storage set, identity value) internal returns (bool) {
+        return _add(set._inner, bytes32(uint256(uint160(value))));
+    }
+
+    function remove(AddressSet storage set, identity value) internal returns (bool) {
+        return _remove(set._inner, bytes32(uint256(uint160(value))));
+    }
+
+    function contains(AddressSet storage set, identity value) internal view returns (bool) {
+        return _contains(set._inner, bytes32(uint256(uint160(value))));
+    }
+
+    function length(AddressSet storage set) internal view returns (uint256) {
+        return _length(set._inner);
+    }
+
+    function at(AddressSet storage set, uint256 index) internal view returns (identity) {
+        return identity(uint160(uint256(_at(set._inner, index))));
+    }
+
+    struct UintSet {
+        Set _inner;
+    }
+
+    function add(UintSet storage set, uint256 value) internal returns (bool) {
+        return _add(set._inner, bytes32(value));
+    }
+
+    function remove(UintSet storage set, uint256 value) internal returns (bool) {
+        return _remove(set._inner, bytes32(value));
+    }
+
+    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
+        return _contains(set._inner, bytes32(value));
+    }
+
+    function length(UintSet storage set) internal view returns (uint256) {
+        return _length(set._inner);
+    }
+
+    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
+        return uint256(_at(set._inner, index));
+    }
+}
+
+library Address {
+
+    function isContract(identity account) internal view returns (bool) {
+        // This method relies on extcodesize, which returns 0 for contracts in
+        // construction, since the code is only stored at the end of the
+        // constructor execution.
+
+        uint256 size;
+        // solhint-disable-next-line no-inline-assembly
+        assembly { size := extcodesize(account) }
+        return size > 0;
+    }
+
+    function sendValue(identity recipient, uint256 amount) internal {
+        require(identity(this).balance >= amount, "Address: insufficient balance");
+
+        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
+        (bool success, ) = recipient.call{ value: amount }("");
+        require(success, "Address: unable to send value, recipient may have reverted");
+    }
+
+    function functionCall(identity target, bytes memory data) internal returns (bytes memory) {
+      return functionCall(target, data, "Address: low-level call failed");
+    }
+
+    function functionCall(identity target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
+        return functionCallWithValue(target, data, 0, errorMessage);
+    }
+
+    function functionCallWithValue(identity target, bytes memory data, uint256 value) internal returns (bytes memory) {
+        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
+    }
+
+    function functionCallWithValue(identity target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
+        require(identity(this).balance >= value, "Address: insufficient balance for call");
+        require(isContract(target), "Address: call to non-contract");
+
+        // solhint-disable-next-line avoid-low-level-calls
+        (bool success, bytes memory returndata) = target.call{ value: value }(data);
+        return _verifyCallResult(success, returndata, errorMessage);
+    }
+
+    function functionStaticCall(identity target, bytes memory data) internal view returns (bytes memory) {
+        return functionStaticCall(target, data, "Address: low-level static call failed");
+    }
+
+    function functionStaticCall(identity target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
+        require(isContract(target), "Address: static call to non-contract");
+
+        // solhint-disable-next-line avoid-low-level-calls
+        (bool success, bytes memory returndata) = target.staticcall(data);
+        return _verifyCallResult(success, returndata, errorMessage);
+    }
+
+    function functionDelegateCall(identity target, bytes memory data) internal returns (bytes memory) {
+        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
+    }
+
+    function functionDelegateCall(identity target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
+        require(isContract(target), "Address: delegate call to non-contract");
+
+        // solhint-disable-next-line avoid-low-level-calls
+        (bool success, bytes memory returndata) = target.delegatecall(data);
+        return _verifyCallResult(success, returndata, errorMessage);
+    }
+
+    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
+        if (success) {
+            return returndata;
+        } else {
+            // Look for revert reason and bubble it up if present
+            if (returndata.length > 0) {
+                // The easiest way to bubble the revert reason is using memory via assembly
+
+                // solhint-disable-next-line no-inline-assembly
+                assembly {
+                    let returndata_size := mload(returndata)
+                    revert(add(32, returndata), returndata_size)
+                }
+            } else {
+                revert(errorMessage);
+            }
+        }
+    }
+}
+
+library SafeMath {
+
+    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        uint256 c = a + b;
+        if (c < a) return (false, 0);
+        return (true, c);
+    }
+
+    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        if (b > a) return (false, 0);
+        return (true, a - b);
+    }
+
+    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        if (a == 0) return (true, 0);
+        uint256 c = a * b;
+        if (c / a != b) return (false, 0);
+        return (true, c);
+    }
+
+    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        if (b == 0) return (false, 0);
+        return (true, a / b);
+    }
+
+    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
+        if (b == 0) return (false, 0);
+        return (true, a % b);
+    }
+
+    function add(uint256 a, uint256 b) internal pure returns (uint256) {
+        uint256 c = a + b;
+        require(c >= a, "SafeMath: addition overflow");
+        return c;
+    }
+
+    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
+        require(b <= a, "SafeMath: subtraction overflow");
+        return a - b;
+    }
+
+    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
+        if (a == 0) return 0;
+        uint256 c = a * b;
+        require(c / a == b, "SafeMath: multiplication overflow");
+        return c;
+    }
+
+    function div(uint256 a, uint256 b) internal pure returns (uint256) {
+        require(b > 0, "SafeMath: division by zero");
+        return a / b;
+    }
+
+    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
+        require(b > 0, "SafeMath: modulo by zero");
+        return a % b;
+    }
+
+    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
+        require(b <= a, errorMessage);
+        return a - b;
+    }
+
+    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
+        require(b > 0, errorMessage);
+        return a / b;
+    }
+
+    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
+        require(b > 0, errorMessage);
+        return a % b;
+    }
+}
+
+library Counters {
+    using SafeMath for uint256;
+
+    struct Counter {
+        // This variable should never be directly accessed by users of the library: interactions must be restricted to
+        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
+        // this feature: see https://github.com/ethereum/solidity/issues/4637
+        uint256 _value; // default: 0
+    }
+
+    function current(Counter storage counter) internal view returns (uint256) {
+        return counter._value;
+    }
+
+    function increment(Counter storage counter) internal {
+        // The {SafeMath} overflow check can be skipped here, see the comment at the top
+        counter._value += 1;
+    }
+
+    function decrement(Counter storage counter) internal {
+        counter._value = counter._value.sub(1);
+    }
+}
+
+abstract contract Context {
+    function _msgSender() internal view virtual returns (identity) {
+        return msg.sender;
+    }
+
+    function _msgData() internal view virtual returns (bytes memory) {
+        this;
+        return msg.data;
+    }
+}
+
+abstract contract AccessControl is Context {
+    using EnumerableSet for EnumerableSet.AddressSet;
+    using Address for identity;
+
+    struct RoleData {
+        EnumerableSet.AddressSet members;
+        bytes32 adminRole;
+    }
+
+    mapping (bytes32 => RoleData) private _roles;
+
+    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
+
+    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
+
+    event RoleGranted(bytes32 indexed role, identity indexed account, identity indexed sender);
+
+    event RoleRevoked(bytes32 indexed role, identity indexed account, identity indexed sender);
+
+    function hasRole(bytes32 role, identity account) public view returns (bool) {
+        return _roles[role].members.contains(account);
+    }
+
+    function getRoleMemberCount(bytes32 role) public view returns (uint256) {
+        return _roles[role].members.length();
+    }
+
+    function getRoleMember(bytes32 role, uint256 index) public view returns (identity) {
+        return _roles[role].members.at(index);
+    }
+
+    function getRoleAdmin(bytes32 role) public view returns (bytes32) {
+        return _roles[role].adminRole;
+    }
+
+    function grantRole(bytes32 role, identity account) public virtual {
+        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to grant");
+
+        _grantRole(role, account);
+    }
+
+    function revokeRole(bytes32 role, identity account) public virtual {
+        require(hasRole(_roles[role].adminRole, _msgSender()), "AccessControl: sender must be an admin to revoke");
+
+        _revokeRole(role, account);
+    }
+
+    function renounceRole(bytes32 role, identity account) public virtual {
+        require(account == _msgSender(), "AccessControl: can only renounce roles for self");
+
+        _revokeRole(role, account);
+    }
+
+    function _setupRole(bytes32 role, identity account) internal virtual {
+        _grantRole(role, account);
+    }
+
+    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
+        emit RoleAdminChanged(role, _roles[role].adminRole, adminRole);
+        _roles[role].adminRole = adminRole;
+    }
+
+    function _grantRole(bytes32 role, identity account) private {
+        if (_roles[role].members.add(account)) {
+            emit RoleGranted(role, account, _msgSender());
+        }
+    }
+
+    function _revokeRole(bytes32 role, identity account) private {
+        if (_roles[role].members.remove(account)) {
+            emit RoleRevoked(role, account, _msgSender());
+        }
+    }
+}
+
+interface IERC165 {
+    function supportsInterface(bytes4 interfaceId) external view returns (bool);
+}
+
+abstract contract ERC165 is IERC165 {
+
+    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
+
+    mapping(bytes4 => bool) private _supportedInterfaces;
+
+    constructor () internal {
+        _registerInterface(_INTERFACE_ID_ERC165);
+    }
+
+    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
+        return _supportedInterfaces[interfaceId];
+    }
+
+    function _registerInterface(bytes4 interfaceId) internal virtual {
+        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
+        _supportedInterfaces[interfaceId] = true;
+    }
+}
+
+interface IERC721 is IERC165 {
+
+    event Transfer(identity indexed from, identity indexed to, uint256 indexed tokenId);
+
+    event Approval(identity indexed owner, identity indexed approved, uint256 indexed tokenId);
+
+    event ApprovalForAll(identity indexed owner, identity indexed operator, bool approved);
+
+    function balanceOf(identity owner) external view returns (uint256 balance);
+
+    function ownerOf(uint256 tokenId) external view returns (identity owner);
+
+    function safeTransferFrom(identity from, identity to, uint256 tokenId) external;
+
+    function transferFrom(identity from, identity to, uint256 tokenId) external;
+
+    function approve(identity to, uint256 tokenId) external;
+
+    function getApproved(uint256 tokenId) external view returns (identity operator);
+
+    function setApprovalForAll(identity operator, bool _approved) external;
+
+    function isApprovedForAll(identity owner, identity operator) external view returns (bool);
+
+    function safeTransferFrom(identity from, identity to, uint256 tokenId, bytes calldata data) external;
+}
+
+interface IERC721Metadata is IERC721 {
+
+    function name() external view returns (string memory);
+
+    function symbol() external view returns (string memory);
+
+    function tokenURI(uint256 tokenId) external view returns (string memory);
+}
+
+interface IERC721Enumerable is IERC721 {
+
+    function totalSupply() external view returns (uint256);
+
+    function tokenOfOwnerByIndex(identity owner, uint256 index) external view returns (uint256 tokenId);
+
+    function tokenByIndex(uint256 index) external view returns (uint256);
+}
+
+interface IERC721Receiver {
+    function onERC721Received(identity operator, identity from, uint256 tokenId, bytes calldata data) external returns (bytes4);
+}
+
+contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable {
+    using SafeMath for uint256;
+    using Address for identity;
+    using EnumerableSet for EnumerableSet.UintSet;
+    using EnumerableMap for EnumerableMap.UintToAddressMap;
+    using Strings for uint256;
+
+    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
+    mapping (identity => EnumerableSet.UintSet) private _holderTokens;
+    EnumerableMap.UintToAddressMap private _tokenOwners;
+    mapping (uint256 => identity) private _tokenApprovals;
+    mapping (identity => mapping (identity => bool)) private _operatorApprovals;
+    string private _name;
+    string private _symbol;
+    mapping (uint256 => string) private _tokenURIs;
+    string private _baseURI;
+    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
+    bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
+    bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
+
+    constructor (string memory name_, string memory symbol_) public {
+        _name = name_;
+        _symbol = symbol_;
+
+        // register the supported interfaces to conform to ERC721 via ERC165
+        _registerInterface(_INTERFACE_ID_ERC721);
+        _registerInterface(_INTERFACE_ID_ERC721_METADATA);
+        _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
+    }
+
+    function balanceOf(identity owner) public view virtual override returns (uint256) {
+        require(owner != identity(0), "ERC721: balance query for the zero address");
+        return _holderTokens[owner].length();
+    }
+
+    function ownerOf(uint256 tokenId) public view virtual override returns (identity) {
+        return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token");
+    }
+
+    function name() public view virtual override returns (string memory) {
+        return _name;
+    }
+
+    function symbol() public view virtual override returns (string memory) {
+        return _symbol;
+    }
+
+    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
+        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
+
+        string memory _tokenURI = _tokenURIs[tokenId];
+        string memory base = baseURI();
+
+        // If there is no base URI, return the token URI.
+        if (bytes(base).length == 0) {
+            return _tokenURI;
+        }
+        // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
+        if (bytes(_tokenURI).length > 0) {
+            return string(abi.encodePacked(base, _tokenURI));
+        }
+        // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
+        return string(abi.encodePacked(base, tokenId.toString()));
+    }
+
+    function baseURI() public view virtual returns (string memory) {
+        return _baseURI;
+    }
+
+    function tokenOfOwnerByIndex(identity owner, uint256 index) public view virtual override returns (uint256) {
+        return _holderTokens[owner].at(index);
+    }
+
+    function totalSupply() public view virtual override returns (uint256) {
+        // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
+        return _tokenOwners.length();
+    }
+
+    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
+        (uint256 tokenId, ) = _tokenOwners.at(index);
+        return tokenId;
+    }
+
+    function approve(identity to, uint256 tokenId) public virtual override {
+        identity owner = ERC721.ownerOf(tokenId);
+        require(to != owner, "ERC721: approval to current owner");
+
+        require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()),
+            "ERC721: approve caller is not owner nor approved for all"
+        );
+
+        _approve(to, tokenId);
+    }
+
+    function getApproved(uint256 tokenId) public view virtual override returns (identity) {
+        require(_exists(tokenId), "ERC721: approved query for nonexistent token");
+
+        return _tokenApprovals[tokenId];
+    }
+
+    function setApprovalForAll(identity operator, bool approved) public virtual override {
+        require(operator != _msgSender(), "ERC721: approve to caller");
+
+        _operatorApprovals[_msgSender()][operator] = approved;
+        emit ApprovalForAll(_msgSender(), operator, approved);
+    }
+
+    function isApprovedForAll(identity owner, identity operator) public view virtual override returns (bool) {
+        return _operatorApprovals[owner][operator];
+    }
+
+    function transferFrom(identity from, identity to, uint256 tokenId) public virtual override {
+        //solhint-disable-next-line max-line-length
+        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
+
+        _transfer(from, to, tokenId);
+    }
+
+    function safeTransferFrom(identity from, identity to, uint256 tokenId) public virtual override {
+        safeTransferFrom(from, to, tokenId, "");
+    }
+
+    function safeTransferFrom(identity from, identity to, uint256 tokenId, bytes memory _data) public virtual override {
+        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
+        _safeTransfer(from, to, tokenId, _data);
+    }
+
+    function _safeTransfer(identity from, identity to, uint256 tokenId, bytes memory _data) internal virtual {
+        _transfer(from, to, tokenId);
+        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
+    }
+
+    function _exists(uint256 tokenId) internal view virtual returns (bool) {
+        return _tokenOwners.contains(tokenId);
+    }
+
+    function _isApprovedOrOwner(identity spender, uint256 tokenId) internal view virtual returns (bool) {
+        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
+        identity owner = ERC721.ownerOf(tokenId);
+        return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender));
+    }
+
+    function _safeMint(identity to, uint256 tokenId) internal virtual {
+        _safeMint(to, tokenId, "");
+    }
+
+    function _safeMint(identity to, uint256 tokenId, bytes memory _data) internal virtual {
+        _mint(to, tokenId);
+        require(_checkOnERC721Received(identity(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
+    }
+
+    function _mint(identity to, uint256 tokenId) internal virtual {
+        require(to != identity(0), "ERC721: mint to the zero address");
+        require(!_exists(tokenId), "ERC721: token already minted");
+
+        _beforeTokenTransfer(identity(0), to, tokenId);
+
+        _holderTokens[to].add(tokenId);
+
+        _tokenOwners.set(tokenId, to);
+
+        emit Transfer(identity(0), to, tokenId);
+    }
+
+    function _burn(uint256 tokenId) internal virtual {
+        identity owner = ERC721.ownerOf(tokenId); // internal owner
+
+        _beforeTokenTransfer(owner, identity(0), tokenId);
+
+        // Clear approvals
+        _approve(identity(0), tokenId);
+
+        // Clear metadata (if any)
+        if (bytes(_tokenURIs[tokenId]).length != 0) {
+            delete _tokenURIs[tokenId];
+        }
+
+        _holderTokens[owner].remove(tokenId);
+
+        _tokenOwners.remove(tokenId);
+
+        emit Transfer(owner, identity(0), tokenId);
+    }
+
+    function _transfer(identity from, identity to, uint256 tokenId) internal virtual {
+        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner
+        require(to != identity(0), "ERC721: transfer to the zero address");
+
+        _beforeTokenTransfer(from, to, tokenId);
+
+        // Clear approvals from the previous owner
+        _approve(identity(0), tokenId);
+
+        _holderTokens[from].remove(tokenId);
+        _holderTokens[to].add(tokenId);
+
+        _tokenOwners.set(tokenId, to);
+
+        emit Transfer(from, to, tokenId);
+    }
+
+    function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
+        require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
+        _tokenURIs[tokenId] = _tokenURI;
+    }
+
+    function _setBaseURI(string memory baseURI_) internal virtual {
+        _baseURI = baseURI_;
+    }
+
+    function _checkOnERC721Received(identity from, identity to, uint256 tokenId, bytes memory _data)
+        private returns (bool)
+    {
+        if (!to.isContract()) {
+            return true;
+        }
+        bytes memory returndata = to.functionCall(abi.encodeWithSelector(
+            IERC721Receiver(to).onERC721Received.selector,
+            _msgSender(),
+            from,
+            tokenId,
+            _data
+        ), "ERC721: transfer to non ERC721Receiver implementer");
+        bytes4 retval = abi.decode(returndata, (bytes4));
+        return (retval == _ERC721_RECEIVED);
+    }
+
+    function _approve(identity to, uint256 tokenId) private {
+        _tokenApprovals[tokenId] = to;
+        emit Approval(ERC721.ownerOf(tokenId), to, tokenId); // internal owner
+    }
+
+    function _beforeTokenTransfer(identity from, identity to, uint256 tokenId) internal virtual { }
+}
+
+abstract contract ERC721Burnable is Context, ERC721 {
+    function burn(uint256 tokenId) public virtual {
+        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved");
+        _burn(tokenId);
+    }
+}
+
+abstract contract Pausable is Context {
+
+    event Paused(identity account);
+
+    event Unpaused(identity account);
+
+    bool private _paused;
+
+    constructor () internal {
+        _paused = false;
+    }
+
+    function paused() public view virtual returns (bool) {
+        return _paused;
+    }
+
+    modifier whenNotPaused() {
+        require(!paused(), "Pausable: paused");
+        _;
+    }
+
+    modifier whenPaused() {
+        require(paused(), "Pausable: not paused");
+        _;
+    }
+
+    function _pause() internal virtual whenNotPaused {
+        _paused = true;
+        emit Paused(_msgSender());
+    }
+
+    function _unpause() internal virtual whenPaused {
+        _paused = false;
+        emit Unpaused(_msgSender());
+    }
+}
+
+abstract contract ERC721Pausable is ERC721, Pausable {
+
+    function _beforeTokenTransfer(identity from, identity to, uint256 tokenId) internal virtual override {
+        super._beforeTokenTransfer(from, to, tokenId);
+
+        require(!paused(), "ERC721Pausable: token transfer while paused");
+    }
+}
+
+contract ERC721PresetMinterPauserAutoId is Context, AccessControl, ERC721Burnable, ERC721Pausable {
+    using Counters for Counters.Counter;
+
+    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
+    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
+
+    Counters.Counter private _tokenIdTracker;
+
+    /**
+     * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the
+     * account that deploys the contract.
+     *
+     * Token URIs will be autogenerated based on `baseURI` and their token IDs.
+     * See {ERC721-tokenURI}.
+     */
+    constructor(string memory name, string memory symbol, string memory baseURI) public ERC721(name, symbol) {
+        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
+
+        _setupRole(MINTER_ROLE, _msgSender());
+        _setupRole(PAUSER_ROLE, _msgSender());
+
+        _setBaseURI(baseURI);
+    }
+
+    /**
+     * @dev Creates a new token for `to`. Its token ID will be automatically
+     * assigned (and available on the emitted {IERC721-Transfer} event), and the token
+     * URI autogenerated based on the base URI passed at construction.
+     *
+     * See {ERC721-_mint}.
+     *
+     * Requirements:
+     *
+     * - the caller must have the `MINTER_ROLE`.
+     */
+    function mint(identity to) public virtual {
+        require(hasRole(MINTER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have minter role to mint");
+
+        // We cannot just use balanceOf to create the new tokenId because tokens
+        // can be burned (destroyed), so we need a separate counter.
+        _mint(to, _tokenIdTracker.current());
+        _tokenIdTracker.increment();
+    }
+
+    /**
+     * @dev Pauses all token transfers.
+     *
+     * See {ERC721Pausable} and {Pausable-_pause}.
+     *
+     * Requirements:
+     *
+     * - the caller must have the `PAUSER_ROLE`.
+     */
+    function pause() public virtual {
+        require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to pause");
+        _pause();
+    }
+
+    /**
+     * @dev Unpauses all token transfers.
+     *
+     * See {ERC721Pausable} and {Pausable-_unpause}.
+     *
+     * Requirements:
+     *
+     * - the caller must have the `PAUSER_ROLE`.
+     */
+    function unpause() public virtual {
+        require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to unpause");
+        _unpause();
+    }
+
+    function _beforeTokenTransfer(identity from, identity to, uint256 tokenId) internal virtual override(ERC721, ERC721Pausable) {
+        super._beforeTokenTransfer(from, to, tokenId);
+    }
+}

BIN
src/main/contract/alipay-solc-0.6.4.tgz


+ 1 - 8
src/main/java/com/izouma/nineth/event/CreateAssetEvent.java

@@ -1,25 +1,18 @@
 package com.izouma.nineth.event;
 
 import com.izouma.nineth.domain.Asset;
-import com.izouma.nineth.domain.Order;
 import org.springframework.context.ApplicationEvent;
 
 public class CreateAssetEvent extends ApplicationEvent {
     private final boolean success;
-    private final Order   order;
     private final Asset   asset;
 
-    public CreateAssetEvent(Object source, boolean success, Order order, Asset asset) {
+    public CreateAssetEvent(Object source, boolean success, Asset asset) {
         super(source);
         this.success = success;
-        this.order = order;
         this.asset = asset;
     }
 
-    public Order getOrder() {
-        return order;
-    }
-
     public Asset getAsset() {
         return asset;
     }

+ 78 - 89
src/main/java/com/izouma/nineth/service/AssetService.java

@@ -38,7 +38,6 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.env.Environment;
 import org.springframework.data.domain.Page;
-import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.ui.Model;
 
@@ -73,71 +72,80 @@ public class AssetService {
         return assetRepo.findAll(JpaUtils.toSpecification(pageQuery, Asset.class), JpaUtils.toPageRequest(pageQuery));
     }
 
-    @Async
-    public void createAsset(Order order) {
+    public Asset createAsset(Order order) {
         User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("用户不存在"));
-        if (StringUtils.isEmpty(user.getPublicKey())) {
-            NFTAccount account = nftService.createAccount(user.getUsername());
-            user.setNftAccount(account.getAccountId());
-            user.setKmsId(account.getAccountKmsId());
-            user.setPublicKey(account.getPublicKey());
-            userRepo.save(user);
-        }
-        try {
-            NFT nft = nftService.createToken(user.getNftAccount());
-            String ipfsUrl = ipfsUpload(order.getPic().get(0).getUrl());
-            if (nft != null) {
-                Asset asset = Asset.builder()
-                        .userId(user.getId())
-                        .orderId(order.getId())
-                        .collectionId(order.getCollectionId())
-                        .minter(order.getMinter())
-                        .minterId(order.getMinterId())
-                        .minterAvatar(order.getMinterAvatar())
-                        .name(order.getName())
-                        .detail(order.getDetail())
-                        .pic(order.getPic())
-                        .properties(order.getProperties())
-                        .category(order.getCategory())
-                        .canResale(order.isCanResale())
-                        .royalties(order.getRoyalties())
-                        .serviceCharge(order.getServiceCharge())
-                        .tokenId(nft.getTokenId())
-                        .blockNumber(nft.getBlockNumber())
-                        .txHash(nft.getTxHash())
-                        .gasUsed(nft.getGasUsed())
-                        .price(order.getPrice())
-                        .status(AssetStatus.NORMAL)
-                        .ipfsUrl(ipfsUrl)
-                        .number((int) (assetRepo.countByIpfsUrlAndStatusNot(ipfsUrl, AssetStatus.TRANSFERRED) + 1))
-                        .owner(user.getNickname())
-                        .ownerId(user.getId())
-                        .ownerAvatar(user.getAvatar())
-                        .build();
-                assetRepo.save(asset);
-                applicationContext.publishEvent(new CreateAssetEvent(this, true, order, asset));
-
-                tokenHistoryRepo.save(TokenHistory.builder()
-                        .tokenId(asset.getTokenId())
-                        .fromUser(order.getMinter())
-                        .fromUserId(order.getMinterId())
-                        .toUser(user.getNickname())
-                        .toUserId(user.getId())
-                        .operation("出售")
-                        .price(order.getPrice())
-                        .build());
-                return;
-            }
-        } catch (Exception e) {
-            log.error("创建token失败", e);
-        }
-        applicationContext.publishEvent(new CreateAssetEvent(this, false, order, null));
+        Asset asset = Asset.builder()
+                .userId(user.getId())
+                .orderId(order.getId())
+                .collectionId(order.getCollectionId())
+                .minter(order.getMinter())
+                .minterId(order.getMinterId())
+                .minterAvatar(order.getMinterAvatar())
+                .name(order.getName())
+                .detail(order.getDetail())
+                .pic(order.getPic())
+                .properties(order.getProperties())
+                .category(order.getCategory())
+                .canResale(order.isCanResale())
+                .royalties(order.getRoyalties())
+                .serviceCharge(order.getServiceCharge())
+                .price(order.getPrice())
+                .status(AssetStatus.NORMAL)
+                .owner(user.getNickname())
+                .ownerId(user.getId())
+                .ownerAvatar(user.getAvatar())
+                .build();
+        assetRepo.save(asset);
 
+        tokenHistoryRepo.save(TokenHistory.builder()
+                .tokenId(asset.getTokenId())
+                .fromUser(order.getMinter())
+                .fromUserId(order.getMinterId())
+                .toUser(user.getNickname())
+                .toUserId(user.getId())
+                .operation("出售")
+                .price(order.getPrice())
+                .build());
+
+        return asset;
     }
 
-    @Async
-    public void createAsset(Order order, BlindBoxItem winItem) {
+    public Asset createAsset(Order order, BlindBoxItem winItem) {
         User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("用户不存在"));
+        Asset asset = Asset.builder()
+                .userId(user.getId())
+                .orderId(order.getId())
+                .collectionId(order.getCollectionId())
+                .minter(winItem.getMinter())
+                .minterId(winItem.getMinterId())
+                .minterAvatar(winItem.getMinterAvatar())
+                .name(winItem.getName())
+                .detail(winItem.getDetail())
+                .pic(winItem.getPic())
+                .properties(winItem.getProperties())
+                .canResale(winItem.isCanResale())
+                .royalties(winItem.getRoyalties())
+                .serviceCharge(winItem.getServiceCharge())
+                .price(order.getPrice())
+                .status(AssetStatus.NORMAL)
+                .ipfsUrl(ipfsUpload(winItem.getPic().get(0).getUrl()))
+                .build();
+        assetRepo.save(asset);
+        tokenHistoryRepo.save(TokenHistory.builder()
+                .tokenId(asset.getTokenId())
+                .fromUser(order.getMinter())
+                .fromUserId(order.getMinterId())
+                .toUser(user.getNickname())
+                .toUserId(user.getId())
+                .operation("出售")
+                .price(order.getPrice())
+                .build());
+
+        return asset;
+    }
+
+    public void mint(Asset asset) {
+        User user = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在"));
         if (StringUtils.isEmpty(user.getPublicKey())) {
             NFTAccount account = nftService.createAccount(user.getUsername());
             user.setNftAccount(account.getAccountId());
@@ -148,41 +156,22 @@ public class AssetService {
         try {
             NFT nft = nftService.createToken(user.getNftAccount());
             if (nft != null) {
-                Asset asset = Asset.builder()
-                        .userId(user.getId())
-                        .orderId(order.getId())
-                        .collectionId(order.getCollectionId())
-                        .minter(winItem.getMinter())
-                        .minterId(winItem.getMinterId())
-                        .minterAvatar(winItem.getMinterAvatar())
-                        .name(winItem.getName())
-                        .detail(winItem.getDetail())
-                        .pic(winItem.getPic())
-                        .properties(winItem.getProperties())
-                        .canResale(winItem.isCanResale())
-                        .royalties(winItem.getRoyalties())
-                        .serviceCharge(winItem.getServiceCharge())
-                        .tokenId(nft.getTokenId())
-                        .blockNumber(nft.getBlockNumber())
-                        .txHash(nft.getTxHash())
-                        .gasUsed(nft.getGasUsed())
-                        .price(order.getPrice())
-                        .status(AssetStatus.NORMAL)
-                        .ipfsUrl(ipfsUpload(winItem.getPic().get(0).getUrl()))
-                        .build();
+                asset.setTokenId(nft.getTokenId());
+                asset.setBlockNumber(nft.getBlockNumber());
+                asset.setTxHash(nft.getTxHash());
+                asset.setGasUsed(nft.getGasUsed());
+                asset.setIpfsUrl(ipfsUpload(asset.getPic().get(0).getUrl()));
                 assetRepo.save(asset);
-                applicationContext.publishEvent(new CreateAssetEvent(this, true, order, asset));
-                return;
             }
         } catch (Exception e) {
-            log.error("创建token失败", e);
+            e.printStackTrace();
         }
-        applicationContext.publishEvent(new CreateAssetEvent(this, false, order, null));
+        applicationContext.publishEvent(new CreateAssetEvent(this, false, asset));
     }
 
     public String ipfsUpload(String url) {
         try {
-            IPFS ipfs = new IPFS("121.40.132.44", 5001);
+            IPFS ipfs = new IPFS("112.74.34.84", 5001);
             HttpRequest request = HttpRequest.get(url);
             File file = File.createTempFile("ipfs", ".tmp");
             request.receive(file);
@@ -396,7 +385,6 @@ public class AssetService {
         }
     }
 
-
     public Object payOrderWeixin(Long id, String tradeType, String openId) throws WxPayException, EncoderException {
         GiftOrder order = giftOrderRepo.findById(id).orElseThrow(new BusinessException("订单不存在"));
         if (order.getStatus() != OrderStatus.NOT_PAID) {
@@ -437,6 +425,7 @@ public class AssetService {
         Asset asset = assetRepo.findById(giftOrder.getAssetId()).orElseThrow(new BusinessException("资产不存在"));
         User newOwner = userRepo.findById(giftOrder.getToUserId()).orElseThrow(new BusinessException("用户不存在"));
 
+        giftOrder.setPayMethod(payMethod);
         giftOrder.setStatus(OrderStatus.FINISH);
         giftOrder.setTransactionId(transactionId);
         giftOrder.setPayTime(LocalDateTime.now());

+ 53 - 1
src/main/java/com/izouma/nineth/service/NFTService.java

@@ -3,10 +3,13 @@ package com.izouma.nineth.service;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alipay.mychain.sdk.api.utils.Utils;
+import com.alipay.mychain.sdk.common.VMTypeEnum;
 import com.alipay.mychain.sdk.domain.transaction.LogEntry;
+import com.alipay.mychain.sdk.utils.ByteUtils;
 import com.antfinancial.mychain.baas.tool.restclient.RestClient;
 import com.antfinancial.mychain.baas.tool.restclient.RestClientProperties;
 import com.antfinancial.mychain.baas.tool.restclient.model.CallRestBizParam;
+import com.antfinancial.mychain.baas.tool.restclient.model.ClientParam;
 import com.antfinancial.mychain.baas.tool.restclient.model.Method;
 import com.antfinancial.mychain.baas.tool.restclient.model.ReceiptDecoration;
 import com.antfinancial.mychain.baas.tool.restclient.response.BaseResp;
@@ -113,7 +116,7 @@ public class NFTService {
                 .bizid(restClientProperties.getBizid())
                 .account(restClientProperties.getAccount())
                 .contractName(Constants.CONTRACT_NAME)
-                .methodSignature("safeTransferFrom(identity,identity,uint256)")
+                .methodSignature("transferFrom(identity,identity,uint256)")
                 .inputParamListStr(jsonArray.toJSONString())
                 .outTypes("[]")//合约返回值类型
                 .mykmsKeyId(restClientProperties.getKmsId())
@@ -147,4 +150,53 @@ public class NFTService {
         }
         throw new BusinessException("创建nft失败");
     }
+
+    public NFT setApprovalForAll(String account) throws Exception {
+        JSONArray jsonArray = new JSONArray();
+        jsonArray.add(Utils.getIdentityByName(account));
+        jsonArray.add(true);
+
+        CallRestBizParam callRestBizParam = CallRestBizParam.builder()
+                .orderId(String.valueOf(new SnowflakeIdWorker(0, 0).nextId()))
+                .bizid(restClientProperties.getBizid())
+                .account(restClientProperties.getAccount())
+                .contractName(Constants.CONTRACT_NAME)
+                .methodSignature("setApprovalForAll(identity,bool)")
+                .inputParamListStr(jsonArray.toJSONString())
+                .outTypes("[]")//合约返回值类型
+                .mykmsKeyId(restClientProperties.getKmsId())
+                .method(Method.CALLCONTRACTBIZASYNC)
+                .tenantid(restClientProperties.getTenantid())
+                .gas(500000L)
+                .build();
+        BaseResp resp = restClient.bizChainCallWithReceipt(callRestBizParam);
+        if (!resp.isSuccess()) {
+            log.info("EVM合约执行失败: " + resp.getCode() + ", " + resp.getData());
+        }
+        if ("200".equals(resp.getCode())) {
+            log.info("EVM合约执行成功");
+            // 合约调用交易回执内容
+            ReceiptDecoration txReceipt = JSON.parseObject(resp.getData(), ReceiptDecoration.class);
+            BigInteger gasUsed = txReceipt.getGasUsed();
+            long result = txReceipt.getResult();
+            log.info("EVM合约交易内容: 哈希 " + txReceipt.getHash() + ", 消耗燃料 " + gasUsed + ", 结果 " + result);
+        } else {
+            // 异步交易未成功需要根据状态码判断交易状态
+            log.error("EVM合约执行未成功: " + resp.getCode());
+        }
+        throw new BusinessException("创建nft失败");
+    }
+
+    public void deployContract() throws Exception {
+        ClientParam clientParam = restClient.createDeployContractTransaction(
+                restClientProperties.getDefaultAccount(),
+                "rest_sol_test_2ghd2g2fr",
+                ByteUtils.hexStringToBytes("6080604052606460005534801561001557600080fd5b50610128806100256000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631ab06ee514605857806360fe47b114608c5780636d4ce63c1460b6575b600080fd5b348015606357600080fd5b50608a600480360381019080803590602001909291908035906020019092919050505060de565b005b348015609757600080fd5b5060b46004803603810190808035906020019092919050505060e9565b005b34801560c157600080fd5b5060c860f3565b6040518082815260200191505060405180910390f35b816000819055505050565b8060008190555050565b600080549050905600a165627a7a723058205bcd66c88d325808b2a6429cba1e79b49c8a6cfa4190c9158d4b63a9030ea1d70029"),
+                VMTypeEnum.EVM,
+                50000L);
+        BaseResp resp = restClient.chainCall(
+                clientParam.getHash(),
+                clientParam.getSignData(),
+                Method.DEPLOYCONTRACT);
+    }
 }

+ 16 - 22
src/main/java/com/izouma/nineth/service/OrderService.java

@@ -207,15 +207,15 @@ public class OrderService {
 
     }
 
-    public void notifyAlipay(Long orderId, PayMethod payMethod, String transactionId) {
+    public void notifyOrder(Long orderId, PayMethod payMethod, String transactionId) {
         Order order = orderRepo.findById(orderId).orElseThrow(new BusinessException("订单不存在"));
         Collection collection = collectionRepo.findById(order.getCollectionId())
                 .orElseThrow(new BusinessException("藏品不存在"));
+        User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("用户不存在"));
         if (order.getStatus() == OrderStatus.NOT_PAID) {
             if (order.getType() == CollectionType.BLIND_BOX) {
                 List<BlindBoxItem> items = blindBoxItemRepo.findByBlindBoxId(order.getCollectionId());
 
-
                 Map<BlindBoxItem, Range<Integer>> randomRange = new HashMap<>();
                 int c = 0, sum = 0;
                 for (BlindBoxItem item : items) {
@@ -269,26 +269,21 @@ public class OrderService {
                 order.setTransactionId(transactionId);
                 order.setPayMethod(payMethod);
                 orderRepo.save(order);
-                assetService.createAsset(order, winItem);
-
-
+                Asset asset = assetService.createAsset(order, winItem);
+                assetService.mint(asset);
             } else {
-                order.setStatus(OrderStatus.PROCESSING);
-                order.setPayTime(LocalDateTime.now());
-                order.setTransactionId(transactionId);
-                order.setPayMethod(payMethod);
-                orderRepo.save(order);
-                assetService.createAsset(order);
-            }
-
-            if (collection.getSource() == CollectionSource.TRANSFER) {
-                Asset asset = assetRepo.findById(collection.getAssetId()).orElse(null);
-                if (asset != null) {
-                    asset.setStatus(AssetStatus.TRANSFERRED);
-                    asset.setPublicShow(false);
-                    asset.setPublicCollectionId(null);
-                    assetRepo.save(asset);
+                if (collection.getSource() == CollectionSource.TRANSFER) {
+                    Asset asset = assetRepo.findById(collection.getAssetId()).orElse(null);
+                    assetService.transfer(asset, user);
                     collectionRepo.delete(collection);
+                } else {
+                    order.setStatus(OrderStatus.PROCESSING);
+                    order.setPayTime(LocalDateTime.now());
+                    order.setTransactionId(transactionId);
+                    order.setPayMethod(payMethod);
+                    orderRepo.save(order);
+                    Asset asset = assetService.createAsset(order);
+                    assetService.mint(asset);
                 }
             }
         } else if (order.getStatus() == OrderStatus.CANCELLED) {
@@ -306,9 +301,8 @@ public class OrderService {
 
     @EventListener
     public void onCreateAsset(CreateAssetEvent event) {
-        Order order = event.getOrder();
         Asset asset = event.getAsset();
-
+        Order order = orderRepo.findById(asset.getOrderId()).orElseThrow(new BusinessException("订单不存在"));
         if (event.isSuccess()) {
             order.setTxHash(asset.getTxHash());
             order.setGasUsed(asset.getGasUsed());

+ 18 - 4
src/main/java/com/izouma/nineth/web/OrderNotifyController.java

@@ -10,6 +10,7 @@ import com.github.binarywang.wxpay.exception.WxPayException;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.izouma.nineth.config.AlipayProperties;
 import com.izouma.nineth.enums.PayMethod;
+import com.izouma.nineth.service.AssetService;
 import com.izouma.nineth.service.OrderService;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -36,6 +37,7 @@ public class OrderNotifyController {
     private final AlipayProperties alipayProperties;
     private final OrderService     orderService;
     private final WxPayService     wxPayService;
+    private final AssetService     assetService;
 
     @PostMapping("/order/alipay")
     @ResponseBody
@@ -65,10 +67,16 @@ public class OrderNotifyController {
             JSONObject body = JSON.parseObject(params.get("body"));
             String action = body.getString("action");
             switch (action) {
-                case "payOrder":
+                case "payOrder": {
                     Long orderId = body.getLong("orderId");
-                    orderService.notifyAlipay(orderId, PayMethod.ALIPAY, MapUtils.getString(params, "trade_no"));
+                    orderService.notifyOrder(orderId, PayMethod.ALIPAY, MapUtils.getString(params, "trade_no"));
                     break;
+                }
+                case "payGiftOrder": {
+                    Long orderId = body.getLong("orderId");
+                    assetService.giftNotify(orderId, PayMethod.ALIPAY, MapUtils.getString(params, "trade_no"));
+                    break;
+                }
             }
             return "success";
         }
@@ -84,10 +92,16 @@ public class OrderNotifyController {
         JSONObject attach = JSONObject.parseObject(notifyResult.getAttach());
         String action = attach.getString("action");
         switch (action) {
-            case "payOrder":
+            case "payOrder": {
                 Long orderId = attach.getLong("orderId");
-                orderService.notifyAlipay(orderId, PayMethod.WEIXIN, notifyResult.getTransactionId());
+                orderService.notifyOrder(orderId, PayMethod.WEIXIN, notifyResult.getTransactionId());
                 break;
+            }
+            case "payGiftOrder": {
+                Long orderId = attach.getLong("orderId");
+                assetService.giftNotify(orderId, PayMethod.WEIXIN, notifyResult.getTransactionId());
+                break;
+            }
         }
         return WxPayNotifyResponse.success("OK");
     }

+ 1 - 1
src/main/java/com/izouma/nineth/web/OrderPayController.java

@@ -44,7 +44,7 @@ public class OrderPayController {
     @RequestMapping(value = "/gift/alipay", method = RequestMethod.GET)
     public String payGiftOrderAlipay(Long id, Model model, @RequestHeader(value = "User-Agent") String userAgent) {
         detectUA(userAgent, model);
-        orderService.payOrderAlipay(id, model);
+        assetService.payOrderAlipay(id, model);
         return "AlipayHtml";
     }
 

+ 1 - 0
src/main/nine-space/package.json

@@ -17,6 +17,7 @@
     "core-js": "^3.6.5",
     "dayjs": "^1.10.7",
     "echarts": "^4.9.0",
+    "element-ui": "^2.15.6",
     "html2canvas": "^1.3.2",
     "lodash": "^4.17.21",
     "mathjs": "^9.5.1",

+ 3 - 0
src/main/nine-space/src/main.js

@@ -9,6 +9,8 @@ import 'vant/lib/index.css';
 import './styles/app.less';
 import './styles/font.less';
 import http from './plugins/http';
+// import ElementUI from 'element-ui';
+// import 'element-ui/lib/theme-chalk/index.css';
 import PageTitle from './components/PageTitle';
 import LikeButton from './components/LikeButton.vue';
 import Driver from './components/Driver.vue';
@@ -56,6 +58,7 @@ http.http
 createApp(App)
     .use(Vant)
     .use(http)
+    // .use(ElementUI)
     .use(ConfigProvider)
     .use(VueClipboard)
     .mixin(common)

+ 10 - 0
src/main/nine-space/src/router/index.js

@@ -156,6 +156,16 @@ const routes = [
         name: 'verifiedSuc',
         component: () => import('../views/account/VerifiedSuc.vue')
     },
+    {
+        path: '/verifiedSucs',
+        name: 'verifiedSucs',
+        component: () => import('../views/account/VerifiedSucs.vue')
+    },
+    {
+        path: '/Authentication',
+        name: 'Authentication',
+        component: () => import('../views/account/Authentication.vue')
+    },
     {
         path: '/setting',
         name: 'userSetting',

+ 2 - 2
src/main/nine-space/src/views/Mine.vue

@@ -43,7 +43,7 @@
                         size="mini"
                         :icon="require('../assets/renzheng_icon_pre.png')"
                         round
-                        @click="$router.push('/verifiedSuc')"
+                        @click="$router.push('/Authentication')"
                         v-if="authStatus === '已认证'"
                         class="verid"
                     >
@@ -194,7 +194,7 @@ export default {
             if (this.authStatus === '认证中' || this.authStatus === '认证失败') {
                 this.$router.push('/waiting');
             } else if (this.authStatus === '未认证') {
-                this.$router.push('/verified');
+                this.$router.push('/Authentication');
             }
         }
     }

+ 93 - 0
src/main/nine-space/src/views/account/Authentication.vue

@@ -0,0 +1,93 @@
+<template>
+    <div class="container">
+        <div class="title">实名认证请选择</div>
+        <div class="name">账户实名认证后不能修改,<span>请使用本人身份信息完成认证</span></div>
+        <div class="box" @click="$router.push('/verified')">
+            <img
+                class="img"
+                src="https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/image/2021-11-11-10-16-06dTNltVml.png"
+                alt=""
+            />
+            <div class="text">个人认证</div>
+            <div class="btn">下一步</div>
+        </div>
+        <!-- <div class="box box1" @click="$router.push('/verifiedSucs')">
+            <img
+                class="img"
+                src="https://ticket-exchange.oss-cn-hangzhou.aliyuncs.com/image/2021-11-11-10-16-35hyCazZgd.png"
+                alt=""
+            />
+            <div class="text">企业认证</div>
+            <div class="btn">下一步</div>
+        </div> -->
+    </div>
+</template>
+
+<script>
+export default {
+    data() {
+        return {};
+    },
+    computed: {},
+    methods: {}
+};
+</script>
+
+<style lang="less" scoped>
+.container {
+    padding: 0 16px;
+    .btn {
+        width: 80px;
+        height: 34px;
+        background: linear-gradient(135deg, #fdfb60 0%, #ff8f3e 100%);
+        border-radius: 22px;
+        color: #333230;
+        font-size: 16px;
+        text-align: center;
+        line-height: 34px;
+    }
+    .title {
+        height: 42px;
+        font-size: 20px;
+        font-weight: 400;
+        color: #ffffff;
+        line-height: 42px;
+        padding-top: 10px;
+    }
+    .name {
+        font-size: 12px;
+        font-weight: 400;
+        color: #939599;
+        line-height: 22px;
+        margin: 10px 0 40px;
+    }
+    span {
+        color: #fdfb60;
+    }
+    .box {
+        display: flex;
+        align-items: center;
+        width: 303px;
+        height: 88px;
+        background: #1f2021;
+        border: 1px solid;
+        border-image: linear-gradient(135deg, rgba(253, 251, 96, 1), rgba(255, 143, 62, 1)) 1 1;
+        border-radius: 10px;
+        .img {
+            width: 38px;
+            height: 38px;
+            margin-left: 30px;
+        }
+        &.box1 {
+            margin-top: 30px;
+        }
+        .text {
+            font-size: 16px;
+            font-weight: bold;
+            margin: 0 50px 0 16px;
+            color: #ffffff;
+            line-height: 24px;
+        }
+    }
+}
+</style>

+ 3 - 12
src/main/nine-space/src/views/account/Verified.vue

@@ -1,7 +1,7 @@
 <template>
     <div class="login">
         <div class="tabs">
-            <div class="text1">实名认证</div>
+            <div class="text1">个人认证</div>
             <div class="text2">
                 <span>账户实名认证后不能修改,</span>
                 <span>请使用本人身份信息完成认证</span>
@@ -168,19 +168,10 @@ export default {
                     let form = { ...this.form };
                     form.userId = this.userInfo.id;
                     form.status = 'PENDING';
-                    let userInfo = {
-                        ...this.userInfo
-                    };
-                    userInfo.authorities = [
-                        ...userInfo.authorities,
-                        {
-                            name: 'ROLE_PERSONAL',
-                            description: '个人机构'
-                        }
-                    ];
+                    form.org = false;
                     this.$http
                         .post('/identityAuth/apply', {
-                            userInfo
+                            ...form
                         })
                         .then(() => {
                             this.$router.replace('/Waiting');

+ 440 - 0
src/main/nine-space/src/views/account/VerifiedSucs.vue

@@ -0,0 +1,440 @@
+<template>
+    <div class="login">
+        <div class="tabs">
+            <div class="text1">企业认证</div>
+            <div class="text2">
+                <span>账户实名认证后不能修改,</span>
+                <span>请使用本人身份信息完成认证</span>
+            </div>
+        </div>
+
+        <van-form @submit="submit" @failed="failed" ref="form">
+            <van-field
+                label="法人姓名"
+                name="法人姓名"
+                placeholder="请输入您法人姓名"
+                v-model="form.realName"
+                :rules="[{ required: true, message: '请输入您法人姓名' }]"
+            >
+            </van-field>
+            <!-- 
+            <van-field
+                type="tel"
+                label="手机号码"
+                name="手机号码"
+                placeholder="请输入您的手机号码"
+                v-model="form.phone"
+                :maxlength="11"
+                :rules="[
+                    { required: true, message: '请输入您的手机号码' },
+                    {
+                        pattern: phonePattern,
+                        message: '手机号码格式错误'
+                    }
+                ]"
+            >
+            </van-field> -->
+
+            <!-- <van-field
+                label="电子邮箱"
+                name="电子邮箱"
+                placeholder="请输入电子邮箱"
+                v-model="form.email"
+                :rules="[
+                    { required: true, message: '请输入电子邮箱' },
+                    {
+                        pattern: emailPattern,
+                        message: '电子邮箱格式错误'
+                    }
+                ]"
+            >
+            </van-field> -->
+
+            <van-field
+                label="身份证号"
+                name="身份证号"
+                placeholder="请输入身份证号"
+                v-model="form.idNo"
+                :rules="[
+                    { required: true, message: '请输入身份证号' },
+                    {
+                        pattern: IDPattern,
+                        message: '身份证号格式错误'
+                    }
+                ]"
+            >
+            </van-field>
+
+            <van-field
+                label="身份证照片(正面照)"
+                name="正面照"
+                v-model="form.idFront"
+                class="img"
+                :rules="[
+                    {
+                        validator: val => {
+                            return !!this.form.idFront;
+                        },
+                        message: '请上传身份证正面照片'
+                    }
+                ]"
+            >
+                <template #input>
+                    <div class="img-content">
+                        <van-image
+                            :src="form.idFront || require('../../assets/svgs/bg-png.svg')"
+                            fit="cover"
+                            radius="20"
+                        />
+                        <van-uploader name="idFront" result-type="file" :after-read="afterRead" />
+                    </div>
+                </template>
+            </van-field>
+            <van-field
+                label="身份证照片(反面照)"
+                name="反面照"
+                v-model="form.idBack"
+                class="img"
+                :rules="[
+                    {
+                        validator: val => {
+                            return !!this.form.idBack;
+                        },
+                        message: '请上传身份证反面照片'
+                    }
+                ]"
+            >
+                <template #input>
+                    <div class="img-content">
+                        <van-image
+                            :src="form.idBack || require('../../assets/svgs/bg-png.svg')"
+                            fit="cover"
+                            radius="20"
+                        />
+                        <van-uploader name="idBack" result-type="file" :after-read="afterRead" />
+                    </div>
+                </template>
+            </van-field>
+            <van-field
+                label="企业名称"
+                name="企业名称"
+                placeholder="请输入企业名称"
+                v-model="form.orgName"
+                :rules="[{ required: true, message: '请输入企业名称' }]"
+            >
+            </van-field>
+            <div class="name">工商营业执照注册号/统一社会信用代码</div>
+            <van-field
+                placeholder="工商营业执照注册号/统一社会信用代码"
+                v-model="form.orgNo"
+                :rules="[{ required: true, message: '工商营业执照注册号/统一社会信用代码' }]"
+            >
+            </van-field>
+            <van-checkbox :value="checked" @change="onChange">长期</van-checkbox>
+            <!-- <van-field name="isPostPoster" label="9.是否在明显位置张贴《疫情防控指南》海报?">
+                <template #input>
+                    <van-radio-group v-model="formData.isPostPoster" direction="horizontal">
+                        <van-radio :name="true">
+                            是
+                            <template #icon="props">
+                                <img class="img-icon" :src="props.checked ? activeIcon : inactiveIcon" />
+                            </template>
+                        </van-radio>
+                    </van-radio-group>
+                </template>
+            </van-field> -->
+            <van-field
+                label="例2034-06-17"
+                :value="form.startTime"
+                placeholder="请选择"
+                @click="pickerShow('newShow')"
+                readonly
+            >
+            </van-field>
+            <van-field
+                label="营业执照"
+                v-model="form.orgLicense"
+                class="img"
+                :rules="[
+                    {
+                        validator: val => {
+                            return !!this.form.orgLicense;
+                        },
+                        message: '请上传营业执照'
+                    }
+                ]"
+            >
+                <template #input>
+                    <div class="img-content">
+                        <van-image
+                            :src="form.orgLicense || require('../../assets/svgs/bg-png.svg')"
+                            fit="cover"
+                            radius="20"
+                        />
+                        <van-uploader name="orgLicense" result-type="file" :after-read="afterRead" />
+                    </div>
+                </template>
+            </van-field>
+            <van-popup :show="newShow" position="bottom" @close="onClose">
+                <van-datetime-picker
+                    type="date"
+                    :value="currentDate"
+                    @input="onInput"
+                    :min-date="minDate"
+                    :formatter="formatter"
+                />
+            </van-popup>
+            <div class="button" ref="btn">
+                <van-button
+                    round
+                    block
+                    @click="submit"
+                    color="linear-gradient(to right, #FDFB60, #FF8F3E)"
+                    class="sure"
+                >
+                    提交审核
+                </van-button>
+            </div>
+        </van-form>
+    </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import phone from '../../mixins/phone';
+export default {
+    computed: {
+        ...mapState(['userInfo'])
+    },
+
+    mixins: [phone],
+    data() {
+        return {
+            checked: true,
+            active: 'phone',
+            emailPattern: /^([a-zA-Z0-9]+[_|_|\-|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|_|.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,6}$/,
+            IDPattern: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/,
+            form: {
+                realName: '',
+                orgName: '',
+                orgNo: '',
+                idNo: '',
+                idFront: '',
+                idBack: '',
+                status: '',
+                orgLicense: ''
+            },
+            btn: null,
+            newShow: false,
+            currentDate: new Date().getTime(),
+            minDate: new Date().getTime(),
+            formatter(type, value) {
+                if (type === 'year') {
+                    return `${value}年`;
+                }
+                if (type === 'month') {
+                    return `${value}月`;
+                }
+                return value;
+            }
+        };
+    },
+    mounted() {
+        this.btn = this.$refs.btn;
+    },
+    methods: {
+        onInput(event) {
+            console.log(event);
+            var date = new Date(date);
+            this.setData({
+                currentDate: event.detail
+            });
+        },
+        pickerShow(key = 'show') {
+            this[key] = true;
+            // wx.hideKeyboard();
+        },
+        onChange(event) {
+            console.log(event);
+            this.setData({
+                checked: event.detail
+            });
+        },
+        // // 时间确认按钮
+        // onConfirm(event) {
+        //     this.currentDate = event.detail;
+        //     var timeValue = this.timeFormat(new Date(event.detail), 'yyyy-MM-dd hh:mm');
+        //     this.form.startTime = timeValue;
+        //     this.newShow = false;
+        // },
+        // // 时间取消按钮
+        // onCancel() {
+        //     this.newShow = false;
+        // },
+        submit() {
+            this.$refs.form
+                .validate()
+                .then(() => {
+                    let form = { ...this.form };
+                    form.userId = this.userInfo.id;
+                    form.status = 'PENDING';
+                    form.org = false;
+                    this.$http
+                        .post('/identityAuth/apply', {
+                            ...form
+                        })
+                        .then(() => {
+                            this.$router.replace('/Waiting');
+                        });
+                })
+                .catch(() => {
+                    this.bs.value.refresh();
+                });
+        },
+        afterRead(file, e) {
+            this.updateFile(file).then(img => {
+                this.form[e.name] = img;
+            });
+        },
+        failed() {
+            console.log('验证失败');
+        }
+    }
+};
+</script>
+
+<style lang="less" scoped>
+.login {
+    padding: 10px 16px 150px;
+}
+
+.tabs {
+    padding-bottom: 12px;
+    .text1 {
+        font-size: 20px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 30px;
+    }
+    .text2 {
+        font-size: 12px;
+        color: #939599;
+        line-height: 22px;
+        margin-top: 4px;
+        span {
+            &:last-child {
+                color: @prim;
+            }
+        }
+    }
+}
+.name {
+    font-size: 14px;
+    font-weight: bold;
+    color: #ffffff;
+    line-height: 24px;
+    margin-top: 10px;
+}
+.van-cell::after {
+    border-bottom-color: #202122;
+}
+
+.icon {
+    display: block;
+    margin-top: 12px;
+}
+/deep/ .van-form {
+    // margin-top: 28px;
+    .van-cell {
+        padding: 0px 0;
+
+        .van-field__left-icon {
+            margin-right: 8px;
+        }
+    }
+
+    .van-field__body {
+        height: 70px;
+        align-items: center;
+    }
+
+    .van-field__label {
+        font-size: 14px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 24px;
+        margin-top: 25px;
+    }
+}
+.button {
+    margin-top: 60px;
+
+    .del {
+        margin-top: 20px;
+        border-color: #ffffff;
+    }
+
+    .sure {
+        color: @bg !important;
+    }
+
+    .van-button {
+        font-weight: bold;
+    }
+}
+
+.sub-code {
+    padding-right: 0;
+    border-width: 0;
+}
+
+.img {
+    display: flex;
+    padding: 20px 0 10px;
+
+    .img-label {
+        font-size: 14px;
+        font-weight: bold;
+        color: #ffffff;
+        line-height: 20px;
+        margin: 5px 12px 5px 0;
+        min-width: 86px;
+    }
+}
+
+.img-content {
+    position: relative;
+    /deep/.van-uploader {
+        position: absolute;
+        left: 0;
+        top: 0;
+        opacity: 0;
+        .van-uploader__upload {
+            width: 160px;
+            height: 160px;
+        }
+    }
+}
+
+.button {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-color: @bg2;
+    padding: 6px 42px;
+    z-index: 20;
+}
+
+/deep/.img {
+    &.van-cell {
+        margin-top: 20px;
+        .van-field__body {
+            height: 160px;
+        }
+        .van-field__label {
+            margin-top: 5px;
+        }
+    }
+}
+</style>

+ 32 - 4
src/main/nine-space/src/views/asset/Consignment.vue

@@ -6,7 +6,7 @@
         </div>
         <div class="border border1"></div>
         <div class="content">
-            <van-field type="number" label="寄售价格(元)" placeholder="请设置寄售价格" v-model="message" />
+            <van-field type="number" label="寄售价格(元)" placeholder="请设置寄售价格" v-model="price" />
         </div>
         <div class="border"></div>
         <div class="input">
@@ -35,11 +35,12 @@ export default {
     name: 'Top',
     data() {
         return {
-            password: '',
+            price: '',
             showKeyboard: false,
+            password: '',
             list: [
                 {
-                    title: '1. 作品寄售为单个作品价格?'
+                    title: '1. 作品寄售为单个作品价格'
                 },
                 {
                     title: '2. 用户将会看到加密作品的权益、加密空间的使用情况'
@@ -56,7 +57,34 @@ export default {
             ]
         };
     },
-    methods: {}
+    methods: {
+        submit() {
+            this.$http
+                .post('/user/verifyTradeCode', {
+                    tradeCode: this.password
+                })
+                .then(() => {
+                    this.$http
+                        .post('/asset/consignment', {
+                            id: this.$route.query.id,
+                            price: this.price
+                        })
+                        .then(res => {
+                            console.log(res);
+                        })
+                        .catch(e => {
+                            if (e) {
+                                this.$toast(e.error);
+                            }
+                        });
+                })
+                .catch(e => {
+                    if (e) {
+                        this.$toast(e.error);
+                    }
+                });
+        }
+    }
 };
 </script>
 

+ 4 - 2
src/main/nine-space/src/views/asset/Detail.vue

@@ -119,7 +119,7 @@
         </div> -->
         <div class="btn van-safe-area-bottom" ref="btn">
             <div class="btns1">
-                <div @click="$router.push('/giveSearch')">
+                <div @click="$router.push('/giveSearch?id' + info.id)">
                     <img
                         class="img"
                         src="https://9space-2021.oss-cn-shenzhen.aliyuncs.com/image/2021-11-09-15-17-04hsdZwERv.png"
@@ -130,7 +130,9 @@
                 <van-button class="btn1" type="primary" block round @click="Exhibition">{{
                     info.publicShow ? '取消展示' : '公开展示'
                 }}</van-button>
-                <van-button type="primary" block round @click="$router.push('/Consignment')">寄售上架</van-button>
+                <van-button type="primary" block round @click="$router.push('/Consignment?id' + info.id)"
+                    >寄售上架</van-button
+                >
             </div>
         </div>
 

+ 41 - 2
src/main/nine-space/yarn.lock

@@ -2061,6 +2061,13 @@ async-limiter@~1.0.0:
   resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz"
   integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
 
+async-validator@~1.8.1:
+  version "1.8.5"
+  resolved "https://registry.npmmirror.com/async-validator/download/async-validator-1.8.5.tgz?cache=0&sync_timestamp=1634529574100&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fasync-validator%2Fdownload%2Fasync-validator-1.8.5.tgz#dc3e08ec1fd0dddb67e60842f02c0cd1cec6d7f0"
+  integrity sha1-3D4I7B/Q3dtn5ghC8CwM0c7G1/A=
+  dependencies:
+    babel-runtime "6.x"
+
 async@^2.6.2:
   version "2.6.3"
   resolved "https://registry.npmjs.org/async/-/async-2.6.3.tgz"
@@ -2127,6 +2134,11 @@ babel-extract-comments@^1.0.0:
   dependencies:
     babylon "^6.18.0"
 
+babel-helper-vue-jsx-merge-props@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.nlark.com/babel-helper-vue-jsx-merge-props/download/babel-helper-vue-jsx-merge-props-2.0.3.tgz#22aebd3b33902328e513293a8e4992b384f9f1b6"
+  integrity sha1-Iq69OzOQIyjlEyk6jkmSs4T58bY=
+
 babel-loader@^8.1.0:
   version "8.2.3"
   resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz"
@@ -2181,7 +2193,7 @@ babel-plugin-transform-object-rest-spread@^6.26.0:
     babel-plugin-syntax-object-rest-spread "^6.8.0"
     babel-runtime "^6.26.0"
 
-babel-runtime@^6.26.0:
+babel-runtime@6.x, babel-runtime@^6.26.0:
   version "6.26.0"
   resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz"
   integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
@@ -3445,7 +3457,7 @@ deep-is@~0.1.3:
   resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
   integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
 
-deepmerge@^1.5.2:
+deepmerge@^1.2.0, deepmerge@^1.5.2:
   version "1.5.2"
   resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz"
   integrity sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==
@@ -3747,6 +3759,18 @@ electron-to-chromium@^1.3.867:
   resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.875.tgz"
   integrity sha512-K/rqxvLwZOshysgPOqfU1x8rfdFXyieYLdT1JYlLHkLj8gI/4Qh4Xi+KrO6kq4t3aNhp/wGSGOyR4ooYvXbvyg==
 
+element-ui@^2.15.6:
+  version "2.15.6"
+  resolved "https://registry.npmmirror.com/element-ui/download/element-ui-2.15.6.tgz#c9609add35af5a686a4b7685dc1d757c75e01df3"
+  integrity sha1-yWCa3TWvWmhqS3aF3B11fHXgHfM=
+  dependencies:
+    async-validator "~1.8.1"
+    babel-helper-vue-jsx-merge-props "^2.0.0"
+    deepmerge "^1.2.0"
+    normalize-wheel "^1.0.1"
+    resize-observer-polyfill "^1.5.0"
+    throttle-debounce "^1.0.1"
+
 elliptic@^6.5.3:
   version "6.5.4"
   resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz"
@@ -6357,6 +6381,11 @@ normalize-url@^3.0.0:
   resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz"
   integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==
 
+normalize-wheel@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npm.taobao.org/normalize-wheel/download/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45"
+  integrity sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=
+
 npm-run-path@^2.0.0:
   version "2.0.2"
   resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz"
@@ -7644,6 +7673,11 @@ requires-port@^1.0.0:
   resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz"
   integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
 
+resize-observer-polyfill@^1.5.0:
+  version "1.5.1"
+  resolved "https://registry.nlark.com/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
+  integrity sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ=
+
 resolve-cwd@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz"
@@ -8546,6 +8580,11 @@ thread-loader@^2.1.3:
     loader-utils "^1.1.0"
     neo-async "^2.6.0"
 
+throttle-debounce@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.npm.taobao.org/throttle-debounce/download/throttle-debounce-1.1.0.tgz?cache=0&sync_timestamp=1604313832516&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fthrottle-debounce%2Fdownload%2Fthrottle-debounce-1.1.0.tgz#51853da37be68a155cb6e827b3514a3c422e89cd"
+  integrity sha1-UYU9o3vmihVctugns1FKPEIuic0=
+
 through2@^2.0.0:
   version "2.0.5"
   resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz"

+ 1 - 1
src/main/pc-space/src/views/user/CollectionOrder.vue

@@ -156,7 +156,7 @@ export default {
                 customClass: 'myClass',
                 type: 'warning'
             }).then(() => {
-                this.$http.get('/order/del' + row.id).then(() => {
+                this.$http.post('/order/del/' + row.id).then(() => {
                     this.$message.success('删除成功');
                     setTimeout(() => {
                         this.getData();

+ 38 - 29
src/main/pc-space/src/views/user/EnterpriseAuthentication.vue

@@ -64,9 +64,10 @@
                         ></el-input>
                     </el-form-item>
                     <div class="content">
-                        <el-form-item prop="orgLicenseExpire" label="工商营业执照有效日期截止时间">
+                        <el-form-item @change="Price" prop="orgLicenseExpire" label="工商营业执照有效日期截止时间">
                             <el-date-picker
                                 v-model="sizeForm.orgLicenseExpire"
+                                :disabled="sizeForm.negotiateDirectly"
                                 type="date"
                                 style="width: 300px"
                                 value-format="yyyy-MM-dd"
@@ -74,9 +75,7 @@
                             >
                             </el-date-picker>
                         </el-form-item>
-                        <template>
-                            <el-radio v-model="sizeForm.radio" label="1">长期</el-radio>
-                        </template>
+                        <el-checkbox @change="Directly" v-model="sizeForm.negotiateDirectly">长期</el-checkbox>
                     </div>
                     <div class="description">证照有效截止日期需大于60天,如证照上日期为长期或无,请勾选长期</div>
                     <el-form-item label="营业执照" prop="orgLicense">
@@ -102,12 +101,12 @@ export default {
             sizeForm: {
                 realName: '',
                 orgLicenseExpire: '',
+                negotiateDirectly: false,
                 idFront: '',
                 orgLicense: '',
                 idBack: '',
                 orgName: '',
                 orgNo: '',
-                // phone: '',
                 idNo: '',
                 radio: '1'
             },
@@ -120,12 +119,25 @@ export default {
                     message: '请输入18位统一社会信用代码',
                     trigger: 'blur'
                 },
+                orgLicenseExpire: [
+                    {
+                        required: true,
+                        validator: (rule, value, callback) => {
+                            if (!this.sizeForm.negotiateDirectly) {
+                                if (!this.sizeForm.orgLicenseExpire) {
+                                    callback(new Error('请选择日期截止方式'));
+                                } else {
+                                    callback();
+                                }
+                            } else {
+                                callback();
+                            }
+                        }
+                    }
+                ],
                 idNo: { required: true, min: 18, max: 18, message: '请输入18位身份证号', trigger: 'blur' },
                 realName: { required: true, message: '请输入', trigger: 'blur' },
-                orgLicenseExpire: { required: true, message: '请选择', trigger: 'blur' },
-                // orgNo: { required: true, message: '请选择', trigger: 'blur' },
                 orgName: { required: true, message: '请输入企业名称', trigger: 'blur' },
-                // phone: { required: true, message: '请输入您的联系方式', trigger: 'blur' },
                 idFront: { required: true, message: '请添加您的法人身份证(正面)', trigger: 'blur' },
                 idBack: { required: true, message: '请添加您的法人身份证(反面)', trigger: 'blur' },
                 orgLicense: { required: true, message: '请添加营业执照', trigger: 'blur' }
@@ -147,23 +159,18 @@ export default {
             });
         }
     },
-    // created() {
-    //     this.$http
-    //         .get('/personal/my')
-    //         .then(res => {
-    //             this.sizeForm = {
-    //                 ...res,
-    //                 realName: this.userInfo.realName,
-    //                 phone: this.userInfo.phone,
-    //                 avatar: this.userInfo.avatar,
-    //                 email: this.userInfo.email
-    //             };
-    //         })
-    //         .catch(e => {
-    //             console.log(e);
-    //         });
-    // },
     methods: {
+        Price() {
+            if (this.sizeForm.orgLicenseExpire) {
+                this.sizeForm.negotiateDirectly = false;
+            }
+        },
+        Directly() {
+            if (this.sizeForm.negotiateDirectly == true) {
+                this.$set(this.sizeForm, 'orgLicenseExpire', undefined);
+            }
+            this.$forceUpdate();
+        },
         Jump() {
             this.$router.go(-1);
         },
@@ -185,12 +192,11 @@ export default {
         },
         preservation() {
             let form = { ...this.sizeForm };
+            delete form.negotiateDirectly;
             form.userId = this.userInfo.id;
             form.status = 'PENDING';
             form.org = true;
             console.log(form);
-            // let org = false;
-            // this.updateUser({ org: org }).then(res => {
             this.$http
                 .post('/identityAuth/apply', {
                     ...form
@@ -198,7 +204,6 @@ export default {
                 .then(res => {
                     this.$store.dispatch('getUserInfo', res);
                 });
-            // });
         }
     }
 };
@@ -225,8 +230,12 @@ export default {
     /deep/ .el-form-item__content {
         display: flex;
     }
-    /deep/ .el-radio {
-        margin-top: 14px;
+    /deep/ .el-checkbox {
+        margin-top: 12px;
+        border-radius: 50%;
+    }
+    /deep/ .el-checkbox__inner {
+        border-radius: 50%;
     }
     /deep/ .el-button {
         width: 130px;

+ 1 - 1
src/main/pc-space/src/views/user/PayRecord.vue

@@ -106,7 +106,7 @@ export default {
                 customClass: 'myClass',
                 type: 'warning'
             }).then(() => {
-                this.$http.get('/order/del' + row.id).then(() => {
+                this.$http.post('/order/del/' + row.id).then(() => {
                     this.$message.success('删除成功');
                     setTimeout(() => {
                         this.getData();

+ 3 - 3
src/main/pc-space/src/views/user/TransactionOrdes.vue

@@ -27,8 +27,8 @@
                 <el-table-column prop="payMethod" label="交易类型" width="158" :formatter="statusFormatter">
                 </el-table-column>
                 <el-table-column prop="name" label="藏品信息" width="164"> </el-table-column>
-                <el-table-column style="color: #fdfb60" prop="source" label="来源" width="130"> </el-table-column>
-                <el-table-column prop="username" label="去向" width="190"> </el-table-column>
+                <el-table-column style="color: #fdfb60" prop="minter" label="来源" width="130"> </el-table-column>
+                <!-- <el-table-column prop="username" label="去向" width="190"> </el-table-column> -->
                 <el-table-column prop="payTime" label="交易时间" width="198"> </el-table-column>
                 <el-table-column fixed="right" label="操作">
                     <template slot-scope="scope">
@@ -104,7 +104,7 @@ export default {
                 customClass: 'myClass',
                 type: 'warning'
             }).then(() => {
-                this.$http.get('/order/del' + row.id).then(() => {
+                this.$http.post('/order/del/' + row.id).then(() => {
                     this.$message.success('删除成功');
                     setTimeout(() => {
                         this.getData();

+ 92 - 90
src/main/vue/package-lock.json

@@ -1871,70 +1871,6 @@
           "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
           "dev": true
         },
-        "ansi-styles": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "color-convert": "^2.0.1"
-          }
-        },
-        "chalk": {
-          "version": "4.1.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true,
-          "optional": true
-        },
-        "emojis-list": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
-          "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
-          "dev": true,
-          "optional": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true,
-          "optional": true
-        },
-        "loader-utils": {
-          "version": "2.0.2",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
-          "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^2.1.2"
-          }
-        },
         "minimist": {
           "version": "1.2.5",
           "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
@@ -1949,28 +1885,6 @@
           "requires": {
             "minipass": "^3.1.1"
           }
-        },
-        "supports-color": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "vue-loader-v16": {
-          "version": "npm:vue-loader@16.8.3",
-          "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
-          "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "chalk": "^4.1.0",
-            "hash-sum": "^2.0.0",
-            "loader-utils": "^2.0.0"
-          }
         }
       }
     },
@@ -4636,7 +4550,7 @@
     },
     "de-indent": {
       "version": "1.0.2",
-      "resolved": "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
       "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=",
       "dev": true
     },
@@ -14077,6 +13991,94 @@
         }
       }
     },
+    "vue-loader-v16": {
+      "version": "npm:vue-loader@16.8.3",
+      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
+      "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "hash-sum": "^2.0.0",
+        "loader-utils": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true,
+          "optional": true
+        },
+        "emojis-list": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+          "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+          "dev": true,
+          "optional": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true,
+          "optional": true
+        },
+        "loader-utils": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
+          "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
     "vue-router": {
       "version": "3.5.3",
       "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.3.tgz",
@@ -14101,9 +14103,9 @@
       }
     },
     "vue-template-compiler": {
-      "version": "2.6.10",
-      "resolved": "https://registry.npm.taobao.org/vue-template-compiler/download/vue-template-compiler-2.6.10.tgz",
-      "integrity": "sha1-MjtPNJXwT6o1AzN6gvXWUHeZycw=",
+      "version": "2.6.14",
+      "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz",
+      "integrity": "sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==",
       "dev": true,
       "requires": {
         "de-indent": "^1.0.2",

+ 2 - 2
src/main/vue/package.json

@@ -26,7 +26,7 @@
     "randomstring": "^1.2.1",
     "resolve-url": "^0.2.1",
     "tinymce": "^5.2.2",
-    "vue": "^2.6.11",
+    "vue": "2.6.11",
     "vue-avatar-cropper": "^1.0.5",
     "vue-axios": "^2.1.5",
     "vue-chartjs": "^3.5.0",
@@ -50,6 +50,6 @@
     "prettier": "1.19.1",
     "style-resources-loader": "^1.3.3",
     "vue-cli-plugin-style-resources-loader": "^0.1.4",
-    "vue-template-compiler": "^2.6.14"
+    "vue-template-compiler": "2.6.11"
   }
 }

Plik diff jest za duży
+ 726 - 636
src/main/vue/yarn.lock


+ 6 - 3
src/test/java/com/izouma/nineth/service/NFTServiceTest.java

@@ -5,8 +5,6 @@ import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 
-import static org.junit.Assert.*;
-
 public class NFTServiceTest extends ApplicationTests {
     @Autowired
     private NFTService nftService;
@@ -27,7 +25,12 @@ public class NFTServiceTest extends ApplicationTests {
 
     @Test
     public void transferToken() throws Exception {
-        nftService.transferToken("0000000000000000000000000000000000000000000000000000000000000097",
+        nftService.transferToken("000000000000000000000000000000000000000000000000000000000000009d",
                 "9th_BHlKkGWw", "9th_test");
     }
+
+    @Test
+    public void setApprovalForAll() throws Exception {
+        nftService.setApprovalForAll("9th_test");
+    }
 }

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików