driver-api.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. /**
  2. * 司机端API接口模拟系统
  3. * 模拟后台司机管理、订单状态更新和位置共享功能
  4. */
  5. class DriverApiService {
  6. constructor() {
  7. this.listeners = []; // 订单状态变化监听器
  8. this.locationListeners = []; // 位置更新监听器
  9. this.initDriverData();
  10. // 模拟司机位置更新
  11. this.startLocationSimulation();
  12. }
  13. // 初始化司机数据
  14. initDriverData() {
  15. const drivers = this.getAllDrivers();
  16. if (drivers.length === 0) {
  17. // 初始化示例司机数据
  18. const sampleDrivers = [
  19. {
  20. id: 'driver_001',
  21. name: '张师傅',
  22. phone: '13800138001',
  23. carNumber: '京A12345',
  24. carModel: '宇通大巴',
  25. avatar: '/images/avatar-default.png',
  26. rating: 4.8,
  27. completedOrders: 1250,
  28. status: 'available', // available, busy, offline
  29. currentLocation: {
  30. lng: 116.404,
  31. lat: 39.915,
  32. address: '北京市东城区东直门',
  33. updateTime: new Date().toISOString()
  34. },
  35. certification: {
  36. driverLicense: '11010119800101****',
  37. vehicleLicense: '京A12345',
  38. verified: true
  39. }
  40. },
  41. {
  42. id: 'driver_002',
  43. name: '李师傅',
  44. phone: '13800138002',
  45. carNumber: '京B67890',
  46. carModel: '奔驰V级商务车',
  47. avatar: '/images/avatar-default.png',
  48. rating: 4.9,
  49. completedOrders: 890,
  50. status: 'available',
  51. currentLocation: {
  52. lng: 121.473,
  53. lat: 31.230,
  54. address: '上海市黄浦区人民广场',
  55. updateTime: new Date().toISOString()
  56. },
  57. certification: {
  58. driverLicense: '31010219850301****',
  59. vehicleLicense: '京B67890',
  60. verified: true
  61. }
  62. }
  63. ];
  64. this.saveDrivers(sampleDrivers);
  65. }
  66. }
  67. // 获取所有司机
  68. getAllDrivers() {
  69. try {
  70. return wx.getStorageSync('drivers') || [];
  71. } catch (error) {
  72. console.error('获取司机数据失败:', error);
  73. return [];
  74. }
  75. }
  76. // 保存司机数据
  77. saveDrivers(drivers) {
  78. try {
  79. wx.setStorageSync('drivers', drivers);
  80. return true;
  81. } catch (error) {
  82. console.error('保存司机数据失败:', error);
  83. return false;
  84. }
  85. }
  86. // 根据ID获取司机信息
  87. getDriverById(driverId) {
  88. const drivers = this.getAllDrivers();
  89. return drivers.find(driver => driver.id === driverId);
  90. }
  91. // 为订单分配司机(模拟后台API)
  92. async assignDriverToOrder(orderId, orderType = 'bus') {
  93. return new Promise((resolve, reject) => {
  94. setTimeout(() => {
  95. try {
  96. const drivers = this.getAllDrivers();
  97. const availableDrivers = drivers.filter(driver =>
  98. driver.status === 'available' &&
  99. this.isDriverSuitableForOrder(driver, orderType)
  100. );
  101. if (availableDrivers.length === 0) {
  102. reject(new Error('暂无可用司机'));
  103. return;
  104. }
  105. // 随机选择一个可用司机
  106. const selectedDriver = availableDrivers[Math.floor(Math.random() * availableDrivers.length)];
  107. // 更新司机状态为忙碌
  108. const updatedDrivers = drivers.map(driver =>
  109. driver.id === selectedDriver.id
  110. ? { ...driver, status: 'busy', currentOrderId: orderId }
  111. : driver
  112. );
  113. this.saveDrivers(updatedDrivers);
  114. // 创建司机订单关联
  115. this.createDriverOrderRelation(selectedDriver.id, orderId);
  116. resolve({
  117. success: true,
  118. data: {
  119. driverId: selectedDriver.id,
  120. driverName: selectedDriver.name,
  121. driverPhone: selectedDriver.phone,
  122. carNumber: selectedDriver.carNumber,
  123. carModel: selectedDriver.carModel,
  124. rating: selectedDriver.rating,
  125. estimatedArrival: this.calculateEstimatedArrival(),
  126. assignTime: new Date().toISOString()
  127. }
  128. });
  129. } catch (error) {
  130. reject(error);
  131. }
  132. }, 2000); // 模拟API延迟
  133. });
  134. }
  135. // 判断司机是否适合订单类型
  136. isDriverSuitableForOrder(driver, orderType) {
  137. if (orderType === 'business-charter') {
  138. return driver.carModel.includes('商务车') || driver.carModel.includes('奔驰') || driver.carModel.includes('宝马');
  139. }
  140. return true; // 大巴司机可以接所有订单
  141. }
  142. // 计算预计到达时间
  143. calculateEstimatedArrival() {
  144. const now = new Date();
  145. const estimatedMinutes = Math.floor(Math.random() * 20) + 10; // 10-30分钟
  146. const estimatedTime = new Date(now.getTime() + estimatedMinutes * 60000);
  147. return {
  148. minutes: estimatedMinutes,
  149. time: estimatedTime.toISOString(),
  150. display: `约${estimatedMinutes}分钟后到达`
  151. };
  152. }
  153. // 创建司机订单关联
  154. createDriverOrderRelation(driverId, orderId) {
  155. try {
  156. const relations = wx.getStorageSync('driver_order_relations') || [];
  157. const newRelation = {
  158. id: `relation_${Date.now()}`,
  159. driverId,
  160. orderId,
  161. createTime: new Date().toISOString(),
  162. status: 'assigned', // assigned, picked_up, in_transit, completed
  163. events: [
  164. {
  165. type: 'assigned',
  166. time: new Date().toISOString(),
  167. description: '司机已分配'
  168. }
  169. ]
  170. };
  171. relations.push(newRelation);
  172. wx.setStorageSync('driver_order_relations', relations);
  173. return newRelation;
  174. } catch (error) {
  175. console.error('创建司机订单关联失败:', error);
  176. return null;
  177. }
  178. }
  179. // 获取订单的司机信息
  180. getOrderDriverInfo(orderId) {
  181. try {
  182. const relations = wx.getStorageSync('driver_order_relations') || [];
  183. const relation = relations.find(r => r.orderId === orderId);
  184. if (!relation) {
  185. return null;
  186. }
  187. const driver = this.getDriverById(relation.driverId);
  188. if (!driver) {
  189. return null;
  190. }
  191. return {
  192. relation,
  193. driver,
  194. status: relation.status,
  195. events: relation.events,
  196. currentLocation: driver.currentLocation
  197. };
  198. } catch (error) {
  199. console.error('获取订单司机信息失败:', error);
  200. return null;
  201. }
  202. }
  203. // 司机确认乘客上车(模拟司机端操作)
  204. async confirmPickup(orderId, driverId) {
  205. return new Promise((resolve, reject) => {
  206. setTimeout(() => {
  207. try {
  208. const relations = wx.getStorageSync('driver_order_relations') || [];
  209. const relationIndex = relations.findIndex(r => r.orderId === orderId && r.driverId === driverId);
  210. if (relationIndex === -1) {
  211. reject(new Error('订单司机关联不存在'));
  212. return;
  213. }
  214. // 更新关联状态
  215. relations[relationIndex].status = 'picked_up';
  216. relations[relationIndex].events.push({
  217. type: 'picked_up',
  218. time: new Date().toISOString(),
  219. description: '乘客已上车',
  220. location: this.getDriverById(driverId)?.currentLocation
  221. });
  222. wx.setStorageSync('driver_order_relations', relations);
  223. // 通知监听器
  224. this.notifyOrderStatusChange(orderId, 'picked_up', '乘客已上车');
  225. resolve({
  226. success: true,
  227. message: '确认上车成功',
  228. status: 'picked_up',
  229. time: new Date().toISOString()
  230. });
  231. } catch (error) {
  232. reject(error);
  233. }
  234. }, 1000);
  235. });
  236. }
  237. // 司机开始行程(模拟司机端操作)
  238. async startTrip(orderId, driverId) {
  239. return new Promise((resolve, reject) => {
  240. setTimeout(() => {
  241. try {
  242. const relations = wx.getStorageSync('driver_order_relations') || [];
  243. const relationIndex = relations.findIndex(r => r.orderId === orderId && r.driverId === driverId);
  244. if (relationIndex === -1) {
  245. reject(new Error('订单司机关联不存在'));
  246. return;
  247. }
  248. relations[relationIndex].status = 'in_transit';
  249. relations[relationIndex].events.push({
  250. type: 'in_transit',
  251. time: new Date().toISOString(),
  252. description: '行程已开始',
  253. location: this.getDriverById(driverId)?.currentLocation
  254. });
  255. wx.setStorageSync('driver_order_relations', relations);
  256. this.notifyOrderStatusChange(orderId, 'in_transit', '行程中');
  257. resolve({
  258. success: true,
  259. message: '行程开始',
  260. status: 'in_transit',
  261. time: new Date().toISOString()
  262. });
  263. } catch (error) {
  264. reject(error);
  265. }
  266. }, 1000);
  267. });
  268. }
  269. // 司机确认到达(模拟司机端操作)
  270. async confirmArrival(orderId, driverId) {
  271. return new Promise((resolve, reject) => {
  272. setTimeout(() => {
  273. try {
  274. const relations = wx.getStorageSync('driver_order_relations') || [];
  275. const relationIndex = relations.findIndex(r => r.orderId === orderId && r.driverId === driverId);
  276. if (relationIndex === -1) {
  277. reject(new Error('订单司机关联不存在'));
  278. return;
  279. }
  280. relations[relationIndex].status = 'completed';
  281. relations[relationIndex].events.push({
  282. type: 'completed',
  283. time: new Date().toISOString(),
  284. description: '已到达目的地',
  285. location: this.getDriverById(driverId)?.currentLocation
  286. });
  287. wx.setStorageSync('driver_order_relations', relations);
  288. // 释放司机
  289. const drivers = this.getAllDrivers();
  290. const updatedDrivers = drivers.map(driver =>
  291. driver.id === driverId
  292. ? { ...driver, status: 'available', currentOrderId: null }
  293. : driver
  294. );
  295. this.saveDrivers(updatedDrivers);
  296. this.notifyOrderStatusChange(orderId, 'completed', '已完成');
  297. resolve({
  298. success: true,
  299. message: '行程完成',
  300. status: 'completed',
  301. time: new Date().toISOString()
  302. });
  303. } catch (error) {
  304. reject(error);
  305. }
  306. }, 1000);
  307. });
  308. }
  309. // 更新司机位置(模拟司机端定位)
  310. updateDriverLocation(driverId, location) {
  311. try {
  312. const drivers = this.getAllDrivers();
  313. const updatedDrivers = drivers.map(driver =>
  314. driver.id === driverId
  315. ? {
  316. ...driver,
  317. currentLocation: {
  318. ...location,
  319. updateTime: new Date().toISOString()
  320. }
  321. }
  322. : driver
  323. );
  324. this.saveDrivers(updatedDrivers);
  325. this.notifyLocationUpdate(driverId, location);
  326. return true;
  327. } catch (error) {
  328. console.error('更新司机位置失败:', error);
  329. return false;
  330. }
  331. }
  332. // 获取司机实时位置
  333. getDriverLocation(driverId) {
  334. const driver = this.getDriverById(driverId);
  335. return driver ? driver.currentLocation : null;
  336. }
  337. // 模拟司机位置移动
  338. startLocationSimulation() {
  339. // 清除之前的定时器
  340. if (this.locationTimer) {
  341. clearInterval(this.locationTimer);
  342. }
  343. this.locationTimer = setInterval(() => {
  344. const drivers = this.getAllDrivers();
  345. const busyDrivers = drivers.filter(driver => driver.status === 'busy');
  346. busyDrivers.forEach(driver => {
  347. // 模拟位置变化
  348. const currentLoc = driver.currentLocation;
  349. const newLocation = {
  350. lng: currentLoc.lng + (Math.random() - 0.5) * 0.01, // 随机移动
  351. lat: currentLoc.lat + (Math.random() - 0.5) * 0.01,
  352. address: this.generateRandomAddress(),
  353. updateTime: new Date().toISOString()
  354. };
  355. this.updateDriverLocation(driver.id, newLocation);
  356. });
  357. }, 10000); // 每10秒更新一次位置
  358. }
  359. // 停止位置模拟
  360. stopLocationSimulation() {
  361. if (this.locationTimer) {
  362. clearInterval(this.locationTimer);
  363. this.locationTimer = null;
  364. }
  365. }
  366. // 生成随机地址(模拟)
  367. generateRandomAddress() {
  368. const addresses = [
  369. '北京市朝阳区建国门外大街',
  370. '北京市海淀区中关村大街',
  371. '北京市东城区王府井大街',
  372. '北京市西城区金融街',
  373. '上海市黄浦区南京东路',
  374. '上海市浦东新区陆家嘴'
  375. ];
  376. return addresses[Math.floor(Math.random() * addresses.length)];
  377. }
  378. // 监听器管理
  379. addOrderStatusListener(callback) {
  380. this.listeners.push(callback);
  381. }
  382. removeOrderStatusListener(callback) {
  383. const index = this.listeners.indexOf(callback);
  384. if (index > -1) {
  385. this.listeners.splice(index, 1);
  386. }
  387. }
  388. notifyOrderStatusChange(orderId, status, statusText) {
  389. this.listeners.forEach(callback => {
  390. try {
  391. callback({ orderId, status, statusText, time: new Date().toISOString() });
  392. } catch (error) {
  393. console.error('订单状态监听器回调执行失败:', error);
  394. }
  395. });
  396. }
  397. addLocationListener(callback) {
  398. this.locationListeners.push(callback);
  399. }
  400. removeLocationListener(callback) {
  401. const index = this.locationListeners.indexOf(callback);
  402. if (index > -1) {
  403. this.locationListeners.splice(index, 1);
  404. }
  405. }
  406. notifyLocationUpdate(driverId, location) {
  407. this.locationListeners.forEach(callback => {
  408. try {
  409. callback({ driverId, location, time: new Date().toISOString() });
  410. } catch (error) {
  411. console.error('位置监听器回调执行失败:', error);
  412. }
  413. });
  414. }
  415. // 模拟司机端操作API(供测试使用)
  416. async simulateDriverActions(orderId, driverId) {
  417. try {
  418. console.log('开始模拟司机操作流程...');
  419. // 5秒后确认上车
  420. setTimeout(async () => {
  421. await this.confirmPickup(orderId, driverId);
  422. console.log('司机已确认乘客上车');
  423. }, 5000);
  424. // 10秒后开始行程
  425. setTimeout(async () => {
  426. await this.startTrip(orderId, driverId);
  427. console.log('司机已开始行程');
  428. }, 10000);
  429. // 60秒后确认到达(模拟1分钟行程)
  430. setTimeout(async () => {
  431. await this.confirmArrival(orderId, driverId);
  432. console.log('司机已确认到达');
  433. }, 60000);
  434. } catch (error) {
  435. console.error('模拟司机操作失败:', error);
  436. }
  437. }
  438. }
  439. // 创建单例实例
  440. const driverApiService = new DriverApiService();
  441. export default driverApiService;