2 Commity 92510848bd ... bb4b07c2ca

Autor SHA1 Wiadomość Data
  颜琼丽 bb4b07c2ca Merge remote-tracking branch 'origin/master' 1 miesiąc temu
  颜琼丽 ed63313155 feat:创建订单,地址管理增加地址智能识别功能 1 miesiąc temu

+ 9 - 0
jd-logistics-ui-v3/src/api/logistics/book.js

@@ -49,3 +49,12 @@ export function getDefaultAddress() {
   })
 }
 
+
+/**
+ * 获取地址信息你
+ */
+export function getAddressInfo(data) {
+  return request.post('/system/kd100/wxmini/queryIcrExpres',data)
+}
+
+

+ 38 - 29
jd-logistics-ui-v3/src/views/login.vue

@@ -42,12 +42,12 @@
             <img :src="codeUrl" @click="getCode" class="login-code-img"/>
           </div>
         </el-form-item>
-        <el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>
+<!--        <el-checkbox v-model="loginForm.rememberMe">记住密码</el-checkbox>-->
 
-        <!-- 同意用户协议和隐私协议复选框 -->
+        <!-- 同意用户协议和隐私协议复选框(已移除Cookie政策) -->
         <el-form-item prop="agree" style="margin-bottom: 20px;">
           <el-checkbox v-model="loginForm.agree">
-            同意
+            我已阅读并同意
             <el-link type="primary" :underline="false" href="https://rjsd.mychery.com/user_agreement.html" target="_blank">《用户协议》</el-link>
             <el-link type="primary" :underline="false" href="https://rjsd.mychery.com/privacy_policy.html" target="_blank">《隐私政策》</el-link>
@@ -72,10 +72,11 @@
       </el-form>
     </div>
 
-    <!-- Cookie同意横幅(深色字体,浅色背景) -->
+    <!-- Cookie同意横幅(底部,含查看链接和同意按钮) -->
     <div v-if="showCookieBanner" class="cookie-banner">
       <span class="cookie-text">
-        我们将使用Cookie优化您的浏览体验,并通过第三方SDK实现网站功能。如果您想继续浏览本网站,请您同意使用Cookie和隐私条款。
+        我们将使用Cookie优化您的浏览体验,并通过第三方SDK实现网站功能。
+        <el-link type="primary" :underline="false" href="https://rjsd.mychery.com/cookie.html" target="_blank">查看《Cookie政策》</el-link>
       </span>
       <el-button type="primary" size="small" @click="acceptCookies">同意</el-button>
     </div>
@@ -111,7 +112,7 @@ const loginForm = ref({
   rememberMe: false,
   code: "",
   uuid: "",
-  agree: false
+  agree: false          // 仅用于用户协议和隐私政策
 })
 
 // 表单验证规则
@@ -139,23 +140,33 @@ function handleLogin() {
   if (!proxy.$refs.loginRef) return
 
   proxy.$refs.loginRef.validate((valid) => {
+    // 检查是否已同意用户协议和隐私政策
     if (!loginForm.value.agree) {
-      ElMessage.warning('请先同意用户协议和隐私协议')
+      ElMessage.warning('请先同意用户协议和隐私政策')
       return
     }
 
+    // 检查是否已同意Cookie政策
+    const cookieConsented = localStorage.getItem('cookieConsent') === 'true'
+    // if (!cookieConsented) {
+    //   ElMessage.warning('请先同意Cookie政策')
+    //   // 如果未同意,显示横幅引导用户操作
+    //   showCookieBanner.value = true
+    //   return
+    // }
+
     if (valid) {
       loading.value = true
       // 记住密码
-      if (loginForm.value.rememberMe) {
-        Cookies.set("username", loginForm.value.username, { expires: 30 })
-        Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 })
-        Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 })
-      } else {
-        Cookies.remove("username")
-        Cookies.remove("password")
-        Cookies.remove("rememberMe")
-      }
+      // if (loginForm.value.rememberMe) {
+      //   Cookies.set("username", loginForm.value.username, { expires: 30 })
+      //   Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 })
+      //   Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 })
+      // } else {
+      //   Cookies.remove("username")
+      //   Cookies.remove("password")
+      //   Cookies.remove("rememberMe")
+      // }
 
       userStore.login(loginForm.value).then(() => {
         const query = route.query
@@ -209,30 +220,23 @@ function getCookie() {
   }
 }
 
-// 检查是否已经同意过Cookie(使用localStorage)
+// 检查Cookie同意状态,控制横幅显示
 function checkCookieConsent() {
-  const consented = localStorage.getItem('cookieConsent')
-  if (consented === 'true') {
-    showCookieBanner.value = false
-    // 如果之前同意过,自动勾选协议复选框
-    loginForm.value.agree = true
-  } else {
-    showCookieBanner.value = true
-  }
+  const consented = localStorage.getItem('cookieConsent') === 'true'
+  showCookieBanner.value = !consented   // 未同意则显示横幅
 }
 
-// 同意Cookie
+// 同意Cookie(点击横幅按钮)
 function acceptCookies() {
   localStorage.setItem('cookieConsent', 'true')
   showCookieBanner.value = false
-  loginForm.value.agree = true  // 同时勾选协议复选框
-  ElMessage.success('感谢您的同意')
+  // ElMessage.success('感谢您同意Cookie政策')
 }
 
 // 初始化
 onMounted(() => {
   getCode()
-  getCookie()
+  // getCookie()
   checkCookieConsent()
 })
 </script>
@@ -342,6 +346,11 @@ onMounted(() => {
 .el-button--small:hover {
   background-color: #66b1ff;
 }
+/* 底部查看链接样式 */
+.cookie-text .el-link {
+  margin-left: 4px;
+  font-weight: 500;
+}
 
 .el-login-footer {
   height: 40px;

+ 170 - 50
jd-logistics-ui-v3/src/views/logistics/book/index.vue

@@ -1,14 +1,6 @@
 <template>
   <div class="app-container">
     <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="120px">
-<!--      <el-form-item label="公司名称" prop="companyName">-->
-<!--        <el-input-->
-<!--            v-model="queryParams.companyName"-->
-<!--            placeholder="请输入公司名称"-->
-<!--            clearable-->
-<!--            @keyup.enter="handleQuery"-->
-<!--        />-->
-<!--      </el-form-item>-->
       <el-form-item label="联系人姓名" prop="contactName">
         <el-input
             v-model="queryParams.contactName"
@@ -110,7 +102,6 @@
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="联系人姓名" align="center" prop="contactName" width="180"/>
       <el-table-column label="联系人电话" align="center" prop="contactPhone" width="180"/>
-<!--      <el-table-column label="公司名称" align="center" prop="companyName" width="180"/>-->
       <el-table-column label="省/市/区(县)" align="center"  width="280">
         <template #default="scope">
           {{scope.row.provinceName}}/{{scope.row.cityName}}/{{scope.row.countyName}}
@@ -123,8 +114,6 @@
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180"/>
-<!--      <el-table-column label="更新时间" align="center" prop="updateTime" width="180"/>-->
-<!--      <el-table-column label="备注" align="center" prop="remark" width="180"/>-->
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" min-width="180">
         <template #default="scope">
           <el-button link type="primary"  @click="handleUpdate(scope.row)" v-hasPermi="['system:book:edit']">修改</el-button>
@@ -141,12 +130,39 @@
         @pagination="getList"
     />
 
-    <!-- 添加或修改地址簿管理对话框 -->
+    <!-- 添加或修改地址簿管理对话框(增加智能识别区域) -->
     <el-dialog :title="title" v-model="open" width="800px" append-to-body>
+      <!-- 智能识别区域 -->
+      <div class="recognition-area">
+        <div class="recognition-tip">识别后,请检查拆分地址信息是否准确,如有遗漏请及时补充</div>
+        <el-input
+            type="textarea"
+            v-model="recognitionText"
+            placeholder="请输入文本,自动识别姓名、电话和地址"
+            :rows="3"
+            maxlength="250"
+            show-word-limit
+            class="recognition-textarea"
+        />
+        <div class="recognition-actions">
+          <el-button
+              type="primary"
+              @click="handleRecognition(1)"
+              v-if="!recognitionText"
+              class="recognition-btn"
+              :loading="recognitionLoading"
+          >粘贴并识别</el-button>
+          <el-button
+              type="primary"
+              @click="handleRecognition(2)"
+              v-else
+              class="recognition-btn"
+              :loading="recognitionLoading"
+          >识别</el-button>
+        </div>
+      </div>
+
       <el-form ref="bookRef" :model="form" :rules="rules" label-width="120px">
-<!--        <el-form-item label="公司名称" prop="companyName">-->
-<!--          <el-input v-model="form.companyName" placeholder="请输入公司名称" maxlength="20" show-word-limit />-->
-<!--        </el-form-item>-->
         <el-form-item label="联系人姓名" prop="contactName">
           <el-input v-model="form.contactName" placeholder="请输入联系人姓名" maxlength="20" show-word-limit />
         </el-form-item>
@@ -179,9 +195,6 @@
             ></el-option>
           </el-select>
         </el-form-item>
-<!--        <el-form-item label="备注" prop="remark">-->
-<!--          <el-input v-model="form.remark" placeholder="请输入备注" maxlength="500" show-word-limit type="textarea" :rows="3" />-->
-<!--        </el-form-item>-->
       </el-form>
       <template #footer>
         <div class="dialog-footer">
@@ -190,6 +203,7 @@
         </div>
       </template>
     </el-dialog>
+
     <!-- 供应商导入对话框 -->
     <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
       <el-upload
@@ -221,20 +235,20 @@
         </div>
       </template>
     </el-dialog>
-
   </div>
 </template>
 
 <script setup name="Book">
-import { listBook, getBook, delBook, addBook, updateBook } from "@/api/logistics/book"
+import { listBook, getBook, delBook, addBook, updateBook, getAddressInfo } from "@/api/logistics/book"
 import RegionCascader from '@/components/RegionCascader.vue'
 import { getToken } from "@/utils/auth"
 import { download } from '@/utils/request'
-// 导入本地 JSON 数据
-import { getCodesByNames  } from '@/utils/area-data.js'
+import { getCodesByNames } from '@/utils/area-data.js'
+import { ElMessage } from 'element-plus'
+import { UploadFilled } from '@element-plus/icons-vue'
 
 const { proxy } = getCurrentInstance()
-const {  yes_or_no } = proxy.useDict("yes_or_no")
+const { yes_or_no } = proxy.useDict("yes_or_no")
 
 const bookList = ref([])
 const open = ref(false)
@@ -268,17 +282,11 @@ const validateRegion = (rule, value, callback) => {
 
 /*** 地址簿导入参数 */
 const upload = reactive({
-  // 是否显示弹出层(导入)
   open: false,
-  // 弹出层标题
   title: "",
-  // 是否禁用上传
   isUploading: false,
-  // 设置上传的请求头部
   headers: { Authorization: "Bearer " + getToken() },
-  // 上传的地址
   url: import.meta.env.VITE_APP_BASE_API + "/system/book/importData",
-  // 当前选中的文件
   selectedFile: null
 })
 
@@ -299,10 +307,6 @@ const data = reactive({
     userId: null,
   },
   rules: {
-    companyName: [
-      { required: true, message: '公司名称不能为空', trigger: 'blur' },
-      { min: 1, max: 100, message: '公司名称长度在 1 到 100 个字符', trigger: 'blur' }
-    ],
     contactName: [
       { required: true, message: '联系人姓名不能为空', trigger: 'blur' },
       { min: 1, max: 50, message: '联系人姓名长度在 1 到 50 个字符', trigger: 'blur' }
@@ -319,15 +323,102 @@ const data = reactive({
     ],
     defaultFlag: [
       { required: true, message: '是否默认不能为空', trigger: 'change' }
-    ],
-    remark: [
-      { max: 500, message: '备注长度不能超过 500 个字符', trigger: 'blur' }
     ]
   }
 })
 
 const { queryParams, form, rules } = toRefs(data)
 
+// 智能识别相关
+const recognitionText = ref('')
+const recognitionLoading = ref(false)
+
+// 处理识别
+const handleRecognition = async (actionType) => {
+  let text = ''
+  if (actionType === 1) {
+    // 粘贴并识别:读取剪贴板
+    try {
+      const clipboardText = await navigator.clipboard.readText()
+      if (!clipboardText) {
+        ElMessage.warning('剪贴板内容为空')
+        return
+      }
+      recognitionText.value = clipboardText
+      text = clipboardText
+    } catch (err) {
+      ElMessage.error('读取剪贴板失败,请手动粘贴')
+      return
+    }
+  } else {
+    // 直接识别:使用当前文本域内容
+    text = recognitionText.value
+  }
+
+  if (!text.trim()) {
+    ElMessage.warning('请输入要识别的文本')
+    return
+  }
+
+  recognitionLoading.value = true
+  try {
+    const params = { param: text }
+    const res = await getAddressInfo(params)
+    if (res.code === 200 && res.data?.result?.length > 0) {
+      const result = res.data.result[0]
+
+      // 填充表单
+      form.value.contactName = result.name || ''
+      if (result.mobile && result.mobile.length > 0) {
+        form.value.contactPhone = result.mobile[0]
+      }
+
+      // 省市区
+      if (result.xzq) {
+        let province = '', city = '', district = ''
+        if (result.xzq.fullName) {
+          const parts = result.xzq.fullName.split(',').map(s => s.trim())
+          province = parts[0] || ''
+          city = parts[1] || ''
+          district = parts[2] || ''
+        } else {
+          province = result.xzq.province || ''
+          city = result.xzq.city || ''
+          district = result.xzq.district || ''
+        }
+        form.value.provinceName = province
+        form.value.cityName = city
+        form.value.countyName = district
+
+        // 获取省市区代码并设置 region
+        const codes = getCodesByNames(province, city, district)
+        form.value.region = codes
+
+        // 详细地址
+        if (result.xzq.subArea) {
+          form.value.detailedAddress = result.xzq.subArea
+        } else if (result.address) {
+          const fullAddr = result.address
+          const prefix = province + city + district
+          form.value.detailedAddress = fullAddr.startsWith(prefix) ? fullAddr.substring(prefix.length) : fullAddr
+        }
+      }
+
+      // 清空识别文本域
+      recognitionText.value = ''
+
+      ElMessage.success('识别成功,请核对信息')
+    } else {
+      ElMessage.error(res.message || '识别失败')
+    }
+  } catch (error) {
+    console.error('识别错误', error)
+    ElMessage.error('识别失败,请重试')
+  } finally {
+    recognitionLoading.value = false
+  }
+}
+
 /** 查询地址簿管理列表 */
 function getList() {
   loading.value = true
@@ -366,6 +457,7 @@ function reset() {
     createBy: null,
     updateBy: null
   }
+  recognitionText.value = '' // 重置识别文本域
   proxy.resetForm("bookRef")
 }
 
@@ -393,7 +485,7 @@ const handleRegionChange = (regionInfo) => {
   form.value.provinceName = regionInfo.provinceName || ''
   form.value.cityName = regionInfo.cityName || ''
   form.value.countyName = regionInfo.districtName || ''
-  form.value.region = [regionInfo.provinceCode,regionInfo.cityCode,regionInfo.districtCode]
+  form.value.region = [regionInfo.provinceCode, regionInfo.cityCode, regionInfo.districtCode]
 }
 
 /** 新增按钮操作 */
@@ -409,7 +501,7 @@ function handleUpdate(row) {
   const _addressId = row.addressId || ids.value
   getBook(_addressId).then(response => {
     form.value = response.data
-    form.value.region = getCodesByNames(response.data.provinceName,response.data.cityName,response.data.countyName)
+    form.value.region = getCodesByNames(response.data.provinceName, response.data.cityName, response.data.countyName)
     form.value.defaultFlag = form.value.defaultFlag + ''
     open.value = true
     title.value = "修改地址簿管理"
@@ -420,15 +512,6 @@ function handleUpdate(row) {
 function submitForm() {
   proxy.$refs["bookRef"].validate(valid => {
     if (valid) {
-      // 确保省市区信息正确设置
-      if (form.value.region && form.value.region.length === 3) {
-        // 这里确保省市区名称已通过handleRegionChange设置
-        if (!form.value.provinceName || !form.value.cityName || !form.value.countyName) {
-          proxy.$modal.msgError("请选择完整的省市区信息")
-          return
-        }
-      }
-
       if (form.value.addressId != null) {
         updateBook(form.value).then(response => {
           proxy.$modal.msgSuccess("修改成功")
@@ -464,8 +547,6 @@ function handleExport() {
   }, `book_${new Date().getTime()}.xlsx`)
 }
 
-
-
 /** 下载模板 */
 const handleDownloadTemplate = () => {
   download('/system/book/importTemplate', {}, '地址簿模板.xlsx')
@@ -513,4 +594,43 @@ function submitFileForm() {
 }
 
 getList()
-</script>
+</script>
+
+<style scoped>
+/* 识别区域样式(与 createOrder 一致) */
+.recognition-area {
+  background-color: #fff;
+  //border-radius: 8px;
+  //padding: 16px;
+  margin-bottom: 20px;
+  //border: 1px solid #e4e7ed;
+}
+
+.recognition-textarea :deep(.el-textarea__inner) {
+  background-color: #F5F7FA;
+  border: none;
+  border-radius: 4px;
+  font-size: 14px;
+}
+
+.recognition-actions {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 12px;
+}
+
+.recognition-btn {
+  width: 120px;
+  height: 36px;
+  background: #1B64F0;
+  border-radius: 18px;
+  font-size: 14px;
+}
+
+.recognition-tip {
+  font-size: 12px;
+  color: #999;
+  margin-bottom: 8px;
+  line-height: 1.5;
+}
+</style>

+ 237 - 47
jd-logistics-ui-v3/src/views/logistics/order/createOrder.vue

@@ -2,20 +2,51 @@
   <div class="express-order-page">
     <!-- 寄件人和收件人在同一行 -->
     <div class="form-row">
+
       <!-- 寄件人 -->
       <div class="form-card">
         <div class="card-header send">
           <span class="header-title"><img src="../../../assets/images/icon-send.png"/>寄件人</span>
-          <el-button
-              type="primary"
-              link
-              @click="openAddressBook('sender')"
-              class="address-book-btn"
-          >
-            <img src="../../../assets/images/create-order-address.png"/>地址簿
-          </el-button>
+          <div class="header-actions">
+            <el-button
+                type="primary"
+                link
+                @click="openAddressBook('sender')"
+                class="action-btn"
+            >
+              <img src="../../../assets/images/create-order-address.png"/>地址簿
+            </el-button>
+          </div>
         </div>
         <div class="form-content">
+          <!-- 智能识别区域(寄件人) -->
+          <div class="recognition-area">
+            <div class="recognition-tip">识别后,请检查拆分地址信息是否准确,如有遗漏请及时补充</div>
+            <el-input
+                type="textarea"
+                v-model="senderRecognitionText"
+                placeholder="请输入文本,自动识别姓名、电话和地址"
+                :rows="3"
+                maxlength="250"
+                show-word-limit
+                class="recognition-textarea"
+            />
+            <div class="recognition-actions">
+              <el-button
+                  type="primary"
+                  @click="handleRecognition('sender', 1)"
+                  v-if="!senderRecognitionText"
+                  class="recognition-btn"
+              >粘贴并识别</el-button>
+              <el-button
+                  type="primary"
+                  @click="handleRecognition('sender', 2)"
+                  v-else
+                  class="recognition-btn"
+              >识别</el-button>
+            </div>
+          </div>
+
           <el-form
               label-position="left"
               :model="sender"
@@ -74,26 +105,7 @@
             </el-form-item>
 
             <div class="default-address-footer">
-<!--              <div class="default-address-wrapper">-->
-<!--                <label class="checkbox-label">-->
-<!--                  <el-checkbox-->
-<!--                      v-model="sender.defaultFlag"-->
-<!--                      :true-label="'1'"-->
-<!--                      :false-label="'0'"-->
-<!--                      size="large"-->
-<!--                      class="default-address-radio"-->
-<!--                  />-->
-<!--                  <span class="checkbox-text">设为默认寄件地址</span>-->
-<!--                </label>-->
-<!--              </div>-->
-
-<!--              <el-button-->
-<!--                  type="primary"-->
-<!--                  @click="addToAddressBook('sender')"-->
-<!--                  class="add-address-btn"-->
-<!--              >-->
-<!--                加入地址簿-->
-<!--              </el-button>-->
+              <!-- 默认地址相关已注释,保留原样 -->
             </div>
           </el-form>
         </div>
@@ -103,16 +115,46 @@
       <div class="form-card">
         <div class="card-header receive">
           <span class="header-title"><img src="../../../assets/images/icon-receive.png"/>收件人</span>
-          <el-button
-              type="primary"
-              link
-              @click="openAddressBook('receiver')"
-              class="address-book-btn"
-          >
-            <img src="../../../assets/images/create-order-address.png"/>地址簿
-          </el-button>
+          <div class="header-actions">
+            <el-button
+                type="primary"
+                link
+                @click="openAddressBook('receiver')"
+                class="action-btn"
+            >
+              <img src="../../../assets/images/create-order-address.png"/>地址簿
+            </el-button>
+          </div>
         </div>
         <div class="form-content">
+          <!-- 智能识别区域(收件人) -->
+          <div class="recognition-area">
+            <div class="recognition-tip">识别后,请检查拆分地址信息是否准确,如有遗漏请及时补充</div>
+            <el-input
+                type="textarea"
+                v-model="receiverRecognitionText"
+                placeholder="请输入文本,自动识别姓名、电话和地址"
+                :rows="3"
+                maxlength="250"
+                show-word-limit
+                class="recognition-textarea"
+            />
+            <div class="recognition-actions">
+              <el-button
+                  type="primary"
+                  @click="handleRecognition('receiver', 1)"
+                  v-if="!receiverRecognitionText"
+                  class="recognition-btn"
+              >粘贴并识别</el-button>
+              <el-button
+                  type="primary"
+                  @click="handleRecognition('receiver', 2)"
+                  v-else
+                  class="recognition-btn"
+              >识别</el-button>
+            </div>
+          </div>
+
           <el-form
               label-position="left"
               :model="receiver"
@@ -169,19 +211,10 @@
                   @input="handleReceiverChange"
               />
             </el-form-item>
-
-<!--            <div class="form-footer">-->
-<!--              <el-button-->
-<!--                  type="primary"-->
-<!--                  @click="addToAddressBook('receiver')"-->
-<!--                  class="add-address-btn"-->
-<!--              >-->
-<!--                加入地址簿-->
-<!--              </el-button>-->
-<!--            </div>-->
           </el-form>
         </div>
       </div>
+
     </div>
 
     <!-- 寄件方式 -->
@@ -479,7 +512,7 @@ const { proxy } = getCurrentInstance()
 const { jd_logistics_product_code, sf_logistics_product_code } = proxy.useDict("jd_logistics_product_code", "sf_logistics_product_code")
 
 import { useRoute } from 'vue-router';
-import {updateBook,getDefaultAddress} from "../../../api/logistics/book.js";
+import {updateBook,getDefaultAddress,getAddressInfo} from "../../../api/logistics/book.js";
 
 const route = useRoute();
 
@@ -751,6 +784,113 @@ watch(signReturnType, (newVal) => {
 })
 
 
+// ==================== 新增智能识别相关 ====================
+const senderRecognitionText = ref('')
+const receiverRecognitionText = ref('')
+const recognitionLoading = ref(false)
+
+// 处理识别
+const handleRecognition = async (type, actionType) => {
+  let text = ''
+  if (actionType === 1) {
+    // 粘贴并识别:读取剪贴板
+    try {
+      const clipboardText = await navigator.clipboard.readText()
+      if (!clipboardText) {
+        ElMessage.warning('剪贴板内容为空')
+        return
+      }
+      if (type === 'sender') {
+        senderRecognitionText.value = clipboardText
+        text = clipboardText
+      } else {
+        receiverRecognitionText.value = clipboardText
+        text = clipboardText
+      }
+    } catch (err) {
+      ElMessage.error('读取剪贴板失败,请手动粘贴')
+      return
+    }
+  } else {
+    // 直接识别:使用当前文本域内容
+    text = type === 'sender' ? senderRecognitionText.value : receiverRecognitionText.value
+  }
+
+  if (!text.trim()) {
+    ElMessage.warning('请输入要识别的文本')
+    return
+  }
+
+  recognitionLoading.value = true
+  try {
+    const params = { param: text }
+    const res = await getAddressInfo(params)
+    if (res.code === 200 && res.data?.result?.length > 0) {
+      const result = res.data.result[0]
+      const target = type === 'sender' ? sender : receiver
+
+      // 清空原有 addressId,视为新地址
+      target.addressId = ''
+
+      // 姓名
+      target.contactName = result.name || ''
+
+      // 电话(取第一个)
+      if (result.mobile && result.mobile.length > 0) {
+        target.contactPhone = result.mobile[0]
+      }
+
+      // 省市区
+      if (result.xzq) {
+        let province = '', city = '', district = ''
+        if (result.xzq.fullName) {
+          const parts = result.xzq.fullName.split(',').map(s => s.trim())
+          province = parts[0] || ''
+          city = parts[1] || ''
+          district = parts[2] || ''
+        } else {
+          province = result.xzq.province || ''
+          city = result.xzq.city || ''
+          district = result.xzq.district || ''
+        }
+        target.provinceName = province
+        target.cityName = city
+        target.countyName = district
+
+        // 获取省市区代码并设置 region(用于 RegionCascader 回显)
+        const codes = getCodesByNames(province, city, district)
+        target.region = codes
+
+        // 详细地址
+        if (result.xzq.subArea) {
+          target.detailedAddress = result.xzq.subArea
+        } else if (result.address) {
+          const fullAddr = result.address
+          const prefix = province + city + district
+          target.detailedAddress = fullAddr.startsWith(prefix) ? fullAddr.substring(prefix.length) : fullAddr
+        }
+      }
+
+      // 清空对应识别文本域(可选)
+      if (type === 'sender') {
+        senderRecognitionText.value = ''
+      } else {
+        receiverRecognitionText.value = ''
+      }
+
+      ElMessage.success('识别成功,请核对信息')
+    } else {
+      ElMessage.error(res.message || '识别失败')
+    }
+  } catch (error) {
+    console.error('识别错误', error)
+    ElMessage.error('识别失败,请重试')
+  } finally {
+    recognitionLoading.value = false
+  }
+}
+// ==================== 新增代码结束 ====================
+
 // 处理寄件人地区变化
 const handleSenderRegionChange = (regionInfo) => {
   console.log('寄件人地区信息:', regionInfo)
@@ -1819,4 +1959,54 @@ onMounted(() => {
     justify-content: flex-start;
   }
 }
+
+
+/* 添加识别区域样式 */
+.recognition-area {
+  background-color: #fff;
+  //border-radius: 8px;
+  //padding: 16px;
+  margin-bottom: 20px;
+  //border: 1px solid #e4e7ed;
+}
+
+.recognition-textarea :deep(.el-textarea__inner) {
+  background-color: #F5F7FA;
+  border: none;
+  border-radius: 4px;
+  font-size: 14px;
+}
+
+.recognition-actions {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 12px;
+}
+
+.recognition-btn {
+  width: 120px;
+  height: 36px;
+  background: #1B64F0;
+  border-radius: 18px;
+  font-size: 14px;
+}
+
+.recognition-tip {
+  font-size: 12px;
+  color: #999;
+  margin-bottom: 8px;
+  line-height: 1.5;
+}
+
+.header-actions {
+  display: flex;
+  gap: 12px;
+  align-items: center;
+}
+
+.action-btn {
+  display: flex;
+  align-items: center;
+  gap: 4px;
+}
 </style>

+ 9 - 3
jd-logistics-ui-v3/src/views/logistics/order/index.vue

@@ -795,9 +795,13 @@ const signReturnTypeError = ref('')
 // 计算属性:保价开关是否开启
 const insuranceEnabled = computed({
   get() {
-    return addedServiceData.value.guaranteeMoney !== null && addedServiceData.value.guaranteeMoney !== ''
+    return addedServiceData.value.guaranteeMoney != undefined
+        && addedServiceData.value.guaranteeMoney != 'undefined'
+        && addedServiceData.value.guaranteeMoney != null
+        && addedServiceData.value.guaranteeMoney != ''
   },
   set(value) {
+    debugger
     if (!value) {
       addedServiceData.value.guaranteeMoney = null
     } else {
@@ -809,7 +813,9 @@ const insuranceEnabled = computed({
 // 计算属性:签单返还开关是否开启
 const signReturnEnabled = computed({
   get() {
-    return addedServiceData.value.isReceiptCollect !== null
+    return addedServiceData.value.isReceiptCollect != null
+        && addedServiceData.value.isReceiptCollect != undefined
+        && addedServiceData.value.isReceiptCollect != ""
   },
   set(value) {
     if (!value) {
@@ -1050,7 +1056,7 @@ function handleView(row) {
       data.receiverRegion = getCodesByNames(data.receiverProvince, data.receiverCity, data.receiverCounty)
     }
     data.orderStatus = data.orderStatus + ''
-
+    debugger
     // 处理增值服务数据
     if (data.addedService && typeof data.addedService === 'string') {
       try {

+ 3 - 3
jd-logistics-ui-v3/src/views/system/user/index.vue

@@ -146,13 +146,13 @@
 
         <el-row>
           <el-col :span="12">
-            <el-form-item v-if="form.userId == undefined" label="用户账号" prop="userName">
-              <el-input v-model="form.userName" placeholder="请输入用户账号" maxlength="30"/>
+            <el-form-item label="用户账号" prop="userName">
+              <el-input v-model="form.userName" placeholder="请输入用户账号" maxlength="30" :disabled="form.userId !== undefined"/>
             </el-form-item>
           </el-col>
           <el-col :span="12">
             <el-form-item label="手机号码" prop="phonenumber">
-              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11"/>
+              <el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" :disabled="form.userId !== undefined"/>
             </el-form-item>
           </el-col>
         </el-row>