Kaynağa Gözat

Merge branch 'dev_1.1.7_lint' of DeNet/de-net-official into master

合并 v1.1.7
wenliming 2 yıl önce
ebeveyn
işleme
cb7fb6e88a

+ 2 - 2
.editorconfig

@@ -2,8 +2,8 @@
 root = true
 
 [*]
-indent_style = space
-indent_size = 2
+indent_style = tab
+indent_size = 4
 end_of_line = lf
 charset = utf-8
 trim_trailing_whitespace = true

+ 15 - 0
.eslintrc.js

@@ -0,0 +1,15 @@
+module.exports = {
+	env: {
+		es2021: true,
+		node: true,
+	},
+	extends: ['eslint:recommended', 'plugin:vue/vue3-essential'],
+	parserOptions: {
+		ecmaVersion: 'latest',
+		sourceType: 'module',
+	},
+	plugins: ['vue'],
+	rules: {
+		'vue/multi-word-component-names': 'off',
+	},
+};

+ 36 - 0
.husky/_/husky.sh

@@ -0,0 +1,36 @@
+#!/usr/bin/env sh
+if [ -z "$husky_skip_init" ]; then
+  debug () {
+    if [ "$HUSKY_DEBUG" = "1" ]; then
+      echo "husky (debug) - $1"
+    fi
+  }
+
+  readonly hook_name="$(basename -- "$0")"
+  debug "starting $hook_name..."
+
+  if [ "$HUSKY" = "0" ]; then
+    debug "HUSKY env variable is set to 0, skipping hook"
+    exit 0
+  fi
+
+  if [ -f ~/.huskyrc ]; then
+    debug "sourcing ~/.huskyrc"
+    . ~/.huskyrc
+  fi
+
+  readonly husky_skip_init=1
+  export husky_skip_init
+  sh -e "$0" "$@"
+  exitCode="$?"
+
+  if [ $exitCode != 0 ]; then
+    echo "husky - $hook_name hook exited with code $exitCode (error)"
+  fi
+
+  if [ $exitCode = 127 ]; then
+    echo "husky - command not found in PATH=$PATH"
+  fi
+
+  exit $exitCode
+fi

+ 4 - 0
.husky/pre-commit

@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+. "$(dirname -- "$0")/_/husky.sh"
+
+yarn lint-staged

+ 8 - 0
.prettierrc.json

@@ -0,0 +1,8 @@
+{
+	"printWidth": 300,
+  	"tabWidth": 4,
+  	"useTabs": true,
+  	"semi": true,
+  	"singleQuote": true,
+  	"bracketSpacing": true
+}

+ 1 - 1
README.md

@@ -95,4 +95,4 @@ pm2 list (pm2常用命令 https://zhuanlan.zhihu.com/p/395339261
 
 停止守护进程: pm2 stop "de-net-official"
 
-删除守护进程: pm2 delete "de-net-official"
+删除守护进程: pm2 delete "de-net-official"

+ 353 - 318
components/CustomCardCover.vue

@@ -1,354 +1,389 @@
 <!-- 自定义卡片红包封面 -->
 <!-- todo:目前只有自定义奖品类型,货币类型待添加 -->
 <template>
-    <!-- 改版之后的卡片 -->
-    <div class="not-open-custom-card custom-card">
-        <img class="customImg" v-if="posterType === 2 && !!customPosterInstalled" :src="customPosterInstalled" />
-        <div class="common-top" v-else>
-          <img class="cover" v-if="isLottaryCpd" :src="require('../static/svg/img-custom-lottary-bg.svg')"  />
-          <img class="cover" v-else :src="require('../static/svg/img-custom-common-bg.svg')"  />
-          <img class="gift" :src="require('../static/svg/icon-gift.gif')" />
-          <div class="prize">
-              <font-zoom width="340">
-                <img class="icon" :src="require('../static/svg/icon-gift-inline.svg')"/>
-                <span class="name" id="custom-name" >
-                  {{customizedReward}}
-                  <span class="total">X{{totalCount}}</span>
-                </span>
-              </font-zoom>
-          </div>
-        </div>
+	<!-- 改版之后的卡片 -->
+	<div class="not-open-custom-card custom-card">
+		<img class="customImg" v-if="posterType === 2 && !!customPosterInstalled" :src="customPosterInstalled" />
+		<div class="common-top" v-else>
+			<img class="cover" v-if="isLottaryCpd" :src="require('../static/svg/img-custom-lottary-bg.svg')" />
+			<img class="cover" v-else :src="require('../static/svg/img-custom-common-bg.svg')" />
+			<img class="gift" :src="require('../static/svg/icon-gift.gif')" />
+			<div class="prize">
+				<font-zoom width="340">
+					<img class="icon" :src="require('../static/svg/icon-gift-inline.svg')" />
+					<span class="name" id="custom-name">
+						{{ customizedReward }}
+						<span class="total">X{{ totalCount }}</span>
+					</span>
+				</font-zoom>
+			</div>
+		</div>
 
-        <!-- 底部公共模块 -->
-        <div class="common-bottom" v-if="showBottomInfo">
-            <div class="theme">
-                <img v-if="isLottaryCpd" class="theme-icon" :src="require('../static/svg/icon-last-time.svg')"/>
-                <span v-if="isLottaryCpd" class="theme-time" >{{validity || '00:00:00'}}</span>
-                <span class="theme-info">{{isLottaryCpd ? 'Left' : 'Instant Giveaway'}}</span>
-            </div>
-            <div class="winner-info">
-                <font-zoom width="340">
-                  <span class="count">{{totalCount}}Winners</span>
-                  <span>to Share </span>
-                  <span class="prize-name">{{isMoneyRewardCpd ? amountValue + ' ' + tokenSymbol : customizedReward}}</span>
-                </font-zoom>
-            </div>
-        </div>
-    </div>
+		<!-- 底部公共模块 -->
+		<div class="common-bottom" v-if="showBottomInfo">
+			<div class="theme">
+				<img v-if="isLottaryCpd" class="theme-icon" :src="require('../static/svg/icon-last-time.svg')" />
+				<span v-if="isLottaryCpd" class="theme-time">{{ validity || '00:00:00' }}</span>
+				<span class="theme-info">{{ isLottaryCpd ? 'Left' : 'Instant Giveaway' }}</span>
+			</div>
+			<div class="winner-info">
+				<font-zoom width="340">
+					<span class="count">{{ totalCount }}Winners</span>
+					<span>to Share </span>
+					<span class="prize-name">{{ isMoneyRewardCpd ? amountValue + ' ' + tokenSymbol : customizedReward }}</span>
+				</font-zoom>
+			</div>
+		</div>
+	</div>
 </template>
 
 <script>
-import { formatSecondsAsDaysOrTime } from "../utils/help";
-import FontZoom  from './FontZoom.vue';
-import { RewardType, PlayType } from "../types";
+import FontZoom from './FontZoom.vue';
+import { RewardType, PlayType } from '../types';
 export default {
-  name:'CustomCardCover',
-  props: {
-    totalCount: 0,
-    amountValue: 0,
-    tokenSymbol: "",
-    playType: 1,
-    validityDuration: "",
-    userInfo: {},
-    rewardType: 1,
-    customizedReward: "",
-    validity: "",
-    showBottomInfo: true,
-    customPosterInstalled: "",
-    posterType: 1
-  },
-  data() {
-      return {
-          amount_font_size: 22,
-      }
-  },
-  computed: {
-    isMoneyRewardCpd() {
-      return this.rewardType === RewardType.money
-    },
-    isLottaryCpd() {
-      return this.playType === PlayType.lottery
-    }
-  },
-  mounted() {
-      this.setFontSize()
-  },
-  methods: {
-      setFontSize() {
-          let lendom = document.querySelector('#custom-name');
-          if (lendom) {
-              let lenstr = lendom.innerText.length;
-              let num = parseInt(450 / lenstr);
-              this.amount_font_size = num < 22 ? num : 22;
-          }
-      }
-  },
-  components: { FontZoom }
-}
+	name: 'CustomCardCover',
+	props: {
+		totalCount: {
+			type: Number,
+			default: 0,
+		},
+		amountValue: {
+			type: Number,
+			default: 0,
+		},
+		tokenSymbol: {
+			type: String,
+			default: '',
+		},
+		playType: {
+			type: Number,
+			default: 1,
+		},
+		validityDuration: {
+			type: String,
+			default: '',
+		},
+		userInfo: {
+			type: Object,
+			default: () => {},
+		},
+		rewardType: {
+			type: Number,
+			default: 1,
+		},
+		customizedReward: {
+			type: String,
+			default: '',
+		},
+		validity: {
+			type: String,
+			default: '',
+		},
+		showBottomInfo: {
+			type: Boolean,
+			default: true,
+		},
+		customPosterInstalled: {
+			type: String,
+			default: '',
+		},
+		posterType: {
+			type: Number,
+			default: 1,
+		},
+	},
+	data() {
+		return {
+			amount_font_size: 22,
+		};
+	},
+	computed: {
+		isMoneyRewardCpd() {
+			return this.rewardType === RewardType.money;
+		},
+		isLottaryCpd() {
+			return this.playType === PlayType.lottery;
+		},
+	},
+	mounted() {
+		this.setFontSize();
+	},
+	methods: {
+		setFontSize() {
+			let lendom = document.querySelector('#custom-name');
+			if (lendom) {
+				let lenstr = lendom.innerText.length;
+				let num = parseInt(450 / lenstr);
+				this.amount_font_size = num < 22 ? num : 22;
+			}
+		},
+	},
+	components: { FontZoom },
+};
 </script>
 
 <style scoped lang="scss">
 .not-open-custom-card {
-    width: 100%;
-    height: 100%;
-    position: relative;
-    border-radius: 16px;
-    filter: drop-shadow(0px 2px 20px rgba(0, 0, 0, 0.1));
+	width: 100%;
+	height: 100%;
+	position: relative;
+	border-radius: 16px;
+	filter: drop-shadow(0px 2px 20px rgba(0, 0, 0, 0.1));
 
-    .customImg {
-        width: 100%;
-        min-height: 373px;
-    }
-    .common-top {
-      position: relative;
-    }
+	.customImg {
+		width: 100%;
+		min-height: 373px;
+	}
+	.common-top {
+		position: relative;
+	}
 
-    .money-area {
-        width: 100%;
-        position: absolute;
-        top: 65px;
+	.money-area {
+		width: 100%;
+		position: absolute;
+		top: 65px;
 
-        .txt {
-            font-weight: 800;
-            font-size: 16px;
-            text-align: center;
-            letter-spacing: 0.3px;
-            color: #ffffff;
-        }
+		.txt {
+			font-weight: 800;
+			font-size: 16px;
+			text-align: center;
+			letter-spacing: 0.3px;
+			color: #ffffff;
+		}
 
-        .coin {
-            text-align: center;
-            width: 100%;
-            padding: 6px 0;
-            margin: 0 auto;
-            display: flex;
-            align-items: center;
-            justify-content: center;
+		.coin {
+			text-align: center;
+			width: 100%;
+			padding: 6px 0;
+			margin: 0 auto;
+			display: flex;
+			align-items: center;
+			justify-content: center;
 
-            img {
-                width: 46px;
-                height: 46px;
-                border-radius: 50%;
-                border: 3px solid #ffffff;
-            }
+			img {
+				width: 46px;
+				height: 46px;
+				border-radius: 50%;
+				border: 3px solid #ffffff;
+			}
 
-            span {
-                margin-left: 15px;
-                font-weight: 800;
-                font-size: 60px;
-                line-height: 76px;
-                color: #ffffff;
-            }
-        }
+			span {
+				margin-left: 15px;
+				font-weight: 800;
+				font-size: 60px;
+				line-height: 76px;
+				color: #ffffff;
+			}
+		}
 
-        .people {
-            font-weight: 800;
-            font-size: 13px;
-            line-height: 16px;
-            letter-spacing: 0.05em;
-            color: #ffffff;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-        }
+		.people {
+			font-weight: 800;
+			font-size: 13px;
+			line-height: 16px;
+			letter-spacing: 0.05em;
+			color: #ffffff;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
 
-        .time-area {
-            display: flex;
-            justify-content: center;
-            align-items: center;
-            width: 100%;
-            height: 46px;
-            background: rgba(0,0,0,.15);
-            color: #FFCC4D;
-            font-weight: 900;
-            font-size: 26px;
-            margin-top: -10px;
-            .icon-clock {
-                width: 26px;
-                height: 26px;
-                margin-right: 10px;
-            }
-        }
-    }
+		.time-area {
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			width: 100%;
+			height: 46px;
+			background: rgba(0, 0, 0, 0.15);
+			color: #ffcc4d;
+			font-weight: 900;
+			font-size: 26px;
+			margin-top: -10px;
+			.icon-clock {
+				width: 26px;
+				height: 26px;
+				margin-right: 10px;
+			}
+		}
+	}
 
-    .title {
-        position: absolute;
-        top: 15px;
-        left: 15px;
-        z-index: 3;
-        width: 100%;
-        display: flex;
-        align-items: center;
+	.title {
+		position: absolute;
+		top: 15px;
+		left: 15px;
+		z-index: 3;
+		width: 100%;
+		display: flex;
+		align-items: center;
 
-        img {
-            width: 24px;
-            height: 24px;
-            border: 2px solid #fff;
-            border-radius: 50%;
-        }
+		img {
+			width: 24px;
+			height: 24px;
+			border: 2px solid #fff;
+			border-radius: 50%;
+		}
 
-        span {
-            margin-left: 10px;
-            font-weight: 600;
-            font-size: 16px;
-            letter-spacing: 0.3px;
-            color: #fff;
-        }
-    }
+		span {
+			margin-left: 10px;
+			font-weight: 600;
+			font-size: 16px;
+			letter-spacing: 0.3px;
+			color: #fff;
+		}
+	}
 
-    // .txt {
-    //   width: 100%;
-    //   position: absolute;
-    //   font-style: normal;
-    //   font-weight: 700;
-    //   font-size: 42px;
-    //   line-height: 50px;
-    //   text-align: center;
+	// .txt {
+	//   width: 100%;
+	//   position: absolute;
+	//   font-style: normal;
+	//   font-weight: 700;
+	//   font-size: 42px;
+	//   line-height: 50px;
+	//   text-align: center;
 
-    //   color: #FFF2D3;
-    //   top: 90px;
-    //   z-index: 3;
-    // }
+	//   color: #FFF2D3;
+	//   top: 90px;
+	//   z-index: 3;
+	// }
 
-    img {
-        width: 100%;
-    }
+	img {
+		width: 100%;
+	}
 
-    .cover {
-        border-radius: 16px;
-    }
+	.cover {
+		border-radius: 16px;
+	}
 
-    .up {
-        position: absolute;
-        top: 0;
-        // box-shadow: 0px 4px 44px rgba(0, 0, 0, 0.1);
-        z-index: 1;
-    }
+	.up {
+		position: absolute;
+		top: 0;
+		// box-shadow: 0px 4px 44px rgba(0, 0, 0, 0.1);
+		z-index: 1;
+	}
 
-    .down {
-        position: absolute;
-        top: 253px;
-    }
+	.down {
+		position: absolute;
+		top: 253px;
+	}
 
-    .open {
-        width: 335px;
-        height: 50px;
-        cursor: pointer;
-        position: absolute;
-        bottom: 28px;
-        left: 50%;
-        margin-left: -167.5px;
-        z-index: 2;
-    }
+	.open {
+		width: 335px;
+		height: 50px;
+		cursor: pointer;
+		position: absolute;
+		bottom: 28px;
+		left: 50%;
+		margin-left: -167.5px;
+		z-index: 2;
+	}
 
-    .open-gif {
-        width: 200px;
-        height: 200px;
-        text-align: center;
-        position: absolute;
-        bottom: 90px;
-        left: 50%;
-        margin-left: -100px;
-        z-index: 3;
-    }
+	.open-gif {
+		width: 200px;
+		height: 200px;
+		text-align: center;
+		position: absolute;
+		bottom: 90px;
+		left: 50%;
+		margin-left: -100px;
+		z-index: 3;
+	}
 }
 .custom-card {
-    position: relative;
-    background:#111214;
-    width: 100%;
-    position: relative;
-    border-radius: 10px;
-    filter: drop-shadow(0px 2px 20px rgba(0, 0, 0, 0.1));
-    .cover {
-        width: 100%;
-        border-radius: 10px 10px 0 0;
-    }
-    .gift {
-        width: 210px;
-        position: absolute;
-        left: 50%;
-        top: 83px;
-        transform: translateX(-50%);
-    }
-    .prize {
-        width: 100%;
-        position: absolute;
-        top: 76%;
-        left: 0;
-        height: 47px;
-        display: flex;
-        flex-direction: row;
-        justify-content: center;
-        font-style: normal;
-        font-weight: 800;
-        font-size: 22px;
-        line-height: 47px;
-        letter-spacing: 0.3px;
+	position: relative;
+	background: #111214;
+	width: 100%;
+	position: relative;
+	border-radius: 10px;
+	filter: drop-shadow(0px 2px 20px rgba(0, 0, 0, 0.1));
+	.cover {
+		width: 100%;
+		border-radius: 10px 10px 0 0;
+	}
+	.gift {
+		width: 210px;
+		position: absolute;
+		left: 50%;
+		top: 83px;
+		transform: translateX(-50%);
+	}
+	.prize {
+		width: 100%;
+		position: absolute;
+		top: 76%;
+		left: 0;
+		height: 47px;
+		display: flex;
+		flex-direction: row;
+		justify-content: center;
+		font-style: normal;
+		font-weight: 800;
+		font-size: 22px;
+		line-height: 47px;
+		letter-spacing: 0.3px;
 
-        .icon {
-            width: 24px;
-        }
-        .name {
-            padding: 0 7px;
-            color: #fff;
-        }
-        .total {
-            color: #F5C03F;
-        }
-    }
-    .common-bottom {
-        width: 100%;
-        height: 62px;
-        background:#111214;
-        border-radius: 0 0 10px 10px;
-        padding: 10px 16px;
-        font-weight: 500;
-        font-size: 12px;
-        line-height: 14px;
-        letter-spacing: 0.3px;
-        color: #838383;
-        line-height: 20px;
-        .theme {
-            display: flex;
-            height: 20px;
-            align-items: center;
-            justify-content: flex-start;
-            &-icon {
-                width: 12px;
-            }
-            &-time {
-                margin: 0 4px;
-                color: #1D9BF0;
-            }
-        }
-        .winner-info {
-            display: flex;
-            height: 20px;
-            align-items: center;
-            justify-content: flex-start;
-            margin-bottom: 13px;
-            .count{
-                color: #1D9BF0;
-                margin-right: 4px;
-            }
-            .prize-name {
-                color: #1D9BF0;
-                margin-left: 4px;
-            }
-        }
-        .open-btn {
-            width: 100%;
-            height: 45px;
-            background: linear-gradient(180deg, #4AB6FF 0%, #1D9BF0 100%, #1D9BF0 100%);
-            border: 1.5px solid rgba(255, 255, 255, 0.15);
-            border-radius: 52px;
-            line-height: 45px;
-            text-align: center;
-            cursor: pointer;
-            font-weight: 800;
-            font-size: 16px;
-            color: #FFFFFF;
-        }
-    }
+		.icon {
+			width: 24px;
+		}
+		.name {
+			padding: 0 7px;
+			color: #fff;
+		}
+		.total {
+			color: #f5c03f;
+		}
+	}
+	.common-bottom {
+		width: 100%;
+		height: 62px;
+		background: #111214;
+		border-radius: 0 0 10px 10px;
+		padding: 10px 16px;
+		font-weight: 500;
+		font-size: 12px;
+		line-height: 14px;
+		letter-spacing: 0.3px;
+		color: #838383;
+		line-height: 20px;
+		.theme {
+			display: flex;
+			height: 20px;
+			align-items: center;
+			justify-content: flex-start;
+			&-icon {
+				width: 12px;
+			}
+			&-time {
+				margin: 0 4px;
+				color: #1d9bf0;
+			}
+		}
+		.winner-info {
+			display: flex;
+			height: 20px;
+			align-items: center;
+			justify-content: flex-start;
+			margin-bottom: 13px;
+			.count {
+				color: #1d9bf0;
+				margin-right: 4px;
+			}
+			.prize-name {
+				color: #1d9bf0;
+				margin-left: 4px;
+			}
+		}
+		.open-btn {
+			width: 100%;
+			height: 45px;
+			background: linear-gradient(180deg, #4ab6ff 0%, #1d9bf0 100%, #1d9bf0 100%);
+			border: 1.5px solid rgba(255, 255, 255, 0.15);
+			border-radius: 52px;
+			line-height: 45px;
+			text-align: center;
+			cursor: pointer;
+			font-weight: 800;
+			font-size: 16px;
+			color: #ffffff;
+		}
+	}
 }
 </style>

+ 24 - 24
components/InstallExtension.vue

@@ -1,32 +1,32 @@
 <template>
-    <div>
-        <img @click="installExtension" src="/svg/icon-install-nft-plugin.svg" />
-    </div>
+	<div>
+		<img @click="installExtension" src="/svg/icon-install-nft-plugin.svg" />
+	</div>
 </template>
 <script>
 export default {
-    name: 'install_chrome',
-    props: {
-        extensionsInstallUrl: {
-            type: String,
-            default: ''
-        } 
-    },
-    data() {
-        return {
-            config: {},
-        }
-    },
-    methods: {
-        installExtension() {
-            window.open(this.extensionsInstallUrl)
-        }
-    }
-}
-
+	name: 'install_chrome',
+	props: {
+		extensionsInstallUrl: {
+			type: String,
+			default: '',
+		},
+	},
+	data() {
+		return {
+			config: {},
+		};
+	},
+	methods: {
+		installExtension() {
+			this.$emit('installClick', {});
+			window.open(this.extensionsInstallUrl);
+		},
+	},
+};
 </script>
 <style lang="scss" scoped>
 img {
-    cursor: pointer;
+	cursor: pointer;
 }
-</style>
+</style>

+ 455 - 0
components/MobileLandPage.vue

@@ -0,0 +1,455 @@
+<template>
+	<div class="mobile-land-page" :class="isLoading ? 'loading-page' : ''">
+		<div class="mobile-land-page-invited-info" v-if="useFul && !isNFTCpd">
+			<img :src="userInfo.avatarUrl" class="invited-photo" />
+			<div class="invited-name">{{ userInfo.nickName }}</div>
+			<div class="invited-text">{{ isTreasureCpd ? 'Invite You to Hunt the Treasure' : 'Send You Giveaway!' }}</div>
+		</div>
+		<div class="mobile-land-page-icon-wrap">
+			<img class="mobile-land-page-icon" :src="iconCpd" />
+		</div>
+		<div class="mobile-land-page-prize-info">
+			<template v-if="!useFul">
+				<div class="mobile-land-page-prize-info-test">
+					<!-- time-expired -->
+				</div>
+			</template>
+			<!-- 红包 -->
+			<template v-else-if="isLottaryCpd">
+				<div class="mobile-land-page-prize-info-test">You are gifted an entries to earn</div>
+				<div class="mobile-land-page-prize-info-test">
+					<img v-if="!isCustomRewardCpd" class="icon" :src="currencyIconPath" />
+					<span class="pre-amount-value">{{ isCustomRewardCpd ? 1 : amountValue }}</span>
+					<span class="prize-name">{{ prize }}</span>
+					<span class="usd-amount" v-if="!isCustomRewardCpd && usValue"> (${{ usValue }})</span>
+				</div>
+			</template>
+			<!-- 抽奖 -->
+			<template v-else-if="isCommonCpd">
+				<div class="mobile-land-page-prize-info-test">
+					You Won
+					<img v-if="!isCustomRewardCpd" class="icon" :src="currencyIconPath" />
+					<span class="pre-amount-value">{{ isCustomRewardCpd ? 1 : amountValue }}</span>
+					<FontZoom width="240" style="color: #000">
+						<span class="prize-name">{{ prize }}</span>
+					</FontZoom>
+					<span class="usd-amount" v-if="!isCustomRewardCpd && usValue"> (${{ usValue }})</span>
+				</div>
+				<div class="mobile-land-page-prize-info-test">in the Giveaway!</div>
+			</template>
+			<!-- 夺宝 -->
+			<template v-else-if="isTreasureCpd">
+				<div class="mobile-land-page-prize-info-test">Complete the quest to win up to</div>
+				<div class="mobile-land-page-prize-info-test">
+					<span class="usd-amount treasure-usd-amount"> ${{ usValue }} for you two!</span>
+				</div>
+			</template>
+			<!-- NFT -->
+			<template v-else-if="isNFTCpd">
+				<div class="mobile-land-page-prize-info-test">
+					<span class="prize-name">{{ prize }}</span>
+					is in your
+				</div>
+				<div class="mobile-land-page-prize-info-test">DeNet NFT wallet!</div>
+			</template>
+			<!-- 兜底显示 -->
+			<template v-else>
+				<div class="mobile-land-page-prize-info-test"></div>
+			</template>
+		</div>
+		<FontZoom width="330">
+			<div class="mobile-land-page-tip">{{ tipCpd }}</div>
+		</FontZoom>
+		<div class="mobile-land-page-login-twitter" @click="toLogin">{{ isLoginCpd || loginSuccessBack ? (!useFul || isNFTCpd ? 'Install' : 'Claim Prize') : 'Login Twitter' }}</div>
+		<template v-if="isLoading">
+			<img class="loading" src="../static/svg/icon-loading.svg" />
+		</template>
+	</div>
+</template>
+<script>
+import { RewardType, PlayType } from '../types';
+import { getStorage, setStorage, removeStorage, storageKey, getMid, getOauthUrl } from '../utils/help';
+import { postRequest } from '../http';
+import FontZoom from './FontZoom';
+import { Toast } from 'vant';
+import Report from './../log-center/log';
+
+const overTimePic = require('../static/img/icon-h5-denet.svg');
+const giveawayPic = require('../static/img/icon-h5-giveaway.svg');
+const redpackPic = require('../static/img/icon-h5-redpack.svg');
+const treasurePic = require('../static/img/icon-h5-treasure.svg');
+
+export default {
+	name: 'mobileLandPage',
+	props: {
+		playType: {
+			// 玩法类型, 红包 / 抽奖 / 夺宝 / NFT
+			type: Number,
+		},
+		rewardType: {
+			// 奖品类型  货币/ 自定义奖品
+			type: Number,
+			default: 1,
+		},
+		useFul: {
+			// 红包仍在有效期,可领取
+			type: Boolean,
+			default: true,
+		},
+		userInfo: {
+			type: Object,
+			default: () => {
+				return {};
+			},
+		},
+		currencyIconPath: {
+			// 货币头像
+			type: String,
+			default: '',
+		},
+		amountValue: {
+			// 奖品数量
+			type: [String, Number],
+			default: '1',
+		},
+		usValue: {
+			// 转换为美金 的价值
+			type: [String, Number],
+			default: '',
+		},
+		prize: {
+			// 奖品 描述
+			type: String,
+			default: '',
+		},
+		srcContentId: {
+			// 推文ID
+			type: String,
+			default: '',
+		},
+		postId: {
+			// 推文ID,用于retweer
+			type: String,
+			default: '',
+		},
+		nftProjectId: {
+			// NFT ID
+			type: String,
+			default: '',
+		},
+		prizePicPath: {
+			// NFT图片
+			type: String,
+			default: '',
+		},
+	},
+	data() {
+		return {
+			timer: {},
+			loginSuccessBack: false,
+			isLoading: false,
+		};
+	},
+	computed: {
+		isCustomRewardCpd() {
+			return this.rewardType === RewardType.custom;
+		},
+		isLottaryCpd() {
+			return this.playType === PlayType.lottery;
+		},
+		isCommonCpd() {
+			return this.playType === PlayType.common;
+		},
+		isTreasureCpd() {
+			return this.playType === PlayType.Treasure;
+		},
+		isNFTCpd() {
+			return this.playType === PlayType.NFT;
+		},
+		iconCpd() {
+			if (!this.useFul) {
+				return overTimePic;
+			} else if (this.isCommonCpd) {
+				return redpackPic;
+			} else if (this.isLottaryCpd) {
+				return giveawayPic;
+			} else if (this.isTreasureCpd) {
+				return treasurePic;
+			} else if (this.isNFTCpd) {
+				return this.prizePicPath;
+			}
+			{
+				return overTimePic;
+			}
+		},
+		tipCpd() {
+			if (!this.useFul) {
+				return 'login Twitter to install DeNet Chrome Extension';
+			} else if (this.isCommonCpd) {
+				return 'to claim,  log in twitter to install Denet Chrome Extension';
+			} else if (this.isLottaryCpd) {
+				return 'To participate, login Twitter to install DeNet Chrome Extension';
+			} else if (this.isTreasureCpd) {
+				return 'To complete, log in twitter to install Denet Chrome Extension';
+			} else {
+				return 'login Twitter to install DeNet Chrome Extension';
+			}
+		},
+		isLoginCpd() {
+			return !!getStorage(storageKey.userInfo);
+		},
+	},
+	methods: {
+		toLogin() {
+			let userInfo = getStorage(storageKey.userInfo);
+			let logData = {
+				baseInfo: {
+					mid: getMid(),
+					pageSource: Report.pageSource.mobileLandingPage,
+					machineCode: getMid(),
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.buttonClick,
+						objectType: userInfo ? Report.objectType.cliamRewardButton : Report.objectType.loginTwitterButton,
+						postId: this.postId,
+					},
+				},
+			};
+			if (this.isNFTCpd) {
+				delete logData.params.eventData.postId;
+				logData.params.eventData.nftProjectId = this.nftProjectId;
+			}
+			if (userInfo) {
+				// ios手机跳转时丢失log,缓存至下个页面进行上报
+				setStorage('land-page-log', JSON.stringify(logData));
+				this.goCoursePage();
+			} else {
+				Report.reportLog(logData);
+				this.twitterAuth();
+			}
+		},
+		goCoursePage() {
+			location.href = `/course?useful=${this.useFul ? '1' : '0'}&playType=${this.playType}&rewardType=${this.rewardType}&postId=${this.postId}&nftProjectId=${this.nftProjectId}&srcContentId=${this.srcContentId}`;
+		},
+		async twitterAuth() {
+			let win = window.open();
+			win.opener = null;
+			postRequest(`/denet/user/twitterRequestToken`, {
+				params: {
+					oauthCallback: `${location.protocol}//${location.host}/authlogin`,
+				},
+			}).then(({ code, data }) => {
+				if (code == 0) {
+					let url = getOauthUrl(data.authToken);
+					this.isLoading = true;
+					setStorage('goto-twitter-login-page', 1);
+					win.location.href = url;
+					this.timer.value = setInterval(() => {
+						if (win && win.closed) {
+							clearInterval(this.timer.value);
+							this.twitterLogin(data);
+							if (getStorage(storageKey.backFromTwitterLogin)) {
+								// 从twitter授权取消页面回来
+								this.isLoading = false;
+								removeStorage(storageKey.backFromTwitterLogin);
+								this.goCoursePage();
+							}
+						}
+					}, 500);
+				} else {
+					Toast('login fail');
+					win.close();
+					this.goCoursePage();
+				}
+			});
+		},
+		async twitterLogin(authData) {
+			let verifier = getStorage(storageKey.verifier);
+			removeStorage('goto-twitter-login-page');
+			if (verifier) {
+				postRequest(`/denet/user/twitterLogin`, {
+					params: {
+						consumerKey: authData.consumerKey,
+						oauthToken: authData.authToken,
+						oauthVerifier: verifier,
+					},
+				}).then(({ code, data }) => {
+					if (code == 0) {
+						setStorage(storageKey.userInfo, data);
+						removeStorage(storageKey.verifier);
+						this.loginSuccessBack = true;
+						this.isLoading = false;
+						this.goCoursePage();
+					} else {
+						this.isLoading = false;
+						Toast('login fail');
+					}
+				});
+			} else {
+				this.isLoading = false;
+			}
+		},
+		visibilityHandle() {
+			console.log('visibilitychange', document.hidden);
+			var isHidden = document.hidden;
+			if (!isHidden) {
+				// 此处解决 点击login按钮后 主动返回的情况
+				let verifier = getStorage(storageKey.verifier);
+				const isFromTwitterLoginPage = getStorage('goto-twitter-login-page');
+				if (isFromTwitterLoginPage && !verifier) {
+					removeStorage('goto-twitter-login-page');
+					this.isLoading = false;
+					this.goCoursePage();
+				}
+			}
+		},
+	},
+	mounted() {
+		document.addEventListener('visibilitychange', this.visibilityHandle);
+	},
+	unmounted() {
+		removeStorage('goto-twitter-login-page');
+		removeStorage(storageKey.backFromTwitterLogin);
+		document.removeEventListener('visibilitychange', this.visibilityHandle);
+	},
+	components: { FontZoom },
+};
+</script>
+<style lang="scss" scoped>
+.mobile-land-page {
+	min-height: 100%;
+	max-height: 100%;
+	background: linear-gradient(180deg, #cceaff 0%, #ffffff 70.42%);
+	display: flex;
+	flex-direction: column;
+	justify-content: space-between;
+	align-items: center;
+	padding: 0 16px;
+	&-invited-info {
+		min-width: 302px;
+		height: 72px;
+		margin-top: 28px;
+		position: relative;
+		padding-left: 81px;
+		border-radius: 35px;
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		justify-content: flex-start;
+		background: #ffffff;
+		border: 1px solid #c0daeb;
+		padding-right: 12px;
+		box-sizing: border-box;
+		white-space: nowrap;
+
+		.invited-photo {
+			width: 70px;
+			height: 70px;
+			border-radius: 50%;
+			position: absolute;
+			left: 0;
+			top: 0;
+		}
+		.invited-name {
+			margin: 13px 0 5px;
+			font-weight: 500;
+			font-size: 13px;
+			line-height: 16px;
+			letter-spacing: 0.3px;
+			color: #000000;
+			max-width: 210px;
+			text-overflow: ellipsis;
+			white-space: nowrap;
+			overflow: hidden;
+		}
+		.invited-text {
+			font-weight: 700;
+			font-size: 17px;
+			line-height: 20px;
+			letter-spacing: 0.3px;
+			color: #f99d23;
+		}
+	}
+	&-icon-wrap {
+		display: flex;
+		flex: 1;
+		align-items: center;
+		.mobile-land-page-icon {
+			width: 100%;
+		}
+	}
+	&-prize-info {
+		font-style: normal;
+		font-weight: 700;
+		font-size: 18px;
+		line-height: 21px;
+		color: #000000;
+		&-test {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			.pre-amount-value {
+				margin-left: 3px;
+			}
+			.icon {
+				width: 22px;
+				height: 22px;
+				margin-left: 3px;
+			}
+			.prize-name {
+				margin: 0 3px;
+			}
+
+			.treasure-usd-amount {
+				color: #f99d23;
+				font-weight: 700;
+				font-size: 18px;
+			}
+		}
+	}
+	&-tip {
+		font-weight: 400;
+		font-size: 13px;
+		line-height: 16px;
+		text-align: center;
+		color: #7b7b7b;
+		margin-top: 10px;
+	}
+	&-login-twitter {
+		width: 100%;
+		height: 54px;
+		margin: 18px 16px 30px;
+		border-radius: 54px;
+		background: #1d9bf0;
+		text-align: center;
+		line-height: 54px;
+		font-weight: 700;
+		font-size: 18px;
+		text-align: center;
+		color: #fff;
+	}
+	.loading {
+		position: absolute;
+		transform: translate(-50%, -50%);
+		top: 50%;
+		left: 50%;
+		margin: auto;
+		width: 40px;
+		border-radius: 50%;
+		z-index: 1;
+	}
+}
+.loading-page {
+	position: relative;
+}
+.loading-page::after {
+	content: '';
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	background-color: #fff;
+	left: 0;
+	top: 0;
+}
+</style>

+ 79 - 0
http/index.js

@@ -0,0 +1,79 @@
+// http封装库
+import axios from 'axios';
+import { getEnvConfig, removeStorage, storageKey, getMid, getUserInfo, appVersionCode } from '../utils/help';
+// 测试数据(需手动开启关闭)
+// import '../mockjs/index';
+
+// axios config
+const { host } = getEnvConfig();
+const instance = axios.create({
+	baseURL: host,
+	timeout: 240000,
+	headers: {
+		'content-type': 'application/json',
+		Accept: 'application/json',
+	},
+});
+
+// 响应拦截器
+instance.interceptors.response.use(
+	(res) => {
+		if (res.data.code === -107) {
+			// token失效
+			removeStorage(storageKey.userInfo);
+			location.reload();
+		} else {
+			return res.data;
+		}
+	},
+	function (err) {
+		return Promise.reject(err);
+	}
+);
+
+export const postRequest = (url, params = {}, config = null) => {
+	const myConfig = {};
+	const userInfo = getUserInfo();
+	if (config) {
+		Object.assign(myConfig, config);
+	}
+	let isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+	params = Object.assign(
+		{
+			baseInfo: {
+				mid: getMid(),
+				machineCode: getMid(),
+				loginUid: (userInfo && userInfo.uid) || '',
+				token: (userInfo && userInfo.accessToken) || '',
+				appType: isMobile ? 2 : 1,
+				appVersionCode,
+			},
+		},
+		params
+	);
+
+	return instance
+		.post(url, params, myConfig)
+		.then((res) => {
+			return res;
+		})
+		.catch((err) => {
+			return err;
+		});
+};
+
+export const getRequest = (url, params = {}, config = null) => {
+	const myConfig = Object.assign({}, { params: Object.assign({}, params) });
+	if (config) {
+		Object.assign(myConfig, config);
+	}
+
+	return instance
+		.get(url, myConfig)
+		.then((res) => {
+			return res;
+		})
+		.catch((err) => {
+			return err;
+		});
+};

+ 16 - 12
log-center/logEnum.js

@@ -1,19 +1,23 @@
 export const logType = {
-    'denet': '150',//denet-event-log
-}
+	denet: '150', //denet-event-log
+};
 
 export const businessType = {
-    buttonView: "buttonView",
-    buttonClick: "buttonClick",
-    pageView: "pageView",
-}
+	buttonView: 'buttonView',
+	buttonClick: 'buttonClick',
+	pageView: 'pageView',
+};
 
 export const objectType = {
-    installButton: "install-button",
-    copyLinkButton: "copy-link-button"
-}
+	installButton: 'install-button',
+	copyLinkButton: 'copy-link-button',
+	loginTwitterButton: 'login-twitter-button',
+	cliamRewardButton: 'cliam-reward-button',
+	rtButton: 'rt-button',
+};
 
 export const pageSource = {
-    newUserLandingPage: "new-user-landing-page",
-    mobileLandingPage: "mobile-landing-page"
-}
+	newUserLandingPage: 'pc-landing-page',
+	mobileLandingPage: 'mobile-landing-page',
+	tutorialPage: 'tutorial-page',
+};

+ 42 - 33
log-center/logger.js

@@ -1,55 +1,64 @@
 import axios from 'axios';
 import { logType } from './logEnum.js';
-import { getBrowser } from '../utils/help';
+import { getBrowser, getUserInfo, appVersionCode, denetExtensionId, detectExtension } from '../utils/help';
 
-const logApi = {
-	prod: 'https://log.weiqumeta.com',
-	pre: 'https://prelog.weiqumeta.com',
-	test: 'https://testlog.weiqumeta.com'
-}
+export const logApi = {
+	prod: 'https://log.denetme.net',
+	pre: 'https://prelog.denetme.net',
+	test: 'https://testlog.denetme.net',
+};
 
-const logAPIUrl = logApi[process.env.NUXT_ENV.MODE] + '/log-center'
+const logAPIUrl = logApi[process.env.NUXT_ENV.MODE] + '/denet/log';
 
 /**
  * @eventData 以键值对存储,会在最终上报里解开的参数
  * @extParams 最终上报到阿里云以json字符串存储的参数,如果extparams传入的不是obj会转换成obj
  */
 export function reportLog(params) {
-    paramsPretreatmentAndRequest(logType.denet, params)
+	paramsPretreatmentAndRequest(logType.denet, params);
 }
 
 function paramsPretreatmentAndRequest(logType, params) {
-    let {eventData = {}, extParams = {}} = params.params ||  {
-        params: {
-        }
-    }
-    let isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
-    let platform = isMobile ? `mobile` : `pc`;
-    let browser = getBrowser();
-    let extData = {
-        url: location.href,
-        browser,
-        platform,
-        ...eventData,
-    }
-    eventData = wrapObject(extData)
-    params.params.logType = logType;
-    params.params.eventData = JSON.stringify(eventData)
-    params.params.extParams  = JSON.stringify(extParams)
-    
-    axios.post(`${logAPIUrl}/statistics/uploadLogFromFrontend`, params)
+	let { eventData = {}, extParams = {} } = params.params || {
+		params: {},
+	};
+	const userInfo = getUserInfo();
+	if (userInfo) {
+		params.baseInfo.loginUid = userInfo.uid;
+	}
+	params.baseInfo.appVersionCode = appVersionCode;
+	let isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+	params.baseInfo.appType = isMobile ? 2 : 1;
+	let platform = isMobile ? `mobile` : `pc`;
+	let browser = getBrowser();
+	let extData = {
+		url: location.href,
+		browser,
+		platform,
+		refer: document ? document.referrer : '',
+		...eventData,
+	};
+	eventData = wrapObject(extData);
+	params.params.logType = logType;
+
+	detectExtension(denetExtensionId, (isInstall) => {
+		eventData.isExtensionInstalled = isInstall ? 1 : 0;
+		params.params.eventData = JSON.stringify(eventData);
+		params.params.extParams = JSON.stringify(extParams);
+		axios.post(`${logAPIUrl}/uploadLogFromFrontend`, params);
+	});
 }
 
 function wrapObject(extParams) {
-    if (typeDecide(extParams, 'Object')) {
-        return extParams
-    }
-    return { 'defaultExt': extParams }
+	if (typeDecide(extParams, 'Object')) {
+		return extParams;
+	}
+	return { defaultExt: extParams };
 }
 
 /**
  * 检测对象类型
  */
 function typeDecide(o, type) {
-    return Object.prototype.toString.call(o) === `[object ${type}]`;
-}
+	return Object.prototype.toString.call(o) === `[object ${type}]`;
+}

+ 95 - 95
nuxt.config.js

