鸿宇研学生前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

403 lines
11 KiB

  1. <template>
  2. <view class="page__view">
  3. <navbar title="填写订单" leftClick @leftClick="$utils.navigateBack" />
  4. <view class="main">
  5. <productCard :data="orderInfo"></productCard>
  6. <uv-form
  7. ref="form"
  8. :model="form"
  9. errorType="toast"
  10. >
  11. <view class="card">
  12. <view class="card-header">联系人信息</view>
  13. <view class="form-item">
  14. <uv-form-item prop="name" :customStyle="formItemStyle">
  15. <view class="form-item-label">
  16. <image class="icon" src="@/pages_order/static/icon-require.png" mode="widthFix"></image>
  17. 真实姓名
  18. </view>
  19. <view class="form-item-content">
  20. <formInput v-model="form.name"></formInput>
  21. </view>
  22. </uv-form-item>
  23. </view>
  24. <view class="form-item">
  25. <uv-form-item prop="phone" :customStyle="formItemStyle">
  26. <view class="form-item-label">
  27. <image class="icon" src="@/pages_order/static/icon-require.png" mode="widthFix"></image>
  28. 手机号码
  29. </view>
  30. <view class="form-item-content">
  31. <formInput v-model="form.phone"></formInput>
  32. </view>
  33. </uv-form-item>
  34. </view>
  35. </view>
  36. <view class="card">
  37. <view class="card-header">订单详情</view>
  38. <view style="margin-top: 16rpx;">
  39. <uv-form-item prop="members" :customStyle="formItemStyle">
  40. <view>
  41. <peopleNumberInput style="width: calc(100vw - 40rpx*2);"
  42. v-model="form.prices"
  43. :options="orderInfo.priceList"
  44. ></peopleNumberInput>
  45. <memberChooseView
  46. :members.sync="form.members"
  47. ></memberChooseView>
  48. </view>
  49. </uv-form-item>
  50. </view>
  51. </view>
  52. <view class="card">
  53. <view class="card-header">其他</view>
  54. <view class="form-item">
  55. <uv-form-item prop="couponId" :customStyle="formItemStyle">
  56. <view class="form-item-label">选择优惠券</view>
  57. <view class="form-item-content">
  58. <view class="flex row" @click="jumpToSelectCoupon">
  59. <view v-if="form.couponId" class="text">{{ couponInfo.title }}</view>
  60. <view v-else class="text placeholder">请选择</view>
  61. <uv-icon name="arrow-right" color="#C6C6C6" size="32rpx"></uv-icon>
  62. </view>
  63. </view>
  64. </uv-form-item>
  65. </view>
  66. <view class="form-item">
  67. <uv-form-item prop="receiptId" :customStyle="formItemStyle">
  68. <view class="form-item-label">选择发票类型</view>
  69. <view class="form-item-content">
  70. <view class="flex row" @click="jumpToSelectInvoice">
  71. <view v-if="form.receiptId" class="text">{{ getInvoiceDesc(form.receiptId) }}</view>
  72. <view v-else class="text placeholder">请选择</view>
  73. <uv-icon name="arrow-right" color="#C6C6C6" size="32rpx"></uv-icon>
  74. </view>
  75. </view>
  76. </uv-form-item>
  77. </view>
  78. </view>
  79. </uv-form>
  80. <view class="notice">
  81. <!-- <view class="notice-header">下单须知</view> -->
  82. <view class="notice-content">
  83. <!-- todo: check key -->
  84. <!-- <uv-parse :content="configList['order_instructions']"></uv-parse> -->
  85. 如有特殊病史或有不宜参加的旅程项目男女报名如无法同住分开报名需安排同住同车等请备注
  86. </view>
  87. </view>
  88. </view>
  89. <view class="bottom">
  90. <view class="agreement">
  91. <uv-checkbox-group
  92. v-model="checkboxValue"
  93. shape="circle"
  94. >
  95. <uv-checkbox
  96. size="40rpx"
  97. icon-size="40rpx"
  98. activeColor="#00A9FF"
  99. :name="1"
  100. ></uv-checkbox>
  101. </uv-checkbox-group>
  102. <view class="desc">
  103. 我已阅读并同意
  104. <text class="highlight" @click="$refs.modal.open('unsubscribe_policy', '退订政策')">退订政策</text>
  105. <text class="highlight" @click="$refs.modal.open('model_contract', '合同范本')">合同范本</text>
  106. <text class="highlight" @click="$refs.modal.open('booking_instructions', '预订须知')">预订须知</text>
  107. <text class="highlight" @click="$refs.modal.open('safety_reminder', '安全提示')">安全提示</text>
  108. </view>
  109. </view>
  110. <view class="flex bar">
  111. <view class="col price">
  112. <view class="flex price-label">
  113. 已选<view class="highlight">{{ `${totolPeople}` }}</view>总额
  114. </view>
  115. <view class="flex price-value">
  116. ¥<view class="highlight">{{ totalPrice }}</view>
  117. </view>
  118. </view>
  119. <button class="col btn btn-primary btn-pay" @click="onPay">立即支付</button>
  120. </view>
  121. </view>
  122. <agreementModal ref="modal" @confirm="onConfirmAgreement"></agreementModal>
  123. </view>
  124. </template>
  125. <script>
  126. import { mapState } from 'vuex'
  127. import productCard from '@/pages_order/order/components/productCard.vue'
  128. import peopleNumberInput from './peopleNumberInput.vue'
  129. import memberChooseView from './memberChooseView.vue'
  130. import formInput from '@/pages_order/components/formInput.vue'
  131. import agreementModal from '@/pages_order/components/agreementModal.vue'
  132. export default {
  133. components: {
  134. productCard,
  135. peopleNumberInput,
  136. memberChooseView,
  137. formInput,
  138. agreementModal,
  139. },
  140. data() {
  141. return {
  142. form: {
  143. name: '',
  144. phone: '',
  145. prices: [],
  146. members: [],
  147. couponId: '',
  148. receiptId: '',
  149. },
  150. rules: {
  151. 'name': {
  152. type: 'string',
  153. required: true,
  154. message: '请输入真实姓名',
  155. },
  156. 'phone': {
  157. type: 'string',
  158. required: true,
  159. message: '请输入手机号码',
  160. },
  161. 'prices': {
  162. type: 'array',
  163. message: '请选择人数',
  164. validator: (rule, value, callback) => {
  165. if (value.some(num => num > 0)) {
  166. return true
  167. }
  168. return false
  169. },
  170. },
  171. 'members': {
  172. type: 'array',
  173. required: true,
  174. message: '请选择出行人',
  175. },
  176. },
  177. checkboxValue: [],
  178. formItemStyle: { padding: 0 },
  179. }
  180. },
  181. computed: {
  182. ...mapState(['configList', 'userInfo', 'orderInfo', 'couponInfo']),
  183. productPackage() {
  184. const { time, product } = this.orderInfo
  185. const { dateList } = product || {}
  186. return dateList?.find?.(item => item.id === time) || {}
  187. },
  188. totolPeople() {
  189. const { prices } = this.orderInfo
  190. return prices.reduce((total, num) => {
  191. return total + num
  192. }, 0)
  193. },
  194. priceOrigin() {
  195. const { prices, priceList } = this.orderInfo
  196. return prices.reduce((total, num, index) => {
  197. return total + priceList[index].price * (num || 0)
  198. }, 0)
  199. },
  200. discount() {
  201. return this.couponInfo?.discountAmount || 0
  202. },
  203. totalPrice() {
  204. return this.priceOrigin - this.discount
  205. },
  206. },
  207. onShow() {
  208. if (this.couponInfo) {
  209. this.form.couponId = this.couponInfo.id
  210. }
  211. },
  212. onLoad(arg) {
  213. console.log('onLoad')
  214. console.log('orderInfo', this.orderInfo)
  215. this.initData()
  216. },
  217. onReady() {
  218. this.$refs.form.setRules(this.rules);
  219. },
  220. onUnload() {
  221. this.$store.commit('setCouponInfo', null)
  222. },
  223. methods: {
  224. initData() {
  225. const {
  226. time,
  227. prices,
  228. priceList,
  229. members,
  230. } = this.orderInfo
  231. console.log('priceList', priceList)
  232. console.log('members', members)
  233. let arr = []
  234. this.form = {
  235. name: '',
  236. phone: '',
  237. prices,
  238. members: members.map(item => ({ ...item, isSelected: true })),
  239. couponId: '',
  240. receiptId: '',
  241. }
  242. },
  243. jumpToSelectCoupon() {
  244. uni.navigateTo({
  245. url: `/pages_order/coupon/couponSelect/index`
  246. })
  247. },
  248. getCouponDesc() {
  249. // todo
  250. },
  251. jumpToSelectInvoice() {
  252. // todo
  253. },
  254. getInvoiceDesc() {
  255. // todo
  256. },
  257. onConfirmAgreement(confirm) {
  258. if (confirm) {
  259. this.checkboxValue = [1]
  260. } else {
  261. this.checkboxValue = []
  262. }
  263. },
  264. async onPay() {
  265. if(!this.checkboxValue.length){
  266. return uni.showToast({
  267. title: '请先同意《用户协议》《隐私协议》《消费者告知》',
  268. icon:'none'
  269. })
  270. }
  271. try {
  272. await this.$refs.form.validate()
  273. const {
  274. product,
  275. time,
  276. priceList,
  277. } = this.orderInfo
  278. console.log('priceList', priceList)
  279. console.log('members', members)
  280. const {
  281. name,
  282. phone,
  283. prices,
  284. members,
  285. couponId,
  286. receiptId,
  287. } = this.form
  288. const { startDate, endDate } = this.productPackage
  289. // let json = members.map(member => {
  290. // const { periodId } = member
  291. // const { period_dictText, price } = priceList.find(item => item.periodId === periodId) || {}
  292. // return {
  293. // ...member,
  294. // period_dictText,
  295. // price,
  296. // }
  297. // })
  298. // console.log('json', json)
  299. let params = {
  300. activityId: product.id,
  301. startDate,
  302. endDate,
  303. dayNum: this.$dayjs(endDate).diff(this.$dayjs(startDate), 'day'),
  304. couponId,
  305. receiptId,
  306. name,
  307. phone,
  308. priceOrigin: this.priceOrigin,
  309. discount: this.discount,
  310. priceDiscount: this.totalPrice,
  311. payAmount: this.totalPrice,
  312. tourisIds: members.map(touris => touris.id).join(';'),
  313. // jsonObject: JSON.stringify(json),
  314. }
  315. const orderId = await this.$fetch('createOrder', params)
  316. uni.navigateTo({
  317. url: `/pages_order/order/orderPay/index?id=${orderId}`
  318. })
  319. } catch (err) {
  320. console.log('createOrder', err)
  321. }
  322. },
  323. },
  324. }
  325. </script>
  326. <style scoped lang="scss">
  327. @import '../styles/style.scss';
  328. .price {
  329. justify-content: flex-start;
  330. &-label {
  331. justify-content: flex-start;
  332. column-gap: 12rpx;
  333. font-family: PingFang SC;
  334. font-weight: 400;
  335. font-size: 24rpx;
  336. line-height: 1.4;
  337. color: #626262;
  338. .highlight {
  339. font-size: 24rpx;
  340. font-weight: 500;
  341. color: $uni-color;
  342. }
  343. }
  344. &-value {
  345. justify-content: flex-start;
  346. column-gap: 8rpx;
  347. font-family: PingFang SC;
  348. font-weight: 500;
  349. font-size: 24rpx;
  350. line-height: 1.4;
  351. color: $uni-color;
  352. .highlight {
  353. font-size: 40rpx;
  354. }
  355. }
  356. }
  357. .btn-pay {
  358. flex: none;
  359. width: auto;
  360. padding: 14rpx 74rpx;
  361. }
  362. </style>