jihuaqiang 2 лет назад
Родитель
Сommit
73a5980aef
7 измененных файлов с 491 добавлено и 143 удалено
  1. 163 0
      components/MobileLandPage.vue
  2. 78 0
      http/index.js
  3. 76 81
      nuxt.config.js
  4. 53 0
      pages/auth/authLogin.vue
  5. 3 56
      pages/index.vue
  6. 27 4
      types/global.js
  7. 91 2
      utils/help.js

+ 163 - 0
components/MobileLandPage.vue

@@ -0,0 +1,163 @@
+<template>
+	<div class="mobile-land-page">
+		<div class="mobile-land-page-invited-info">
+			<img :src="detail.postBizData.postUserInfo.avatarUrl" class="invited-photo" />
+			<div class="invited-name">{{ detail.postBizData.postUserInfo.nickName }}</div>
+			<div class="invited-text">Send You Giveaway!</div>
+		</div>
+		<div class="mobile-land-page-icon">icon</div>
+		<div class="mobile-land-page-prize-info">
+			<template></template>
+		</div>
+		<div class="mobile-land-page-login-twitter" @click="toLogin">Login Twitter</div>
+	</div>
+</template>
+<script>
+import { RewardType, PlayType } from '../types';
+import { getStorage, setStorage, removeStorage, storageKey, getOauthUrl, createWindow } from '../utils/help';
+import { postRequest } from '../http';
+
+export default {
+	name: 'mobileLandPage',
+	props: {
+		detail: {
+			type: Object,
+			default: () => {
+				return {
+					postBizData: {},
+				};
+			},
+		},
+		extensionsInstallUrl: {
+			type: String,
+			default: '',
+		},
+	},
+	data() {
+		return {
+			config: {},
+			timer: {},
+		};
+	},
+	computed: {
+		isMoneyRewardCpd() {
+			return this.rewardType === RewardType.money;
+		},
+		isLottaryCpd() {
+			return this.playType === PlayType.lottery;
+		},
+	},
+	methods: {
+		toLogin() {
+			let userInfo = getStorage(storageKey.userInfo);
+			if (userInfo) {
+				location.href = `/nft/list`;
+			} else {
+				this.twitterAuth();
+			}
+		},
+		async twitterAuth() {
+			postRequest(`/denet/user/twitterRequestToken`, {
+				params: {
+					oauthCallback: `${location.protocol}://${location.host}/authlogin`,
+				},
+			}).then(({ data }) => {
+				if (data.code == 0) {
+					console.log('%c [ data ]-78', 'font-size:13px; background:pink; color:#bf2c9f;', data);
+					let url = getOauthUrl(data.authToken);
+
+					let win = createWindow(url);
+					this.timer.value = setInterval(() => {
+						if (win && win.closed) {
+							clearInterval(this.timer.value);
+							this.twitterLogin(data);
+						}
+					}, 500);
+				}
+			});
+		},
+		async twitterLogin(authData) {
+			let verifier = getStorage(storageKey.verifier);
+			if (verifier) {
+				postRequest(`/denet/user/twitterLogin`, {
+					params: {
+						consumerKey: authData.consumerKey,
+						oauthToken: authData.authToken,
+						oauthVerifier: verifier,
+					},
+				}).then(({ data }) => {
+					if (data.code == 0) {
+						console.log('%c [ data ]-100', 'font-size:13px; background:pink; color:#bf2c9f;', data);
+						setStorage(storageKey.userInfo, data);
+						removeStorage(storageKey.verifier);
+					}
+				});
+			}
+		},
+	},
+};
+</script>
+<style lang="scss" scoped>
+.mobile-land-page {
+	min-height: 100vh;
+	max-height: 100vh;
+	background: linear-gradient(180deg, #cceaff 0%, #ffffff 70.42%);
+	display: flex;
+	flex-direction: column;
+	justify-content: space-between;
+	align-items: center;
+	&-invited-info {
+		width: 300px;
+		height: 70px;
+		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;
+		.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;
+		}
+		.invited-text {
+			font-weight: 700;
+			font-size: 17px;
+			line-height: 20px;
+			letter-spacing: 0.3px;
+			color: #f99d23;
+		}
+	}
+	&-icon {
+		flex: 1;
+	}
+	&-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;
+	}
+}
+</style>

+ 78 - 0
http/index.js

@@ -0,0 +1,78 @@
+// http封装库
+import axios from 'axios';
+import { getEnvConfig, removeStorage, storageKey, getMid, getUserInfo, appVersionCode, appType } 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.href = `/`;
+		} 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);
+	}
+	params = Object.assign(
+		{
+			baseInfo: {
+				mid: getMid(),
+				machineCode: getMid(),
+				loginUid: (userInfo && userInfo.uid) || '',
+				token: (userInfo && userInfo.accessToken) || '',
+				appType,
+				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;
+		});
+};

+ 76 - 81
nuxt.config.js

@@ -1,89 +1,84 @@
-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' }
-    ]
-  },
+	// 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: {
-  },
-  
-  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]
-  }
-}
+	// Build Configuration: https://go.nuxtjs.dev/config-build
+	build: {},
+
+	router: {
+		extendRoutes(routes, resolve) {
+			routes.push(
+				{
+					name: 'Authlogin',
+					path: '/authlogin',
+					component: resolve(__dirname, 'pages/auth/authLogin.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: 'custom',
+					path: '*',
+					component: resolve(__dirname, 'pages/404.vue'),
+				}
+			);
+		},
+	},
+	env: {
+		NUXT_ENV: env[process.env.MODE],
+	},
+};

