Commit 20a89551 by hometown

feat: commit final feature

parent 5e74d300
......@@ -16,7 +16,7 @@ function defineConfigCreator(): BaseRsbuildConfig {
'process.env.REACT_APP_ENV': JSON.stringify(ENV_DEV),
'process.env.REACT_APP_API_URL': JSON.stringify(devEnvConfig.REACT_APP_API_URL)
}},
tools: { bundlerChain(chain, { env }) { chain.devtool('eval'); } }
tools: { bundlerChain(chain) { chain.devtool('eval'); } }
}
return defineConfig(merge({}, buildBaseConfig, devBuildConfig))
......
......@@ -3,7 +3,7 @@ import { type RsbuildConfig as BaseRsbuildConfig } from '@rsbuild/shared';
type HtmlTemplateType = BaseRsbuildConfig['html']
export const HTML_TEMPLATE_CONFIG:HtmlTemplateType = {
title: 'test',
title: '厅堂一元购',
favicon: './static/favicon.ico',
tags: [
{ tag: 'meta', attrs: { charset: 'UTF-8'} },
......
......@@ -148,3 +148,91 @@ export const queryOrderInfo = async (orderId: string): Promise<BackendResponse<Q
throw error
}
}
interface SubmitDrawRequestData {
activityCode: string
branchName: string;
branchCode: string;
}
export interface SubmitDrawResponse {
iconUrl: string;
orderId: string;
prizeCode: string;
prizeName: string;
prizeType: string;
prizeValue: number;
prizeValueType: string;
receiveDeadlineTime: string;
showOrder: number;
}
/**
* 提交抽奖请求
* @param requestData
*/
export const submitDraw = async (requestData: SubmitDrawRequestData): Promise<BackendResponse<SubmitDrawResponse>> => {
try {
const response = await axiosInstance.post<BackendResponse<SubmitDrawResponse>>('/api/activity/submitDraw', requestData)
return response.data
} catch (error) {
throw error;
}
}
interface QueryMyPrizeListRequestData {
activityCode: string;
pageNum: number;
pageSize: number;
}
export interface QueryMyPrizeListResponse {
orderId: string;
// 状态 01:待领取 02:已到账 03:已过期 04:发送失败 05:领取中
orderStatus: string;
prizeCode: string;
prizeName: string;
prizeValue: number;
// 奖品价值类型01:积分 02:立减金券
prizeValueType: string;
receiveDeadlineTime: string;
useDeadlineTime: string;
}
/**
* 查询我的中奖列表
* @param requestData
*/
export const queryMyPrizeList = async (requestData: QueryMyPrizeListRequestData): Promise<BackendResponse<RecordsData<QueryMyPrizeListResponse>>> => {
try {
const response = await axiosInstance.post<BackendResponse<RecordsData<QueryMyPrizeListResponse>>>('/api/activity/queryMyPrizeList', requestData)
return response.data
} catch (error) {
throw error;
}
}
interface ReceivePrizeRequestData {
orderId: string;
}
interface ReceivePrizeResponse {
method: string;
miniProgramType: string;
orderId: string;
path: string;
username: string;
}
/**
* 用户领取奖品接口
* @param requestData
*/
export const receivePrize = async (requestData: ReceivePrizeRequestData): Promise<BackendResponse<ReceivePrizeResponse>> => {
try {
const response = await axiosInstance.post<BackendResponse<ReceivePrizeResponse>>('/api/activity/receivePrize', requestData)
return response.data
} catch (error) {
throw error;
}
}
\ No newline at end of file

117 KB | W: | H:

582 KB | W: | H:

src/assets/images/homeTopBanner.png
src/assets/images/homeTopBanner.png
src/assets/images/homeTopBanner.png
src/assets/images/homeTopBanner.png
  • 2-up
  • Swipe
  • Onion skin
