Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
f2bd1d37a2
|
@ -0,0 +1,31 @@
|
||||||
|
import server from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询平台接入列表
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const queryList = (data: any) => server.post(`/network/card/platform/_query`, data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询详情
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const queryById = (id: any) => server.get(`/network/card/platform/${id}`)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const save = (data: any) => server.post(`/network/card/platform`, data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const update = (data: any) => server.patch(`/network/card/platform`, data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const del = (id: string) => server.remove(`/network/card/platform/${id}`)
|
|
@ -4,14 +4,14 @@
|
||||||
<a-popconfirm v-bind="popConfirm" :disabled="!isPermission || props.disabled">
|
<a-popconfirm v-bind="popConfirm" :disabled="!isPermission || props.disabled">
|
||||||
<a-tooltip v-if="tooltip" v-bind="tooltip">
|
<a-tooltip v-if="tooltip" v-bind="tooltip">
|
||||||
<slot v-if="noButton"></slot>
|
<slot v-if="noButton"></slot>
|
||||||
<a-button v-else v-bind="buttonProps" :disabled="_isPermission" @click="handleClick">
|
<a-button v-else v-bind="_buttonProps" :disabled="_isPermission" @click="handleClick">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<slot name="icon"></slot>
|
<slot name="icon"></slot>
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-button v-else v-bind="buttonProps" :disabled="_isPermission" @click="handleClick">
|
<a-button v-else v-bind="_buttonProps" :disabled="_isPermission" @click="handleClick">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<slot name="icon"></slot>
|
<slot name="icon"></slot>
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
<template v-else-if="tooltip">
|
<template v-else-if="tooltip">
|
||||||
<a-tooltip v-bind="tooltip">
|
<a-tooltip v-bind="tooltip">
|
||||||
<slot v-if="noButton"></slot>
|
<slot v-if="noButton"></slot>
|
||||||
<a-button v-else v-bind="buttonProps" :disabled="_isPermission" @click="handleClick">
|
<a-button v-else v-bind="_buttonProps" :disabled="_isPermission" @click="handleClick">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<slot name="icon"></slot>
|
<slot name="icon"></slot>
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<slot v-if="noButton"></slot>
|
<slot v-if="noButton"></slot>
|
||||||
<a-button v-else v-bind="buttonProps" :disabled="_isPermission" @click="handleClick">
|
<a-button v-else v-bind="_buttonProps" :disabled="_isPermission" @click="handleClick">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<slot name="icon"></slot>
|
<slot name="icon"></slot>
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
</template>
|
</template>
|
||||||
<a-tooltip v-else title="没有权限">
|
<a-tooltip v-else title="没有权限">
|
||||||
<slot v-if="noButton"></slot>
|
<slot v-if="noButton"></slot>
|
||||||
<a-button v-else v-bind="buttonProps" :disabled="_isPermission" @click="handleClick">
|
<a-button v-else v-bind="_buttonProps" :disabled="_isPermission" @click="handleClick">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<slot name="icon"></slot>
|
<slot name="icon"></slot>
|
||||||
|
@ -51,7 +51,9 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts" name="PermissionButton">
|
<script setup lang="ts" name="PermissionButton">
|
||||||
import type { ButtonProps, TooltipProps, PopconfirmProps } from 'ant-design-vue'
|
import { PropType } from 'vue'
|
||||||
|
import { TooltipProps, PopconfirmProps } from 'ant-design-vue/es'
|
||||||
|
import { buttonProps } from 'ant-design-vue/es/button/button'
|
||||||
import { usePermissionStore } from '@/store/permission';
|
import { usePermissionStore } from '@/store/permission';
|
||||||
|
|
||||||
interface PermissionButtonEmits {
|
interface PermissionButtonEmits {
|
||||||
|
@ -60,16 +62,33 @@ interface PermissionButtonEmits {
|
||||||
|
|
||||||
const emits = defineEmits<PermissionButtonEmits>()
|
const emits = defineEmits<PermissionButtonEmits>()
|
||||||
|
|
||||||
interface PermissionButtonProps extends ButtonProps {
|
// interface PermissionButtonProps extends ButtonProps {
|
||||||
tooltip?: TooltipProps;
|
// tooltip?: TooltipProps;
|
||||||
popConfirm?: PopconfirmProps;
|
// popConfirm?: PopconfirmProps;
|
||||||
hasPermission?: string | Array<string>;
|
// hasPermission?: string | Array<string>;
|
||||||
noButton?: boolean;
|
// noButton?: boolean;
|
||||||
}
|
// }
|
||||||
const props = withDefaults(defineProps<PermissionButtonProps>(), {
|
// const props = withDefaults(defineProps<PermissionButtonProps>(), {
|
||||||
noButton: false
|
// noButton: false,
|
||||||
|
// })
|
||||||
|
const props = defineProps({
|
||||||
|
noButton: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => false
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
type: Object as PropType<TooltipProps>,
|
||||||
|
},
|
||||||
|
popConfirm: {
|
||||||
|
type: Object as PropType<PopconfirmProps>,
|
||||||
|
},
|
||||||
|
hasPermission: {
|
||||||
|
type: String || Array,
|
||||||
|
},
|
||||||
|
...buttonProps()
|
||||||
})
|
})
|
||||||
const { tooltip, popConfirm, hasPermission, noButton, ...buttonProps } = props;
|
|
||||||
|
const { tooltip, popConfirm, hasPermission, noButton, ..._buttonProps } = props;
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
|
@ -82,7 +101,7 @@ const isPermission = computed(() => {
|
||||||
const _isPermission = computed(() =>
|
const _isPermission = computed(() =>
|
||||||
'hasPermission' in props && isPermission.value
|
'hasPermission' in props && isPermission.value
|
||||||
? 'disabled' in buttonProps
|
? 'disabled' in buttonProps
|
||||||
? buttonProps.disabled
|
? buttonProps.disabled as boolean
|
||||||
: false
|
: false
|
||||||
: true
|
: true
|
||||||
)
|
)
|
||||||
|
|
|
@ -162,7 +162,7 @@ const findChildrenRoute = (code: string, url: string, routes: any[] = []): MenuI
|
||||||
const extraRoutes = extraRouteObj[code].children.map((route: MenuItem) => {
|
const extraRoutes = extraRouteObj[code].children.map((route: MenuItem) => {
|
||||||
return {
|
return {
|
||||||
url: `${url}/${route.code}`,
|
url: `${url}/${route.code}`,
|
||||||
code: route.code,
|
code: `${code}/${route.code}`,
|
||||||
name: route.name,
|
name: route.name,
|
||||||
isShow: false
|
isShow: false
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,249 @@
|
||||||
|
<template>
|
||||||
|
<page-container>
|
||||||
|
<a-card>
|
||||||
|
<a-row :gutter="24">
|
||||||
|
<a-col :span="14">
|
||||||
|
<TitleComponent data="详情" />
|
||||||
|
<a-form
|
||||||
|
:layout="'vertical'"
|
||||||
|
ref="formRef"
|
||||||
|
:rules="rules"
|
||||||
|
:model="form"
|
||||||
|
>
|
||||||
|
<a-form-item
|
||||||
|
label="平台类型"
|
||||||
|
name="operatorName"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<PlatformType
|
||||||
|
:disabled="false"
|
||||||
|
:model="'singular'"
|
||||||
|
:itemStyle="{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
minWidth: '130px',
|
||||||
|
}"
|
||||||
|
:options="platformTypeList"
|
||||||
|
v-model:value="form.operatorName"
|
||||||
|
@change="typeChange"
|
||||||
|
></PlatformType
|
||||||
|
></a-form-item>
|
||||||
|
<a-form-item label="名称" name="name">
|
||||||
|
<a-input
|
||||||
|
v-model:value="form.name"
|
||||||
|
placeholder="请输入名称"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<!-- onelink -->
|
||||||
|
<div v-if="form.operatorName === 'onelink'">
|
||||||
|
<a-form-item label="App ID" name="appId">
|
||||||
|
<a-input
|
||||||
|
v-model:value="form.appId"
|
||||||
|
placeholder="请输入App ID"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="Password" name="passWord">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="form.passWord"
|
||||||
|
placeholder="请输入密码"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="接口地址" name="apiAddr">
|
||||||
|
<a-input
|
||||||
|
v-model:value="form.apiAddr"
|
||||||
|
placeholder="请输入接口地址"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
<!-- ctwing -->
|
||||||
|
<div v-if="form.operatorName === 'ctwing'">
|
||||||
|
<a-form-item label="用户id" name="userId">
|
||||||
|
<a-input
|
||||||
|
v-model:value="form.userId"
|
||||||
|
placeholder="请输入用户id"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="密码" name="passWord">
|
||||||
|
<a-input-password
|
||||||
|
v-model:value="form.passWord"
|
||||||
|
placeholder="请输入密码"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="secretKey" name="secretKey">
|
||||||
|
<a-input
|
||||||
|
v-model:value="form.secretKey"
|
||||||
|
placeholder="请输入secretKey"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
<!-- unicom -->
|
||||||
|
<div v-if="form.operatorName === 'unicom'">
|
||||||
|
<a-form-item label="App ID" name="appId">
|
||||||
|
<a-input
|
||||||
|
v-model:value="form.appId"
|
||||||
|
placeholder="请输入App ID"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="App Secret" name="appSecret">
|
||||||
|
<a-input
|
||||||
|
v-model:value="form.appSecret"
|
||||||
|
placeholder="请输入App Secret"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="创建者ID" name="openId">
|
||||||
|
<a-input
|
||||||
|
v-model:value="form.openId"
|
||||||
|
placeholder="请输入创建者ID"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-form-item label="说明" name="explain">
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="form.explain"
|
||||||
|
placeholder="请输入说明"
|
||||||
|
showCount
|
||||||
|
:rows="3"
|
||||||
|
:maxlength="200"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<a-divider />
|
||||||
|
<a-button
|
||||||
|
:loading="saveBtnLoading"
|
||||||
|
type="primary"
|
||||||
|
@click="handleSave"
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="10">
|
||||||
|
<Doc :type="form.operatorName" />
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-card>
|
||||||
|
</page-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { getImage } from '@/utils/comm';
|
||||||
|
import PlatformType from '@/views/iot-card/components/PlatformType.vue';
|
||||||
|
import { queryById, save, update } from '@/api/iot-card/platform';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import Doc from '../doc/index.vue';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const formRef = ref();
|
||||||
|
const saveBtnLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
operatorName: 'onelink',
|
||||||
|
name: undefined,
|
||||||
|
// onelink
|
||||||
|
appId: undefined,
|
||||||
|
passWord: undefined,
|
||||||
|
apiAddr: undefined,
|
||||||
|
// ctwing
|
||||||
|
userId: undefined,
|
||||||
|
secretKey: undefined,
|
||||||
|
// unicom
|
||||||
|
appSecret: undefined,
|
||||||
|
openId: undefined,
|
||||||
|
explain: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
const platformTypeList = [
|
||||||
|
{
|
||||||
|
label: '移动OneLink',
|
||||||
|
value: 'onelink',
|
||||||
|
imgUrl: getImage('/iot-card/onelink.png'),
|
||||||
|
imgSize: ['78px', '20px'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '电信Ctwing',
|
||||||
|
value: 'ctwing',
|
||||||
|
imgUrl: getImage('/iot-card/ctwingcmp.png'),
|
||||||
|
imgSize: ['52px', '25px'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '联通Unicom',
|
||||||
|
value: 'unicom',
|
||||||
|
imgUrl: getImage('/iot-card/unicom.png'),
|
||||||
|
imgSize: ['56px', '41px'],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入名称' },
|
||||||
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
|
],
|
||||||
|
appId: [
|
||||||
|
{ required: true, message: '请输入App ID' },
|
||||||
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
|
],
|
||||||
|
passWord: [
|
||||||
|
{ required: true, message: '请输入密码' },
|
||||||
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
|
],
|
||||||
|
apiAddr: [{ required: true, message: '请输入接口地址' }],
|
||||||
|
userId: [
|
||||||
|
{ required: true, message: '请输入用户 ID' },
|
||||||
|
{ max: 64, message: '最多可输入64个字符' },
|
||||||
|
],
|
||||||
|
secretKey: [{ required: true, message: '请输入secretKey' }],
|
||||||
|
appSecret: [{ required: true, message: '请输入App Secret' }],
|
||||||
|
openId: [{ required: true, message: '请输入创建者ID' }],
|
||||||
|
explain: [{ required: false, max: 200, message: '最多可输入200个字符' }],
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDetail = async () => {
|
||||||
|
if (route.params.id === ':id') return;
|
||||||
|
const resp: any = await queryById(route.params.id);
|
||||||
|
if (resp.status === 200) {
|
||||||
|
Object.assign(form, resp.result, { ...resp.result.config });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const typeChange = (val: any) => {
|
||||||
|
formRef.value.resetFields();
|
||||||
|
form.operatorName = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
const data: any = await formRef.value.validate();
|
||||||
|
const formData = {
|
||||||
|
operatorName: data.operatorName,
|
||||||
|
name: data.name,
|
||||||
|
config: {
|
||||||
|
appId: data.appId,
|
||||||
|
passWord: data.passWord,
|
||||||
|
apiAddr: data.apiAddr,
|
||||||
|
userId: data.userId,
|
||||||
|
secretKey: data.secretKey,
|
||||||
|
appSecret: data.appSecret,
|
||||||
|
openId: data.openId,
|
||||||
|
},
|
||||||
|
explain: data.explain,
|
||||||
|
};
|
||||||
|
saveBtnLoading.value = true;
|
||||||
|
|
||||||
|
const res: any =
|
||||||
|
route.params.id === ':id'
|
||||||
|
? await save(formData)
|
||||||
|
: await update({ id: route.params.id, ...formData });
|
||||||
|
if (res.status === 200) {
|
||||||
|
message.success('保存成功!');
|
||||||
|
router.back();
|
||||||
|
}
|
||||||
|
saveBtnLoading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
getDetail();
|
||||||
|
</script>
|
|
@ -0,0 +1,220 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="type === 'onelink'" class="doc">
|
||||||
|
<div class="url">
|
||||||
|
中国移动物联卡能力开放平台:
|
||||||
|
<a
|
||||||
|
style="word-break: break-all"
|
||||||
|
href="https://api.iot.10086.cn/api/index.html#/login"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
https://api.iot.10086.cn/api/index.html#/login
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<h1>1.概述</h1>
|
||||||
|
<p>
|
||||||
|
平台对接通过API的方式与三方系统进行数据对接,为物联卡的管理提供数据交互支持。
|
||||||
|
</p>
|
||||||
|
<h1>2.配置说明</h1>
|
||||||
|
<h2>1、APP ID</h2>
|
||||||
|
<p>
|
||||||
|
第三方应用唯一标识,中国移动物联网全网管理员在 OneLink
|
||||||
|
能力开放平台上分配并展示给集团客户。
|
||||||
|
<br />
|
||||||
|
获取路径:“中移物联卡能力开放平台”--“个人中心”--“客户信息”--“接入信息”
|
||||||
|
</p>
|
||||||
|
<div class="image">
|
||||||
|
<a-image
|
||||||
|
width="100%"
|
||||||
|
:src="getImage('/iot-card/onelink-appid.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h2>2、Password</h2>
|
||||||
|
<p>
|
||||||
|
API 接入秘钥,由中国移动物联网提供,集团客户从“OneLink
|
||||||
|
能力开放平台”获取。
|
||||||
|
<br />
|
||||||
|
获取路径:“中移物联卡能力开放平台”--“个人中心”--“客户信息”--“接入信息”
|
||||||
|
</p>
|
||||||
|
<div class="image">
|
||||||
|
<a-image
|
||||||
|
width="100%"
|
||||||
|
:src="getImage('/iot-card/onelink-pass.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<h2>3、接口地址</h2>
|
||||||
|
<p>
|
||||||
|
https://api.iot.10086.cn/v5/ec/get/token
|
||||||
|
<br />
|
||||||
|
token后缀请根据实际情况填写
|
||||||
|
<br />
|
||||||
|
示例:https://api.iot.10086.cn/v5/authService?appid=xxx&password=xxx&transid=xxx
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="type === 'ctwing'" class="doc">
|
||||||
|
<div class="url">
|
||||||
|
5G连接管理平台:
|
||||||
|
<a
|
||||||
|
style="word-break: break-all"
|
||||||
|
href="https://cmp.ctwing.cn:4821/login"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
https://cmp.ctwing.cn:4821/login
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1>1.概述</h1>
|
||||||
|
<p>
|
||||||
|
平台对接通过API的方式与三方系统进行数据对接,为物联卡的管理提供数据交互支持。
|
||||||
|
</p>
|
||||||
|
<h1>2.配置说明</h1>
|
||||||
|
<h2>1、用户 id</h2>
|
||||||
|
<p>
|
||||||
|
5G连接管理平台用户的唯一标识,用于身份识别。
|
||||||
|
<br />
|
||||||
|
获取路径:“5G连接管理平台”--“能力开放”--“API网关账号管理”
|
||||||
|
</p>
|
||||||
|
<div class="image">
|
||||||
|
<a-image
|
||||||
|
width="100%"
|
||||||
|
:src="getImage('/iot-card/ctwing-id.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>2、密码</h2>
|
||||||
|
<p>
|
||||||
|
用户id经加密之后的密码。
|
||||||
|
<br />
|
||||||
|
获取路径:“5G连接管理平台”--“能力开放”--“API网关账号管理”
|
||||||
|
</p>
|
||||||
|
<div class="image">
|
||||||
|
<a-image
|
||||||
|
width="100%"
|
||||||
|
:src="getImage('/iot-card/ctwing-pass.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>3、secretKey</h2>
|
||||||
|
<p>
|
||||||
|
APP secret唯一秘钥。
|
||||||
|
<br />
|
||||||
|
获取路径:“5G连接管理平台”--“能力开放”--“API网关账号管理”
|
||||||
|
</p>
|
||||||
|
<div class="image">
|
||||||
|
<a-image
|
||||||
|
width="100%"
|
||||||
|
:src="getImage('/iot-card/ctwing-secret.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="type === 'unicom'" class="doc">
|
||||||
|
<div class="url">
|
||||||
|
雁飞智连CMP平台:
|
||||||
|
<a
|
||||||
|
style="word-break: break-all"
|
||||||
|
href=" https://cmp.10646.cn/webframe/login"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
https://cmp.10646.cn/webframe/login
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h1>1.概述</h1>
|
||||||
|
<p>
|
||||||
|
平台对接通过API的方式与三方系统进行数据对接,为物联卡的管理提供数据交互支持。
|
||||||
|
</p>
|
||||||
|
<h1>2.配置说明</h1>
|
||||||
|
<h2>1、APP ID</h2>
|
||||||
|
<p>
|
||||||
|
第三方应用唯一标识。
|
||||||
|
<br />
|
||||||
|
获取路径:“雁飞智连CMP平台”--“我的应用”--“应用列表”
|
||||||
|
</p>
|
||||||
|
<div class="image">
|
||||||
|
<a-image
|
||||||
|
width="100%"
|
||||||
|
:src="getImage('/iot-card/unicom-id.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>2、App Secret</h2>
|
||||||
|
<p>
|
||||||
|
API 接入秘钥。
|
||||||
|
<br />
|
||||||
|
获取路径:“雁飞智连CMP平台”--“我的应用”--“应用列表”
|
||||||
|
</p>
|
||||||
|
<div class="image">
|
||||||
|
<a-image
|
||||||
|
width="100%"
|
||||||
|
:src="getImage('/iot-card/unicom-secret.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>3、创建者ID</h2>
|
||||||
|
<p>
|
||||||
|
接口参数中的 OpenId。
|
||||||
|
<br />
|
||||||
|
获取路径:“雁飞智连CMP平台”--“我的应用”--“应用列表”
|
||||||
|
<br />
|
||||||
|
</p>
|
||||||
|
<div class="image">
|
||||||
|
<a-image
|
||||||
|
width="100%"
|
||||||
|
:src="getImage('/iot-card/unicom-openid.png')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getImage } from '@/utils/comm';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: { type: String, default: 'onelink' },
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.doc {
|
||||||
|
height: 800px;
|
||||||
|
padding: 24px;
|
||||||
|
overflow-y: auto;
|
||||||
|
color: rgba(#000, 0.8);
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
|
||||||
|
.url {
|
||||||
|
padding: 8px 16px;
|
||||||
|
color: #2f54eb;
|
||||||
|
background-color: rgba(#a7bdf7, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 16px 0;
|
||||||
|
color: rgba(#000, 0.85);
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
|
||||||
|
// &:first-child {
|
||||||
|
// margin-top: 0;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 6px 0;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image {
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,305 @@
|
||||||
|
<!-- 平台对接 -->
|
||||||
|
<template>
|
||||||
|
<page-container>
|
||||||
|
<Search
|
||||||
|
:columns="columns"
|
||||||
|
target="platform-search"
|
||||||
|
@search="handleSearch"
|
||||||
|
/>
|
||||||
|
<JTable
|
||||||
|
ref="platformRef"
|
||||||
|
:columns="columns"
|
||||||
|
:request="queryList"
|
||||||
|
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||||
|
:params="params"
|
||||||
|
>
|
||||||
|
<template #headerTitle>
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="handleAdd">
|
||||||
|
<AIcon type="PlusOutlined" />新增
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
<template #card="slotProps">
|
||||||
|
<CardBox
|
||||||
|
:value="slotProps"
|
||||||
|
:actions="getActions(slotProps, 'card')"
|
||||||
|
v-bind="slotProps"
|
||||||
|
:status="slotProps.state.value"
|
||||||
|
:statusText="slotProps.state.text"
|
||||||
|
:statusNames="{
|
||||||
|
enabled: 'success',
|
||||||
|
disabled: 'error',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #img>
|
||||||
|
<slot name="img">
|
||||||
|
<img :src="getImage('/iot-card/iot-card-bg.png')" />
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
<template #content>
|
||||||
|
<h3 class="card-item-content-title">
|
||||||
|
{{ slotProps.name }}
|
||||||
|
</h3>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
平台类型
|
||||||
|
</div>
|
||||||
|
<div>{{ slotProps.operatorName }}</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div class="card-item-content-text">说明</div>
|
||||||
|
<div>{{ slotProps.explain }}</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
<template #actions="item">
|
||||||
|
<a-tooltip
|
||||||
|
v-bind="item.tooltip"
|
||||||
|
:title="item.disabled && item.tooltip.title"
|
||||||
|
>
|
||||||
|
<a-popconfirm
|
||||||
|
v-if="item.popConfirm"
|
||||||
|
v-bind="item.popConfirm"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
>
|
||||||
|
<a-button :disabled="item.disabled">
|
||||||
|
<AIcon
|
||||||
|
type="DeleteOutlined"
|
||||||
|
v-if="item.key === 'delete'"
|
||||||
|
/>
|
||||||
|
<template v-else>
|
||||||
|
<AIcon :type="item.icon" />
|
||||||
|
<span>{{ item.text }}</span>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
<template v-else>
|
||||||
|
<a-button
|
||||||
|
:disabled="item.disabled"
|
||||||
|
@click="item.onClick"
|
||||||
|
>
|
||||||
|
<AIcon
|
||||||
|
type="DeleteOutlined"
|
||||||
|
v-if="item.key === 'delete'"
|
||||||
|
/>
|
||||||
|
<template v-else>
|
||||||
|
<AIcon :type="item.icon" />
|
||||||
|
<span>{{ item.text }}</span>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</CardBox>
|
||||||
|
</template>
|
||||||
|
<template #state="slotProps">
|
||||||
|
<a-badge
|
||||||
|
:text="slotProps.state.text"
|
||||||
|
:status="
|
||||||
|
slotProps.state.value === 'disabled'
|
||||||
|
? 'error'
|
||||||
|
: 'success'
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #action="slotProps">
|
||||||
|
<a-space :size="16">
|
||||||
|
<a-tooltip
|
||||||
|
v-for="i in getActions(slotProps, 'table')"
|
||||||
|
:key="i.key"
|
||||||
|
v-bind="i.tooltip"
|
||||||
|
>
|
||||||
|
<a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
|
||||||
|
<a-button
|
||||||
|
:disabled="i.disabled"
|
||||||
|
style="padding: 0"
|
||||||
|
type="link"
|
||||||
|
><AIcon :type="i.icon"
|
||||||
|
/></a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
<a-button
|
||||||
|
style="padding: 0"
|
||||||
|
type="link"
|
||||||
|
v-else
|
||||||
|
@click="i.onClick && i.onClick(slotProps)"
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
:disabled="i.disabled"
|
||||||
|
style="padding: 0"
|
||||||
|
type="link"
|
||||||
|
><AIcon :type="i.icon"
|
||||||
|
/></a-button>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</JTable>
|
||||||
|
</page-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getImage } from '@/utils/comm';
|
||||||
|
import type { ActionsType } from '@/components/Table';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { queryList, update, del } from '@/api/iot-card/platform';
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const platformRef = ref<Record<string, any>>({});
|
||||||
|
const params = ref<Record<string, any>>({});
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
ellipsis: true,
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '平台类型',
|
||||||
|
dataIndex: 'operatorName',
|
||||||
|
key: 'operatorName',
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '移动OneLink', value: 'onelink' },
|
||||||
|
{ label: '电信Ctwing', value: 'ctwing' },
|
||||||
|
{ label: '联通Unicom', value: 'unicom' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'state',
|
||||||
|
key: 'state',
|
||||||
|
scopedSlots: true,
|
||||||
|
width: 120,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '启用', value: 'enabled' },
|
||||||
|
{ label: '禁用', value: 'disabled' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '说明',
|
||||||
|
dataIndex: 'explain',
|
||||||
|
key: 'explain',
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 250,
|
||||||
|
scopedSlots: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const statusUpdate = async (data: any) => {
|
||||||
|
const res = await update(data);
|
||||||
|
if (res.status === 200) {
|
||||||
|
message.success('操作成功');
|
||||||
|
platformRef.value?.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getActions = (
|
||||||
|
data: Partial<Record<string, any>>,
|
||||||
|
type: 'card' | 'table',
|
||||||
|
): ActionsType[] => {
|
||||||
|
if (!data) return [];
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: 'edit',
|
||||||
|
text: '编辑',
|
||||||
|
tooltip: {
|
||||||
|
title: '编辑',
|
||||||
|
},
|
||||||
|
icon: 'EditOutlined',
|
||||||
|
onClick: () => {
|
||||||
|
router.push(`/iot-card/Platform/detail/${data.id}`);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'action',
|
||||||
|
text: data.state.value === 'enabled' ? '禁用' : '启用',
|
||||||
|
tooltip: {
|
||||||
|
title: data.state.value === 'enabled' ? '禁用' : '启用',
|
||||||
|
},
|
||||||
|
icon:
|
||||||
|
data.state.value === 'enabled'
|
||||||
|
? 'StopOutlined'
|
||||||
|
: 'PlayCircleOutlined',
|
||||||
|
popConfirm: {
|
||||||
|
title: `确认${
|
||||||
|
data.state.value === 'enabled' ? '禁用' : '启用'
|
||||||
|
}?`,
|
||||||
|
okText: ' 确定',
|
||||||
|
cancelText: '取消',
|
||||||
|
onConfirm: () => {
|
||||||
|
if (data.state.value === 'enabled') {
|
||||||
|
statusUpdate({
|
||||||
|
id: data.id,
|
||||||
|
config: { ...data.config },
|
||||||
|
state: 'disabled',
|
||||||
|
operatorName: data.operatorName,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
statusUpdate({
|
||||||
|
id: data.id,
|
||||||
|
config: { ...data.config },
|
||||||
|
state: 'enabled',
|
||||||
|
operatorName: data.operatorName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'delete',
|
||||||
|
text: '删除',
|
||||||
|
tooltip: {
|
||||||
|
title:
|
||||||
|
data.state.value !== 'enabled' ? '删除' : '请先禁用再删除',
|
||||||
|
},
|
||||||
|
disabled: data.state.value === 'enabled',
|
||||||
|
popConfirm: {
|
||||||
|
title: '确认删除?',
|
||||||
|
okText: ' 确定',
|
||||||
|
cancelText: '取消',
|
||||||
|
onConfirm: async () => {
|
||||||
|
const resp: any = await del(data.id);
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功!');
|
||||||
|
platformRef.value?.reload();
|
||||||
|
} else {
|
||||||
|
message.error('操作失败!');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
icon: 'DeleteOutlined',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = (params: any) => {
|
||||||
|
console.log(params);
|
||||||
|
params.value = params;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增
|
||||||
|
*/
|
||||||
|
const handleAdd = () => {
|
||||||
|
router.push(`/iot-card/Platform/detail/:id`)
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
|
@ -0,0 +1,205 @@
|
||||||
|
<!-- 平台类型 -->
|
||||||
|
<template>
|
||||||
|
<div :class="['radio-card-items', className, disabled ? 'disabled' : '']">
|
||||||
|
<div
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.value"
|
||||||
|
:style="itemStyle"
|
||||||
|
:class="[
|
||||||
|
'radio-card-item',
|
||||||
|
keys.includes(item.value) ? 'checked' : '',
|
||||||
|
]"
|
||||||
|
@click="toggleOption(item.value)"
|
||||||
|
>
|
||||||
|
<div class="card-list">
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
:style="`width: ${item.imgSize?.[0]}; height: ${item.imgSize?.[1]}`"
|
||||||
|
v-if="item.imgUrl"
|
||||||
|
:src="item.imgUrl"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>{{ item.label }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="checked-icon">
|
||||||
|
<div><AIcon type="CheckOutlined" /></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const emit = defineEmits(['update:value', 'change'], );
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
model: {
|
||||||
|
validator: function (value) {
|
||||||
|
return ['multiple', 'singular'].includes(value);
|
||||||
|
},
|
||||||
|
default: () => 'singular',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: () => '',
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => true,
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const keys = ref(
|
||||||
|
!(props.model && props.model === 'singular') ? props.value : [props.value],
|
||||||
|
);
|
||||||
|
|
||||||
|
const toggleOption = (key) => {
|
||||||
|
if (props.disabled) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const optionIndex = keys.value.includes(key);
|
||||||
|
const newKeys = [...keys.value];
|
||||||
|
const singular = props.model && props.model === 'singular';
|
||||||
|
if (!optionIndex) {
|
||||||
|
if (!(props.model && props.model === 'singular')) {
|
||||||
|
newKeys.push(key);
|
||||||
|
} else {
|
||||||
|
newKeys[0] = key;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newKeys.splice(optionIndex, 1);
|
||||||
|
}
|
||||||
|
emit('update:value', singular ? newKeys[0] : newKeys);
|
||||||
|
emit('change', singular ? newKeys[0] : newKeys);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(newVal) => {
|
||||||
|
keys.value = !(props.model && props.model === 'singular')
|
||||||
|
? newVal
|
||||||
|
: [newVal];
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@border: 1px solid @border-color-base;
|
||||||
|
|
||||||
|
.radio-card-items {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.radio-card-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 180px;
|
||||||
|
padding: 22px 28px;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 14px;
|
||||||
|
border: @border;
|
||||||
|
border-radius: @border-radius-base;
|
||||||
|
|
||||||
|
.card-list {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
div {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> img {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: @primary-color-hover;
|
||||||
|
border-color: @primary-color-hover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checked-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: -22px;
|
||||||
|
bottom: -22px;
|
||||||
|
z-index: 2;
|
||||||
|
display: none;
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
color: #fff;
|
||||||
|
background-color: @primary-color-active;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
|
||||||
|
> div {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
|
||||||
|
> span {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
left: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.checked {
|
||||||
|
position: relative;
|
||||||
|
color: @primary-color-active;
|
||||||
|
border-color: @primary-color-active;
|
||||||
|
|
||||||
|
> .checked-icon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
.radio-card-item {
|
||||||
|
color: @disabled-color;
|
||||||
|
border-color: @disabled-bg;
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
.checked-icon {
|
||||||
|
background-color: @disabled-active-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: @disabled-color;
|
||||||
|
border-color: @disabled-active-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.checked {
|
||||||
|
color: @disabled-color;
|
||||||
|
border-color: @disabled-active-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue