logic.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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. award: 0,
  47. punishment: 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, award: 0, punishment: 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. } catch (err) {
  181. console.error('拒绝接单失败:', err);
  182. uni.showToast({ title: '操作失败', icon: 'none' });
  183. } finally {
  184. uni.hideLoading();
  185. }
  186. },
  187. openAcceptModal(item) {
  188. this.currentOrder = item;
  189. this.showAcceptConfirmModal = true;
  190. },
  191. closeAcceptModal() {
  192. this.showAcceptConfirmModal = false;
  193. this.currentOrder = null;
  194. },
  195. async confirmAccept() {
  196. if (!this.currentOrder?.id) return
  197. try {
  198. await acceptOrder(this.currentOrder.id)
  199. uni.showToast({ title: '接单成功', icon: 'success' })
  200. this.showAcceptConfirmModal = false
  201. this.currentOrder = null
  202. this.loadTaskList()
  203. this.loadProfile()
  204. } catch (err) {
  205. console.error('接单失败:', err)
  206. uni.showToast({ title: '接单失败', icon: 'none' })
  207. }
  208. },
  209. openNavigation(item, pointType) {
  210. this.navTargetItem = item;
  211. this.navTargetPointType = pointType;
  212. this.showNavModal = true;
  213. },
  214. closeNavModal() {
  215. this.showNavModal = false;
  216. },
  217. chooseMap(mapType) {
  218. let item = this.navTargetItem;
  219. let pointType = this.navTargetPointType;
  220. let name = pointType === 'start' ? item.startLocation : item.endLocation;
  221. let address = pointType === 'start' ? item.startAddress : item.endAddress;
  222. this.showNavModal = false;
  223. uni.openLocation({
  224. latitude: 30.52, // Mock lat
  225. longitude: 114.31, // Mock lng
  226. name: name || '目的地',
  227. address: address || '默认地址',
  228. success: function () {
  229. console.log('打开导航成功: ' + mapType);
  230. }
  231. });
  232. },
  233. selectService(type) {
  234. this.tempFilter.service = type;
  235. },
  236. selectDistance(type) {
  237. this.tempFilter.distance = type;
  238. },
  239. selectAmount(type) {
  240. this.tempFilter.amount = type;
  241. },
  242. resetFilter() {
  243. this.tempFilter = {
  244. service: null,
  245. distance: '全部',
  246. amount: '全部'
  247. };
  248. },
  249. confirmFilter() {
  250. this.activeFilter = { ...this.tempFilter };
  251. this.isFilterShow = false;
  252. this.loadTaskList();
  253. },
  254. closeFilter() {
  255. this.isFilterShow = false;
  256. },
  257. goToDetail(item) {
  258. console.log('Go to detail', item);
  259. },
  260. async loadTaskList() {
  261. try {
  262. const params = {
  263. service: this.activeFilter.service,
  264. minPrice: this.getMinPrice(),
  265. maxPrice: this.getMaxPrice(),
  266. pageNum: 1,
  267. pageSize: 20
  268. }
  269. const res = await getPendingOrders(params)
  270. this.taskList = (res.rows || []).map(item => this.transformOrder(item))
  271. } catch (err) {
  272. console.error('获取订单列表失败:', err)
  273. uni.showToast({ title: '加载失败', icon: 'none' })
  274. this.taskList = []
  275. }
  276. },
  277. getMinPrice() {
  278. const amount = this.activeFilter.amount
  279. if (amount === '100以下') return 0
  280. if (amount === '100-200') return 10000
  281. if (amount === '200-500') return 20000
  282. if (amount === '500以上') return 50000
  283. return undefined
  284. },
  285. getMaxPrice() {
  286. const amount = this.activeFilter.amount
  287. if (amount === '100以下') return 10000
  288. if (amount === '100-200') return 20000
  289. if (amount === '200-500') return 50000
  290. return undefined
  291. },
  292. transformOrder(item) {
  293. const service = this.serviceList.find(s => s.id === item.service)
  294. const serviceText = service?.name || '未知'
  295. const serviceIcon = service?.iconUrl || ''
  296. const mode = service?.mode || 0
  297. const isRoundTrip = mode === 1
  298. return {
  299. id: item.id,
  300. type: isRoundTrip ? 1 : item.service,
  301. typeText: serviceText,
  302. typeIcon: serviceIcon,
  303. price: (item.price / 100).toFixed(2),
  304. timeLabel: '服务时间',
  305. time: item.serviceTime,
  306. petAvatar: '/static/dog.png',
  307. petName: item.petName,
  308. petBreed: item.breed,
  309. petGender: 'M',
  310. petAge: '',
  311. petWeight: '',
  312. petPersonality: '',
  313. petHobby: '',
  314. petRemark: '',
  315. petTags: [],
  316. petLogs: [],
  317. startLocation: isRoundTrip ? item.fromAddress : '',
  318. startAddress: isRoundTrip ? item.fromAddress : '',
  319. startDistance: '0km',
  320. endLocation: (item.customerName || item.contact || '') + ' ' + (item.customerPhone || ''),
  321. endAddress: item.toAddress,
  322. endDistance: '0km',
  323. serviceContent: '',
  324. remark: item.remark || ''
  325. }
  326. },
  327. setFilter(type) {
  328. this.currentFilter = type;
  329. if (type === 'distance') {
  330. this.sortDistance = this.sortDistance === 'asc' ? 'desc' : 'asc';
  331. uni.showToast({ title: `按距离${this.sortDistance === 'asc' ? '升序' : '降序'}`, icon: 'none' });
  332. } else if (type === 'time') {
  333. this.sortTime = this.sortTime === 'asc' ? 'desc' : 'asc';
  334. uni.showToast({ title: `按时间${this.sortTime === 'asc' ? '升序' : '降序'}`, icon: 'none' });
  335. }
  336. },
  337. showFilterDropdown() {
  338. this.toggleFilter();
  339. }
  340. }
  341. }