diff --git a/src/components/partner-intro/index.tsx b/src/components/partner-intro/index.tsx index 58508db..7c8a616 100644 --- a/src/components/partner-intro/index.tsx +++ b/src/components/partner-intro/index.tsx @@ -1,19 +1,19 @@ import { Button, Canvas } from '@tarojs/components'; import Taro from '@tarojs/taro'; -import { useCallback, useState } from 'react'; +import { useCallback } from 'react'; import { openCustomerServiceChat } from '@/utils/common'; -import { getPartnerQrcode } from '@/utils/partner'; +import { getCouponQrCode, generateMembershipCoupon } from '@/utils/coupon'; import './index.less'; const PREFIX = 'partner-intro'; export default function PartnerIntro() { - const [posterPath, setPosterPath] = useState(''); const getQrcode = async () => { try { - const data = await getPartnerQrcode(); // 假设 getPartnerQrcode 返回 ArrayBuffer + const { code } = await generateMembershipCoupon(); + const data = await getCouponQrCode(code); const base64 = Taro.arrayBufferToBase64(data); return `data:image/png;base64,${base64}`; } catch (error) { @@ -39,8 +39,6 @@ export default function PartnerIntro() { fileType: 'jpg', }); - setPosterPath(tempFilePath.tempFilePath); - resolve(tempFilePath.tempFilePath); }); } catch (error) { @@ -57,8 +55,8 @@ export default function PartnerIntro() { const canvas = res[0].node; const ctx = canvas.getContext('2d'); - canvas.width = 550*2; - canvas.height = 918*2; + canvas.width = 550 * 2; + canvas.height = 918 * 2; ctx.scale(2, 2); // 绘制背景图片 @@ -84,13 +82,10 @@ export default function PartnerIntro() { }); }; const savePoster = async () => { - let filePath = posterPath; - if (!filePath) { - Taro.showLoading({ title: '正在生成海报' }); - const qrCode = await getQrcode(); - filePath = await drawCanvas(qrCode); - Taro.hideLoading(); - } + Taro.showLoading({ title: '正在生成海报' }); + const qrCode = await getQrcode(); + const filePath = await drawCanvas(qrCode); + Taro.hideLoading(); const res = await Taro.getSetting(); const hasPermission = res.authSetting['scope.writePhotosAlbum']; diff --git a/src/http/api.ts b/src/http/api.ts index a29d67b..024cd42 100644 --- a/src/http/api.ts +++ b/src/http/api.ts @@ -1,4 +1,4 @@ -// export const DOMAIN = 'http://192.168.60.191:8082'; +// export const DOMAIN = 'http://192.168.60.116:8082'; export const DOMAIN = process.env.BRAND === 'dev' ? 'https://dev.neighbourhood.cn' : 'https://neighbourhood.cn'; // export const DOMAIN = 'https://dev.neighbourhood.cn'; export const BASE_URL = `${DOMAIN}/api`; @@ -85,4 +85,7 @@ export enum API { GET_PROFIT_STAT = '/user/profits', WITHDRAW = '/user/withdraw', GET_WITHDRAW_LIST = '/user/withdraw/records', + GENERATE_MEMBERSHIP_COUPON = '/coupon/membership/generate', + CLAIM_MEMBERSHIP_COUPON = '/coupon/membership/claim', + GET_VIP_QRCODE = '/user/getVipQrCode', } diff --git a/src/pages/give-vip/index.tsx b/src/pages/give-vip/index.tsx index 58f6214..1efb795 100644 --- a/src/pages/give-vip/index.tsx +++ b/src/pages/give-vip/index.tsx @@ -1,50 +1,80 @@ import { Image, Button } from '@tarojs/components'; +import { useLoad } from '@tarojs/taro'; -import { Fragment, useCallback } from 'react'; +import { Fragment, useCallback, useState } from 'react'; import SafeBottomPadding from '@/components/safe-bottom-padding'; import { PageUrl } from '@/constants/app'; import { logWithPrefix } from '@/utils/common'; -import { switchTab } from '@/utils/route'; - +import { claimMembershipCoupon, getCouponCodeFromQuery } from '@/utils/coupon'; +import { getPageQuery, switchTab } from '@/utils/route'; +import { formatTime } from '@/utils/time'; import './index.less'; const PREFIX = 'give-vip'; const log = logWithPrefix(PREFIX); +enum State { + PENDING, + SUCCESS, + FAILED, +} export default function GiveVip() { + const [state, setState] = useState(State.PENDING); + const [expireAt, setExpireAt] = useState(''); const handleNavigate = useCallback(() => { switchTab(PageUrl.Job); }, []); + + useLoad(() => { + const query = getPageQuery<{ d: string }>(); + const code = getCouponCodeFromQuery(query); + claimMembershipCoupon(code!) + .then(res => { + setExpireAt(res.usageExpireAt); + setState(Date.now() > new Date(res.usageExpireAt).getTime() ? State.FAILED : State.SUCCESS); + }) + .catch(err => { + console.error(err); + setState(State.FAILED); + }); + }); + return (
- -
- -
宝子,播络会员领取成功
-
-
- -
播络日会员
-
- 会员有效期内可增加
10次
报单机会 + {state === State.SUCCESS && ( + +
+ +
宝子,播络会员领取成功
-
有效期至:2025年/8/26 22:23:56
-
- - -
- -
宝子,链接已失效
-
-
- 请联系分享人
再次分享
-
-
+
+ +
播络日会员
+
+ 会员有效期内可增加
10次
报单机会 +
+
+ 有效期至:{formatTime(expireAt, 'YYYY/MM/DD HH:mm:ss', false)} +
+
+ + )} + {state === State.FAILED && ( + +
+ +
宝子,链接已失效
+
+
+ 请联系分享人
再次分享
+
+
+ )}
播络简介
diff --git a/src/pages/partner/index.tsx b/src/pages/partner/index.tsx index 04e4f5d..bb527ec 100644 --- a/src/pages/partner/index.tsx +++ b/src/pages/partner/index.tsx @@ -8,10 +8,10 @@ import PartnerInviteList from '@/components/partner-invite-list'; import PartnerProfit from '@/components/partner-profit'; import { PageUrl } from '@/constants/app'; import useInviteCode from '@/hooks/use-invite-code'; +import { generateMembershipCoupon } from '@/utils/coupon'; import { getCommonShareMessage } from '@/utils/share'; import './index.less'; - const PREFIX = 'partner'; export default function Partner() { @@ -20,13 +20,15 @@ export default function Partner() { const handleChange = v => { setTab(v); }; - useShareAppMessage(() => { + useShareAppMessage(async () => { console.log('Partner inviteCode', inviteCode); + const { code } = await generateMembershipCoupon(); return getCommonShareMessage({ useCapture: false, inviteCode, title: '宝子,送你个播络会员,找工作更方便', path: PageUrl.GiveVip, + params: { d: code }, imageUrl: 'https://publiccdn.neighbourhood.com.cn/img/share-coupon.png', }); }); diff --git a/src/types/coupon.ts b/src/types/coupon.ts new file mode 100644 index 0000000..5aa80c8 --- /dev/null +++ b/src/types/coupon.ts @@ -0,0 +1,10 @@ +export type ClaimMembershipCouponResponse = { + code: string; + usageExpireAt: string; +}; + +export type GenerateMembershipCouponResponse = { + code: string; + linkExpireAt: string; + shareUrl: string; +}; diff --git a/src/utils/coupon.ts b/src/utils/coupon.ts new file mode 100644 index 0000000..ef0dc2f --- /dev/null +++ b/src/utils/coupon.ts @@ -0,0 +1,31 @@ +import http from '@/http'; +import { API } from '@/http/api'; +import { ClaimMembershipCouponResponse, GenerateMembershipCouponResponse } from '@/types/coupon'; + +export const generateMembershipCoupon = async () => { + return await http.post(API.GENERATE_MEMBERSHIP_COUPON); +}; +export const claimMembershipCoupon = async (code: string) => { + return await http.post(API.CLAIM_MEMBERSHIP_COUPON, { + contentType: 'application/x-www-form-urlencoded', + data: { code }, + }); +}; +export const getCouponQrCode = async (code: string) => { + return await http.post(API.GET_VIP_QRCODE, { + contentType: 'application/x-www-form-urlencoded', + responseType: 'arraybuffer', + data: { code }, + }); +}; +export const getCouponCodeFromQuery = (query: Record): string | undefined => { + if (query) { + if (query.scene) { + return query.scene.replace('d%3D', ''); + } + if (query.d) { + return query.d; + } + } + return undefined; +}; diff --git a/src/utils/time.ts b/src/utils/time.ts index 7db1026..e5246f6 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -1,10 +1,12 @@ import dayjs from 'dayjs'; -export function formatTime(time: number | string, template = 'YYYY-MM-DD'): string { +export function formatTime(time: number | string, template = 'YYYY-MM-DD', toNum = true): string { if (!time) { return ''; } - time = Number(time); + if (toNum) { + time = Number(time); + } return dayjs(time).format(template); }