548 lines
25 KiB
Vue
548 lines
25 KiB
Vue
<template>
|
|
<page-container>
|
|
<a-card>
|
|
<a-row :gutter="24">
|
|
<a-col :span="16">
|
|
<TitleComponent data="基本信息" />
|
|
<a-form
|
|
:layout="'vertical'"
|
|
ref="formRef"
|
|
:model="modelRef"
|
|
>
|
|
<a-row :gutter="24">
|
|
<a-col :span="24">
|
|
<a-form-item
|
|
label="名称"
|
|
name="name"
|
|
:rules="[
|
|
{
|
|
required: true,
|
|
message: '请输入名称',
|
|
},
|
|
{
|
|
max: 64,
|
|
message: '最多输入64个字符',
|
|
},
|
|
]"
|
|
>
|
|
<a-input
|
|
placeholder="请输入名称"
|
|
v-model:value="modelRef.name"
|
|
/>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :span="24">
|
|
<a-form-item
|
|
:name="['accessConfig', 'regionId']"
|
|
:rules="[
|
|
{
|
|
required: true,
|
|
message: '请选择服务地址',
|
|
},
|
|
]"
|
|
>
|
|
<template #label>
|
|
<span>
|
|
服务地址
|
|
<a-tooltip
|
|
title="阿里云内部给每台机器设置的唯一编号"
|
|
>
|
|
<AIcon
|
|
type="QuestionCircleOutlined"
|
|
style="margin-left: 2px"
|
|
/>
|
|
</a-tooltip>
|
|
</span>
|
|
</template>
|
|
<a-select
|
|
placeholder="请选择服务地址"
|
|
v-model:value="
|
|
modelRef.accessConfig.regionId
|
|
"
|
|
show-search
|
|
:filter-option="filterOption"
|
|
@blur="productChange"
|
|
>
|
|
<a-select-option
|
|
v-for="item in regionsList"
|
|
:key="item.id"
|
|
:value="item.id"
|
|
:label="item.name"
|
|
>{{ item.name }}</a-select-option
|
|
>
|
|
</a-select>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :span="24">
|
|
<a-form-item
|
|
:name="['accessConfig', 'instanceId']"
|
|
>
|
|
<template #label>
|
|
<span>
|
|
实例ID
|
|
<a-tooltip
|
|
title="阿里云物联网平台中的实例ID,没有则不填"
|
|
>
|
|
<AIcon
|
|
type="QuestionCircleOutlined"
|
|
style="margin-left: 2px"
|
|
/>
|
|
</a-tooltip>
|
|
</span>
|
|
</template>
|
|
<a-input
|
|
placeholder="请输入实例ID"
|
|
v-model:value="
|
|
modelRef.accessConfig.instanceId
|
|
"
|
|
@blur="productChange"
|
|
/>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :span="24">
|
|
<a-form-item
|
|
:name="['accessConfig', 'accessKeyId']"
|
|
:rules="[
|
|
{
|
|
required: true,
|
|
message: '请输入accessKey',
|
|
},
|
|
{
|
|
max: 64,
|
|
message: '最多输入64个字符',
|
|
},
|
|
]"
|
|
>
|
|
<template #label>
|
|
<span>
|
|
accessKey
|
|
<a-tooltip
|
|
title="用于程序通知方式调用云服务API的用户标识"
|
|
>
|
|
<AIcon
|
|
type="QuestionCircleOutlined"
|
|
style="margin-left: 2px"
|
|
/>
|
|
</a-tooltip>
|
|
</span>
|
|
</template>
|
|
<a-input
|
|
placeholder="请输入accessKey"
|
|
v-model:value="
|
|
modelRef.accessConfig.accessKeyId
|
|
"
|
|
@blur="productChange"
|
|
/>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :span="24">
|
|
<a-form-item
|
|
:name="['accessConfig', 'accessSecret']"
|
|
:rules="[
|
|
{
|
|
required: true,
|
|
message: '请输入accessSecret',
|
|
},
|
|
{
|
|
max: 64,
|
|
message: '最多输入64个字符',
|
|
},
|
|
]"
|
|
>
|
|
<template #label>
|
|
<span>
|
|
accessSecret
|
|
<a-tooltip
|
|
title="用于程序通知方式调用云服务费API的秘钥标识"
|
|
>
|
|
<AIcon
|
|
type="QuestionCircleOutlined"
|
|
style="margin-left: 2px"
|
|
/>
|
|
</a-tooltip>
|
|
</span>
|
|
</template>
|
|
<a-input
|
|
placeholder="请输入accessSecret"
|
|
v-model:value="
|
|
modelRef.accessConfig.accessSecret
|
|
"
|
|
@blur="productChange"
|
|
/>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :span="24">
|
|
<a-form-item
|
|
name="bridgeProductKey"
|
|
:rules="{
|
|
required: true,
|
|
message: '请选择网桥产品',
|
|
}"
|
|
>
|
|
<template #label>
|
|
<span>
|
|
网桥产品
|
|
<a-tooltip
|
|
title="物联网平台对应的阿里云产品"
|
|
>
|
|
<AIcon
|
|
type="QuestionCircleOutlined"
|
|
style="margin-left: 2px"
|
|
/>
|
|
</a-tooltip>
|
|
</span>
|
|
</template>
|
|
<a-select
|
|
placeholder="请选择网桥产品"
|
|
v-model:value="
|
|
modelRef.bridgeProductKey
|
|
"
|
|
show-search
|
|
:filter-option="filterOption"
|
|
>
|
|
<a-select-option
|
|
v-for="item in aliyunProductList"
|
|
:key="item.productKey"
|
|
:value="item.productKey"
|
|
:label="item.productName"
|
|
>{{
|
|
item.productName
|
|
}}</a-select-option
|
|
>
|
|
</a-select>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :span="24">
|
|
<p>产品映射</p>
|
|
<a-collapse
|
|
v-if="modelRef.mappings.length"
|
|
:activeKey="activeKey"
|
|
@change="onCollChange"
|
|
>
|
|
<a-collapse-panel
|
|
v-for="(
|
|
item, index
|
|
) in modelRef.mappings"
|
|
:key="index"
|
|
:header="
|
|
item.productKey
|
|
? aliyunProductList.find(
|
|
(i) =>
|
|
i.productKey ===
|
|
item.productKey,
|
|
)?.productName
|
|
: `产品映射${index + 1}`
|
|
"
|
|
>
|
|
<template #extra
|
|
><AIcon
|
|
type="DeleteOutlined"
|
|
@click="delItem(index)"
|
|
/></template>
|
|
<a-row :gutter="24">
|
|
<a-col :span="12">
|
|
<a-form-item
|
|
label="阿里云产品"
|
|
:name="[
|
|
'mappings',
|
|
index,
|
|
'productKey',
|
|
]"
|
|
:rules="{
|
|
required: true,
|
|
message:
|
|
'请选择阿里云产品',
|
|
}"
|
|
>
|
|
<a-select
|
|
placeholder="请选择阿里云产品"
|
|
v-model:value="
|
|
item.productKey
|
|
"
|
|
show-search
|
|
:filter-option="
|
|
filterOption
|
|
"
|
|
>
|
|
<a-select-option
|
|
v-for="i in getAliyunProductList(
|
|
item.productKey,
|
|
)"
|
|
:key="i.productKey"
|
|
:value="
|
|
i.productKey
|
|
"
|
|
:label="
|
|
i.productName
|
|
"
|
|
>{{
|
|
i.productName
|
|
}}</a-select-option
|
|
>
|
|
</a-select>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :span="12">
|
|
<a-form-item
|
|
label="平台产品"
|
|
:name="[
|
|
'mappings',
|
|
index,
|
|
'productId',
|
|
]"
|
|
:rules="{
|
|
required: true,
|
|
message:
|
|
'请选择平台产品',
|
|
}"
|
|
>
|
|
<a-select
|
|
placeholder="请选择平台产品"
|
|
v-model:value="
|
|
item.productId
|
|
"
|
|
show-search
|
|
:filter-option="
|
|
filterOption
|
|
"
|
|
>
|
|
<a-select-option
|
|
v-for="i in getPlatProduct(
|
|
item.productId,
|
|
)"
|
|
:key="i.id"
|
|
:value="item.id"
|
|
:label="i.name"
|
|
>{{
|
|
i.name
|
|
}}</a-select-option
|
|
>
|
|
</a-select>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
</a-collapse-panel>
|
|
</a-collapse>
|
|
</a-col>
|
|
<a-col :span="24">
|
|
<a-button
|
|
type="dashed"
|
|
style="width: 100%; margin-top: 10px"
|
|
@click="addItem"
|
|
>
|
|
<AIcon
|
|
type="PlusOutlined"
|
|
style="margin-left: 2px"
|
|
/>添加
|
|
</a-button>
|
|
</a-col>
|
|
<a-col :span="24" style="margin-top: 20px">
|
|
<a-form-item
|
|
label="说明"
|
|
name="description"
|
|
:rules="{
|
|
max: 200,
|
|
message: '最多输入200个字符',
|
|
}"
|
|
>
|
|
<a-textarea
|
|
v-model:value="modelRef.description"
|
|
placeholder="请输入说明"
|
|
showCount
|
|
:maxlength="200"
|
|
/>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
</a-form>
|
|
<div v-if="type === 'edit'">
|
|
<a-button
|
|
:loading="loading"
|
|
type="primary"
|
|
@click="saveBtn"
|
|
>保存</a-button
|
|
>
|
|
</div>
|
|
</a-col>
|
|
<a-col :span="8">
|
|
<Doc />
|
|
</a-col>
|
|
</a-row>
|
|
</a-card>
|
|
</page-container>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import Doc from './doc.vue';
|
|
import {
|
|
savePatch,
|
|
detail,
|
|
getRegionsList,
|
|
getAliyunProductsList,
|
|
queryProductList,
|
|
} from '@/api/northbound/alicloud';
|
|
import _ from 'lodash';
|
|
import { message } from 'ant-design-vue';
|
|
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
|
|
const formRef = ref();
|
|
|
|
const modelRef = reactive({
|
|
id: undefined,
|
|
name: undefined,
|
|
accessConfig: {
|
|
regionId: undefined,
|
|
instanceId: undefined,
|
|
accessKeyId: undefined,
|
|
accessSecret: undefined,
|
|
},
|
|
bridgeProductKey: undefined,
|
|
bridgeProductName: undefined,
|
|
mappings: [
|
|
{
|
|
productKey: undefined,
|
|
productId: undefined,
|
|
},
|
|
],
|
|
description: undefined,
|
|
});
|
|
|
|
const addItem = () => {
|
|
activeKey.value.push(String(modelRef.mappings.length));
|
|
modelRef.mappings.push({
|
|
productKey: undefined,
|
|
productId: undefined,
|
|
});
|
|
};
|
|
|
|
const delItem = (index: number) => {
|
|
modelRef.mappings.splice(index, 1);
|
|
};
|
|
|
|
const productList = ref<Record<string, any>[]>([]);
|
|
const regionsList = ref<Record<string, any>[]>([]);
|
|
const aliyunProductList = ref<Record<string, any>[]>([]);
|
|
const loading = ref<boolean>(false);
|
|
const type = ref<'edit' | 'view'>('edit');
|
|
const activeKey = ref<string[]>(['0']);
|
|
|
|
const filterOption = (input: string, option: any) => {
|
|
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
|
};
|
|
|
|
const queryRegionsList = async () => {
|
|
const resp = await getRegionsList();
|
|
if (resp.status === 200) {
|
|
regionsList.value = resp.result as Record<string, any>[];
|
|
}
|
|
};
|
|
const getProduct = async () => {
|
|
const resp = await queryProductList({
|
|
paging: false,
|
|
sorts: [{ name: 'createTime', order: 'desc' }],
|
|
});
|
|
if (resp.status === 200) {
|
|
productList.value = resp?.result as Record<string, any>[];
|
|
}
|
|
};
|
|
|
|
const getAliyunProduct = async (data: any) => {
|
|
if (data.regionId && data.accessKeyId && data.accessSecret) {
|
|
const resp: any = await getAliyunProductsList(data);
|
|
if (resp.status === 200) {
|
|
aliyunProductList.value = resp?.result?.data as Record<
|
|
string,
|
|
any
|
|
>[];
|
|
}
|
|
}
|
|
};
|
|
|
|
const productChange = () => {
|
|
const data = modelRef.accessConfig;
|
|
getAliyunProduct(data);
|
|
};
|
|
|
|
const getPlatProduct = (val: string) => {
|
|
const arr = modelRef.mappings.map((item) => item?.productId) || [];
|
|
const checked = _.cloneDeep(arr);
|
|
const _index = checked.findIndex((i) => i === val);
|
|
checked.splice(_index, 1);
|
|
const list = productList.value.filter(
|
|
(i: any) => !checked.includes(i?.id as any),
|
|
);
|
|
return list || [];
|
|
};
|
|
|
|
const getAliyunProductList = (val: string) => {
|
|
const items = modelRef.mappings.map((item) => item?.productKey) || [];
|
|
const checked = _.cloneDeep(items);
|
|
const _index = checked.findIndex((i) => i === val);
|
|
checked.splice(_index, 1);
|
|
const list = aliyunProductList.value?.filter(
|
|
(i: any) => !checked.includes(i?.productKey as any),
|
|
);
|
|
return list || [];
|
|
};
|
|
|
|
const onCollChange = (_key: string[]) => {
|
|
activeKey.value = _key;
|
|
};
|
|
|
|
const saveBtn = () => {
|
|
formRef.value
|
|
.validate()
|
|
.then(async (data: any) => {
|
|
const product = (aliyunProductList.value || []).find(
|
|
(item: any) =>
|
|
item?.bridgeProductKey === data?.bridgeProductKey,
|
|
);
|
|
data.bridgeProductName = product?.productName || '';
|
|
loading.value = true;
|
|
const resp = await savePatch(toRaw(modelRef));
|
|
loading.value = false;
|
|
if (resp.status === 200) {
|
|
message.success('操作成功!');
|
|
formRef.value.resetFields();
|
|
router.push('/iot/northbound/AliCloud');
|
|
}
|
|
})
|
|
.catch((err: any) => {
|
|
const _arr = err.errorFields.map((i: any) => i.name);
|
|
_arr.map((item: string | any[]) => {
|
|
if (item.length === 3 && !activeKey.value.includes(item[1])) {
|
|
activeKey.value.push(item[1]);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
watch(
|
|
() => route.params?.id,
|
|
async (newId) => {
|
|
if (newId) {
|
|
queryRegionsList();
|
|
getProduct();
|
|
if (newId === ':id' || !newId) return;
|
|
const resp = await detail(newId as string);
|
|
const _data: any = resp.result;
|
|
if (_data) {
|
|
getAliyunProduct(_data?.accessConfig);
|
|
}
|
|
Object.assign(modelRef, _data);
|
|
}
|
|
},
|
|
{ immediate: true, deep: true },
|
|
);
|
|
|
|
watch(
|
|
() => route.query.type,
|
|
(newVal) => {
|
|
if (newVal) {
|
|
type.value = newVal as 'edit' | 'view';
|
|
}
|
|
},
|
|
{ immediate: true, deep: true },
|
|
);
|
|
</script> |