Explorar o código

[add] 发布接口联调

wenliming %!s(int64=3) %!d(string=hai) anos
pai
achega
07621cfc2e

+ 0 - 7
library/paypal.html

@@ -92,13 +92,6 @@
                                     var transaction =
                                         orderData.purchase_units[0].payments
                                             .captures[0];
-                                    alert(
-                                        "Transaction " +
-                                            transaction.status +
-                                            ": " +
-                                            transaction.id +
-                                            "\n\nSee console for all available details"
-                                    );
                                     amount = 0;
                                     window.parent.postMessage(
                                         {

+ 2 - 2
package.json

@@ -27,10 +27,10 @@
     "@vue/cli-service": "~5.0.0",
     "eslint": "^7.32.0",
     "eslint-plugin-vue": "^8.0.3",
-    "unplugin-auto-import": "^0.6.6",
-    "unplugin-vue-components": "^0.18.3",
     "node-sass": "^7.0.1",
     "sass-loader": "^12.6.0",
+    "unplugin-auto-import": "^0.6.6",
+    "unplugin-vue-components": "^0.18.3",
     "vue-cli-plugin-chrome-extension-cli": "~1.1.2"
   },
   "eslintConfig": {

+ 1 - 1
src/entry/content.js

@@ -29,7 +29,7 @@ window.onmessage = (res) => {
 				hideIframeHandler();
 				break;
 			case "IFRAME_SHOW_TWITTER_PUBLISH_DIALOG":
-				showTwitterPublishDialogHandler()
+				showTwitterPublishDialogHandler(res.data.publishRes)
 				break;
 		}
 	}

+ 27 - 0
src/http/publishApi.js

@@ -0,0 +1,27 @@
+import {
+  service
+} from "./request";
+
+export function postPublish(params) {
+  return service({
+    url: `/post/publish`,
+    method: 'post',
+    data: params
+  })
+}
+
+export function verifyPaypalResult(params) {
+    return service({
+      url: `/wallet/pay/verifyPaypalResult`,
+      method: 'post',
+      data: params
+    })
+}
+
+export function srcPublishSuccess(params) {
+    return service({
+      url: `/post/srcPublishSuccess`,
+      method: 'post',
+      data: params
+    })
+}

+ 65 - 0
src/http/request.js

@@ -0,0 +1,65 @@
+import axios from 'axios'
+import {getStorage} from "../uilts/chromeExtension"
+
+let baseUrl = 'https://denettestapi.piaoquantv.com/denet';
+let userInfo = '';
+// 创建axios实例
+export const service = axios.create({
+  baseURL: baseUrl, // api的base_url
+  timeout: 240000, // 请求超时时间
+  headers: {
+    'Content-Type': 'application/json', //指定消息格式
+    'Accept': 'application/json',
+  },
+})
+
+// request拦截器
+service.interceptors.request.use(config => {
+  if(!userInfo) {
+    userInfo = getStorage('de-userInfo');
+  }
+  const { accessToken: token = '' } = userInfo || {};
+
+  if (config.method === 'get') {
+    let {baseInfo = null} = config.params || {};
+    if(!baseInfo || !baseInfo.token) {
+      config['params']['baseInfo'] = {
+        token: token,
+      }
+    }
+    let params = {
+      ...config.params
+    }
+    config['params'] = params;
+  }
+
+  if (config.method === 'post') {
+    let {baseInfo = null} = config.data || {};
+    if(!baseInfo || !baseInfo.token) {
+      config['data']['baseInfo'] = {
+        token: token,
+      }
+    }
+    let data = {
+      ...config.data
+    }
+    config['data'] = data;
+  }
+  return config
+}, error => {
+  // Do something with request error
+  console.log(error) // for debug
+  Promise.reject(error)
+})
+
+// respone拦截器
+service.interceptors.response.use(
+  response => {
+    const res = response.data;
+    return res
+  },
+  error => {
+    console.log('err' + error) // for debug
+    return Promise.reject(error)
+  }
+)

+ 43 - 14
src/logic/twitter.js

@@ -1,6 +1,7 @@
 /* eslint-disable */
 import { getChromeStorage, setChromeStorage } from '../uilts/chromeExtension.js'
 import { getTtwitterRequestToken, twitterLogin } from '../server/twitter.js'
+import { srcPublishSuccess } from '../http/publishApi'
 
 let dom = {};
 
@@ -67,8 +68,8 @@ export function renderDom(port) {
 /**
  * 展示give弹窗
  */
-export function showGiveDialogHandler() {
-    dom.iframe.contentWindow.postMessage({ actionType: 'CONTENT_SHOW_GIVE_DIALOG' }, '*');
+export function showGiveDialogHandler(userInfo) {
+    dom.iframe.contentWindow.postMessage({ actionType: 'CONTENT_SHOW_GIVE_DIALOG', userInfo }, '*');
 }
 
 export function showIframeHandler() {
@@ -82,9 +83,27 @@ export function hideIframeHandler() {
 /**
  * 展示twitter原生发布框
  */
-export function showTwitterPublishDialogHandler() {
+export function showTwitterPublishDialogHandler(publishRes) {
     dom.tweetBtn.click();
-    _publishTweetEvent();
+    _setPublishContent(publishRes.srcContent);
+    _publishTweetEvent(publishRes.srcContent ,(twitterArtId) => {
+        if(twitterArtId) {
+            getUserInfo((userInfo) => {
+                if(userInfo) {
+                    srcPublishSuccess({
+                        baseInfo: {
+                            token: userInfo.accessToken
+                        },
+                        params : {
+                            postId: publishRes.postId,
+                            srcContentId: twitterArtId
+                        }
+                    }).then((res) => { 
+                    })
+                }
+            }) 
+        }
+    });
 }
 
 function getUserInfo(cb) {
@@ -97,14 +116,16 @@ function getUserInfo(cb) {
  * 监听dialog内点击原生发布按钮事件
  * @private
  */
-function _publishTweetEvent(cb) {
-    let publishTweetBtn = document.querySelector('div[role="dialog"]').querySelector('div[data-testid="tweetButton"]');
-    publishTweetBtn.addEventListener('click', function () {
-        setTimeout(() => {
-            let twitterArtId = _getTwitterArtId();
-            cb && cb(twitterArtId)
-        }, 1000)
-    });
+function _publishTweetEvent(contentStr, cb) {
+    setTimeout(() => {
+        let publishTweetBtn = document.querySelector('div[role="dialog"]').querySelector('div[data-testid="tweetButton"]');
+        publishTweetBtn.addEventListener('click', function () {
+            setTimeout(() => {
+                let twitterArtId = _getTwitterArtId(contentStr);
+                cb && cb(twitterArtId)
+            }, 1500)
+        });
+    }, 800)
 }
 
 /**
@@ -208,7 +229,8 @@ function _addIframe() {
  */
 function _getTwitterArtId() {
     let firstTwitterArtId = document.querySelector('article[data-testid="tweet"]').querySelector('a[dir="auto"]').getAttribute('href');
-    return firstTwitterArtId;
+
+    return firstTwitterArtId.split('/status/')[1];
 }
 
 /**
@@ -218,7 +240,14 @@ function _getTwitterArtId() {
 function _deNetBtnClick(port) {
     getUserInfo((res) => {
         if (res) {
-            showGiveDialogHandler();
+            
+            if(window.location.pathname != '/home') {
+                if(!dom.homeBtn) {
+                    dom.homeBtn = document.querySelector('a[data-testid="AppTabBar_Home_Link"]');
+                }
+                dom.homeBtn.click();
+            }
+            showGiveDialogHandler(res);
         } else {
             port.postMessage({ state: 'CONTENT_TWITTER_LOGIN' })
         }

+ 1 - 1
src/server/twitter.js

@@ -1,7 +1,7 @@
 // twitter专用api
 // import axios from 'axios'
 
-let base_url = 'http://192.168.80.44:8080/denet'
+let base_url = 'http://testapi.denet.me/denet'
 
 export function getTtwitterRequestToken() {
     return new Promise(function (resolve, reject) {

+ 13 - 0
src/uilts/chromeExtension.js

@@ -12,4 +12,17 @@ export function getChromeStorage(key = '',callback) {
             callback(null)
         }
     });
+}
+
+export function setStorage(key, value) {
+    return localStorage.setItem(key, JSON.stringify(value));
+}
+
+export function getStorage(key) {
+    const item = localStorage.getItem(key);
+    try {
+        return item ? JSON.parse(item) : '';
+    } catch (e) {
+        return item;
+    }
 }

+ 118 - 55
src/view/components/give-dialog.vue

@@ -35,8 +35,9 @@
                                         USD
                                     </div>
                                     <el-input
-                                        v-model="baseFormData.amount"
+                                        v-model="baseFormData.amountValue"
                                         placeholder="$0.00"
+                                        oninput = "value=value.replace(/[^\d]/g,'')"
                                         :input-style="{ 'box-shadow': 'none' }"/>
                                 </div>
                                 <div class="item">
@@ -46,8 +47,9 @@
                                         Quantity
                                         </div>
                                     <el-input
-                                        v-model="baseFormData.quantity"
+                                        v-model="baseFormData.totalCount"
                                         placeholder="Enter quantity"
+                                        oninput = "value=value.replace(/[^\d]/g,'')"
                                         :input-style="{ 'box-shadow': 'none' }"/>
                                 </div>
                             </div>
@@ -67,7 +69,7 @@
                                                     v-for="(item, index) in optionsList"
                                                     :key="index"
                                                     @click="addOption(item)">
-                                                    {{ item.type }}
+                                                    {{ item.label }}
                                                 </el-dropdown-item>
                                             </el-dropdown-menu>
                                         </template>
@@ -80,21 +82,28 @@
                                     <div class="label">
                                         <img class="icon"
                                             :src="item.icon" />
-                                        {{ item.type }}
+                                        {{ item.label }}
                                     </div>
                                     <div class="control">
                                         <el-input
-                                            v-model="formData[item.type]"
-                                            v-if="item.type == 'Follow'"
+                                            :type="item.nodeType"
+                                            rows="2"
+                                            resize="none"
+                                            v-model="item.text"
+                                            v-if="item.nodeType == 'textarea'"
                                             placeholder="Enter account number"
                                             :input-style="{
                                                 'box-shadow': 'none',
+                                                'padding': '1px',
+                                                'line-height': '1'
                                             }"/>
                                         <div
                                             class="inner"
                                             v-else
                                             @click="selectChange(item)">
-                                            {{formData[item.type]? "✅": "❌"}}
+                                            <img class="icon"
+                                                v-if="item.checked"
+                                                :src="require('../../assets/svg/icon-option-checked.svg')" />
                                         </div>
                                     </div>
                                     <img class="icon-remove-button"
@@ -105,10 +114,10 @@
                         </div>
                         <div class="submit-btn" @click="confirm">NEXT</div>
                     </template>
-                    <template v-else>
+                    <div v-show="showPreview">
                         <preview-card></preview-card>
-                        <paypal-button :amount="baseFormData.amount" @payPalFinsh="payPalFinsh"></paypal-button>
-                    </template>
+                        <paypal-button :amount="baseFormData.amountValue" @payPalFinsh="payPalFinsh"></paypal-button>
+                    </div>
                 </div>
             </div>
         </div>
@@ -116,56 +125,53 @@
 </template>
 
 <script setup>
-/* eslint-disable */
-import { ref, watch, reactive, onMounted } from "vue";
+import { ref, watch, reactive, defineProps, defineEmits } from "vue";
+import {postPublish, verifyPaypalResult} from "../../http/publishApi"
+
 import previewCard from "./preview-card";
 import paypalButton from "./paypal-button";
 
+const paypalClientId = 'ASn7k0zqyS5AWYikVSfmamR-RFpjyU_QFJWSxOHHoWE04-RgHNO6nahn0GyHUaUAEBxj-aKgtSrq4O4G';
+
+let publishRes = reactive({})
+
 let visible = ref(true);
 let showPreview = ref(false);
 let dialogHeight = ref(620);
 let previewDialogHeight = ref(880)
 
 let baseFormData = reactive({
-    amount: "",
-    quantity: "",
+    amountCurrencyCode: "USD",
+    amountValue: "",
+    totalCount: "",
 });
 
-let formData = reactive({
-    Follow: "",
-    Like: false,
-    Retweet: false,
-});
 
 let optionsList = reactive([
     { 
-        type: "Follow", 
-        icon: require('../../assets/svg/icon-follow.svg')
+        label: "Follow", 
+        icon: require('../../assets/svg/icon-follow.svg'),
+        nodeType: 'textarea',
+        type: 1,
+        text: '',
     },
     { 
-        type: "Like",
-        icon: require('../../assets/svg/icon-like.svg')
+        label: "Like",
+        icon: require('../../assets/svg/icon-like.svg'),
+        nodeType: 'div',
+        type: 2, 
+        checked: false
     },
     { 
-        type: "Retweet",
-        icon: require('../../assets/svg/icon-retweet.svg')
+        label: "Retweet",
+        icon: require('../../assets/svg/icon-retweet.svg'),
+        nodeType: 'div',
+        type: 3,
+        checked: false
     },
 ]);
 
-let formList = reactive([
-    { 
-        type: "Follow", 
-        icon: require('../../assets/svg/icon-follow.svg')
-    },
-    { 
-        type: "Like",
-        icon: require('../../assets/svg/icon-like.svg')
-    },
-    { 
-        type: "Retweet",
-        icon: require('../../assets/svg/icon-retweet.svg')
-    },
-]);
+let formList = reactive([]);
 
 const props = defineProps({
     dialogVisible: {
@@ -176,13 +182,13 @@ const props = defineProps({
 
 watch(
     () => props.dialogVisible,
-    (newVal, oldVal) => {
+    (newVal) => {
         console.log("watch", newVal);
         visible.value = newVal;
     }
 );
 
-const emits = defineEmits(["close", "confirm"]);
+const emits = defineEmits(["close", "confirm", "payPalFinsh"]);
 
 const close = () => {
     if (showPreview.value) {
@@ -196,22 +202,66 @@ const setPreviewDialogHeight = () => {
     let clientHeight = document.documentElement.clientHeight;
     let gapSafe = 80;
 
-    if(clientHeight - gapSafe >= previewDialogHeight.value) {
-
-    } else {
+    if(previewDialogHeight.value > clientHeight - gapSafe) {
         previewDialogHeight.value = clientHeight - gapSafe;
     }
 };
 
 const confirm = () => {
-    setPreviewDialogHeight();
-    showPreview.value = true;
+    let {amountValue = 0, totalCount = 0, amountCurrencyCode} = baseFormData;
+    if(!amountValue || !totalCount) {
+        return;
+    }
+    amountValue = amountValue * 100; // 元转分
+
+    let finishConditions = [];
+    for(let i = 0; i < formList.length; i++) {
+        let item = {};
+        item.type = formList[i]['type'];
+        if(item.type == 1 && formList[i]['text']) { // follow 参数
+            let relatedUsers = [];
+            let text = formList[i]['text'].replace(/\s*/g,""); // 删除空格
+            let textList = text.split('@');
+            
+            for(let i = 0; i < textList.length; i++) {
+                let item =  textList[i];
+                if(item) {
+                    relatedUsers.push({name: item});
+                }
+            }
+            item.relatedUsers = relatedUsers;
+            finishConditions.push(item);
+        } else if(formList[i]['checked']){
+            finishConditions.push(item);
+        }
+    }
+    console.log('finishConditions', finishConditions);
+    let formData = {
+        amountCurrencyCode,
+        amountValue,
+        totalCount,
+        finishConditions
+    }
+    let data = {
+        params: {
+            postBizData: JSON.stringify(formData),
+            postSrc: 1,  //1 twitter
+            postType: 1, //1 红包
+        }
+    }
+    postPublish(data).then((res) => {
+        if(res.code == 0) {
+            publishRes = res.data;
+            setPreviewDialogHeight();
+            showPreview.value = true;
+        }
+    })
 };
 
 const addOption = (params) => {
     let hasItem = formList.find((item) => item.type == params.type);
     if (!formList.length || !hasItem) {
-        formList.push(params);
+        formList.push({...params});
     }
 };
 
@@ -219,17 +269,29 @@ const removeOption = (params, index) => {
     formList.splice(index, 1);
 };
 
-const selectChange = (params, index) => {
-    formData[params.type] = !formData[params.type];
+const selectChange = (params) => {
+    params.checked = !params.checked;
 };
 
-const payPalFinsh = () => {
-    emits("close", false);
+const payPalFinsh = (params) => {
+    let transaction = params.transaction;
+    console.log('transaction', transaction)
+    verifyPaypalResult({
+        params: {
+            paypalTransactionId: transaction.id,
+            postId: publishRes.postId,
+            paypalClientId: paypalClientId
+        }
+    }).then((res) => {
+        if(res.code == 0) {
+            //支付状态 0:未支付,1:支付成功,2:支付失败,3:已关闭,4:已退款
+            if(res.data && res.data.payStatus == 1) {
+                emits("payPalFinsh", {publishRes});
+            }
+        } 
+    })
 }
 
-onMounted(() => {
-});
-
 </script>
 
 <style lang="scss" scoped>
@@ -412,7 +474,8 @@ onMounted(() => {
                                     width: 100%;
                                     height: 100%;
                                     box-sizing: border-box;
-                                    padding-left: 10px;
+                                    display: flex;
+                                    align-items: center;
                                 }
                             }
 

+ 2 - 3
src/view/components/paypal-button.vue

@@ -8,7 +8,7 @@
             <iframe
                 class="iframe-pay"
                 ref="iframe"
-                src="https://art-weapp.oss-cn-hangzhou.aliyuncs.com/chromeExtension/paypal.html"></iframe>
+                :src="`https://art-weapp.oss-cn-hangzhou.aliyuncs.com/chromeExtension/paypal.html?amount=${amount}`"></iframe>
         </div>
     </div>
 </template>
@@ -37,8 +37,7 @@ onMounted(() => {
                         event.data.orderData,
                         event.data.transaction
                     );
-                    emits("payPalFinsh", {});
-                    window.parent.postMessage({ actionType: "IFRAME_SHOW_TWITTER_PUBLISH_DIALOG" }, "*");
+                    emits("payPalFinsh", event.data);
                     break;
                 case "iframeLoaded":
                     iframe.value.contentWindow.postMessage(

+ 6 - 10
src/view/test.vue

@@ -4,31 +4,26 @@
             :dialogVisible="dialogVisible"
             @close="close"
             @confirm="confirm"
+            @payPalFinsh="payPalFinsh"
         ></give-dialog>
     </div>
 </template>
 
 <script setup>
-/* eslint-disable */
 import { ref } from "vue";
+import {setStorage} from "../uilts/chromeExtension";
 import giveDialog from "./components/give-dialog.vue";
 
 let dialogVisible = ref(false);
-let payDialogVisible = ref(false);
 
 const close = () => {
     dialogVisible.value = false;
     hideIframe();
 };
 
-const confirm = () => {
-    // dialogVisible.value = false;
-    payDialogVisible.value = true;
-};
-
-const confirmPay = () => {
-    payDialogVisible.value = false;
-    window.parent.postMessage({ actionType: "IFRAME_SHOW_TWITTER_PUBLISH_DIALOG" }, "*");
+const payPalFinsh = (params) => {
+    close();
+    window.parent.postMessage({ actionType: "IFRAME_SHOW_TWITTER_PUBLISH_DIALOG", publishRes: params.publishRes }, "*");
 };
 
 const hideIframe = () => {
@@ -39,6 +34,7 @@ window.addEventListener("message", function (event) {
     console.log("addEventListener", event);
     if (event.data && event.data.actionType == "CONTENT_SHOW_GIVE_DIALOG") {
         window.parent.postMessage({ actionType: "IFRAME_SHOW_IFREME" }, "*");
+        setStorage('de-userInfo', event.data.userInfo);
         dialogVisible.value = true;
     }
 });

+ 15 - 0
yarn.lock

@@ -2091,6 +2091,7 @@ aws4@^1.8.0:
   version "1.11.0"
   resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
   integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+
 axios@^0.26.1:
   version "0.26.1"
   resolved "https://registry.npmmirror.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9"
@@ -5192,6 +5193,11 @@ object-assign@^4.0.1, object-assign@^4.1.1:
   resolved "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
   integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
 
+object-inspect@^1.9.0:
+  version "1.12.0"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
+  integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
+
 object-is@^1.0.1:
   version "1.1.5"
   resolved "https://registry.npmmirror.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
@@ -6317,6 +6323,15 @@ shell-quote@^1.6.1:
   resolved "https://registry.npmmirror.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123"
   integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==
 
+side-channel@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
+  integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
+  dependencies:
+    call-bind "^1.0.0"
+    get-intrinsic "^1.0.2"
+    object-inspect "^1.9.0"
+
 signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
   version "3.0.7"
   resolved "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"