iot-ui-vue/src/views/device/Instance/Import/file.vue

248 lines
7.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="file">
<j-form layout="vertical">
<j-form-item>
<template #label>
<div>
文件上传
<div class="alert"><AIcon style="margin-right: 5px;" type="InfoCircleOutlined" />导入系统已存在的设备数据不会更改已存在设备的所属产品信息</div>
</div>
</template>
<a-upload-dragger
v-model:fileList="modelRef.upload"
name="file"
:action="FILE_UPLOAD"
:headers="{
'X-Access-Token': LocalStore.get(TOKEN_KEY),
}"
:maxCount="1"
:showUploadList="false"
@change="uploadChange"
:accept="'.xlsx,.csv'"
:before-upload="beforeUpload"
:disabled="disabled"
@drop="handleDrop"
>
<div class="dragger-box">
<AIcon class="icon" type="PlusCircleFilled" />
<span style="margin: 16px 0 8px 0">点击或拖拽上传文件</span>
<span>格式.xlsx, .csv</span>
</div>
</a-upload-dragger>
</j-form-item>
<div style="margin-bottom: 16px">
<j-checkbox v-model:checked="modelRef.file.autoDeploy"
>导入并启用</j-checkbox
>
</div>
<div v-if="importLoading" class="result">
<div v-if="flag">
<j-spin size="small" style="margin-right: 10px" />正在导入
</div>
<div v-else>
<AIcon
style="
color: #08e21e;
margin-right: 10px;
font-size: 16px;
"
type="CheckCircleOutlined"
/>导入完成
</div>
<div>导入成功:{{ count }} 个</div>
<div>
导入失败:<span style="color: #ff595e">{{ errCount }}</span>
个<a
v-if="errMessage && !flag && errCount > 0"
style="margin-left: 20px"
@click="downError"
>下载</a
>
</div>
</div>
<j-form-item label="下载模板">
<div class="file-download">
<j-button class="btn" @click="downFile('xlsx')">模板格式.xlsx</j-button>
<j-button class="btn" @click="downFile('csv')">模板格式.csv</j-button>
</div>
</j-form-item>
</j-form>
</div>
</template>
<script setup lang='ts' name='DeviceImportFile'>
import { FILE_UPLOAD } from '@/api/comm';
import { TOKEN_KEY } from '@/utils/variable';
import { LocalStore, onlyMessage } from '@/utils/comm';
import { downloadFileByUrl } from '@/utils/utils';
import { deviceImport, templateDownload } from '@/api/device/instance';
import { EventSourcePolyfill } from 'event-source-polyfill';
const props = defineProps({
product: {
type: String,
default: undefined,
},
});
const modelRef = reactive({
product: props.product,
upload: [],
file: {
fileType: 'xlsx',
autoDeploy: false,
},
});
const importLoading = ref<boolean>(false);
const flag = ref<boolean>(false);
const count = ref<number>(0);
const errCount = ref<number>(0);
const errMessage = ref<string>('');
const disabled = ref(false);
const downFile = async (type: string) => {
const res: any = await templateDownload(props.product!, type);
if (res) {
const blob = new Blob([res], { type: type });
const url = URL.createObjectURL(blob);
downloadFileByUrl(url, `设备导入模板`, type);
}
};
const beforeUpload = (_file: any) => {
// const fileType = modelRef.file?.fileType === 'csv' ? 'csv' : 'xlsx';
const isCsv = _file.type === 'text/csv';
const isXlsx =
_file.type ===
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
if (!isCsv) {
onlyMessage('请上传.csv格式文件', 'warning');
}
if (!isXlsx) {
onlyMessage('请上传.xlsx格式文件', 'warning');
}
// return (isCsv && fileType !== 'xlsx') || (isXlsx && fileType !== 'csv');
return isCsv || isXlsx;
};
const handleDrop = () => {};
const downError = () => {
window.open(errMessage.value);
};
const submitData = async (fileUrl: string) => {
if (!!fileUrl) {
count.value = 0;
errCount.value = 0;
const autoDeploy = !!modelRef?.file?.autoDeploy || false;
importLoading.value = true;
let dt = 0;
let et = 0;
const source = new EventSourcePolyfill(
deviceImport(props.product!, fileUrl, autoDeploy),
);
source.onmessage = (e: any) => {
const res = JSON.parse(e.data);
if (res.success) {
const temp = res.result.total;
dt += temp;
count.value = dt;
} else {
if (res.detailFile) {
errMessage.value = res.detailFile;
} else {
et += 1;
errCount.value = et;
}
}
disabled.value = false;
};
source.onerror = (e: { status: number }) => {
if (e.status === 403) errMessage.value = '暂无权限,请联系管理员';
flag.value = false;
disabled.value = false;
source.close();
};
source.onopen = () => {};
} else {
onlyMessage('请先上传文件', 'error');
}
};
const uploadChange = async (info: Record<string, any>) => {
disabled.value = true;
if (info.file.status === 'done') {
const resp: any = info.file.response || { result: '' };
await submitData(resp?.result || '');
}
};
</script>
<style scoped lang='less'>
.file {
.file-type-label {
display: flex;
gap: 16px;
align-items: center;
.file-type-radio {
display: flex;
flex-grow: 1;
:deep(.ant-radio-button-wrapper) {
width: 50%;
}
}
}
.file-download {
display: flex;
gap: 16px;
.btn {
border: none;
background-color: #ECECF0;
width: 152px;
color: #666666;
}
}
.dragger-box {
margin: 46px 0;
display: flex;
flex-direction: column;
color: #666666;
.icon {
font-size: 30px;
color: @primary-color;
}
}
.result {
div {
margin: 5px 0;
color: #605e5c;
}
}
.alert {
height: 40px;
width: 100%;
padding: 0 20px 0 10px;
color: rgba(0, 0, 0, 0.55);
line-height: 40px;
background-color: #f6f6f6;
}
:deep(.ant-form-item) {
.ant-upload.ant-upload-drag {
background: #F8F9FC;
border: 1px dashed rgba(212, 219, 243, 0.7);
}
}
}
</style>