order-detail.ts 18 KB

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