Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
I
inspect_report
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
zhengjinlei
inspect_report
Commits
d3b2bac2
Commit
d3b2bac2
authored
Jul 21, 2020
by
zhengjinlei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
增加客户画像
parent
4fd706a0
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
347 additions
and
29 deletions
+347
-29
__init__.py
src/inspect_report/api/__init__.py
+2
-0
openapi.py
src/inspect_report/api/openapi.py
+32
-0
profileapi.py
src/inspect_report/api/profileapi.py
+43
-0
cron.py
src/inspect_report/cron.py
+24
-5
models.py
src/inspect_report/models.py
+39
-0
permissions.py
src/inspect_report/permissions.py
+12
-10
urls.py
src/inspect_report/urls.py
+2
-1
urls_api_v1.py
src/inspect_report/urls_api_v1.py
+3
-1
report_utils.py
src/inspect_report/utils/report_utils.py
+177
-11
views.py
src/inspect_report/views.py
+13
-1
No files found.
src/inspect_report/api/__init__.py
View file @
d3b2bac2
...
@@ -4,3 +4,5 @@ from .toolapi import ToolsApi
...
@@ -4,3 +4,5 @@ from .toolapi import ToolsApi
from
.tasksapi
import
TasksApi
from
.tasksapi
import
TasksApi
from
.dataapi
import
DataApi
from
.dataapi
import
DataApi
from
.agencyapi
import
AgencyApi
from
.agencyapi
import
AgencyApi
from
.profileapi
import
ProfileApi
from
.openapi
import
OpenApi
src/inspect_report/api/openapi.py
0 → 100644
View file @
d3b2bac2
# coding: utf-8
from
rest_framework
import
viewsets
from
rest_framework.decorators
import
action
from
rest_framework.request
import
Request
from
rest_framework.response
import
Response
from
inspect_report
import
permissions
from
inspect_report.models
import
CustomProfile
import
json
import
logging
logger
=
logging
.
getLogger
(
__name__
)
class
OpenApi
(
viewsets
.
ViewSet
):
authentication_classes
=
()
permission_classes
=
(
permissions
.
ValidateToken
,
)
# permission_classes = ()
@
action
([
'get'
],
detail
=
False
)
def
labels
(
self
,
req
:
Request
):
phone_num
=
req
.
GET
.
get
(
'phone_num'
)
if
not
phone_num
:
logger
.
error
(
'[phone_label]---invalid params'
)
return
Response
({
'code'
:
-
1
,
'msg'
:
'请传入手机号'
})
labels
=
[]
profile
=
CustomProfile
.
objects
.
filter
(
phone_number
=
phone_num
)
.
first
()
if
not
profile
:
return
Response
({
'code'
:
0
,
'msg'
:
'查询成功'
,
'data'
:
json
.
dumps
(
labels
)})
if
profile
.
custom_labels
:
labels
=
profile
.
custom_labels
.
split
(
'、'
)
return
Response
({
'code'
:
0
,
'msg'
:
'查询成功'
,
'data'
:
labels
})
src/inspect_report/api/profileapi.py
0 → 100644
View file @
d3b2bac2
# coding: utf-8
from
django.core.paginator
import
Paginator
,
PageNotAnInteger
,
EmptyPage
from
rest_framework
import
viewsets
from
rest_framework.decorators
import
action
from
rest_framework.request
import
Request
from
rest_framework.response
import
Response
from
before_request
import
before_request
from
config.config
import
name_list
from
inspect_report.models
import
CustomProfile
import
logging
logger
=
logging
.
getLogger
(
__name__
)
class
ProfileApi
(
viewsets
.
ViewSet
):
authentication_classes
=
()
permission_classes
=
()
@
action
([
'get'
],
detail
=
False
)
@
before_request
def
labels
(
self
,
req
:
Request
):
page
=
req
.
GET
.
get
(
'page'
,
'1'
)
page_size
=
req
.
GET
.
get
(
'page_size'
,
'10'
)
region
=
req
.
GET
.
get
(
'region'
,
''
)
username
=
req
.
data
.
get
(
'username'
,
''
)
if
username
in
name_list
:
logger
.
info
(
'[profile_labels]获取的username是:
%
s'
,
username
)
region
=
username
condition
=
{}
if
region
:
condition
[
'region'
]
=
region
profiles
=
CustomProfile
.
objects
.
filter
(
**
condition
)
.
values
(
'phone_number'
,
'region'
,
'call_recent'
,
'call_count'
,
'custom_labels'
)
paginator
=
Paginator
(
profiles
,
page_size
)
total_count
=
paginator
.
count
try
:
objects
=
paginator
.
page
(
page
)
except
PageNotAnInteger
:
objects
=
paginator
.
page
(
1
)
except
EmptyPage
:
objects
=
paginator
.
page
(
paginator
.
num_pages
)
return
Response
({
'code'
:
0
,
'msg'
:
'查询成功'
,
'total'
:
total_count
,
'data'
:
objects
.
object_list
})
src/inspect_report/cron.py
View file @
d3b2bac2
# coding: utf-8
# coding: utf-8
from
inspect_report.models
import
Tasks
,
CheckSession
,
RulesStat
,
SeatStat
,
ScoreStat
,
Team
,
Seat
from
inspect_report.models
import
Tasks
,
CheckSession
,
RulesStat
from
config.config
import
TABLE_PRE
from
config.config
import
TABLE_PRE
import
json
import
json
import
logging
import
logging
import
kronos
import
kronos
from
datetime
import
datetime
,
timedelta
from
datetime
import
datetime
,
timedelta
from
inspect_report.utils.report_utils
import
single_rules_stat
,
single_seat_stat
,
single_score_stat
from
inspect_report.utils.report_utils
import
single_rules_stat
,
single_seat_stat
,
single_score_stat
,
single_data_stat
"""定时任务
"""定时任务
...
@@ -15,7 +15,7 @@ from inspect_report.utils.report_utils import single_rules_stat, single_seat_sta
...
@@ -15,7 +15,7 @@ from inspect_report.utils.report_utils import single_rules_stat, single_seat_sta
logger
=
logging
.
getLogger
(
'app_file'
)
logger
=
logging
.
getLogger
(
'app_file'
)
@
kronos
.
register
(
'30 6 * * *'
)
#
@kronos.register('30 6 * * *')
def
rule_stat
(
date_str
=
None
):
def
rule_stat
(
date_str
=
None
):
"""
"""
首页概述-违规项统计
首页概述-违规项统计
...
@@ -39,7 +39,7 @@ def rule_stat(date_str=None):
...
@@ -39,7 +39,7 @@ def rule_stat(date_str=None):
logger
.
info
(
'[rule_stat]rule stat end.'
)
logger
.
info
(
'[rule_stat]rule stat end.'
)
@
kronos
.
register
(
'30 6 * * *'
)
#
@kronos.register('30 6 * * *')
def
seat_stat
(
date_str
=
None
):
def
seat_stat
(
date_str
=
None
):
"""
"""
首页概述-违规坐席统计
首页概述-违规坐席统计
...
@@ -58,7 +58,7 @@ def seat_stat(date_str=None):
...
@@ -58,7 +58,7 @@ def seat_stat(date_str=None):
logger
.
info
(
'[seat_stat]violate seat stat end.'
)
logger
.
info
(
'[seat_stat]violate seat stat end.'
)
@
kronos
.
register
(
'30 6 * * *'
)
#
@kronos.register('30 6 * * *')
def
score_stat
(
date_str
=
None
):
def
score_stat
(
date_str
=
None
):
"""
"""
坐席得分统计
坐席得分统计
...
@@ -77,6 +77,25 @@ def score_stat(date_str=None):
...
@@ -77,6 +77,25 @@ def score_stat(date_str=None):
logger
.
info
(
'[score_stat]seat score stat end.'
)
logger
.
info
(
'[score_stat]seat score stat end.'
)
@
kronos
.
register
(
'30 6 * * *'
)
def
data_stat
(
date_str
=
None
):
"""
坐席得分统计
:return:
"""
if
not
date_str
:
date_str
=
datetime
.
now
()
.
strftime
(
'
%
Y-
%
m-
%
d'
)
create_date
=
date_str
logger
.
info
(
'[data_stat]data stat start...'
)
task_condition
=
{
'hasCheck'
:
1
,
'name__endswith'
:
date_str
}
tasks
=
Tasks
.
objects
.
filter
(
**
task_condition
)
.
values
(
'id'
,
'name'
,
'sessionCollectionId'
,
'extra'
)
stat_count
=
0
for
t
in
tasks
:
single_data_stat
(
t
,
create_date
,
stat_count
)
logger
.
info
(
'[data_stat]seat count: [
%
s]'
,
stat_count
)
logger
.
info
(
'[data_stat]seat score stat end.'
)
def
seat_time_stat
(
start_date
=
None
,
end_date
=
None
):
def
seat_time_stat
(
start_date
=
None
,
end_date
=
None
):
"""
"""
首页概述-违规坐席统计
首页概述-违规坐席统计
...
...
src/inspect_report/models.py
View file @
d3b2bac2
...
@@ -246,6 +246,45 @@ class ScoreTemplate(models.Model):
...
@@ -246,6 +246,45 @@ class ScoreTemplate(models.Model):
db_table
=
'score_template'
db_table
=
'score_template'
class
CustomProfile
(
models
.
Model
):
"""客户画像"""
name
=
models
.
CharField
(
'客户姓名'
,
max_length
=
190
,
null
=
True
,
blank
=
True
)
phone_number
=
models
.
CharField
(
'客户手机号'
,
max_length
=
20
,
null
=
True
,
blank
=
True
)
call_recent
=
models
.
DateTimeField
(
'最近通话日期'
,
null
=
True
,
blank
=
True
)
call_count
=
models
.
IntegerField
(
'通话次数'
,
default
=
0
)
custom_labels
=
models
.
CharField
(
'客户标签'
,
max_length
=
2000
,
null
=
True
,
blank
=
True
)
region
=
models
.
CharField
(
'所属地市'
,
max_length
=
100
,
null
=
True
,
blank
=
True
)
create_at
=
models
.
DateTimeField
(
'创建时间'
,
blank
=
True
,
null
=
True
)
update_at
=
models
.
DateTimeField
(
'更新时间'
,
blank
=
True
,
null
=
True
)
def
__str__
(
self
):
return
self
.
phone_number
class
Meta
:
db_table
=
'custom_profile'
class
CustomLabel
(
models
.
Model
):
"""客户标签"""
profile_id
=
models
.
IntegerField
(
'客户画像主键'
,
null
=
True
,
blank
=
True
)
call_time
=
models
.
DateTimeField
(
'通话日期'
,
null
=
True
,
blank
=
True
)
label
=
models
.
CharField
(
'客户标签'
,
max_length
=
100
,
null
=
True
,
blank
=
True
)
team
=
models
.
CharField
(
'呼叫团队'
,
null
=
True
,
max_length
=
100
)
agent_name
=
models
.
CharField
(
'坐席名称'
,
null
=
True
,
max_length
=
64
)
task_id
=
models
.
IntegerField
(
'质检任务标识'
)
session_id
=
models
.
CharField
(
'会话唯一标识'
,
max_length
=
64
)
session_table_id
=
models
.
IntegerField
(
'会话主键'
)
session_collection_id
=
models
.
CharField
(
'所在表'
,
null
=
True
,
max_length
=
32
)
create_at
=
models
.
DateTimeField
(
'创建时间'
,
blank
=
True
,
null
=
True
)
update_at
=
models
.
DateTimeField
(
'更新时间'
,
blank
=
True
,
null
=
True
)
def
__str__
(
self
):
return
self
.
label
class
Meta
:
db_table
=
'custom_label'
class
Round
(
Func
):
class
Round
(
Func
):
function
=
'ROUND'
function
=
'ROUND'
arity
=
2
arity
=
2
src/inspect_report/permissions.py
View file @
d3b2bac2
...
@@ -2,6 +2,7 @@
...
@@ -2,6 +2,7 @@
import
logging
import
logging
from
rest_framework.permissions
import
BasePermission
from
rest_framework.permissions
import
BasePermission
from
rest_framework.authentication
import
exceptions
from
rest_framework.authentication
import
exceptions
from
config.config
import
CUSTOM_PROFILE_TOKEN
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -10,17 +11,18 @@ class ValidateToken(BasePermission):
...
@@ -10,17 +11,18 @@ class ValidateToken(BasePermission):
""" token 正确才可以调用 """
""" token 正确才可以调用 """
def
has_permission
(
self
,
request
,
view
):
def
has_permission
(
self
,
request
,
view
):
try
:
try
:
http_auth
=
request
.
GET
.
get
(
'token'
,
''
)
http_auth
=
request
.
META
[
'HTTP_AUTHORIZATION'
]
if
http_auth
:
if
http_auth
:
# token = http_auth.split(' ')[1]
token
=
http_auth
.
split
(
' '
)[
1
]
# if http_auth.split(' ')[0] != 'Token':
if
http_auth
.
split
(
' '
)[
0
]
!=
'Token'
:
# log.error('token 认证异常 | HTTP_WXAUTH 中缺少 Token')
log
.
error
(
'token 认证异常 | HTTP_AUTHORIZATION 中缺少 Token'
)
# raise exceptions.AuthenticationFailed(detail={'code': -5, 'msg': 'token 认证异常'})
raise
exceptions
.
AuthenticationFailed
(
detail
=
{
'code'
:
-
5
,
# key = request.session.get(token, None)
'msg'
:
'token认证异常,HTTP_AUTHORIZATION 中缺少 Token'
})
# if not key:
if
token
==
CUSTOM_PROFILE_TOKEN
:
# log.error('token 认证异常 | Token不存在或者已过期')
log
.
info
(
'token 认证成功'
)
# raise exceptions.AuthenticationFailed(detail={'code': -5, 'msg': '无效的token'})
return
True
return
True
else
:
raise
exceptions
.
AuthenticationFailed
(
detail
=
{
'code'
:
-
5
,
'msg'
:
'token 认证异常'
})
except
KeyError
as
ke
:
except
KeyError
as
ke
:
log
.
error
(
'token 认证异常 | header中缺少HTTP_WXAUTH | 异常信息 : KeyError :
%
s'
,
str
(
ke
))
log
.
error
(
'token 认证异常 | header中缺少HTTP_WXAUTH | 异常信息 : KeyError :
%
s'
,
str
(
ke
))
raise
exceptions
.
AuthenticationFailed
(
detail
=
{
'code'
:
-
5
,
'msg'
:
'token 认证异常'
})
raise
exceptions
.
AuthenticationFailed
(
detail
=
{
'code'
:
-
5
,
'msg'
:
'token 认证异常'
})
...
...
src/inspect_report/urls.py
View file @
d3b2bac2
...
@@ -16,7 +16,7 @@ Including another URLconf
...
@@ -16,7 +16,7 @@ Including another URLconf
from
django.contrib
import
admin
from
django.contrib
import
admin
from
django.urls
import
path
from
django.urls
import
path
from
.api.tasksapi
import
rule
,
seat
,
group
,
score
,
check
,
city_score
from
.api.tasksapi
import
rule
,
seat
,
group
,
score
,
check
,
city_score
from
.views
import
stat_rules_every
,
stat_seats_every
,
stat_scores_every
,
stat_time_every
from
.views
import
stat_rules_every
,
stat_seats_every
,
stat_scores_every
,
stat_time_every
,
stat_data_every
urlpatterns
=
[
urlpatterns
=
[
# path('admin/', admin.site.urls),
# path('admin/', admin.site.urls),
...
@@ -30,4 +30,5 @@ urlpatterns = [
...
@@ -30,4 +30,5 @@ urlpatterns = [
path
(
'inspect/stat/seat/'
,
stat_seats_every
),
path
(
'inspect/stat/seat/'
,
stat_seats_every
),
path
(
'inspect/stat/score/'
,
stat_scores_every
),
path
(
'inspect/stat/score/'
,
stat_scores_every
),
path
(
'inspect/stat/time/'
,
stat_time_every
),
path
(
'inspect/stat/time/'
,
stat_time_every
),
path
(
'inspect/stat/data/'
,
stat_data_every
),
]
]
src/inspect_report/urls_api_v1.py
View file @
d3b2bac2
...
@@ -23,7 +23,9 @@ router = routers.DefaultRouter()
...
@@ -23,7 +23,9 @@ router = routers.DefaultRouter()
router
.
register
(
r'tools'
,
api
.
ToolsApi
,
base_name
=
'tools'
)
router
.
register
(
r'tools'
,
api
.
ToolsApi
,
base_name
=
'tools'
)
router
.
register
(
r'tasks'
,
api
.
TasksApi
,
base_name
=
'tasks'
)
router
.
register
(
r'tasks'
,
api
.
TasksApi
,
base_name
=
'tasks'
)
router
.
register
(
r'data'
,
api
.
DataApi
,
base_name
=
'data'
)
router
.
register
(
r'data'
,
api
.
DataApi
,
base_name
=
'data'
)
router
.
register
(
r'agency'
,
api
.
AgencyApi
,
base_name
=
'data'
)
router
.
register
(
r'profile'
,
api
.
ProfileApi
,
base_name
=
'profile'
)
router
.
register
(
r'agency'
,
api
.
AgencyApi
,
base_name
=
'agency'
)
router
.
register
(
r'custom'
,
api
.
OpenApi
,
base_name
=
'custom'
)
# Wire up our API using automatic URL routing.
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
# Additionally, we include login URLs for the browsable API.
...
...
src/inspect_report/utils/report_utils.py
View file @
d3b2bac2
This diff is collapsed.
Click to expand it.
src/inspect_report/views.py
View file @
d3b2bac2
from
datetime
import
datetime
,
timedelta
from
datetime
import
datetime
,
timedelta
from
.cron
import
rule_stat
,
seat_stat
,
score_stat
,
seat_time_stat
from
.cron
import
rule_stat
,
seat_stat
,
score_stat
,
seat_time_stat
,
data_stat
from
django.http.response
import
JsonResponse
from
django.http.response
import
JsonResponse
from
dateutil.rrule
import
rrule
,
DAILY
from
dateutil.rrule
import
rrule
,
DAILY
...
@@ -41,6 +41,18 @@ def stat_scores_every(request):
...
@@ -41,6 +41,18 @@ def stat_scores_every(request):
return
JsonResponse
({
'code'
:
0
,
'msg'
:
'stat success'
})
return
JsonResponse
({
'code'
:
0
,
'msg'
:
'stat success'
})
def
stat_data_every
(
request
):
start_date
=
request
.
GET
.
get
(
'start_date'
)
end_date
=
request
.
GET
.
get
(
'end_date'
)
s_date
=
datetime
.
strptime
(
start_date
,
'
%
Y-
%
m-
%
d'
)
e_date
=
datetime
.
strptime
(
end_date
,
'
%
Y-
%
m-
%
d'
)
seed_dt
=
list
(
rrule
(
DAILY
,
byweekday
=
[
0
,
1
,
2
,
3
,
4
,
5
,
6
],
dtstart
=
s_date
,
until
=
e_date
))
for
date
in
seed_dt
:
date_str
=
date
.
strftime
(
'
%
Y-
%
m-
%
d'
)
data_stat
(
date_str
)
return
JsonResponse
({
'code'
:
0
,
'msg'
:
'stat success'
})
def
stat_time_every
(
request
):
def
stat_time_every
(
request
):
start_date
=
request
.
GET
.
get
(
'start_date'
)
start_date
=
request
.
GET
.
get
(
'start_date'
)
end_date
=
request
.
GET
.
get
(
'end_date'
)
end_date
=
request
.
GET
.
get
(
'end_date'
)
...
...
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