Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
易企天创
zentaoatf
提交
b96165eb
Z
zentaoatf
项目概览
易企天创
/
zentaoatf
12 个月 前同步成功
通知
11
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
3
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
Z
zentaoatf
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
3
Issue
3
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
b96165eb
编写于
2月 23, 2022
作者:
aaronchen2k2k
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
update ui
上级
802f2c7a
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
310 addition
and
34 deletion
+310
-34
ui/package.json
ui/package.json
+1
-0
ui/src/views/exec/exec/case.vue
ui/src/views/exec/exec/case.vue
+1
-2
ui/src/views/exec/exec/module.vue
ui/src/views/exec/exec/module.vue
+77
-8
ui/src/views/exec/exec/suite.vue
ui/src/views/exec/exec/suite.vue
+77
-8
ui/src/views/exec/exec/task.vue
ui/src/views/exec/exec/task.vue
+77
-8
ui/src/views/exec/exec/unit.vue
ui/src/views/exec/exec/unit.vue
+77
-8
未找到文件。
ui/package.json
浏览文件 @
b96165eb
...
...
@@ -11,6 +11,7 @@
"svgo"
:
"svgo -f src/assets/iconsvg --config=src/assets/iconsvg/svgo.yml"
},
"dependencies"
:
{
"@highlightjs/vue-plugin"
:
"^2.1.0"
,
"@toast-ui/editor"
:
"^2.5.3"
,
"ant-design-vue"
:
"^2.2.8"
,
"axios"
:
"^0.21.4"
,
...
...
ui/src/views/exec/exec/case.vue
浏览文件 @
b96165eb
...
...
@@ -236,7 +236,6 @@ export default defineComponent({
proxy
.
$sub
(
WsEventName
,
(
data
)
=>
{
console
.
log
(
data
[
0
].
msg
);
const
jsn
=
JSON
.
parse
(
data
[
0
].
msg
)
as
WsMsg
console
.
log
(
jsn
);
if
(
jsn
.
conn
)
{
// ws connection status updated
wsStatus
.
value
=
jsn
.
conn
...
...
@@ -327,11 +326,11 @@ export default defineComponent({
selectedKeys
,
checkedKeys
,
hideWsStatus
,
exec
,
stop
,
isRunning
,
back
,
hideWsStatus
,
}
}
...
...
ui/src/views/exec/exec/module.vue
浏览文件 @
b96165eb
...
...
@@ -44,7 +44,18 @@
<div
id=
"resize"
></div>
<div
id=
"content"
>
<div
id=
"logs"
class=
"logs"
>
<div
v-if=
"wsStatus === 'success'"
class=
"ws-status"
:class=
"wsStatus"
>
<icon-svg
type=
"pass-outline"
/>
<span
class=
"text"
>
{{t('ws_conn_success')}}
</span>
<span
@
click=
"hideWsStatus"
class=
"icon-close"
><icon-svg
type=
"close"
/></span>
</div>
<div
v-if=
"wsStatus === 'fail'"
class=
"ws-status"
:class=
"wsStatus"
>
<icon-svg
type=
"fail-outline"
/>
<span
class=
"text"
>
{{t('ws_conn_success')}}
</span>
<span
@
click=
"hideWsStatus"
class=
"icon-close"
><icon-svg
type=
"close"
/></span>
</div>
<div
id=
"logs"
class=
"logs"
:class=
"{ 'with-status': wsStatus }"
>
<span
v-html=
"wsMsg.out"
></span>
</div>
</div>
...
...
@@ -72,6 +83,7 @@ import {resizeWidth, scroll} from "@/utils/dom";
import
{
genExecInfo
}
from
"
@/views/exec/service
"
;
import
throttle
from
"
lodash.debounce
"
;
import
{
useI18n
}
from
"
vue-i18n
"
;
import
IconSvg
from
"
@/components/IconSvg/index
"
;
interface
ExecCasePageSetupData
{
t
:
(
key
:
string
|
number
)
=>
string
;
...
...
@@ -79,9 +91,12 @@ interface ExecCasePageSetupData {
seq
:
string
wsMsg
:
any
,
wsStatus
:
Ref
<
string
>
,
exec
:
(
keys
)
=>
void
;
stop
:
(
keys
)
=>
void
;
isRunning
:
Ref
<
string
>
;
hideWsStatus
:
()
=>
void
;
back
:
()
=>
void
;
labelCol
:
any
...
...
@@ -98,6 +113,7 @@ interface ExecCasePageSetupData {
export
default
defineComponent
({
name
:
'
ExecutionSuitePage
'
,
components
:
{
IconSvg
},
setup
():
ExecCasePageSetupData
{
const
{
t
}
=
useI18n
();
...
...
@@ -120,12 +136,12 @@ export default defineComponent({
const
products
=
computed
<
any
[]
>
(()
=>
store
.
state
.
zentao
.
products
);
const
modules
=
computed
<
any
[]
>
(()
=>
store
.
state
.
zentao
.
modules
);
const
fetchProducts
=
throttle
(
():
void
=>
{
const
fetchProducts
=
():
void
=>
{
store
.
dispatch
(
'
zentao/fetchProducts
'
).
catch
((
error
)
=>
{
if
(
error
.
response
.
data
.
code
===
2000
)
router
.
push
(
`/config`
)
})
}
,
600
)
fetchProducts
()
}
//
fetchProducts()
watch
(
currConfig
,
()
=>
{
fetchProducts
()
})
...
...
@@ -168,12 +184,18 @@ export default defineComponent({
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
WebSocket
.
init
(
proxy
)
let
wsStatus
=
ref
(
''
)
let
i
=
1
if
(
init
)
{
proxy
.
$sub
(
WsEventName
,
(
data
)
=>
{
console
.
log
(
data
[
0
].
msg
);
const
jsn
=
JSON
.
parse
(
data
[
0
].
msg
)
if
(
jsn
.
conn
)
{
// ws connection status updated
wsStatus
.
value
=
jsn
.
conn
return
}
if
(
'
isRunning
'
in
jsn
)
{
isRunning
.
value
=
jsn
.
isRunning
}
...
...
@@ -184,6 +206,9 @@ export default defineComponent({
});
init
=
false
;
}
const
hideWsStatus
=
():
void
=>
{
wsStatus
.
value
=
''
}
onMounted
(()
=>
{
console
.
log
(
'
onMounted
'
)
...
...
@@ -235,6 +260,7 @@ export default defineComponent({
model
,
seq
,
wsMsg
,
wsStatus
,
labelCol
:
{
span
:
6
},
wrapperCol
:
{
span
:
16
},
...
...
@@ -252,6 +278,7 @@ export default defineComponent({
isRunning
,
back
,
hideWsStatus
,
}
}
...
...
@@ -287,15 +314,57 @@ export default defineComponent({
#content {
flex: 1;
height: 100%;
padding: 16px;
overflow: auto;
padding: 0px;
.ws-status {
padding-left: 8px;
height: 44px;
line-height: 44px;
color: #333333;
&.success {
background-color: #DAF7E9;
svg {
color: #DAF7E9;
}
}
&.error {
background-color: #FFD6D0;
svg {
color: #FFD6D0;
}
}
.text {
display: inline-block;
margin-left: 5px;
}
.icon-close {
position: absolute;
padding: 5px;
line-height: 34px;
right: 15px;
cursor: pointer;
svg {
font-size: 8px;
color: #333333;
}
}
}
#logs {
margin: 0;
padding: 0;
height: calc(100% - 10px);
padding: 10px;
width: 100%;
overflow-y: auto;
white-space: pre-wrap;
word-wrap: break-word;
font-family:monospace;
height: 100%;
&.with-status {
height: calc(100% - 45px);
}
}
}
}
...
...
ui/src/views/exec/exec/suite.vue
浏览文件 @
b96165eb
...
...
@@ -44,7 +44,18 @@
<div
id=
"resize"
></div>
<div
id=
"content"
>
<div
id=
"logs"
class=
"logs"
>
<div
v-if=
"wsStatus === 'success'"
class=
"ws-status"
:class=
"wsStatus"
>
<icon-svg
type=
"pass-outline"
/>
<span
class=
"text"
>
{{t('ws_conn_success')}}
</span>
<span
@
click=
"hideWsStatus"
class=
"icon-close"
><icon-svg
type=
"close"
/></span>
</div>
<div
v-if=
"wsStatus === 'fail'"
class=
"ws-status"
:class=
"wsStatus"
>
<icon-svg
type=
"fail-outline"
/>
<span
class=
"text"
>
{{t('ws_conn_success')}}
</span>
<span
@
click=
"hideWsStatus"
class=
"icon-close"
><icon-svg
type=
"close"
/></span>
</div>
<div
id=
"logs"
class=
"logs"
:class=
"{ 'with-status': wsStatus }"
>
<span
v-html=
"wsMsg.out"
></span>
</div>
</div>
...
...
@@ -72,6 +83,7 @@ import {resizeWidth, scroll} from "@/utils/dom";
import
{
genExecInfo
}
from
"
@/views/exec/service
"
;
import
throttle
from
"
lodash.debounce
"
;
import
{
useI18n
}
from
"
vue-i18n
"
;
import
IconSvg
from
"
@/components/IconSvg/index
"
;
interface
ExecSuitePageSetupData
{
t
:
(
key
:
string
|
number
)
=>
string
;
...
...
@@ -79,9 +91,12 @@ interface ExecSuitePageSetupData {
seq
:
string
wsMsg
:
any
,
wsStatus
:
Ref
<
string
>
,
exec
:
(
keys
)
=>
void
;
stop
:
(
keys
)
=>
void
;
isRunning
:
Ref
<
string
>
;
hideWsStatus
:
()
=>
void
;
back
:
()
=>
void
;
labelCol
:
any
...
...
@@ -98,6 +113,7 @@ interface ExecSuitePageSetupData {
export
default
defineComponent
({
name
:
'
ExecutionSuitePage
'
,
components
:
{
IconSvg
},
setup
():
ExecSuitePageSetupData
{
const
{
t
}
=
useI18n
();
...
...
@@ -120,12 +136,12 @@ export default defineComponent({
const
products
=
computed
<
any
[]
>
(()
=>
store
.
state
.
zentao
.
products
);
const
suites
=
computed
<
any
[]
>
(()
=>
store
.
state
.
zentao
.
suites
);
const
fetchProducts
=
throttle
(
():
void
=>
{
const
fetchProducts
=
():
void
=>
{
store
.
dispatch
(
'
zentao/fetchProducts
'
).
catch
((
error
)
=>
{
if
(
error
.
response
.
data
.
code
===
2000
)
router
.
push
(
`/config`
)
})
}
,
600
)
fetchProducts
()
}
//
fetchProducts()
watch
(
currConfig
,
()
=>
{
fetchProducts
()
})
...
...
@@ -168,12 +184,18 @@ export default defineComponent({
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
WebSocket
.
init
(
proxy
)
let
wsStatus
=
ref
(
''
)
let
i
=
1
if
(
init
)
{
proxy
.
$sub
(
WsEventName
,
(
data
)
=>
{
console
.
log
(
data
[
0
].
msg
);
const
jsn
=
JSON
.
parse
(
data
[
0
].
msg
)
if
(
jsn
.
conn
)
{
// ws connection status updated
wsStatus
.
value
=
jsn
.
conn
return
}
if
(
'
isRunning
'
in
jsn
)
{
isRunning
.
value
=
jsn
.
isRunning
}
...
...
@@ -184,6 +206,9 @@ export default defineComponent({
});
init
=
false
;
}
const
hideWsStatus
=
():
void
=>
{
wsStatus
.
value
=
''
}
onMounted
(()
=>
{
console
.
log
(
'
onMounted
'
)
...
...
@@ -235,6 +260,7 @@ export default defineComponent({
model
,
seq
,
wsMsg
,
wsStatus
,
labelCol
:
{
span
:
6
},
wrapperCol
:
{
span
:
16
},
...
...
@@ -252,6 +278,7 @@ export default defineComponent({
isRunning
,
back
,
hideWsStatus
,
}
}
...
...
@@ -287,15 +314,57 @@ export default defineComponent({
#content {
flex: 1;
height: 100%;
padding: 16px;
overflow: auto;
padding: 0px;
.ws-status {
padding-left: 8px;
height: 44px;
line-height: 44px;
color: #333333;
&.success {
background-color: #DAF7E9;
svg {
color: #DAF7E9;
}
}
&.error {
background-color: #FFD6D0;
svg {
color: #FFD6D0;
}
}
.text {
display: inline-block;
margin-left: 5px;
}
.icon-close {
position: absolute;
padding: 5px;
line-height: 34px;
right: 15px;
cursor: pointer;
svg {
font-size: 8px;
color: #333333;
}
}
}
#logs {
margin: 0;
padding: 0;
height: calc(100% - 0px);
padding: 10px;
width: 100%;
overflow-y: auto;
white-space: pre-wrap;
word-wrap: break-word;
font-family:monospace;
height: 100%;
&.with-status {
height: calc(100% - 45px);
}
}
}
}
...
...
ui/src/views/exec/exec/task.vue
浏览文件 @
b96165eb
...
...
@@ -44,7 +44,18 @@
<div
id=
"resize"
></div>
<div
id=
"content"
>
<div
id=
"logs"
class=
"logs"
>
<div
v-if=
"wsStatus === 'success'"
class=
"ws-status"
:class=
"wsStatus"
>
<icon-svg
type=
"pass-outline"
/>
<span
class=
"text"
>
{{t('ws_conn_success')}}
</span>
<span
@
click=
"hideWsStatus"
class=
"icon-close"
><icon-svg
type=
"close"
/></span>
</div>
<div
v-if=
"wsStatus === 'fail'"
class=
"ws-status"
:class=
"wsStatus"
>
<icon-svg
type=
"fail-outline"
/>
<span
class=
"text"
>
{{t('ws_conn_success')}}
</span>
<span
@
click=
"hideWsStatus"
class=
"icon-close"
><icon-svg
type=
"close"
/></span>
</div>
<div
id=
"logs"
class=
"logs"
:class=
"{ 'with-status': wsStatus }"
>
<span
v-html=
"wsMsg.out"
></span>
</div>
</div>
...
...
@@ -71,6 +82,7 @@ import {resizeWidth, scroll} from "@/utils/dom";
import
{
genExecInfo
}
from
"
@/views/exec/service
"
;
import
throttle
from
"
lodash.debounce
"
;
import
{
useI18n
}
from
"
vue-i18n
"
;
import
IconSvg
from
"
@/components/IconSvg/index
"
;
interface
ExecTaskPageSetupData
{
t
:
(
key
:
string
|
number
)
=>
string
;
...
...
@@ -78,9 +90,12 @@ interface ExecTaskPageSetupData {
seq
:
string
wsMsg
:
any
,
wsStatus
:
Ref
<
string
>
,
exec
:
(
keys
)
=>
void
;
stop
:
(
keys
)
=>
void
;
isRunning
:
Ref
<
string
>
;
hideWsStatus
:
()
=>
void
;
back
:
()
=>
void
;
labelCol
:
any
...
...
@@ -97,6 +112,7 @@ interface ExecTaskPageSetupData {
export
default
defineComponent
({
name
:
'
ExecutionTaskPage
'
,
components
:
{
IconSvg
},
setup
():
ExecTaskPageSetupData
{
const
{
t
}
=
useI18n
();
...
...
@@ -119,12 +135,12 @@ export default defineComponent({
const
products
=
computed
<
any
[]
>
(()
=>
store
.
state
.
zentao
.
products
);
const
tasks
=
computed
<
any
[]
>
(()
=>
store
.
state
.
zentao
.
tasks
);
const
fetchProducts
=
throttle
(
():
void
=>
{
const
fetchProducts
=
():
void
=>
{
store
.
dispatch
(
'
zentao/fetchProducts
'
).
catch
((
error
)
=>
{
if
(
error
.
response
.
data
.
code
===
2000
)
router
.
push
(
`/config`
)
})
}
,
600
)
fetchProducts
()
}
//
fetchProducts()
watch
(
currConfig
,
()
=>
{
fetchProducts
()
})
...
...
@@ -167,12 +183,18 @@ export default defineComponent({
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
WebSocket
.
init
(
proxy
)
let
wsStatus
=
ref
(
''
)
let
i
=
1
if
(
init
)
{
proxy
.
$sub
(
WsEventName
,
(
data
)
=>
{
console
.
log
(
data
[
0
].
msg
);
const
jsn
=
JSON
.
parse
(
data
[
0
].
msg
)
if
(
jsn
.
conn
)
{
// ws connection status updated
wsStatus
.
value
=
jsn
.
conn
return
}
if
(
'
isRunning
'
in
jsn
)
{
isRunning
.
value
=
jsn
.
isRunning
}
...
...
@@ -183,6 +205,9 @@ export default defineComponent({
});
init
=
false
;
}
const
hideWsStatus
=
():
void
=>
{
wsStatus
.
value
=
''
}
onMounted
(()
=>
{
console
.
log
(
'
onMounted
'
)
...
...
@@ -234,6 +259,7 @@ export default defineComponent({
model
,
seq
,
wsMsg
,
wsStatus
,
labelCol
:
{
span
:
6
},
wrapperCol
:
{
span
:
16
},
...
...
@@ -251,6 +277,7 @@ export default defineComponent({
isRunning
,
back
,
hideWsStatus
,
}
}
...
...
@@ -286,15 +313,57 @@ export default defineComponent({
#content {
flex: 1;
height: 100%;
padding: 16px;
overflow: auto;
padding: 0px;
.ws-status {
padding-left: 8px;
height: 44px;
line-height: 44px;
color: #333333;
&.success {
background-color: #DAF7E9;
svg {
color: #DAF7E9;
}
}
&.error {
background-color: #FFD6D0;
svg {
color: #FFD6D0;
}
}
.text {
display: inline-block;
margin-left: 5px;
}
.icon-close {
position: absolute;
padding: 5px;
line-height: 34px;
right: 15px;
cursor: pointer;
svg {
font-size: 8px;
color: #333333;
}
}
}
#logs {
margin: 0;
padding: 0;
height: calc(100% - 0px);
padding: 10px;
width: 100%;
overflow-y: auto;
white-space: pre-wrap;
word-wrap: break-word;
font-family:monospace;
height: 100%;
&.with-status {
height: calc(100% - 45px);
}
}
}
}
...
...
ui/src/views/exec/exec/unit.vue
浏览文件 @
b96165eb
...
...
@@ -58,7 +58,18 @@
<div
id=
"resize"
></div>
<div
id=
"content"
>
<div
id=
"logs"
class=
"logs"
>
<div
v-if=
"wsStatus === 'success'"
class=
"ws-status"
:class=
"wsStatus"
>
<icon-svg
type=
"pass-outline"
/>
<span
class=
"text"
>
{{t('ws_conn_success')}}
</span>
<span
@
click=
"hideWsStatus"
class=
"icon-close"
><icon-svg
type=
"close"
/></span>
</div>
<div
v-if=
"wsStatus === 'fail'"
class=
"ws-status"
:class=
"wsStatus"
>
<icon-svg
type=
"fail-outline"
/>
<span
class=
"text"
>
{{t('ws_conn_success')}}
</span>
<span
@
click=
"hideWsStatus"
class=
"icon-close"
><icon-svg
type=
"close"
/></span>
</div>
<div
id=
"logs"
class=
"logs"
:class=
"{ 'with-status': wsStatus }"
>
<span
v-html=
"wsMsg.out"
></span>
</div>
</div>
...
...
@@ -87,6 +98,7 @@ import {genExecInfo} from "@/views/exec/service";
import
{
getUnitTestFrameworks
,
getUnitTestTools
}
from
"
@/utils/testing
"
;
import
throttle
from
"
lodash.debounce
"
;
import
{
useI18n
}
from
"
vue-i18n
"
;
import
IconSvg
from
"
@/components/IconSvg/index
"
;
interface
ExecCasePageSetupData
{
t
:
(
key
:
string
|
number
)
=>
string
;
...
...
@@ -99,9 +111,12 @@ interface ExecCasePageSetupData {
unitTestTools
:
Ref
wsMsg
:
any
,
wsStatus
:
Ref
<
string
>
,
exec
:
(
keys
)
=>
void
;
stop
:
(
keys
)
=>
void
;
back
:
()
=>
void
;
hideWsStatus
:
()
=>
void
;
isRunning
:
Ref
<
string
>
;
rules
:
any
...
...
@@ -113,6 +128,7 @@ interface ExecCasePageSetupData {
export
default
defineComponent
({
name
:
'
ExecutionSuitePage
'
,
components
:
{
IconSvg
},
setup
():
ExecCasePageSetupData
{
const
{
t
}
=
useI18n
();
...
...
@@ -128,12 +144,12 @@ export default defineComponent({
const
store
=
useStore
<
{
zentao
:
ZentaoData
}
>
();
const
products
=
computed
<
any
[]
>
(()
=>
store
.
state
.
zentao
.
products
);
const
fetchProducts
=
throttle
(
():
void
=>
{
const
fetchProducts
=
():
void
=>
{
store
.
dispatch
(
'
zentao/fetchProducts
'
).
catch
((
error
)
=>
{
if
(
error
.
response
.
data
.
code
===
2000
)
router
.
push
(
`/config`
)
})
}
,
600
)
fetchProducts
()
}
//
fetchProducts()
watch
(
currConfig
,
()
=>
{
fetchProducts
()
})
...
...
@@ -150,12 +166,18 @@ export default defineComponent({
const
{
proxy
}
=
getCurrentInstance
()
as
any
;
WebSocket
.
init
(
proxy
)
let
wsStatus
=
ref
(
''
)
let
i
=
1
if
(
init
)
{
proxy
.
$sub
(
WsEventName
,
(
data
)
=>
{
console
.
log
(
data
[
0
].
msg
);
const
jsn
=
JSON
.
parse
(
data
[
0
].
msg
)
if
(
jsn
.
conn
)
{
// ws connection status updated
wsStatus
.
value
=
jsn
.
conn
return
}
if
(
'
isRunning
'
in
jsn
)
{
isRunning
.
value
=
jsn
.
isRunning
}
...
...
@@ -166,6 +188,9 @@ export default defineComponent({
});
init
=
false
;
}
const
hideWsStatus
=
():
void
=>
{
wsStatus
.
value
=
''
}
onMounted
(()
=>
{
console
.
log
(
'
onMounted
'
)
...
...
@@ -242,6 +267,7 @@ export default defineComponent({
unitTestFrameworks
,
unitTestTools
,
wsMsg
,
wsStatus
,
rules
,
validate
,
...
...
@@ -252,6 +278,7 @@ export default defineComponent({
exec
,
stop
,
back
,
hideWsStatus
,
}
}
...
...
@@ -287,15 +314,57 @@ export default defineComponent({
#content {
flex: 1;
height: 100%;
padding: 16px;
overflow: auto;
padding: 0px;
.ws-status {
padding-left: 8px;
height: 44px;
line-height: 44px;
color: #333333;
&.success {
background-color: #DAF7E9;
svg {
color: #DAF7E9;
}
}
&.error {
background-color: #FFD6D0;
svg {
color: #FFD6D0;
}
}
.text {
display: inline-block;
margin-left: 5px;
}
.icon-close {
position: absolute;
padding: 5px;
line-height: 34px;
right: 15px;
cursor: pointer;
svg {
font-size: 8px;
color: #333333;
}
}
}
#logs {
margin: 0;
padding: 0;
height: calc(100% - 0px);
padding: 10px;
width: 100%;
overflow-y: auto;
white-space: pre-wrap;
word-wrap: break-word;
font-family:monospace;
height: 100%;
&.with-status {
height: calc(100% - 45px);
}
}
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录