// 状态 01:待领取 02:已到账 03:已过期 04:发送失败 05:领取中
/**
* 抽奖单子领取状态__待领取
*/
export const LOTTERY_ORDER_STATUS__UNCLAIMED = '01'
/**
* 抽奖单子领取状态__已到账
*/
export const LOTTERY_ORDER_STATUS__RECEIVED = '02'
/**
* 抽奖单子领取状态__已过期
*/
export const LOTTERY_ORDER_STATUS__EXPIRED = '03'
/**
* 抽奖单子领取状态__发送失败
*/
export const LOTTERY_ORDER_STATUS__FALL_IN_SEND = '04'
/**
* 抽奖单子领取状态__领取中
*/
export const LOTTERY_ORDER_STATUS__RECEIVING = '05'
/**
* 抽奖单子领取状态__已使用
*/
export const LOTTERY_ORDER_STATUS__USED = '06'
/**
* 抽奖奖品价值类型__积分
*/
export const LOTTERY_PRIZE_VALUE_TYPE__POINT = '01'
/**
* 抽奖奖品价值类型__券
*/
export const LOTTERY_PRIZE_VALUE_TYPE__TICKET = '02'
\ No newline at end of file
export * from './backend'
\ No newline at end of file
export * from './backend'
export * from './common'
\ No newline at end of file
import React, {useEffect, useState} from "react";
import homeProductBanner1Img from "@/assets/images/homeProductBanner1.png";
import homeProductBanner2Img from "@/assets/images/homeProductBanner2.png";
import homeRulesOverlayCloseImg from "@/assets/images/homeRulesOverlayClose.png";
import homeLogoImg from "@/assets/images/homeLogo.png";
import styles from "@/pages/Home/index.module.scss";
import HomeProductItem from "@/pages/Home/components/HomeProductItem";
import {Overlay, Popup, Toast} from "@nutui/nutui-react";
import homeRulesOverlayCloseImg from "@/assets/images/homeRulesOverlayClose.png";
import HomeRuleContent from "@/pages/Home/components/HomeRuleContent";
import apis from "@/apis";
import {type QueryBranchListResponseData} from "@/apis/common";
......@@ -13,8 +14,8 @@ import {useNavigate} from "react-router-dom";
const HomeContent: React.FC = () => {
const [productList] = useState([
{bannerImg: homeProductBanner1Img, title: "厅堂实物 1元购", buttonTextColor: "#F41E71", productCode: "4"},
{bannerImg: homeProductBanner2Img, title: "微信立减金等你来拿", buttonTextColor: "#1FA189", productCode: "5"}
{bannerImg: homeProductBanner1Img, title: "厅堂实物 1元购", buttonTextColor: "#F41E71", productCode: "4", buttonText: "立即购买"},
{bannerImg: homeProductBanner2Img, title: "微信立减金抽奖100%中奖", buttonTextColor: "#1FA189", productCode: "5", buttonText: "立即抽奖"}
]);
const [branchList, setBranchList] = useState<QueryBranchListResponseData[]>([]);
......@@ -59,7 +60,6 @@ const HomeContent: React.FC = () => {
setBranchList(res.data);
}
}).catch(() => {
Toast.show(`查询网点列表失败`);
});
return () => {
......@@ -75,12 +75,16 @@ const HomeContent: React.FC = () => {
bannerImg={item.bannerImg}
title={item.title}
buttonTextColor={item.buttonTextColor}
buttonText={item.buttonText}
key={index}
idx={index}
onButtonClick={handleClickProduct}
/>
);
})}
<img className={styles.homeLogo} src={homeLogoImg} alt=""/>
<div className={styles.productTips}>活动最终解释权归本行所有</div>
{/* 网点列表 */}
......
......@@ -4,21 +4,19 @@ import styles from "@/pages/Home/index.module.scss";
const HomeRuleContent: React.FC = () => {
return (
<div className={styles.rulesOverlayContentInner}>
<h2>活动规则</h2>
<h3>闸北支行一元购,新年钜惠等你来拿</h3>
<h4>活动时间:</h4>
<p>2023年1月9日~2023年4月30</p>
<p>2024年1月1日~2024年3月31</p>
<h4>活动对象:</h4>
<p>掌银新客户,信用卡新客户,财富贵宾客户</p>
<p>闸北掌银注册客户。欢迎掌银新客,数币新客,信用卡新客,或财富贵宾等客户积极参与</p>
<h4>活动规则:</h4>
<p>
1.打开掌银,扫描网点厅堂二维码进入活动页面,在网点工作人员的指导下购买新客礼,每人在活动期限内限参与1次活动
使用农行掌银扫活动二维码进入页面,活动礼品分为实物礼品和线上礼券两类,活动期间内每人限参与其中1类,每类限参与1次,客户支付1元即表示参与活动,参与成功后1元将原路退回。实物礼品以网点现场礼品为准,线上礼券为微信立减金抽奖,立减金面额有2.22元、5.55元、8.88元、10元、58.88元,线上礼券每月限量,每月1号刷新库存,当月礼券抽完活动即止
<br/>
2.同一证件号、同一手机号、同一设备均视为同一客户
重要提示:微信立减金兑换有效期为当月月底前,使用有效期为自兑换之日起7天内(含兑换当日),过期不予补发
<br/>
3.成功支付后请出示订单详情页,于网点大堂当场核销礼品
凡参与本活动的客户,即视为同意接受本活动相关规则,活动期间用户不得使用不正当手段以及其他破坏活动规则、违背活动公平原则的方式参加本次活动,否则活动方有权取消用户参与资格,收回已经领取的权益
<br/>
4.凡参加本次活动者,即视为同意接受本次活动相关规则,活动期间用户不得使用不正当手段破坏活动规则、违背活动公平原则,否则有权取消活动参与资格
本次活动页面服务由“艾普金服(北京)科技有限公司上海分公司”提供,如有活动相关问题请咨询客服热线010-57256207(周一至周日8:00-16:00)
</p>
</div>
);
......
import apis from "@/apis";
import {type CreateOrderRequestData} from "@/apis/common";
import {type NavigateFunction} from "react-router-dom";
import {Toast} from "@nutui/nutui-react";
class OrderHelper {
/**
......@@ -16,26 +15,22 @@ class OrderHelper {
try {
const createOrderRes = await apis.common.createOrder(params);
if (!createOrderRes.data) {
Toast.show("创建订单失败");
return;
}
const queryPayUrlRes = await apis.common.queryPayUrl({orderId: createOrderRes.data});
if (!queryPayUrlRes.data) {
Toast.show("支付链接获取失败");
return;
}
const tokenId = new URLSearchParams(new URL(queryPayUrlRes.data).search).get("TOKEN");
if (!tokenId) {
Toast.show("TOKEN 未找到");
return;
}
const queryPayConfigRes = await apis.common.queryPayConfig<Record<"param", Record<string, string>>>();
if (!queryPayConfigRes.data) {
Toast.show("支付配置信息查询失败");
return;
}
......@@ -46,7 +41,6 @@ class OrderHelper {
console.log(result, "支付结果");
});
} catch (error) {
Toast.show("提交订单失败");
}
}
......@@ -58,7 +52,6 @@ class OrderHelper {
try {
const res = await apis.common.queryUserOrder();
if (!res.ok) {
Toast.show("查询用户订单信息失败");
return;
}
......@@ -73,7 +66,6 @@ class OrderHelper {
});
}
} catch (error) {
Toast.show("查询用户订单信息失败");
}
}
......
......@@ -12,10 +12,16 @@
.topBannerImg {
width: 100%;
height: 497px;
position: absolute;
top: 0;
left: 0;
}
.botBannerImg {
width: 100%;
height: 154px;
position: absolute;
left: 0;
bottom: 0;
}
}
.contentWrap {
......@@ -60,7 +66,7 @@
top: 0;
}
.productItemTitle {
font-size: 20px;
font-size: 18px;
color: #FFFFFF;
line-height: 26px;
position: relative;
......@@ -83,6 +89,12 @@
margin-top: 12px;
}
}
.homeLogo {
width: 109px;
height: 34px;
margin: 0 auto;
margin-bottom: 5px;
}
.productTips {
width: 100%;
text-align: center;
......@@ -102,7 +114,7 @@
justify-content: center;
.rulesOverlayContent {
width: 280px;
height: 400px;
height: 372px;
border-radius: 10px;
background-color: #fff;
position: relative;
......
......@@ -5,7 +5,6 @@ import HomeBg from "@/pages/Home/components/HomeBg";
import HomeContent from "@/pages/Home/components/HomeContent";
import AuthUtil from "@/utils/auth";
import OrderHelper from "@/pages/Home/helper/order";
import {Toast} from "@nutui/nutui-react";
const Home: React.FC = () => {
const [params] = useSearchParams();
......@@ -19,7 +18,6 @@ const Home: React.FC = () => {
await OrderHelper.queryUserOrder(navigate);
setIsAuthed(authResult);
} catch (error) {
Toast.show(`${error}`);
}
};
......
import React from "react";
import {type QueryMyPrizeListResponse} from "@/apis/common";
import styles from "@/pages/Lottery/index.module.scss";
import myPrizeHighLightImg from "@/assets/images/myPrizeHighLight.png";
import myPrizeDisabledImg from "@/assets/images/myPrizeDisabled.png";
import myPrizeUnclaimedImg from "@/assets/images/myPrizeUnclaimed.png";
import myPrizeReceivedImg from "@/assets/images/myPrizeReceived.png";
import myPrizeUsedImg from '@/assets/images/myPrizeUsed.png'
import {
LOTTERY_ORDER_STATUS__EXPIRED, LOTTERY_ORDER_STATUS__FALL_IN_SEND,
LOTTERY_ORDER_STATUS__RECEIVED,
LOTTERY_ORDER_STATUS__UNCLAIMED, LOTTERY_ORDER_STATUS__USED,
LOTTERY_PRIZE_VALUE_TYPE__POINT,
LOTTERY_PRIZE_VALUE_TYPE__TICKET
} from "@/constants";
interface Props {
item: QueryMyPrizeListResponse,
onReceivePrize: (orderId: string) => Promise<void>
}
const MyPrizeItem: React.FC<Props> = ({item, onReceivePrize}) => {
let statusSrc = "";
if ([LOTTERY_ORDER_STATUS__UNCLAIMED, LOTTERY_ORDER_STATUS__FALL_IN_SEND].includes(item.orderStatus)) {
statusSrc = myPrizeUnclaimedImg;
} else if (item.orderStatus === LOTTERY_ORDER_STATUS__RECEIVED) {
statusSrc = myPrizeReceivedImg;
}
let prizeItemBgSrc = "";
if ([LOTTERY_ORDER_STATUS__EXPIRED].includes(item.orderStatus) ) {
prizeItemBgSrc = myPrizeDisabledImg;
} else if(item.orderStatus === LOTTERY_ORDER_STATUS__USED) {
prizeItemBgSrc = myPrizeUsedImg;
} else {
prizeItemBgSrc = myPrizeHighLightImg;
}
return (
<div className={styles.myPrizeItem}>
<img className={styles.myPrizeItemBg} src={prizeItemBgSrc} alt=""/>
{statusSrc && <img className={styles.myPrizeItemStatus} src={statusSrc} alt=""/>}
<div className={styles.myPrizeItemPrice}>
<div>¥<span>{item.prizeValue}</span></div>
<span>
{item.prizeValueType === LOTTERY_PRIZE_VALUE_TYPE__TICKET && "立减金券"}
{item.prizeValueType === LOTTERY_PRIZE_VALUE_TYPE__POINT && "积分"}
</span>
</div>
<div className={styles.myPrizeItemInfo}>
<h3>{item.prizeName}</h3>
<p>请于{item.receiveDeadlineTime}</p>
<p>前完成领取</p>
</div>
{[LOTTERY_ORDER_STATUS__UNCLAIMED, LOTTERY_ORDER_STATUS__FALL_IN_SEND].includes(item.orderStatus) &&
<div className={styles.myPrizeItemButton} onClick={() => onReceivePrize(item.orderId)}>去领取</div>}
</div>
);
};
export default MyPrizeItem;
\ No newline at end of file
......@@ -197,6 +197,28 @@
}
}
}
.myPrizePopupEmpty {
flex: 1;
width: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
//justify-content: center;
padding-top: 79px;
> img {
width: 140px;
height: 121px;
}
> p {
font-size: 13px;
font-weight: 400;
color: #666666;
line-height: 18px;
margin-top: 12px;
}
}
}
.winningLotteryWrap {
......
......@@ -10,15 +10,30 @@ const OrderDetail: React.FC = () => {
const [orderInfo, setOrderInfo] = useState<QueryOrderInfoResponse>();
const [checked, setChecked] = useState(false);
history.pushState(null, '', document.URL);
useEffect(() => {
console.log(params.get("orderId"));
const handleBackButtonEvent = (e: PopStateEvent) => {
e.preventDefault();
history.pushState(null, '', document.URL);
window.AlipayJSBridge.call("abcExitWebAndBackToHome");
};
window.addEventListener("popstate", handleBackButtonEvent);
apis.common.queryOrderInfo(params.get("orderId") || "").then(res => {
console.log(res.data);
if (res.ok) {
setOrderInfo(res.data);
setChecked(true);
}
});
return () => {
window.removeEventListener("popstate", handleBackButtonEvent);
};
}, []);
return (
......
......@@ -4,3 +4,12 @@ interface BackendResponse<T> {
ok: boolean
data: T
}
interface RecordsData<T> {
current: number;
hitCount: boolean;
records: T[],
searchCount: boolean;
size: number;
total: number;
}
\ No newline at end of file
......@@ -5,7 +5,7 @@ class AuthUtil {
static async auth(params: URLSearchParams): Promise<boolean> {
return await new Promise((resolve) => {
if (process.env.REACT_APP_ENV === "development") {
LocalStorageUtil.setItem("__TOKEN__", "6d29e9d470e24cf9af48bd5881b97f80");
LocalStorageUtil.setItem("__TOKEN__", "6cbcd670a7244055b7b3366bafa68022");
resolve(true);
} else {
const token = LocalStorageUtil.getItem("__TOKEN__");
......
import axios, {type AxiosInstance, type InternalAxiosRequestConfig, type AxiosResponse, type AxiosError} from "axios";
import LocalStorageUtil from "@/utils/local";
import {Toast} from "@nutui/nutui-react";
import {LOGIN_EXPIRED_CODE} from "@/constants";
const axiosInstance: AxiosInstance = axios.create({
......@@ -15,9 +14,9 @@ const requestInterceptor = (config: InternalAxiosRequestConfig): InternalAxiosRe
const responseInterceptor = (response: AxiosResponse): AxiosResponse => {
if (response.data.code === LOGIN_EXPIRED_CODE) {
Toast.show({
content: `登录失效: ${response.data.code} ${LocalStorageUtil.getItem("__TOKEN__")}`,
});
// Toast.show({
// content: `登录失效: ${response.data.code} ${LocalStorageUtil.getItem("__TOKEN__")}`,
// });
setTimeout(() => {
LocalStorageUtil.clear();
window.location.replace("/");
......
No preview for this file type
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment