iot-ui-vue/src/views/media/Device/Save/SaveProduct.vue

336 lines
12 KiB
Vue

<template>
<j-modal
v-model:visible="_vis"
title="快速添加"
cancelText="取消"
okText="确定"
@ok="handleOk"
@cancel="handleCancel"
:confirmLoading="btnLoading"
width="660px"
>
<j-form ref="formRef" :model="formData" layout="vertical">
<j-form-item
label="产品名称"
name="name"
:rules="[
{ required: true, message: '请输入产品名称' },
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<j-input
v-model:value="formData.name"
placeholder="请输入名称"
/>
</j-form-item>
<template v-if="deviceType !== 'gateway'">
<template v-for="(item, index) in extendFormItem" :key="index">
<j-form-item
:name="item.name"
:label="item.label"
:rules="[
{
required: item.required,
message: item.message,
trigger: 'change',
},
{
max: 64,
message: '最多输入64个字符',
},
]"
>
<j-select
v-if="item.type === 'enum'"
v-model:value="formData[item.name[0]][item.name[1]]"
:options="item.options"
:placeholder="item.message"
/>
<j-input-password
v-else-if="item.type === 'password'"
v-model:value="formData[item.name[0]][item.name[1]]"
:placeholder="item.message"
/>
<j-input
v-else
v-model:value="formData[item.name[0]][item.name[1]]"
:placeholder="item.message"
/>
</j-form-item>
</template>
</template>
<j-form-item
label="接入网关"
name="accessId"
:rules="{ required: true, message: '请选择接入网关' }"
>
<div class="gateway-box">
<div v-if="!gatewayList.length">
暂无数据,请先
<PermissionButton
type="link"
style="padding: 0"
hasPermission="link/AccessConfig:add"
@click="onJump"
>
添加{{ providerType[props.channel] }}接入网关
</PermissionButton>
</div>
<div
class="gateway-item"
v-for="(item, index) in gatewayList"
:key="index"
>
<CardBox
@click="handleClick"
:active="_selectedRowKeys.includes(item.id)"
:value="item"
v-bind="item"
:status="item.state?.value"
:statusText="item.state?.text"
:statusNames="{
enabled: 'processing',
disabled: 'error',
}"
>
<template #img>
<slot name="img">
<img
:src="getImage('/device-access.png')"
/>
</slot>
</template>
<template #content>
<h3 class="card-item-content-title">
{{ item.name }}
</h3>
<div class="desc">{{ item.description }}</div>
<j-row v-if="props.channel === 'gb28181-2016'">
<j-col :span="12">
{{ item.channelInfo?.name }}
</j-col>
<j-col :span="12">
{{ item.protocolDetail.name }}
</j-col>
<j-col :span="12">
<p
v-for="(i, idx) in item.channelInfo
?.addresses"
:key="`${i.address}_address${idx}`"
>
<Ellipsis>
<j-badge
:text="i.address"
:color="
i.health === -1
? 'red'
: 'green'
"
/>
</Ellipsis>
</p>
</j-col>
</j-row>
<j-row v-else>
<j-col :span="24">
<div class="subtitle">
{{ item.protocolDetail.name }}
</div>
<p>
{{
item.protocolDetail.description
}}
</p>
</j-col>
</j-row>
</template>
</CardBox>
</div>
</div>
</j-form-item>
</j-form>
</j-modal>
</template>
<script setup lang="ts">
import { message } from 'jetlinks-ui-components';
import DeviceApi from '@/api/media/device';
import { getImage } from '@/utils/comm';
import { gatewayType } from '@/views/media/Device/typings';
import { providerType } from '../const';
import { useMenuStore } from '@/store/menu';
const menuStory = useMenuStore();
type Emits = {
(e: 'update:visible', data: boolean): void;
(e: 'update:productId', data: string): void;
(e: 'close'): void;
(e: 'save', data: Record<string, any>): void;
};
const emit = defineEmits<Emits>();
const props = defineProps({
visible: { type: Boolean, default: false },
productId: { type: String, default: '' },
channel: { type: String, default: '' },
deviceType: { type: String, default: 'device' },
});
const _vis = computed({
get: () => props.visible,
set: (val) => emit('update:visible', val),
});
/**
* 获取接入网关
*/
const gatewayList = ref<gatewayType[]>([]);
const getGatewayList = async () => {
const params = {
pageSize: 100,
sorts: [{ name: 'createTime', order: 'desc' }],
terms: [{ column: 'provider', value: props.channel }],
};
const { result } = await DeviceApi.queryProvider(params);
gatewayList.value = result.data;
};
/**
* 点击接入网关, 获取对应配置
* @param e
*/
const _selectedRowKeys = ref<string[]>([]);
const extendFormItem = ref<any[]>();
const handleClick = async (e: any) => {
_selectedRowKeys.value = [e.id];
formData.value.accessId = e.id;
formData.value.accessName = e.name;
formData.value.accessProvider = e.provider;
formData.value.messageProtocol = e.protocolDetail.id;
formData.value.protocolName = e.protocolDetail.name;
formData.value.transportProtocol = e.transport;
const { result } = await DeviceApi.getConfiguration(
e.protocol,
e.transport,
);
extendFormItem.value = result.properties.map((item: any) => ({
name: ['configuration', item.property],
label: item.name,
type: item.type?.type,
value: item.type.expands?.defaultValue,
options: item.type.elements?.map((e: any) => ({
label: e.text,
value: e.value,
})),
required: !!item.type.expands?.required,
message:
item.type?.type === 'enum'
? `请选择${item.name}`
: `请输入${item.name}`,
}));
};
watch(
() => _vis.value,
(val) => {
if (val) {
getGatewayList();
} else {
_selectedRowKeys.value = [];
extendFormItem.value = [];
emit('close');
}
},
);
// 表单数据
const formRef = ref();
const formData = ref({
accessId: '',
accessName: '',
accessProvider: '',
configuration: {
access_pwd: '',
stream_mode: 'UDP',
},
deviceType: props.deviceType,
messageProtocol: '',
name: '',
protocolName: '',
transportProtocol: '',
});
/**
* 提交
*/
const btnLoading = ref(false);
const handleOk = () => {
formRef.value
?.validate()
.then(async () => {
btnLoading.value = true;
const res = await DeviceApi.saveProduct(formData.value);
if (res.success) {
emit('update:productId', res.result.id);
const deployResp = await DeviceApi.deployProductById(
res.result.id,
);
if (deployResp.success) {
emit('save', { ...res.result });
message.success('操作成功');
handleCancel();
}
}
btnLoading.value = false;
})
.catch((err: any) => {
console.log('err: ', err);
});
};
const handleCancel = () => {
_vis.value = false;
formRef.value.resetFields();
};
const onJump = () => {
menuStory.jumpPage(
`link/AccessConfig/Detail`,
{ id: ':id' },
{ view: false },
);
}
</script>
<style lang="less" scoped>
.gateway-box {
max-height: 450px;
overflow-y: auto;
text-align: center;
.gateway-item {
padding: 16px;
text-align: left;
.card-item-content-title,
.desc,
.subtitle {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.desc,
.subtitle {
margin-top: 10px;
color: #666;
font-weight: 400;
font-size: 12px;
}
}
}
</style>