index.vue 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <!-- 订单详情 -->
  2. <template>
  3. <view>
  4. <view class="order-detail">
  5. <PositioningMap :address="detaile.address" />
  6. </view>
  7. <view class="user-info">
  8. <view class="handle-user-info">
  9. <view class="user-name">下单时间:{{ detaile.createTime }}</view>
  10. <view>上门时间:{{ detaile.workDate + ' ' + detaile.workStartTime }}</view>
  11. <view>服务人员:{{ detaile.clientName }} 123123456</view>
  12. <view class="user-id" style="display: flex">服务类别:{{ detaile.businessTireName }}</view>
  13. <view class="adress-text">地址:{{ detaile.address }}</view>
  14. <view class="handle-remark">
  15. <view class="remark-title">备注</view>
  16. <view class="remark-text">{{ detaile.remark || '暂无备注' }}</view>
  17. </view>
  18. </view>
  19. <view class="footer-g">
  20. <view class="handle-start" v-if="orderStatus && detaile.serviceStartTime && dateData">
  21. 服务已开始:<text class="handle-time">{{ dateData }}</text>
  22. </view>
  23. <Slide ref="verify" @change="change" :sliderText="slideData" :btnType="orderStatus ? 'upload' : 'start'" />
  24. </view>
  25. </view>
  26. <!-- <view class="handle-adress">
  27. <up-icon name="map" color="rgba(156, 163, 175, 1)" size="20"></up-icon>
  28. </view> -->
  29. <!-- <view>
  30. <view class="handle-remark">
  31. <text class="remark-title">服务次数:{{ detaile.singleQuantity }}次</text>
  32. </view>
  33. <view class="handle-remark">
  34. <text class="remark-title">服务时间: {{ detaile.workDate + ' ' + detaile.workStartTime }}</text>
  35. </view>
  36. </view> -->
  37. </view>
  38. </template>
  39. <script setup>
  40. import { ref } from 'vue'
  41. import { onLoad, onUnload } from '@dcloudio/uni-app'
  42. import { getVolunteerOrderInfo, getTimesByDate, getVolunteerFinishSecondOrder } from '@/api/volunteer.js'
  43. import PositioningMap from '@/pages_classify/components/PositioningMap/index.vue'
  44. import Slide from '@/pages_classify/components/Slide/index.vue'
  45. import { useDict } from '@/utils/dict.js'
  46. import DictTag from '@/components/DictTag/index.vue'
  47. import { wxMakePhoneCall } from '@/utils/wxRequest.js'
  48. import { getLatLong } from '@/utils/adress'
  49. import { computed } from 'vue'
  50. const secondOrderId = ref('')
  51. const detaile = ref({})
  52. const verify = ref(null)
  53. const { lrr_service_category } = useDict('lrr_service_category')
  54. const orderStatus = ref(false) //false:未开始服务 true:服务已开始,待上传图片
  55. const onPhone = (phone) => {
  56. if (phone) {
  57. wxMakePhoneCall(phone)
  58. }
  59. }
  60. const dateData = ref('00:00:00')
  61. let timer = null
  62. // 获取当前位置信息
  63. const getCurrentLocation = () => {
  64. return new Promise((resolve, reject) => {
  65. // 先检查用户是否授权了位置权限
  66. uni.getSetting({
  67. success: (res) => {
  68. console.log("TCL: getCurrentLocation -> res", res)
  69. // 已授权,直接获取位置
  70. getLocation(resolve, reject);
  71. // if (!res.authSetting['scope.getFuzzyLocation']) {
  72. // // 如果用户未授权,先请求授权
  73. // uni.authorize({
  74. // scope: 'scope.getFuzzyLocation',
  75. // success: () => {
  76. // // 授权成功后获取位置
  77. // getLocation(resolve, reject);
  78. // },
  79. // fail: (err) => {
  80. // console.error('位置授权失败:', err);
  81. // uni.showModal({
  82. // title: '提示',
  83. // content: '需要获取您的位置信息,请在设置中打开位置权限',
  84. // confirmText: '去设置',
  85. // success: (res) => {
  86. // if (res.confirm) {
  87. // uni.openSetting();
  88. // }
  89. // }
  90. // });
  91. // reject(err);
  92. // }
  93. // });
  94. // } else {
  95. // // 已授权,直接获取位置
  96. // getLocation(resolve, reject);
  97. // }
  98. },
  99. fail: (err) => {
  100. console.error('获取设置失败:', err);
  101. reject(err);
  102. }
  103. });
  104. });
  105. }
  106. // 获取位置的具体实现
  107. const getLocation = (resolve, reject) => {
  108. // 删除开发环境模拟位置的代码,始终获取真实位置
  109. uni.getFuzzyLocation({
  110. type: 'gcj02',
  111. // isHighAccuracy: true, // 高精度
  112. // highAccuracyExpireTime: 3000, // 高精度过期时间
  113. success: (res) => {
  114. const { longitude, latitude } = res;
  115. console.log('当前位置 - 经度:', longitude);
  116. console.log('当前位置 - 纬度:', latitude);
  117. resolve({
  118. longitude,
  119. latitude
  120. });
  121. },
  122. fail: (err) => {
  123. console.error('获取位置失败:', err);
  124. // 获取位置失败时向用户提示
  125. uni.showToast({
  126. title: '获取位置失败,请确保已开启位置权限',
  127. icon: 'none',
  128. duration: 2000
  129. });
  130. reject(err);
  131. }
  132. });
  133. }
  134. const slideData = computed(() => {
  135. //服务已开始,待上传图片
  136. if (orderStatus.value) {
  137. return {
  138. successText: '服务已完成',
  139. startText: '滑动结束服务',
  140. successColor: '#f64a1f',
  141. btnText: '上传照片',
  142. }
  143. }
  144. return {
  145. successText: '服务已开始',
  146. startText: '滑动开始服务',
  147. successColor: '#72c13f',
  148. btnText: '开始',
  149. }
  150. })
  151. const getOrderDetail = async () => {
  152. try {
  153. // uni.showLoading({
  154. // title: '数据加载中...',
  155. // })
  156. const res = await getVolunteerOrderInfo({
  157. secondOrderId: secondOrderId.value,
  158. })
  159. detaile.value = res.data
  160. if (res.data.orderStatus === '3') {
  161. orderStatus.value = true
  162. }
  163. if (res.data.serviceStartTime) {
  164. timer = setInterval(() => {
  165. const timeDiff = Math.abs(new Date() - new Date(res.data.serviceStartTime))
  166. const units = {
  167. day: Math.floor(timeDiff / (1000 * 60 * 60 * 24)),
  168. hour: Math.floor(timeDiff / (1000 * 60 * 60)),
  169. minute: Math.floor(timeDiff / (1000 * 60)),
  170. second: Math.floor(timeDiff / 1000),
  171. }
  172. // 默认返回完整格式
  173. const hours = units.hour % 24
  174. const minutes = units.minute % 60
  175. const seconds = units.second % 60
  176. dateData.value = `${hours}小时${minutes}分钟${seconds}秒`
  177. }, 1000)
  178. }
  179. } catch (error) {
  180. console.log('error', error)
  181. uni.showToast({
  182. title: error.msg,
  183. icon: 'error',
  184. })
  185. } finally {
  186. // uni.hideLoading()
  187. }
  188. }
  189. const change = async (e) => {
  190. if (e.state && !orderStatus.value) {
  191. try {
  192. // uni.showLoading({
  193. // title: '获取位置信息...'
  194. // })
  195. // 获取开始服务时的位置
  196. // const locationData = await getCurrentLocation().catch(err => {
  197. // // uni.hideLoading()
  198. // verify.value.initialization()
  199. // throw new Error('无法获取位置信息,请确保已开启位置权限')
  200. // })
  201. const locationData = await getLatLong()
  202. // 构建参数字符串
  203. const params = `secondOrderId=${secondOrderId.value}&serviceStartLongitude=${locationData.longitude.toString()}&serviceStartLatitude=${locationData.latitude.toString()}`
  204. // 调用开始服务接口,通过URL查询参数传递位置信息
  205. const res = await getTimesByDate(params)
  206. if (res.code === 200) {
  207. uni.showToast({
  208. title: '已开始服务',
  209. icon: 'success',
  210. success: () => {
  211. verify.value.initialization()
  212. // 验证成功
  213. orderStatus.value = true
  214. },
  215. })
  216. }
  217. } catch (error) {
  218. console.error('开始服务失败', error)
  219. uni.showToast({
  220. title: error.message || '开始服务失败',
  221. icon: 'none'
  222. })
  223. } finally {
  224. // uni.hideLoading()
  225. }
  226. }
  227. if (e.state && orderStatus.value) {
  228. try {
  229. // uni.showLoading({
  230. // title: '获取位置信息...'
  231. // })
  232. uni.showToast({
  233. title: '操作成功',
  234. icon: 'success',
  235. success: () => {
  236. setTimeout(() => {
  237. uni.redirectTo({
  238. url: `/pages_classify/pages/order/index?secondOrderId=${secondOrderId.value}`,
  239. })
  240. }, 800)
  241. },
  242. })
  243. } catch (error) {
  244. console.error('结束服务失败', error)
  245. uni.showToast({
  246. title: error.message || '结束服务失败',
  247. icon: 'none'
  248. })
  249. verify.value.initialization()
  250. } finally {
  251. // uni.hideLoading()
  252. }
  253. }
  254. }
  255. onLoad((options) => {
  256. secondOrderId.value = options.secondOrderId
  257. getOrderDetail()
  258. // // 初始检查位置权限
  259. // getCurrentLocation().then(location => {
  260. // console.log('位置权限正常,可以获取位置');
  261. // }).catch(err => {
  262. // console.error('位置权限检查失败', err);
  263. // uni.showModal({
  264. // title: '位置权限提示',
  265. // content: '服务需要获取您的位置信息,请确保已开启位置权限',
  266. // confirmText: '去设置',
  267. // cancelText: '知道了',
  268. // success: (res) => {
  269. // if (res.confirm) {
  270. // uni.openSetting();
  271. // }
  272. // }
  273. // });
  274. // });
  275. })
  276. onUnload(() => {
  277. clearInterval(timer)
  278. timer = null
  279. })
  280. </script>
  281. <style lang="scss" scoped>
  282. .handle-user-info {
  283. // display: flex;
  284. // flex-direction: column;
  285. // gap: 10rpx;
  286. position: absolute;
  287. top: 531rpx;
  288. left: 0;
  289. right: 0;
  290. bottom: 0;
  291. background: red;
  292. width: 750rpx;
  293. height: 804rpx;
  294. border-radius: 20rpx 20rpx 0rpx 0rpx;
  295. // margin-left: 38rpx;
  296. // margin-right: 36rpx;
  297. // margin-top: 50rpx;
  298. // > view {
  299. // padding-bottom: 16rpx;
  300. // border-bottom: 1px solid #f0f0f0;
  301. // margin-bottom: 16rpx;
  302. // font-size: 28rpx;
  303. // color: #333;
  304. // // display: flex;
  305. // // justify-content: flex-start;
  306. // // align-items: center;
  307. // }
  308. }
  309. </style>