@@ -1,104 +1,104 @@
-const env = require('./env')
+const env = require('./env');
 
 export default {
-  // Global page headers: https://go.nuxtjs.dev/config-head
-  head: {
-    title: 'de-net-official',
-    htmlAttrs: {
-      lang: 'en'
-    },
-    meta: [
-      { charset: 'utf-8' },
-      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
-      { hid: 'description', name: 'description', content: '' },
-      { name: 'format-detection', content: 'telephone=no' }
-    ],
-    link: [
-      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
-    ],
-    script: [
-      {
-        src: "https://www.googletagmanager.com/gtag/js?id=G-S376V42WBS",
-        async: true
-      },
-      {
-        type: 'text/javascript', charset: 'utf-8',
-        innerHTML: `window.dataLayer = window.dataLayer || [];
-        function gtag() { dataLayer.push(arguments); }
-        gtag('js', new Date());
-        gtag('config', 'G-S376V42WBS');`
-      }
-    ],
-    __dangerouslyDisableSanitizers: ['script']
-  },
+	// Global page headers: https://go.nuxtjs.dev/config-head
+	head: {
+		title: 'de-net-official',
+		htmlAttrs: {
+			lang: 'en',
+		},
+		meta: [{ charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: '' }, { name: 'format-detection', content: 'telephone=no' }],
+		link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
+	},
 
+	// Global CSS: https://go.nuxtjs.dev/config-css
+	css: [],
 
-  // Global CSS: https://go.nuxtjs.dev/config-css
-  css: [
-  ],
+	// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
+	plugins: ['plugins/vant'],
 
-  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
-  plugins: [
-    'plugins/vant'
-  ],
+	// Auto import components: https://go.nuxtjs.dev/config-components
+	components: true,
 
-  // Auto import components: https://go.nuxtjs.dev/config-components
-  components: true,
+	// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
+	buildModules: [],
 
-  // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
-  buildModules: [
-  ],
+	// Modules: https://go.nuxtjs.dev/config-modules
+	modules: [
+		// https://go.nuxtjs.dev/bootstrap
+		'bootstrap-vue/nuxt',
+	],
 
-  // Modules: https://go.nuxtjs.dev/config-modules
-  modules: [
-    // https://go.nuxtjs.dev/bootstrap
-    'bootstrap-vue/nuxt',
-  ],
+	// Build Configuration: https://go.nuxtjs.dev/config-build
+	build: {},
 
-  // Build Configuration: https://go.nuxtjs.dev/config-build
-  build: {
-  },
-
-  router: {
-    extendRoutes(routes, resolve) {
-      routes.push({
-        name: 'RedPackage',
-        path: '/:id?',
-        component: resolve(__dirname, 'pages/index.vue')
-      },
-        {
-          name: 'LuckDraw',
-          path: '/luckdraw/:id?',
-          component: resolve(__dirname, 'pages/luckdraw.vue')
-        },
-        {
-          name: 'ToolBox',
-          path: '/toolbox/:id',
-          component: resolve(__dirname, 'pages/toolbox/index.vue')
-        },
-        {
-          name: 'Install',
-          path: '/install',
-          component: resolve(__dirname, 'pages/install.vue')
-        },
-        {
-          name: 'NFT',
-          path: '/nft/:id/:account',
-          component: resolve(__dirname, 'pages/nft/index.vue')
-        },
-        {
-          name: 'NftGroup',
-          path: '/nft_group/:id',
-          component: resolve(__dirname, 'pages/nft/group.vue')
-        },
-        {
-          name: 'custom',
-          path: '*',
-          component: resolve(__dirname, 'pages/404.vue')
-        })
-    }
-  },
-  env: {
-    NUXT_ENV: env[process.env.MODE]
-  }
-}
+	router: {
+		extendRoutes(routes, resolve) {
+			routes.push(
+				{
+					name: 'Course',
+					path: '/course',
+					component: resolve(__dirname, 'pages/course/index.vue'),
+				},
+				{
+					name: 'Authlogin',
+					path: '/authlogin',
+					component: resolve(__dirname, 'pages/auth/authLogin.vue'),
+				},
+				{
+					name: 'Unlogin',
+					path: '/unlogin',
+					component: resolve(__dirname, 'pages/course/unLogin.vue'),
+				},
+				{
+					name: 'RedPackage',
+					path: '/:id?',
+					component: resolve(__dirname, 'pages/index.vue'),
+				},
+				{
+					name: 'LuckDraw',
+					path: '/luckdraw/:id?',
+					component: resolve(__dirname, 'pages/luckdraw.vue'),
+				},
+				{
+					name: 'ToolBox',
+					path: '/toolbox/:id',
+					component: resolve(__dirname, 'pages/toolbox/index.vue'),
+				},
+				{
+					name: 'Install',
+					path: '/install',
+					component: resolve(__dirname, 'pages/install.vue'),
+				},
+				{
+					name: 'NFT',
+					path: '/nft/:id/:account',
+					component: resolve(__dirname, 'pages/nft/index.vue'),
+				},
+				{
+					name: 'NftGroup',
+					path: '/nft_group/:id',
+					component: resolve(__dirname, 'pages/nft/group.vue'),
+				},
+				{
+					name: 'Treasure',
+					path: '/treasure/:id?',
+					component: resolve(__dirname, 'pages/treasure/index.vue'),
+				},
+				{
+					name: 'TreasureInvite',
+					path: '/treasure/invite/:id/:channel?',
+					component: resolve(__dirname, 'pages/treasure/invite.vue'),
+				},
+				{
+					name: 'custom',
+					path: '*',
+					component: resolve(__dirname, 'pages/404.vue'),
+				}
+			);
+		},
+	},
+	env: {
+		NUXT_ENV: env[process.env.MODE],
+	},
+};

+ 22 - 1
package.json

@@ -10,6 +10,7 @@
   },
   "scripts": {
     "dev": "nuxt",
+	"postinstall": "husky install",
     "dev-test": "cross-env MODE=test nuxt",
     "dev-pre": "cross-env MODE=pre nuxt",
     "dev-prod": "cross-env MODE=prod nuxt",
@@ -19,7 +20,19 @@
     "start": "nuxt start",
     "pm2": "pm2 start yarn --interpreter bash --name oitboy-front -- start",
     "generate": "nuxt generate",
-    "test": "jest"
+    "prepare": "husky install"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "lint-staged"
+    }
+  },
+  "lint-staged": {
+    "*.{js,vue}": [
+      "prettier --write",
+      "eslint --fix --ext .js,.vue --ignore-path .gitignore .",
+      "git add"
+    ]
   },
   "dependencies": {
     "axios": "^0.26.1",
@@ -44,9 +57,17 @@
     "@vue/test-utils": "^1.3.0",
     "babel-core": "7.0.0-bridge.0",
     "babel-jest": "^27.4.4",
+    "eslint": "^8.19.0",
+    "eslint-plugin-vue": "^9.2.0",
+    "husky": "^8.0.1",
     "jest": "^27.4.4",
+    "lint-staged": "^13.0.3",
+    "prettier": "^2.7.1",
     "sass": "^1.49.11",
     "sass-loader": "^10.2.1",
     "vue-jest": "^3.0.4"
+  },
+  "engines" : {
+    "node" : ">=14.0.0"
   }
 }

+ 58 - 0
pages/auth/authLogin.vue

@@ -0,0 +1,58 @@
+<!-- 移动端 twitter授权登录中间页 -->
+<template>
+	<div class="welcome">
+		<span class="text"></span>
+	</div>
+</template>
+
+<script>
+import { setStorage, storageKey } from '../../utils/help';
+export default {
+	name: 'authLogin',
+	data() {
+		return {
+			code: '',
+		};
+	},
+	methods: {
+		close() {
+			window.close();
+		},
+	},
+	mounted() {
+		let url = new URL(window.location.href);
+		let search = url.search;
+		let urlParams = new URLSearchParams(search);
+		let verifier = urlParams.get('oauth_verifier');
+		if (verifier) {
+			setStorage(storageKey.verifier, verifier);
+			let time = process.env.NODE_ENV === 'production' ? 200 : 500;
+			setTimeout(() => {
+				this.close();
+			}, time);
+		} else {
+			// 用户取消 或者 异常进入
+			setStorage(storageKey.backFromTwitterLogin, 1);
+			this.close();
+		}
+	},
+};
+</script>
+
+<style lang="scss" scoped>
+body {
+	background-color: #f5f5f5;
+}
+
+.welcome {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	width: 100%;
+	height: 100%;
+	.text {
+		font-size: 22px;
+		color: #1d9bf0;
+	}
+}
+</style>

+ 251 - 0
pages/course/index.vue

@@ -0,0 +1,251 @@
+<!-- 移动端 教程页面 -->
+<template>
+	<div class="course-page">
+		<div class="course-page-tips">
+			<img class="tip-icon" src="./../../static/img/icon-h5-topc.png" />
+			<span class="tip-text">{{ tipTextCpd }}</span>
+		</div>
+		<div class="course-page-pics-contail">
+			<div class="course-page-pics-contail-wrap" :style="{ transform: translastCpd }">
+				<img class="pic" v-for="(item, index) in course" :key="index" :src="item" />
+			</div>
+		</div>
+		<div class="course-page-pagination">
+			<div class="spon" v-for="(item, index) in course" :key="index" :class="active === index ? 'active' : ''"></div>
+		</div>
+		<div class="course-page-btns">
+			<div v-if="active > 0" class="course-page-btns-btn back" @click="back">Back</div>
+			<div v-if="active < this.course.length - 1" class="course-page-btns-btn next" @click="next">Next</div>
+			<div v-if="active === this.course.length - 1 && isUsefulCpd && (isLottaryCpd || isTreasureCpd || isCommonCpd)" @click="retweer" class="course-page-btns-btn retweer">Retweet</div>
+		</div>
+	</div>
+</template>
+
+<script>
+import { PlayType, UsefulType } from '../../types';
+import axios from 'axios';
+import Report from '../../log-center/log';
+import { getQueryString, baseURL, appVersionCode, getMid, getStorage, removeStorage } from '../../utils/help';
+
+export default {
+	name: 'course',
+	data() {
+		return {
+			active: 0,
+			useful: '',
+			course: [],
+		};
+	},
+	computed: {
+		translastCpd() {
+			return `translateX(${-this.active * 100}vw)`;
+		},
+		isLottaryCpd() {
+			return +this.playType === PlayType.lottery;
+		},
+		isCommonCpd() {
+			return +this.playType === PlayType.common;
+		},
+		isTreasureCpd() {
+			return +this.playType === PlayType.Treasure;
+		},
+		isNFTCpd() {
+			return +this.playType === PlayType.NFT;
+		},
+		isUsefulCpd() {
+			return this.useful === '1';
+		},
+		tipTextCpd() {
+			if (!this.isUsefulCpd) {
+				return 'How to install Denet Chrome Extension';
+			} else if (this.isCommonCpd) {
+				return 'Install DeNet chrome extension to claim your prize';
+			} else if (this.isLottaryCpd || this.isTreasureCpd) {
+				return 'Install Denet Chrome Extension to complete the quest';
+			} else {
+				return 'How to install Denet Chrome Extension';
+			}
+		},
+	},
+	methods: {
+		next() {
+			this.active++;
+			this.reportLog();
+		},
+		back() {
+			this.active--;
+			this.reportLog();
+		},
+		retweer() {
+			let logData = {
+				baseInfo: {
+					mid: getMid(),
+					pageSource: Report.pageSource.tutorialPage,
+					machineCode: getMid(),
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.buttonClick,
+						objectType: Report.objectType.rtButton,
+						postId: getQueryString('postId'),
+					},
+				},
+			};
+			Report.reportLog(logData);
+			if (getQueryString('srcContentId')) {
+				window.location.href = `https://twitter.com/intent/retweet?tweet_id=${getQueryString('srcContentId')}`;
+			}
+		},
+		reportLog() {
+			let logData = {
+				baseInfo: {
+					mid: getMid(),
+					pageSource: Report.pageSource.tutorialPage,
+					machineCode: getMid(),
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.pageView,
+						postId: getQueryString('postId'),
+					},
+					extParams: {
+						pageindex: this.active + 1,
+					},
+				},
+			};
+			if (this.isNFTCpd) {
+				delete logData.params.eventData.postId;
+				logData.params.eventData.nftProjectId = getQueryString('nftProjectId');
+			}
+			Report.reportLog(logData);
+		},
+	},
+	async asyncData(params) {
+		let { route } = params;
+		let { data } = await axios.post(`${baseURL}/denet/base/guide/getAllMobilePageGuide`, {
+			baseInfo: {
+				appVersionCode: appVersionCode,
+				mid: '00000000-0000-0000-0000-000000000000',
+			},
+		});
+		if (data.code == 0) {
+			return {
+				useful: route.query.useful,
+				playType: route.query.playType,
+				course: route.query.useful === UsefulType.unUseful || route.query.playType === PlayType.NFT ? data.data.withoutRewardGuideImages : data.data.withRewardGuideImages,
+			};
+		}
+	},
+	mounted() {
+		this.reportLog();
+		const landPageLog = getStorage('land-page-log');
+		if (landPageLog) {
+			Report.reportLog(JSON.parse(landPageLog));
+			removeStorage('land-page-log');
+		}
+	},
+};
+</script>
+
+<style lang="scss">
+html,
+body,
+#__nuxt,
+#__layout {
+	width: 100%;
+	height: 100%;
+	padding: 0;
+	margin: 0;
+}
+</style>
+
+<style lang="scss" scoped>
+body {
+	background-color: #f5f5f5;
+}
+.course-page {
+	min-height: 100%;
+	max-height: 100%;
+	overflow: hidden;
+	display: flex;
+	flex-direction: column;
+	align-items: center;
+	justify-content: space-between;
+
+	&-tips {
+		width: 100%;
+		height: 80px;
+		background: #94a7b6;
+		display: flex;
+		padding: 0 20px;
+		align-items: center;
+		font-weight: 600;
+		font-size: 16px;
+		line-height: 22px;
+		color: #fff;
+		z-index: 1;
+		.tip-icon {
+			width: 36px;
+			margin-right: 20px;
+		}
+	}
+	&-pics-contail {
+		flex: 1;
+		overflow: hidden;
+		&-wrap {
+			display: flex;
+			transition: all 0.5s;
+			.pic {
+				width: 100%;
+			}
+		}
+	}
+	&-pagination {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		margin: 16px 0;
+		.spon {
+			width: 8px;
+			height: 8px;
+			background: #d9d9d9;
+			margin: 0 3px;
+			border-radius: 50%;
+		}
+		.active {
+			background: #1d9bf0;
+		}
+	}
+	&-btns {
+		width: 100%;
+		display: flex;
+		padding: 0 8px 30px;
+		&-btn {
+			flex: 1;
+			margin: 0 8px;
+			height: 54px;
+			line-height: 54px;
+			text-align: center;
+			border-radius: 60px;
+		}
+		&-btn:active {
+			-webkit-tap-highlight-color: transparent;
+		}
+		.back {
+			background: rgba(29, 155, 240, 0.01);
+			border: 1px solid #e8e8e8;
+			color: #3d3d3d;
+		}
+		.next {
+			background: rgba(0, 0, 0, 0.01);
+			border: 1px solid #b5e1ff;
+			color: #1d9bf0;
+		}
+		.retweer {
+			background: #1d9bf0;
+			border: 1px solid #1d9bf0;
+			color: #fff;
+		}
+	}
+}
+</style>

+ 51 - 0
pages/course/unLogin.vue

@@ -0,0 +1,51 @@
+<!-- 移动端 教程页面 -->
+<template>
+	<div class="course-page">
+		<button class="btn" @click="unlogin">退出Denet登录</button>
+	</div>
+</template>
+
+<script>
+import { removeStorage, storageKey } from '../../utils/help';
+
+export default {
+	name: 'course',
+
+	methods: {
+		unlogin() {
+			removeStorage(storageKey.userInfo);
+		},
+	},
+};
+</script>
+<style lang="scss">
+html,
+body,
+#__nuxt,
+#__layout {
+	width: 100%;
+	height: 100%;
+	padding: 0;
+	margin: 0;
+}
+</style>
+<style lang="scss" scoped>
+.course-page {
+	position: relative;
+	height: 100%;
+	.btn {
+		padding: 20px 30px;
+		border: 1px solid #000;
+		color: #000;
+		font-size: 18px;
+		text-align: center;
+		border-radius: 6px;
+		position: absolute;
+		left: 50%;
+		top: 50%;
+		transform: translate(-50%, -50%);
+	}
+}
+.btn {
+}
+</style>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 241 - 292
pages/index.vue


Dosya farkı çok büyük olduğundan ihmal edildi
+ 666 - 796
pages/luckdraw.vue


+ 450 - 450
pages/nft/group.vue

@@ -1,280 +1,280 @@
 <template>
-    <div class="nft-content">
-        <template v-if="isLoading">
-            <img class="loading" src="../../static/svg/icon-loading.svg" />
-        </template>
-        <template v-else>
-            <template v-if="isMobile">
-                <div class="small">
-                    <div class="banner">
-                        <div class="logo">
-                            <img class="img" :src="postBizData.groupIcon" />
-                        </div>
-                        <div class="desc">{{ postBizData.groupName }}</div>
-                    </div>
-                    <div class="title">Open link on PC to Join Group</div>
-                    <div class="desc">{{ linkHref }}</div>
-                    <div class="copy">
-                        <button class="btn" :data-clipboard-text="linkHref">Copy Link</button>
-                    </div>
-                </div>
-            </template>
-            <template v-else>
-                <div class="logo">
-                    <img src="/img/icon-logo.png" alt />
-                </div>
-                <div class="show">
-                    <div class="center">
-                        <div class="header">
-                            <div class="core">
-                                <div class="core_logo"><img :src="postBizData.groupIcon" /></div>
-                                <div class="core_title">{{ postBizData.groupName }}</div>
-                            </div>
-                            <div class="member">
-                                <label>
-                                    <img src="../../static/svg/icon-nft-member.svg" />
-                                    <span>{{ postBizData.memberCount }} Member</span>
-                                </label>
-                                <label>
-                                    <img src="../../static/svg/icon-nft-post.svg" />
-                                    <span>{{ postBizData.postCount }} Posts</span>
-                                </label>
-                            </div>
-                        </div>
-                        <div class="footer">
-                            <template v-if="isChrome">
-                                <div class="font">Install DeNet to Join The Group</div>
-                                <img class="btn" @click="installExtension"
-                                    src="../../static/svg/icon-install-nft-plugin.svg" />
-                            </template>
-                            <template v-else>
-                                <div class="font">Only Support to Use Chrome<br />to Join Group</div>
-                                <img class="btn" @click="installChrome"
-                                    src="../../static/svg/icon-install-nft-chrome.svg" />
-                            </template>
-                        </div>
-                    </div>
-                </div>
-            </template>
-        </template>
-    </div>
+	<div class="nft-content">
+		<template v-if="isLoading">
+			<img class="loading" src="../../static/svg/icon-loading.svg" />
+		</template>
+		<template v-else>
+			<template v-if="isMobile">
+				<div class="small">
+					<div class="banner">
+						<div class="logo">
+							<img class="img" :src="postBizData.groupIcon" />
+						</div>
+						<div class="desc">{{ postBizData.groupName }}</div>
+					</div>
+					<div class="title">Open link on PC to Join Group</div>
+					<div class="desc">{{ linkHref }}</div>
+					<div class="copy">
+						<button class="btn" :data-clipboard-text="linkHref">Copy Link</button>
+					</div>
+				</div>
+			</template>
+			<template v-else>
+				<div class="logo">
+					<img src="/img/icon-logo.png" alt />
+				</div>
+				<div class="show">
+					<div class="center">
+						<div class="header">
+							<div class="core">
+								<div class="core_logo"><img :src="postBizData.groupIcon" /></div>
+								<div class="core_title">{{ postBizData.groupName }}</div>
+							</div>
+							<div class="member">
+								<label>
+									<img src="../../static/svg/icon-nft-member.svg" />
+									<span>{{ postBizData.memberCount }} Member</span>
+								</label>
+								<label>
+									<img src="../../static/svg/icon-nft-post.svg" />
+									<span>{{ postBizData.postCount }} Posts</span>
+								</label>
+							</div>
+						</div>
+						<div class="footer">
+							<template v-if="isChrome">
+								<div class="font">Install DeNet to Join The Group</div>
+								<img class="btn" @click="installExtension" src="../../static/svg/icon-install-nft-plugin.svg" />
+							</template>
+							<template v-else>
+								<div class="font">Only Support to Use Chrome<br />to Join Group</div>
+								<img class="btn" @click="installChrome" src="../../static/svg/icon-install-nft-chrome.svg" />
+							</template>
+						</div>
+					</div>
+				</div>
+			</template>
+		</template>
+	</div>
 </template>
 
 <script>
-import axios from 'axios'
-import Cookies from 'js-cookie'
+import axios from 'axios';
+import Cookies from 'js-cookie';
 import { Toast } from 'vant';
