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
07703c77
Commit
07703c77
authored
May 30, 2025
by
法拉51246
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
前端腾讯地图api对接
客户信息页面省市区级联+选择地点功能+存储腾讯地图静态地图URL ----- 后端增加产品的导入 改变app-api的会员身份校验(都改为管理员身份userType)
parent
20a8a2b4
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
528 additions
and
39 deletions
+528
-39
WebFrameworkUtils.java
...oder/yudao/framework/web/core/util/WebFrameworkUtils.java
+1
-1
UserController.java
...o/module/system/controller/admin/user/UserController.java
+4
-4
pom.xml
yudao-module-visit/pom.xml
+4
-0
CustomerInfoRespVO.java
.../controller/admin/customerinfo/vo/CustomerInfoRespVO.java
+23
-0
ProductController.java
...ule/visit/controller/admin/product/ProductController.java
+33
-3
ProductImportExcelVO.java
...sit/controller/admin/product/vo/ProductImportExcelVO.java
+37
-0
ProductImportRespVO.java
...isit/controller/admin/product/vo/ProductImportRespVO.java
+24
-0
ProductMapper.java
...r/yudao/module/visit/dal/mysql/product/ProductMapper.java
+4
-0
ErrorCodeConstants.java
.../iocoder/yudao/module/visit/enums/ErrorCodeConstants.java
+2
-0
ProductService.java
...er/yudao/module/visit/service/product/ProductService.java
+7
-0
ProductServiceImpl.java
...udao/module/visit/service/product/ProductServiceImpl.java
+52
-0
package-lock.json
yudao-ui/yudao-ui-admin-vue3/package-lock.json
+14
-0
package.json
yudao-ui/yudao-ui-admin-vue3/package.json
+1
-0
index.ts
yudao-ui/yudao-ui-admin-vue3/src/api/visit/product/index.ts
+5
-0
index.vue
yudao-ui/yudao-ui-admin-vue3/src/views/system/user/index.vue
+8
-8
CustomerInfoForm.vue
...in-vue3/src/views/visit/customerinfo/CustomerInfoForm.vue
+95
-23
ProductImportForm.vue
...-admin-vue3/src/views/visit/product/ProductImportForm.vue
+134
-0
index.vue
...-ui/yudao-ui-admin-vue3/src/views/visit/product/index.vue
+17
-0
MapPicker.vue
...ui/yudao-ui-admin-vue3/src/views/visit/util/MapPicker.vue
+63
-0
No files found.
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
View file @
07703c77
...
...
@@ -113,7 +113,7 @@ public class WebFrameworkUtils {
return
UserTypeEnum
.
ADMIN
.
getValue
();
}
if
(
request
.
getServletPath
().
startsWith
(
properties
.
getAppApi
().
getPrefix
()))
{
return
UserTypeEnum
.
MEMBER
.
getValue
();
return
UserTypeEnum
.
ADMIN
.
getValue
();
//暂时去掉会员的用户类型,全部都是管理员用户类型
}
return
null
;
}
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java
View file @
07703c77
...
...
@@ -147,10 +147,10 @@ public class UserController {
public
void
importTemplate
(
HttpServletResponse
response
)
throws
IOException
{
// 手动创建导出 demo
List
<
UserImportExcelVO
>
list
=
Arrays
.
asList
(
UserImportExcelVO
.
builder
().
username
(
"
yunai"
).
deptId
(
1L
).
email
(
"yunai@iocoder.cn
"
).
mobile
(
"15601691300"
)
.
nickname
(
"
芋道
"
).
status
(
CommonStatusEnum
.
ENABLE
.
getStatus
()).
sex
(
SexEnum
.
MALE
.
getSex
()).
build
(),
UserImportExcelVO
.
builder
().
username
(
"
yuanma"
).
deptId
(
2L
).
email
(
"yuanma@iocoder.cn
"
).
mobile
(
"15601701300"
)
.
nickname
(
"
源码
"
).
status
(
CommonStatusEnum
.
DISABLE
.
getStatus
()).
sex
(
SexEnum
.
FEMALE
.
getSex
()).
build
()
UserImportExcelVO
.
builder
().
username
(
"
falao"
).
deptId
(
1L
).
email
(
"666666@qq.com
"
).
mobile
(
"15601691300"
)
.
nickname
(
"
模板用户1
"
).
status
(
CommonStatusEnum
.
ENABLE
.
getStatus
()).
sex
(
SexEnum
.
MALE
.
getSex
()).
build
(),
UserImportExcelVO
.
builder
().
username
(
"
fala"
).
deptId
(
2L
).
email
(
"666666@qq.com
"
).
mobile
(
"15601701300"
)
.
nickname
(
"
模板用户2
"
).
status
(
CommonStatusEnum
.
DISABLE
.
getStatus
()).
sex
(
SexEnum
.
FEMALE
.
getSex
()).
build
()
);
// 输出
ExcelUtils
.
write
(
response
,
"用户导入模板.xls"
,
"用户列表"
,
UserImportExcelVO
.
class
,
list
);
...
...
yudao-module-visit/pom.xml
View file @
07703c77
...
...
@@ -41,6 +41,10 @@
<groupId>
cn.iocoder.boot
</groupId>
<artifactId>
yudao-spring-boot-starter-excel
</artifactId>
</dependency>
<dependency>
<groupId>
cn.iocoder.boot
</groupId>
<artifactId>
yudao-spring-boot-starter-biz-data-permission
</artifactId>
</dependency>
</dependencies>
</project>
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/customerinfo/vo/CustomerInfoRespVO.java
View file @
07703c77
...
...
@@ -40,6 +40,29 @@ public class CustomerInfoRespVO {
@ExcelProperty
(
"所在地区"
)
private
String
regionFullName
;
@Schema
(
description
=
"详细地址"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"详细地址"
)
private
String
locationText
;
@Schema
(
description
=
"经度"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
private
BigDecimal
longitude
;
@Schema
(
description
=
"纬度"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
private
BigDecimal
latitude
;
@Schema
(
description
=
"产品ID"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"产品ID"
)
private
String
productIds
;
@Schema
(
description
=
"部门"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"部门"
)
@DictFormat
(
"customer_dept"
)
private
String
department
;
@Schema
(
description
=
"静态图"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"静态图"
)
private
String
locationImage
;
@Schema
(
description
=
"创建时间"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
@ExcelProperty
(
"创建时间"
)
private
LocalDateTime
createTime
;
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/product/ProductController.java
View file @
07703c77
package
cn
.
iocoder
.
yudao
.
module
.
visit
.
controller
.
admin
.
product
;
import
cn.iocoder.yudao.framework.common.enums.CommonStatusEnum
;
import
cn.iocoder.yudao.module.system.enums.common.SexEnum
;
import
io.swagger.v3.oas.annotations.Parameters
;
import
org.springframework.web.bind.annotation.*
;
import
javax.annotation.Resource
;
import
org.springframework.validation.annotation.Validated
;
...
...
@@ -28,6 +31,7 @@ import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import
cn.iocoder.yudao.module.visit.controller.admin.product.vo.*
;
import
cn.iocoder.yudao.module.visit.dal.dataobject.product.ProductDO
;
import
cn.iocoder.yudao.module.visit.service.product.ProductService
;
import
org.springframework.web.multipart.MultipartFile
;
@Tag
(
name
=
"管理后台 - 产品"
)
@RestController
...
...
@@ -38,9 +42,6 @@ public class ProductController {
@Resource
private
ProductService
productService
;
public
ProductController
(){
System
.
out
.
println
(
"生效"
);
}
@PostMapping
(
"/create"
)
@Operation
(
summary
=
"创建产品"
)
...
...
@@ -96,4 +97,33 @@ public class ProductController {
BeanUtils
.
toBean
(
list
,
ProductRespVO
.
class
));
}
@GetMapping
(
"/get-import-template"
)
@Operation
(
summary
=
"获得导入品种资料模板"
)
public
void
importTemplate
(
HttpServletResponse
response
)
throws
IOException
{
// 手动创建导出 demo
List
<
ProductImportExcelVO
>
list
=
Arrays
.
asList
(
ProductImportExcelVO
.
builder
().
productName
(
"阿莫西林胶囊"
).
specification
(
"20x20mg"
).
packageName
(
"盒装"
)
.
status
(
CommonStatusEnum
.
ENABLE
.
getStatus
()).
build
(),
ProductImportExcelVO
.
builder
().
productName
(
"阿莫西林胶囊"
).
specification
(
"10x50mg"
).
packageName
(
"袋装"
)
.
status
(
CommonStatusEnum
.
DISABLE
.
getStatus
()).
build
()
);
// 输出
ExcelUtils
.
write
(
response
,
"品种资料导入模板.xls"
,
"品种资料列表"
,
ProductImportExcelVO
.
class
,
list
);
}
@PostMapping
(
"/import"
)
@Operation
(
summary
=
"导入品种资料"
)
@Parameters
({
@Parameter
(
name
=
"file"
,
description
=
"Excel 文件"
,
required
=
true
),
@Parameter
(
name
=
"updateSupport"
,
description
=
"是否支持更新,默认为 false"
,
example
=
"true"
)
})
@PreAuthorize
(
"@ss.hasPermission('system:product:import')"
)
public
CommonResult
<
ProductImportRespVO
>
importExcel
(
@RequestParam
(
"file"
)
MultipartFile
file
,
@RequestParam
(
value
=
"updateSupport"
,
required
=
false
,
defaultValue
=
"false"
)
Boolean
updateSupport
)
throws
Exception
{
List
<
ProductImportExcelVO
>
list
=
ExcelUtils
.
read
(
file
,
ProductImportExcelVO
.
class
);
return
success
(
productService
.
importProductList
(
list
,
updateSupport
));
}
}
\ No newline at end of file
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/product/vo/ProductImportExcelVO.java
0 → 100644
View file @
07703c77
package
cn
.
iocoder
.
yudao
.
module
.
visit
.
controller
.
admin
.
product
.
vo
;
import
cn.iocoder.yudao.framework.excel.core.annotations.DictFormat
;
import
cn.iocoder.yudao.framework.excel.core.convert.DictConvert
;
import
cn.iocoder.yudao.module.system.enums.DictTypeConstants
;
import
com.alibaba.excel.annotation.ExcelProperty
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.AllArgsConstructor
;
import
lombok.Builder
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
lombok.experimental.Accessors
;
/**
* 用户 Excel 导入 VO
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors
(
chain
=
false
)
// 设置 chain = false,避免用户导入有问题
public
class
ProductImportExcelVO
{
@ExcelProperty
(
"品种名称"
)
private
String
productName
;
@ExcelProperty
(
"规格"
)
private
String
specification
;
@ExcelProperty
(
"包装信息"
)
private
String
packageName
;
@ExcelProperty
(
value
=
"状态"
,
converter
=
DictConvert
.
class
)
@DictFormat
(
DictTypeConstants
.
COMMON_STATUS
)
private
Integer
status
;
}
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/product/vo/ProductImportRespVO.java
0 → 100644
View file @
07703c77
package
cn
.
iocoder
.
yudao
.
module
.
visit
.
controller
.
admin
.
product
.
vo
;
import
io.swagger.v3.oas.annotations.media.Schema
;
import
lombok.Builder
;
import
lombok.Data
;
import
java.util.List
;
import
java.util.Map
;
@Schema
(
description
=
"管理后台 - 用户导入 Response VO"
)
@Data
@Builder
public
class
ProductImportRespVO
{
@Schema
(
description
=
"创建成功的品种名称数组"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
private
List
<
String
>
createProductNames
;
@Schema
(
description
=
"更新成功的品种名称数组"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
private
List
<
String
>
updateProductNames
;
@Schema
(
description
=
"导入失败的品种名称用户集合,key 为品种名称,value 为失败原因"
,
requiredMode
=
Schema
.
RequiredMode
.
REQUIRED
)
private
Map
<
String
,
String
>
failureProductNames
;
}
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/dal/mysql/product/ProductMapper.java
View file @
07703c77
...
...
@@ -17,6 +17,10 @@ import cn.iocoder.yudao.module.visit.controller.admin.product.vo.*;
@Mapper
public
interface
ProductMapper
extends
BaseMapperX
<
ProductDO
>
{
default
ProductDO
selectByProductParam
(
String
productName
,
String
specification
,
String
packageName
)
{
return
selectOne
(
ProductDO:
:
getProductName
,
productName
,
ProductDO:
:
getSpecification
,
specification
,
ProductDO:
:
getPackageName
,
packageName
);
}
default
PageResult
<
ProductDO
>
selectPage
(
ProductPageReqVO
reqVO
)
{
return
selectPage
(
reqVO
,
new
LambdaQueryWrapperX
<
ProductDO
>()
.
likeIfPresent
(
ProductDO:
:
getProductName
,
reqVO
.
getProductName
())
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/enums/ErrorCodeConstants.java
View file @
07703c77
...
...
@@ -11,6 +11,8 @@ public interface ErrorCodeConstants {
// ========== 产品 ==========
ErrorCode
PRODUCT_NOT_EXISTS
=
new
ErrorCode
(
1001000001
,
"产品不存在"
);
ErrorCode
PRODUCT_IMPORT_LIST_IS_EMPTY
=
new
ErrorCode
(
1001000002
,
"导入产品数据不能为空!"
);
ErrorCode
PRODUCT_PRODUCT_EXISTS
=
new
ErrorCode
(
1001000002
,
"导入产品已存在!"
);
// ========== 客户信息 ==========
ErrorCode
CUSTOMER_INFO_NOT_EXISTS
=
new
ErrorCode
(
1002000001
,
"客户信息不存在"
);
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/product/ProductService.java
View file @
07703c77
...
...
@@ -52,4 +52,11 @@ public interface ProductService {
*/
PageResult
<
ProductDO
>
getProductPage
(
ProductPageReqVO
pageReqVO
);
/**
* 导入产品信息
*
* @param list 分页查询
* @return 产品分页
*/
ProductImportRespVO
importProductList
(
List
<
ProductImportExcelVO
>
list
,
Boolean
updateSupport
);
}
\ No newline at end of file
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/product/ProductServiceImpl.java
View file @
07703c77
package
cn
.
iocoder
.
yudao
.
module
.
visit
.
service
.
product
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.iocoder.yudao.framework.common.exception.ServiceException
;
import
cn.iocoder.yudao.framework.common.util.collection.CollectionUtils
;
import
cn.iocoder.yudao.framework.common.util.validation.ValidationUtils
;
import
cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
import
javax.validation.ConstraintViolationException
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.transaction.annotation.Transactional
;
...
...
@@ -15,6 +23,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import
cn.iocoder.yudao.module.visit.dal.mysql.product.ProductMapper
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
exception
.
util
.
ServiceExceptionUtil
.
exception
;
import
static
cn
.
iocoder
.
yudao
.
module
.
system
.
enums
.
ErrorCodeConstants
.*;
import
static
cn
.
iocoder
.
yudao
.
module
.
visit
.
enums
.
ErrorCodeConstants
.*;
/**
...
...
@@ -71,4 +80,47 @@ public class ProductServiceImpl implements ProductService {
return
productMapper
.
selectPage
(
pageReqVO
);
}
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
// 添加事务,异常则回滚所有导入
public
ProductImportRespVO
importProductList
(
List
<
ProductImportExcelVO
>
importProducts
,
Boolean
isUpdateSupport
)
{
// 1 参数校验
if
(
CollUtil
.
isEmpty
(
importProducts
))
{
throw
exception
(
PRODUCT_IMPORT_LIST_IS_EMPTY
);
}
// 2. 遍历,逐个创建 or 更新
ProductImportRespVO
respVO
=
ProductImportRespVO
.
builder
().
createProductNames
(
new
ArrayList
<>())
.
updateProductNames
(
new
ArrayList
<>()).
failureProductNames
(
new
LinkedHashMap
<>()).
build
();
importProducts
.
forEach
(
importProduct
->
{
// 2.1.1 校验,判断是否有不符合的原因
try
{
validateProductUnique
(
importProduct
.
getProductName
(),
importProduct
.
getSpecification
(),
importProduct
.
getPackageName
());
}
catch
(
ServiceException
ex
)
{
respVO
.
getFailureProductNames
().
put
(
importProduct
.
getProductName
()+
importProduct
.
getSpecification
()+
importProduct
.
getPackageName
(),
ex
.
getMessage
());
return
;
}
// 2.2.1 判断如果不存在,在进行插入
ProductDO
existProduct
=
productMapper
.
selectByProductParam
(
importProduct
.
getProductName
(),
importProduct
.
getSpecification
(),
importProduct
.
getPackageName
());
if
(
existProduct
==
null
)
{
productMapper
.
insert
(
BeanUtils
.
toBean
(
importProduct
,
ProductDO
.
class
));
respVO
.
getCreateProductNames
().
add
(
importProduct
.
getProductName
()+
importProduct
.
getSpecification
()+
importProduct
.
getPackageName
());
}
});
return
respVO
;
}
private
void
validateProductUnique
(
String
productName
,
String
specification
,
String
packageName
)
{
ProductPageReqVO
productPageReqVO
=
new
ProductPageReqVO
();
productPageReqVO
.
setProductName
(
productName
);
productPageReqVO
.
setSpecification
(
specification
);
productPageReqVO
.
setPackageName
(
packageName
);
PageResult
<
ProductDO
>
productDOPageResult
=
productMapper
.
selectPage
(
productPageReqVO
);
if
(
productDOPageResult
.
getTotal
()
>
0
)
{
throw
exception
(
PRODUCT_PRODUCT_EXISTS
);
}
}
}
\ No newline at end of file
yudao-ui/yudao-ui-admin-vue3/package-lock.json
View file @
07703c77
...
...
@@ -31,6 +31,7 @@
"driver.js"
:
"^1.3.1"
,
"echarts"
:
"^5.5.0"
,
"echarts-wordcloud"
:
"^2.1.0"
,
"element-china-area-data"
:
"^6.1.0"
,
"element-plus"
:
"2.9.1"
,
"fast-xml-parser"
:
"^4.3.2"
,
"highlight.js"
:
"^11.9.0"
,
...
...
@@ -7943,6 +7944,11 @@
"url"
:
"https://github.com/sponsors/fb55"
}
},
"node_modules/china-division"
:
{
"version"
:
"2.7.0"
,
"resolved"
:
"https://registry.npmjs.org/china-division/-/china-division-2.7.0.tgz"
,
"integrity"
:
"sha512-4uUPAT+1WfqDh5jytq7omdCmHNk3j+k76zEG/2IqaGcYB90c2SwcixttcypdsZ3T/9tN1TTpBDoeZn+Yw/qBEA=="
},
"node_modules/chokidar"
:
{
"version"
:
"4.0.3"
,
"resolved"
:
"https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz"
,
...
...
@@ -9423,6 +9429,14 @@
"dev"
:
true
,
"license"
:
"ISC"
},
"node_modules/element-china-area-data"
:
{
"version"
:
"6.1.0"
,
"resolved"
:
"https://registry.npmjs.org/element-china-area-data/-/element-china-area-data-6.1.0.tgz"
,
"integrity"
:
"sha512-IkpcjwQv2A/2AxFiSoaISZ+oMw1rZCPUSOg5sOCwT5jKc96TaawmKZeY81xfxXsO0QbKxU5LLc6AirhG52hUmg=="
,
"dependencies"
:
{
"china-division"
:
"^2.7.0"
}
},
"node_modules/element-plus"
:
{
"version"
:
"2.9.1"
,
"resolved"
:
"https://registry.npmjs.org/element-plus/-/element-plus-2.9.1.tgz"
,
...
...
yudao-ui/yudao-ui-admin-vue3/package.json
View file @
07703c77
...
...
@@ -47,6 +47,7 @@
"driver.js"
:
"^1.3.1"
,
"echarts"
:
"^5.5.0"
,
"echarts-wordcloud"
:
"^2.1.0"
,
"element-china-area-data"
:
"^6.1.0"
,
"element-plus"
:
"2.9.1"
,
"fast-xml-parser"
:
"^4.3.2"
,
"highlight.js"
:
"^11.9.0"
,
...
...
yudao-ui/yudao-ui-admin-vue3/src/api/visit/product/index.ts
View file @
07703c77
...
...
@@ -40,4 +40,9 @@ export const ProductApi = {
exportProduct
:
async
(
params
)
=>
{
return
await
request
.
download
({
url
:
`/visit/product/export-excel`
,
params
})
},
// 下载产品信息导入模板
importProductTemplate
:
async
()
=>
{
return
await
request
.
download
({
url
:
'
/visit/product/get-import-template
'
})
}
}
yudao-ui/yudao-ui-admin-vue3/src/views/system/user/index.vue
View file @
07703c77
...
...
@@ -70,14 +70,14 @@
>
<Icon
icon=
"ep:plus"
/>
新增
</el-button>
<!--
<el-button-->
<!-- type="warning"-->
<!-- plain-->
<!-- @click="handleImport"-->
<!-- v-hasPermi="['system:user:import']"-->
<!-- >--
>
<!--
<Icon
icon=
"ep:upload"
/>
导入-->
<!--
</el-button>
--
>
<el-button
type=
"warning"
plain
@
click=
"handleImport"
v-hasPermi=
"['system:user:import']"
>
<Icon
icon=
"ep:upload"
/>
导入
</el-button
>
<!--
<el-button-->
<!-- type="success"-->
<!-- plain-->
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/customerinfo/CustomerInfoForm.vue
View file @
07703c77
...
...
@@ -26,30 +26,49 @@
/>
</el-select>
</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=
"regionFullName"
>
<el-input
v-model=
"formData.regionFullName"
placeholder=
"请输入所在地区"
/>
<el-cascader
placeholder=
"请选择地区"
size=
"default"
:options=
"pcaTextArr"
v-model=
"selectedOptions"
@
change=
"handleChange"
/>
</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=
"regionFullName"
>
-->
<!--
<el-input
v-model=
"formData.regionFullName"
placeholder=
"请输入所在地区"
/>
-->
<!--
</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-input
v-model=
"formData.locationText"
placeholder=
"请点击右侧选择"
readonly
>
<template
#append
>
<el-link
type=
"primary"
@
click=
"openMapPicker"
>
选择地址
</el-link>
</
template
>
</el-input>
</el-form-item>
<MapPicker
ref=
"mapPickerRef"
@
update-location=
"handleLocation"
/>
<!-- <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=
"productIds"
>
<el-input
v-model=
"formData.productIds"
placeholder=
"请输入产品信息"
/>
</el-form-item>
...
...
@@ -73,7 +92,7 @@
<
script
setup
lang=
"ts"
>
import
{
getIntDictOptions
,
getStrDictOptions
,
DICT_TYPE
}
from
'
@/utils/dict
'
import
{
CustomerInfoApi
,
CustomerInfoVO
}
from
'
@/api/visit/customerinfo
'
import
{
pcaTextArr
}
from
'
element-china-area-data
'
/** 客户信息 表单 */
defineOptions
({
name
:
'
CustomerInfoForm
'
})
...
...
@@ -84,7 +103,25 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const
dialogTitle
=
ref
(
''
)
// 弹窗的标题
const
formLoading
=
ref
(
false
)
// 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
const
formType
=
ref
(
''
)
// 表单的类型:create - 新增;update - 修改
const
formData
=
ref
({
const
selectedOptions
=
ref
([])
interface
CustomerFormData
{
id
?:
number
;
customerName
?:
string
;
contact
?:
string
;
companyName
?:
string
;
customerType
?:
string
;
provinceName
?:
string
;
cityName
?:
string
;
areaName
?:
string
;
regionFullName
?:
string
;
locationText
?:
string
;
longitude
?:
number
;
latitude
?:
number
;
locationImage
?:
string
;
productIds
?:
number
[];
department
?:
string
;
}
const
formData
=
ref
<
CustomerFormData
>
({
id
:
undefined
,
customerName
:
undefined
,
contact
:
undefined
,
...
...
@@ -117,6 +154,26 @@ const formRules = reactive({
})
const
formRef
=
ref
()
// 表单 Ref
//地图相关操作
const
mapPickerRef
=
ref
()
const
openMapPicker
=
()
=>
{
mapPickerRef
.
value
.
open
()
}
const
handleLocation
=
({
lat
,
lng
,
address
})
=>
{
console
.
log
(
'
lat:
'
,
lat
,
'
lng:
'
,
lng
,
'
address:
'
,
address
)
//经纬度和地址名称
formData
.
value
.
latitude
=
lat
formData
.
value
.
longitude
=
lng
formData
.
value
.
locationText
=
address
//静态图
const
mapKey
=
'
KHXBZ-OVYYZ-N4NXF-7JCZ2-PR4FT-RYF4E
'
const
mapUrl
=
`https://apis.map.qq.com/ws/staticmap/v2/?center=
${
lat
}
,
${
lng
}
&zoom=13&size=600*300&maptype=roadmap&markers=size:large|color:0xFFCCFF|label:k|
${
lat
}
,
${
lng
}
&key=
${
mapKey
}
`
formData
.
value
.
locationImage
=
mapUrl
}
/** 打开弹窗 */
const
open
=
async
(
type
:
string
,
id
?:
number
)
=>
{
dialogVisible
.
value
=
true
...
...
@@ -133,6 +190,21 @@ const open = async (type: string, id?: number) => {
}
}
}
const
handleChange
=
(
value
:
string
[])
=>
{
//给省市区和所在地区赋值
const
[
province
,
city
,
area
]
=
value
//正常赋值
formData
.
value
.
provinceName
=
province
formData
.
value
.
cityName
=
city
formData
.
value
.
areaName
=
area
formData
.
value
.
regionFullName
=
province
+
city
+
area
//直辖市需要将city赋值为province一样的值
if
(
province
.
match
(
/
(
北京|上海|天津|重庆
)
/
)){
formData
.
value
.
cityName
=
province
formData
.
value
.
regionFullName
=
province
+
province
+
area
}
console
.
log
(
formData
.
value
.
regionFullName
)
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 提交表单 */
...
...
@@ -180,4 +252,4 @@ const resetForm = () => {
}
formRef
.
value
?.
resetFields
()
}
</
script
>
\ No newline at end of file
</
script
>
yudao-ui/yudao-ui-admin-vue3/src/views/visit/product/ProductImportForm.vue
0 → 100644
View file @
07703c77
<
template
>
<Dialog
v-model=
"dialogVisible"
title=
"产品导入"
width=
"400"
>
<el-upload
ref=
"uploadRef"
v-model:file-list=
"fileList"
:action=
"importUrl + '?updateSupport=' + updateSupport"
:auto-upload=
"false"
:disabled=
"formLoading"
:headers=
"uploadHeaders"
:limit=
"1"
:on-error=
"submitFormError"
:on-exceed=
"handleExceed"
:on-success=
"submitFormSuccess"
accept=
".xlsx, .xls"
drag
>
<Icon
icon=
"ep:upload"
/>
<div
class=
"el-upload__text"
>
将文件拖到此处,或
<em>
点击上传
</em></div>
<template
#tip
>
<div
class=
"el-upload__tip text-center"
>
<span>
仅允许导入 xls、xlsx 格式文件。
</span>
<el-link
:underline=
"false"
style=
"font-size: 12px; vertical-align: baseline"
type=
"primary"
@
click=
"importTemplate"
>
下载模板
</el-link>
</div>
</
template
>
</el-upload>
<
template
#footer
>
<el-button
:disabled=
"formLoading"
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<el-button
@
click=
"dialogVisible = false"
>
取 消
</el-button>
</
template
>
</Dialog>
</template>
<
script
lang=
"ts"
setup
>
import
{
getAccessToken
,
getTenantId
}
from
'
@/utils/auth
'
import
download
from
'
@/utils/download
'
import
{
ProductApi
}
from
"
@/api/visit/product
"
;
defineOptions
({
name
:
'
SystemProductImportForm
'
})
const
message
=
useMessage
()
// 消息弹窗
const
dialogVisible
=
ref
(
false
)
// 弹窗的是否展示
const
formLoading
=
ref
(
false
)
// 表单的加载中
const
uploadRef
=
ref
()
const
importUrl
=
import
.
meta
.
env
.
VITE_BASE_URL
+
import
.
meta
.
env
.
VITE_API_URL
+
'
/visit/product/import
'
const
uploadHeaders
=
ref
()
// 上传 Header 头
const
fileList
=
ref
([])
// 文件列表
const
updateSupport
=
ref
(
0
)
// 是否更新已经存在的用户数据
/** 打开弹窗 */
const
open
=
()
=>
{
dialogVisible
.
value
=
true
updateSupport
.
value
=
0
fileList
.
value
=
[]
resetForm
()
}
defineExpose
({
open
})
// 提供 open 方法,用于打开弹窗
/** 提交表单 */
const
submitForm
=
async
()
=>
{
if
(
fileList
.
value
.
length
==
0
)
{
message
.
error
(
'
请上传文件
'
)
return
}
// 提交请求
uploadHeaders
.
value
=
{
Authorization
:
'
Bearer
'
+
getAccessToken
(),
'
tenant-id
'
:
getTenantId
()
}
formLoading
.
value
=
true
uploadRef
.
value
!
.
submit
()
}
/** 文件上传成功 */
const
emits
=
defineEmits
([
'
success
'
])
const
submitFormSuccess
=
(
response
:
any
)
=>
{
if
(
response
.
code
!==
0
)
{
message
.
error
(
response
.
msg
)
formLoading
.
value
=
false
return
}
// 拼接提示语
const
data
=
response
.
data
let
text
=
'
上传成功数量:
'
+
data
.
createProductNames
.
length
+
'
;
'
for
(
let
productName
of
data
.
createProductNames
)
{
text
+=
'
<
'
+
productName
+
'
>
'
}
// text += '更新成功数量:' + data.updateProductNames.length + ';'
// for (const productName of data.updateProductNames) {
// text += '
<
'
+ productName +
'
>
'
// }
text +=
'
上传失败数量:
'
+ Object.keys(data.failureProductNames).length +
'
;
'
for (const productName in data.failureProductNames) {
text +=
'
<
'
+ productName +
'
:
'
+ data.failureProductNames[productName] +
'
>
'
}
message.alert(text)
formLoading.value = false
dialogVisible.value = false
// 发送操作成功的事件
emits(
'
success
'
)
}
/** 上传错误提示 */
const submitFormError = (): void => {
message.error(
'
上传失败,请您重新上传!
'
)
formLoading.value = false
}
/** 重置表单 */
const resetForm = async (): Promise<void> => {
// 重置上传状态和文件
formLoading.value = false
await nextTick()
uploadRef.value?.clearFiles()
}
/** 文件数超出提示 */
const handleExceed = (): void => {
message.error(
'
最多只能上传一个文件!
'
)
}
/** 下载模板操作 */
const importTemplate = async () => {
const res = await ProductApi.importProductTemplate()
download.excel(res,
'
产品信息导入模版
.
xls
'
)
}
</
script
>
yudao-ui/yudao-ui-admin-vue3/src/views/visit/product/index.vue
View file @
07703c77
...
...
@@ -72,6 +72,14 @@
>
<Icon
icon=
"ep:plus"
class=
"mr-5px"
/>
新增
</el-button>
<el-button
type=
"warning"
plain
@
click=
"handleImport"
v-hasPermi=
"['visit:product:import']"
>
<Icon
icon=
"ep:upload"
/>
导入
</el-button>
<el-button
type=
"success"
plain
...
...
@@ -136,6 +144,8 @@
<!-- 表单弹窗:添加/修改 -->
<ProductForm
ref=
"formRef"
@
success=
"getList"
/>
<!-- 产品信息导入对话框 -->
<ProductImportForm
ref=
"importFormRef"
@
success=
"getList"
/>
</template>
<
script
setup
lang=
"ts"
>
...
...
@@ -144,6 +154,7 @@ import { dateFormatter } from '@/utils/formatTime'
import
download
from
'
@/utils/download
'
import
{
ProductApi
,
ProductVO
}
from
'
@/api/visit/product
'
import
ProductForm
from
'
./ProductForm.vue
'
import
ProductImportForm
from
'
./ProductImportForm.vue
'
/** 产品 列表 */
defineOptions
({
name
:
'
Product
'
})
...
...
@@ -190,6 +201,12 @@ const resetQuery = () => {
handleQuery
()
}
/** 产品导入 */
const
importFormRef
=
ref
()
const
handleImport
=
()
=>
{
importFormRef
.
value
.
open
()
}
/** 添加/修改操作 */
const
formRef
=
ref
()
const
openForm
=
(
type
:
string
,
id
?:
number
)
=>
{
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/util/MapPicker.vue
0 → 100644
View file @
07703c77
<
template
>
<el-dialog
v-model=
"visible"
title=
"选择地址"
width=
"80%"
top=
"5vh"
:close-on-click-modal=
"false"
append-to-body
>
<iframe
id=
"tencentMapPicker"
:src=
"pickerUrl"
width=
"100%"
height=
"600px"
frameborder=
"0"
allow=
"geolocation"
style=
"border: 0"
></iframe>
</el-dialog>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ref
,
onMounted
,
onUnmounted
}
from
'
vue
'
// ✅ 地图弹窗显隐
const
visible
=
ref
(
false
)
// ✅ 腾讯地图 locationPicker 地址,替换成你的 key & 应用名
const
pickerUrl
=
`https://apis.map.qq.com/tools/locpicker?search=1&type=1&key=KHXBZ-OVYYZ-N4NXF-7JCZ2-PR4FT-RYF4E&referer=VISITKEY`
// ✅ 定义暴露 open() 方法,父组件通过 ref 调用
const
open
=
()
=>
{
visible
.
value
=
true
}
defineExpose
({
open
})
// ✅ 向父组件发回选中的地址和经纬度
const
emit
=
defineEmits
<
{
(
e
:
'
update-location
'
,
payload
:
{
lat
:
number
;
lng
:
number
;
address
:
string
}):
void
}
>
()
// ✅ 监听 locationPicker 的 postMessage
const
handleMessage
=
(
event
:
MessageEvent
)
=>
{
const
loc
=
event
.
data
if
(
loc
&&
loc
.
module
===
'
locationPicker
'
)
{
const
lat
=
loc
.
latlng
.
lat
const
lng
=
loc
.
latlng
.
lng
const
address
=
loc
.
poiaddress
||
loc
.
poiname
||
loc
.
address
emit
(
'
update-location
'
,
{
lat
,
lng
,
address
})
visible
.
value
=
false
// 选完后自动关闭弹窗
}
}
onMounted
(()
=>
{
window
.
addEventListener
(
'
message
'
,
handleMessage
)
})
onUnmounted
(()
=>
{
window
.
removeEventListener
(
'
message
'
,
handleMessage
)
})
</
script
>
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