+ 53 - 0
pages/auth/authLogin.vue

@@ -0,0 +1,53 @@
+<template>
+	<div class="welcome">
+		<span class="text">Success</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);
+		}
+	},
+};
+</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>

+ 3 - 56
pages/index.vue

@@ -202,62 +202,7 @@
 			</div>
 			<div v-if="status == 'error'"></div>
 		</div>
-		<div v-if="show_moblie" class="moblie">
-			<div class="head-area">
-				<div class="gift">
-					<img :src="require('../static/subject/gift.svg')" />
-				</div>
-				<div class="txt">
-					<div>Complete tasks</div>
-					<div>to Draw Prizes</div>
-				</div>
-			</div>
-			<!-- 领取列表 -->
-			<div class="luck-list" @scroll="handleScroll($event)">
-				<div class="luck-item" v-for="(item, i) in luck_list" v-bind:key="i">
-					<img v-if="item.simpleUserInfoVO.avatarUrl" :src="item.simpleUserInfoVO.avatarUrl" alt />
-					<img v-else src="/svg/icon-twitter.svg" alt />
-					<div class="luck-content">
-						<div class="luck-title">{{ item.simpleUserInfoVO.nickName || 'Twitter User' }}</div>
-						<div class="luck-time">{{ formatTime(item.receiveTimestamp) }}</div>
-					</div>
-					<div class="luck-money" v-if="isMoneyPrize">
-						<img :src="item.currencyIconPath" alt />
-						<div class="luck-money-txt">{{ item.amountValue || 0 }}</div>
-					</div>
-					<div class="luck-custom-prize" v-else>winner</div>
-					<div class="luck-king" v-if="isMoneyPrize && item.maxAmount">
-						<img src="/svg/icon-king-hat.svg" alt />
-						<span>Luckiest Draw</span>
-					</div>
-				</div>
-			</div>
-			<div class="area-cp-link">
-				<div class="area-list">
-					<div class="item">
-						<div class="icon"><img :src="require('../static/subject/01.svg')" /></div>
-						<div class="font">Complete the tasks on tweet</div>
-					</div>
-					<div class="item">
-						<div class="icon"><img :src="require('../static/subject/02.svg')" /></div>
-						<div class="font">Open link on PC to draw</div>
-						<div class="pc"><img :src="require('../static/subject/pc.svg')" /></div>
-					</div>
-				</div>
-				<div class="area-content">
-					{{ cp_link }}
-				</div>
-				<div class="area-btn">
-					<div class="btn" :data-clipboard-text="cp_link" @click="copyLinkHandle">Copy Link</div>
-				</div>
-			</div>
-			<div class="layer" v-show="layer_show">
-				<div class="layer-box">
-					<div class="layer-txt">Unable to copy, please enter the link manually</div>
-					<div class="layer-btn" @click="layer_show = false">Done</div>
-				</div>
-			</div>
-		</div>
+		<MobileLandPage v-if="show_moblie" :detail="detail"></MobileLandPage>
 	</div>
 </template>
 
@@ -268,6 +213,7 @@ import { isBrowser } from '../utils/help.js';
 import Report from '../log-center/log';
 import { Toast } from 'vant';
 import FontAmount from '../components/FontAmount.vue';
+import MobileLandPage from '../components/MobileLandPage.vue';
 import { RewardType } from '../types';
 
 var moment = require('moment');
@@ -335,6 +281,7 @@ export default {
 	},
 	components: {
 		FontAmount,
+		MobileLandPage,
 	},
 	head() {
 		return {

+ 27 - 4
types/global.js

@@ -8,8 +8,9 @@
  * 抽奖:lottery=2
  */
 export const PlayType = {
-  common: 1,
-  lottery: 2,
+	common: 1,
+	lottery: 2,
+	Treasure: 3,
 };
 
 /**
@@ -18,6 +19,28 @@ 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,
 };

+ 91 - 2
utils/help.js

@@ -1,3 +1,4 @@
+import Cookie from 'js-cookie';
 //application/vnd.chromium.remoting-viewer 可能为360特有 通过_mine判断是否是360
 export function isBrowser() {
 	var agent = navigator.userAgent.toLowerCase();
@@ -51,6 +52,32 @@ export function isBrowser() {
 	}
 }
 
+// 获取host
+export const getEnvConfig = () => {
+	let host, logHost;
+
+	// @ts-ignore
+	switch (process.env.NODE_ENV) {
+		case `production`:
+			host = `https://api.denetme.net`;
+			logHost = `https://log.weiqumeta.com`;
+			break;
+		case `pre`:
+			host = `https://preapi.denetme.net`;
+			logHost = `https://prelog.weiqumeta.com`;
+			break;
+		default:
+			host = `https://testapi.denetme.net`;
+			logHost = `https://testlog.weiqumeta.com`;
+			break;
+	}
+
+	return {
+		host,
+		logHost,
+	};
+};
+
 export function getBrowser() {
 	let browser;
 	let UserAgent = navigator.userAgent.toLowerCase();
@@ -105,9 +132,9 @@ export function formatSecondsAsDaysOrTime(secs) {
 	return text;
 }
 
-export const appVersionCode = 12;
+export const appVersionCode = 17;
 
-export const appType = 1;
+export const appType = 2;
 
 export function getBrowserType() {
 	let device = ''; // ios 安卓 chrome no-chrome
@@ -136,3 +163,65 @@ const page = {
 
 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',
+};
+
+// 推特授权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;
+	}
+};