-import { isBrowser, appVersionCode, appType } from '../../utils/help.js'
-import Report from "@/log-center/log"
+import { isBrowser, appVersionCode, appType } from '../../utils/help.js';
+import Report from '@/log-center/log';
 const api = {
-    prod: 'https://api.denetme.net',
-    pre: 'https://preapi.denetme.net',
-    test: 'https://testapi.denetme.net'
-}
+	prod: 'https://api.denetme.net',
+	pre: 'https://preapi.denetme.net',
+	test: 'https://testapi.denetme.net',
+};
 const page = {
-    prod: "https://h5.denetme.net",
-    pre: "https://preh5.denetme.net",
-    test: 'https://testh5.denetme.net'
-}
-const jumpUrl = page[process.env.NUXT_ENV.MODE] + '/'
-const baseURL = api[process.env.NUXT_ENV.MODE]
-const ClipboardJS = require('clipboard')
+	prod: 'https://h5.denetme.net',
+	pre: 'https://preh5.denetme.net',
+	test: 'https://testh5.denetme.net',
+};
+const jumpUrl = page[process.env.NUXT_ENV.MODE] + '/';
+const baseURL = api[process.env.NUXT_ENV.MODE];
+const ClipboardJS = require('clipboard');
 
 export default {
-    name: 'ntf',
-    data() {
-        return {
-            isLoading: true,
-            appVersionCode: appVersionCode,
-            jumpUrl: jumpUrl,
-            detail: {},
-            postBizData: {
-                groupImagePath: '',
-            },
-            config: {},
-            title: 'DeNet Giveaway',
-            isMobile: false,
-            isChrome: false,
-            linkHref: '',
-            metaTitle: 'DeNet: Join NFT Owners Group',
-        }
-    },
-    head() {
-        return {
-            type: '',
-            title: this.title,
-            appVersionCode: appVersionCode,
-            meta: [
-                // facebook 
-                {
-                    name: 'og:url',
-                    content: this.jumpUrl + 'nft_group/' + this.$route.params.id
-                },
-                {
-                    name: 'og:title',
-                    content: this.metaTitle
-                },
-                {
-                    name: 'og:image',
-                    content: this.postBizData.groupImagePath || ''
-                },
-                // twitter
-                {
-                    name: 'twitter:card',
-                    content: 'summary_large_image'
-                },
-                {
-                    name: 'twitter:url',
-                    content: this.jumpUrl + 'nft_group/' + this.$route.params.id
-                },
-                {
-                    name: 'twitter:title',
-                    content: this.metaTitle
-                },
-                {
-                    name: 'twitter:image',
-                    content: this.postBizData.groupImagePath || ''
-                }
-            ]
-        }
-    },
-    async asyncData(params) {
-        let { route } = params;
-        let { data } = await axios.post(`${baseURL}/denet/post/getDetail`, {
-            baseInfo: {
-                appVersionCode: appVersionCode,
-                mid: function () {
-                    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
-                        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
-                        return v.toString(16);
-                    });
-                }()
-            },
-            params: {
-                postId: route.params.id || ''
-            }
-        })
-        if (data.code == 0 && data.data !== null) {
-            return {
-                detail: data.data,
-                postBizData: JSON.parse(data.data.postBizData),
-            }
-        }
-    },
-    created() {
-        this.setCookieMid();
-        this.getConfig();
-    },
-    mounted() {
-        this.checkBrowser();
-        this.setNftInfo();
-        this.isLoading = false;
+	name: 'ntf',
+	data() {
+		return {
+			isLoading: true,
+			appVersionCode: appVersionCode,
+			jumpUrl: jumpUrl,
+			detail: {},
+			postBizData: {
+				groupImagePath: '',
+			},
+			config: {},
+			title: 'DeNet Giveaway',
+			isMobile: false,
+			isChrome: false,
+			linkHref: '',
+			metaTitle: 'DeNet: Join NFT Owners Group',
+		};
+	},
+	head() {
+		return {
+			type: '',
+			title: this.title,
+			appVersionCode: appVersionCode,
+			meta: [
+				// facebook
+				{
+					name: 'og:url',
+					content: this.jumpUrl + 'nft_group/' + this.$route.params.id,
+				},
+				{
+					name: 'og:title',
+					content: this.metaTitle,
+				},
+				{
+					name: 'og:image',
+					content: this.postBizData.groupImagePath || '',
+				},
+				// twitter
+				{
+					name: 'twitter:card',
+					content: 'summary_large_image',
+				},
+				{
+					name: 'twitter:url',
+					content: this.jumpUrl + 'nft_group/' + this.$route.params.id,
+				},
+				{
+					name: 'twitter:title',
+					content: this.metaTitle,
+				},
+				{
+					name: 'twitter:image',
+					content: this.postBizData.groupImagePath || '',
+				},
+			],
+		};
+	},
+	async asyncData(params) {
+		let { route } = params;
+		let { data } = await axios.post(`${baseURL}/denet/post/getDetail`, {
+			baseInfo: {
+				appVersionCode: appVersionCode,
+				mid: (function () {
+					return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+						var r = (Math.random() * 16) | 0,
+							v = c == 'x' ? r : (r & 0x3) | 0x8;
+						return v.toString(16);
+					});
+				})(),
+			},
+			params: {
+				postId: route.params.id || '',
+			},
+		});
+		if (data.code == 0 && data.data !== null) {
+			return {
+				detail: data.data,
+				postBizData: JSON.parse(data.data.postBizData),
+			};
+		}
+	},
+	created() {
+		this.setCookieMid();
+		this.getConfig();
+	},
+	mounted() {
+		this.checkBrowser();
+		this.setNftInfo();
+		this.isLoading = false;
 
-        var clipboard = new ClipboardJS('.btn');
-        let that = this
-        clipboard.on('success', function (e) {
-            Toast('copy success');
-            that.trackingClick()
-            e.clearSelection();
-        });
+		var clipboard = new ClipboardJS('.btn');
+		let that = this;
+		clipboard.on('success', function (e) {
+			Toast('copy success');
+			that.trackingClick();
+			e.clearSelection();
+		});
 
-        // 埋点
-        this.pageSource = Report.pageSource.newUserLandingPage
-        if (this.isMobile) {
-            this.pageSource = Report.pageSource.mobileLandingPage
-        }
-        Report.reportLog({
-            baseInfo: {
-                appVersionCode: appVersionCode,
-                mid: this.mid,
-                pageSource: this.pageSource,
-                appType,
-                machineCode: this.mid
-            },
-            params: {
-                eventData: {
-                    businessType: Report.businessType.pageView,
-                    postId: this.detail.postId,
-                    srcContentId: this.detail.srcContentId,
-                    senderId: this.detail.srcUserId,
-                    redPacketType: 3,
-                }
-            }
-        })
-    },
-    methods: {
-        trackingClick() {
-            Report.reportLog({
-                baseInfo: {
-                    appVersionCode: appVersionCode,
-                    mid: this.mid,
-                    pageSource: this.pageSource,
-                    appType,
-                    machineCode: this.mid
-                },
-                params: {
-                    eventData: {
-                        businessType: Report.businessType.buttonClick,
-                        postId: this.detail.postId,
-                        srcContentId: this.detail.srcContentId,
-                        senderId: this.detail.srcUserId,
-                        redPacketType: 3,
-                    }
-                }
-            })
-        },
-        guid() {
-            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
-                var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
-                return v.toString(16);
-            });
-        },
-        setCookieMid() {
-            let _cookie_mid_arr = Cookies.get('mid') || []
-            if (_cookie_mid_arr.length > 0) {
-                this.mid = JSON.parse(_cookie_mid_arr)[0].mid
-            } else {
-                this.mid = this.guid()
-                Cookies.set('mid', JSON.stringify([{ mid: this.mid }]), { expires: 1000 })
-            }
-        },
-        installExtension() {
-            // 埋点
-            this.trackingClick()
-            let { extensionsInstallUrl } = this.config;
-            window.open(extensionsInstallUrl)
-        },
-        installChrome() {
-            window.open('https://www.google.com/chrome')
-        },
-        async getConfig() {
-            let { data } = await axios.post(`${baseURL}/denet/base/config/getFrontConfig`, {
-                baseInfo: {
-                    appVersionCode: appVersionCode,
-                    mid: this.mid
-                },
-                params: {}
-            })
-            if (data.code == 0) {
-                this.config = data.data;
-            }
-        },
-        checkBrowser() {
-            this.linkHref = window.location.href;
-            this.isChrome = isBrowser() == 'chrome';
-            this.isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
-        },
-        setNftInfo() {
-            let nftGroupInfo = {
-                twitterAccount: this.postBizData.defaultTwitterAccount || '',
-                createTime: Date.now(),
-                jump_type: 'nft_group_info',
-                postId: this.detail.postId || ''
-            };
-            Cookies.set('jump_info', JSON.stringify(nftGroupInfo), { expires: 100 });
-        },
-    }
-}
+		// 埋点
+		this.pageSource = Report.pageSource.newUserLandingPage;
+		if (this.isMobile) {
+			this.pageSource = Report.pageSource.mobileLandingPage;
+		}
+		Report.reportLog({
+			baseInfo: {
+				appVersionCode: appVersionCode,
+				mid: this.mid,
+				pageSource: this.pageSource,
+				appType,
+				machineCode: this.mid,
+			},
+			params: {
+				eventData: {
+					businessType: Report.businessType.pageView,
+					postId: this.detail.postId,
+					srcContentId: this.detail.srcContentId,
+					senderId: this.detail.srcUserId,
+					redPacketType: 3,
+				},
+			},
+		});
+	},
+	methods: {
+		trackingClick() {
+			Report.reportLog({
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+					pageSource: this.pageSource,
+					appType,
+					machineCode: this.mid,
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.buttonClick,
+						postId: this.detail.postId,
+						objectType: Report.objectType.copyLinkButton,
+						srcContentId: this.detail.srcContentId,
+						senderId: this.detail.srcUserId,
+						redPacketType: 3,
+					},
+				},
+			});
+		},
+		guid() {
+			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+				var r = (Math.random() * 16) | 0,
+					v = c == 'x' ? r : (r & 0x3) | 0x8;
+				return v.toString(16);
+			});
+		},
+		setCookieMid() {
+			let _cookie_mid_arr = Cookies.get('mid') || [];
+			if (_cookie_mid_arr.length > 0) {
+				this.mid = JSON.parse(_cookie_mid_arr)[0].mid;
+			} else {
+				this.mid = this.guid();
+				Cookies.set('mid', JSON.stringify([{ mid: this.mid }]), { expires: 1000 });
+			}
+		},
+		installExtension() {
+			// 埋点
+			this.trackingClick();
+			let { extensionsInstallUrl } = this.config;
+			window.open(extensionsInstallUrl);
+		},
+		installChrome() {
+			window.open('https://www.google.com/chrome');
+		},
+		async getConfig() {
+			let { data } = await axios.post(`${baseURL}/denet/base/config/getFrontConfig`, {
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+				},
+				params: {},
+			});
+			if (data.code == 0) {
+				this.config = data.data;
+			}
+		},
+		checkBrowser() {
+			this.linkHref = window.location.href;
+			this.isChrome = isBrowser() == 'chrome';
+			this.isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+		},
+		setNftInfo() {
+			let nftGroupInfo = {
+				twitterAccount: this.postBizData.defaultTwitterAccount || '',
+				createTime: Date.now(),
+				jump_type: 'nft_group_info',
+			};
+			Cookies.set('jump_info', JSON.stringify(nftGroupInfo), { expires: 100 });
+		},
+	},
+};
 </script>
 
 <style lang="scss">
@@ -282,218 +282,218 @@ html,
 body,
 #__nuxt,
 #__layout {
-    width: 100%;
-    height: 100%;
-    padding: 0;
-    margin: 0;
+	width: 100%;
+	height: 100%;
+	padding: 0;
+	margin: 0;
 }
 
 .nft-content {
-    overflow: hidden;
-    width: 100%;
-    height: 100%;
-    background: linear-gradient(180deg, #FFFFFF 0%, #F0F7FE 94.31%);
+	overflow: hidden;
+	width: 100%;
+	height: 100%;
+	background: linear-gradient(180deg, #ffffff 0%, #f0f7fe 94.31%);
 
-    .loading {
-        position: absolute;
-        transform: translate(-50%, -50%);
-        top: 50%;
-        left: 50%;
-        margin: auto;
-        width: 40px;
-        border-radius: 50%;
-    }
+	.loading {
+		position: absolute;
+		transform: translate(-50%, -50%);
+		top: 50%;
+		left: 50%;
+		margin: auto;
+		width: 40px;
+		border-radius: 50%;
+	}
 
-    .logo {
-        display: flex;
-        align-items: center;
-        height: 70px;
-        margin-left: 25px;
+	.logo {
+		display: flex;
+		align-items: center;
+		height: 70px;
+		margin-left: 25px;
 
-        img {
-            width: 99px;
-            height: 32px;
-        }
-    }
+		img {
+			width: 99px;
+			height: 32px;
+		}
+	}
 
-    .show {
-        display: flex;
-        align-items: center;
-        height: calc(100% - 70px);
+	.show {
+		display: flex;
+		align-items: center;
+		height: calc(100% - 70px);
 
-        .center {
-            display: flex;
-            flex-direction: column;
-            width: 505px;
-            margin: -50px auto 0;
+		.center {
+			display: flex;
+			flex-direction: column;
+			width: 505px;
+			margin: -50px auto 0;
 
-            .header {
-                display: flex;
-                flex-direction: column;
-                width: 100%;
-                height: 180px;
-                padding-left: 25px;
-                justify-content: center;
-                border-radius: 16px 16px 0 0;
-                background: url('../../static/svg/icon-nft-group-pc.svg') no-repeat right bottom #48B1F7;
+			.header {
+				display: flex;
+				flex-direction: column;
+				width: 100%;
+				height: 180px;
+				padding-left: 25px;
+				justify-content: center;
+				border-radius: 16px 16px 0 0;
+				background: url('../../static/svg/icon-nft-group-pc.svg') no-repeat right bottom #48b1f7;
 
-                .core {
-                    display: flex;
-                    align-items: center;
+				.core {
+					display: flex;
+					align-items: center;
 
-                    .core_logo {
-                        overflow: hidden;
-                        width: 54px;
-                        height: 54px;
-                        border-radius: 6px;
-                        background-color: #fff;
+					.core_logo {
+						overflow: hidden;
+						width: 54px;
+						height: 54px;
+						border-radius: 6px;
+						background-color: #fff;
 
-                        img {
-                            width: 100%;
-                            height: 100%;
-                            border-radius: 8px;
-                        }
-                    }
+						img {
+							width: 100%;
+							height: 100%;
+							border-radius: 8px;
+						}
+					}
 
-                    .core_title {
-                        color: #fff;
-                        font-size: 26px;
-                        font-weight: 700;
-                        margin-left: 16px;
-                    }
-                }
+					.core_title {
+						color: #fff;
+						font-size: 26px;
+						font-weight: 700;
+						margin-left: 16px;
+					}
+				}
 
-                .member {
-                    color: #fff;
-                    font-size: 12px;
-                    font-weight: 500;
-                    margin-top: 24px;
+				.member {
+					color: #fff;
+					font-size: 12px;
+					font-weight: 500;
+					margin-top: 24px;
 
-                    label {
-                        margin-right: 17px;
+					label {
+						margin-right: 17px;
 
-                        img {
-                            margin-top: -3px;
-                            vertical-align: middle;
-                        }
-                    }
-                }
-            }
+						img {
+							margin-top: -3px;
+							vertical-align: middle;
+						}
+					}
+				}
+			}
 
-            .footer {
-                display: flex;
-                align-items: center;
-                flex-direction: row;
-                justify-content: space-between;
-                width: 100%;
-                height: 90px;
-                border-radius: 0 0 16px 16px;
-                border: solid 1px #E2E2E2;
+			.footer {
+				display: flex;
+				align-items: center;
+				flex-direction: row;
+				justify-content: space-between;
+				width: 100%;
+				height: 90px;
+				border-radius: 0 0 16px 16px;
+				border: solid 1px #e2e2e2;
 
-                .font {
-                    flex: 1;
-                    text-align: center;
-                    font-size: 16px;
-                    font-weight: 500;
-                }
+				.font {
+					flex: 1;
+					text-align: center;
+					font-size: 16px;
+					font-weight: 500;
+				}
 
-                .btn {
-                    width: 200px;
-                    box-sizing: unset;
-                }
-            }
-        }
-    }
+				.btn {
+					width: 200px;
+					box-sizing: unset;
+				}
+			}
+		}
+	}
 }
 
 .small {
-    position: absolute;
-    top: 40%;
-    width: 100%;
-    padding: 0 16px;
-    box-sizing: border-box;
-    transform: translateY(-50%);
+	position: absolute;
+	top: 40%;
+	width: 100%;
+	padding: 0 16px;
+	box-sizing: border-box;
+	transform: translateY(-50%);
 
-    .banner {
-        position: relative;
-        overflow: hidden;
-        height: 180px;
-        border-radius: 10px;
-        background: url('../../static/svg/icon-nft-group-mobile.svg') no-repeat right bottom #48B1F7;
+	.banner {
+		position: relative;
+		overflow: hidden;
+		height: 180px;
+		border-radius: 10px;
+		background: url('../../static/svg/icon-nft-group-mobile.svg') no-repeat right bottom #48b1f7;
 
-        .logo {
-            position: absolute;
-            display: flex;
-            align-items: center;
-            justify-content: center;
-            z-index: 2;
-            margin: 0;
-            top: 38px;
-            left: 50%;
-            width: 54px;
-            height: 54px;
-            transform: translateX(-50%);
-            border-radius: 5px;
-            background-color: #FFFFFF;
+		.logo {
+			position: absolute;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			z-index: 2;
+			margin: 0;
+			top: 38px;
+			left: 50%;
+			width: 54px;
+			height: 54px;
+			transform: translateX(-50%);
+			border-radius: 5px;
+			background-color: #ffffff;
 
-            .img {
-                position: unset;
-                width: 50px;
-                height: 50px;
-                border-radius: 5px;
-            }
-        }
+			.img {
+				position: unset;
+				width: 50px;
+				height: 50px;
+				border-radius: 5px;
+			}
+		}
 
-        .desc {
-            position: absolute;
-            z-index: 2;
-            top: 115px;
-            width: 100%;
-            color: #FFFFFF;
-            font-weight: 600;
-            font-size: 20px;
-            padding: 0 12px;
-            line-height: 24px;
-            text-align: center;
-            box-sizing: border-box;
-            word-break: break-all;
-            text-overflow: ellipsis;
-            display: -webkit-box;
-            -webkit-box-orient: vertical;
-            -webkit-line-clamp: 2;
-            overflow: hidden;
-        }
-    }
+		.desc {
+			position: absolute;
+			z-index: 2;
+			top: 115px;
+			width: 100%;
+			color: #ffffff;
+			font-weight: 600;
+			font-size: 20px;
+			padding: 0 12px;
+			line-height: 24px;
+			text-align: center;
+			box-sizing: border-box;
+			word-break: break-all;
+			text-overflow: ellipsis;
+			display: -webkit-box;
+			-webkit-box-orient: vertical;
+			-webkit-line-clamp: 2;
+			overflow: hidden;
+		}
+	}
 
-    .title {
-        color: #000000;
-        font-weight: 600;
-        font-size: 20px;
-        text-align: center;
-        padding: 39px 0 7px;
-    }
+	.title {
+		color: #000000;
+		font-weight: 600;
+		font-size: 20px;
+		text-align: center;
+		padding: 39px 0 7px;
+	}
 
-    .desc {
-        color: #8A8A8A;
-        font-size: 13px;
-        padding: 0 22px;
-        word-break: break-all;
-        text-align: center;
-    }
+	.desc {
+		color: #8a8a8a;
+		font-size: 13px;
+		padding: 0 22px;
+		word-break: break-all;
+		text-align: center;
+	}
 
-    .copy {
-        margin-top: 35px;
+	.copy {
+		margin-top: 35px;
 
-        button {
-            width: 100%;
-            border: 0;
-            height: 53px;
-            color: #fff;
-            font-size: 18px;
-            font-weight: 700;
-            border-radius: 55px;
-            background: #1D9BF0;
-        }
-    }
+		button {
+			width: 100%;
+			border: 0;
+			height: 53px;
+			color: #fff;
+			font-size: 18px;
+			font-weight: 700;
+			border-radius: 55px;
+			background: #1d9bf0;
+		}
+	}
 }
-</style>
+</style>

+ 353 - 350
pages/nft/index.vue

@@ -1,261 +1,264 @@
 <template>
-    <div class="nft-content">
-        <template v-if="isLoading">
-            <img class="loading" src="../../static/svg/icon-loading.svg" />
-        </template>
-        <template v-else>
-            <template v-if="isMobile">
-                <div class="small">
-                    <div class="banner"><img :src="detail.pageImagePath" /></div>
-                    <div class="title">Open link on PC to Buy NFT</div>
-                    <div class="desc">{{ linkHref }}</div>
-                    <div class="copy">
-                        <button class="btn" :data-clipboard-text="linkHref">Copy Link</button>
-                    </div>
-                </div>
-            </template>
-            <template v-else>
-                <div class="logo">
-                    <img src="/img/icon-logo.png" alt />
-                </div>
-                <div class="show">
-                    <div class="center">
-                        <div class="img">
-                            <img :src="detail.pageImagePath" />
-                        </div>
-                        <div class="info">
-                            <template v-if="isChrome">
-                                <div class="title">Install DeNet Plugin<br />to Buy NFT</div>
-                                <img class="buy" @click="installExtension"
-                                    src="../../static/img/icon-install-plugin.svg" />
-                            </template>
-                            <template v-else>
-                                <div class="title">Only Support to Use Chrome to buy NFT</div>
-                                <img class="buy" @click="installChrome"
-                                    src="../../static/img/icon-install-chrome.svg" />
-                            </template>
-                        </div>
-                    </div>
-                </div>
-            </template>
-        </template>
-    </div>
+	<div class="nft-content">
+		<template v-if="isLoading">
+			<img class="loading" src="../../static/svg/icon-loading.svg" />
+		</template>
+		<template v-else>
+			<MobileLandPage v-if="isMobile" :prizePicPath="detail.pageImagePath" :playType="PlayType.NFT" :prize="detail.nftProjectName" :useFul="detail.purchaseStatus === 1" :nftProjectId="detail.nftProjectId"> </MobileLandPage>
+			<template v-else>
+				<div class="logo">
+					<img src="/img/icon-logo.png" alt />
+				</div>
+				<div class="show">
+					<div class="center">
+						<div class="img">
+							<img :src="detail.pageImagePath" />
+						</div>
+						<div class="info">
+							<template v-if="isChrome">
+								<div class="title">Install DeNet Plugin<br />to Buy NFT</div>
+								<img class="buy" @click="installExtension" src="../../static/img/icon-install-plugin.svg" />
+							</template>
+							<template v-else>
+								<div class="title">Only Support to Use Chrome to buy NFT</div>
+								<img class="buy" @click="installChrome" src="../../static/img/icon-install-chrome.svg" />
+							</template>
+						</div>
+					</div>
+				</div>
+			</template>
+		</template>
+	</div>
 </template>
 
 <script>
-import axios from 'axios'
-import Cookies from 'js-cookie'
+import axios from 'axios';
+import Cookies from 'js-cookie';
 import { Toast } from 'vant';
-import { isBrowser, appVersionCode, appType } from '../../utils/help.js'
-import Report from "@/log-center/log"
+import { isBrowser, appVersionCode } from '../../utils/help.js';
+import Report from '@/log-center/log';
+import { PlayType } from './../../types';
 
 const api = {
-    prod: 'https://api.denetme.net',
-    pre: 'https://preapi.denetme.net',
-    test: 'https://testapi.denetme.net'
-}
+	prod: 'https://api.denetme.net',
+	pre: 'https://preapi.denetme.net',
+	test: 'https://testapi.denetme.net',
+};
 const page = {
-    prod: "https://h5.denetme.net",
-    pre: "https://preh5.denetme.net",
-    test: 'https://testh5.denetme.net'
-}
-const jumpUrl = page[process.env.NUXT_ENV.MODE] + '/'
-const baseURL = api[process.env.NUXT_ENV.MODE]
-const ClipboardJS = require('clipboard')
+	prod: 'https://h5.denetme.net',
+	pre: 'https://preh5.denetme.net',
+	test: 'https://testh5.denetme.net',
+};
+const jumpUrl = page[process.env.NUXT_ENV.MODE] + '/';
+const baseURL = api[process.env.NUXT_ENV.MODE];
+const ClipboardJS = require('clipboard');
 
 export default {
-    name: 'ntf',
-    data() {
-        return {
-            isLoading: true,
-            appVersionCode: appVersionCode,
-            jumpUrl: jumpUrl,
-            detail: {},
-            config: {},
-            title: 'DeNet Giveaway',
-            isMobile: false,
-            isChrome: false,
-            linkHref: '',
-            metaTitle: 'DeNet: An Easy Web3 Tool For GIVEAWAY / AIRDROP',
-        }
-    },
-    head() {
-        return {
-            type: '',
-            title: this.title,
-            appVersionCode: appVersionCode,
-            meta: [
-                // facebook 
-                {
-                    name: 'og:url',
-                    content: this.jumpUrl + 'nft/' + this.$route.params.id + `/${this.$route.params.account}`
-                },
-                {
-                    name: 'og:title',
-                    content: this.metaTitle
-                },
-                {
-                    name: 'og:image',
-                    content: this.detail.linkImagePath || ''
-                },
-                // twitter
-                {
-                    name: 'twitter:card',
-                    content: 'summary_large_image'
-                },
-                {
-                    name: 'twitter:url',
-                    content: this.jumpUrl + 'nft/' + this.$route.params.id + `/${this.$route.params.account}`
-                },
-                {
-                    name: 'twitter:title',
-                    content: this.metaTitle
-                },
-                {
-                    name: 'twitter:image',
-                    content: this.detail.linkImagePath || ''
-                }
-            ]
-        }
-    },
-    async asyncData(params) {
-        let { route } = params;
-        let { data } = await axios.post(`${baseURL}/denet/nft/project/getNftProjectInfo`, {
-            baseInfo: {
-                appVersionCode: appVersionCode,
-                mid: function () {
-                    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
-                        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
-                        return v.toString(16);
-                    });
-                }()
-            },
-            params: {
-                nftProjectId: route.params.id || ''
-            }
-        })
-        if (data.code == 0 && data.data !== null) {
-            return {
-                detail: data.data,
-            }
-        }
-    },
-    created() {
-        this.setCookieMid();
-        this.getConfig();
-    },
-    mounted() {
-        this.checkBrowser();
-        this.setNftInfo();
-        this.isLoading = false;
+	name: 'ntf',
+	data() {
+		return {
+			PlayType,
+			isLoading: true,
+			appVersionCode: appVersionCode,
+			jumpUrl: jumpUrl,
+			detail: {},
+			config: {},
+			title: 'DeNet Giveaway',
+			isMobile: false,
+			isChrome: false,
+			linkHref: '',
+			metaTitle: 'DeNet: An Easy Web3 Tool For GIVEAWAY / AIRDROP',
+		};
+	},
+	head() {
+		return {
+			type: '',
+			title: this.title,
+			appVersionCode: appVersionCode,
+			meta: [
+				// facebook
+				{
+					name: 'og:url',
+					content: this.jumpUrl + 'nft/' + this.$route.params.id + `/${this.$route.params.account}`,
+				},
+				{
+					name: 'og:title',
+					content: this.metaTitle,
+				},
+				{
+					name: 'og:image',
+					content: this.detail.linkImagePath || '',
+				},
+				// twitter
+				{
+					name: 'twitter:card',
+					content: 'summary_large_image',
+				},
+				{
+					name: 'twitter:url',
+					content: this.jumpUrl + 'nft/' + this.$route.params.id + `/${this.$route.params.account}`,
+				},
+				{
+					name: 'twitter:title',
+					content: this.metaTitle,
+				},
+				{
+					name: 'twitter:image',
+					content: this.detail.linkImagePath || '',
+				},
+			],
+		};
+	},
+	async asyncData(params) {
+		let { route } = params;
+		let { data } = await axios.post(`${baseURL}/denet/nft/project/getNftProjectInfo`, {
+			baseInfo: {
+				appVersionCode: appVersionCode,
+				mid: (function () {
+					return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+						var r = (Math.random() * 16) | 0,
+							v = c == 'x' ? r : (r & 0x3) | 0x8;
+						return v.toString(16);
+					});
+				})(),
+			},
+			params: {
+				nftProjectId: route.params.id || '',
+			},
+		});
+		if (data.code == 0 && data.data !== null) {
+			console.log(data.data);
+			return {
+				detail: data.data,
+			};
+		}
+	},
+	created() {
+		this.setCookieMid();
+		this.getConfig();
+	},
+	mounted() {
+		this.checkBrowser();
+		this.setNftInfo();
+		this.isLoading = false;
 
-        var clipboard = new ClipboardJS('.btn');
-        let that = this
-        clipboard.on('success', function (e) {
-            Toast('copy success');
-            // 埋点
-            that.trackingClick()
-            e.clearSelection();
-        });
-        this.pageSource = Report.pageSource.newUserLandingPage
-        // 埋点
-        if (this.isMobile) {
-            this.pageSource = Report.pageSource.mobileLandingPage
-        }
-        Report.reportLog({
-            baseInfo: {
-                appVersionCode: appVersionCode,
-                mid: this.mid,
-                pageSource: this.pageSource,
-                appType,
-                machineCode: this.mid
-            },
-            params: {
-                eventData: {
-                    businessType: Report.businessType.pageView,
-                    postId: this.detail.postId,
-                    srcContentId: this.detail.srcContentId,
-                    senderId: this.detail.srcUserId,
-                    redPacketType: 2,
-                }
-            }
-        })
-    },
-    methods: {
-        trackingClick() {
-            Report.reportLog({
-                baseInfo: {
-                    appVersionCode: appVersionCode,
-                    mid: this.mid,
-                    pageSource: this.pageSource,
-                    appType,
-                    machineCode: this.mid
-                },
-                params: {
-                    eventData: {
-                        businessType: Report.businessType.buttonClick,
-                        objectType: Report.objectType.installButton,
-                        postId: this.detail.postId,
-                        srcContentId: this.detail.srcContentId,
-                        senderId: this.detail.srcUserId,
-                        redPacketType: 2,
-                    }
-                }
-            })
-        },
-        guid() {
-            return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
-                var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
-                return v.toString(16);
-            });
-        },
-        setCookieMid() {
-            let _cookie_mid_arr = Cookies.get('mid') || []
-            if (_cookie_mid_arr.length > 0) {
-                this.mid = JSON.parse(_cookie_mid_arr)[0].mid
-            } else {
-                this.mid = this.guid()
-                Cookies.set('mid', JSON.stringify([{ mid: this.mid }]), { expires: 1000 })
-            }
-        },
-        installExtension() {
-            // 埋点
-            this.trackingClick()
-            let { extensionsInstallUrl } = this.config;
-            window.open(extensionsInstallUrl)
-        },
-        installChrome() {
-            window.open('https://www.google.com/chrome')
-        },
-        async getConfig() {
-            let { data } = await axios.post(`${baseURL}/denet/base/config/getFrontConfig`, {
-                baseInfo: {
-                    appVersionCode: appVersionCode,
-                    mid: this.mid
-                },
-                params: {}
-            })
-            if (data.code == 0) {
-                this.config = data.data;
-            }
-        },
-        checkBrowser() {
-            this.linkHref = window.location.href;
-            this.isChrome = isBrowser() == 'chrome';
-            this.isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
-        },
-        setNftInfo() {
-            let nftInfo = {
-                nftProjectId: this.detail.nftProjectId || '',
-                twitterAccount: atob(this.$route.params.account || ''),
-                createTime: Date.now(),
-                jump_type: 'nft_info',
-                postId: this.detail.postId || ''
-            };
-            Cookies.set('jump_info', JSON.stringify(nftInfo), { expires: 100 });
-        },
-    }
-}
+		var clipboard = new ClipboardJS('.btn');
+		let that = this;
+		clipboard.on('success', function (e) {
+			Toast('copy success');
+			// 埋点
+			that.trackingClick();
+			e.clearSelection();
+		});
+		this.pageSource = Report.pageSource.newUserLandingPage;
+		// 埋点
+		if (this.isMobile) {
+			this.pageSource = Report.pageSource.mobileLandingPage;
+			Report.reportLog({
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+					pageSource: this.pageSource,
+					machineCode: this.mid,
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.pageView,
+						nftProjectId: this.detail.nftProjectId,
+						redPacketType: 2,
+					},
+				},
+			});
+		} else {
+			Report.reportLog({
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+					pageSource: this.pageSource,
+					machineCode: this.mid,
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.pageView,
+						nftProjectId: this.detail.nftProjectId,
+						redPacketType: 2,
+					},
+				},
+			});
+		}
+	},
+	methods: {
+		trackingClick() {
+			Report.reportLog({
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+					pageSource: this.pageSource,
+					machineCode: this.mid,
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.buttonClick,
+						objectType: Report.objectType.installButton,
+						nftProjectId: this.detail.nftProjectId,
+						redPacketType: 2,
+					},
+				},
+			});
+		},
+		guid() {
+			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+				var r = (Math.random() * 16) | 0,
+					v = c == 'x' ? r : (r & 0x3) | 0x8;
+				return v.toString(16);
+			});
+		},
+		setCookieMid() {
+			let _cookie_mid_arr = Cookies.get('mid') || [];
+			if (_cookie_mid_arr.length > 0) {
+				this.mid = JSON.parse(_cookie_mid_arr)[0].mid;
+			} else {
+				this.mid = this.guid();
+				Cookies.set('mid', JSON.stringify([{ mid: this.mid }]), { expires: 1000 });
+			}
+		},
+		installExtension() {
+			// 埋点
+			this.trackingClick();
+			let { extensionsInstallUrl } = this.config;
+			window.open(extensionsInstallUrl);
+		},
+		installChrome() {
+			window.open('https://www.google.com/chrome');
+		},
+		async getConfig() {
+			let { data } = await axios.post(`${baseURL}/denet/base/config/getFrontConfig`, {
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+				},
+				params: {},
+			});
+			if (data.code == 0) {
+				this.config = data.data;
+			}
+		},
+		checkBrowser() {
+			this.linkHref = window.location.href;
+			this.isChrome = isBrowser() == 'chrome';
+			this.isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+		},
+		setNftInfo() {
+			let nftInfo = {
+				nftProjectId: this.detail.nftProjectId || '',
+				twitterAccount: atob(this.$route.params.account || ''),
+				createTime: Date.now(),
+				jump_type: 'nft_info',
+			};
+			Cookies.set('jump_info', JSON.stringify(nftInfo), { expires: 100 });
+		},
+	},
+};
 </script>
 
 <style lang="scss">
