fast.vue 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <template>
  2. <view>
  3. <scroll-view scroll-x class="navigation_wrap">
  4. <view class="uni-scroll-view-content" :style="{ paddingTop: `${statusBarHeight}px` }">
  5. <uni-badge class="uni-badge-left-margin" :text="realtimeData[index]?.order_num" absolute="rightTop" size="small" v-for="(item, index) in category" :key="index">
  6. <view :class="current == index && 'active'" @tap="onChangeTab(index)">
  7. <view class="box">
  8. <view class="tab_title">{{ item?.category_name }}</view>
  9. </view>
  10. <view class="tab_line"></view>
  11. </view>
  12. </uni-badge>
  13. </view>
  14. </scroll-view>
  15. <scroll-view scroll-y v-if="orderData && orderData?.length">
  16. <view class="card service_wrap" v-for="(item, index) in orderData" :key="index" @tap="handleOrderDetail(item?.id)" :data-id="item.id">
  17. <view style="position: relative">
  18. <image class="service_thumbnail" :src="item?.project?.icon" mode="aspectFill" />
  19. <view
  20. style="position: absolute; top: 0; font-size: 23upx; width: 250upx; text-align: center; background: #ffffffbb; padding: 10upx; color: red; font-weight: 600"
  21. v-if="item?.type == 2"
  22. >
  23. 预约订单
  24. </view>
  25. </view>
  26. <view style="width: 400upx">
  27. <view class="service_title">
  28. <text>{{ item?.project?.name }}</text>
  29. <text class="service_extra_order" style="font-weight: 400; color: #999; font-size: 24upx">
  30. <text class="service_extra_order_num">≤ {{ item?.distance }}</text>
  31. Km
  32. </text>
  33. </view>
  34. <view class="service_detail">
  35. <text>{{ item?.address }}</text>
  36. </view>
  37. <view class="service_extra" style="justify-content: space-between">
  38. <view style="display: flex; align-items: center">
  39. <image src="/static/common/timer.png" mode="aspectFill" class="service_extra_image" />
  40. <text class="service_extra_text">{{ item?.minute }}分钟</text>
  41. </view>
  42. <view class="service_footer">
  43. <view class="service_footer_price">
  44. <text class="text-xs">分成</text>
  45. <text class="service_footer_price_prefix">¥</text>
  46. <text>{{ item?.order_price }}</text>
  47. </view>
  48. </view>
  49. </view>
  50. <view class="service_footer">
  51. <view class="service_footer_price">
  52. <text class="service_footer_price_prefix">¥</text>
  53. <text>{{ item?.price }}</text>
  54. </view>
  55. <view>
  56. <button class="submit_btn disabled_btn" :data-id="item?.id" v-if="isFastSuccess(item)">已抢单</button>
  57. <button class="submit_btn" :data-id="item?.id" @tap.stop="handleFastOrder" v-else>立即抢单</button>
  58. </view>
  59. </view>
  60. </view>
  61. </view>
  62. </scroll-view>
  63. <view v-else>
  64. <view class="service_wrap" style="padding: 18upx 0px 10upx; display: flex; flex-direction: column; align-items: center">
  65. <image mode="widthFix" src="/static/common/no_order.png" class="commend_icon" style="width: 455upx; height: 259upx; margin-top: 20upx" />
  66. <text style="font-size: 28upx; font-weight: 400; color: #999999; margin-top: 30upx">{{ locationMessage[current] }}</text>
  67. </view>
  68. </view>
  69. <view class="footer">
  70. <image mode="widthFix" src="/static/common/footer.png" />
  71. </view>
  72. <callAlarm />
  73. </view>
  74. </template>
  75. <script setup>
  76. import callAlarm from '/components/callAlarm.vue';
  77. import { ref, watch, reactive, computed } from 'vue';
  78. import { onLoad, onShow, onPullDownRefresh } from '@dcloudio/uni-app';
  79. import getLocation from '/common/getLocation.js';
  80. import request from '/common/request.js';
  81. const statusBarHeight = ref(0);
  82. const current = ref(0);
  83. const locationMessage = ref([]);
  84. const category = reactive([]);
  85. const address = ref({
  86. city: null,
  87. district: null,
  88. street: null,
  89. location: {}
  90. });
  91. const realtimeOpen = ref(true);
  92. const realtimeData = ref([]);
  93. const params = reactive({
  94. page: 1,
  95. category_id: 0,
  96. type: 8
  97. });
  98. const orderData = ref([]);
  99. const userData = ref();
  100. function timeStamp(value) {
  101. const date = new Date(value * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
  102. const year = date.getFullYear();
  103. const month = ('0' + (date.getMonth() + 1)).slice(-2);
  104. const sdate = ('0' + date.getDate()).slice(-2);
  105. const hour = ('0' + date.getHours()).slice(-2);
  106. const minute = ('0' + date.getMinutes()).slice(-2);
  107. const second = ('0' + date.getSeconds()).slice(-2);
  108. // 拼接
  109. return `${year}-${month}-${sdate} ${hour}:${minute}`;
  110. }
  111. const getProjectCategory = () => {
  112. request({
  113. url: '/api/jsProjectCategory/getList',
  114. method: 'GET',
  115. success: (res) => {
  116. console.log('项目分类', res.data?.data);
  117. category.push(...res.data?.data);
  118. params.category_id = res.data?.data[current.value]?.id;
  119. },
  120. fail: () => {},
  121. complete: () => {}
  122. });
  123. };
  124. const onChangeTab = (index) => {
  125. console.log('切换选项卡', index);
  126. locationMessage.value[index] = '';
  127. if (current.value !== index) {
  128. current.value = index;
  129. params.category_id = category[current.value]?.id;
  130. }
  131. };
  132. const getOrderNumber = () => {
  133. request({
  134. url: '/api/userjs/getClassifyOrderNum',
  135. data: {},
  136. success: (res) => {
  137. //console.log(res);
  138. console.log('实时订单数', res);
  139. // that.arrnum = res.data.data;
  140. if (res.data?.code == 10001) {
  141. console.log('10001');
  142. realtimeOpen.value = false;
  143. }
  144. if (res.data?.code == 1) {
  145. realtimeData.value = res.data?.data;
  146. realtimeOpen.value = true;
  147. }
  148. },
  149. fail: () => {},
  150. complete: () => {}
  151. });
  152. };
  153. const handleOrderDetail = (order_id) => {
  154. uni.navigateTo({ url: `/pages/order/detail?id=${order_id}` });
  155. };
  156. const getUserInfo = () => {
  157. request({
  158. url: '/api/user/getInfo',
  159. method: 'GET',
  160. success: (res) => {
  161. console.log('客户信息', res);
  162. if (res.data.code == 1) {
  163. userData.value = res.data?.data ?? {};
  164. uni.$emit('fastOrderNum', true);
  165. uni.$emit('receiveOrdernum', true);
  166. } else if (res.data.code == 10001) {
  167. uni.removeStorageSync('token');
  168. uni.removeStorageSync('id');
  169. uni.$emit('fastOrderNum', false);
  170. uni.$emit('receiveOrdernum', false);
  171. uni.showToast({
  172. title: '登录已失效,请重新登录',
  173. duration: 2000,
  174. icon: 'none',
  175. success: () => {
  176. uni.navigateTo({
  177. url: '/pages/account/login'
  178. });
  179. }
  180. });
  181. }
  182. },
  183. fail: () => {},
  184. complete: () => {}
  185. });
  186. };
  187. const isFastSuccess = (order) => {
  188. const fast_number_list = order.fast_number_list;
  189. let isFast = -1;
  190. if (fast_number_list && fast_number_list?.length) isFast = fast_number_list.indexOf(userData.value?.js?.id);
  191. return isFast == -1 ? false : true;
  192. };
  193. const getOrderList = (next = true, showLoading = true) => {
  194. showLoading && uni.showLoading();
  195. request({
  196. url: '/api/userjs/getFastOrderList',
  197. data: params,
  198. success: (res) => {
  199. console.log('订单列表', res);
  200. if (res.data?.code == 1) {
  201. orderData.value = res.data?.data;
  202. }
  203. },
  204. fail: () => {},
  205. complete: () => {
  206. showLoading && uni.stopPullDownRefresh();
  207. showLoading && uni.hideLoading();
  208. }
  209. });
  210. };
  211. const handleFastOrder = (e) => {
  212. const id = e.currentTarget.dataset.id;
  213. uni.showModal({
  214. title: '提示',
  215. content: '确定要抢单吗?',
  216. success(res) {
  217. // 用户确定要删除
  218. if (res.confirm) {
  219. //return
  220. uni.showLoading({
  221. content: '加载中',
  222. mask: true
  223. });
  224. request({
  225. url: '/api/userjs/jeidanPost',
  226. method: 'POST',
  227. data: {
  228. order_id: id
  229. },
  230. success: (res) => {
  231. console.log('快速抢单', res);
  232. if (res.data?.code == 1) {
  233. uni.showToast({
  234. title: '抢单报名成功,等待客户选择',
  235. duration: 2000,
  236. icon: 'none'
  237. });
  238. getOrderList(false, false);
  239. } else {
  240. uni.showToast({
  241. title: res.data.msg,
  242. duration: 2000,
  243. icon: 'none'
  244. });
  245. }
  246. },
  247. fail: () => {},
  248. complete: () => {
  249. setTimeout(() => {
  250. uni.hideLoading();
  251. }, 2000);
  252. }
  253. });
  254. }
  255. }
  256. });
  257. };
  258. const initLocation = () => {
  259. statusBarHeight.value = uni.getSystemInfoSync().statusBarHeight;
  260. const address_storage = uni.getStorageSync('address');
  261. address.value = address_storage;
  262. console.log('初始化');
  263. realtimeOpen.value = true;
  264. getProjectCategory();
  265. uni.$on('realtimeOrderOpen', changeRealtimeOpen);
  266. };
  267. const changeRealtimeOpen = (e) => {
  268. realtimeOpen.value = !!e;
  269. };
  270. const renderData = async () => {
  271. console.log('渲染');
  272. realtimeOpen.value = true;
  273. uni.pageScrollTo({ scrollTop: 0, duration: 0 });
  274. getOrderList();
  275. getOrderNumber();
  276. getUserInfo();
  277. const realtime = setInterval(() => {
  278. if (realtimeOpen.value) {
  279. getOrderNumber();
  280. } else clearInterval(realtime);
  281. }, 3000);
  282. // const new_address = await getLocation();
  283. // if (new_address) address.value = new_address;
  284. };
  285. onLoad((option) => {
  286. initLocation();
  287. });
  288. onShow(() => {
  289. address.value = uni.getStorageSync('address');
  290. renderData();
  291. });
  292. watch(
  293. () => params.category_id,
  294. () => {
  295. getOrderList();
  296. }
  297. );
  298. watch(
  299. () => realtimeOpen.value,
  300. (newVal) => {
  301. console.log('newVal', newVal);
  302. }
  303. );
  304. watch(
  305. () => realtimeData.value,
  306. (newVal, oldVal) => {
  307. console.log('新值', newVal);
  308. console.log('旧值', oldVal);
  309. newVal.forEach((element, index) => {
  310. if (oldVal.length) {
  311. const old_element = oldVal[index];
  312. element['id'] == old_element['id'] && element['order_num'] != old_element['order_num'] && current.value == index && getOrderList();
  313. }
  314. });
  315. },
  316. //深度监听
  317. { deep: false }
  318. );
  319. </script>
  320. <style lang="scss" scoped>
  321. .navigation_wrap {
  322. padding: 20upx 20upx 0upx;
  323. .uni-badge--x {
  324. margin: 20upx 0;
  325. }
  326. }
  327. </style>