feat: 增加物联卡列表卡片、导出、导入、绑定设备
This commit is contained in:
parent
2b6048707b
commit
ac62778a2f
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
|
@ -65,3 +65,36 @@ export const sync = () => server.get(`/network/card/state/_sync`);
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
export const removeCards = (data: any) => server.post(`/network/card/batch/_delete`, data);
|
export const removeCards = (data: any) => server.post(`/network/card/batch/_delete`, data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解绑设备
|
||||||
|
* @param cardId
|
||||||
|
*/
|
||||||
|
export const unbind = (cardId: string) => server.get(`/network/card/${cardId}/_unbind`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询未绑定设备列表
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const queryUnbounded = (data: any) => server.post(`/network/card/unbounded/device/_query`, data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定设备
|
||||||
|
* @param cardId
|
||||||
|
* @param deviceId 选择的设备id
|
||||||
|
*/
|
||||||
|
export const bind = (cardId: string | any, deviceId: string) => server.get(`/network/card/${cardId}/${deviceId}/_bind`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入物联卡实例
|
||||||
|
* @param configId 对接平台id
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export const _import = (configId: any, params: any) => server.get(`/network/card/${configId}/_import`, params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id批量导出
|
||||||
|
* @param format 类型 xlsx、csv
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export const _export = (format: string, data: any) => server.post(`/network/card/download.${format}/_query`, data, 'blob');
|
|
@ -232,6 +232,17 @@ const handleClick = () => {
|
||||||
:deep(.card-item-content-title) {
|
:deep(.card-item-content-title) {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.card-item-heard-name) {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.card-item-content-text) {
|
||||||
|
color: rgba(0, 0, 0, 0.75);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-mask {
|
.card-mask {
|
||||||
|
|
|
@ -54,6 +54,17 @@ export const downloadObject = (record: Record<string, any>, fileName: string, fo
|
||||||
formElement.submit();
|
formElement.submit();
|
||||||
document.body.removeChild(formElement);
|
document.body.removeChild(formElement);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const downloadFileByUrl = (url: string, name: string, type: string) => {
|
||||||
|
const downNode = document.createElement('a');
|
||||||
|
downNode.style.display = 'none';
|
||||||
|
downNode.download = `${name}.${type}`;
|
||||||
|
downNode.href = url;
|
||||||
|
document.body.appendChild(downNode);
|
||||||
|
downNode.click();
|
||||||
|
document.body.removeChild(downNode);
|
||||||
|
};
|
||||||
|
|
||||||
// 是否不是community版本
|
// 是否不是community版本
|
||||||
export const isNoCommunity = !(localStorage.getItem(SystemConst.VERSION_CODE) === 'community');
|
export const isNoCommunity = !(localStorage.getItem(SystemConst.VERSION_CODE) === 'community');
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
<!-- 绑定设备 -->
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:maskClosable="false"
|
||||||
|
width="1100px"
|
||||||
|
:visible="true"
|
||||||
|
title="选择设备"
|
||||||
|
@ok="handleOk"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
:confirmLoading="btnLoading"
|
||||||
|
>
|
||||||
|
<div style="margin-top: 10px">
|
||||||
|
<Search
|
||||||
|
:columns="columns"
|
||||||
|
target="iot-card-management-search"
|
||||||
|
@search="handleSearch"
|
||||||
|
/>
|
||||||
|
<JTable
|
||||||
|
ref="bindDeviceRef"
|
||||||
|
:columns="columns"
|
||||||
|
:request="queryUnbounded"
|
||||||
|
:defaultParams="{
|
||||||
|
sorts: [{ name: 'createTime', order: 'desc' }],
|
||||||
|
}"
|
||||||
|
:rowSelection="{
|
||||||
|
type: 'radio',
|
||||||
|
selectedRowKeys: _selectedRowKeys,
|
||||||
|
onSelect: onSelectChange,
|
||||||
|
}"
|
||||||
|
@cancelSelect="cancelSelect"
|
||||||
|
:params="params"
|
||||||
|
>
|
||||||
|
<template #registryTime="slotProps">
|
||||||
|
{{
|
||||||
|
slotProps.registryTime
|
||||||
|
? moment(slotProps.registryTime).format(
|
||||||
|
'YYYY-MM-DD HH:mm:ss',
|
||||||
|
)
|
||||||
|
: ''
|
||||||
|
}}
|
||||||
|
</template>
|
||||||
|
<template #state="slotProps">
|
||||||
|
<a-badge
|
||||||
|
:text="slotProps.state.text"
|
||||||
|
:status="statusMap.get(slotProps.state.value)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</JTable>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { queryUnbounded, bind } from '@/api/iot-card/cardManagement';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['change']);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
cardId: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const bindDeviceRef = ref<Record<string, any>>({});
|
||||||
|
const params = ref<Record<string, any>>({});
|
||||||
|
const _selectedRowKeys = ref<string[]>([]);
|
||||||
|
const btnLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
const statusMap = new Map();
|
||||||
|
statusMap.set('online', 'processing');
|
||||||
|
statusMap.set('offline', 'error');
|
||||||
|
statusMap.set('notActive', 'warning');
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
ellipsis: true,
|
||||||
|
fixed: 'left',
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '设备名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
ellipsis: true,
|
||||||
|
search: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '注册时间',
|
||||||
|
dataIndex: 'registryTime',
|
||||||
|
key: 'registryTime',
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'date',
|
||||||
|
},
|
||||||
|
// sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'state',
|
||||||
|
key: 'state',
|
||||||
|
scopedSlots: true,
|
||||||
|
search: {
|
||||||
|
type: 'select',
|
||||||
|
options: [
|
||||||
|
{ label: '禁用', value: 'notActive' },
|
||||||
|
{ label: '离线', value: 'offline' },
|
||||||
|
{ label: '在线', value: 'online' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// filterMultiple: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleSearch = (params: any) => {
|
||||||
|
console.log(params);
|
||||||
|
params.value = params;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onSelectChange = (record: any) => {
|
||||||
|
_selectedRowKeys.value = [record.id];
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelSelect = () => {
|
||||||
|
_selectedRowKeys.value = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOk = () => {
|
||||||
|
btnLoading.value = true;
|
||||||
|
bind(props.cardId, _selectedRowKeys.value[0])
|
||||||
|
.then((resp: any) => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功');
|
||||||
|
emit('change', true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
btnLoading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('change', false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
|
@ -0,0 +1,65 @@
|
||||||
|
<template>
|
||||||
|
<!-- 导入 -->
|
||||||
|
<a-modal
|
||||||
|
:maskClosable="false"
|
||||||
|
:visible="true"
|
||||||
|
title="导出"
|
||||||
|
@ok="handleOk"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<div style="margin-top: 10px">
|
||||||
|
<a-space>
|
||||||
|
<span>文件格式:</span>
|
||||||
|
<a-radio-group
|
||||||
|
v-model:value="type"
|
||||||
|
placeholder="请选择文件格式"
|
||||||
|
button-style="solid"
|
||||||
|
>
|
||||||
|
<a-radio-button value="xlsx">xlsx</a-radio-button>
|
||||||
|
<a-radio-button value="csv">csv</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import moment from 'moment';
|
||||||
|
import { _export } from '@/api/iot-card/cardManagement';
|
||||||
|
import { downloadFileByUrl } from '@/utils/utils';
|
||||||
|
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const type = ref<string>('xlsx');
|
||||||
|
|
||||||
|
const handleOk = () => {
|
||||||
|
console.log(props.data);
|
||||||
|
_export(type.value, props.data).then((res: any) => {
|
||||||
|
if (res) {
|
||||||
|
const blob = new Blob([res.data], { type: type.value });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
downloadFileByUrl(
|
||||||
|
url,
|
||||||
|
`物联卡管理-${moment(new Date()).format(
|
||||||
|
'YYYY/MM/DD HH:mm:ss',
|
||||||
|
)}`,
|
||||||
|
type.value,
|
||||||
|
);
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('close');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less"></style>
|
|
@ -0,0 +1,157 @@
|
||||||
|
<template>
|
||||||
|
<!-- 导入 -->
|
||||||
|
<a-modal
|
||||||
|
:maskClosable="false"
|
||||||
|
:visible="true"
|
||||||
|
title="导入"
|
||||||
|
@ok="handleCancel"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<div style="margin-top: 10px">
|
||||||
|
<a-form :layout="'vertical'">
|
||||||
|
<a-form-item label="平台对接" required>
|
||||||
|
<a-select
|
||||||
|
showSearch
|
||||||
|
v-model:value="modelRef.configId"
|
||||||
|
:options="configList"
|
||||||
|
placeholder="请选择平台对接"
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item v-if="modelRef.configId" label="文件格式">
|
||||||
|
<a-radio-group
|
||||||
|
button-style="solid"
|
||||||
|
v-model:value="modelRef.fileType"
|
||||||
|
placeholder="请选择文件格式"
|
||||||
|
>
|
||||||
|
<a-radio-button value="xlsx">xlsx</a-radio-button>
|
||||||
|
<a-radio-button value="csv">csv</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="文件上传" v-if="modelRef.configId">
|
||||||
|
<a-upload
|
||||||
|
v-model:fileList="modelRef.upload"
|
||||||
|
name="file"
|
||||||
|
:action="FILE_UPLOAD"
|
||||||
|
:headers="{
|
||||||
|
'X-Access-Token': LocalStore.get(TOKEN_KEY),
|
||||||
|
}"
|
||||||
|
:accept="`.${modelRef.fileType || 'xlsx'}`"
|
||||||
|
:showUploadList="false"
|
||||||
|
@change="fileChange"
|
||||||
|
>
|
||||||
|
<a-button :loading="loading">
|
||||||
|
<template #icon>
|
||||||
|
<AIcon type="UploadOutlined" />
|
||||||
|
</template>
|
||||||
|
文件上传
|
||||||
|
</a-button>
|
||||||
|
</a-upload>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="modelRef.configId" label="下载模板">
|
||||||
|
<a-space>
|
||||||
|
<a-button icon="file" @click="downFileFn('xlsx')">
|
||||||
|
.xlsx
|
||||||
|
</a-button>
|
||||||
|
<a-button icon="file" @click="downFileFn('csv')">
|
||||||
|
.csv
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
<div v-if="totalCount">
|
||||||
|
<a-icon class="check-num" type="check" /> 已完成 总数量
|
||||||
|
<span class="check-num">{{ totalCount }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="errCount">
|
||||||
|
<a-icon class="check-num" style="color: red" type="close" />
|
||||||
|
失败 总数量
|
||||||
|
<span class="check-num">{{ errCount }}</span>
|
||||||
|
</div>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { FILE_UPLOAD } from '@/api/comm';
|
||||||
|
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||||
|
import { LocalStore } from '@/utils/comm';
|
||||||
|
import { downloadFile } from '@/utils/utils';
|
||||||
|
import { queryPlatformNoPage, _import } from '@/api/iot-card/cardManagement';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['close']);
|
||||||
|
|
||||||
|
const configList = ref<Record<string, any>[]>([]);
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const totalCount = ref<number>(0);
|
||||||
|
const errCount = ref<number>(0);
|
||||||
|
|
||||||
|
const modelRef = reactive({
|
||||||
|
configId: undefined,
|
||||||
|
upload: [],
|
||||||
|
fileType: 'xlsx',
|
||||||
|
});
|
||||||
|
|
||||||
|
const getConfig = async () => {
|
||||||
|
const resp: any = await queryPlatformNoPage({
|
||||||
|
paging: false,
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
terms: [
|
||||||
|
{
|
||||||
|
column: 'state',
|
||||||
|
termType: 'eq',
|
||||||
|
value: 'enabled',
|
||||||
|
type: 'and',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
configList.value = resp.result.map((item: any) => {
|
||||||
|
return { key: item.id, label: item.name, value: item.id };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileChange = (info: any) => {
|
||||||
|
loading.value = true;
|
||||||
|
if (info.file.status === 'done') {
|
||||||
|
const r = info.file.response || { result: '' };
|
||||||
|
_import(modelRef.configId, { fileUrl: r.result })
|
||||||
|
.then((resp: any) => {
|
||||||
|
totalCount.value = resp.result.total;
|
||||||
|
message.success('导入成功');
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
message.error(err.response.data.message || '导入失败');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const downFileFn = (type: string) => {
|
||||||
|
const url = `${BASE_API_PATH}/network/card/template.${type}`;
|
||||||
|
downloadFile(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
totalCount.value = 0;
|
||||||
|
errCount.value = 0;
|
||||||
|
modelRef.configId = undefined;
|
||||||
|
emit('close', true);
|
||||||
|
};
|
||||||
|
|
||||||
|
getConfig();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.check-num {
|
||||||
|
margin: 6px;
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -103,6 +103,113 @@
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
|
<template #card="slotProps">
|
||||||
|
<CardBox
|
||||||
|
:value="slotProps"
|
||||||
|
@click="handleClick"
|
||||||
|
:actions="getActions(slotProps, 'card')"
|
||||||
|
v-bind="slotProps"
|
||||||
|
:active="_selectedRowKeys.includes(slotProps.id)"
|
||||||
|
:status="slotProps.cardStateType.value"
|
||||||
|
:statusText="slotProps.cardStateType.text"
|
||||||
|
:statusNames="{
|
||||||
|
using: 'success',
|
||||||
|
toBeActivated: 'default',
|
||||||
|
deactivate: '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"
|
||||||
|
@click.stop="handleView(slotProps.id)"
|
||||||
|
>
|
||||||
|
{{ slotProps.id }}
|
||||||
|
</h3>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="8">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
平台对接
|
||||||
|
</div>
|
||||||
|
<div>{{ slotProps.platformConfigName }}</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<div class="card-item-content-text">类型</div>
|
||||||
|
<div>{{ slotProps.cardType.text }}</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<div class="card-item-content-text">提醒</div>
|
||||||
|
<!-- <div>{{ slotProps.cardType.text }}</div> -->
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-divider style="margin: 12px 0" />
|
||||||
|
<div v-if="slotProps.usedFlow === 0">
|
||||||
|
<span class="flow-text">
|
||||||
|
{{ slotProps.totalFlow }}
|
||||||
|
</span>
|
||||||
|
<span class="card-item-content-text"> M 使用流量</span>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="progress-text">
|
||||||
|
<div>{{ slotProps.totalFlow - slotProps.usedFlow }} %</div>
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
总共 {{ slotProps.totalFlow }} M
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-progress
|
||||||
|
:strokeColor="'#ADC6FF'"
|
||||||
|
:showInfo="false"
|
||||||
|
:percent="slotProps.totalFlow - slotProps.usedFlow"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</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 #deviceId="slotProps">
|
||||||
|
{{ slotProps.deviceName }}
|
||||||
|
</template>
|
||||||
<template #totalFlow="slotProps">
|
<template #totalFlow="slotProps">
|
||||||
<div>
|
<div>
|
||||||
{{
|
{{
|
||||||
|
@ -157,7 +264,7 @@
|
||||||
<template #action="slotProps">
|
<template #action="slotProps">
|
||||||
<a-space :size="16">
|
<a-space :size="16">
|
||||||
<a-tooltip
|
<a-tooltip
|
||||||
v-for="i in getActions(slotProps)"
|
v-for="i in getActions(slotProps, 'table')"
|
||||||
:key="i.key"
|
:key="i.key"
|
||||||
v-bind="i.tooltip"
|
v-bind="i.tooltip"
|
||||||
>
|
>
|
||||||
|
@ -186,6 +293,20 @@
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template>
|
||||||
</JTable>
|
</JTable>
|
||||||
|
<!-- 批量导入 -->
|
||||||
|
<Import v-if="importVisible" @close="importVisible = false" />
|
||||||
|
<!-- 批量导出 -->
|
||||||
|
<Export
|
||||||
|
v-if="exportVisible"
|
||||||
|
@close="exportVisible = false"
|
||||||
|
:data="_selectedRowKeys"
|
||||||
|
/>
|
||||||
|
<!-- 绑定设备 -->
|
||||||
|
<BindDevice
|
||||||
|
v-if="bindDeviceVisible"
|
||||||
|
:cardId="cardId"
|
||||||
|
@change="bindDevice"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -204,16 +325,25 @@ import {
|
||||||
resumptionBatch,
|
resumptionBatch,
|
||||||
sync,
|
sync,
|
||||||
removeCards,
|
removeCards,
|
||||||
|
unbind,
|
||||||
} from '@/api/iot-card/cardManagement';
|
} from '@/api/iot-card/cardManagement';
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
import type { CardManagement } from './typing';
|
||||||
|
import { getImage } from '@/utils/comm';
|
||||||
|
import BindDevice from './BindDevice.vue';
|
||||||
|
import Import from './Import.vue';
|
||||||
|
import Export from './Export.vue';
|
||||||
|
|
||||||
const cardManageRef = ref<Record<string, any>>({});
|
const cardManageRef = ref<Record<string, any>>({});
|
||||||
const params = ref<Record<string, any>>({});
|
const params = ref<Record<string, any>>({});
|
||||||
const _selectedRowKeys = ref<string[]>([]);
|
const _selectedRowKeys = ref<string[]>([]);
|
||||||
const _selectedRow = ref<any[]>([]);
|
const _selectedRow = ref<any[]>([]);
|
||||||
|
const bindDeviceVisible = ref<boolean>(false);
|
||||||
const visible = ref<boolean>(false);
|
const visible = ref<boolean>(false);
|
||||||
const exportVisible = ref<boolean>(false);
|
const exportVisible = ref<boolean>(false);
|
||||||
const importVisible = ref<boolean>(false);
|
const importVisible = ref<boolean>(false);
|
||||||
|
const cardId = ref<any>();
|
||||||
|
const current = ref<Partial<CardManagement>>({});
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
@ -239,9 +369,10 @@ const columns = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '绑定设备',
|
title: '绑定设备',
|
||||||
dataIndex: 'deviceName',
|
dataIndex: 'deviceId',
|
||||||
key: 'deviceName',
|
key: 'deviceId',
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
|
scopedSlots: true,
|
||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -360,7 +491,10 @@ const columns = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
const getActions = (
|
||||||
|
data: Partial<Record<string, any>>,
|
||||||
|
type: 'card' | 'table',
|
||||||
|
): ActionsType[] => {
|
||||||
if (!data) return [];
|
if (!data) return [];
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -386,6 +520,25 @@ const getActions = (data: Partial<Record<string, any>>): ActionsType[] => {
|
||||||
title: data.deviceId ? '解绑设备' : '绑定设备',
|
title: data.deviceId ? '解绑设备' : '绑定设备',
|
||||||
},
|
},
|
||||||
icon: data.deviceId ? 'DisconnectOutlined' : 'LinkOutlined',
|
icon: data.deviceId ? 'DisconnectOutlined' : 'LinkOutlined',
|
||||||
|
popConfirm: data.deviceId
|
||||||
|
? {
|
||||||
|
title: '确认解绑设备?',
|
||||||
|
onConfirm: async () => {
|
||||||
|
unbind(data.id).then((resp: any) => {
|
||||||
|
if (resp.status === 200) {
|
||||||
|
message.success('操作成功');
|
||||||
|
cardManageRef.value?.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
onClick: () => {
|
||||||
|
if (!data.deviceId) {
|
||||||
|
bindDeviceVisible.value = true;
|
||||||
|
cardId.value = data.id;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'activation',
|
key: 'activation',
|
||||||
|
@ -479,11 +632,38 @@ const cancelSelect = () => {
|
||||||
_selectedRowKeys.value = [];
|
_selectedRowKeys.value = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClick = (dt: any) => {
|
||||||
|
if (_selectedRowKeys.value.includes(dt.id)) {
|
||||||
|
const _index = _selectedRowKeys.value.findIndex((i) => i === dt.id);
|
||||||
|
_selectedRowKeys.value.splice(_index, 1);
|
||||||
|
} else {
|
||||||
|
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查看
|
||||||
|
*/
|
||||||
|
const handleView = (id: string) => {
|
||||||
|
message.warn(id + '暂未开发');
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增
|
* 新增
|
||||||
*/
|
*/
|
||||||
const handleAdd = () => {};
|
const handleAdd = () => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定设备关闭窗口
|
||||||
|
*/
|
||||||
|
const bindDevice = (val: boolean) => {
|
||||||
|
bindDeviceVisible.value = false;
|
||||||
|
cardId.value = '';
|
||||||
|
if (val) {
|
||||||
|
cardManageRef.value?.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量激活
|
* 批量激活
|
||||||
*/
|
*/
|
||||||
|
@ -565,7 +745,25 @@ const handelRemove = async () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
.page-container {
|
||||||
.search {
|
.search {
|
||||||
width: calc(100% - 330px);
|
width: calc(100% - 330px);
|
||||||
}
|
}
|
||||||
|
.flow-text {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
:deep(.ant-progress-inner) {
|
||||||
|
border-radius: 0px;
|
||||||
|
}
|
||||||
|
:deep(.ant-progress-bg) {
|
||||||
|
border-radius: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
export type CardManagement = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
iccId: string;
|
||||||
|
deviceId: string;
|
||||||
|
deviceName: string;
|
||||||
|
platformConfigId: string;
|
||||||
|
operatorName: string;
|
||||||
|
cardType: any;
|
||||||
|
totalFlow: number;
|
||||||
|
usedFlow: number;
|
||||||
|
residualFlow: number;
|
||||||
|
activationDate: string;
|
||||||
|
updateTime: string;
|
||||||
|
cardStateType: any;
|
||||||
|
cardState: any;
|
||||||
|
describe: string;
|
||||||
|
platformConfigName: string;
|
||||||
|
operatorPlatformType: any;
|
||||||
|
};
|
Loading…
Reference in New Issue