logic.js 11 KB

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