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.

420 lines
13 KiB

  1. <template>
  2. <view class="companion-select-page">
  3. <!-- 顶部警告提示 -->
  4. <view class="warning-tip">
  5. <view class="warning-icon">
  6. <uni-icons type="info" size="16" color="#A94F20"></uni-icons>
  7. </view>
  8. <view class="warning-text">
  9. <text>指定之前服务过的伴宠师需要额外收10元哦单选最终由系统根据伴宠师的接单时间安排为您安排您喜欢的伴宠师</text>
  10. </view>
  11. </view>
  12. <!-- 伴宠师列表 -->
  13. <scroll-view scroll-y class="companion-scroll">
  14. <view class="companion-list">
  15. <view v-for="(item, index) in companionList" :key="index" class="companion-wrapper"
  16. :class="{ 'selected': selectedCompanionId === item.userId }">
  17. <!-- 左侧选中标记 -->
  18. <view class="select-icon" @click="selectCompanion(item)">
  19. <view class="checkbox-circle" :class="{ 'checked': selectedCompanionId === item.userId }">
  20. <view class="checkbox-inner" v-if="selectedCompanionId === item.userId"></view>
  21. </view>
  22. </view>
  23. <!-- 使用CompanionItem组件 -->
  24. <view class="companion-item-wrapper">
  25. <companion-item
  26. :item="item"
  27. @click="handleItemClick"
  28. :showDetailBtn="true"
  29. :showNumerBtn="false"
  30. @like="handleItemLike">
  31. </companion-item>
  32. </view>
  33. </view>
  34. <!-- 无数据提示 -->
  35. <view class="no-data" v-if="companionList.length === 0">
  36. <image src="/static/images/personal/no-data.png" mode="aspectFit"></image>
  37. <text>暂无伴宠师数据</text>
  38. </view>
  39. </view>
  40. </scroll-view>
  41. <!-- 底部按钮 -->
  42. <view class="footer-buttons">
  43. <view class="cancel-btn" @click="cancel">
  44. <text>取消</text>
  45. </view>
  46. <view class="confirm-btn" @click="confirm">
  47. <text>确定{{ selectedCompanionId ? '(1)' : '' }}</text>
  48. </view>
  49. </view>
  50. </view>
  51. </template>
  52. <script>
  53. import CompanionItem from '@/components/CompanionItem/CompanionItem.vue'
  54. import { getTecByUser, getOrderDetail, getTeacherDetail } from '@/api/order/order.js'
  55. import { getOpenIdKey } from '@/utils/auth'
  56. import { getAddressDetails } from '@/api/system/address.js'
  57. import { mapState } from 'vuex'
  58. import positionMixin from '@/mixins/position'
  59. export default {
  60. mixins: [positionMixin],
  61. components: {
  62. CompanionItem
  63. },
  64. data() {
  65. return {
  66. companionList: [],
  67. selectedCompanionId: null, // 改为单选
  68. defaultTeacherId: null, // 默认选中的技师ID(用于再来一单)
  69. originalOrderData: null, // 原始订单数据
  70. orderId: null, // 订单ID
  71. };
  72. },
  73. computed: {
  74. ...mapState(['teacherLevelList']),
  75. // 获取当前选中的伴宠师
  76. selectedCompanion() {
  77. if (!this.selectedCompanionId) return null;
  78. return this.companionList.find(item => item.userId === this.selectedCompanionId);
  79. }
  80. },
  81. onLoad(options) {
  82. // 获取传递的技师ID(用于再来一单时默认选中)
  83. if (options.teacherId) {
  84. this.defaultTeacherId = options.teacherId;
  85. }
  86. // 获取订单ID(用于再来一单时获取订单详情)
  87. if (options.orderId) {
  88. this.orderId = options.orderId;
  89. this.loadOrderData();
  90. }
  91. // 获取选择过的伴宠师列表
  92. this.getServicedCompanions();
  93. },
  94. onPullDownRefresh() {
  95. this.getServicedCompanions()
  96. },
  97. methods: {
  98. // 获取服务过的伴宠师
  99. getServicedCompanions() {
  100. console.log(getOpenIdKey())
  101. getTecByUser({
  102. openId: getOpenIdKey()
  103. }).then(res => {
  104. uni.stopPullDownRefresh()
  105. if (res && res.code == 200) {
  106. this.companionList = res.data || [];
  107. // 如果有默认技师ID,自动选中该技师
  108. if (this.defaultTeacherId) {
  109. const defaultCompanion = this.companionList.find(item => item.userId == this.defaultTeacherId);
  110. if (defaultCompanion) {
  111. this.selectedCompanionId = this.defaultTeacherId;
  112. }
  113. }
  114. }
  115. }).catch(err => {
  116. uni.stopPullDownRefresh()
  117. console.error('获取服务过的伴宠师失败', err);
  118. });
  119. },
  120. // 加载订单数据
  121. async loadOrderData() {
  122. if (!this.orderId) return;
  123. const params = {
  124. openId: getOpenIdKey(),
  125. orderId: this.orderId
  126. };
  127. try {
  128. const res = await getOrderDetail(params);
  129. if (res) {
  130. this.originalOrderData = res;
  131. } else {
  132. console.error('获取订单详情失败');
  133. }
  134. } catch (error) {
  135. console.error('获取订单数据失败', error);
  136. }
  137. },
  138. // 选择伴宠师(单选)
  139. selectCompanion(companion) {
  140. const userId = companion.userId;
  141. if (this.selectedCompanionId === userId) {
  142. // 如果已选中,则取消选中
  143. this.selectedCompanionId = null;
  144. } else {
  145. // 如果未选中,则选中该伴宠师
  146. this.selectedCompanionId = userId;
  147. }
  148. },
  149. // 处理伴宠师列表项点击事件
  150. handleItemClick(item) {
  151. uni.navigateTo({
  152. url: '/pages_order/companionPetList/companionPetInfo?id=' + item.userId
  153. })
  154. },
  155. // 处理伴宠师列表项点赞事件
  156. handleItemLike(item) {
  157. // 这里可以添加点赞的业务逻辑
  158. console.log('点赞伴宠师:', item);
  159. },
  160. // 取消选择
  161. cancel() {
  162. uni.navigateBack();
  163. },
  164. // 确认选择
  165. confirm() {
  166. if (!this.selectedCompanionId) {
  167. uni.showToast({
  168. title: '请选择一个伴宠师',
  169. icon: 'none'
  170. });
  171. return;
  172. }
  173. this.submit()
  174. },
  175. async submit() {
  176. let order = this.originalOrderData
  177. this.$globalData.newOrderData.originalOrderData = order
  178. this.$globalData.newOrderData.moreOrderPrice = 10
  179. // 验证地址是否存在
  180. if (order.addressId) {
  181. try {
  182. const addressRes = await getAddressDetails(order.addressId);
  183. if (addressRes && addressRes.id) {
  184. // 地址存在,设置地址信息
  185. this.$globalData.newOrderData.currentAddress = {
  186. id: order.addressId,
  187. name: order.receiverName,
  188. phone: order.receiverPhone,
  189. province: order.receiverProvince,
  190. city: order.receiverCity,
  191. district: order.receiverDistrict,
  192. detailAddress: order.receiverDetailAddress,
  193. latitude: order.latitude,
  194. longitude: order.longitude,
  195. }
  196. } else {
  197. // 地址不存在,不设置地址信息
  198. console.log('地址不存在,addressId:', order.addressId);
  199. this.$globalData.newOrderData.currentAddress = {};
  200. }
  201. } catch (error) {
  202. console.error('验证地址失败:', error);
  203. // 验证失败时也不设置地址信息
  204. this.$globalData.newOrderData.currentAddress = {};
  205. }
  206. } else {
  207. // 没有地址ID,不设置地址信息
  208. this.$globalData.newOrderData.currentAddress = {};
  209. }
  210. if (order.teacherId) {
  211. getTeacherDetail({
  212. userId: order.teacherId
  213. }).then(response => {
  214. if (response) {
  215. let companionInfo = response
  216. companionInfo.distanceText = this.calculateDistanceAddress(response.appletAddresseList)
  217. this.buyInfo.teacher = companionInfo
  218. }
  219. })
  220. }
  221. if (order.companionLevel) {
  222. this.$globalData.newOrderData.companionLevel =
  223. this.teacherLevelList.find(item => item.paramValueNum == order.companionLevel);
  224. }
  225. // 处理提前熟悉相关数据
  226. if (order.needPreFamiliarize) {
  227. this.$globalData.newOrderData.needPreFamiliarize = ['是否提前熟悉']
  228. }
  229. // 组装宠物数据
  230. // if (order.petVOList && order.petVOList.length > 0) {
  231. // this.$globalData.newOrderData.currentPets = order.petVOList.map(pet => {
  232. // // 获取该宠物的服务日期
  233. // const petServices = order.orderServiceList.filter(service => service.petId === pet.id);
  234. // const selectedDate = petServices.map(service => ({
  235. // date: service.serviceDate,
  236. // info: "预定"
  237. // }));
  238. // return {
  239. // ...pet,
  240. // checked: ['checked'], // 默认选中
  241. // selectedDate,
  242. // };
  243. // });
  244. // }
  245. uni.navigateTo({
  246. url: `/pages/newOrder/serviceNew`
  247. });
  248. },
  249. // 查看伴宠师详情
  250. viewCompanionDetail(companionId) {
  251. // 跳转到伴宠师详情页面
  252. uni.navigateTo({
  253. url: `/pages_order/companionPetList/companionPetInfo?id=${companionId}`
  254. });
  255. }
  256. }
  257. }
  258. </script>
  259. <style lang="scss" scoped>
  260. .companion-select-page {
  261. background-color: #F5F5F5;
  262. min-height: 100vh;
  263. display: flex;
  264. flex-direction: column;
  265. padding-bottom: 120rpx;
  266. }
  267. .warning-tip {
  268. background-color: #FFF4E5;
  269. padding: 20rpx 30rpx;
  270. display: flex;
  271. align-items: center;
  272. margin: 20rpx;
  273. .warning-icon {
  274. margin-right: 10rpx;
  275. }
  276. .warning-text {
  277. flex: 1;
  278. font-size: 24rpx;
  279. color: #A94F20;
  280. line-height: 1.4;
  281. }
  282. }
  283. .companion-scroll {
  284. flex: 1;
  285. height: calc(100vh - 250rpx);
  286. }
  287. .companion-list {
  288. padding: 10rpx;
  289. padding-right: 0;
  290. }
  291. .companion-wrapper {
  292. display: flex;
  293. align-items: flex-start;
  294. margin-bottom: 20rpx;
  295. border-radius: 16rpx;
  296. padding: 10rpx;
  297. display: flex;
  298. align-items: center;
  299. .select-icon {
  300. margin-right: 10rpx;
  301. .checkbox-circle {
  302. width: 45rpx;
  303. height: 45rpx;
  304. border: 2rpx solid #DDDDDD;
  305. background-color: #fff;
  306. border-radius: 50%;
  307. display: flex;
  308. align-items: center;
  309. justify-content: center;
  310. &.checked {
  311. border-color: #FFAA48;
  312. background-color: #FFAA48;
  313. }
  314. .checkbox-inner {
  315. width: 16rpx;
  316. height: 10rpx;
  317. border: 2rpx solid #FFFFFF;
  318. border-top: none;
  319. border-right: none;
  320. transform: rotate(-45deg);
  321. margin-top: -4rpx;
  322. }
  323. }
  324. }
  325. .companion-item-wrapper {
  326. flex: 1;
  327. }
  328. }
  329. .no-data {
  330. text-align: center;
  331. image {
  332. width: 200rpx;
  333. height: 200rpx;
  334. margin-bottom: 20rpx;
  335. }
  336. text {
  337. font-size: 28rpx;
  338. color: #999;
  339. }
  340. }
  341. .footer-buttons {
  342. position: fixed;
  343. bottom: 0;
  344. left: 0;
  345. right: 0;
  346. display: flex;
  347. padding: 20rpx 30rpx;
  348. background-color: #FFFFFF;
  349. box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
  350. .cancel-btn,
  351. .confirm-btn {
  352. flex: 1;
  353. height: 88rpx;
  354. line-height: 88rpx;
  355. text-align: center;
  356. border-radius: 44rpx;
  357. font-size: 30rpx;
  358. }
  359. .cancel-btn {
  360. background-color: #FFFFFF;
  361. color: #666;
  362. border: 1px solid #DDDDDD;
  363. margin-right: 20rpx;
  364. }
  365. .confirm-btn {
  366. background-color: #FFAA48;
  367. color: #FFFFFF;
  368. box-shadow: 0 4rpx 8rpx rgba(255, 170, 72, 0.3);
  369. }
  370. }
  371. </style>