order-detail.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. // pages/orders/order-detail.ts
  2. import { api_executeOrder, api_executePayment, api_queryByParamName, api_userPaymentOrderDetail, api_userPaymentOrderUnpaid } from "../../api/login";
  3. import { api_sysAreaQueryAllProvince, api_userReceiveAddressPage, api_userReceiveAddressSave } from "../../api/new";
  4. import { formatPrice, GRADE_ENUM } from "../../utils/util";
  5. // 获取应用实例
  6. const app = getApp<IAppOption>()
  7. Page({
  8. /**
  9. * 页面的初始数据
  10. */
  11. data: {
  12. status: 'WAIT_PAY',
  13. statusList: {
  14. WAIT_PAY: {
  15. logo: './images/ing.png',
  16. title: '等待付款',
  17. content: '请尽快完成支付,以便我们为您处理订单'
  18. },
  19. },
  20. backParams: null,
  21. addressList: [] as any,
  22. goodsInfo: {} as any,
  23. hasInstrument: false, // 是否有乐器
  24. cacheArea: [] as { cityCode: string, shiftCityCode: string }[], // 临时存储的对应关系
  25. receiveAddress: '', // 选择的地址信息
  26. receiveAddressInfo: {
  27. addressDetail: '',
  28. name: '',
  29. phoneNumber: ''
  30. },
  31. userBeneficiaryId: '', // 添加购买人信息
  32. userBeneficiaryInfo: {
  33. name: '',
  34. phoneNumber: '',
  35. schoolInfo: ''
  36. },
  37. isExpanded: false,
  38. paymentType: null as any, // 支付类型
  39. paymentChannel: null as any,
  40. serviceShow: true,
  41. showArea: false,
  42. areaList: [] as any,
  43. currentValues: [] as any,
  44. addressShow: false,
  45. addressAfterLeave: false,
  46. // 添加地址表单信息
  47. id: "",
  48. name: '',
  49. phoneNumber: '',
  50. detailAddress: '',
  51. cityCode: null as any,
  52. cityName: "",
  53. provinceCode: 0,
  54. provinceName: "",
  55. regionCode: '',
  56. regionName: "",
  57. },
  58. /**
  59. * 生命周期函数--监听页面加载
  60. */
  61. onLoad(options: any) {
  62. this.queryPayType()
  63. if (options.orderInfo) {
  64. console.log('goods', options)
  65. const goods = JSON.parse(decodeURIComponent(options.orderInfo));
  66. console.log(goods, 'goods', options)
  67. const infos = {
  68. allSalePrice: 0,
  69. allOriginPrice: 0,
  70. originIntegerPart: '',
  71. originDecimalPart: '',
  72. allDiscountPrice: '',
  73. discountIntegerPart: '',
  74. discountDecimalPart: '',
  75. integerPart: '',
  76. decimalPart: '',
  77. name: '',
  78. shopId: '',
  79. orderNo: options.orderNo || '',
  80. goodsList: [] as any,
  81. createTime: '', // 订单时间
  82. }
  83. // 是否有乐器
  84. let hasInstrument = false
  85. for (let i in goods) {
  86. const item = goods[i]
  87. if (item.goodsType === "INSTRUMENTS") {
  88. hasInstrument = true
  89. }
  90. infos.name = infos.name ? infos.name + '+' + item.name : item.name
  91. infos.shopId = item.shopId
  92. const afterPrice: any = formatPrice(item.salePrice)
  93. // console.log(infos.goodsList, 'infos.goodsList')
  94. infos.goodsList.push({
  95. ...item,
  96. originalPrice: formatPrice(Number(item.originalPrice || 0), 'ALL'),
  97. typePeriod: this.formatPeriod(item.num, item.period),
  98. ...afterPrice
  99. })
  100. infos.allSalePrice += Number(item.salePrice)
  101. infos.allOriginPrice += Number(item.originalPrice)
  102. }
  103. const allAfterPrice: any = formatPrice(infos.allSalePrice)
  104. infos.allDiscountPrice = formatPrice(infos.allOriginPrice - infos.allSalePrice, 'ALL') as string
  105. const allDiscount: any = formatPrice(infos.allOriginPrice - infos.allSalePrice)
  106. infos.integerPart = allAfterPrice.integerPart
  107. infos.decimalPart = allAfterPrice.decimalPart
  108. infos.discountIntegerPart = allDiscount.integerPart
  109. infos.discountDecimalPart = allDiscount.decimalPart
  110. const allOriginPrices: any = formatPrice(infos.allOriginPrice)
  111. infos.originIntegerPart = allOriginPrices.integerPart
  112. infos.originDecimalPart = allOriginPrices.decimalPart
  113. this.setData({
  114. goodsInfo: infos,
  115. userBeneficiaryId: options.userBeneficiaryId,
  116. status: options.status || '',
  117. hasInstrument
  118. }, () => {
  119. this.getOrderDetail()
  120. });
  121. }
  122. },
  123. /** 获取订单详情 */
  124. async getOrderDetail() {
  125. try {
  126. if (!this.data.goodsInfo.orderNo) return
  127. const { data } = await api_userPaymentOrderDetail(this.data.goodsInfo.orderNo, {
  128. version: 'V2'
  129. });
  130. const result = data.data || {}
  131. const addresses: any = result.addresses
  132. const beneficiary: any = result.beneficiary
  133. const tempSchoolAddress = [beneficiary?.provinceName, beneficiary?.cityName || '', beneficiary?.regionName || '', beneficiary?.schoolAreaName, GRADE_ENUM[beneficiary?.currentGradeNum], beneficiary?.currentClass + '班']
  134. this.setData({
  135. receiveAddress: addresses?.id,
  136. receiveAddressInfo: {
  137. addressDetail: addresses?.detailAddress,
  138. name: addresses?.name,
  139. phoneNumber: addresses?.phoneNumber
  140. },
  141. userBeneficiaryId: beneficiary.schoolAreaId, // 添加购买人信息
  142. userBeneficiaryInfo: {
  143. name: beneficiary.name,
  144. phoneNumber: beneficiary.phone,
  145. schoolInfo: tempSchoolAddress.join('')
  146. },
  147. status: result.wechatStatus,
  148. 'goodsInfo.createTime': result.createTime
  149. }, () => {
  150. console.log(this.data)
  151. })
  152. } catch {
  153. //
  154. }
  155. },
  156. // 格式化类型
  157. formatPeriod(num: number, type: string) {
  158. if (!type) return ''
  159. const template: any = {
  160. DAY: "天",
  161. MONTH: "月",
  162. YEAR: "年"
  163. }
  164. if (type === "YEAR" && num >= 99) {
  165. return '终身'
  166. }
  167. return num + (template[type] || '')
  168. },
  169. // 获取后台配置的支付方式
  170. async queryPayType() {
  171. try {
  172. // wxlite_payment_service_provider
  173. const { data } = await api_queryByParamName({
  174. paramName: app.globalData.appId
  175. });
  176. if (data.code == 200) {
  177. const paramValue = data.data.paramValue ? JSON.parse(data.data.paramValue) : {}
  178. this.setData({
  179. paymentType: paramValue.vendor,
  180. paymentChannel: paramValue.channel
  181. });
  182. }
  183. } catch (error) {
  184. console.log(error, "error");
  185. }
  186. },
  187. /** 添加收货地址 */
  188. onSelectAddress() {
  189. console.log(this.data.addressList.length > 0, this.data.receiveAddress)
  190. if (this.data.addressList.length > 0 || this.data.receiveAddress) {
  191. wx.navigateTo({
  192. url: `../address/index?receiveAddress=${this.data.receiveAddress}`,
  193. })
  194. } else {
  195. this.onShowAddress()
  196. }
  197. },
  198. onPayError(message?: string) {
  199. wx.hideLoading()
  200. wx.showToast({
  201. title: message || '支付取消',
  202. icon: 'none'
  203. })
  204. },
  205. // 购买
  206. async onSubmit() {
  207. if (!this.data.receiveAddress && this.data.hasInstrument) {
  208. wx.showToast({
  209. title: '请选择收货地址',
  210. icon: 'none'
  211. })
  212. return
  213. }
  214. wx.showLoading({
  215. mask: true,
  216. title: "订单提交中...",
  217. });
  218. try {
  219. const { allSalePrice, shopId, name, orderNo, goodsList } = this.data.goodsInfo
  220. const goodsInfos: any = []
  221. goodsList.forEach((item: any) => {
  222. goodsInfos.push({
  223. "goodsId": item.id,
  224. "goodsNum": 1,
  225. "goodsType": item.goodsType,
  226. "paymentCashAmount": item.salePrice,
  227. "paymentCouponAmount": 0
  228. })
  229. })
  230. if (orderNo) {
  231. const { data } = await api_userPaymentOrderUnpaid({
  232. orderNo: orderNo,
  233. paymentType: 'WECHAT_MINI'
  234. })
  235. if (data.code === 200) {
  236. const { paymentConfig, paymentType, orderNo } = data.data.paymentConfig
  237. this.onExecutePay(paymentConfig, paymentType, orderNo)
  238. } else {
  239. this.onPayError()
  240. }
  241. } else {
  242. const { data } = await api_executeOrder({
  243. orderType: "WECHAT_MINI",
  244. paymentType: this.data.paymentType,
  245. paymentCashAmount: allSalePrice,
  246. paymentCouponAmount: 0,
  247. shopId: shopId,
  248. openId: app.globalData.userInfo?.liteOpenid,
  249. goodsInfos: goodsInfos,
  250. receiveAddress: this.data.receiveAddress,
  251. userBeneficiaryId: this.data.userBeneficiaryId,
  252. orderName: name,
  253. orderDesc: name
  254. })
  255. if (data.code === 200) {
  256. const { paymentConfig, paymentType, orderNo } = data.data
  257. this.onExecutePay(paymentConfig, paymentType, orderNo)
  258. } else if (data.code === 5200) {
  259. wx.hideLoading()
  260. wx.showToast({
  261. title: data.message,
  262. icon: 'none'
  263. })
  264. } else if ([5435, 5436, 5437, 5439, 5442, 5443, 5408, 5427, 5432].includes(data.code)) {
  265. wx.hideLoading()
  266. wx.showToast({
  267. title: data.message,
  268. icon: 'none'
  269. })
  270. setTimeout(() => {
  271. wx.navigateBack()
  272. }, 1000);
  273. } else {
  274. this.onPayError()
  275. }
  276. }
  277. } catch {
  278. wx.hideLoading()
  279. }
  280. },
  281. async onExecutePay(paymentConfig: any, paymentType: string, orderNo: string) {
  282. wx.login({
  283. success: async (wxres: any) => {
  284. const res = await api_executePayment({
  285. merOrderNo: paymentConfig.merOrderNo,
  286. paymentChannel: this.data.paymentChannel || 'wx_lite', // 'wx_pub', //
  287. paymentType,
  288. userId: app.globalData.userInfo?.id,
  289. code: wxres.code,
  290. wxMiniAppId: app.globalData.appId
  291. // code: '011yjYkl289aye4q2zml24UEWT3yjYkn',
  292. // wxPubAppId: 'wxbde13f59d40cb4f2'
  293. })
  294. wx.hideLoading()
  295. if (res.data.code === 200) {
  296. this.onPay(paymentType, res.data.data.reqParams, orderNo)
  297. } else if ([5435, 5436, 5437, 5439, 5442, 5443, 5408, 5427, 5432].includes(res.data.code)) {
  298. wx.hideLoading()
  299. wx.showToast({
  300. title: res.data.message,
  301. icon: 'none'
  302. })
  303. setTimeout(() => {
  304. wx.navigateBack()
  305. }, 1000);
  306. } else {
  307. this.onPayError(res.data.message)
  308. }
  309. },
  310. fail: () => {
  311. this.onPayError()
  312. }
  313. })
  314. },
  315. onPay(paymentType: string, paymentConfig: any, orderNo: string) {
  316. const isYeePay = paymentType.indexOf('yeepay') !== -1
  317. const prePayInfo = isYeePay ? JSON.parse(paymentConfig.prePayTn)
  318. : paymentConfig?.expend
  319. ? JSON.parse(paymentConfig?.expend?.pay_info)
  320. : paymentConfig
  321. const that = this
  322. wx.requestPayment({
  323. timeStamp: prePayInfo.timeStamp,
  324. nonceStr: prePayInfo.nonceStr,
  325. package: prePayInfo.package ? prePayInfo.package : prePayInfo.packageValue,
  326. paySign: prePayInfo.paySign,
  327. signType: prePayInfo.signType ? prePayInfo.signType : 'MD5',
  328. success() {
  329. wx.showToast({ title: '支付成功', icon: 'success' });
  330. wx.redirectTo({
  331. url: '/pages/orders/order-result?orderNo=' + orderNo
  332. })
  333. },
  334. fail(ressonInfo) {
  335. console.log('支付失败', ressonInfo)
  336. that.onPayError()
  337. that.setData({
  338. 'goodsInfo.orderNo': orderNo
  339. }, () => {
  340. that.getOrderDetail()
  341. })
  342. }
  343. })
  344. },
  345. /**
  346. * 生命周期函数--监听页面初次渲染完成
  347. */
  348. onReady() {
  349. },
  350. /**
  351. * 生命周期函数--监听页面显示
  352. */
  353. onShow() {
  354. if (this.data.backParams) {
  355. // console.log(this.data.backParams, 'backParams'); // { key: 'value' }
  356. const backParams: any = this.data.backParams || {};
  357. this.setData({
  358. receiveAddress: backParams.receiveAddress,
  359. receiveAddressInfo: backParams.receiveAddressInfo,
  360. backParams: null // 清空参数
  361. })
  362. }
  363. this.getAddress()
  364. this.setData({
  365. serviceShow: true,
  366. })
  367. },
  368. onHide() {
  369. this.setData({
  370. serviceShow: false
  371. })
  372. },
  373. /** 地址列表 */
  374. async getAddress() {
  375. try {
  376. const { data } = await api_userReceiveAddressPage({ page: 1, rows: -1 })
  377. this.setData({
  378. addressList: data.data.rows || []
  379. }, () => {
  380. if (this.data.addressList.length <= 0) {
  381. this.getAreas()
  382. }
  383. })
  384. } catch {
  385. //
  386. }
  387. },
  388. /** 获取省市区 */
  389. async getAreas() {
  390. try {
  391. const { data } = await api_sysAreaQueryAllProvince({})
  392. const areaList: any = this.formateArea(data.data)
  393. const currentValues = []
  394. if (areaList?.province_list) {
  395. // 获取第一个键值对
  396. const firstKey = Object.keys(areaList?.province_list)[0];
  397. // 通过键获取值
  398. const firstValue = areaList?.province_list[firstKey];
  399. currentValues.push({
  400. code: firstKey,
  401. name: firstValue
  402. })
  403. }
  404. if (areaList?.city_list) {
  405. // 获取第一个键值对
  406. const firstKey = Object.keys(areaList?.city_list)[0];
  407. // 通过键获取值
  408. const firstValue = areaList?.city_list[firstKey];
  409. currentValues.push({
  410. code: firstKey,
  411. name: firstValue
  412. })
  413. }
  414. if (areaList?.county_list) {
  415. // 获取第一个键值对
  416. const firstKey = Object.keys(areaList?.county_list)[0];
  417. // 通过键获取值
  418. const firstValue = areaList?.county_list[firstKey];
  419. currentValues.push({
  420. code: firstKey,
  421. name: firstValue
  422. })
  423. }
  424. this.setData({
  425. areaList,
  426. currentValues
  427. })
  428. } catch {
  429. //
  430. }
  431. },
  432. formateArea(area: any[]) {
  433. const province_list: { [_: string]: string } = {};
  434. const city_list: { [_: string]: string } = {};
  435. const county_list: { [_: string]: string } = {};
  436. area.forEach((item: any) => {
  437. province_list[item.code] = item.name;
  438. });
  439. area.forEach((item: any) => {
  440. item.areas && item.areas.forEach((city: any, index: number) => {
  441. let code = city.code + ""
  442. // 某些数据不标准 这里需要转换一下
  443. if (code[4] !== "0" || code[5] !== "0") {
  444. // 现在把区域的数据改为市的
  445. const newCode = code.substring(0, 2) + (index < 10 ? `a${index}` : index < 20 ? `b${index - 10}` : index < 30 ? `c${index - 20}` : `d${index - 30}`) + "00";
  446. this.data.cacheArea.push({
  447. cityCode: code,
  448. shiftCityCode: newCode
  449. })
  450. code = newCode
  451. }
  452. city_list[code] = city.name;
  453. });
  454. });
  455. area.forEach((item: any) => {
  456. item.areas && item.areas.forEach((city: any) => {
  457. city.areas && city.areas.forEach((county: any) => {
  458. county_list[county.code] = county.name;
  459. });
  460. });
  461. });
  462. return {
  463. province_list,
  464. city_list,
  465. county_list
  466. };
  467. },
  468. // 转换
  469. formateCityCode(reverse?: boolean) {
  470. if (!this.data.regionCode && this.data.cityCode) {
  471. const cityCodeObj = this.data.cacheArea.find((item: any) => {
  472. return item[reverse ? "cityCode" : "shiftCityCode"] == this.data.cityCode
  473. })
  474. return cityCodeObj ? cityCodeObj[reverse ? "shiftCityCode" : "cityCode"] : ""
  475. }
  476. return this.data.cityCode
  477. },
  478. /** 显示选择地区 */
  479. async onShowAreaList() {
  480. this.setData({
  481. showArea: true
  482. })
  483. },
  484. /** 关闭选择地区 */
  485. onCloseAreaList() {
  486. this.setData({
  487. showArea: false
  488. })
  489. },
  490. /** 确定选择地区 */
  491. submitArea(e: any) {
  492. const selectedOptions: any = e.detail.values
  493. this.setData({
  494. provinceCode: selectedOptions[0].code,
  495. cityCode: selectedOptions[1].code,
  496. regionCode: selectedOptions[2]?.code || null,
  497. provinceName: selectedOptions[0].name || '',
  498. cityName: selectedOptions[1].name || '',
  499. regionName: selectedOptions[2]?.name || '',
  500. showArea: false,
  501. })
  502. },
  503. onShowAddress() {
  504. this.setData({
  505. addressAfterLeave: false,
  506. addressShow: true
  507. })
  508. },
  509. onCloseAddress() {
  510. this.setData({
  511. addressShow: false
  512. })
  513. },
  514. onAddressAfterLeave() {
  515. this.setData({
  516. addressAfterLeave: true,
  517. name: '',
  518. phoneNumber: '',
  519. detailAddress: '',
  520. cityCode: null,
  521. cityName: "",
  522. provinceCode: 0,
  523. provinceName: "",
  524. regionCode: '',
  525. regionName: ""
  526. })
  527. },
  528. /** 创建/修改收货地址 */
  529. async onOperationAddress() {
  530. const addressForm = this.data
  531. try {
  532. if (!addressForm.name) {
  533. wx.showToast({
  534. title: '请输入收货人姓名',
  535. icon: "none"
  536. })
  537. return
  538. }
  539. if (!addressForm.phoneNumber || !/^1[3456789]\d{9}$/.test(addressForm.phoneNumber)) {
  540. wx.showToast({
  541. title: '请输入正确的手机号码',
  542. icon: "none"
  543. })
  544. return
  545. }
  546. if (!addressForm.provinceCode || !addressForm.cityCode) {
  547. wx.showToast({
  548. title: '请选择地区',
  549. icon: "none"
  550. })
  551. return
  552. }
  553. if (!addressForm.detailAddress) {
  554. wx.showToast({
  555. title: '请输入详细地址',
  556. icon: "none"
  557. })
  558. return
  559. }
  560. const citycode = this.formateCityCode()
  561. const params = {
  562. name: addressForm.name,
  563. phoneNumber: addressForm.phoneNumber,
  564. province: addressForm.provinceCode,
  565. city: citycode,
  566. region: addressForm.regionCode || '',
  567. detailAddress: addressForm.detailAddress
  568. }
  569. const { data } = await api_userReceiveAddressSave({
  570. ...params
  571. })
  572. wx.showToast({
  573. title: '添加成功',
  574. icon: 'none'
  575. })
  576. this.setData({
  577. receiveAddress: data.data, // 选择的地址信息
  578. receiveAddressInfo: {
  579. addressDetail: (addressForm.provinceName || '') + (addressForm.cityName || '') + (addressForm.regionName || '') + addressForm.detailAddress,
  580. name: addressForm.name,
  581. phoneNumber: addressForm.phoneNumber
  582. }
  583. })
  584. this.onCloseAddress()
  585. } catch (e) {
  586. //
  587. console.log(e, '1212')
  588. }
  589. },
  590. onExpanded() {
  591. this.setData({
  592. isExpanded: !this.data.isExpanded
  593. })
  594. },
  595. onCopy(e: { currentTarget: any }) {
  596. wx.setClipboardData({
  597. data: e.currentTarget.dataset.orderno,
  598. success: () => {
  599. wx.showToast({title: '复制成功', icon: 'none'})
  600. },
  601. fail: () => {
  602. wx.showToast({title: '复制失败,请稍后再试', icon: 'none'})
  603. }
  604. })
  605. },
  606. /**
  607. * 用户点击右上角分享
  608. */
  609. onShareAppMessage() {
  610. return {
  611. title: '器乐数字AI工具',
  612. path: '/pages/index/index',
  613. imageUrl: 'https://oss.dayaedu.com/ktyq/1739764429916.png'
  614. }
  615. }
  616. })