Merge pull request #65 from jetlinks/dev-hub

style: 设备接入网关、网络组件以及详情样式微调
This commit is contained in:
胡彪 2023-03-21 10:23:30 +08:00 committed by GitHub
commit acae0936dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1180 additions and 1334 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="title" :style="style"> <div class="title" :style="style">
<span class="titleData">{{ data }}</span> <div class="title-content">{{ data }}</div>
<slot name="extra"></slot> <slot name="extra"></slot>
</div> </div>
</template> </template>
@ -22,27 +22,28 @@ const props = defineProps({
<style lang="less" scoped> <style lang="less" scoped>
.title { .title {
position: relative; display: flex;
align-items: center;
width: 100%; width: 100%;
margin-bottom: 10px; margin-bottom: 16px;
color: rgba(0, 0, 0, 0.8);
font-weight: 600; .title-content {
font-size: 16px; position: relative;
} padding-left: 10px;
.titleData { color: rgba(0, 0, 0, 0.8);
position: relative; font-weight: 600;
width: 100%; line-height: 1;
padding-left: 12px;
&::before { &::before {
position: absolute; position: absolute;
border-top-right-radius: 3px; top: 0;
border-bottom-right-radius: 3px; left: 0;
bottom: 0.5px; width: 4px;
left: 0; height: 100%;
width: 4px; background-color: @primary-color;
height: 80%; border-radius: 0 3px 3px 0;
background-color: @primary-color; content: ' ';
content: ''; }
} }
} }
</style> </style>

View File

@ -1,14 +1,19 @@
<template> <template>
<j-card <j-card
hoverable hoverable
:class="['card-render', checked === data.id ? 'checked' : '']" :class="[
'card-render',
'container',
checked === data.id ? 'checked' : '',
]"
@click="checkedChange(data.id)" @click="checkedChange(data.id)"
> >
<div class="title"> <div class="title">
<j-tooltip placement="topLeft" :title="data.name">{{ <Ellipsis style="width: calc(100% - 100px); margin-bottom: 24px">
data.name {{ data.name }}
}}</j-tooltip> </Ellipsis>
</div> </div>
<slot name="other"></slot> <slot name="other"></slot>
<div class="desc"> <div class="desc">
<j-tooltip placement="topLeft" :title="data.description">{{ <j-tooltip placement="topLeft" :title="data.description">{{
@ -46,16 +51,18 @@ const checkedChange = (id: string) => {
.card-render { .card-render {
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
background: url('/public/images/access.png') no-repeat; // background: url('/public/images/access.png') no-repeat;
background-size: 100% 100%; // background-size: 100% 100%;
height: 120px; height: 140px;
background: #fafafa;
border: 1px solid #e6e6e6;
.title { .title {
width: calc(100% - 88px); font-style: normal;
overflow: hidden;
font-weight: 800; font-weight: 800;
white-space: nowrap; font-size: 16px;
text-overflow: ellipsis; line-height: 22px;
color: rgba(0, 0, 0, 0.85);
opacity: 0.85;
} }
.desc { .desc {
@ -78,8 +85,7 @@ const checkedChange = (id: string) => {
width: 44px; width: 44px;
height: 44px; height: 44px;
color: #fff; color: #fff;
background-color: red; background-color: @primary-color;
background-color: #2f54eb;
transform: rotate(-45deg); transform: rotate(-45deg);
> div { > div {
@ -92,11 +98,16 @@ const checkedChange = (id: string) => {
} }
&.checked { &.checked {
position: relative; position: relative;
color: #2f54eb; color: @primary-color;
border-color: #2f54eb; border-color: @primary-color;
z-index: 0;
.checked-icon { .checked-icon {
display: block; display: block;
} }
} }
} }
.container {
background: url('/public/images/access-icon.png') no-repeat;
background-position: bottom right;
}
</style> </style>

View File

@ -1,91 +1,73 @@
<template> <template>
<div class="container"> <div v-if="type === 'channel'" class="card-last">
<div v-if="type === 'channel'" class="card-last"> <j-row :gutter="[24, 24]">
<j-row :gutter="[24, 24]"> <j-col :span="12">
<j-col :span="12"> <title-component data="基本信息" />
<title-component data="基本信息" /> <div>
<div> <j-form
<j-form :model="formState"
:model="formState" name="basic"
name="basic" autocomplete="off"
autocomplete="off" layout="vertical"
layout="vertical" @finish="onFinish"
@finish="onFinish" >
<j-form-item
label="名称"
name="name"
:rules="[
{
required: true,
message: '请输入名称',
trigger: 'blur',
},
{ max: 64, message: '最多可输入64个字符' },
]"
> >
<j-form-item <j-input
label="名称" placeholder="请输入名称"
name="name" v-model:value="formState.name"
:rules="[ />
{ </j-form-item>
required: true, <j-form-item label="说明" name="description">
message: '请输入名称', <j-textarea
trigger: 'blur', placeholder="请输入说明"
}, :rows="4"
{ max: 64, message: '最多可输入64个字符' }, v-model:value="formState.description"
]" show-count
:maxlength="200"
/>
</j-form-item>
<j-form-item>
<PermissionButton
v-if="view === 'false'"
type="primary"
html-type="submit"
:hasPermission="`link/AccessConfig:${
id === ':id' ? 'add' : 'update'
}`"
> >
<j-input 保存
placeholder="请输入名称" </PermissionButton>
v-model:value="formState.name" </j-form-item>
/> </j-form>
</j-form-item> </div>
<j-form-item label="说明" name="description"> </j-col>
<j-textarea <j-col :span="12">
placeholder="请输入说明" <div class="doc" style="height: 600px">
:rows="4" <TitleComponent data="配置概览" />
v-model:value="formState.description" <p>接入方式{{ provider.name }}</p>
show-count <p>
:maxlength="200" {{ provider.description }}
/> </p>
</j-form-item> <p>消息协议{{ provider.id }}</p>
<j-form-item> <TitleComponent data="设备接入指引" />
<PermissionButton <p>1配置{{ provider.name }}通道</p>
v-if="view === 'false'" <p>2创建{{ provider.name }}设备接入网关</p>
type="primary" <p>3创建产品并选中接入方式为{{ provider.name }}</p>
html-type="submit" <p>4添加设备单独为每一个设备进行数据点绑定</p>
:hasPermission="`link/AccessConfig:${ </div>
id === ':id' ? 'add' : 'update' </j-col>
}`" </j-row>
>
保存
</PermissionButton>
</j-form-item>
</j-form>
</div>
</j-col>
<j-col :span="12">
<div class="config-right">
<div class="config-right-item">
<title-component data="配置概览" />
<div class="config-right-item-context">
接入方式{{ provider.name }}
</div>
<div class="config-right-item-context">
{{ provider.description }}
</div>
<div class="config-right-item-context">
消息协议{{ provider.id }}
</div>
</div>
<div class="config-right-item">
<title-component data="设备接入指引" />
<div class="config-right-item-context">
1配置{{ provider.name }}通道
</div>
<div class="config-right-item-context">
2创建{{ provider.name }}设备接入网关
</div>
<div class="config-right-item-context">
3创建产品并选中接入方式为{{ provider.name }}
</div>
<div class="config-right-item-context">
4添加设备单独为每一个设备进行数据点绑定
</div>
</div>
</div>
</j-col>
</j-row>
</div>
</div> </div>
</template> </template>
@ -147,31 +129,9 @@ onMounted(() => {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.container {
margin: 20px;
}
.card-last { .card-last {
padding-right: 5px; padding-right: 5px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
.config-right {
padding: 20px;
.config-right-item {
margin-bottom: 10px;
.config-right-item-title {
width: 100%;
margin-bottom: 10px;
font-weight: 600;
}
.config-right-item-context {
margin: 5px 0;
color: rgba(0, 0, 0, 0.8);
}
}
}
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="container"> <div>
<j-steps class="steps-steps" :current="stepCurrent"> <j-steps class="steps-steps" :current="stepCurrent">
<j-step v-for="item in steps" :key="item" :title="item" /> <j-step v-for="item in steps" :key="item" :title="item" />
</j-steps> </j-steps>
@ -9,7 +9,7 @@
<AIcon type="InfoCircleOutlined" /> <AIcon type="InfoCircleOutlined" />
通过CTWing平台的HTTP推送服务进行数据接入 通过CTWing平台的HTTP推送服务进行数据接入
</div> </div>
<div style="margin-top: 15px"> <div style="margin-top: 42px">
<j-row :gutter="[24, 24]"> <j-row :gutter="[24, 24]">
<j-col :span="16"> <j-col :span="16">
<j-form <j-form
@ -86,7 +86,6 @@
/> />
</j-form-item> </j-form-item>
</j-col> </j-col>
<j-col :span="12"> </j-col>
</j-row> </j-row>
<j-row :gutter="[24, 24]"> <j-row :gutter="[24, 24]">
<j-col :span="24"> <j-col :span="24">
@ -116,7 +115,10 @@
</div> </div>
<div> <div>
2CTWing端配置产品/设备/分组级订阅订阅方URL地址请填写: 2CTWing端配置产品/设备/分组级订阅订阅方URL地址请填写:
<div style="word-wrap: break-word"> <div
class="url"
style="word-wrap: break-word"
>
{{ {{
`${origin}/api/ctwing/${randomString()}/notify` `${origin}/api/ctwing/${randomString()}/notify`
}} }}
@ -181,23 +183,19 @@
新增 新增
</PermissionButton> </PermissionButton>
</div> </div>
<j-scrollbar height="500"> <j-scrollbar height="480">
<j-row <j-row :gutter="[24, 24]" v-if="procotolList.length > 0">
:gutter="[24, 24]"
v-if="procotolList.length > 0"
style="margin-right: 10px"
>
<j-col <j-col
:span="8" :span="8"
v-for="item in procotolList" v-for="item in procotolList"
:key="item.id" :key="item.id"
> >
<access-card <AccessCard
@checkedChange="procotolChange" @checkedChange="procotolChange"
:checked="procotolCurrent" :checked="procotolCurrent"
:data="item" :data="item"
> >
</access-card> </AccessCard>
</j-col> </j-col>
</j-row> </j-row>
<j-empty v-else description="暂无数据" /> <j-empty v-else description="暂无数据" />
@ -207,79 +205,69 @@
<div v-if="current === 2" class="card-last"> <div v-if="current === 2" class="card-last">
<j-row :gutter="[24, 24]"> <j-row :gutter="[24, 24]">
<j-col :span="12"> <j-col :span="12">
<title-component data="基本信息" /> <TitleComponent data="基本信息" />
<div> <j-form
<j-form :model="formData"
:model="formData" name="basic"
name="basic" autocomplete="off"
autocomplete="off" layout="vertical"
layout="vertical" ref="formRef2"
ref="formRef2" >
<j-form-item
label="名称"
name="name"
:rules="[
{
required: true,
message: '请输入名称',
trigger: 'blur',
},
{ max: 64, message: '最多可输入64个字符' },
]"
> >
<j-form-item <j-input
label="名称" placeholder="请输入名称"
name="name" v-model:value="formData.name"
:rules="[ />
{ </j-form-item>
required: true, <j-form-item label="说明" name="description">
message: '请输入名称', <j-textarea
trigger: 'blur', placeholder="请输入说明"
}, :rows="4"
{ max: 64, message: '最多可输入64个字符' }, v-model:value="formData.description"
]" show-count
> :maxlength="200"
<j-input />
placeholder="请输入名称" </j-form-item>
v-model:value="formData.name" </j-form>
/>
</j-form-item>
<j-form-item label="说明" name="description">
<j-textarea
placeholder="请输入说明"
:rows="4"
v-model:value="formData.description"
show-count
:maxlength="200"
/>
</j-form-item>
</j-form>
</div>
</j-col> </j-col>
<j-col :span="12"> <j-col :span="12">
<div class="config-right"> <div class="doc" style="height: 606px">
<div class="config-right-item"> <TitleComponent data="配置概览" />
<title-component data="配置概览" /> <p>接入方式{{ provider.name }}</p>
<div class="config-right-item-context"> <p>
接入方式{{ provider.name }} {{ provider.description }}
</div> </p>
<div class="config-right-item-context"> <p>消息协议{{ procotolCurrent }}</p>
{{ provider.description }} <TitleComponent data="设备接入指引" />
</div> <p>
<div class="config-right-item-context"> 1创建类型为{{
消息协议{{ procotolCurrent }} props?.provider?.id === 'OneNet'
</div> ? 'OneNet'
</div> : 'CTWing'
<div class="config-right-item"> }}的设备接入网关
<title-component data="设备接入指引" /> </p>
<div class="config-right-item-context"> <p>
1创建类型为{{ 2创建产品并选中接入方式为
props?.provider?.id === 'OneNet' {{
? 'OneNet' props?.provider?.id === 'OneNet'
: 'CTWing' ? 'OneNet'
}}的设备接入网关 : 'CTWing,选中后需填写CTWing平台中的产品ID、Master-APIkey。'
</div> }}
<div class="config-right-item-context"> </p>
2创建产品并选中接入方式为 <p>
{{ 3添加设备为每一台设备设置唯一的IMEIIMSI码需与OneNet平台中填写的值一致若OneNet平台没有对应的设备将会通过OneNet平台提供的LWM2M协议自动创建
props?.provider?.id === 'OneNet' </p>
? 'OneNet'
: 'CTWing,选中后需填写CTWing平台中的产品ID、Master-APIkey。'
}}
</div>
<div class="config-right-item-context">
3添加设备为每一台设备设置唯一的IMEIIMSI码需与OneNet平台中填写的值一致若OneNet平台没有对应的设备将会通过OneNet平台提供的LWM2M协议自动创建
</div>
</div>
</div> </div>
</j-col> </j-col>
</j-row> </j-row>
@ -481,12 +469,8 @@ watch(
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.container {
margin: 20px;
}
.steps-content { .steps-content {
margin: 20px; margin-top: 20px;
} }
.steps-box { .steps-box {
min-height: 400px; min-height: 400px;
@ -501,7 +485,6 @@ watch(
.steps-action { .steps-action {
width: 100%; width: 100%;
margin-top: 24px; margin-top: 24px;
margin-left: 20px;
} }
.steps-action-save { .steps-action-save {
margin-left: 0; margin-left: 0;
@ -518,52 +501,4 @@ watch(
margin: 15px 0; margin: 15px 0;
justify-content: space-between; justify-content: space-between;
} }
.card-last {
padding-right: 5px;
overflow-y: auto;
overflow-x: hidden;
}
.config-right {
padding: 20px;
.config-right-item {
margin-bottom: 10px;
.config-right-item-title {
width: 100%;
margin-bottom: 10px;
font-weight: 600;
}
.config-right-item-context {
margin: 5px 0;
color: rgba(0, 0, 0, 0.8);
}
}
}
.doc {
height: 550px;
padding: 24px;
overflow-x: hidden;
overflow-y: auto;
color: rgba(#000, 0.8);
font-size: 14px;
background-color: #fafafa;
h1 {
margin: 16px 0;
color: rgba(#000, 0.85);
font-weight: bold;
font-size: 14px;
&:first-child {
margin-top: 0;
}
}
.image {
margin: 16px 0;
}
}
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="container"> <div>
<j-steps class="steps-steps" :current="stepCurrent"> <j-steps class="steps-steps" :current="stepCurrent">
<j-step v-for="item in steps" :key="item" :title="item" /> <j-step v-for="item in steps" :key="item" :title="item" />
</j-steps> </j-steps>
@ -9,7 +9,7 @@
<AIcon type="InfoCircleOutlined" /> <AIcon type="InfoCircleOutlined" />
通过OneNet平台的HTTP推送服务进行数据接入 通过OneNet平台的HTTP推送服务进行数据接入
</div> </div>
<div style="margin-top: 15px"> <div style="margin-top: 42px">
<j-row :gutter="[24, 24]"> <j-row :gutter="[24, 24]">
<j-col :span="16"> <j-col :span="16">
<j-form <j-form
@ -265,23 +265,19 @@
新增 新增
</PermissionButton> </PermissionButton>
</div> </div>
<j-scrollbar height="500"> <j-scrollbar height="480">
<j-row <j-row :gutter="[24, 24]" v-if="procotolList.length > 0">
:gutter="[24, 24]"
v-if="procotolList.length > 0"
style="margin-right: 10px"
>
<j-col <j-col
:span="8" :span="8"
v-for="item in procotolList" v-for="item in procotolList"
:key="item.id" :key="item.id"
> >
<access-card <AccessCard
@checkedChange="procotolChange" @checkedChange="procotolChange"
:checked="procotolCurrent" :checked="procotolCurrent"
:data="item" :data="item"
> >
</access-card> </AccessCard>
</j-col> </j-col>
</j-row> </j-row>
<j-empty v-else description="暂无数据" /> <j-empty v-else description="暂无数据" />
@ -330,40 +326,32 @@
</div> </div>
</j-col> </j-col>
<j-col :span="12"> <j-col :span="12">
<div class="config-right"> <div class="doc" style="height: 606px">
<div class="config-right-item"> <TitleComponent data="配置概览" />
<title-component data="配置概览" /> <p>接入方式{{ provider.name }}</p>
<div class="config-right-item-context"> <p>
接入方式{{ provider.name }} {{ provider.description }}
</div> </p>
<div class="config-right-item-context"> <p>消息协议{{ procotolCurrent }}</p>
{{ provider.description }} <TitleComponent data="设备接入指引" />
</div> <p>
<div class="config-right-item-context"> 1创建类型为{{
消息协议{{ procotolCurrent }} props?.provider?.id === 'OneNet'
</div> ? 'OneNet'
</div> : 'CTWing'
<div class="config-right-item"> }}的设备接入网关
<title-component data="设备接入指引" /> </p>
<div class="config-right-item-context"> <p>
1创建类型为{{ 2创建产品并选中接入方式为
props?.provider?.id === 'OneNet' {{
? 'OneNet' props?.provider?.id === 'OneNet'
: 'CTWing' ? 'OneNet'
}}的设备接入网关 : 'CTWing,选中后需填写CTWing平台中的产品ID、Master-APIkey。'
</div> }}
<div class="config-right-item-context"> </p>
2创建产品并选中接入方式为 <p>
{{ 3添加设备为每一台设备设置唯一的IMEISNIMSIPSK码需与CTWingt平台中填写的值一致若CTWing平台没有对应的设备将会通过CTWing平台提供的LWM2M协议自动创建
props?.provider?.id === 'OneNet' </p>
? 'OneNet'
: 'CTWing,选中后需填写CTWing平台中的产品ID、Master-APIkey。'
}}
</div>
<div class="config-right-item-context">
3添加设备为每一台设备设置唯一的IMEISNIMSIPSK码需与CTWingt平台中填写的值一致若CTWing平台没有对应的设备将会通过CTWing平台提供的LWM2M协议自动创建
</div>
</div>
</div> </div>
</j-col> </j-col>
</j-row> </j-row>
@ -567,12 +555,8 @@ watch(
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.container {
margin: 20px;
}
.steps-content { .steps-content {
margin: 20px; margin-top: 20px;
} }
.steps-box { .steps-box {
min-height: 400px; min-height: 400px;
@ -586,7 +570,6 @@ watch(
.steps-action { .steps-action {
width: 100%; width: 100%;
margin-top: 24px; margin-top: 24px;
margin-left: 20px;
} }
.steps-action-save { .steps-action-save {
margin-left: 0; margin-left: 0;
@ -609,54 +592,9 @@ watch(
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
.config-right {
padding: 20px;
.config-right-item {
margin-bottom: 10px;
.config-right-item-title {
width: 100%;
margin-bottom: 10px;
font-weight: 600;
}
.config-right-item-context {
margin: 5px 0;
color: rgba(0, 0, 0, 0.8);
}
}
}
.doc {
height: 550px;
padding: 24px;
overflow-x: hidden;
overflow-y: auto;
color: rgba(#000, 0.8);
font-size: 14px;
background-color: #fafafa;
h1 {
margin: 16px 0;
color: rgba(#000, 0.85);
font-weight: bold;
font-size: 14px;
&:first-child {
margin-top: 0;
}
}
.image {
margin: 16px 0;
}
}
.form-label { .form-label {
height: 30px; height: 30px;
padding-bottom: 8px; padding-bottom: 8px;
.form-label-required {
color: red;
margin: 0 4px 0 -2px;
}
} }
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-if="type === 'edge'" class="container"> <div v-if="type === 'edge'">
<j-steps <j-steps
v-if="channel !== 'edge-child-device'" v-if="channel !== 'edge-child-device'"
class="steps-steps" class="steps-steps"
@ -29,12 +29,8 @@
新增 新增
</PermissionButton> </PermissionButton>
</div> </div>
<j-scrollbar height="500"> <j-scrollbar height="480">
<j-row <j-row :gutter="[24, 24]" v-if="networkList.length > 0">
:gutter="[24, 24]"
v-if="networkList.length > 0"
style="margin-right: 10px"
>
<j-col <j-col
:span="8" :span="8"
v-for="item in networkList" v-for="item in networkList"
@ -66,11 +62,7 @@
class="item" class="item"
> >
<j-badge <j-badge
:color=" :status="getColor(i)"
i.health === -1
? 'red'
: 'green'
"
/>{{ i.address }} />{{ i.address }}
</div> </div>
</div> </div>
@ -82,11 +74,7 @@
class="item" class="item"
> >
<j-badge <j-badge
:color=" :status="getColor(i)"
i.health === -1
? 'red'
: 'green'
"
:text="i.address" :text="i.address"
/> />
<span <span
@ -163,19 +151,13 @@
</j-form> </j-form>
</j-col> </j-col>
<j-col :span="12"> <j-col :span="12">
<div class="config-right"> <div class="doc" style="height: 600px">
<div class="config-right-item"> <TitleComponent data="配置概览" />
<title-component data="配置概览" /> <p>接入方式{{ provider.name }}</p>
<div class="config-right-item-context"> <p>
接入方式{{ provider.name }} {{ provider.description }}
</div> </p>
<div class="config-right-item-context"> <p>消息协议{{ provider.id }}</p>
{{ provider.description }}
</div>
<div class="config-right-item-context">
消息协议{{ provider.id }}
</div>
</div>
</div> </div>
</j-col> </j-col>
</j-row> </j-row>
@ -278,6 +260,7 @@ const onFinish = async (values: any) => {
const checkedChange = (id: string) => { const checkedChange = (id: string) => {
networkCurrent.value = id; networkCurrent.value = id;
}; };
const getColor = (i: any) => (i.health === -1 ? 'error' : 'processing');
const queryNetworkList = async (id: string, include: string, data = {}) => { const queryNetworkList = async (id: string, include: string, data = {}) => {
const resp = await getNetworkList( const resp = await getNetworkList(
@ -359,12 +342,8 @@ watch(
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.container {
margin: 20px;
}
.steps-content { .steps-content {
margin: 20px; margin-top: 20px;
} }
.steps-box { .steps-box {
min-height: 400px; min-height: 400px;
@ -378,7 +357,6 @@ watch(
.steps-action { .steps-action {
width: 100%; width: 100%;
margin-top: 24px; margin-top: 24px;
margin-left: 20px;
} }
.steps-action-save { .steps-action-save {
margin-left: 0; margin-left: 0;

View File

@ -9,421 +9,397 @@
<AIcon type="InfoCircleOutlined" /> <AIcon type="InfoCircleOutlined" />
配置设备信令参数 配置设备信令参数
</div> </div>
<div>
<j-form <j-form
:model="formState" :model="formState"
ref="formRef1" ref="formRef1"
name="basic" name="basic"
autocomplete="off" autocomplete="off"
layout="vertical" layout="vertical"
>
<j-row :gutter="[24, 24]">
<j-col :span="12">
<j-form-item
label="SIP 域"
name="domain"
:rules="[
{
required: true,
message: '请输入SIP 域',
},
{
max: 64,
message: '最大可输入64个字符',
},
]"
>
<j-input
v-model:value="formState.domain"
placeholder="请输入SIP 域"
/>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
label="SIP ID"
name="sipId"
:rules="[
{
required: true,
message: '请输入SIP ID',
},
{
max: 64,
message: '最大可输入64个字符',
},
]"
>
<j-input
v-model:value="formState.sipId"
placeholder="请输入SIP ID"
/>
</j-form-item>
</j-col>
</j-row>
<j-form-item
name="shareCluster"
:rules="[
{
required: true,
message: '请选择集群',
},
]"
> >
<template #label>
集群
<j-tooltip
title="共享配置:集群下所有节点共用同一配置,独立配置:集群下不同节点使用不同配置"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</template>
<j-radio-group v-model:value="formState.shareCluster">
<j-radio :value="true">共享配置</j-radio>
<j-radio :value="false">独立配置</j-radio>
</j-radio-group>
</j-form-item>
<div v-if="formState.shareCluster" class="form-item1">
<j-row :gutter="[24, 24]"> <j-row :gutter="[24, 24]">
<j-col :span="12"> <j-col :span="6">
<j-form-item <j-form-item
label="SIP 域" label="SIP 地址"
name="domain" :name="['hostPort', 'host']"
:rules="[ :rules="[
{ {
required: true, required: true,
message: '请输入SIP 域', message: '请选择SIP地址',
},
{
max: 64,
message: '最大可输入64个字符',
}, },
]" ]"
> >
<j-input <j-select
v-model:value="formState.domain" v-model:value="formState.hostPort.host"
placeholder="请输入SIP 域" style="width: 105%"
:disabled="true"
show-search
:filter-option="filterOption"
>
<j-select-option value="0.0.0.0"
>0.0.0.0</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="6">
<j-form-item
:name="['hostPort', 'port']"
:rules="[
{
required: true,
message: '请选择端口',
},
]"
>
<div class="form-label"></div>
<j-select
v-model:value="formState.hostPort.port"
:options="sipList"
placeholder="请选择端口"
allowClear
show-search
:filter-option="filterOption"
/> />
</j-form-item> </j-form-item>
</j-col> </j-col>
<j-col :span="12"> <j-col :span="6">
<j-form-item <j-form-item
label="SIP ID" label="公网 Host"
name="sipId" :name="['hostPort', 'publicHost']"
:rules="[ :rules="[
{ {
required: true, required: true,
message: '请输入SIP ID', message: '请输入IP地址',
}, },
{ {
max: 64, pattern:
message: '最大可输入64个字符', /^([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/,
message: '请输入正确的IP地址',
}, },
]" ]"
> >
<j-input <j-input
v-model:value="formState.sipId" style="width: 105%"
placeholder="请输入SIP ID" v-model:value="
formState.hostPort.publicHost
"
placeholder="请输入IP地址"
/>
</j-form-item>
</j-col>
<j-col :span="6">
<j-form-item
:name="['hostPort', 'publicPort']"
:rules="[
{
required: true,
message: '输入端口',
},
]"
>
<div class="form-label"></div>
<j-input-number
style="width: 100%"
placeholder="请输入端口"
v-model:value="
formState.hostPort.publicPort
"
:min="1"
:max="65535"
/> />
</j-form-item> </j-form-item>
</j-col> </j-col>
</j-row> </j-row>
<j-form-item
name="shareCluster"
:rules="[
{
required: true,
message: '请选择集群',
},
]"
>
<template #label>
集群
<j-tooltip
title="共享配置:集群下所有节点共用同一配置,独立配置:集群下不同节点使用不同配置"
>
<AIcon
type="QuestionCircleOutlined"
style="margin-left: 2px"
/>
</j-tooltip>
</template>
<j-radio-group
v-model:value="formState.shareCluster"
>
<j-radio :value="true">共享配置</j-radio>
<j-radio :value="false">独立配置</j-radio>
</j-radio-group>
</j-form-item>
<div v-if="formState.shareCluster" class="form-item1">
<j-row :gutter="[24, 24]">
<j-col :span="6">
<j-form-item
label="SIP 地址"
:name="['hostPort', 'host']"
:rules="[
{
required: true,
message: '请选择SIP地址',
},
]"
>
<j-select
v-model:value="
formState.hostPort.host
"
style="width: 105%"
:disabled="true"
show-search
:filter-option="filterOption"
>
<j-select-option value="0.0.0.0"
>0.0.0.0</j-select-option
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="6">
<j-form-item
:name="['hostPort', 'port']"
:rules="[
{
required: true,
message: '请选择端口',
},
]"
>
<div class="form-label"></div>
<j-select
v-model:value="
formState.hostPort.port
"
:options="sipList"
placeholder="请选择端口"
allowClear
show-search
:filter-option="filterOption"
/>
</j-form-item>
</j-col>
<j-col :span="6">
<j-form-item
label="公网 Host"
:name="['hostPort', 'publicHost']"
:rules="[
{
required: true,
message: '请输入IP地址',
},
{
pattern:
/^([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/,
message: '请输入正确的IP地址',
},
]"
>
<j-input
style="width: 105%"
v-model:value="
formState.hostPort.publicHost
"
placeholder="请输入IP地址"
/>
</j-form-item>
</j-col>
<j-col :span="6">
<j-form-item
:name="['hostPort', 'publicPort']"
:rules="[
{
required: true,
message: '输入端口',
},
]"
>
<div class="form-label"></div>
<j-input-number
style="width: 100%"
placeholder="请输入端口"
v-model:value="
formState.hostPort.publicPort
"
:min="1"
:max="65535"
/>
</j-form-item>
</j-col>
</j-row>
</div>
</j-form>
<div v-if="!formState.shareCluster">
<j-form
ref="formRef2"
layout="vertical"
name="dynamic_form_nest_item"
:model="dynamicValidateForm"
>
<div
v-for="(
cluster, index
) in dynamicValidateForm.cluster"
:key="cluster.id"
>
<j-collapse v-model:activeKey="activeKey">
<j-collapse-panel
:key="cluster.id"
:header="`#${index + 1}.节点`"
>
<template #extra>
<AIcon
@click="removeCluster(cluster)"
type="DeleteOutlined"
/>
</template>
<j-row :gutter="[24, 24]">
<j-col :span="8">
<j-form-item
label="节点名称"
:name="[
'cluster',
index,
'clusterNodeId',
]"
:rules="{
required: true,
message:
'请选择节点名称',
}"
>
<j-select
v-model:value="
cluster.clusterNodeId
"
:options="clustersList"
placeholder="请选择节点名称"
allowClear
show-search
:filter-option="
filterOption
"
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="4">
<j-form-item
:name="[
'cluster',
index,
'host',
]"
:rules="{
required: true,
message:
'请选择SIP 地址',
}"
>
<div class="form-label">
SIP 地址
<span
class="form-label-required"
>*</span
>
<j-tooltip>
<template #title>
<p>
绑定到服务器上的网卡地址,绑定到所有网卡:0.0.0.0
</p>
</template>
<AIcon
type="QuestionCircleOutlined"
/>
</j-tooltip>
</div>
<j-select
v-model:value="
cluster.host
"
:options="sipListOption"
placeholder="请选择IP地址"
allowClear
show-search
:filter-option="
filterOption
"
style="width: 110%"
@change="
handleChangeForm2Sip(
index,
)
"
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="4">
<j-form-item
:name="[
'cluster',
index,
'port',
]"
:rules="{
required: true,
message: '请选择端口',
}"
>
<div
class="form-label"
></div>
<j-select
v-model:value="
cluster.port
"
:options="
sipListIndex[index]
"
placeholder="请选择端口"
allowClear
show-search
:filter-option="
filterOption
"
/>
</j-form-item>
</j-col>
<j-col :span="4">
<j-form-item
:name="[
'cluster',
index,
'publicHost',
]"
:rules="[
{
required: true,
message:
'请输入公网 Host',
},
{
pattern:
/^([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/,
message:
'请输入正确的IP地址',
},
]"
>
<div class="form-label">
公网 Host
<span
class="form-label-required"
>*</span
>
<j-tooltip>
<template #title>
<p>
监听指定端口的请求
</p>
</template>
<AIcon
type="QuestionCircleOutlined"
/>
</j-tooltip>
</div>
<j-input
style="width: 110%"
v-model:value="
cluster.publicHost
"
placeholder="请输入IP地址"
allowClear
/>
</j-form-item>
</j-col>
<j-col :span="4">
<j-form-item
:name="[
'cluster',
index,
'publicPort',
]"
:rules="[
{
required: true,
message:
'请输入端口',
},
]"
>
<div
class="form-label"
></div>
<j-input-number
style="width: 100%"
placeholder="请输入端口"
v-model:value="
cluster.publicPort
"
:min="1"
:max="65535"
/>
</j-form-item>
</j-col>
</j-row>
</j-collapse-panel>
</j-collapse>
</div>
<j-form-item>
<j-button
style="margin-top: 10px"
type="dashed"
block
@click="addCluster"
>
<AIcon type="PlusOutlined" />
新增
</j-button>
</j-form-item>
</j-form>
</div> </div>
</j-form>
<div v-if="!formState.shareCluster">
<j-form
ref="formRef2"
layout="vertical"
name="dynamic_form_nest_item"
:model="dynamicValidateForm"
>
<div
v-for="(
cluster, index
) in dynamicValidateForm.cluster"
:key="cluster.id"
>
<j-collapse v-model:activeKey="activeKey">
<j-collapse-panel
:key="cluster.id"
:header="`#${index + 1}.节点`"
>
<template #extra>
<span
@click="removeCluster(cluster)"
class="delete-btn"
>删除</span
>
</template>
<j-row :gutter="[24, 24]">
<j-col :span="8">
<j-form-item
label="节点名称"
:name="[
'cluster',
index,
'clusterNodeId',
]"
:rules="{
required: true,
message: '请选择节点名称',
}"
>
<j-select
v-model:value="
cluster.clusterNodeId
"
:options="clustersList"
placeholder="请选择节点名称"
allowClear
show-search
:filter-option="
filterOption
"
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="4">
<j-form-item
:name="[
'cluster',
index,
'host',
]"
:rules="{
required: true,
message: '请选择SIP 地址',
}"
>
<template #label>
SIP 地址
<j-tooltip
title="到服务器上的网卡地址,绑定到所有网卡:0.0.0.0"
>
<AIcon
type="QuestionCircleOutlined"
style="
margin-left: 2px;
"
/>
</j-tooltip>
</template>
<j-select
v-model:value="cluster.host"
:options="sipListOption"
placeholder="请选择IP地址"
allowClear
show-search
:filter-option="
filterOption
"
style="width: 110%"
@change="
handleChangeForm2Sip(
index,
)
"
>
</j-select>
</j-form-item>
</j-col>
<j-col :span="4">
<j-form-item
:name="[
'cluster',
index,
'port',
]"
:rules="{
required: true,
message: '请选择端口',
}"
>
<div class="form-label"></div>
<j-select
v-model:value="cluster.port"
:options="
sipListIndex[index]
"
placeholder="请选择端口"
allowClear
show-search
:filter-option="
filterOption
"
/>
</j-form-item>
</j-col>
<j-col :span="4">
<j-form-item
:name="[
'cluster',
index,
'publicHost',
]"
:rules="[
{
required: true,
message:
'请输入公网 Host',
},
{
pattern:
/^([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.([0-9]|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/,
message:
'请输入正确的IP地址',
},
]"
>
<template #label>
公网 Host
<j-tooltip
title="监听指定端口的请求"
>
<AIcon
type="QuestionCircleOutlined"
style="
margin-left: 2px;
"
/>
</j-tooltip>
</template>
<j-input
style="width: 110%"
v-model:value="
cluster.publicHost
"
placeholder="请输入IP地址"
allowClear
/>
</j-form-item>
</j-col>
<j-col :span="4">
<j-form-item
:name="[
'cluster',
index,
'publicPort',
]"
:rules="[
{
required: true,
message: '请输入端口',
},
]"
>
<div class="form-label"></div>
<j-input-number
style="width: 100%"
placeholder="请输入端口"
v-model:value="
cluster.publicPort
"
:min="1"
:max="65535"
/>
</j-form-item>
</j-col>
</j-row>
</j-collapse-panel>
</j-collapse>
</div>
<j-form-item>
<j-button
style="margin-top: 10px"
type="primary"
block
ghost
@click="addCluster"
>
<AIcon type="PlusOutlined" />
新增
</j-button>
</j-form-item>
</j-form>
</div> </div>
</div> </div>
<div class="steps-box" v-else> <div class="steps-box" v-else>
@ -465,30 +441,22 @@
</div> </div>
</j-col> </j-col>
<j-col :span="12"> <j-col :span="12">
<div class="config-right"> <div class="doc" style="height: 400px">
<div class="config-right-item"> <h1>接入方式</h1>
<div class="config-right-item-title"> <p>
接入方式 {{ provider.name }}
</div> </p>
<div class="config-right-item-context"> <p>
{{ provider.name }} {{ provider.description }}
</div> </p>
<div class="config-right-item-context"> <h1>消息协议</h1>
{{ provider.description }} <p>
</div> {{
</div> provider?.id === 'fixed-media'
<div class="config-right-item"> ? 'URL'
<div class="config-right-item-title"> : 'SIP'
消息协议 }}
</div> </p>
<div>
{{
provider?.id === 'fixed-media'
? 'URL'
: 'SIP'
}}
</div>
</div>
</div> </div>
</j-col> </j-col>
</j-row> </j-row>
@ -625,7 +593,7 @@ const filterOption = (input: string, option: any) => {
}; };
const handleChangeForm2Sip = (index: number) => { const handleChangeForm2Sip = (index: number) => {
dynamicValidateForm.cluster[index].port = ''; dynamicValidateForm.cluster[index].port = undefined;
const value = dynamicValidateForm.cluster[index].host; const value = dynamicValidateForm.cluster[index].host;
sipListIndex.value[index] = sipListConst sipListIndex.value[index] = sipListConst
.find((i: any) => i.host === value) .find((i: any) => i.host === value)
@ -800,27 +768,6 @@ watch(
} }
} }
.config-right {
padding: 20px;
color: rgba(0, 0, 0, 0.8);
background: rgba(0, 0, 0, 0.04);
.config-right-item {
margin-bottom: 10px;
.config-right-item-title {
width: 100%;
margin-bottom: 10px;
font-weight: 600;
}
.config-right-item-context {
margin: 5px 0;
color: rgba(0, 0, 0, 0.8);
}
}
}
.form-item1 { .form-item1 {
background-color: #f6f6f6; background-color: #f6f6f6;
padding: 10px; padding: 10px;
@ -828,9 +775,13 @@ watch(
.form-label { .form-label {
height: 30px; height: 30px;
padding-bottom: 8px; padding-bottom: 8px;
.form-label-required { }
color: red; .delete-btn {
margin: 0 4px 0 -2px; display: inline-block;
} color: #e50012;
padding: 0px 8px;
background: #ffffff;
border: 1px solid #e50012;
border-radius: 2px;
} }
</style> </style>

View File

@ -54,26 +54,18 @@
</div> </div>
</j-col> </j-col>
<j-col :span="12"> <j-col :span="12">
<div class="config-right"> <div class="doc">
<div class="config-right-item"> <h1>接入方式</h1>
<div class="config-right-item-title">接入方式</div> <p>
<div class="config-right-item-context"> {{ provider.name }}
{{ provider.name }} </p>
</div> <p>
<div class="config-right-item-context"> {{ provider.description }}
{{ provider.description }} </p>
</div> <h1>消息协议</h1>
</div> <p>
<div class="config-right-item"> {{ provider.id === 'fixed-media' ? 'URL' : 'SIP' }}
<div class="config-right-item-title">消息协议</div> </p>
<div class="config-right-item-context">
{{
provider.id === 'fixed-media'
? 'URL'
: 'SIP'
}}
</div>
</div>
</div> </div>
</j-col> </j-col>
</j-row> </j-row>
@ -149,24 +141,4 @@ onMounted(() => {
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
.config-right {
padding: 20px;
color: rgba(0, 0, 0, 0.8);
background: rgba(0, 0, 0, 0.04);
.config-right-item {
margin-bottom: 10px;
.config-right-item-title {
width: 100%;
margin-bottom: 10px;
font-weight: 600;
}
.config-right-item-context {
margin: 5px 0;
color: rgba(0, 0, 0, 0.8);
}
}
}
</style> </style>

View File

@ -26,11 +26,7 @@
</PermissionButton> </PermissionButton>
</div> </div>
<j-scrollbar height="480"> <j-scrollbar height="480">
<j-row <j-row :gutter="[24, 24]" v-if="networkList.length > 0">
:gutter="[24, 24]"
v-if="networkList.length > 0"
style="margin-right: 10px"
>
<j-col <j-col
:span="8" :span="8"
v-for="item in networkList" v-for="item in networkList"
@ -62,7 +58,7 @@
class="item" class="item"
> >
<j-badge <j-badge
:color="getColor(i)" :status="getColor(i)"
/>{{ i.address }} />{{ i.address }}
</div> </div>
</div> </div>
@ -74,7 +70,7 @@
class="item" class="item"
> >
<j-badge <j-badge
:color="getColor(i)" :status="getColor(i)"
:text="i.address" :text="i.address"
/> />
<span <span
@ -116,11 +112,7 @@
</PermissionButton> </PermissionButton>
</div> </div>
<j-scrollbar height="480"> <j-scrollbar height="480">
<j-row <j-row :gutter="[24, 24]" v-if="procotolList.length > 0">
:gutter="[24, 24]"
v-if="procotolList.length > 0"
style="margin-right: 10px"
>
<j-col <j-col
:span="8" :span="8"
v-for="item in procotolList" v-for="item in procotolList"
@ -177,66 +169,46 @@
</j-form> </j-form>
</j-col> </j-col>
<j-col :span="12"> <j-col :span="12">
<j-scrollbar height="600"> <j-scrollbar height="580">
<div class="config-right"> <div class="doc">
<div class="config-right-item"> <h1>接入方式</h1>
<div class="config-right-item-title"> <p>
接入方式 {{ provider.name }}
</div> </p>
<div class="config-right-item-context"> <p>
{{ provider.name }} {{ provider.description }}
</div> </p>
<div class="config-right-item-context"> <h1>消息协议</h1>
{{ provider.description }} <p>
</div> {{
</div> procotolList.find(
<div class="config-right-item"> (i: any) =>
<div class="config-right-item-title"> i.id === procotolCurrent,
消息协议 ).name
</div> }}
<div class="config-right-item-context"> </p>
{{ <p v-if="config.document">
procotolList.find( <Markdown :source="config.document" />
(i: any) => </p>
i.id === <div v-if="getNetworkCurrent()">
procotolCurrent, <h1>网络组件</h1>
).name <p
}}
</div>
<div
class="config-right-item-context"
v-if="config.document"
>
<Markdown
:source="config.document"
/>
</div>
</div>
<div
class="config-right-item"
v-if="getNetworkCurrent()"
>
<div class="config-right-item-title">
网络组件
</div>
<div
v-for="i in getNetworkCurrentData()" v-for="i in getNetworkCurrentData()"
:key="i.address" :key="i.address"
> >
<j-badge <j-badge
:color="getColor(i)" :status="getColor(i)"
:text="i.address" :text="i.address"
/> />
</div> </p>
</div> </div>
<div <div
class="config-right-item"
v-if=" v-if="
config.routes && config.routes &&
config.routes.length > 0 config.routes.length > 0
" "
> >
<div class="config-right-item-title"> <h1>
{{ {{
data.provider === data.provider ===
'mqtt-server-gateway' || 'mqtt-server-gateway' ||
@ -245,8 +217,8 @@
? 'topic' ? 'topic'
: 'URL信息' : 'URL信息'
}} }}
</div> </h1>
<j-scrollbar height="200"> <j-scrollbar height="400">
<j-table <j-table
:pagination="false" :pagination="false"
:rowKey="generateUUID()" :rowKey="generateUUID()"
@ -259,7 +231,7 @@
? columnsMQTT ? columnsMQTT
: columnsHTTP : columnsHTTP
" "
:scroll="{ y: 300 }" :scroll="{ y: 400 }"
> >
<template <template
#bodyCell="{ #bodyCell="{
@ -463,11 +435,9 @@ const getNetworkCurrentData = () =>
? networkList.value.find((i: any) => i.id === networkCurrent).addresses ? networkList.value.find((i: any) => i.id === networkCurrent).addresses
: []; : [];
const getColor = (i: any) => (i.health === -1 ? 'red' : 'green'); const getColor = (i: any) => (i.health === -1 ? 'error' : 'processing');
const getStream = (record: any) => { const getStream = (record: any) => {
console.log(222, record);
let stream = ''; let stream = '';
if (record.upstream && record.downstream) stream = '上行、下行'; if (record.upstream && record.downstream) stream = '上行、下行';
else if (record.upstream) stream = '上行'; else if (record.upstream) stream = '上行';
@ -644,7 +614,7 @@ watch(
<style lang="less" scoped> <style lang="less" scoped>
.steps-content { .steps-content {
margin: 20px; margin-top: 20px;
} }
.steps-box { .steps-box {
min-height: 400px; min-height: 400px;
@ -657,7 +627,6 @@ watch(
.steps-action { .steps-action {
width: 100%; width: 100%;
margin-top: 24px; margin-top: 24px;
margin-left: 20px;
} }
.alert { .alert {
height: 40px; height: 40px;
@ -685,25 +654,4 @@ watch(
text-overflow: ellipsis; text-overflow: ellipsis;
} }
} }
.config-right {
padding: 20px;
color: rgba(0, 0, 0, 0.8);
background: rgba(0, 0, 0, 0.04);
.config-right-item {
margin-bottom: 10px;
.config-right-item-title {
width: 100%;
margin-bottom: 10px;
font-weight: 600;
}
.config-right-item-context {
margin: 5px 0;
color: rgba(0, 0, 0, 0.8);
}
}
}
</style> </style>

View File

@ -5,6 +5,18 @@
<j-row :gutter="[24, 24]"> <j-row :gutter="[24, 24]">
<j-col :span="12" v-for="item in items.list" :key="item.id"> <j-col :span="12" v-for="item in items.list" :key="item.id">
<div class="provider"> <div class="provider">
<div
class="card-content-bg1"
:style="{
background: getBackgroundColor(),
}"
></div>
<div
class="card-content-bg2"
:style="{
background: getBackgroundColor(),
}"
></div>
<div class="box"> <div class="box">
<div class="left"> <div class="left">
<div class="images"> <div class="images">
@ -47,6 +59,14 @@ const props = defineProps({
const emit = defineEmits(['onClick']); const emit = defineEmits(['onClick']);
const getBackgroundColor = () => {
return `linear-gradient(
188.4deg,
rgba(9, 46, 231, 0.03) 22.94%,
rgba(9, 46, 231, 0) 94.62%
)`;
};
const click = (value: object) => { const click = (value: object) => {
emit('onClick', value); emit('onClick', value);
}; };
@ -61,10 +81,11 @@ const click = (value: object) => {
.provider { .provider {
position: relative; position: relative;
width: 100%; width: 100%;
padding: 20px; padding: 24px;
background: url('/public/images/access/background.png') no-repeat; // background: url('/public/images/access/background.png') no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
border: 1px solid #e6e6e6; border: 1px solid #e6e6e6;
overflow: hidden;
&::before { &::before {
position: absolute; position: absolute;
@ -84,6 +105,33 @@ const click = (value: object) => {
box-shadow: 0 0 24px rgba(#000, 0.1); box-shadow: 0 0 24px rgba(#000, 0.1);
} }
} }
.card-content-bg1 {
position: absolute;
right: -5%;
height: 100%;
width: 44.65%;
top: 0;
background: linear-gradient(
188.4deg,
rgba(229, 0, 18, 0.03) 22.94%,
rgba(229, 0, 18, 0) 94.62%
);
transform: skewX(-15deg);
}
.card-content-bg2 {
position: absolute;
right: -5%;
height: 100%;
width: calc(44.65% + 34px);
top: 0;
background: linear-gradient(
188.4deg,
rgba(229, 0, 18, 0.03) 22.94%,
rgba(229, 0, 18, 0) 94.62%
);
transform: skewX(-15deg);
}
.box { .box {
display: flex; display: flex;
@ -92,31 +140,40 @@ const click = (value: object) => {
width: 100%; width: 100%;
.left { .left {
display: flex; display: flex;
width: calc(100% - 70px); width: calc(100% - 100px);
.images { .images {
width: 64px; width: 88px;
height: 64px; height: 88px;
img { img {
width: 100%; width: 88px;
height: 88px;
} }
} }
.context { .context {
width: calc(100% - 84px); width: calc(100% - 88px);
margin: 10px; margin: 8px;
margin-left: 24px;
.title { .title {
font-weight: 600; font-style: normal;
font-weight: 800;
font-size: 18px;
line-height: 22px;
color: rgba(0, 0, 0, 0.85);
opacity: 0.85;
} }
.desc { .desc {
width: 100%; width: 100%;
margin-top: 10px; margin-top: 24px;
overflow: hidden; font-style: normal;
color: rgba(0, 0, 0, 0.55);
font-weight: 400; font-weight: 400;
font-size: 13px; font-size: 12px;
line-height: 20px;
color: #666666;
overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
} }

View File

@ -37,7 +37,7 @@
:status="slotProps.state.value" :status="slotProps.state.value"
:statusText="slotProps.state.text" :statusText="slotProps.state.text"
:statusNames="{ :statusNames="{
enabled: 'success', enabled: 'processing',
disabled: 'error', disabled: 'error',
}" }"
> >
@ -51,15 +51,12 @@
<Ellipsis <Ellipsis
style=" style="
width: calc(100% - 100px); width: calc(100% - 100px);
margin-bottom: 10px; margin-bottom: 20px;
color: #2f54eb; color: #2f54eb;
" "
> >
<span <span
style=" class="card-title"
font-size: 16px;
font-weight: 600;
"
@click.stop="handlEye(slotProps.id)" @click.stop="handlEye(slotProps.id)"
> >
{{ slotProps.name }} {{ slotProps.name }}
@ -71,11 +68,17 @@
v-if="slotProps.channelInfo" v-if="slotProps.channelInfo"
class="card-item-content-text" class="card-item-content-text"
> >
<div class="card-item-content-text"> <div
class="card-item-content-text-title"
>
{{ slotProps.channelInfo.name }} {{ slotProps.channelInfo.name }}
</div> </div>
<div <Ellipsis
class="card-item-content-text" style="
width: calc(100% - 10px);
display: flex;
margin-top: 4px;
"
v-if=" v-if="
slotProps.channelInfo.addresses slotProps.channelInfo.addresses
" "
@ -83,53 +86,51 @@
<j-badge <j-badge
:status="getStatus(slotProps)" :status="getStatus(slotProps)"
/> />
<j-tooltip> <span>
<template #title>{{
slotProps.channelInfo
.addresses[0].address
}}</template>
{{ {{
slotProps.channelInfo slotProps.channelInfo
.addresses[0].address .addresses[0].address
}} }}
</j-tooltip> </span>
</div> </Ellipsis>
</j-col> </j-col>
<j-col <j-col
:span="12" :span="12"
v-if="slotProps.protocolDetail" v-if="slotProps.protocolDetail"
class="card-item-content-text"
> >
<div class="card-item-content-text"> <div
class="card-item-content-text-title"
>
协议 协议
</div> </div>
<div class="card-item-content-text"> <Ellipsis
<j-tooltip> style="
<template #title>{{ width: calc(100% - 10px);
slotProps.protocolDetail display: flex;
.name margin-top: 4px;
}}</template> "
>
<span>
{{ {{
slotProps.protocolDetail slotProps.protocolDetail
.name .name
}} }}
</j-tooltip> </span>
</div> </Ellipsis>
</j-col> </j-col>
</j-row> </j-row>
<j-row> <j-row>
<j-col :span="24"> <j-col
<div class="card-item-content-text"> :span="24"
<j-tooltip> class="card-item-content-description"
<template #title> >
{{ <j-tooltip>
getDescription( <template #title>
slotProps,
)
}}
</template>
{{ getDescription(slotProps) }} {{ getDescription(slotProps) }}
</j-tooltip> </template>
</div> {{ getDescription(slotProps) }}
</j-tooltip>
</j-col> </j-col>
</j-row> </j-row>
</div> </div>
@ -207,8 +208,8 @@ const columns = [
search: { search: {
type: 'select', type: 'select',
options: async () => { options: async () => {
const res = await getProviders(); const res: any = await getProviders();
return (res?.result || []).map((item) => ({ return (res?.result || [])?.map((item: any) => ({
lable: item.name, lable: item.name,
value: item.id, value: item.id,
})); }));
@ -339,7 +340,7 @@ const getDescription = (slotProps: Record<string, any>) =>
)?.description; )?.description;
const getStatus = (slotProps: Record<string, any>) => const getStatus = (slotProps: Record<string, any>) =>
slotProps.channelInfo.addresses[0].health === -1 ? 'error' : 'success'; slotProps.channelInfo.addresses[0].health === -1 ? 'error' : 'processing';
/** /**
* 搜索 * 搜索
@ -358,12 +359,29 @@ const handleSearch = (e: any) => {
.card-item-content { .card-item-content {
min-height: 100px; min-height: 100px;
.card-title {
font-size: 18px;
font-weight: 800;
line-height: 22px;
}
.card-item-content-box { .card-item-content-box {
min-height: 50px; min-height: 50px;
} }
.card-item-content-text {
color: rgba(0, 0, 0, 0.75); .card-item-content-text-title {
font-style: normal;
font-weight: 400;
font-size: 12px; font-size: 12px;
color: rgba(0, 0, 0, 0.75);
opacity: 0.75;
}
.card-item-content-description {
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 20px;
color: #666666;
overflow: hidden; // overflow: hidden; //
text-overflow: ellipsis; // text-overflow: ellipsis; //
white-space: nowrap; // white-space: nowrap; //

View File

@ -75,11 +75,13 @@
</j-form-item> </j-form-item>
</j-col> </j-col>
</j-row> </j-row>
<j-form <j-form
ref="formRef2" ref="formRef2"
layout="vertical" layout="vertical"
name="dynamic_form_nest_item" name="dynamic_form_nest_item"
:model="dynamicValidateForm" :model="dynamicValidateForm"
class="form2"
> >
<div <div
v-for="( v-for="(
@ -582,59 +584,71 @@
</j-radio-group> </j-radio-group>
</j-form-item> </j-form-item>
</j-col> </j-col>
<div class="form2-row">
<j-col
:span="12"
v-if="
cluster.configuration.secure
"
>
<j-form-item
label="证书"
:name="[
'cluster',
index,
'configuration',
'certId',
]"
:rules="Rules.certId"
class="form2-left"
>
<j-select
v-model:value="
cluster
.configuration
.certId
"
:options="certIdOptions"
placeholder="请选择证书"
allowClear
show-search
:filter-option="
filterOption
"
/>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="
cluster.configuration.secure
"
>
<j-form-item
label="私钥别名"
:name="[
'cluster',
index,
'configuration',
'privateKeyAlias',
]"
:rules="
Rules.privateKeyAlias
"
class="form2-right"
>
<j-input
v-model:value="
cluster
.configuration
.privateKeyAlias
"
placeholder="请输入私钥别名"
/>
</j-form-item>
</j-col>
</div>
<j-col
:span="12"
v-if="cluster.configuration.secure"
>
<j-form-item
label="证书"
:name="[
'cluster',
index,
'configuration',
'certId',
]"
:rules="Rules.certId"
>
<j-select
v-model:value="
cluster.configuration
.certId
"
:options="certIdOptions"
placeholder="请选择证书"
allowClear
show-search
:filter-option="
filterOption
"
/>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="cluster.configuration.secure"
>
<j-form-item
label="私钥别名"
:name="[
'cluster',
index,
'configuration',
'privateKeyAlias',
]"
:rules="Rules.privateKeyAlias"
>
<j-input
v-model:value="
cluster.configuration
.privateKeyAlias
"
placeholder="请输入私钥别名"
/>
</j-form-item>
</j-col>
<j-col <j-col
:span="24" :span="24"
v-if=" v-if="
@ -690,249 +704,265 @@
/> />
</j-form-item> </j-form-item>
</j-col> </j-col>
<div class="form2-row">
<j-col <j-col
:span="12" :span="12"
v-if=" v-if="
isVisible( isVisible(
'delimited', 'delimited',
cluster.configuration
.parserType,
)
"
>
<j-form-item
label="分隔符"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'delimited',
]"
:rules="Rules.delimited"
>
<j-input
v-model:value="
cluster.configuration cluster.configuration
.parserConfiguration .parserType,
.delimited )
" "
placeholder="请输入分隔符"
/>
</j-form-item>
</j-col>
<j-col
:span="24"
v-if="
isVisible(
'lang',
cluster.configuration
.parserType,
)
"
>
<j-form-item
v-show="false"
label="脚本语言"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'lang',
]"
> >
<j-input <j-form-item
v-model:value=" label="分隔符"
cluster.configuration :name="[
.parserConfiguration 'cluster',
.lang index,
" 'configuration',
/> 'parserConfiguration',
</j-form-item> 'delimited',
</j-col> ]"
<j-col :rules="Rules.delimited"
:span="24" class="form2-left"
v-if="
isVisible(
'script',
cluster.configuration
.parserType,
)
"
>
<j-form-item
label="解析脚本"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'script',
]"
:rules="Rules.script"
>
<div
style="
width: 100%;
height: 400px;
"
> >
<j-monaco-editor <j-input
theme="vs"
v-model:value=" v-model:value="
cluster cluster
.configuration .configuration
.parserConfiguration .parserConfiguration
.script .delimited
" "
language="javascript" placeholder="请输入分隔符"
/> />
</div> </j-form-item>
</j-form-item> </j-col>
</j-col>
<j-col <!-- <j-col
:span="12" :span="24"
v-if=" v-if="
isVisible( isVisible(
'size', 'lang',
cluster.configuration
.parserType,
)
"
>
<j-form-item
label="长度值"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'size',
]"
:rules="Rules.size"
>
<j-input-number
style="width: 100%"
v-model:value="
cluster.configuration cluster.configuration
.parserConfiguration .parserType,
.size )
" "
placeholder="请输入长度值"
/>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="
isVisible(
'length',
cluster.configuration
.parserType,
)
"
>
<j-form-item
label="长度"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'length',
]"
:rules="Rules.length"
> >
<j-select <j-form-item
style="width: 100%" v-show="false"
v-model:value=" label="脚本语言"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'lang',
]"
class="form2-left"
>
<j-input
v-model:value="
cluster
.configuration
.parserConfiguration
.lang
"
/>
</j-form-item>
</j-col> -->
<j-col
:span="24"
v-if="
isVisible(
'script',
cluster.configuration cluster.configuration
.parserConfiguration .parserType,
.length )
" "
:options="LengthOptions"
placeholder="请选择长度"
allowClear
show-search
:filter-option="
filterOption
"
/>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="
isVisible(
'offset',
cluster.configuration
.parserType,
)
"
>
<j-form-item
label="偏移量"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'offset',
]"
:rules="Rules.offset"
> >
<j-input-number <j-form-item
style="width: 100%" label="解析脚本"
v-model:value=" :name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'script',
]"
:rules="Rules.script"
class="form2-left form2-right"
>
<div
style="
width: 100%;
height: 400px;
"
>
<j-monaco-editor
theme="vs"
v-model:value="
cluster
.configuration
.parserConfiguration
.script
"
language="javascript"
/>
</div>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="
isVisible(
'size',
cluster.configuration cluster.configuration
.parserConfiguration .parserType,
.offset )
" "
placeholder="请输入偏移量"
:min="0"
:max="65535"
/>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="
isVisible(
'little',
cluster.configuration
.parserType,
)
"
>
<j-form-item
label="大小端"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'little',
]"
> >
<j-select <j-form-item
style="width: 100%" label="长度值"
v-model:value=" :name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'size',
]"
:rules="Rules.size"
class="form2-left"
>
<j-input-number
style="width: 100%"
v-model:value="
cluster
.configuration
.parserConfiguration
.size
"
placeholder="请输入长度值"
/>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="
isVisible(
'length',
cluster.configuration cluster.configuration
.parserConfiguration .parserType,
.little )
" "
:options="LittleOptions" >
placeholder="请选择大小端" <j-form-item
allowClear label="长度"
show-search :name="[
:filter-option=" 'cluster',
filterOption index,
" 'configuration',
/> 'parserConfiguration',
</j-form-item> 'length',
</j-col> ]"
:rules="Rules.length"
class="form2-left"
>
<j-select
style="width: 100%"
v-model:value="
cluster
.configuration
.parserConfiguration
.length
"
:options="LengthOptions"
placeholder="请选择长度"
allowClear
show-search
:filter-option="
filterOption
"
/>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="
isVisible(
'offset',
cluster.configuration
.parserType,
)
"
>
<j-form-item
label="偏移量"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'offset',
]"
:rules="Rules.offset"
class="form2-right"
>
<j-input-number
style="width: 100%"
v-model:value="
cluster
.configuration
.parserConfiguration
.offset
"
placeholder="请输入偏移量"
:min="0"
:max="65535"
/>
</j-form-item>
</j-col>
<j-col
:span="12"
v-if="
isVisible(
'little',
cluster.configuration
.parserType,
)
"
>
<j-form-item
label="大小端"
:name="[
'cluster',
index,
'configuration',
'parserConfiguration',
'little',
]"
class="form2-left"
>
<j-select
style="width: 100%"
v-model:value="
cluster
.configuration
.parserConfiguration
.little
"
:options="LittleOptions"
placeholder="请选择大小端"
allowClear
show-search
:filter-option="
filterOption
"
/>
</j-form-item>
</j-col>
</div>
</j-row> </j-row>
</j-collapse-panel> </j-collapse-panel>
</j-collapse> </j-collapse>
@ -1278,8 +1308,39 @@ watch(
width: 100%; width: 100%;
margin-top: 24px; margin-top: 24px;
} }
.form2 {
:deep(.ant-collapse-content-box) {
background: #fafafa;
border-radius: 2px;
}
.form2-row {
display: flex;
width: 100%;
position: relative;
flex-flow: row wrap;
.form2-left {
padding-left: 16px;
flex: 1;
}
.form2-right {
padding-right: 16px;
flex: 1;
}
&::before {
position: absolute;
top: -10px;
left: 10px;
right: 10px;
width: calc(100%-10px);
height: 100%;
background-color: #f4f4f4;
content: ' ';
}
}
}
.collapse { .collapse {
margin-bottom: 20px; margin-bottom: 20px;
background: #f4f4f4;
} }
</style> </style>

View File

@ -36,7 +36,7 @@
:status="slotProps.state.value" :status="slotProps.state.value"
:statusText="slotProps.state.text" :statusText="slotProps.state.text"
:statusNames="{ :statusNames="{
enabled: 'success', enabled: 'processing',
disabled: 'error', disabled: 'error',
}" }"
> >
@ -50,7 +50,7 @@
<Ellipsis <Ellipsis
style=" style="
width: calc(100% - 100px); width: calc(100% - 100px);
margin-bottom: 10px; margin-bottom: 20px;
color: #2f54eb; color: #2f54eb;
" "
> >
@ -65,8 +65,10 @@
</span> </span>
</Ellipsis> </Ellipsis>
<j-row class="card-item-content-box"> <j-row class="card-item-content-box">
<j-col :span="12"> <j-col :span="8">
<div class="card-item-content-text"> <div
class="card-item-content-text-title"
>
类型 类型
</div> </div>
<div class="card-item-content-text"> <div class="card-item-content-text">
@ -78,8 +80,11 @@
</j-tooltip> </j-tooltip>
</div> </div>
</j-col> </j-col>
<j-col :span="12">
<div class="card-item-content-text"> <j-col :span="16">
<div
class="card-item-content-text-title"
>
详情 详情
</div> </div>
<div class="card-item-content-text"> <div class="card-item-content-text">
@ -87,9 +92,7 @@
<template #title>{{ <template #title>{{
getDetails(slotProps) getDetails(slotProps)
}}</template> }}</template>
<span class="details-text">{{ {{ getDetails(slotProps) }}
getDetails(slotProps)
}}</span>
</j-tooltip> </j-tooltip>
</div> </div>
</j-col> </j-col>
@ -143,10 +146,14 @@
</j-space> </j-space>
</template> </template>
<template #state="slotProps"> <template #state="slotProps">
<j-badge <BadgeStatus
:text="slotProps.state.text" :text="slotProps.state.text"
:status="statusMap.get(slotProps.state.value)" :status="slotProps.state.value"
/> :statusNames="{
enabled: 'processing',
disabled: 'error',
}"
></BadgeStatus>
</template> </template>
<template #shareCluster="slotProps"> <template #shareCluster="slotProps">
{{ {{
@ -171,15 +178,16 @@ import { getImage } from '@/utils/comm';
import { supports, query, remove, start, shutdown } from '@/api/link/type'; import { supports, query, remove, start, shutdown } from '@/api/link/type';
import { onlyMessage } from '@/utils/comm'; import { onlyMessage } from '@/utils/comm';
import { useMenuStore } from 'store/menu'; import { useMenuStore } from 'store/menu';
import BadgeStatus from '@/components/BadgeStatus/index.vue';
const menuStory = useMenuStore(); const menuStory = useMenuStore();
const tableRef = ref<Record<string, any>>({}); const tableRef = ref<Record<string, any>>({});
const params = ref<Record<string, any>>({}); const params = ref<Record<string, any>>({});
const options = ref([]); const options = ref([]);
const statusMap = new Map(); // const statusMap = new Map();
statusMap.set('enabled', 'success'); // statusMap.set('enabled', 'processing');
statusMap.set('disabled', 'error'); // statusMap.set('disabled', 'error');
const columns = [ const columns = [
{ {
@ -387,15 +395,23 @@ const handleSearch = (e: any) => {
min-height: 50px; min-height: 50px;
} }
.card-item-content-text { .card-item-content-text {
color: rgba(0, 0, 0, 0.75); font-style: normal;
font-size: 12px; font-weight: 400;
font-size: 14px;
line-height: 170%;
color: rgba(0, 0, 0, 0.85);
opacity: 0.75;
overflow: hidden; // overflow: hidden; //
text-overflow: ellipsis; // text-overflow: ellipsis; //
white-space: nowrap; // white-space: nowrap; //
} }
} .card-item-content-text-title {
.details-text { font-style: normal;
font-weight: 700; font-weight: 400;
font-size: 14px; font-size: 12px;
line-height: 170%;
color: rgba(0, 0, 0, 0.75);
opacity: 0.75;
}
} }
</style> </style>

View File

@ -3700,8 +3700,8 @@ jetlinks-store@^0.0.3:
jetlinks-ui-components@^1.0.5: jetlinks-ui-components@^1.0.5:
version "1.0.5" version "1.0.5"
resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#1059095549559c679f9197df360e3ee2360eff44" resolved "http://47.108.170.157:9013/jetlinks-ui-components/-/jetlinks-ui-components-1.0.5.tgz#682711e0f69c141fff2c256db61a060c82539611"
integrity sha512-aK2ym5HF6DBsEnvrILGkzRkdPC+QSjrft3xK2DrDRqU5lZq0uqS55ksk88GoaFzGSgqznK+PPWZaYc0Lo2WH/A== integrity sha512-rQxD/YlE+XSAG7BWIcFTtKrCQJXk5o+TUgejyuUT/baBThJB6xYt1k2dQEdXyiwpukYen5FzaoLpelSD9SUegw==
dependencies: dependencies:
"@vueuse/core" "^9.12.0" "@vueuse/core" "^9.12.0"
ant-design-vue "^3.2.15" ant-design-vue "^3.2.15"