nieyuge 2 年之前
父节点
当前提交
677e057caa

+ 303 - 0
src/components/currency-list.vue

@@ -0,0 +1,303 @@
+<template>
+    <template v-if="!isSelect">
+        <div class="header">
+            <input
+                class="input" 
+                @input="onInput"
+                v-model="keywords"
+                placeholder="Search name" />
+            <img
+                class="icon-clear"
+                src="../static/img/icon-clear-search.svg" 
+                v-if="keywords"
+                @click="clearIpt" >
+        </div>
+        <div class="list-wrapper">
+            <template v-if="!showSearch">
+                <div
+                    class="list-item"
+                    :key="index"
+                    v-for="(item, index) in currencyInfoList">
+                    <div
+                        class="item-title"
+                        v-if="item.data.length">
+                        <template v-if="item.type == 1">
+                            <img class="icon" src="../static/img/icon-currency-category-01.svg" />
+                            <span>Cash</span>
+                        </template>
+                        <template v-else>
+                            <img class="icon" src="../static/img/icon-currency-category-02.svg" />
+                            <span>Crypto</span>
+                        </template>
+                    </div>
+                    <div
+                        class="item-detail"
+                        v-for="(data, idx) in item.data"
+                        :key="idx"
+                        @click="selectCurrency(data)">
+                        <div class="left">
+                            <img class="icon-currency" :src="data.currencies[0].iconPath" />
+                            <div class="currency-info">
+                                <div class="name">{{ data.currencies[0].currencyCode == 'USD' ? 'USD' : data.currencies[0].tokenSymbol }}</div>
+                                <div class="desc">{{ data.currencies[0].currencyCode == 'USD' ? 'Paypal' : data.currencies[0].currencyName }}
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="no-data" v-if="show_empty">
+                    Not found
+                </div>
+            </template>
+            <template v-else>
+                <div
+                    class="item-detail"
+                    :key="idx"
+                    v-for="(data, idx) in searchList"
+                    @click="selectCurrency(data)">
+                    <div class="left">
+                        <img class="icon-currency" :src="data.currencies[0].iconPath" />
+                        <div class="currency-info">
+                            <div class="name">{{ data.currencies[0].currencyCode == 'USD' ? 'USD' : data.currencies[0].tokenSymbol }}</div>
+                            <div class="desc">{{ data.currencies[0].currencyName }}</div>
+                        </div>
+                    </div>
+                </div>
+                <div class="no-data" v-if="!searchList.length">
+                    Not found
+                </div>
+            </template>
+        </div>
+    </template>
+    <template v-else>
+        <div class="list-wrapper">
+            <div class="list-item">
+                <div
+                    :key="idx"
+                    v-for="(data, idx) in isSelectData"
+                    @click="selectItem(data)">
+                    <div class="item-title">
+                        <img class="icon" :src="data.chainInfo.iconPath" />
+                        {{data.chainInfo.chainName}}
+                    </div>
+                    <div class="item-detail">
+                        <div class="left">
+                            <img class="icon-currency" :src="data?.iconPath" />
+                            <div class="currency-info">
+                                <div class="name">{{ data.currencyCode == 'USD' ? 'USD' : data.tokenSymbol }}</div>
+                                <div class="desc">{{ data.currencyCode == 'USD' ? 'Paypal' : data.currencyName }}</div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </template>
+</template>
+
+<script lang="ts" setup>
+import { ref, onBeforeMount, defineEmits } from 'vue';
+import Api from '../static/http/api';
+import { postRequest } from '../static/http';
+import { debounce } from '../static/utils';
+
+const keywords = ref('');
+const showSearch = ref(false);
+const currencyInfoList = ref([]);
+const searchList = ref([]);
+const show_empty = ref(false);
+const isSelect = ref(false);
+const isSelectData = ref(null);
+const listReqParams = {
+    params: {
+        pageNum: 1,
+        pageSize: 100,
+    },
+    loadMore: false,
+};
+const emits = defineEmits(['selectCurrencyItem'])
+
+const clearIpt = () => {
+    keywords.value = '';
+    showSearch.value = false;
+    searchList.value = [];
+}
+const onInput = (val: any) => {
+    console.log(keywords.value);
+    if (keywords.value) {
+        showSearch.value = true;
+        searchCurrency(keywords.value);
+    } else {
+        showSearch.value = false;
+        searchList.value = [];
+    }
+}
+
+const searchCurrency = debounce(function (searchWords: any) {
+    postRequest(Api.searchCurrencyInfo, {
+        params: {
+            pageNum: 1,
+            pageSize: 100,
+            searchWords,
+            filterFiatCurrency: false
+        }
+    }).then(res => {
+        if (res.code == 0) {
+            if (res.data.currencyCategories && res.data.currencyCategories.length) {
+                let list = res.data.currencyCategories[0];
+                if (list && list.data && list.data.length) {
+                    searchList.value = list.data;
+                } else {
+                    searchList.value = [];
+                }
+            } else {
+                searchList.value = [];
+            }
+        }
+    })
+}, 500)
+
+const getCurrencyInfoList = () => {
+    postRequest(Api.getCurrencyInfo, {
+        params: {
+            pageNum: listReqParams.params.pageNum,
+            pageSize: listReqParams.params.pageSize,
+            filterFiatCurrency: false,
+            filterEmptyBalance: false
+        }
+    }).then(res => {
+        if (res.code == 0) {
+            let resData = res.data;
+            if (resData && resData.currencyCategories.length) {
+                if (listReqParams.params.pageNum < 2) {
+                    currencyInfoList.value = res.data.currencyCategories;   
+                    if(resData.currencyCategories.length == 1 && (!resData.currencyCategories[0]['data'] || !resData.currencyCategories[0]['data'].length)) {
+                        show_empty.value = true
+                    }
+                } else {
+                    let data = currencyInfoList.value;
+                    let currencyCategories = resData.currencyCategories;
+                    data = data.concat(currencyCategories);
+                    currencyInfoList.value = data;
+                }
+                listReqParams.loadMore = false;
+            } else {
+                show_empty.value = true
+            }
+        }
+    })
+}
+
+const selectItem = (data: any) => {
+    emits('selectCurrencyItem', data);
+}
+
+const selectCurrency = (data: any) => {
+    if (data.currencies.length > 1) {
+        isSelect.value = true;
+        isSelectData.value = data.currencies;
+    } else {
+        emits('selectCurrencyItem', data.currencies[0]);
+    }
+}
+
+onBeforeMount(() => {
+    getCurrencyInfoList()
+})
+
+</script>
+
+<style lang="less" scoped>
+.header {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    height: 60px;
+    background: #F7F7F7;
+    .input {
+        width: calc(100% - 20px);
+        height: calc(100% - 20px);
+        background: #f1f1f1;
+        border-radius: 110px;
+        box-sizing: border-box;
+        border: none;
+        outline: none;
+        padding: 10px 80px 10px 22px;
+        color: #adadad;
+    }
+    input::placeholder {
+        color: #adadad;
+    }
+    .icon-clear {
+        position: absolute;
+        right: 6%;
+        cursor: pointer;
+    }
+}
+
+.list-wrapper {
+    overflow-y: auto;
+    max-height: calc(420px - 60px);
+    .list-item {
+        .item-title {
+            display: flex;
+            align-items: center;
+            height: 42px;
+            padding: 0 10px;
+            box-sizing: border-box;
+            background: #fafafa;
+            font-size: 14px;
+            color: #a2a2a2;
+
+            .icon {
+                width: 24px;
+                height: 24px;
+                margin-right: 6px;
+            }
+        }
+    }
+    .item-detail {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        padding: 12px 20px;
+        box-sizing: border-box;
+        cursor: pointer;
+
+        .left {
+            display: flex;
+
+            .icon-currency {
+                width: 24px;
+                height: 24px;
+                margin-right: 12px;
+                margin-top: 4px;
+            }
+
+            .currency-info {
+                .name {
+                    font-weight: 500;
+                    font-size: 15px;
+                    margin-bottom: 5px;
+                    word-break: break-all;
+                }
+
+                .desc {
+                    font-weight: 400;
+                    font-size: 12px;
+                    color: #a2a2a2;
+                }
+            }
+        }
+    }
+    .no-data {
+        font-weight: 500;
+        font-size: 22px;
+        color: #BBBBBB;
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+    }
+}
+</style>

