Compare commits
6 Commits
d0369bab36
...
6d76c82e96
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d76c82e96 | |||
| 087e05a9a0 | |||
| aea8323d95 | |||
| 61686950bd | |||
| eea89263f2 | |||
| 285db3f445 |
@ -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'];
|
||||
@ -144,7 +139,9 @@ export default function PartnerIntro() {
|
||||
<div className={`${PREFIX}__block`}>
|
||||
<div className={`${PREFIX}__title`}>分享方法</div>
|
||||
<div className={`${PREFIX}__card`}>
|
||||
<div className={`${PREFIX}__body`}>分享小程序任意页面到群、朋友圈、好友即可</div>
|
||||
<div className={`${PREFIX}__body`}>
|
||||
点击底部按钮向好友群友赠送会员,或者分享通告列表、通告详情等页面给朋友即可
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`${PREFIX}__block`}>
|
||||
|
||||
@ -36,7 +36,7 @@ interface CityOption extends ISelectOption<CityValue> {
|
||||
const PREFIX = 'user-batch-publish';
|
||||
const log = logWithPrefix(PREFIX);
|
||||
const SERVICE_ILLUSTRATE = `服务方式:帮您把招聘需求发到众多同城合作主播群
|
||||
群发次数:每日1次,连发3天
|
||||
群发次数:杭州、广州发3次,其他城市1次
|
||||
内容要求:仅限带货主播招聘需求,其他不发
|
||||
主播联系:内容中留招聘方联系方式,主播直接联系`;
|
||||
const cityValues: CityValue[] = [
|
||||
|
||||
@ -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',
|
||||
}
|
||||
|
||||
@ -1,50 +1,82 @@
|
||||
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>(State.PENDING);
|
||||
const [expireAt, setExpireAt] = useState('');
|
||||
const [usedBefore, setUsedBefore] = useState(false);
|
||||
const handleNavigate = useCallback(() => {
|
||||
switchTab(PageUrl.Job);
|
||||
}, []);
|
||||
|
||||
useLoad(() => {
|
||||
const query = getPageQuery<{ d: string }>();
|
||||
const code = getCouponCodeFromQuery(query);
|
||||
claimMembershipCoupon(code!)
|
||||
.then(res => {
|
||||
setUsedBefore(res.usedBefore);
|
||||
setExpireAt(res.usageExpireAt);
|
||||
setState(Date.now() > new Date(res.usageExpireAt).getTime() ? State.FAILED : State.SUCCESS);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
setState(State.FAILED);
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={PREFIX}>
|
||||
<Fragment>
|
||||
<div className={`${PREFIX}__title`}>
|
||||
<Image src="https://publiccdn.neighbourhood.com.cn/img/partner-yes.svg" className={`${PREFIX}__icon`} />
|
||||
<div>宝子,播络会员领取成功</div>
|
||||
</div>
|
||||
<div className={`${PREFIX}__coupon-info`}>
|
||||
<Image src="https://publiccdn.neighbourhood.com.cn/img/parnet-share-bg.png" className={`${PREFIX}__bg`} />
|
||||
<div className={`${PREFIX}__coupon-title`}>播络日会员</div>
|
||||
<div className={`${PREFIX}__coupon-intro`}>
|
||||
会员有效期内可增加<div className="highlight">10次</div>报单机会
|
||||
{state === State.SUCCESS && (
|
||||
<Fragment>
|
||||
<div className={`${PREFIX}__title`}>
|
||||
<Image src="https://publiccdn.neighbourhood.com.cn/img/partner-yes.svg" className={`${PREFIX}__icon`} />
|
||||
<div>{usedBefore ? '宝子,你已经领过了,下周再来' : '宝子,播络会员领取成功'}</div>
|
||||
</div>
|
||||
<div className={`${PREFIX}__coupon-valid`}>有效期至:2025年/8/26 22:23:56</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
<Fragment>
|
||||
<div className={`${PREFIX}__hint`}>
|
||||
<Image
|
||||
src="https://publiccdn.neighbourhood.com.cn/img/link-invalid.svg"
|
||||
mode="aspectFit"
|
||||
className={`${PREFIX}__icon`}
|
||||
/>
|
||||
<div className={`${PREFIX}__hint-title`}>宝子,链接已失效</div>
|
||||
</div>
|
||||
<div className={`${PREFIX}__title`}>
|
||||
请联系分享人<div className="highlight">再次分享</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
<div className={`${PREFIX}__coupon-info`}>
|
||||
<Image src="https://publiccdn.neighbourhood.com.cn/img/parnet-share-bg.png" className={`${PREFIX}__bg`} />
|
||||
<div className={`${PREFIX}__coupon-title`}>播络日会员</div>
|
||||
<div className={`${PREFIX}__coupon-intro`}>
|
||||
会员有效期内可增加<div className="highlight">10次</div>报单机会
|
||||
</div>
|
||||
<div className={`${PREFIX}__coupon-valid`}>
|
||||
有效期至:{formatTime(expireAt, 'YYYY/MM/DD HH:mm:ss', false)}
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
)}
|
||||
{state === State.FAILED && (
|
||||
<Fragment>
|
||||
<div className={`${PREFIX}__hint`}>
|
||||
<Image
|
||||
src="https://publiccdn.neighbourhood.com.cn/img/link-invalid.svg"
|
||||
mode="aspectFit"
|
||||
className={`${PREFIX}__icon`}
|
||||
/>
|
||||
<div className={`${PREFIX}__hint-title`}>宝子,链接已失效</div>
|
||||
</div>
|
||||
<div className={`${PREFIX}__title`}>
|
||||
请联系分享人<div className="highlight">再次分享</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
)}
|
||||
<div className={`${PREFIX}__info-block`}>
|
||||
<div className={`${PREFIX}__info-title`}>播络简介</div>
|
||||
<div className={`${PREFIX}__info-card`}>
|
||||
|
||||
@ -56,7 +56,27 @@
|
||||
&__icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
&__block {
|
||||
margin-top: 24px;
|
||||
.flex-row();
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__status {
|
||||
font-size: 28px;
|
||||
line-height: 32px;
|
||||
font-weight: 400;
|
||||
color: @blColorG1;
|
||||
|
||||
&.open {
|
||||
color: @blHighlightColor;
|
||||
}
|
||||
|
||||
&.error {
|
||||
color: #FF5051;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ import classNames from 'classnames';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { EventName, OpenSource } from '@/constants/app';
|
||||
import { JOB_MANAGE_STATUS_TITLE_MAP, JobManageStatus } from '@/constants/job';
|
||||
import { JobManageInfo } from '@/types/job';
|
||||
import { getJobLocation, requestJobManageList } from '@/utils/job';
|
||||
import { getPageQuery, navigateBack } from '@/utils/route';
|
||||
@ -15,7 +16,14 @@ import Toast from '@/utils/toast';
|
||||
import './index.less';
|
||||
|
||||
const PREFIX = 'page-job-select-my-publish';
|
||||
|
||||
const STATUS_CLASS_MAP = {
|
||||
[JobManageStatus.WaitVerify]: 'pending',
|
||||
[JobManageStatus.Open]: 'open',
|
||||
[JobManageStatus.Pending]: 'pending',
|
||||
[JobManageStatus.Error]: 'error',
|
||||
[JobManageStatus.Close]: 'close',
|
||||
[JobManageStatus.Expire]: 'close',
|
||||
};
|
||||
export default function JobSelectMyPublish() {
|
||||
const [list, setList] = useState<JobManageInfo[]>([]);
|
||||
const [jobId, setJobId] = useState<string | null>('1');
|
||||
@ -57,13 +65,18 @@ export default function JobSelectMyPublish() {
|
||||
</div>
|
||||
<div className={`${PREFIX}__right`}>
|
||||
<div className={`${PREFIX}__right__time`}>{formatTime(item.updated)}</div>
|
||||
{item.id === jobId && (
|
||||
<Image
|
||||
mode="aspectFit"
|
||||
className={`${PREFIX}__right__icon`}
|
||||
src={require('@/statics/svg/success.svg')}
|
||||
/>
|
||||
)}
|
||||
<div className={`${PREFIX}__right__block`}>
|
||||
<div className={classNames(`${PREFIX}__right__status`, { [STATUS_CLASS_MAP[item.status]]: true })}>
|
||||
{JOB_MANAGE_STATUS_TITLE_MAP[item.status]}
|
||||
</div>
|
||||
{item.id === jobId && (
|
||||
<Image
|
||||
mode="aspectFit"
|
||||
className={`${PREFIX}__right__icon`}
|
||||
src={require('@/statics/svg/success.svg')}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@ -6,7 +6,9 @@ import { useState } from 'react';
|
||||
import PartnerIntro from '@/components/partner-intro';
|
||||
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';
|
||||
|
||||
@ -18,12 +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',
|
||||
});
|
||||
});
|
||||
|
||||
@ -82,7 +82,7 @@ export default function BizService() {
|
||||
<div className={`${PREFIX}__delegate-h5`}>服务说明</div>
|
||||
<div className={`${PREFIX}__delegate-card`}>
|
||||
<div className={`${PREFIX}__delegate-body`}>服务方式:帮您把招聘需求发到众多同城合作主播群</div>
|
||||
<div className={`${PREFIX}__delegate-body`}>群发次数:每日1次,连发3天</div>
|
||||
<div className={`${PREFIX}__delegate-body`}>群发次数:杭州、广州发3次,其他城市1次</div>
|
||||
<div className={`${PREFIX}__delegate-body`}>内容要求:仅限带货主播招聘需求,其他不发</div>
|
||||
<div className={`${PREFIX}__delegate-body`}>主播联系:内容中留招聘方联系方式,主播直接联系</div>
|
||||
</div>
|
||||
|
||||
11
src/types/coupon.ts
Normal file
11
src/types/coupon.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export type ClaimMembershipCouponResponse = {
|
||||
code: string;
|
||||
usedBefore: boolean;
|
||||
usageExpireAt: string;
|
||||
};
|
||||
|
||||
export type GenerateMembershipCouponResponse = {
|
||||
code: string;
|
||||
linkExpireAt: string;
|
||||
shareUrl: string;
|
||||
};
|
||||
31
src/utils/coupon.ts
Normal file
31
src/utils/coupon.ts
Normal file
@ -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<GenerateMembershipCouponResponse>(API.GENERATE_MEMBERSHIP_COUPON);
|
||||
};
|
||||
export const claimMembershipCoupon = async (code: string) => {
|
||||
return await http.post<ClaimMembershipCouponResponse>(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, string>): string | undefined => {
|
||||
if (query) {
|
||||
if (query.scene) {
|
||||
return query.scene.replace('d%3D', '');
|
||||
}
|
||||
if (query.d) {
|
||||
return query.d;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user