Commit 49bf301a09f241155ec242088a28c9c617d7ecd1

Authored by ww
1 parent 5c85498b

perf: 设备列表导入字段调整

... ... @@ -3,6 +3,7 @@ import { DeviceTypeEnum } from './deviceModel';
3 3 export interface ImportDeviceParams {
4 4 file: string;
5 5 tkDeviceProfileId: string;
  6 + tbDeviceProfileId: string;
6 7 organizationId: string;
7 8 deviceTypeEnum: DeviceTypeEnum;
8 9 mapping: {
... ... @@ -11,6 +12,8 @@ export interface ImportDeviceParams {
11 12 header: boolean;
12 13 update: boolean;
13 14 };
  15 + gateWayTbDeviceId: string;
  16 + isTcpDeviceProfile: boolean;
14 17 }
15 18
16 19 export interface ImportDeviceResponse {
... ...
1 1 <script lang="ts" setup>
2 2 import { Button } from 'ant-design-vue';
3   - import { computed, nextTick, onMounted } from 'vue';
4   - import { basicInfoForm, FieldsEnum } from './config';
  3 + import { onMounted } from 'vue';
  4 + import { basicInfoForm } from './config';
5 5 import { basicProps } from './props';
6 6 import StepContainer from './StepContainer.vue';
7 7 import { BasicForm, useForm } from '/@/components/Form';
... ... @@ -15,26 +15,14 @@
15 15
16 16 const emit = defineEmits(['update:value']);
17 17
18   - const canGoNext = computed(() => {
19   - const values = props.value as Recordable;
20   - return (
21   - Reflect.has(values, FieldsEnum.ORGANIZATION_ID) &&
22   - Reflect.has(values, FieldsEnum.TK_DEVICE_PROFILE_ID) &&
23   - Reflect.has(values, FieldsEnum.DEVICE_TYPE)
24   - );
25   - });
26   - const [register, { getFieldsValue, setFieldsValue }] = useForm({
  18 + const [register, { getFieldsValue, setFieldsValue, validate }] = useForm({
27 19 schemas: basicInfoForm,
28 20 layout: 'vertical',
29 21 showActionButtonGroup: false,
30   - submitFunc: async () => {
31   - await nextTick();
32   - const values = getFieldsValue() || {};
33   - emit('update:value', values);
34   - },
35 22 });
36 23
37   - const handleGoNext = () => {
  24 + const handleGoNext = async () => {
  25 + await validate();
38 26 emit('update:value', getFieldsValue());
39 27 props.goNextStep?.();
40 28 };
... ... @@ -48,7 +36,7 @@
48 36 <StepContainer>
49 37 <BasicForm @register="register" />
50 38 <div class="flex justify-end gap-2">
51   - <Button type="primary" @click="handleGoNext" :disabled="!canGoNext">下一步</Button>
  39 + <Button type="primary" @click="handleGoNext">下一步</Button>
52 40 </div>
53 41 </StepContainer>
54 42 </template>
... ...
... ... @@ -8,6 +8,7 @@
8 8 ColumnFileEnum,
9 9 ColumTypeEnum,
10 10 generateColumnTypeOptions,
  11 + CredentialsEnum,
11 12 } from './config';
12 13 import { nextTick, onMounted, ref, unref, watch } from 'vue';
13 14 import { ColumnDataRecord, Options, UploadFileParseValue } from './type';
... ... @@ -47,7 +48,7 @@
47 48 const exampleRow = content.at(0) || {};
48 49
49 50 const getColumnType = (index: number) => {
50   - return index === DEVICE_NAME_INDEX ? ColumTypeEnum.NAME : ColumTypeEnum.SERVER_ATTRIBUTE;
  51 + return index === DEVICE_NAME_INDEX ? ColumTypeEnum.NAME : CredentialsEnum.ACCESS_TOKEN;
51 52 };
52 53
53 54 const dataSource = header.map((columnKey, index) => {
... ...
... ... @@ -7,6 +7,7 @@
7 7 import { CreateEntityValue, UploadFileParseValue } from './type';
8 8 import { batchImportDevice } from '/@/api/device/batchImport';
9 9 import { ImportDeviceParams, ImportDeviceResponse } from '/@/api/device/model/batchImportModel';
  10 + import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
10 11
11 12 const props = defineProps({
12 13 ...basicProps,
... ... @@ -37,7 +38,7 @@
37 38 try {
38 39 const value = transfromData(JSON.parse(JSON.stringify(props.value)));
39 40 const result = await batchImportDevice(value);
40   - await sleep(3000);
  41 + await sleep(1000);
41 42 emit('update:result', result);
42 43 props.goNextStep?.();
43 44 } catch (error) {
... ... @@ -75,7 +76,16 @@
75 76
76 77 const transfromData = (data: CreateEntityValue) => {
77 78 const { basicInfo, columnConfiguration, fileParseValue } = data;
78   - const { tkDeviceProfileId, organizationId, deviceTypeEnum, deviceTypeName } = basicInfo;
  79 + const {
  80 + tkDeviceProfileId,
  81 + organizationId,
  82 + deviceTypeEnum,
  83 + deviceTypeName,
  84 + gateWayTbDeviceId,
  85 + tbDeviceProfileId,
  86 + isTcpDeviceProfile,
  87 + } = basicInfo;
  88 +
79 89 const { file, columns } = insertDeviceTypeName(
80 90 deviceTypeName,
81 91 fileParseValue,
... ... @@ -86,12 +96,15 @@
86 96 tkDeviceProfileId,
87 97 organizationId,
88 98 deviceTypeEnum,
  99 + tbDeviceProfileId,
89 100 mapping: {
90 101 columns: columns,
91 102 delimiter: DelimiterEnum.COMMA,
92 103 header: true,
93 104 update: true,
94 105 },
  106 + isTcpDeviceProfile,
  107 + ...(deviceTypeEnum === DeviceTypeEnum.SENSOR ? { gateWayTbDeviceId } : {}),
95 108 } as ImportDeviceParams;
96 109 };
97 110
... ...
... ... @@ -49,6 +49,7 @@
49 49 const fileReader = new FileReader();
50 50 fileReader.onload = (event: ProgressEvent) => {
51 51 const data = (event.target as FileReader).result as string;
  52 +
52 53 const result = XLSX.read(data, { type: 'string' });
53 54
54 55 const sheetName = result.SheetNames.at(0);
... ...
1 1 import { Options } from './type';
  2 +import { getMeetTheConditionsDevice } from '/@/api/dataBoard';
2 3 import { queryDeviceProfileBy } from '/@/api/device/deviceManager';
  4 +import { DeviceRecord, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
3 5 import { findDictItemByCode } from '/@/api/system/dict';
4 6 import { getOrganizationList } from '/@/api/system/system';
5 7 import { FormSchema } from '/@/components/Form';
6 8 import { BasicColumn } from '/@/components/Table';
7 9 import { copyTransFun } from '/@/utils/fnUtils';
  10 +import { TransportTypeEnum } from '/@/views/device/profiles/components/TransportDescript/const';
8 11
9 12 export enum FieldsEnum {
10 13 ORGANIZATION_ID = 'organizationId',
... ... @@ -14,6 +17,9 @@ export enum FieldsEnum {
14 17 DELIMITER = 'delimiter',
15 18 HEADER = 'header',
16 19 UPDATE = 'update',
  20 + GATEWAY_TB_DEVICE_ID = 'gateWayTbDeviceId',
  21 + TB_DEVICE_PROFILE_ID = 'tbDeviceProfileId',
  22 + IS_TCP_DEVICE_PROFILE = 'isTcpDeviceProfile',
17 23 }
18 24
19 25 export enum DelimiterEnum {
... ... @@ -39,7 +45,7 @@ export enum ColumnFileEnum {
39 45
40 46 export enum ColumTypeEnum {
41 47 NAME = 'NAME',
42   - // TYPE = 'TYPE',
  48 + TYPE = 'TYPE',
43 49 LABEL = 'LABEL',
44 50 DESCRIPTION = 'DESCRIPTION',
45 51 SHARED_ATTRIBUTE = 'SHARED_ATTRIBUTE',
... ... @@ -48,6 +54,17 @@ export enum ColumTypeEnum {
48 54 IS_GATEWAY = 'IS_GATEWAY',
49 55 }
50 56
  57 +export enum ColumnTypeNameEnum {
  58 + NAME = '名称',
  59 + TYPE = '类型',
  60 + LABEL = '标签',
  61 + DESCRIPTION = '说明',
  62 + SHARED_ATTRIBUTE = '共享属性',
  63 + SERVER_ATTRIBUTE = '服务器属性',
  64 + TIMESERIES = 'Timeseries',
  65 + IS_GATEWAY = 'Is网关',
  66 +}
  67 +
51 68 export enum CredentialsEnum {
52 69 ACCESS_TOKEN = 'ACCESS_TOKEN',
53 70 X509 = 'X509',
... ... @@ -67,17 +84,6 @@ export enum CredentialsEnum {
67 84 // LWM2M_SERVER_CLIENT_SECRET_KEY = 'LWM2M_SERVER_CLIENT_SECRET_KEY',
68 85 }
69 86
70   -export enum ColumnTypeNameEnum {
71   - NAME = '名称',
72   - // TYPE = '类型',
73   - // LABEL = '标签',
74   - // DESCRIPTION = '说明',
75   - SHARED_ATTRIBUTE = '共享属性',
76   - SERVER_ATTRIBUTE = '服务器属性',
77   - TIMESERIES = 'Timeseries',
78   - IS_GATEWAY = 'Is网关',
79   -}
80   -
81 87 export enum CredentialsNameEnum {
82 88 ACCESS_TOKEN = '访问令牌',
83 89 X509 = 'X.509',
... ... @@ -103,8 +109,7 @@ export const basicInfoForm: FormSchema[] = [
103 109 label: '所属组织',
104 110 component: 'ApiTreeSelect',
105 111 rules: [{ required: true, message: '所属组织为必填项' }],
106   - componentProps: ({ formActionType }) => {
107   - const { submit } = formActionType;
  112 + componentProps: () => {
108 113 return {
109 114 maxLength: 250,
110 115 placeholder: '请选择所属组织',
... ... @@ -114,7 +119,6 @@ export const basicInfoForm: FormSchema[] = [
114 119 return data;
115 120 },
116 121 getPopupContainer: () => document.body,
117   - onChange: () => submit(),
118 122 };
119 123 },
120 124 },
... ... @@ -124,7 +128,7 @@ export const basicInfoForm: FormSchema[] = [
124 128 component: 'ApiSelect',
125 129 rules: [{ required: true, message: '设备类型为必填项' }],
126 130 componentProps: ({ formActionType }) => {
127   - const { setFieldsValue, submit, clearValidate } = formActionType;
  131 + const { setFieldsValue, clearValidate } = formActionType;
128 132 return {
129 133 api: findDictItemByCode,
130 134 params: {
... ... @@ -136,8 +140,8 @@ export const basicInfoForm: FormSchema[] = [
136 140 setFieldsValue({
137 141 [FieldsEnum.DEVICE_TYPE_NAME]: value ? options.label : null,
138 142 [FieldsEnum.TK_DEVICE_PROFILE_ID]: null,
  143 + [FieldsEnum.GATEWAY_TB_DEVICE_ID]: null,
139 144 });
140   - submit();
141 145 clearValidate();
142 146 },
143 147 };
... ... @@ -149,7 +153,7 @@ export const basicInfoForm: FormSchema[] = [
149 153 label: '产品',
150 154 rules: [{ required: true, message: '产品为必填项' }],
151 155 componentProps: ({ formActionType, formModel }) => {
152   - const { submit } = formActionType;
  156 + const { setFieldsValue } = formActionType;
153 157 const deviceType = Reflect.get(formModel, FieldsEnum.DEVICE_TYPE);
154 158 return {
155 159 api: queryDeviceProfileBy,
... ... @@ -158,7 +162,14 @@ export const basicInfoForm: FormSchema[] = [
158 162 placeholder: '请选择产品',
159 163 params: { deviceType },
160 164 getPopupContainer: () => document.body,
161   - onChange: () => submit(),
  165 + onChange(value: string, options: DeviceRecord) {
  166 + setFieldsValue({
  167 + [FieldsEnum.IS_TCP_DEVICE_PROFILE]: value
  168 + ? options.transportType === TransportTypeEnum.TCP
  169 + : false,
  170 + [FieldsEnum.TB_DEVICE_PROFILE_ID]: value ? options.tbProfileId : null,
  171 + });
  172 + },
162 173 showSearch: true,
163 174 filterOption: (inputValue: string, options: Record<'label', string>) => {
164 175 return options.label.includes(inputValue);
... ... @@ -167,6 +178,51 @@ export const basicInfoForm: FormSchema[] = [
167 178 },
168 179 },
169 180 {
  181 + field: FieldsEnum.GATEWAY_TB_DEVICE_ID,
  182 + component: 'ApiSelect',
  183 + label: '网关设备',
  184 + ifShow: ({ model }) => model[FieldsEnum.DEVICE_TYPE] === DeviceTypeEnum.SENSOR,
  185 + required: true,
  186 + componentProps: ({ formModel }) => {
  187 + const organizationId = formModel[FieldsEnum.ORGANIZATION_ID];
  188 + return {
  189 + api: async () => {
  190 + try {
  191 + if (!organizationId) return;
  192 + const result = await getMeetTheConditionsDevice({
  193 + deviceType: DeviceTypeEnum.GATEWAY,
  194 + organizationId,
  195 + });
  196 + return result;
  197 + } catch (error) {
  198 + return [];
  199 + }
  200 + },
  201 + labelField: 'name',
  202 + valueField: 'tbDeviceId',
  203 + getPopupContainer: () => document.body,
  204 + };
  205 + },
  206 + },
  207 + {
  208 + field: FieldsEnum.IS_TCP_DEVICE_PROFILE,
  209 + component: 'Checkbox',
  210 + label: 'tcp产品标志',
  211 + show: false,
  212 + },
  213 + {
  214 + field: FieldsEnum.TB_DEVICE_PROFILE_ID,
  215 + component: 'Input',
  216 + label: 'tb设备配置id',
  217 + show: false,
  218 + },
  219 + {
  220 + field: FieldsEnum.GATEWAY_TB_DEVICE_ID,
  221 + component: 'Input',
  222 + label: 'tb网关设备ID',
  223 + show: false,
  224 + },
  225 + {
170 226 field: FieldsEnum.DEVICE_TYPE_NAME,
171 227 component: 'Input',
172 228 label: '设备名称',
... ... @@ -205,14 +261,16 @@ export const importConfigurationSchema: FormSchema[] = [
205 261 ];
206 262
207 263 export const generateColumnTypeOptions = () => {
208   - const valueOptions = Object.keys(ColumTypeEnum);
209   - const labelOptions = Object.values(ColumnTypeNameEnum);
  264 + // const valueOptions = Object.keys(ColumTypeEnum);
  265 + // const labelOptions = Object.values(ColumnTypeNameEnum);
210 266 const credentialsValueOptions = Object.keys(CredentialsEnum);
211 267 const credentialsNameOptions = Object.values(CredentialsNameEnum);
212   - const options: Options[] = valueOptions.map((value, index) => ({
213   - label: labelOptions[index],
214   - value,
215   - }));
  268 + // const options: Options[] = valueOptions.map((value, index) => ({
  269 + // label: labelOptions[index],
  270 + // value,
  271 + // }));
  272 +
  273 + const options: Options[] = [];
216 274
217 275 const credentialsOption: Options = {
218 276 label: 'credentials',
... ... @@ -245,9 +303,8 @@ export const columnTypeSchema: BasicColumn[] = [
245 303 },
246 304 ];
247 305
248   -export const csvTemplate = `name,username,password
249   -Device 11,admin,password
250   -Device 22,admin1,password1
  306 +export const csvTemplate = `设备名称,凭证账号,凭证密码
  307 +温湿度设备,admin,123456
251 308 `;
252 309
253 310 export const downloadFile = (data: string, fileName: string, type: string, ext: string) => {
... ...
... ... @@ -138,7 +138,7 @@
138 138 </Steps.Step>
139 139 </Steps>
140 140 <Tooltip
141   - title="模板表头的第一列为设备名称,且不能重复,如需预置访问凭证(ACCESS_TOKEN、MQTT client ID、MQTT user name、MQTT password)添加新的列即可。例如:username、password"
  141 + title="模板表头的第一列为设备名称,且不能重复,如需预置访问凭证(ACCESS_TOKEN、MQTT client ID、MQTT user name、MQTT password)添加新的列即可。例如:凭证账号,凭证密码"
142 142 >
143 143 <Button
144 144 type="text"
... ...
... ... @@ -20,9 +20,16 @@ export interface Options {
20 20 }
21 21
22 22 export type BasicInfoRecord = Record<
23   - 'organizationId' | 'tkDeviceProfileId' | 'deviceTypeEnum' | 'deviceTypeName',
  23 + | 'organizationId'
  24 + | 'tkDeviceProfileId'
  25 + | 'deviceTypeEnum'
  26 + | 'deviceTypeName'
  27 + | 'gateWayTbDeviceId'
  28 + | 'gateWayTkDeviceId'
  29 + | 'tbDeviceProfileId',
24 30 string
25   ->;
  31 +> &
  32 + Record<'isTcpDeviceProfile', boolean>;
26 33
27 34 export interface CreateEntityValue {
28 35 basicInfo: BasicInfoRecord;
... ...