|
@@ -1,5 +1,5 @@
|
|
<template>
|
|
<template>
|
|
- <div class="min-h-screen w-full ">
|
|
|
|
|
|
+ <div class="min-h-screen w-full">
|
|
<div class="relative overflow-hidden py-4 pb-10 bg-[#fdedc5]">
|
|
<div class="relative overflow-hidden py-4 pb-10 bg-[#fdedc5]">
|
|
<img
|
|
<img
|
|
src="https://oss.hhmdtech.com/merchant/RmW4frEmQRr99JJ4RJ5hwdZR8FYDhTe8PKn6inRBijRJMRcA.png"
|
|
src="https://oss.hhmdtech.com/merchant/RmW4frEmQRr99JJ4RJ5hwdZR8FYDhTe8PKn6inRBijRJMRcA.png"
|
|
@@ -8,75 +8,85 @@
|
|
/>
|
|
/>
|
|
<div class="relative">
|
|
<div class="relative">
|
|
<div class="h-full w-full overflow-hidden px-4">
|
|
<div class="h-full w-full overflow-hidden px-4">
|
|
- <div
|
|
|
|
- class="flex h-full w-full rounded bg-[#ffc72f] transition-all duration-150"
|
|
|
|
- >
|
|
|
|
- <div class="flex-1 p-4">
|
|
|
|
- <div
|
|
|
|
- class="mb-2 max-w-[8em] truncate whitespace-nowrap text-2xl"
|
|
|
|
- >
|
|
|
|
- {{ goodsDetail.memberCardName }}
|
|
|
|
- </div>
|
|
|
|
- <div v-if="goodsDetail?.originPrice" class="text-gray-500 line-through">
|
|
|
|
- <span>¥</span>
|
|
|
|
- <span>
|
|
|
|
- {{ parseFloat((goodsDetail?.originPrice / 100).toFixed(2)) }}
|
|
|
|
- </span>
|
|
|
|
- <span>/{{ goodsDetail.memberCard?.lifespan }}天</span>
|
|
|
|
- </div>
|
|
|
|
- <div :class="goodsDetail?.originPrice ? 'pb-3' : 'py-3'">
|
|
|
|
- <span>¥</span>
|
|
|
|
- <span class="text-2xl">
|
|
|
|
- {{ parseFloat((goodsDetail.memberCard?.price / 100).toFixed(2)) }}
|
|
|
|
- </span>
|
|
|
|
- <span>/{{ goodsDetail.memberCard?.lifespan }}天</span>
|
|
|
|
- </div>
|
|
|
|
- <div class="text-base text-gray-500">{{ goodsDetail.title }}</div>
|
|
|
|
|
|
+ <div
|
|
|
|
+ class="flex h-full w-full rounded bg-[#ffc72f] transition-all duration-150"
|
|
|
|
+ >
|
|
|
|
+ <div class="flex-1 p-4">
|
|
|
|
+ <div class="mb-2 max-w-[8em] truncate whitespace-nowrap text-2xl">
|
|
|
|
+ {{ goodsDetail.memberCardName }}
|
|
</div>
|
|
</div>
|
|
- <img
|
|
|
|
- src="@/assets/icon-vip.png"
|
|
|
|
- class="m-4 h-12 w-12"
|
|
|
|
- />
|
|
|
|
|
|
+ <div
|
|
|
|
+ v-if="goodsDetail?.originPrice"
|
|
|
|
+ class="text-gray-500 line-through"
|
|
|
|
+ >
|
|
|
|
+ <span>¥</span>
|
|
|
|
+ <span>
|
|
|
|
+ {{ parseFloat((goodsDetail?.originPrice / 100).toFixed(2)) }}
|
|
|
|
+ </span>
|
|
|
|
+ <span>/{{ goodsDetail.memberCard?.lifespan }}天</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div :class="goodsDetail?.originPrice ? 'pb-3' : 'py-3'">
|
|
|
|
+ <span>¥</span>
|
|
|
|
+ <span class="text-2xl">
|
|
|
|
+ {{ parseFloat((goodsDetail?.price / 100).toFixed(2)) }}
|
|
|
|
+ </span>
|
|
|
|
+ <span>/{{ goodsDetail.memberCard?.lifespan }}天</span>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="text-base text-gray-500">{{ goodsDetail.title }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
+ <img src="@/assets/icon-vip.png" class="m-4 h-12 w-12" />
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="relative -top-6 rounded rounded-t-2xl bg-white z-10">
|
|
<div class="relative -top-6 rounded rounded-t-2xl bg-white z-10">
|
|
<div class="p-4 pb-20">
|
|
<div class="p-4 pb-20">
|
|
- <div class="" v-html="goodsDetail.memberCard?.content"></div>
|
|
|
|
|
|
+ <div class="" v-html="goodsDetail.saleSlogan"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
- <div class="z-[2000] fixed bottom-6 left-0 flex w-full items-center justify-center">
|
|
|
|
|
|
+ <div
|
|
|
|
+ class="z-[2000] fixed bottom-6 left-0 flex w-full items-center justify-center"
|
|
|
|
+ >
|
|
<div
|
|
<div
|
|
- class=" flex w-10/12 items-center justify-center overflow-hidden rounded-xl bg-[#2c2c2c]">
|
|
|
|
|
|
+ class="flex w-10/12 items-center justify-center overflow-hidden rounded-xl bg-[#2c2c2c]"
|
|
|
|
+ >
|
|
<button
|
|
<button
|
|
class="flex-1 whitespace-nowrap border-0 bg-[#2c2c2c] p-4 text-sm text-[#e59223] after:hidden"
|
|
class="flex-1 whitespace-nowrap border-0 bg-[#2c2c2c] p-4 text-sm text-[#e59223] after:hidden"
|
|
- @click="buy">
|
|
|
|
-
|
|
|
|
|
|
+ @click="buyHistory"
|
|
|
|
+ >
|
|
|
|
+ <span class="text-base">购买记录</span>
|
|
|
|
+ </button>
|
|
|
|
+ <div class="h-5 w-px bg-[#e59223]"></div>
|
|
|
|
+ <button
|
|
|
|
+ class="flex-1 whitespace-nowrap border-0 bg-[#2c2c2c] p-4 text-sm text-[#e59223] after:hidden"
|
|
|
|
+ @click="buy"
|
|
|
|
+ >
|
|
<span class="text-base">立即购买</span>
|
|
<span class="text-base">立即购买</span>
|
|
</button>
|
|
</button>
|
|
-
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<PaymentDialog
|
|
<PaymentDialog
|
|
- :show="showDialog"
|
|
|
|
|
|
+ v-model:show="showDialog"
|
|
:onClose="handleClose"
|
|
:onClose="handleClose"
|
|
:onConfirm="handleConfirm"
|
|
:onConfirm="handleConfirm"
|
|
/>
|
|
/>
|
|
|
|
+ <PaymentHistoryDialog v-model:show="showHistory" :openId="openId" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
-import { ref, reactive, onMounted, computed, watch } from "vue";
|
|
|
|
|
|
+import { ref, reactive, onMounted, computed, watch, provide } from "vue";
|
|
|
|
|
|
-import PaymentDialog from './components/PaymentDialog.vue'
|
|
|
|
|
|
+import PaymentDialog from "./components/PaymentDialog.vue";
|
|
|
|
+import PaymentHistoryDialog from "./components/PaymentHistoryDialog.vue";
|
|
import { useRoute, useRouter } from "vue-router";
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
|
|
|
import { request } from "@/utils";
|
|
import { request } from "@/utils";
|
|
|
|
|
|
const [route, router] = [useRoute(), useRouter()];
|
|
const [route, router] = [useRoute(), useRouter()];
|
|
-const goodsDetail = ref({})
|
|
|
|
|
|
+const goodsDetail = ref({});
|
|
|
|
+provide("goodsDetail", goodsDetail);
|
|
const getGoodsDetail = async () => {
|
|
const getGoodsDetail = async () => {
|
|
const { data } = await request.get(
|
|
const { data } = await request.get(
|
|
`archivesService/member/promotionGoods/detail`,
|
|
`archivesService/member/promotionGoods/detail`,
|
|
@@ -86,24 +96,163 @@ const getGoodsDetail = async () => {
|
|
},
|
|
},
|
|
}
|
|
}
|
|
);
|
|
);
|
|
- goodsDetail.value = data.detail
|
|
|
|
|
|
+ goodsDetail.value = data.detail;
|
|
};
|
|
};
|
|
getGoodsDetail();
|
|
getGoodsDetail();
|
|
|
|
|
|
-
|
|
|
|
-const showDialog = ref(false)
|
|
|
|
|
|
+const showDialog = ref(false);
|
|
|
|
|
|
const handleClose = () => {
|
|
const handleClose = () => {
|
|
- showDialog.value = false
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-const handleConfirm = () => {
|
|
|
|
- console.log('Payment confirmed')
|
|
|
|
- showDialog.value = false
|
|
|
|
|
|
+ showDialog.value = false;
|
|
|
|
+};
|
|
|
|
+function onBridgeReady(paySign) {
|
|
|
|
+ if (!WeixinJSBridge) {
|
|
|
|
+ return showToast("请在微信浏览器中打开");
|
|
|
|
+ }
|
|
|
|
+ WeixinJSBridge.invoke(
|
|
|
|
+ "getBrandWCPayRequest",
|
|
|
|
+ {
|
|
|
|
+ appId: appId.value, //公众号ID,由商户传入
|
|
|
|
+ ...paySign,
|
|
|
|
+ },
|
|
|
|
+ function (res) {
|
|
|
|
+ console.log(res);
|
|
|
|
+ if (res.err_msg == "get_brand_wcpay_request:ok") {
|
|
|
|
+ // 使用以上方式判断前端返回,微信团队郑重提示:
|
|
|
|
+ //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠,商户需进一步调用后端查单确认支付结果。
|
|
|
|
+ console.log("支付成功");
|
|
|
|
+ router.push({
|
|
|
|
+ name: "promotionPayResult",
|
|
|
|
+ query: {
|
|
|
|
+ promotionGoodsId: route.query.promotionGoodsId,
|
|
|
|
+ promotionSiteId: route.query.promotionSiteId,
|
|
|
|
+ },
|
|
|
|
+ });
|
|
|
|
+ } else {
|
|
|
|
+ showToast("支付失败" + res.err_msg);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ );
|
|
}
|
|
}
|
|
|
|
+const handleConfirm = async (mobile, captcha) => {
|
|
|
|
+ console.log("Payment confirmed");
|
|
|
|
+ showDialog.value = false;
|
|
|
|
+ const { data } = await request.post(
|
|
|
|
+ `/archivesService/member/promotionGoods/paymentParams`,
|
|
|
|
+ {
|
|
|
|
+ promotionGoodsId: route.query.promotionGoodsId,
|
|
|
|
+ promotionSiteId: route.query.promotionSiteId,
|
|
|
|
+ mobile,
|
|
|
|
+ captcha,
|
|
|
|
+ openId: openId.value,
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ console.log(data.paymentParams);
|
|
|
|
+ data.paymentParams?.paySign && onBridgeReady(data.paymentParams.paySign);
|
|
|
|
+};
|
|
|
|
+const showHistory = ref(false);
|
|
|
|
+const buyHistory = () => {
|
|
|
|
+ showHistory.value = true;
|
|
|
|
+};
|
|
const buy = () => {
|
|
const buy = () => {
|
|
- showDialog.value = true
|
|
|
|
-}
|
|
|
|
|
|
+ showDialog.value = true;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const preCheck = async () => {
|
|
|
|
+ const { data } = await request.get(
|
|
|
|
+ `/archivesService/member/promotionGoods/preData`,
|
|
|
|
+ {
|
|
|
|
+ params: {
|
|
|
|
+ promotionGoodsId: route.query.promotionGoodsId,
|
|
|
|
+ promotionSiteId: route.query.promotionSiteId,
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ return data;
|
|
|
|
+};
|
|
|
|
+// const jsSdkConfig = async () => {
|
|
|
|
+// const { data } = await request.post(
|
|
|
|
+// "archivesService/member/promotionGoods/getJssdk",
|
|
|
|
+// {
|
|
|
|
+// url: location.href,
|
|
|
|
+// promotionGoodsId: route.query.promotionGoodsId,
|
|
|
|
+// }
|
|
|
|
+// );
|
|
|
|
+// return data;
|
|
|
|
+// };
|
|
|
|
+// const wxConfig = async () => {
|
|
|
|
+// const { data } = await jsSdkConfig();
|
|
|
|
+// window["wx"]?.config?.(data.config);
|
|
|
|
+// window["wx"]?.error((res) => {
|
|
|
|
+// console.log(res);
|
|
|
|
+// });
|
|
|
|
+// };
|
|
|
|
+const appId = ref(sessionStorage.getItem("appId"));
|
|
|
|
+// const openId = ref("KfZnJNKFaFXWWCagSlX0dT4tNkwsLEwQVlrzpHvo");
|
|
|
|
+const openId = ref("");
|
|
|
|
+const getWeChatAuth = async () => {
|
|
|
|
+ const { appId, errMsg, paymentSettingId } = await preCheck();
|
|
|
|
+ if (errMsg) {
|
|
|
|
+ // return showToast(errMsg);
|
|
|
|
+ router.push({
|
|
|
|
+ name: "error",
|
|
|
|
+ query: {
|
|
|
|
+ msg: errMsg,
|
|
|
|
+ },
|
|
|
|
+ });
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (appId) {
|
|
|
|
+ //缓存信息
|
|
|
|
+ sessionStorage.setItem("appId", appId);
|
|
|
|
+ sessionStorage.setItem("paymentSettingId", paymentSettingId);
|
|
|
|
+ //跳转微信授权
|
|
|
|
+
|
|
|
|
+ const redirectUri = encodeURIComponent(location.href);
|
|
|
|
+ location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_base&state=123#wechat_redirect`;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ showToast("微信配置不存在");
|
|
|
|
+};
|
|
|
|
+const getOpenId = async () => {
|
|
|
|
+ const { code } = route.query;
|
|
|
|
+ const paymentSettingId = sessionStorage.getItem("paymentSettingId");
|
|
|
|
+ if (!code) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ const { data } = await request.get(
|
|
|
|
+ `archivesService/member/promotionGoods/getOpenId`,
|
|
|
|
+ {
|
|
|
|
+ params: {
|
|
|
|
+ code,
|
|
|
|
+ paymentSettingId,
|
|
|
|
+ },
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ if (data.openId) {
|
|
|
|
+ openId.value = data.openId;
|
|
|
|
+ } else {
|
|
|
|
+ showToast("获取openId失败");
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+const init = async () => {
|
|
|
|
+ const { code, promotionGoodsId, promotionSiteId } = route.query;
|
|
|
|
+ if (!promotionSiteId || !promotionGoodsId) {
|
|
|
|
+ return router.push({
|
|
|
|
+ name: "error",
|
|
|
|
+ query: {
|
|
|
|
+ msg: "参数异常",
|
|
|
|
+ },
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ const paymentSettingId = sessionStorage.getItem("paymentSettingId");
|
|
|
|
+ if (!code || !paymentSettingId) {
|
|
|
|
+ return getWeChatAuth();
|
|
|
|
+ }
|
|
|
|
+ getOpenId()
|
|
|
|
+ // wxConfig();
|
|
|
|
+};
|
|
|
|
+onMounted(() => init());
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped></style>
|
|
<style lang="scss" scoped></style>
|