package-detail.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  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="'i' + 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. loadDetail() {
  63. var self = this
  64. self.loading = true
  65. uni.showLoading({ title: '加载中...', mask: true })
  66. getProblemPackageDetail(self.packageId).then(function(res) {
  67. uni.hideLoading()
  68. self.loading = false
  69. var data = res && res.data
  70. if (data) {
  71. self.pkg = data
  72. // 解析包含项目
  73. var items = data.includedItems || data.included_items || data.contains || []
  74. self.includedItems = Array.isArray(items) ? items : []
  75. } else {
  76. self.pkg = self.getFallbackPackage()
  77. }
  78. }).catch(function() {
  79. uni.hideLoading()
  80. self.loading = false
  81. self.pkg = self.getFallbackPackage()
  82. })
  83. },
  84. getFallbackPackage() {
  85. return {
  86. id: this.packageId || 0,
  87. name: '方案套餐',
  88. description: '包含检测、评估与个性化方案',
  89. price: 199,
  90. validityDays: 30,
  91. rewardCfValue: 500
  92. }
  93. },
  94. buyNow() {
  95. var self = this
  96. if (self.buying) return
  97. self.buying = true
  98. uni.showLoading({ title: '处理中...', mask: true })
  99. // 调用创建订单接口
  100. var api = require('../../utils/api.js')
  101. var createOrder = api.createPackageOrder || api.buyPackage
  102. if (createOrder) {
  103. createOrder({ packageId: self.packageId }).then(function(res) {
  104. uni.hideLoading()
  105. self.buying = false
  106. if (res && (res.code === 0 || res.code === 200)) {
  107. uni.showToast({ title: '购买成功', icon: 'success' })
  108. // 推进旅程
  109. updateUserIntentStage(3).then(function() {}).catch(function() {})
  110. setTimeout(function() {
  111. uni.navigateTo({
  112. url: '/pages/problem/logistics?code=' + self.code
  113. })
  114. }, 500)
  115. } else {
  116. uni.showToast({ title: res.message || '购买失败', icon: 'none' })
  117. }
  118. }).catch(function() {
  119. uni.hideLoading()
  120. self.buying = false
  121. uni.showToast({ title: '购买失败,请重试', icon: 'none' })
  122. })
  123. } else {
  124. // 无创建订单接口,模拟购买
  125. uni.hideLoading()
  126. self.buying = false
  127. uni.showToast({ title: '购买成功', icon: 'success' })
  128. updateUserIntentStage(3).then(function() {}).catch(function() {})
  129. setTimeout(function() {
  130. uni.navigateTo({
  131. url: '/pages/problem/logistics?code=' + self.code
  132. })
  133. }, 500)
  134. }
  135. }
  136. }
  137. }
  138. </script>
  139. <style scoped>
  140. .pd-wrap {
  141. min-height: 100vh;
  142. background: #FFF7ED;
  143. padding: 0 0 160rpx;
  144. box-sizing: border-box;
  145. }
  146. .pd-loading, .pd-empty {
  147. text-align: center;
  148. font-size: 28rpx;
  149. color: #999;
  150. padding: 80rpx 0;
  151. }
  152. .pd-hero {
  153. background: linear-gradient(135deg, #F97316, #FB923C);
  154. padding: 60rpx 40rpx;
  155. text-align: center;
  156. }
  157. .pd-hero-name {
  158. display: block;
  159. font-size: 40rpx;
  160. font-weight: bold;
  161. color: #fff;
  162. }
  163. .pd-hero-price {
  164. display: block;
  165. font-size: 52rpx;
  166. font-weight: bold;
  167. color: #fff;
  168. margin-top: 16rpx;
  169. }
  170. .pd-hero-meta {
  171. display: block;
  172. font-size: 24rpx;
  173. color: rgba(255, 255, 255, 0.8);
  174. margin-top: 8rpx;
  175. }
  176. .pd-section {
  177. margin: 24rpx 32rpx;
  178. background: #fff;
  179. border-radius: 20rpx;
  180. padding: 28rpx 30rpx;
  181. box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
  182. }
  183. .pd-section-title {
  184. display: block;
  185. font-size: 30rpx;
  186. font-weight: 600;
  187. color: #333;
  188. margin-bottom: 16rpx;
  189. }
  190. .pd-section-text {
  191. display: block;
  192. font-size: 26rpx;
  193. color: #666;
  194. line-height: 1.6;
  195. }
  196. .pd-item {
  197. display: flex;
  198. align-items: flex-start;
  199. margin-bottom: 12rpx;
  200. }
  201. .pd-item-icon {
  202. font-size: 28rpx;
  203. color: #F97316;
  204. margin-right: 12rpx;
  205. }
  206. .pd-item-text {
  207. font-size: 26rpx;
  208. color: #666;
  209. flex: 1;
  210. }
  211. .pd-buy-bar {
  212. position: fixed;
  213. left: 0;
  214. right: 0;
  215. bottom: 0;
  216. display: flex;
  217. align-items: center;
  218. background: #fff;
  219. padding: 20rpx 32rpx 40rpx;
  220. box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.08);
  221. }
  222. .pd-buy-price {
  223. flex: 1;
  224. }
  225. .pd-buy-amount {
  226. font-size: 40rpx;
  227. font-weight: bold;
  228. color: #F97316;
  229. }
  230. .pd-buy-free {
  231. font-size: 32rpx;
  232. color: #16A34A;
  233. }
  234. .pd-buy-btn {
  235. background: linear-gradient(135deg, #F97316, #FB923C);
  236. border-radius: 48rpx;
  237. padding: 22rpx 60rpx;
  238. }
  239. .pd-buy-btn:active {
  240. opacity: 0.9;
  241. }
  242. .pd-buy-btn-text {
  243. color: #fff;
  244. font-size: 30rpx;
  245. font-weight: 600;
  246. }
  247. </style>