Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
B
baifang-java
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
单欣鑫
baifang-java
Commits
29054b48
Commit
29054b48
authored
Jun 04, 2025
by
法拉51246
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
三个基本功能的新增修改完善,地图当前还不能根据已选择经纬度打开
parent
db94161b
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
350 additions
and
128 deletions
+350
-128
CustomerInfoController.java
...controller/admin/customerinfo/CustomerInfoController.java
+27
-0
CustomerInfoPageReqVO.java
...ntroller/admin/customerinfo/vo/CustomerInfoPageReqVO.java
+3
-0
CustomerInfoRespVO.java
.../controller/admin/customerinfo/vo/CustomerInfoRespVO.java
+4
-1
CustomerInfoSaveReqVO.java
...ntroller/admin/customerinfo/vo/CustomerInfoSaveReqVO.java
+3
-0
InfoPageReqVO.java
.../module/visit/controller/admin/info/vo/InfoPageReqVO.java
+5
-2
InfoRespVO.java
...dao/module/visit/controller/admin/info/vo/InfoRespVO.java
+5
-3
InfoSaveReqVO.java
.../module/visit/controller/admin/info/vo/InfoSaveReqVO.java
+6
-1
CustomerInfoDO.java
...ule/visit/dal/dataobject/customerinfo/CustomerInfoDO.java
+4
-0
InfoDO.java
...ocoder/yudao/module/visit/dal/dataobject/info/InfoDO.java
+5
-1
CustomerInfoMapper.java
...dule/visit/dal/mysql/customerinfo/CustomerInfoMapper.java
+14
-0
CustomerInfoService.java
...odule/visit/service/customerinfo/CustomerInfoService.java
+5
-0
CustomerInfoServiceImpl.java
...e/visit/service/customerinfo/CustomerInfoServiceImpl.java
+14
-0
InfoServiceImpl.java
...oder/yudao/module/visit/service/info/InfoServiceImpl.java
+41
-12
index.ts
...i/yudao-ui-admin-vue3/src/api/visit/customerinfo/index.ts
+14
-0
index.ts
yudao-ui/yudao-ui-admin-vue3/src/api/visit/info/index.ts
+57
-57
UploadImgs.vue
...i-admin-vue3/src/components/UploadFile/src/UploadImgs.vue
+2
-1
CustomerInfoForm.vue
...in-vue3/src/views/visit/customerinfo/CustomerInfoForm.vue
+6
-3
productTable.vue
...-admin-vue3/src/views/visit/customerinfo/productTable.vue
+8
-3
InfoForm.vue
...-ui/yudao-ui-admin-vue3/src/views/visit/info/InfoForm.vue
+110
-37
index.vue
yudao-ui/yudao-ui-admin-vue3/src/views/visit/info/index.vue
+17
-6
ProductList.vue
.../yudao-ui-admin-vue3/src/views/visit/util/ProductList.vue
+0
-1
No files found.
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/CustomerInfoController.java
View file @
29054b48
...
...
@@ -81,6 +81,33 @@ public class CustomerInfoController {
return
success
(
bean
);
}
@GetMapping
(
"/getByCompanyName"
)
@Operation
(
summary
=
"通过公司名称带出基本信息"
)
@Parameter
(
name
=
"companyName"
,
description
=
"公司名称"
,
required
=
true
,
example
=
"郑州小牛"
)
public
CommonResult
<
List
<
CustomerInfoRespVO
>>
getCustomerInfoByCompanyName
(
@RequestParam
(
"companyName"
)
String
companyName
)
{
List
<
CustomerInfoDO
>
customerInfo
=
customerInfoService
.
getCustomerInfoByCompanyName
(
companyName
);
List
<
CustomerInfoRespVO
>
bean
=
BeanUtils
.
toBean
(
customerInfo
,
CustomerInfoRespVO
.
class
);
return
success
(
bean
);
}
@GetMapping
(
"/getByPhone"
)
@Operation
(
summary
=
"通过手机号带出基本信息"
)
@Parameter
(
name
=
"companyName"
,
description
=
"联系方式"
,
required
=
true
,
example
=
"156"
)
public
CommonResult
<
List
<
CustomerInfoRespVO
>>
getCustomerInfoByContact
(
@RequestParam
(
"contact"
)
String
contact
)
{
List
<
CustomerInfoDO
>
customerInfo
=
customerInfoService
.
getCustomerInfoByContact
(
contact
);
List
<
CustomerInfoRespVO
>
bean
=
BeanUtils
.
toBean
(
customerInfo
,
CustomerInfoRespVO
.
class
);
return
success
(
bean
);
}
@GetMapping
(
"/getAll"
)
@Operation
(
summary
=
"查出所有"
)
public
CommonResult
<
List
<
CustomerInfoRespVO
>>
getAllCustomerInfo
()
{
List
<
CustomerInfoDO
>
customerInfo
=
customerInfoService
.
getAllCustomerInfo
();
List
<
CustomerInfoRespVO
>
bean
=
BeanUtils
.
toBean
(
customerInfo
,
CustomerInfoRespVO
.
class
);
return
success
(
bean
);
}
@GetMapping
(
"/page"
)
@Operation
(
summary
=
"获得客户信息分页"
)
@PreAuthorize
(
"@ss.hasPermission('visit:customer-info:query')"
)
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/vo/CustomerInfoPageReqVO.java
View file @
29054b48
...
...
@@ -31,6 +31,9 @@ public class CustomerInfoPageReqVO extends PageParam {
@Schema
(
description
=
"市级行政区编码"
)
private
String
cityCode
;
@Schema
(
description
=
"品种名称(多选,逗号分隔)"
)
private
String
productNames
;
@Schema
(
description
=
"创建时间"
)
@DateTimeFormat
(
pattern
=
FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND
)
private
LocalDateTime
[]
createTime
;
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/vo/CustomerInfoRespVO.java
View file @
29054b48
...
...
@@ -62,9 +62,12 @@ public class CustomerInfoRespVO {
private
BigDecimal
latitude
;
@Schema
(
description
=
"产品ID"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"产品ID"
)
private
String
productIds
;
@Schema
(
description
=
"产品名称"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"产品名称"
)
private
String
productNames
;
@Schema
(
description
=
"客户所属部门"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"客户所属部门"
)
@DictFormat
(
"customer_dept"
)
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/vo/CustomerInfoSaveReqVO.java
View file @
29054b48
...
...
@@ -64,6 +64,9 @@ public class CustomerInfoSaveReqVO {
@Schema
(
description
=
"产品信息"
)
private
String
productIds
;
@Schema
(
description
=
"产品信息名称"
)
private
String
productNames
;
@Schema
(
description
=
"客户部门"
)
private
String
department
;
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/info/vo/InfoPageReqVO.java
View file @
29054b48
...
...
@@ -31,8 +31,8 @@ public class InfoPageReqVO extends PageParam {
private
String
regionFullName
;
@Schema
(
description
=
"拜访日期"
)
@DateTimeFormat
(
pattern
=
FORMAT_YEAR_MONTH_DAY
)
private
LocalDate
[]
visitDate
;
@DateTimeFormat
(
pattern
=
FORMAT_YEAR_MONTH_DAY
_HOUR_MINUTE_SECOND
)
private
LocalDate
Time
[]
visitDate
;
@Schema
(
description
=
"性质等级"
,
example
=
"1"
)
private
Integer
customerStatus
;
...
...
@@ -40,6 +40,9 @@ public class InfoPageReqVO extends PageParam {
@Schema
(
description
=
"拜访品种(多选,逗号分隔)"
)
private
String
visitProductIds
;
@Schema
(
description
=
"拜访品种名称(多选,逗号分隔)"
)
private
String
visitProductNames
;
@Schema
(
description
=
"拜访方式(字典)"
)
private
Integer
visitMethod
;
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/info/vo/InfoRespVO.java
View file @
29054b48
...
...
@@ -64,8 +64,7 @@ public class InfoRespVO {
@Schema
(
description
=
"拜访日期"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"拜访日期"
)
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
)
private
LocalDate
visitDate
;
private
LocalDateTime
visitDate
;
@Schema
(
description
=
"性质等级"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"1"
)
@ExcelProperty
(
value
=
"性质等级"
,
converter
=
DictConvert
.
class
)
...
...
@@ -73,9 +72,12 @@ public class InfoRespVO {
private
Integer
customerStatus
;
@Schema
(
description
=
"拜访品种(多选,逗号分隔)"
)
@ExcelProperty
(
"拜访品种(多选,逗号分隔)"
)
private
String
visitProductIds
;
@Schema
(
description
=
"拜访品种(多选,逗号分隔)"
)
@ExcelProperty
(
"拜访品种"
)
private
String
visitProductNames
;
@Schema
(
description
=
"拜访方式(字典)"
)
@ExcelProperty
(
value
=
"拜访方式(字典)"
,
converter
=
DictConvert
.
class
)
@DictFormat
(
"visit_method"
)
// TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/info/vo/InfoSaveReqVO.java
View file @
29054b48
...
...
@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import
lombok.*
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.util.*
;
import
javax.validation.constraints.*
;
import
java.math.BigDecimal
;
...
...
@@ -40,6 +41,7 @@ public class InfoSaveReqVO {
private
String
areaName
;
@Schema
(
description
=
"所在地区"
)
@NotEmpty
(
message
=
"所在地区不能为空"
)
private
String
regionFullName
;
@Schema
(
description
=
"定位地址文字描述"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
...
...
@@ -60,7 +62,7 @@ public class InfoSaveReqVO {
@Schema
(
description
=
"拜访日期"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@NotNull
(
message
=
"拜访日期不能为空"
)
private
LocalDate
visitDate
;
private
LocalDate
Time
visitDate
;
@Schema
(
description
=
"性质等级"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
,
example
=
"1"
)
@NotNull
(
message
=
"性质等级不能为空"
)
...
...
@@ -69,6 +71,9 @@ public class InfoSaveReqVO {
@Schema
(
description
=
"拜访品种(多选,逗号分隔)"
)
private
String
visitProductIds
;
@Schema
(
description
=
"拜访品种名称(多选,逗号分隔)"
)
private
String
visitProductNames
;
@Schema
(
description
=
"拜访方式(字典)"
)
private
Integer
visitMethod
;
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/dataobject/customerinfo/CustomerInfoDO.java
View file @
29054b48
...
...
@@ -95,6 +95,10 @@ public class CustomerInfoDO extends BaseDO {
* 产品信息
*/
private
String
productIds
;
/**
* 产品信息
*/
private
String
productNames
;
/**
* 客户部门
*
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/dataobject/info/InfoDO.java
View file @
29054b48
...
...
@@ -90,7 +90,7 @@ public class InfoDO extends BaseDO {
/**
* 拜访日期
*/
private
LocalDate
visitDate
;
private
LocalDate
Time
visitDate
;
/**
* 性质等级
*/
...
...
@@ -99,6 +99,10 @@ public class InfoDO extends BaseDO {
* 拜访品种(多选,逗号分隔)
*/
private
String
visitProductIds
;
/**
* 拜访品种(多选,逗号分隔)
*/
private
String
visitProductNames
;
/**
* 拜访方式(字典)
*
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/customerinfo/CustomerInfoMapper.java
View file @
29054b48
...
...
@@ -28,4 +28,18 @@ public interface CustomerInfoMapper extends BaseMapperX<CustomerInfoDO> {
.
orderByDesc
(
CustomerInfoDO:
:
getId
));
}
//根据公司名称查询客户信息(验证是否唯一使用)
default
CustomerInfoDO
selectByCompanyName
(
String
companyName
){
return
selectOne
(
CustomerInfoDO:
:
getCompanyName
,
companyName
);
}
// 根据公司名称或手机号查询(根据任一条件带出符合条件的列表)
default
List
<
CustomerInfoDO
>
selectListByCompanyName
(
String
companyName
)
{
return
selectList
(
new
LambdaQueryWrapperX
<
CustomerInfoDO
>()
.
likeIfPresent
(
CustomerInfoDO:
:
getCompanyName
,
companyName
));
}
default
List
<
CustomerInfoDO
>
selectListByContact
(
String
contact
)
{
return
selectList
(
new
LambdaQueryWrapperX
<
CustomerInfoDO
>()
.
likeIfPresent
(
CustomerInfoDO:
:
getContact
,
contact
));
}
}
\ No newline at end of file
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/customerinfo/CustomerInfoService.java
View file @
29054b48
...
...
@@ -52,4 +52,9 @@ public interface CustomerInfoService {
*/
PageResult
<
CustomerInfoDO
>
getCustomerInfoPage
(
CustomerInfoPageReqVO
pageReqVO
);
List
<
CustomerInfoDO
>
getCustomerInfoByCompanyName
(
String
companyName
);
List
<
CustomerInfoDO
>
getCustomerInfoByContact
(
String
contact
);
List
<
CustomerInfoDO
>
getAllCustomerInfo
();
}
\ No newline at end of file
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/customerinfo/CustomerInfoServiceImpl.java
View file @
29054b48
...
...
@@ -71,4 +71,18 @@ public class CustomerInfoServiceImpl implements CustomerInfoService {
return
customerInfoMapper
.
selectPage
(
pageReqVO
);
}
@Override
public
List
<
CustomerInfoDO
>
getCustomerInfoByCompanyName
(
String
companyName
)
{
return
customerInfoMapper
.
selectListByCompanyName
(
companyName
);
}
@Override
public
List
<
CustomerInfoDO
>
getCustomerInfoByContact
(
String
contact
)
{
return
customerInfoMapper
.
selectListByContact
(
contact
);
}
@Override
public
List
<
CustomerInfoDO
>
getAllCustomerInfo
()
{
return
customerInfoMapper
.
selectList
();
}
}
\ No newline at end of file
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/info/InfoServiceImpl.java
View file @
29054b48
package
cn
.
iocoder
.
yudao
.
module
.
visit
.
service
.
info
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.transaction.annotation.Transactional
;
import
java.util.*
;
import
cn.iocoder.yudao.module.visit.controller.admin.info.vo.*
;
import
cn.iocoder.yudao.module.visit.dal.dataobject.info.InfoDO
;
import
cn.iocoder.yudao.framework.common.pojo.PageResult
;
import
cn.iocoder.yudao.framework.common.pojo.PageParam
;
import
cn.iocoder.yudao.framework.common.util.object.BeanUtils
;
import
cn.iocoder.yudao.module.visit.controller.admin.customerinfo.vo.CustomerInfoSaveReqVO
;
import
cn.iocoder.yudao.module.visit.controller.admin.info.vo.InfoPageReqVO
;
import
cn.iocoder.yudao.module.visit.controller.admin.info.vo.InfoSaveReqVO
;
import
cn.iocoder.yudao.module.visit.dal.dataobject.customerinfo.CustomerInfoDO
;
import
cn.iocoder.yudao.module.visit.dal.dataobject.info.InfoDO
;
import
cn.iocoder.yudao.module.visit.dal.mysql.customerinfo.CustomerInfoMapper
;
import
cn.iocoder.yudao.module.visit.dal.mysql.info.InfoMapper
;
import
org.springframework.stereotype.Service
;
import
org.springframework.transaction.annotation.Transactional
;
import
org.springframework.validation.annotation.Validated
;
import
javax.annotation.Resource
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
exception
.
util
.
ServiceExceptionUtil
.
exception
;
import
static
cn
.
iocoder
.
yudao
.
module
.
visit
.
enums
.
ErrorCodeConstants
.
*
;
import
static
cn
.
iocoder
.
yudao
.
module
.
visit
.
enums
.
ErrorCodeConstants
.
INFO_NOT_EXISTS
;
/**
* 客户拜访记录 Service 实现类
...
...
@@ -29,11 +30,39 @@ public class InfoServiceImpl implements InfoService {
@Resource
private
InfoMapper
infoMapper
;
@Resource
private
CustomerInfoMapper
customerInfoMapper
;
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
Long
createInfo
(
InfoSaveReqVO
createReqVO
)
{
// 插入
InfoDO
info
=
BeanUtils
.
toBean
(
createReqVO
,
InfoDO
.
class
);
infoMapper
.
insert
(
info
);
int
insert
=
infoMapper
.
insert
(
info
);
if
(
insert
>
0
){
//拜访记录插入成功,根据【公司名称】判断该客户是否记录在案,如果没有,则插入一条客户信息
CustomerInfoDO
customerInfoDO
=
customerInfoMapper
.
selectByCompanyName
(
info
.
getCompanyName
());
if
(
customerInfoDO
==
null
){
//没查到说明该客户没有记录,插入一条客户信息
CustomerInfoSaveReqVO
customerInfoSaveReqVO
=
new
CustomerInfoSaveReqVO
();
customerInfoSaveReqVO
.
setCustomerName
(
info
.
getCustomerName
());
customerInfoSaveReqVO
.
setContact
(
info
.
getContact
());
customerInfoSaveReqVO
.
setCompanyName
(
info
.
getCompanyName
());
customerInfoSaveReqVO
.
setCustomerType
(
info
.
getCustomerStatus
());
customerInfoSaveReqVO
.
setProvinceName
(
info
.
getProvinceName
());
customerInfoSaveReqVO
.
setCityName
(
info
.
getCityName
());
customerInfoSaveReqVO
.
setAreaName
(
info
.
getAreaName
());
customerInfoSaveReqVO
.
setRegionFullName
(
info
.
getRegionFullName
());
customerInfoSaveReqVO
.
setLocationText
(
info
.
getLocationText
());
customerInfoSaveReqVO
.
setLongitude
(
info
.
getLongitude
());
customerInfoSaveReqVO
.
setLatitude
(
info
.
getLatitude
());
customerInfoSaveReqVO
.
setLocationImage
(
info
.
getLocationImage
());
customerInfoSaveReqVO
.
setProductIds
(
info
.
getVisitProductIds
());
customerInfoSaveReqVO
.
setProductNames
(
info
.
getVisitProductNames
());
customerInfoMapper
.
insert
(
BeanUtils
.
toBean
(
customerInfoSaveReqVO
,
CustomerInfoDO
.
class
));
}
}
// 返回
return
info
.
getId
();
}
...
...
yudao-ui/yudao-ui-admin-vue3/src/api/visit/customerinfo/index.ts
View file @
29054b48
...
...
@@ -31,6 +31,20 @@ export const CustomerInfoApi = {
return
await
request
.
get
({
url
:
`/visit/customer-info/get?id=`
+
id
})
},
// 查询客户信息详情根据客户公司名称
getCustomerInfoByCompanyName
:
async
(
param
:
string
)
=>
{
return
await
request
.
get
({
url
:
`/visit/customer-info/getByCompanyName?companyName=`
+
param
})
},
// 查询客户信息详情根据手机号
getCustomerInfoByPhone
:
async
(
param
:
string
)
=>
{
return
await
request
.
get
({
url
:
`/visit/customer-info/getByPhone?contact=`
+
param
})
},
// 查询所有客户信息详情
getAll
:
async
()
=>
{
return
await
request
.
get
({
url
:
`/visit/customer-info/getAll`
})
},
// 查询客户信息中拜访品种详情
getProductSimpleList
:
async
(
id
:
number
)
=>
{
return
await
request
.
get
({
url
:
`/visit/customer-info/getProductSimpleList?id=`
+
id
})
...
...
yudao-ui/yudao-ui-admin-vue3/src/api/visit/info/index.ts
View file @
29054b48
import
request
from
'
@/config/axios
'
// 客户拜访记录 VO
export
interface
InfoVO
{
id
:
number
// 主键ID
customerName
:
string
// 客户姓名
contact
:
string
// 联系方式(客户手机号)
companyName
:
string
// 客户公司名称
provinceName
:
string
// 省名称
cityName
:
string
// 市名称
areaName
:
string
// 区名称
locationText
:
string
// 定位地址文字描述
longitude
:
number
// 经度
latitude
:
number
// 纬度
locationImage
:
string
// 定位静态图URL
visitDate
:
Date
// 拜访日期
customerStatus
:
number
// 性质等级
visitProductIds
:
string
// 拜访品种(多选,逗号分隔)
visitMethod
:
number
// 拜访方式(字典)
visitType
:
number
// 拜访类型(字典)
serviceContent
:
string
// 服务内容
customerFeedback
:
string
// 客户反馈
serviceImages
:
string
// 服务记录图片URL列表(JSON数组)
}
// 客户拜访记录 API
export
const
InfoApi
=
{
// 查询客户拜访记录分页
getInfoPage
:
async
(
params
:
any
)
=>
{
return
await
request
.
get
({
url
:
`/visit/info/page`
,
params
})
},
// 查询客户拜访记录详情
getInfo
:
async
(
id
:
number
)
=>
{
return
await
request
.
get
({
url
:
`/visit/info/get?id=`
+
id
})
},
// 新增客户拜访记录
createInfo
:
async
(
data
:
InfoVO
)
=>
{
return
await
request
.
post
({
url
:
`/visit/info/create`
,
data
})
},
// 修改客户拜访记录
updateInfo
:
async
(
data
:
InfoVO
)
=>
{
return
await
request
.
put
({
url
:
`/visit/info/update`
,
data
})
},
// 删除客户拜访记录
deleteInfo
:
async
(
id
:
number
)
=>
{
return
await
request
.
delete
({
url
:
`/visit/info/delete?id=`
+
id
})
},
// 导出客户拜访记录 Excel
exportInfo
:
async
(
params
)
=>
{
return
await
request
.
download
({
url
:
`/visit/info/export-excel`
,
params
})
},
}
\ No newline at end of file
import
request
from
'
@/config/axios
'
// 客户拜访记录 VO
export
interface
InfoVO
{
id
:
number
// 主键ID
customerName
:
string
// 客户姓名
contact
:
string
// 联系方式(客户手机号)
companyName
:
string
// 客户公司名称
provinceName
:
string
// 省名称
cityName
:
string
// 市名称
areaName
:
string
// 区名称
locationText
:
string
// 定位地址文字描述
longitude
:
number
// 经度
latitude
:
number
// 纬度
locationImage
:
string
// 定位静态图URL
visitDate
:
Date
// 拜访日期
customerStatus
:
number
// 性质等级
visitProductIds
:
string
// 拜访品种(多选,逗号分隔)
visitMethod
:
number
// 拜访方式(字典)
visitType
:
number
// 拜访类型(字典)
serviceContent
:
string
// 服务内容
customerFeedback
:
string
// 客户反馈
serviceImages
:
string
// 服务记录图片URL列表(JSON数组)
}
// 客户拜访记录 API
export
const
InfoApi
=
{
// 查询客户拜访记录分页
getInfoPage
:
async
(
params
:
any
)
=>
{
return
await
request
.
get
({
url
:
`/visit/info/page`
,
params
})
},
// 查询客户拜访记录详情
getInfo
:
async
(
id
:
number
)
=>
{
return
await
request
.
get
({
url
:
`/visit/info/get?id=`
+
id
})
},
// 新增客户拜访记录
createInfo
:
async
(
data
:
InfoVO
)
=>
{
return
await
request
.
post
({
url
:
`/visit/info/create`
,
data
})
},
// 修改客户拜访记录
updateInfo
:
async
(
data
:
InfoVO
)
=>
{
return
await
request
.
put
({
url
:
`/visit/info/update`
,
data
})
},
// 删除客户拜访记录
deleteInfo
:
async
(
id
:
number
)
=>
{
return
await
request
.
delete
({
url
:
`/visit/info/delete?id=`
+
id
})
},
// 导出客户拜访记录 Excel
exportInfo
:
async
(
params
)
=>
{
return
await
request
.
download
({
url
:
`/visit/info/export-excel`
,
params
})
},
}
yudao-ui/yudao-ui-admin-vue3/src/components/UploadFile/src/UploadImgs.vue
View file @
29054b48
...
...
@@ -140,8 +140,9 @@ watch(
// 防止 val 为字符串、null、undefined 报错
let
urls
:
string
[]
=
[]
//过滤数组中的空字符串
if
(
Array
.
isArray
(
val
))
{
urls
=
val
urls
=
val
.
filter
((
url
)
=>
url
.
trim
()
!==
''
)
}
else
if
(
typeof
val
===
'
string
'
)
{
urls
=
val
.
split
(
'
,
'
).
filter
((
url
)
=>
url
.
trim
()
!==
''
)
}
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/customerinfo/CustomerInfoForm.vue
View file @
29054b48
...
...
@@ -71,7 +71,7 @@
<!-- </el-form-item>-->
<el-form-item
label=
"产品信息"
prop=
"productIds"
>
<el-input
v-model=
"formData.product
Id
s"
v-model=
"formData.product
Name
s"
placeholder=
"请点击右侧选择"
readonly
>
...
...
@@ -130,6 +130,7 @@ interface CustomerFormData {
latitude
?:
number
;
locationImage
?:
string
;
productIds
?:
string
;
productNames
?:
string
;
department
?:
string
;
}
const
formData
=
ref
<
CustomerFormData
>
({
...
...
@@ -147,6 +148,7 @@ const formData = ref<CustomerFormData>({
latitude
:
undefined
,
locationImage
:
undefined
,
productIds
:
undefined
,
productNames
:
undefined
,
department
:
undefined
,
})
const
formRules
=
reactive
({
...
...
@@ -173,10 +175,10 @@ const openProduct=()=>{
productListRef
.
value
?.
open
();
// 调用子组件暴露的方法
}
const
handleUpdateProduct
=
(
ids
:
string
)
=>
{
console
.
log
(
'
来自子组件的产品ID:
'
,
ids
);
const
handleUpdateProduct
=
(
ids
:
string
,
names
:
string
)
=>
{
//存入表单
formData
.
value
.
productIds
=
ids
;
formData
.
value
.
productNames
=
names
;
};
//===========================================地图相关操作=================================
const
mapPickerRef
=
ref
()
...
...
@@ -285,6 +287,7 @@ const resetForm = () => {
latitude
:
undefined
,
locationImage
:
undefined
,
productIds
:
undefined
,
productNames
:
undefined
,
department
:
undefined
,
}
formRef
.
value
?.
resetFields
()
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/customerinfo/productTable.vue
View file @
29054b48
...
...
@@ -126,12 +126,13 @@ const props = defineProps({
const
tableRef
=
ref
();
//表单
// 定义事件名和参数类型(可选)
const
emit
=
defineEmits
<
{
(
e
:
'
updateProduct
'
,
data
:
string
):
void
;
(
e
:
'
updateProduct
'
,
ids
:
string
,
names
:
string
):
void
;
}
>
();
const
sendToParent
=
()
=>
{
const
joinedIds
=
multipleSelection
.
value
.
join
(
'
,
'
);
// ✅ 转为 "101,203,305"
emit
(
'
updateProduct
'
,
joinedIds
);
// ✅ 传 string 给父组件
const
joinedNames
=
multipleSelectionName
.
value
.
join
(
'
,
'
);
// ✅ 转为 "阿莫西林,银翘片"
emit
(
'
updateProduct
'
,
joinedIds
,
joinedNames
);
// ✅ 传 string 给父组件
dialogTableVisible
.
value
=
false
;
// ✅ 关闭弹窗
};
...
...
@@ -149,6 +150,7 @@ const queryParams = reactive({
})
const
queryFormRef
=
ref
()
// 搜索的表单
const
multipleSelection
=
ref
<
any
[]
>
([])
//存储多选内容
const
multipleSelectionName
=
ref
<
any
[]
>
([])
//存储多选内容
// 打开弹窗
const
open
=
()
=>
{
dialogTableVisible
.
value
=
true
...
...
@@ -164,7 +166,10 @@ const open = () => {
/** 多选操作**/
const
handleSelectionChange
=
(
val
)
=>
{
multipleSelection
.
value
=
val
.
map
(
item
=>
item
.
id
)
console
.
log
(
val
,
multipleSelection
)
multipleSelectionName
.
value
=
val
.
map
(
item
=>
item
.
productName
)
console
.
log
(
val
)
console
.
log
(
"
=========
"
)
console
.
log
(
multipleSelectionName
)
}
/** 查询列表 */
const
getList
=
async
()
=>
{
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/info/InfoForm.vue
View file @
29054b48
...
...
@@ -14,20 +14,15 @@
<el-input
v-model=
"formData.contact"
placeholder=
"请输入联系方式"
/>
</el-form-item>
<el-form-item
label=
"公司名称"
prop=
"companyName"
>
<el-input
v-model=
"formData.companyName"
placeholder=
"请输入客户公司名称"
/>
<el-autocomplete
v-model=
"formData.companyName"
:fetch-suggestions=
"querySearch"
clearable
class=
"inline-input w-50"
@
select=
"handleSelect"
placeholder=
"请输入客户公司名称"
/>
</el-form-item>
<!--
<el-form-item
label=
"省名称"
prop=
"provinceName"
>
-->
<!--
<el-input
v-model=
"formData.provinceName"
placeholder=
"请输入省名称"
/>
-->
<!--
</el-form-item>
-->
<!--
<el-form-item
label=
"市名称"
prop=
"cityName"
>
-->
<!--
<el-input
v-model=
"formData.cityName"
placeholder=
"请输入市名称"
/>
-->
<!--
</el-form-item>
-->
<!--
<el-form-item
label=
"区名称"
prop=
"areaName"
>
-->
<!--
<el-input
v-model=
"formData.areaName"
placeholder=
"请输入区名称"
/>
-->
<!--
</el-form-item>
-->
<!--
<el-form-item
label=
"所在地址"
prop=
"areaName"
>
-->
<!--
<el-input
v-model=
"formData.regionFullName"
placeholder=
"请输入区名称"
/>
-->
<!--
</el-form-item>
-->
<el-form-item
label=
"所在地区"
prop=
"regionFullName"
>
<el-cascader
placeholder=
"请选择地区"
...
...
@@ -37,18 +32,6 @@
@
change=
"handleChange"
/>
</el-form-item>
<!--
<el-form-item
label=
"定位地址文字描述"
prop=
"locationText"
>
-->
<!--
<el-input
v-model=
"formData.locationText"
placeholder=
"请输入定位地址文字描述"
/>
-->
<!--
</el-form-item>
-->
<!--
<el-form-item
label=
"经度"
prop=
"longitude"
>
-->
<!--
<el-input
v-model=
"formData.longitude"
placeholder=
"请输入经度"
/>
-->
<!--
</el-form-item>
-->
<!--
<el-form-item
label=
"纬度"
prop=
"latitude"
>
-->
<!--
<el-input
v-model=
"formData.latitude"
placeholder=
"请输入纬度"
/>
-->
<!--
</el-form-item>
-->
<!--
<el-form-item
label=
"定位静态图URL"
prop=
"locationImage"
>
-->
<!--
<UploadImg
v-model=
"formData.locationImage"
/>
-->
<!--
</el-form-item>
-->
<el-form-item
label=
"详细地址"
prop=
"locationText"
>
<el-input
v-model=
"formData.locationText"
...
...
@@ -64,7 +47,7 @@
<el-form-item
label=
"拜访日期"
prop=
"visitDate"
>
<el-date-picker
v-model=
"formData.visitDate"
type=
"date"
type=
"date
time
"
value-format=
"x"
placeholder=
"选择拜访日期"
/>
...
...
@@ -79,9 +62,9 @@
/>
</el-select>
</el-form-item>
<el-form-item
label=
"拜访品种"
prop=
"visitProduct
Id
s"
>
<el-form-item
label=
"拜访品种"
prop=
"visitProduct
Name
s"
>
<el-input
v-model=
"formData.visitProduct
Id
s"
v-model=
"formData.visitProduct
Name
s"
placeholder=
"请点击右侧选择"
readonly
>
...
...
@@ -111,10 +94,24 @@
</el-select>
</el-form-item>
<el-form-item
label=
"服务内容"
prop=
"serviceContent"
>
<Editor
v-model=
"formData.serviceContent"
height=
"150px"
/>
<el-input
v-model=
"formData.serviceContent"
type=
"textarea"
placeholder=
"请输入服务内容"
maxlength=
"500"
show-word-limit
:autosize=
"{ minRows: 4, maxRows: 6 }"
/>
</el-form-item>
<el-form-item
label=
"客户反馈"
prop=
"customerFeedback"
>
<el-input
v-model=
"formData.customerFeedback"
placeholder=
"请输入客户反馈"
/>
<el-input
v-model=
"formData.customerFeedback"
type=
"textarea"
placeholder=
"请输入客户反馈"
maxlength=
"500"
show-word-limit
:autosize=
"{ minRows: 4, maxRows: 6 }"
/>
</el-form-item>
<el-form-item
label=
"服务记录图片URL列表"
prop=
"serviceImages"
>
<UploadImgs
v-model=
"formData.serviceImages"
:limit=
"9"
/>
...
...
@@ -130,10 +127,11 @@
<
script
setup
lang=
"ts"
>
import
{
getIntDictOptions
,
DICT_TYPE
}
from
'
@/utils/dict
'
import
{
InfoApi
,
InfoVO
}
from
'
@/api/visit/info
'
import
{
CustomerInfoApi
}
from
'
@/api/visit/customerinfo
'
import
productTable
from
"
@/views/visit/customerinfo/productTable.vue
"
;
import
{
pcaTextArr
}
from
'
element-china-area-data
'
import
MapPicker
from
'
../util/MapPicker.vue
'
import
dayjs
from
'
dayjs
'
;
import
{
onMounted
}
from
'
vue
'
/** 客户拜访记录 表单 */
defineOptions
({
name
:
'
InfoForm
'
})
...
...
@@ -159,9 +157,10 @@ const formData = ref({
longitude
:
undefined
,
latitude
:
undefined
,
locationImage
:
undefined
,
visitDate
:
undefined
,
visitDate
:
Date
.
now
()
,
customerStatus
:
undefined
,
visitProductIds
:
undefined
,
visitProductNames
:
undefined
,
visitMethod
:
undefined
,
visitType
:
undefined
,
serviceContent
:
undefined
,
...
...
@@ -182,9 +181,79 @@ const formRules = reactive({
locationImage
:
[{
required
:
true
,
message
:
'
定位静态图URL不能为空
'
,
trigger
:
'
blur
'
}],
visitDate
:
[{
required
:
true
,
message
:
'
拜访日期不能为空
'
,
trigger
:
'
blur
'
}],
customerStatus
:
[{
required
:
true
,
message
:
'
性质等级不能为空
'
,
trigger
:
'
blur
'
}],
serviceContent
:
[{
required
:
true
,
message
:
'
请输入服务内容
'
,
trigger
:
'
blur
'
},
{
max
:
500
,
message
:
'
最多输入 500 个字符
'
,
trigger
:
'
blur
'
}],
customerFeedback
:
[{
required
:
true
,
message
:
'
请输入客户反馈
'
,
trigger
:
'
blur
'
},
{
max
:
500
,
message
:
'
最多输入 500 个字符
'
,
trigger
:
'
blur
'
}],
})
const
formRef
=
ref
()
// 表单 Ref
//===========================================下拉搜索相关====================================
interface
RestaurantItem
{
companyName
:
string
contact
:
string
}
const
restaurants
=
ref
<
RestaurantItem
[]
>
([])
const
querySearch
=
(
queryString
:
string
,
cb
:
any
)
=>
{
const
results
=
queryString
?
restaurants
.
value
.
filter
(
createFilter
(
queryString
))
:
restaurants
.
value
// call callback function to return suggestions
console
.
log
(
results
)
cb
(
results
)
}
const
createFilter
=
(
queryString
:
string
)
=>
{
return
(
restaurant
:
RestaurantItem
)
=>
{
return
(
restaurant
.
value
.
toLowerCase
().
indexOf
(
queryString
.
toLowerCase
())
===
0
)
}
}
const
loadAll
=
async
()
=>
{
try
{
const
res
=
await
CustomerInfoApi
.
getAll
()
if
(
!
res
||
!
Array
.
isArray
(
res
))
{
console
.
warn
(
'
返回结果格式不符合预期:
'
,
res
)
restaurants
.
value
=
[]
return
}
restaurants
.
value
=
res
.
map
(
item
=>
({
value
:
item
?.
companyName
||
''
,
companyName
:
item
?.
companyName
||
''
,
contact
:
item
?.
contact
||
''
,
customerName
:
item
?.
customerName
||
''
,
provinceName
:
item
?.
provinceName
||
''
,
cityName
:
item
?.
cityName
||
''
,
areaName
:
item
?.
areaName
||
''
,
regionFullName
:
item
?.
regionFullName
||
''
,
locationText
:
item
?.
locationText
||
''
,
longitude
:
item
?.
longitude
||
''
,
latitude
:
item
?.
latitude
||
''
,
locationImage
:
item
?.
locationImage
||
''
,
customerStatus
:
item
?.
customerType
??
''
,
}))
}
catch
(
error
)
{
console
.
error
(
'
加载公司信息失败:
'
,
error
)
restaurants
.
value
=
[]
}
}
/** 选中后自动带出公司名称和联系方式 */
const
handleSelect
=
(
item
:
Record
<
string
,
any
>
)
=>
{
formData
.
value
.
companyName
=
item
.
companyName
;
formData
.
value
.
contact
=
item
.
contact
;
formData
.
value
.
customerName
=
item
.
customerName
;
formData
.
value
.
regionFullName
=
item
.
regionFullName
;
formData
.
value
.
provinceName
=
item
.
provinceName
;
formData
.
value
.
cityName
=
item
.
cityName
;
formData
.
value
.
areaName
=
item
.
areaName
;
formData
.
value
.
locationText
=
item
.
locationText
;
formData
.
value
.
longitude
=
item
.
longitude
;
formData
.
value
.
latitude
=
item
.
latitude
;
formData
.
value
.
locationImage
=
item
.
locationImage
;
formData
.
value
.
customerStatus
=
item
.
customerStatus
;
restoreSelectedOptionsFromForm
();
}
//===========================================选择产品相关操作=================================
const
productListRef
=
ref
<
InstanceType
<
typeof
productTable
>
|
null
>
(
null
);
// 产品列表 Ref
...
...
@@ -193,10 +262,11 @@ const openProduct=()=>{
productListRef
.
value
?.
open
();
// 调用子组件暴露的方法
}
const
handleUpdateProduct
=
(
ids
:
string
)
=>
{
console
.
log
(
'
来自子组件的产品ID:
'
,
ids
);
const
handleUpdateProduct
=
(
ids
:
string
,
names
:
string
)
=>
{
//存入表单
formData
.
value
.
visitProductIds
=
ids
;
console
.
log
(
names
)
formData
.
value
.
visitProductNames
=
names
;
};
//===========================================地图相关操作=================================
const
mapPickerRef
=
ref
()
...
...
@@ -280,8 +350,6 @@ const submitForm = async () => {
if
(
Array
.
isArray
(
raw
.
serviceImages
))
{
raw
.
serviceImages
=
raw
.
serviceImages
.
join
(
'
,
'
);
}
//时间戳转换成字符串
formData
.
value
.
visitDate
=
dayjs
(
formData
.
value
.
visitDate
).
format
(
'
YYYY-MM-DD
'
);
// 提交请求
formLoading
.
value
=
true
try
{
...
...
@@ -316,9 +384,10 @@ const resetForm = () => {
longitude
:
undefined
,
latitude
:
undefined
,
locationImage
:
undefined
,
visitDate
:
undefined
,
visitDate
:
Date
.
now
()
,
customerStatus
:
undefined
,
visitProductIds
:
undefined
,
visitProductNames
:
undefined
,
visitMethod
:
undefined
,
visitType
:
undefined
,
serviceContent
:
undefined
,
...
...
@@ -328,4 +397,8 @@ const resetForm = () => {
formRef
.
value
?.
resetFields
()
selectedOptions
.
value
=
[];
}
onMounted
(()
=>
{
loadAll
()
})
</
script
>
yudao-ui/yudao-ui-admin-vue3/src/views/visit/info/index.vue
View file @
29054b48
...
...
@@ -135,16 +135,26 @@
<el-table
v-loading=
"loading"
:data=
"list"
:stripe=
"true"
:show-overflow-tooltip=
"true"
>
<el-table-column
label=
"主键ID"
align=
"center"
prop=
"id"
/>
<el-table-column
label=
"拜访人姓名"
align=
"center"
prop=
"customerName"
width=
"100px"
/>
<el-table-column
label=
"联系方式"
align=
"center"
prop=
"contact"
/>
<el-table-column
label=
"客户公司名称"
align=
"center"
prop=
"companyName"
width=
"120px"
/>
<el-table-column
label=
"所在省市区"
align=
"center"
prop=
"regionFullName"
width=
"100px"
/>
<el-table-column
label=
"拜访日期"
align=
"center"
prop=
"visitDate"
/>
<el-table-column
label=
"联系方式"
align=
"center"
prop=
"contact"
width=
"120px"
/>
<el-table-column
label=
"客户公司名称"
align=
"center"
prop=
"companyName"
width=
"160px"
/>
<el-table-column
label=
"所在省市区"
align=
"center"
prop=
"regionFullName"
width=
"160px"
/>
<el-table-column
label=
"拜访日期"
align=
"center"
prop=
"visitDate"
:formatter=
"dateFormatter"
width=
"180px"
/>
<el-table-column
label=
"性质等级"
align=
"center"
prop=
"customerStatus"
>
<template
#default
="
scope
"
>
<dict-tag
:type=
"DICT_TYPE.CUSTOMER_TYPE"
:value=
"scope.row.customerStatus"
/>
</
template
>
</el-table-column>
<el-table-column
label=
"拜访品种"
align=
"center"
prop=
"visitProductIds"
/>
<el-table-column
label=
"拜访品种"
align=
"center"
prop=
"visitProductIds"
width=
"100px"
>
<
template
#default
="
scope
"
>
<ProductList
:ids=
scope.row.visitProductIds
/>
</
template
>
</el-table-column>
<el-table-column
label=
"拜访方式"
align=
"center"
prop=
"visitMethod"
>
<
template
#default
="
scope
"
>
<dict-tag
:type=
"DICT_TYPE.VISIT_METHOD"
:value=
"scope.row.visitMethod"
/>
...
...
@@ -162,7 +172,7 @@
:formatter=
"dateFormatter"
width=
"180px"
/>
<el-table-column
label=
"操作"
align=
"center"
min-width=
"120px"
>
<el-table-column
label=
"操作"
align=
"center"
min-width=
"120px"
fixed=
"right"
>
<
template
#default
="
scope
"
>
<el-button
link
...
...
@@ -202,6 +212,7 @@ import { dateFormatter } from '@/utils/formatTime'
import
download
from
'
@/utils/download
'
import
{
InfoApi
,
InfoVO
}
from
'
@/api/visit/info
'
import
InfoForm
from
'
./InfoForm.vue
'
import
ProductList
from
"
@/views/visit/util/ProductList.vue
"
;
/** 客户拜访记录 列表 */
defineOptions
({
name
:
'
Info
'
})
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/util/ProductList.vue
View file @
29054b48
...
...
@@ -33,7 +33,6 @@ const gridData = ref<Product[]>([])
const
getHandler
=
async
():
Promise
<
void
>
=>
{
try
{
gridData
.
value
=
await
ProductApi
.
getProductByIds
(
props
.
ids
)
// 显式使用props
console
.
log
(
gridData
);
}
catch
(
error
)
{
console
.
error
(
'
获取产品失败:
'
,
error
)
gridData
.
value
=
[]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment