Bläddra i källkod

Merge branch 'dev_1.1.6' into dev_v1.1.4_220720_optimization

wenliming 2 år sedan
förälder
incheckning
33046c96c0

+ 30 - 0
buildTestApp.sh

@@ -0,0 +1,30 @@
+
+#! /bin/bash
+env=$1
+if [ ! $env ]; then  
+    env='test'
+fi 
+
+echo '当前打包环境: '$env
+
+read -p "请输入压缩后的包名称(直接回车将使用 test_版本号 命名)" libname
+
+if [ ! $libname ]; then  
+    JQ_EXEC=`which jq`
+    FILE_PATH=./src/manifest.json
+    libname=test_$(cat $FILE_PATH | ${JQ_EXEC} .version | sed 's/\"//g')
+fi  
+
+echo '打包文件名: '$libname
+
+echo '----------------开始打包--------------------'
+
+yarn build-$env
+
+echo '----------------打包结束--------------------'
+
+zip $libname.zip dist/*
+
+open ./
+open $libname.zip -R
+

+ 1 - 0
package.json

@@ -5,6 +5,7 @@
   "scripts": {
     "serve": "vue-cli-service serve",
     "build-test": "vue-cli-service build --mode development",
+    "build-local": "sh buildTestApp.sh",
     "build-pre": "vue-cli-service build --mode pre",
     "build-prod": "vue-cli-service build --mode production",
     "lint": "vue-cli-service lint",

+ 6 - 1
src/http/fetch.js

@@ -61,7 +61,12 @@ export async function commonFetch({ url = '', method = 'POST' , params = {}, bas
                 resolve(data);
             })
             .catch((error) => {
-                reject({url: _url, error: error, requestParams: bodyObj});
+                if(!error) {
+                    error = {}
+                }
+                reject({url: _url, 
+                        error: { message: error.message, stack: error.stack }, 
+                        requestParams: bodyObj });
             });
     })
 }

+ 6 - 1
src/iframe/publish.js

@@ -3,7 +3,9 @@ import App from '@/view/iframe/publish/publish.vue'
 
 import "ant-design-vue/dist/antd.css"; // or 'ant-design-vue/dist/antd.less'
 
-import {Button,message,Tooltip, Switch} from "ant-design-vue";
+import { Button, message, Tooltip, Switch } from "ant-design-vue";
+
+import AutoLog from '@/log-center/autoLog';
 
 message.config({
     top: `10px`,
@@ -17,7 +19,10 @@ app.use(Button);
 app.use(Tooltip);
 app.use(message);
 app.use(Switch);
+app.use(AutoLog);
+
 
 import CoutomSentry from "@/uilts/sentry.js"
 CoutomSentry.initVue(app)
 app.mount('#app');
+

+ 29 - 0
src/log-center/autoLog/click.js

@@ -0,0 +1,29 @@
+// 点击埋点自定义属性
+
+import { reportLog } from '../logger';
+import { getTargetElementWhenClick } from '@/uilts/help';
+
+let clickDataMap = new Map();
+
+const clickHandle = (e) => { 
+    const target = getTargetElementWhenClick(e);
+    const logData = clickDataMap.get(target?.denetClickLogkey);
+    return  logData && reportLog({
+        ...logData
+    })
+}
+
+const clickLog =  {
+    mounted: (el, binding) => { 
+        const { value } = binding;
+        el.denetClickLogkey = el.denetClickLogkey || Math.random().toString(36).slice(-6);
+        clickDataMap.set(el.denetClickLogkey, value);
+        el.addEventListener('click', clickHandle,true)
+    },
+    unmounted(el) { 
+        // remove EventListener
+        el.removeEventListener('click', clickHandle, true)
+    }
+}
+
+export default clickLog;

+ 23 - 0
src/log-center/autoLog/index.js

@@ -0,0 +1,23 @@
+// 埋点插件
+
+import { showReportDialog } from '@sentry/vue';
+import clickLog from './click';
+import ShowLogObserver from './show';
+
+const AutoLog = {};
+
+AutoLog.install = (app) => { 
+    app.directive('click-log', clickLog);
+    app.directive('show-log', {
+        mounted(el, binding) {
+            // 加载阶段设置随机key标记当前元素
+            el.denetShowLogkey = el.denetShowLogkey || Math.random().toString(36).slice(-6);
+            ShowLogObserver.add(el, binding);
+        },
+        unmounted(el) {
+            ShowLogObserver.remove(el);
+        },
+    });
+}
+
+export default AutoLog;

+ 48 - 0
src/log-center/autoLog/show.js

@@ -0,0 +1,48 @@
+import { reportLog } from '../logger';
+import { getActiveKeyAfterClick } from '@/uilts/help';
+
+// 每个窗口共享一个Observer实例
+class ShowLogObserver { 
+    constructor() { 
+        this._observe = null;
+        this.showLogMap = new Map();
+        this.init();
+    }
+
+    init() {
+        this._observe = new IntersectionObserver((entries, observer) => {
+            entries.forEach((entry) => {
+                if (entry.isIntersecting) {
+                    this.report(entry);
+                    // show-log-once  ===  '1' &&  曝光之后取消观察
+                    if (entry?.target?.getAttribute('show-log-once') === '1') { 
+                        this.remove(entry.target);
+                    }
+                }
+            })
+        }, {
+            root: null,
+            rootMargin: '0px',
+            threshold: 1
+        })
+    }
+
+    remove(el) { 
+        this._observe.unobserve(el);
+        this.showLogMap.delete(el.denetShowLogkey);
+    }
+
+    add(el, binding) { 
+        this._observe.observe(el);
+        this.showLogMap.set(el.denetShowLogkey, binding.value)
+    }
+
+    report(el) { 
+        const logData = this.showLogMap.get(el?.target?.denetShowLogkey);
+        return  logData && reportLog({
+            ...logData
+        })
+    }
+}
+
+export default new ShowLogObserver();

+ 1 - 1
src/logic/background/twitter.js

@@ -310,7 +310,7 @@ export function onInstalledCreateTab() {
                         groupTabData: JSON.stringify({
                             deTabVal: 'deGroupTab'
                         })
-                    }, (res) => {
+                    }, (response) => {
                         let url = `https://twitter.com/${res.twitterAccount}`
                         chrome.tabs.create({
                             url

+ 20 - 2
src/logic/content/twitter.js

@@ -819,7 +819,6 @@ function initParseCard() {
                 if (queue_num <= 0) {
                     return
                 }
-                console.log('queue_num', queue_num)
                 initGroupTip()
                 setIframeRedPacket()
                 checkHasDeBtn()
@@ -868,6 +867,7 @@ export function init() {
     }
 
     if (window.location.host.includes('twitter.com')) {
+        onPageVisbile();
         renderDom();
         showNFTCard()
         showNFTGroupIcon()
@@ -911,6 +911,24 @@ export function init() {
     });
 }
 
+function onPageVisbile() {
+    document.addEventListener('visibilitychange', function () {
+        let isHidden = document.hidden;
+        if (!isHidden) {
+            depositUSShowPopupPage();
+        }
+    });
+}
+
+const depositUSShowPopupPage = async () => {
+    let {form = ''} = await getChromeStorage('achPayData') || {};
+    if(form == 'popupPage') {
+        showPopupPage();
+        chrome.storage.local.remove("achPayData");
+    }
+}
+
+
 function checkHasSliderDeBtn() {
     let deBtn = document.getElementById('de-btn');
     let deBtn3 = document.getElementById('de-btn3');
@@ -1600,7 +1618,7 @@ export const loginSuccessHandle = () => {
 
 export const showPublishDialog = () => {
     let smallBtn = document.getElementById('de-btn1');
-    if(smallBtn) {
+    if (smallBtn) {
         smallBtn.click();
     }
 }

+ 2 - 3
src/manifest.json

@@ -2,8 +2,8 @@
     "manifest_version": 3,
     "name": "DeNet",
     "description": "Growing more twitter followers with Denet",
-    "version": "1.1.5.1",
-    "denet_app_version_code": "16",
+    "version": "1.1.6",
+    "denet_app_version_code": "17",
     "background": {
         "service_worker": "/js/background.js"
     },
@@ -72,7 +72,6 @@
         "tabs",
         "action",
         "cookies",
-        "webNavigation",
         "declarativeNetRequest",
         "activeTab",
         "scripting",

+ 9 - 0
src/uilts/help.js

@@ -101,6 +101,15 @@ export function getBit(value) {
   }
 }
 
+export function getTargetElementWhenClick(e) { 
+  const { target, path } = e;
+  let result = null;
+  if (Array.isArray(path) && path.length > 0) { 
+    result = path.find((item) => item.denetClickLogkey)
+  }
+  return result
+}
+
 export function getCookie(name) {
   var strcookie = document.cookie; //获取cookie字符串
   var arrcookie = strcookie.split("; "); //分割

+ 20 - 3
src/view/iframe/buy-nft/buy/home.vue

@@ -1,5 +1,5 @@
 <template>
-    <div class="dialog">
+    <div class="dialog"  :style="{'height': dialogStyle.height + 'px'}">
         <!-- home -->
         <div class="area-title">
             <img :src="require('@/assets/svg/icon-close.svg')" @click="clickClose" />
@@ -87,6 +87,9 @@ import BtnLoading from '../components/btn-loading.vue'
 import { getQueryString } from "@/uilts/help";
 let pay_info = inject('pay_info');
 const router = useRouter()
+let dialogStyle = reactive({
+    height: '800'
+})
 let state = reactive({
     data: {
         salePlans: [
@@ -118,7 +121,19 @@ const clickJump = (item) => {
     pay_info.home.sale_plan = item
     router.push({ path: '/pay' });
 }
+
+const setDialogStyle = () => {
+    let clientHeight = window.innerHeight;
+    if(clientHeight >= 840) {
+        dialogStyle.height = 800;
+    } else {
+        dialogStyle.height = clientHeight - 40;
+    }
+}
+
 onMounted(() => {
+    setDialogStyle();
+
     let nft_project_Id = router.currentRoute.value.query.nftProjectId
     let nft_group_Id = router.currentRoute.value.query.nft_group_Id
     if(nft_group_Id){
@@ -151,7 +166,6 @@ onMounted(() => {
     max-width: 1000px;
     min-width: 1000px;
     max-height: 90%;
-    min-height: 800px;
     z-index: 23;
     display: flex;
     flex-direction: column;
@@ -184,7 +198,7 @@ onMounted(() => {
 
         img {
             width: 100%;
-            height: 100%;
+            object-fit: contain;
         }
     }
 
@@ -217,6 +231,7 @@ onMounted(() => {
             display: flex;
             padding: 15px 0;
             min-height: 50px;
+            box-sizing: border-box;
 
             .buy5 {
                 border: 1px solid #1D9BF0;
@@ -233,6 +248,7 @@ onMounted(() => {
                 font-size: 14px;
                 cursor: pointer;
                 margin-right: 12px;
+                box-sizing: border-box;
 
                 .left {
                     margin-right: 20px;
@@ -279,6 +295,7 @@ onMounted(() => {
                 justify-content: space-between;
                 padding: 0 15px 0 20px;
                 margin-right: 25px;
+                box-sizing: border-box;
 
                 .left {
                     margin-right: 20px;

+ 16 - 3
src/view/iframe/buy-nft/buy/pay.vue

@@ -1,5 +1,5 @@
 <template>
-    <div class="dialog">
+    <div class="dialog" :style="{'height': dialogStyle.height + 'px'}">
         <!-- home -->
         <div class="area-title">
             <img :src="require('@/assets/svg/icon-back.svg')" @click="clickBack" />
@@ -111,6 +111,10 @@ let currentCurrencyInfo = reactive({
     balance: "",
 });
 
+let dialogStyle = reactive({
+    height: '800'
+})
+
 const updateData = (obj_data) => {
     if (Number(obj_data.balance) >= Number(pay_info.home.sale_plan.price)) {
         state.is_btn_grey = false
@@ -196,9 +200,19 @@ const getCurrencyInfo = async () => {
     }
 }
 
+const setDialogStyle = () => {
+    let clientHeight = window.innerHeight;
+    if(clientHeight >= 840) {
+        dialogStyle.height = 800;
+    } else {
+        dialogStyle.height = clientHeight - 40;
+    }
+}
+
 onMounted(() => {
     currentCurrencyInfo.currencyCode = pay_info.home.sale_plan.currencyCode
-    getLocalCurrencyInfoByCode()
+    getLocalCurrencyInfoByCode();
+    setDialogStyle()
 })
 
 
@@ -210,7 +224,6 @@ onMounted(() => {
     max-width: 1000px;
     min-width: 800px;
     max-height: 90%;
-    min-height: 800px;
     z-index: 23;
     display: flex;
     flex-direction: column;

+ 32 - 1
src/view/iframe/nft/card.vue

@@ -23,7 +23,7 @@
 </template>
 
 <script setup>
-import { onBeforeMount, ref } from 'vue'
+import { onBeforeMount, ref, onMounted, onBeforeUnmount } from 'vue'
 import { getTwitterSaleNftProjectInfo, getNftProjectInfo } from '@/http/nft'
 import { pageUrl } from "@/http/configAPI.js"
 import { getChromeStorage, setChromeStorage } from '@/uilts/chromeExtension.js'
@@ -109,6 +109,7 @@ const share = () => {
 const buy = () => {
     getChromeStorage('userInfo', (_userInfo) => {
         if (!_userInfo) {
+            setChromeStorage({ buyNFTCardData: JSON.stringify({ action: 'buy' })});
             chrome.runtime.sendMessage(
                 { actionType: "POPUP_LOGIN", data: "" },
                 (response) => {
@@ -128,6 +129,14 @@ const buy = () => {
     })
 }
 
+const loginSuccessHandler = async () => {
+    let {action = ''} = await getChromeStorage('buyNFTCardData') || {};
+    if(action == 'buy') {
+        chrome.storage.local.remove("buyNFTCardData");
+        buy();
+    }
+} 
+
 onBeforeMount(() => {
     let urlParams = new URL(window.location.href);
     let searchParmas = new URLSearchParams(urlParams.search);
@@ -139,6 +148,28 @@ onBeforeMount(() => {
         getSaleInfo()
     }
 })
+
+const onRuntimeMsg = () => {
+    chrome.runtime.onMessage.addListener(msgListener)
+}
+
+
+const msgListener = (req, sender, sendResponse) => {
+    switch (req.actionType) {
+        case 'BG_LOGIN_SET_USERINFO_CB':
+            loginSuccessHandler();
+            break;
+    }
+}
+
+onMounted(() => {
+    onRuntimeMsg();
+})
+
+
+onBeforeUnmount(() => {
+    chrome.runtime.onMessage.removeListener(msgListener);
+})
 </script>
 
 <style lang='scss'>

+ 57 - 2
src/view/iframe/publish/give-dialog.vue

@@ -153,7 +153,7 @@
                                                         :src="require('@/assets/svg/icon-winner-v2.svg')"/>
                                                     Winner Count
                                                 </div>
-                                                <div class="msg" v-show="selectModeInfo.type == PlayType.common">Recommend Winners 100~10000</div>
+                                                <div class="msg" v-show="selectModeInfo.type == PlayType.common">Recommend Winners 50~500</div>
                                             </div>
                                             <input v-model="baseFormData.totalCount"
                                                 placeholder="0"
@@ -176,6 +176,7 @@
                                             </div>
                                         </div>
                                     </div>
+                                    <div class="usd-min-message" v-show="isShowUsdMinMessage" v-html="checkUsdMinNumber('inTemplate')"></div>
                                     <div class="giveaway-poster" @click="customCoverImg">
                                         <div class="show-img">
                                             <div
@@ -510,6 +511,9 @@ let atUserList = ref([]);
 // 表单错误提示
 let iptErrMsgTxt = ref("Select a reward");
 
+// usd最小金额限制提示展示
+let isShowUsdMinMessage = ref(false);
+
 // 是否返回
 let isBack = ref(false);
 
@@ -795,7 +799,7 @@ const setDialogStyle = (resize = false) => {
             dialogStyle.dialogHeight = clientHeight - gapSafe;
         } else {
             if(resize) {
-                dialogStyle.dialogHeight = 680;
+                dialogStyle.dialogHeight = 720;
             }
         }
 
@@ -1014,6 +1018,12 @@ const updateCurrencyBanlce = async () => {
     if(currentCurrencyInfo.value.currencyCode == 'USD') {
         let currencyInfoRes = await getCurrencyByCode({currencyCode: currentCurrencyInfo.value.currencyCode});
 
+        calcRechPayAmount({
+            currencyCode: currentCurrencyInfo.value.currencyCode,
+            orderAmountValue: baseFormData.amountValue,
+            payChannel: 'ach'
+        });
+
         if(currencyInfoRes.code == 0 && currencyInfoRes.data) {
             currentCurrencyInfo.value = currencyInfoRes.data;
         }
@@ -1372,6 +1382,32 @@ const calcIptValue = (cb) => {
     }
 };
 
+/**
+ * usd最小金额判断
+ * luckdropPostConfig.usdLimitEnable 当前选中的token是否开启usd最小金额判断
+ */
+const checkUsdMinNumber = (isInTemplate) => {
+    let forbiddenText = '';
+    const { usdPrice, luckdropPostConfig } = currentCurrencyInfo.value;
+    if (baseFormData.rewardType === RewardType.money && luckdropPostConfig?.usdLimitEnable === 1) {
+        const { amountValue, totalCount } = baseFormData;
+        if (luckdropPostConfig?.minTotalUsdAmount === 0 || luckdropPostConfig?.minAvgUsdAmount === 0) {
+            // 当前token允许的usd最小金额为0 或单个红包最小金额为0,则无限制
+            return forbiddenText;
+        } else {
+            const isAmountForbidden = luckdropPostConfig?.minTotalUsdAmount ? math.format(math.evaluate(amountValue * usdPrice)) < luckdropPostConfig.minTotalUsdAmount : false;
+            const isAvgForbidden = luckdropPostConfig?.minAvgUsdAmount ? math.format(math.evaluate(amountValue / totalCount * usdPrice)) < luckdropPostConfig.minAvgUsdAmount : false;
+            forbiddenText = isAmountForbidden && isAvgForbidden ? 
+                            `The prize pool must be above 
+                            ${isInTemplate ? ('<span class="font-color-1D9BF0">$' + luckdropPostConfig.minTotalUsdAmount + '</span>') : ('$' + luckdropPostConfig.minTotalUsdAmount)} 
+                            or the average prize must be above
+                            ${isInTemplate ? ('<span class="font-color-1D9BF0">$' + luckdropPostConfig.minAvgUsdAmount +' per person.</span>' ): ('$' + luckdropPostConfig.minAvgUsdAmount + ' per person.') }`
+                            : '';
+        }
+    }
+    return forbiddenText;
+};
+
 /**
  * 设置输入提示语
  */
