package-detail.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. <template>
  2. <view class="pd-wrap">
  3. <view class="pd-loading" v-if="loading">加载中...</view>
  4. <view class="pd-empty" v-else-if="!pkg">暂无套餐信息</view>
  5. <template v-else>
  6. <view class="pd-hero">
  7. <text class="pd-hero-name">{{ pkg.name }}</text>
  8. <text class="pd-hero-price" v-if="pkg.price">¥{{ pkg.price }}</text>
  9. <text class="pd-hero-meta" v-if="pkg.validityDays">有效期 {{ pkg.validityDays }} 天</text>
  10. </view>
  11. <view class="pd-section">
  12. <text class="pd-section-title">方案介绍</text>
  13. <text class="pd-section-text">{{ pkg.description || '暂无详细介绍' }}</text>
  14. </view>
  15. <view class="pd-section" v-if="pkg.usageGuide">
  16. <text class="pd-section-title">使用方式</text>
  17. <text class="pd-section-text">{{ pkg.usageGuide }}</text>
  18. </view>
  19. <view class="pd-section" v-if="includedItems && includedItems.length > 0">
  20. <text class="pd-section-title">包含项目</text>
  21. <view class="pd-item" v-for="(item, i) in includedItems" :key="getIncKey(i)">
  22. <text class="pd-item-icon">•</text>
  23. <text class="pd-item-text">{{ item }}</text>
  24. </view>
  25. </view>
  26. <view class="pd-section" v-if="pkg.rewardCfValue">
  27. <text class="pd-section-title">完成奖励</text>
  28. <text class="pd-section-text">全部任务完成后可获得 {{ pkg.rewardCfValue }} CF 值奖励</text>
  29. </view>
  30. </template>
  31. <view class="pd-buy-bar" v-if="!loading && pkg">
  32. <view class="pd-buy-price">
  33. <text class="pd-buy-amount" v-if="pkg.price">¥{{ pkg.price }}</text>
  34. <text class="pd-buy-free" v-else>免费</text>
  35. </view>
  36. <view class="pd-buy-btn" @click="buyNow">
  37. <text class="pd-buy-btn-text">立即购买</text>
  38. </view>
  39. </view>
  40. </view>
  41. </template>
  42. <script>
  43. import { getProblemPackageDetail } from '../../utils/api.js'
  44. import { updateUserIntentStage } from '../../utils/api.js'
  45. export default {
  46. data() {
  47. return {
  48. packageId: '',
  49. code: '',
  50. pkg: null,
  51. includedItems: [],
  52. loading: false,
  53. buying: false
  54. }
  55. },
  56. onLoad(options) {
  57. this.packageId = (options && options.packageId) || ''
  58. this.code = (options && options.code) || ''
  59. this.loadDetail()
  60. },
  61. methods: {
  62. getIncKey: function(i) { return 'i' + i },
  63. loadDetail() {
  64. var self = this
  65. self.loading = true
  66. uni.showLoading({ title: '加载中...', mask: true })
  67. getProblemPackageDetail(self.packageId).then(function(res) {
  68. uni.hideLoading()
  69. self.loading = false
  70. var data = res && res.data
  71. if (data) {
  72. self.pkg = data
  73. // 解析包含项目
  74. var items = data.includedItems || data.included_items || data.contains || []
  75. self.includedItems = Array.isArray(items) ? items : []
  76. } else {
  77. self.pkg = self.getFallbackPackage()
  78. }
  79. }).catch(function() {
  80. uni.hideLoading()
  81. self.loading = false
  82. self.pkg = self.getFallbackPackage()
  83. })
  84. },
  85. getFallbackPackage() {
  86. return {
  87. id: this.packageId || 0,
  88. name: '方案套餐',
  89. description: '包含检测、评估与个性化方案',
  90. price: 199,
  91. validityDays: 30,
  92. rewardCfValue: 500
  93. }
  94. },
  95. buyNow() {
  96. var self = this
  97. if (self.buying) return
  98. self.buying = true
  99. uni.showLoading({ title: '处理中...', mask: true })
  100. // 调用创建订单接口
  101. var api = require('../../utils/api.js')
  102. var createOrder = api.createPackageOrder || api.buyPackage
  103. if (createOrder) {
  104. createOrder({ packageId: self.packageId }).then(function(res) {
  105. uni.hideLoading()
  106. self.buying = false
  107. if (res && (res.code === 0 || res.code === 200)) {
  108. uni.showToast({ title: '购买成功', icon: 'success' })
  109. // 推进旅程
  110. updateUserIntentStage(3).then(function() {}).catch(function() {})
  111. setTimeout(function() {
  112. uni.navigateTo({
  113. url: '/pages/problem/logistics?code=' + self.code
  114. })
  115. }, 500)
  116. } else {
  117. uni.showToast({ title: res.message || '购买失败', icon: 'none' })
  118. }
  119. }).catch(function() {
  120. uni.hideLoading()
  121. self.buying = false
  122. uni.showToast({ title: '购买失败,请重试', icon: 'none' })
  123. })
  124. } else {
  125. // 无创建订单接口,模拟购买
  126. uni.hideLoading()
  127. self.buying = false
  128. uni.showToast({ title: '购买成功', icon: 'success' })
  129. updateUserIntentStage(3).then(function() {}).catch(function() {})
  130. setTimeout(function() {
  131. uni.navigateTo({
  132. url: '/pages/problem/logistics?code=' + self.code
  133. })
  134. }, 500)
  135. }
  136. }
  137. }
  138. }
  139. </script>
  140. <style scoped>
  141. .pd-wrap {
  142. min-height: 100vh;
  143. background: #FFF7ED;
  144. padding: 0 0 160rpx;
  145. box-sizing: border-box;
  146. }
  147. .pd-loading, .pd-empty {
  148. text-align: center;
  149. font-size: 28rpx;
  150. color: #999;
  151. padding: 80rpx 0;
  152. }
  153. .pd-hero {
  154. background: linear-gradient(135deg, #F97316, #FB923C);
  155. padding: 60rpx 40rpx;
  156. text-align: center;
  157. }
  158. .pd-hero-name {
  159. display: block;
  160. font-size: 40rpx;
  161. font-weight: bold;
  162. color: #fff;
  163. }
  164. .pd-hero-price {
  165. display: block;
  166. font-size: 52rpx;
  167. font-weight: bold;
  168. color: #fff;
  169. margin-top: 16rpx;
  170. }
  171. .pd-hero-meta {
  172. display: block;
  173. font-size: 24rpx;
  174. color: rgba(255, 255, 255, 0.8);
  175. margin-top: 8rpx;
  176. }
  177. .pd-section {
  178. margin: 24rpx 32rpx;
  179. background: #fff;
  180. border-radius: 20rpx;
  181. padding: 28rpx 30rpx;
  182. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
  183. }
  184. .pd-section-title {
  185. display: block;
  186. font-size: 30rpx;
  187. font-weight: 600;
  188. color: #333;
  189. margin-bottom: 16rpx;
  190. }
  191. .pd-section-text {
  192. display: block;
  193. font-size: 26rpx;
  194. color: #666;
  195. line-height: 1.6;
  196. }
  197. .pd-item {
  198. display: flex;
  199. align-items: flex-start;
  200. margin-bottom: 12rpx;
  201. }
  202. .pd-item-icon {
  203. font-size: 28rpx;
  204. color: #F97316;
  205. margin-right: 12rpx;
  206. }
  207. .pd-item-text {
  208. font-size: 26rpx;
  209. color: #666;
  210. flex: 1;
  211. }
  212. .pd-buy-bar {
  213. position: fixed;
  214. left: 0;
  215. right: 0;
  216. bottom: 0;
  217. display: flex;
  218. align-items: center;
  219. background: #fff;
  220. padding: 20rpx 32rpx 40rpx;
  221. box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
  222. }
  223. .pd-buy-price {
  224. flex: 1;
  225. }
  226. .pd-buy-amount {
  227. font-size: 40rpx;
  228. font-weight: bold;
  229. color: #F97316;
  230. }
  231. .pd-buy-free {
  232. font-size: 32rpx;
  233. color: #16A34A;
  234. }
  235. .pd-buy-btn {
  236. background: linear-gradient(135deg, #F97316, #FB923C);
  237. border-radius: 48rpx;
  238. padding: 22rpx 60rpx;
  239. }
  240. .pd-buy-btn:active {
  241. opacity: 0.9;
  242. }
  243. .pd-buy-btn-text {
  244. color: #fff;
  245. font-size: 30rpx;
  246. font-weight: 600;
  247. }
  248. </style>