index.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. <template>
  2. <!-- 不同类型进入的loadType(1:学校课程;2:体育馆课程;3:教练课程) -->
  3. <view class="content">
  4. <view class="g-orderinfo-card">
  5. <view class="g-shoping-info" v-if="previewCourseInfo">
  6. <image class="shoping-img" :src="previewCourseInfo.cover" mode=""></image>
  7. <view class="shoping-info">
  8. <view class="name">{{ previewCourseInfo.placeName || previewCourseInfo.name }}</view>
  9. <view class="price-info">
  10. <!-- previewCourseInfo?.originalPrice字段用来判断是课程订单还是场地订单 -->
  11. <view class="price"><text class="mini-text">¥</text>{{ previewCourseInfo?.originalPrice ?
  12. previewCourseInfo?.originalPrice : previewCourseInfo?.sellingPrice.toFixed(2)
  13. }}</view>
  14. <view class="price-stepper">
  15. <view class="minus" @click="minusNum">-</view>
  16. <input v-model="countTotal" disabled type="number" />
  17. <view class="add" @click="addNum">+</view>
  18. </view>
  19. </view>
  20. </view>
  21. </view>
  22. <view class="g-shoping-total">
  23. <view class="total-price">
  24. <view class="">商品总价(共{{ countTotal }}件)</view>
  25. <view class="">¥{{
  26. previewCourseInfo?.originalPrice ? (previewCourseInfo?.originalPrice * countTotal).toFixed(2) :
  27. previewCourseInfo?.sellingPrice.toFixed(2)
  28. * countTotal }}</view>
  29. </view>
  30. <view class="total-price">
  31. <view class="">
  32. <text v-if="buyType == 1">试听优惠</text>
  33. <text v-if="buyType == 0 || placeId">团购优惠</text>
  34. </view>
  35. <view class="">-¥
  36. <!-- <text v-if="buyType == 0 || !placeId">{{ previewCourseInfo?.discountPrice }}</text> -->
  37. <text v-if="buyType == 1">{{ previewCourseInfo?.sellingPrice.toFixed(2) }}</text>
  38. <text v-else>{{
  39. previewCourseInfo?.originalPrice ? (previewCourseInfo?.originalPrice -
  40. previewCourseInfo?.sellingPrice.toFixed(2)) * countTotal : ((previewCourseInfo?.sellingPrice
  41. -
  42. previewCourseInfo?.totalPrice.toFixed(2))) * countTotal }}</text>
  43. </view>
  44. </view>
  45. </view>
  46. <view class="subtotal">小计 ¥
  47. <text v-if="buyType == 1">{{ (0 + totalInsurePrice).toFixed(2) }}</text>
  48. <text v-else>{{ previewCourseInfo?.originalPrice ? (previewCourseInfo?.sellingPrice *
  49. countTotal).toFixed(2) : ((previewCourseInfo?.sellingPrice - (previewCourseInfo?.sellingPrice
  50. - previewCourseInfo?.totalPrice)) * countTotal).toFixed(2) }}</text>
  51. </view>
  52. </view>
  53. <!-- 课程进入 -->
  54. <view class="r-insurance" v-for="item in insureIdList" :key="item.id">
  55. <view class="r-insurance-infobox">
  56. <view class="r-image-box">
  57. <image :src="item.coverImg" mode=""></image>
  58. </view>
  59. <view class="r-insurance-title">
  60. <view class="r-insurance-name">
  61. <view class="r-name">{{ item.name }}</view>
  62. <view class="r-tags">不支持退款</view>
  63. </view>
  64. <view class="r-insurance-desc" v-for="(desc, index) in item.insuranceObvious" :key="index">
  65. <text v-for="([key, value], idx) in Object.entries(desc)" :key="key + idx">{{ key }}, {{
  66. value }};</text>
  67. </view>
  68. <view class="r-insurance-type">保险公司:{{ item.insuranceName_dictText }}</view>
  69. <view class="r-insurance-price">
  70. <view class="r-price">¥{{ item.priceDataList[0].insurePrice }}/天·人</view>
  71. <view class="r-insurance-btn" v-if="insureData.length < 1"
  72. @click="gotoInsuracePage(item, item.priceDataList)">去投保
  73. </view>
  74. </view>
  75. </view>
  76. </view>
  77. <view class="line" v-if="insureData.length > 0 && insureId == item.id"></view>
  78. <blcok v-if="insureData.length > 0 && insureId == item.id">
  79. <view class="r-insurance-adduser" v-for="(insureUser, index) in insureData" :key="index">
  80. <view class="r-adduser-btn">
  81. <view class="r-celar" @click="clearUser">清除</view>
  82. <view class="r-edit"
  83. @click="RouterUtils.to_page(`/pages/index/insure/index?priceDataList=${JSON.stringify(item.priceDataList)}`)">
  84. 修改</view>
  85. </view>
  86. <view class="r-userinfo-list">
  87. <view class="r-userinfo-item">
  88. <view class="r-item-title">被保人</view>
  89. <view class="r-item-info">{{ insureUser.userData.length }}人(<text
  90. v-for="(user, index) in insureUser.userData" :key="user.id">{{ user.fullName }}{{
  91. index < insureUser.userData.length - 1 ? ',' : '' }}</text>)
  92. </view>
  93. </view>
  94. <view class="r-userinfo-item">
  95. <view class="r-item-title">生效时间</view>
  96. <view class="r-item-info">{{ insureUser.slectObj.insureDay }}天({{ insureUser.startDate }}-{{
  97. insureUser.endDate }})
  98. </view>
  99. </view>
  100. <view class="r-userinfo-item">
  101. <view class="r-item-title">保费总金额</view>
  102. <view class="r-item-info">¥{{ insureUser.totalPrice }}</view>
  103. </view>
  104. </view>
  105. </view>
  106. </blcok>
  107. </view>
  108. <view class="g-userinfo-card" v-if="!placeId">
  109. <view class="r-user">
  110. <view class="user-title">用户信息 <text class="mini-text">至少需选择{{ countTotal }}人</text></view>
  111. <view class="invite">
  112. <zzx-icon name="wechat" size="16"></zzx-icon>
  113. <view style="margin-bottom: 8rpx;">邀请微信好友</view>
  114. <zzx-icon name="ashRight" size="12"></zzx-icon>
  115. <button class="g-share-btn" open-type="share"></button>
  116. </view>
  117. </view>
  118. <!-- <view class="user-tags">张三</view> -->
  119. <view class="r-user-list" v-for="item in userData" :key="item.id">
  120. <view class="minus-user" @click="deleteUser(item)">-</view>
  121. <view class="r-list">
  122. <view class="name">{{ item.fullName }}</view>
  123. <view class="id-num">身份证 {{ idCardHide(item.identityCard) }}</view>
  124. </view>
  125. </view>
  126. <view class="g-adduser-btn" @click="toUserList">
  127. <view class="add-icon">+</view>
  128. <view class="add-text">添加用户</view>
  129. </view>
  130. </view>
  131. <view class="g-usetips-card">
  132. <view class="use-title">{{ placeId ? '使用须知' : '购买须知' }}</view>
  133. <block v-if="previewCourseInfo?.usableCount && previewCourseInfo?.indate">
  134. <view class="use-title" style="font-size: 24rpx;margin-top: 14rpx;">有效期</view>
  135. <view class="use-text">购买后{{ previewCourseInfo?.indate }}天有效</view>
  136. <view class="use-title" style="font-size: 24rpx;margin-top: 14rpx;">除外日期</view>
  137. <view class="use-text">每<text v-for="item in previewCourseInfo?.downTime">{{ '周' + item + ' '
  138. }}</text>不可用
  139. </view>
  140. <view class="use-title" style="font-size: 24rpx;margin-top: 14rpx;">预约信息</view>
  141. <view class="use-text">{{ previewCourseInfo?.advanceTime == 0 ? '免预约' :
  142. '请你提前' + previewCourseInfo?.advanceTime + '小时预约' }}</view>
  143. <view class="use-title" style="font-size: 24rpx;margin-top: 14rpx;">适用人数</view>
  144. <view class="use-text">每张券最多{{ previewCourseInfo?.usableCount }}人使用</view>
  145. <view class="use-title" style="font-size: 24rpx;margin-top: 14rpx;">温馨提示</view>
  146. </block>
  147. <view class="use-text">
  148. <view class="item-text">
  149. <rich-text :nodes="previewCourseInfo?.reminder"></rich-text>
  150. </view>
  151. </view>
  152. <!-- <view class="use-tips-more"
  153. @click="RouterUtils.to_page(`/pages/index/useNotice/index?reminder=${previewCourseInfo?.reminder}`)">
  154. <view class="more-text">查看更多</view>
  155. <view class="use-line"></view>
  156. </view> -->
  157. </view>
  158. <view class="g-usetips-card">
  159. <view class="use-title">服务保障</view>
  160. <view class="use-text">
  161. <view>退款规则</view>
  162. <view class="item-text">
  163. {{ previewCourseInfo?.refundType == 1 ? '未消费随时退款,过期未消费自动退款。' : '不支退款,请慎重考虑后购买。' }}
  164. </view>
  165. </view>
  166. <!-- <view class="use-tips-more">
  167. <view class="more-text">查看更多</view>
  168. <view class="use-line"></view>
  169. </view> -->
  170. </view>
  171. <view style="height: 166rpx;"></view>
  172. <view class="footer footer-box">
  173. <view class="footer-price">
  174. <view class="total-price">合计:</view>
  175. <view class="price">
  176. <text class="mini-text">¥</text>
  177. <text>{{
  178. previewCourseInfo?.originalPrice ? (previewCourseInfo?.originalPrice * countTotal).toFixed(2) :
  179. ((previewCourseInfo?.sellingPrice
  180. || 0) * countTotal + totalInsurePrice).toFixed(2) }}</text>
  181. </view>
  182. <view class="discount">优惠¥
  183. <text v-if="buyType == 1">{{ previewCourseInfo?.sellingPrice.toFixed(2) }}</text>
  184. <text v-else>{{
  185. previewCourseInfo?.originalPrice ? (previewCourseInfo?.originalPrice -
  186. previewCourseInfo?.sellingPrice.toFixed(2)) * countTotal : ((previewCourseInfo?.sellingPrice
  187. -
  188. previewCourseInfo?.totalPrice.toFixed(2))) * countTotal }}</text>
  189. </view>
  190. </view>
  191. <view class="footer-btn" @click="submitOrder">
  192. <button>
  193. <view class="btn-price">
  194. <text v-if="buyType == 1">{{ (0 + totalInsurePrice).toFixed(2) }}</text>
  195. <text v-else>
  196. ¥{{ previewCourseInfo?.originalPrice ? (previewCourseInfo?.sellingPrice *
  197. countTotal).toFixed(2) :
  198. (((previewCourseInfo?.sellingPrice || 0) - ((previewCourseInfo?.sellingPrice || 0) -
  199. (previewCourseInfo?.totalPrice || 0))) * countTotal + totalInsurePrice).toFixed(2) }}</text>
  200. </view>
  201. <view class="btn-price">立即支付</view>
  202. </button>
  203. </view>
  204. </view>
  205. </view>
  206. <uni-popup ref="insurePopup" type="center">
  207. <view class="r-center-popup" v-if="agreementContent">
  208. <view class="r-popup-title">{{ agreementContent.protocolName }}</view>
  209. <view class="r-popup-content">
  210. <rich-text :nodes="agreementContent.protocolContent"></rich-text>
  211. </view>
  212. <view class="r-popup-footer">
  213. <view class="r-popup-needbtn" @click="toNeed">我需要购买保险</view>
  214. <view class="r-popup-refusebtn" @click="toRefuse">我拒绝购买保险</view>
  215. <view class="r-popup-checkbox" @click="select_insurance = !select_insurance">
  216. <zzx-icon :name="select_insurance ? 'selected' : 'unchecked'" size="14"></zzx-icon>
  217. <text>我已认真阅读及确认</text>
  218. </view>
  219. </view>
  220. </view>
  221. </uni-popup>
  222. </template>
  223. <script lang="ts" setup>
  224. import { ref, onMounted, computed } from 'vue';
  225. import { onLoad, onShareAppMessage } from '@dcloudio/uni-app';
  226. import { RouterUtils, TipsUtils, idCardHide, debounce } from '@/utils/util';
  227. import { http } from '@/utils/http'
  228. import { useCacheStore } from '@/stores/cache'
  229. const cache = useCacheStore()
  230. const insurePopup = ref()
  231. const select_insurance = ref(false)
  232. const loadType = ref(1)
  233. const buyType = ref()
  234. const placeId = ref()
  235. onLoad((options) => {
  236. console.log(options);
  237. loadType.value = options.type
  238. courseId.value = options.courseId
  239. placeId.value = options.placeId
  240. buyType.value = options.buyType
  241. orderFormData.value.type = options.orderType
  242. orderFormData.value.orFreeOrder = options.buyType
  243. orderFormData.value.amount = 1
  244. })
  245. onShareAppMessage((res) => {
  246. if (res.from === 'button') {
  247. console.log(res.target)
  248. }
  249. return {
  250. title: '邀请您加入',
  251. path: `pages/index/userList/index?userId=${cache.get('USER_INFO').id}`
  252. }
  253. })
  254. onMounted(() => {
  255. if (placeId.value) {
  256. getEventsDetail()
  257. } else {
  258. get_previewOrderCourse()
  259. }
  260. get_userData()
  261. getInsureData()
  262. })
  263. const toUserList = () => {
  264. RouterUtils.to_page('/pages/index/userList/index')
  265. }
  266. const userData = ref([])
  267. const get_userData = () => {
  268. uni.$on('userData', function (data) {
  269. userData.value = data
  270. if (data.length > 0) {
  271. let familyIds = data.map(item => item.id)
  272. orderFormData.value.familyIds = familyIds.join(',')
  273. } else {
  274. orderFormData.value.familyIds = []
  275. }
  276. })
  277. }
  278. const deleteUser = async (e) => {
  279. let res: any = await TipsUtils.tips_alert('确定删除该用户吗?', true)
  280. if (res.confirm) {
  281. userData.value = userData.value.filter(user => user.id !== e.id)
  282. let familyIds = userData.value.map(item => item.id)
  283. orderFormData.value.familyIds = familyIds.join(',')
  284. }
  285. }
  286. const priceDataListData = ref([])
  287. const insureId = ref()
  288. const gotoInsuracePage = (e1: any, e2: any) => {
  289. insureId.value = e1.id
  290. getFindByType(e1.insuranceName)
  291. priceDataListData.value = e2
  292. orderFormData.value.insureOrderInfoForm.insureId = e1.id
  293. }
  294. const agreementContent = ref()
  295. const getFindByType = (insuranceName: any) => {
  296. http.get('/my/feedback/findByType', { data: { insuranceName: insuranceName, protocolType: 0 }, loading: true }).then((res: any) => {
  297. agreementContent.value = res.result
  298. insurePopup.value.open()
  299. })
  300. }
  301. const courseId = ref()
  302. const previewCourseInfo = ref()
  303. const insureIdList = ref([]) // 保险列表
  304. const insurePrice = ref() // 保险价格
  305. // 课程预览
  306. const get_previewOrderCourse = () => {
  307. http.get('/order/previewOrderCourse', { data: { courseId: courseId.value }, loading: true }).then((res) => {
  308. previewCourseInfo.value = res.result
  309. orderFormData.value.productIds = res.result.id
  310. res.result.insureIdList.map((item: any) => {
  311. item.insuranceObvious = JSON.parse(item.insuranceObvious)
  312. item.insuranceObvious = [item.insuranceObvious]
  313. item.priceDataList.map((item2: any) => {
  314. if (item2.insureDay === 1) {
  315. insurePrice.value = item2.insurePrice
  316. }
  317. })
  318. })
  319. insureIdList.value = res.result.insureIdList
  320. })
  321. }
  322. // 场地预览
  323. const getEventsDetail = () => {
  324. http.get('/order/PreviewOrderPlaceGymnasiumNoFixation', { data: { placeId: placeId.value }, loading: true }).then((res) => {
  325. previewCourseInfo.value = res.result
  326. orderFormData.value.productIds = res.result.id || res.result.placeId
  327. })
  328. }
  329. const insureData = ref([])
  330. const getInsureData = () => {
  331. uni.$on('insureData', function (data) {
  332. insureData.value = data
  333. console.log(insureData.value, '投保人信息');
  334. orderFormData.value.insureOrderInfoForm.assertStartTime = insureData.value[0].startDate
  335. orderFormData.value.insureOrderInfoForm.assertEndTime = insureData.value[0].endDate
  336. orderFormData.value.insureOrderInfoForm.insurePriceId = insureData.value[0].slectObj.id
  337. if (data.length > 0) {
  338. let familyMembersIds = data[0].userData.map(item => item.id)
  339. orderFormData.value.insureOrderInfoForm.familyMembersIds = familyMembersIds.join(',')
  340. } else {
  341. orderFormData.value.insureOrderInfoForm.familyMembersIds = []
  342. }
  343. })
  344. }
  345. // 计算保费
  346. const totalInsurePrice = computed(() => {
  347. if (!insureData.value || insureData.value.length === 0) {
  348. return 0;
  349. }
  350. if (insureData.value.length === 1) {
  351. return parseFloat(insureData.value[0].totalPrice) || 0;
  352. }
  353. return insureData.value.reduce((total, insure) => total + (parseFloat(insure.totalPrice) || 0), 0);
  354. });
  355. const clearUser = async () => {
  356. let res: any = await TipsUtils.tips_alert('确定清除投保人信息吗?', true)
  357. if (res.confirm) {
  358. insureData.value = []
  359. }
  360. }
  361. const countTotal = ref(1)
  362. const minusNum = () => {
  363. if (countTotal.value > 1) {
  364. countTotal.value--
  365. orderFormData.value.amount = countTotal.value
  366. }
  367. }
  368. const addNum = () => {
  369. if (buyType.value == 1) return TipsUtils.tips_toast('试听课程不支持多个购买')
  370. if (courseId.value) {
  371. get_checkCourseLimitNum(countTotal.value + 1)
  372. } else {
  373. countTotal.value++
  374. }
  375. }
  376. const get_checkCourseLimitNum = (targetNum) => {
  377. http.get('/order/checkCourseLimitNum', {
  378. data: {
  379. courseId: courseId.value,
  380. limitNum: targetNum
  381. },
  382. loading: true
  383. }).then((res) => {
  384. if (res.result === true) {
  385. countTotal.value = targetNum
  386. } else {
  387. TipsUtils.tips_toast('超出可购数量')
  388. }
  389. })
  390. }
  391. const toNeed = () => {
  392. if (!select_insurance.value) return TipsUtils.tips_toast('请先阅读并同意协议')
  393. RouterUtils.to_page(`/pages/index/insure/index?priceDataList=${JSON.stringify(priceDataListData.value)}`)
  394. insurePopup.value.close()
  395. }
  396. const toRefuse = () => {
  397. if (select_insurance.value) {
  398. insurePopup.value.close()
  399. } else {
  400. TipsUtils.tips_toast('请先阅读并同意协议')
  401. }
  402. }
  403. let orderFormData = ref({
  404. type: null,
  405. orderType: null,
  406. orFreeOrder: null, //0正常 1试听
  407. productIds: null,
  408. amount: null,
  409. familyIds: '',
  410. insureOrderInfoForm: {
  411. insureId: '',
  412. assertStartTime: '',
  413. assertEndTime: '',
  414. insurePriceId: '',
  415. familyMembersIds: '',
  416. }
  417. })
  418. const orderCode = ref(null)
  419. const orderId = ref(null)
  420. const submitOrderImpl = () => {
  421. orderFormData.value.amount = countTotal.value
  422. // 计算总金额
  423. let totalPrice = 0;
  424. if (previewCourseInfo.value?.originalPrice) {
  425. totalPrice = previewCourseInfo.value.originalPrice * countTotal.value;
  426. } else {
  427. const sellingPrice = previewCourseInfo.value?.sellingPrice || 0;
  428. const totalPriceValue = previewCourseInfo.value?.totalPrice || 0;
  429. totalPrice = ((sellingPrice - (sellingPrice - totalPriceValue)) * countTotal.value + totalInsurePrice.value);
  430. }
  431. if (!placeId.value) {
  432. if (!userData.value) return TipsUtils.tips_toast('请添加用户信息')
  433. if (userData.value.length < countTotal.value) return TipsUtils.tips_toast(`请至少选择${countTotal.value}人`)
  434. if (userData.value.length > countTotal.value) return TipsUtils.tips_toast(`最多选择${countTotal.value}人`)
  435. orderFormData.value.orderType = 5
  436. orderFormData.value.type = 2
  437. } else {
  438. orderFormData.value.type = 0
  439. orderFormData.value.orderType = 2
  440. }
  441. let data = { ...orderFormData.value };
  442. if (!insureData.value || insureData.value.length === 0) {
  443. delete data.insureOrderInfoForm;
  444. }
  445. if (!userData || userData.value.length === 0) {
  446. delete data.familyIds
  447. }
  448. // 如果总金额为0,直接创建订单并跳转,不调用微信支付
  449. if (totalPrice === 0 || buyType.value == 1) {
  450. http.post('/order/createOrder', data, { loading: true }).then((res) => {
  451. orderCode.value = res.result.orderCode
  452. orderId.value = res.result.orderId
  453. // 直接查询订单状态,模拟支付成功
  454. getOrderQuery(orderCode.value, orderId.value)
  455. })
  456. return;
  457. }
  458. uni.requestSubscribeMessage({
  459. tmplIds: ['HbK-qbIC_iTY0w08xfkgirdeR_VrVhetLwEIBo3Lue4', 'T2icwNiI--oBnLfTiAniAoAJAwq1Ukb78bCjIcpuTRQ'],
  460. success(res) {
  461. TipsUtils.tips_toast('订阅成功')
  462. http.post('/order/createOrder', data, { loading: true }).then((res) => {
  463. orderCode.value = res.result.orderCode
  464. orderId.value = res.result.orderId
  465. paymentOrder(res.result.params)
  466. })
  467. },
  468. fail(err) {
  469. console.log(err, '订阅消息失败')
  470. http.post('/order/createOrder', data, { loading: true }).then((res) => {
  471. orderCode.value = res.result.orderCode
  472. orderId.value = res.result.orderId
  473. paymentOrder(res.result.params)
  474. })
  475. }
  476. })
  477. }
  478. const paymentOrder = (payInfo: object) => {
  479. // getOrderQuery(orderCode.value, orderId.value)
  480. console.log(payInfo, '支付参数');
  481. uni.requestPayment({
  482. provider: 'wxpay',
  483. ...payInfo,
  484. success: function (res) {
  485. console.log('支付成功', res);
  486. setTimeout(() => {
  487. getOrderQuery(orderCode.value, orderId.value)
  488. }, 500)
  489. },
  490. fail: function (err) {
  491. console.log('支付失败', err);
  492. if (err.errMsg == 'requestPayment:fail cancel') {
  493. RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${orderId.value}&orderType=${orderFormData.value.orderType}`)
  494. return
  495. } else {
  496. RouterUtils.to_page(`/pages/index/payError/index?errMsg=${err.errMsg}`)
  497. }
  498. // TipsUtils.tips_toast('支付失败,请稍后重试');
  499. }
  500. });
  501. }
  502. const submitOrder = debounce(submitOrderImpl, 500)
  503. // code编码 "100001支付成功";"100002查询失败"; "100003查询中 "; "100004支付失败"
  504. const getOrderQuery = (orderCode: string, orderId: string, retryCount = 0) => {
  505. http.get('/order/orderQuery', { data: { orderCode: orderCode }, loading: true }).then((res) => {
  506. if (res.result == '100001') {
  507. RouterUtils.to_page(`/pages/index/toBeUsed/index?orderId=${orderId}&orderType=${orderFormData.value.orderType}`)
  508. } else if (retryCount <= 3) {
  509. setTimeout(() => {
  510. getOrderQuery(orderCode, orderId, retryCount + 1)
  511. }, 1000)
  512. } else {
  513. if (res.result == '100003') {
  514. console.log('查询中,但已达到最大查询次数')
  515. } else if (res.result == '100002') {
  516. console.log('查询失败')
  517. } else if (res.result == '100004') {
  518. console.log('支付失败')
  519. TipsUtils.tips_toast('支付失败')
  520. }
  521. }
  522. }).catch((error) => {
  523. console.error('查询订单失败:', error)
  524. if (retryCount < 2) {
  525. setTimeout(() => {
  526. getOrderQuery(orderCode, orderId, retryCount + 1)
  527. }, 1000)
  528. }
  529. })
  530. }
  531. </script>
  532. <style lang="less" scoped>
  533. .g-orderinfo-card {
  534. background: #FFFFFF;
  535. border-radius: 32rpx;
  536. padding: 20rpx;
  537. margin-top: 20rpx;
  538. .g-shoping-info {
  539. display: flex;
  540. align-items: center;
  541. gap: 20rpx;
  542. .shoping-img {
  543. width: 200rpx;
  544. height: 200rpx;
  545. border-radius: 32rpx;
  546. }
  547. .shoping-info {
  548. width: 440rpx;
  549. .name {
  550. font-weight: 800;
  551. font-size: 32rpx;
  552. color: #222222;
  553. line-height: 44rp
  554. }
  555. .price-info {
  556. display: flex;
  557. align-items: center;
  558. justify-content: space-between;
  559. margin-top: 26rpx;
  560. .price {
  561. font-weight: 800;
  562. font-size: 48rpx;
  563. color: #FB5B5B;
  564. }
  565. .price-stepper {
  566. display: flex;
  567. align-items: center;
  568. border: 1rpx solid #F0F0F0;
  569. border-radius: 8rpx;
  570. .minus {
  571. text-align: center;
  572. width: 44rpx;
  573. border-right: 1rpx solid #F0F0F0;
  574. }
  575. &>input {
  576. width: 80rpx;
  577. font-size: 28rpx;
  578. color: #222222;
  579. text-align: center;
  580. }
  581. .add {
  582. text-align: center;
  583. width: 44rpx;
  584. border-left: 1rpx solid #F0F0F0;
  585. }
  586. }
  587. }
  588. }
  589. }
  590. .g-shoping-total {
  591. height: 148rpx;
  592. margin-top: 24rpx;
  593. border-top: 1rpx solid #F0F0F0;
  594. .total-price {
  595. margin-top: 24rpx;
  596. display: flex;
  597. align-items: center;
  598. justify-content: space-between;
  599. font-size: 28rpx;
  600. color: #222222;
  601. }
  602. }
  603. .subtotal {
  604. border-top: 1rpx solid #F0F0F0;
  605. height: 84rpx;
  606. line-height: 84rpx;
  607. font-weight: bold;
  608. font-size: 28rpx;
  609. color: #FB5B5B;
  610. text-align: right;
  611. }
  612. }
  613. .g-buy-tips {
  614. margin-top: 20rpx;
  615. .tips-title {
  616. font-weight: bold;
  617. font-size: 32rpx;
  618. color: #222222;
  619. }
  620. .tips-info-card {
  621. background: #FFFFFF;
  622. border-radius: 32rpx;
  623. padding: 20rpx;
  624. margin-top: 20rpx;
  625. .title {
  626. font-weight: bold;
  627. font-size: 28rpx;
  628. color: #222222;
  629. }
  630. .text {
  631. font-size: 24rpx;
  632. color: #AAAAAA;
  633. margin-top: 20rpx;
  634. margin-bottom: 20rpx;
  635. }
  636. }
  637. }
  638. .r-insurance {
  639. margin-top: 20rpx;
  640. padding: 20rpx;
  641. background: #FFFFFF;
  642. border-radius: 32rpx;
  643. .r-insurance-infobox {
  644. display: flex;
  645. align-items: center;
  646. justify-content: space-between;
  647. gap: 20rpx;
  648. margin-bottom: 20rpx;
  649. .r-image-box {
  650. &>image {
  651. width: 200rpx;
  652. height: 200rpx;
  653. border-radius: 32rpx;
  654. }
  655. }
  656. .r-insurance-title {
  657. .r-insurance-name {
  658. display: flex;
  659. align-items: center;
  660. gap: 16rpx;
  661. .r-name {
  662. font-weight: 800;
  663. font-size: 28rpx;
  664. color: #222222;
  665. }
  666. .r-tags {
  667. width: 136rpx;
  668. height: 36rpx;
  669. background: #FDD143;
  670. border-radius: 8rpx;
  671. font-size: 22rpx;
  672. color: #222222;
  673. text-align: center;
  674. line-height: 36rpx;
  675. }
  676. }
  677. .r-insurance-desc {
  678. width: 440rpx;
  679. margin-top: 10rpx;
  680. font-size: 24rpx;
  681. color: #AAAAAA;
  682. }
  683. .r-insurance-type {
  684. margin-top: 10rpx;
  685. font-size: 24rpx;
  686. color: #AAAAAA;
  687. }
  688. .r-insurance-price {
  689. display: flex;
  690. align-items: center;
  691. justify-content: space-between;
  692. .r-price {
  693. font-weight: bold;
  694. font-size: 28rpx;
  695. color: #FB5B5B;
  696. }
  697. .r-insurance-btn {
  698. width: 200rpx;
  699. height: 68rpx;
  700. background: #C8FF0C;
  701. border-radius: 60rpx;
  702. font-weight: bold;
  703. font-size: 28rpx;
  704. color: #222222;
  705. text-align: center;
  706. line-height: 68rpx;
  707. }
  708. }
  709. }
  710. }
  711. .r-insurance-adduser {
  712. background: #F6F6F6;
  713. border-radius: 32rpx;
  714. padding: 20rpx;
  715. margin-top: 20rpx;
  716. .r-adduser-btn {
  717. display: flex;
  718. align-items: center;
  719. justify-content: flex-end;
  720. gap: 20rpx;
  721. .r-celar {
  722. width: 192rpx;
  723. height: 60rpx;
  724. background: #FFFFFF;
  725. border-radius: 60rpx;
  726. border: 2rpx solid #FB5B5B;
  727. font-weight: bold;
  728. font-size: 28rpx;
  729. color: #FB5B5B;
  730. text-align: center;
  731. line-height: 68rpx;
  732. }
  733. .r-edit {
  734. width: 200rpx;
  735. height: 68rpx;
  736. background: #C8FF0C;
  737. border-radius: 60rpx;
  738. font-weight: bold;
  739. font-size: 28rpx;
  740. color: #222222;
  741. text-align: center;
  742. line-height: 68rpx;
  743. }
  744. }
  745. .r-userinfo-list {
  746. .r-userinfo-item {
  747. display: flex;
  748. align-items: center;
  749. justify-content: space-between;
  750. margin-top: 20rpx;
  751. .r-item-title {
  752. font-size: 28rpx;
  753. color: #AAAAAA;
  754. }
  755. .r-item-info {
  756. font-size: 28rpx;
  757. color: #222222;
  758. }
  759. }
  760. }
  761. }
  762. }
  763. .g-userinfo-card {
  764. margin-top: 20rpx;
  765. padding: 20rpx;
  766. background: #FFFFFF;
  767. border-radius: 32rpx;
  768. .r-user {
  769. display: flex;
  770. align-items: center;
  771. justify-content: space-between;
  772. .user-title {
  773. font-weight: bold;
  774. font-size: 28rpx;
  775. color: #222222;
  776. }
  777. .invite {
  778. display: flex;
  779. align-items: center;
  780. gap: 8rpx;
  781. font-size: 24rpx;
  782. color: #AAAAAA;
  783. position: relative;
  784. .g-share-btn {
  785. position: absolute;
  786. width: 200rpx;
  787. height: 60rpx;
  788. opacity: 0;
  789. }
  790. }
  791. }
  792. .user-tags {
  793. margin-top: 20rpx;
  794. width: 112rpx;
  795. height: 40rpx;
  796. background: #FDD143;
  797. border-radius: 8rpx;
  798. line-height: 40rpx;
  799. font-weight: bold;
  800. font-size: 28rpx;
  801. color: #222222;
  802. text-align: center;
  803. font-size: 28rpx;
  804. color: #222222;
  805. }
  806. .r-user-list {
  807. margin-top: 20rpx;
  808. display: flex;
  809. align-items: center;
  810. gap: 20rpx;
  811. border-top: 1rpx solid #F0F0F0;
  812. height: 140rpx;
  813. .minus-user {
  814. width: 30rpx;
  815. height: 30rpx;
  816. border-radius: 50%;
  817. background: #FB5B5B;
  818. text-align: center;
  819. line-height: 20rpx;
  820. font-weight: 600;
  821. color: #fff;
  822. font-size: 40rpx;
  823. }
  824. .r-list {
  825. .name {
  826. font-weight: bold;
  827. font-size: 28rpx;
  828. color: #222222;
  829. }
  830. .id-num {
  831. font-size: 28rpx;
  832. color: #222222;
  833. }
  834. }
  835. }
  836. .g-adduser-btn {
  837. display: flex;
  838. height: 88rpx;
  839. align-items: center;
  840. justify-content: center;
  841. gap: 20rpx;
  842. border-top: 1rpx solid #F0F0F0;
  843. .add-icon {
  844. width: 30rpx;
  845. height: 30rpx;
  846. border-radius: 50%;
  847. background: #FDD143;
  848. font-size: 30rpx;
  849. font-weight: 600;
  850. color: #fff;
  851. text-align: center;
  852. line-height: 20rpx;
  853. }
  854. .add-text {
  855. font-size: 28rpx;
  856. color: #FDD143;
  857. }
  858. }
  859. }
  860. .g-usetips-card {
  861. margin-top: 20rpx;
  862. padding: 20rpx;
  863. background: #FFFFFF;
  864. border-radius: 32rpx;
  865. .use-title {
  866. font-weight: bold;
  867. font-size: 28rpx;
  868. color: #222222;
  869. }
  870. .use-text {
  871. font-size: 24rpx;
  872. color: #222222;
  873. .item-text {
  874. margin-top: 20rpx;
  875. }
  876. }
  877. .use-tips-more {
  878. margin-top: 20rpx;
  879. .more-text {
  880. text-align: center;
  881. font-size: 24rpx;
  882. color: #CCCCCC;
  883. }
  884. .use-line {
  885. margin: auto;
  886. margin-top: 10rpx;
  887. width: 38rpx;
  888. height: 4rpx;
  889. background: #CCCCCC;
  890. border-radius: 2rpx;
  891. }
  892. }
  893. }
  894. .footer {
  895. left: 0;
  896. .footer-price {
  897. display: flex;
  898. align-items: center;
  899. .total-price {
  900. font-weight: bold;
  901. font-size: 28rpx;
  902. color: #222222;
  903. }
  904. .price {
  905. font-weight: 800;
  906. font-size: 48rpx;
  907. color: #FB5B5B;
  908. }
  909. .discount {
  910. margin-left: 10rpx;
  911. font-size: 24rpx;
  912. color: #222222;
  913. }
  914. }
  915. .footer-btn {
  916. &>button {
  917. width: 226rpx;
  918. height: 100rpx;
  919. background: #C8FF0C;
  920. border-radius: 60rpx;
  921. font-weight: bold;
  922. font-size: 26rpx;
  923. color: #222222;
  924. line-height: 30rpx;
  925. .btn-price:nth-child(1) {
  926. margin-top: 20rpx;
  927. }
  928. }
  929. &>button::after {
  930. border: none;
  931. }
  932. }
  933. }
  934. .r-center-popup {
  935. width: 646rpx;
  936. max-height: 1000rpx;
  937. background: #F6F6F6;
  938. border-radius: 32rpx;
  939. padding: 20rpx;
  940. .r-popup-title {
  941. font-weight: bold;
  942. font-size: 32rpx;
  943. color: #222222;
  944. text-align: center;
  945. }
  946. .r-popup-content {
  947. margin-top: 28rpx;
  948. font-size: 28rpx;
  949. color: #222222;
  950. max-height: 600rpx;
  951. overflow: auto;
  952. }
  953. .r-popup-footer {
  954. margin-top: 20rpx;
  955. .r-popup-needbtn {
  956. margin: auto;
  957. width: 598rpx;
  958. height: 100rpx;
  959. background: #C8FF0C;
  960. border-radius: 60rpx;
  961. font-weight: bold;
  962. font-size: 32rpx;
  963. color: #222222;
  964. text-align: center;
  965. line-height: 100rpx;
  966. }
  967. .r-popup-refusebtn {
  968. margin: auto;
  969. margin-top: 24rpx;
  970. width: 598rpx;
  971. height: 100rpx;
  972. background: #f0eeee;
  973. border-radius: 60rpx;
  974. font-weight: bold;
  975. font-size: 32rpx;
  976. color: #AAAAAA;
  977. text-align: center;
  978. line-height: 100rpx;
  979. }
  980. .r-popup-checkbox {
  981. margin-top: 20rpx;
  982. display: flex;
  983. align-items: center;
  984. justify-content: center;
  985. gap: 16rpx;
  986. font-size: 24rpx;
  987. color: #AAAAAA;
  988. &>text {
  989. margin-bottom: 8rpx;
  990. }
  991. }
  992. }
  993. }
  994. </style>