@@ -263,130 +266,130 @@ html,
 body,
 #__nuxt,
 #__layout {
-    width: 100%;
-    height: 100%;
-    padding: 0;
-    margin: 0;
+	width: 100%;
+	height: 100%;
+	padding: 0;
+	margin: 0;
 }
 
 .nft-content {
-    overflow: hidden;
-    width: 100%;
-    height: 100%;
-    background: linear-gradient(180deg, #FFFFFF 0%, #F0F7FE 94.31%);
+	overflow: hidden;
+	width: 100%;
+	height: 100%;
+	background: linear-gradient(180deg, #ffffff 0%, #f0f7fe 94.31%);
 
-    .loading {
-        position: absolute;
-        transform: translate(-50%, -50%);
-        top: 50%;
-        left: 50%;
-        margin: auto;
-        width: 40px;
-        border-radius: 50%;
-    }
+	.loading {
+		position: absolute;
+		transform: translate(-50%, -50%);
+		top: 50%;
+		left: 50%;
+		margin: auto;
+		width: 40px;
+		border-radius: 50%;
+	}
 
-    .logo {
-        display: flex;
-        align-items: center;
-        height: 70px;
-        margin-left: 25px;
+	.logo {
+		display: flex;
+		align-items: center;
+		height: 70px;
+		margin-left: 25px;
 
-        img {
-            width: 99px;
-            height: 32px;
-        }
-    }
+		img {
+			width: 99px;
+			height: 32px;
+		}
+	}
 
-    .show {
-        display: flex;
-        align-items: center;
-        height: calc(100% - 70px);
+	.show {
+		display: flex;
+		align-items: center;
+		height: calc(100% - 70px);
 
-        .center {
-            display: flex;
-            margin: -50px auto 0;
-            width: 1000px;
+		.center {
+			display: flex;
+			margin: -50px auto 0;
+			width: 1000px;
 
-            .img {
-                width: 50%;
-                margin-right: 6%;
+			.img {
+				width: 50%;
+				margin-right: 6%;
 
-                img {
-                    width: 100%;
-                }
-            }
+				img {
+					width: 100%;
+				}
+			}
 
-            .info {
-                display: flex;
-                flex-direction: column;
-                justify-content: center;
-                width: 44%;
+			.info {
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
+				width: 44%;
 
-                .tag {
-                    width: 25%;
-                    margin-bottom: 6px;
-                }
+				.tag {
+					width: 25%;
+					margin-bottom: 6px;
+				}
 
-                .title {
-                    color: #3A4B56;
-                    font-size: 2.2vw;
-                    font-family: 'SF Pro Display';
-                    font-weight: bold;
-                    word-break: break-word;
-                    margin-bottom: 1vw;
-                }
+				.title {
+					color: #3a4b56;
+					font-size: 2.2vw;
+					font-family: 'SF Pro Display';
+					font-weight: bold;
+					word-break: break-word;
+					margin-bottom: 1vw;
+				}
 
-                .buy {
-                    width: 75%;
-                    max-width: 263px;
-                    max-height: 64px;
-                    cursor: pointer;
-                }
-            }
-        }
-    }
+				.buy {
+					width: 75%;
+					max-width: 263px;
+					max-height: 64px;
+					cursor: pointer;
+				}
+			}
+		}
+	}
 }
 
 .small {
-    padding: 30px 20px;
+	padding: 30px 20px;
 
-    .banner {
-        width: 100%;
+	.banner {
+		width: 100%;
 
-        img {
-            width: 100%;
-        }
-    }
+		img {
+			width: 100%;
+		}
+	}
 
-    .title {
-        color: #000000;
-        font-weight: 600;
-        font-size: 20px;
-        text-align: center;
-        padding: 17px 0 12px;
-    }
+	.title {
+		color: #000000;
+		font-weight: 600;
+		font-size: 20px;
+		text-align: center;
+		padding: 17px 0 12px;
+	}
 
-    .desc {
-        color: #8A8A8A;
-        font-size: 13px;
-        padding: 0 22px;
-        word-break: break-all;
-        text-align: center;
-    }
+	.desc {
+		color: #8a8a8a;
+		font-size: 13px;
+		padding: 0 22px;
+		word-break: break-all;
+		text-align: center;
+	}
 
-    .copy {
-        margin-top: 35px;
+	.copy {
+		margin-top: 35px;
 
-        button {
-            width: 100%;
-            border: 0;
-            height: 53px;
-            color: #fff;
-            font-size: 18px;
-            font-weight: 700;
-            border-radius: 55px;
-            background: #1D9BF0;
-        }
-    }
+		button {
+			width: 100%;
+			border: 0;
+			height: 53px;
+			color: #fff;
+			font-size: 18px;
+			font-weight: 700;
+			border-radius: 55px;
+			background: #1d9bf0;
+		}
+	}
 }
-</style>
+</style>

+ 318 - 275
pages/toolbox/index.vue

@@ -1,309 +1,352 @@
 <template>
-    <div class="main">
-        <!-- pc -->
-        <div v-if="device == 'chrome' || device == 'no-chrome'" class="content">
-            <v-logo></v-logo>
-            <div class="tool-cover">
-                <img :src="img_url" alt="">
-            </div>
-            <!-- 非chrome -->
-            <div v-if="device == 'no-chrome'">
-                <div class="txt">Use chrome browser to access {{ detail.postBizData.linkTitle || '' }}</div>
-                <install-chrome></install-chrome>
-            </div>
-            <!-- chrome -->
-            <div v-if="device == 'chrome'">
-                <div class="txt">Use chrome browser to access {{ detail.postBizData.linkTitle || '' }}</div>
-                <install-extension :extensionsInstallUrl="config.extensionsInstallUrl"></install-extension>
-            </div>
-        </div>
+	<div class="main">
+		<!-- pc -->
+		<div v-if="device == 'chrome' || device == 'no-chrome'" class="content">
+			<v-logo></v-logo>
+			<div class="tool-cover">
+				<img :src="img_url" alt="" />
+			</div>
+			<!-- 非chrome -->
+			<div v-if="device == 'no-chrome'">
+				<div class="txt">Use chrome browser to access {{ detail.postBizData.linkTitle || '' }}</div>
+				<install-chrome></install-chrome>
+			</div>
+			<!-- chrome -->
+			<div v-if="device == 'chrome'">
+				<div class="txt">Use chrome browser to access {{ detail.postBizData.linkTitle || '' }}</div>
+				<install-extension :extensionsInstallUrl="config.extensionsInstallUrl" @installClick="installClick"></install-extension>
+			</div>
+		</div>
 
-        <!-- 移动端 -->
-        <!-- <div v-if="device == 'ios' || device == '安卓'" class="mobile">
-            <div class="mobile-content">
-                <img :src="detail.postBizData.linkImagePath" alt="">
-                <div class="title">Open link on PC to use Subway Surfers</div>
-            </div>
-            <div class="area-button">
-                <div class="btn1" @click="clickExtension">
-                    Install Chrome Extension
-                </div>
-                <div class="btn2" @click="clickCopy" :data-clipboard-text="copy_link">
-                    Copy Link
-                </div>
-            </div>
-        </div> -->
-    </div>
+		<!-- 移动端 -->
+		<div v-if="device == 'ios' || device == '安卓'" class="mobile">
+			<div class="mobile-content">
+				<img :src="detail.postBizData.linkImagePath" alt="" />
+				<div class="title">Open link on PC to use Subway Surfers</div>
+			</div>
+			<div class="area-button">
+				<div class="btn1" @click="clickExtension">Install Chrome Extension</div>
+				<div class="btn2" @click="clickCopy" :data-clipboard-text="copy_link">Copy Link</div>
+			</div>
+		</div>
+	</div>
 </template>
 <script>
-import VLogo from '@/components/logo.vue'
-import InstallChrome from '@/components/InstallChrome.vue'
-import InstallExtension from '@/components/InstallExtension.vue'
-import { getBrowserType, baseURL, appVersionCode, jumpUrl } from '@/utils/help.js'
-import axios from 'axios'
-import Cookies from 'js-cookie'
+import VLogo from '@/components/logo.vue';
+import InstallChrome from '@/components/InstallChrome.vue';
+import InstallExtension from '@/components/InstallExtension.vue';
+import { getBrowserType, baseURL, appVersionCode, jumpUrl, appType } from '@/utils/help.js';
+import axios from 'axios';
+import Cookies from 'js-cookie';
 import { Toast } from 'vant';
+import Report from '@/log-center/log';
 
-
-var ClipboardJS = require('clipboard')
+var ClipboardJS = require('clipboard');
 
 export default {
-    name: 'tool_box',
-    data() {
-        return {
-            config: {},
-            copy_link: '',
-            title: 'Install DeNet Plugin to Participate',
-            metaTitle: 'Install DeNet Plugin to Participate',
-            device: '',
-            detail: {},
-            img_url: ''
-        }
-    },
-    head() {
-        return {
-            type: '',
-            title: this.title,
-            appVersionCode: appVersionCode,
-            meta: [
-                // facebook 
-                {
-                    name: 'og:url',
-                    content: jumpUrl + 'toolbox/' + this.$route.params.id
-                },
-                {
-                    name: 'og:title',
-                    content: this.metaTitle
-                },
-                {
-                    name: 'og:image',
-                    content: this.detail.postBizData.linkImagePath || ''
-                },
-                // twitter
-                {
-                    name: 'twitter:card',
-                    content: 'summary_large_image'
-                },
-                {
-                    name: 'twitter:url',
-                    content: jumpUrl + 'toolbox/' + this.$route.params.id
-                },
-                {
-                    name: 'twitter:title',
-                    content: this.detail.postBizData.linkTitle || this.metaTitle
-                },
-                {
-                    name: 'twitter:image',
-                    content: this.detail.postBizData.linkImagePath || ''
-                }
-            ]
-        }
-    },
-    components: {
-        VLogo,
-        InstallChrome,
-        InstallExtension
-    },
-    async asyncData(params) {
-        let { route } = params;
-        let { data } = await axios.post(`${baseURL}/denet/post/getDetail`, {
-            baseInfo: {
-                appVersionCode: appVersionCode,
-                mid: '00000000-0000-0000-0000-000000000000',
-            },
-            params: {
-                postId: route.params.id || ''
-            }
-        })
-        if (data.code == 0) {
-            if (data.data && data.data.postBizData && typeof data.data.postBizData == 'string') {
-                data.data.postBizData = JSON.parse(data.data.postBizData)
-            }
-            if (data.data.postBizData === null) {
-                data.data.postBizData = {
-                    postUserInfo: {}
-                }
-            }
-            console.log('detail', data.data)
-
-            return {
-                detail: data.data,
-            }
-        }
-    },
-    mounted() {
-        if (this.detail.postBizData.linkImagePath.indexOf('default') > 0) {
-            this.img_url = '/img/img-default.png'
-        } else {
-            this.img_url = this.detail.postBizData.linkImagePath
-        }
+	name: 'tool_box',
+	data() {
+		return {
+			config: {},
+			copy_link: '',
+			title: 'Install DeNet Plugin to Participate',
+			metaTitle: 'Install DeNet Plugin to Participate',
+			device: '',
+			detail: {},
+			mid: '',
+			pageSource: '',
+			img_url: '',
+		};
+	},
+	head() {
+		return {
+			type: '',
+			title: this.title,
+			appVersionCode: appVersionCode,
+			meta: [
+				// facebook
+				{
+					name: 'og:url',
+					content: jumpUrl + 'toolbox/' + this.$route.params.id,
+				},
+				{
+					name: 'og:title',
+					content: this.metaTitle,
+				},
+				{
+					name: 'og:image',
+					content: this.detail.postBizData.linkImagePath || '',
+				},
+				// twitter
+				{
+					name: 'twitter:card',
+					content: 'summary_large_image',
+				},
+				{
+					name: 'twitter:url',
+					content: jumpUrl + 'toolbox/' + this.$route.params.id,
+				},
+				{
+					name: 'twitter:title',
+					content: this.detail.postBizData.linkTitle || this.metaTitle,
+				},
+				{
+					name: 'twitter:image',
+					content: this.detail.postBizData.linkImagePath || '',
+				},
+			],
+		};
+	},
+	components: {
+		VLogo,
+		InstallChrome,
+		InstallExtension,
+	},
+	async asyncData(params) {
+		let { route } = params;
+		let { data } = await axios.post(`${baseURL}/denet/post/getDetail`, {
+			baseInfo: {
+				appVersionCode: appVersionCode,
+				mid: '00000000-0000-0000-0000-000000000000',
+			},
+			params: {
+				postId: route.params.id || '',
+			},
+		});
+		if (data.code == 0) {
+			if (data.data && data.data.postBizData && typeof data.data.postBizData == 'string') {
+				data.data.postBizData = JSON.parse(data.data.postBizData);
+			}
+			if (data.data.postBizData === null) {
+				data.data.postBizData = {
+					postUserInfo: {},
+				};
+			}
+			console.log('detail', data.data);
 
+			return {
+				detail: data.data,
+			};
+		}
+	},
+	mounted() {
+		if (this.detail.postBizData.linkImagePath.indexOf('default') > 0) {
+			this.img_url = '/img/img-default.png';
+		} else {
+			this.img_url = this.detail.postBizData.linkImagePath;
+		}
 
-        this.copy_link = window.location.href
-        this.device = getBrowserType()
-        console.log('device', this.device)
-        if (this.device == 'ios' || this.device == '安卓') {
-            return window.location = this.detail.postBizData.convertUrl
-        }
-        this.getConfig()
-        if (this.device == 'chrome') {
-            this.setCookie()
-        }
-    },
+		this.pageSource = Report.pageSource.newUserLandingPage;
+		this.setCookieMid();
+		Report.reportLog({
+			baseInfo: {
+				appVersionCode: appVersionCode,
+				mid: this.mid,
+				pageSource: this.pageSource,
+				appType,
+				machineCode: this.mid,
+			},
+			params: {
+				eventData: {
+					businessType: Report.businessType.pageView,
+					postId: this.detail.postId,
+					srcContentId: this.detail.srcContentId,
+					redPacketType: 5,
+					postEditorUrl: this.detail.postBizData.convertUrl,
+				},
+			},
+		});
+		this.copy_link = window.location.href;
+		this.device = getBrowserType();
+		this.getConfig();
+		console.log('device', this.device);
+		if (this.device == 'chrome') {
+			this.setCookie();
+		}
+	},
 
-    methods: {
-        setCookie() {
-            let pickupInfo = {
-                srcContentId: this.detail.srcContentId || '',
-                postNickName: this.detail.srcUserId || '',
-                createTime: Date.now(),
-                jump_type: 'tool_box',
-                postId: this.detail.postBizData.postId || ''
-            };
-            Cookies.set('jump_info', JSON.stringify(pickupInfo), { expires: 1000 });
-        },
-        async getConfig() {
-            let { data } = await axios.post(`${baseURL}/denet/base/config/getFrontConfig`, {
-                baseInfo: {
-                    appVersionCode: this.appVersionCode,
-                    mid: this.mid
-                },
-                params: {
-                }
-            })
-            if (data.code == 0) {
-                this.config = data.data;
-            }
-        },
-        clickCopy() {
-            // 复制链接
-            var clipboard = new ClipboardJS('.btn2');
-            clipboard.on('success', function (e) {
-                Toast('copy success');
-                e.clearSelection();
-            });
-
-            clipboard.on('error', function (e) {
-                Toast('copy error');
-            });
-        },
-        clickExtension() {
-            window.open(this.config.extensionsInstallUrl)
-        }
-    }
-}
+	methods: {
+		installClick() {
+			Report.reportLog({
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+					pageSource: this.pageSource,
+					appType,
+					machineCode: this.mid,
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.buttonClick,
+						objectType: Report.objectType.installButton,
+						postId: this.detail.postId,
+						srcContentId: this.detail.srcContentId,
+						redPacketType: 5,
+						postEditorUrl: this.detail.postBizData.convertUrl,
+					},
+				},
+			});
+		},
+		guid() {
+			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+				var r = (Math.random() * 16) | 0,
+					v = c == 'x' ? r : (r & 0x3) | 0x8;
+				return v.toString(16);
+			});
+		},
+		setCookieMid() {
+			let _cookie_mid_arr = Cookies.get('mid') || [];
+			if (_cookie_mid_arr.length > 0) {
+				this.mid = JSON.parse(_cookie_mid_arr)[0].mid;
+			} else {
+				this.mid = this.guid();
+				Cookies.set('mid', JSON.stringify([{ mid: this.mid }]), { expires: 1000 });
+			}
+		},
+		setCookie() {
+			let pickupInfo = {
+				srcContentId: this.detail.srcContentId || '',
+				postNickName: this.detail.srcUserId || '',
+				createTime: Date.now(),
+				jump_type: 'jump_info',
+			};
+			Cookies.set('jump_info', JSON.stringify(pickupInfo), { expires: 1000 });
+		},
+		async getConfig() {
+			let { data } = await axios.post(`${baseURL}/denet/base/config/getFrontConfig`, {
+				baseInfo: {
+					appVersionCode: this.appVersionCode,
+					mid: this.mid,
+				},
+				params: {},
+			});
+			if (data.code == 0) {
+				this.config = data.data;
+			}
+		},
+		clickCopy() {
+			// 复制链接
+			var clipboard = new ClipboardJS('.btn2');
+			clipboard.on('success', function (e) {
+				Toast('copy success');
+				e.clearSelection();
+			});
 
+			clipboard.on('error', function () {
+				Toast('copy error');
+			});
+		},
+		clickExtension() {
+			window.open(this.config.extensionsInstallUrl);
+		},
+	},
+};
 </script>