@@ -1390,6 +1426,9 @@ const onIptSetErrorTxt = (params = {}) => {
         iptErrMsgTxt.value = "Enter an amount";
     } else if (!baseFormData.totalCount || baseFormData.totalCount == '0') {
             iptErrMsgTxt.value = "Enter the number of winners";
+    } else if (iptErrMsgTxt.value = checkUsdMinNumber()) {
+        // 最小法币金额限制
+        return isShowUsdMinMessage.value = true;
     } else if(baseFormData.rewardType === RewardType.money && +baseFormData.amountValue <= +currentCurrencyInfo.value.balance) {
         // 输入金额 小于 余额
         let res = calcIptValue();
@@ -1941,6 +1980,12 @@ onMounted(() => {
 });
 </script>
 
+<style lang="scss">
+.font-color-1D9BF0 {
+    color: #1D9BF0;
+}
+</style>
+
 <style lang="scss" scoped>
 
 :deep() .ant-switch {
@@ -2373,6 +2418,16 @@ onMounted(() => {
                     }
                 }
 
+                .usd-min-message {
+                    font-style: normal;
+                    font-weight: 400;
+                    font-size: 12px;
+                    line-height: 16px;
+                    letter-spacing: 0.3px;
+                    color: #C88726;
+                    margin-top: 8px;
+                }
+
                 .giveaway-poster {
                     display: flex;
                     align-items: center;

+ 5 - 1
src/view/iframe/publish/tool-box/child/editor.vue

@@ -153,7 +153,11 @@ const searchHandler = async (_params) => {
   }
   
   let convertRes = await convertUrl({ params: { originUrl: siteUrl.value } });
-  let params = { convertUrl: siteUrl.value, originUrl: siteUrl.value, appId: currentApp.appId, linkImagePath: currentApp.linkImagePath, currentApp };
+  let params = { convertUrl: siteUrl.value, 
+                  originUrl: siteUrl.value, 
+                  appId: currentApp.appId, 
+                  linkImagePath: currentApp.linkImagePath, 
+                  currentApp };
 
   loadingHide();
   clearTimeout(timer);

+ 5 - 5
src/view/iframe/publish/tool-box/child/preview.vue

@@ -37,7 +37,7 @@
                     <div class="card-wrapper" :style="{ 'zoom': reviewCanvasParams.zoom }">
                         <img class="cover" v-if="previewData.linkImagePath && previewData.appId"
                             :src="previewData.linkImagePath" />
-                        <iframe class="iframe" :src="previewData.convertUrl" scrolling="no" v-else></iframe>
+                        <iframe class="iframe" sandbox :src="previewData.convertUrl" scrolling="no" v-else></iframe>
 
                         <div class="bottom-bar">
                             <div class="site-url">DeNet.me</div>
@@ -120,7 +120,7 @@ const props = defineProps({
 watch(() => props.screenshotWebsiteData,
     (newVal) => {
         let { appId } = props.previewData;
-        if (loadingHide && !appId && (newVal.url || newVal.status)) {
+        if (loadingHide && (!appId || appId && !props.previewData.linkImagePath ) && (newVal.url || newVal.status)) {
             loadingHide();
             loadingHide = null;
             submitPublish();
@@ -198,7 +198,7 @@ const publishHandler = () => {
         return;
     }
 
-    if (!appId && !props.screenshotWebsiteData.url) {
+    if ((!appId || appId && !props.previewData.linkImagePath) && !props.screenshotWebsiteData.url) {
         loadingHide = message.loading('loading...', 0);
         return;
     }
@@ -398,7 +398,7 @@ onUnmounted(() => {
                     top: 90px;
 
                     .iframe {
-                        height: calc(100% - 73px);
+                        height: calc(100% - 71px);
                         width: 100%;
                         border: none;
                         pointer-events: none;
@@ -408,7 +408,7 @@ onUnmounted(() => {
                     .cover {
                         height: calc(100% - 73px);
                         width: 100%;
-                        object-fit: contain;
+                        object-fit: cover;
                     }
 
                     .bottom-bar {

+ 3 - 3
src/view/iframe/publish/tool-box/index.vue

@@ -64,9 +64,9 @@ const changeShowCom = (params) => {
     previewData.linkImagePath = params.linkImagePath || '';
     previewData.currentApp = params.currentApp || {};
 
-    if(!params.appId) {
-        screenshotWebsiteData.url = '';
-        screenshotWebsiteData.status = '';
+    screenshotWebsiteData.url = '';
+    screenshotWebsiteData.status = '';
+    if(!params.appId || params.appId && !params.linkImagePath) {
         screenshotWebsite({
             params: {
                 url: params.convertUrl

+ 1 - 1
src/view/iframe/tool-box/card.vue

@@ -8,7 +8,7 @@
             </div>
         </div>
         <div class="content" v-if="pre_view">
-            <iframe :src="iframe_url" frameborder="0"></iframe>
+            <iframe :src="iframe_url" frameborder="0" sandbox></iframe>
         </div>
         <div class="content" v-else>
             <iframe :src="state.iframe_url" v-show="state.status == 'iframe'" ref="dom_iframe" frameborder="0"

+ 3 - 0
src/view/popup/currency-detail.vue

@@ -294,6 +294,9 @@ const confirmDeposit = (params) => {
   };
   let guideUrl = chrome.runtime.getURL('/iframe/ach-cashier.html');
   setChromeStorage({ achPayInfo : JSON.stringify(achPayInfo)});
+  setChromeStorage({ achPayData : JSON.stringify({
+    form: 'popupPage'
+  })});
 
   chrome.tabs.create({
     url: guideUrl

+ 0 - 1
src/view/popup/tabbar-page/index.vue

@@ -111,7 +111,6 @@ const onRuntimeMsg = () => {
 }
 
 const msgListener = (req, sender, sendResponse) => {
-  ;
   switch (req.actionType) {
     case 'BG_LOGIN_SET_USERINFO_CB':
       if (!userInfo.value.accessToken) {