+ 75 - 3
src/pages/nft/add.vue

@@ -52,12 +52,20 @@
 
 
                 <div class="name">NFTs Price</div>
                 <div class="name">NFTs Price</div>
                 <div class="price">
                 <div class="price">
-                    <div class="currency">
-                        <img class="head" src="" alt="" />
-                        <div class="font">SHBI</div>
+                    <div class="currency" @click="showCurrencyDialog" v-if="currencyItem">
+                        <img class="head" :src="currencyItem.iconPath" alt="" />
+                        <div class="font">{{currencyItem.currencyName}}</div>
                         <img class="arrow" src="../../static/img/icon-add-arrow.svg" alt="" />
                         <img class="arrow" src="../../static/img/icon-add-arrow.svg" alt="" />
                     </div>
                     </div>
+                    <div class="no-select" @click="showCurrencyDialog" v-else>
+                        <div class="font">Select a reward</div>
+                        <img class="arrow" src="../../static/img/icon-add-arrow-white.svg" alt="" />
+                    </div>
                     <div class="input"><input type="text" /></div>
                     <div class="input"><input type="text" /></div>
+                    <!-- 货币列表 -->
+                    <div class="currency-pop" v-if="currencyDialog">
+                        <currency-list @selectCurrencyItem="selectCurrencyItem"></currency-list>
+                    </div>
                 </div>
                 </div>
 
 
                 <div class="explain">
                 <div class="explain">