-<style lang="scss" >
+<style lang="scss">
 html,
 body,
 #__nuxt,
 #__layout {
-    margin: 0;
-    padding: 0;
-    width: 100%;
-    height: 100%;
-    background: #F5FAFF;
-
-
+	margin: 0;
+	padding: 0;
+	width: 100%;
+	height: 100%;
+	background: #f5faff;
 }
 
 .main {
-    width: 100%;
-    height: 100%;
-
-    .tool-cover {
-        min-width: 400px;
-        margin-right: 90px;
-
-        img {
-            max-height: 270px;
-        }
-    }
-
-    .content {
-        width: 100%;
-        height: 100%;
-        display: flex;
-        justify-content: center;
-        align-items: center;
-        padding-bottom: 70px;
+	width: 100%;
+	height: 100%;
 
-        .txt {
-            width: 400px;
-            font-weight: 700;
-            font-size: 36px;
-            line-height: 44px;
-            /* or 122% */
+	.tool-cover {
+		min-width: 400px;
+		margin-right: 90px;
 
-            letter-spacing: 0.3px;
+		img {
+			max-height: 270px;
+		}
+	}
 
-            color: #323232;
-            margin-bottom: 40px;
-        }
-    }
+	.content {
+		width: 100%;
+		height: 100%;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		padding-bottom: 70px;
 
-    .mobile {
-        .mobile-content {
-            padding: 36px 16px 0 16px;
+		.txt {
+			width: 400px;
+			font-weight: 700;
+			font-size: 36px;
+			line-height: 44px;
+			/* or 122% */
 
-            img {
-                width: 100%;
-                margin-bottom: 25px;
-                border-radius: 5px;
-            }
+			letter-spacing: 0.3px;
 
-            .title {
-                font-weight: 700;
-                font-size: 22px;
-                line-height: 26px;
-                text-align: center;
-                letter-spacing: 0.3px;
-                color: #000000;
-                width: 240px;
-                margin: 0 auto;
-            }
-        }
+			color: #323232;
+			margin-bottom: 40px;
+		}
+	}
 
+	.mobile {
+		.mobile-content {
+			padding: 36px 16px 0 16px;
 
+			img {
+				width: 100%;
+				margin-bottom: 25px;
+				border-radius: 5px;
+			}
 
-        .area-button {
-            position: fixed;
-            width: 100%;
-            padding: 27px 16px 25px 16px;
-            bottom: 0;
-            height: 170px;
+			.title {
+				font-weight: 700;
+				font-size: 22px;
+				line-height: 26px;
+				text-align: center;
+				letter-spacing: 0.3px;
+				color: #000000;
+				width: 240px;
+				margin: 0 auto;
+			}
+		}
 
-            .btn1 {
-                height: 50px;
-                line-height: 50px;
-                background: #1D9BF0;
-                border-radius: 100px;
-                width: 100%;
-                font-weight: 600;
-                font-size: 18px;
-                text-align: center;
-                letter-spacing: 0.3px;
+		.area-button {
+			position: fixed;
+			width: 100%;
+			padding: 27px 16px 25px 16px;
+			bottom: 0;
+			height: 170px;
 
-                color: #FFFFFF;
-                margin-bottom: 16px;
-            }
+			.btn1 {
+				height: 50px;
+				line-height: 50px;
+				background: #1d9bf0;
+				border-radius: 100px;
+				width: 100%;
+				font-weight: 600;
+				font-size: 18px;
+				text-align: center;
+				letter-spacing: 0.3px;
 
-            .btn2 {
-                height: 50px;
-                line-height: 50px;
-                background: rgba(29, 155, 240, 0.01);
-                border: 1px solid #1D9BF0;
-                border-radius: 100px;
-                width: 100%;
-                font-weight: 600;
-                font-size: 18px;
-                text-align: center;
-                letter-spacing: 0.3px;
-                color: #1D9BF0;
+				color: #ffffff;
+				margin-bottom: 16px;
+			}
 
-            }
-        }
-    }
+			.btn2 {
+				height: 50px;
+				line-height: 50px;
+				background: rgba(29, 155, 240, 0.01);
+				border: 1px solid #1d9bf0;
+				border-radius: 100px;
+				width: 100%;
+				font-weight: 600;
+				font-size: 18px;
+				text-align: center;
+				letter-spacing: 0.3px;
+				color: #1d9bf0;
+			}
+		}
+	}
 }
-</style>
+</style>

+ 429 - 0
pages/treasure/index.vue

