detailDialog.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. <template>
  2. <uni-popup ref="detailPopup" :animation="false" :is-mask-click="false"
  3. mask-background-color="rgba(51, 137, 217, 0.65);">
  4. <view class="mall-detail-dialog">
  5. <view class="detail-content-box">
  6. <icon class="yfmx-title"></icon>
  7. <icon class="dialog-close-btn" @click="detailCloseBtn"></icon>
  8. <view class="detail-body-box">
  9. <!-- 全选/取消全选 -->
  10. <view class="select-all-box" @click="toggleSelectAll">
  11. <checkbox :checked="isAllSelected" class="detail-checkbox" />
  12. <text>全选</text>
  13. </view>
  14. <!-- 使用 checkbox-group 管理多选 -->
  15. <checkbox-group @change="handleCheckboxChange">
  16. <view class="detail-item-box" v-for="item in localList" :key="item.id">
  17. <checkbox :value="item.id.toString()" :checked="selectedIds.includes(item.id)"
  18. class="detail-checkbox" />
  19. <img :src="item.cover" class="mall-image" />
  20. <view class="content-body-box">
  21. <view class="content-name">
  22. <view class="name-text">{{item.name}}</view>
  23. </view>
  24. <view class="content-text">{{item.intro}}</view>
  25. <view class="content-row">
  26. <view class="content-yuanjia">¥{{item.xianjia}}</view>
  27. </view>
  28. </view>
  29. </view>
  30. </checkbox-group>
  31. </view>
  32. </view>
  33. <!-- 子组件自己的底部结算栏 -->
  34. <view class="footer-mall-pay-box">
  35. <view class="mall-left-box">
  36. <view class="price-icon-box">
  37. <text class="red-price fh-text">¥</text>
  38. <text class="red-price">{{totalPrice}}</text>明细
  39. <icon :class="mxjtClass"></icon>
  40. </view>
  41. </view>
  42. <view class="pay-status-box" v-if="payType =='weixin'&&currentPlatform =='android'"
  43. @click="switchPayWay">
  44. <icon class="wx-icon"></icon>微信
  45. </view>
  46. <view class="pay-status-box" v-if="payType =='zhifubao'&&currentPlatform =='android'"
  47. @click="switchPayWay">
  48. <icon class="zfb-icon"></icon>支付宝
  49. </view>
  50. <view class="pay-status-box apple-status-box" v-if="currentPlatform =='ios'">
  51. <icon class="apple-icon"></icon>apple
  52. </view>
  53. <view v-if="currentPlatform =='android'" class="open-svip-btn" @touchstart="creatOrder">立即支付
  54. </view>
  55. <view v-if="currentPlatform =='ios'" style="margin-top: 20rpx;" class="open-svip-btn"
  56. @touchstart="creatOrderIos">立即支付</view>
  57. </view>
  58. </view>
  59. </uni-popup>
  60. </template>
  61. <script setup>
  62. import {
  63. ref,
  64. computed,
  65. onMounted,
  66. watch
  67. } from 'vue';
  68. import {
  69. debounce,
  70. toast
  71. } from "@/utils/common";
  72. import cacheManager from "@/utils/cacheManager.js";
  73. import {
  74. orderAdd,
  75. orderPayAli,
  76. orderPayWx,
  77. orderPayApple,
  78. orderCheck
  79. } from "@/api/order.js"
  80. const props = defineProps({
  81. selectedList: { // 父组件传入的初始选中商品列表
  82. type: Array,
  83. default: () => []
  84. }
  85. });
  86. const payType = ref('weixin');
  87. const mxjtClass = ref('mxjt-sq-icon');
  88. // 本地维护的商品列表(独立于父组件)
  89. const localList = ref([]);
  90. const selectedIds = ref([]); // 存储选中项的id
  91. let orderId = ref('');
  92. // 本地选中状态管理
  93. const localSelectedMap = ref({});
  94. let currentPlatform = ref('android')
  95. // 初始化本地数据
  96. // 初始化数据
  97. watch(() => props.selectedList, (newVal) => {
  98. localList.value = [...newVal];
  99. selectedIds.value = newVal.map(item => item.id); // 初始全部选中
  100. }, {
  101. immediate: true
  102. });
  103. onMounted(() => {
  104. isIOSorAndroid()
  105. })
  106. const isIOSorAndroid = () => {
  107. const systemInfo = uni.getSystemInfoSync();
  108. console.log('systemInfo', systemInfo);
  109. if (systemInfo.platform == 'ios') {
  110. return currentPlatform.value = 'ios'
  111. } else {
  112. return currentPlatform.value = 'android'
  113. }
  114. }
  115. function genggaiVip(data) {
  116. uni.hideLoading();
  117. const localList = cacheManager.get('auth').levelIdList || []
  118. const mergeList = [...new Set([...localList, ...data.levelIdList])]
  119. cacheManager.updateObject('auth', {
  120. levelIdList: mergeList
  121. })
  122. toast("chenggong!!!! 之后跳转我的订单页面")
  123. // if (formPage.value == 'my') {
  124. // uni.redirectTo({
  125. // url: '/pages/my/index'
  126. // })
  127. // } else {
  128. // uni.redirectTo({
  129. // url: '/pages/study/index'
  130. // })
  131. // }
  132. }
  133. const creatOrderIos = debounce((data => {
  134. const selectedItems = localList.value
  135. .filter(item => selectedIds.value.includes(item.id));
  136. console.log('selectedItems', selectedItems);
  137. const cardIds = selectedItems.map(item => item.id);
  138. if (cardIds.length === 0) {
  139. uni.showToast({
  140. title: '请选择至少一个商品',
  141. icon: 'none'
  142. });
  143. return;
  144. }
  145. uni.showLoading({
  146. title: '',
  147. mask: true
  148. });
  149. if (appleFlag.value.toString() == 'true') {
  150. productId.value = 'llisoftEzhuangyuanceshi'
  151. } else {
  152. if (cardId.value == 1) {
  153. productId.value = 'llisoftEzhuangyuan'
  154. } else {
  155. productId.value = 'llisoftEzhuangyuanYingyu'
  156. }
  157. }
  158. let req = {
  159. cardIds: cardIds
  160. }
  161. orderAdd(req).then(res => {
  162. console.log('res', res);
  163. if (res.code == 0) {
  164. uni.hideLoading();
  165. orderId.value = res.data.id
  166. // 测试ios 1元
  167. applePay()
  168. } else {
  169. uni.hideLoading();
  170. return false
  171. console.log('请求失败');
  172. }
  173. }).catch((e) => {
  174. uni.hideLoading();
  175. toast("订单创建失败")
  176. return false
  177. })
  178. }), 500)
  179. function applePaySuccess(data) {
  180. uni.showLoading({
  181. title: '会员开通中',
  182. mask: true
  183. });
  184. let req = {
  185. "id": orderId.value,
  186. "paynum": data.transactionIdentifier,
  187. "receipt": data.transactionReceipt
  188. }
  189. console.log('reqreq', req);
  190. orderPayApple(req).then(res => {
  191. if (res.code == 0 && res.data) {
  192. iapChannel.finishTransaction(data.transactionIdentifier)
  193. console.log('resiapChanneliapChanneliapChannel', res);
  194. genggaiVip()
  195. } else {
  196. iapChannel.finishTransaction(data.transactionIdentifier)
  197. uni.hideLoading();
  198. toast("苹果内购失败")
  199. console.log('orderPayApple失败');
  200. return false
  201. }
  202. })
  203. }
  204. function applePay() {
  205. console.log('123123');
  206. if (!productId.value) {
  207. uni.showToast({
  208. title: '苹果内购ID缺失,请选择其它支付方式或联系客服',
  209. icon: "none"
  210. });
  211. return false;
  212. }
  213. uni.showLoading({
  214. title: '正在支付中...'
  215. });
  216. try {
  217. plus.payment.getChannels(function(channels) { //判读项目支付通道开通情况
  218. for (var i in channels) {
  219. iapChannel = channels[i];
  220. // 获取 id 为 'appleiap' 的 channel
  221. console.info("支付通道", iapChannel)
  222. if (iapChannel.id === 'appleiap') { //开通了app应用内支付,在manifest.josn中设置,开通后需打自定议基座
  223. console.info("苹果支付通道", iapChannel)
  224. // ids 数组中的项为 App Store Connect 配置的内购买项目产品ID(productId)
  225. var ids = [productId.value];
  226. // iap 为应用内支付对象
  227. iapChannel.requestOrder(ids, function(e) {
  228. // 获取订单信息成功回调方法
  229. console.log('requestOrder success: ' + JSON.stringify(e));
  230. uni.requestPayment({
  231. provider: 'appleiap',
  232. orderInfo: {
  233. productid: productId.value, //产品id,来自于苹果
  234. quantity: quantity.value, //产品数量
  235. manualFinishTransaction: true
  236. },
  237. success: (e) => {
  238. uni.hideLoading();
  239. // toast("苹果内购成功")
  240. console.info("苹果内购成功", e)
  241. applePaySuccess(e)
  242. //e.payment.orderNo = that.orderNo
  243. //支付成功回调,前端调用后台接口
  244. },
  245. fail: (e) => {
  246. uni.hideLoading();
  247. toast("苹果内购失败")
  248. console.info("苹果内购失败", e)
  249. },
  250. })
  251. },
  252. function(e) {
  253. // 获取订单信息失败回调方法
  254. console.log('requestOrder failed: ' + JSON.stringify(e));
  255. });
  256. } else {
  257. console.log('不支持苹果支付')
  258. }
  259. }
  260. },
  261. function(e) {
  262. console.log("获取iap支付通道失败:" + e.message);
  263. });
  264. } catch (e) {
  265. uni.showModal({
  266. title: "init",
  267. content: e.message,
  268. showCancel: false
  269. });
  270. } finally {
  271. uni.hideLoading();
  272. }
  273. }
  274. function wxPay() {
  275. orderPayWx({
  276. id: orderId.value
  277. }).then(res2 => {
  278. uni.hideLoading();
  279. console.log('res2', res2);
  280. uni.requestPayment({
  281. "provider": "wxpay",
  282. "orderInfo": {
  283. "appid": res2.data.appid, // 应用ID(AppID)
  284. "partnerid": res2.data.partnerId, // 商户号(PartnerID)
  285. "prepayid": res2.data.prepayId, // 预支付交易会话ID
  286. "package": res2.data.packageVal, // 固定值
  287. "noncestr": res2.data.nonceStr, // 随机字符串
  288. "timestamp": res2.data.timestamp, // 时间戳(单位:秒)
  289. "sign": res2.data.sign // 签名,这里用的 MD5 签名
  290. }, //此处为服务器返回的订单信息字符串
  291. success: function(res) {
  292. //var rawdata = JSON.parse(res.rawdata);
  293. // console.log('res',res);
  294. // console.log('支付成功');
  295. // console.log('rawdata', rawdata);
  296. uni.showLoading({
  297. title: '会员开通中,请稍后...'
  298. });
  299. orderCheck({
  300. id: orderId.value
  301. }).then(res3 => {
  302. console.log('res3', res3);
  303. if (res3.code == 0) {
  304. genggaiVip(res3.data)
  305. } else {
  306. setTimeout(() => {
  307. orderCheck({
  308. id: orderId.value
  309. }).then(res4 => {
  310. if (res4.code == 0) {
  311. genggaiVip(res4.data)
  312. } else {
  313. toast(
  314. "开通失败,请联系管理员!"
  315. )
  316. uni
  317. .hideLoading();
  318. return false
  319. }
  320. }).catch(() => {
  321. uni.hideLoading();
  322. toast("check接口报错")
  323. return false
  324. })
  325. }, 5000)
  326. }
  327. }).catch(() => {
  328. uni.hideLoading();
  329. toast("check接口报错")
  330. return false
  331. })
  332. },
  333. fail: function(err) {
  334. uni.hideLoading();
  335. // toast('支付失败:' + JSON.stringify(err));
  336. console.log('支付失败:' + JSON.stringify(err));
  337. }
  338. });
  339. }).catch((error) => {
  340. uni.hideLoading();
  341. console.log(error);
  342. })
  343. }
  344. function aliApy() {
  345. orderPayAli({
  346. id: orderId.value
  347. }).then(res2 => {
  348. console.log('res2', res2);
  349. uni.hideLoading();
  350. uni.requestPayment({
  351. "provider": "alipay",
  352. "orderInfo": res2.data.text, //此处为服务器返回的订单信息字符串
  353. success: function(res) {
  354. // var rawdata = JSON.parse(res.rawdata);
  355. // console.log('支付成功');
  356. // console.log('rawdata', rawdata);
  357. uni.showLoading({
  358. title: '会员开通中,请稍后...'
  359. });
  360. orderCheck({
  361. id: orderId.value
  362. }).then(res3 => {
  363. if (res3.code == 0) {
  364. genggaiVip(res3.data)
  365. } else {
  366. setTimeout(() => {
  367. orderCheck({
  368. id: orderId.value
  369. }).then(res4 => {
  370. if (res4.code ==
  371. 0) {
  372. genggaiVip(res4.data)
  373. } else {
  374. toast(
  375. "开通失败,请联系管理员!"
  376. )
  377. uni
  378. .hideLoading();
  379. return false
  380. }
  381. }).catch(() => {
  382. uni.hideLoading();
  383. toast("check接口报错")
  384. return false
  385. })
  386. }, 5000)
  387. }
  388. }).catch(() => {
  389. uni.hideLoading();
  390. toast("check接口报错")
  391. return false
  392. })
  393. },
  394. fail: function(err) {
  395. console.log('支付失败:' + JSON.stringify(err));
  396. uni.hideLoading();
  397. }
  398. });
  399. })
  400. }
  401. const creatOrder = debounce((data) => {
  402. const selectedItems = localList.value
  403. .filter(item => selectedIds.value.includes(item.id));
  404. console.log('selectedItems', selectedItems);
  405. const cardIds = selectedItems.map(item => item.id);
  406. if (cardIds.length === 0) {
  407. uni.showToast({
  408. title: '请选择至少一个商品',
  409. icon: 'none'
  410. });
  411. return;
  412. }
  413. console.log('123123123123');
  414. uni.showLoading({
  415. title: '',
  416. mask: true
  417. });
  418. if (payType.value == 'weixin') {
  419. console.log('创建订单11');
  420. let req = {
  421. cardIds: cardIds
  422. }
  423. orderAdd(req).then(res => {
  424. console.log('res', res);
  425. console.log(' res.data.id', res.data.id);
  426. orderId.value = res.data.id
  427. wxPay()
  428. }).catch((err) => {
  429. uni.hideLoading();
  430. toast("订单创建失败")
  431. return false
  432. })
  433. } else {
  434. let req = {
  435. cardIds: cardIds
  436. }
  437. orderAdd(req).then(res => {
  438. console.log('res', res);
  439. orderId.value = res.data.id
  440. aliApy()
  441. }).catch((err) => {
  442. uni.hideLoading();
  443. toast("订单创建失败")
  444. return false
  445. })
  446. }
  447. }, 500)
  448. // 是否全选
  449. const isAllSelected = computed(() => {
  450. return localList.value.length > 0 &&
  451. selectedIds.value.length === localList.value.length;
  452. });
  453. // 处理checkbox变化
  454. function handleCheckboxChange(e) {
  455. selectedIds.value = e.detail.value.map(id => parseInt(id));
  456. }
  457. // 全选/取消全选
  458. function toggleSelectAll() {
  459. if (isAllSelected.value) {
  460. selectedIds.value = []; // 取消全选
  461. } else {
  462. selectedIds.value = localList.value.map(item => item.id); // 全选
  463. }
  464. }
  465. // 计算总价
  466. const totalPrice = computed(() => {
  467. return localList.value
  468. .filter(item => selectedIds.value.includes(item.id))
  469. .reduce((sum, item) => sum + parseFloat(item.xianjia || 0), 0)
  470. .toFixed(2);
  471. });
  472. // 支付方式切换
  473. function switchPayWay() {
  474. payType.value = payType.value == 'weixin' ? 'zhifubao' : 'weixin'
  475. }
  476. // 支付处理
  477. const detailPopup = ref(null);
  478. function detailShow() {
  479. detailPopup.value.open();
  480. }
  481. function detailCloseBtn() {
  482. detailPopup.value.close();
  483. }
  484. defineExpose({
  485. detailShow,
  486. detailCloseBtn
  487. });
  488. </script>
  489. <style>
  490. </style>