@@ -95,6 +103,8 @@
         <button class="btn">Done</button>
         <button class="btn">Done</button>
     </div>
     </div>
     <div class="succ-bg" v-if="showSuccess"></div>
     <div class="succ-bg" v-if="showSuccess"></div>
+
+    <div class="mask-bg" v-if="currencyDialog" @click="hideCurrencyDialog"></div>
 </template>
 </template>
 
 
 <script lang="ts" setup>
 <script lang="ts" setup>
@@ -102,6 +112,7 @@ import { ref, onMounted } from 'vue';
 import Api from '../../static/http/api';
 import Api from '../../static/http/api';
 import { postRequest } from '../../static/http';
 import { postRequest } from '../../static/http';
 import { uploadFile } from '../../static/utils/upload'
 import { uploadFile } from '../../static/utils/upload'
+import currencyList from '../../components/currency-list.vue';
 
 
 const isNext = ref(false);
 const isNext = ref(false);
 const isUpload = ref(false);
 const isUpload = ref(false);
@@ -110,6 +121,8 @@ const showSuccess = ref(false);
 const maxSize = ref(1000);
 const maxSize = ref(1000);
 const configList = ref([]);
 const configList = ref([]);
 const selectItem = ref(null);
 const selectItem = ref(null);
+const currencyDialog = ref(false);
+const currencyItem = ref(null);
 
 
 const getConfig = () => {
 const getConfig = () => {
     postRequest(Api.createConfig).then(res => {
     postRequest(Api.createConfig).then(res => {
@@ -128,6 +141,19 @@ const select = (item: any) => {
     selectItem.value = item;
     selectItem.value = item;
 }
 }
 
 
+const showCurrencyDialog = () => {
+    currencyDialog.value = true;
+}
+
+const hideCurrencyDialog = () => {
+    currencyDialog.value = false;
+}
+
+const selectCurrencyItem = (data: any) => {
+    currencyItem.value = data;
+    hideCurrencyDialog();
+}
+
 const uploadImg = (e: any) => {
 const uploadImg = (e: any) => {
     let file = e.target.files[0];
     let file = e.target.files[0];
     // 清空file
     // 清空file
@@ -329,6 +355,7 @@ onMounted(() => {
                 }
                 }
             }
             }
             .price {
             .price {
+                position: relative;
                 display: flex;
                 display: flex;
                 justify-content: space-between;
                 justify-content: space-between;
                 .currency {
                 .currency {
@@ -362,10 +389,47 @@ onMounted(() => {
                         margin-left: 8px
                         margin-left: 8px
                     }
                     }
                 }
                 }
+                .no-select {
+                    display: flex;
+                    align-items: center;
+                    justify-content: center;
+                    flex-direction: row;
+                    cursor: pointer;
+                    height: 43px;
+                    padding: 0 14px;
+                    margin-right: 13px;
+                    border-radius: 25px;
+                    background: #1d9bf0;
+                    .font {
+                        max-width: 250px;
+                        color: #fff;
+                        font-size: 15px;
+                        font-weight: 500;
+                        white-space: nowrap;
+                        overflow: hidden;
+                        text-overflow: ellipsis;
+                    }
+                    .arrow {
+                        margin-left: 8px
+                    }
+                }
                 .input {
                 .input {
                     flex: 1;
                     flex: 1;
                     margin-bottom: 0;
                     margin-bottom: 0;
                 }
                 }
+
+                .currency-pop {
+                    position: absolute;
+                    overflow: hidden;
+                    z-index: 3;
+                    left: 0;
+                    bottom: 50px;
+                    width: 375px;
+                    max-height: 420px;
+                    border-radius: 20px;
+                    background-color: #fff;
+                    box-shadow: 0px 4px 20px rgba(0, 0, 0, 0.25);
+                }
             }
             }
             .explain {
             .explain {
                 color: #B4B4B4;
                 color: #B4B4B4;
@@ -518,4 +582,12 @@ onMounted(() => {
     height: 100%;
     height: 100%;
     background: rgba(0, 0, 0, .8);
     background: rgba(0, 0, 0, .8);
 }
 }
+.mask-bg {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 2;
+    width: 100%;
+    height: 100%;
+}
 </style>
 </style>

+ 2 - 0
src/static/http/api.ts

@@ -7,4 +7,6 @@ export default {
     'userNftSetStatus' : '/denet/nft/project/create/setPublishStatus',
     'userNftSetStatus' : '/denet/nft/project/create/setPublishStatus',
     'createConfig' : '/denet/nft/project/create/config',
     'createConfig' : '/denet/nft/project/create/config',
     'mediaUpload' : '/denet/media/uploadSignature',
     'mediaUpload' : '/denet/media/uploadSignature',
+    'getCurrencyInfo' : '/denet/currency/v2/getCurrencyInfo',
+    'searchCurrencyInfo' : '/denet/currency/v2/searchCurrencyInfo',
 }
 }

+ 8 - 1
src/static/http/index.ts

@@ -1,5 +1,6 @@
 // http封装库
 // http封装库
 import axios from 'axios';
 import axios from 'axios';
+import { removeStorage, storageKey } from '../utils/storage'
 import { getEnvConfig, getMid, getUserInfo, appVersionCode, } from '../utils';
 import { getEnvConfig, getMid, getUserInfo, appVersionCode, } from '../utils';
 // 测试数据(需手动开启关闭)
 // 测试数据(需手动开启关闭)
 import '../mockjs/index';
 import '../mockjs/index';
@@ -17,7 +18,13 @@ const instance = axios.create({
 
 
 // 响应拦截器
 // 响应拦截器
 instance.interceptors.response.use((res) => {
 instance.interceptors.response.use((res) => {
-    return res.data;
+    if (res.data.code === -107) {
+        // token失效
+        removeStorage(storageKey.userInfo);
+        location.href = `/`;
+    } else {
+        return res.data;
+    }
 }, function (err) {
 }, function (err) {
     return Promise.reject(err);
     return Promise.reject(err);
 });
 });

+ 3 - 0
src/static/img/icon-add-arrow-white.svg

@@ -0,0 +1,3 @@
+<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M10.7246 4.34766L6.37193 9L2.01925 4.34766" stroke="white" stroke-width="1.5"/>
+</svg>

+ 3 - 0
src/static/img/icon-clear-search.svg

@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM15.4115 7.31454L16.5933 8.49625L13.1818 11.9995L16.9753 15.6988L15.7935 16.8806L12.0001 13.1812L8.15904 16.8806L6.97733 15.6988L10.8184 11.9995L7.17299 8.49625L8.3547 7.31454L12.0001 10.8178L15.4115 7.31454Z" fill="#BCBCBC"/>
+</svg>

文件差异内容过多而无法显示
+ 1 - 0
src/static/img/icon-currency-category-01.svg


+ 3 - 0
src/static/img/icon-currency-category-02.svg

@@ -0,0 +1,3 @@
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M12.1243 5.01728L12.1 5.00382L12.0757 5.01728L6.75674 7.96928L6.67795 8.01301L6.75674 8.05672L9.46574 9.55972L9.4994 9.57839L9.52606 9.55064C10.1741 8.87593 11.0883 8.45 12.1 8.45C13.1117 8.45 14.0259 8.87593 14.6739 9.55064L14.7006 9.57839L14.7343 9.55972L17.4433 8.05672L17.5221 8.01301L17.4433 7.96928L12.1243 5.01728ZM11.1757 18.4877L11.25 18.5289V18.444V15.483V15.4441L11.2123 15.4345C9.67711 15.0441 8.55 13.6507 8.55 12C8.55 11.6886 8.5856 11.3875 8.66502 11.1139L8.67613 11.0757L8.64129 11.0563L5.82429 9.4903L5.75 9.449V9.534V15.447V15.4764L5.77574 15.4907L11.1757 18.4877ZM12.95 18.444V18.5289L13.0243 18.4877L18.4243 15.4907L18.45 15.4764V15.447V9.534V9.449L18.3757 9.4903L15.5587 11.0563L15.5242 11.0755L15.5349 11.1135C15.6144 11.3964 15.65 11.6977 15.65 12.009C15.65 13.6597 14.5229 15.0531 12.9877 15.4435L12.95 15.4531V15.492V18.444ZM12.1 3.0572L20.15 7.52942V16.4706L12.1 20.9428L4.05 16.4706V7.52942L12.1 3.0572ZM12.1 10.15C11.0824 10.15 10.25 10.9824 10.25 12C10.25 13.0176 11.0824 13.85 12.1 13.85C13.1176 13.85 13.95 13.0176 13.95 12C13.95 10.9824 13.1176 10.15 12.1 10.15Z" fill="#1D9BF0" stroke="#F7F7F7" stroke-width="0.1"/>
+</svg>

+ 12 - 1
src/static/utils/index.ts

@@ -84,4 +84,15 @@ export const getCookie = (name: string) => {
 // 设置cookie
 // 设置cookie
 export const setCookie = (name: string, val: any) => {
 export const setCookie = (name: string, val: any) => {
     Cookie.set(name, JSON.stringify(val), { expires: 1000 })
     Cookie.set(name, JSON.stringify(val), { expires: 1000 })
-}
+}
+
+export function debounce(fn: any, delay: number) {
+    let timer: number; // 定时器
+    return function (...args) {
+        let context = this;
+        timer && clearTimeout(timer);
+        timer = setTimeout(function () {
+            fn.apply(context, args);
+        }, delay);
+    };
+  }

部分文件因为文件数量过多而无法显示