瀏覽代碼

Merge remote-tracking branch 'origin/master' into master

zxf 1 天之前
父節點
當前提交
d2414a29c9
共有 100 個文件被更改,包括 8546 次插入11 次删除
  1. 1 1
      jd-logistics-auth/src/main/java/com/ruoyi/auth/controller/WxMiniController.java
  2. 15 4
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/front/controller/MonthQRCodeController.java
  3. 3 3
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/front/controller/WxMiniController.java
  4. 1 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/controller/BizWaybillCostDetailsController.java
  5. 14 2
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/LogisticsOrderService.java
  6. 9 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/LogisticsService.java
  7. 97 1
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/JDLogisticsService.java
  8. 10 0
      jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/SFLogisticsService.java
  9. 26 0
      jd_logistics-app/App.vue
  10. 26 0
      jd_logistics-app/api/agreement.js
  11. 25 0
      jd_logistics-app/api/ai.js
  12. 39 0
      jd_logistics-app/api/home.js
  13. 17 0
      jd_logistics-app/api/message.js
  14. 44 0
      jd_logistics-app/api/order.js
  15. 67 0
      jd_logistics-app/api/user.js
  16. 217 0
      jd_logistics-app/components/AreaPickerCustommer.vue
  17. 220 0
      jd_logistics-app/components/TimelineItem.vue
  18. 66 0
      jd_logistics-app/components/agreeRecharge.vue
  19. 66 0
      jd_logistics-app/components/agreeVip.vue
  20. 52 0
      jd_logistics-app/components/headerInfo.vue
  21. 80 0
      jd_logistics-app/components/paymentCommon.vue
  22. 27 0
      jd_logistics-app/config/app.js
  23. 3 0
      jd_logistics-app/config/cache.js
  24. 46 0
      jd_logistics-app/config/env.js
  25. 112 0
      jd_logistics-app/hooks/useToast.js
  26. 20 0
      jd_logistics-app/index.html
  27. 40 0
      jd_logistics-app/libs/login.js
  28. 45 0
      jd_logistics-app/main.js
  29. 72 0
      jd_logistics-app/manifest.json
  30. 18 0
      jd_logistics-app/package-lock.json
  31. 5 0
      jd_logistics-app/package.json
  32. 232 0
      jd_logistics-app/pages.json
  33. 192 0
      jd_logistics-app/pages/address/address_list.vue
  34. 434 0
      jd_logistics-app/pages/address/edit.vue
  35. 716 0
      jd_logistics-app/pages/ai/ai.vue
  36. 60 0
      jd_logistics-app/pages/ai/components/agentCheck.vue
  37. 145 0
      jd_logistics-app/pages/ai/components/messagesInfo.vue
  38. 72 0
      jd_logistics-app/pages/ai/components/messagesInfoDefault.vue
  39. 37 0
      jd_logistics-app/pages/ai/components/tools.vue
  40. 156 0
      jd_logistics-app/pages/historyList/historyList.vue
  41. 165 0
      jd_logistics-app/pages/index/components/PersonalExpressDialog.vue
  42. 273 0
      jd_logistics-app/pages/index/index.vue
  43. 146 0
      jd_logistics-app/pages/index111/index.vue
  44. 369 0
      jd_logistics-app/pages/logistics/index.vue
  45. 602 0
      jd_logistics-app/pages/mine/mine.vue
  46. 252 0
      jd_logistics-app/pages/mine/mine1.vue
  47. 370 0
      jd_logistics-app/pages/order/components/OrderItem.vue
  48. 152 0
      jd_logistics-app/pages/order/components/TrackPopup.vue
  49. 385 0
      jd_logistics-app/pages/order/index.vue
  50. 634 0
      jd_logistics-app/pages/order/order_detail.vue
  51. 71 0
      jd_logistics-app/pages/policy/ad_detail.vue
  52. 23 0
      jd_logistics-app/pages/policy/recharge_policy.vue
  53. 23 0
      jd_logistics-app/pages/policy/vip_policy.vue
  54. 144 0
      jd_logistics-app/pages/recharge/recharge.vue
  55. 98 0
      jd_logistics-app/pages/recharge/success_pay.vue
  56. 295 0
      jd_logistics-app/pages/recharge/vip.vue
  57. 100 0
      jd_logistics-app/pages/recharge/wallet.vue
  58. 209 0
      jd_logistics-app/pages/search/search.vue
  59. 110 0
      jd_logistics-app/pages/user/user.vue
  60. 60 0
      jd_logistics-app/pages/webView/webView.vue
  61. 538 0
      jd_logistics-app/static/css/base.scss
  62. 二進制
      jd_logistics-app/static/img/addHuiHua.png
  63. 二進制
      jd_logistics-app/static/img/arrow-right.png
  64. 二進制
      jd_logistics-app/static/img/check.png
  65. 二進制
      jd_logistics-app/static/img/copy.png
  66. 二進制
      jd_logistics-app/static/img/home/tool.png
  67. 二進制
      jd_logistics-app/static/img/icon-logo-jd.png
  68. 二進制
      jd_logistics-app/static/img/icon-logo-sf.png
  69. 二進制
      jd_logistics-app/static/img/index-bg.png
  70. 二進制
      jd_logistics-app/static/img/index-personal.png
  71. 二進制
      jd_logistics-app/static/img/index-time.png
  72. 二進制
      jd_logistics-app/static/img/index-un-time.png
  73. 二進制
      jd_logistics-app/static/img/logo.png
  74. 二進制
      jd_logistics-app/static/img/mine/Logout.png
  75. 二進制
      jd_logistics-app/static/img/mine/chongzhijulu.png
  76. 二進制
      jd_logistics-app/static/img/mine/icon-mine-about.png
  77. 二進制
      jd_logistics-app/static/img/mine/icon-mine-address.png
  78. 二進制
      jd_logistics-app/static/img/mine/icon-mine-order.png
  79. 二進制
      jd_logistics-app/static/img/mine/icon-mine-policy.png
  80. 二進制
      jd_logistics-app/static/img/mine/icon-mine-server.png
  81. 二進制
      jd_logistics-app/static/img/mine/kefu.png
  82. 二進制
      jd_logistics-app/static/img/mine/money.png
  83. 二進制
      jd_logistics-app/static/img/mine/order.png
  84. 二進制
      jd_logistics-app/static/img/mine/vip.png
  85. 二進制
      jd_logistics-app/static/img/mine/vipcard.png
  86. 二進制
      jd_logistics-app/static/img/qianbao.png
  87. 二進制
      jd_logistics-app/static/img/search.png
  88. 二進制
      jd_logistics-app/static/img/service/aijiqiren.png
  89. 二進制
      jd_logistics-app/static/img/service/assistant-avatar.png
  90. 二進制
      jd_logistics-app/static/img/service/maikefengyuyin.png
  91. 二進制
      jd_logistics-app/static/img/service/send-icon.png
  92. 二進制
      jd_logistics-app/static/img/service/tupian.png
  93. 二進制
      jd_logistics-app/static/img/service/user-avatar.png
  94. 二進制
      jd_logistics-app/static/img/service/xiaoxi.png
  95. 二進制
      jd_logistics-app/static/img/shuaxin.png
  96. 二進制
      jd_logistics-app/static/img/tabs/home.png
  97. 二進制
      jd_logistics-app/static/img/tabs/home_active.png
  98. 二進制
      jd_logistics-app/static/img/tabs/search.png
  99. 二進制
      jd_logistics-app/static/img/tabs/search_active.png
  100. 0 0
      jd_logistics-app/static/img/tabs/user.png

+ 1 - 1
jd-logistics-auth/src/main/java/com/ruoyi/auth/controller/WxMiniController.java

@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 /**
- * 微信小程序登录
+ * WX-微信小程序登录
  */
 @RestController
 @RequestMapping("/wxmini")

+ 15 - 4
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/front/controller/MonthQRCodeController.java

@@ -1,6 +1,7 @@
 package com.ruoyi.front.controller;
 
 import com.alibaba.fastjson.JSONObject;
+import com.ruoyi.common.core.exception.ServiceException;
 import com.ruoyi.common.core.web.domain.AjaxResult;
 import com.ruoyi.logistics.service.LogisticsOrderService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -8,15 +9,25 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+/**
+ * WX-月结二维码生成
+ *
+ * @author lydgt
+ * @date 2026-02-04
+ */
 @RestController
-@RequestMapping("/callback/qrcode")
+@RequestMapping("/front/qrcode")
 public class MonthQRCodeController {
 
     @Autowired
     private LogisticsOrderService logisticsOrderService;
 
-    public AjaxResult qrcode(@RequestParam String channelCode) {
-        JSONObject jd = logisticsOrderService.getQRCode(channelCode);
-        return AjaxResult.success(jd);
+    @RequestMapping
+    public AjaxResult qrcode(@RequestParam("orderType") Integer orderType) {
+        JSONObject jsonObject = logisticsOrderService.getQRCode(orderType);
+        if(!jsonObject.getBooleanValue("success")){
+            throw new ServiceException("获取二维码失败! 原因:"+jsonObject.getString("msg"));
+        }
+        return AjaxResult.success(jsonObject.getString("msg"));
     }
 }

+ 3 - 3
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/front/controller/WxMiniController.java

@@ -53,15 +53,15 @@ public class WxMiniController {
         SysUser currentUser = sysUserService.selectUserByOpenId(sysUser);
         if (StringUtils.isNull(currentUser))
         {
-            currentUser = sysUserService.selectUserByOpenId(sysUser);
+            currentUser = sysUserService.selectUserByUserName(sysUser.getUserName());
             if (StringUtils.isNull(currentUser))
             {
                 return R.fail("用户不存在");
             }
             currentUser.setOpenId(sysUser.getOpenId());
+            // 更新用户openid
+            sysUserService.updateUser(currentUser);
         }
-        // 更新用户openid
-        sysUserService.updateUser(currentUser);
         // 角色集合
         Set<String> roles = permissionService.getRolePermission(currentUser);
         // 权限集合

+ 1 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/controller/BizWaybillCostDetailsController.java

@@ -41,6 +41,7 @@ public class BizWaybillCostDetailsController extends BaseController
      * 参数:  月份--月度账单中的月份 格式2026.01
      *        供应商--也叫部门id
      */
+    @RequiresPermissions("system:costDetails:list")
     @GetMapping("/list")
     public TableDataInfo list(BizWaybillCostDetails bizWaybillCostDetails)
     {

+ 14 - 2
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/LogisticsOrderService.java

@@ -39,13 +39,25 @@ public class LogisticsOrderService {
         return cancelOrder;
     }
 
-    public JSONObject getQRCode(String channelCode) {
+    public JSONObject getQRCode(Integer orderType) {
         // 根据订单中的物流公司类型获取对应服务
-        LogisticsService logisticsService = logisticsFactory.getLogisticsService(channelCode);
+        LogisticsService logisticsService = logisticsFactory.getLogisticsService(orderType==1?"JD":"SF");
         JSONObject qrCode = logisticsService.getMonthQRCode();
         return qrCode;
     }
 
+    public JSONObject queryOrderByQRCode(Integer orderType, String qrCode) {
+        // 根据订单中的物流公司类型获取对应服务
+        LogisticsService logisticsService = logisticsFactory.getLogisticsService(orderType==1?"JD":"SF");
+        JSONObject jsonObject = logisticsService.queryOrderByQRCode(qrCode);
+        return jsonObject;
+    }
 
+    public JSONObject queryOrderDetailByWaybillCode(Integer orderType, String waybillCode) {
+        // 根据订单中的物流公司类型获取对应服务
+        LogisticsService logisticsService = logisticsFactory.getLogisticsService(orderType==1?"JD":"SF");
+        JSONObject jsonObject = logisticsService.queryOrderDetailByWaybillCode(waybillCode);
+        return jsonObject;
+    }
 }
 

+ 9 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/LogisticsService.java

@@ -47,5 +47,14 @@ public interface LogisticsService {
      */
     JSONObject getMonthQRCode();
 
+    /**
+     * 根据二维码查询
+     */
+    JSONObject queryOrderByQRCode(String qrCode);
+
+    /**
+     * 根据运单号查询订单详情
+     */
+    JSONObject queryOrderDetailByWaybillCode(String waybillCode);
 
 }

+ 97 - 1
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/JDLogisticsService.java

@@ -10,6 +10,8 @@ import com.lop.open.api.sdk.domain.ECAP.CommonCreateOrderApi.commonCheckPreCreat
 import com.lop.open.api.sdk.domain.ECAP.CommonCreateOrderApi.commonCheckPreCreateOrderV1.Contact;
 import com.lop.open.api.sdk.domain.ECAP.CommonCreateOrderApi.commonCreateOrderV1.CommonCargoInfo;
 import com.lop.open.api.sdk.domain.ECAP.CommonModifyCancelOrderApi.commonCancelOrderV1.CommonOrderCancelRequest;
+import com.lop.open.api.sdk.domain.ECAP.CommonQueryOrderApi.commonGetOrderByMonthSettleQRV1.CommonMonthSettleQRQueryRequest;
+import com.lop.open.api.sdk.domain.ECAP.CommonQueryOrderApi.commonGetOrderInfoV1.CommonOrderInfoRequest;
 import com.lop.open.api.sdk.plugin.LopPlugin;
 import com.lop.open.api.sdk.plugin.factory.OAuth2PluginFactory;
 import com.lop.open.api.sdk.request.ECAP.*;
@@ -524,7 +526,7 @@ public class JDLogisticsService  implements LogisticsService {
             if (response.getCode().equals("0")) {
                 if (response.getResponse().getCode() == 0) {
                     result.put("success", true);
-                    result.put("msg", "");
+                    result.put("msg", response.getResponse().getData().getVerifyMessage());
                 } else {
                     result.put("success", false);
                     result.put("msg", "京东开放平台获取商家二维码!失败原因:" + response.getResponse().getMsg());
@@ -539,4 +541,98 @@ public class JDLogisticsService  implements LogisticsService {
         }
         return result;
     }
+
+    @Override
+    public JSONObject queryOrderByQRCode(String qrCode) {
+        log.info("京东开放平台根据二维码查询运单接口,入参:{}", qrCode);
+        JSONObject result = new JSONObject();
+        try {
+            //设置接口域名(有的对接方案同时支持生产和沙箱环境,有的仅支持生产,具体以对接方案中的【API文档-请求地址】为准),生产域名:https://api.jdl.com 预发环境域名:https://uat-api.jdl.com
+            //DefaultDomainApiClient对象全局只需要创建一次
+            DefaultDomainApiClient client = new DefaultDomainApiClient(jdExpressConfig.getServerUrl(),500,15000);
+
+            //入参对象
+            CommonqueryorderapiCommongetorderbymonthsettleqrv1LopRequest request = new CommonqueryorderapiCommongetorderbymonthsettleqrv1LopRequest();
+
+            CommonMonthSettleQRQueryRequest requestDTO = new CommonMonthSettleQRQueryRequest();
+            requestDTO.setCustomerCode(sysConfigService.selectConfigByKey(SysConfigConstants.JD_LOGISTICS_CUSTOMERCODE));
+            requestDTO.setMonthSettleQR(qrCode);
+            requestDTO.setAppKey(jdExpressConfig.getAppKey());
+
+            request.setRequest(requestDTO);
+
+            //设置插件,必须的操作,不同类型的应用入参不同,请看入参注释,公共参数按顺序分别为AppKey、AppSecret、AccessToken
+            //使用开放平台ISV/自研商家应用调用接口
+            LopPlugin lopPlugin = OAuth2PluginFactory.produceLopPlugin(jdExpressConfig.getAppKey(), jdExpressConfig.getAppSecret(), jdExpressConfig.getAccessToken());
+            request.addLopPlugin(lopPlugin);
+
+            log.info("京东开放平台根据二维码查询运单接口,请求参数:{}", JSON.toJSONString(request));
+            CommonqueryorderapiCommongetorderbymonthsettleqrv1LopResponse response = client.execute(request);
+            log.info("京东开放平台根据二维码查询运单接口,响应结果:{}", JSON.toJSONString(response));
+
+            if (response.getCode().equals("0")) {
+                if (response.getResponse().getCode() == 0) {
+                    result.put("success", true);
+                    result.put("msg", response.getResponse().getData().getWaybillQRVerifyInfoList());
+                } else {
+                    result.put("success", false);
+                    result.put("msg", "京东开放平台根据二维码查询运单接口!失败原因:" + response.getResponse().getMsg());
+                }
+            } else {
+                result.put("success", false);
+                result.put("msg", "京东开放平台根据二维码查询运单接口!失败原因:" + response.getMsg());
+            }
+        } catch (LopException e) {
+            log.error("京东开放平台根据二维码查询运单接口异常:{}", e);
+            throw new ServiceException("京东开放平台根据二维码查询运单接口异常");
+        }
+        return result;
+    }
+
+    @Override
+    public JSONObject queryOrderDetailByWaybillCode(String waybillCode) {
+        log.info("京东开放平台根据运单号查询运单详情接口,入参:{}", waybillCode);
+        JSONObject result = new JSONObject();
+        try {
+            //设置接口域名(有的对接方案同时支持生产和沙箱环境,有的仅支持生产,具体以对接方案中的【API文档-请求地址】为准),生产域名:https://api.jdl.com 预发环境域名:https://uat-api.jdl.com
+            //DefaultDomainApiClient对象全局只需要创建一次
+            DefaultDomainApiClient client = new DefaultDomainApiClient(jdExpressConfig.getServerUrl(),500,15000);
+
+            //入参对象
+            EcapV1OrdersDetailsQueryLopRequest request = new EcapV1OrdersDetailsQueryLopRequest();
+
+            CommonOrderInfoRequest requestDTO = new CommonOrderInfoRequest();
+            requestDTO.setCustomerCode(sysConfigService.selectConfigByKey(SysConfigConstants.JD_LOGISTICS_CUSTOMERCODE));
+            requestDTO.setBusinessUnitCode(sysConfigService.selectConfigByKey(SysConfigConstants.JD_LOGISTICS_BUSINESSUNITCODE));
+            requestDTO.setWaybillCode(waybillCode);
+
+            request.setRequest(requestDTO);
+
+            //设置插件,必须的操作,不同类型的应用入参不同,请看入参注释,公共参数按顺序分别为AppKey、AppSecret、AccessToken
+            //使用开放平台ISV/自研商家应用调用接口
+            LopPlugin lopPlugin = OAuth2PluginFactory.produceLopPlugin(jdExpressConfig.getAppKey(), jdExpressConfig.getAppSecret(), jdExpressConfig.getAccessToken());
+            request.addLopPlugin(lopPlugin);
+
+            log.info("京东开放平台根据运单号查询运单详情接口,请求参数:{}", JSON.toJSONString(request));
+            EcapV1OrdersDetailsQueryLopResponse response = client.execute(request);
+            log.info("京东开放平台根据运单号查询运单详情接口,响应结果:{}", JSON.toJSONString(response));
+
+            if (response.getCode().equals("0")) {
+                if (response.getResult().getCode() == 0) {
+                    result.put("success", true);
+                    result.put("msg", response.getResult().getData());
+                } else {
+                    result.put("success", false);
+                    result.put("msg", "京东开放平台根据运单号查询运单详情接口!失败原因:" + response.getResult().getMsg());
+                }
+            } else {
+                result.put("success", false);
+                result.put("msg", "京东开放平台根据运单号查询运单详情接口!失败原因:" + response.getMsg());
+            }
+        } catch (LopException e) {
+            log.error("京东开放平台根据运单号查询运单详情接口:{}", e);
+            throw new ServiceException("京东开放平台获取商家二维码接口异常");
+        }
+        return result;
+    }
 }

+ 10 - 0
jd-logistics-modules/jd-logistics-system/src/main/java/com/ruoyi/logistics/service/impl/SFLogisticsService.java

@@ -344,4 +344,14 @@ public class SFLogisticsService implements LogisticsService {
     public JSONObject getMonthQRCode() {
         return null;
     }
+
+    @Override
+    public JSONObject queryOrderByQRCode(String qrCode) {
+        return null;
+    }
+
+    @Override
+    public JSONObject queryOrderDetailByWaybillCode(String waybillCode) {
+        return null;
+    }
 }

+ 26 - 0
jd_logistics-app/App.vue

@@ -0,0 +1,26 @@
+<script setup>
+import { onShow, onLaunch, onHide } from "@dcloudio/uni-app"
+import { getLocation, getNavbarHeight, uniLogin, getUserInfo } from "@/utils/util.js";
+onLaunch((e)=>{
+	console.log('App1 Launch',e)
+	// 获取系统信息
+ 	getNavbarHeight();
+	
+	// getLocation(false);
+	// uniLogin();
+	getUserInfo();
+});
+onShow(()=>{
+	console.log('App1 onShow')
+});
+onHide(()=>{
+	console.log('App1 onHide')
+});
+
+</script>
+
+<style lang="scss">
+	/*每个页面公共css */
+	@import "@/uni_modules/uview-plus/index.scss";
+	@import "static/css/base.scss";
+</style>

+ 26 - 0
jd_logistics-app/api/agreement.js

@@ -0,0 +1,26 @@
+import request from "@/utils/request.js";
+
+
+/**
+ * VIP会员开通协议
+ * 
+ */
+export function agreementMember(data) {
+  return request.get('mini/agreement/member', data);
+}
+/**
+ * 充值协议
+ * 
+ */
+export function agreementRecharge(data) {
+  return request.get('mini/agreement/recharge', data);
+}
+/**
+ * 充值活动规则
+ * 
+ */
+export function agreementRechargeRule(data) {
+  return request.get('mini/agreement/recharge_rule', data);
+}
+
+

+ 25 - 0
jd_logistics-app/api/ai.js

@@ -0,0 +1,25 @@
+import request from "@/utils/request.js";
+
+
+/**
+ * 智能体聊天记录列表
+ * 
+ */
+export function chatHistoryList(data) {
+  return request.get('mini/ai/chatHistoryList', data);
+}
+/**
+ * 批量删除会话
+ * 
+ */
+export function delChatHistoryList(data) {
+  return request.delete('mini/ai/delete', data);
+}
+/**
+ * 智能体聊天记录详情
+ * 
+ */
+export function chatHistoryDetails(data) {
+  return request.get('mini/ai/chatHistoryDetails', data);
+}
+

+ 39 - 0
jd_logistics-app/api/home.js

@@ -0,0 +1,39 @@
+import request from "@/utils/request.js";
+
+
+/**
+ * 广告轮播图
+ * 
+ */
+export function adList(data) {
+  return request.get('mini/ad/list', data, {noAuth:true});
+}
+/**
+ * 广告轮播图
+ * 
+ */
+export function getAgentList(data) {
+  return request.get('mini/agent/list', data, {noAuth:true});
+}
+/**
+ * 热搜
+ * 
+ */
+export function getAdSearch(id='') {
+  return request.get(`mini/ad/search/${id}`, {}, {noAuth:true});
+}
+/**
+ * 获取客服电话
+ * 
+ */
+export function getAdServicePhone() {
+  return request.get(`mini/ad/servicePhone`, {}, {noAuth:true});
+}
+/**
+ * 广告详情
+ * 
+ */
+export function getAdDetails({dictCode}) {
+  return request.get(`mini/ad/details/${dictCode}`, {}, {noAuth:true});
+}
+

+ 17 - 0
jd_logistics-app/api/message.js

@@ -0,0 +1,17 @@
+import request from "@/utils/request.js";
+
+/**
+ * 新增订单留言
+ */
+export function addMessage(data) {
+  return request.post('mini/message', data);
+}
+/**
+ * 订单留言列表
+ */
+export function getMessageList(data) {
+  return request.get('mini/message/list', data);
+}
+
+
+

+ 44 - 0
jd_logistics-app/api/order.js

@@ -0,0 +1,44 @@
+import request from "@/utils/request.js";
+
+/**
+ * 创建订单
+ * "payMethod":"1",  //支付方式 0微信 1余额
+    "productType":"1",//商品类型 0购买会员 1充值
+    "productId":2,//充值规则id
+    "orderNum":1,//订单数量
+    "orderAmt":1000//订单金额
+ * 
+ */
+export function createOrder(data) {
+  return request.post('mini/order/createOrder', data);
+}
+/**
+ * 支付结果
+ * 
+ */
+export function payResult(data) {
+  return request.post('mini/order/payResult/'+data.orderId, data);
+}
+/**
+ * 查询订单列表
+ * 
+ */
+export function getOrderListApi(data) {
+  return request.get('mini/order/list', data);
+}
+/**
+ * 查询订单列表
+ * 
+ */
+export function getOrderList(data) {
+  return request.get('mini/order/list', data);
+}
+/**
+ * 查询订单详情
+ * 
+ */
+export function getOrderDetail({id=''}) {
+  return request.get('mini/order/'+id, {});
+}
+
+

+ 67 - 0
jd_logistics-app/api/user.js

@@ -0,0 +1,67 @@
+import request from "@/utils/request.js";
+
+
+/**
+ * 更新用户openid
+ * 
+ */
+export function bannerList(data) {
+  return request.get('system/front/banner/listByType', data);
+}
+
+/**
+ * 更新用户openid
+ * 
+ */
+export function updateOpenId(data) {
+  return request.post('mini/user/openId', data, {noAuth:true},{});
+}
+/**
+ * 微信登录
+ * 
+ */
+export function wxLogin(data) {
+  return request.post('auth/wxmini/login', data, {noAuth:true});
+}
+/**
+ * 退出登录
+ * 
+ */
+export function userLogout(data) {
+  return request.post('mini/user/userLogout', data);
+}
+/**
+ * 根据token获取用户信息
+ * 
+ */
+export function getUserInfo(data) {
+  return request.get('system/front/wxmini/getInfo', data);
+}
+/**
+ * 修改用户信息
+ * 
+ */
+export function userEdit(data) {
+  return request.put('mini/user/userEdit', data);
+}
+/**
+ * 会员套餐列表
+ * 
+ */
+export function getPlanList(data) {
+  return request.get('mini/plan/list', data);
+}
+/**
+ * 查询充值规则列表
+ * 
+ */
+export function getRuleList(data) {
+  return request.get('mini/rule/list', data);
+}
+/**
+ * 钱包流水记录
+ * 
+ */
+export function getRecordList(data) {
+  return request.get('mini/record/list', data);
+}

+ 217 - 0
jd_logistics-app/components/AreaPickerCustommer.vue

@@ -0,0 +1,217 @@
+<!-- components/AreaPicker.vue -->
+<template>
+  <view>
+    <!-- 地区选择器 -->
+    <u-picker 
+      :show="show" 
+      :columns="areaColumns"
+      keyName="label"
+      @confirm="handleConfirm"
+      @cancel="handleCancel"
+      @change="handleChange"
+      ref="pickerRef"
+    ></u-picker>
+  </view>
+</template>
+
+<script setup>
+import { ref, watch, nextTick, onMounted, reactive, defineProps, defineEmits } from 'vue';
+import { getProvinces, getCities, getDistricts } from '@/utils/area-data.js';
+
+// 定义props
+const props = defineProps({
+  show: {
+    type: Boolean,
+    default: false
+  }
+});
+
+// 定义emits
+const emit = defineEmits(['update:show', 'confirm']);
+
+// 响应式数据
+const areaColumns = reactive([[], [], []]);
+const pickerRef = ref(null);
+const isUpdating = ref(false); // 防止重复更新
+
+// 初始化数据
+const initAreaData = () => {
+  // 获取省份数据
+  const provinces = getProvinces();
+  areaColumns[0] = provinces;
+  
+  // 获取第一个省份的城市
+  if (provinces.length > 0) {
+    const cities = getCities(provinces[0].value);
+    areaColumns[1] = cities;
+    
+    // 获取第一个城市的区县
+    if (cities.length > 0) {
+      const districts = getDistricts(cities[0].value);
+      areaColumns[2] = districts;
+    }
+  }
+};
+
+// 处理选择器变化
+const handleChange = (e) => {
+  if (isUpdating.value) return; // 防止重复更新
+  
+  const valueIndex = e.indexs; // 获取索引数组
+  
+  console.log('选择器变化 - 索引:', valueIndex);
+  
+  // 省份变化 (第一列)
+  if (valueIndex[0] !== undefined) {
+    isUpdating.value = true;
+    
+    // 通过索引获取省份对象
+    const province = areaColumns[0][valueIndex[0]];
+    console.log('选择了省份:', province);
+    
+    if (province) {
+      // 获取城市数据
+      const cities = getCities(province.value);
+      areaColumns[1] = cities;
+      
+      // 检查城市索引是否超出范围
+      let cityIndex = valueIndex[1] || 0;
+      if (cityIndex >= cities.length) {
+        cityIndex = 0; // 超出范围则重置为0
+      }
+      
+      // 获取区县数据
+      let districts = [];
+      if (cities.length > 0) {
+        // 使用调整后的城市索引获取区县数据
+        const selectedCity = cities[cityIndex];
+        if (selectedCity) {
+          districts = getDistricts(selectedCity.value);
+        } else if (cities.length > 0) {
+          // 如果选中的城市不存在,使用第一个城市
+          districts = getDistricts(cities[0].value);
+        }
+      } else {
+        // 直辖市情况:直接使用省份code获取区县
+        districts = getDistricts(province.value);
+      }
+      areaColumns[2] = districts;
+      
+      // 检查区县索引是否超出范围
+      let districtIndex = valueIndex[2] || 0;
+      if (districtIndex >= districts.length) {
+        districtIndex = 0; // 超出范围则重置为0
+      }
+      
+      // 更新选择器位置
+      nextTick(() => {
+        if (pickerRef.value && pickerRef.value.setIndexes) {
+          // 重置城市和区县索引(市超出则重置为0,区超出也重置为0)
+          pickerRef.value.setIndexes([valueIndex[0], cityIndex, districtIndex]);
+        }
+        isUpdating.value = false;
+      });
+    } else {
+      isUpdating.value = false;
+    }
+    return; // 省份变化处理后直接返回,避免城市变化逻辑执行
+  }
+  
+  // 城市变化 (第二列)
+  if (valueIndex[1] !== undefined && areaColumns[1].length > 0) {
+    isUpdating.value = true;
+    
+    // 检查城市索引是否超出范围
+    let cityIndex = valueIndex[1];
+    if (cityIndex >= areaColumns[1].length) {
+      cityIndex = 0; // 超出范围则重置为0
+    }
+    
+    // 通过索引获取城市对象
+    const city = areaColumns[1][cityIndex];
+    if (city) {
+      // 获取区县数据
+      const districts = getDistricts(city.value);
+      areaColumns[2] = districts;
+      
+      // 检查区县索引是否超出范围
+      let districtIndex = valueIndex[2] || 0;
+      if (districtIndex >= districts.length) {
+        districtIndex = 0; // 超出范围则重置为0
+      }
+      
+      // 更新选择器位置
+      nextTick(() => {
+        if (pickerRef.value && pickerRef.value.setIndexes) {
+          // 获取当前的省份索引
+          const currentIndexes = pickerRef.value.getIndexes ? pickerRef.value.getIndexes() : [0, 0, 0];
+          const provinceIndex = currentIndexes[0];
+          
+          // 设置索引:省份保持当前,城市使用调整后的索引,区县使用调整后的索引
+          pickerRef.value.setIndexes([provinceIndex, cityIndex, districtIndex]);
+        }
+        isUpdating.value = false;
+      });
+    } else {
+      isUpdating.value = false;
+    }
+  }
+};
+
+// 确认选择
+const handleConfirm = (e) => {
+  const areaData = e.value;
+  
+  // 根据选中的对象获取值
+  const province = areaData[0];
+  const city = areaData[1] !== undefined ? areaData[1] : { label: '', value: '' };
+  const district = areaData[2] !== undefined ? areaData[2] : { label: '', value: '' };
+  
+  const result = {
+    province: {
+      name: province.label,
+      code: province.value
+    },
+    city: city.label ? {
+      name: city.label,
+      code: city.value
+    } : null,
+    district: district.label ? {
+      name: district.label,
+      code: district.value
+    } : null,
+    fullAddress: province.label + (city.label ? ' ' + city.label : '') + (district.label ? ' ' + district.label : '')
+  };
+  
+  console.log('确认选择:', result);
+  emit('confirm', result);
+  emit('update:show', false);
+};
+
+// 取消选择
+const handleCancel = () => {
+  emit('update:show', false);
+};
+
+// 组件挂载时初始化数据
+onMounted(() => {
+  console.log('AreaPicker 组件已挂载');
+  initAreaData();
+});
+
+// 监听显示状态
+watch(() => props.show, (newVal) => {
+  console.log('show 状态变化:', newVal);
+  if (newVal) {
+    // 每次显示时重新初始化数据
+    initAreaData();
+    
+    // 延迟设置选择器位置,确保DOM已更新
+    setTimeout(() => {
+      if (pickerRef.value && pickerRef.value.setIndexes) {
+        pickerRef.value.setIndexes([0, 0, 0]);
+      }
+    }, 100);
+  }
+});
+</script>

+ 220 - 0
jd_logistics-app/components/TimelineItem.vue

@@ -0,0 +1,220 @@
+<template>
+	<view class="timeline-item">
+		<!-- 左侧时间线 -->
+		<view class="timeline-left">
+			<view class="timeline">
+				<view class="dot" :class="{'dot-choose-bg': showDotBg}">
+					<view class="timeline-dot" :class="{
+              'dot-active': isActive,
+              'dot-passed': !isActive
+            }"></view>
+				</view>
+				<view 
+					v-if="showLine" 
+					class="timeline-line " 
+					:class="{
+					  'line-active': isActive,
+					  'line-passed': !isActive
+					}"
+				></view>
+			</view>
+		</view>
+
+
+		<!-- 右侧状态内容 -->
+		<view class="status-section">
+			<!-- 状态标签 -->
+			<view 
+				v-if="title" 
+				class="status-badge" 
+				:class="{
+					'status-collected': title === '已代收',
+					'status-title-active': isActive
+				}"
+			>
+				{{ title }}
+			</view>
+
+			<!-- 状态详情 -->
+			<view v-if="desc" class="status-detail">
+				{{ desc }}
+			</view>
+
+			<!-- 状态时间 -->
+			<view v-if="time" class="status-time">
+				{{ time }}
+			</view>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	defineProps({
+		// 是否激活状态(即当前状态)
+		isActive: {
+			type: Boolean,
+			default: false
+		},
+		// 标题,例如:已代收、派送中
+		title: {
+			type: String,
+			default: ''
+		},
+		// 状态描述
+		desc: {
+			type: String,
+			default: ''
+		},
+		// 时间
+		time: {
+			type: String,
+			default: ''
+		},
+		// 是否显示连接线(最后一个节点不显示)
+		showLine: {
+			type: Boolean,
+			default: true
+		},
+		// 是否显示连接线(第一个节点显示  后边不显示)
+		showDotBg: {
+			type: Boolean,
+			default: true
+		}
+	})
+</script>
+
+<style scoped lang="less">
+	.timeline-item {
+		display: flex;
+		// background-color: #F5F7FA;
+		// border-radius: 16rpx;
+		min-height: 120rpx; /* 确保最小高度 */
+
+		&:last-child {
+			margin-bottom: 0;
+		}
+
+		.timeline-left {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			width: 54rpx; /* 增加宽度确保有足够空间 */
+			margin-right: 20rpx;
+			flex-shrink: 0;
+		}
+
+		.timeline {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			height: 100%; /* 确保时间线占满整个高度 */
+			
+			/* 修复 dot 样式 */
+			.dot {
+				width: 34rpx;
+				height: 34rpx;
+				border-radius: 50%;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				flex-shrink: 0;
+				position: relative;
+				z-index: 2; /* 确保圆点在最上层 */
+				
+				&.dot-choose-bg {
+					background-color: #C1D5FF;
+				}
+			}
+
+			.timeline-dot {
+				width: 18rpx;
+				height: 18rpx;
+				border-radius: 50%;
+				position: relative;
+				z-index: 3;
+
+				&.dot-active {
+					background-color: #1B64F0;
+				}
+
+				&.dot-passed {
+					background-color: #CCCCCC;
+				}
+			}
+
+			.timeline-line {
+				flex: 1; /* 关键:使用flex:1让连接线自适应高度 */
+				width: 4rpx;
+				min-height: 40rpx; /* 确保最小高度 */
+				margin-top: 10rpx;
+				
+				&.line-active {
+					border-left: 4rpx dashed #1B64F0;
+				}
+
+				&.line-passed {
+					border-left: 4rpx dashed #CCCCCC;
+				}
+			}
+		}
+
+		.status-section {
+			flex: 1;
+			min-width: 0;
+			display: flex;
+			margin-bottom: 20rpx;
+			flex-direction: column;
+			justify-content: center; /* 垂直居中内容 */
+
+			.status-badge {
+				margin-bottom: 8rpx;
+				height: 48rpx;
+				font-weight: 400;
+				font-size: 32rpx;
+				line-height: 48rpx;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
+
+				&.status-collected {
+					color: #333333;
+				}
+
+				&.status-title-active {
+					color: #1B64F0;
+					font-weight: 600;
+				}
+				
+				/* 默认颜色 */
+				&:not(.status-title-active) {
+					color: #333333;
+				}
+			}
+
+			.status-detail {
+				font-weight: 400;
+				font-size: 28rpx;
+				color: #333333;
+				line-height: 44rpx;
+				margin-top: 8rpx;
+				word-break: break-all;
+				display: -webkit-box;
+				// -webkit-line-clamp: 4; /* 限制最多显示2行 */
+				// -webkit-box-orient: vertical;
+				overflow: hidden;
+			}
+
+			.status-time {
+				margin-top: 8rpx;
+				height: 40rpx;
+				font-weight: 400;
+				font-size: 24rpx;
+				color: #999999;
+				line-height: 40rpx;
+				overflow: hidden;
+				text-overflow: ellipsis;
+				white-space: nowrap;
+			}
+		}
+	}
+</style>

+ 66 - 0
jd_logistics-app/components/agreeRecharge.vue

@@ -0,0 +1,66 @@
+<template>
+  <!-- 用户协议勾选 -->
+  <view class="agree-row mt30">
+    <u-checkbox
+      :customStyle="{marginBottom: '8px'}"
+      label="请阅读并同意"
+      name="agree"
+      usedAlone
+      v-model:checked="aloneChecked"
+      labelSize="12"
+      @change="checkboxChange"
+    >
+    </u-checkbox>
+    <text class="agree-text">
+      <text class="protocol-link" @click="openProtocol()">《充值协议》</text> 
+    </text>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import { useToast } from "@/hooks/useToast";
+const { Toast } = useToast();
+
+const emit = defineEmits(['setAloneChecked']);
+
+// 协议勾选状态
+const aloneChecked = ref(false);
+
+function checkboxChange(e){
+  emit('setAloneChecked', e);
+}
+
+// 模拟打开协议逻辑(实际可跳转 webview 或弹窗展示)
+const openProtocol = (type) => {
+  uni.navigateTo({
+		url: '/pages/policy/recharge_policy'
+	});
+};
+</script>
+
+<style scoped lang="scss">
+
+/* 协议勾选行 */
+.agree-row {
+  display: flex;
+  align-items: center;
+  margin-bottom: 40rpx;
+  width: 100%;
+  box-sizing: border-box;
+}
+.agree-checkbox {
+  transform: scale(0.8);
+  margin-right: 10rpx;
+}
+.agree-text {
+  font-size: 24rpx;
+  color: #666;
+  line-height: 36rpx;
+}
+.protocol-link {
+  color: $theme-color;
+  /* text-decoration: underline; */
+}
+
+</style>

+ 66 - 0
jd_logistics-app/components/agreeVip.vue

@@ -0,0 +1,66 @@
+<template>
+  <!-- 用户协议勾选 -->
+  <view class="agree-row mt30">
+    <u-checkbox
+      :customStyle="{marginBottom: '8px'}"
+      label="请阅读并同意"
+      name="agree"
+      usedAlone
+      v-model:checked="aloneChecked"
+      labelSize="12"
+      @change="checkboxChange"
+    >
+    </u-checkbox>
+    <text class="agree-text">
+      <text class="protocol-link" @click="openProtocol()">《VIP会员开通协议》</text> 
+    </text>
+  </view>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import { useToast } from "@/hooks/useToast";
+const { Toast } = useToast();
+
+const emit = defineEmits(['setAloneChecked']);
+
+// 协议勾选状态
+const aloneChecked = ref(false);
+
+function checkboxChange(e){
+  emit('setAloneChecked', e);
+}
+
+// 模拟打开协议逻辑(实际可跳转 webview 或弹窗展示)
+const openProtocol = (type) => {
+  uni.navigateTo({
+		url: '/pages/policy/vip_policy'
+	});
+};
+</script>
+
+<style scoped lang="scss">
+
+/* 协议勾选行 */
+.agree-row {
+  display: flex;
+  align-items: center;
+  margin-bottom: 40rpx;
+  width: 100%;
+  box-sizing: border-box;
+}
+.agree-checkbox {
+  transform: scale(0.8);
+  margin-right: 10rpx;
+}
+.agree-text {
+  font-size: 24rpx;
+  color: #666;
+  line-height: 36rpx;
+}
+.protocol-link {
+  color: $theme-color;
+  /* text-decoration: underline; */
+}
+
+</style>

+ 52 - 0
jd_logistics-app/components/headerInfo.vue

@@ -0,0 +1,52 @@
+<template>
+<view :class="props.class" class="header_info"
+:style="{ height: appStore.navbarHeight + 'px',paddingTop: appStore.statusBarHeight + 'px'}"
+>
+  <view class="isBack" >
+    <u-icon name="arrow-left" :color="color" size="24"  v-if="isBack" @click="goBack"></u-icon>
+    <slot name="right"></slot>
+  </view>
+  <text class="font_size35 bold color_fff flex_1 text_align_center">{{title}}</text>
+</view>
+</template>
+
+<script setup>
+const props = defineProps({
+  title: {
+    type: String,
+    default: "建材信息平台",
+  },
+  class: {
+    type: String,
+    default: 'flex-center',
+  },
+  isBack: {
+    type: Boolean,
+    default: false,
+  },
+  color: {
+    type: String,
+    default: '#ffffff',
+  },
+});
+
+import { useAppStore } from "@/stores/app";
+const appStore = useAppStore();
+
+const goBack = () => {
+  uni.navigateBack({
+    delta: 1,
+  });
+}
+</script>
+
+<style scoped lang="scss">
+.header_info{
+  position: relative;
+  .isBack{
+    position: absolute;
+    left: 0;
+    bottom: 10px;
+  }
+}
+</style>

+ 80 - 0
jd_logistics-app/components/paymentCommon.vue

@@ -0,0 +1,80 @@
+<template>
+  <u-popup :show="popupShow" mode="bottom" @close="popupShow = false" class="u_popup_bottom">
+    <view class="bg_color_fff u_popup_bottom">
+      <view class="u_popup_bottom_desc border-bottom gray font_size25 text_align_center">请选择付款方式</view>
+      <view class="padding30 border-bottom text_align_center" @click="popupShow = false;pay(0)">微信支付</view>
+      <!-- <view class="padding30 border-bottom text_align_center" @click="popupShow = false;pay(1)">
+        余额支付
+        <text class="color_price"> ( {{appStore.userInfo?.rechargeBalance}} {{appStore.moneyUnit}} )</text>
+      </view> -->
+      <view class="padding30 text_align_center" @click="popupShow = false">取消</view>
+    </view>
+  </u-popup>
+</template>
+<script setup>
+import { ref } from 'vue'
+import { createOrder } from "@/api/order.js";
+import { wxPay } from "@/utils/util.js";
+import { useAppStore } from "@/stores/app";
+const appStore = useAppStore();
+defineExpose({
+  open
+});
+const emit = defineEmits(['reloadList']);
+const popupShow = ref(false);
+const orderId = ref(null);
+const payType = ref('');//支付方式 0微信 1余额
+function open(e) {
+  popupShow.value = true;
+  orderId.value = e.orderId;
+}
+
+async function pay(payMethod){
+  console.log('pay',payMethod,orderId.value);
+  payType.value = payMethod;
+  const res = await createOrder({
+    payMethod:payType.value,//支付方式 0微信 1余额
+    orderId:orderId.value
+  });
+  orderId.value = res.data.orderId;
+  // 余额支付
+  if(payType.value==1){
+    //1成功 0失败;
+    const paySuccess = res.data.paySuccess;
+    orderStatusQuery({isSuccess:paySuccess?1:0});
+  }else{ 
+    const payInfo = res.data.payData.prepayWithRequestPaymentResponse;
+    wxPay({
+      timeStamp:payInfo.timeStamp,
+      nonceStr:payInfo.nonceStr,
+      packageVal:payInfo.packageVal,
+      signType:payInfo.signType,
+      paySign:payInfo.paySign,
+    },orderStatusQuery);
+  }
+}
+function orderStatusQuery({isSuccess}){
+ emit('reloadList');
+ to_success_pay({isSuccess});
+}
+function to_success_pay({isSuccess}){
+	console.log('to_success_pay',isSuccess);
+	uni.navigateTo({
+    url: `/pages/recharge/success_pay?orderId=${orderId.value}&isSuccess=${isSuccess}&payMethod=${payType.value}`
+  })
+}
+</script>
+<style lang="scss">
+.u_popup_bottom{
+	.u-popup__content{
+		border-radius: 30rpx 30rpx 0 0;
+	}
+  .u_popup_bottom_desc{
+		padding: 50rpx 50rpx 30rpx;
+	}
+}
+</style>
+<style lang="scss" scoped>
+.u_popup_bottom{
+}
+</style>

+ 27 - 0
jd_logistics-app/config/app.js

@@ -0,0 +1,27 @@
+
+import { domainInfo } from './env.js';
+
+export const HTTP_REQUEST_URL = domainInfo.domain
+export const HTTP_REQUEST_URL_WS = domainInfo.domainWS
+
+// PC 后台 API 地址(用于上传图片)
+export const HTTP_ADMIN_URL = domainInfo.domain
+
+// 请求头
+export const HEADER = {
+  'content-type': 'application/json'
+}
+
+// 表单提交头
+export const HEADERPARAMS = {
+  'content-type': 'application/x-www-form-urlencoded'
+}
+
+// token 名称
+export const TOKENNAME = 'Authorization'
+
+// 缓存时间,0 为永久
+export const EXPIRE = 0
+
+// 分页默认限制条数
+export const LIMIT = 10

+ 3 - 0
jd_logistics-app/config/cache.js

@@ -0,0 +1,3 @@
+export const USER_INFO = "USER_INFO"
+export const CITYINFO = "CITYINFO"
+export const TOKEN = "TOKEN"

+ 46 - 0
jd_logistics-app/config/env.js

@@ -0,0 +1,46 @@
+// 根据微信小程序环境版本设置 baseUrl
+// let domain = 'http://192.168.100.254:8024/front-api' // 内网IP
+// let domain = 'http://192.168.100.199:8081' // 晋守桦IP
+// let domain = 'http://192.168.100.14:8081' // 赵乔功IP
+// let domain = 'http://192.168.100.146:8079' // 马二勇
+ let domain = 'http://192.168.100.92:8080' // 朝龙
+// let domain = 'https://www.bjwdys.com/prod-api' //线上环境
+
+const getBaseUrl = () => {
+  // 获取小程序账户信息(包含环境版本)
+  const accountInfo = uni.getAccountInfoSync()||{};
+  const envVersion = accountInfo.miniProgram.envVersion;
+  console.log('环境版本-getBaseUrl:', envVersion);
+  switch (envVersion) {
+    case 'develop': // 开发版
+      return {
+        // domain:'https://www.bjwdys.com/prod-api',
+        // domainWS:'wss://www.bjwdys.com/prod-api',
+        domain:domain,
+        domainWS:domain,
+      };
+    case 'trial':   // 这边分为测试版本和预生产,根据开发注释掉
+      // 测试 -对应LS体验版
+      return  {
+        // domain:'https://www.bjwdys.com/prod-api',
+        // domainWS:'wss://www.bjwdys.com/prod-api',
+        domain:domain,
+        domainWS:domain,
+      };;
+      // 预生产 - 对应壹加体验版
+      // return 'https://wxmp-pre.equah.com.cn';
+    case 'release': // 正式版
+      return  {
+        domain:domain,
+        domainWS:domain,
+		
+      };;
+    default:
+      return  {
+        domain:'https://www.bjwdys.com/prod-api',
+        domainWS:'wss://www.bjwdys.com/prod-api',
+      };;
+  }
+};
+
+export const domainInfo = getBaseUrl();

+ 112 - 0
jd_logistics-app/hooks/useToast.js

@@ -0,0 +1,112 @@
+import { ref } from "vue";
+
+	/**
+	 * opt  object | string
+	 * to_url object | string
+	 * 例:
+	 * this.Tips('/pages/test/test'); 跳转不提示
+	 * this.Tips({title:'提示'},'/pages/test/test'); 提示并跳转
+	 * this.Tips({title:'提示'},{tab:1,url:'/pages/index/index'}); 提示并跳转值table上
+	 * tab=1 一定时间后跳转至 table上
+	 * tab=2 一定时间后跳转至非 table上
+	 * tab=3 一定时间后返回上页面
+	 * tab=4 关闭所有页面跳转至非table上
+	 * tab=5 关闭当前页面跳转至table上
+	 */
+
+export function useToast() {
+  // 提示标题
+  const tipTitle = ref("");
+  // 提示图标
+  const tipIcon = ref("none");
+  // 提示持续时间
+  const tipEndtime = ref(2000);
+
+  /**
+   * Tips - 显示提示并可按需跳转页面
+   * @param {Object|string} opt 提示配置或直接为跳转路径
+   * @param {Object|string|Function} to_url 跳转配置、路径或回调
+   */
+  function Toast(opt, to_url) {
+    console.log("Toast", opt, to_url);
+    // 如果第一个参数是字符串,视为跳转路径
+    if (typeof opt == "string") {
+      to_url = opt;
+      opt = {};
+    }
+    // 提示内容
+    tipTitle.value = opt.title || "";
+    // 图标
+    tipIcon.value = opt.icon || "none";
+    // 持续时间
+    tipEndtime.value = opt.endtime || 2000;
+    // 接口调用成功的回调函数
+    let success = opt.success;
+    // 显示提示
+    if (tipTitle.value)
+      uni.showToast({
+        title: tipTitle.value,
+        icon: tipIcon.value,
+        duration: tipEndtime.value,
+        success,
+      });
+    // 跳转逻辑
+    if (to_url != undefined) {
+      if (typeof to_url == "object") {
+        // 对象方式配置跳转
+        let tab = to_url.tab || 1,
+          url = to_url.url || "";
+        console.log('tab', tab)
+        switch (tab) {
+          case 1:
+            // 一定时间后跳转至 table
+            setTimeout(() => uni.switchTab({ url }), tipEndtime.value);
+            break;
+          case 2:
+            // 跳转至非table页面
+            setTimeout(() => uni.navigateTo({ url }), tipEndtime.value);
+            break;
+          case 3:
+            // 返回上一个页面
+            setTimeout(() => {
+
+              // #ifndef H5
+              uni.navigateBack({ delta: 1 });
+              // #endif
+
+              // #ifdef H5
+              history.back();
+              // #endif
+
+            }, tipEndtime.value);
+            break;
+          case 4:
+            // 关闭所有页面跳转到非 tab 页面
+            setTimeout(() => uni.reLaunch({ url }), tipEndtime.value);
+            break;
+          case 5:
+            // 关闭当前页面跳转到非 tab 页面
+            setTimeout(() => uni.redirectTo({ url }), tipEndtime.value);
+            break;
+        }
+      } else if (typeof to_url == "function") {
+        // 回调函数
+        setTimeout(() => to_url && to_url(), tipEndtime.value);
+      } else {
+        // 普通路径跳转
+        setTimeout(
+          () => uni.navigateTo({ url: to_url }),
+          tipTitle.value ? tipEndtime.value : 0
+        );
+      }
+    }
+  }
+
+  // 导出响应式数据和方法
+  return {
+    tipTitle,
+    tipIcon,
+    tipEndtime,
+    Toast
+  };
+}

+ 20 - 0
jd_logistics-app/index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+  <head>
+    <meta charset="UTF-8" />
+    <script>
+      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
+        CSS.supports('top: constant(a)'))
+      document.write(
+        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
+        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+    </script>
+    <title></title>
+    <!--preload-links-->
+    <!--app-context-->
+  </head>
+  <body>
+    <div id="app"><!--app-html--></div>
+    <script type="module" src="/main.js"></script>
+  </body>
+</html>

+ 40 - 0
jd_logistics-app/libs/login.js

@@ -0,0 +1,40 @@
+import { useAppStore } from "@/stores/app.js";
+import Cache from "../utils/cache";
+// import { Debounce } from "@/utils/validate.js";
+
+import {
+  USER_INFO,TOKEN,CITYINFO
+} from "@/config/cache";
+
+function prePage() {
+  let pages = getCurrentPages();
+  let prePage = pages[pages.length - 1];
+  return prePage.route;
+}
+
+// export const toLogin = Debounce(_toLogin, 800);
+
+export function toLogin(push, pathLogin) {
+  const appStore = useAppStore();
+  // appStore.LOGOUT();
+  // let path = prePage();
+  // let login_back_url = Cache.get(BACK_URL);
+
+
+  uni.navigateTo({
+    url: "/pages/login/login",
+  });
+}
+
+export function checkLogin() {
+  let userInfo = Cache.get(USER_INFO) ? JSON.parse(Cache.get(USER_INFO)) : null;
+  let token = Cache.get(TOKEN);
+  const appStore = useAppStore();
+  if (userInfo && userInfo.userPhone && token) {
+    return true;
+  } else {
+    Cache.clear(TOKEN);
+    Cache.clear(USER_INFO);
+    return false;
+  }
+}

+ 45 - 0
jd_logistics-app/main.js

@@ -0,0 +1,45 @@
+import App from './App'
+
+// #ifndef VUE3
+import Vue from 'vue'
+import './uni.promisify.adaptor'
+Vue.config.productionTip = false
+App.mpType = 'app'
+const app = new Vue({
+  ...App
+})
+app.$mount()
+// #endif
+
+// #ifdef VUE3
+import * as Pinia from 'pinia';
+import uviewPlus, { setConfig  } from '@/uni_modules/uview-plus'
+
+
+import { createSSRApp } from 'vue'
+export function createApp() {
+  const app = createSSRApp(App)
+  
+  app.use(Pinia.createPinia())
+
+  app.use(uviewPlus, () => {
+		return {
+			options: {
+				// 修改$u.config对象的属性
+				config: {
+					// 修改默认单位为rpx,相当于执行 uni.$u.config.unit = 'rpx'
+					unit: 'rpx',
+          // customIcon: {
+            // family: 'iconfont',
+            // url: '//at.alicdn.com/t/c/font_4946742_e8oa3t01rkk.css'
+          // }
+				}
+			}
+		}
+  })
+  return {
+    app
+  }
+}
+
+// #endif

+ 72 - 0
jd_logistics-app/manifest.json

@@ -0,0 +1,72 @@
+{
+    "name" : "lightning-app-cs",
+    "appid" : "__UNI__516F309",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {}
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "wxdc3282b1876a4286",
+        "setting" : {
+            "urlCheck" : false
+        },
+        "usingComponents" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    },
+    "vueVersion" : "3"
+}

+ 18 - 0
jd_logistics-app/package-lock.json

@@ -0,0 +1,18 @@
+{
+  "name": "lightning-app-cs",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "dayjs": "^1.11.13"
+      }
+    },
+    "node_modules/dayjs": {
+      "version": "1.11.18",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
+      "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==",
+      "license": "MIT"
+    }
+  }
+}

+ 5 - 0
jd_logistics-app/package.json

@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "dayjs": "^1.11.13"
+  }
+}

+ 232 - 0
jd_logistics-app/pages.json

@@ -0,0 +1,232 @@
+{
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": "瑞鲸物流",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/mine/mine",
+			"style" : 
+			{
+				"navigationBarTitleText" : "我的",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/logistics/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : "物流轨迹"
+				
+			}
+		},
+		{
+			"path" : "pages/search/search",
+			"style" : 
+			{
+				"navigationBarTitleText" : "",
+				"transparentTitle": "always",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/ai/ai",
+			"style" : 
+			{
+				"navigationBarTitleText" : "",
+				"transparentTitle": "always",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/mine/settlementCode",
+			"style" : 
+			{
+				"navigationBarTitleText" : "到付月结码"
+			}
+		}
+	],
+	"subPackages": [
+		{
+			"root": "pages/user",
+      "name": "user",
+			"pages": [
+				{
+					"path" : "user",
+					"style" : 
+					{
+						"navigationBarTitleText" : "个人资料"
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/webView",
+      "name": "webView",
+			"pages": [
+				{
+					"path" : "webView",
+					"style" : 
+					{
+						"navigationBarTitleText" : "文章详情"
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/historyList",
+      "name": "historyList",
+			"pages": [
+				{
+					"path" : "historyList",
+					"style" : 
+					{
+						"navigationBarTitleText" : "历史对话记录"
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/recharge",
+      "name": "recharge",
+			"pages": [
+				{
+					"path" : "recharge",
+					"style" : 
+					{
+						"navigationBarTitleText" : "充值"
+					}
+				},
+				{
+					"path" : "vip",
+					"style" : 
+					{
+						"navigationBarTitleText" : "会员中心",
+						"navigationStyle": "custom",
+						"transparentTitle": "always"
+					}
+				},
+				{
+					"path" : "wallet",
+					"style" : 
+					{
+						"navigationBarTitleText" : "我的钱包"
+					}
+				},
+				{
+					"path" : "success_pay",
+					"style" : 
+					{
+						"navigationBarTitleText" : "支付结果"
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/policy",
+      "name": "policy",
+			"pages": [
+				{
+					"path" : "recharge_policy",
+					"style" : 
+					{
+						"navigationBarTitleText" : "充值协议"
+					}
+				},
+				{
+					"path" : "vip_policy",
+					"style" : 
+					{
+						"navigationBarTitleText" : "VIP会员开通协议"
+					}
+				},
+				{
+					"path" : "ad_detail",
+					"style" : 
+					{
+						"navigationBarTitleText" : "详情"
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/order",
+      "name": "order",
+			"pages": [
+				{
+					"path" : "index",
+					"style" : 
+					{
+						"navigationBarTitleText" : "订单列表"
+					}
+				},
+				{
+					"path" : "order_detail",
+					"style" : 
+					{
+						"navigationBarTitleText" : "订单详情"
+					}
+				},
+				{
+					"path" : "create_order",
+					"style" : 
+					{
+						"navigationBarTitleText" : "创建订单"
+					}
+				}
+			]
+		},
+		{
+			"root": "pages/address",
+      "name": "address",
+			"pages": [
+				{
+					"path" : "address_list",
+					"style" : 
+					{
+						"navigationBarTitleText" : "地址薄"
+					}
+				},
+				{
+					"path" : "edit",
+					"style" : 
+					{
+						"navigationBarTitleText" : "新增地址"
+					}
+				}
+			]
+		}
+	],
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "uni-app",
+		"navigationBarBackgroundColor": "#fff",
+		"backgroundColor": "#F5F7FA"
+	},
+		"tabBar": {
+		"color": "#333333",
+		"selectedColor": "#1B64F0",
+		"borderStyle": "black",
+		"backgroundColor": "#ffffff",
+		"list": [{
+			"pagePath": "pages/index/index",
+			"selectedIconPath": "static/img/tabs/home_active.png",
+			"iconPath": "static/img/tabs/home.png",
+			"text": "首页"
+		},{
+			"pagePath": "pages/search/search",
+			"selectedIconPath": "static/img/tabs/search_active.png",
+			"iconPath": "static/img/tabs/search.png",
+			"text": "查快递"
+		},{
+			"pagePath": "pages/mine/mine",
+			"selectedIconPath": "static/img/tabs/user_active.png",
+			"iconPath": "static/img/tabs/user.png",
+			"text": "我的"
+		}]
+	},
+	"uniIdRouter": {}
+}

+ 192 - 0
jd_logistics-app/pages/address/address_list.vue

@@ -0,0 +1,192 @@
+<template>
+	<view class="address-page">
+		<!-- 地址列表 -->
+		<scroll-view class="address-list" scroll-y>
+			<!-- 地址项组件 -->
+			<address-item v-for="(item, index) in addressList" :key="item.id" :address="item"
+				:is-default="item.isDefault" @set-default="handleSetDefault(index)" @edit="handleEdit(index)"
+				@delete="handleDelete(index)" />
+		</scroll-view>
+
+		<!-- 添加新地址按钮 -->
+		<view class="add-btn-container">
+			<button class="add-btn" @click="handleAddAddress">
+				<text class="add-btn-text">添加新地址</text>
+			</button>
+		</view>
+
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref
+	} from 'vue'
+	import AddressItem from '@/components/AddressItem.vue'
+
+	// 模拟地址数据
+	const addressList = ref([{
+			id: 1,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路97号',
+			isDefault: true
+		},
+		{
+			id: 2,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		},
+		{
+			id: 3,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		},
+		{
+			id: 3,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		},
+		{
+			id: 3,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		},
+		{
+			id: 3,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		},
+		{
+			id: 3,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		},
+		{
+			id: 3,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		},
+		{
+			id: 3,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		},
+		{
+			id: 3,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路97号',
+			isDefault: false
+		}
+	])
+
+	// 当前要操作的地址索引
+	const currentIndex = ref(-1)
+
+	// 设置默认地址
+	const handleSetDefault = (index) => {
+		addressList.value.forEach((item, i) => {
+			item.isDefault = i === index
+		})
+	}
+
+	// 编辑地址
+	const handleEdit = (index) => {
+		console.log('编辑地址:', index)
+		// 这里可以跳转到编辑页面
+		// uni.navigateTo({ url: '/pages/address/edit?id=' + addressList.value[index].id })
+	}
+
+	// 删除地址
+	const handleDelete = (index) => {
+		currentIndex.value = index
+		uni.showModal({
+			title: '确认删除',
+			content: '是否确认删除这个地址',
+			// showCancel:false,
+			success: function(res) {
+				if (res.confirm) {
+					confirmDelete()
+				} else if (res.cancel) {
+					console.log('用户点击取消');
+				}
+			}
+		});
+	}
+
+	// 确认删除
+	const confirmDelete = () => {
+		if (currentIndex.value >= 0) {
+			addressList.value.splice(currentIndex.value, 1)
+			currentIndex.value = -1
+		}
+	}
+
+	// 添加新地址
+	const handleAddAddress = () => {
+		console.log('添加新地址')
+		uni.navigateTo({
+			url: '/pages/address/edit'
+		})
+	}
+</script>
+
+<style scoped>
+	.address-page {
+		display: flex;
+		flex-direction: column;
+		height: 100vh;
+		background-color: #F5F7FA;
+	}
+
+	.address-list {
+		flex: 1;
+		padding: 20rpx 30rpx;
+		box-sizing: border-box;
+	}
+
+	.add-btn-container {
+		width: 100%;
+		position: fixed;
+		bottom: 0rpx;
+		padding: 32rpx;
+		background-color: #fff;
+		border-top: 1rpx solid #eee;
+	}
+
+	.add-btn {
+		height: 88rpx;
+		background: #1B64F0;
+		border-radius: 44rpx;
+	}
+
+	.add-btn-text {
+		color: #fff;
+		font-size: 32rpx;
+		font-weight: 500;
+		height: 88rpx;
+		line-height: 88rpx;
+	}
+
+	/* 按钮激活效果 */
+	.add-btn:active {
+		opacity: 0.8;
+	}
+</style>

+ 434 - 0
jd_logistics-app/pages/address/edit.vue

@@ -0,0 +1,434 @@
+<template>
+	<view class="container">
+
+		<!-- 物品信息 -->
+		<view class="form-card">
+
+			<view class="form-item">
+				<view class="item-label">
+					<input class="input-field" placeholder="姓名" placeholder-class="placeholder" v-model="formInfo" />
+				</view>
+				<view class="item-control">
+					<input class="input-field" placeholder="电话" placeholder-class="placeholder" v-model="formInfo" />
+				</view>
+			</view>
+			<view class="form-item" @click="showTimePicker = true">
+				<text class="time-value placeholder">省市区</text>
+				<text class="time-value value">{{ selectedTime }}</text>
+				<u-icon class="arrow" name='arrow-right' size="18"></u-icon>
+			</view>
+
+			<view class="form-item">
+				<view class="item-control">
+					<input class="input-field" placeholder="详细地址" placeholder-class="placeholder" v-model="formInfo" />
+				</view>
+			</view>
+
+
+			<view class="form-item">
+				<!-- 设置默认和清空 -->
+				<view class="form-actions">
+					<view class="action-left">
+						<switch color="#007AFF" @change="onDefaultChange" />
+						<text class="action-text">设为默认寄件地址</text>
+					</view>
+					<view class="action-right" @click="clearForm">
+						<text class="clear-text">清空</text>
+					</view>
+				</view>
+			</view>
+		</view>
+
+
+		<view class="section-title">最近使用地址</view>
+
+		<!-- 最近使用地址 -->
+		<view class="recent-address">
+			<!-- 地址项1 -->
+			<view class="address-item" @tap="selectAddress(0)">
+				
+					<AddressInfo v-if="addressSend.id" :address="addressSend" />
+				<view class="address-info">
+					<view class="address-name">袁添昊 13344642161</view>
+					<view class="address-detail">湖北省荆州市新石南路747号</view>
+				</view>
+			<!-- 	<view class="address-select">
+					
+				</view> -->
+			</view>
+
+			<!-- 地址项2 -->
+			<view class="address-item" @tap="selectAddress(1)">
+				<view class="address-info">
+					<view class="address-name">袁添昊 13344642161</view>
+					<view class="address-detail">湖北省荆州市新石南路747号</view>
+				</view>
+				<!-- <view class="address-select">
+					
+				</view> -->
+			</view>
+		</view>
+		<!-- 下单按钮 -->
+		<view class="submit-btn" @click="onConfirm">
+			确定
+		</view>
+
+		<!-- 安全区域占位 -->
+		<view class="safe-area"></view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		reactive
+	} from 'vue'
+	import {onLoad} from '@dcloudio/uni-app'
+	import AddressInfo from '@/components/AddressInfo.vue'
+	
+	const addType = ref('1') //1 表示从创建订单过来  2 表示编辑  3表示创建
+	
+	// 表单数据
+	const formData = reactive({
+		name: '',
+		phone: '',
+		region: [],
+		address: '',
+		isDefault: false
+	})
+	
+	// 最近地址列表
+	const recentAddresses = ref([{
+			name: '袁添昊',
+			phone: '13344642161',
+			address: '湖北省荆州市新石南路747号'
+		},
+		{
+			name: '袁添昊',
+			phone: '13344642161',
+			address: '湖北省荆州市新石南路747号'
+		}
+	])
+	
+	onLoad((option)=>{
+		
+	})
+
+
+	// 省市区选择
+	const onRegionChange = (e) => {
+		formData.region = e.detail.value
+	}
+
+	// 默认地址切换
+	const onDefaultChange = (e) => {
+		formData.isDefault = e.detail.value
+	}
+
+	// 清空表单
+	const clearForm = () => {
+		formData.name = ''
+		formData.phone = ''
+		formData.region = []
+		formData.address = ''
+		formData.isDefault = false
+	}
+
+	// 选择地址
+	const selectAddress = (index) => {
+		const address = recentAddresses.value[index]
+		formData.name = address.name
+		formData.phone = address.phone
+		formData.address = address.address
+	}
+
+	// 确定提交
+	const onConfirm = () => {
+		// 这里可以添加表单验证
+		if (!formData.name || !formData.phone || !formData.address) {
+			uni.showToast({
+				title: '请填写完整信息',
+				icon: 'none'
+			})
+			return
+		}
+
+		// 提交逻辑
+		console.log('提交数据:', formData)
+		uni.showToast({
+			title: '提交成功',
+			icon: 'success'
+		})
+
+		// 返回上一页或执行其他操作
+		// uni.navigateBack()
+	}
+</script>
+
+<style scoped lang="less">
+	.container {
+		background-color: #F5F7FA;
+		min-height: 100vh;
+		padding: 20rpx 20rpx 30rpx 20rpx;
+	}
+
+	.form-card {
+		background-color: #fff;
+		border-radius: 32rpx;
+		padding: 0rpx 20rpx;
+	}
+
+	.form-title {
+		font-size: 32rpx;
+		font-weight: 600;
+		color: #333;
+		margin-bottom: 32rpx;
+	}
+
+
+	.form-item {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		height: 100rpx;
+		border-bottom: 1rpx solid #F1F3F8;
+
+		&:last-child {
+			border-bottom: none;
+			margin-bottom: 0;
+		}
+
+		.item-label {
+			font-size: 28rpx;
+			color: #666;
+			font-weight: 400;
+
+			&.required::before {
+				content: '*';
+				color: #ff4444;
+				margin-right: 8rpx;
+			}
+		}
+
+		.item-control {
+			display: flex;
+			align-items: center;
+
+			&.btn {
+				background: #fff;
+				border: 1rpx solid #dcdfe6;
+				border-radius: 5rpx;
+				height: 59rpx;
+				width: 266rpx;
+				box-sizing: border-box;
+			}
+
+		}
+
+		.input-field {
+			width: 100%;
+			height: 100rpx;
+			line-height: 100rpx;
+			padding: 0 24rpx;
+			font-size: 28rpx;
+			color: #333;
+			text-align: left;
+
+
+			&::placeholder {
+				color: #999;
+			}
+		}
+
+		.time-value {
+			display: flex;
+			align-items: center;
+			font-size: 28rpx;
+			color: #333;
+			line-height: 88rpx;
+			height: 88rpx;
+			padding: 0 24rpx;
+
+			&.placeholder {
+				color: #999;
+			}
+
+			.value {
+				margin-right: 16rpx;
+			}
+
+			.arrow {
+				margin-left: 32rpx;
+				color: #999;
+				font-size: 28rpx;
+				font-weight: bold;
+			}
+		}
+	}
+
+	/* 寄件标识 */
+	.send-tag {
+		padding: 40rpx 30rpx 20rpx;
+		background-color: #fff;
+	}
+
+	.send-circle {
+		width: 60rpx;
+		height: 60rpx;
+		border-radius: 50%;
+		background-color: #007AFF;
+		color: #fff;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		font-size: 28rpx;
+		font-weight: bold;
+	}
+
+	/* 表单区域 */
+	.form-container {
+		background-color: #fff;
+		padding: 0 30rpx;
+		margin-bottom: 20rpx;
+	}
+
+	.form-title {
+		font-size: 18px;
+		font-weight: 500;
+		color: #333;
+		padding: 30rpx 0 20rpx;
+		border-bottom: 1rpx solid #eee;
+	}
+
+	.form-item {
+		width: 100%;
+		padding: 30rpx 0;
+		border-bottom: 1rpx solid #eee;
+	}
+
+	.form-input {
+		font-size: 16px;
+		height: 40rpx;
+		line-height: 40rpx;
+		color: #333;
+	}
+
+	.form-input::placeholder {
+		color: #999;
+	}
+
+	.picker-placeholder {
+		font-size: 16px;
+		height: 40rpx;
+		line-height: 40rpx;
+		color: #999;
+	}
+
+	.picker-placeholder.has-value {
+		color: #333;
+	}
+
+	/* 表单操作 */
+	.form-actions {
+		width: 100%;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding: 30rpx 0;
+	}
+
+	.action-left {
+		display: flex;
+		align-items: center;
+	}
+
+	.action-text {
+		font-size: 28rpx;
+		color: #333;
+		margin-left: 10rpx;
+	}
+
+	.action-right {
+		padding: 10rpx 20rpx;
+	}
+
+	.clear-text {
+		height: 44rpx;
+		font-weight: 400;
+		font-size: 28rpx;
+		color: #1B64F0;
+		line-height: 44rpx;
+	}
+
+	/* 最近地址 */
+	.recent-address {
+		background-color: #fff;
+		padding: 0 30rpx;
+	}
+
+	.section-title {
+		height: 48rpx;
+		font-size: 32rpx;
+		color: #333333;
+		line-height: 48rpx;
+		margin: 20rpx 0rpx;
+		font-weight: bold;
+	}
+
+	.address-item {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding: 30rpx 0;
+		border-bottom: 1rpx solid #eee;
+	}
+
+	.address-info {
+		flex: 1;
+	}
+
+	.address-name {
+		font-size: 16px;
+		color: #333;
+		margin-bottom: 10rpx;
+	}
+
+	.address-detail {
+		font-size: 14px;
+		color: #666;
+		line-height: 1.4;
+	}
+
+	.address-select {
+		width: 40rpx;
+		height: 40rpx;
+		border: 1rpx solid #007AFF;
+		border-radius: 50%;
+		margin-left: 20rpx;
+	}
+
+
+	.safe-area {
+		height: 140rpx;
+	}
+
+	.submit-btn {
+		position: fixed;
+		bottom: 40rpx;
+		left: 30rpx;
+		right: 30rpx;
+		width: 686rpx;
+		height: 88rpx;
+		background: #1B64F0;
+		border-radius: 44rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+
+		font-size: 32rpx;
+		color: #FFFFFF;
+		line-height: 88rpx;
+		text-align: center;
+		z-index: 10;
+	}
+</style>

+ 716 - 0
jd_logistics-app/pages/ai/ai.vue

@@ -0,0 +1,716 @@
+<template>
+  <view class="chat-container"  :style="{ 
+    paddingTop: appStore.navbarHeight + 'px',
+  }">
+		<view class="mine_ybt_title flex-center bg_color_fff" 
+		:style="{ height: appStore.navbarHeight + 'px',
+    paddingTop: appStore.statusBarHeight + 'px'}"
+		>
+			<!-- <text class="font_size35 bold">AI客服</text> -->
+     <agentCheck ref="agentCheckRef"></agentCheck>
+		</view>
+    <!-- 聊天消息区域 -->
+    <view class="chat-messages flex-column">
+			<!-- 工具栏 -->
+			<tools @addHuiHuaFn="addHuiHuaFn"></tools>
+			<!-- 消息列表 -->
+      <scroll-view
+        class="scrollViewRef flex_1"
+        scroll-y="true" 
+        :scroll-top="scrollTop"
+        ref="scrollViewRef"
+        :scroll-with-animation="true"
+        @refresherrefresh="handlePullDownRefresh"
+        :refresher-enabled="true"
+        :refresher-triggered="triggered"
+      >
+        <messagesInfoDefault v-if="messages.length==0" 
+        @sendMessage="sendMessage"
+        ref="messagesInfoDefaultRef" key="messagesInfoDefaultRef">
+        </messagesInfoDefault>
+        <messagesInfo 
+        :messages="messages" 
+        :isLoading="isLoading" 
+        @imageLoaded="scrollToBottom"
+        :id="`msg-${messagesKey}`">
+        </messagesInfo>
+      </scroll-view>
+    </view>
+    <!-- 输入区域 -->
+    <view class="input-area">
+      <button class="image-btn" :disabled="isLoading" @click.stop.prevent="uploadImage">
+        <image class="image-icon" src="/static/img/service/tupian.png" model="aspectFit"></image>
+      </button>
+      <button v-if="isvoice"
+        class="record-btn"
+        :class="{ recording: isRecording }"
+        @touchstart="startRecord"
+        @touchend="stopRecord"
+        @touchmove="handleTouchMove"
+        @touchcancel="cancelRecord"
+        :disabled="isRecording && isCancel"
+      >
+        <view v-if="!isRecording">按住说话</view>
+        <view v-if="isRecording && !isCancel">松手发送,上移取消</view>
+        <view v-if="isRecording && isCancel">松手取消</view>
+        <text v-if="recordDuration>0"></text>
+      </button>
+      <input v-else
+        class="input-box"
+        :placeholder="isLoading?'努力回答中...':'发消息或按住说话'"
+        placeholder-style="color: #999"
+        v-model.trim="inputText"
+        :disabled="isLoading"
+        @confirm="sendMessage({chatType:0,msgContent:inputText})"
+      />
+      <button class="isvoice-btn" @click.stop.prevent="isvoice=!isvoice;authorizeRecord()" :disabled="isLoading">
+        <image class="mic-icon" src="/static/img/service/xiaoxi.png" v-if="isvoice" model="aspectFit"></image>
+        <image class="mic-icon" src="/static/img/service/maikefengyuyin.png" v-else model="aspectFit"></image>
+      </button>
+      <button class="send-btn" @click.stop.prevent="sendMessage({chatType:0,msgContent:inputText})" :disabled="isLoading" v-if="!isvoice">
+        <image class="send-icon" src="/static/img/service/send-icon.png"></image>
+      </button>
+      <view class="ai-tip">内容由AI生成,仅供参考</view>
+    </view>
+     <!-- 录音动画/提示 -->
+      <view 
+        class="record-toast" 
+        v-if="isRecording"
+        :class="{ cancel: isCancel }"
+      >
+        <image 
+          v-if="!isCancel"
+          src="/static/img/voice/recording.gif" 
+          class="toast-icon"
+          alt="录音中动画"
+        ></image>
+        <image 
+          v-if="isCancel"
+          src="/static/img/voice/cancel.png" 
+          class="toast-icon"
+          alt="取消录音图标"
+        ></image>
+        <text v-if="!isCancel">正在录音...({{60-recordDuration}})</text>
+        <text v-if="isCancel">松手取消发送</text>
+      </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, nextTick, watch } from 'vue';
+import { onShow,onHide,onLoad } from "@dcloudio/uni-app"
+import { chatHistoryDetails } from '@/api/ai.js';
+import messagesInfo from "./components/messagesInfo.vue";
+import messagesInfoDefault from "./components/messagesInfoDefault.vue";
+import tools from "./components/tools.vue";
+import agentCheck from "./components/agentCheck.vue";
+import {
+	HTTP_REQUEST_URL,
+	HTTP_REQUEST_URL_WS,
+  TOKENNAME
+} from '@/config/app';
+import { chooseImageOne,checkLoginShowModal,checkAiQuotaDailyModal,getUserInfo } from "@/utils/util.js";
+// 封装的websocket
+import WSClient from '@/utils/wsUtil.js';
+import { useAppStore } from '@/stores/app'
+import { useToast } from '@/hooks/useToast'
+import dayjs from "dayjs";
+const appStore = useAppStore();
+const { Toast } = useToast();
+const agentCheckRef = ref(null);
+const messagesInfoDefaultRef = ref(null);
+const newSession = ref(false);//是否新会话
+const historySession = ref('');//是否新会话
+
+// 添加滚动相关变量
+const scrollTimeout = ref(null);
+const scrollViewRef = ref(null);
+const scrollTop = ref(0);
+const messagesKey = ref(0);
+const triggered = ref(false);
+
+// 底部发送功能
+const inputText = ref('');
+const isLoading = ref(false);//思考中
+const isvoice = ref(false);//是否语音输入
+const wsClient = ref(null);
+
+// 模拟聊天消息数据
+const messages = ref([]);
+
+watch(() => appStore.agentId, (state) => {
+  messages.value = [];
+  getAdSearchFn()
+});
+
+onLoad((e)=>{
+  console.log('ai onLoad',e);
+})
+onShow(async()=>{
+  if(!await checkLoginShowModal())return;
+  nextTick(async ()=>{
+    // 初始化选择智能体
+    await agentCheckRef.value.initAgentId();
+     // 初始化完成后获取 agentId
+    console.log('agentId:', agentCheckRef.value.agentId);
+    if(appStore.msgContent){
+      sendMessage({chatType:0,msgContent:appStore.msgContent});
+      appStore.UPDATE_msgContent('');
+    }else if(appStore.sessionId){
+      handlePullDownRefresh();
+    }else{
+      // getAdSearchFn()
+    }
+    
+  })
+
+	aiStartChatFn();
+});
+onHide(()=>{
+  isLoading.value = false;
+  cleanupResources();
+});
+// 新增:添加回话功能
+function addHuiHuaFn(){
+  newSession.value = true;
+  messages.value = [];
+  getAdSearchFn();
+}
+function getAdSearchFn(){
+  nextTick(()=>{
+    setTimeout(()=>{
+      messagesInfoDefaultRef.value.getAdSearchFn();
+    },50)
+  })
+}
+
+function authorizeRecord() { 
+    uni.authorize({
+    scope: 'scope.record',
+    success() {
+      // uni.getRecorderManager();
+    }
+  })
+}
+function aiStartChatFn(){ 
+  cleanupResources();
+  wsClient.value = new WSClient({
+    url: `${HTTP_REQUEST_URL_WS}/api/websocket`,
+    method: 'POST',
+    headers: {
+      "Authorization": 'Bearer '+appStore.token
+    }
+  });
+  // 注册SSE事件
+  registerEvents();
+  wsClient.value.open({type:0,message:inputText.value})
+}
+
+// 
+async function sendMessage({chatType,msgContent=""}){
+  console.log('sendMessage',wsClient.value);
+  // 登录检测
+  if(!await checkLoginShowModal())return;
+  // 今日免费提问次数检测
+  if(!await checkAiQuotaDailyModal())return;
+  if (!msgContent) {
+    Toast({title:'请输入内容'});
+    return;
+  }
+  isLoading.value = true
+  messages.value.push({
+    msgContent,
+    chatType,// 0 (文本),1 (图片)
+    speakerType:0//0用户消息1AI消息
+  });
+  messages.value.push({
+    msgContent: "",
+    event: "start",//sse长链接的返回状态
+    chatType,
+    speakerType:1,
+    messageTimeNow:dayjs().format('HH:mm')
+  });
+  //type  0 (文本),1 (图片)
+  wsClient.value.send({
+    type:chatType,
+    message:msgContent,
+    agentId:agentCheckRef.value.agentId,
+    useBalance:true,
+    newSession:newSession.value,
+    historySession:historySession.value
+  });
+  messagesKey.value++;
+  inputText.value = '';
+  newSession.value = false;
+  // 每次收到新消息时滚动到底部
+  // 如果是图片,子组件里图片加载成功后触发
+  if(chatType!=1)scrollToBottom();
+}
+async function uploadImage(){
+  if(!await checkLoginShowModal())return;
+  const res = await chooseImageOne();
+  console.log('uploadImage',res);
+  if(res){
+    // userInfo.value[key] = res.fileName
+    sendMessage({chatType:1,msgContent:res.data})
+  }
+}
+function cleanupResources(closeSSE=true) {
+  // 关闭SSE连接
+  if (wsClient.value) {
+    // 移除所有事件监听
+    if (wsClient.value.callbacks) {
+      Object.keys(wsClient.value.callbacks).forEach(event => {
+        wsClient.value.callbacks[event] = [];
+      });
+    }
+    wsClient.value.close('clean');
+    wsClient.value = null;
+  }
+}
+function registerEvents(){
+  wsClient.value.on('open', (data) => {
+    console.log('ws连接成功',data);
+  });
+  wsClient.value.on('answer', (data) => {
+    console.log('answer',data.segment,messages.value.length - 1);
+    isLoading.value = false;
+    const lastIndex = messages.value.length - 1;
+    // 保存完整内容(累加片段)
+    // const newFullAnswer = messages.value[lastIndex].msgContent + data.segment;
+    messages.value[lastIndex].msgContent = messages.value[lastIndex].msgContent + data.segment;
+    messagesKey.value++;
+    console.log('answer',messages);
+    // 每次收到新消息时滚动到底部
+    scrollToBottom();
+    nextTick(()=>{
+      // 获取用户信息
+      getUserInfo();
+    })
+  });
+  wsClient.value.on('error', (err) => {
+    isLoading.value = false;
+    console.log('error',err);
+    // aiStartChatFn();
+    Toast({ title: JSON.stringify(err) || "服务器异常" });
+  });
+  wsClient.value.on('close', (data) => {
+    isLoading.value = false;
+    let lastIndex = messages.value.length - 1;
+    console.log('close',data,lastIndex);
+    // 判断关闭原因,取消,删除当前聊天内容,超时提示请求超时
+    switch (data.reason) {
+      case 'timeout': {
+        // 提示超时
+        // uni.showToast({
+        //   title: '请求超时,请重试',
+        //   icon: 'none'
+        // });
+        if(lastIndex>-1)messages.value[lastIndex].msgContent = messages.value[lastIndex].msgContent || "请求超时,请重试";
+        aiStartChatFn();
+        break;
+      }
+      default:
+        break;
+    }
+  });
+}
+
+// 新增:滚动到底部的方法
+function scrollToBottom() {
+  nextTick(() => {
+    // if (scrollTimeout.value) return;
+    // scrollTimeout.value = setTimeout(() => {
+      uni.createSelectorQuery()
+      .select(`#msg-${messagesKey.value}`)
+      .boundingClientRect(rect => {
+        if (rect) {
+          scrollTop.value = rect.height;
+          // 使用更平滑的滚动方式
+          uni.pageScrollTo({
+            scrollTop: rect.bottom,
+            duration: 100
+          })
+        }
+      })
+      .exec();
+      // scrollTimeout.value = null;
+    // }, 80); // 延长节流间隔至80ms,减少冲突
+  });
+}
+
+/*******************************************历史数据********************************************************/ 
+
+const hitstoryParams = ref({
+  pageNum: 0,
+  pageSize: 10,
+  sessionId:appStore.sessionId,
+});
+// 重命名方法,避免与小程序生命周期冲突
+function handlePullDownRefresh() {
+  console.log('下拉刷新触发');
+  triggered.value = true;
+  hitstoryParams.value.pageNum++;
+  chatHistoryDetailsFn();
+}
+function chatHistoryDetailsFn(){
+  hitstoryParams.value.sessionId = appStore.sessionId;
+  chatHistoryDetails(hitstoryParams.value).then(res=>{ 
+    triggered.value = false;
+    console.log('chatHistoryFn',res);
+    const rows = res?.rows || [];
+    if(rows.length==0 && hitstoryParams.value.pageNum>0){
+      hitstoryParams.value.pageNum--;
+      // Toast({title:'没有更多历史记录了'});
+      return;
+    }
+    if(messages.value.length==res.total){
+      Toast({title:'没有更多历史记录了'});
+      return;
+    }
+    messages.value = [...rows, ...messages.value]
+  })
+}
+
+
+/*******************************************语音功能********************************************************/ 
+
+const isRecording = ref(false);// 是否正在录音
+const isCancel = ref(false);         // 是否取消录音
+const recordDuration = ref(0);       // 录音时长(秒)
+const tempFilePath = ref('');        // 录音临时文件路径
+const recordTimer = ref(null);       // 录音计时定时器
+const recorderManager = uni.getRecorderManager();  // 录音管理
+// 开始录音(触摸开始)
+const startRecord = async (e) => {
+  if(!await checkLoginShowModal())return;
+  // 防止冒泡导致的异常
+  e.stopPropagation();
+  
+  // 初始化录音参数
+  const options = {
+    format: 'mp3',       // 录音格式
+    sampleRate: 44100,   // 采样率
+    numberOfChannels: 1, // 声道数
+    encodeBitRate: 96000 // 编码比特率
+  };
+
+  // 开始录音
+  recorderManager.start(options);
+  isRecording.value = true;
+  isCancel.value = false;
+  recordDuration.value = 0;
+
+  // 计时逻辑
+  recordTimer.value = setInterval(() => {
+    recordDuration.value++;
+    // 限制最大录音时长(如60秒)
+    if (recordDuration.value >= 60) {
+      stopRecord();
+    }
+  }, 1000);
+
+  // 监听录音错误
+  recorderManager.onError((err) => {
+    console.error('录音错误:', err);
+    cancelRecord();
+    uni.showToast({ title: '录音失败', icon: 'none' });
+  });
+};
+
+// 停止录音(触摸结束)
+const stopRecord = () => {
+  if (!isRecording.value) return;
+
+  // 清除计时
+  clearInterval(recordTimer.value);
+  
+  // 停止录音
+  recorderManager.stop();
+  recorderManager.onStop((res) => {
+    tempFilePath.value = res.tempFilePath;
+    console.log('recorderManager',res.tempFilePath);
+    
+    // 判断是否取消或录音过短
+    if (isCancel.value) {
+      uni.showToast({ title: '已取消发送', icon: 'none' });
+    } else if (recordDuration.value < 1) {
+      uni.showToast({ title: '录音时间太短', icon: 'none' });
+    } else {
+      // 上传录音并添加到列表
+      uploadVoice(res.tempFilePath);
+    }
+    // 重置状态
+    resetRecordState();
+  });
+
+ 
+};
+
+// 处理触摸移动(用于判断是否取消)
+const handleTouchMove = (e) => {
+  if (!isRecording.value) return;
+
+  // 获取按钮位置和触摸位置
+  const buttonRect = uni.createSelectorQuery().select('.record-btn').boundingClientRect();
+  buttonRect.exec((rects) => {
+    const rect = rects[0];
+    if (!rect) return;
+
+    // 计算触摸点与按钮的垂直距离(向上移动超过50px视为取消)
+    const touchY = e.touches[0].clientY;
+    const buttonTop = rect.top;
+    if (touchY < buttonTop - 50) {
+      isCancel.value = true;
+    } else {
+      isCancel.value = false;
+    }
+  });
+};
+
+// 取消录音(触摸中断)
+const cancelRecord = () => {
+  if (!isRecording.value) return;
+  
+  clearInterval(recordTimer.value);
+  recorderManager.stop();
+  resetRecordState();
+  uni.showToast({ title: '已取消发送', icon: 'none' });
+};
+
+// 重置录音状态
+const resetRecordState = () => {
+  isRecording.value = false;
+  isCancel.value = false;
+  recordDuration.value = 0;
+  tempFilePath.value = '';
+};
+
+// 上传录音到服务器
+const uploadVoice = (filePath) => {
+  if (!filePath) return;
+
+  uni.showLoading({ title: '发送中...' });
+  
+  // 调用上传接口
+  uni.uploadFile({
+    url: `${HTTP_REQUEST_URL}/mini/chat/file/voiceUpload`, // 替换为你的后端接口
+    filePath,
+    name: 'file',        // 后端接收文件的参数名
+    formData: {
+      duration: recordDuration.value // 携带录音时长
+    },
+    method: 'POST',
+    header: {
+      "Authorization": appStore.token
+    },
+    success: (res) => {
+      console.log('上传结果:', res);
+      const result = JSON.parse(res.data);
+      if (result.code === 200) {
+        // 上传成功,添加到消息列表
+        sendMessage({ chatType:0,msgContent:result.data });
+        // messages.value.push({
+        //   id: Date.now(),
+        //   isMine: true,
+        //   avatar: '/static/avatar/user.png',
+        //   duration: recordDuration.value,
+        //   url: result.data.url, // 服务器返回的音频地址
+        //   isPlaying: false
+        // });
+      } else {
+        uni.showToast({ title: '发送失败', icon: 'none' });
+      }
+    },
+    fail: (err) => {
+      console.error('语音上传失败:', err);
+      uni.showToast({ title: '发送失败', icon: 'none' });
+    },
+    complete: () => {
+      uni.hideLoading();
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.mine_ybt_title{
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  z-index: 1;
+}
+/* 录音区域 */
+.record-btn{
+  flex: 1;
+  height: 70rpx;
+  line-height: 70rpx;
+  font-size: 30rpx;
+  color: #333;
+
+}
+.record-area {
+  padding: 30rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.record-btn {
+  flex: 1;
+  height: 70rpx;
+  line-height: 70rpx;
+  font-size: 30rpx;
+  color: #333;
+  background-color: #f2f2f2;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: none;
+}
+
+.record-btn.recording {
+  background-color: #ff4d4f;
+  color: #fff;
+}
+
+.record-btn.cancel {
+  background-color: #999;
+}
+/* 整体容器样式 */
+.chat-container {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  // padding-bottom: 200rpx;
+  /* background-color: #f5f5f5; */
+}
+
+/* 聊天消息区域样式 */
+.chat-messages {
+  flex: 1;
+  overflow-y: auto;
+  .scrollViewRef{
+    // height: 100%;
+     padding: 16rpx;
+     overflow-y: auto;
+  }
+  // height: calc(100vh - 200rpx);
+}
+
+
+
+/* 输入区域样式 */
+.input-area {
+  // position: fixed;
+  // left: 0;
+  // bottom: 0;
+  // width: 100%;
+  display: flex;
+  align-items: center;
+  background-color: #fff;
+  padding: 30rpx 40rpx;
+  border-top: 1rpx solid #e0e0e0;
+  position: relative;
+}
+.ai-tip{
+  position: absolute;
+  bottom: 5rpx;
+  width: calc(100% - 80rpx);
+  text-align: center;
+  font-size: 20rpx;
+  color: #999;
+}
+
+/* 图片图标样式 */
+.image-btn{
+  margin-right: 30rpx;
+  width: 40rpx;
+  height: 40rpx;
+  &[disabled]{
+    .image-icon{
+      opacity: 0.4;
+    }
+  }
+  .image-icon {
+    width: 100%;
+    height:100%;
+  }
+}
+
+/* 输入框样式 */
+.input-box {
+  flex: 1;
+  height: 70rpx;
+  font-size: 30rpx;
+  color: #333;
+  background-color: transparent;
+}
+
+/* 麦克风图标样式 */
+.isvoice-btn{
+  width: 40rpx;
+  height: 40rpx;
+  margin: 0 40rpx;
+  &[disabled]{
+    .mic-icon{
+      opacity: 0.4;
+    }
+  }
+  .mic-icon {
+    width: 100%;
+    height:100%;
+  }
+}
+
+/* 发送按钮样式 */
+.send-btn {
+  width: 60rpx;
+  height: 60rpx;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0;
+  &[disabled]{
+    .send-icon{
+      opacity: 0.4;
+    }
+  }
+}
+
+/* 发送图标样式 */
+.send-icon {
+  width: 100%;
+  height: 100%;
+}
+
+/* 录音提示 */
+.record-toast {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  width: 300rpx;
+  height: 300rpx;
+  border-radius: 20rpx;
+  background-color: rgba(0, 0, 0, 0.7);
+  color: #fff;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  z-index: 999;
+}
+
+.record-toast.cancel {
+  background-color: rgba(255, 77, 79, 0.8);
+}
+
+.toast-icon {
+  width: 200rpx;
+  height: 200rpx;
+  margin-bottom: 20rpx;
+}
+</style>

+ 60 - 0
jd_logistics-app/pages/ai/components/agentCheck.vue

@@ -0,0 +1,60 @@
+<template>
+ 	<view class="agentCheck">
+    <u-dropdown class="up-dropdown">
+      <u-dropdown-item v-model="agentId" @change="changeAgentId" :title="agentName" :options="agentList"></u-dropdown-item>
+    </u-dropdown>
+  </view>
+</template>
+<script setup>
+import { ref, computed } from "vue";
+import { useAppStore } from "@/stores/app";
+import { getAgentList } from "@/api/home.js";
+import { onLoad } from '@dcloudio/uni-app'
+const appStore = useAppStore();
+const agentId = ref('');
+const agentList = ref([]);
+defineExpose({
+  initAgentId,
+  agentId
+});
+
+//计算属性
+const agentName = computed(()=>{
+  return agentList.value.find(item=>item.value == agentId.value)?.label || '';
+})
+onLoad(()=>{
+  // agentListFn();
+});
+async function agentListFn(){
+	await getAgentList().then(res=>{
+		if(res.code == 200){
+      let rows = res.rows || [];
+			agentList.value = rows.map(item=>{
+        return {
+          label: item.agentName,
+          value: item.agentId
+        }
+      });
+		}
+	})
+}
+async function initAgentId(){
+  await agentListFn();
+  console.log('initAgentId',agentList.value,appStore.agentId);
+  agentId.value = appStore.agentId || agentList.value[0].value;
+  appStore.agentId = agentId.value;
+}
+function changeAgentId(){
+  console.log('changeAgentId',agentId.value);
+  appStore.agentId = agentId.value;
+  appStore.sessionId = '';
+}
+
+</script>
+<style lang="scss" scoped>
+.agentCheck{
+  width: 100vw;
+  position: relative;
+  z-index: 20;
+}
+</style>

+ 145 - 0
jd_logistics-app/pages/ai/components/messagesInfo.vue

@@ -0,0 +1,145 @@
+<template>
+<view class="messagesInfo">
+  <view 
+      v-for="(msg, index) in props.messages" 
+      :key="index" 
+      :class="['message-item', msg.speakerType==0? 'is-mine' : '']"
+    >
+      <image v-if="msg.speakerType==1"
+        src="/static/img/service/aijiqiren.png" 
+        class="message-avatar"
+        mode="aspectFill"
+      />
+      <view class="message-content">
+        <view class="typing-indicator" 
+        v-if="props.isLoading && msg.speakerType==1 && index== props.messages.length-1"
+        >
+          <view class="dot"></view>
+          <view class="dot"></view>
+          <view class="dot"></view>
+        </view>
+        <!-- 0用户消息1AI消息 -->
+        <view v-if="msg.speakerType==0">
+          <!-- 0 (文本),1 (图片) -->
+          <image v-if="msg.chatType==1"
+            :src="msg.msgContent" 
+            class="content-image"
+            mode="widthFix"
+            @load="onImageLoad"
+            @error="onImageLoad"
+            
+          />
+          <text v-else>{{ msg.msgContent }}</text>
+        </view>
+        <zero-markdown-view v-else
+          :markdown="msg.msgContent" 
+          themeColor="#000000" 
+          :aiMode='false' 
+        >
+        </zero-markdown-view>
+        <view v-if="msg.messageTime" class="gray font_size20">{{msg.messageTime}}</view>
+        <view v-else-if="msg.speakerType==1 && msg.messageTimeNow" class="gray font_size20 text_align_right">
+          {{props.isLoading && index== props.messages.length-1?'':msg.messageTimeNow}}
+        </view>
+      </view>
+      <image v-if="msg.speakerType==0"
+        :src="appStore?.userInfo?.userAvatar || appStore.logo || '/static/img/service/user-avatar.png'" 
+        class="message-avatar mine-avatar"
+        mode="aspectFill"
+      />
+    </view>
+</view>
+</template>
+<script setup>
+import { ref } from 'vue'
+import { useAppStore } from "@/stores/app";
+const appStore = useAppStore();
+const emit = defineEmits(['imageLoaded'])
+const props = defineProps({
+  messages: {
+    type: Array,
+    default: [],
+  },
+  isLoading: {
+    type: Boolean,
+    default: false,
+  }
+});
+function onImageLoad() {
+  emit('imageLoaded')
+}
+</script>
+<style lang="scss" scoped>
+.messagesInfo{
+  .content-image{
+    width: 200rpx;
+  }
+    /* 单个消息样式 */
+  .message-item {
+    display: flex;
+    align-items: flex-start;
+    margin-bottom: 16rpx;
+  }
+
+  /* 用户自己发送的消息样式 */
+  .is-mine {
+    justify-content: flex-end;
+  }
+
+  /* 头像样式 */
+  .message-avatar {
+    width: 60rpx;
+    height: 60rpx;
+    border-radius: 50%;
+    margin-right: 16rpx;
+    &.mine-avatar{
+      margin-left: 16rpx;
+      margin-right: 0;
+    }
+  }
+
+  /* 消息内容样式 */
+  .message-content {
+    max-width: 70%;
+    min-width: 100rpx;
+    padding: 16rpx;
+    border-radius: 16rpx;
+    background-color: #fff;
+    box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
+    position: relative;
+  }
+
+  /* 用户自己发送的消息内容样式 */
+  .is-mine.message-content {
+    background-color: #00c853;
+    color: #fff;
+  }
+    /* 打字指示器(加载动画) */
+  .typing-indicator {
+    // position: absolute;
+    // top: 20rpx;
+    // left: 20rpx;
+    display: flex;
+    align-items: center;
+    gap: 8rpx;
+    padding: 5rpx 0;
+  }
+  /* 加载动画关键帧 */
+  @keyframes typing {
+    0% { transform: scale(0); }
+    40% { transform: scale(1); }
+    80% { transform: scale(0); }
+    100% { transform: scale(0); }
+  }
+
+  /* 加载动画的点 */
+  .dot {
+    width: 12rpx;
+    height: 12rpx;
+    background-color: #666;
+    border-radius: 50%;
+    animation: typing 1.4s infinite ease-in-out both;
+  }
+
+}
+</style>

+ 72 - 0
jd_logistics-app/pages/ai/components/messagesInfoDefault.vue

@@ -0,0 +1,72 @@
+<template>
+ <view class=" messagesInfoDefault">
+  <view class="flex_1 flex-column-center">
+    <image 
+      src="/static/img/service/aijiqiren.png" 
+      class="service-avatar"
+      mode="widthFix"
+    />
+    <view class="bold font_size40 mt20">Hi~,我是财税小助手!</view>
+  </view>
+  <view class="padding30 border_radius_20 bg_color_fff mt20" v-if="adSearchList.length>0">
+    <view class="font_size30 bold">AI赋能,专业解答财税问题</view>
+    <view class="font_size25 mt20 padding20 bg_color_f5 border_radius_20"
+     @click="sendMessage(item.dictValue)"
+    v-for="(item,index) in adSearchList" :key="index">
+      #{{item.dictValue}}
+    </view>
+    <view class="flex-center mt20">
+      <view class="flex-center-between gray" @click="getAdSearchFn">
+        <img src="/static/img/shuaxin.png" alt="" class="mr20" style="width:40rpx;height:40rpx;"/>
+        <text>换一批</text>
+      </view>
+    </view>
+  </view>
+  <!-- <view class="gray mt20 font_size25 flex-center">( 下拉获取历史数据 )</view> -->
+</view>
+</template>
+<script setup>
+import { ref,watch,nextTick } from "vue";
+import { getAdSearch } from "@/api/home";
+import { useAppStore } from "@/stores/app";
+import { onLoad } from '@dcloudio/uni-app'
+const appStore = useAppStore();
+const adSearchList = ref([]);
+const emit = defineEmits(['sendMessage']);
+
+defineExpose({
+  getAdSearchFn
+});
+
+// watch(() => appStore.agentId, (state) => {
+//   nextTick(()=>{
+//     setTimeout(()=>{ 
+//       getAdSearchFn();
+//     },500)
+//   })
+// });
+
+function getAdSearchFn(){
+  getAdSearch(appStore.agentId).then(res=>{
+    if(res.code == 200){
+      adSearchList.value = res.data || [];
+    }
+  })
+}
+function sendMessage(msgContent){
+  emit('sendMessage',{chatType:0,msgContent});
+}
+
+</script>
+<style lang="scss" scoped>
+.messagesInfoDefault{
+  position: fixed;
+  width: 100%;
+  top: 40rpx;
+  left: 0;
+  padding: 30rpx;
+  .service-avatar{
+    width: 200rpx;
+  }
+}
+</style>

+ 37 - 0
jd_logistics-app/pages/ai/components/tools.vue

@@ -0,0 +1,37 @@
+<template>
+ 	<view class="bg_color_fff tools flex-center-between">
+    <view class="font_size25 nowrap">今日次数 <text class="color_price">{{appStore.userInfo?.aiQuotaDaily}}</text> 次</view>
+    <view class="font_size25 nowrap">余额 <text class="color_price">{{appStore.userInfo?.rechargeBalance}}</text> {{appStore.moneyUnit}}</view>
+    <view>
+      <image src="/static/img/wenhua.png" mode="" class="mr20 tool-icon" @click="tohistoryList"/>
+      <image src="/static/img/addHuiHua.png" mode="" class="mr20 ml20 tool-icon" @click="addHuiHuaFn"/>
+    </view>
+  </view>
+</template>
+<script setup>
+import { ref } from "vue";
+import { useAppStore } from "@/stores/app";
+import { onShow} from '@dcloudio/uni-app'
+const appStore = useAppStore();
+const emit = defineEmits(['addHuiHuaFn'])
+// 新增:添加回话功能
+function addHuiHuaFn(){
+  appStore.sessionId = '';
+  emit('addHuiHuaFn');
+}
+function tohistoryList(){
+  uni.navigateTo({
+    url: '/pages/historyList/historyList',
+  })
+}
+
+</script>
+<style lang="scss" scoped>
+.tools{
+  padding: 0 20rpx 20rpx;
+  .tool-icon{
+    width: 50rpx;
+    height: 50rpx;
+  }
+}
+</style>

+ 156 - 0
jd_logistics-app/pages/historyList/historyList.vue

@@ -0,0 +1,156 @@
+<template>
+<view class="historyList padding30">
+  <z-paging
+    ref="pagingRef"
+    class="paginng-contaner"
+    :default-page-size="20"
+    :use-refresher-status-bar-placeholder="true"
+    v-model="list"
+    @query="handleQuery"
+  >
+		<view class="bg_color_fff padding20 border_radius_20">
+			<u-search placeholder="查找对话内容" v-model="keyword" 
+      @search="reloadList" @custom="reloadList" @clear="reloadList"
+      :showAction="false" borderColor="#ffffff"></u-search>
+		</view>
+    <view class="padding20" v-for="group in groupedList" :key="group.date">
+      <view>{{group.date}}</view>
+      <view class="flex-between padding20 bg_color_fff border_radius_20 mt10" 
+      v-for="message in group.messages" :key="message.sessionId">
+        <view class="payment-radio  mr20" @click="checkboxChange(message.sessionId)">
+            <view
+						class="radio-circle"
+						:class="{ checked: selected.includes(message.sessionId) }"
+					></view>
+				</view>
+        <image src="/static/img/wenhua.png" class="mr20" mode="" style="width: 40rpx;height: 40rpx;"/>
+        <view class="flex_1 mr20" @click="add(message.sessionId)">{{message.firstMessageContent}}</view>
+        <text class="gray font_size20">{{message.HS}}</text>
+      </view>
+    </view>
+    <view class="footplaceholder"></view>
+     <!-- foot -->
+    <view class="foot bg_color_fff flex-center-between">
+			<view class="order_btn paddingTB20 flex_1 text_align_center mr20 plain" @click="del">删除</view>
+			<view class="order_btn paddingTB20 flex_1 text_align_center" @click="add">新增会话</view>
+		</view>
+  </z-paging>
+</view>
+</template>
+<script setup> 
+import { ref, computed } from 'vue'
+import dayjs from 'dayjs'
+import { chatHistoryList, delChatHistoryList } from '@/api/ai'
+import { useAppStore } from '@/stores/app'
+const appStore = useAppStore();
+
+const pagingRef = ref();
+const keyword = ref('');
+const list = ref([]);
+const selected = ref([]);
+
+function checkboxChange(sessionId){
+  if(selected.value.includes(sessionId)){
+    selected.value = selected.value.filter(item => item !== sessionId);
+  }else{
+    selected.value.push(sessionId);
+  }
+}
+function del(){
+  if(selected.value.length==0){
+    uni.showToast({
+      title: '请选择要删除的会话',
+      icon: 'none'
+    });
+    return;
+  }
+  uni.showModal({
+    title: '提示',
+    content: '确定要删除吗?',
+    success: function (res) {
+      if (res.confirm) {
+        delChatHistoryList(selected.value).then(res => {
+          if(res.code == 200){
+            uni.showToast({
+              title: '删除成功',
+              icon: 'success'
+            });
+            selected.value = [];
+            reloadList();
+          }
+        })
+      } else if (res.cancel) {
+        console.log('用户点击取消');
+      }
+    }
+  });
+}
+//跳转ai页面
+function add(sessionId){
+  if(sessionId) appStore.sessionId = sessionId;
+  uni.switchTab({
+    url: '/pages/ai/ai'
+  });
+}
+function reloadList(item) {
+  pagingRef.value.reload();
+}
+// 下拉刷新和滚动底部会自动触发此方法
+async function handleQuery(page, pageSize, from) {
+  try {
+    const params = {
+      pageNum: page,
+      pageSize,
+			agentId:appStore.agentId,
+    };
+    const { rows } = await chatHistoryList(params);
+    pagingRef.value.complete(rows);
+  } catch (e) {
+		console.log('msg-comment',e)
+    pagingRef.value.complete(false);
+  }
+}
+const groupedList = computed(() => {
+  const groups = {};
+  
+  list.value.forEach(message => {
+    const date = dayjs(message.firstMessageTime);
+    const today = dayjs().startOf('day');
+    const yesterday = today.subtract(1, 'day');
+    message.HS=date.format('HH:mm');
+    
+    let groupKey;
+    if (date.isSame(today, 'day')) {
+      groupKey = '今天';
+    } else if (date.isSame(yesterday, 'day')) {
+      groupKey = '昨天';
+    } else {
+      groupKey = date.format('YYYY-MM-DD');
+    }
+    
+    if (!groups[groupKey]) {
+      groups[groupKey] = [];
+    }
+    groups[groupKey].push(message);
+  });
+  
+  // 转换并排序
+  return Object.keys(groups)
+    .map(key => ({
+      date: key,
+      messages: groups[key]
+    }))
+    .sort((a, b) => {
+      // 按日期倒序排列
+      if (a.date === '今天') return -1;
+      if (b.date === '今天') return 1;
+      if (a.date === '昨天') return -1;
+      if (b.date === '昨天') return 1;
+      return new Date(b.date) - new Date(a.date);
+    });
+});
+</script>
+<style lang="less" scoped>
+.historyList{
+}
+</style>

+ 165 - 0
jd_logistics-app/pages/index/components/PersonalExpressDialog.vue

@@ -0,0 +1,165 @@
+<template>
+	<!-- 使用 u-popup 组件 -->
+	<u-popup :show="visible" mode="bottom" :round="30" :closeable="false" :closeOnClickOverlay="true"
+		@close="handleClose">
+		<view class="popup-content">
+			<!-- 标题 -->
+			<view class="popup-header">
+				<text class="popup-title">个人寄件</text>
+			</view>
+
+			<!-- 物流选项 -->
+			<view class="express-options">
+				<!-- 顺丰选项 -->
+				<view class="express-option sf-option" :class="{ 'selected': selectedExpress === '顺丰' }"
+					@click="selectExpress('顺丰')">
+					<image class="option-icon" src="/static/img/icon-logo-sf.png"
+						mode="aspectFit" />
+					<text class="option-text">顺丰物流</text>
+					
+				</view>
+
+				<!-- 京东选项 -->
+				<view class="express-option jd-option" :class="{ 'selected': selectedExpress === '京东' }"
+					@click="selectExpress('京东')">
+					<image class="option-icon" src="/static/img/icon-logo-jd.png"
+						mode="aspectFit" />
+					<text class="option-text">京东物流</text>
+				</view>
+			</view>
+
+			<!-- 取消按钮 -->
+			<view class="popup-footer">
+				<button class="cancel-btn" @click="handleClose">取消</button>
+			</view>
+		</view>
+	</u-popup>
+</template>
+
+<script setup>
+	import {
+		ref
+	} from 'vue'
+
+	const props = defineProps({
+		visible: {
+			type: Boolean,
+			default: false
+		}
+	})
+
+	const emit = defineEmits(['update:visible', 'select'])
+
+	const selectedExpress = ref('')
+
+	const selectExpress = (company) => {
+		selectedExpress.value = company
+
+		// 延时关闭并传递选择结果
+		setTimeout(() => {
+			emit('select', company)
+			emit('update:visible', false)
+			selectedExpress.value = ''
+		}, 300)
+	}
+
+	const handleClose = () => {
+		selectedExpress.value = ''
+		emit('update:visible', false)
+	}
+</script>
+
+<style lang="scss" scoped>
+	.popup-content {
+		padding: 32rpx 16rpx 0rpx 16rpx;
+		background-color: #fff;
+		border-radius: 40rpx 40rpx 0rpx 0rpx;
+	}
+
+	.popup-header {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		margin-bottom: 46rpx;
+	}
+
+	.popup-title {
+		height: 52rpx;
+		line-height: 52rpx;
+		font-size: 36rpx;
+		font-weight: bold;
+		color: #333;
+	}
+
+
+	.express-options {
+		height: 204rpx;
+		display: flex;
+		justify-content: space-around;
+	}
+
+	.express-option {
+		width: 200rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+
+		&.selected {
+			width: 200rpx;
+			height: 204rpx;
+			background: #E9F0FF;
+			border-radius: 32rpx;
+			border: 2rpx solid #C1D5FF;
+		}
+		
+		
+		.option-icon {
+			width: 88rpx;
+			height: 88rpx;
+			margin-bottom: 8rpx;
+		}
+		
+		.option-text {
+			font-size: 28rpx;
+			font-weight: 500;
+			color: #333;
+		}
+	}
+
+
+	.popup-footer {
+		margin-top: 44rpx;
+		
+		
+		.cancel-btn {
+			width: 100%;
+			height: 88rpx;
+			background: #E9F0FF;
+			border-radius: 44rpx;
+			font-weight: 400;
+			font-size: 32rpx;
+			color: #2361FF;
+			line-height: 88rpx;
+			text-align: center;
+			font-style: normal;
+			text-transform: none;
+		
+		}
+	}
+
+
+	@keyframes popIn {
+		0% {
+			transform: scale(0);
+		}
+
+		70% {
+			transform: scale(1.2);
+		}
+
+		100% {
+			transform: scale(1);
+		}
+	}
+</style>

+ 273 - 0
jd_logistics-app/pages/index/index.vue

@@ -0,0 +1,273 @@
+<template>
+	<view class="container">
+		<!-- 上半部分:轮播图区域 -->
+		<view class="top-section">
+			<swiper class="swiper" 
+				:indicator-dots="true" 
+				:autoplay="true" 
+				:interval="3000" 
+				:duration="1000" 
+				:circular="true"
+				indicator-active-color="#1B64F0"
+				indicator-color="rgba(255, 255, 255, 0.6)"
+				indicator-class="swiper-indicator"
+				active-class="swiper-indicator-active">
+				<swiper-item v-for="(item, index) in swiperList" :key="index">
+					<view class="swiper-item">
+						<image class="swiper-img" :src="item.imageUrl" mode="aspectFill" />
+					</view>
+				</swiper-item>
+			</swiper>
+		</view>
+		
+		<view class="btn-container">
+			<view class="btn-item" @click="handleExpress('2')">
+				<image class="button-icon" src="/static/img/index-time.png" />
+				<view class="button-right">
+					<view class="button-title">瑞鲸速达(顺丰)</view>
+					<view class="button-desc">一小时下单取件</view>
+				</view>
+				
+			</view>
+			<view class="btn-item" @click="handleExpress('1')">
+				<image class="button-icon" src="/static/img/index-un-time.png" />
+				<view class="button-right">
+					<view class="button-title">瑞鲸速达(京东)</view>
+					<view class="button-desc">下单当日取件</view>
+				</view>
+				
+			</view>
+			<view class="btn-item" @click="showExpressDialog">
+				<image class="button-icon" src="/static/img/index-personal.png" />
+				<view class="button-right">
+					<view class="button-title">个人寄件</view>
+					<view class="button-desc">支持顺丰和京东</view>
+				</view>
+				
+			</view>
+			
+		</view>
+
+		<!-- 使用 u-popup 弹框组件 -->
+		<PersonalExpressDialog :visible="showDialog" @update:visible="showDialog = $event"
+			@select="handleExpressSelect" />
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,onMounted
+	} from 'vue'
+	// 导入 u-popup 弹框组件
+	import PersonalExpressDialog from './components/PersonalExpressDialog.vue'
+	import { bannerList } from '../../api/user'
+
+	const showDialog = ref(false)
+
+	// 轮播图数据
+	const swiperList = ref([])
+	
+	onMounted(()=>{
+		getBannerList()
+	})
+	
+	const getBannerList = ()=>{
+		bannerList().then(res=>{
+			if(res.code == 200){
+				swiperList.value = res.data
+			}
+		},{})
+	}
+
+	const showExpressDialog = () => {
+		console.log('显示个人寄件弹框')
+		showDialog.value = true
+	}
+
+	const handleExpressSelect = (company) => {
+		uni.showToast({
+			title: `已选择${company}物流`,
+			icon: 'success',
+			duration: 1500
+		})
+
+		// 模拟跳转到下单页面
+		setTimeout(() => {
+			uni.showLoading({
+				title: '正在跳转...'
+			})
+
+			setTimeout(() => {
+				uni.hideLoading()
+				// 实际跳转代码
+				// uni.navigateTo({ 
+				//   url: `/pages/order/create?company=${company}` 
+				// })
+			}, 800)
+		}, 500)
+	}
+
+	const handleExpress = (company) => {
+	  uni.navigateTo({ 
+		    url: `/pages/order/create_order?product=${company}` 
+		  })
+		
+		// 实际跳转代码
+		// setTimeout(() => {
+		//   uni.navigateTo({ 
+		//     url: `/pages/order/create?company=${company}` 
+		//   })
+		// }, 1500)
+	}
+</script>
+
+<style lang="scss" scoped>
+	.container {
+		display: flex;
+		flex-direction: column;
+		height: 100vh;
+		background-color: #F5F7FA;
+	}
+
+	.top-section {
+		height: 563rpx;
+		position: relative;
+	}
+
+	.swiper {
+		width: 100%;
+		height: 100%;
+		position: relative;
+	}
+
+	.swiper-item {
+		width: 100%;
+		height: 100%;
+		position: relative;
+	}
+
+	.swiper-img {
+		width: 100%;
+		height: 100%;
+		object-fit: cover;
+	}
+
+	/* 自定义指示点样式 - 通过定位调整位置 */
+	/* 方法一:调整整个指示器容器的位置 */
+	/* 注意:在不同平台可能需要使用不同的选择器 */
+	/* 微信小程序 */
+	::v-deep .wx-swiper-dots {
+		bottom: 80rpx !important; /* 调整指示器容器的位置 */
+		display: flex !important;
+		justify-content: center !important;
+		align-items: center !important;
+	}
+	
+	/* H5平台 */
+	::v-deep .uni-swiper-dots {
+		bottom: 80rpx !important; /* 调整指示器容器的位置 */
+		display: flex !important;
+		justify-content: center !important;
+		align-items: center !important;
+	}
+
+	/* 方法二:直接修改指示点样式,通过调整父容器样式 */
+	.swiper-indicator {
+		width: 8rpx !important;
+		height: 8rpx !important;
+		border-radius: 50% !important;
+		background: rgba(255, 255, 255, 0.6) !important;
+		margin: 0 4rpx !important;
+	}
+	
+	.swiper-indicator-active {
+		width: 32rpx !important;
+		height: 8rpx !important;
+		background: #1B64F0 !important;
+		border-radius: 4rpx !important;
+	}
+
+	/* 方法三:如果上述方法都不生效,可以使用绝对定位自定义指示器 */
+	.custom-indicator {
+		position: absolute;
+		left: 0;
+		right: 0;
+		bottom: 80rpx; /* 调整指示器的垂直位置 */
+		z-index: 10;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+	
+	.custom-indicator-dot {
+		width: 8rpx;
+		height: 8rpx;
+		border-radius: 50%;
+		background: rgba(255, 255, 255, 0.6);
+		margin: 0 4rpx;
+		transition: all 0.3s ease;
+	}
+	
+	.custom-indicator-dot.active {
+		width: 32rpx;
+		height: 8rpx;
+		background: #1B64F0;
+		border-radius: 4rpx;
+	}
+	
+	.btn-container{
+			display: flex;
+			flex-wrap: wrap;
+			justify-content: space-between;
+			position: relative;
+			top: -40rpx;
+			padding: 0rpx 20rpx;
+		
+		.btn-item{
+			width: 339rpx;
+			height: 172rpx;
+			background: #FFFFFF;
+			box-shadow: 0rpx 4rpx 16rpx 0rpx rgba(27,100,240,0.08), 0rpx 0rpx 8rpx 0rpx rgba(27,100,240,0.08);
+			border-radius: 32rpx;
+			border: 2rpx solid #FFFFFF;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			padding: 20rpx 0rpx 20rpx 20rpx;
+			margin-bottom: 32rpx;
+			
+			.button-icon{
+				width: 88rpx;
+				height: 88rpx;
+			}
+			
+			.button-right{
+				display: flex;
+				flex-direction: column;
+				flex: 1;
+				margin-left: 16rpx;
+				
+				.button-title {
+					height: 48rpx;
+					line-height: 48rpx;
+					font-size: 28rpx;
+					font-weight: bold;
+					color: #333;
+					flex-shrink: 0;
+				}
+				
+				.button-desc {
+					height: 44rpx;
+					line-height: 44rpx;
+					font-size: 24rpx;
+					color: #666;
+					margin-top: 8rpx;
+				}
+			}
+		}
+		
+		
+	}
+
+	
+</style>

+ 146 - 0
jd_logistics-app/pages/index111/index.vue

@@ -0,0 +1,146 @@
+<template>
+	<view class="content padding30">
+		<view class="bg_color_fff padding20 border_radius_20" @click="to_service_search">
+			<u-search placeholder="输入你想知道的事" v-model="keyword" 
+			@search="toAi({msgContent:keyword})" 
+			@custom="toAi({msgContent:keyword})"
+			:showAction="false" borderColor="#ffffff"></u-search>
+		</view>
+		<swiper class="swiper_list bg_color_fff border_radius_20 mt20" circular :indicator-dots="true" :autoplay="true" indicator-active-color="#ffffff">
+			<swiper-item v-for="(item, index) in swiperList" :key="index" class="swiper_item border_radius_20"
+			@click="toWebView(item)"
+			>
+				<image :src="HTTP_ADMIN_URL+item.dictValue" mode="" class="swiper_img border_radius_20"></image>
+			</swiper-item>
+		</swiper>
+		<!-- 财智工具箱 -->
+		<view class="mt20 bg_color_fff border_radius_20">
+			<view class="bold font_size30 padding20">财智工具箱</view>
+			<view class="grid-container padding20">
+				<view class="border_radius_20" 
+				@click="toAi({agentId:item.agentId})"
+				v-for="(item, index) in agentList" :key="index">
+					<image :src="HTTP_ADMIN_URL+item.imageUrl" class="item-img"></image>
+					<view class="item-content">
+						<view class="font_size30 bold title text-ellipsis">{{item.agentName}}</view>
+						<view class="font_size20 gray mt10 desc text-ellipsis">{{item.agentDesc}}</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<!-- 常见问题 -->
+		<view class="mt20 bg_color_fff border_radius_20">
+			<view class="bold font_size30 padding20">常见问题</view>
+			<view class="padding20 flex-center-between border-bottom" 
+			@click="toAi({agentId:item.cssClass*1,msgContent:item.dictValue})"
+			v-for="(item, index) in adSearchList" :key="index">
+				<text class="flex_1 mr20">#{{item.dictValue}}</text>
+				<image src="/static/img/arrow-right.png" mode="widthFix" class="menu_img"></image>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { adList, getAgentList, getAdSearch } from "@/api/home.js";
+import { HTTP_ADMIN_URL } from "@/config/app.js";
+import { onLoad, onShareAppMessage} from '@dcloudio/uni-app'
+onShareAppMessage((res) => {
+  return appStore.onShareAppMessageObj
+})
+import { useAppStore } from "@/stores/app";
+const appStore = useAppStore();
+const keyword = ref('');
+const swiperList = ref([]);
+const agentList = ref([]);
+const adSearchList = ref([]);
+
+onLoad(()=>{
+	console.log('index onLoad');
+	adListFn();
+	agentListFn();
+	getAdSearchFn();
+});
+
+function toWebView({targetPath,dictCode}){
+	if(targetPath){
+		uni.navigateTo({
+			url: '/pages/webView/webView?url='+encodeURIComponent(url)
+		});
+	}else{
+		uni.navigateTo({
+			url: '/pages/policy/ad_detail?dictCode='+dictCode
+		});
+	}
+}
+function toAi({agentId='', msgContent=''}){
+	if(agentId) appStore.UPDATE_agentId(agentId);
+	if(msgContent)appStore.UPDATE_msgContent(msgContent);
+	uni.switchTab({
+		url: '/pages/ai/ai'
+	});
+}
+//获取轮播图
+function adListFn(){
+	adList().then(res=>{
+		if(res.code == 200){
+			swiperList.value = res.data || [];
+		}
+	})
+}
+//获取智能体列表
+function agentListFn(){
+	getAgentList().then(res=>{
+		if(res.code == 200){
+			agentList.value = res.rows || [];
+		}
+	})
+}
+// 搜索常用问题
+function getAdSearchFn(){
+  getAdSearch().then(res=>{
+    if(res.code == 200){
+      adSearchList.value = res.data || [];
+    }
+  })
+}
+
+</script>
+
+<style scoped lang="scss">
+	.content{
+		/* 轮播 */
+		.swiper_list{
+			height: 350rpx;
+			overflow: visible;
+			.swiper_item{
+				height: fit-content !important;
+				.swiper_img{
+					width: 100%;
+					height: 350rpx;
+				}
+			}
+		}
+		.grid-container{
+			.item-img{
+				width: 100%;
+				height: 200rpx;
+				object-fit: cover;
+				object-position: center;
+				border-radius: 20rpx 20rpx 0 0;
+			}
+			.title, .desc {
+				display: -webkit-box; /* 将对象作为弹性伸缩盒子模型显示 ,适用于webkit内核浏览器 */
+				-webkit-box-orient: vertical; /* 设置或检索伸缩盒对象的子元素的排列方式 为垂直排列 */
+				-webkit-line-clamp: 1; /* 显示的行数,这里设置为2行 */
+				overflow: hidden; /* 隐藏超出的内容 */
+			}
+		}
+		.menu_img{
+			width: 50rpx;
+			height: 50rpx;
+		}
+	}
+
+</style>

+ 369 - 0
jd_logistics-app/pages/logistics/index.vue

@@ -0,0 +1,369 @@
+<template>
+	<view class="logistics-container">
+		<!-- 头部快递信息 -->
+		<view class="logistics-header">
+			<image class="logo" src="/static/img/icon-logo-jd.png"></image>
+			<view class="company-info">
+				<text class="company-name">京东物流</text>
+				<view class="tracking-number">
+					<text class="number">JDVA40141037033</text>
+					<text class="copy-btn" @click="copyTrackingNumber">复制</text>
+				</view>
+			</view>
+		</view>
+
+		<!-- 物流轨迹时间轴 -->
+		<view class="timeline-container">
+			<TimelineItem v-for="(item, index) in trackList" :key="index" :title="item.title" :desc="item.desc"
+				:time="item.time" :is-active="item.isActive" :show-line="index < trackList.length - 1"
+				:show-dot-bg="index === 0" />
+		</view>
+
+	
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		onMounted
+	} from 'vue'
+	import TimelineItem from '@/components/TimelineItem.vue'
+
+	const scrollHeight = ref(400)
+
+	// 模拟物流轨迹数据
+	const trackList = ref([{
+			title: '已代收',
+			desc: '您的快件已由[门卫]代收,快递员:马新宽、联系...',
+			time: '2026-01-11 17:32:32',
+			isActive: true
+		},
+		{
+			title: '派送中',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '运输中',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '运输中',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '运输中',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿站】...',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		}
+	])
+
+	onMounted(() => {
+		// 计算滚动区域高度
+		uni.getSystemInfo({
+			success: (res) => {
+				scrollHeight.value = res.windowHeight - 420 // 减去头部、当前状态、底部等固定高度
+			}
+		})
+	})
+
+	const copyTrackingNumber = () => {
+		uni.setClipboardData({
+			data: 'JDVA40141037033',
+			success: () => {
+				uni.showToast({
+					title: '已复制运单号',
+					icon: 'success'
+				})
+			}
+		})
+	}
+
+	const contactCourier = () => {
+		uni.showModal({
+			title: '联系快递员',
+			content: '拨打快递员电话?',
+			success: (res) => {
+				if (res.confirm) {
+					uni.makePhoneCall({
+						phoneNumber: '请填写快递员电话'
+					})
+				}
+			}
+		})
+	}
+
+	const viewDetails = () => {
+		uni.showToast({
+			title: '查看详情',
+			icon: 'none'
+		})
+	}
+
+	const copyAllInfo = () => {
+		const allInfo =
+			`京东物流\n运单号:JDVA40141037033\n状态:已代收\n快递员:马新宽\n\n物流轨迹:\n2026-01-11 17:32:32 已代收\n2026-01-11 17:32:32 派送中\n2026-01-11 17:32:32 运输中\n2026-01-11 17:32:32 已揽件`
+
+		uni.setClipboardData({
+			data: allInfo,
+			success: () => {
+				uni.showToast({
+					title: '已复制全部信息',
+					icon: 'success'
+				})
+			}
+		})
+	}
+</script>
+
+<style lang="scss" scoped>
+	.logistics-container {
+		padding: 20rpx;
+		background-color: #f5f5f5;
+		min-height: 100vh;
+	}
+
+	// 头部样式
+	.logistics-header {
+		height: 140rpx;
+		background: #FFFFFF;
+		border-radius: 32rpx;
+		padding: 20rpx;
+		display: flex;
+
+		.logo {
+			width: 100rpx;
+			height: 100rpx;
+		}
+	}
+
+	.company-info {
+		margin-left: 20rpx;
+
+		.company-name {
+			font-size: 32rpx;
+			height: 48rpx;
+			line-height: 48rpx;
+			font-weight: bold;
+			display: block;
+			margin-bottom: 8rpx;
+		}
+
+		.tracking-number {
+			height: 44rpx;
+			display: flex;
+			align-items: center;
+
+			.number {
+				height: 44rpx;
+				font-weight: 400;
+				line-height: 44rpx;
+				font-size: 28rpx;
+				color: #666;
+			}
+
+			.copy-btn {
+				height: 44rpx;
+				font-weight: 400;
+				font-size: 28rpx;
+				color: #1B64F0;
+				margin-left: 8rpx;
+				line-height: 44rpx;
+				text-align: center;
+			}
+		}
+	}
+
+
+	// 当前状态样式
+	.current-status {
+		background-color: #fff;
+		border-radius: 16rpx;
+		padding: 30rpx;
+		margin-bottom: 20rpx;
+		display: flex;
+		align-items: flex-start;
+		box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
+	}
+
+	.status-icon {
+		width: 80rpx;
+		height: 80rpx;
+		background: #1aad19;
+		border-radius: 50%;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		margin-right: 20rpx;
+
+		.icon {
+			color: #fff;
+			font-size: 40rpx;
+			font-weight: bold;
+		}
+	}
+
+	.status-info {
+		flex: 1;
+
+		.status-text {
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333;
+			display: block;
+			margin-bottom: 10rpx;
+		}
+
+		.status-desc {
+			font-size: 26rpx;
+			color: #666;
+			display: block;
+			margin-bottom: 15rpx;
+			line-height: 1.4;
+		}
+
+		.courier-info {
+			background: #f8f8f8;
+			border-radius: 12rpx;
+			padding: 15rpx;
+			margin-bottom: 15rpx;
+
+			.courier-text {
+				font-size: 26rpx;
+				color: #333;
+				display: block;
+				margin-bottom: 5rpx;
+			}
+
+			.contact-text {
+				font-size: 24rpx;
+				color: #1aad19;
+			}
+		}
+
+		.status-time {
+			font-size: 24rpx;
+			color: #999;
+			display: block;
+		}
+	}
+
+	// 时间轴容器
+	.timeline-container {
+		margin-top: 20rpx;
+		background-color: #fff;
+		border-radius: 32rpx;
+		margin-bottom: 20rpx;
+		padding: 20rpx;
+	}
+
+</style>

+ 602 - 0
jd_logistics-app/pages/mine/mine.vue

@@ -0,0 +1,602 @@
+<!-- pages/mine/mine.vue -->
+<template>
+	<view class="mine-container">
+		<!-- 顶部用户信息区域 -->
+		<view class="user-header ">
+			<headerInfo title="个人中心"></headerInfo>
+			<view class="user-info-section">
+				<view class="avatar-section">
+					<u-avatar 
+						@click="toUser"
+						size="144rpx"
+						shape="circle"
+						:src="userAvatar"
+						mode="aspectFill"
+						:show-level="false"
+					></u-avatar>
+					<view class="user-text-info">
+						<view class="user-name-section">
+							<view v-if="isLoggedIn">
+								<view class="name-section">
+									<view class="user-name" @click="toUser">
+										{{ displayName }}
+									</view>
+									<view class="department-badge">
+										储运部
+									</view>
+								</view>
+								
+								<view class="user-account">
+									账号:{{ userAccount }}
+								</view>
+							</view>
+							<button v-else
+								class="login-button"
+								open-type="getPhoneNumber"
+								@getphonenumber="handleGetPhoneNumber"
+								:loading="isLogging"
+								:disabled="isLogging || isProcessing"
+							>
+								{{ loginButtonText }}
+							</button>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<!-- 菜单功能区域 -->
+		<view class="menu-section">
+			<view class="menu-card">
+				<!-- 订单列表 -->
+				<view class="menu-item" @click="toOrderList">
+					<view class="menu-item-left">
+						<image src="/static/img/mine/icon-mine-order.png" class="menu-icon"></image>
+						<text class="menu-text">订单列表</text>
+					</view>
+					<image src="/static/img/arrow-right.png" class="arrow-icon"></image>
+				</view>
+
+				<!-- 地址簿 -->
+				<view class="menu-item" @click="toAddressBook">
+					<view class="menu-item-left">
+						<image src="/static/img/mine/icon-mine-address.png" class="menu-icon"></image>
+						<text class="menu-text">地址簿</text>
+					</view>
+					<image src="/static/img/arrow-right.png" class="arrow-icon"></image>
+				</view>
+				
+				<!-- 到付月结码 -->
+				<view class="menu-item" @click="toSettlementCode">
+					<view class="menu-item-left">
+						<image src="/static/img/mine/icon-mine-qr.png" class="menu-icon"></image>
+						<text class="menu-text">到付月结码</text>
+					</view>
+					<image src="/static/img/arrow-right.png" class="arrow-icon"></image>
+				</view>
+
+				<!-- 联系客服 -->
+				<view class="menu-item" @click="makePhoneCall">
+					<view class="menu-item-left">
+						<image src="/static/img/mine/icon-mine-server.png" class="menu-icon"></image>
+						<text class="menu-text">联系客服</text>
+					</view>
+					<image src="/static/img/arrow-right.png" class="arrow-icon"></image>
+				</view>
+
+				<!-- 隐私政策 -->
+				<view class="menu-item" @click="toPrivacyPolicy">
+					<view class="menu-item-left">
+						<image src="/static/img/mine/icon-mine-policy.png" class="menu-icon"></image>
+						<text class="menu-text">隐私政策</text>
+					</view>
+					<image src="/static/img/arrow-right.png" class="arrow-icon"></image>
+				</view>
+
+				<!-- 关于我们 -->
+				<view class="menu-item" @click="toAboutUs">
+					<view class="menu-item-left">
+						<image src="/static/img/mine/icon-mine-about.png" class="menu-icon"></image>
+						<text class="menu-text">关于我们</text>
+					</view>
+					<image src="/static/img/arrow-right.png" class="arrow-icon"></image>
+				</view>
+
+				<!-- 退出登录(仅登录后显示) -->
+				<view 
+					class="menu-item logout-item" 
+					v-if="isLoggedIn"
+					@click="userLogoutFn">
+					<text class="menu-text logout-text">退出登录</text>
+				</view>
+			</view>
+		</view>
+		
+		<!-- 加载提示 -->
+		<u-loading-page :loading="pageLoading" bg-color="transparent"></u-loading-page>
+	</view>
+</template>
+
+<script setup>
+import { ref, computed, onMounted } from "vue";
+import headerInfo from "@/components/headerInfo.vue";
+import { userLogout } from "@/api/user.js";
+import { getAdServicePhone } from "@/api/home.js";
+import { checkLoginShowModal, quickLogin } from "@/utils/util.js";
+import { onLoad, onShow, onShareAppMessage } from '@dcloudio/uni-app'
+import { useAppStore } from "@/stores/app";
+
+const appStore = useAppStore();
+
+// 响应式数据
+const isLogging = ref(false);
+const isProcessing = ref(false);
+const pageLoading = ref(false);
+const phoneNumber = ref('');
+
+// 计算属性
+const isLoggedIn = computed(() => {
+	return !!(appStore.userInfo?.phonenumber && appStore.token);
+});
+
+const userAvatar = computed(() => {
+	return appStore.userInfo?.avatar || '/static/img/default-avatar.png';
+});
+
+const displayName = computed(() => {
+	return appStore.userInfo?.nickName || appStore.userInfo?.userName;
+});
+
+const userAccount = computed(() => {
+	return appStore.userInfo?.phonenumber || '';
+});
+
+const loginButtonText = computed(() => {
+	if (isLogging.value) return '登录中...';
+	if (isProcessing.value) return '处理中...';
+	return '请点击登录';
+});
+
+onShareAppMessage((res) => {
+	return appStore.onShareAppMessageObj;
+});
+
+onLoad(() => {
+	getAdServicePhoneFn();
+	// 检查用户登录状态
+	checkUserStatus();
+});
+
+onShow(() => {
+	// 页面显示时检查是否需要重新获取用户信息
+	if (appStore.token && !appStore.userInfo?.userPhone) {
+		appStore.USERINFO();
+	}
+});
+
+// 检查用户状态
+async function checkUserStatus() {
+	if (appStore.token && !appStore.userInfo) {
+		pageLoading.value = true;
+		try {
+			await appStore.USERINFO();
+		} catch (error) {
+			console.error('获取用户信息失败:', error);
+		} finally {
+			pageLoading.value = false;
+		}
+	}
+}
+
+// 获取客服电话
+function getAdServicePhoneFn() {
+	getAdServicePhone({}).then(res => {
+		phoneNumber.value = res.data?.servicePhone || '';
+	}).catch(err => {
+		console.log(err);
+	});
+}
+
+// 跳转到用户信息页
+async function toUser() {
+	if (!await checkLoginShowModal()) return;
+	uni.navigateTo({
+		url: '/pages/user/user'
+	});
+}
+
+// 跳转到订单列表
+async function toOrderList() {
+	if (!await checkLoginShowModal()) return;
+	uni.navigateTo({
+		url: '/pages/order/index'
+	});
+}
+
+// 跳转到地址簿
+async function toAddressBook() {
+	if (!await checkLoginShowModal()) return;
+	uni.navigateTo({
+		url: '/pages/address/address_list'
+	});
+}
+
+// 跳转到月结码
+async function toSettlementCode() {
+	if (!await checkLoginShowModal()) return;
+	uni.navigateTo({
+		url: '/pages/mine/settlementCode'
+	});
+}
+
+// 跳转到隐私政策
+async function toPrivacyPolicy() {
+	uni.navigateTo({
+		url: '/pages/webview/webview?url=' + encodeURIComponent('https://your-domain.com/privacy')
+	});
+}
+
+// 跳转到关于我们
+async function toAboutUs() {
+	uni.navigateTo({
+		url: '/pages/about/index'
+	});
+}
+
+// 处理获取手机号登录 - 使用优化后的quickLogin
+async function handleGetPhoneNumber(e) {
+	if (isLogging.value || isProcessing.value) return;
+	
+	isLogging.value = true;
+	isProcessing.value = true;
+	
+	// 先隐藏loading(如果有)
+	uni.hideLoading();
+	
+	try {
+		// 显示加载提示
+		uni.showLoading({
+			title: '登录中...',
+			mask: true
+		});
+		
+		// 调用快速登录,并传入自定义回调
+		await quickLogin(e, {
+			onSuccess: (result) => {
+				console.log('页面登录成功回调:', result);
+				// 页面特定的成功逻辑
+				uni.showToast({
+					title: result.message || `欢迎回来,${result.userInfo?.userName || '用户'}`,
+					icon: 'success',
+					duration: 2000
+				});
+				
+				// 由于appStore.USERINFO()已经在工具函数中调用,这里不需要再调用
+				// 但我们可以触发页面更新
+				uni.$emit('pageRefresh');
+			},
+			onFail: (error) => {
+				console.log('页面登录失败回调:', error);
+				// 页面特定的失败逻辑
+				let errorMessage = error.message || '登录失败,请重试';
+				
+				if (error.type === 'auth_denied') {
+					errorMessage = '您拒绝了授权,无法登录';
+					// 如果是授权拒绝,可以显示引导重新授权的提示
+					uni.showModal({
+						title: '提示',
+						content: '需要手机号授权才能正常使用,请点击右上角菜单,选择「重新进入小程序」后重新授权',
+						showCancel: false,
+						confirmText: '知道了'
+					});
+				} else if (error.type === 'auth_code_missing') {
+					errorMessage = '授权信息不完整';
+				} else if (error.type === 'login_failed') {
+					errorMessage = error.originalError || error.message;
+				}
+				
+				// 只在需要时显示Toast(非授权拒绝的情况)
+				if (error.type !== 'auth_denied') {
+					uni.showToast({
+						title: errorMessage,
+						icon: 'none',
+						duration: 3000
+					});
+				}
+			},
+			redirectUrl: '/pages/mine/mine'
+		});
+		
+	} catch (error) {
+		console.error('登录处理异常:', error);
+		// 这里是未在onFail中捕获的错误(应该是很少出现的)
+		uni.showToast({
+			title: error,
+			icon: 'none'
+		});
+	} finally {
+		isLogging.value = false;
+		isProcessing.value = false;
+		// 确保loading被隐藏
+		setTimeout(() => {
+			uni.hideLoading();
+		}, 300);
+	}
+}
+
+// 拨打电话
+const makePhoneCall = () => {
+	if (!phoneNumber.value) {
+		uni.showToast({
+			title: '客服电话暂时无法接通',
+			icon: 'none'
+		});
+		return;
+	}
+	
+	uni.makePhoneCall({
+		phoneNumber: phoneNumber.value,
+		success: () => {
+			console.log('成功唤起拨号界面');
+		},
+		fail: (err) => {
+			console.error('唤起拨号界面失败', err);
+			uni.showToast({
+				title: '拨号失败',
+				icon: 'none'
+			});
+		}
+	});
+};
+
+// 退出登录
+function userLogoutFn() {
+	uni.showModal({
+		title: '提示',
+		content: '确认要退出登录吗?',
+		success: function(res) {
+			if (res.confirm) {
+				uni.showLoading({
+					title: '正在退出...'
+				});
+				
+				userLogout({}).then(res => {
+					appStore.LOGOUT();
+					uni.hideLoading();
+					uni.showToast({
+						title: '已退出登录',
+						icon: 'success'
+					});
+					
+					// 延迟刷新页面状态
+					setTimeout(() => {
+						uni.$emit('userLogoutSuccess');
+					}, 500);
+				}).catch(err => {
+					uni.hideLoading();
+					uni.showToast({
+						title: '退出失败',
+						icon: 'none'
+					});
+				});
+			}
+		}
+	});
+}
+</script>
+
+<style lang="less" scoped>
+.mine-container {
+	height: 100vh;
+	background: linear-gradient(135deg, #CFE9FF 0%, #F5F7FA 50.86%);
+	position: relative;
+
+	// 用户信息区域
+	.user-header {
+		padding: 0rpx 24rpx;
+
+		.user-info-section {
+			margin-top: 32rpx;
+			display: flex;
+			flex-direction: column;
+			gap: 20rpx;
+
+			.avatar-section {
+				display: flex;
+				align-items: center;
+				min-height: 144rpx; // 添加最小高度防止闪烁
+
+				.user-text-info {
+					flex: 1;
+					display: flex;
+					flex-direction: column;
+					justify-content: center;
+					min-height: 144rpx; // 添加最小高度防止闪烁
+				}
+
+				.user-name-section {
+					margin-left: 16rpx;
+					min-height: 100rpx; // 固定高度防止闪烁
+					display: flex;
+					flex-direction: column;
+					justify-content: center;
+					
+					.name-section {
+						height: 52rpx;
+						display: flex;
+						align-items: center;
+						margin-bottom: 8rpx;
+					}
+					
+					.user-name {
+						font-weight: bold;
+						font-size: 36rpx;
+						color: #333333;
+						text-align: center;
+						line-height: 1;
+					}
+
+					.login-button {
+						background: transparent;
+						font-size: 40rpx;
+						font-weight: 600;
+						color: #333;
+						line-height: 56rpx;
+						padding: 0;
+						margin: 0;
+						text-align: left;
+						height: auto;
+						min-height: 56rpx;
+						display: flex;
+						align-items: center;
+						justify-content: flex-start;
+
+						&::after {
+							border: none;
+						}
+						
+						&[disabled] {
+							opacity: 0.7;
+						}
+					}
+				}
+
+				.user-account {
+					height: 44rpx;
+					font-weight: 400;
+					font-size: 28rpx;
+					color: #333333;
+					line-height: 44rpx;
+					margin-top: 4rpx;
+				}
+			}
+
+			.department-badge {
+				width: 104rpx;
+				background: #1B64F0;
+				border-radius: 8rpx;
+				font-size: 24rpx;
+				color: #FFFFFF;
+				text-align: center;
+				margin-left: 8rpx;
+				padding: 7rpx 16rpx;
+				line-height: 1;
+			}
+		}
+	}
+
+	// 菜单区域
+	.menu-section {
+		padding: 0 20rpx;
+		margin-top: 20rpx;
+
+		.menu-card {
+			overflow: hidden;
+		}
+
+		.menu-item {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 32rpx;
+			background: #FFFFFF;
+			border-radius: 24rpx;
+			margin-bottom: 20rpx;
+			min-height: 112rpx; // 固定高度防止闪烁
+
+			&:last-child {
+				border-bottom: none;
+				margin-bottom: 0;
+			}
+
+			.menu-item-left {
+				display: flex;
+				align-items: center;
+				gap: 24rpx;
+				flex: 1;
+			}
+
+			.menu-icon {
+				width: 48rpx;
+				height: 48rpx;
+				flex-shrink: 0;
+			}
+
+			.menu-text {
+				font-size: 32rpx;
+				font-weight: 500;
+				color: #333333;
+				line-height: 45rpx;
+			}
+
+			.arrow-icon {
+				width: 48rpx;
+				height: 48rpx;
+				opacity: 0.5;
+				flex-shrink: 0;
+			}
+
+			&.logout-item {
+				height: 88rpx;
+				background: #F52929;
+				border-radius: 32rpx;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				.logout-text {
+					font-weight: 400;
+					font-size: 32rpx;
+					color: #FFFFFF;
+					text-align: center;
+				}
+			}
+		}
+	}
+}
+
+// 动画效果
+.menu-item {
+	transition: all 0.3s ease;
+	opacity: 1;
+
+	&:active {
+		background-color: rgba(66, 133, 244, 0.05);
+		transform: translateX(8rpx);
+	}
+	
+	&[disabled] {
+		opacity: 0.6;
+		pointer-events: none;
+	}
+}
+
+.department-badge {
+	transition: all 0.3s ease;
+
+	&:active {
+		transform: scale(0.95);
+	}
+}
+
+// 响应式适配
+@media (max-width: 375px) {
+	.menu-section {
+		padding: 0 20rpx !important;
+	}
+
+	.menu-card {
+		padding: 0 20rpx !important;
+	}
+
+	.menu-text {
+		font-size: 30rpx !important;
+	}
+}
+
+// 防止闪烁的全局样式
+view, text, image {
+	will-change: auto;
+	backface-visibility: hidden;
+	-webkit-backface-visibility: hidden;
+}
+</style>

+ 252 - 0
jd_logistics-app/pages/mine/mine1.vue

@@ -0,0 +1,252 @@
+<template>
+	<view class="mine_ybt bg_color_primary">
+		<view class="mine_ybt_top pad30">
+			<headerInfo title="个人中心"></headerInfo>
+			 <view class="flex-center-between color_fff mg20">
+				<u-avatar  @click="toUser"
+					size="100rpx"
+					shape="circle"
+					:src="appStore?.userInfo?.avatar"
+					mode="aspectFill"
+				></u-avatar>
+				<view class="flex_1 flex-center-between ml20">
+					<view class="">
+						<view class="font_size35">
+							<text v-if="appStore.userInfo?.userPhone" class="mr20"  @click="toUser">{{appStore.userInfo?.nickName}}</text>
+							<!-- <text v-else @click="toLogin()">请点击登录</text> -->
+							<button v-else
+								class="login-btn" 
+								open-type="getPhoneNumber"
+								@getphonenumber="getPhoneNumberFn"
+							>
+								请点击登录
+							</button>
+							<text v-if="appStore.userInfo?.memberStatus==1" class="memberPlanName">{{appStore.userInfo?.memberPlanName}}</text>
+						</view>
+						<view class="font_size25 mt20" v-if="appStore.userInfo?.memberExpire">
+							<!-- <text>{{appStore.userInfo?.memberPlanName}}</text> -->
+							<text class="vipTime">到期时间:{{appStore.userInfo?.memberExpire}}</text>
+						</view>
+					</view>
+					<view class="order_btn flex-center share_btn" @click="toUser">
+						<view class="flex-center border_radius_20">
+							<text>编辑资料</text>
+						</view>
+					</view>
+				</view>
+			 </view>
+			<view class="border_radius_20 padding20 vipCar flex-center-between">
+				<view class="flex_1 flex-center-flex-start mr20">
+					<image src="/static/img/mine/vipcard.png" mode="" class="vipcard-img mr10"></image>
+					<text style="color: rgb(246, 223, 185);">开通会员解锁更多权益</text>
+				</view>
+				<view class="order_btns jiesuo border_radius_20 font_size25" @click="toVip">
+					{{appStore.userInfo?.memberStatus==1?'查看权益' : '立即解锁'}}
+				</view>
+			</view>
+		</view>
+		<view class="mine_content padding30 mt20">
+			<!-- 我的订单 -->
+			<view class="font_size25 padding20 border_radius_20 bg_color_fff mb20">
+				<view class="flex-center-between paddingTB20 border-bottom menuList"
+				@click="toPage(item)"
+				 v-for="(item, index) in menuList" :key="index">
+					<view class="flex-center-flex-start mr20 flex_1">
+						<image :src="item.img" mode="" class="order-img mr20"></image>
+						<text>{{item.name}}</text>
+					</view>
+					<image src="/static/img/arrow-right.png" mode="widthFix" class="menu_img"></image>
+				</view>
+				<view class="flex-center-between paddingTB20 border-bottom menuList" @click="makePhoneCall">
+					<view class="flex-center-flex-start mr20 flex_1">
+						<image src="/static/img/mine/kefu.png" mode="" class="order-img mr20"></image>
+						<text>服务热线</text>
+					</view>
+					<image src="/static/img/arrow-right.png" mode="widthFix" class="menu_img"></image>
+				</view>
+				<view class="flex-center-between paddingTB20 border-bottom menuList" v-if="appStore.userInfo?.userPhone"
+				@click="userLogoutFn(item)">
+					<view class="flex-center-flex-start mr20 flex_1">
+						<image src="/static/img/mine/Logout.png" mode="" class="order-img mr20"></image>
+						<text>退出登录</text>
+					</view>
+					<image src="/static/img/arrow-right.png" mode="widthFix" class="menu_img"></image>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { userLogout } from "@/api/user.js";
+import { getAdServicePhone } from "@/api/home.js";
+import headerInfo from "@/components/headerInfo.vue";
+import { telEncrypt,checkLoginShowModal, getPhoneNumber } from "@/utils/util.js";
+import { onLoad, onShareAppMessage} from '@dcloudio/uni-app'
+import { useAppStore } from "@/stores/app";
+const appStore = useAppStore();
+
+onShareAppMessage((res) => {
+  return appStore.onShareAppMessageObj
+})
+
+	const menuList = ref([
+		{
+			name: '我的钱包',
+			img: "/static/img/mine/money.png",
+			url: '/pages/recharge/wallet'
+		},
+		{
+			name: '去充值',
+			img: "/static/img/mine/vip.png",
+			url: '/pages/recharge/recharge'
+		},
+		// {
+		// 	name: '会员充值记录',
+		// 	img: "/static/img/mine/chongzhijulu.png",
+		// 	url: ''
+		// },
+		{
+			name: '我的订单',
+			img: "/static/img/mine/order.png",
+			url: '/pages/order/order_list'
+		}
+	]);
+
+onLoad(() => {
+	getAdServicePhoneFn();
+});
+async function toUser(){
+	if(!await checkLoginShowModal())return;
+	uni.navigateTo({
+		url: '/pages/user/user'
+	});
+}
+async function toVip(){
+	if(!await checkLoginShowModal())return;
+	uni.navigateTo({
+		url: '/pages/recharge/vip'
+	});
+}
+async function toPage(item){
+	if(!await checkLoginShowModal())return;
+	if(!item.url) return;
+	uni.navigateTo({
+		url: item.url
+	});
+}
+function getPhoneNumberFn(e){
+  getPhoneNumber(e)
+};
+// 退出登录
+function userLogoutFn(){
+	//确认退出登录吗
+	uni.showModal({
+		title: '提示',
+		content: '确认要退出登录吗?',
+		success: function (res) {
+			if (res.confirm) {
+				userLogout({}).then(res=>{ 
+					appStore.LOGOUT();
+				})
+			}
+		}
+	})
+}
+// 获取客服电话
+const phoneNumber = ref('');
+function getAdServicePhoneFn() {
+  getAdServicePhone({}).then(res => {
+    phoneNumber.value = res.data?.servicePhone || '';
+  }).catch(err => {
+    console.log(err);
+  });
+}
+// 拨打电话方法
+const makePhoneCall = () => {
+  if(!phoneNumber.value){
+    Toast({title:'请先配置客服电话'})
+    return;
+  }
+  uni.makePhoneCall({
+    phoneNumber:phoneNumber.value,
+    success: () => {
+      console.log('成功唤起拨号界面');
+    },
+    fail: (err) => {
+      console.error('唤起拨号界面失败', err);
+    }
+  });
+};
+</script>
+
+<style lang="less" scoped>
+.mine_ybt{
+	height: 100vh;
+	.vipCar{
+		margin-top: 30rpx;
+    background: linear-gradient(97.4139deg, rgb(137, 153, 191) 4.58393%, rgb(89, 88, 103) 97.8314%);
+		.jiesuo{
+			background: linear-gradient(94.5323deg, rgb(251, 239, 216) 10.1217%, rgb(241, 210, 164) 94.0504%);
+		}
+		.vipcard-img{
+			width: 80rpx;
+			height: 80rpx;
+		}
+	}
+	// background-size: 100% 100%;
+	.order_btns{
+		padding: 8rpx 20rpx;
+		display: inline-block;
+		&.active{
+			background: #fc4f1d;
+		}
+	}
+	.share_btn{
+		border:1px solid #ffffff;
+		padding: 10rpx 20rpx;
+		background: transparent;
+		.share_img{
+			width: 30rpx;
+		}
+	}
+	.mine_content{
+		border-radius: 30rpx 30rpx 0 0;
+		background: #f5f5f5;
+		min-height: calc(100vh - 200rpx);
+	}
+	.order-img{
+		width: 40rpx;
+		height: 40rpx;
+	}
+	.menu_img{
+		width: 50rpx;
+		height: 50rpx;
+	}
+	.menuList{
+		&:last-child{
+			border-bottom: none;
+		}
+	}
+	.vipTime{
+		opacity: .7;
+	}
+	/* 登录按钮 */
+	.login-btn {
+		background-color: transparent;
+		color: #fff;
+		font-size: 35rpx;
+		font-weight: bold;
+		text-align: left;
+	}
+  .memberPlanName{
+		background: linear-gradient(90deg, #FDE492    0%, #FDB85D  100%);
+		color: #874605 ;
+    padding: 5rpx 10rpx;
+    border-radius: 20rpx;
+    font-size: 24rpx;
+  }
+	
+}
+</style>

+ 370 - 0
jd_logistics-app/pages/order/components/OrderItem.vue

@@ -0,0 +1,370 @@
+<template>
+	<view class="card">
+		<view class="card-header">
+			<text class="waybill-number">运单号:JDVA401410370033</text>
+			<image src="/static/img/copy.png" @click="copyWaybillNumber"></image>
+		</view>
+
+		<view class="content">
+			<!-- 左侧寄件人信息 -->
+			<view class="sender-info">
+				<view class="city-tag">洛阳市</view>
+				<view class="name">下海龙</view>
+			</view>
+
+			<view class="translate">
+				<view class="status">待取件</view>
+				<image src="/static/img/translte-1.png"></image>
+			</view>
+
+			<!-- 右侧收件人信息 -->
+			<view class="receiver-info">
+				<view class="city-tag">北京市</view>
+				<view class="name">周欣源</view>
+			</view>
+		</view>
+
+		<!-- 状态信息 -->
+		<view class="section-continer">
+			<view class="timeline">
+				<view class="dot">
+					<view class="timeline-dot dot-active"></view>
+				</view>
+				<view class="timeline-line line-active"></view>
+			</view>
+			<view class="status-section">
+				<view class="status-badge status-collected">已代收</view>
+				<view class="status-detail">
+					快件已投递至【北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿】
+				</view>
+				<view class="status-time">2026-01-11 17:32:32</view>
+			</view>
+		</view>
+
+		<!-- 操作按钮 -->
+		<view class="action-buttons">
+			<view class="action-btn" @click="showExpressTrack">
+				<text class="btn-text">物流轨迹</text>
+			</view>
+			<view class="action-btn" @click="showOrderInfo">
+				<text class="btn-text">运单详情</text>
+			</view>
+			<view class="action-btn btn-cancel">
+				<text class="btn-text">运单取消</text>
+			</view>
+		</view>
+		
+		<!-- 物流轨迹弹框 -->
+		<TrackPopup 
+			v-model:showPopup="showTrackPopup" 
+			:expressData="expressData"
+		/>
+	</view>
+</template>
+
+<script setup>
+	import { ref, defineProps, defineEmits } from 'vue'
+	import TrackPopup from './TrackPopup.vue'
+
+	const emit = defineEmits(['success'])
+	const props = defineProps({
+		isGrab: {
+			type: Boolean,
+			default: false
+		},
+		orderDetail: {
+			type: Object,
+			default: () => ({
+				goodsMainImage: null,
+				goodsName: null,
+				id: undefined,
+				orderCreateTime: '',
+				shopConfirmStatus: "",
+				shopEvaluateStatus: '',
+				shopDispatchVerifyStatus: "",
+				shopGoodsId: undefined,
+				shopOrderAmount: undefined,
+				shopOrderId: "",
+				shopOrderNum: 1,
+				shopOrderStatus: "1",
+				shopPrice: 102,
+				shopRefundReviewStatus: null,
+				shopServiceStatus: null,
+				shopUserTime: null,
+				userId: "1989219383070896130",
+				userNickName: "bonjour",
+				userPhone: "17639845061"
+			})
+		}
+	})
+	
+	// 控制弹框显示
+	const showTrackPopup = ref(false)
+	const expressData = ref({
+		company: '顺丰速运',
+		number: 'JDVA401410370033',
+		status: '待取件'
+	})
+	
+	// 显示物流轨迹弹框
+	const showExpressTrack = () => {
+		// 这里可以调用API获取物流信息
+		// 暂时使用模拟数据
+		showTrackPopup.value = true
+	}
+	
+	const showOrderInfo = () => {
+		uni.navigateTo({
+			url:'/pages/order/order_detail'
+		})
+	}
+	
+	// 复制运单号
+	const copyWaybillNumber = () => {
+		uni.setClipboardData({
+			data: 'JDVA401410370033',
+			success: () => {
+				uni.showToast({
+					title: '运单号已复制',
+					icon: 'success'
+				})
+			}
+		})
+	}
+</script>
+
+<style scoped lang="less">
+	.card {
+		background-color: #fff;
+		border-radius: 32rpx;
+		margin-bottom: 20rpx;
+		padding: 20rpx;
+
+		.card-header {
+			height: 45rpx;
+			margin-bottom: 20rpx;
+			display: flex;
+			align-items: center;
+
+			.waybill-number {
+				height: 100%;
+				line-height: 45rpx;
+				font-size: 28rpx;
+				color: #333;
+				font-weight: 500;
+			}
+
+			image {
+				width: 50rpx;
+				height: 50rpx;
+				padding: 10rpx;
+				margin-left: 8rpx;
+				flex-shrink: 0;
+			}
+		}
+
+		.content {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			margin-bottom: 20rpx;
+
+			.sender-info,
+			.receiver-info {
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				min-width: 0; /* 防止flex子元素溢出 */
+
+				.city-tag {
+					max-width: 250rpx;
+					height: 52rpx;
+					font-size: 36rpx;
+					color: #333333;
+					line-height: 52rpx;
+					font-weight: bold;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
+
+				.name {
+					max-width: 250rpx;
+					height: 44rpx;
+					font-weight: 400;
+					font-size: 28rpx;
+					color: #333333;
+					line-height: 44rpx;
+					margin-top: 8rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
+			}
+
+			.translate {
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				justify-content: center;
+				width: 160rpx;
+				flex-shrink: 0;
+
+				.status {
+					height: 44rpx;
+					font-weight: 400;
+					font-size: 28rpx;
+					color: #333333;
+					line-height: 44rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+					max-width: 100%;
+				}
+
+				image {
+					height: 28rpx;
+					width: 160rpx;
+					margin-top: 8rpx;
+					flex-shrink: 0;
+				}
+			}
+		}
+
+		.section-continer {
+			display: flex;
+			background-color: #F5F7FA;
+			border-radius: 16rpx;
+			padding: 20rpx;
+			margin-bottom: 20rpx;
+			
+			.timeline {
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				width: 34rpx;
+				margin-right: 20rpx;
+				flex-shrink: 0;
+				
+				.dot {
+					width: 34rpx;
+					height: 34rpx;
+					border-radius: 50%;
+					background-color: #C1D5FF;
+					display: flex;
+					justify-content: center;
+					align-items: center;
+					flex-shrink: 0;
+				}
+			
+				.timeline-dot {
+					width: 18rpx;
+					height: 18rpx;
+					border-radius: 50%;
+					
+					&.dot-active {
+						background-color: #1B64F0;
+					}
+				}
+			
+				.timeline-line {
+					flex: 1;
+					width: 4rpx;
+					box-sizing: border-box;
+					margin-top: 10rpx;
+					
+					&.line-active {
+						border-left: 4rpx dashed #1B64F0;
+					}
+				}
+			}
+			
+			.status-section {
+				flex: 1;
+				min-width: 0;
+			
+				.status-badge {
+					margin-bottom: 8rpx;
+					height: 48rpx;
+					font-weight: 400;
+					font-size: 32rpx;
+					color: #333333;
+					line-height: 48rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
+			
+				.status-detail {
+					font-weight: 400;
+					font-size: 28rpx;
+					color: #333333;
+					line-height: 44rpx;
+					margin-top: 8rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
+			
+				.status-time {
+					margin-top: 8rpx;
+					height: 40rpx;
+					font-weight: 400;
+					font-size: 24rpx;
+					color: #999999;
+					line-height: 40rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
+			}
+		}
+		
+		.action-buttons {
+			margin-top: 20rpx;
+			display: flex;
+			justify-content: flex-end;
+
+			.action-btn {
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				width: 160rpx;
+				height: 60rpx;
+				border-radius: 80rpx;
+				border: 2rpx solid #F1F3F8;
+				margin-left: 20rpx;
+		
+				&:first-child {
+					margin-left: 0;
+				}
+
+				&:last-child {
+					margin-right: 0;
+				}
+
+				.btn-text {
+					font-size: 28rpx;
+					color: #333;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
+				}
+
+				&.btn-cancel {
+					background-color: #fff5f5;
+
+					.btn-text {
+						color: #ff6b6b;
+					}
+				}
+				
+				/* 添加点击效果 */
+				&:active {
+					opacity: 0.7;
+				}
+			}
+		}
+	}
+</style>

+ 152 - 0
jd_logistics-app/pages/order/components/TrackPopup.vue

@@ -0,0 +1,152 @@
+<template>
+	<u-popup :show="showPopup" mode="center" round="20" @close="closePopup" :closeable="true"
+		:safeAreaInsetBottom="false" :closeOnClickOverlay="true">
+		<view class="express-popup">
+			<!-- 弹框头部 -->
+			<view class="popup-header">
+				<text class="title">物流轨迹</text>
+
+			</view>
+
+			<!-- 右上角关闭按钮 -->
+			<view class="close-btn" @tap="closePopup">
+				<u-icon name="close" size="22" color="#333"></u-icon>
+			</view>
+			<!-- 物流轨迹时间线 -->
+			<scroll-view class="timeline-container" scroll-y="true">
+				<TimelineItem v-for="(item, index) in trackList" :key="index" :title="item.title" :desc="item.desc"
+					:time="item.time" :is-active="item.isActive" :show-line="index < trackList.length - 1"
+					:show-dot-bg="index == 0" />
+			</scroll-view>
+		</view>
+	</u-popup>
+</template>
+
+<script setup>
+	import {
+		ref,
+		defineProps,
+		defineEmits
+	} from 'vue'
+	import TimelineItem from '@/components/TimelineItem.vue'
+
+	const props = defineProps({
+		showPopup: {
+			type: Boolean,
+			default: false
+		},
+		expressData: {
+			type: Object,
+			default: () => ({
+				company: '顺丰速运',
+				number: 'SF1234567890123',
+				status: '已签收'
+			})
+		}
+	})
+
+	const emit = defineEmits(['update:showPopup', 'close'])
+
+	// 模拟物流轨迹数据,实际应用中应该通过API获取
+	const trackList = ref([{
+			title: '已代收',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿...】',
+			time: '2026-01-11 17:32:32',
+			isActive: true
+		},
+		{
+			title: '派送中',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿...】',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '运输中',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿.北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿..】',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿.北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿..】',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿.北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿..】',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿.北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿北京海淀区北京大学菜鸟驿..】',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		},
+		{
+			title: '已揽件',
+			desc: '快件已投递至【北京海淀区北京大学菜鸟驿..北京海淀区北京大学菜鸟驿.】',
+			time: '2026-01-11 17:32:32',
+			isActive: false
+		}
+	])
+
+	const closePopup = () => {
+		emit('update:showPopup', false)
+		emit('close')
+	}
+</script>
+
+<style scoped lang="less">
+	.express-popup {
+		width: 670rpx;
+		background-color: #ffffff;
+		border-radius: 32rpx;
+		padding: 32rpx;
+		max-height: 88vh;
+		display: flex;
+		flex-direction: column;
+	}
+
+	/* 头部样式 */
+	.popup-header {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		padding-bottom: 20rpx;
+
+
+		.title {
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+	}
+
+	.close-btn {
+		position: absolute;
+		right: 32rpx;
+		top: 40rpx;
+	}
+
+	/* 时间线容器 */
+	.timeline-container {
+		overflow-y: auto;
+		max-height: calc(88vh - 120rpx);
+	}
+
+	/* 弹框样式调整 */
+	:deep(.u-popup) {
+		display: flex;
+		justify-content: center;
+		align-items: flex-end;
+	}
+
+	:deep(.u-popup__content) {
+		width: 90% !important;
+		max-width: 670rpx !important;
+		/* 限制最大宽度,避免在宽屏上过宽 */
+		margin: 0 auto;
+	}
+</style>

+ 385 - 0
jd_logistics-app/pages/order/index.vue

@@ -0,0 +1,385 @@
+<template>
+	<view class="container">
+		<!-- 搜索框 -->
+		<view class="search-section">
+			<u-search v-model="searchKeyword" placeholder="请输入订单编号或用户名称" :show-action="false" shape="square"
+				bg-color="#F5F7FA" @search="handleSearch" @clear="handleSearch"></u-search>
+		</view>
+
+		<!-- Tab切换 -->
+		<!-- <view class="tabs-section"> -->
+		<!-- 	<view class="custom-tabs">
+				<view class="tab-item" :class="{ active: currentTab == index }" v-for="(tab, index) in tabList"
+					:key="index" @click="switchTab(index)">
+					{{ tab.name }}
+				</view>
+			</view> -->
+		<!-- </view> -->
+
+		<!-- 订单列表 -->
+		<scroll-view class="order-list" scroll-y="true" @scrolltolower="loadMore">
+			<view v-if="ordersList.length > 0" v-for="order in ordersList" :key="order.id">
+				<OrderItem :order-detail="order" @success="getOrderList(false)"></OrderItem>
+			</view>
+			<view class="empty-state" v-else>
+				<u-icon class="empty-icon" name="list" size="60" color="#ccc"></u-icon>
+				<view class="empty-text">暂无相关订单</view>
+			</view>
+
+			<view class="load-more-status" v-if="loadFinished && ordersList.length !== 0">
+				<text>没有更多数据了</text>
+			</view>
+
+			<!-- 加载状态提示 -->
+			<view class="load-more-status" v-if="loadState">
+				<text>加载中...</text>
+			</view>
+
+		</scroll-view>
+
+
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		computed
+	} from 'vue'
+	import {
+		onShow,
+		onLoad
+	} from '@dcloudio/uni-app' // 导入 UniApp 的生命周期
+	import OrderItem from './components/OrderItem.vue'
+	import { getOrderListApi } from '../../api/order'
+
+	// 搜索关键词
+	const searchKeyword = ref('')
+	const pageNum = ref(1)
+	const pageSize = ref(10)
+	const recordTotal = ref(0)
+	const loadState = ref(false)
+	const loadFinished = ref(false)
+
+	// Tab数据
+	const tabList = ref([{
+			name: '全部订单'
+		},
+		{
+			name: '待确认'
+		},
+		{
+			name: '已完成'
+		},
+		{
+			name: '申请退款'
+		}
+	])
+	// 1-全部订单, 2-待确认,  4-已完成, 5-申请退款
+	//orderType: 订单类型(1-全部订单, 2-待确认, 3-待核销, 4-已完成, 5-申请退款, 6-服务中)
+	const orderTypeMap = {
+		0: 1, // 全部订单
+		1: 2, // 待确认 
+		2: 4, // 已完成  
+		3: 5, // 申请退款  
+	}
+
+	// 当前选中的Tab
+	const currentTab = ref(0)
+
+	// 订单数据
+	const ordersList = ref([{},{},{},{},{}])
+
+
+	// 获取状态类名
+	const getStatusClass = (status) => {
+		switch (status) {
+			case 0:
+				return 'status-pending' // 待派单
+			case 1:
+				return 'status-assigned' // 已派单
+			case 2:
+				return 'status-completed' // 已完成
+			case 3:
+				return 'status-market' // 抢单市场
+			default:
+				return 'status-pending'
+		}
+	}
+
+	onLoad((option) => {
+		if (option.orderStatusType) {
+			currentTab.value = option.orderStatusType
+		}
+	})
+
+	onShow(() => {
+		// 可以在这里初始化数据
+		getOrderList(false)
+	})
+
+	// Tab切换事件
+	const switchTab = (index) => {
+		currentTab.value = index
+		getOrderList(false)
+	}
+	const loadMore = () => {
+		pageNum.value++
+		getOrderList(true)
+	}
+
+	const handleSearch = () => {
+		getOrderList(false)
+	}
+
+	// 获取收益明细列表
+	const getOrderList = async (isLoadMore = false) => {
+		return
+		if (loadState.value) return
+
+		if (!isLoadMore) {
+			pageNum.value = 1
+			loadFinished.value = false
+			ordersList.value = []
+		}
+		loadState.value = true
+		//orderType: 订单类型(1-全部订单, 2-待确认,  4-已完成, 5-申请退款)
+		try {
+			uni.showLoading({
+				mask: true
+			})
+			const orderType = orderTypeMap[currentTab.value]
+			const params = {
+				pageNum: pageNum.value,
+				pageSize: pageSize.value,
+				orderType: orderType,
+				keyword: searchKeyword.value
+			}
+			var res = await getOrderListApi(params)
+			if (res.code === 200) {
+				const list = res.rows || []
+				const total = res.total || 0
+
+
+				if (isLoadMore) {
+					ordersList.value = [...ordersList.value, ...list]
+				} else {
+					ordersList.value = list
+				}
+				recordTotal.value = total
+				// 判断是否还有更多数据
+				if (list.length < pageSize.value) {
+					loadFinished.value = true
+				}
+			}
+		} catch (error) {
+
+		} finally {
+			loadState.value = false
+			uni.hideLoading()
+		}
+	}
+
+
+	// 查看订单详情
+	const viewOrderDetail = (order) => {
+		uni.showToast({
+			title: `查看订单详情 - ${order.orderNumber}`,
+			icon: 'none'
+		})
+	}
+</script>
+
+<style lang="scss" scoped>
+	.container {
+		display: flex;
+		flex-direction: column;
+		height: 100vh;
+		background-color: #F5F7FA;
+	}
+
+
+	.search-section {
+		background-color: #fff;
+		padding: 16rpx;
+		margin-left: 14rpx;
+
+		:deep .u-search__content {
+			border-radius: 36rpx !important;
+		}
+
+	}
+
+	.page-title {
+		font-size: 36rpx;
+		font-weight: bold;
+		text-align: center;
+		margin-bottom: 30rpx;
+		color: #333333;
+	}
+
+	.tabs-section {
+		height: 88rpx;
+		background-color: #ffffff;
+	}
+
+	.custom-tabs {
+		display: flex;
+		width: 100%;
+	}
+
+	.tab-item {
+		flex: 1;
+		text-align: center;
+		padding: 30rpx 0;
+		font-size: 28rpx;
+		color: #333333;
+		position: relative;
+		transition: all 0.3s;
+	}
+
+	.tab-item.active {
+		color: #0089FF;
+	}
+
+	.tab-item.active::after {
+		content: '';
+		position: absolute;
+		bottom: 0;
+		left: 50%;
+		transform: translateX(-50%);
+		width: 40rpx;
+		height: 6rpx;
+		background-color: #2979ff;
+		border-radius: 4rpx;
+	}
+
+	.order-list {
+		flex: 1;
+		padding: 20rpx;
+		min-height: 500rpx;
+		background-color: #F5F7FA;
+		box-sizing: border-box;
+	}
+
+	.order-card {
+		background-color: #ffffff;
+		border-radius: 16rpx;
+		padding: 16rpx;
+		margin-bottom: 16rpx;
+		position: relative;
+	}
+
+	.order-header {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		margin-bottom: 20rpx;
+	}
+
+	.order-title {
+		font-size: 32rpx;
+		font-weight: bold;
+		color: #333333;
+	}
+
+	.order-status {
+		width: 136rpx;
+		height: 54rpx;
+		line-height: 54rpx;
+		color: #fff;
+		font-size: 24rpx;
+		border-radius: 0rpx 16rpx 0rpx 16rpx;
+		position: absolute;
+		right: 0px;
+		top: 0px;
+		text-align: center;
+	}
+
+	.status-pending {
+		background: linear-gradient(270deg, #49ABFF 0%, #0089FF 100%);
+	}
+
+	.status-assigned {
+		background: linear-gradient(134deg, #5ED89B 0%, #36B475 99%);
+	}
+
+	.status-completed {
+		background: linear-gradient(134deg, #5ED89B 0%, #36B475 99%);
+	}
+
+	.status-market {
+		background: linear-gradient(90deg, #FF9F23 0%, #FD5F3C 100%);
+	}
+
+	.price-section {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		margin-bottom: 16rpx;
+	}
+
+	.order-price {
+		font-size: 32rpx;
+		font-weight: bold;
+		color: #FD5F3C;
+	}
+
+	.countdown {
+		font-size: 24rpx;
+		color: #F52929;
+	}
+
+	.order-details {
+		margin-bottom: 16rpx;
+		padding: 16rpx;
+		background: #F5F7FA;
+		border-radius: 16rpx;
+
+
+		.customer-info {
+			display: flex;
+			align-items: center;
+			margin-bottom: 16rpx;
+		}
+
+		.customer-photo {
+			width: 48rpx;
+			height: 48rpx;
+			border-radius: 48rpx;
+			margin-right: 16rpx;
+		}
+
+		.customer-name {
+			font-size: 24rpx;
+			color: #333333;
+			font-weight: bold;
+		}
+
+	}
+
+	.load-more-status {
+		text-align: center;
+		padding: 20rpx;
+		font-size: 24rpx;
+		color: #999;
+		position: fixed;
+		width: 100%;
+		height: 100%;
+	}
+
+
+	.empty-state {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		padding: 120rpx 40rpx;
+		color: #999999;
+	}
+
+	.empty-text {
+		margin-top: 20rpx;
+		font-size: 28rpx;
+	}
+</style>

+ 634 - 0
jd_logistics-app/pages/order/order_detail.vue

@@ -0,0 +1,634 @@
+<template>
+	<view class="verification-container">
+		<!-- 内容区域 -->
+		<view class="content">
+
+
+			<!-- 用户信息卡片 -->
+			<view class="info-card1">
+				<view class="address-item">
+					<view class="img-status-text">
+						<image src="/static/img/icon-send.png" mode="" class="img"></image>
+						<!-- <view class="status-text">{{getStatusText}}</view> -->
+					</view>
+					<view class="user-info">
+						<AddressInfo :address="addressSend"/>
+					</view>
+				</view>
+				<view class="address-item">
+					<view class="img-status-text">
+						<image src="/static/img/icon-receive.png" mode="" class="img"></image>
+						<!-- <view class="status-text">{{getStatusText}}</view> -->
+					</view>
+					<view class="user-info">
+						<AddressInfo :address="addressReceive"/>
+					</view>
+				</view>
+			</view>
+
+			<view class="action-title">运单信息</view>
+
+
+			<OrderInfo :order-detail="orderInfo"></OrderInfo>
+
+			<view class="action-title">费用信息</view>
+
+			<OrderFeesInfo :order-detail="orderInfo"/>
+
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref,
+		computed
+	} from 'vue'
+	import {
+		onLoad,
+		onShow
+	} from '@dcloudio/uni-app'
+	import OrderInfo from './components/OrderInfo.vue'
+	import OrderFeesInfo from './components/OrderFeesInfo.vue'
+	import AddressInfo from '@/components/AddressInfo.vue'
+
+
+
+	import {
+		useAppStore
+	} from '@/stores/app'
+	const appStore = useAppStore()
+
+	const shopOrderId = ref('')
+	
+	const addressSend = ref({
+			id: 1,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路97号',
+			isDefault: true
+		})
+	const addressReceive = ref({
+			id: 1,
+			name: '张三',
+			phone: '132****5678',
+			address: '广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路广东省深圳市罗湖区贝丽北路97号',
+			isDefault: true
+		})
+
+	const orderInfo = ref({
+		createTime: null,
+		goodsInfo: null,
+		goodsMainImage: null,
+		goodsName: "",
+		serviceAvatar: null,
+		serviceBelongShop: "",
+		serviceCommission: "",
+		serviceName: "",
+		servicePhone: "",
+		shopOrderAmount: "",
+		shopOrderId: "",
+		shopOrderNum: 1,
+		userName: "",
+		userPhone: "",
+		dispatchInfo: {},
+		goodsInfo: {},
+		grabInfo: {},
+		userInfo: {}
+	})
+
+	const showOrderCofirmBtn = ref(false)
+	const showOrderDispatchBtn = ref(false)
+	const showOrderRefundBtn = ref(false)
+	const showCallUserBtn = ref(true)
+
+
+	onLoad((option) => {
+		shopOrderId.value = option.id
+	})
+
+	onShow(() => {
+		// getOrderInfo()
+	})
+
+	const getOrderInfo = () => {
+		const param = {
+			shopOrderId: shopOrderId.value
+		}
+		getOrderInfoApi(param).then(res => {
+			if (res.code == 200) {
+				console.log('getOrderInfoApi=========', res)
+				orderInfo.value = res.data
+			}
+		})
+	}
+
+	// 返回按钮点击事件
+	const handleBack = () => {
+		uni.navigateBack()
+	}
+
+	// 确认核销按钮点击事件
+	const handleVerification = () => {
+		uni.showModal({
+			title: '确认核销',
+			content: '确定要核销此订单吗?',
+			success: (res) => {
+				if (res.confirm) {
+					uni.showToast({
+						title: '核销成功',
+						icon: 'success'
+					})
+					// 这里可以添加核销成功的后续逻辑
+				}
+			}
+		})
+	}
+
+
+	const makePhoneCall = (phoneNum) => {
+		// 这里以拨打10086为例,实际使用时可以替换为动态获取的电话号码
+
+		uni.makePhoneCall({
+			phoneNumber: phoneNum, // 电话号码
+			success: () => {
+				console.log('拨打电话成功')
+			},
+			fail: (err) => {
+				console.log('拨打电话失败:', err)
+			}
+		})
+	}
+
+
+
+	//确认订单是去派单状态
+	const updateOrderDispatch = () => {
+		if (!appStore.userInfo.orderDispatch) {
+			uni.showToast({
+				title: "当前会员不能使用此功,请升级为SVIP会员",
+				icon: "none"
+			})
+			return
+		}
+		uni.showModal({
+			title: '去派单',
+			content: '是否确认去派单?',
+			success: (res) => {
+				if (res.confirm) {
+					const params = {
+						shopOrderId: orderInfo.value.shopOrderId,
+						dispatchVerifyStatus: "0"
+					}
+					updateOrderDispatchApi(params).then(res => {
+						if (res.code == 200) {
+							uni.showToast({
+								title: '操作成功',
+								icon: 'success'
+							})
+							uni.navigateBack()
+						}
+					})
+				}
+			}
+		})
+
+	}
+
+
+	//直接核销订单
+	const updateOrderVerify = () => {
+		const params = {
+			shopOrderId: orderInfo.value.shopOrderId
+		}
+		updateOrderVerifyApi(params).then(res => {
+			if (res.code == 200) {
+				uni.showToast({
+					title: '操作成功',
+					icon: 'success'
+				})
+				uni.navigateBack()
+			}
+		})
+	}
+
+	//0 待服务 1 服务中 2 服务完成 3 待接单
+	const startServe = () => {
+
+		// 在实际UniApp项目中,使用以下代码:
+		uni.scanCode({
+			success: (res) => {
+				console.log(res, '=============scanCode==startServe=')
+				if (res.result == orderInfo.value.shopOrderId) {
+					//这里判断 grabId 是否相同 相同的话直接更新
+					updateOrderVerify()
+				} else {
+					uni.showModal({
+						content: "服务订单与扫码订单不一致",
+						confirmText: "确认",
+						showCancel: false
+					})
+				}
+			},
+			fail: (err) => {
+				uni.showToast({
+					title: '扫码失败',
+					icon: 'none'
+				})
+			}
+		})
+
+	}
+
+
+	const handleOrderRefund = (status) => {
+		if (status == '2') {
+			uni.showModal({
+				title: '拒绝退款',
+				content: '是否确认拒绝退款?',
+				success: (res) => {
+					if (res.confirm) {
+						updateOrderRefund(status)
+					}
+				}
+			})
+			return
+		}
+		uni.showModal({
+			title: '确认退款',
+			content: '是否确认退款?',
+			success: (res) => {
+				if (res.confirm) {
+					updateOrderRefundSure(status)
+				}
+			}
+		})
+	}
+
+
+	//处理退款订单  0 待审核 1 审核通过 2 审核拒绝
+	const updateOrderRefundSure = (status) => {
+		const params = {
+			shopOrderId: orderInfo.value.shopOrderId
+		}
+		updateOrderRefundSureApi(params).then(res => {
+			if (res.code == 200) {
+				uni.showToast({
+					title: '操作成功',
+					icon: 'success'
+				})
+				uni.navigateBack()
+				// emit('success');
+			}
+		})
+	}
+
+	//处理退款订单  0 待审核 1 审核通过 2 审核拒绝
+	const updateOrderRefund = (status) => {
+		const params = {
+			shopOrderId: orderInfo.value.shopOrderId,
+			reviewResult: status
+		}
+		updateOrderRefundApi(params).then(res => {
+			if (res.code == 200) {
+				uni.showToast({
+					title: '操作成功',
+					icon: 'success'
+				})
+				uni.navigateBack()
+			}
+		})
+	}
+
+	// 发布抢单
+	const publishOrder = () => {
+		uni.navigateTo({
+			url: '/pages/dispatchOrders/publishOrder?id=' + orderInfo.value.shopOrderId
+		})
+	}
+
+	// 直接派单
+	const assignOrder = () => {
+		uni.navigateTo({
+			url: '/pages/dispatchOrders/dispatch?id=' + orderInfo.value.shopOrderId
+		})
+	}
+
+
+	const reSetBtnStatus = () => {
+		showOrderCofirmBtn.value = false
+		showOrderDispatchBtn.value = false
+		showOrderRefundBtn.value = false
+		showCallUserBtn.value = false
+	}
+
+
+	//orderType: 订单类型(1-全部订单, 2-待确认, 3-待核销, 4-已完成, 5-申请退款, 6-服务中)
+	const getStatusText = computed(() => {
+		// shop_order_status	 商品订单状态(0 待支付  1 待使用 2 退款中  3 退款成功  4 退款失败   5  服务完成)	
+		// shop_evaluate_status  评价状态(0 待评价 1 已评价)	
+		// shop_refund_review_status  订单退款审核状态(0 待审核 1 审核通过 2 审核拒绝)			
+		// shop_service_status	服务状态:0=待服务,1=正在服务中,2=服务完成	
+		// shop_confirm_status	确认状态:0=待确认,1=已确认
+		// shop_dispatch_verify_status	派单核销状态:0=待派单,1=待核销,2=已派单,3=已核销
+
+		//dispatchInfo.shopOrderServiceStatus   0 待派单 1 已派单 2 待抢单  3 已抢单
+		reSetBtnStatus()
+
+
+		if (orderInfo.value.shopOrderStatus == '2') {
+			showOrderRefundBtn.value = true
+			return '申请退款'
+		}
+		if (orderInfo.value.shopOrderStatus == '3') {
+			showCallUserBtn.value = true
+			return '退款成功'
+		}
+
+		if (orderInfo.value.shopOrderStatus == '4') {
+			showCallUserBtn.value = true
+			return '退款失败'
+		}
+
+
+		if (orderInfo.value.shopOrderStatus == '0') {
+			showCallUserBtn.value = true
+			return '待支付'
+		}
+
+		if (orderInfo.value.shopConfirmStatus == '0') {
+			showOrderCofirmBtn.value = true
+			return '待确认'
+		}
+
+
+		if (orderInfo.value.shopOrderStatus == '5') {
+			if (orderInfo.value.shopEvaluateStatus == '0') {
+				showCallUserBtn.value = true
+				return '待评价'
+			}
+			if (orderInfo.value.shopEvaluateStatus == '1') {
+				showCallUserBtn.value = true
+				return '已评价'
+			}
+			return '服务完成'
+		}
+
+		//orderDetail.shopConfirmStatus == '1' 的时候才会有下边的状态值
+		if (orderInfo.value.shopOrderStatus == '1' && orderInfo.value.shopConfirmStatus == '1') {
+
+			if (orderInfo.value.dispatchInfo && orderInfo.value.dispatchInfo.shopOrderServiceStatus == '2') {
+				showCallUserBtn.value = true
+				return '待抢单'
+			}
+			if (orderInfo.value.dispatchInfo && orderInfo.value.dispatchInfo.shopOrderServiceStatus == '3') {
+				showCallUserBtn.value = true
+				return '已抢单'
+			}
+
+			switch (orderInfo.value.shopDispatchVerifyStatus) {
+				case '0':
+					//这里需要看下是否是有会员 派单权限
+					showOrderDispatchBtn.value = true
+					return '待派单' // 待派单
+				case '1':
+					showCallUserBtn.value = true
+					return '待核销' // 待核销
+				case '2':
+					showCallUserBtn.value = true
+					return '已派单' // 已派单
+				case '3':
+					showCallUserBtn.value = true
+					return '已核销' // 已核销
+			}
+			return '待使用'
+		}
+	})
+</script>
+
+<style lang="scss" scoped>
+	.verification-container {
+		min-height: 100vh;
+		background-color: #F5F7FA;
+		position: relative;
+		padding-bottom: 140rpx;
+		/* 为底部固定按钮预留空间 */
+
+		.content {
+			padding: 20rpx;
+		}
+
+		.verification-status {
+			height: 72rpx;
+			background: #FFF7EC;
+			border-radius: 16rpx 16rpx 16rpx 16rpx;
+			align-items: center;
+			display: flex;
+			padding-left: 16rpx;
+
+			image {
+				width: 28rpx;
+				height: 28rpx;
+			}
+
+			.status-text {
+				margin-left: 8rpx;
+				height: 40rpx;
+				font-weight: 400;
+				font-size: 24rpx;
+				color: #FFAF41;
+				line-height: 40rpx;
+			}
+		}
+
+		.action-title {
+			height: 48rpx;
+			font-weight: bold;
+			font-size: 32rpx;
+			color: #333333;
+			line-height: 48rpx;
+			margin: 20rpx 0rpx;
+		}
+
+		.info-card1 {
+			background: #fff;
+			border-radius: 32rpx;
+			padding: 20rpx;
+			margin-bottom: 16rpx;
+			// F1F3F8
+			.address-item{
+				display: flex;
+												
+				&:first-child {
+				    border-bottom: 2rpx solid #F1F3F8;
+					padding-bottom: 20rpx;
+				}
+				&:last-child {
+					padding-top: 20rpx;
+				}
+			}
+
+			.user-info {
+				flex: 1;
+				margin-left: 26rpx;
+			}
+
+			.img-status-text {
+				align-self: center;
+				text-align: center;
+				flex-shrink: 0;
+
+				.img {
+					width: 56rpx;
+					height: 56rpx;
+				}
+
+				.status-text {
+					font-size: 24rpx;
+					color: #0089FF;
+					font-size: 500;
+				}
+			}
+		}
+
+
+		.info-card {
+			background-color: #ffffff;
+			border-radius: 16rpx;
+			overflow: hidden;
+			padding: 16rpx;
+			margin-top: 16rpx;
+
+			.card-header {
+				display: flex;
+				align-items: center;
+
+				image {
+					width: 35rpx;
+					height: 35rpx;
+				}
+
+				.card-title {
+					height: 48rpx;
+					line-height: 48rpx;
+					font-weight: 400;
+					font-size: 32rpx;
+					font-weight: bold;
+					color: #333;
+					margin-left: 10rpx;
+				}
+			}
+
+		}
+
+		.verification-card-body {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+
+			image {
+				margin-top: 16rpx;
+				width: 320rpx;
+				height: 320rpx;
+			}
+		}
+
+		.verification-code {
+			padding: 20rpx 0;
+			display: flex;
+			align-items: center;
+
+			.code-label {
+				font-size: 28rpx;
+				color: #666;
+			}
+
+			.code-value {
+				font-size: 32rpx;
+				color: #333;
+				font-weight: bold;
+			}
+
+		}
+
+		.fixed-footer {
+			position: fixed;
+			bottom: 0;
+			left: 0;
+			right: 0;
+			background-color: #ffffff;
+			box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
+
+			.footer-buttons {
+				display: flex;
+				justify-content: center;
+				padding: 22rpx;
+
+				.back {
+					width: 238rpx;
+					height: 88rpx;
+					background: rgba(0, 137, 255, 0.1);
+					border-radius: 8rpx 8rpx 8rpx 8rpx;
+					font-family: PingFang SC, PingFang SC;
+					font-weight: 400;
+					font-size: 32rpx;
+					color: #0089FF;
+					line-height: 88rpx;
+					text-align: center;
+				}
+
+				.confirm {
+					width: 416rpx;
+					height: 88rpx;
+					margin-left: 32rpx;
+					align-items: center;
+					background: #0089FF;
+					border-radius: 16rpx 16rpx 16rpx 16rpx;
+					font-family: PingFang SC Bold, PingFang SC Bold;
+					font-weight: 400;
+					font-size: 32rpx;
+					color: #FFFFFF;
+					line-height: 88rpx;
+					text-align: center;
+				}
+
+				.call {
+					width: 327rpx;
+					height: 88rpx;
+					border-radius: 16rpx 16rpx 16rpx 16rpx;
+					font-family: PingFang SC, PingFang SC;
+					font-weight: 400;
+					font-size: 32rpx;
+					line-height: 88rpx;
+					text-align: center;
+				}
+
+				.call-user {
+					width: 100%;
+					height: 88rpx;
+					border-radius: 16rpx 16rpx 16rpx 16rpx;
+					font-family: PingFang SC, PingFang SC;
+					font-weight: 400;
+					font-size: 32rpx;
+					line-height: 88rpx;
+					text-align: center;
+					background: #0089FF;
+					color: #FFFFFF;
+					margin: 0rpx 32rpx;
+				}
+
+				.shop {
+					background: rgba(0, 137, 255, 0.1);
+					color: #0089FF;
+				}
+
+				.user {
+					margin-left: 32rpx;
+					background: #0089FF;
+					color: #FFFFFF;
+				}
+			}
+		}
+	}
+</style>

+ 71 - 0
jd_logistics-app/pages/policy/ad_detail.vue

@@ -0,0 +1,71 @@
+<template> 
+<view class="padding20 ad_detail">
+  <image :src="HTTP_ADMIN_URL+imageUrl" mode="" class="swiper_img border_radius_20"></image>
+  <view v-html="remark" class="padding20 border_radius_20 bg_color_fff mt20"></view>
+  <view class="mt20">
+    <view v-for="(item, index) in aiAgents" :key="index" 
+    @click="toAi({agentId:item.agentId})"
+    class="flex-center-between padding20 border_radius_20 bg_color_fff mt20">
+      <image :src="HTTP_ADMIN_URL+item.imageUrl" mode="" class="aiAgents_img border_radius_20 mr20"></image>
+      <view class="ml20 flex_1 flex-center-between">
+        <view class="flex_1 mr20">
+          <view class="bold font_size35 line2">{{item.agentName}}</view>
+          <view class="gray font_size25 line2">{{item.agentDesc}}</view>
+        </view>
+        <image src="/static/img/arrow-right.png" mode="widthFix" class="menu_img"></image>
+      </view>
+    </view>
+  </view>
+</view>
+</template>
+<script setup> 
+import { ref } from "vue";
+import { HTTP_ADMIN_URL } from "@/config/app.js";
+import { getAdDetails } from "@/api/home";
+import { onLoad } from "@dcloudio/uni-app";
+import { useAppStore } from "@/stores/app";
+const appStore = useAppStore();
+
+const imageUrl = ref('');
+const remark = ref('');
+const aiAgents = ref([]);
+
+onLoad(({dictCode}) => { 
+  getAdDetailsFn(dictCode);
+})
+function getAdDetailsFn(dictCode) { 
+  getAdDetails({dictCode}).then(res => {
+    if (res.code == 200) {
+      imageUrl.value = res.data?.sysDictData?.dictValue ||  '';
+      remark.value = res.data?.sysDictData?.remark || '';
+      aiAgents.value = res.data?.aiAgents || [];
+    }
+  })
+}
+function toAi({agentId='', msgContent=''}){
+	if(agentId) appStore.UPDATE_agentId(agentId);
+	if(msgContent)appStore.UPDATE_msgContent(msgContent);
+	uni.switchTab({
+		url: '/pages/ai/ai'
+	});
+}
+
+</script>
+<style lang="scss" scoped>
+  .ad_detail{
+    height: 100%;
+    .swiper_img{
+      width: 100%;
+      height: 350rpx;
+      background-color: #ffffff;
+    }
+    .aiAgents_img{
+      width: 100rpx;
+      height: 100rpx;
+    }
+    .menu_img{
+      width: 40rpx;
+      height: 40rpx;
+    } 
+  }
+</style>

+ 23 - 0
jd_logistics-app/pages/policy/recharge_policy.vue

@@ -0,0 +1,23 @@
+<template> 
+<view class="padding30">
+  <view v-html="info.content" class="padding30 border_radius_20 bg_color_fff"></view>
+</view>
+</template>
+<script setup> 
+import { ref } from "vue";
+import { agreementRecharge } from "@/api/agreement";
+import { onLoad } from "@dcloudio/uni-app";
+const info = ref({});
+
+onLoad(() => { 
+  agreementRechargeFn();
+})
+function agreementRechargeFn() { 
+  agreementRecharge().then(res => {
+    if (res.code == 200) {
+      info.value = res.data;
+    }
+  })
+}
+
+</script>

+ 23 - 0
jd_logistics-app/pages/policy/vip_policy.vue

@@ -0,0 +1,23 @@
+<template> 
+<view class="padding30">
+  <view v-html="info.content" class="padding30 border_radius_20 bg_color_fff"></view>
+</view>
+</template>
+<script setup> 
+import { ref } from "vue";
+import { agreementMember } from "@/api/agreement";
+import { onLoad } from "@dcloudio/uni-app";
+const info = ref({});
+
+onLoad(() => { 
+  agreementMemberFn();
+})
+function agreementMemberFn() { 
+  agreementMember().then(res => {
+    if (res.code == 200) {
+      info.value = res.data;
+    }
+  })
+}
+
+</script>

+ 144 - 0
jd_logistics-app/pages/recharge/recharge.vue

@@ -0,0 +1,144 @@
+<template>
+	<view class="recharge padding30">
+		<!-- 余额 -->
+		<view class="blance color_fff border_radius_20">
+			<view class="flex-center-between">
+				<view class="font_size30 mr20">余额 ( {{appStore.moneyUnit}} )</view>
+				<view class="font_size30" @click="toWallet">账户明细</view>
+			</view>
+			<view class="font_size60 bold mt30">{{appStore.userInfo?.rechargeBalance}}</view>
+		</view>
+		<!-- 充值金额 -->
+    <view class="padding30 border_radius_20 bg_color_fff mt20">
+      <view class="font_size30 bold">充值金额</view>
+      <view class="grid-container mt30">
+        <view class="flex-column-center bg_color_f5 border_radius_20 paddingTB20 rePrice"
+				:class="{active: ruleId==item.ruleId }"
+				@click="ruleId = item.ruleId;orderAmt = item.rechargeAmount"
+				 v-for="(item, index) in ruleList" :key="index">
+          <view class="bold font_size40 color_price">{{item.rechargeAmount}}</view>
+          <view class="font_size20 mt10 gray">{{item.offerTag}}</view>
+					<image src="/static/img/check.png" mode="widthFix" class="checked_img" v-if="ruleId==item.ruleId"></image>
+        </view>
+      </view>
+			<view class="mt30">
+				<view class="bold font_size25">{{rechargeRuleInfo.agreementName}}</view>
+				<view class="mt10 gary font_size25">
+					1.活动有效期为 {{ruleList[0]?.startTime}} 至 {{ruleList[0]?.endTime}}。
+				</view>
+				<view class="mt20 gary font_size25" v-html="rechargeRuleInfo.content"></view>
+			</view>
+    </view>
+		<agreeRecharge ref="agreeRecharge" @setAloneChecked="setAloneChecked"></agreeRecharge>
+		<!-- foot -->
+    <view class="foot bg_color_fff">
+			<view class="order_btn paddingTB20 flex_1 text_align_center" @click="submitForm">充值</view>
+		</view>
+	</view>
+</template>
+<script setup>
+import { ref } from "vue";
+import { getRuleList } from "@/api/user";
+import { createOrder } from "@/api/order";
+import { wxPay,getUserInfo } from "@/utils/util.js";
+import { agreementRechargeRule } from "@/api/agreement";
+import { agreeRecharge } from "@/components/agreeRecharge.vue"
+import { useToast } from "@/hooks/useToast";
+const { Toast } = useToast();
+import { onLoad } from "@dcloudio/uni-app";
+import { useAppStore } from "@/stores/app";
+const appStore = useAppStore();
+const ruleList = ref([]);
+const orderId = ref('');
+const rechargeRuleInfo = ref('');
+const ruleId = ref('');
+const orderAmt = ref('');
+const aloneChecked = ref(false);
+
+onLoad(() => {
+	getRuleListFn();
+	agreementRechargeRuleFn();
+});
+async function submitForm(){
+	if(!aloneChecked.value){
+		Toast({ title: "请先阅读并同意充值协议", icon: 'none' });
+		return;
+	}
+	const res = await createOrder({
+		payMethod:0,//支付方式 0微信 1余额
+		productType:1,//商品类型 0购买会员 1充值
+		productId:ruleId.value,
+		orderNum:1,//订单数量
+		orderAmt:orderAmt.value//订单金额
+	});
+	//payData
+	orderId.value = res.data.orderId;
+	const payInfo = res.data.payData.prepayWithRequestPaymentResponse
+	wxPay({
+		timeStamp:payInfo.timeStamp,
+		nonceStr:payInfo.nonceStr,
+		packageVal:payInfo.packageVal,
+		signType:payInfo.signType,
+		paySign:payInfo.paySign,
+	},to_success_pay);
+}
+function to_success_pay({isSuccess}){
+	console.log('to_success_pay',isSuccess);
+	uni.navigateTo({
+    url: `/pages/recharge/success_pay?orderId=${orderId.value}&isSuccess=${isSuccess}&payMethod=0`
+  })
+}
+function toWallet(){
+	uni.navigateTo({
+		url: '/pages/recharge/wallet'
+	});
+}
+function getRuleListFn(){ 
+	getRuleList().then(res => {
+		if(res.code == 200){
+			ruleList.value = res.data || [];
+			if(ruleList.value.length > 0){
+				ruleId.value = ruleList.value[0].ruleId || '';
+				orderAmt.value = ruleList.value[0].rechargeAmount || '';
+			}
+		}
+	})
+}
+function agreementRechargeRuleFn(){ 
+	agreementRechargeRule().then(res => {
+		if(res.code == 200){
+			rechargeRuleInfo.value = res.data || {};
+		}
+	})
+}
+function setAloneChecked(value){
+  aloneChecked.value = value;
+}
+</script>
+<style lang="less" scoped>
+.recharge{
+  background: #f5f5f5;
+	.blance{
+		background-color: #fb7145;
+		padding: 30rpx 30rpx 60rpx;
+	}
+	.rePrice{
+		position: relative;
+		border: 1rpx solid transparent;
+		&.active{
+			border: 1rpx solid #fb7145;
+		}
+		.checked_img{
+			width: 40rpx;
+			height: 40rpx;
+			position: absolute;
+			top: 50%;
+			right: 20rpx;
+			transform: translateY(-50%);
+		}
+	}
+	.order_btn{
+		background-color: #fb7145;
+	}
+}
+</style>

+ 98 - 0
jd_logistics-app/pages/recharge/success_pay.vue

@@ -0,0 +1,98 @@
+<template>
+  <view class="pay-success-container">
+    <!-- 支付成功图标及状态 -->
+    <view class="icon-circle">
+      <image class="success-icon" src="/static/success_card.png"></image> 
+    </view>
+    <text class="title">{{title}}</text>
+    <text class="desc gray">{{msg}}</text>
+    <!-- 查看订单按钮 -->
+    <button class="check-order-btn bg_color_primary" @click="goBack">返回</button>
+  </view>
+</template>
+
+<script setup>
+import { ref,computed } from 'vue';
+import { payResult } from "@/api/order.js";
+import { getUserInfo } from "@/utils/util.js";
+import { onLoad } from "@dcloudio/uni-app";
+const orderId = ref('');
+const isSuccess = ref(1);//1成功 0失败;
+const payMethod = ref('');//支付方式 0微信 1余额
+
+const title = computed(()=>{
+	return isSuccess.value==1 ? '支付成功' : '支付失败'
+})
+const msg = computed(()=>{
+	return isSuccess.value==1 ? '非常感谢您购买我们的服务~' : '抱歉,支付失败,请稍后再试~'
+})
+
+onLoad((e)=>{
+	orderId.value = e.orderId || 0;
+	isSuccess.value = e.isSuccess;
+	payMethod.value = e.payMethod;
+  console.log("pay-success-onload",e);
+  getUserInfo();
+  if(payMethod.value == 0)payResultFn();
+})
+// 导航到订单详情页面
+function goBack() {
+  uni.navigateBack({
+    delta: 1
+  });
+}
+function payResultFn() {
+  payResult({
+    orderId: orderId.value,
+  }).then(res => {
+    console.log("payResult", res);
+  });
+}
+</script>
+
+<style scoped>
+.pay-success-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: start;
+  min-height: 100vh;
+  background-color: #f5f5f5;
+  padding: 0 20rpx;
+}
+.icon-circle {
+  width: 160rpx;
+  height: 160rpx;
+  border-radius: 50%;
+  background-color: #ffd9d1;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin: 120rpx 0 40rpx;
+}
+.success-icon {
+  width: 80rpx;
+  height: 80rpx;
+}
+.title {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 20rpx;
+}
+.desc {
+  font-size: 28rpx;
+  text-align: center;
+  margin-bottom: 60rpx;
+  line-height: 44rpx;
+}
+.check-order-btn {
+  /* width: 320rpx; */
+	width: 100%;
+  height: 88rpx;
+  line-height: 88rpx;
+  color: #fff;
+  font-size: 32rpx;
+  border-radius: 44rpx;
+}
+</style>

+ 295 - 0
jd_logistics-app/pages/recharge/vip.vue

@@ -0,0 +1,295 @@
+<template>
+	<view class="vip">
+    <view class="vip_top">
+      <headerInfo title="会员中心" :isBack="true"></headerInfo>
+      <view class="flex-center-between color_fff mg20">
+        <u-avatar  @click="toUser"
+					size="100rpx"
+					shape="circle"
+					:src="appStore?.userInfo?.avatar"
+					mode="aspectFill"
+				></u-avatar>
+        <view class="flex_1 flex-center-between ml20">
+          <view class="flex-column flex_1">
+            <view>
+              <text class="font_size32 nickName bold mr20">{{appStore.userInfo?.nickName}}</text>
+              <text class="memberPlanName" v-if="appStore.userInfo?.memberStatus==1">{{appStore.userInfo?.memberPlanName}}</text>
+            </view>
+            <text class="font_size32 nickName mt10" v-if="appStore.userInfo?.memberStatus==1">
+							<text class="vipTime">到期时间: {{appStore.userInfo?.memberExpire}}</text>
+            </text>
+            <text class="font_size32 nickName mt10" v-else>未开通VIP,无法享受会员</text>
+          </view>
+          <image src="/static/img/vip/vip.png" mode="" style="width:204rpx;height:204rpx;"/>
+        </view>
+      </view>
+    </view>
+    <view class="padding20 vip_content">
+      <!-- 会员充值 -->
+      <view class="flex-center mt10">
+        <view class="flex-center-between">
+          <view class="line_vip"></view>
+            <text class="title_vip font_size32 bold">会员充值</text>
+          <view class="line_vip reverse"></view>
+        </view>
+      </view>
+      <view class="mt20 vip_pay">
+        <view class="grid-container3 mt30">
+          <view class="flex-column-center border_radius_20 paddingTB20 plan" 
+          :class="{'active':planId==item.planId}"
+          @click="planId=item.planId;orderAmt=item.price;"
+          v-for="(item, index) in planList" :key="index">
+            <view class="bold font_size28 planName">{{item.planName}}</view>
+            <view class="font_size35 mt20 color_price"><text class="font_size20">¥</text>{{item.price}}</view>
+            <view class="font_size20 mt20 gray line_through">¥{{item.originalPrice}}</view>
+            <view class="bold font_size28 planName mt20">{{item.durationUnit=='lifetime'?'':item.duration}}{{item.durationUnitName}}</view>
+            <view class="hot" v-if="item.durationUnit=='lifetime'">
+              <image src="/static/img/vip/fire.png" mode="" style="width:20rpx;height:20rpx"/>
+              <text class="font_size20 color_fff">推荐</text>
+            </view>
+          </view>
+        </view>
+      </view>
+      <!-- 会员专享4大权益 -->
+      <view class="flex-center mt30">
+        <view class="flex-center-between">
+          <view class="line_vip"></view>
+            <text class="title_vip font_size32 bold">会员专享4大权益</text>
+          <view class="line_vip reverse"></view>
+        </view>
+      </view>
+      <view class="grid-container mt30">
+        <view class="flex-center-between border_radius_20 bg_color_fff padding20" v-for="(item, index) in quanyilList" :key="index">
+          <image :src="item.icon" class="icon mr20" mode="" />
+          <view class="flex_1">
+            <view class="bold font_size28">{{item.title}}</view>
+            <view class="font_size24 mt10 gray">{{item.content}}</view>
+          </view>
+        </view>
+      </view>
+     
+      <!-- 付款方式 -->
+      <view class="padding30 border_radius_20 bg_color_fff mt20"  v-if="isEdit!=1">
+        <view class="font_size32 bold mb20">付款方式</view>
+        <view class="flex-center-between mt20 paddingTB20" v-for="(item, index) in payments" :key="index" @click="payType=item.value">
+          <view class="flex-center-between">
+            <image :src="item.icon" mode="widthFix" class="weixin_img mr20"></image>
+            <text>{{item.label}}</text>
+            <text class="color_price ml20 font_size24" v-if="index==1"> 余额:{{appStore.userInfo?.rechargeBalance}} ({{appStore.moneyUnit}})</text>
+          </view>
+          <view class="payment-radio">
+            <view
+              class="radio-circle"
+              :class="{ checked: payType === item.value }"
+            ></view>
+          </view>
+        </view>
+      </view>
+      <agreeVip ref="agreeVip" @setAloneChecked="setAloneChecked"></agreeVip>
+    </view>
+    <!-- foot -->
+    <view class="foot bg_color_fff">
+			<view class="order_btn paddingTB20 flex_1 text_align_center" @click="submitForm">
+        <text>{{appStore.userInfo?.memberStatus==1?'续费':'立即解锁'}}</text>
+        <text>¥{{orderAmt}}</text>
+      </view>
+		</view>
+	</view>
+</template>
+<script setup>
+import { ref } from "vue";
+import { wxPay,getUserInfo } from "@/utils/util.js";
+import headerInfo from "@/components/headerInfo.vue";
+import { createOrder } from "@/api/order";
+import { useToast } from "@/hooks/useToast";
+const { Toast } = useToast();
+import { getPlanList } from "@/api/user";
+import { agreeVip } from "@/components/agreeVip"
+import { onLoad } from '@dcloudio/uni-app'
+import { useAppStore } from "@/stores/app"
+const appStore = useAppStore();
+const aloneChecked = ref(false);
+const planId = ref('');
+const orderId = ref('');
+const orderAmt = ref('');
+const planList = ref([]);
+const payType = ref(0);
+const payments = ref([
+  {
+    value: 0,
+    label: "微信支付",
+		icon: "/static/img/weixin.png"
+  },
+  {
+    value: 1,
+    label: "钱包支付",
+		icon: "/static/img/qianbao.png"
+  },
+]);
+const quanyilList = ref([
+  {
+    title: "问答无限制",
+    content: "最新AI聊天模型接口",
+    icon: "/static/img/vip/question.png"
+  },
+  {
+    title: "学习帮手",
+    content: "帮您提高创作效率",
+    icon: "/static/img/vip/xuexi.png"
+  },
+  {
+    title: "疑问解答",
+    content: "互动性聊天体验",
+    icon: "/static/img/vip/yiwen.png"
+  },
+  {
+    title: "私人助理",
+    content: "提供最优解决方案",
+    icon: "/static/img/vip/siren.png"
+  },
+]);
+async function submitForm(){
+  if(!aloneChecked.value){
+		Toast({ title: "请先阅读并同意VIP会员开通协议", icon: 'none' });
+		return;
+	}
+  const res = await createOrder({
+		payMethod:payType.value,//支付方式 0微信 1余额
+		productType:0,//商品类型 0购买会员 1充值
+		productId:planId.value,
+		orderNum:1,//订单数量
+		orderAmt:orderAmt.value//订单金额
+	});
+  orderId.value = res.data.orderId;
+  // 余额支付
+  if(payType.value==1){
+    //1成功 0失败;
+    const paySuccess = res.data.paySuccess;
+    to_success_pay({isSuccess:paySuccess?1:0});
+  }else{ 
+    const payInfo = res.data.payData.prepayWithRequestPaymentResponse
+    wxPay({
+      timeStamp:payInfo.timeStamp,
+      nonceStr:payInfo.nonceStr,
+      packageVal:payInfo.packageVal,
+      signType:payInfo.signType,
+      paySign:payInfo.paySign,
+    },to_success_pay);
+  }
+}
+function to_success_pay({isSuccess}){
+	console.log('to_success_pay',isSuccess);
+	uni.navigateTo({
+    url: `/pages/recharge/success_pay?orderId=${orderId.value}&isSuccess=${isSuccess}&payMethod=${payType.value}`
+  })
+}
+onLoad(() => {
+	getPlanListFn();
+});
+function getPlanListFn(){
+	getPlanList().then(res => {
+		if(res.code == 200){
+			planList.value = res.data || [];
+      //默认单位是durationUnit=='lifetime'
+      if(planList.value.length>0){
+        let plan = planList.value.find(item=>item.durationUnit=='lifetime');
+        planId.value = plan?.planId || planList.value[0].planId;
+        orderAmt.value = plan?.price || planList.value[0].price;
+      }
+		}
+	})
+}
+function setAloneChecked(value){
+  aloneChecked.value = value;
+}
+async function toUser(){
+	uni.navigateTo({
+		url: '/pages/user/user'
+	});
+}
+</script>
+<style lang="less" scoped>
+.vip{
+  height: 100vh;
+  background: #f5f5f5;
+  
+  .vip_top{
+    //#51402E #2B2724 渐变色,从上向下
+    background: linear-gradient(90deg, #51402E 0%, #2B2724 100%);
+    padding: 0 0 50rpx 30rpx;
+    .nickName{
+      color: #DDD3D0;
+    }
+  }
+  .vip_content{
+    position: relative;
+    top: -40rpx;
+    border-radius: 48rpx 48rpx 0 0;
+    background: #f5f5f5;
+    padding-bottom: 100rpx;
+    .title_vip{
+      color: #333333 ;
+      margin: 0 30rpx;
+    }
+    .line_vip{
+      width: 92rpx;
+      height: 6rpx;
+      background: linear-gradient(90deg, #D8D8D8  0%, #333333 100%);
+      &.reverse{
+        transform: rotate(180deg);
+      }
+    }
+  }
+  .gray{
+    color: #999;
+  }
+  .grid-container{
+    gap: 20rpx;
+    .icon{
+      width: 70rpx;
+      height: 70rpx;
+    }
+  }
+  .vip_pay{
+    .plan{
+      padding: 30rpx 20rpx 40rpx;
+      border:1px solid #CCCCCC ;
+      position: relative;
+      background-color: #ffffff;
+      &.active{
+        background-color: #FEF7EA ;
+        border-color: #874605 
+      }
+      .color_price{
+        color: #874605;
+      }
+      .planName{
+        color: #333333;
+      }
+      .hot{
+        position: absolute;
+        top: -20rpx;
+        left: 0rpx;
+        background: linear-gradient(90deg, #2B2724   0%, #503F2E  100%);
+        color: #fff;
+        font-size: 20rpx;
+        padding: 5rpx 10rpx;
+        border-radius: 10rpx 0 10rpx 0;
+      }
+    }
+  }
+  .weixin_img{
+    width: 60rpx;
+    height: 60rpx;
+  }
+  .order_btn ,.memberPlanName{
+		background: linear-gradient(90deg, #FDE492    0%, #FDB85D  100%);
+    color: #874605 ;
+	}
+  .memberPlanName{
+    padding: 5rpx 10rpx;
+    border-radius: 20rpx;
+    font-size: 24rpx;
+  }
+}
+</style>

+ 100 - 0
jd_logistics-app/pages/recharge/wallet.vue

@@ -0,0 +1,100 @@
+<template>
+<view class="wallet">
+	<z-paging
+	ref="pagingRef"
+	class="paginng-contaner"
+	:default-page-size="20"
+	:use-refresher-status-bar-placeholder="true"
+	v-model="list"
+	@query="handleQuery"
+	>
+		<!-- 余额 -->
+		<view class="blance">
+			<view class="flex-center-between">
+				<view class="color_fff">
+					<text class="font_size60 bold mr20">{{appStore.userInfo?.rechargeBalance}}</text>
+					<text class="font_size30">{{appStore.moneyUnit}}</text>
+				</view>
+				<view class="order_btn plain chongzhi font_size30" @click="toRecharge">充值</view>
+			</view>
+			<view class="color_fff font_size25 mt20">账户余额 ( {{appStore.moneyUnit}} )</view>
+		</view>
+		<!-- 账户明细 -->
+		<view class="padding30 accountDetails bg_color_f5">
+			<view class="flex-center-flex-start mb20">
+				<view class="line_vertical"></view>
+				<view class="font_size30 bold">账户明细</view>
+			</view>
+			<view class="bg_color_fff border_radius_20 padding30">
+				<view class="flex-center-between paddingTB20 border_bottom" v-for="item in list" :key="item.recordId">
+					<view class="flex_1">
+						<!-- 交易类型(0=充值,1=消费,2=退款) -->
+						<view class="font_size25 bold">
+							{{item.transactionTypeName}}
+						</view>
+						<view class="font_size20 color_999 mt10">{{item.createTime}}</view>
+					</view>
+					<!-- 交易金额(充值/退款为正,消费为负) -->
+					<view class="flex-column-end">
+						<text class="font_size40 color_price">{{item.amount}}</text>
+						<text class="font_size25 gray">余额{{item.balanceAfter}}</text>
+					</view>
+				</view>
+			</view>
+		</view>
+	</z-paging>
+</view>
+</template>
+<script setup>
+import { ref } from "vue";
+import { getRecordList } from "@/api/user";
+import { useAppStore } from "@/stores/app"
+const appStore = useAppStore();
+const pagingRef = ref();
+const list = ref([]);
+// 下拉刷新和滚动底部会自动触发此方法
+async function handleQuery(page, pageSize, from) {
+  try {
+    const params = {
+      pageNum: page,
+      pageSize,
+			reasonable:false,
+			orderByColumn: 'createTime',
+			isAsc: 'desc'
+    };
+    const { rows } = await getRecordList(params);
+    pagingRef.value.complete(rows);
+  } catch (e) {
+		console.log('msg-comment',e)
+    pagingRef.value.complete(false);
+  }
+}
+function toRecharge(){
+	uni.navigateTo({
+		url: '/pages/recharge/recharge'
+	});
+}
+</script>
+<style lang="less" scoped>
+.wallet{
+	.blance{
+		padding: 80rpx 60rpx;
+		background-color: #fb7145;
+	}
+	.chongzhi{
+		color: #fb7145;
+		padding: 10rpx 40rpx;
+		border-radius: 50rpx;
+	}
+	.line_vertical{
+		background-color: #fb7145;
+		margin-right: 20rpx;
+	}
+	.accountDetails{
+		border-radius: 30rpx 30rpx 0 0;
+		position: relative;
+		top: -30rpx;
+		padding-bottom: 0;
+	}
+}
+</style>

+ 209 - 0
jd_logistics-app/pages/search/search.vue

@@ -0,0 +1,209 @@
+<template>
+	<view class="container">
+
+		<!-- 导航栏 -->
+		<view class="nav-bar">
+			<text class="title">查快递</text>
+		</view>
+
+		<!-- 主体内容 -->
+		<view class="main-content">
+			<!-- Logo 和公司名称 -->
+			<view class="company-section">
+				<view class="logo-placeholder">
+					<!-- 这里可以使用网络图片或本地图标 -->
+					<image class="logo" src="@/static/img/logo.png" mode="aspectFit" />
+				</view>
+				<!-- <text class="company-name">瑞鲸科技</text>
+        <text class="company-en-name">REJOIN</text> -->
+			</view>
+
+			<!-- 搜索区域 -->
+			<view class="search-section">
+				<view class="search-input-wrapper">
+					<image class="search-icon" src="@/static/img/search.png" />
+					<input class="search-input" placeholder="请输入要查询的运单号" placeholder-class="placeholder-style"
+						@focus="onInputFocus" @blur="onInputBlur" v-model="trackingNumber" />
+					<view class="search-btn" @click="handleSearch">
+						搜索
+					</view>
+				</view>
+
+				
+			</view>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import {
+		ref
+	} from 'vue'
+
+	const trackingNumber = ref('')
+	const isInputFocused = ref(false)
+
+	const onInputFocus = () => {
+		isInputFocused.value = true
+	}
+
+	const onInputBlur = () => {
+		isInputFocused.value = false
+	}
+
+	const handleSearch = () => {
+		uni.navigateTo({
+			url:'/pages/logistics/index'
+		})
+		return
+		if (!trackingNumber.value.trim()) {
+			uni.showToast({
+				title: '请输入运单号',
+				icon: 'none'
+			})
+			return
+		}
+
+		// 这里处理搜索逻辑
+		console.log('搜索运单号:', trackingNumber.value)
+		uni.showLoading({
+			title: '查询中...'
+		})
+
+		// 模拟API调用
+		setTimeout(() => {
+			uni.hideLoading()
+			uni.showToast({
+				title: '查询成功',
+				icon: 'success'
+			})
+		}, 1500)
+	}
+</script>
+
+<style lang="scss" scoped>
+	.container {
+		width: 100%;
+		min-height: 100vh;
+		background: linear-gradient( 135deg, #CFE9FF 0%, #F5F7FA 50.86%);
+		display: flex;
+		flex-direction: column;
+	}
+
+
+	/* 导航栏样式 */
+	.nav-bar {
+		margin-top: 100rpx;
+		width: 100%;
+		height: 52rpx;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+
+		.title {
+			height: 52rpx;
+			line-height: 52rpx;
+			font-size: 36rpx;
+			font-weight: 600;
+			color: #333;
+		}
+	}
+
+	/* 主体内容 */
+	.main-content {
+		flex: 1;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		padding-top: 300rpx;
+	}
+
+	/* 公司信息区域 */
+	.company-section {
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		margin-bottom: 72rpx;
+
+		.logo-placeholder {
+			width: 244rpx;
+			height: 70rpx;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			.logo {
+				width: 100%;
+				height: 100%;
+			}
+		}
+
+		.company-name {
+			font-size: 40rpx;
+			font-weight: 600;
+			color: #000000;
+			margin-bottom: 8rpx;
+		}
+
+		.company-en-name {
+			font-size: 28rpx;
+			color: #666666;
+			letter-spacing: 2rpx;
+		}
+	}
+
+	/* 搜索区域 */
+	.search-section {
+		width: 100%;
+		padding: 0 32rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+
+		.search-input-wrapper {
+			width: 100%;
+			height: 88rpx;
+			background: #FFFFFF;
+			border-radius: 44rpx;
+			font-size: 28rpx;
+			color: #333;
+			border: 4rpx solid #1B64F0;
+			padding: 6rpx;
+			display: flex;
+			justify-content: center;
+			justify-items: center;
+			align-items: center;
+			
+			.search-icon{
+				width: 40rpx;
+				height: 40rpx;
+				margin-left: 18rpx;
+			}
+
+			.search-input {
+				flex: 1;
+				margin-left: 8rpx;
+				margin-right: 8rpx;
+			}
+
+			
+			.placeholder-style {
+				color: #999999;
+			}
+			
+			.search-btn {
+				width: 160rpx;
+				height: 76rpx;
+				background: #1B64F0;
+				border-radius: 38rpx;
+				font-weight: 400;
+				font-size: 32rpx;
+				color: #FFFFFF;
+				line-height: 76rpx;
+				text-align: center;
+				font-style: normal;
+			}
+				
+		}
+
+	}
+</style>

+ 110 - 0
jd_logistics-app/pages/user/user.vue

@@ -0,0 +1,110 @@
+<template>
+	<view class="user padding30">
+		
+		<view class="padding30 bg_color_fff border_radius_20">
+			<u-form labelPosition="left" :model="userInfo" :rules="rules" ref="formRef" labelWidth="auto">
+				
+				<u-form-item label="头像" prop="avatar" :borderBottom="true" required>
+					<view class="avatar flex-center-flex-end">
+						<button class="chooseAvatar" open-type="chooseAvatar" @chooseavatar="chooseAvatar">
+									<u-avatar 
+									size="120rpx"
+									shape="circle"
+									:src="userInfo.avatar"
+									mode="aspectFill"
+								></u-avatar>
+						</button>
+					</view>
+						
+				</u-form-item>
+				<u-form-item label="昵称" prop="nickName" :borderBottom="true" required>
+					<u-input v-model="userInfo.nickName" placeholder="请输入昵称" border="none" clearable inputAlign="right" type="nickname"></u-input>
+				</u-form-item>
+				<u-form-item label="手机号" :borderBottom="false" required>
+					<u-input v-model="userInfo.userPhone" placeholder="账号" border="none" clearable inputAlign="right" readonly></u-input>
+				</u-form-item>
+			</u-form>
+		</view>
+		<view class="foot bg_color_fff">
+			<view class="order_btn paddingTB20 flex_1 text_align_center" @click="submitForm">提交</view>
+		</view>
+	</view>
+</template>
+<script setup>
+import { ref,reactive } from 'vue'
+import { userEdit } from "@/api/user.js";
+import { telEncrypt,chooseImageOne,uploadFile } from "@/utils/util.js";
+import { useToast } from "@/hooks/useToast";
+const { Toast } = useToast();
+import { useAppStore } from "@/stores/app";
+const appStore = useAppStore();
+
+const formRef = ref(null);
+const dgtPopupRef = ref(null);
+const userInfo = ref({
+  userPhone: telEncrypt(appStore.userInfo?.userPhone),
+  nickName: appStore.userInfo?.nickName,
+  avatar: appStore.userInfo?.avatar,
+});
+const rules = reactive({
+  "avatar": [
+    { required: true, message: '请上传头像', trigger: ['blur', 'change'] },
+  ],
+  "nickName": [
+    { required: true, message: '请输入昵称', trigger: ['blur', 'change'] },
+  ]
+});
+// 提交表单
+async function submitForm(){
+  formRef.value
+	.validate()
+	.then((valid) => {
+		console.log('submitForm',valid);
+		if (valid) {
+			userEdit(userInfo.value).then(async res=>{ 
+				await appStore.USERINFO();
+				uni.navigateBack();
+			})
+		} else {
+			Toast({ title: "请完善个人资料" });
+		}
+	})
+	.catch((e) => {
+		console.log('error submit!!',e[0].message);
+		Toast({ title: e[0]?.message || "请完善个人资料!" });
+	});
+};
+
+async function uploadImage(){
+  const res = await chooseImageOne('user/userAvatarUpload');
+  console.log('uploadImage',res);
+  if(res){
+  	userInfo.value.avatar= res.data
+  }
+}
+async function chooseAvatar(e){
+	console.log('chooseAvatar',e);
+	if(e.detail?.avatarUrl){
+		const res = await uploadFile(e.detail?.avatarUrl,'user/userAvatarUpload');
+		console.log('uploadImage',res);
+		if(res){
+			userInfo.value.avatar= res.data
+		}
+	}
+	
+
+}
+</script>
+
+<style lang="scss">
+.user{ 
+	.foot{
+		.order_btn{
+			border-radius: 50rpx;
+		}
+	}
+	.avatar{
+		width: 100%;
+	}
+}
+</style>

+ 60 - 0
jd_logistics-app/pages/webView/webView.vue

@@ -0,0 +1,60 @@
+<template>
+  <view class="web-view-container">
+    <web-view :src="webUrl" @message="handleMessage" @error="handleError"></web-view>
+  </view>
+</template>
+
+<script setup>
+import { ref  } from 'vue';
+import { onBackPress,onLoad } from '@dcloudio/uni-app';
+
+// 页面参数
+const webUrl = ref('');
+
+// 页面加载时接收参数
+onLoad((options) => {
+  // 从跳转入参中获取url,如果没有则使用默认地址
+  if (options.url) {
+    // 解码URL,防止参数传递时的编码问题
+    webUrl.value = decodeURIComponent(options.url);
+  } else {
+    // 默认地址,可以根据实际需求修改
+    webUrl.value = 'about:blank';
+  }
+});
+
+// 返回上一页
+function goBack() {
+  uni.navigateBack();
+}
+
+// 处理web-view发送的消息
+function handleMessage(e) {
+  console.log('web-view message:', e);
+  // 可以根据实际需求处理来自web-view的消息
+}
+
+// 处理web-view加载错误
+function handleError(e) {
+  console.error('web-view load error:', e);
+  // 可以在这里添加错误处理逻辑,如显示错误页面等
+}
+
+// 监听返回按钮事件
+onBackPress(() => {
+  goBack();
+  return true;
+});
+</script>
+
+<style scoped lang="scss">
+.web-view-container {
+  width: 100%;
+  height: 100vh;
+  background-color: #f5f5f5;
+}
+web-view {
+  flex: 1;
+  width: 100%;
+}
+</style>

+ 538 - 0
jd_logistics-app/static/css/base.scss

@@ -0,0 +1,538 @@
+@charset "UTF-8";
+wx-image{
+	height: auto;
+}
+.padding20 {
+	padding: 20rpx
+}
+.paddingTB20 {
+	padding: 20rpx 0
+}
+.paddingTB30 {
+	padding: 30rpx 0
+}
+.paddingTB10 {
+	padding: 10rpx 0
+}
+
+.pad20 {
+	padding: 0 20rpx
+}
+
+.padding15 {
+	padding: 15rpx
+}
+.padding30 {
+	padding: 30rpx
+}
+
+.pad30 {
+	padding: 0 30rpx
+}
+.pt20 {
+	padding-top: 20rpx
+}
+.pb15 {
+	padding-bottom: 15rpx
+}
+.pb20 {
+	padding-bottom: 20rpx
+}
+.pb30 {
+	padding-bottom: 30rpx
+}
+
+.mb30 {
+	margin-bottom: 30rpx;
+}
+.mr20 {
+	margin-right: 20rpx;
+}
+.mr10 {
+	margin-right: 10rpx;
+}
+.ml20 {
+	margin-left: 20rpx;
+}
+.mt20 {
+	margin-top: 20rpx;
+}
+.mt30 {
+	margin-top: 30rpx;
+}
+.mt10 {
+	margin-top: 10rpx;
+}
+.mb20 {
+	margin-bottom: 20rpx;
+}
+
+page, view, text, image, button, input, scroll-view, swiper{
+	box-sizing: border-box
+}
+
+page {
+	font-size: 28rpx;
+	background-color: #f5f5f5 !important;
+	/* background-color: #ffffff !important; */
+	color: #333;
+	/* height: 100%; */
+}
+
+body,html {
+	background-color: #f5f5f5 !important;
+	/* background-color: #ffffff !important; */
+/* 	height: unset */
+}
+
+button {
+	padding: 0;
+	margin: 0;
+	line-height: normal;
+	background-color: #fff
+}
+
+button::after {
+	border: 0
+}
+
+
+
+radio .wx-radio-input.wx-radio-input-checked {
+	border: 1px solid #E93323 !important;
+	background-color: #E93323 !important
+}
+
+radio .uni-radio-input {
+	border-radius: 50%;
+	width: 38rpx;
+	height: 38rpx
+}
+
+radio .uni-radio-input.uni-radio-input-checked {
+	border: 1px solid #E93323 !important;
+	background-color: #E93323 !important
+}
+
+checkbox .wx-checkbox-input {
+	border-radius: 50%;
+	width: 38rpx;
+	height: 38rpx;
+	margin-right: 0 !important;
+}
+
+checkbox .wx-checkbox-input.wx-checkbox-input-checked {
+	border: 1px solid #E93323 !important;
+	background-color: #E93323 !important;
+	color: #fff!important;
+	margin-right: 0 !important;
+}
+
+checkbox .wx-checkbox-input.wx-checkbox-input-checked::before {
+	font-size: 35rpx
+}
+
+checkbox .uni-checkbox-input {
+	border-radius: 50%;
+	width: 38rpx;
+	height: 38rpx
+}
+
+checkbox .uni-checkbox-input.uni-checkbox-input-checked {
+	border: 1px solid #E93323 !important;
+	background-color: #E93323 !important;
+	color: #fff!important
+}
+
+checkbox .uni-checkbox-input.uni-checkbox-input-checked::before {
+	font-size: 35rpx
+}
+
+.line1 {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap
+}
+
+.line2 {
+	word-break: break-all;
+	display: -webkit-box;
+	-webkit-line-clamp: 2;
+	-webkit-box-orient: vertical;
+	overflow: hidden;
+	/* height: 84rpx; */
+}
+
+.mask {
+	position: fixed;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	background-color: #000;
+	opacity: .5;
+	z-index: 5
+}
+
+@keyframes load {
+	from {
+		transform: rotate(0)
+	}
+
+	to {
+		transform: rotate(360deg)
+	}
+}
+
+@-webkit-keyframes load {
+	from {
+		transform: rotate(0)
+	}
+
+	to {
+		transform: rotate(360deg)
+	}
+}
+
+.loadingpic {
+	animation: load 3s linear 1s infinite;
+	--webkit-animation: load 3s linear 1s infinite
+}
+
+.loading-list {
+	animation: load linear 1s infinite;
+	-webkit-animation: load linear 1s infinite;
+	font-size: 40rpx;
+	margin-right: 22rpx
+}
+
+.loading {
+	width: 100%;
+	height: 100rpx;
+	line-height: 100rpx;
+	align-items: center;
+	justify-content: center;
+	position: relative;
+	text-align: center
+}
+
+.loading .line {
+	position: absolute;
+	width: 450rpx;
+	left: 150rpx;
+	top: 50rpx;
+	height: 1px;
+	border-top: 1px solid #eee
+}
+
+.loading .text {
+	position: relative;
+	display: inline-block;
+	padding: 0 20rpx;
+	background: #fff;
+	z-index: 2;
+	color: #777
+}
+
+.loadingicon .loading {
+	animation: load linear 1s infinite;
+	font-size: 45rpx;
+	color: #000
+}
+
+.loadingicon {
+	width: 100%;
+	height: 80rpx;
+	overflow: hidden
+}
+.bg-color-huic{
+	background: #F1F1F1!important;
+	border: 1px solid #ccc!important;
+	color: #ccc!important;
+}
+.nowrap{
+	white-space: nowrap;
+}
+/*flex样式*/
+.flex_1{
+  flex:1;
+}
+.flex{
+  display: flex;
+}
+.flex_2{
+  flex: 2;
+}
+.flex-between{/*两边对齐*/
+  display: flex;
+  justify-content: space-between;
+}
+.flex-align-center{/*垂直居中*/
+  display: flex !important;
+  align-items: center;
+}
+.flex-center{/*水平垂直居中*/
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.flex-center-flex-end{/*水平垂直居中-尾部对齐*/
+  display: flex;
+  justify-content: flex-end;
+  align-items: center;
+}
+.flex-center-box-end{/*水平垂直居中-铺满盒内*/
+  display: -webkit-inline-box;
+  justify-content: flex-end;
+  align-items: center;
+}
+.flex-center-flex-start{/*水平垂直居中-首部对齐*/
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+}
+.flex-center-around{/*水平垂直居中-平均对齐*/
+  display: flex;
+  justify-content: space-around;
+  align-items: center;
+}
+.flex-center-between{/*水平垂直居中-两边对齐*/
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.flex-column{/*竖直方向*/
+  display: flex;
+  flex-direction: column;
+}
+.flex-column-center{/*竖直方向水平居中 两端对齐*/
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  align-items: center;
+}
+.flex-column-start{/*竖直方向水平居中 首部对齐*/
+  display: flex;
+  flex-direction: column;
+  justify-content: space-around;
+  align-items: self-start;
+}
+.flex-column-end{/*竖直方向水平居中 尾部部对齐*/
+  display: flex;
+  flex-direction: column;
+	align-items: flex-end;
+}
+.flex-column-start-between{/*竖直方向-首部对齐-两端对齐*/
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  align-items: self-start;
+}
+.flex-column-align{/*竖直方向水平居中*/
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+.flex-center-flex-start-warp{/*水平垂直居中-首部对齐*/
+  display: flex;
+  justify-content: flex-start;
+  align-items: center;
+   flex-wrap:wrap ;
+}
+.grid-container {
+	display: grid;
+	grid-template-columns: repeat(2, 1fr);
+	gap: 30rpx;
+}
+.grid-container3 {
+	display: grid;
+	grid-template-columns: repeat(3, 1fr);
+	gap: 30rpx;
+}
+.order_btn{
+	font-size: 25rpx;
+	color: #ffffff;
+	border-radius:10rpx;
+	background-color: $theme-color;
+	&.error{
+		background-color: #E93323;
+	}
+	&.plain{
+		border:1px solid #cccccc;
+		color: #000000;
+		background-color: #ffffff;
+	}
+}
+.border{
+	border: 1px solid #eeeeee;
+}
+.border-bottom{
+	border-bottom: 1px solid #eeeeee;
+}
+.gray{
+	color: #666666;
+}
+.link{
+	color: #007aff;
+}
+.bg_color_f5{
+	background-color: #f5f5f5;
+}
+.bg_color_fff{
+	background-color: #ffffff;
+}
+.bg_color_primary{
+	background-color: $theme-color;
+}
+.border_radius_10{
+	border-radius: 10rpx;
+}
+.border_radius_20{
+	border-radius: 20rpx;
+}
+.border_radius_30{
+	border-radius: 30rpx;
+}
+.bold{
+	font-weight: bold;
+}
+.font_size60{
+	font-size: 60rpx;
+}
+.font_size40{
+	font-size: 40rpx;
+}
+.font_size35{
+	font-size: 36rpx;
+}
+.font_size30{
+	font-size: 30rpx;
+}
+.font_size32{
+	font-size: 32rpx;
+}
+.font_size20{
+	font-size: 20rpx;
+}
+.font_size24{
+	font-size: 24rpx;
+}
+.font_size28{
+	font-size: 28rpx;
+}
+.font_size25{
+	font-size: 25rpx;
+}
+.line_vertical{
+	width: 8rpx;
+	height: 30rpx;
+	background-color: $theme-color;
+	border-radius: 4rpx;
+}
+.color_price{
+	color: #fc4f1d;
+}
+.color_vip{
+	color: #fee189;
+}
+.color_fff{
+	color: #333;
+}
+.color_000{
+	color: #000000;
+}
+.color_theme{
+	color: $theme-color;
+}
+
+.text_align_center{
+	text-align: center;
+}
+.text_align_right{
+	text-align: right;
+}
+.foot{
+	width: 100%;
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	box-shadow: 0 -4px 6px -1px rgba(0, 0, 0, 0.1);
+	z-index: 10;
+	padding: 20rpx 30rpx;
+}
+.footplaceholder{
+	height: 100rpx;
+}
+.ellipsis{
+	overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+.bg_img{
+	width: 100%;
+	position: absolute;
+	top: 0;
+	left: 0;;
+	z-index: -1;
+}
+.line_through{
+	text-decoration: line-through;
+}
+
+.required{
+	color: #E93323;
+}
+.u_popup_bottom{
+	border-radius: 30rpx 30rpx 0 0;
+}
+.overflow_hidden{
+	overflow: hidden;
+}
+
+
+.payment-radio {
+  width: 40rpx;
+  height: 40rpx;
+
+  .radio-circle {
+    width: 100%;
+    height: 100%;
+    border: 3rpx solid #ddd;
+    border-radius: 50%;
+    position: relative;
+    transition: all 0.3s;
+
+    &.checked {
+      border-color: $theme-color;
+
+      &::after {
+        content: "";
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        width: 20rpx;
+        height: 20rpx;
+        background: $theme-color;
+        border-radius: 50%;
+      }
+    }
+  }
+}
+.noData{
+	text-align: center;
+	padding: 30rpx 0;
+	color: #c8c7cc;
+}
+.serviceLabel{
+	background-color: #ffe8e6;
+	font-size: 25rpx;
+	color: #E93323;
+	border-radius: 10rpx;
+	padding: 5rpx 10rpx;
+	display: inline-block;
+	// margin-top: 20rpx;
+	&:not(:last-child){ 
+		margin-right: 10rpx;
+	}
+}

二進制
jd_logistics-app/static/img/addHuiHua.png


二進制
jd_logistics-app/static/img/arrow-right.png


二進制
jd_logistics-app/static/img/check.png


二進制
jd_logistics-app/static/img/copy.png


二進制
jd_logistics-app/static/img/home/tool.png


二進制
jd_logistics-app/static/img/icon-logo-jd.png


二進制
jd_logistics-app/static/img/icon-logo-sf.png


二進制
jd_logistics-app/static/img/index-bg.png


二進制
jd_logistics-app/static/img/index-personal.png


二進制
jd_logistics-app/static/img/index-time.png


二進制
jd_logistics-app/static/img/index-un-time.png


二進制
jd_logistics-app/static/img/logo.png


二進制
jd_logistics-app/static/img/mine/Logout.png


二進制
jd_logistics-app/static/img/mine/chongzhijulu.png


二進制
jd_logistics-app/static/img/mine/icon-mine-about.png


二進制
jd_logistics-app/static/img/mine/icon-mine-address.png


二進制
jd_logistics-app/static/img/mine/icon-mine-order.png


二進制
jd_logistics-app/static/img/mine/icon-mine-policy.png


二進制
jd_logistics-app/static/img/mine/icon-mine-server.png


二進制
jd_logistics-app/static/img/mine/kefu.png


二進制
jd_logistics-app/static/img/mine/money.png


二進制
jd_logistics-app/static/img/mine/order.png


二進制
jd_logistics-app/static/img/mine/vip.png


二進制
jd_logistics-app/static/img/mine/vipcard.png


二進制
jd_logistics-app/static/img/qianbao.png


二進制
jd_logistics-app/static/img/search.png


二進制
jd_logistics-app/static/img/service/aijiqiren.png


二進制
jd_logistics-app/static/img/service/assistant-avatar.png


二進制
jd_logistics-app/static/img/service/maikefengyuyin.png


二進制
jd_logistics-app/static/img/service/send-icon.png


二進制
jd_logistics-app/static/img/service/tupian.png


二進制
jd_logistics-app/static/img/service/user-avatar.png


二進制
jd_logistics-app/static/img/service/xiaoxi.png


二進制
jd_logistics-app/static/img/shuaxin.png


二進制
jd_logistics-app/static/img/tabs/home.png


二進制
jd_logistics-app/static/img/tabs/home_active.png


二進制
jd_logistics-app/static/img/tabs/search.png


二進制
jd_logistics-app/static/img/tabs/search_active.png


+ 0 - 0
jd_logistics-app/static/img/tabs/user.png


Some files were not shown because too many files changed in this diff