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
fbf8a14a
Commit
fbf8a14a
authored
Jun 06, 2025
by
法拉51246
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
less改为scss
打印完成 大屏样式问题
parent
6a3f72ad
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
526 additions
and
64 deletions
+526
-64
WebFrameworkUtils.java
...oder/yudao/framework/web/core/util/WebFrameworkUtils.java
+4
-1
DeptServiceImpl.java
...der/yudao/module/system/service/dept/DeptServiceImpl.java
+4
-1
HomeController.java
...ao/module/visit/controller/admin/home/HomeController.java
+58
-4
HomeReqVO.java
...udao/module/visit/controller/admin/home/vo/HomeReqVO.java
+3
-1
InfoController.java
...ao/module/visit/controller/admin/info/InfoController.java
+12
-2
CustomerInfoServiceImpl.java
...e/visit/service/customerinfo/CustomerInfoServiceImpl.java
+1
-1
HomeService.java
.../iocoder/yudao/module/visit/service/home/HomeService.java
+2
-2
HomeServiceImpl.java
...oder/yudao/module/visit/service/home/HomeServiceImpl.java
+47
-16
Index.vue
yudao-ui/yudao-ui-admin-vue3/src/views/Home/Index.vue
+2
-2
YearRangeSelector.vue
.../yudao-ui-admin-vue3/src/views/Home/YearRangeSelector.vue
+2
-2
BarChart.vue
...udao-ui-admin-vue3/src/views/Home/components/BarChart.vue
+2
-2
LineChart.vue
...dao-ui-admin-vue3/src/views/Home/components/LineChart.vue
+2
-2
PieChart.vue
...udao-ui-admin-vue3/src/views/Home/components/PieChart.vue
+3
-3
barChart_1.vue
...ao-ui-admin-vue3/src/views/Home/components/barChart_1.vue
+2
-2
CustomerInfoForm.vue
...in-vue3/src/views/visit/customerinfo/CustomerInfoForm.vue
+2
-2
index.vue
...udao-ui-admin-vue3/src/views/visit/customerinfo/index.vue
+29
-11
InfoForm.vue
...-ui/yudao-ui-admin-vue3/src/views/visit/info/InfoForm.vue
+3
-3
index.vue
yudao-ui/yudao-ui-admin-vue3/src/views/visit/info/index.vue
+25
-7
PrintContent.vue
...yudao-ui-admin-vue3/src/views/visit/util/PrintContent.vue
+288
-0
print.ts
yudao-ui/yudao-ui-admin-vue3/src/views/visit/util/print.ts
+35
-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 @
fbf8a14a
...
...
@@ -11,6 +11,7 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import
javax.servlet.ServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
import
java.util.Optional
;
/**
* 专属于 web 包的工具类
...
...
@@ -106,7 +107,9 @@ public class WebFrameworkUtils {
if
(
request
==
null
)
{
return
null
;
}
return
request
.
getAttribute
(
REQUEST_ATTRIBUTE_LOGIN_USER_NAME
).
toString
();
return
Optional
.
ofNullable
(
request
.
getAttribute
(
REQUEST_ATTRIBUTE_LOGIN_USER_NAME
))
.
map
(
Object:
:
toString
)
.
orElse
(
""
);
}
/**
...
...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
View file @
fbf8a14a
...
...
@@ -68,7 +68,10 @@ public class DeptServiceImpl implements DeptService {
validateParentDept
(
updateReqVO
.
getId
(),
updateReqVO
.
getParentId
());
// 校验部门名的唯一性
validateDeptNameUnique
(
updateReqVO
.
getId
(),
updateReqVO
.
getParentId
(),
updateReqVO
.
getName
());
//如果没有leaderUserId说明是删除了leaderUserId
if
(
ObjectUtil
.
isNull
(
updateReqVO
.
getLeaderUserId
()))
{
updateReqVO
.
setLeaderUserId
(
null
);
}
// 更新部门
DeptDO
updateObj
=
BeanUtils
.
toBean
(
updateReqVO
,
DeptDO
.
class
);
deptMapper
.
updateById
(
updateObj
);
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/home/HomeController.java
View file @
fbf8a14a
...
...
@@ -13,6 +13,12 @@ import org.springframework.web.bind.annotation.*;
import
javax.annotation.Resource
;
import
javax.validation.Valid
;
import
java.time.LocalDate
;
import
java.time.LocalDateTime
;
import
java.time.Year
;
import
java.time.YearMonth
;
import
java.util.Objects
;
import
static
cn
.
iocoder
.
yudao
.
framework
.
common
.
pojo
.
CommonResult
.
success
;
@Tag
(
name
=
"管理后台 - 首页信息"
)
...
...
@@ -32,6 +38,8 @@ public class HomeController {
@GetMapping
(
"/getHomeInfoFirst"
)
@Operation
(
summary
=
"获得首页第一排信息"
)
public
CommonResult
<
HomeFirstRespVO
>
getHomeInfoFirst
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeFirstRespVO
data
=
homeService
.
getHomeInfoFirst
(
reqVO
);
return
success
(
data
);
}
...
...
@@ -40,6 +48,8 @@ public class HomeController {
@GetMapping
(
"/getHomeInfoBfztj"
)
@Operation
(
summary
=
"获得首页拜访周统计"
)
public
CommonResult
<
HomeBfztjRespVO
>
getHomeInfoBfztj
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeBfztjRespVO
data
=
homeService
.
getHomeInfoBfztj
(
reqVO
);
return
success
(
data
);
}
...
...
@@ -48,20 +58,26 @@ public class HomeController {
@GetMapping
(
"/getHomeInfoKhxzdjzbqk"
)
@Operation
(
summary
=
"获得首页客户性质等级占比情况"
)
public
CommonResult
<
HomeKhxzdjzbqkRespVO
>
getHomeInfoKhxzdjzbqk
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeKhxzdjzbqkRespVO
data
=
homeService
.
getHomeInfoKhxzdjzbqk
(
reqVO
);
return
success
(
data
);
}
@GetMapping
(
"/getHomeInfoBfrjfbqk"
)
@Operation
(
summary
=
"获得首页拜访人均分布情况"
)
public
CommonResult
<
HomeBfrjfbqkRespVO
>
getHomeInfoBfrjfbqk
(
@Valid
HomeReqVO
reqVO
)
{
HomeBfrjfbqkRespVO
data
=
homeService
.
getHomeInfoBfrjfbqk
(
reqVO
);
public
CommonResult
<
HomeKhxzdjzbqkRespVO
>
getHomeInfoBfrjfbqk
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeKhxzdjzbqkRespVO
data
=
homeService
.
getHomeInfoBfrjfbqk
(
reqVO
);
return
success
(
data
);
}
@GetMapping
(
"/getHomeInfoKhbffszbqk"
)
@Operation
(
summary
=
"获得首页客户拜访方式占比情况"
)
public
CommonResult
<
HomeKhxzdjzbqkRespVO
>
getHomeInfoKhbffszbqk
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeKhxzdjzbqkRespVO
data
=
homeService
.
getHomeInfoKhbffszbqk
(
reqVO
);
return
success
(
data
);
}
...
...
@@ -69,6 +85,8 @@ public class HomeController {
@GetMapping
(
"/getHomeInfoKhbmzbqk"
)
@Operation
(
summary
=
"获得首页客户部门占比情况"
)
public
CommonResult
<
HomeKhxzdjzbqkRespVO
>
getHomeInfoKhbmzbqk
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeKhxzdjzbqkRespVO
data
=
homeService
.
getHomeInfoKhbmzbqk
(
reqVO
);
return
success
(
data
);
}
...
...
@@ -76,14 +94,18 @@ public class HomeController {
@GetMapping
(
"/getHomeInfoKhbflxzbqk"
)
@Operation
(
summary
=
"获得首页客户拜访类型占比情况"
)
public
CommonResult
<
HomeKhxzdjzbqkRespVO
>
getHomeInfoKhbflxzbqk
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeKhxzdjzbqkRespVO
data
=
homeService
.
getHomeInfoKhbflxzbqk
(
reqVO
);
return
success
(
data
);
}
@GetMapping
(
"/getHomeInfoBfcplxzbqk"
)
@Operation
(
summary
=
"获得首页拜访产品类型占比情况"
)
public
CommonResult
<
HomeBfrjfbqkRespVO
>
getHomeInfoBfcplxzbqk
(
@Valid
HomeReqVO
reqVO
)
{
HomeBfrjfbqkRespVO
data
=
homeService
.
getHomeInfoBfcplxzbqk
(
reqVO
);
public
CommonResult
<
HomeKhxzdjzbqkRespVO
>
getHomeInfoBfcplxzbqk
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeKhxzdjzbqkRespVO
data
=
homeService
.
getHomeInfoBfcplxzbqk
(
reqVO
);
return
success
(
data
);
}
...
...
@@ -91,6 +113,8 @@ public class HomeController {
@GetMapping
(
"/getHomeInfoBfrtj"
)
@Operation
(
summary
=
"获得首页拜访日统计"
)
public
CommonResult
<
HomeBfrtjRespVO
>
getHomeInfoBfrtj
(
@Valid
HomeReqVO
reqVO
)
{
LocalDateTime
[]
localDateTimes
=
parseSearchTime
(
reqVO
.
getSearchTimeString
());
reqVO
.
setSearchTime
(
localDateTimes
);
HomeBfrtjRespVO
data
=
homeService
.
getHomeInfoBfrtj
(
reqVO
);
return
success
(
data
);
}
...
...
@@ -98,7 +122,37 @@ public class HomeController {
//将前端传的查询时间String[] 转换为LocalDateTime[]
public
static
LocalDateTime
[]
parseSearchTime
(
String
[]
searchTime
)
{
if
(
searchTime
==
null
||
searchTime
.
length
!=
2
||
Objects
.
equals
(
searchTime
[
0
],
""
)
||
Objects
.
equals
(
searchTime
[
1
],
""
))
{
return
null
;
}
String
startStr
=
searchTime
[
0
];
String
endStr
=
searchTime
[
1
];
LocalDateTime
startTime
;
LocalDateTime
endTime
;
if
(
startStr
.
matches
(
"^\\d{4}$"
)
&&
endStr
.
matches
(
"^\\d{4}$"
))
{
// 年
startTime
=
Year
.
parse
(
startStr
).
atDay
(
1
).
atStartOfDay
();
endTime
=
Year
.
parse
(
endStr
).
atMonth
(
12
).
atEndOfMonth
().
atTime
(
23
,
59
,
59
);
}
else
if
(
startStr
.
matches
(
"^\\d{4}-\\d{2}$"
)
&&
endStr
.
matches
(
"^\\d{4}-\\d{2}$"
))
{
// 年-月
startTime
=
YearMonth
.
parse
(
startStr
).
atDay
(
1
).
atStartOfDay
();
endTime
=
YearMonth
.
parse
(
endStr
).
atEndOfMonth
().
atTime
(
23
,
59
,
59
);
}
else
if
(
startStr
.
matches
(
"^\\d{4}-\\d{2}-\\d{2}$"
)
&&
endStr
.
matches
(
"^\\d{4}-\\d{2}-\\d{2}$"
))
{
// 年-月-日
startTime
=
LocalDate
.
parse
(
startStr
).
atStartOfDay
();
endTime
=
LocalDate
.
parse
(
endStr
).
atTime
(
23
,
59
,
59
);
}
else
{
throw
new
IllegalArgumentException
(
"searchTime 格式非法,必须是 [yyyy] 或 [yyyy-MM] 或 [yyyy-MM-dd]"
);
}
return
new
LocalDateTime
[]{
startTime
,
endTime
};
}
}
\ No newline at end of file
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/home/vo/HomeReqVO.java
View file @
fbf8a14a
...
...
@@ -20,7 +20,9 @@ public class HomeReqVO {
private
String
companyName
;
@Schema
(
description
=
"查询时间"
)
@DateTimeFormat
(
pattern
=
FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND
)
private
LocalDateTime
[]
searchTime
;
@Schema
(
description
=
"查询时间前端传入的String[]"
)
private
String
[]
searchTimeString
;
}
\ No newline at end of file
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/controller/admin/info/InfoController.java
View file @
fbf8a14a
package
cn
.
iocoder
.
yudao
.
module
.
visit
.
controller
.
admin
.
info
;
import
com.fhs.common.utils.StringUtil
;
import
org.springframework.web.bind.annotation.*
;
import
javax.annotation.Resource
;
import
org.springframework.validation.annotation.Validated
;
...
...
@@ -74,6 +75,10 @@ public class InfoController {
@GetMapping
(
"/getPrintListByIds"
)
@Operation
(
summary
=
"获得客户拜访打印信息根据Ids"
)
public
CommonResult
<
List
<
InfoPrintVO
>>
getPrintListByIds
(
@RequestParam
(
"ids"
)
String
ids
)
{
//如果ids是空的,返回异常提示,请先选择需要打印的记录
if
(
StringUtil
.
isEmpty
(
ids
))
{
throw
new
RuntimeException
(
"请先选择需要打印的记录"
);
}
String
[]
split
=
ids
.
split
(
","
);
//转为List
List
<
Long
>
idList
=
new
ArrayList
<>();
...
...
@@ -86,9 +91,14 @@ public class InfoController {
@GetMapping
(
"/getPrintListByCompanyName"
)
@Operation
(
summary
=
"获得客户拜访打印信息根据公司名称"
)
public
CommonResult
<
InfoPrintVO
>
getPrintListByCompanyName
(
@RequestParam
(
"companyName"
)
String
companyName
)
{
public
CommonResult
<
List
<
InfoPrintVO
>
>
getPrintListByCompanyName
(
@RequestParam
(
"companyName"
)
String
companyName
)
{
InfoPrintVO
info
=
infoService
.
getInfoByCompanyName
(
companyName
);
return
success
(
info
);
List
<
InfoPrintVO
>
infoPrintVO
=
new
ArrayList
<>();
if
(
info
==
null
){
return
success
(
infoPrintVO
);
}
infoPrintVO
.
add
(
info
);
return
success
(
infoPrintVO
);
}
@GetMapping
(
"/page"
)
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/customerinfo/CustomerInfoServiceImpl.java
View file @
fbf8a14a
...
...
@@ -87,7 +87,7 @@ public class CustomerInfoServiceImpl implements CustomerInfoService {
// 更新
CustomerInfoDO
updateObj
=
BeanUtils
.
toBean
(
updateReqVO
,
CustomerInfoDO
.
class
);
CustomerInfoDO
customerInfoDO
=
customerInfoMapper
.
selectByCompanyName
(
updateObj
.
getCompanyName
());
if
(
customerInfoDO
!=
null
)
{
if
(
customerInfoDO
!=
null
&&
!
customerInfoDO
.
getId
().
equals
(
updateObj
.
getId
())
)
{
throw
exception
(
CUSTOMER_INFO_COMPANY_NAME_DUPLICATE
);
}
if
(
updateObj
.
getLocationImage
()
!=
null
&&
updateObj
.
getLocationImage
().
startsWith
(
"https://apis.map.qq.com/ws/staticmap/v2/"
)){
...
...
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/home/HomeService.java
View file @
fbf8a14a
...
...
@@ -18,7 +18,7 @@ public interface HomeService {
HomeKhxzdjzbqkRespVO
getHomeInfoKhxzdjzbqk
(
@Valid
HomeReqVO
reqVO
);
Home
Bfrjf
bqkRespVO
getHomeInfoBfrjfbqk
(
@Valid
HomeReqVO
reqVO
);
Home
Khxzdjz
bqkRespVO
getHomeInfoBfrjfbqk
(
@Valid
HomeReqVO
reqVO
);
HomeKhxzdjzbqkRespVO
getHomeInfoKhbffszbqk
(
@Valid
HomeReqVO
reqVO
);
...
...
@@ -26,7 +26,7 @@ public interface HomeService {
HomeKhxzdjzbqkRespVO
getHomeInfoKhbflxzbqk
(
@Valid
HomeReqVO
reqVO
);
Home
Bfrjf
bqkRespVO
getHomeInfoBfcplxzbqk
(
@Valid
HomeReqVO
reqVO
);
Home
Khxzdjz
bqkRespVO
getHomeInfoBfcplxzbqk
(
@Valid
HomeReqVO
reqVO
);
HomeBfrtjRespVO
getHomeInfoBfrtj
(
@Valid
HomeReqVO
reqVO
);
}
\ No newline at end of file
yudao-module-visit/src/main/java/cn/iocoder/yudao/module/visit/service/home/HomeServiceImpl.java
View file @
fbf8a14a
package
cn
.
iocoder
.
yudao
.
module
.
visit
.
service
.
home
;
import
cn.hutool.core.collection.CollUtil
;
import
cn.iocoder.yudao.framework.common.pojo.PageResult
;
import
cn.iocoder.yudao.module.system.api.dict.DictDataApi
;
import
cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO
;
...
...
@@ -85,8 +86,17 @@ public class HomeServiceImpl implements HomeService {
//拜访周统计
@Override
public
HomeBfztjRespVO
getHomeInfoBfztj
(
HomeReqVO
reqVO
)
{
LocalDateTime
start
=
reqVO
.
getSearchTime
()[
0
];
LocalDateTime
end
=
reqVO
.
getSearchTime
()[
1
];
//如果查询时间是空,则start = LocalDateTime.now().minusWeeks(10);
LocalDateTime
start
=
null
;
LocalDateTime
end
=
null
;
if
(
reqVO
.
getSearchTime
()
==
null
)
{
start
=
LocalDateTime
.
now
().
minusWeeks
(
10
);
end
=
LocalDateTime
.
now
();
}
else
{
start
=
reqVO
.
getSearchTime
()[
0
];
end
=
reqVO
.
getSearchTime
()[
1
];
}
// 对齐到每周一
start
=
start
.
with
(
DayOfWeek
.
MONDAY
);
...
...
@@ -155,7 +165,7 @@ public class HomeServiceImpl implements HomeService {
//拜访人均分布情况
@Override
public
Home
Bfrjf
bqkRespVO
getHomeInfoBfrjfbqk
(
HomeReqVO
reqVO
)
{
public
Home
Khxzdjz
bqkRespVO
getHomeInfoBfrjfbqk
(
HomeReqVO
reqVO
)
{
//1.先查出所有的拜访记录
InfoPageReqVO
infoPageReqVO
=
new
InfoPageReqVO
();
infoPageReqVO
.
setPageSize
(-
1
);
...
...
@@ -175,12 +185,19 @@ public class HomeServiceImpl implements HomeService {
.
collect
(
Collectors
.
toList
());
// 拆分为两个数组
List
<
String
>
names
=
top10
.
stream
().
map
(
Map
.
Entry
::
getKey
).
collect
(
Collectors
.
toList
());
List
<
Integer
>
values
=
top10
.
stream
().
map
(
e
->
e
.
getValue
().
intValue
()).
collect
(
Collectors
.
toList
());
HomeBfrjfbqkRespVO
respVO
=
new
HomeBfrjfbqkRespVO
();
respVO
.
setNames
(
names
);
respVO
.
setValues
(
values
);
// List<String> names = top10.stream().map(Map.Entry::getKey).collect(Collectors.toList());
// List<Integer> values = top10.stream().map(e -> e.getValue().intValue()).collect(Collectors.toList());
//直接成对放入
List
<
HomeKhxzdjzbqkRespVO
.
TypeCountItem
>
list
=
top10
.
stream
()
.
map
(
entry
->
{
HomeKhxzdjzbqkRespVO
.
TypeCountItem
item
=
new
HomeKhxzdjzbqkRespVO
.
TypeCountItem
();
item
.
setName
(
entry
.
getKey
());
item
.
setValue
(
entry
.
getValue
().
intValue
());
return
item
;
})
.
collect
(
Collectors
.
toList
());
HomeKhxzdjzbqkRespVO
respVO
=
new
HomeKhxzdjzbqkRespVO
();
respVO
.
setList
(
list
);
return
respVO
;
}
...
...
@@ -296,7 +313,7 @@ public class HomeServiceImpl implements HomeService {
}
@Override
public
Home
Bfrjf
bqkRespVO
getHomeInfoBfcplxzbqk
(
HomeReqVO
reqVO
)
{
public
Home
Khxzdjz
bqkRespVO
getHomeInfoBfcplxzbqk
(
HomeReqVO
reqVO
)
{
//1.先查出所有的客户信息
InfoPageReqVO
infoPageReqVO
=
new
InfoPageReqVO
();
infoPageReqVO
.
setPageSize
(-
1
);
...
...
@@ -317,7 +334,13 @@ public class HomeServiceImpl implements HomeService {
.
collect
(
Collectors
.
toSet
());
// 3. 查询产品信息(id => 名称-规格)
List
<
ProductDO
>
productList
=
productMapper
.
selectBatchIds
(
productIdSet
);
//判断是否为空
if
(
CollUtil
.
isEmpty
(
productIdSet
)){
HomeKhxzdjzbqkRespVO
vo
=
new
HomeKhxzdjzbqkRespVO
();
vo
.
setList
(
new
ArrayList
<
HomeKhxzdjzbqkRespVO
.
TypeCountItem
>());
return
vo
;
}
List
<
ProductDO
>
productList
=
productMapper
.
selectByIds
(
productIdSet
);
Map
<
Long
,
String
>
productMap
=
productList
.
stream
()
.
collect
(
Collectors
.
toMap
(
ProductDO:
:
getId
,
...
...
@@ -342,13 +365,21 @@ public class HomeServiceImpl implements HomeService {
.
limit
(
10
)
.
collect
(
Collectors
.
toList
());
List
<
String
>
names
=
topList
.
stream
().
map
(
Map
.
Entry
::
getKey
).
collect
(
Collectors
.
toList
());
List
<
Integer
>
values
=
topList
.
stream
().
map
(
Map
.
Entry
::
getValue
).
collect
(
Collectors
.
toList
());
//直接成对放入list
List
<
HomeKhxzdjzbqkRespVO
.
TypeCountItem
>
list
=
topList
.
stream
()
.
map
(
entry
->
{
HomeKhxzdjzbqkRespVO
.
TypeCountItem
item
=
new
HomeKhxzdjzbqkRespVO
.
TypeCountItem
();
item
.
setName
(
entry
.
getKey
());
item
.
setValue
(
entry
.
getValue
());
return
item
;
})
.
collect
(
Collectors
.
toList
());
// List<String> names = topList.stream().map(Map.Entry::getKey).collect(Collectors.toList());
// List<Integer> values = topList.stream().map(Map.Entry::getValue).collect(Collectors.toList());
// 6. 构建返回结果
HomeBfrjfbqkRespVO
vo
=
new
HomeBfrjfbqkRespVO
();
vo
.
setNames
(
names
);
vo
.
setValues
(
values
);
HomeKhxzdjzbqkRespVO
vo
=
new
HomeKhxzdjzbqkRespVO
();
vo
.
setList
(
list
);
return
vo
;
}
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/Home/Index.vue
View file @
fbf8a14a
...
...
@@ -340,7 +340,7 @@ watch(timeRange, (newVal: any) => {
getEcharts
()
})
</
script
>
<
style
scoped
lang=
"
le
ss"
>
<
style
scoped
lang=
"
sc
ss"
>
/* 自定义 Element Plus 组件样式 */
.filter-item
{
width
:
200px
;
...
...
@@ -393,4 +393,4 @@ h3 {
width
:
32%
;
}
}
</
style
>
\ No newline at end of file
</
style
>
yudao-ui/yudao-ui-admin-vue3/src/views/Home/YearRangeSelector.vue
View file @
fbf8a14a
...
...
@@ -231,7 +231,7 @@ onUnmounted(() => {
})
</
script
>
<
style
scoped
lang=
"
le
ss"
>
<
style
scoped
lang=
"
sc
ss"
>
.year-range-picker
{
position
:
relative
;
...
...
@@ -313,4 +313,4 @@ onUnmounted(() => {
opacity
:
0
;
}
}
</
style
>
\ No newline at end of file
</
style
>
yudao-ui/yudao-ui-admin-vue3/src/views/Home/components/BarChart.vue
View file @
fbf8a14a
...
...
@@ -125,7 +125,7 @@ const handleChartReady = (chart: any) => {
}
</
script
>
<
style
scoped
lang=
"
le
ss"
>
<
style
scoped
lang=
"
sc
ss"
>
.bar-chart
{
.chart-title
{
font-size
:
16px
;
...
...
@@ -134,4 +134,4 @@ const handleChartReady = (chart: any) => {
color
:
#333
;
}
}
</
style
>
\ No newline at end of file
</
style
>
yudao-ui/yudao-ui-admin-vue3/src/views/Home/components/LineChart.vue
View file @
fbf8a14a
...
...
@@ -142,7 +142,7 @@ const handleChartReady = (chart: any) => {
}
</
script
>
<
style
scoped
lang=
"
le
ss"
>
<
style
scoped
lang=
"
sc
ss"
>
.line-chart
{
.chart-title
{
font-size
:
16px
;
...
...
@@ -151,4 +151,4 @@ const handleChartReady = (chart: any) => {
color
:
#333
;
}
}
</
style
>
\ No newline at end of file
</
style
>
yudao-ui/yudao-ui-admin-vue3/src/views/Home/components/PieChart.vue
View file @
fbf8a14a
...
...
@@ -47,7 +47,7 @@ const props = defineProps({
const
chartOption
=
computed
(()
=>
{
// console.log(props.data,"props.data");
const
legendData
=
props
.
data
.
map
((
item
)
=>
item
.
name
)
return
{
tooltip
:
{
...
...
@@ -135,7 +135,7 @@ const handleChartReady = (chart: echarts.ECharts) => {
}
</
script
>
<
style
scoped
lang=
"
le
ss"
>
<
style
scoped
lang=
"
sc
ss"
>
.visit-way-pie-chart
{
.chart-title
{
font-size
:
16px
;
...
...
@@ -144,4 +144,4 @@ const handleChartReady = (chart: echarts.ECharts) => {
color
:
#333
;
}
}
</
style
>
\ No newline at end of file
</
style
>
yudao-ui/yudao-ui-admin-vue3/src/views/Home/components/barChart_1.vue
View file @
fbf8a14a
...
...
@@ -116,7 +116,7 @@ const handleChartReady = (chart: any) => {
}
</
script
>
<
style
scoped
lang=
"
le
ss"
>
<
style
scoped
lang=
"
sc
ss"
>
.horizontal-bar-chart
{
.chart-title
{
font-size
:
16px
;
...
...
@@ -125,4 +125,4 @@ const handleChartReady = (chart: any) => {
color
:
'#333'
;
}
}
</
style
>
\ No newline at end of file
</
style
>
yudao-ui/yudao-ui-admin-vue3/src/views/visit/customerinfo/CustomerInfoForm.vue
View file @
fbf8a14a
...
...
@@ -160,10 +160,10 @@ const formRules = reactive({
cityName
:
[{
required
:
true
,
message
:
'
市名称不能为空
'
,
trigger
:
'
blur
'
}],
areaName
:
[{
required
:
true
,
message
:
'
区名称不能为空
'
,
trigger
:
'
blur
'
}],
regionFullName
:
[{
required
:
true
,
message
:
'
所在地区不能为空
'
,
trigger
:
'
blur
'
}],
locationText
:
[{
required
:
true
,
message
:
'
详细地址不能为空
'
,
trigger
:
'
blur
'
}],
locationText
:
[{
required
:
true
,
message
:
'
详细地址不能为空
'
,
trigger
:
'
change
'
}],
longitude
:
[{
required
:
true
,
message
:
'
经度不能为空
'
,
trigger
:
'
blur
'
}],
latitude
:
[{
required
:
true
,
message
:
'
纬度不能为空
'
,
trigger
:
'
blur
'
}],
locationImage
:
[{
required
:
true
,
message
:
'
定位静态图
URL
不能为空
'
,
trigger
:
'
blur
'
}],
locationImage
:
[{
required
:
true
,
message
:
'
定位静态图不能为空
'
,
trigger
:
'
blur
'
}],
})
const
formRef
=
ref
()
// 表单 Ref
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/customerinfo/index.vue
View file @
fbf8a14a
...
...
@@ -166,7 +166,12 @@
<!-- 表单弹窗:添加/修改 -->
<CustomerInfoForm
ref=
"formRef"
@
success=
"getList"
/>
<!-- 打印弹窗 -->
<VisitPrint
ref=
"visitPrintRef"
:data=
"selectedData"
/>
<!-- <VisitPrint ref="visitPrintRef" :data="selectedData" />-->
<Teleport
to=
"body"
>
<div
v-show=
"false"
>
<PrintContent
ref=
"printComp"
:dataList=
"printData"
/>
</div>
</Teleport>
<!-- 客户信息导入对话框 -->
<CustomerImportForm
ref=
"importFormRef"
@
success=
"getList"
/>
</template>
...
...
@@ -181,6 +186,8 @@ import ProductList from "@/views/visit/util/ProductList.vue";
import
{
useRouter
}
from
'
vue-router
'
import
{
InfoApi
,
InfoPrintVO
}
from
"
@/api/visit/info
"
;
import
CustomerImportForm
from
"
@/views/visit/customerinfo/CustomerImportForm.vue
"
;
import
PrintContent
from
"
@/views/visit/util/PrintContent.vue
"
;
import
{
usePrint
}
from
"
@/views/visit/util/print
"
;
/** 客户信息 列表 */
...
...
@@ -212,25 +219,36 @@ const importFormRef = ref()
const
handleImport
=
()
=>
{
importFormRef
.
value
.
open
()
}
const
printData
=
ref
<
InfoPrintVO
[]
>
([])
const
visitPrintRef
=
ref
()
const
printComp
=
ref
()
// 模拟获取详情数据的方法(你应该调 InfoApi.getInfoListByIds 或类似接口)
const
selectedData
=
ref
<
InfoPrintVO
[]
>
([])
const
handlePrint
=
async
(
companyName
:
string
)
=>
{
selectedData
.
value
=
await
InfoApi
.
getPrintListByCompanyName
(
companyNam
e
)
const
handlePrint
=
async
(
companyName
)
=>
{
printData
.
value
=
await
InfoApi
.
getPrintListByCompanyName
(
companyName
)
await
nextTick
()
console
.
log
(
printData
.
valu
e
)
//判断是否有数据
if
(
!
selectedData
.
value
)
{
if
(
printData
.
value
.
length
===
0
)
{
message
.
warning
(
'
该客户暂无拜访记录
'
)
return
}
console
.
log
(
selectedData
.
value
)
await
nextTick
()
visitPrintRef
.
value
?.
print
()
const
dom
=
printComp
.
value
.
printRef
if
(
dom
)
usePrint
(
dom
)
}
// const handlePrint = async (companyName: string) => {
// selectedData.value = await InfoApi.getPrintListByCompanyName(companyName)
// //判断是否有数据
// if (!selectedData.value) {
// message.warning('该客户暂无拜访记录')
// return
// }
// console.log(selectedData.value)
// await nextTick()
// printComp.value?.print()
// }
/** 多选操作**/
const
handleSelectionChange
=
(
val
)
=>
{
multipleSelection
.
value
=
val
.
map
(
item
=>
item
.
id
)
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/info/InfoForm.vue
View file @
fbf8a14a
...
...
@@ -123,7 +123,7 @@
:autosize=
"{ minRows: 4, maxRows: 6 }"
/>
</el-form-item>
<el-form-item
label=
"服务记录图片
URL列表
"
prop=
"serviceImages"
>
<el-form-item
label=
"服务记录图片"
prop=
"serviceImages"
>
<UploadImgs
v-model=
"formData.serviceImages"
:limit=
"9"
/>
</el-form-item>
</el-form>
...
...
@@ -185,10 +185,10 @@ const formRules = reactive({
cityName
:
[{
required
:
true
,
message
:
'
市名称不能为空
'
,
trigger
:
'
blur
'
}],
areaName
:
[{
required
:
true
,
message
:
'
区名称不能为空
'
,
trigger
:
'
blur
'
}],
regionFullName
:
[{
required
:
true
,
message
:
'
所在地区不能为空
'
,
trigger
:
'
blur
'
}],
locationText
:
[{
required
:
true
,
message
:
'
定位地址文字描述不能为空
'
,
trigger
:
'
blur
'
}],
locationText
:
[{
required
:
true
,
message
:
'
详细地址不能为空
'
,
trigger
:
'
change
'
}],
longitude
:
[{
required
:
true
,
message
:
'
经度不能为空
'
,
trigger
:
'
blur
'
}],
latitude
:
[{
required
:
true
,
message
:
'
纬度不能为空
'
,
trigger
:
'
blur
'
}],
locationImage
:
[{
required
:
true
,
message
:
'
定位静态图
URL
不能为空
'
,
trigger
:
'
blur
'
}],
locationImage
:
[{
required
:
true
,
message
:
'
定位静态图不能为空
'
,
trigger
:
'
blur
'
}],
visitDate
:
[{
required
:
true
,
message
:
'
拜访日期不能为空
'
,
trigger
:
'
blur
'
}],
customerStatus
:
[{
required
:
true
,
message
:
'
性质等级不能为空
'
,
trigger
:
'
blur
'
}],
department
:
[{
required
:
true
,
message
:
'
客户部门不能为空
'
,
trigger
:
'
blur
'
}],
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/info/index.vue
View file @
fbf8a14a
...
...
@@ -214,7 +214,14 @@
<!-- 表单弹窗:添加/修改 -->
<InfoForm
ref=
"formRef"
@
success=
"getList"
/>
<!-- 打印弹窗 -->
<VisitPrint
ref=
"visitPrintRef"
:data=
"selectedData"
/>
<!-- <VisitPrint ref="visitPrintRef" :data="selectedData" />-->
<Teleport
to=
"body"
>
<div
v-show=
"false"
>
<PrintContent
ref=
"printComp"
:dataList=
"printData"
/>
</div>
</Teleport>
</template>
<
script
setup
lang=
"ts"
>
...
...
@@ -226,20 +233,31 @@ import InfoForm from './InfoForm.vue'
import
ProductList
from
"
@/views/visit/util/ProductList.vue
"
;
import
{
useRoute
}
from
'
vue-router
'
const
visitPrintRef
=
ref
()
// 模拟获取详情数据的方法(你应该调 InfoApi.getInfoListByIds 或类似接口)
const
selectedData
=
ref
<
InfoPrintVO
[]
>
([])
import
{
usePrint
}
from
'
../util/print
'
import
PrintContent
from
'
../util/PrintContent.vue
'
//==========
const
printData
=
ref
([
{
name
:
'
张三
'
,
date
:
'
2025-06-01
'
,
remark
:
'
拜访说明
'
,
image
:
'
https://image.xnszz.com//20250604/visit_1749022959344.png
'
},
{
name
:
'
李四
'
,
date
:
'
2025-06-03
'
,
remark
:
'
再次拜访
'
,
image
:
'
https://image.xnszz.com//20250604/visit_1749022959344.png
'
},
])
const
printComp
=
ref
()
const
handlePrint
=
async
()
=>
{
if
(
multipleSelection
.
value
.
length
===
0
)
{
return
message
.
warning
(
'
请先选择需要打印的记录
'
)
}
selected
Data
.
value
=
await
InfoApi
.
getPrintListByIds
(
multipleSelection
.
value
.
join
(
'
,
'
))
console
.
log
(
selected
Data
.
value
)
print
Data
.
value
=
await
InfoApi
.
getPrintListByIds
(
multipleSelection
.
value
.
join
(
'
,
'
))
console
.
log
(
print
Data
.
value
)
await
nextTick
()
visitPrintRef
.
value
?.
print
()
const
dom
=
printComp
.
value
.
printRef
if
(
dom
)
usePrint
(
dom
)
}
// 模拟获取详情数据的方法(你应该调 InfoApi.getInfoListByIds 或类似接口)
const
route
=
useRoute
()
/** 客户拜访记录 列表 */
...
...
yudao-ui/yudao-ui-admin-vue3/src/views/visit/util/PrintContent.vue
0 → 100644
View file @
fbf8a14a
<!-- PrintContent.vue -->
<
template
>
<div
ref=
"printRef"
style=
"padding: 20px; font-size: 14px;"
>
<div
v-for=
"(item, index) in dataList"
:key=
"index"
style=
"width: 210mm;
height: 297mm;
padding: 20mm;
border: 1px solid #eee;
margin: 20px auto;
font-size: 14px;
page-break-after: always;
display: flex;
flex-direction: column;
justify-content: space-between;"
>
<h2
style=
"text-align: center; margin-bottom: 16px;"
>
渠道服务记录
</h2>
<div
style=
"display: flex;
flex-direction: row;
gap: 20px;
flex: 1;"
>
<!-- 左侧 1/3 -->
<div
style=
"width: 40%;
display: flex;
flex-direction: column;
gap: 8px;
background-color: rgb(78,157,249) !important;;
color: white !important;;
padding: 10px;"
>
<div
style=
"height: 160px;
width: 100%;"
>
<img
crossorigin=
"anonymous"
:src=
"item.locationImage"
class=
"main"
alt=
""
style=
" width: 100%;
height: 100%;
object-fit: fill;
border: 1px solid #ccc;"
/>
</div>
<div
style=
"display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.1);
padding: 12px 15px;
margin-bottom: 12px;
font-size: 16px;
border-radius: 2px;
border: rgb(95, 174, 251) 1px solid;
height: 40px;"
>
业务员:
{{
item
.
salesman
}}
</div>
<div
style=
"display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.1);
padding: 12px 15px;
margin-bottom: 12px;
font-size: 16px;
border-radius: 2px;
border: rgb(95, 174, 251) 1px solid;
height: 40px;"
>
服务数量:
{{
item
.
serviceCount
}}
</div>
<div
style=
"display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.1);
padding: 12px 15px;
margin-bottom: 12px;
font-size: 16px;
border-radius: 2px;
border: rgb(95, 174, 251) 1px solid;
height: 40px;"
>
拜访时间记录
</div>
<ul
style=
"list-style: none; /* 移除默认的列表符号 */
padding: 0;
margin: 0;
display: flex; /* 启用 Flex 布局 */
flex-direction: column; /* 垂直排列 */
gap: 8px; /* 项间距 */
height: 180px;"
>
<li
v-for=
"(time, i) in item.visitDate"
:key=
"i"
style=
"display: flex; /* 启用 Flex 布局 */
align-items: center; /* 垂直居中 */
justify-content: center; /* 水平居中 */
height: 40px; /* 与其他 div 高度一致 */
width: 100%; /* 需要设定宽度 */"
>
{{
formatDate
(
time
)
}}
</li>
</ul>
<div
style=
"display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.1);
padding: 12px 15px;
margin-bottom: 12px;
font-size: 16px;
border-radius: 2px;
border: rgb(95, 174, 251) 1px solid;
height: 40px;"
>
主要服务内容
</div>
<ul
style=
"list-style: none; /* 移除默认的列表符号 */
padding: 0;
margin: 0;
display: flex; /* 启用 Flex 布局 */
flex-direction: column; /* 垂直排列 */
gap: 8px; /* 项间距 */
height: 280px;"
>
<li
v-for=
"(content, i) in item.serviceContent"
:key=
"i"
style=
"height:60px;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.4;"
>
内容
{{
i
+
1
}}
:
{{
content
}}
</li>
</ul>
</div>
<!-- 右侧 2/3 -->
<div
style=
"width: 60%;
padding-left: 20px;
display: flex;
flex-direction: column;
gap: 8px;"
>
<p>
客户名称:
{{
item
.
companyName
}}
</p>
<p>
客户部门:
{{
getDictLabel
(
DICT_TYPE
.
CUSTOMER_DEPT
,
item
.
department
)
}}
</p>
<p>
推广产品:
{{
item
.
visitProductNames
}}
</p>
<div
style=
"border: 1px solid #ccc;background-color: #f9f9f9;; height: 40px; display: flex; align-items: center; justify-content: center;"
>
拜访签到实景图
</div>
<div
style=
"display: flex;
flex-direction: column;
height: 800px; /* 父容器高度,按需设置 */"
>
<img
crossorigin=
"anonymous"
v-for=
"(url, i) in getSafeImages(item.serviceImages)"
:key=
"i"
:src=
"url"
style=
"width: 100%;
height: 25%;
object-fit: cover;
border: 1px solid #ccc;"
/>
</div>
</div>
</div>
<div
style=
"page-break-after: always;"
></div>
</div>
</div>
</
template
>
<
script
setup
lang=
"ts"
>
import
{
ref
,
defineExpose
}
from
'
vue
'
import
{
DICT_TYPE
,
getDictLabel
}
from
"
@/utils/dict
"
;
const
props
=
defineProps
({
dataList
:
Array
})
const
printRef
=
ref
(
null
)
const
formatDate
=
(
date
:
string
|
Date
)
=>
{
const
d
=
new
Date
(
date
)
return
d
.
toLocaleString
()
}
const
getSafeImages
=
(
val
?:
string
)
=>
{
if
(
!
val
||
val
===
''
)
return
[]
return
val
.
split
(
'
,
'
).
slice
(
0
,
4
)
}
defineExpose
({
printRef
})
</
script
>
<
style
>
*
{
box-sizing
:
border-box
;
margin
:
0
;
padding
:
0
;
}
.print-page
{
width
:
210mm
;
height
:
297mm
;
padding
:
20mm
;
border
:
1px
solid
#eee
;
margin
:
20px
auto
;
font-size
:
14px
;
page-break-after
:
always
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
space-between
;
}
.print-page
>
.content
{
display
:
flex
;
flex-direction
:
row
;
gap
:
20px
;
flex
:
1
;
}
.left
{
width
:
40%
;
display
:
flex
;
flex-direction
:
column
;
gap
:
8px
;
background-color
:
rgb
(
78
,
157
,
249
);
color
:
white
;
padding
:
10px
;
}
.right
{
width
:
60%
;
padding-left
:
20px
;
display
:
flex
;
flex-direction
:
column
;
gap
:
8px
;
}
.image-grid
{
display
:
flex
;
flex-direction
:
column
;
height
:
800px
;
/* 父容器高度,按需设置 */
}
.image-grid
img
{
width
:
100%
;
height
:
25%
;
object-fit
:
contain
;
border
:
1px
solid
#ccc
;
}
/* 全局重置 ul/li 的默认样式 */
.print-page
>
ul
{
list-style
:
none
;
/* 移除默认的列表符号 */
padding
:
0
;
margin
:
0
;
display
:
flex
;
/* 启用 Flex 布局 */
flex-direction
:
column
;
/* 垂直排列 */
gap
:
8px
;
/* 项间距 */
}
.print-page
>
li
{
display
:
flex
;
/* 启用 Flex 布局 */
align-items
:
center
;
/* 垂直居中 */
justify-content
:
center
;
/* 水平居中 */
height
:
40px
;
/* 与其他 div 高度一致 */
width
:
100%
;
/* 需要设定宽度 */
}
/* 多行文本控制 */
.info-content
{
height
:
60px
;
display
:
-webkit-box
;
-webkit-box-orient
:
vertical
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
line-height
:
1.4
;
}
/* 通用 Flex 居中容器 */
.flex-center
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
background-color
:
rgba
(
255
,
255
,
255
,
0.1
);
padding
:
12px
15px
;
margin-bottom
:
12px
;
font-size
:
16px
;
border-radius
:
2px
;
border
:
rgb
(
95
,
174
,
251
)
1px
solid
;
}
/* 高度 40px 的容器 */
.box-40
{
height
:
40px
;
}
/* 无边框、无背景的容器(可选) */
.clean-box
{
border
:
none
;
background-color
:
transparent
;
}
</
style
>
yudao-ui/yudao-ui-admin-vue3/src/views/visit/util/print.ts
0 → 100644
View file @
fbf8a14a
// src/utils/print.ts
export
const
usePrint
=
(
target
:
HTMLElement
)
=>
{
const
printWindow
=
window
.
open
(
''
,
'
_blank
'
)
if
(
!
printWindow
)
return
const
style
=
`
<style>
@page { size: A4; margin: 10mm; }
body { margin: 0; padding: 0; }
</style>
`
const
content
=
target
.
innerHTML
printWindow
.
document
.
write
(
`<html><head><title>打印</title>
${
style
}
</head><body>
${
content
}
</body></html>`
)
printWindow
.
document
.
close
()
const
images
=
printWindow
.
document
.
images
let
loaded
=
0
const
onload
=
()
=>
{
loaded
++
if
(
loaded
===
images
.
length
)
{
printWindow
.
print
()
printWindow
.
close
()
}
}
if
(
images
.
length
===
0
)
{
printWindow
.
print
()
printWindow
.
close
()
}
else
{
Array
.
from
(
images
).
forEach
(
img
=>
{
img
.
onload
=
img
.
onerror
=
onload
})
}
}
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