MainAbilitySlice.java 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. package com.fujica.abk.slice;
  2. import com.fujica.abk.ResourceTable;
  3. import com.fujica.abk.api.auth;
  4. import com.fujica.abk.api.cache;
  5. import com.fujica.abk.api.pay;
  6. import com.fujica.abk.common.EventBus;
  7. import com.fujica.abk.component.*;
  8. import com.fujica.abk.component.nav.ChargeComponent;
  9. import com.fujica.abk.component.nav.OrderComponent;
  10. import com.fujica.abk.component.nav.ParkComponent;
  11. import com.fujica.abk.model.out.OrderRes;
  12. import com.fujica.abk.model.out.ParkNearRes;
  13. import com.fujica.abk.model.out.ParkingFeeInfo;
  14. import com.fujica.abk.model.out.PayChannelResponse;
  15. import com.fujica.abk.model.out.PayChannelInfo;
  16. import com.fujica.abk.utils.*;
  17. import com.huawei.hms.accountsdk.constant.CommonConstant;
  18. import com.huawei.hms.accountsdk.exception.ApiException;
  19. import com.huawei.hms.accountsdk.support.account.AccountAuthManager;
  20. import com.huawei.hms.accountsdk.support.account.request.AccountAuthParams;
  21. import com.huawei.hms.accountsdk.support.account.request.AccountAuthParamsHelper;
  22. import com.huawei.hms.accountsdk.support.account.result.AuthAccount;
  23. import com.huawei.hms.accountsdk.support.account.service.AccountAuthService;
  24. import com.huawei.hms.accountsdk.support.account.tasks.OnFailureListener;
  25. import com.huawei.hms.accountsdk.support.account.tasks.OnSuccessListener;
  26. import com.huawei.hms.accountsdk.support.account.tasks.Task;
  27. import ohos.aafwk.ability.AbilitySlice;
  28. import ohos.aafwk.content.Intent;
  29. import ohos.agp.components.*;
  30. import ohos.agp.utils.Color;
  31. import ohos.agp.window.service.Window;
  32. import ohos.agp.window.service.WindowManager;
  33. public class MainAbilitySlice extends AbilitySlice {
  34. // 页面容器
  35. private StackLayout pageContainer;
  36. // 底部导航栏组件
  37. private DirectionalLayout navCharge;
  38. private DirectionalLayout navPark;
  39. private DirectionalLayout navOrder;
  40. private DirectionalLayout navCurrentLocation;
  41. // 底部导航栏文字和图标
  42. private Text textCharge;
  43. private Text textPark;
  44. private Text textOrder;
  45. private Image iconPark;
  46. private Image iconPark1;
  47. private Image iconCharge;
  48. private Image iconCharge1;
  49. private Image iconOrder;
  50. private Image iconOrder1;
  51. // 页面组件
  52. private ChargeComponent chargeComponent;
  53. private ParkComponent parkComponent; // 找车位页面组件
  54. private OrderComponent orderComponent; // 缴费记录页面组件
  55. // 页面初始化标志
  56. private boolean isChargeComponentInitialized = false;
  57. private boolean isParkComponentInitialized = false;
  58. private boolean isOrderComponentInitialized = false;
  59. // 详情区域
  60. private DirectionalLayout mainRight; // 右侧详情区域
  61. private OrderDetailComponent orderDetailComponent; // 订单详情组件
  62. private ParkDetailComponent parkDetailComponent; // 停车场详情组件
  63. // Loading组件
  64. private LoadingComponent loadingComponent;
  65. // 登录成功事件监听器
  66. private EventBus.EventListener loginSuccessListener;
  67. // 认证状态变化事件监听器
  68. private EventBus.EventListener authChangedListener;
  69. private Image quit;
  70. // 当前选中的 tab
  71. private int currentTab = 0; // 0: 找车位, 1: 计费, 2: 缴费记录
  72. @Override
  73. public void onStart(Intent intent) {
  74. super.onStart(intent);
  75. // try {
  76. // //com.fujica.abk_BD8VI9k5bO0HeGAPnhTGeYX++mgKw87G8y+3RZ6nrb9evCePddojupXJN03auUKxTKn1qbFrYQAjFyGumpjsHzw=
  77. // String appId = getApplicationContext().getBundleManager().getBundleInfo(getBundleName(), 0).getAppId();
  78. // Log.info(appId);
  79. // } catch (RemoteException e) {
  80. // }
  81. // 设置全屏显示
  82. setFullScreen();
  83. // 设置布局
  84. super.setUIContent(ResourceTable.Layout_ability_main);
  85. // 初始化Loading组件并添加到根布局
  86. loadingComponent = findComponentById(ResourceTable.Id_loading_component);
  87. // 初始化详情区域
  88. mainRight = findComponentById(ResourceTable.Id_main_right);
  89. if (mainRight != null) {
  90. // 创建详情组件
  91. orderDetailComponent = new OrderDetailComponent(this);
  92. parkDetailComponent = new ParkDetailComponent(this);
  93. }
  94. quit = findComponentById(ResourceTable.Id_quit);
  95. quit.setClickedListener(v -> {
  96. DialogUtil.confirm(getContext(), "确认要退出吗?", () -> {
  97. cache.logout(getContext());
  98. quit.setVisibility(Component.HIDE);
  99. });
  100. });
  101. quit.setVisibility(cache.isAuth(getContext()) ? Component.VISIBLE : Component.HIDE);
  102. // 初始化组件
  103. initComponents();
  104. // 设置事件监听
  105. setupListeners();
  106. Button mBtnHuaweiIdSignIn = findComponentById(ResourceTable.Id_btn_hwid_sign_in);
  107. mBtnHuaweiIdSignIn.setClickedListener((Component c) -> {
  108. huaweiIdSignIn();
  109. });
  110. // 订阅登录成功事件
  111. subscribeLoginSuccessEvent();
  112. // 订阅认证状态变化事件
  113. subscribeAuthChangedEvent();
  114. }
  115. void huaweiIdSignIn() {
  116. AccountAuthService accountAuthService;
  117. // 1、配置登录请求参数AccountAuthParams,包括请求用户id(openid、unionid)、email、profile(昵称、头像)等。
  118. // 2、DEFAULT_AUTH_REQUEST_PARAM默认包含了id和profile(昵称、头像)的请求。
  119. // 3、如需要再获取用户邮箱,需要setEmail();
  120. // 4、如需要获取其他受限信息,如国家和地区,则需要先申请scope,再设置请求参数。
  121. AccountAuthParams accountAuthParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM)
  122. .setEmail()
  123. .createParams();
  124. try {
  125. accountAuthService = AccountAuthManager.getService(accountAuthParams);
  126. } catch (ApiException e) {
  127. // 处理初始化登录授权服务失败,status code标识了失败的原因,请参考API中的错误码参考了解详细错误原因
  128. e.getStatusCode();
  129. Toast.error(getContext(), "Init Huawei accountAuthService FAILED.");
  130. return;
  131. }
  132. Toast.info(getContext(), "Init Huawei accountAuthService SUCCESS");
  133. if (accountAuthService == null) {
  134. Toast.error(getContext(), "获取不到账号信息");
  135. return;
  136. }
  137. // 调用静默登录接口。
  138. // 如果华为系统帐号已经登录,并且已经授权,会登录成功;
  139. // 否则静默登录失败,需要在失败监听中,显式地调用前台登录授权接口,完成登录授权。
  140. Task<AuthAccount> taskSilentSignIn = accountAuthService.silentSignIn();
  141. // Task<AuthAccount> taskSilentSignIn = accountAuthService.silentSignIn();
  142. Toast.info(getContext(), "SilentSign START.");
  143. // 添加静默登录成功处理监听
  144. taskSilentSignIn.addOnSuccessListener(authAccount -> updateUI(authAccount));
  145. // 添加静默登录失败监听
  146. taskSilentSignIn.addOnFailureListener(e -> {
  147. if (e instanceof ApiException) {
  148. ApiException apiException = (ApiException) e;
  149. Toast.error(getContext(), "SilentSignIn FAILED, status code: " + apiException.getStatusCode() + ". Need to foreground sign in" + "\r\n" + apiException.getStatusMessage()
  150. + "\r\n" + apiException.getMessage() + "\r\n" + apiException.getCause());
  151. // 静默登录失败,显式地调用前台登录授权接口,完成登录授权。
  152. Task<AuthAccount> taskSignIn = accountAuthService.signIn();
  153. Toast.info(getContext(), "SignIn foreground START.");
  154. if (taskSignIn == null) {
  155. Toast.info(getContext(), "SignIn foreground task is null.");
  156. return;
  157. }
  158. taskSignIn.addOnSuccessListener(new OnSuccessListener<AuthAccount>() {
  159. @Override
  160. public void onSuccess(AuthAccount result) {
  161. Toast.info(getContext(), "SignIn foreground SUCCESS.");
  162. updateUI(result);
  163. }
  164. });
  165. taskSignIn.addOnFailureListener(new OnFailureListener() {
  166. @Override
  167. public void onFailure(Exception e) {
  168. Toast.info(getContext(), "SignIn foreground FAILED.");
  169. if (e instanceof ApiException) {
  170. ApiException apiException = (ApiException) e;
  171. // 登录失败,status code标识了失败的原因,请参考API中的错误码参考了解详细错误原因
  172. apiException.getStatusCode();
  173. Toast.info(getContext(), "SignIn foreground FAILED. status code: "
  174. + apiException.getStatusCode()
  175. + ".");
  176. if (CommonConstant.RETCODE.SIGN_IN_CANCELLED == apiException.getStatusCode()) {
  177. Toast.info(getContext(), "Error message: User click CANCEL or Return, user cancel login in.");
  178. }
  179. }
  180. }
  181. });
  182. }
  183. });
  184. }
  185. private void updateUI(AuthAccount authAccount) {
  186. Toast.info(getContext(), authAccount.getOpenId() + " : " + authAccount.getUnionId());
  187. }
  188. /**
  189. * 设置全屏显示
  190. */
  191. private void setFullScreen() {
  192. try {
  193. Window window = getWindow();
  194. if (window != null) {
  195. WindowManager.LayoutConfig layoutConfig = window.getLayoutConfig().orElse(null);
  196. if (layoutConfig == null) {
  197. layoutConfig = new WindowManager.LayoutConfig();
  198. }
  199. layoutConfig.type = WindowManager.LayoutConfig.MARK_FULL_SCREEN;
  200. window.setLayoutConfig(layoutConfig);
  201. }
  202. } catch (Exception e) {
  203. Log.error("设置全屏失败: " + e.getMessage());
  204. }
  205. }
  206. /**
  207. * 初始化组件
  208. */
  209. private void initComponents() {
  210. // 初始化页面容器
  211. pageContainer = findComponentById(ResourceTable.Id_page_container);
  212. // 初始化底部导航栏
  213. initBottomNavigation();
  214. // 默认初始化找车位页面(因为默认显示该页面)
  215. // initParkComponent();
  216. // 默认选中找车位
  217. switchToPage(0);
  218. }
  219. /**
  220. * 初始化缴费页面组件
  221. */
  222. private void initChargeComponent() {
  223. if (isChargeComponentInitialized || pageContainer == null) {
  224. return;
  225. }
  226. try {
  227. Log.info("首次初始化缴费页面");
  228. chargeComponent = new ChargeComponent(MainAbilitySlice.this);
  229. chargeComponent.setLoadingComponent(loadingComponent);
  230. // 设置支付详情展示监听器
  231. chargeComponent.setOnPayDetailShowListener(new ChargeComponent.OnPayDetailShowListener() {
  232. @Override
  233. public void onShowPayDetail(ParkingFeeInfo feeInfo) {
  234. showPayDetail(feeInfo);
  235. }
  236. });
  237. chargeComponent.setVisibility(Component.HIDE);
  238. pageContainer.addComponent(chargeComponent);
  239. isChargeComponentInitialized = true;
  240. Log.info("缴费页面初始化完成");
  241. } catch (Exception e) {
  242. Log.error("创建缴费页面组件失败: " + e.getMessage());
  243. e.printStackTrace();
  244. }
  245. }
  246. /**
  247. * 初始化找车位页面组件
  248. */
  249. private void initParkComponent() {
  250. if (isParkComponentInitialized || pageContainer == null) {
  251. return;
  252. }
  253. try {
  254. Log.info("首次初始化找车位页面");
  255. parkComponent = new ParkComponent(MainAbilitySlice.this);
  256. parkComponent.setLoadingComponent(loadingComponent);
  257. // 设置停车场选中监听器
  258. parkComponent.setOnParkSelectedListener(new ParkComponent.OnParkSelectedListener() {
  259. @Override
  260. public void onParkSelected(ParkNearRes park) {
  261. showParkDetail(park);
  262. }
  263. @Override
  264. public void onParkDeselected() {
  265. hideDetail();
  266. }
  267. });
  268. parkComponent.setVisibility(Component.HIDE);
  269. pageContainer.addComponent(parkComponent);
  270. isParkComponentInitialized = true;
  271. //是否要申请权限
  272. if(!PermissionManager.requestLocation(getContext())){
  273. parkComponent.loadParkingDataByLocation();
  274. }
  275. Log.info("找车位页面初始化完成");
  276. } catch (Exception e) {
  277. Log.error("创建找车位页面组件失败: " + e.getMessage());
  278. e.printStackTrace();
  279. }
  280. }
  281. /**
  282. * 初始化缴费记录页面组件
  283. */
  284. private void initOrderComponent() {
  285. if (isOrderComponentInitialized || pageContainer == null) {
  286. return;
  287. }
  288. try {
  289. Log.info("首次初始化缴费记录页面");
  290. orderComponent = new OrderComponent(MainAbilitySlice.this);
  291. orderComponent.setLoadingComponent(loadingComponent);
  292. // 设置订单选中监听器
  293. orderComponent.setOnOrderSelectedListener(new OrderComponent.OnOrderSelectedListener() {
  294. @Override
  295. public void onOrderSelected(OrderRes order) {
  296. showOrderDetail(order);
  297. }
  298. @Override
  299. public void onOrderDeselected() {
  300. hideDetail();
  301. }
  302. });
  303. orderComponent.setVisibility(Component.HIDE);
  304. pageContainer.addComponent(orderComponent);
  305. isOrderComponentInitialized = true;
  306. Log.info("缴费记录页面初始化完成");
  307. } catch (Exception e) {
  308. Log.error("创建缴费记录页面组件失败: " + e.getMessage());
  309. e.printStackTrace();
  310. }
  311. }
  312. /**
  313. * 初始化底部导航栏
  314. */
  315. private void initBottomNavigation() {
  316. navCharge = findComponentById(ResourceTable.Id_nav_charge);
  317. navPark = findComponentById(ResourceTable.Id_nav_find_parking);
  318. navOrder = findComponentById(ResourceTable.Id_nav_order);
  319. navCurrentLocation = findComponentById(ResourceTable.Id_nav_current_location);
  320. textCharge = findComponentById(ResourceTable.Id_text_charge);
  321. textPark = findComponentById(ResourceTable.Id_text_park);
  322. textOrder = findComponentById(ResourceTable.Id_text_order);
  323. iconPark = findComponentById(ResourceTable.Id_icon_park);
  324. iconPark1 = findComponentById(ResourceTable.Id_icon_park_1);
  325. iconCharge = findComponentById(ResourceTable.Id_icon_charge);
  326. iconCharge1 = findComponentById(ResourceTable.Id_icon_charge_1);
  327. iconOrder = findComponentById(ResourceTable.Id_icon_order);
  328. iconOrder1 = findComponentById(ResourceTable.Id_icon_order_1);
  329. // 设置点击事件
  330. if (navPark != null) {
  331. navPark.setClickedListener(component -> switchToPage(0));
  332. }
  333. if (navCharge != null) {
  334. navCharge.setClickedListener(component -> switchToPageAfterLogin(1));
  335. }
  336. if (navOrder != null) {
  337. navOrder.setClickedListener(component -> switchToPageAfterLogin(2));
  338. }
  339. if (navCurrentLocation != null) {
  340. navCurrentLocation.setClickedListener(component -> {
  341. if(currentTab == 0 && parkComponent!=null && isParkComponentInitialized){
  342. parkComponent.loadParkingDataByLocation();
  343. }
  344. });
  345. }
  346. }
  347. private void switchToPageAfterLogin(int index) {
  348. // 先检查是否已登录
  349. if (!cache.isAuth(this)) {
  350. // 未登录,调用登录方法
  351. Log.info("未登录,开始登录流程");
  352. auth.login(this).thenAccept(success -> {
  353. if (success) {
  354. // 登录成功后切换到缴费记录页面
  355. DialogUtil.postTask(() -> switchToPage(index));
  356. } else {
  357. Toast.error(this, "登录失败,请重试");
  358. }
  359. }).exceptionally(e -> {
  360. Log.error("登录异常: " + e.getMessage());
  361. e.printStackTrace();
  362. Toast.error(this, "登录异常: " + e.getMessage());
  363. return null;
  364. });
  365. } else {
  366. // 已登录,直接切换页面
  367. switchToPage(index);
  368. }
  369. }
  370. /**
  371. * 切换到指定页面
  372. */
  373. private void switchToPage(int index) {
  374. if (index < 0 || index > 2) {
  375. return;
  376. }
  377. // 隐藏所有页面
  378. if (chargeComponent != null) {
  379. chargeComponent.setVisibility(Component.HIDE);
  380. }
  381. if (parkComponent != null) {
  382. parkComponent.setVisibility(Component.HIDE);
  383. }
  384. if (orderComponent != null) {
  385. orderComponent.setVisibility(Component.HIDE);
  386. }
  387. // 显示目标页面
  388. switch (index) {
  389. case 0: // 找车位
  390. // 首次打开时初始化
  391. if (!isParkComponentInitialized) {
  392. // 首次初始化时,组件内部已经加载了数据,无需再调用refresh()
  393. initParkComponent();
  394. } else if (parkComponent != null) {
  395. // 非首次打开时才刷新数据
  396. parkComponent.switchTab(2);
  397. parkComponent.loadParkingData(true);
  398. }
  399. if (parkComponent != null) {
  400. parkComponent.setVisibility(Component.VISIBLE);
  401. }
  402. break;
  403. case 1: // 计费
  404. // 首次打开时初始化
  405. if (!isChargeComponentInitialized) {
  406. initChargeComponent();
  407. // 首次初始化时,组件内部已经加载了数据,无需再调用refresh()
  408. } else if (chargeComponent != null) {
  409. // 非首次打开时才刷新数据
  410. chargeComponent.refresh();
  411. }
  412. if (chargeComponent != null) {
  413. chargeComponent.setVisibility(Component.VISIBLE);
  414. }
  415. break;
  416. case 2: // 缴费记录
  417. // 首次打开时初始化
  418. if (!isOrderComponentInitialized) {
  419. initOrderComponent();
  420. // 首次初始化时,组件内部已经加载了数据,无需再调用reset()
  421. } else if (orderComponent != null) {
  422. // 非首次打开时才刷新数据
  423. orderComponent.reset();
  424. }
  425. if (orderComponent != null) {
  426. orderComponent.setVisibility(Component.VISIBLE);
  427. }
  428. break;
  429. }
  430. // 更新当前tab状态
  431. currentTab = index;
  432. updateBottomNavState(index);
  433. // 切换页面时隐藏详情
  434. hideDetail();
  435. }
  436. /**
  437. * 更新底部导航栏状态
  438. */
  439. private void updateBottomNavState(int index) {
  440. // 重置所有导航项样式
  441. Color grayColor = new Color(Color.getIntColor("#FF666666"));
  442. Color blueColor = new Color(Color.getIntColor("#FA6332"));
  443. if (textCharge != null) {
  444. textCharge.setTextColor(grayColor);
  445. }
  446. if (textPark != null) {
  447. textPark.setTextColor(grayColor);
  448. }
  449. if (textOrder != null) {
  450. textOrder.setTextColor(grayColor);
  451. }
  452. // 设置选中状态
  453. switch (index) {
  454. case 0: // 找车位
  455. textPark.setTextColor(blueColor);
  456. iconCharge.setVisibility(Component.VISIBLE);
  457. iconCharge1.setVisibility(Component.HIDE);
  458. iconOrder.setVisibility(Component.VISIBLE);
  459. iconOrder1.setVisibility(Component.HIDE);
  460. iconPark.setVisibility(Component.HIDE);
  461. iconPark1.setVisibility(Component.VISIBLE);
  462. break;
  463. case 1: // 我的
  464. textCharge.setTextColor(blueColor);
  465. iconCharge.setVisibility(Component.HIDE);
  466. iconCharge1.setVisibility(Component.VISIBLE);
  467. iconOrder.setVisibility(Component.VISIBLE);
  468. iconOrder1.setVisibility(Component.HIDE);
  469. iconPark.setVisibility(Component.VISIBLE);
  470. iconPark1.setVisibility(Component.HIDE);
  471. break;
  472. case 2: // 缴费记录
  473. textOrder.setTextColor(blueColor);
  474. iconCharge.setVisibility(Component.VISIBLE);
  475. iconCharge1.setVisibility(Component.HIDE);
  476. iconOrder.setVisibility(Component.HIDE);
  477. iconOrder1.setVisibility(Component.VISIBLE);
  478. iconPark.setVisibility(Component.VISIBLE);
  479. iconPark1.setVisibility(Component.HIDE);
  480. break;
  481. }
  482. }
  483. /**
  484. * 设置事件监听
  485. */
  486. private void setupListeners() {
  487. // 事件监听已在initBottomNavigation中设置
  488. }
  489. /**
  490. * 订阅登录成功事件
  491. */
  492. private void subscribeLoginSuccessEvent() {
  493. loginSuccessListener = event -> {
  494. // 在主线程更新UI
  495. DialogUtil.postTask(() -> {
  496. // 刷新我的页面
  497. if (chargeComponent != null) {
  498. chargeComponent.refresh();
  499. }
  500. quit.setVisibility(Component.VISIBLE);
  501. // 可以在这里添加其他需要更新的UI逻辑
  502. });
  503. };
  504. EventBus.getInstance().on("onLoginSuccess", loginSuccessListener);
  505. }
  506. /**
  507. * 订阅认证状态变化事件
  508. */
  509. private void subscribeAuthChangedEvent() {
  510. authChangedListener = event -> {
  511. // 在主线程更新UI
  512. DialogUtil.postTask(() -> {
  513. Log.error("收到认证状态变化事件,更新UI");
  514. // 隐藏退出按钮
  515. if (quit != null) {
  516. quit.setVisibility(Component.HIDE);
  517. }
  518. // 刷新我的页面
  519. if (chargeComponent != null) {
  520. chargeComponent.refresh();
  521. }
  522. // 可以在这里添加其他需要更新的UI逻辑
  523. });
  524. // 认证过期后重新登录
  525. auth.login(MainAbilitySlice.this).thenAccept(success -> {
  526. if (success) {
  527. Log.info("重新登录成功");
  528. } else {
  529. Log.error("重新登录失败");
  530. }
  531. }).exceptionally(e -> {
  532. Log.error("重新登录异常: " + e.getMessage());
  533. return null;
  534. });
  535. };
  536. EventBus.getInstance().on("onLoginExpired", authChangedListener);
  537. }
  538. @Override
  539. protected void onStop() {
  540. // AggrPayClient
  541. super.onStop();
  542. // 取消订阅登录成功事件
  543. if (loginSuccessListener != null) {
  544. EventBus.getInstance().off("onLoginSuccess", loginSuccessListener);
  545. }
  546. // 取消订阅认证状态变化事件
  547. if (authChangedListener != null) {
  548. EventBus.getInstance().off("onLoginExpired", authChangedListener);
  549. }
  550. // 取消parkComponent的事件订阅
  551. if (parkComponent != null) {
  552. parkComponent.unsubscribeEvents();
  553. parkComponent.stopLocation();
  554. }
  555. }
  556. /**
  557. * 显示订单详情
  558. */
  559. private void showOrderDetail(OrderRes order) {
  560. // Uri content_url = Uri.parse("petalmaps://navigation?saddr=25.102916,55.165363&daddr=25.164610000000,55.228869000000&type=drive&utm_source=fb");
  561. // Intent intent = new Intent(Intent.ACTION_VIEW, content_url);
  562. // if (intent.resolveActivity(getPackageManager()) != null) {
  563. // startActivity(intent);
  564. // }
  565. // sta
  566. if (mainRight == null || orderDetailComponent == null) {
  567. return;
  568. }
  569. // 移除所有子组件
  570. mainRight.removeAllComponents();
  571. // 设置订单数据
  572. orderDetailComponent.setOrderData(order, getContext());
  573. // 添加详情组件
  574. mainRight.addComponent(orderDetailComponent);
  575. // 显示详情区域
  576. mainRight.setVisibility(Component.VISIBLE);
  577. }
  578. /**
  579. * 显示停车场详情
  580. */
  581. private void showParkDetail(ParkNearRes park) {
  582. if (mainRight == null || parkDetailComponent == null) {
  583. return;
  584. }
  585. // 移除所有子组件
  586. mainRight.removeAllComponents();
  587. // 设置停车场数据
  588. parkDetailComponent.setParkData(park);
  589. // 添加详情组件
  590. mainRight.addComponent(parkDetailComponent);
  591. // 显示详情区域
  592. mainRight.setVisibility(Component.VISIBLE);
  593. }
  594. /**
  595. * 显示支付订单详情
  596. */
  597. private void showPayDetail(ParkingFeeInfo feeInfo) {
  598. PayDetailDialog payDetailDialog = new PayDetailDialog(this);
  599. // 设置支付详情组件的支付按钮点击监听器
  600. payDetailDialog.setOnPayClickListener(fee -> {
  601. // 获取车场ID
  602. String parkId = fee.getParkId();
  603. if (parkId == null || parkId.isEmpty()) {
  604. Log.error("车场ID为空,无法获取支付渠道");
  605. return;
  606. }
  607. // 先获取支付渠道
  608. pay.getPayChannel(getContext(), parkId).thenAccept(result -> {
  609. getContext().getUITaskDispatcher().asyncDispatch(() -> {
  610. String paySceneCode = null;
  611. if (result != null && result.isSuccess() && result.getData() != null) {
  612. PayChannelResponse channelData = result.getData();
  613. // 判断支付渠道
  614. if (channelData.getPayChannelInfoList() != null && !channelData.getPayChannelInfoList().isEmpty()) {
  615. boolean hasWx = false;
  616. boolean hasAli = false;
  617. for (PayChannelInfo channelInfo : channelData.getPayChannelInfoList()) {
  618. String channelCode = channelInfo.getPayChannelCode();
  619. if (channelCode != null) {
  620. if (channelCode.contains("WX")) {
  621. hasWx = true;
  622. }
  623. if (channelCode.contains("ALI")) {
  624. hasAli = true;
  625. }
  626. }
  627. }
  628. // 优先使用微信支付
  629. if (hasWx) {
  630. paySceneCode = "WX_NA";
  631. Log.info("支持微信支付,使用微信扫码");
  632. } else if (hasAli) {
  633. paySceneCode = "ALI_PCRE";
  634. Log.info("支持支付宝支付,使用支付宝扫码");
  635. } else {
  636. Log.warn("未配置支持的支付渠道");
  637. }
  638. } else {
  639. Log.warn("未获取到支付渠道列表");
  640. }
  641. } else {
  642. Log.warn("获取支付渠道失败");
  643. }
  644. // 检查是否获取到支付渠道
  645. if (paySceneCode == null) {
  646. // 先关闭支付详情弹框,避免倒计时继续运行导致空指针
  647. payDetailDialog.hide();
  648. Toast.error(getContext(), "未配置支付渠道");
  649. return;
  650. }
  651. // 关闭支付详情弹框
  652. payDetailDialog.hide();
  653. // 创建并显示二维码弹框
  654. QRCodeScanDialog qrCodeScanDialog = new QRCodeScanDialog(this);
  655. // 设置费用信息
  656. qrCodeScanDialog.setFeeInfo(fee);
  657. // 设置支付场景代码
  658. qrCodeScanDialog.setPaySceneCode(paySceneCode);
  659. // 设置弹框关闭监听器 - 关闭时刷新ChargeComponent
  660. qrCodeScanDialog.setOnCloseListener(() -> {
  661. Log.info("二维码弹框关闭,刷新ChargeComponent");
  662. if (chargeComponent != null) {
  663. chargeComponent.refresh();
  664. }
  665. });
  666. // 设置支付结果监听器
  667. qrCodeScanDialog.setOnPayResultListener(new QRCodeScanDialog.OnPayResultListener() {
  668. @Override
  669. public void onPaySuccess(String payNo) {
  670. Log.info("支付成功: payNo=" + payNo);
  671. }
  672. @Override
  673. public void onPayFailed(String errorMsg) {
  674. Log.error("支付失败: " + errorMsg);
  675. }
  676. @Override
  677. public void onPayTimeout() {
  678. Log.info("支付超时");
  679. }
  680. });
  681. // 显示二维码扫描对话框
  682. qrCodeScanDialog.show();
  683. });
  684. }).exceptionally(ex -> {
  685. getContext().getUITaskDispatcher().asyncDispatch(() -> {
  686. Log.error("获取支付渠道异常: " + ex.getMessage());
  687. // 异常时使用默认支付方式
  688. payDetailDialog.hide();
  689. QRCodeScanDialog qrCodeScanDialog = new QRCodeScanDialog(this);
  690. qrCodeScanDialog.setFeeInfo(fee);
  691. qrCodeScanDialog.setPaySceneCode("ALI_PCRE"); // 默认支付宝
  692. qrCodeScanDialog.setOnCloseListener(() -> {
  693. Log.info("二维码弹框关闭,刷新ChargeComponent");
  694. if (chargeComponent != null) {
  695. chargeComponent.refresh();
  696. }
  697. });
  698. qrCodeScanDialog.setOnPayResultListener(new QRCodeScanDialog.OnPayResultListener() {
  699. @Override
  700. public void onPaySuccess(String payNo) {
  701. Log.info("支付成功: payNo=" + payNo);
  702. }
  703. @Override
  704. public void onPayFailed(String errorMsg) {
  705. Log.error("支付失败: " + errorMsg);
  706. }
  707. @Override
  708. public void onPayTimeout() {
  709. Log.info("支付超时");
  710. }
  711. });
  712. qrCodeScanDialog.show();
  713. });
  714. return null;
  715. });
  716. });
  717. // 设置支付订单数据
  718. payDetailDialog.setFeeInfo(feeInfo);
  719. // 显示弹框(弹框内部会自动获取倒计时时间并重新计费)
  720. payDetailDialog.show();
  721. }
  722. /**
  723. * 隐藏详情
  724. */
  725. private void hideDetail() {
  726. if (mainRight == null) {
  727. return;
  728. }
  729. // 移除所有子组件
  730. mainRight.removeAllComponents();
  731. // 隐藏详情区域
  732. mainRight.setVisibility(Component.HIDE);
  733. }
  734. }