logic.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. import { getMyProfile, getPendingOrders, acceptOrder, getOrderCount } from '@/api/fulfiller'
  2. import { listAllService } from '@/api/service/list/index'
  3. import { rejectOrderApi } from '@/api/order/subOrder/index.js'
  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: 'resting', // resting | busy | disabled
  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. // 每次进入页面强制刷新所有展示数据
  65. this.loadProfile()
  66. this.loadOrderStats()
  67. this.loadTaskList()
  68. this.loadServiceList() // 确保服务配置也是最新的
  69. }
  70. },
  71. async onPullDownRefresh() {
  72. this.checkWorkStatus();
  73. try {
  74. await this.loadServiceList();
  75. const tasks = [
  76. this.loadTaskList()
  77. ];
  78. if (isLoggedIn()) {
  79. tasks.push(this.loadProfile());
  80. tasks.push(this.loadOrderStats());
  81. }
  82. await Promise.all(tasks);
  83. } catch (err) {
  84. console.error('刷新异常:', err);
  85. } finally {
  86. uni.stopPullDownRefresh();
  87. uni.showToast({ title: '刷新成功', icon: 'success' });
  88. }
  89. },
  90. methods: {
  91. async loadProfile() {
  92. if (this.profileLoading) return
  93. this.profileLoading = true
  94. try {
  95. const res = await getMyProfile()
  96. const data = res.data || null
  97. this.profile = data
  98. // 以服务器返回的状态为准进行更新
  99. if (data && data.status) {
  100. this.workStatus = data.status;
  101. uni.setStorageSync('workStatus', data.status);
  102. }
  103. } catch (err) {
  104. console.error('获取个人信息失败:', err)
  105. } finally {
  106. this.profileLoading = false
  107. }
  108. },
  109. async loadServiceList() {
  110. try {
  111. const res = await listAllService()
  112. this.serviceList = res.data || []
  113. } catch (err) {
  114. console.error('获取服务类型失败:', err)
  115. }
  116. },
  117. async loadOrderStats() {
  118. try {
  119. const res = await getOrderCount()
  120. this.orderStats = res.data || { total: 0, reject: 0, completed: 0, price: 0 }
  121. } catch (err) {
  122. console.error('获取订单统计失败:', err)
  123. }
  124. },
  125. checkWorkStatus() {
  126. const status = uni.getStorageSync('workStatus');
  127. if (status) {
  128. this.workStatus = status;
  129. } else {
  130. // 默认状态为休息
  131. this.workStatus = 'resting';
  132. uni.setStorageSync('workStatus', 'resting');
  133. }
  134. },
  135. toggleFilter() {
  136. 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.
  137. this.isFilterShow = !this.isFilterShow;
  138. },
  139. goToWorkStatus() {
  140. uni.navigateTo({
  141. url: '/pages/home/work-status'
  142. });
  143. },
  144. startWork() {
  145. this.showConfirmModal = true;
  146. },
  147. confirmStartWork() {
  148. this.workStatus = 'busy';
  149. uni.setStorageSync('workStatus', 'busy');
  150. this.loadTaskList();
  151. this.showConfirmModal = false;
  152. uni.showToast({ title: '已开始接单', icon: 'success' });
  153. },
  154. closeConfirmModal() {
  155. this.showConfirmModal = false;
  156. },
  157. showPetProfile(item) {
  158. this.currentPetInfo = item;
  159. this.showPetModal = true;
  160. },
  161. closePetProfile() {
  162. this.showPetModal = false;
  163. },
  164. openRejectModal(item) {
  165. this.currentOrder = item;
  166. this.rejectReason = '';
  167. this.showRejectModal = true;
  168. },
  169. closeRejectModal() {
  170. this.showRejectModal = false;
  171. this.currentOrder = null;
  172. },
  173. async confirmReject() {
  174. if (!this.rejectReason.trim()) {
  175. uni.showToast({ title: '请输入拒绝理由', icon: 'none' });
  176. return;
  177. }
  178. if (!this.currentOrder?.id) return
  179. try {
  180. uni.showLoading({ title: '提交中...', mask: true });
  181. await rejectOrderApi({
  182. orderId: this.currentOrder.id,
  183. rejectReason: this.rejectReason
  184. });
  185. uni.showToast({ title: '已拒绝接单', icon: 'success' });
  186. this.showRejectModal = false;
  187. this.currentOrder = null;
  188. this.loadTaskList();
  189. this.loadOrderStats();
  190. } catch (err) {
  191. console.error('拒绝接单失败:', err);
  192. uni.showToast({ title: '操作失败', icon: 'none' });
  193. } finally {
  194. uni.hideLoading();
  195. }
  196. },
  197. openAcceptModal(item) {
  198. this.currentOrder = item;
  199. this.showAcceptConfirmModal = true;
  200. },
  201. closeAcceptModal() {
  202. this.showAcceptConfirmModal = false;
  203. this.currentOrder = null;
  204. },
  205. async confirmAccept() {
  206. if (!this.currentOrder?.id) return
  207. try {
  208. await acceptOrder(this.currentOrder.id)
  209. uni.showToast({ title: '接单成功', icon: 'success' })
  210. this.showAcceptConfirmModal = false
  211. this.currentOrder = null
  212. this.loadTaskList()
  213. this.loadProfile()
  214. this.loadOrderStats()
  215. } catch (err) {
  216. console.error('接单失败:', err)
  217. uni.showToast({ title: '接单失败', icon: 'none' })
  218. }
  219. },
  220. openNavigation(item, pointType) {
  221. this.navTargetItem = item;
  222. this.navTargetPointType = pointType;
  223. this.showNavModal = true;
  224. },
  225. closeNavModal() {
  226. this.showNavModal = false;
  227. },
  228. chooseMap(mapType) {
  229. let item = this.navTargetItem;
  230. let pointType = this.navTargetPointType;
  231. let name = pointType === 'start' ? item.startLocation : item.endLocation;
  232. let address = pointType === 'start' ? item.startAddress : item.endAddress;
  233. this.showNavModal = false;
  234. uni.openLocation({
  235. latitude: 30.52, // Mock lat
  236. longitude: 114.31, // Mock lng
  237. name: name || '目的地',
  238. address: address || '默认地址',
  239. success: function () {
  240. console.log('打开导航成功: ' + mapType);
  241. }
  242. });
  243. },
  244. selectService(type) {
  245. this.tempFilter.service = type;
  246. },
  247. selectDistance(type) {
  248. this.tempFilter.distance = type;
  249. },
  250. selectAmount(type) {
  251. this.tempFilter.amount = type;
  252. },
  253. resetFilter() {
  254. this.tempFilter = {
  255. service: null,
  256. distance: '全部',
  257. amount: '全部'
  258. };
  259. },
  260. confirmFilter() {
  261. this.activeFilter = { ...this.tempFilter };
  262. this.isFilterShow = false;
  263. this.loadTaskList();
  264. },
  265. closeFilter() {
  266. this.isFilterShow = false;
  267. },
  268. goToDetail(item) {
  269. console.log('Go to detail', item);
  270. },
  271. async loadTaskList() {
  272. try {
  273. const params = {
  274. service: this.activeFilter.service,
  275. minPrice: this.getMinPrice(),
  276. maxPrice: this.getMaxPrice(),
  277. pageNum: 1,
  278. pageSize: 20
  279. }
  280. const res = await getPendingOrders(params)
  281. this.taskList = (res.rows || []).map(item => this.transformOrder(item))
  282. } catch (err) {
  283. console.error('获取订单列表失败:', err)
  284. uni.showToast({ title: '加载失败', icon: 'none' })
  285. this.taskList = []
  286. }
  287. },
  288. getMinPrice() {
  289. const amount = this.activeFilter.amount
  290. if (amount === '100以下') return 0
  291. if (amount === '100-200') return 10000
  292. if (amount === '200-500') return 20000
  293. if (amount === '500以上') return 50000
  294. return undefined
  295. },
  296. getMaxPrice() {
  297. const amount = this.activeFilter.amount
  298. if (amount === '100以下') return 10000
  299. if (amount === '100-200') return 20000
  300. if (amount === '200-500') return 50000
  301. return undefined
  302. },
  303. transformOrder(item) {
  304. const service = this.serviceList.find(s => s.id === item.service)
  305. const serviceText = service?.name || '未知'
  306. const serviceIcon = service?.iconUrl || ''
  307. const mode = service?.mode || 0
  308. const isRoundTrip = mode === 1
  309. return {
  310. id: item.id,
  311. type: isRoundTrip ? 1 : item.service,
  312. typeText: serviceText,
  313. typeIcon: serviceIcon,
  314. price: (item.price / 100).toFixed(2),
  315. timeLabel: '服务时间',
  316. time: item.serviceTime,
  317. petAvatar: item.petAvatar || '/static/dog.png',
  318. petAvatarUrl: item.petAvatarUrl || '',
  319. petName: item.petName,
  320. petBreed: item.breed,
  321. petGender: 'M',
  322. petAge: '',
  323. petWeight: '',
  324. petPersonality: '',
  325. petHobby: '',
  326. petRemark: '',
  327. petTags: [],
  328. petLogs: [],
  329. startLocation: isRoundTrip ? item.fromAddress : '',
  330. startAddress: isRoundTrip ? item.fromAddress : '',
  331. startDistance: '0km',
  332. endLocation: (item.customerName || item.contact || '') + ' ' + (item.customerPhone || ''),
  333. endAddress: item.toAddress,
  334. endDistance: '0km',
  335. serviceContent: '',
  336. remark: item.remark || ''
  337. }
  338. },
  339. setFilter(type) {
  340. this.currentFilter = type;
  341. if (type === 'distance') {
  342. this.sortDistance = this.sortDistance === 'asc' ? 'desc' : 'asc';
  343. uni.showToast({ title: `按距离${this.sortDistance === 'asc' ? '升序' : '降序'}`, icon: 'none' });
  344. } else if (type === 'time') {
  345. this.sortTime = this.sortTime === 'asc' ? 'desc' : 'asc';
  346. uni.showToast({ title: `按时间${this.sortTime === 'asc' ? '升序' : '降序'}`, icon: 'none' });
  347. }
  348. },
  349. showFilterDropdown() {
  350. this.toggleFilter();
  351. }
  352. }
  353. }