logic.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. import { getMyProfile, getPendingOrders, acceptOrder, getOrderCount } from '@/api/fulfiller'
  2. import { getServiceList } from '@/api/service'
  3. import { rejectOrderApi } from '@/api/order/subOrder/index'
  4. import { isLoggedIn } from '@/utils/auth'
  5. import customTabbar from '@/components/custom-tabbar/index.vue'
  6. export default {
  7. components: {
  8. customTabbar
  9. },
  10. data() {
  11. return {
  12. taskList: [],
  13. currentFilter: 'default', // default, distance, time
  14. filterCondition: '筛选条件',
  15. sortDistance: 'asc', // asc, desc
  16. sortTime: 'asc',
  17. scrollTop: 0, // Track scroll position
  18. isFilterShow: false,
  19. tempFilter: {
  20. service: null,
  21. distance: '全部',
  22. amount: '全部'
  23. },
  24. activeFilter: {
  25. service: null,
  26. distance: '全部',
  27. amount: '全部'
  28. },
  29. workStatus: 'working', // working | resting
  30. showConfirmModal: false,
  31. showPetModal: false,
  32. currentPetInfo: {},
  33. showRejectModal: false,
  34. rejectReason: '',
  35. currentOrder: null,
  36. showAcceptConfirmModal: false,
  37. showNavModal: false,
  38. navTargetItem: null,
  39. navTargetPointType: '',
  40. profile: null,
  41. profileLoading: false,
  42. serviceList: [],
  43. orderStats: {
  44. total: 0,
  45. reject: 0,
  46. completed: 0,
  47. price: 0
  48. }
  49. }
  50. },
  51. onPageScroll(e) {
  52. this.scrollTop = e.scrollTop;
  53. },
  54. async onLoad() {
  55. // Initial load
  56. this.checkWorkStatus();
  57. await this.loadServiceList();
  58. this.loadTaskList();
  59. },
  60. onShow() {
  61. uni.hideTabBar()
  62. this.checkWorkStatus();
  63. if (isLoggedIn()) {
  64. this.loadProfile()
  65. this.loadOrderStats()
  66. }
  67. },
  68. async onPullDownRefresh() {
  69. this.checkWorkStatus();
  70. try {
  71. await this.loadServiceList();
  72. const tasks = [
  73. this.loadTaskList()
  74. ];
  75. if (isLoggedIn()) {
  76. tasks.push(this.loadProfile());
  77. tasks.push(this.loadOrderStats());
  78. }
  79. await Promise.all(tasks);
  80. } catch (err) {
  81. console.error('刷新异常:', err);
  82. } finally {
  83. uni.stopPullDownRefresh();
  84. uni.showToast({ title: '刷新成功', icon: 'success' });
  85. }
  86. },
  87. methods: {
  88. async loadProfile() {
  89. if (this.profileLoading) return
  90. this.profileLoading = true
  91. try {
  92. const res = await getMyProfile()
  93. this.profile = res.data || null
  94. } catch (err) {
  95. console.error('获取个人信息失败:', err)
  96. } finally {
  97. this.profileLoading = false
  98. }
  99. },
  100. async loadServiceList() {
  101. try {
  102. const res = await getServiceList()
  103. this.serviceList = res.data || []
  104. } catch (err) {
  105. console.error('获取服务类型失败:', err)
  106. }
  107. },
  108. async loadOrderStats() {
  109. try {
  110. const res = await getOrderCount()
  111. this.orderStats = res.data || { total: 0, reject: 0, completed: 0, price: 0 }
  112. } catch (err) {
  113. console.error('获取订单统计失败:', err)
  114. }
  115. },
  116. checkWorkStatus() {
  117. const status = uni.getStorageSync('workStatus');
  118. if (status) {
  119. this.workStatus = status;
  120. } else {
  121. // Default to working if not set
  122. this.workStatus = 'working';
  123. uni.setStorageSync('workStatus', 'working');
  124. }
  125. },
  126. toggleFilter() {
  127. if (this.workStatus === 'resting') return; // Disable filter when resting? Or keep it? User didn't specify, but usually disabled. Let's keep it enabled for now as they might look at filters before working.
  128. this.isFilterShow = !this.isFilterShow;
  129. },
  130. goToWorkStatus() {
  131. uni.navigateTo({
  132. url: '/pages/home/work-status'
  133. });
  134. },
  135. startWork() {
  136. this.showConfirmModal = true;
  137. },
  138. confirmStartWork() {
  139. this.workStatus = 'working';
  140. uni.setStorageSync('workStatus', 'working');
  141. this.loadTaskList();
  142. this.showConfirmModal = false;
  143. uni.showToast({ title: '已开始接单', icon: 'success' });
  144. },
  145. closeConfirmModal() {
  146. this.showConfirmModal = false;
  147. },
  148. showPetProfile(item) {
  149. this.currentPetInfo = item;
  150. this.showPetModal = true;
  151. },
  152. closePetProfile() {
  153. this.showPetModal = false;
  154. },
  155. openRejectModal(item) {
  156. this.currentOrder = item;
  157. this.rejectReason = '';
  158. this.showRejectModal = true;
  159. },
  160. closeRejectModal() {
  161. this.showRejectModal = false;
  162. this.currentOrder = null;
  163. },
  164. async confirmReject() {
  165. if (!this.rejectReason.trim()) {
  166. uni.showToast({ title: '请输入拒绝理由', icon: 'none' });
  167. return;
  168. }
  169. if (!this.currentOrder?.id) return
  170. try {
  171. uni.showLoading({ title: '提交中...', mask: true });
  172. await rejectOrderApi({
  173. orderId: this.currentOrder.id,
  174. rejectReason: this.rejectReason
  175. });
  176. uni.showToast({ title: '已拒绝接单', icon: 'success' });
  177. this.showRejectModal = false;
  178. this.currentOrder = null;
  179. this.loadTaskList();
  180. this.loadOrderStats();
  181. } catch (err) {
  182. console.error('拒绝接单失败:', err);
  183. uni.showToast({ title: '操作失败', icon: 'none' });
  184. } finally {
  185. uni.hideLoading();
  186. }
  187. },
  188. openAcceptModal(item) {
  189. this.currentOrder = item;
  190. this.showAcceptConfirmModal = true;
  191. },
  192. closeAcceptModal() {
  193. this.showAcceptConfirmModal = false;
  194. this.currentOrder = null;
  195. },
  196. async confirmAccept() {
  197. if (!this.currentOrder?.id) return
  198. try {
  199. await acceptOrder(this.currentOrder.id)
  200. uni.showToast({ title: '接单成功', icon: 'success' })
  201. this.showAcceptConfirmModal = false
  202. this.currentOrder = null
  203. this.loadTaskList()
  204. this.loadProfile()
  205. this.loadOrderStats()
  206. } catch (err) {
  207. console.error('接单失败:', err)
  208. uni.showToast({ title: '接单失败', icon: 'none' })
  209. }
  210. },
  211. openNavigation(item, pointType) {
  212. this.navTargetItem = item;
  213. this.navTargetPointType = pointType;
  214. this.showNavModal = true;
  215. },
  216. closeNavModal() {
  217. this.showNavModal = false;
  218. },
  219. chooseMap(mapType) {
  220. let item = this.navTargetItem;
  221. let pointType = this.navTargetPointType;
  222. let name = pointType === 'start' ? item.startLocation : item.endLocation;
  223. let address = pointType === 'start' ? item.startAddress : item.endAddress;
  224. this.showNavModal = false;
  225. uni.openLocation({
  226. latitude: 30.52, // Mock lat
  227. longitude: 114.31, // Mock lng
  228. name: name || '目的地',
  229. address: address || '默认地址',
  230. success: function () {
  231. console.log('打开导航成功: ' + mapType);
  232. }
  233. });
  234. },
  235. selectService(type) {
  236. this.tempFilter.service = type;
  237. },
  238. selectDistance(type) {
  239. this.tempFilter.distance = type;
  240. },
  241. selectAmount(type) {
  242. this.tempFilter.amount = type;
  243. },
  244. resetFilter() {
  245. this.tempFilter = {
  246. service: null,
  247. distance: '全部',
  248. amount: '全部'
  249. };
  250. },
  251. confirmFilter() {
  252. this.activeFilter = { ...this.tempFilter };
  253. this.isFilterShow = false;
  254. this.loadTaskList();
  255. },
  256. closeFilter() {
  257. this.isFilterShow = false;
  258. },
  259. goToDetail(item) {
  260. console.log('Go to detail', item);
  261. },
  262. async loadTaskList() {
  263. try {
  264. const params = {
  265. service: this.activeFilter.service,
  266. minPrice: this.getMinPrice(),
  267. maxPrice: this.getMaxPrice(),
  268. pageNum: 1,
  269. pageSize: 20
  270. }
  271. const res = await getPendingOrders(params)
  272. this.taskList = (res.rows || []).map(item => this.transformOrder(item))
  273. } catch (err) {
  274. console.error('获取订单列表失败:', err)
  275. uni.showToast({ title: '加载失败', icon: 'none' })
  276. this.taskList = []
  277. }
  278. },
  279. getMinPrice() {
  280. const amount = this.activeFilter.amount
  281. if (amount === '100以下') return 0
  282. if (amount === '100-200') return 10000
  283. if (amount === '200-500') return 20000
  284. if (amount === '500以上') return 50000
  285. return undefined
  286. },
  287. getMaxPrice() {
  288. const amount = this.activeFilter.amount
  289. if (amount === '100以下') return 10000
  290. if (amount === '100-200') return 20000
  291. if (amount === '200-500') return 50000
  292. return undefined
  293. },
  294. transformOrder(item) {
  295. const service = this.serviceList.find(s => s.id === item.service)
  296. const serviceText = service?.name || '未知'
  297. const serviceIcon = service?.iconUrl || ''
  298. const mode = service?.mode || 0
  299. const isRoundTrip = mode === 1
  300. return {
  301. id: item.id,
  302. type: isRoundTrip ? 1 : item.service,
  303. typeText: serviceText,
  304. typeIcon: serviceIcon,
  305. price: (item.price / 100).toFixed(2),
  306. timeLabel: '服务时间',
  307. time: item.serviceTime,
  308. petAvatar: item.petAvatar || '/static/dog.png',
  309. petAvatarUrl: item.petAvatarUrl || '',
  310. petName: item.petName,
  311. petBreed: item.breed,
  312. petGender: 'M',
  313. petAge: '',
  314. petWeight: '',
  315. petPersonality: '',
  316. petHobby: '',
  317. petRemark: '',
  318. petTags: [],
  319. petLogs: [],
  320. startLocation: isRoundTrip ? item.fromAddress : '',
  321. startAddress: isRoundTrip ? item.fromAddress : '',
  322. startDistance: '0km',
  323. endLocation: (item.customerName || item.contact || '') + ' ' + (item.customerPhone || ''),
  324. endAddress: item.toAddress,
  325. endDistance: '0km',
  326. serviceContent: '',
  327. remark: item.remark || ''
  328. }
  329. },
  330. setFilter(type) {
  331. this.currentFilter = type;
  332. if (type === 'distance') {
  333. this.sortDistance = this.sortDistance === 'asc' ? 'desc' : 'asc';
  334. uni.showToast({ title: `按距离${this.sortDistance === 'asc' ? '升序' : '降序'}`, icon: 'none' });
  335. } else if (type === 'time') {
  336. this.sortTime = this.sortTime === 'asc' ? 'desc' : 'asc';
  337. uni.showToast({ title: `按时间${this.sortTime === 'asc' ? '升序' : '降序'}`, icon: 'none' });
  338. }
  339. },
  340. showFilterDropdown() {
  341. this.toggleFilter();
  342. }
  343. }
  344. }