Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
U
unify_api2
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
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
chaonan
unify_api2
Commits
7fb7f69a
Commit
7fb7f69a
authored
Apr 12, 2023
by
wang.wenrong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
anshiU
parent
6aff3dca
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
2646 additions
and
0 deletions
+2646
-0
__init__.py
unify_api/modules/anshiu/__init__.py
+0
-0
__init__.py
unify_api/modules/anshiu/components/__init__.py
+0
-0
equip_management_cps.py
unify_api/modules/anshiu/components/equip_management_cps.py
+170
-0
fine_monitor_cps.py
unify_api/modules/anshiu/components/fine_monitor_cps.py
+97
-0
scope_operations_cps.py
unify_api/modules/anshiu/components/scope_operations_cps.py
+509
-0
__init__.py
unify_api/modules/anshiu/dao/__init__.py
+0
-0
__init__.py
unify_api/modules/anshiu/procedures/__init__.py
+0
-0
equip_management_pds.py
unify_api/modules/anshiu/procedures/equip_management_pds.py
+175
-0
fine_monitor_pds.py
unify_api/modules/anshiu/procedures/fine_monitor_pds.py
+79
-0
scope_operations_pds.py
unify_api/modules/anshiu/procedures/scope_operations_pds.py
+73
-0
__init__.py
unify_api/modules/anshiu/service/__init__.py
+0
-0
equip_management_serv.py
unify_api/modules/anshiu/service/equip_management_serv.py
+50
-0
fine_monitor_serv.py
unify_api/modules/anshiu/service/fine_monitor_serv.py
+515
-0
scope_operations_serv.py
unify_api/modules/anshiu/service/scope_operations_serv.py
+534
-0
__init__.py
unify_api/modules/anshiu/views/__init__.py
+0
-0
equip_management.py
unify_api/modules/anshiu/views/equip_management.py
+131
-0
fine_monitor.py
unify_api/modules/anshiu/views/fine_monitor.py
+112
-0
scope_operations.py
unify_api/modules/anshiu/views/scope_operations.py
+158
-0
time_format.py
unify_api/utils/time_format.py
+43
-0
No files found.
unify_api/modules/anshiu/__init__.py
0 → 100644
View file @
7fb7f69a
unify_api/modules/anshiu/components/__init__.py
0 → 100644
View file @
7fb7f69a
unify_api/modules/anshiu/components/equip_management_cps.py
0 → 100644
View file @
7fb7f69a
from
dataclasses
import
dataclass
from
pot_libs.sanic_api
import
Model
from
pot_libs.common.components.fields
import
Cid
from
pot_libs.sanic_api.column
import
Opt
,
Float
,
Int
,
Str
,
List
,
Enum
from
unify_api.utils.response_code
import
DbErr
,
ParamErr
,
JwtErr
,
UserErr
@
dataclass
class
EquipManagementTotalReq
(
Model
):
'''
设备管理汇总-请求格式
'''
cid
:
Cid
@
dataclass
class
EquipManagementListReq
(
Model
):
'''
设备管理列表-请求格式
'''
cid
:
Cid
is_download
:
int
=
Int
(
"是否是下载 0-不是 1-是"
)
.
eg
(
0
)
page_size
:
int
=
Opt
(
Int
(
"页大小"
)
.
eg
(
10
))
page_num
:
int
=
Opt
(
Int
(
"页码"
)
.
eg
(
1
))
@
dataclass
class
EquipRunStatusReq
(
Model
):
'''
运行统计状态
'''
point_id
:
int
=
Opt
(
Int
(
"监测点"
)
.
eg
(
260
))
@
dataclass
class
EquipManagementTotalResp
(
Model
):
'''
设备管理汇总-返回格式
'''
installed_number
:
int
=
Int
(
"安装点数"
)
.
eg
(
1
)
start_time
:
str
=
Str
(
"启用时间"
)
.
eg
(
"2022-06-16"
)
@
dataclass
class
EquipManagementInfo
(
Model
,
DbErr
,
UserErr
,
JwtErr
):
'''
设备管理列表详情-返回格式
'''
installed_location
:
str
=
Opt
(
Str
(
"安装位置"
)
.
eg
(
"3#变压器"
))
device_number
:
str
=
Opt
(
Str
(
"设备编号"
)
.
eg
(
"A1904000083"
))
wiring_type
:
str
=
Opt
(
Str
(
"接线形式"
)
.
eg
(
"三表法"
))
ct_change
:
str
=
Opt
(
Int
(
"ct变比"
)
.
eg
(
1000
))
pt_change
:
str
=
Opt
(
Int
(
"pt变比"
)
.
eg
(
1000
))
rated_voltage
:
int
=
Opt
(
Int
(
"额定电压"
)
.
eg
(
400
))
start_time
:
str
=
Str
(
"接线时间"
)
.
eg
(
"2022-06-17 16:42"
)
@
dataclass
class
EquipManagementListResp
(
Model
,
DbErr
,
UserErr
,
JwtErr
):
'''
设备管理列表-返回格式
'''
rows
:
list
=
List
(
"设备信息"
)
.
items
(
EquipManagementInfo
)
total
:
int
=
Int
(
"总量"
)
page_num
:
int
=
Int
(
"当前页"
)
.
eg
(
1
)
@
dataclass
class
EquipRunReq
(
Model
):
'''
运行统计-请求格式
'''
cid
:
Cid
page_size
:
int
=
Opt
(
Int
(
"每页记录数"
)
.
eg
(
20
))
page_num
:
int
=
Opt
(
Int
(
"当前页码"
)
.
eg
(
1
))
is_download
:
int
=
Int
(
"是否是下载 0-不是 1-是"
)
.
eg
(
0
)
start
:
str
=
Opt
(
Str
(
"开始时间"
)
.
eg
(
"2020-05-01 00:00:00"
))
end
:
str
=
Opt
(
Str
(
"结束时间"
)
.
eg
(
"2020-05-01 23:59:59"
))
point_ids
:
list
=
Opt
(
List
(
"监测点 []表示没有 [-1]表示全部"
)
.
eg
([
260
,
261
,
268
]))
sort_field
:
list
=
Enum
(
'排序字段'
)
.
of
(
'point_name'
,
'start_time'
,
'end_time'
,
'run_time'
)
sort_type
:
list
=
Enum
(
'排序方向'
)
.
of
(
'asc'
,
'desc'
)
@
classmethod
def
example
(
cls
):
return
{
"cid"
:
154
,
"point_ids"
:
[
182
,
421
,
422
,
423
,
1752
,
1753
,
1754
],
"start"
:
"2022-06-28 00:00:00"
,
"end"
:
"2022-06-28 23:59:59"
,
"is_download"
:
0
,
"page_num"
:
1
,
"page_size"
:
20
,
"sort_field"
:
"start_time"
,
"sort_type"
:
"desc"
}
@
dataclass
class
EquipRunInfo
(
Model
,
DbErr
,
UserErr
,
JwtErr
):
'''
运行统计列表详情-返回格式
'''
point_name
:
str
=
Opt
(
Str
(
"监测点"
)
.
eg
(
"3#变压器"
))
start_time
:
str
=
Str
(
"开启时间"
)
.
eg
(
"2022-06-17 16:42"
)
end_time
:
str
=
Str
(
"关闭时间"
)
.
eg
(
"2022-06-21 16:42"
)
run_time
:
str
=
Str
(
"运行时长"
)
.
eg
(
"1小时20分"
)
@
dataclass
class
EquipRunListResp
(
Model
,
DbErr
,
UserErr
,
ParamErr
):
'''
运行统计-返回格式
'''
rows
:
list
=
List
(
"运行信息"
)
.
items
(
EquipRunInfo
)
total
:
int
=
Int
(
"总量"
)
page_num
:
int
=
Int
(
"当前页"
)
.
eg
(
1
)
@
dataclass
class
EquipRunStatisticsReq
(
Model
):
'''
运行统计数据-请求格式
'''
cid
:
Cid
start
:
str
=
Opt
(
Str
(
"开始时间"
)
.
eg
(
"2020-05-01 00:00:00"
))
end
:
str
=
Opt
(
Str
(
"结束时间"
)
.
eg
(
"2020-05-01 23:59:59"
))
point_ids
:
list
=
Opt
(
List
(
"监测点 []表示没有 [-1]表示全部"
)
.
eg
([
260
,
261
,
268
]))
@
classmethod
def
example
(
cls
):
return
{
"cid"
:
84
,
"point_ids"
:
[
261
,
262
,
266
,
268
],
"start"
:
"2021-09-06 15:04:51"
,
"end"
:
"2021-12-06 15:04:51"
,
}
@
dataclass
class
EquipRunStatisticsResp
(
Model
,
ParamErr
):
'''
运行统计数据-返回格式
'''
count
:
int
=
Int
(
"运行次数"
)
.
eg
(
23
)
run_all_time
:
str
=
Str
(
"运行时长"
)
.
eg
(
"11小时21分"
)
run_avg_time
:
str
=
Str
(
"平均时长"
)
.
eg
(
"1小时05分"
)
run_max_time
:
str
=
Str
(
"最长时长"
)
.
eg
(
"2小时23分"
)
@
dataclass
class
EquipRunStatusResp
(
Model
,
ParamErr
):
'''
运行统计状态-返回格式
'''
is_run
:
int
=
Int
(
"是否运行:0-否、1-是 2-非动力设备"
)
.
eg
(
1
)
unify_api/modules/anshiu/components/fine_monitor_cps.py
0 → 100644
View file @
7fb7f69a
from
dataclasses
import
dataclass
from
pot_libs.sanic_api
import
Model
from
pot_libs.sanic_api.column
import
List
,
Str
,
Int
,
Opt
,
Float
from
pot_libs.common.components.fields
import
Cid
,
Item
,
DateTime
from
unify_api.utils.response_code
import
DbErr
,
ParamErr
@
dataclass
class
FineMonitorChartReq
(
Model
):
'''
精确监测-图表请求
'''
pid
:
int
=
Int
(
"监测点id"
)
.
eg
(
261
)
start
:
str
=
Str
(
"开始时间"
)
.
eg
(
"2022-06-20 00:00:00"
)
end
:
str
=
Str
(
"结束时间"
)
.
eg
(
"2022-06-20 23:59:59"
)
location_ids
:
list
=
List
(
"location_ids"
)
.
eg
([
487
,
488
,
489
,
490
,
491
])
@
dataclass
class
FineMonitorInfoReq
(
Model
):
'''
精确监测-指标统计请求
'''
pid
:
int
=
Int
(
"监测点id"
)
.
eg
(
261
)
start
:
str
=
Str
(
"开始时间"
)
.
eg
(
"2022-06-20 00:00:00"
)
end
:
str
=
Str
(
"结束时间"
)
.
eg
(
"2022-06-20 23:59:59"
)
location_ids
:
list
=
List
(
"location_ids"
)
.
eg
([
487
,
488
,
489
,
490
,
491
])
@
dataclass
class
Chart
(
Model
,
DbErr
):
'''图表格式'''
item
:
str
=
Opt
(
Str
(
'类型'
)
.
eg
(
'A相'
))
value_slots
:
list
=
Opt
(
List
(
'数据列表'
)
.
items
(
Float
()))
@
dataclass
class
Statistics
(
Model
,
DbErr
):
type
:
str
=
Str
(
'指标类型'
)
.
eg
(
'temperature'
)
item
:
Item
=
Item
max
:
float
=
Float
(
"最大值"
)
max_time
:
DateTime
=
DateTime
min
:
float
=
Float
(
"最小值"
)
min_time
:
DateTime
=
DateTime
avg
:
float
=
Float
(
'平均值'
)
@
dataclass
class
FineMonitorChartResp
(
Model
,
DbErr
,
ParamErr
):
'''
精确监测-图表返回
'''
time_slots
:
list
=
List
(
"横坐标时序"
)
.
items
(
Float
())
residual_current
:
list
=
List
(
"漏电流"
)
.
items
(
Chart
)
temperature
:
list
=
List
(
"温度"
)
.
items
(
Chart
)
power
:
list
=
List
(
"功率(p表示有功,q表示无功)"
)
.
items
(
Chart
)
i
:
list
=
List
(
"电流"
)
.
items
(
Chart
)
v
:
list
=
List
(
"电压"
)
.
items
(
Chart
)
ctnum
:
int
=
Int
(
"接线方式:包含两表法、三表法"
)
.
eg
(
3
)
@
classmethod
def
example
(
cls
):
return
{
"time_slots"
:
[
"00:00"
,
"00:15"
],
"ctnum"
:
3
,
"residual_current"
:
[{
"item"
:
"漏电流"
,
"value_slots"
:
[
3.26
,
3.31
]
}],
"temperature"
:
[{
"item"
:
"A相"
,
"value_slots"
:
[
27.48
,
27.43
]
},
{
"item"
:
"B相"
,
"value_slots"
:
[
28.04
,
28.03
]
}],
"power"
:
[{
"item"
:
"p"
,
"value_slots"
:
[]
}],
"i"
:
[{
"item"
:
"ia"
,
"value_slots"
:
[
12
,
34
]
}],
"v"
:
[{
"item"
:
"ua"
,
"value_slots"
:
[]
}]
}
@
dataclass
class
FineMonitorInfoResp
(
Model
,
DbErr
,
ParamErr
):
'''
精确监测-指标统计返回
'''
info_list
:
list
=
List
(
"指标统计列表"
)
.
items
(
Statistics
)
unify_api/modules/anshiu/components/scope_operations_cps.py
0 → 100644
View file @
7fb7f69a
This diff is collapsed.
Click to expand it.
unify_api/modules/anshiu/dao/__init__.py
0 → 100644
View file @
7fb7f69a
unify_api/modules/anshiu/procedures/__init__.py
0 → 100644
View file @
7fb7f69a
unify_api/modules/anshiu/procedures/equip_management_pds.py
0 → 100644
View file @
7fb7f69a
from
pot_libs.mysql_util.mysql_util
import
MysqlUtil
from
pot_libs.logger
import
log
from
unify_api.modules.product_info.procedures.hardware_pds
import
(
get_user_hardware_info
,
hardware_statistics
)
async
def
check_company_exist
(
company_id
):
'''
判断工厂是否存在
'''
raw_sql
=
"select count(*) as company_count from company where cid =
%
s"
async
with
MysqlUtil
()
as
conn
:
company_count
=
await
conn
.
fetchone
(
sql
=
raw_sql
,
args
=
(
company_id
))
return
company_count
.
get
(
'company_count'
)
>
0
async
def
equip_management_list
(
company_id
,
page_num
,
page_size
):
'''
获取设备管理的监测点列表,先保留老的写法,后面1.0改版的时候统一改
'''
datas
=
await
get_user_hardware_info
(
company_id
,
page_num
,
page_size
)
return_fields
=
(
"installed_location"
,
"device_number"
,
"wiring_type"
,
"ct_change"
,
"pt_change"
,
"rated_voltage"
,
"start_time"
)
return_datas
=
[]
for
data
in
datas
.
get
(
'rows'
):
return_one
=
{}
for
return_field
in
return_fields
:
return_one
[
return_field
]
=
data
.
get
(
return_field
)
return_datas
.
append
(
return_one
)
datas
[
'rows'
]
=
return_datas
return
datas
async
def
equip_management_total
(
company_id
):
'''
获取设备管理的汇总信息
'''
datas
=
await
hardware_statistics
(
company_id
)
return
datas
async
def
equip_run_list
(
company_id
,
point_ids
,
start_time
,
end_time
,
page_num
,
page_size
,
sort_field
,
sort_type
):
'''
获取设备运行记录
'''
async
with
MysqlUtil
()
as
conn
:
raw_sql
=
"SELECT {} from scope_equip_run_record s "
\
"left join (select pid,max(id) max_id "
\
"from scope_equip_run_record group by pid) sp "
\
"on s.pid = sp.pid "
\
"left join point p on s.pid=p.pid "
\
"left join monitor_reuse r on p.mtid = r.mtid "
\
"where "
\
"(p.cid=
%
s or r.cid =
%
s) and s.start_time "
\
"BETWEEN
%
s and
%
s and "
\
"(s.end_time > 0 or (s.end_time = 0 and s.id = sp.max_id)) "
if
point_ids
:
raw_sql
+=
" and s.pid in
%
s"
args
=
(
company_id
,
company_id
,
start_time
,
end_time
,
tuple
(
point_ids
)
)
else
:
args
=
(
company_id
,
company_id
,
start_time
,
end_time
,
)
# 先总数
count_sql
=
raw_sql
.
format
(
"count(*) as run_count"
,
""
)
count_result
=
await
conn
.
fetchone
(
sql
=
count_sql
,
args
=
args
)
list_result
=
[]
if
count_result
.
get
(
"run_count"
,
0
)
>
0
:
# 排序字段处理
if
sort_field
==
'point_name'
:
sort_field
=
'p.name'
elif
sort_field
==
'run_time'
:
sort_field
=
'(s.end_time-s.start_time)'
# 再分页列表
raw_sql
=
raw_sql
.
format
(
"s.pid,p.name point_name,s.start_time,s.end_time"
,
)
raw_sql
+=
" order by {} {} LIMIT
%
s OFFSET
%
s"
.
format
(
sort_field
,
sort_type
)
if
point_ids
:
args
=
(
company_id
,
company_id
,
start_time
,
end_time
,
tuple
(
point_ids
),
page_size
,
(
page_num
-
1
)
*
page_size
)
else
:
args
=
(
company_id
,
company_id
,
start_time
,
end_time
,
page_size
,
(
page_num
-
1
)
*
page_size
)
list_result
=
await
conn
.
fetchall
(
sql
=
raw_sql
,
args
=
args
)
return
list_result
,
count_result
.
get
(
"run_count"
,
0
)
async
def
equip_run_statistics
(
company_id
,
point_ids
,
start_time
,
end_time
):
'''
获取运行统计数据
'''
dura_time
=
"case when end_time > 0 then end_time-start_time else 0 end"
async
with
MysqlUtil
()
as
conn
:
count_sql
=
f
"SELECT count(*) as total_count,"
\
f
"avg({dura_time}) as avg_time,"
\
f
"sum({dura_time}) as all_time,"
\
f
"max({dura_time}) as max_time "
\
"from scope_equip_run_record s "
\
"left join (select pid,max(id) max_id from "
\
"scope_equip_run_record group by pid) sp "
\
"on s.pid = sp.pid "
\
"left join point p on s.pid=p.pid "
\
"left join monitor_reuse r on p.mtid = r.mtid "
\
"where (p.cid=
%
s or r.cid =
%
s) "
\
"and s.start_time BETWEEN
%
s and
%
s and (s.end_time > 0 "
\
"or (s.end_time = 0 and s.id = sp.max_id)) "
if
point_ids
:
count_sql
+=
" and s.pid in
%
s"
args
=
(
company_id
,
company_id
,
start_time
,
end_time
,
tuple
(
point_ids
)
)
else
:
args
=
(
company_id
,
company_id
,
start_time
,
end_time
,
)
count_result
=
await
conn
.
fetchone
(
sql
=
count_sql
,
args
=
args
)
return
count_result
async
def
get_equip_run_status
(
point_id
):
'''
获取当前设备是否正在运行
'''
async
with
MysqlUtil
()
as
conn
:
# 是否非动力设备
power_equip_sql
=
"select is_power_equipment from monitor m "
\
"left join point p on m.mtid = p.mtid "
\
"where p.pid =
%
s"
power_equip_result
=
await
conn
.
fetchone
(
sql
=
power_equip_sql
,
args
=
(
point_id
,))
if
power_equip_result
.
get
(
"is_power_equipment"
,
0
)
==
0
:
return
2
raw_sql
=
"select count(*) run_count from scope_equip_run_record s "
\
"left join (select pid,max(id) max_id from "
\
"scope_equip_run_record group by pid) sp "
\
"on s.pid = sp.pid "
\
"WHERE s.pid=
%
s and start_time < unix_timestamp(NOW()) "
\
"and (end_time > unix_timestamp(NOW()) or "
\
"(end_time=0 and id=max_id)) "
result
=
await
conn
.
fetchone
(
sql
=
raw_sql
,
args
=
(
point_id
,))
return
1
if
result
.
get
(
"run_count"
)
>
0
else
0
unify_api/modules/anshiu/procedures/fine_monitor_pds.py
0 → 100644
View file @
7fb7f69a
from
pot_libs.logger
import
log
from
pot_libs.mysql_util.mysql_util
import
MysqlUtil
from
pot_libs.es_util.es_utils
import
EsUtil
from
unify_api
import
constants
async
def
get_location_by_ids
(
location_ids
):
'''
根据location_id获取各项温度信息
'''
async
with
MysqlUtil
()
as
conn
:
sql
=
"select id,item,type from location where id in
%
s"
result
=
await
conn
.
fetchall
(
sql
,
args
=
(
tuple
(
location_ids
),))
location_info
=
{
res
.
get
(
'id'
):
res
for
res
in
result
}
return
location_info
async
def
get_threshold_by_location
(
location_ids
,
type
=
'overResidualCurrent'
,
default_threshold
=
30
):
'''
根据location_id获取阈值
'''
async
with
MysqlUtil
()
as
conn
:
sql
=
"select threshold from alarm_setting where location_id in
%
s "
\
"and type =
%
s limit 1 "
settings
=
await
conn
.
fetchall
(
sql
,
args
=
(
tuple
(
location_ids
),
type
))
if
settings
:
return
settings
[
0
][
"threshold"
]
return
default_threshold
async
def
get_es_aiao_15min_data
(
query_body
):
'''
从es中获取环境相关数据(15min)
'''
async
with
EsUtil
()
as
es
:
es_results
=
await
es
.
search_origin
(
body
=
query_body
,
index
=
constants
.
LOCATION_15MIN_AIAO
)
return
es_results
.
get
(
"aggregations"
,
{})
async
def
get_es_point_15min_data
(
query_body
):
'''
从es中获取电力相关数据(15min)
'''
async
with
EsUtil
()
as
es
:
es_results
=
await
es
.
search_origin
(
body
=
query_body
,
index
=
constants
.
POINT_15MIN_INDEX
)
return
es_results
.
get
(
"aggregations"
,
{})
async
def
get_es_aiao_1min_data
(
query_body
,
start
):
'''
从es中获取环境相关数据(1min)
'''
async
with
EsUtil
()
as
es
:
# 环境相关qmin的数据需要分表查询
p_database
=
"poweriot_location_1min_aiao_"
+
start
[:
4
]
+
"_"
+
\
str
(
int
(
start
[
5
:
7
]))
es_results
=
await
es
.
search_origin
(
body
=
query_body
,
index
=
p_database
)
return
es_results
.
get
(
"hits"
,
{})
.
get
(
"hits"
,
{})
async
def
get_es_point_1min_data
(
query_body
,
start
):
'''
从es中获取电气相关数据(1min)
'''
async
with
EsUtil
()
as
es
:
# 电气相关数据1min的需要分表查询
p_database
=
"poweriot_point_1min_index_"
+
start
[:
4
]
+
"_"
+
\
str
(
int
(
start
[
5
:
7
]))
es_results
=
await
es
.
search_origin
(
body
=
query_body
,
index
=
p_database
)
return
es_results
.
get
(
"hits"
,
{})
.
get
(
"hits"
,
{})
unify_api/modules/anshiu/procedures/scope_operations_pds.py
0 → 100644
View file @
7fb7f69a
import
json
from
pot_libs.es_util.es_utils
import
EsUtil
from
pot_libs.logger
import
log
from
pot_libs.mysql_util.mysql_util
import
MysqlUtil
from
unify_api
import
constants
async
def
get_scope_config_by_pid
(
pid
):
'''
获取某个设备的录波配置
'''
async
with
MysqlUtil
()
as
conn
:
sql
=
"select threshold from scope_config_record where pid =
%
s"
result
=
await
conn
.
fetchone
(
sql
=
sql
,
args
=
(
pid
,))
return
result
.
get
(
'threshold'
,
{})
if
result
else
{}
async
def
set_scope_config_by_pid
(
pid
,
config
):
'''
设置录波配置
'''
try
:
async
with
MysqlUtil
()
as
conn
:
sql
=
"update scope_config_record set threshold=
%
s where pid=
%
s"
result
=
await
conn
.
execute
(
sql
=
sql
,
args
=
(
config
,
pid
))
except
Exception
as
e
:
log
.
error
(
'set_scope_config_by_pid update error:'
+
str
(
e
))
return
-
1
return
result
async
def
add_scope_config_by_pid
(
pid
,
configs
):
'''
增加录波配置
'''
try
:
async
with
MysqlUtil
()
as
conn
:
sql
=
"INSERT INTO `power_iot`.`scope_config_record` (`pid`, "
\
"`coef`, `threshold`, `vol_cur`) VALUES (
%
s,
%
s,
%
s,
%
s)"
result
=
await
conn
.
execute
(
sql
=
sql
,
args
=
(
pid
,
json
.
dumps
(
configs
[
"coef"
]),
json
.
dumps
(
configs
[
"threshold"
]),
json
.
dumps
(
configs
)))
except
Exception
as
e
:
log
.
error
(
'add_scope_config_by_pid add error:'
+
str
(
e
))
return
-
1
return
result
async
def
get_scope_list_by_pid
(
pids
,
start_dt
,
end_dt
,
scope_g
=
"2s"
):
"""
ES查询2s录波记录数据
"""
query_body
=
{
"size"
:
10000
,
"query"
:
{
"bool"
:
{
"must"
:
[
{
"terms"
:
{
"point_id"
:
pids
}},
{
"term"
:
{
"scope_g"
:
{
"value"
:
scope_g
}}},
{
"range"
:
{
"datetime"
:
{
"gte"
:
start_dt
,
"lt"
:
end_dt
}}}
]
}
},
"sort"
:
[{
"datetime"
:
{
"order"
:
"asc"
}}]
}
async
with
EsUtil
()
as
es
:
datas
=
await
es
.
search_origin
(
body
=
query_body
,
index
=
constants
.
POINT_1MIN_SCOPE
)
return
datas
[
"hits"
][
"hits"
]
\ No newline at end of file
unify_api/modules/anshiu/service/__init__.py
0 → 100644
View file @
7fb7f69a
unify_api/modules/anshiu/service/equip_management_serv.py
0 → 100644
View file @
7fb7f69a
from
unify_api.modules.anshiu.procedures.equip_management_pds
import
\
equip_run_list
,
equip_run_statistics
from
unify_api.modules.anshiu.components.equip_management_cps
import
\
EquipRunInfo
from
unify_api.utils.time_format
import
get_time_duration
,
get_datetime_str
,
\
get_date_timestamp
,
get_time_duration_by_str
async
def
equip_run_list_serv
(
company_id
,
point_ids
,
start_time
,
end_time
,
page_num
,
page_size
,
sort_field
,
sort_type
):
'''
获取运行统计列表
'''
start_time
=
get_date_timestamp
(
start_time
)
end_time
=
get_date_timestamp
(
end_time
)
rows
,
total
=
await
equip_run_list
(
company_id
,
point_ids
,
start_time
,
end_time
,
page_num
,
page_size
,
sort_field
,
sort_type
)
run_lists
=
[]
for
row
in
rows
:
run_time
=
get_time_duration
(
row
[
'start_time'
],
row
[
'end_time'
])
if
\
row
[
'start_time'
]
and
row
[
'end_time'
]
else
''
start_time_one
=
get_datetime_str
(
row
[
'start_time'
])
if
row
[
'start_time'
]
else
''
end_time_one
=
get_datetime_str
(
row
[
'end_time'
])
if
row
[
'end_time'
]
\
else
''
equip_run_info
=
EquipRunInfo
(
point_name
=
row
[
'point_name'
],
start_time
=
start_time_one
,
end_time
=
end_time_one
,
run_time
=
run_time
)
run_lists
.
append
(
equip_run_info
)
return
run_lists
,
total
async
def
equip_run_statistics_serv
(
company_id
,
point_ids
,
start_time
,
end_time
):
'''
运行统计数据
'''
start_time
=
get_date_timestamp
(
start_time
)
end_time
=
get_date_timestamp
(
end_time
)
data
=
await
equip_run_statistics
(
company_id
,
point_ids
,
start_time
,
end_time
)
data
[
'all_time'
]
=
get_time_duration_by_str
(
data
[
'all_time'
])
if
data
[
'total_count'
]
else
''
data
[
'avg_time'
]
=
get_time_duration_by_str
(
data
[
'avg_time'
])
if
data
[
'total_count'
]
else
''
data
[
'max_time'
]
=
get_time_duration_by_str
(
data
[
'max_time'
])
if
data
[
'total_count'
]
else
''
return
data
unify_api/modules/anshiu/service/fine_monitor_serv.py
0 → 100644
View file @
7fb7f69a
This diff is collapsed.
Click to expand it.
unify_api/modules/anshiu/service/scope_operations_serv.py
0 → 100644
View file @
7fb7f69a
This diff is collapsed.
Click to expand it.
unify_api/modules/anshiu/views/__init__.py
0 → 100644
View file @
7fb7f69a
unify_api/modules/anshiu/views/equip_management.py
0 → 100644
View file @
7fb7f69a
from
pot_libs.sanic_api
import
summary
,
description
,
examples
from
pot_libs.logger
import
log
from
unify_api.modules.anshiu.service.equip_management_serv
import
\
equip_run_list_serv
,
equip_run_statistics_serv
from
unify_api.modules.anshiu.components.equip_management_cps
import
(
EquipManagementTotalReq
,
EquipManagementListReq
,
EquipManagementTotalResp
,
EquipManagementListResp
,
EquipRunReq
,
EquipRunListResp
,
EquipRunStatusReq
,
EquipRunStatusResp
,
EquipRunStatisticsReq
,
EquipRunStatisticsResp
)
from
unify_api.modules.anshiu.procedures.equip_management_pds
import
(
check_company_exist
,
equip_management_list
,
equip_management_total
,
equip_run_list
,
get_equip_run_status
)
@
summary
(
"设备管理-获取设备统计信息"
)
async
def
post_equip_management_total
(
request
,
body
:
EquipManagementTotalReq
)
->
EquipManagementTotalResp
:
company_id
=
body
.
cid
total_info
=
await
equip_management_total
(
company_id
)
return
EquipManagementTotalResp
(
installed_number
=
total_info
[
"installed_number"
],
start_time
=
total_info
[
"start_time"
])
@
summary
(
"设备管理-获取设备列表/下载"
)
@
description
(
"列表的时候正常传页码,下载的时候is_download=1"
)
async
def
post_equip_management_list
(
request
,
body
:
EquipManagementListReq
)
->
EquipManagementListResp
:
company_id
=
body
.
cid
is_download
=
body
.
is_download
page_size
,
page_num
=
body
.
page_size
,
body
.
page_num
log
.
info
(
f
"post_equip_management_list company_id={company_id},page_size={page_size},page_num={page_num}"
)
# 下载(限制最大10000条)
if
is_download
==
1
:
page_num
,
page_size
=
1
,
10000
company_exist
=
await
check_company_exist
(
company_id
)
if
not
company_exist
:
return
EquipManagementListResp
.
user_error
()
page_map
=
await
equip_management_list
(
company_id
,
page_num
,
page_size
)
return
EquipManagementListResp
(
rows
=
page_map
[
"rows"
],
total
=
page_map
[
"total"
],
page_num
=
page_num
)
@
summary
(
"运行统计-列表"
)
@
description
(
"列表的时候正常传页码,下载的时候is_download=1"
)
async
def
post_equip_run_list
(
request
,
body
:
EquipRunReq
)
->
EquipRunListResp
:
try
:
company_id
=
body
.
cid
point_ids
=
body
.
point_ids
page_size
=
body
.
page_size
page_num
=
body
.
page_num
start_time
=
body
.
start
end_time
=
body
.
end
is_download
=
body
.
is_download
sort_field
=
body
.
sort_field
if
body
.
sort_field
and
is_download
==
0
\
else
'start_time'
sort_type
=
body
.
sort_type
if
body
.
sort_type
and
is_download
==
0
\
else
'desc'
# 未选中监测点直接返回
if
len
(
point_ids
)
==
0
:
return
EquipRunListResp
(
rows
=
[],
total
=
0
,
page_num
=
page_num
)
# 监测点选中全部
if
point_ids
[
0
]
==
-
1
:
point_ids
=
[]
# 未选中监测点且未选中工厂提示错误
if
len
(
point_ids
)
==
0
and
not
company_id
:
log
.
error
(
"post_scope_list_param_error pids:
%
s cid:
%
s"
%
(
point_ids
,
company_id
))
return
EquipRunListResp
.
error_param
()
# 下载(限制最大10000条)
if
is_download
==
1
:
page_num
,
page_size
=
1
,
10000
except
Exception
as
e
:
log
.
error
(
"post_equip_run_list_error :"
+
e
)
return
EquipRunListResp
.
param_error
()
# 从数据库中获取数据
rows
,
total
=
await
equip_run_list_serv
(
company_id
,
point_ids
,
start_time
,
end_time
,
page_num
,
page_size
,
sort_field
,
sort_type
)
return
EquipRunListResp
(
rows
=
rows
,
total
=
total
,
page_num
=
page_num
)
@
summary
(
"运行统计-获取统计数据"
)
async
def
post_equip_run_statistics
(
request
,
body
:
EquipRunStatisticsReq
)
->
EquipRunStatisticsResp
:
'''
获取运行统计数据
'''
cid
=
body
.
cid
start_time
=
body
.
start
end_time
=
body
.
end
point_ids
=
body
.
point_ids
# 未选中监测点直接返回
if
len
(
point_ids
)
==
0
:
return
EquipRunStatisticsResp
(
count
=
0
,
run_all_time
=
''
,
run_avg_time
=
''
,
run_max_time
=
''
)
# 监测点选中全部
if
point_ids
[
0
]
==
-
1
:
point_ids
=
[]
# 未选中监测点且未选中工厂提示错误
if
len
(
point_ids
)
==
0
and
not
cid
:
log
.
error
(
"post_scope_list_param_error pids:
%
s cid:
%
s"
%
(
point_ids
,
cid
))
return
EquipRunStatisticsResp
.
error_param
()
data
=
await
equip_run_statistics_serv
(
cid
,
point_ids
,
start_time
,
end_time
)
return
EquipRunStatisticsResp
(
count
=
data
[
'total_count'
],
run_all_time
=
data
[
'all_time'
],
run_avg_time
=
data
[
'avg_time'
],
run_max_time
=
data
[
'max_time'
])
@
summary
(
'获取检测点运行状态'
)
async
def
post_equit_run_status
(
request
,
body
:
EquipRunStatusReq
)
->
EquipRunStatusResp
:
point_id
=
body
.
point_id
if
not
point_id
or
point_id
<=
0
:
log
.
error
(
f
'get_equit_run_status_param_error point:{point_id}'
)
return
EquipRunStatusResp
.
param_error
()
status
=
await
get_equip_run_status
(
point_id
)
return
EquipRunStatusResp
(
is_run
=
status
)
unify_api/modules/anshiu/views/fine_monitor.py
0 → 100644
View file @
7fb7f69a
from
pot_libs.sanic_api
import
summary
,
examples
from
pot_libs.common.components.query
import
PageRequest
from
pot_libs.logger
import
log
from
pot_libs.utils.pendulum_wrapper
import
my_pendulum
from
unify_api.utils.request_util
import
filed_value_from_list
from
unify_api.utils
import
time_format
from
unify_api.modules.anshiu.components.fine_monitor_cps
import
(
FineMonitorChartReq
,
FineMonitorInfoReq
,
FineMonitorChartResp
,
FineMonitorInfoResp
)
from
unify_api.modules.anshiu.procedures.fine_monitor_pds
import
(
get_location_by_ids
,
get_threshold_by_location
)
from
unify_api.modules.anshiu.service.fine_monitor_serv
import
(
get_adio_chart_data
,
get_point_chart_data
,
get_adio_info_data
,
get_point_info_data
)
@
summary
(
"精细监测-五个图表"
)
async
def
post_fine_monitor_chart
(
request
,
body
:
FineMonitorChartReq
)
->
FineMonitorChartResp
:
try
:
date_start
=
body
.
start
date_end
=
body
.
end
# 起始时间转化为时间戳
start_timestamp
=
time_format
.
get_date_timestamp
(
date_start
)
end_timestamp
=
time_format
.
get_date_timestamp
(
date_end
)
# 计算间隔与坐标点
intervel
,
slots
=
time_format
.
time_pick_transf
(
date_start
,
date_end
)
# 获取监测点
point_id
=
body
.
pid
if
not
point_id
or
point_id
<=
0
:
raise
Exception
(
'point_error point_id:{}'
.
format
(
point_id
))
# 获取location点
location_group
=
body
.
location_ids
if
not
location_group
:
raise
Exception
(
'in_groups is NULL, no location_id'
)
except
Exception
as
e
:
log
.
error
(
'get_fine_monitor_chart_error '
+
str
(
e
))
return
FineMonitorChartResp
.
param_error
()
# 获取location表的信息
try
:
location_info
=
await
get_location_by_ids
(
location_group
)
except
Exception
as
e
:
log
.
error
(
'get_fine_monitor_chart_error '
+
e
)
return
FineMonitorChartResp
.
db_error
()
# 获取温度及漏电流数据
temperature_list
,
residual_currents_list
=
await
get_adio_chart_data
(
location_group
,
location_info
,
start_timestamp
,
end_timestamp
,
intervel
,
slots
)
# 电力数据 power_list、电流曲线、电压曲线
power_list
,
i_list
,
v_list
,
ctnum
=
await
get_point_chart_data
(
point_id
,
start_timestamp
,
end_timestamp
,
\
intervel
,
slots
)
# 获取温度与漏电流的曲线数据
# 获取用电数据
return
FineMonitorChartResp
(
time_slots
=
slots
,
temperature
=
temperature_list
,
residual_current
=
residual_currents_list
,
power
=
power_list
,
i
=
i_list
,
v
=
v_list
,
ctnum
=
ctnum
)
@
summary
(
"精细监测-指标统计"
)
async
def
post_fine_monitor_info
(
request
,
body
:
FineMonitorInfoReq
)
->
FineMonitorInfoResp
:
try
:
date_start
=
body
.
start
date_end
=
body
.
end
# 起始时间转化为时间戳
start_timestamp
=
time_format
.
get_date_timestamp
(
date_start
)
end_timestamp
=
time_format
.
get_date_timestamp
(
date_end
)
# 起始时间转化为es时间格式
es_start_dt
=
my_pendulum
.
from_format
(
date_start
,
"YYYY-MM-DD HH:mm:ss"
)
es_end_dt
=
my_pendulum
.
from_format
(
date_end
,
"YYYY-MM-DD HH:mm:ss"
)
# 获取监测点
point_id
=
body
.
pid
if
not
point_id
or
point_id
<=
0
:
raise
Exception
(
'point_error point_id:{}'
.
format
(
point_id
))
# 获取location点
location_group
=
body
.
location_ids
if
not
location_group
:
raise
Exception
(
'in_groups is NULL, no location_id'
)
except
Exception
as
e
:
log
.
error
(
'get_fine_monitor_info '
+
str
(
e
))
return
FineMonitorInfoResp
.
param_error
()
# 获取location表的信息
try
:
location_info
=
await
get_location_by_ids
(
location_group
)
except
Exception
as
e
:
log
.
error
(
'get_fine_monitor_chart_error '
+
e
)
return
FineMonitorChartResp
.
db_error
()
info_list
=
[]
# 环境相关数据
adio_list
=
await
get_adio_info_data
(
location_group
,
location_info
,
start_timestamp
,
end_timestamp
)
# 用电相关数据
point_list
=
await
get_point_info_data
(
point_id
,
es_start_dt
,
es_end_dt
)
info_list
.
extend
(
adio_list
)
info_list
.
extend
(
point_list
)
return
FineMonitorInfoResp
(
info_list
=
info_list
)
unify_api/modules/anshiu/views/scope_operations.py
0 → 100644
View file @
7fb7f69a
from
pot_libs.common.components.responses
import
Success
from
pot_libs.logger
import
log
from
pot_libs.sanic_api
import
summary
,
description
,
examples
from
pot_libs.utils.exc_util
import
BusinessException
from
unify_api.modules.anshiu.components.scope_operations_cps
import
\
ScopeListReq
,
ScopeListResp
,
GetScopeConfigReq
,
GetScopeConfigResp
,
\
SetScopeConfigReq
,
SetScopeConfigResp
,
\
scope_list_req_example
,
ScopeDetailsResp
,
ScopeDetailRep
,
\
set_scope_config_example
,
InitScopeConfigReq
,
FlushScopeEsDataReq
,
\
ScopeListDownloadReq
,
ScopeListDownloadResp
from
unify_api.modules.anshiu.service.scope_operations_serv
import
\
search_scope_service
,
scope_detail_data
,
get_scope_config_serv
,
\
set_scope_config_serv
,
init_scope_config
,
flush_scope_es_data
,
\
scope_list_download_data
@
summary
(
"识别记录-列表"
)
@
description
(
"列表的时候正常传页码,下载的时候is_download=1"
)
@
examples
(
scope_list_req_example
)
async
def
post_scope_list
(
request
,
body
:
ScopeListReq
)
->
ScopeListResp
:
'''
识别记录
'''
cid
=
body
.
cid
page_size
=
body
.
page_size
page_num
=
body
.
page_num
start
=
body
.
start
end
=
body
.
end
scope_g
=
body
.
scope_g
pids
=
body
.
pids
is_download
=
body
.
is_download
# 监测点选中全部
if
pids
and
pids
[
0
]
==
-
1
:
pids
=
[]
# 未选中监测点且未选中工厂提示错误
if
len
(
pids
)
==
0
and
not
cid
:
log
.
error
(
"post_scope_list_param_error pids:
%
s cid:
%
s"
%
(
pids
,
cid
))
return
ScopeListResp
.
error_param
()
if
page_num
*
page_size
>
30000
:
log
.
error
(
f
"post_scope_list_param_error page_too_large page_num"
f
":{page_num},page_size:{page_size}"
)
raise
BusinessException
(
message
=
'只能查询前
%
s条数据,建议缩小查询范围'
%
30000
)
# 下载(限制最大10000条)
if
is_download
==
1
:
page_num
,
page_size
=
1
,
10000
# 替换scope_g
if
scope_g
:
scope_g
=
[
'200ms'
if
i
==
'0.2s'
else
i
for
i
in
scope_g
]
rows
,
total
=
await
search_scope_service
(
pids
,
cid
,
page_num
,
page_size
,
start
,
end
,
scope_g
)
return
ScopeListResp
(
rows
=
rows
,
total
=
total
,
page_num
=
page_num
)
@
summary
(
"2s录波数据下载"
)
async
def
post_scope_list_download
(
request
,
body
:
ScopeListDownloadReq
)
->
ScopeListDownloadResp
:
start
=
body
.
start
end
=
body
.
end
pids
=
body
.
pids
if
len
(
pids
)
>
1
:
raise
BusinessException
(
message
=
"只允许下载一个监测点的数据"
)
datas
=
await
scope_list_download_data
(
pids
,
start
,
end
)
return
ScopeListDownloadResp
(
rows
=
datas
)
@
summary
(
"识别记录-详情"
)
async
def
post_scope_detail
(
request
,
body
:
ScopeDetailRep
)
->
ScopeDetailsResp
:
'''
识别详情
'''
doc_id
=
body
.
id
return
await
scope_detail_data
(
doc_id
)
@
summary
(
"识别设置-获取配置信息"
)
async
def
post_get_scope_config
(
request
,
body
:
GetScopeConfigReq
)
->
GetScopeConfigResp
:
'''
识别设置-配置展示
'''
pid
=
body
.
pid
try
:
data
=
await
get_scope_config_serv
(
pid
)
except
Exception
as
e
:
log
.
error
(
'post_get_scope_config error:'
+
str
(
e
))
return
GetScopeConfigResp
.
server_error
()
return
GetScopeConfigResp
(
pid
=
pid
,
rows
=
data
)
@
summary
(
"识别设置-设置配置信息"
)
@
examples
(
set_scope_config_example
)
async
def
post_set_scope_config
(
request
,
body
:
SetScopeConfigReq
)
->
SetScopeConfigResp
:
'''
识别设置-配置设置
'''
pid
=
body
.
pid
type
=
body
.
type
scope_type
=
body
.
scope_type
# 每一种类型需要的字段
fields
=
{
'state'
:
[
'state'
],
'i'
:
[
'imax'
,
'igap'
],
'v'
:
[
'umax'
,
'umin'
,
'ugap'
],
'residual_current'
:
[
'lcmax'
,
'lcgap'
],
'power'
:
[
'pttlmax'
,
'pttlgap'
],
'time'
:
[
'one_time'
,
'two_time'
,
'three_time'
]}
args
=
{}
for
field
in
fields
.
get
(
type
):
args
[
field
]
=
getattr
(
body
,
field
)
try
:
await
set_scope_config_serv
(
pid
,
type
,
scope_type
,
args
)
except
Exception
as
e
:
log
.
error
(
'post_set_scope_config'
+
str
(
e
))
return
SetScopeConfigResp
(
success
=
0
,
message
=
str
(
e
))
return
SetScopeConfigResp
(
success
=
1
,
message
=
'操作成功'
)
@
summary
(
"识别设置-初始化设备配置信息(开发专用!)"
)
async
def
post_init_scope_config
(
request
,
body
:
InitScopeConfigReq
)
->
Success
:
pids
=
body
.
pids
# user_id = request.ctx.user_id
# if user_id not in ['100653']:
# return Success(success=0, message='无此操作权限')
error_list
=
[]
for
pid
in
pids
:
try
:
await
init_scope_config
(
pid
)
except
Exception
as
e
:
log
.
error
(
f
'{pid}:post_init_scope_config error {str(e)}'
)
error_list
.
append
(
str
(
e
))
continue
if
error_list
:
log
.
error
(
f
"post_init_scope_config error:{','.join(error_list)}"
)
else
:
log
.
info
(
f
"post_init_scope_config success total_success_count:"
f
"{str(len(pids))}"
)
return
Success
(
success
=
1
,
message
=
','
.
join
(
error_list
))
@
summary
(
"刷新es录波数据(开发专用!)"
)
async
def
post_flush_scope_es_data
(
request
,
body
:
FlushScopeEsDataReq
)
->
\
Success
:
scope_type_list
=
body
.
scope_type_list
start_time
=
body
.
start_time
end_time
=
body
.
end_time
try
:
for
scope_g
in
scope_type_list
:
if
scope_g
not
in
[
'200ms'
,
'2s'
,
'0.25ms'
]:
continue
await
flush_scope_es_data
(
scope_g
,
start_time
,
end_time
)
except
Exception
as
e
:
log
.
error
(
f
'post_flush_scope_es_data error {str(e)}'
)
return
Success
(
success
=
0
,
message
=
str
(
e
))
return
Success
(
success
=
1
,
message
=
'操作成功'
)
unify_api/utils/time_format.py
View file @
7fb7f69a
...
...
@@ -1400,3 +1400,46 @@ def get_start_end_by_tz_time_new(time_str, from_format='YYYY-MM-DD',
start
=
date
.
start_of
(
"day"
)
.
format
(
to_format
)
end
=
date
.
end_of
(
"day"
)
.
format
(
to_format
)
return
start
,
end
def
get_time_duration
(
start_time
,
end_time
,
is_timestamp
=
True
,
is_need_trans
=
True
):
"""
根据开始、结束时间获取格式化的时间差
"""
if
is_timestamp
:
start_time
=
convert_timestamp_to_dt
(
start_time
)
end_time
=
convert_timestamp_to_dt
(
end_time
)
else
:
start_time
=
convert_to_dt
(
start_time
)
end_time
=
convert_to_dt
(
end_time
)
# 计算时间差
duration
=
end_time
-
start_time
# 如果不需要转换 则直接返回
duration_str
=
duration
.
seconds
+
duration
.
days
*
24
*
60
*
60
if
not
is_need_trans
:
return
duration_str
# 返回
return_str
=
get_time_duration_by_str
(
duration_str
)
return
return_str
def
get_time_duration_by_str
(
duration_str
):
"""
根据时间戳获取格式化的时间差
"""
return_str
=
''
days
=
int
(
duration_str
/
(
60
*
60
*
24
))
if
days
>
0
:
return_str
+=
"
%
s天"
%
str
(
days
)
hours
=
int
(
duration_str
%
(
60
*
60
*
24
)
/
(
60
*
60
))
if
hours
>
0
:
return_str
+=
"
%
s时"
%
str
(
hours
)
minutes
=
int
(
duration_str
%
(
60
*
60
*
24
)
%
(
60
*
60
)
/
60
)
if
minutes
>
0
:
return_str
+=
"
%
s分"
%
str
(
minutes
)
seconds
=
int
(
duration_str
%
(
60
*
60
*
24
)
%
(
60
*
60
)
%
60
)
if
seconds
>
0
:
return_str
+=
"
%
s秒"
%
str
(
seconds
)
return
return_str
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