@@ -0,0 +1,429 @@
+<template>
+	<div class="nft-content">
+		<template v-if="isLoading">
+			<img class="loading" src="../../static/svg/icon-loading.svg" />
+		</template>
+		<template v-else>
+			<template v-if="isMobile">
+				<MobileLandPage :playType="PlayType.Treasure" :useFul="true" :userInfo="detail.postUserInfo" :usValue="detail.upGainAmountValue" :postId="detail.postId" :srcContentId="detail.srcContentId"></MobileLandPage>
+			</template>
+			<template v-else>
+				<div class="logo">
+					<img src="/img/icon-logo.png" alt />
+				</div>
+				<div class="show">
+					<div class="center">
+						<div class="content-wrapper">
+							<img class="img img-left" :src="detail.postUserInfo.avatarUrl" alt="" />
+							<div class="middle">
+								<div class="invite-txt">@{{ detail.postUserInfo.nickName }} invite you to</div>
+								<div class="title">Hunt the Treaure</div>
+								<div class="up-gain-txt">
+									Each can gain up to <span class="amount"> ${{ detail.upGainAmountValue }}</span>
+								</div>
+							</div>
+							<img class="img" src="../../static/svg/icon-treasure.svg" alt="" />
+						</div>
+						<div class="btn-wrapper" @click="clickBtn()">
+							<template v-if="isChrome"> Install Denet Chrome Extension </template>
+							<template v-else>
+								<img class="img" src="../../static/svg/icon-chrome-down.svg" />
+								Open in Chrome to participate
+							</template>
+						</div>
+					</div>
+				</div>
+			</template>
+		</template>
+	</div>
+</template>
+
+<script>
+import axios from 'axios';
+import Cookies from 'js-cookie';
+import { Toast } from 'vant';
+import { isBrowser, appVersionCode, appType } from '../../utils/help.js';
+import Report from '@/log-center/log';
+import MobileLandPage from '@/components/MobileLandPage.vue';
+import { PlayType } from '@/types';
+
+const api = {
+	prod: 'https://api.denetme.net',
+	pre: 'https://preapi.denetme.net',
+	test: 'https://testapi.denetme.net',
+};
+const page = {
+	prod: 'https://h5.denetme.net',
+	pre: 'https://preh5.denetme.net',
+	test: 'https://testh5.denetme.net',
+};
+const jumpUrl = page[process.env.NUXT_ENV.MODE] + '/';
+const baseURL = api[process.env.NUXT_ENV.MODE];
+const ClipboardJS = require('clipboard');
+
+export default {
+	name: 'ntf',
+	data() {
+		return {
+			PlayType,
+			isLoading: true,
+			appVersionCode: appVersionCode,
+			jumpUrl: jumpUrl,
+			detail: {
+				postUserInfo: {
+					avatarUrl: '',
+					nickName: '',
+				},
+			},
+			config: {},
+			title: 'Treasure Hunt',
+			isMobile: false,
+			isChrome: false,
+			linkHref: '',
+		};
+	},
+	components: {
+		MobileLandPage,
+	},
+	head() {
+		return {
+			type: '',
+			title: this.title,
+			appVersionCode: appVersionCode,
+			meta: [
+				// facebook
+				{
+					name: 'og:title',
+					content: `Treasure Chest: ${this.detail.amountValue} ${this.detail.currencySymbol} (worth $${this.detail.amountUsdValue}) for ${this.detail.totalCount} winners`,
+				},
+				{
+					name: 'og:image',
+					content: this.detail.imagePath || '',
+				},
+				// twitter
+				{
+					name: 'twitter:card',
+					content: 'summary_large_image',
+				},
+				{
+					name: 'twitter:title',
+					content: `Treasure Chest: ${this.detail.amountValue} ${this.detail.currencySymbol} (worth $${this.detail.amountUsdValue}) for ${this.detail.totalCount} winners`,
+				},
+				{
+					name: 'twitter:image',
+					content: this.detail.imagePath || '',
+				},
+			],
+		};
+	},
+	async asyncData(params) {
+		let { route } = params;
+		let { data } = await axios.post(`${baseURL}/denet/post/treasure/detail`, {
+			baseInfo: {
+				appVersionCode: appVersionCode,
+				mid: (function () {
+					return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+						var r = (Math.random() * 16) | 0,
+							v = c == 'x' ? r : (r & 0x3) | 0x8;
+						return v.toString(16);
+					});
+				})(),
+			},
+			params: {
+				postId: route.params.id || '',
+			},
+		});
+		if (data.code == 0) {
+			return {
+				detail: data.data,
+			};
+		}
+	},
+	created() {
+		this.setCookieMid();
+		this.getConfig();
+	},
+	mounted() {
+		this.setTreasureInfo();
+		setTimeout(() => {
+			this.checkInstall()
+				.then(() => {
+					console.log(this.detail);
+					if (this.detail.srcContentId && this.detail.postUserInfo && this.detail.postUserInfo.nickName) {
+						let url = `https://twitter.com/${this.detail.postUserInfo.nickName}/status/${this.detail.srcContentId}`;
+						window.location.replace(url);
+					}
+					this.isLoading = false;
+				})
+				.catch(() => {
+					this.isLoading = false;
+				});
+		}, 1000);
+		this.checkBrowser();
+
+		var clipboard = new ClipboardJS('.btn');
+		let that = this;
+		clipboard.on('success', function (e) {
+			Toast('copy success');
+			// 埋点
+			that.trackingClick();
+			e.clearSelection();
+		});
+		this.pageSource = Report.pageSource.newUserLandingPage;
+		// 埋点
+		if (this.isMobile) {
+			this.pageSource = Report.pageSource.mobileLandingPage;
+			setTimeout(() => {
+				Report.reportLog({
+					baseInfo: {
+						appVersionCode: this.appVersionCode,
+						mid: this.mid,
+						pageSource: this.pageSource,
+						machineCode: this.mid,
+					},
+					params: {
+						eventData: {
+							businessType: Report.businessType.pageView,
+							postId: this.detail.postId,
+						},
+					},
+				});
+			}, 500);
+		} else {
+			Report.reportLog({
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+					pageSource: this.pageSource,
+					appType,
+					machineCode: this.mid,
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.pageView,
+						postId: this.detail.postId,
+						srcContentId: this.detail.srcContentId,
+						redPacketType: 4,
+					},
+				},
+			});
+		}
+	},
+	methods: {
+		clickBtn() {
+			if (this.isChrome) {
+				Report.reportLog({
+					baseInfo: {
+						appVersionCode: appVersionCode,
+						mid: this.mid,
+						pageSource: this.pageSource,
+						appType,
+						machineCode: this.mid,
+					},
+					params: {
+						eventData: {
+							businessType: Report.businessType.buttonClick,
+							postId: this.detail.postId,
+							srcContentId: this.detail.srcContentId,
+							redPacketType: 4,
+						},
+					},
+				});
+				let { extensionsInstallUrl } = this.config;
+				window.open(extensionsInstallUrl);
+			} else {
+				this.installChrome();
+			}
+		},
+		checkInstall() {
+			return new Promise((resolve, reject) => {
+				let dom = document.querySelector('#denet_message');
+				if (dom) {
+					resolve(true);
+				} else {
+					reject(false);
+				}
+			});
+		},
+		trackingClick() {},
+		guid() {
+			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+				var r = (Math.random() * 16) | 0,
+					v = c == 'x' ? r : (r & 0x3) | 0x8;
+				return v.toString(16);
+			});
+		},
+		setCookieMid() {
+			let _cookie_mid_arr = Cookies.get('mid') || [];
+			if (_cookie_mid_arr.length > 0) {
+				this.mid = JSON.parse(_cookie_mid_arr)[0].mid;
+			} else {
+				this.mid = this.guid();
+				Cookies.set('mid', JSON.stringify([{ mid: this.mid }]), { expires: 1000 });
+			}
+		},
+		installExtension() {
+			// 埋点
+			this.trackingClick();
+			let { extensionsInstallUrl } = this.config;
+			window.open(extensionsInstallUrl);
+		},
+		installChrome() {
+			window.open('https://www.google.com/chrome');
+		},
+		async getConfig() {
+			let { data } = await axios.post(`${baseURL}/denet/base/config/getFrontConfig`, {
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+				},
+				params: {},
+			});
+			if (data.code == 0) {
+				this.config = data.data;
+			}
+		},
+		checkBrowser() {
+			this.linkHref = window.location.href;
+			this.isChrome = isBrowser() == 'chrome';
+			this.isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+		},
+		setTreasureInfo() {
+			let treasureInfo = {
+				createTime: Date.now(),
+				jump_type: 'treasure_info',
+				srcContentId: this.detail.srcContentId || '',
+				postNickName: this.detail.postUserInfo.nickName,
+			};
+			Cookies.set('jump_info', JSON.stringify(treasureInfo), { expires: 100 });
+		},
+	},
+};
+</script>
+
+<style lang="scss">
+html,
+body,
+#__nuxt,
+#__layout {
+	width: 100%;
+	height: 100%;
+	padding: 0;
+	margin: 0;
+}
+
+.nft-content {
+	overflow: hidden;
+	width: 100%;
+	height: 100%;
+	background: linear-gradient(180deg, #d8efff 0%, #ffffff 44.3%);
+
+	.loading {
+		position: absolute;
+		transform: translate(-50%, -50%);
+		top: 50%;
+		left: 50%;
+		margin: auto;
+		width: 40px;
+		border-radius: 50%;
+	}
+
+	.logo {
+		display: flex;
+		align-items: center;
+		height: 70px;
+		margin-left: 25px;
+
+		img {
+			width: 99px;
+			height: 32px;
+		}
+	}
+
+	.show {
+		display: flex;
+		align-items: center;
+		height: calc(100% - 70px);
+
+		.center {
+			margin: -50px auto 0;
+			width: 480px;
+			height: 260px;
+			box-shadow: 0px 2px 18px rgba(0, 0, 0, 0.1);
+			border-radius: 12px;
+			display: flex;
+			justify-content: space-between;
+			flex-direction: column;
+			padding: 26px;
+			box-sizing: border-box;
+
+			.content-wrapper {
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				margin-top: 14px;
+
+				.img {
+					width: 70px;
+					height: 70px;
+				}
+
+				.img-left {
+					border-radius: 50%;
+				}
+
+				.middle {
+					padding: 0 20px;
+					box-sizing: border-box;
+
+					.invite-txt {
+						color: #727272;
+						font-weight: 400;
+						font-size: 13px;
+					}
+
+					.title {
+						font-weight: 800;
+						font-size: 20px;
+						margin: 6px 3px 0;
+					}
+
+					.up-gain-txt {
+						color: #f8bc2b;
+						font-weight: 600;
+						font-size: 13px;
+						display: flex;
+						align-items: center;
+
+						.amount {
+							font-weight: 700;
+							font-size: 22px;
+						}
+					}
+				}
+			}
+
+			.btn-wrapper {
+				margin-top: 54px;
+				padding: 16px;
+				box-sizing: border-box;
+				background: #1d9bf0;
+				border-radius: 100px;
+				color: #ffffff;
+				font-weight: 700;
+				font-size: 17px;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				cursor: pointer;
+
+				.img {
+					width: 28px;
+					height: 28px;
+					margin-right: 8px;
+				}
+			}
+		}
+	}
+}
+</style>

+ 437 - 0
pages/treasure/invite.vue

@@ -0,0 +1,437 @@
+<template>
+	<div class="nft-content">
+		<template v-if="isLoading">
+			<img class="loading" src="../../static/svg/icon-loading.svg" />
+		</template>
+		<template v-else>
+			<template v-if="isMobile">
+				<MobileLandPage :playType="PlayType.Treasure" :useFul="true" :userInfo="detail.inviteUserInfo" :usValue="detail.upGainAmountValue" :postId="detail.postId" :srcContentId="detail.srcContentId"></MobileLandPage>
+			</template>
+			<template v-else>
+				<div class="logo">
+					<img src="/img/icon-logo.png" alt />
+				</div>
+				<div class="show">
+					<div class="center">
+						<div class="content-wrapper">
+							<img class="img img-left" :src="detail.inviteUserInfo.avatarUrl" alt="" />
+							<div class="middle">
+								<div class="invite-txt">@{{ detail.inviteUserInfo.nickName }} invite you to</div>
+								<div class="title">Hunt the Treaure</div>
+								<div class="up-gain-txt">
+									Each can gain up to <span class="amount"> ${{ detail.upGainAmountValue }}</span>
+								</div>
+							</div>
+							<img class="img" src="../../static/svg/icon-treasure.svg" alt="" />
+						</div>
+						<div class="btn-wrapper" @click="clickBtn()">
+							<template v-if="isChrome"> Install Denet Chrome Extension </template>
+							<template v-else>
+								<img class="img" src="../../static/svg/icon-chrome-down.svg" />
+								Open in Chrome to participate
+							</template>
+						</div>
+					</div>
+				</div>
+			</template>
+		</template>
+	</div>
+</template>
+
+<script>
+import axios from 'axios';
+import Cookies from 'js-cookie';
+import { Toast } from 'vant';
+import { isBrowser, appVersionCode, appType } from '../../utils/help.js';
+import Report from '@/log-center/log';
+import MobileLandPage from '@/components/MobileLandPage.vue';
+import { PlayType } from '@/types';
+
+const api = {
+	prod: 'https://api.denetme.net',
+	pre: 'https://preapi.denetme.net',
+	test: 'https://testapi.denetme.net',
+};
+const page = {
+	prod: 'https://h5.denetme.net',
+	pre: 'https://preh5.denetme.net',
+	test: 'https://testh5.denetme.net',
+};
+const jumpUrl = page[process.env.NUXT_ENV.MODE] + '/';
+const baseURL = api[process.env.NUXT_ENV.MODE];
+const ClipboardJS = require('clipboard');
+
+export default {
+	name: 'ntf',
+	data() {
+		return {
+			PlayType,
+			isLoading: true,
+			appVersionCode: appVersionCode,
+			jumpUrl: jumpUrl,
+			detail: {
+				inviteUserInfo: {
+					avatarUrl: '',
+					nickName: '',
+				},
+				amountValue: '',
+				currencySymbol: '',
+				amountUsdValue: '',
+				totalCount: '',
+			},
+			config: {},
+			title: 'Treasure Hunt',
+			isMobile: false,
+			isChrome: false,
+			linkHref: '',
+		};
+	},
+	components: {
+		MobileLandPage,
+	},
+	head() {
+		return {
+			type: '',
+			title: this.title,
+			appVersionCode: appVersionCode,
+			meta: [
+				// facebook
+				{
+					name: 'og:title',
+					content: `Treasure Chest: ${this.detail.amountValue} ${this.detail.currencySymbol} (worth $${this.detail.amountUsdValue}) for ${this.detail.totalCount} winners`,
+				},
+				{
+					name: 'og:image',
+					content: this.detail.imagePath || '',
+				},
+				// twitter
+				{
+					name: 'twitter:card',
+					content: 'summary_large_image',
+				},
+				{
+					name: 'twitter:title',
+					content: `Treasure Chest: ${this.detail.amountValue} ${this.detail.currencySymbol} (worth $${this.detail.amountUsdValue}) for ${this.detail.totalCount} winners`,
+				},
+				{
+					name: 'twitter:image',
+					content: this.detail.imagePath || '',
+				},
+			],
+		};
+	},
+	async asyncData(params) {
+		let { route } = params;
+		let { data } = await axios.post(`${baseURL}/denet/post/treasure/invite/detail`, {
+			baseInfo: {
+				appVersionCode: appVersionCode,
+				mid: (function () {
+					return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+						var r = (Math.random() * 16) | 0,
+							v = c == 'x' ? r : (r & 0x3) | 0x8;
+						return v.toString(16);
+					});
+				})(),
+			},
+			params: {
+				inviteCode: route.params.id || '',
+			},
+		});
+		if (data.code == 0) {
+			return {
+				detail: data.data,
+			};
+		}
+	},
+	created() {
+		this.setCookieMid();
+		this.getConfig();
+	},
+	mounted() {
+		Cookies.set(this.detail.postId, JSON.stringify({ inviteCode: this.$route.params.id }), { expires: 100 });
+		this.setTreasureInfo();
+
+		setTimeout(() => {
+			this.checkInstall()
+				.then(() => {
+					console.log(this.detail);
+					if (this.detail.repostSrcContentId && this.detail.inviteUserInfo && this.detail.inviteUserInfo.nickName) {
+						let url = `https://twitter.com/${this.detail.inviteUserInfo.nickName}/status/${this.detail.repostSrcContentId}`;
+						window.location.replace(url);
+					}
+					this.isLoading = false;
+				})
+				.catch(() => {
+					this.isLoading = false;
+				});
+		}, 1000);
+		this.checkBrowser();
+
+		var clipboard = new ClipboardJS('.btn');
+		let that = this;
+		clipboard.on('success', function (e) {
+			Toast('copy success');
+			// 埋点
+			that.trackingClick();
+			e.clearSelection();
+		});
+		this.pageSource = Report.pageSource.newUserLandingPage;
+		// 埋点
+		if (this.isMobile) {
+			this.pageSource = Report.pageSource.mobileLandingPage;
+			Report.reportLog({
+				baseInfo: {
+					appVersionCode: this.appVersionCode,
+					mid: this.mid,
+					pageSource: this.pageSource,
+					machineCode: this.mid,
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.pageView,
+						shareLinkId: this.$route.params.id,
+						postId: this.detail.postId,
+					},
+				},
+			});
+		} else {
+			Report.reportLog({
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+					pageSource: this.pageSource,
+					appType,
+					machineCode: this.mid,
+				},
+				params: {
+					eventData: {
+						businessType: Report.businessType.pageView,
+						postId: this.detail.postId,
+						srcContentId: this.detail.srcContentId,
+						redPacketType: 4,
+						shareLinkId: this.$route.params.id,
+					},
+				},
+			});
+		}
+	},
+	methods: {
+		clickBtn() {
+			if (this.isChrome) {
+				Report.reportLog({
+					baseInfo: {
+						appVersionCode: appVersionCode,
+						mid: this.mid,
+						pageSource: this.pageSource,
+						appType,
+						machineCode: this.mid,
+					},
+					params: {
+						eventData: {
+							businessType: Report.businessType.buttonClick,
+							postId: this.detail.postId,
+							srcContentId: this.detail.srcContentId,
+							redPacketType: 4,
+							shareLinkId: this.$route.params.id,
+						},
+					},
+				});
+				let { extensionsInstallUrl } = this.config;
+				window.open(extensionsInstallUrl);
+			} else {
+				this.installChrome();
+			}
+		},
+		checkInstall() {
+			return new Promise((resolve, reject) => {
+				let dom = document.querySelector('#denet_message');
+				console.log('denet_message', dom);
+				if (dom) {
+					resolve(true);
+				} else {
+					reject(false);
+				}
+			});
+		},
+		trackingClick() {},
+		guid() {
+			return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+				var r = (Math.random() * 16) | 0,
+					v = c == 'x' ? r : (r & 0x3) | 0x8;
+				return v.toString(16);
+			});
+		},
+		setCookieMid() {
+			let _cookie_mid_arr = Cookies.get('mid') || [];
+			if (_cookie_mid_arr.length > 0) {
+				this.mid = JSON.parse(_cookie_mid_arr)[0].mid;
+			} else {
+				this.mid = this.guid();
+				Cookies.set('mid', JSON.stringify([{ mid: this.mid }]), { expires: 1000 });
+			}
+		},
+		installExtension() {
+			// 埋点
+			this.trackingClick();
+			let { extensionsInstallUrl } = this.config;
+			window.open(extensionsInstallUrl);
+		},
+		installChrome() {
+			window.open('https://www.google.com/chrome');
+		},
+		async getConfig() {
+			let { data } = await axios.post(`${baseURL}/denet/base/config/getFrontConfig`, {
+				baseInfo: {
+					appVersionCode: appVersionCode,
+					mid: this.mid,
+				},
+				params: {},
+			});
+			if (data.code == 0) {
+				this.config = data.data;
+			}
+		},
+		checkBrowser() {
+			this.linkHref = window.location.href;
+			this.isChrome = isBrowser() == 'chrome';
+			this.isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+		},
+		setTreasureInfo() {
+			let treasureInfo = {
+				createTime: Date.now(),
+				jump_type: 'treasure_info',
+				srcContentId: this.detail.repostSrcContentId || '',
+				postNickName: this.detail.inviteUserInfo.nickName,
+			};
+			Cookies.set('jump_info', JSON.stringify(treasureInfo), { expires: 100 });
+		},
+	},
+};
+</script>
+
+<style lang="scss">
+html,
+body,
+#__nuxt,
+#__layout {
+	width: 100%;
+	height: 100%;
+	padding: 0;
+	margin: 0;
+}
+
+.nft-content {
+	overflow: hidden;
+	width: 100%;
+	height: 100%;
+	background: linear-gradient(180deg, #d8efff 0%, #ffffff 44.3%);
+
+	.loading {
+		position: absolute;
+		transform: translate(-50%, -50%);
+		top: 50%;
+		left: 50%;
+		margin: auto;
+		width: 40px;
+		border-radius: 50%;
+	}
+
+	.logo {
+		display: flex;
+		align-items: center;
+		height: 70px;
+		margin-left: 25px;
+
+		img {
+			width: 99px;
+			height: 32px;
+		}
+	}
+
+	.show {
+		display: flex;
+		align-items: center;
+		height: calc(100% - 70px);
+
+		.center {
+			margin: -50px auto 0;
+			width: 480px;
+			height: 260px;
+			box-shadow: 0px 2px 18px rgba(0, 0, 0, 0.1);
+			border-radius: 12px;
+			display: flex;
+			justify-content: space-between;
+			flex-direction: column;
+			padding: 26px;
+			box-sizing: border-box;
+
+			.content-wrapper {
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				margin-top: 14px;
+
+				.img {
+					width: 70px;
+					height: 70px;
+				}
+
+				.img-left {
+					border-radius: 50%;
+				}
+
+				.middle {
+					padding: 0 20px;
+					box-sizing: border-box;
+
+					.invite-txt {
+						color: #727272;
+						font-weight: 400;
+						font-size: 13px;
+					}
+
+					.title {
+						font-weight: 800;
+						font-size: 20px;
+						margin: 6px 3px 0;
+					}
+
+					.up-gain-txt {
+						color: #f8bc2b;
+						font-weight: 600;
+						font-size: 13px;
+						display: flex;
+						align-items: center;
+
+						.amount {
+							font-weight: 700;
+							font-size: 22px;
+						}
+					}
+				}
+			}
+
+			.btn-wrapper {
+				margin-top: 54px;
+				padding: 16px;
+				box-sizing: border-box;
+				background: #1d9bf0;
+				border-radius: 100px;
+				color: #ffffff;
+				font-weight: 700;
+				font-size: 17px;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				cursor: pointer;
+
+				.img {
+					width: 28px;
+					height: 28px;
+					margin-right: 8px;
+				}
+			}
+		}
+	}
+}
+</style>

+ 3 - 0
static/img/icon-h5-Retweet.svg

@@ -0,0 +1,3 @@
+<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M6.01009 3.72763C5.71249 3.42412 5.23017 3.42412 4.93256 3.72763L2.50768 6.20064C2.16411 6.55103 2.16411 7.11931 2.50768 7.4697C2.85101 7.81985 3.40748 7.81985 3.75082 7.4697L4.59208 6.61174V13.0454C4.59208 14.8605 6.03473 16.3311 7.81341 16.3311H11.5607C12.0459 16.3311 12.44 15.9299 12.44 15.434C12.44 14.9381 12.0459 14.5369 11.5607 14.5369H7.81341C7.0051 14.5369 6.35058 13.8687 6.35058 13.0454V6.61174L7.19184 7.4697C7.53517 7.81985 8.09165 7.81985 8.43498 7.4697C8.77855 7.11931 8.77855 6.55103 8.43498 6.20064L6.01009 3.72763ZM15.8232 16.2724C16.1208 16.5759 16.6032 16.5759 16.9008 16.2724L19.3257 13.7994C19.6692 13.449 19.6692 12.8807 19.3257 12.5303C18.9823 12.1801 18.4258 12.1801 18.0825 12.5303L17.2413 13.3883V6.95456C17.2413 5.1395 15.7986 3.66886 14.0199 3.66886H10.2726C9.78741 3.66886 9.39335 4.07011 9.39335 4.566C9.39335 5.0619 9.78741 5.46314 10.2726 5.46314H14.0199C14.8282 5.46314 15.4828 6.13129 15.4828 6.95456V13.3883L14.6415 12.5303C14.2982 12.1801 13.7417 12.1801 13.3984 12.5303C13.0548 12.8807 13.0548 13.449 13.3984 13.7994L15.8232 16.2724Z" fill="white"/>
+</svg>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 0
static/img/icon-h5-denet.svg


+ 50 - 0
static/img/icon-h5-giveaway.svg

@@ -0,0 +1,50 @@
+<svg width="250" height="255" viewBox="0 0 250 255" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.1" filter="url(#filter0_f_24035_282608)">
+<path d="M215 225.938C215 229.769 174.482 237 124.5 237C74.5182 237 34 229.769 34 225.938C34 222.106 74.5182 219 124.5 219C174.482 219 215 222.106 215 225.938Z" fill="black"/>
+</g>
+<path d="M130.735 121.898V173.72L87.1777 193.659V137.537L130.735 121.898Z" fill="#A56C18"/>
+<path d="M175.289 137.95V192.945L129.32 173.406V122.625L175.289 137.95Z" fill="#A56C18"/>
+<path d="M132.691 155.738V211.632L85.8008 193.707V138.047L132.691 155.738Z" fill="#F9CE46"/>
+<path opacity="0.5" d="M132.691 155.725V211.619L132.475 155.88L85.8008 137.496L132.691 155.725Z" fill="url(#paint0_linear_24035_282608)"/>
+<path d="M176.28 137.656V193.701L132.703 211.626V155.732L176.28 137.656Z" fill="#FEB13E"/>
+<path opacity="0.5" d="M176.28 137.496L132.969 155.88L132.703 211.619V155.725L176.28 137.496Z" fill="url(#paint1_linear_24035_282608)"/>
+<path d="M129.375 122.111L175.451 137.914L132.665 155.528L86.2113 138.053L129.375 122.111ZM149.872 137.954C149.872 136.911 149.308 135.943 148.341 135.086C147.373 134.229 145.984 133.466 144.284 132.83C140.883 131.557 136.195 130.775 131.022 130.775C125.847 130.775 121.159 131.557 117.757 132.83C116.057 133.466 114.668 134.229 113.7 135.086C112.733 135.943 112.169 136.911 112.169 137.954C112.169 138.996 112.733 139.965 113.7 140.821C114.668 141.678 116.057 142.441 117.757 143.077C121.159 144.349 125.847 145.131 131.022 145.131C136.195 145.131 140.883 144.349 144.284 143.077C145.984 142.441 147.373 141.678 148.341 140.821C149.308 139.965 149.872 138.996 149.872 137.954Z" fill="#F9CE46" stroke="#FFD99F" stroke-width="0.4"/>
+<path d="M176.268 139.824L129.329 122.129L85.8008 139.824L129.377 121.898L176.268 139.824Z" fill="#FFBF06"/>
+<path d="M133.189 155.066L133.189 211.288" stroke="#FFD99F" stroke-width="0.4"/>
+<path opacity="0.3" d="M112.394 138.817C112.394 138.942 112.4 139.064 112.413 139.187C112.335 138.895 112.291 138.599 112.291 138.299C112.291 133.992 120.686 130.5 131.039 130.5C141.395 130.5 149.79 133.992 149.79 138.299C149.79 138.599 149.746 138.895 149.668 139.187C149.681 139.064 149.687 138.942 149.687 138.817C149.687 134.488 141.338 130.98 131.039 130.98C120.742 130.98 112.394 134.488 112.394 138.817Z" fill="white"/>
+<path opacity="0.3" d="M149.885 138.047C149.417 141.9 141.161 144.97 131.039 144.97C120.92 144.97 112.663 141.9 112.195 138.047C113.27 141.652 121.297 144.453 131.039 144.453C140.783 144.453 148.81 141.652 149.885 138.047Z" fill="white"/>
+<path opacity="0.3" d="M215.503 100.818L188.953 82.6144C188.953 82.6144 188.96 82.6155 188.955 82.6163C178.215 84.4224 163.57 117.545 163.57 117.545L191.987 137.03C199.299 122.338 204.706 114.383 215.503 100.818Z" fill="#9FA0FF"/>
+<path opacity="0.4" d="M30.3366 125.513L46.4963 109.668C46.4963 109.668 46.4919 109.67 46.4951 109.67C54.1521 109.609 68.3352 130.754 68.3352 130.754L51.0393 147.714C44.183 138.434 39.4682 133.587 30.3366 125.513Z" fill="#4092B8"/>
+<path opacity="0.4" d="M35.2926 70.4848L44.7306 61.2308C44.7306 61.2308 44.728 61.2317 44.7299 61.2317C49.2018 61.1962 57.4853 73.5455 57.4853 73.5455L47.3838 83.451C43.3795 78.0314 40.6258 75.2001 35.2926 70.4848Z" fill="#3E6EFE"/>
+<path opacity="0.3" d="M192.561 54.4547L173.366 41.2941C173.366 41.2941 173.371 41.2949 173.368 41.2955C165.603 42.6012 155.015 66.5472 155.015 66.5472L175.559 80.6346C180.846 70.0128 184.755 64.2614 192.561 54.4547Z" fill="#AB7BDB"/>
+<path d="M48.4227 28.0456L123.689 7.34749C123.689 7.34749 123.69 7.34752 123.683 7.35033C145.696 15.0231 153.798 106.996 153.798 106.996L73.2363 129.153C68.2658 89.8819 62.2638 67.4808 48.4227 28.0456Z" fill="url(#paint2_linear_24035_282608)"/>
+<path d="M117.191 39.6511L116.472 37.271C115.897 35.3669 113.783 34.3606 111.815 34.9607L83.0927 43.722C81.1254 44.3221 79.9237 46.34 80.4986 48.244L81.2172 50.6241C75.777 53.4456 72.9341 59.7866 74.7602 65.8348C76.7046 72.2751 83.2404 76.0306 89.7048 74.6703C93.8017 79.9036 100.685 82.5744 107.675 81.329L110.042 88.2082L98.8006 91.6372C98.1823 91.8258 97.6963 92.2493 97.3931 92.7699C97.1265 93.3099 97.0426 93.9471 97.2286 94.5631C97.6006 95.7952 98.9167 96.4946 100.153 96.1174L127.134 87.8876C128.37 87.5104 129.078 86.1938 128.706 84.9617C128.334 83.7297 127.017 83.0302 125.781 83.4074L114.539 86.8365L112.172 79.9574C116.104 78.2383 119.216 75.3318 121.167 71.8315C122.47 69.5382 123.241 67.0095 123.458 64.3745C129.585 61.8942 132.933 55.0932 130.997 48.6809C129.143 42.6412 123.273 38.9577 117.191 39.6511ZM79.2569 64.4632C78.1832 60.9071 79.6675 57.1823 82.6121 55.2444L86.7715 69.021C86.8983 69.441 87.0617 69.8804 87.2166 70.2919C83.6325 70.3148 80.3306 68.0194 79.2569 64.4632ZM110.214 55.479L108.55 58.7084C108.353 59.0741 108.339 59.537 108.551 59.9313L110.153 63.204C110.642 64.2166 109.755 65.3435 108.675 65.1224L105.428 64.431C104.967 64.327 104.517 64.4642 104.191 64.8082L101.874 67.197C101.107 68.0119 99.7379 67.5428 99.5853 66.4273L99.1075 62.8117C99.0454 62.4025 98.8061 62.0168 98.4321 61.7945L95.2627 60.0397C94.3037 59.5065 94.3449 58.1179 95.334 57.6327L98.4138 56.1428C98.7538 55.9474 99.0347 55.5559 99.1215 55.1319L99.6221 51.7071C99.7759 50.5899 101.181 50.1613 101.955 50.9956L104.265 53.5631C104.552 53.9036 105.001 54.0722 105.44 53.9996L108.824 53.5178C109.915 53.3686 110.717 54.5001 110.214 55.479ZM123.069 59.3251C122.971 58.8965 122.872 58.4679 122.737 58.0199L118.586 44.2713C122.114 44.2655 125.407 46.5329 126.472 50.0611C127.546 53.6173 126.07 57.3701 123.069 59.3251Z" fill="#A96F00"/>
+<defs>
+<filter id="filter0_f_24035_282608" x="16.08" y="201.08" width="216.84" height="53.84" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feGaussianBlur stdDeviation="8.96" result="effect1_foregroundBlur_24035_282608"/>
+</filter>
+<linearGradient id="paint0_linear_24035_282608" x1="-32048.1" y1="112043" x2="51375.9" y2="57572.9" gradientUnits="userSpaceOnUse">
+<stop stop-color="white"/>
+<stop offset="0.2" stop-color="white"/>
+<stop offset="0.3" stop-color="#9A969A"/>
+<stop offset="0.5" stop-color="white"/>
+<stop offset="0.6" stop-color="#B7BFC1"/>
+<stop offset="0.7" stop-color="white"/>
+<stop offset="1" stop-color="white"/>
+</linearGradient>
+<linearGradient id="paint1_linear_24035_282608" x1="94074.9" y1="316121" x2="266159" y2="211703" gradientUnits="userSpaceOnUse">
+<stop stop-color="#DED9D6"/>
+<stop offset="0.3" stop-color="#8B878D"/>
+<stop offset="0.5" stop-color="#F3F4F4"/>
+<stop offset="0.6" stop-color="#807B80"/>
+<stop offset="0.8" stop-color="white"/>
+<stop offset="1" stop-color="#A7A9AC"/>
+</linearGradient>
+<linearGradient id="paint2_linear_24035_282608" x1="90.8602" y1="15.5011" x2="76.4741" y2="86.0408" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FFDD5E"/>
+<stop offset="1" stop-color="#FFCA00"/>
+</linearGradient>
+</defs>
+</svg>

+ 71 - 0
static/img/icon-h5-redpack.svg

@@ -0,0 +1,71 @@
+<svg width="250" height="255" viewBox="0 0 250 255" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g opacity="0.15" filter="url(#filter0_f_24035_282607)">
+<path d="M212 225.938C212 229.769 172.825 237 124.5 237C76.1751 237 37 229.769 37 225.938C37 222.106 76.1751 219 124.5 219C172.825 219 212 222.106 212 225.938Z" fill="black"/>
+</g>
+<g opacity="0.5" filter="url(#filter1_d_24035_282607)">
+<path d="M46.1504 94.3627L133.591 118.112L199.441 93.2832L119.557 76.5508L46.1504 94.3627Z" fill="#FFEAD2"/>
+</g>
+<g filter="url(#filter2_df_24035_282607)">
+<path d="M46.1504 94.3627L133.591 118.112L199.441 93.2832L119.557 76.5508L46.1504 94.3627Z" fill="white"/>
+</g>
+<path d="M48.3891 165.473L47.2843 95.2401L119.575 77.6989L198.258 94.1798L194.608 148.413L48.3891 165.473Z" stroke="#9D651A" stroke-width="2.24"/>
+<path d="M199.187 96.2188L131.838 117.705L131.84 197.997L197.559 172.8" fill="#F9CE46"/>
+<path d="M46.1967 95.8906L46.1934 95.8911L47.2887 167.81L131.979 198.001L131.837 117.71L46.1967 95.8906Z" fill="#F99D23"/>
+<path d="M46.1951 97.1282L131.38 119.089L199.185 97.4517L199.225 93.2812L131.916 115.263L46.1446 94.5451H46.1426L46.1951 97.1282Z" fill="#D38217"/>
+<g style="mix-blend-mode:multiply">
+<path d="M77.7949 102.164V179.102L91.8286 184.118V105.722L77.7949 102.164Z" fill="#BC020C"/>
+</g>
+<g style="mix-blend-mode:multiply">
+<path d="M160.947 105.697V186.843L174.951 181.462V101.379L160.947 105.697Z" fill="#E10001"/>
+</g>
+<path d="M45.1055 57.8577L124.184 40.1836L199.349 55.5625L131.979 78.6156" fill="#F9CE46"/>
+<path d="M199.346 55.5508L131.976 78.6039L131.875 98.8997L131.915 98.9098L203.016 76.069" fill="#F9CE46"/>
+<g style="mix-blend-mode:multiply">
+<path d="M160.946 69.4125L160.945 69.4106V89.6024L174.949 85.1879V63.5977L160.946 69.4125Z" fill="#E10001"/>
+</g>
+<path d="M45.1062 57.8516L42.9121 77.5407L131.879 98.9053L131.98 78.6095L45.1062 57.8516Z" fill="#F99D23"/>
+<g style="mix-blend-mode:multiply">
+<path d="M77.793 65.7539V86.2647L91.8266 89.2925V69.1029L77.793 65.7539Z" fill="#BC020C"/>
+</g>
+<path d="M59.252 61.2432L131.98 78.6038L189.522 59.7266L131.718 74.4179L59.252 61.2432Z" fill="#FFF1B6"/>
+<path d="M79.8862 54.0773C79.8862 54.0773 66.5296 54.0773 67.753 58.6576C68.9765 63.2379 88.0863 63.5412 95.9324 62.6413C103.779 61.7414 113.04 61.4482 117.166 62.4897C121.291 63.5311 140.502 68.7382 147.114 69.4258C153.727 70.1133 153.333 64.9365 153.333 64.9365C153.333 64.9365 140.583 63.3895 139.956 63.3996C139.329 63.4097 124.83 55.7557 124.203 55.7557C123.576 55.7557 98.5512 52.8438 98.5512 52.8438L89.1277 52.9853L79.8862 54.0773Z" fill="#B76F18"/>
+<g style="mix-blend-mode:multiply">
+<path d="M145.436 44.4609L77.793 65.756L91.8475 69.1015L159.086 47.3325L145.436 44.4609Z" fill="#E10001"/>
+</g>
+<path d="M130.219 49.3023C130.219 49.3023 142.241 49.3023 154.738 36.4209C171.29 19.3737 173.332 30.3037 177.993 38.7464C181.805 45.6522 189.378 51.375 181.926 58.7965C161.371 79.3219 128.793 61.5063 128.793 61.5063" fill="#E10001"/>
+<path d="M119.895 45.9193C116.593 44.4167 113.618 42.2799 111.139 39.6302C106.599 34.9691 101.756 27.3049 95.8211 24.4637C80.9478 17.3051 82.6768 27.8711 78.6324 31.7841C75.2452 35.0095 68.5214 33.9479 68.1978 42.9062C67.308 69.1948 124.294 59.4074 124.294 59.4074" fill="#E10001"/>
+<path d="M123.545 57.1179C121.978 57.3505 102.959 59.9692 90.1784 52.4668C79.6225 46.289 69.1171 41.9211 68.3184 45.652C71.4629 68.1895 123.08 59.5446 124.232 59.3423L124.121 58.8975L123.545 57.1179Z" fill="#A50404"/>
+<path d="M113.722 58.6888C113.851 56.6894 114.108 54.7002 114.49 52.7334C114.541 52.147 112.913 57.9001 110.234 57.6676C107.554 57.435 108.11 59.3561 108.11 59.3561C108.11 59.3561 113.732 59.4876 113.722 58.6888Z" fill="#A50404"/>
+<path d="M173.809 45.0139C167.146 47.0361 160.664 58.6941 146.772 61.7881C144.621 62.2458 142.429 62.4896 140.23 62.5161H139.907C138.006 62.5767 135.518 60.8882 135.205 59.9782C134.356 56.8539 133.395 53.1836 135.69 50.5042C135.967 50.2559 136.155 49.9242 136.226 49.5592C136.298 49.1943 136.248 48.8161 136.085 48.482C134.177 49.0232 132.204 49.3022 130.22 49.3111L128.805 61.4443V61.5252H128.875L129.007 61.6162C131.889 63.5272 158.875 80.2811 178.268 60.9185C181.048 58.138 183.424 56.3484 184.334 53.1229C185.254 47.8248 180.603 42.9209 173.809 45.0139Z" fill="#A50404"/>
+<path d="M133.748 49.2442C129.41 54.2997 136.68 62.9042 132.908 64.6635C129.825 66.0992 124.092 61.792 118.419 61.7717C112.747 61.7515 113.364 57.4644 114.577 54.9872C115.79 52.51 113.475 46.0592 117.186 43.8651C119.734 42.2777 137.741 44.6336 133.748 49.2442Z" fill="#E10001"/>
+<path d="M134.481 56.821C135.048 59.278 138 63.0696 143.844 62.3012C149.688 61.5327 139.881 63.7774 139.881 63.7774L136.615 63.1909L134.724 61.2698L134.148 57.2254C134.148 57.2254 133.753 53.8585 134.481 56.821Z" fill="#A50404"/>
+<path d="M124.599 59.8026C122.405 58.5893 119.897 61.3597 117.339 61.5013C117.143 61.5657 116.939 61.5998 116.732 61.6024C117.288 61.7132 117.854 61.7674 118.421 61.7642C122.981 61.7642 127.582 64.5649 130.807 64.9087L131.333 64.848C129.139 64.0695 126.267 60.7329 124.599 59.8026Z" fill="#A50404"/>
+<defs>
+<filter id="filter0_f_24035_282607" x="19.08" y="201.08" width="210.84" height="53.84" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
+<feGaussianBlur stdDeviation="8.96" result="effect1_foregroundBlur_24035_282607"/>
+</filter>
+<filter id="filter1_d_24035_282607" x="35.6971" y="66.0974" width="174.198" height="62.4692" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset/>
+<feGaussianBlur stdDeviation="5.22667"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.917647 0 0 0 0 0.823529 0 0 0 1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_24035_282607"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_24035_282607" result="shape"/>
+</filter>
+<filter id="filter2_df_24035_282607" x="31.9637" y="62.3641" width="181.664" height="69.9358" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset/>
+<feGaussianBlur stdDeviation="5.22667"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.917647 0 0 0 0 0.823529 0 0 0 1 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_24035_282607"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_24035_282607" result="shape"/>
+<feGaussianBlur stdDeviation="7.09333" result="effect2_foregroundBlur_24035_282607"/>
+</filter>
+</defs>
+</svg>

BIN
static/img/icon-h5-topc.png


Dosya farkı çok büyük olduğundan ihmal edildi
+ 5 - 0
static/img/icon-h5-treasure.svg


Dosya farkı çok büyük olduğundan ihmal edildi
+ 6 - 0
static/svg/icon-chrome-down.svg


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
static/svg/icon-treasure.svg


+ 8 - 7
test/NuxtLogo.spec.js

@@ -1,9 +1,10 @@
-import { mount } from '@vue/test-utils'
-import NuxtLogo from '@/components/NuxtLogo.vue'
+/* eslint-disable */
+import { mount } from '@vue/test-utils';
+import NuxtLogo from '@/components/NuxtLogo.vue';
 
 describe('NuxtLogo', () => {
-  test('is a Vue instance', () => {
-    const wrapper = mount(NuxtLogo)
-    expect(wrapper.vm).toBeTruthy()
-  })
-})
+	test('is a Vue instance', () => {
+		const wrapper = mount(NuxtLogo);
+		expect(wrapper.vm).toBeTruthy();
+	});
+});

+ 41 - 6
types/global.js

@@ -4,12 +4,16 @@
 
 /**
  * 玩法类型
- * 普通任务:common=1;
- * 抽奖:lottery=2
+ * 普通红包:common=1;
+ * 抽奖:lottery=2;
+ * 夺宝:Treasure=3;
+ * NFT
  */
 export const PlayType = {
-  common: 1,
-  lottery: 2,
+	common: 1,
+	lottery: 2,
+	Treasure: 3,
+	NFT: 4,
 };
 
 /**
@@ -18,6 +22,37 @@ export const PlayType = {
  * 自定义奖品:custom=2
  */
 export const RewardType = {
-  money: 1,
-  custom: 2,
+	money: 1,
+	custom: 2,
+};
+
+/**
+ * 任务类型
+ */
+export const TaskType = {
+	twitterFollow: 1,
+	twitterLikeTweet: 2,
+	twitterRetweet: 3,
+	joinDiscord: 7,
+	repostToFacebook: 8,
+	twitterCommentAndTag: 9,
+};
+
+/**
+ * 帖子类型
+ */
+
+export const PostType = {
+	giveaway: 1,
+	nftGroup: 2,
+	postEditor: 3,
+};
+
+/**
+ * 奖品 是否有效
+ * 过期、NFT不可领等都被定义为无效
+ */
+export const UsefulType = {
+	unUseful: '0',
+	useful: '1',
 };

+ 227 - 113
utils/help.js

@@ -1,138 +1,252 @@
+import Cookie from 'js-cookie';
 //application/vnd.chromium.remoting-viewer 可能为360特有 通过_mine判断是否是360
 export function isBrowser() {
-    var agent = navigator.userAgent.toLowerCase()
-    console.log(agent)
-    System = function () {
-        if (agent.indexOf('qqbrowser') > 0) {//判断是qq浏览器还是其它浏览器
-            return "qq浏览器"
-        }
-        if (agent.indexOf("se 2.x") > 0) {
-            return "搜狗浏览器"
-        }
-
-        var is360 = _mime("type", "application/vnd.chromium.remoting-viewer");
-
-        if (is360) {
-            return "360浏览器"
-        }
-
-        //检测是否是谷歌内核(可排除360及谷歌以外的浏览器)
-        //测试mime
-        function _mime(option, value) {
-            var mimeTypes = navigator.mimeTypes;
-            console.log(mimeTypes)
-            for (var mt in mimeTypes) {
-                if (mimeTypes[mt][option] == value) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-    let s = System()
-    if (s) {
-        return s
-    }
-    if (agent.indexOf('firefox') > 0) {
-        return "firefox浏览器"
-    }
-    if (agent.indexOf('trident') > 0) {
-        return "IE浏览器"
-    }
-    if (agent.indexOf('edg') > 0) {
-        return "IE浏览器"
-    }
-    if (agent.indexOf("safari") > 0 && agent.indexOf("chrome") < 0) {
-        return 'Safari'
-    }
-    if (agent.indexOf("chrome") > 0) {
-        return 'chrome'
-    }
+	var agent = navigator.userAgent.toLowerCase();
+	console.log(agent);
+	const System = function () {
+		if (agent.indexOf('qqbrowser') > 0) {
+			//判断是qq浏览器还是其它浏览器
+			return 'qq浏览器';
+		}
+		if (agent.indexOf('se 2.x') > 0) {
+			return '搜狗浏览器';
+		}
+
+		var is360 = _mime('type', 'application/vnd.chromium.remoting-viewer');
+
+		if (is360) {
+			return '360浏览器';
+		}
+
+		//检测是否是谷歌内核(可排除360及谷歌以外的浏览器)
+		//测试mime
+		function _mime(option, value) {
+			var mimeTypes = navigator.mimeTypes;
+			console.log(mimeTypes);
+			for (var mt in mimeTypes) {
+				if (mimeTypes[mt][option] == value) {
+					return true;
+				}
+			}
+			return false;
+		}
+	};
+	let s = System();
+	if (s) {
+		return s;
+	}
+	if (agent.indexOf('firefox') > 0) {
+		return 'firefox浏览器';
+	}
+	if (agent.indexOf('trident') > 0) {
+		return 'IE浏览器';
+	}
+	if (agent.indexOf('edg') > 0) {
+		return 'IE浏览器';
+	}
+	if (agent.indexOf('safari') > 0 && agent.indexOf('chrome') < 0) {
+		return 'Safari';
+	}
+	if (agent.indexOf('chrome') > 0) {
+		return 'chrome';
+	}
 }
 
+// 获取host
+export const getEnvConfig = () => {
+	let host, logHost;
+
+	console.log('NODE_ENV=', process.env.NUXT_ENV.MODE);
+
+	// @ts-ignore
+	switch (process.env.NUXT_ENV.MODE) {
+		case `prod`:
+			host = `https://api.denetme.net`;
+			logHost = 'https://log.denetme.net';
+			break;
+		case `pre`:
+			host = `https://preapi.denetme.net`;
+			logHost = 'https:/prelog.denetme.net';
+			break;
+		default:
+			host = `https://testapi.denetme.net`;
+			logHost = 'https://testlog.denetme.net';
+			break;
+	}
+
+	return {
+		host,
+		logHost,
+	};
+};
+
 export function getBrowser() {
-    let browser;
-    let UserAgent = navigator.userAgent.toLowerCase();
-    if (UserAgent.indexOf('chrome') > -1 || UserAgent.indexOf('crios') > -1) {
-        browser = `Chrome`
-    } else if (UserAgent.indexOf('firefox') > -1) {
-        browser = `Firefox`
-    } else if (UserAgent.indexOf('opera') > -1) {
-        browser = `Opera`
-    } else if (UserAgent.indexOf('safari') > -1 && UserAgent.indexOf('chrome') == -1) {
-        browser = `Safari`
-    } else if (UserAgent.indexOf('edge') > -1) {
-        browser = `Edge`
-    } else {
-        browser = `Other`
-    }
-    return browser;
+	let browser;
+	let UserAgent = navigator.userAgent.toLowerCase();
+	if (UserAgent.indexOf('chrome') > -1 || UserAgent.indexOf('crios') > -1) {
+		browser = `Chrome`;
+	} else if (UserAgent.indexOf('firefox') > -1) {
+		browser = `Firefox`;
+	} else if (UserAgent.indexOf('opera') > -1) {
+		browser = `Opera`;
+	} else if (UserAgent.indexOf('safari') > -1 && UserAgent.indexOf('chrome') == -1) {
+		browser = `Safari`;
+	} else if (UserAgent.indexOf('edge') > -1) {
+		browser = `Edge`;
+	} else {
+		browser = `Other`;
+	}
+	return browser;
 }
 
 export function formatSecondsAsTime(secs) {
-    var hr = Math.floor(secs / 3600)
-    var min = Math.floor((secs - (hr * 3600)) / 60)
-    var sec = Math.floor(secs - (hr * 3600) - (min * 60))
-    var text
-    if (hr < 10) {
-        hr = "0" + hr
-    }
-    if (min < 10) {
-        min = "0" + min
-    }
-    if (sec < 10) {
-        sec = "0" + sec
-    }
-    text = hr + ':' + min + ':' + sec
-
-    return text
+	var hr = Math.floor(secs / 3600);
+	var min = Math.floor((secs - hr * 3600) / 60);
+	var sec = Math.floor(secs - hr * 3600 - min * 60);
+	var text;
+	if (hr < 10) {
+		hr = '0' + hr;
+	}
+	if (min < 10) {
+		min = '0' + min;
+	}
+	if (sec < 10) {
+		sec = '0' + sec;
+	}
+	text = hr + ':' + min + ':' + sec;
+
+	return text;
 }
 
 // 抽奖红包 left
 export function formatSecondsAsDaysOrTime(secs) {
-    if (secs <= 0) {
-      return '00:00:00'
-    }
-    let text = ''
-    var hr = Math.floor(secs / 3600)
-    if (hr >= 24) {
-      let day = parseInt(hr / 24)
-      text = `${day} days left`
-    } else {
-      text = formatSecondsAsTime(secs)
-    }
-    return text
+	if (secs <= 0) {
+		return '00:00:00';
+	}
+	let text = '';
+	var hr = Math.floor(secs / 3600);
+	if (hr >= 24) {
+		let day = parseInt(hr / 24);
+		text = `${day} days left`;
+	} else {
+		text = formatSecondsAsTime(secs);
+	}
+	return text;
 }
 
-export const appVersionCode = 12;
+export const appVersionCode = 17;
 
 export const appType = 1;
 
-export function getBrowserType(){
-    let device =  '' // ios 安卓 chrome no-chrome
-    if(/android/i.test(navigator.userAgent)){
-        device = '安卓'
-	}else if(/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)){
-		 device = 'ios'
-	}else if(isBrowser() == 'chrome'){
-        device = 'chrome'
-    }else{
-        device = 'no-chrome'
-    }
-    return device
+export function getBrowserType() {
+	let device = ''; // ios 安卓 chrome no-chrome
+	if (/android/i.test(navigator.userAgent)) {
+		device = '安卓';
+	} else if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
+		device = 'ios';
+	} else if (isBrowser() == 'chrome') {
+		device = 'chrome';
+	} else {
+		device = 'no-chrome';
+	}
+	return device;
 }
 
-
 const api = {
 	prod: 'https://api.denetme.net',
 	pre: 'https://preapi.denetme.net',
-	test: 'https://testapi.denetme.net'
-}
+	test: 'https://testapi.denetme.net',
+};
 const page = {
-	prod: "https://h5.denetme.net",
-	pre: "https://preh5.denetme.net",
-	test: 'https://testh5.denetme.net'
+	prod: 'https://h5.denetme.net',
+	pre: 'https://preh5.denetme.net',
+	test: 'https://testh5.denetme.net',
+};
+
+export const jumpUrl = page[process.env.NUXT_ENV.MODE] + '/';
+export const baseURL = api[process.env.NUXT_ENV.MODE];
+
+export const getStorage = (key) => {
+	return JSON.parse(localStorage.getItem(key));
+};
+
+export const setStorage = (key, data) => {
+	localStorage.setItem(key, JSON.stringify(data));
+};
+
+export const removeStorage = (key) => {
+	localStorage.removeItem(key);
+};
+
+// storageKey
+export const storageKey = {
+	verifier: 'verifierKey',
+	userInfo: 'userInfo',
+	backFromTwitterLogin: 'denet-mobile-landpage-back-from-twitter-login',
+};
+
+// 推特授权url
+export const getOauthUrl = (token) => {
+	return `https://api.twitter.com/oauth/authenticate?oauth_token=${token}`;
+};
+
+// 创建窗口
+export const createWindow = (url, w = 400, h = 600) => {
+	var left = Math.round((window.screen.availWidth - w) / 2);
+	var top = Math.round((window.screen.availHeight - 100 - h) / 2);
+	var win = window.open(url, `newWin`, `width=${w}, height=${h}, top=${top}, left=${left}, toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, status=no`);
+	return win;
+};
+
+// 帮助函数
+const guid = () => {
+	return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+		var r = (Math.random() * 16) | 0,
+			v = c == 'x' ? r : (r & 0x3) | 0x8;
+		return v.toString(16);
+	});
+};
+
+// 获取mid
+export const getMid = () => {
+	let _mid;
+	let _cookie_mid_arr = Cookie.get('mid') || [];
+	if (_cookie_mid_arr.length > 0) {
+		_mid = JSON.parse(_cookie_mid_arr)[0].mid;
+	} else {
+		_mid = guid();
+		Cookie.set('mid', JSON.stringify([{ mid: _mid }]), { expires: 1000 });
+	}
+	return _mid;
+};
+
+export const getUserInfo = () => {
+	let userInfo = getStorage(storageKey.userInfo) || null;
+	if (userInfo) {
+		return userInfo;
+	} else {
+		return null;
+	}
+};
+
+export function getQueryString(name) {
+	let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
+	let r = window.location.search.substr(1).match(reg);
+	if (r != null) {
+		return decodeURIComponent(r[2]);
+	}
+	return null;
 }
 
-export const jumpUrl = page[process.env.NUXT_ENV.MODE] + '/'
-export const baseURL = api[process.env.NUXT_ENV.MODE]
+export const denetExtensionId = 'inlfbeejfdgkknpiodhemfcokbdgofja';
+export function detectExtension(extensionId, callback) {
+	var img;
+	img = new Image();
+	img.src = 'chrome-extension://' + extensionId + '/img/icon-denet-logo.svg';
+	img.onload = function () {
+		callback(true);
+	};
+	img.onerror = function () {
+		callback(false);
+	};
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 515 - 15
yarn.lock


Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor