|
|
@@ -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>
|