Browse Source

feat: 数据对接

pull/3/head
jiannibang 4 years ago
parent
commit
a48591e507
  1. 4
      package.json
  2. 2
      src/components/DefaultPopup/DefaultPopup.js
  3. 4
      src/components/HeadBar/HeadBar.scss
  4. 10
      src/components/NavBottom/NavBottom.js
  5. 3
      src/components/Popup/Popup.js
  6. 217
      src/js/helpers/data-helper.js
  7. 138
      src/pages/Activities/Activities.js
  8. 264
      src/pages/Activities/Activities.scss
  9. 4
      src/pages/Activities/back.svg
  10. 3
      src/pages/Activities/clock.svg
  11. BIN
      src/pages/Activities/close.png
  12. BIN
      src/pages/Activities/detail.png
  13. 102
      src/pages/Coupons/ApplyModal/ApplyModal.js
  14. 118
      src/pages/Coupons/ApplyModal/ApplyModal.scss
  15. 4
      src/pages/Coupons/ApplyModal/back.svg
  16. 163
      src/pages/Coupons/CouponList/CouponList.js
  17. 268
      src/pages/Coupons/CouponList/CouponList.scss
  18. 34
      src/pages/Coupons/CouponList/bg0.svg
  19. 32
      src/pages/Coupons/CouponList/bg1.svg
  20. 32
      src/pages/Coupons/CouponList/bg2.svg
  21. 3
      src/pages/Coupons/CouponList/close.svg
  22. BIN
      src/pages/Coupons/CouponList/noData.png
  23. 3
      src/pages/Coupons/CouponList/tri.svg
  24. 55
      src/pages/Coupons/Coupons.js
  25. 69
      src/pages/Coupons/Coupons.scss
  26. 4
      src/pages/Coupons/ListEnd/ListEnd.js
  27. 5
      src/pages/Coupons/ListEnd/ListEnd.scss
  28. 4
      src/pages/Coupons/ListEnd/bg.svg
  29. 25
      src/pages/Coupons/Qrcode/Qrcode.js
  30. 0
      src/pages/Coupons/Qrcode/Qrcode.scss
  31. 59
      src/pages/Coupons/ScanModal/ScanModal.js
  32. 72
      src/pages/Coupons/ScanModal/ScanModal.scss
  33. 4
      src/pages/Coupons/ScanModal/back.svg
  34. 3
      src/pages/Coupons/ScanModal/border.svg
  35. 4
      src/pages/Coupons/ScanModal/close.svg
  36. 9
      src/pages/Coupons/ScanModal/scaner.svg
  37. 130
      src/pages/Coupons/ShopManager/ShopManager.js
  38. 132
      src/pages/Coupons/ShopManager/ShopManager.scss
  39. BIN
      src/pages/Coupons/ShopManager/noDataPic.png
  40. 26
      src/pages/Coupons/ShopTabs/ShopTabs.js
  41. 32
      src/pages/Coupons/ShopTabs/ShopTabs.scss
  42. 3
      src/pages/Coupons/ShopTabs/card.svg
  43. 3
      src/pages/Coupons/ShopTabs/cardActive.svg
  44. 3
      src/pages/Coupons/ShopTabs/ticket.svg
  45. 3
      src/pages/Coupons/ShopTabs/ticketActive.svg
  46. 148
      src/pages/Coupons/WriteOffModal/WriteOffModal.js
  47. 162
      src/pages/Coupons/WriteOffModal/WriteOffModal.scss
  48. 4
      src/pages/Coupons/WriteOffModal/back.svg
  49. 5
      src/pages/Coupons/WriteOffModal/scan.svg
  50. 4
      src/pages/Coupons/WriteOffModal/search.svg
  51. BIN
      src/pages/Coupons/notMember.png
  52. 241
      src/pages/Index/Index.js
  53. 121
      src/pages/ShopCoupons/ShopCoupons.js
  54. 144
      src/pages/ShopCoupons/ShopCoupons.scss
  55. 9
      src/pages/ShopCoupons/arrow.svg
  56. 3
      src/pages/ShopCoupons/back.svg

4
package.json

@ -1,5 +1,5 @@
{ {
"name": "qmplaza",
"name": "qmgo",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"homepage": "./", "homepage": "./",
@ -29,7 +29,7 @@
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build && coscmd config -a AKIDjS6at7fjTAVgggDNCrogRiZTSL304DPR -s FPPGCXr4xgZRLKDC8tZGp7HTZXlqx0gU -b lg-cjdqwkbo-1256266248 -r ap-shanghai && coscmd delete qmplaza -f && coscmd upload -r build qmplaza",
"build": "react-scripts build && coscmd config -a AKIDjS6at7fjTAVgggDNCrogRiZTSL304DPR -s FPPGCXr4xgZRLKDC8tZGp7HTZXlqx0gU -b lg-cjdqwkbo-1256266248 -r ap-shanghai && coscmd delete qmgo -f && coscmd upload -r build qmgo",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject" "eject": "react-scripts eject"
}, },

2
src/components/DefaultPopup/DefaultPopup.js

@ -201,7 +201,7 @@ const DefaultPopup = ({
setState(STATES.init); setState(STATES.init);
onClick(e); onClick(e);
}} }}
wingHeight="calc(100vh - 400px)"
wingHeight="calc(100vh - 310px)"
></ShopsWithFilter> ></ShopsWithFilter>
</div> </div>
)} )}

4
src/components/HeadBar/HeadBar.scss

