Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
customer-admin
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
EzijingWeb
customer-admin
Commits
4fc50246
提交
4fc50246
authored
10月 25, 2021
作者:
pengxiaohui
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: 大客户管理页面接口调试
上级
6f71692e
隐藏空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
480 行增加
和
33 行删除
+480
-33
base.js
src/api/base.js
+4
-0
AppList.vue
src/components/base/AppList.vue
+24
-3
AppUserSearch.vue
src/components/base/AppUserSearch.vue
+95
-0
api.js
src/modules/customer/api.js
+7
-3
CreateCustomer.vue
src/modules/customer/components/CreateCustomer.vue
+129
-0
Index.vue
src/modules/customer/views/Index.vue
+221
-27
没有找到文件。
src/api/base.js
浏览文件 @
4fc50246
...
...
@@ -27,3 +27,7 @@ export function uploadFile(data) {
headers
:
{
'Content-Type'
:
'multipart/form-data'
}
})
}
// 搜索紫荆用户
export
function
userSearch
(
params
)
{
return
httpRequest
.
get
(
'/api/customer/admin/v1/system/search-sso-users'
,
{
params
})
}
src/components/base/AppList.vue
浏览文件 @
4fc50246
...
...
@@ -5,7 +5,7 @@
<div
class=
"table-list-filter"
>
<el-form
v-if=
"filters.length"
:inline=
"true"
:model=
"params"
ref=
"filterForm"
>
<template
v-for=
"item in filters"
>
<el-form-item
:label=
"item.label"
:prop=
"item.prop"
:key=
"item.prop"
>
<el-form-item
:label=
"item.label"
:prop=
"item.prop"
:key=
"item.prop"
class=
"filter-form-item"
>
<template
v-if=
"item.slots"
>
<slot
:name=
"item.slots"
v-bind=
"
{ params }">
</slot>
</
template
>
...
...
@@ -31,11 +31,22 @@
</template>
</el-form-item>
</template>
<el-form-item
class=
"filter-buttons"
>
<el-form-item
class=
"filter-buttons"
v-if=
"!searchResetSeparateLine"
>
<el-button
type=
"primary"
icon=
"el-icon-search"
@
click=
"search"
>
搜索
</el-button>
<el-button
icon=
"el-icon-refresh-left"
@
click=
"reset"
>
重置
</el-button>
</el-form-item>
</el-form>
<div
class=
"filter-bar"
>
<div
class=
"filte-bar-left-btns"
>
<
template
v-if=
"searchResetSeparateLine"
>
<el-button
type=
"primary"
icon=
"el-icon-search"
size=
"small"
@
click=
"search"
>
搜索
</el-button>
<el-button
icon=
"el-icon-refresh-left"
size=
"small"
@
click=
"reset"
>
重置
</el-button>
</
template
>
</div>
<div
class=
"filter-bar-right"
>
<slot
name=
"filter-bar-right"
/>
</div>
</div>
</div>
<div
class=
"table-list-hd-aside"
><slot
name=
"header-aside"
/></div>
</div>
...
...
@@ -47,7 +58,6 @@
v-loading=
"loading"
v-bind=
"$attrs"
v-on=
"$listeners"
style=
"width: 100%"
ref=
"table"
>
<
template
v-for=
"item in columns"
>
...
...
@@ -89,6 +99,7 @@ export default {
remote
:
{
type
:
Object
,
default
:
()
=>
({})
},
// 筛选
filters
:
{
type
:
Array
,
default
:
()
=>
[]
},
searchResetSeparateLine
:
{
type
:
Boolean
,
default
:
false
},
// 列表项
columns
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 列表数据
...
...
@@ -214,6 +225,16 @@ export default {
.table-list-filter
{
flex
:
1
;
}
.filter-bar
{
display
:flex
;
margin-bottom
:
15px
;
}
.filte-bar-left-btns
{
flex
:
1
;
}
.el-form--inline
.el-form-item
{
margin-right
:
30px
;
}
.table-list-bd
{
flex
:
1
;
}
...
...
src/components/base/AppUserSearch.vue
0 → 100644
浏览文件 @
4fc50246
<
template
>
<el-select
v-model=
"userId"
v-bind=
"options"
placeholder=
"输入邮箱/手机号码搜索"
filterable
remote
:remote-method=
"fetchUserList"
:loading=
"searchUsersloading"
@
change=
"handleChange"
>
<el-option
:label=
"user.realname || user.nickname "
:value=
"user.id"
v-for=
"user in userList"
:key=
"user.id"
>
<span
style=
"float: left"
>
{{
user
.
realname
||
user
.
nickname
}}
<template
v-if=
"user.mobile"
>
(手机号:
{{
user
.
mobile
}}
)
</
template
>
</span>
<span
style=
"float: right; color: #8492a6; font-size: 13px; margin:0 20px 0 10px;"
v-if=
"user.email"
>
邮箱:{{ user.email }}
</span>
<span
style=
"float: right; color: #8492a6; font-size: 13px; margin:0 20px 0 10px;"
v-else
>
ID:{{ user.id }}
</span>
</el-option>
</el-select>
</template>
<
script
>
import
{
userSearch
}
from
'@/api/base.js'
const
MOBILE_REG
=
/^1
(
3
[
0-9
]
|4
[
01456879
]
|5
[
0-35-9
]
|6
[
2567
]
|7
[
0-8
]
|8
[
0-9
]
|9
[
0-35-9
])\d{4,8}
$/
const
EMAIL_REG
=
/^
[
A-Za-z0-9
]
+
([
_.
\\
-
][
A-Za-z0-9
]
+
)
*@
[
A-Za-z0-9-.
]
+$/
export
default
{
props
:
{
value
:
{
type
:
[
Array
,
String
]
},
defaultList
:
{
type
:
Array
,
default
:
()
=>
{
return
[]
}
},
options
:
{
type
:
Object
,
default
:
()
=>
{
return
{}
}
}
},
data
()
{
return
{
userId
:
this
.
value
,
searchUsersloading
:
false
,
userList
:
[]
}
},
watch
:
{
value
:
{
handler
:
function
(
nv
)
{
this
.
userId
=
nv
},
immediate
:
true
,
deep
:
true
},
defaultList
:
{
handler
:
function
(
nv
)
{
this
.
userList
=
nv
},
immediate
:
true
,
deep
:
true
}
},
methods
:
{
handleChange
()
{
const
selectedUser
=
this
.
userList
.
find
(
item
=>
item
.
id
===
this
.
userId
)
this
.
$emit
(
'input'
,
this
.
userId
)
this
.
$emit
(
'select'
,
selectedUser
)
},
fetchUserList
(
val
)
{
let
searchType
=
'username'
if
(
EMAIL_REG
.
test
(
val
))
{
searchType
=
'email'
}
else
if
(
MOBILE_REG
.
test
(
val
))
{
searchType
=
'mobile'
}
if
(
!
val
)
return
false
else
{
const
params
=
{
[
searchType
]:
val
}
this
.
searchUsersloading
=
true
userSearch
(
params
)
.
then
(
res
=>
{
this
.
searchUsersloading
=
false
if
(
res
.
data
&&
Array
.
isArray
(
res
.
data
.
items
))
{
this
.
userList
=
res
.
data
.
items
}
})
.
catch
(()
=>
{})
}
}
}
}
</
script
>
<
style
scoped
>
.el-select
{
width
:
100%
;
}
</
style
>
\ No newline at end of file
src/modules/customer/api.js
浏览文件 @
4fc50246
import
httpRequest
from
'@/utils/axios'
// 获取用户信息
export
function
getUser
()
{
return
httpRequest
.
get
(
'/api/passport/account/get-user-info'
)
// 获取大客户列表
export
function
getCustomerList
(
params
)
{
return
httpRequest
.
get
(
'/api/customer/admin/v1/customers'
,
{
params
})
}
// 新建客户组
export
function
createCustomer
(
data
)
{
return
httpRequest
.
post
(
'/api/customer/admin/v1/customer'
,
data
)
}
src/modules/customer/components/CreateCustomer.vue
0 → 100644
浏览文件 @
4fc50246
<
template
>
<el-dialog
custom-class=
"create-custom-dialog"
title=
"创建客户"
:visible=
"value"
:close-on-click-modal=
"false"
:close-on-press-escape=
"false"
top=
"50px"
@
close=
"handleClose"
>
<!--
<div
slot=
"title"
>
</div>
-->
<el-form
:model=
"form"
:rules=
"rules"
ref=
"ruleForm"
label-width=
"90px"
>
<el-form-item
label=
"客户名称"
prop=
"name"
>
<el-input
v-model=
"form.name"
size=
"small"
placeholder=
"请输入客户名称"
/>
</el-form-item>
<el-form-item
label=
"客户简称"
>
<el-input
v-model=
"form.short_name"
size=
"small"
placeholder=
"请输入客户简称"
/>
</el-form-item>
<el-form-item
label=
"客户来源"
prop=
"source"
class=
"form-item-select"
style=
"margin-right:20px;"
>
<el-select
v-model=
"form.source"
placeholder=
"请选择客户来源"
size=
"small"
style=
"width:100%;"
>
<el-option
label=
"公司资源"
:value=
"1"
></el-option>
<el-option
label=
"自己开拓"
:value=
"2"
></el-option>
<el-option
label=
"第三方介绍"
:value=
"3"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"客户分类"
prop=
"type"
class=
"form-item-select"
>
<el-select
v-model=
"form.type"
placeholder=
"请选择客户分类"
size=
"small"
style=
"width:100%;"
>
<el-option
label=
"普通客户"
:value=
"1"
></el-option>
<el-option
label=
"重点客户"
:value=
"2"
></el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"所在地区"
prop=
"region"
class=
"form-item-select"
>
<app-area
v-model=
"form.region"
/>
</el-form-item>
<el-form-item
label=
"详细地址"
>
<el-input
v-model=
"form.address"
size=
"small"
placeholder=
"请输入详细地址"
/>
</el-form-item>
<el-form-item
label=
"备注"
prop=
"remark"
>
<el-input
v-model=
"form.remark"
type=
"textarea"
size=
"small"
rows=
"4"
placeholder=
"请输入备注"
/>
</el-form-item>
<el-form-item>
<el-button
size=
"mini"
@
click=
"$emit('dialogClose')"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"handleSubmit"
size=
"mini"
>
提交
</el-button>
</el-form-item>
</el-form>
</el-dialog>
</
template
>
<
script
>
import
AppArea
from
'@/components/base/AppArea.vue'
import
{
createCustomer
}
from
'../api'
export
default
{
components
:
{
AppArea
},
props
:
{
value
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
type
:
''
,
dialogVisible
:
true
,
form
:
{
name
:
''
,
short_name
:
''
,
source
:
''
,
type
:
''
,
region
:
''
,
address
:
''
,
remark
:
''
},
rules
:
{
name
:
{
required
:
true
,
message
:
'请输入客户名称'
,
trigger
:
'blur'
},
source
:
{
required
:
true
,
message
:
'请选择客户来源'
,
trigger
:
'change'
},
region
:
{
required
:
true
,
message
:
'请选择所在地区'
,
trigger
:
'change'
}
}
}
},
watch
:
{
value
(
val
)
{
this
.
dialogVisible
=
val
}
},
methods
:
{
handleClose
()
{
this
.
type
=
''
this
.
$emit
(
'input'
,
false
)
},
handleSubmit
()
{
this
.
$refs
.
ruleForm
.
validate
((
valid
)
=>
{
if
(
valid
)
{
this
.
fetchCreateCustomer
()
}
})
},
fetchCreateCustomer
()
{
const
params
=
Object
.
assign
({},
this
.
form
)
params
.
region
=
this
.
form
.
region
.
join
(
'-'
)
createCustomer
(
params
).
then
(
res
=>
{
if
(
res
.
code
===
0
&&
res
.
data
&&
res
.
data
.
id
)
{
this
.
$message
.
success
(
'创建客户成功'
)
this
.
$emit
(
'input'
,
false
)
this
.
$emit
(
'change'
)
}
else
{
this
.
$message
.
error
(
'创建客户失败'
)
}
}).
catch
(()
=>
{
this
.
$message
.
error
(
'创建客户失败'
)
})
}
}
}
</
script
>
<
style
scoped
>
::v-deep
.case-dialog
{
width
:
95%
;
max-width
:
1160px
;
margin-bottom
:
20px
;
}
::v-deep
.el-dialog__header
{
padding
:
12px
20px
20px
;
}
::v-deep
.el-dialog__headerbtn
{
top
:
12px
;
}
::v-deep
.el-dialog__body
{
padding
:
0
20px
20px
;
}
::v-deep
.form-item-select
{
display
:
inline-block
;
width
:
calc
(
50%
-
10px
);
}
::v-deep
.el-cascader
{
width
:
100%
;
}
</
style
>
src/modules/customer/views/Index.vue
浏览文件 @
4fc50246
<
template
>
<app-card>
<app-list
v-bind=
"tableOptions"
ref=
"list"
>
<template
#
header-aside
>
<el-button
type=
"primary"
>
创建客户
</el-button>
<app-card
class=
"customer"
>
<app-list
v-bind=
"tableOptions"
ref=
"list"
searchResetSeparateLine
>
<template
#
filter-bar-right
>
<el-button
type=
"primary"
size=
"small"
@
click=
"dialogVisable = true"
>
创建客户
</el-button>
</
template
>
<!-- 筛选 -->
<
template
v-slot:filter-date=
"{ params }"
>
<el-date-picker
v-model=
"params.date"
v-model=
"params.
create_
date"
type=
"datetimerange"
range-separator=
"至"
start-placeholder=
"开始日期时间"
end-placeholder=
"结束日期时间"
start-placeholder=
"开始时间"
end-placeholder=
"结束时间"
size=
'small'
>
</el-date-picker>
</
template
>
<
template
v-slot:filter-region=
"{ params }"
>
<app-area
v-model=
"params.region"
></app-area>
</
template
>
<
template
v-slot:filter-userSearch=
"{ params }"
>
<app-user-search
v-model=
"params.created_by"
></app-user-search>
</
template
>
<
template
v-slot:filter-follow-date=
"{ params }"
>
<el-date-picker
v-model=
"params.follow_date"
type=
"datetimerange"
range-separator=
"至"
start-placeholder=
"开始时间"
end-placeholder=
"结束时间"
size=
'small'
>
</el-date-picker>
</
template
>
...
...
@@ -23,36 +41,154 @@
</
template
>
</template>
</app-list>
<create-customer
v-model=
"dialogVisable"
@
change=
"$refs.list.refetch()"
/>
</app-card>
</template>
<
script
>
// 组件
import
App
List
from
'@/components/base/AppList
.vue'
import
AppCard
from
'@/components/base/AppCard
.vue'
import
AppUserSearch
from
'@/components/base/AppUserSearch.vue'
import
App
Area
from
'@/components/base/AppArea
.vue'
import
CreateCustomer
from
'../components/CreateCustomer
.vue'
// 接口
// import { getRole
List } from '../api'
import
{
getCustomer
List
}
from
'../api'
const
sourceList
=
[
{
name
:
'公司资源'
,
id
:
1
},
{
name
:
'自己开拓'
,
id
:
2
},
{
name
:
'第三方介绍'
,
id
:
3
}
]
const
typeList
=
[
{
name
:
'普通客户'
,
id
:
1
},
{
name
:
'重点客户'
,
id
:
2
}
]
export
default
{
components
:
{
App
Card
,
AppList
},
components
:
{
App
UserSearch
,
AppArea
,
CreateCustomer
},
data
()
{
return
{}
return
{
staffList
:
[
{
name
:
'员工1'
,
id
:
'1'
},
{
name
:
'员工2'
,
id
:
'2'
}
],
typeList
:
[
{
name
:
'普通客户'
,
id
:
1
},
{
name
:
'重点客户'
,
id
:
2
}
],
sourceList
:
[
{
name
:
'公司资源'
,
id
:
1
},
{
name
:
'自己开拓'
,
id
:
2
},
{
name
:
'第三方介绍'
,
id
:
3
}
],
projectList
:
[
{
name
:
'产业学员'
,
id
:
1
},
{
name
:
'1+x'
,
id
:
2
}
],
progressList
:
[
{
name
:
'待更进'
,
id
:
1
},
{
name
:
'更进中'
,
id
:
2
},
{
name
:
'待签约'
,
id
:
3
},
{
name
:
'已签约'
,
id
:
4
},
{
name
:
'已合作'
,
id
:
5
},
{
name
:
'已失效'
,
id
:
6
}
],
dialogVisable
:
false
}
},
computed
:
{
// 列表配置
tableOptions
()
{
return
{
// remote: {
// httpRequest: getRoleList,
// params: { },
// },
remote
:
{
httpRequest
:
getCustomerList
,
beforeRequest
:
this
.
beforeRequest
,
params
:
{
name
:
''
,
short_name
:
''
,
source
:
''
,
type
:
''
,
region
:
''
,
created_by
:
''
,
project_tag
:
''
,
project_status
:
''
,
project_sso_id
:
''
,
last_record_start_time
:
''
,
last_record_end_time
:
''
,
created_start_time
:
''
,
created_end_time
:
''
}
},
filters
:
[
{
prop
:
'create_date'
,
slots
:
'filter-date'
,
label
:
'创建时间:'
,
class
:
'filter-form-item'
},
{
prop
:
'follow_date'
,
slots
:
'filter-follow-date'
,
label
:
'最近跟进时间:'
},
{
prop
:
'created_by'
,
slots
:
'filter-userSearch'
,
label
:
'创建员工:'
},
// {
// type: 'select',
// placeholder: '请选择创建员工',
// prop: 'creator',
// options: this.staffList,
// labelKey: 'name',
// valueKey: 'id',
// size: 'small',
// label: '创建员工:'
// },
{
type
:
'input'
,
prop
:
'name'
,
placeholder
:
'请输入活动名'
placeholder
:
'请输入客户名称'
,
options
:
this
.
staffList
,
size
:
'small'
,
label
:
'客户名称:'
},
{
type
:
'select'
,
placeholder
:
'请选择客户分类'
,
prop
:
'type'
,
options
:
typeList
,
labelKey
:
'name'
,
valueKey
:
'id'
,
size
:
'small'
,
label
:
'客户分类:'
},
{
type
:
'select'
,
placeholder
:
'请选择客户来源'
,
prop
:
'source'
,
options
:
sourceList
,
labelKey
:
'name'
,
valueKey
:
'id'
,
size
:
'small'
,
label
:
'客户来源:'
},
{
type
:
'select'
,
placeholder
:
'请选择合作项目'
,
prop
:
'project'
,
options
:
this
.
projectList
,
labelKey
:
'name'
,
valueKey
:
'id'
,
size
:
'small'
,
label
:
'合作项目:'
},
{
prop
:
'date'
,
slots
:
'filter-date'
}
{
type
:
'select'
,
placeholder
:
'请选择项目进度'
,
prop
:
'progress'
,
options
:
this
.
progressList
,
labelKey
:
'name'
,
valueKey
:
'id'
,
size
:
'small'
,
label
:
'项目进度:'
},
{
type
:
'select'
,
placeholder
:
'请选择项目负责人'
,
prop
:
'director'
,
options
:
[],
labelKey
:
'name'
,
valueKey
:
'id'
,
size
:
'small'
,
label
:
'项目负责人:'
},
{
prop
:
'region'
,
slots
:
'filter-region'
,
label
:
'所在地区:'
}
],
data
:
[
{
...
...
@@ -70,20 +206,63 @@ export default {
columns
:
[
// { type: 'selection', minWidth: '40px' },
{
prop
:
'name'
,
label
:
'客户名称'
,
minWidth
:
'120px'
},
{
prop
:
'source'
,
label
:
'客户来源'
,
minWidth
:
'80px'
},
{
prop
:
'category'
,
label
:
'客户分类'
,
minWidth
:
'150px'
},
{
prop
:
'address'
,
label
:
'所在地区'
,
minWidth
:
'150px'
},
{
prop
:
'time'
,
label
:
'最近跟进时间'
,
minWidth
:
'140px'
},
{
prop
:
'project'
,
label
:
'合作项目'
,
minWidth
:
'140px'
},
{
prop
:
'contacts'
,
label
:
'联系人'
,
minWidth
:
'140px'
},
{
prop
:
'creator'
,
label
:
'创建员工'
,
minWidth
:
'140px'
},
{
prop
:
'created_time'
,
label
:
'创建时间'
,
minWidth
:
'140px'
},
{
prop
:
'source'
,
label
:
'客户来源'
,
minWidth
:
'100px'
,
computed
({
row
})
{
const
item
=
sourceList
.
find
(
it
=>
it
.
id
===
row
.
source
)
||
{}
return
item
.
name
}
},
{
prop
:
'type'
,
label
:
'客户分类'
,
minWidth
:
'120px'
,
computed
({
row
})
{
const
item
=
typeList
.
find
(
it
=>
it
.
id
===
row
.
type
)
||
{}
return
item
.
name
}
},
{
prop
:
'region'
,
label
:
'所在地区'
,
minWidth
:
'150px'
},
{
prop
:
'last_record_time'
,
label
:
'最近跟进时间'
,
minWidth
:
'140px'
},
{
prop
:
'project_count'
,
label
:
'合作项目'
,
minWidth
:
'80px'
},
{
prop
:
'contact_count'
,
label
:
'联系人'
,
minWidth
:
'80px'
},
{
prop
:
'created_by.realname'
,
label
:
'创建员工'
,
minWidth
:
'140px'
},
{
prop
:
'created_at'
,
label
:
'创建时间'
,
minWidth
:
'140px'
},
{
label
:
'操作'
,
minWidth
:
'140px'
,
slots
:
'table-operate'
}
]
}
}
},
methods
:
{
beforeRequest
(
params
)
{
const
_params
=
Object
.
assign
({},
params
)
for
(
const
key
in
_params
)
{
if
(
!
_params
[
key
]
||
_params
.
length
===
0
)
{
delete
_params
[
key
]
}
}
if
(
params
.
create_date
)
{
delete
_params
.
create_date
_params
.
created_start_time
=
params
.
create_date
[
0
]
_params
.
created_end_time
=
params
.
create_date
[
1
]
}
if
(
params
.
follow_date
)
{
delete
_params
.
follow_date
_params
.
last_record_start_time
=
params
.
follow_date
[
0
]
_params
.
last_record_end_time
=
params
.
follow_date
[
1
]
}
if
(
params
.
region
)
{
if
(
params
.
region
.
length
===
3
)
{
_params
.
region
=
_params
.
region
.
join
(
'-'
)
}
else
{
delete
_params
.
region
}
}
console
.
log
(
_params
)
return
_params
},
// 查看
handleDetails
(
row
)
{
console
.
log
(
row
)
...
...
@@ -106,4 +285,19 @@ export default {
</
script
>
<
style
lang=
"scss"
scoped
>
.
customer
:
:
v-deep
.
table-list-hd
.
el-date-editor--datetimerange
.
el-input__inner
{
width
:
280px
;
padding
:
3px
0
3px
6px
;
}
.
customer
:
:
v-deep
.
table-list-hd
.
el-input
{
width
:
280px
;
min-width
:
160px
;
}
.
customer
:
:
v-deep
.
table-list-hd
.
el-select
{
width
:
280px
;
min-width
:
160px
;
}
.
customer
:
:
v-deep
.
table-list-hd
.
el-form
{
margin-right
:
-30px
;
}
</
style
>
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论