Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
so-manage-ui
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
smart-operation
so-manage-ui
Commits
b8c8a74f
Commit
b8c8a74f
authored
Mar 23, 2023
by
赵伟庚
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[feat](配置管理): 首选项配置&访问规则管理列表接口联调
parent
765100c1
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
255 additions
and
232 deletions
+255
-232
src/assets/css/index.css
src/assets/css/index.css
+1
-0
src/page/main/config/accessRule/index.vue
src/page/main/config/accessRule/index.vue
+217
-223
src/page/main/config/preference/index.vue
src/page/main/config/preference/index.vue
+33
-5
src/page/main/home-config/recommend/edit/index.vue
src/page/main/home-config/recommend/edit/index.vue
+3
-3
src/page/main/home-config/recommend/index.vue
src/page/main/home-config/recommend/index.vue
+1
-1
No files found.
src/assets/css/index.css
View file @
b8c8a74f
...
...
@@ -282,6 +282,7 @@ div {
color
:
#404a62
;
text-align
:
center
;
padding
:
0
16px
;
line-height
:
1
;
}
.dialog_box
.el-dialog__body
{
padding
:
24px
;
...
...
src/page/main/config/accessRule/index.vue
View file @
b8c8a74f
...
...
@@ -2,7 +2,7 @@
<div
class=
"page_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.
keyword
"
placeholder=
"请输入规则名称或规则"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.
search
"
placeholder=
"请输入规则名称或规则"
>
<template
v-slot:left_action
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"addRule"
>
...
...
@@ -37,18 +37,22 @@
</bg-filter-group>
<div
class=
"table_container"
>
<bg-table
ref=
"bgTable"
:headers=
"headers"
:rows=
"tableRows"
:stripe=
"true"
select
>
<
template
v-slot:ability_name=
"{ row }"
>
<span
@
click=
"goDetail(row)"
class=
"can_click_text"
>
{{
row
.
ability_name
}}
<span
v-if=
"row.include_mock_service"
class=
"mock_tip"
>
mock
</span>
</span>
<
template
v-slot:rule_type=
"{ row }"
>
<span>
{{
[
""
,
"
IP
"
][
row
.
rule_type
]
}}
</span>
</
template
>
<
template
v-slot:ability_state=
"{ row }"
>
<span
class=
"circle"
:class=
"'bgc_' + row.ability_state"
></span>
{{
[
"
待上架
"
,
"
已上架
"
,
"
已下架
"
,
"
上架中
"
,
"
下架中
"
][
row
.
ability_state
]
}}
<
template
v-slot:num_user=
"{ row }"
>
<span
class=
"can_click_text under_line"
@
click=
"openUserDialog(row)"
>
{{
row
.
num_user
}}
</span>
</
template
>
<
template
v-slot:start_use=
"{ row }"
>
<el-switch></el-switch>
<
template
v-slot:state=
"{ row }"
>
<bg-switch
@
click=
"stateChange(row)"
:labels=
"['否', '是']"
:values=
"[0, 1]"
v-model=
"row.state"
></bg-switch>
</
template
>
<
template
v-slot:updated_time=
"{ row }"
>
<span>
{{
dateStringTransform
(
row
.
updated_time
)
}}
</span>
</
template
>
<
template
v-slot:action=
"{ row }"
>
<bg-table-btns2
:limit=
"3"
:key=
"row.id"
>
...
...
@@ -59,7 +63,7 @@
</bg-table>
<bg-pagination
:page=
"filter.page"
:size=
"filter.
size
"
:size=
"filter.
limit
"
:total=
"tableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
...
...
@@ -71,139 +75,102 @@
<div
class=
"content_detail"
>
<div
class=
"form_filter"
>
<div
class=
"left"
>
<el-select
placeholder=
"全部类型
"
style=
"width: 200px; margin-left: 16px"
>
<el-option
label=
"选共享1"
value=
"1"
>
</el-option>
<el-option
label=
"选共享2"
value=
"2"
>
</el-option>
</el-select>
<el-select
placeholder=
"请选择所属组织"
style=
"width: 200px; margin-left: 16px"
>
<el-option
label=
"选共享1"
value=
"1"
>
</el-option
>
<
el-option
label=
"选共享2"
value=
"2"
>
<
/el-option>
<el-select
v-model=
"userFilter.isAdmin"
placeholder=
"请选择
"
style=
"width: 200px; margin-left: 16px"
>
<el-option
v-for=
"(item, index) in userTypeList"
:key=
"'pushOptions' + index"
:label=
"item.name"
:value=
"item.value"
>
</el-option>
</el-select>
<el-cascader
v-model=
"userFilter.organizationId"
:options=
"orgList"
placeholder=
"请选择组织"
:props=
"{
expandTrigger: 'hover',
label: 'name',
value: 'organization_id',
emitPath: false,
checkStrictly: true,
children: 'Child',
}"
:clearable=
"true"
collapse-tags
style=
"width: 200px; margin-left: 16px"
>
<
template
#default
="{
data
}"
>
<span>
{{
data
.
name
}}
</span>
</
template
>
</el-cascader>
<el-input
placeholder=
"请输入关键词"
style=
"width: 200px; margin-left: 16px"
:prefix-icon=
"Search"
/>
</div>
<div
class=
"right"
>
<el-button
type=
"primary"
@
click=
"
cancelCache
"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"c
onfirmCache
"
>
重置
</el-button>
<el-button
type=
"primary"
@
click=
"
searchUsers
"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"c
learAction
"
>
重置
</el-button>
</div>
</div>
<div
class=
"table_content"
>
<bg-table
ref=
"bgTable"
:headers=
"detailHeaders"
:rows=
"tableRows"
height=
"430"
:stripe=
"true"
>
<
template
v-slot:ability_name=
"{ row }"
>
<span
@
click=
"goDetail(row)"
class=
"can_click_text"
>
{{
row
.
ability_name
}}
<span
v-if=
"row.include_mock_service"
class=
"mock_tip"
>
mock
</span>
</span>
</
template
>
<
template
v-slot:ability_state=
"{ row }"
>
<span
class=
"circle"
:class=
"'bgc_' + row.ability_state"
></span>
{{
[
"
待上架
"
,
"
已上架
"
,
"
已下架
"
,
"
上架中
"
,
"
下架中
"
][
row
.
ability_state
]
}}
</
template
>
<
template
v-slot:action=
"{ row }"
>
<bg-table-btns2
:limit=
"3"
:key=
"row.id"
>
<bg-table-btn
@
click=
"approve(row)"
>
审批
</bg-table-btn>
<bg-table-btn
@
click=
"approveDetail(row)"
>
审批详情
</bg-table-btn>
</bg-table-btns2>
<bg-table
ref=
"bgTable"
:headers=
"userHeaders"
:rows=
"userTableRows"
height=
"430"
:stripe=
"true"
>
<
template
v-slot:isAdmin=
"{ row }"
>
<span>
{{
[
""
,
"
业务系统用户
"
,
"
组织管理员
"
,
"
平台用户
"
][
row
.
isAdmin
]
}}
</span>
</
template
>
</bg-table>
<bg-pagination
:page=
"
f
ilter.page"
:size=
"
filter.size
"
:total=
"
t
ableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
:page=
"
userF
ilter.page"
:size=
"
userFilter.limit
"
:total=
"
userT
ableTotal"
@
change-page=
"change
User
Page"
@
change-size=
"change
User
Size"
>
</bg-pagination>
</div>
</div>
</el-dialog>
<el-dialog
class=
"dialog_box"
title=
"提示"
v-model=
"cacheDialog"
width=
"400px"
>
<div
style=
"font-size: 16px; color: #404a62"
>
你有未提交的服务,是否继续编辑该服务?
</div>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"cancelCache"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"confirmCache"
>
确 定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
reactive
,
toRefs
,
computed
,
onBeforeMount
}
from
"
vue
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
store
from
"
@/store
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
{
dateStringTransform
}
from
"
@/services/helper.js
"
;
const
router
=
useRouter
();
const
state
=
reactive
({
filter
:
{
state
:
""
,
keyword
:
""
,
search
:
""
,
page
:
1
,
size
:
10
,
abilityType
:
0
,
limit
:
10
,
time
:
[],
},
stateOptions
:
[
{
name
:
"
全部
"
,
value
:
""
,
},
{
name
:
"
已上架
"
,
value
:
"
1
"
,
},
{
name
:
"
已下架
"
,
value
:
"
2
"
,
},
{
name
:
"
上架中
"
,
value
:
"
3
"
,
},
{
name
:
"
下架中
"
,
value
:
"
4
"
,
},
{
name
:
"
待上架
"
,
value
:
"
0
"
,
},
],
headers
:
[
{
label
:
"
规则名称
"
,
prop
:
"
ability_name
"
,
// minWidth: 280,
prop
:
"
rule_name
"
,
},
{
label
:
"
规则类型
"
,
prop
:
"
synopsis
"
,
// minWidth: 360,
prop
:
"
rule_type
"
,
},
{
label
:
"
用户数量
"
,
prop
:
"
created_time
"
,
// width: 200,
prop
:
"
num_user
"
,
},
{
label
:
"
规则
"
,
prop
:
"
ability_state
"
,
// width: 120,
prop
:
"
rule_detail
"
,
},
{
label
:
"
是否启用
"
,
prop
:
"
start_use
"
,
// width: 120,
prop
:
"
state
"
,
},
{
label
:
"
修改时间
"
,
prop
:
"
ability_stat
e
"
,
prop
:
"
updated_tim
e
"
,
width
:
240
,
},
{
...
...
@@ -213,84 +180,100 @@ const state = reactive({
fixed
:
"
right
"
,
},
],
detailHeaders
:
[
tableRows
:
[],
tableTotal
:
0
,
actionRow
:
{},
dialogDetail
:
false
,
userFilter
:
{
page
:
1
,
limit
:
10
,
search
:
""
,
isAdmin
:
""
,
organizationId
:
""
,
disp
:
0
,
},
userTypeList
:
[
{
name
:
"
全部类型
"
,
value
:
""
,
},
{
name
:
"
业务系统用户
"
,
value
:
1
,
},
{
name
:
"
组织管理员
"
,
value
:
2
,
},
{
name
:
"
平台用户
"
,
value
:
3
,
},
],
orgList
:
[],
userHeaders
:
[
{
label
:
"
账号
"
,
prop
:
"
ability_name
"
,
// minWidth: 280,
prop
:
"
systemAccount
"
,
},
{
label
:
"
类型
"
,
prop
:
"
synopsis
"
,
// minWidth: 360,
prop
:
"
isAdmin
"
,
},
{
label
:
"
用户手机号
"
,
prop
:
"
created_time
"
,
// width: 200,
prop
:
"
phone
"
,
},
{
label
:
"
所属组织
"
,
prop
:
"
ability_state
"
,
// width: 120,
prop
:
"
name
"
,
},
],
tableRows
:
[],
tableTotal
:
0
,
actionRow
:
{},
dialogDetail
:
false
,
cacheDialog
:
false
,
userTableRows
:
[],
userTableTotal
:
0
,
});
const
{
filter
,
stateOptions
,
headers
,
detailHeaders
,
tableRows
,
tableTotal
,
dialogDetail
,
cacheDialog
}
=
toRefs
(
state
);
// 认证方案未确定,暂时使用假数据registerValid,后续更改
const
registerValid
=
computed
(()
=>
{
return
store
.
state
.
registerValid
;
});
//新增
const
addRule
=
()
=>
{
router
.
push
(
"
/develop/menu/add
"
);
};
//批量删除
const
deleteBatch
=
()
=>
{};
//清空
const
cleanSelected
=
()
=>
{};
const
cancelCache
=
()
=>
{
axios
.
get
(
`/apaas/service/v5/ability/clear/cach?abilityType=0`
)
.
then
((
res
)
=>
{
const
getOrgList
=
()
=>
{
axios
.
get
(
`/apaas/system/v5/org/tree`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
cacheDialog
=
false
;
router
.
push
(
"
/ability-register/add
"
);
state
.
orgList
=
res
.
data
.
data
||
[];
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
})
.
catch
((
err
)
=>
{
router
.
push
(
"
/ability-register/add
"
);
});
};
// 取消按钮,清空缓存跳转注册页
const
confirmCache
=
()
=>
{
state
.
cacheDialog
=
false
;
router
.
push
(
"
/ability-register/add
"
);
};
// 确定按钮,直接跳转注册页
};
// 获取组织
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
keyword
=
val
;
state
.
filter
.
search
=
val
;
changePage
(
1
);
};
};
// 关键字
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
};
// 改变页码
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
limit
=
size
;
changePage
(
1
);
};
// 改变每页条数
const
filterAction
=
()
=>
{
changePage
(
1
);
};
// 高级搜索中查询
const
filterClear
=
()
=>
{
state
.
filter
=
{
search
:
""
,
page
:
1
,
limit
:
10
,
time
:
[],
};
changePage
(
1
);
};
// 高级搜索中重置
const
getTableRows
=
()
=>
{
let
params
=
{
...
state
.
filter
};
params
.
registerStartTime
=
params
.
time
?
params
.
time
[
0
]
||
""
:
""
;
params
.
registerEndTime
=
params
.
time
?
params
.
time
[
1
]
||
""
:
""
;
params
.
updatedTimeFrom
=
params
.
time
?
params
.
time
[
0
]
||
""
:
""
;
params
.
updatedTimeTo
=
params
.
time
?
params
.
time
[
1
]
||
""
:
""
;
delete
params
.
time
;
axios
.
get
(
`/apaas/s
ervice/v5/ability/list
`
,
{
.
get
(
`/apaas/s
ystem/v5/accessRule/listAccessRule
`
,
{
params
,
})
.
then
((
res
)
=>
{
...
...
@@ -301,45 +284,99 @@ const getTableRows = () => {
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
filterAction
=
()
=>
{
changePage
(
1
);
};
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
size
=
size
;
};
// 获取表格数据
const
addRule
=
()
=>
{
// 新增规则跳转
};
//新增
const
deleteBatch
=
()
=>
{};
//批量删除
const
cleanSelected
=
()
=>
{};
//清空
const
stateChange
=
(
row
)
=>
{
axios
.
put
(
`/apaas/system/v5/accessRule/updateState?id=
${
row
.
id
}
&state=
${
row
.
state
}
`
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
);
changePage
(
1
);
};
const
filterClear
=
()
=>
{
state
.
filter
=
{
state
:
""
,
keyword
:
""
,
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
row
.
state
=
row
.
state
==
0
?
1
:
0
;
}
});
};
// 改变规则状态
const
openUserDialog
=
(
row
)
=>
{
state
.
dialogDetail
=
true
;
state
.
actionRow
=
row
;
clearAction
();
};
// 打开用户弹窗
const
searchUsers
=
()
=>
{
changeUserPage
(
1
);
};
// 用户弹窗查询
const
clearAction
=
()
=>
{
state
.
userFilter
=
{
page
:
1
,
size
:
10
,
abilityType
:
0
,
time
:
[],
limit
:
10
,
search
:
""
,
isAdmin
:
""
,
organizationId
:
""
,
disp
:
0
,
};
changePage
(
1
);
changeUserPage
(
1
);
};
// 用户弹窗重置
const
changeUserPage
=
(
page
)
=>
{
state
.
userFilter
.
page
=
page
;
getUserTableRows
();
};
// 用户详情改变分页
const
changeUserSize
=
(
size
)
=>
{
state
.
userFilter
.
limit
=
size
;
changeUserPage
(
1
);
};
//编辑
const
getUserTableRows
=
()
=>
{
let
params
=
{
...
state
.
userFilter
,
id
:
state
.
actionRow
.
id
,
};
axios
.
get
(
`/apaas/system/v5/accessRule/listRuleUser`
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
userTableRows
=
res
.
data
.
data
||
[];
state
.
userTableTotal
=
res
.
data
.
total
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 用户详情弹窗数据
const
edit
=
(
row
)
=>
{
state
.
dialogDetail
=
true
;
//
state.dialogDetail = true;
// router.push(`/develop/account/add`);
};
//删除
const
deleteCurrent
=
(
row
)
=>
{
router
.
push
(
`/develop/account/detail`
);
};
};
//编辑
const
deleteCurrent
=
(
row
)
=>
{};
//删除
const
{
filter
,
headers
,
userHeaders
,
tableRows
,
tableTotal
,
dialogDetail
,
userTableRows
,
userTableTotal
,
userFilter
,
userTypeList
,
orgList
,
}
=
toRefs
(
state
);
const
goDetail
=
(
row
)
=>
{
router
.
push
({
path
:
"
/ability-manage/real-list/detail
"
,
query
:
{
id
:
row
.
id
,
},
});
};
onBeforeMount
(()
=>
{
getTableRows
();
getOrgList
();
});
</
script
>
...
...
@@ -410,51 +447,8 @@ onBeforeMount(() => {
padding
:
0
16px
;
.el-table
{
flex
:
1
;
.circle
{
display
:
inline-block
;
width
:
6px
;
height
:
6px
;
border-radius
:
3px
;
margin-right
:
8px
;
transform
:
translateY
(
-2px
);
}
.bgc_1
{
background-color
:
#48ad97
;
}
.bgc_2
{
background-color
:
#d75138
;
}
.bgc_3
{
background-color
:
#3759be
;
}
.bgc_4
{
background-color
:
#ea7d19
;
}
.bgc_0
{
background-color
:
#9e9e9e
;
}
.mock_tip
{
display
:
inline-block
;
margin-left
:
4px
;
width
:
43px
;
height
:
20px
;
font-size
:
12px
;
color
:
#2b4695
;
text-align
:
center
;
background-color
:
#eff2fa
;
border-radius
:
3px
;
border
:
solid
1px
#b0bee8
;
}
:deep
()
td
{
padding
:
9px
0
!
important
;
}
:deep
()
.el-switch
{
height
:
20px
;
width
:
44px
;
.el-switch__core
{
height
:
20px
;
min-width
:
44px
;
}
.under_line
{
text-decoration
:
underline
;
}
}
}
...
...
src/page/main/config/preference/index.vue
View file @
b8c8a74f
...
...
@@ -159,7 +159,7 @@
<el-input
placeholder=
"请输入分钟数"
v-model.number=
"registerFormData.login_lock_time"
></el-input>
</el-form-item>
<span>
分钟
</span>
<el-button
type=
"primary"
>
一键还原受限
</el-button>
<el-button
type=
"primary"
@
click=
"restoreLimited"
>
一键还原受限
</el-button>
</div>
<bg-form-gap
title=
"注册配置"
></bg-form-gap>
<el-form-item
label=
"允许注册"
prop=
"register_config_state"
>
...
...
@@ -174,6 +174,19 @@
</div>
</div>
</div>
<el-dialog
class=
"dialog_box"
title=
"提示"
v-model=
"restoreDialog"
width=
"420px"
>
<div>
该操作将还原所有锁定账号和输错次数,是否继续?
</div>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"restoreDialog = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"confirm"
>
确 定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
...
...
@@ -295,8 +308,7 @@ const state = reactive({
},
//选中项索引
activeIndex
:
1
,
//首选项配置
preferenceConfig
:
{},
restoreDialog
:
false
,
});
const
{
authorizeFormData
,
...
...
@@ -306,7 +318,7 @@ const {
registerFormData
,
registerRules
,
activeIndex
,
preferenceConfi
g
,
restoreDialo
g
,
}
=
toRefs
(
state
);
onBeforeMount
(()
=>
{
getPreferenceConfig
();
...
...
@@ -329,7 +341,6 @@ const getPreferenceConfig = () => {
Object
.
keys
(
state
.
registerFormData
).
forEach
((
item
)
=>
{
state
.
registerFormData
[
item
]
=
data
[
item
];
});
state
.
preferenceConfig
=
res
.
data
.
data
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
...
...
@@ -378,6 +389,7 @@ const save = () => {
});
}
};
// 请求接口发送消息
const
postData
=
(
url
,
params
)
=>
{
axios
.
post
(
url
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
...
...
@@ -388,6 +400,22 @@ const postData = (url, params) => {
}
});
};
// 一键还原受限
const
restoreLimited
=
()
=>
{
state
.
restoreDialog
=
true
}
const
confirm
=
()
=>
{
axios
.
post
(
`/apaas/system/v5/sysOptions/reStartConfig`
).
then
(
res
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
res
.
data
.
msg
)
state
.
restoreDialog
=
false
}
else
{
ElMessage
.
error
(
res
.
data
.
data
)
}
})
}
</
script
>
<
style
lang=
"scss"
scoped
>
...
...
src/page/main/home-config/recommend/edit/index.vue
View file @
b8c8a74f
...
...
@@ -642,12 +642,12 @@ const {
</
style
>
<
style
>
.select_dialog
{
margin-top
:
8
0px
;
margin-top
:
8
vh
;
}
.
el-
dialog
.el-dialog__body
{
.
select_
dialog
.el-dialog__body
{
padding
:
0
;
}
.
el-
dialog
.el-dialog__footer
{
.
select_
dialog
.el-dialog__footer
{
padding
:
16px
;
}
</
style
>
src/page/main/home-config/recommend/index.vue
View file @
b8c8a74f
<!--
banner
管理 -->
<!--
推荐
管理 -->
<
template
>
<div
class=
"detail_container"
>
<bg-breadcrumb></bg-breadcrumb>
...
...
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