@ -127,8 +127,8 @@
.label { .label {
display: inline-block; display: inline-block;
flex: 0 0 20px;
text-align: center;
flex: 0 0 30px;
text-align: right;
margin-left: 8px; margin-left: 8px;
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;

10
src/components/NavBottom/NavBottom.js

@ -107,16 +107,6 @@ const NavBottom = ({
}} }}
/> />
)} )}
<div
className="ar-btn"
onClick={() => {
!paused && puaseOrResume();
handleAR(end);
}}
>
<img src={arpng} />
AR导航
</div>
{showNav ? ( {showNav ? (
<div className="nav"> <div className="nav">
<img <img

3
src/components/Popup/Popup.js

@ -56,9 +56,6 @@ const Popup = ({
<div className="tab" onClick={() => setEnd()}> <div className="tab" onClick={() => setEnd()}>
<img src={navpng} /> 导航动画 <img src={navpng} /> 导航动画
</div> </div>
<div className="tab" onClick={() => handleAR(shop)}>
<img src={arpng} /> AR实时导航
</div>
</div> </div>
</div> </div>
)} )}

217
src/js/helpers/data-helper.js

@ -1,10 +1,10 @@
import axios from "axios"; import axios from "axios";
import icons from "./image-helper"; import icons from "./image-helper";
let mallInfos = new Map(); let mallInfos = new Map();
export const cdnUrl = "https://cdn.1000my.cn";
export const code = "b4a45cf0-85ce-4123-99f0-e4ddce2731de";
export const baseUrl = "https://test.ar.1000my.com";
export const post = async (url = "", data = {}) => {
export const code = "project-200";
export const baseUrl = "https://project-iot.test.1000my.com";
export const get = async (url = "", data = {}) => {
const response = await fetch(baseUrl + url, { const response = await fetch(baseUrl + url, {
method: "POST", method: "POST",
headers: { headers: {
@ -14,24 +14,12 @@ export const post = async (url = "", data = {}) => {
}); });
return response.json(); return response.json();
}; };
const getMallInfo = async ({ memberID }) => {
const { name, city, groundFloorOrder, floors, scale, offsetToNorth } = {
name: "千目广场",
const getMallInfo = async () => {
const { name, city, groundFloorOrder, scale, offsetToNorth } = {
name: "桥北万象",
city: "南京", city: "南京",
groundFloorOrder: 1,
groundFloorOrder: 2,
scale: 0.15, scale: 0.15,
floors: [
{
name: "F1",
floorOrder: 0,
url: null,
},
{
name: "F2",
floorOrder: 1,
url: true,
},
],
offsetToNorth: 0, offsetToNorth: 0,
}; };
document.title = name; document.title = name;
@ -43,121 +31,74 @@ const getMallInfo = async ({ memberID }) => {
groundFloorIndex: groundFloorOrder, groundFloorIndex: groundFloorOrder,
needSpotLight: false, needSpotLight: false,
scale, scale,
floors,
isNew: true, isNew: true,
cloud: "1000my", cloud: "1000my",
offsetToNorth, offsetToNorth,
}; };
const config = { const config = {
mapDataUrl: `${cdnUrl}/test-projects/${code}/Aeditor/Aeditor.json?t=${new Date().getTime()}`,
shopInfoUrl: `${cdnUrl}/test-projects/${code}/QueryShopListForMap/QueryShopListForMap.json?t=${new Date().getTime()}`,
mapDataUrl: `${baseUrl}/api/guide/v1/web/getMallMapData/${code}/Aeditor`,
shopInfoUrl: `${baseUrl}/api/guide/v1/web/getMapInfo?projectCode=${code}`,
}; };
try {
const {
data: { mapUrl, shopUrl },
} = await axios.get(
`${cdnUrl}/test-projects/${code}/config.json?t=${new Date().getTime()}`
);
if (mapUrl) config.mapDataUrl = mapUrl;
if (shopUrl) config.shopInfoUrl = shopUrl;
} catch (error) {
console.log("获取config失败");
}
const [
mapDataJSON,
serverShopInfo,
facs,
activities,
pois,
menu,
shopCouponMap,
] = await Promise.all([
(async () => {
try {
const {
data: {
data: { mapData: mapDataJSON },
},
} = await axios.get(config.mapDataUrl);
return mapDataJSON;
} catch (error) {
console.error(error);
return {};
}
})(),
(async () => {
try {
const {
data: { data: serverShopInfo },
} = await axios.get(config.shopInfoUrl);
return serverShopInfo;
} catch (error) {
console.error(error);
return {};
}
})(),
(async () => {
try {
const { data: facs } = await post(`/Api/Cdn/FacilityInfo`);
return facs;
} catch (error) {
console.error(error);
return [];
}
})(),
(async () => {
try {
const { data: activities } = await post(`/Api/Operation/MallActList`, {
memberID,
});
return activities;
} catch (error) {
console.error(error);
return [];
}
})(),
(async () => {
try {
const { data: pois } = await post(`/api/Operation/GetPoiList`);
return pois;
} catch (error) {
console.error(error);
return [];
}
})(),
(async () => {
try {
const { data: menu } = await post(`/Api/AppModule/MallAppModules`);
return menu;
} catch (error) {
console.error(error);
return [];
}
})(),
(async () => {
try {
const {
data: { shopDetailShowCoupon },
} = await post(`/Api/Operation/MiniproBasicData`, {
memberID,
});
const shopCouponMap = shopDetailShowCoupon.reduce(
(acc, nxt) => ({ ...acc, [nxt]: true }),
{}
);
return shopCouponMap;
} catch (error) {
console.error(error);
return {};
}
})(),
]);
const [cdnUrl, mapDataJSON, [buildingList, serverShopInfo], facs] =
await Promise.all([
(async () => {
try {
const {
data: { data: cdnUrl },
} = await axios.get(`${baseUrl}/api/info/v1/web/getUploadUrl`);
return cdnUrl;
} catch (error) {
console.error(error);
return {};
}
})(),
(async () => {
try {
const {
data: {
data: { mapData: mapDataJSON },
},
} = await axios.get(config.mapDataUrl);
return mapDataJSON;
} catch (error) {
console.error(error);
return {};
}
})(),
(async () => {
try {
const {
data: {
data: { buildingList, shopList: serverShopInfo },
},
} = await axios.get(config.shopInfoUrl);
return [buildingList, serverShopInfo];
} catch (error) {
console.error(error);
return {};
}
})(),
(async () => {
try {
const {
data: { data: facs },
} = await axios.get(
`${baseUrl}/api/guide/v1/web/getProjectUsedIconList?projectCode=${code}`
);
return facs;
} catch (error) {
console.error(error);
return [];
}
})(),
]);
const mapData = JSON.parse(mapDataJSON)[0]; const mapData = JSON.parse(mapDataJSON)[0];
mall.activities = activities;
mall.pois = pois;
const poiMap = pois.reduce((acc, nxt) => ({ ...acc, [nxt.code]: nxt }), {});
mall.floors = buildingList[0].floorList.map(({ floor, floorOrder }) => ({
name: floor,
floorOrder,
url: true,
}));
mall.facilityTypeMap = facs.reduce( mall.facilityTypeMap = facs.reduce(
(acc, nxt) => ({ (acc, nxt) => ({
...acc, ...acc,
@ -165,11 +106,25 @@ const getMallInfo = async ({ memberID }) => {
}), }),
{} {}
); );
const shopInfo = serverShopInfo;
const shopInfo = serverShopInfo
.filter(({ buildingOrder }) => buildingOrder === 0)
.map((iot) => ({
...iot,
name: iot.shopName,
houseNum: iot.houseNumber,
nameEn: iot.shopNameEn,
logoPath: cdnUrl + iot.logoUrl,
shopFormat: iot.industryFatherName,
}))
.reduce((acc, nxt) => {
if (!acc[nxt.floorOrder]) acc[nxt.floorOrder] = [nxt];
else acc[nxt.floorOrder] = [...acc[nxt.floorOrder], nxt];
return acc;
}, [])
.map((shopList, floorOrder) => ({ floorOrder, shopList }));
console.log(shopInfo);
shopInfo.forEach(({ shopList }) => shopInfo.forEach(({ shopList }) =>
shopList.forEach((shop) => { shopList.forEach((shop) => {
if (shopCouponMap[shop.code]) shop.hasCoupon = true;
else shop.hasCoupon = false;
shop.initialsCn = shop.name shop.initialsCn = shop.name
.split(" ") .split(" ")
.filter((t) => t) .filter((t) => t)
@ -204,8 +159,6 @@ const getMallInfo = async ({ memberID }) => {
acc[floorOrder] = [url, name]; acc[floorOrder] = [url, name];
return acc; return acc;
}, new Array()), }, new Array()),
poiMap,
menu,
}); });
const mallInfo = { mall, shopInfo, images }; const mallInfo = { mall, shopInfo, images };
mallInfos.set(mall.code, mallInfo); mallInfos.set(mall.code, mallInfo);

138
src/pages/Activities/Activities.js

@ -1,138 +0,0 @@
import React, { useEffect, useState } from "react";
import "./Activities.scss";
import back from "./back.svg";
import clock from "./clock.svg";
import detail from "./detail.png";
import { post } from "../../js/helpers/data-helper";
const Activities = ({
initActivity,
setInitActivity,
onGo,
mall: { activities, pois },
facilities,
memberID,
}) => {
const [activity, setActivity] = useState(null);
const [receiving, setReceiving] = useState(false);
const poiMap = pois.reduce((acc, nxt) => ({ ...acc, [nxt.code]: nxt }), {});
const getFacByAct = (activity) => {
if (!activity) return null;
const poiCode = activity.poiList.find((code) => poiMap[code]);
const poi = poiCode ? poiMap[poiCode] : null;
if (!poi) return null;
const actFacs = facilities ? facilities["活动"] : [];
if (!actFacs) return null;
const actFac = actFacs.find(({ title }) => title === poi.name);
return actFac;
};
const reject = () => {
window.weui.toast("该活动即将上线,敬请期待!", {
className: "toast",
});
};
const receive = async (activity) => {
setReceiving(true);
try {
const { code, data, msg } = await post("/Api/Coupon/CouponReceive", {
activityCode: activity.code,
memberID,
});
window.weui.toast(msg, {
className: "toast",
});
if (code === "200") {
activity.isReceived = true;
}
} catch (error) {
console.warn(error);
} finally {
setReceiving(false);
}
};
useEffect(() => {
if (initActivity) {
setActivity(initActivity);
setInitActivity(null);
}
}, [initActivity]);
return (
<div className="activities">
<div className="header">活动</div>
<div className="list-container">
{activities &&
activities.map((act) => (
<div key={act.code} className="card">
<img className="card-header" src={act.fileUrl}></img>
<div className="card-content">
<div className="detail" onClick={() => setActivity(act)}>
<img src={detail}></img>
</div>
<div
className="btn"
onClick={() => {
const fac = getFacByAct(act);
if (!fac) return reject();
return onGo && onGo(fac);
}}
>
GO
</div>
</div>
</div>
))}
</div>
{activity && (
<div className="activity">
<img
className="back"
onClick={() => setActivity(null)}
src={back}
></img>
<img className="r1" src={activity.fileUrl}></img>
<div className="r2">
<div className="rr1">{activity.name}</div>
<div className="rr2">
<img src={clock}></img>
{activity.beginTime.split(" ")[0]}
{activity.endTime.split(" ")[0]}
</div>
<div className="r3">
<div className="title">活动介绍</div>
{activity.intro}
<div
className="r4"
onClick={() => {
const fac = getFacByAct(activity);
if (!fac) return reject();
return onGo && onGo(fac);
}}
>
开始导航
</div>
{activity.defaultAwardTitle && (
<div className="r5">
<div className="t1">{activity.defaultAwardTitle}</div>
<div className="meta">活动奖励</div>
<div
onClick={() =>
!activity.isReceived && !receiving && receive(activity)
}
className={`btn ${
activity.isReceived || receiving ? "disabled" : ""
}`}
>
领取奖励
</div>
</div>
)}
</div>
</div>
</div>
)}
</div>
);
};
export default Activities;

264
src/pages/Activities/Activities.scss

@ -1,264 +0,0 @@
.activities {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
background: #f0f0f0;
pointer-events: auto;
.header {
position: absolute;
height: 25px;
left: 24px;
top: 24px;
font-family: "PingFang SC";
font-style: normal;
font-weight: 600;
font-size: 18px;
line-height: 25px;
display: flex;
align-items: center;
color: #353230;
}
.list-container {
position: absolute;
top: 64px;
left: 17px;
right: 17px;
bottom: 0;
overflow-x: hidden;
overflow-y: auto;
.card {
display: inline-flex;
flex-direction: column;
background: #ffffff;
border-radius: 10px;
overflow: hidden;
.card-header {
width: calc(100vw - 34px);
height: calc((100vw - 34px) / 321 * 180);
border-radius: 10px;
object-fit: cover;
}
.card-content {
display: flex;
height: 72px;
padding-left: 24px;
padding-right: 16px;
font-family: "PingFang SC";
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 22px;
color: #353230;
align-items: center;
justify-content: space-between;
.detail {
display: inline-flex;
align-items: center;
img {
width: 20px;
height: 20px;
margin-right: 8px;
}
}
.btn {
display: flex;
width: 80px;
height: 40px;
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%);
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2);
border-radius: 8px;
font-family: "HarmonyOS Sans SC";
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 19px;
text-align: right;
color: #ffffff;
justify-content: center;
align-items: center;
}
}
}
.card + .card {
margin-top: 16px;
}
}
.activity {
position: absolute;
top: 0;
bottom: -98px;
left: 0;
right: 0;
background: #f0f0f0;
z-index: 1;
border-radius: 18px;
.back {
position: absolute;
width: 40px;
height: 40px;
left: 16px;
top: 8px;
z-index: 2;
}
.r1 {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 56vw;
width: 100vw;
z-index: 1;
border-radius: 10px 10px 0 0;
object-fit: cover;
}
.r2 {
position: absolute;
top: 192px;
left: 0;
right: 0;
bottom: 0;
z-index: 2;
background: linear-gradient(
180.18deg,
#ffffff 17.3%,
rgba(255, 255, 255, 0) 99.84%
);
border-radius: 16px 16px 0 0;
display: flex;
flex-direction: column;
.rr1 {
font-family: "PingFang SC";
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 22px;
margin-top: 16px;
margin-bottom: 8px;
color: #353230;
padding-left: 24px;
}
.rr2 {
display: inline-flex;
font-family: "PingFang SC";
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 17px;
color: #68655e;
align-items: center;
padding-left: 24px;
img {
width: 16px;
height: 16px;
margin-right: 8px;
}
}
.r3 {
position: absolute;
top: 97px;
left: 10px;
right: 10px;
bottom: 0;
font-family: "PingFang SC";
font-style: normal;
font-weight: 400;
font-size: 14px;
line-height: 22px;
color: #9d988f;
overflow-x: hidden;
overflow-y: auto;
background: #f9f9fb;
border-radius: 16px 16px 0px 0px;
padding: 16px 14px;
.title {
font-family: "PingFang SC";
font-style: normal;
font-weight: 600;
font-size: 14px;
line-height: 20px;
color: #353230;
margin-bottom: 4px;
}
}
.r4 {
display: flex;
position: absolute;
height: 56px;
left: 18px;
right: 18px;
bottom: 56px;
margin: auto;
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%);
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2);
border-radius: 16px;
font-family: "HarmonyOS Sans SC";
font-style: normal;
font-weight: 600;
font-size: 16px;
line-height: 22px;
align-items: center;
justify-content: center;
color: #ffffff;
}
.r5 {
position: absolute;
bottom: 139px;
left: 14px;
right: 14px;
height: 80px;
background: rgba(255, 255, 255, 0.7);
box-shadow: 0px 12px 16px rgba(104, 110, 127, 0.08);
border-radius: 10px;
.t1 {
position: absolute;
top: 19px;
left: 20px;
font-weight: 600;
font-size: 17px;
line-height: 22px;
color: #437af7;
width: 174px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.meta {
position: absolute;
top: 45px;
left: 20px;
font-weight: 600;
font-size: 12px;
line-height: 16px;
color: #a1a5b3;
}
.btn {
position: absolute;
display: flex;
width: 80px;
height: 40px;
top: 19px;
right: 12px;
background: #ffffff;
box-shadow: 0px 12px 16px rgba(104, 110, 127, 0.08);
border-radius: 10px;
font-weight: 600;
font-size: 15px;
line-height: 20px;
color: #437af7;
justify-content: center;
align-items: center;
border: 1px solid rgba(80, 138, 247, 0.6);
&.disabled {
color: #a1a5b3;
border: 1px solid #a1a5b3;
}
}
}
}
}
}

4
src/pages/Activities/back.svg

@ -1,4 +0,0 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="40" height="40" rx="20" fill="#323337" fill-opacity="0.6"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.1859 12.5495C23.6189 12.9283 23.6627 13.5864 23.2839 14.0194L18.0508 20.0001L23.2839 25.9808C23.6627 26.4138 23.6189 27.0719 23.1859 27.4507C22.753 27.8295 22.0949 27.7857 21.716 27.3527L16.1228 20.9604C15.6417 20.4106 15.6417 19.5896 16.1228 19.0398L21.716 12.6475C22.0949 12.2145 22.753 12.1707 23.1859 12.5495Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 559 B

3
src/pages/Activities/clock.svg

@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.00004 2.66659C5.05452 2.66659 2.66671 5.0544 2.66671 7.99992C2.66671 10.9454 5.05452 13.3333 8.00004 13.3333C10.9456 13.3333 13.3334 10.9454 13.3334 7.99992C13.3334 5.0544 10.9456 2.66659 8.00004 2.66659ZM1.33337 7.99992C1.33337 4.31802 4.31814 1.33325 8.00004 1.33325C11.6819 1.33325 14.6667 4.31802 14.6667 7.99992C14.6667 11.6818 11.6819 14.6666 8.00004 14.6666C4.31814 14.6666 1.33337 11.6818 1.33337 7.99992ZM8.00004 3.99992C8.36823 3.99992 8.66671 4.2984 8.66671 4.66659V7.72378L10.4714 9.52851C10.7318 9.78886 10.7318 10.211 10.4714 10.4713C10.2111 10.7317 9.78899 10.7317 9.52864 10.4713L7.52864 8.47132C7.40361 8.3463 7.33337 8.17673 7.33337 7.99992V4.66659C7.33337 4.2984 7.63185 3.99992 8.00004 3.99992Z" fill="#437AF7"/>
</svg>

Before

Width:  |  Height:  |  Size: 848 B

BIN
src/pages/Activities/close.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/pages/Activities/detail.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

102
src/pages/Coupons/ApplyModal/ApplyModal.js

@ -1,102 +0,0 @@
import "./ApplyModal.scss";
import Modal from "react-modal";
import { useState } from "react";
import { post } from "../../../js/helpers/data-helper";
const ApplyModal = ({ onBack, memberID }) => {
const [title, setTitle] = useState("");
const [totalCount, setTotalCount] = useState("");
const [beginTime, setBeginTime] = useState("");
const [endTime, setEndTime] = useState("");
const [couponRules, setCouponRules] = useState("");
const toast = (text) =>
window.weui.toast(text, {
className: "toast",
});
const submit = async () => {
if (!title) return toast("请输入礼券标题");
if (!totalCount) return toast("请输入发放数量");
if (!beginTime) return toast("请选择开始时间");
if (!endTime) return toast("请选择结束时间");
try {
const { code, msg } = await post("/api/coupon/ApplyCoupon", {
title,
totalCount,
beginTime,
endTime,
memberID,
couponRules,
});
if (code === "200") {
toast("已提交申请,审核中!");
onBack && onBack();
} else {
toast(msg);
}
} catch (error) {}
};
return (
<Modal isOpen ariaHideApp={false} className="ApplyModal">
<div className="back" onClick={() => onBack && onBack()}></div>
<div className="title">申请发券</div>
<div className="content">
<div className="item">
<div className="label">礼券标题</div>
<input
type="text"
className="inputText"
placeholder="请输入礼券标题"
maxLength={30}
value={title}
onChange={(e) => setTitle(e.target.value)}
></input>
</div>
<div className="item">
<div className="label">发放数量</div>
<input
type="number"
className="inputText"
placeholder="请输入发放数量"
value={totalCount}
min={1}
max={9999}
onChange={(e) => setTotalCount(e.target.value)}
></input>
</div>
<div className="item">
<div className="label">使用期限</div>
<div className="dates">
<input
type="date"
value={beginTime}
onChange={(e) => setBeginTime(e.target.value)}
placeholder="请选择开始时间"
></input>
<div style={{ margin: "0 15px" }}></div>
<input
type="date"
value={endTime}
onChange={(e) => setEndTime(e.target.value)}
placeholder="请选择结束时间"
></input>
</div>
</div>
<div className="item">
<div className="label">礼券规则</div>
<textarea
type="text"
className="inputTextArea"
placeholder="请输入礼券规则"
value={couponRules}
maxLength={100}
onChange={(e) => setCouponRules(e.target.value)}
></textarea>
</div>
<div className="btn" onClick={submit}>
免费申请
</div>
</div>
</Modal>
);
};
export default ApplyModal;

118
src/pages/Coupons/ApplyModal/ApplyModal.scss

@ -1,118 +0,0 @@
.ApplyModal {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #f6f6f6;
overflow: hidden;
.back {
position: absolute;
top: 10px;
left: 10px;
width: 60px;
height: 60px;
background: center / cover no-repeat url(./back.svg);
}
.title {
position: absolute;
top: 28px;
right: 16px;
font-style: normal;
font-weight: 600;
font-size: 20px;
line-height: 25px;
color: #000000;
}
.content {
position: absolute;
top: 92px;
left: 10px;
right: 10px;
bottom: 34px;
background: #ffffff;
border-radius: 18px;
padding: 32px 24px;
.item {
height: 58px;
border-bottom: 1px solid rgba(218, 215, 209, 0.4);
.label {
font-weight: 600;
font-size: 17px;
line-height: 22px;
color: #353230;
margin-bottom: 8px;
}
.inputText {
font-weight: 400;
font-size: 15px;
line-height: 20px;
color: #68655e;
border: none;
outline: none;
opacity: 0.8;
&::placeholder {
color: #dad7d1;
}
}
.inputTextArea {
width: 100%;
background: #f9f9fb;
border-radius: 8px;
height: 152px;
padding: 16px;
border: none;
font-weight: 400;
font-size: 15px;
line-height: 20px;
outline: none;
color: #68655e;
&::placeholder {
color: #dad7d1;
}
}
.dates {
display: flex;
font-weight: 400;
font-size: 15px;
line-height: 20px;
color: #353230;
input {
flex: 1;
font-weight: 400;
font-size: 15px;
line-height: 20px;
color: #68655e;
border: none;
outline: none;
opacity: 0.8;
overflow: hidden;
&::placeholder {
color: #dad7d1;
}
}
}
}
.item + .item {
margin-top: 24px;
}
.btn {
position: absolute;
left: 18px;
right: 18px;
bottom: 18px;
height: 56px;
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%);
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2);
border-radius: 10px;
font-weight: 600;
font-size: 16px;
line-height: 22px;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
}
}

4
src/pages/Coupons/ApplyModal/back.svg

@ -1,4 +0,0 @@
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="60" height="60" rx="10" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.0976 18.0794C35.7903 18.6855 35.8605 19.7385 35.2544 20.4312L26.8813 30.0003L35.2544 39.5695C35.8605 40.2622 35.7903 41.3152 35.0976 41.9213C34.4048 42.5274 33.3519 42.4573 32.7458 41.7645L23.7966 31.5369C23.0268 30.6571 23.0268 29.3436 23.7966 28.4638L32.7458 18.2362C33.3519 17.5434 34.4048 17.4733 35.0976 18.0794Z" fill="#353230"/>
</svg>

Before

Width:  |  Height:  |  Size: 544 B

163
src/pages/Coupons/CouponList/CouponList.js

@ -1,163 +0,0 @@
import "./CouponList.scss";
import { useState, useRef, useEffect, useCallback } from "react";
import ListEnd from "../ListEnd/ListEnd";
import noData from "./noData.png";
import Qrcode from "../Qrcode/Qrcode";
import Modal from "react-modal";
import { post } from "../../../js/helpers/data-helper";
import InfiniteScroll from "react-infinite-scroller";
const stateMap = {
0: "未使用",
1: "已使用",
2: "已失效",
};
const stateList = [0, 1, 2];
const CouponList = ({ memberID }) => {
const [state, setState] = useState(stateList[0]);
const [list, setList] = useState([]);
const [nextPageIndex, setNextPageIndex] = useState(1);
const [loading, setLoading] = useState(false);
const hasMore = nextPageIndex !== null;
const [modalCoupon, setModalCoupon] = useState(null);
const listRef = useRef();
const showNoData = list !== null && list.length === 0;
const showListEnd = list !== null && list.length > 0;
const showCouponModal = !!modalCoupon;
const loadMore = useCallback(async () => {
if (loading || nextPageIndex === null || !memberID) return;
setLoading(true);
try {
const { code, data, msg } = await post("/api/coupon/UserCouponList", {
paging: 1,
state,
pageIndex: nextPageIndex,
pageSize: 10,
memberID,
});
if (code === "200") {
setList([...list, ...data.list]);
setNextPageIndex(
nextPageIndex + 1 > data.allPage ? null : nextPageIndex + 1
);
} else {
setNextPageIndex(null);
window.weui.toast(msg, {
className: "toast",
});
}
} catch (error) {
setNextPageIndex(null);
} finally {
setLoading(false);
}
}, [list, loading, nextPageIndex]);
useEffect(() => {
if (listRef.current) listRef.current.scrollTop = 0;
setNextPageIndex(1);
setList([]);
}, [state]);
return (
<div className="CouponList">
<div className="CouponTabs">
{stateList.map((item) => (
<div
key={item}
className={`tab ${state === item ? "active" : ""}`}
onClick={() => setState(item)}
>
{stateMap[item]}
</div>
))}
</div>
<div className="list-container" ref={listRef}>
<InfiniteScroll
pageStart={0}
loadMore={loadMore}
hasMore={hasMore}
useWindow={false}
getScrollParent={() => listRef && listRef.current}
>
{showNoData && (
<div className="noData">
<img className="bg" src={noData}></img>
<div className="meta">
<div className="btn" onClick={() => {}}>
参加AR
</div>
活动可领取优惠券
</div>
</div>
)}
{list !== null &&
list.map((coupon) => (
<div
key={coupon.orderNo}
className={`coupon bg${state}`}
onClick={() => setModalCoupon(coupon)}
>
{coupon.logoUrl ? (
<img
className="logo"
src={coupon.logoUrl}
style={{
width: (window.innerWidth / 375) * 64,
height: (window.innerWidth / 375) * 64,
}}
></img>
) : (
<Qrcode
className="qrcode"
size={(window.innerWidth / 375) * 64}
text={coupon.orderNo}
></Qrcode>
)}
<div className="title">{coupon.title}</div>
<div className="meta">{coupon.showNo}</div>
<div className="duration">
使用期限<div className="sep"></div>
{coupon.beginTime}{coupon.endTime}
</div>
</div>
))}
{showListEnd && <ListEnd></ListEnd>}
</InfiniteScroll>
</div>
{showCouponModal && (
<Modal
isOpen
ariaHideApp={false}
style={{ overlay: { background: "rgba(0, 0, 0, 0.6)" } }}
className="CouponModal"
>
<div className="close" onClick={() => setModalCoupon(null)}></div>
<Qrcode
className="qrcode"
size={120}
text={modalCoupon.orderNo}
></Qrcode>
<div className="content">
<div className="title">{modalCoupon.title}</div>
<div className="coupon-code">{modalCoupon.showNo}</div>
<div className="meta">使用期限</div>
<div className="value">
{modalCoupon.beginTime}{modalCoupon.endTime}
</div>
{modalCoupon.couponRules && (
<>
<div className="meta">礼券规则</div>
<div className="value">{modalCoupon.couponRules}</div>
</>
)}
</div>
</Modal>
)}
</div>
);
};
export default CouponList;

268
src/pages/Coupons/CouponList/CouponList.scss

@ -1,268 +0,0 @@
.CouponList {
flex: 1;
display: flex;
flex-direction: column;
background: linear-gradient(
180deg,
#f2f2f2 0%,
rgba(249, 249, 249, 0) 20.18%
);
border-radius: 18px 18px 0 0;
padding-top: 10px;
width: 100vw;
align-items: center;
overflow: hidden;
.CouponTabs {
display: flex;
flex: 0 0 56px;
width: calc(100vw - 20px);
background: #ffffff;
border-radius: 10px;
.tab {
position: relative;
display: flex;
flex: 1;
font-weight: 400;
font-size: 15px;
line-height: 20px;
color: #9d988f;
justify-content: center;
align-items: center;
&.active {
color: #508af7;
&::before {
content: "";
position: absolute;
bottom: 10px;
left: 0;
right: 0;
margin: auto;
width: 4px;
height: 4px;
background: #508af7;
border-radius: 50%;
}
&::after {
content: "";
position: absolute;
width: 30px;
height: 6px;
bottom: 0;
left: 0;
right: 0;
margin: auto;
background: center / cover no-repeat url(./tri.svg);
}
}
}
}
.list-container {
flex: 1;
overflow-x: hidden;
overflow-y: scroll;
padding-top: 16px;
text-align: center;
scroll-behavior: smooth;
&::-webkit-scrollbar {
display: none;
}
.coupon {
position: relative;
width: calc(100vw - 20px);
height: calc((100vw - 20px) / 355 * 134);
&.bg0 {
background: center / cover no-repeat url(./bg0.svg);
}
&.bg1 {
background: center / cover no-repeat url(./bg1.svg);
}
&.bg2 {
background: center / cover no-repeat url(./bg2.svg);
}
.logo {
position: absolute;
top: 5.333vw;
left: 5.333vw;
border-radius: 4px;
object-fit: cover;
}
.title {
position: absolute;
top: 8vw;
left: 27.733vw;
right: 2.667vw;
font-weight: 600;
font-size: 4.533vw;
line-height: 5.867vw;
color: #353230;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
text-align: left;
}
.meta {
position: absolute;
top: 14.933vw;
left: 27.733vw;
font-weight: 600;
font-size: 3.467vw;
line-height: 4.8vw;
color: #68655e;
opacity: 0.8;
}
.duration {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 9.067vw;
font-weight: 400;
font-size: 3.2vw;
line-height: 4.267vw;
text-align: center;
color: #9d988f;
display: flex;
justify-content: center;
align-items: center;
.sep {
width: 0.267vw;
height: 2.667vw;
opacity: 0.3;
border-left: 0.267vw solid #68655e;
margin-left: 3.2vw;
margin-right: 3.2vw;
}
}
.time-left {
position: absolute;
height: 3.467vw;
top: 2.133vw;
right: 1.067vw;
font-weight: 600;
font-size: 2.933vw;
line-height: 3.467vw;
color: #c1a672;
opacity: 0.8;
}
.qrcode {
position: absolute;
top: 5.333vw;
left: 5.333vw;
}
}
.coupon + .coupon {
margin-top: 8px;
}
.noData {
display: flex;
flex-direction: column;
width: calc(100vw - 20px);
height: 396px;
border-radius: 18px;
background: #ffffff;
align-items: center;
.bg {
margin: auto;
width: 250px;
height: 250px;
margin-top: 16px;
}
.meta {
width: calc(100vw - 46px);
flex: 0 0 90px;
border-top: 1px solid #f5f5f5;
display: flex;
font-weight: 400;
font-size: 17px;
line-height: 22px;
color: #9d988f;
height: 90px;
justify-content: center;
align-items: center;
.btn {
color: #508af7;
}
}
}
}
}
.CouponModal {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 326px;
height: 416px;
margin: auto;
background: #f9f9fb;
border-radius: 16px;
.close {
position: absolute;
top: 16px;
right: 16px;
width: 24px;
height: 24px;
background: center / cover no-repeat url(./close.svg);
}
.qrcode {
position: absolute;
top: 52px;
left: 0;
right: 0;
margin: auto;
}
.content {
position: absolute;
bottom: 8px;
left: 8px;
right: 8px;
background: #f3f4f8;
border-radius: 10px;
height: 192px;
display: flex;
justify-content: center;
align-items: flex-start;
flex-direction: column;
padding: 24px 16px 0 16px;
.title {
font-weight: 600;
font-size: 17px;
line-height: 22px;
color: #323337;
}
.coupon-code {
font-weight: 600;
font-size: 13px;
line-height: 18px;
color: #437af7;
opacity: 0.8;
margin-top: 4px;
padding-bottom: 8px;
border-bottom: 1px dashed #c9cbd1;
margin-bottom: 17px;
width: 100%;
}
.meta {
font-weight: 400;
font-size: 12px;
line-height: 16px;
color: #7a7e8d;
opacity: 0.8;
margin-bottom: 2px;
}
.value {
font-weight: 600;
font-size: 12px;
line-height: 16px;
color: #474a56;
opacity: 0.8;
margin-bottom: 8px;
min-height: 16px;
overflow: hidden;
text-overflow: ellipsis;
}
}
}

34
src/pages/Coupons/CouponList/bg0.svg

@ -1,34 +0,0 @@
<svg width="355" height="134" viewBox="0 0 355 134" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_285_11)">
<path d="M0 8C0 3.58172 3.58172 0 8 0H347C351.418 0 355 3.58172 355 8V126C355 130.418 351.418 134 347 134H8C3.58172 134 0 130.418 0 126V8Z" fill="url(#paint0_linear_285_11)"/>
<path d="M16 -3L242 -3L128 134H-98L16 -3Z" fill="url(#paint1_linear_285_11)"/>
<path opacity="0.5" d="M353.667 25.5833H354.167V25.0833V-3.33333C354.167 -4.83623 353.57 -6.27757 352.507 -7.34027C351.444 -8.40298 350.003 -9 348.5 -9H255.5C253.997 -9 252.556 -8.40298 251.493 -7.34027C250.43 -6.27757 249.833 -4.83623 249.833 -3.33333V25.0833H250.333V25.5833C253.626 25.5833 256.785 26.8915 259.113 29.2201C261.442 31.5487 262.75 34.7069 262.75 38C262.75 41.2931 261.442 44.4513 259.113 46.7799C256.785 49.1085 253.626 50.4167 250.333 50.4167H249.833V50.9167V79.3333C249.833 80.8362 250.43 82.2776 251.493 83.3403C252.556 84.403 253.997 85 255.5 85H348.5C350.003 85 351.444 84.403 352.507 83.3403C353.57 82.2776 354.167 80.8362 354.167 79.3333V50.9167V50.4167H353.667C350.374 50.4167 347.215 49.1085 344.887 46.7799C342.558 44.4513 341.25 41.2931 341.25 38C341.25 34.7069 342.558 31.5487 344.887 29.2201C347.215 26.8915 350.374 25.5833 353.667 25.5833ZM261.167 16.86V2.33333H311.833V73.6667H261.167V59.14C265.009 57.1724 268.245 54.1935 270.523 50.5217C272.856 46.7618 274.092 42.4249 274.092 38C274.092 33.5751 272.856 29.2382 270.523 25.4783C268.245 21.8065 265.009 18.8276 261.167 16.86ZM342.833 73.6667H323.167V2.33333H342.833V16.86C338.991 18.8276 335.755 21.8065 333.477 25.4783C331.144 29.2382 329.908 33.5751 329.908 38C329.908 42.4249 331.144 46.7618 333.477 50.5217C335.755 54.1935 338.991 57.1724 342.833 59.14V73.6667Z" fill="white" fill-opacity="0.1" stroke="url(#paint2_linear_285_11)"/>
<rect y="100" width="355" height="34" fill="white" fill-opacity="0.2"/>
<rect x="16" y="16" width="72" height="72" rx="4" fill="black" fill-opacity="0.05"/>
<line opacity="0.4" x1="-2" y1="99.5" x2="355" y2="99.5" stroke="white" stroke-dasharray="2 2"/>
<circle cy="100" r="6" fill="#F6F6F6"/>
<circle cx="355" cy="100" r="6" fill="#F6F6F6"/>
</g>
<path d="M8 1H347V-1H8V1ZM354 8V126H356V8H354ZM347 133H8V135H347V133ZM1 126V8H-1V126H1ZM8 133C4.13401 133 1 129.866 1 126H-1C-1 130.971 3.02943 135 8 135V133ZM354 126C354 129.866 350.866 133 347 133V135C351.971 135 356 130.971 356 126H354ZM347 1C350.866 1 354 4.13401 354 8H356C356 3.02944 351.971 -1 347 -1V1ZM8 -1C3.02944 -1 -1 3.02944 -1 8H1C1 4.13401 4.13401 1 8 1V-1Z" fill="url(#paint3_linear_285_11)"/>
<defs>
<linearGradient id="paint0_linear_285_11" x1="346" y1="134" x2="3.49999" y2="-1.30007e-05" gradientUnits="userSpaceOnUse">
<stop stop-color="#ECE2C7"/>
<stop offset="1" stop-color="#F1ECD5"/>
</linearGradient>
<linearGradient id="paint1_linear_285_11" x1="234" y1="-9.49998" x2="111" y2="134" gradientUnits="userSpaceOnUse">
<stop stop-color="#F6F6F6" stop-opacity="0.24"/>
<stop offset="1" stop-color="#F6F6F6" stop-opacity="0.16"/>
</linearGradient>
<linearGradient id="paint2_linear_285_11" x1="254" y1="88.5" x2="302.252" y2="8.27527" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0.55"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint3_linear_285_11" x1="-8.5" y1="4.74984e-06" x2="16.5" y2="100" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<clipPath id="clip0_285_11">
<path d="M0 8C0 3.58172 3.58172 0 8 0H347C351.418 0 355 3.58172 355 8V126C355 130.418 351.418 134 347 134H8C3.58172 134 0 130.418 0 126V8Z" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

32
src/pages/Coupons/CouponList/bg1.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

32
src/pages/Coupons/CouponList/bg2.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

3
src/pages/Coupons/CouponList/close.svg

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4099 12.0002L17.7099 7.71019C17.8982 7.52188 18.004 7.26649 18.004 7.00019C18.004 6.73388 17.8982 6.47849 17.7099 6.29019C17.5216 6.10188 17.2662 5.99609 16.9999 5.99609C16.7336 5.99609 16.4782 6.10188 16.2899 6.29019L11.9999 10.5902L7.70994 6.29019C7.52164 6.10188 7.26624 5.99609 6.99994 5.99609C6.73364 5.99609 6.47824 6.10188 6.28994 6.29019C6.10164 6.47849 5.99585 6.73388 5.99585 7.00019C5.99585 7.26649 6.10164 7.52188 6.28994 7.71019L10.5899 12.0002L6.28994 16.2902C6.19621 16.3831 6.12182 16.4937 6.07105 16.6156C6.02028 16.7375 5.99414 16.8682 5.99414 17.0002C5.99414 17.1322 6.02028 17.2629 6.07105 17.3848C6.12182 17.5066 6.19621 17.6172 6.28994 17.7102C6.3829 17.8039 6.4935 17.8783 6.61536 17.9291C6.73722 17.9798 6.86793 18.006 6.99994 18.006C7.13195 18.006 7.26266 17.9798 7.38452 17.9291C7.50638 17.8783 7.61698 17.8039 7.70994 17.7102L11.9999 13.4102L16.2899 17.7102C16.3829 17.8039 16.4935 17.8783 16.6154 17.9291C16.7372 17.9798 16.8679 18.006 16.9999 18.006C17.132 18.006 17.2627 17.9798 17.3845 17.9291C17.5064 17.8783 17.617 17.8039 17.7099 17.7102C17.8037 17.6172 17.8781 17.5066 17.9288 17.3848C17.9796 17.2629 18.0057 17.1322 18.0057 17.0002C18.0057 16.8682 17.9796 16.7375 17.9288 16.6156C17.8781 16.4937 17.8037 16.3831 17.7099 16.2902L13.4099 12.0002Z" fill="#353230"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/pages/Coupons/CouponList/noData.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

3
src/pages/Coupons/CouponList/tri.svg

@ -1,3 +0,0 @@
<svg width="25" height="6" viewBox="0 0 25 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.1488 1.04262L2.48295 5.54887C1.91296 5.84526 1.27998 6 0.637537 6H24.088C23.3514 6 22.629 5.79657 22.0006 5.41214L15.0816 1.17935C13.8853 0.447484 12.3931 0.395605 11.1488 1.04262Z" fill="#F6F6F6"/>
</svg>

Before

Width:  |  Height:  |  Size: 313 B

55
src/pages/Coupons/Coupons.js

@ -1,55 +0,0 @@
import "./Coupons.scss";
import notMember from "./notMember.png";
import Modal from "react-modal";
import { useState } from "react";
import ShopTabs from "./ShopTabs/ShopTabs";
import CouponList from "./CouponList/CouponList";
import ShopManager from "./ShopManager/ShopManager";
const Coupons = ({ show, memberID, isShop = false }) => {
const isNotMember = !memberID;
const [showCoupons, setShowCoupons] = useState(true);
return (
<Modal
isOpen={show}
ariaHideApp={false}
style={{ overlay: { background: "transparent", pointerEvents: "none" } }}
className="Coupons"
>
{isNotMember ? (
<div className="notMember">
<img className="bg" src={notMember}></img>
<div className="meta">
<div
className="btn"
onClick={() => {
window.wx.miniProgram.redirectTo({
url: `/pages/login/index`,
});
}}
>
注册/登录
</div>
可查看优惠卷
</div>
</div>
) : (
<>
{isShop && (
<ShopTabs
showCoupons={showCoupons}
setShowCoupons={setShowCoupons}
></ShopTabs>
)}
{(!isShop || (isShop && showCoupons)) && (
<CouponList memberID={memberID}></CouponList>
)}
{isShop && !showCoupons && (
<ShopManager memberID={memberID}></ShopManager>
)}
</>
)}
</Modal>
);
};
export default Coupons;

69
src/pages/Coupons/Coupons.scss

@ -1,69 +0,0 @@
.Coupons {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 98px;
z-index: 100000;
background: #f6f6f6;
pointer-events: auto;
display: flex;
flex-direction: column;
align-items: center;
.notMember {
display: flex;
flex-direction: column;
width: calc(100vw - 20px);
height: 396px;
border-radius: 18px;
background: #ffffff;
align-items: center;
.bg {
margin: auto;
width: 250px;
height: 250px;
margin-top: 16px;
}
.meta {
width: calc(100vw - 46px);
flex: 0 0 90px;
border-top: 1px solid #f5f5f5;
display: flex;
font-weight: 400;
font-size: 17px;
line-height: 22px;
color: #9d988f;
height: 90px;
justify-content: center;
align-items: center;
.btn {
color: #437af7;
}
}
}
.shopTabs {
display: flex;
width: calc(100vw - 20px);
height: 56px;
background: #ffffff;
border-radius: 12px;
padding: 4px;
.tab {
display: flex;
flex: 1;
height: 48px;
font-weight: 500;
font-size: 16px;
line-height: 22px;
color: #68655e;
justify-content: center;
align-items: center;
border-radius: 8px;
&.active {
color: #ffffff;
background: #daba7f;
box-shadow: 0px 6px 12px rgba(214, 154, 66, 0.3);
}
}
}
}

4
src/pages/Coupons/ListEnd/ListEnd.js

@ -1,4 +0,0 @@
import bg from "./bg.svg";
import "./ListEnd.scss";
const ListEnd = () => <img className="ListEnd" src={bg}></img>;
export default ListEnd;

5
src/pages/Coupons/ListEnd/ListEnd.scss

@ -1,5 +0,0 @@
.ListEnd {
margin-top: 24px;
width: 62px;
height: 40px;
}

4
src/pages/Coupons/ListEnd/bg.svg

@ -1,4 +0,0 @@
<svg width="63" height="40" viewBox="0 0 63 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M31.4998 18.3337C26.8973 18.3337 23.1665 14.6028 23.1665 10.0003C23.1665 5.39783 26.8973 1.66699 31.4998 1.66699C36.1023 1.66699 39.8332 5.39783 39.8332 10.0003C39.8332 14.6028 36.1023 18.3337 31.4998 18.3337ZM31.4998 16.667C33.2679 16.667 34.9636 15.9646 36.2139 14.7144C37.4641 13.4641 38.1665 11.7684 38.1665 10.0003C38.1665 8.23222 37.4641 6.53652 36.2139 5.28628C34.9636 4.03604 33.2679 3.33366 31.4998 3.33366C29.7317 3.33366 28.036 4.03604 26.7858 5.28628C25.5355 6.53652 24.8332 8.23222 24.8332 10.0003C24.8332 11.7684 25.5355 13.4641 26.7858 14.7144C28.036 15.9646 29.7317 16.667 31.4998 16.667ZM27.3332 10.0003H28.9998C28.9998 10.6634 29.2632 11.2993 29.7321 11.7681C30.2009 12.2369 30.8368 12.5003 31.4998 12.5003C32.1629 12.5003 32.7988 12.2369 33.2676 11.7681C33.7364 11.2993 33.9998 10.6634 33.9998 10.0003H35.6665C35.6665 11.1054 35.2275 12.1652 34.4461 12.9466C33.6647 13.728 32.6049 14.167 31.4998 14.167C30.3948 14.167 29.335 13.728 28.5536 12.9466C27.7722 12.1652 27.3332 11.1054 27.3332 10.0003Z" fill="#DAD7D1"/>
<path d="M2.988 26.376L2.376 26.976C3.264 27.612 3.972 28.212 4.488 28.788L5.1 28.176C4.524 27.576 3.828 26.976 2.988 26.376ZM2.652 29.256L2.04 29.856C2.88 30.492 3.54 31.092 4.02 31.656L4.644 31.044C4.104 30.444 3.444 29.856 2.652 29.256ZM4.14 32.52C3.6 33.936 2.964 35.316 2.232 36.672L3.096 37.044C3.768 35.724 4.368 34.32 4.92 32.832L4.14 32.52ZM6.408 32.244C6.792 33.348 7.44 34.308 8.34 35.1C7.428 35.652 6.336 36.096 5.04 36.444L5.472 37.236C6.852 36.816 8.04 36.288 9.036 35.64C9.996 36.336 11.208 36.876 12.672 37.272L13.104 36.492C11.784 36.18 10.656 35.724 9.744 35.124C10.764 34.308 11.508 33.336 11.988 32.208V31.416H5.652V32.244H6.408ZM9.048 34.62C8.256 33.96 7.656 33.168 7.248 32.244H11.028C10.608 33.156 9.948 33.948 9.048 34.62ZM6.78 26.664V28.14C6.78 29.1 6.228 29.832 5.148 30.348L5.724 31.008C6.996 30.312 7.644 29.328 7.644 28.044V27.48H10.176V29.472C10.176 30.156 10.536 30.504 11.256 30.504H12.84V29.688H11.472C11.172 29.688 11.028 29.544 11.028 29.28V26.664H6.78ZM17.7 30.516H22.464V31.824H17.7V30.516ZM22.464 32.58V33.852H17.7V32.58H22.464ZM22.464 34.608V35.976C22.464 36.264 22.308 36.408 21.996 36.408C21.6 36.408 21.168 36.384 20.712 36.36L20.928 37.152H22.272C22.944 37.128 23.28 36.828 23.28 36.24V29.76H17.712C18 29.316 18.252 28.848 18.492 28.368H24.816V27.528H18.852C19.02 27.108 19.164 26.676 19.308 26.232L18.432 26.124C18.288 26.592 18.108 27.06 17.904 27.528H14.328V28.368H17.508C16.68 29.916 15.516 31.284 14.004 32.484L14.568 33.216C15.432 32.52 16.212 31.74 16.884 30.9V37.176H17.7V34.608H22.464ZM26.364 26.676V27.48H31.068V28.524H27.396V33.276H30.912C30.792 33.9 30.576 34.416 30.288 34.824C29.616 34.476 28.992 34.068 28.428 33.6L27.768 34.056C28.356 34.56 29.004 35.004 29.7 35.388C28.932 35.94 27.708 36.276 26.04 36.408L26.412 37.2C28.32 36.984 29.7 36.528 30.54 35.808C32.328 36.624 34.428 37.092 36.84 37.188L37.056 36.36C34.752 36.288 32.76 35.892 31.08 35.184C31.416 34.704 31.644 34.068 31.788 33.276H35.652V28.524H31.932V27.48H36.648V26.676H26.364ZM34.8 32.52H31.896L31.932 31.668V31.248H34.8V32.52ZM31.032 32.52H28.248V31.248H31.068V31.668C31.068 31.956 31.056 32.244 31.032 32.52ZM28.248 30.528V29.268H31.068V30.528H28.248ZM31.932 29.268H34.8V30.528H31.932V29.268ZM43.452 26.16C42.396 27.312 40.8 28.08 38.664 28.488L39.168 29.28C40.452 28.992 41.556 28.572 42.492 28.02H45.996C45.324 29.004 44.352 29.76 43.104 30.264C42.72 29.784 42.312 29.352 41.88 28.944L41.124 29.304C41.532 29.676 41.928 30.096 42.3 30.552C41.436 30.804 40.476 30.96 39.396 31.032L39.768 31.812C43.272 31.536 45.684 30.24 46.98 27.936V27.252H43.536C43.776 27.036 44.004 26.808 44.22 26.568L43.452 26.16ZM42.996 33.66L42.228 34.02C42.672 34.452 43.092 34.944 43.5 35.484C42.144 35.94 40.524 36.168 38.652 36.18L39 37.008C43.656 36.9 46.824 35.436 48.528 32.604V31.92H45.24C45.576 31.668 45.876 31.392 46.164 31.104L45.42 30.696C44.172 32.016 42.24 32.82 39.624 33.084L40.14 33.852C41.592 33.6 42.84 33.216 43.896 32.712H47.448C46.68 33.768 45.636 34.596 44.304 35.172C43.896 34.632 43.452 34.128 42.996 33.66ZM55.248 30.192V35.832C55.248 36.132 55.08 36.288 54.756 36.288C54.084 36.288 53.448 36.264 52.86 36.216L53.1 37.056C53.64 37.08 54.276 37.104 54.996 37.104C55.74 37.104 56.124 36.732 56.124 35.988V30.624C57.528 29.712 58.788 28.752 59.904 27.744V26.904H50.832V27.744H58.728C57.624 28.68 56.472 29.496 55.248 30.192Z" fill="#C7C5C2"/>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

25
src/pages/Coupons/Qrcode/Qrcode.js

@ -1,25 +0,0 @@
import QRCode from "qrcodejs2";
import { useRef, useEffect } from "react";
const Qrcode = ({ size, text, className }) => {
const ref = useRef();
useEffect(() => {
const domEl = ref.current;
domEl.innerHTML = "";
new QRCode(domEl, {
width: size,
height: size,
text,
colorDark: "#000",
colorLight: "#fff",
});
}, [ref]);
return (
<div
className={className}
ref={ref}
style={{ width: size + "px", height: size + "px" }}
></div>
);
};
export default Qrcode;

0
src/pages/Coupons/Qrcode/Qrcode.scss

59
src/pages/Coupons/ScanModal/ScanModal.js

@ -1,59 +0,0 @@
import "./ScanModal.scss";
import Modal from "react-modal";
import { useState, useEffect } from "react";
import { Html5Qrcode } from "html5-qrcode";
const ScanModal = ({ onBack, onCode }) => {
const [loaded, setLoaded] = useState(false);
const toast = (text) =>
window.weui.toast(text, {
className: "toast",
});
useEffect(() => {
if (loaded) {
const dom = document.getElementById("qrcode-scaner");
const html5QrCode = new Html5Qrcode("qrcode-scaner");
html5QrCode
.start(
{ facingMode: "environment" },
{ fps: 10, qrbox: { width: 280, height: 280 } },
(code) => {
html5QrCode.stop();
onCode && onCode(code);
}
)
.catch(() => {
toast("启动二维码扫描失败");
onBack && onBack();
});
return () => {
html5QrCode.stop();
};
}
}, [loaded]);
return (
<Modal
onAfterOpen={() => setLoaded(true)}
isOpen
ariaHideApp={false}
className="ScanModal"
>
<div className="border">
<div className="scaner"></div>
<div
className="container"
id="qrcode-scaner"
width="280px"
height="280px"
></div>
</div>
<div className="btn" onClick={() => onBack && onBack()}>
手动输入券码
</div>
<div className="back" onClick={() => onBack && onBack()}></div>
</Modal>
);
};
export default ScanModal;

72
src/pages/Coupons/ScanModal/ScanModal.scss

@ -1,72 +0,0 @@
.ScanModal {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #353230;
overflow: hidden;
.back {
position: absolute;
bottom: 48px;
left: 0;
right: 0;
margin: auto;
width: 48px;
height: 48px;
background: center / cover no-repeat url(./close.svg);
}
.btn {
position: absolute;
height: 56px;
left: 29px;
right: 28px;
bottom: 130px;
background: #ffffff;
border-radius: 10px;
font-weight: 600;
font-size: 16px;
line-height: 22px;
color: #437af7;
display: flex;
justify-content: center;
align-items: center;
}
.border {
position: absolute;
top: 94px;
left: 0;
right: 0;
margin: auto;
width: 320px;
height: 320px;
background: center / cover no-repeat url(./border.svg);
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
@keyframes scaner {
0% {
top: -74px;
}
100% {
top: 320px;
}
}
.scaner {
position: absolute;
left: 0;
right: 0;
width: 320px;
height: 74px;
background: center / cover no-repeat url(./scaner.svg);
animation: 1s scaner infinite ease-in-out;
z-index: 2;
}
.container {
width: 280px;
height: 280px;
overflow: hidden;
}
}
}

4
src/pages/Coupons/ScanModal/back.svg

@ -1,4 +0,0 @@
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="60" height="60" rx="10" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.0976 18.0794C35.7903 18.6855 35.8605 19.7385 35.2544 20.4312L26.8813 30.0003L35.2544 39.5695C35.8605 40.2622 35.7903 41.3152 35.0976 41.9213C34.4048 42.5274 33.3519 42.4573 32.7458 41.7645L23.7966 31.5369C23.0268 30.6571 23.0268 29.3436 23.7966 28.4638L32.7458 18.2362C33.3519 17.5434 34.4048 17.4733 35.0976 18.0794Z" fill="#353230"/>
</svg>

Before

Width:  |  Height:  |  Size: 544 B

3
src/pages/Coupons/ScanModal/border.svg

@ -1,3 +0,0 @@
<svg width="320" height="320" viewBox="0 0 320 320" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.86102e-06 0H30V4H4L4 30H2.86102e-06V0ZM320 0V30H316V4L290 4V0H320ZM290 320H320V290H316V316H290V320ZM0 320V290H4L4 316H30V320H0Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 303 B

4
src/pages/Coupons/ScanModal/close.svg

@ -1,4 +0,0 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.0001 22.5858L28.9501 17.6357C29.3406 17.2453 29.9737 17.2453 30.3641 17.6357C30.7546 18.0262 30.7546 18.6593 30.3641 19.0497L25.4141 23.9998L30.364 28.9497C30.7545 29.3402 30.7545 29.9733 30.364 30.3637C29.9736 30.7542 29.3405 30.7542 28.95 30.3637L24.0001 25.4138L19.0502 30.3636C18.6597 30.7541 18.0267 30.7541 17.6362 30.3636C17.2457 29.9732 17.2457 29.3401 17.6362 28.9496L22.5861 23.9998L17.6362 19.0497C17.2457 18.6592 17.2457 18.0262 17.6362 17.6357C18.0267 17.2453 18.6597 17.2453 19.0502 17.6357L24.0001 22.5858Z" fill="white"/>
<rect x="1" y="1" width="46" height="46" rx="23" stroke="white" stroke-opacity="0.4" stroke-width="2"/>
</svg>

Before

Width:  |  Height:  |  Size: 758 B

9
src/pages/Coupons/ScanModal/scaner.svg

@ -1,9 +0,0 @@
<svg width="320" height="74" viewBox="0 0 320 74" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="320" height="74" fill="url(#paint0_linear_1115_21600)"/>
<defs>
<linearGradient id="paint0_linear_1115_21600" x1="160" y1="0" x2="160" y2="74" gradientUnits="userSpaceOnUse">
<stop stop-color="#437AF7" stop-opacity="0"/>
<stop offset="1" stop-color="#437AF7" stop-opacity="0.7"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 424 B

130
src/pages/Coupons/ShopManager/ShopManager.js

@ -1,130 +0,0 @@
import "./ShopManager.scss";
import noDataPic from "./noDataPic.png";
import { post } from "../../../js/helpers/data-helper";
import InfiniteScroll from "react-infinite-scroller";
import { useState, useRef, useCallback } from "react";
import ListEnd from "../ListEnd/ListEnd";
import ApplyModal from "../ApplyModal/ApplyModal";
import WriteOffModal from "../WriteOffModal/WriteOffModal";
const stateMap = {
0: "待审核",
1: "已发布",
2: "已拒绝",
};
const ShopManager = ({ memberID }) => {
const [list, setList] = useState([]);
const [nextPageIndex, setNextPageIndex] = useState(1);
const [loading, setLoading] = useState(false);
const [showApplyModal, setShowApplyModal] = useState(false);
const [showWriteOffModal, setShowWriteOffModal] = useState(false);
const listRef = useRef();
const showNoData = !loading && list.length === 0;
const showListEnd = !loading && list.length > 0;
const hasMore = nextPageIndex !== null;
const loadMore = useCallback(async () => {
if (loading || nextPageIndex === null) return;
setLoading(true);
try {
const { code, data, msg } = await post("/api/coupon/ApplyedList", {
paging: 1,
pageIndex: nextPageIndex,
pageSize: 10,
memberID,
});
if (code === "200") {
setList([...list, ...data.list]);
setNextPageIndex(
nextPageIndex + 1 > data.allPage ? null : nextPageIndex + 1
);
} else {
setNextPageIndex(null);
window.weui.toast(msg, {
className: "toast",
});
}
} catch (error) {
setNextPageIndex(null);
} finally {
setLoading(false);
}
}, [list, loading, nextPageIndex]);
return (
<div className="ShopManager">
<div className="btns">
<div className="btn" onClick={() => setShowApplyModal(true)}>
申请
</div>
<div className="btn" onClick={() => setShowWriteOffModal(true)}>
核销
</div>
</div>
<div className="list-container" ref={listRef}>
<InfiniteScroll
loadMore={loadMore}
hasMore={hasMore}
useWindow={false}
getScrollParent={() => listRef && listRef.current}
>
{showNoData && (
<>
<img className="noDataPic" src={noDataPic}></img>
<div className="noDataText">
当前您还未发布礼券请先申请等待后台申请通过后刷新页面显示
</div>
</>
)}
{list !== null &&
list.map((coupon) => (
<div key={coupon.code} className={`coupon status${coupon.state}`}>
<div className="row">
<div className="r1">礼券标题</div>
<div className="r2">{coupon.title}</div>
</div>
<div className="row">
<div className="r1">发放数量</div>
<div className="r2">{coupon.totalCount}</div>
</div>
{coupon.state === 1 && (
<div className="row">
<div className="r1">已领取数</div>
<div className="r2">{coupon.received}</div>
</div>
)}
<div className="row">
<div className="r1">使用期限</div>
<div className="r2">
{coupon.beginTime}{coupon.endTime}
</div>
</div>
<div className="status">{stateMap[coupon.state]}</div>
</div>
))}
{showListEnd && <ListEnd></ListEnd>}
</InfiniteScroll>
</div>
{showApplyModal && (
<ApplyModal
onBack={() => {
setShowApplyModal(false);
setList([]);
setNextPageIndex(1);
}}
memberID={memberID}
></ApplyModal>
)}
{showWriteOffModal && (
<WriteOffModal
onBack={() => setShowWriteOffModal(false)}
memberID={memberID}
></WriteOffModal>
)}
</div>
);
};
export default ShopManager;

132
src/pages/Coupons/ShopManager/ShopManager.scss

@ -1,132 +0,0 @@
.ShopManager {
flex: 1;
display: flex;
flex-direction: column;
background: linear-gradient(
180deg,
#f2f2f2 0%,
rgba(249, 249, 249, 0) 20.18%
);
border-radius: 18px 18px 0 0;
padding-top: 10px;
width: 100vw;
align-items: center;
overflow: hidden;
.btns {
display: flex;
margin-bottom: 10px;
width: calc(100vw - 20px);
.btn {
display: flex;
flex: 1;
font-weight: 400;
font-size: 17px;
color: #353230;
height: 48px;
background: #ffffff;
border-radius: 10px;
justify-content: center;
align-items: center;
}
.btn + .btn {
margin-left: 9px;
}
}
.noDataPic {
margin-top: 64px;
width: 250px;
height: 250px;
}
.noDataText {
margin: 0 43px;
font-weight: 400;
font-size: 17px;
line-height: 22px;
text-align: center;
color: #68655e;
}
.list-container {
flex: 1;
overflow-x: hidden;
overflow-y: scroll;
padding-top: 16px;
text-align: center;
scroll-behavior: smooth;
&::-webkit-scrollbar {
display: none;
}
.coupon {
position: relative;
width: calc(100vw - 20px);
border-radius: 16px;
overflow: hidden;
padding: 24px;
.row {
height: 50px;
border-bottom: 1px solid rgba(240, 240, 240, 0.4);
.r1 {
font-weight: 400;
font-size: 15px;
line-height: 20px;
color: #9d988f;
text-align: left;
}
.r2 {
font-weight: 600;
font-size: 17px;
line-height: 22px;
color: #353230;
margin-top: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
}
.row + .row {
margin-top: 10px;
}
.status {
position: absolute;
width: 72px;
height: 32px;
top: 0;
right: 0;
display: flex;
font-weight: 600;
font-size: 13px;
line-height: 18px;
color: #ffffff;
border-radius: 0px 0px 0px 14px;
justify-content: center;
align-items: center;
}
&.status0 {
background: linear-gradient(241.87deg, #ffffff 2.89%, #fffbf8 97.29%);
.status {
background: linear-gradient(90deg, #ecd3a6 5.56%, #dbb979 100%);
box-shadow: 4px 6px 18px rgba(214, 162, 101, 0.3);
}
}
&.status1 {
background: linear-gradient(241.87deg, #ffffff 2.89%, #fefff8 97.29%);
.status {
background: linear-gradient(270.4deg, #71c956 0.27%, #7add83 87.87%);
box-shadow: 4px 6px 18px rgba(151, 214, 101, 0.3);
}
}
&.status2 {
background: linear-gradient(241.87deg, #ffffff 2.89%, #fffafa 97.29%);
.status {
background: linear-gradient(270deg, #e76464 3.47%, #ffa0a0 90.28%);
box-shadow: 4px 6px 18px rgba(214, 101, 122, 0.3);
}
}
}
.coupon + .coupon {
margin-top: 8px;
}
}
}

BIN
src/pages/Coupons/ShopManager/noDataPic.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

26
src/pages/Coupons/ShopTabs/ShopTabs.js

@ -1,26 +0,0 @@
import "./ShopTabs.scss";
import card from "./card.svg";
import cardActive from "./cardActive.svg";
import ticket from "./ticket.svg";
import ticketActive from "./ticketActive.svg";
const ShopTabs = ({ showCoupons, setShowCoupons }) => {
return (
<div className="ShopTabs">
<div
className={`tab ${showCoupons ? "active" : ""}`}
onClick={() => setShowCoupons(true)}
>
<img src={showCoupons ? cardActive : card}></img>
我的礼包
</div>
<div
className={`tab ${!showCoupons ? "active" : ""}`}
onClick={() => setShowCoupons(false)}
>
<img src={!showCoupons ? ticketActive : ticket}></img>
券管家
</div>
</div>
);
};
export default ShopTabs;

32
src/pages/Coupons/ShopTabs/ShopTabs.scss

@ -1,32 +0,0 @@
.ShopTabs {
display: flex;
width: calc(100vw - 20px);
height: 56px;
background: #ffffff;
border-radius: 12px;
padding: 4px;
margin-bottom: 16px;
margin-top: 10px;
.tab {
display: flex;
flex: 1;
height: 48px;
font-weight: 500;
font-size: 16px;
line-height: 22px;
color: #68655e;
justify-content: center;
align-items: center;
border-radius: 8px;
img {
width: 20px;
height: 20px;
margin-right: 8px;
}
&.active {
color: #ffffff;
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%);
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2);
}
}
}

3
src/pages/Coupons/ShopTabs/card.svg

@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 5.83333H17.5C17.721 5.83333 17.9329 5.92113 18.0892 6.07741C18.2455 6.23369 18.3333 6.44565 18.3333 6.66667V16.6667C18.3333 16.8877 18.2455 17.0996 18.0892 17.2559C17.9329 17.4122 17.721 17.5 17.5 17.5H2.49996C2.27895 17.5 2.06698 17.4122 1.9107 17.2559C1.75442 17.0996 1.66663 16.8877 1.66663 16.6667V3.33333C1.66663 3.11232 1.75442 2.90036 1.9107 2.74408C2.06698 2.5878 2.27895 2.5 2.49996 2.5H15V5.83333ZM3.33329 7.5V15.8333H16.6666V7.5H3.33329ZM3.33329 4.16667V5.83333H13.3333V4.16667H3.33329ZM12.5 10.8333H15V12.5H12.5V10.8333Z" fill="#9D988F"/>
</svg>

Before

Width:  |  Height:  |  Size: 667 B

3
src/pages/Coupons/ShopTabs/cardActive.svg

@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 5.83333H17.5C17.721 5.83333 17.9329 5.92113 18.0892 6.07741C18.2455 6.23369 18.3333 6.44565 18.3333 6.66667V16.6667C18.3333 16.8877 18.2455 17.0996 18.0892 17.2559C17.9329 17.4122 17.721 17.5 17.5 17.5H2.49996C2.27895 17.5 2.06698 17.4122 1.9107 17.2559C1.75442 17.0996 1.66663 16.8877 1.66663 16.6667V3.33333C1.66663 3.11232 1.75442 2.90036 1.9107 2.74408C2.06698 2.5878 2.27895 2.5 2.49996 2.5H15V5.83333ZM3.33329 7.5V15.8333H16.6666V7.5H3.33329ZM3.33329 4.16667V5.83333H13.3333V4.16667H3.33329ZM12.5 10.8333H15V12.5H12.5V10.8333Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 665 B

3
src/pages/Coupons/ShopTabs/ticket.svg

@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.6667 1.66699C17.1267 1.66699 17.5 2.04033 17.5 2.50033V5.63116L15.8333 7.29783V3.33366H4.16667V16.667H15.8333V14.3687L17.5 12.702V17.5003C17.5 17.9603 17.1267 18.3337 16.6667 18.3337H3.33333C2.87333 18.3337 2.5 17.9603 2.5 17.5003V2.50033C2.5 2.04033 2.87333 1.66699 3.33333 1.66699H16.6667ZM18.1483 7.34033L19.3267 8.51866L12.845 15.0003L11.665 14.9987L11.6667 13.822L18.1483 7.34033ZM10.8333 10.0003V11.667H6.66667V10.0003H10.8333ZM13.3333 6.66699V8.33366H6.66667V6.66699H13.3333Z" fill="#9D988F"/>
</svg>

Before

Width:  |  Height:  |  Size: 617 B

3
src/pages/Coupons/ShopTabs/ticketActive.svg

@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.6667 1.66699C17.1267 1.66699 17.5 2.04033 17.5 2.50033V5.63116L15.8333 7.29783V3.33366H4.16667V16.667H15.8333V14.3687L17.5 12.702V17.5003C17.5 17.9603 17.1267 18.3337 16.6667 18.3337H3.33333C2.87333 18.3337 2.5 17.9603 2.5 17.5003V2.50033C2.5 2.04033 2.87333 1.66699 3.33333 1.66699H16.6667ZM18.1483 7.34033L19.3267 8.51866L12.845 15.0003L11.665 14.9987L11.6667 13.822L18.1483 7.34033ZM10.8333 10.0003V11.667H6.66667V10.0003H10.8333ZM13.3333 6.66699V8.33366H6.66667V6.66699H13.3333Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 615 B

148
src/pages/Coupons/WriteOffModal/WriteOffModal.js

@ -1,148 +0,0 @@
import "./WriteOffModal.scss";
import Modal from "react-modal";
import { useState, useRef, useEffect, useCallback } from "react";
import { post } from "../../../js/helpers/data-helper";
import ScanModal from "../ScanModal/ScanModal";
import InfiniteScroll from "react-infinite-scroller";
import ListEnd from "../ListEnd/ListEnd";
const WriteOffModal = ({ onBack, memberID }) => {
const [orderNo, setOrderNo] = useState("");
const [showScanModal, setShowScanModal] = useState(false);
const [list, setList] = useState([]);
const [nextPageIndex, setNextPageIndex] = useState(1);
const [loading, setLoading] = useState(false);
const hasMore = nextPageIndex !== null;
const [allCount, setAllCount] = useState(0);
const [month, setMonth] = useState(new Date().toJSON().slice(0, 7));
const showListEnd = list !== null && list.length > 0;
const listRef = useRef();
const loadMore = useCallback(async () => {
if (loading || nextPageIndex === null) return;
setLoading(true);
try {
const { code, data, msg } = await post("/api/Coupon/WriteOffHis", {
paging: 1,
pageIndex: nextPageIndex,
pageSize: 10,
memberID,
month,
});
if (code === "200") {
setList([...list, ...data.list]);
setNextPageIndex(
nextPageIndex + 1 > data.allPage ? null : nextPageIndex + 1
);
setAllCount(data.allCount);
} else {
setNextPageIndex(null);
window.weui.toast(msg, {
className: "toast",
});
}
} catch (error) {
setNextPageIndex(null);
} finally {
setLoading(false);
}
}, [list, loading, nextPageIndex]);
useEffect(() => {
if (listRef.current) listRef.current.scrollTop = 0;
setNextPageIndex(1);
setAllCount(0);
setList([]);
}, [month]);
const toast = (text) =>
window.weui.toast(text, {
className: "toast",
});
const writeOff = async (orderNo) => {
try {
const { code, msg } = await post("/api/coupon/writeoffcoupon", {
orderNo,
memberID,
});
if (code === "200") {
toast("核销成功");
return true;
} else {
toast(msg);
return false;
}
} catch (error) {
return false;
}
};
const submitFromBtn = async (orderNo) => {
const result = await writeOff(orderNo);
if (result) {
setOrderNo("");
}
};
const handleCode = async (orderNo) => {
await writeOff(orderNo);
setShowScanModal(false);
};
return (
<Modal isOpen ariaHideApp={false} className="WriteOffModal">
<div className="back" onClick={() => onBack && onBack()}></div>
<div className="title">核销</div>
<div className="search">
<div className="icon"></div>
<input
type="number"
value={orderNo}
onChange={(e) => setOrderNo(e.target.value)}
></input>
</div>
<div className="scan" onClick={() => setShowScanModal(true)}></div>
{!!orderNo && (
<div className="btn" onClick={() => submitFromBtn(orderNo)}>
确认核销
</div>
)}
<div className="bar">
<div>已核销{allCount}</div>
<input
type="month"
value={month}
onChange={(e) => setMonth(e.target.value)}
></input>
</div>
<div className="list-container" ref={listRef}>
<InfiniteScroll
pageStart={0}
loadMore={loadMore}
hasMore={hasMore}
useWindow={false}
getScrollParent={() => listRef && listRef.current}
>
{list !== null &&
list.map((coupon) => (
<div key={coupon.orderNo} className="coupon">
<div className="block">
<div className="r1">礼券标题</div>
<div className="r2">{coupon.title}</div>
</div>
<div className="block">
<div className="r1">核销时间</div>
<div className="r2">{coupon.writeOffTime}</div>
</div>
</div>
))}
{showListEnd && <ListEnd></ListEnd>}
</InfiniteScroll>
</div>
{showScanModal && (
<ScanModal
onBack={() => setShowScanModal(false)}
onCode={handleCode}
></ScanModal>
)}
</Modal>
);
};
export default WriteOffModal;

162
src/pages/Coupons/WriteOffModal/WriteOffModal.scss

@ -1,162 +0,0 @@
.WriteOffModal {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #f6f6f6;
overflow: hidden;
.back {
position: absolute;
top: 10px;
left: 10px;
width: 60px;
height: 60px;
background: center / cover no-repeat url(./back.svg);
}
.title {
position: absolute;
top: 28px;
right: 16px;
font-style: normal;
font-weight: 600;
font-size: 20px;
line-height: 25px;
color: #000000;
}
.search {
position: absolute;
top: 94px;
left: 10px;
right: 108px;
background: #ffffff;
border-radius: 10px;
height: 60px;
overflow: hidden;
.icon {
position: absolute;
top: 14px;
left: 14px;
width: 47px;
height: 32px;
background: center / cover no-repeat url(./search.svg);
}
input {
position: absolute;
left: 75px;
right: 0;
top: 0;
bottom: 0;
margin: auto;
font-weight: 600;
font-size: 16px;
line-height: 22px;
border: none;
outline: none;
color: #353230;
&::placeholder {
color: #dad7d1;
}
}
}
.scan {
position: absolute;
top: 94px;
right: 16px;
width: 80px;
height: 60px;
background: center / cover no-repeat url(./scan.svg);
}
.btn {
position: absolute;
height: 56px;
left: 29px;
right: 28px;
bottom: 126px;
font-weight: 600;
font-size: 16px;
line-height: 22px;
text-align: center;
color: #ffffff;
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%);
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2);
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
z-index: 1;
}
.bar {
position: absolute;
top: 178px;
left: 24px;
right: 24px;
height: 20px;
font-weight: 600;
font-size: 15px;
line-height: 20px;
color: #353230;
display: flex;
justify-content: space-between;
input {
outline: none;
border: none;
background: none;
}
&::after {
content: "";
position: absolute;
left: -8px;
bottom: -8px;
right: -5px;
height: 1px;
background: #dad7d1;
opacity: 0.6;
}
}
.list-container {
position: absolute;
top: 206px;
bottom: 0px;
left: 10px;
right: 10px;
overflow-x: hidden;
overflow-y: scroll;
text-align: center;
&::-webkit-scrollbar {
display: none;
}
.coupon {
height: 170px;
background: #ffffff;
border-radius: 16px;
padding: 24px;
margin-top: 10px;
.block {
height: 54px;
border-bottom: 1px solid rgba(240, 240, 240, 0.4);
text-align: left;
.r1 {
font-weight: 400;
font-size: 15px;
line-height: 20px;
color: #9d988f;
}
.r2 {
font-style: normal;
font-weight: 600;
font-size: 17px;
line-height: 22px;
color: #353230;
margin-top: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.block + .block {
margin-top: 16px;
}
}
}
}

4
src/pages/Coupons/WriteOffModal/back.svg

@ -1,4 +0,0 @@
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="60" height="60" rx="10" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.0976 18.0794C35.7903 18.6855 35.8605 19.7385 35.2544 20.4312L26.8813 30.0003L35.2544 39.5695C35.8605 40.2622 35.7903 41.3152 35.0976 41.9213C34.4048 42.5274 33.3519 42.4573 32.7458 41.7645L23.7966 31.5369C23.0268 30.6571 23.0268 29.3436 23.7966 28.4638L32.7458 18.2362C33.3519 17.5434 34.4048 17.4733 35.0976 18.0794Z" fill="#353230"/>
</svg>

Before

Width:  |  Height:  |  Size: 544 B

5
src/pages/Coupons/WriteOffModal/scan.svg

@ -1,5 +0,0 @@
<svg width="80" height="60" viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="80" height="60" rx="10" fill="white"/>
<path d="M49 24V29H31V24H33V27H47V24H49ZM31 19H49V21H31V19ZM49 16H47V13H33V16H31V11H49V16Z" fill="#353230"/>
<path d="M26.992 38.964V40.188H31.804V42.984H27.316V44.184H31.804V47.148H26.776V48.372H31.804V48.96H33.076V38.964H26.992ZM26.596 42.864C26.188 43.056 25.78 43.236 25.36 43.404V41.412H26.536V40.224H25.36V38.16H24.1V40.224H22.612V41.412H24.1V43.836C23.56 44.004 23.008 44.136 22.456 44.244L22.756 45.444C23.212 45.324 23.656 45.192 24.1 45.048V47.544C24.1 47.832 23.968 47.976 23.704 47.976C23.44 47.976 23.152 47.952 22.864 47.904L23.152 49.116H24.136C24.952 49.116 25.36 48.696 25.36 47.856V44.616C25.78 44.448 26.188 44.28 26.596 44.112V42.864ZM34.54 42.972V44.22H45.448V42.972H34.54ZM50.992 38.964V40.188H55.804V42.984H51.316V44.184H55.804V47.148H50.776V48.372H55.804V48.96H57.076V38.964H50.992ZM50.596 42.864C50.188 43.056 49.78 43.236 49.36 43.404V41.412H50.536V40.224H49.36V38.16H48.1V40.224H46.612V41.412H48.1V43.836C47.56 44.004 47.008 44.136 46.456 44.244L46.756 45.444C47.212 45.324 47.656 45.192 48.1 45.048V47.544C48.1 47.832 47.968 47.976 47.704 47.976C47.44 47.976 47.152 47.952 46.864 47.904L47.152 49.116H48.136C48.952 49.116 49.36 48.696 49.36 47.856V44.616C49.78 44.448 50.188 44.28 50.596 44.112V42.864Z" fill="#9D988F"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

4
src/pages/Coupons/WriteOffModal/search.svg

@ -1,4 +0,0 @@
<svg width="47" height="32" viewBox="0 0 47 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.6667 2.66666C21.2907 2.66666 26.6667 8.04266 26.6667 14.6667C26.6667 21.2907 21.2907 26.6667 14.6667 26.6667C8.04269 26.6667 2.66669 21.2907 2.66669 14.6667C2.66669 8.04266 8.04269 2.66666 14.6667 2.66666ZM14.6667 24C19.8227 24 24 19.8227 24 14.6667C24 9.50932 19.8227 5.33332 14.6667 5.33332C9.50935 5.33332 5.33335 9.50932 5.33335 14.6667C5.33335 19.8227 9.50935 24 14.6667 24ZM25.98 24.0947L29.752 27.8653L27.8654 29.752L24.0947 25.98L25.98 24.0947V24.0947Z" fill="#9D988F"/>
<rect x="46" y="8" width="1" height="16" fill="#DAD7D1"/>
</svg>

Before

Width:  |  Height:  |  Size: 653 B

BIN
src/pages/Coupons/notMember.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

241
src/pages/Index/Index.js

@ -1,7 +1,7 @@
import React, { useState, useEffect, useReducer, useRef } from "react"; import React, { useState, useEffect, useReducer, useRef } from "react";
import Qmmap from "qmmap"; import Qmmap from "qmmap";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { getMallInfo, post } from "../../js/helpers/data-helper";
import { getMallInfo } from "../../js/helpers/data-helper";
import "./Index.scss"; import "./Index.scss";
import Floors from "../../components/Floors/Floors"; import Floors from "../../components/Floors/Floors";
import HeadBar from "../../components/HeadBar/HeadBar"; import HeadBar from "../../components/HeadBar/HeadBar";
@ -17,12 +17,6 @@ import DefaultPopup, {
} from "../../components/DefaultPopup/DefaultPopup"; } from "../../components/DefaultPopup/DefaultPopup";
import More from "../../components/More/More"; import More from "../../components/More/More";
import arpng from "./ar.png"; import arpng from "./ar.png";
import Car from "../Car/Car";
import axios from "axios";
import Activities from "../Activities/Activities";
import Coupons from "../Coupons/Coupons";
import TabMap from "./tabs/Tabs";
import ShopCoupons from "../ShopCoupons/ShopCoupons";
export const MallCode = React.createContext(null); export const MallCode = React.createContext(null);
// const vConsole = new window.VConsole(); // const vConsole = new window.VConsole();
@ -74,26 +68,7 @@ const Index = () => {
const [ARshop, setARShop] = useState(null); const [ARshop, setARShop] = useState(null);
const [isTyping, setIsTyping] = useState(null); const [isTyping, setIsTyping] = useState(null);
const [showFindCar, setShowFindCar] = useState(false); const [showFindCar, setShowFindCar] = useState(false);
const [showActivities, setShowActivities] = useState(false);
const [showCoupon, setShowCoupon] = useState(false);
const [tab, setTab] = useState("地图");
const [couponShop, setCouponShop] = useState(null);
const [initActivity, setInitActivity] = useState(null);
const showShopCoupons = !!couponShop;
const hasTab = mall && mall.menu.length > 1;
const setStatistics = mall
? ({ userId, navType, pointType, objectCode, objectName, floorName }) =>
axios.post(mall.baseUrl + "/Api/Statistics/AddGuideRecord", {
mallCode: mall.code,
userId,
navType,
pointType,
objectCode,
objectName,
floorName,
})
: undefined;
useEffect(() => { useEffect(() => {
if (shop) { if (shop) {
const e = shop.houseNum const e = shop.houseNum
@ -131,17 +106,6 @@ const Index = () => {
} }
if (!endId) return; if (!endId) return;
if (endId === "findcar") return setShowFindCar(true); if (endId === "findcar") return setShowFindCar(true);
if (endId === "me") return setTab("我的");
if (endId.startsWith && endId.startsWith("activities")) {
setTab("活动");
if (endId === "activities") return;
else {
const code = endId.replace("activities", "");
const activity = mall.activities.find((act) => act.code === code);
if (activity) setInitActivity(activity);
return;
}
}
if (mall.mcShopIDHouseNumMap && mall.mcShopIDHouseNumMap[endId]) if (mall.mcShopIDHouseNumMap && mall.mcShopIDHouseNumMap[endId])
endId = mall.mcShopIDHouseNumMap[endId]; endId = mall.mcShopIDHouseNumMap[endId];
@ -430,21 +394,12 @@ const Index = () => {
const isShop = "intro" in end; const isShop = "intro" in end;
const isP = end.isP; const isP = end.isP;
const isDevice = end.isDevice; const isDevice = end.isDevice;
setStatistics({
userId: openid,
navType: 2,
pointType: isShop || isDevice ? "1" : isP ? "3" : "2",
objectCode: isShop ? end.code : isP ? end.houseNum : end.Type,
objectName: end.name,
floorName: end.floorName || mall.floors[end.floorOrder][1],
});
} }
} }
}, [navigation]); }, [navigation]);
useEffect(() => { useEffect(() => {
if (mallInfo) { if (mallInfo) {
setTab(mall.menu[0].name);
loadMap(); loadMap();
} }
}, [mallInfo]); }, [mallInfo]);
@ -465,38 +420,11 @@ const Index = () => {
} }
}, [map]); }, [map]);
useEffect(() => {
switch (tab) {
case "活动":
setShowFindCar(false);
setShowCoupon(false);
setShowActivities(true);
break;
case "地图":
setShowFindCar(false);
setShowCoupon(false);
setShowActivities(false);
break;
case "寻车":
setShowCoupon(false);
setShowActivities(false);
setShowFindCar(true);
break;
case "我的":
setShowActivities(false);
setShowFindCar(false);
setShowCoupon(true);
break;
default:
break;
}
}, [tab]);
return ( return (
<MallCode.Provider value={mallCode}> <MallCode.Provider value={mallCode}>
<div <div
className={ className={
`index ${hasTab ? "hasTab" : ""}` +
`index` +
(showDefaultPopup (showDefaultPopup
? defaultPopupState === DefaultPopupStates.init ? defaultPopupState === DefaultPopupStates.init
? " t1" ? " t1"
@ -506,127 +434,6 @@ const Index = () => {
: "") : "")
} }
> >
{showShopCoupons && (
<Modal
isOpen={showShopCoupons}
ariaHideApp={false}
className="shopcoupon-wrapper"
>
<ShopCoupons
memberID={memberID}
mall={mall}
onBack={() => setCouponShop(null)}
shop={couponShop}
></ShopCoupons>
</Modal>
)}
{showActivities && (
<Modal
isOpen={showActivities}
style={{
overlay: {
background: "transparent",
pointerEvents: "none",
},
}}
ariaHideApp={false}
className="activity-modal"
>
<Activities
initActivity={initActivity}
setInitActivity={setInitActivity}
memberID={memberID}
mall={mall}
onBack={() => setTab("地图")}
facilities={facilities}
onGo={(fac) => {
setTab("地图");
map && map.focusFacilityById(fac.id);
}}
></Activities>
</Modal>
)}
{showFindCar && mall && (
<Modal
isOpen={!!(showFindCar && mall)}
style={{
overlay: {
background: "transparent",
pointerEvents: "none",
},
}}
ariaHideApp={false}
className="car-wrapper"
>
<Car
hasReverse={
mall.menu.find(({ name }) => name === "寻车")?.specialType === 1
}
plate={plate}
lots={mall.lots}
onBack={() => setTab("地图")}
onLot={(e) => {
setDoFocus(2);
map.focusPByHouseNum(e);
setTab("地图");
}}
></Car>
</Modal>
)}
{showARPrompt && (
<Modal
isOpen={showARPrompt}
style={{
overlay: { zIndex: 10001, background: `rgba(0, 0, 0, 0.6)` },
}}
ariaHideApp={false}
className="prompt"
>
<img className="icon" src={arpng} />
<div className="title">即将离开模拟导航 进入AR导航</div>
<div className="meta">是否要继续</div>
<div className="btns">
<div className="btn2" onClick={() => setShowARPrompt(false)}>
取消
</div>
<div
className="btn1"
onClick={() => {
if (openid && openid !== "null") {
const isShop = "intro" in ARshop;
const isP = ARshop.isP;
const isDevice = ARshop.isDevice;
setStatistics({
userId: openid,
navType: 1,
pointType: isShop || isDevice ? "1" : isP ? "3" : "2",
objectCode: isShop
? ARshop.code
: isP
? ARshop.houseNum
: ARshop.Type,
objectName: ARshop.name,
floorName:
ARshop.floorName || mall.floors[ARshop.floorOrder][1],
});
}
setShowARPrompt(false);
window.wx.miniProgram.redirectTo({
url: `/pages/index/index?e=${
ARshop.houseNum
? ARshop.houseNum
: ARshop.isDevice
? `${ARshop.floorOrder}_${ARshop.navPoint}_${ARshop.name}`
: encodeURIComponent(ARshop.id)
}&searchType=${searchType}`,
});
}}
>
确定
</div>
</div>
</Modal>
)}
{!online && ( {!online && (
<Modal <Modal
isOpen={!online} isOpen={!online}
@ -637,25 +444,9 @@ const Index = () => {
<img className="img" src={offline}></img> <img className="img" src={offline}></img>
</Modal> </Modal>
)} )}
<Coupons
show={showCoupon}
memberID={memberID}
isShop={isShop}
></Coupons>
<div className={"hud " + (isTyping ? "bg" : "")}> <div className={"hud " + (isTyping ? "bg" : "")}>
{!(start || end) && ( {!(start || end) && (
<div
className="top-left"
onClick={async () => {
const { msg } = await post("/Api/Operation/GetUserAward", {
memberID,
poiCode: "97be8faa6ab34e08864bf2b1c231e6ab",
});
window.weui.toast(msg, {
className: "toast",
});
}}
>
<div className="top-left">
<img alt="图左" src={pos} className="left"></img> <img alt="图左" src={pos} className="left"></img>
<span style={{ color: "#7A7E8D" }}>{mall && mall.city}</span> <span style={{ color: "#7A7E8D" }}>{mall && mall.city}</span>
<div className="border"></div> <div className="border"></div>
@ -756,7 +547,6 @@ const Index = () => {
defaultPopup={ defaultPopup={
showDefaultPopup && ( showDefaultPopup && (
<DefaultPopup <DefaultPopup
hasTab={hasTab}
state={defaultPopupState} state={defaultPopupState}
setState={setDefaultPopupState} setState={setDefaultPopupState}
facilities={facilities} facilities={facilities}
@ -799,9 +589,6 @@ const Index = () => {
sceneIndex={sceneIndex} sceneIndex={sceneIndex}
setSceneIndex={setSceneIndex} setSceneIndex={setSceneIndex}
isNavEnd={isNavEnd} isNavEnd={isNavEnd}
onActivity={() => {
setShowActivities(true);
}}
mall={mall} mall={mall}
hasCoupon={hasCoupon} hasCoupon={hasCoupon}
></Floors> ></Floors>
@ -823,9 +610,6 @@ const Index = () => {
setARShop(shop); setARShop(shop);
setShowARPrompt(true); setShowARPrompt(true);
}} }}
onClickCoupon={() => {
setCouponShop(shop);
}}
></Popup> ></Popup>
{showNav && ( {showNav && (
<NavBottom <NavBottom
@ -867,25 +651,6 @@ const Index = () => {
开始导航 开始导航
</div> </div>
)} )}
{mall && mall.menu.length > 1 && (
<div className="tab-bar">
{mall.menu.map(({ name, alias }) => {
const isActive = tab === name;
return (
<div
key={name}
className={`tab ${isActive ? "active" : ""}`}
onClick={() => setTab(name)}
>
<img
src={isActive ? TabMap[name].logoActive : TabMap[name].logo}
></img>
{alias || name}
</div>
);
})}
</div>
)}
</div> </div>
</MallCode.Provider> </MallCode.Provider>
); );

121
src/pages/ShopCoupons/ShopCoupons.js

@ -1,121 +0,0 @@
import "./ShopCoupons.scss";
import { useState, useEffect } from "react";
import { post } from "../../js/helpers/data-helper";
const ShopCoupons = ({ onBack, shop, memberID }) => {
const [coupons, setCoupons] = useState([]);
const [receiving, setReceiving] = useState(false);
const getList = async () => {
try {
const { code, data, msg } = await post(
"/Api/Coupon/ShopDetailCouponList",
{
paging: 0,
memberID,
shopCode: shop.code,
}
);
if (code !== "200")
window.weui.toast(msg, {
className: "toast",
});
else setCoupons(data);
} catch (error) {
console.warn(error);
}
};
useEffect(() => {
getList();
}, []);
const receive = async (coupon) => {
setReceiving(true);
try {
const { code, data, msg } = await post("/Api/Coupon/ShopCouponReceive", {
couponCode: coupon.code,
memberID,
});
window.weui.toast(msg, {
className: "toast",
});
if (code === "200") {
getList();
}
} catch (error) {
console.warn(error);
} finally {
setReceiving(false);
}
};
return (
<div className="ShopCoupons">
<div className="header">
<div
className="back"
onClick={() => {
onBack && onBack();
}}
></div>
{shop.name}
</div>
<div className="list">
{coupons.map((coupon, i) => (
<div className="item" key={coupon.code}>
<div className="left">
<img className="avatar" src={shop.logoPath}></img>
</div>
<div className="right">
<div className="r1">
<div className="content">{coupon.title}</div>
<div
className={
"btn " +
(coupon.detailReceived >= coupon.detailReceiveCount
? "disabled"
: "")
}
onClick={() => {
if (
coupon.detailReceived >= coupon.detailReceiveCount ||
receiving
)
return;
receive(coupon);
}}
>
{coupon.detailReceived >= coupon.detailReceiveCount
? "已领取"
: "领券"}
</div>
</div>
<div className="r2">
<div>使用期限</div>
<div>
{coupon.beginTime}{coupon.endTime}
</div>
<div
className="desc"
onClick={() => {
coupon.isOpen = !coupon.isOpen;
setCoupons([...coupons]);
}}
>
查看详情
<div
className={"icon " + (coupon.isOpen ? "open" : "")}
></div>
</div>
</div>
{!!coupon.isOpen && (
<div className="r3">
<div className="title">使用规则</div>
<div className="content">{coupon.couponRules}</div>
</div>
)}
</div>
</div>
))}
</div>
</div>
);
};
export default ShopCoupons;

144
src/pages/ShopCoupons/ShopCoupons.scss

@ -1,144 +0,0 @@
.ShopCoupons {
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #f3f4f8;
display: flex;
flex-direction: column;
.header {
flex: 0 0 43px;
display: flex;
padding: 9px 16px 10px 18px;
justify-content: space-between;
font-weight: 600;
font-size: 20px;
line-height: 25px;
color: #323337;
white-space: nowrap;
align-items: center;
.back {
width: 24px;
height: 24px;
background: center / cover no-repeat url(./back.svg);
}
}
.list {
flex: 1;
overflow-x: hidden;
overflow-y: auto;
padding: 0 10px;
* {
display: flex;
}
.item {
background: #ffffff;
border: 1px solid #edeff3;
box-shadow: 2px 6px 8px rgba(104, 110, 127, 0.08);
border-radius: 18px;
padding: 16px;
.left {
flex: 0 0 40px;
.avatar {
width: 40px;
height: 40px;
padding: 5px;
border: 1px solid #edeff3;
box-shadow: 2px 6px 8px rgba(104, 110, 127, 0.08);
border-radius: 38px;
object-fit: cover;
}
}
.right {
flex: 1;
flex-direction: column;
.r1 {
padding-left: 10px;
height: 40px;
justify-content: space-between;
flex: 1;
align-items: center;
.content {
display: block;
width: calc(100vw - 192px);
font-size: 20px;
color: #323337;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.btn {
flex: 0 0 90px;
width: 90px;
height: 38px;
background: linear-gradient(180deg, #508af7 0%, #5ea5f9 100%);
box-shadow: 0px 6px 12px rgba(93, 172, 249, 0.2);
border-radius: 10px;
align-items: center;
justify-content: center;
font-size: 14px;
color: #ffffff;
&.disabled {
background: #f3f4f8;
box-shadow: none;
color: #a1a5b3;
}
&:active {
opacity: 0.7;
}
}
}
.r2 {
margin-left: 10px;
margin-top: 18px;
border-top: 1px solid #edeff3;
padding-top: 6px;
font-size: 12px;
line-height: 18px;
color: #474a56;
flex-direction: column;
.desc {
margin-top: 10px;
font-size: 13px;
height: 18px;
color: #437af7;
align-items: center;
.icon {
margin-left: 2px;
width: 16px;
height: 16px;
background: center / cover no-repeat url(./arrow.svg);
transition: all 0.25s ease-in-out;
margin-left: 2px;
&.open {
transform: rotate(90deg);
}
}
}
}
.r3 {
flex-direction: column;
background: #f9f9fb;
border-radius: 8px;
padding: 10px;
.title {
font-size: 13px;
line-height: 18px;
color: #7a7e8d;
margin-bottom: 4px;
}
.content {
font-size: 12px;
line-height: 16px;
color: #a1a5b3;
opacity: 0.8;
}
}
}
}
.item + .item {
margin-top: 8px;
}
}
}

9
src/pages/ShopCoupons/arrow.svg

@ -1,9 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.45122 2.03921C5.10485 2.34227 5.06975 2.86874 5.37282 3.21511L9.55933 7.99969L5.37282 12.7843C5.06975 13.1306 5.10485 13.6571 5.45122 13.9602C5.79758 14.2632 6.32405 14.2281 6.62712 13.8818L11.1017 8.76794C11.4866 8.32808 11.4866 7.6713 11.1017 7.23143L6.62712 2.1176C6.32405 1.77123 5.79758 1.73614 5.45122 2.03921Z" fill="url(#paint0_linear_1524_22411)"/>
<defs>
<linearGradient id="paint0_linear_1524_22411" x1="8.2785" y1="1.83301" x2="8.2785" y2="14.1664" gradientUnits="userSpaceOnUse">
<stop stop-color="#508AF7"/>
<stop offset="1" stop-color="#5EA5F9"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 743 B

3
src/pages/ShopCoupons/back.svg

@ -1,3 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.8232 3.0593C16.3427 3.5139 16.3954 4.3036 15.9408 4.82315L9.66101 12L15.9408 19.1769C16.3954 19.6964 16.3427 20.4861 15.8232 20.9407C15.3036 21.3953 14.5139 21.3427 14.0593 20.8231L7.34742 13.1524C6.7701 12.4926 6.7701 11.5074 7.34742 10.8476L14.0593 3.17689C14.5139 2.65734 15.3036 2.60469 15.8232 3.0593Z" fill="#353230"/>
</svg>

Before

Width:  |  Height:  |  Size: 481 B

Loading…
Cancel
Save