wwf
13 小时以前 a1d7e81859f554f3a53680cc35f0f49bf1f77098
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
import request from '@/config/axios'
import { isEmpty } from '@/utils/is'
 
/**
 * IoT 产品物模型
 */
export interface ThingModelData {
  id?: number // 物模型功能编号
  identifier?: string // 功能标识
  name?: string // 功能名称
  description?: string // 功能描述
  productId?: number // 产品编号
  productKey?: string // 产品标识
  dataType: string // 数据类型,与 dataSpecs 的 dataType 保持一致
  type: number // 功能类型
  property: ThingModelProperty // 属性
  event?: ThingModelEvent // 事件
  service?: ThingModelService // 服务
}
 
/**
 * ThingModelProperty 类型
 */
export interface ThingModelProperty {
  [key: string]: any
}
 
/**
 * ThingModelEvent 类型
 */
export interface ThingModelEvent {
  [key: string]: any
}
 
/**
 * ThingModelService 类型
 */
export interface ThingModelService {
  [key: string]: any
}
 
/** dataSpecs 数值型数据结构 */
export interface DataSpecsNumberData {
  dataType: 'int' | 'float' | 'double' // 数据类型,取值为 INT、FLOAT 或 DOUBLE
  max: string // 最大值,必须与 dataType 设置一致,且为 STRING 类型
  min: string // 最小值,必须与 dataType 设置一致,且为 STRING 类型
  step: string // 步长,必须与 dataType 设置一致,且为 STRING 类型
  precise?: string // 精度,当 dataType 为 FLOAT 或 DOUBLE 时可选
  defaultValue?: string // 默认值,可选
  unit: string // 单位的符号
  unitName: string // 单位的名称
}
 
/** dataSpecs 枚举型数据结构 */
export interface DataSpecsEnumOrBoolData {
  dataType: 'enum' | 'bool'
  defaultValue?: string // 默认值,可选
  name: string // 枚举项的名称
  value: number | undefined // 枚举值
}
 
/** 物模型TSL响应数据结构 */
export interface IotThingModelTSLResp {
  productId: number
  productKey: string
  properties: ThingModelProperty[]
  events: ThingModelEvent[]
  services: ThingModelService[]
}
 
/** 物模型属性 */
export interface ThingModelProperty {
  identifier: string
  name: string
  accessMode: string
  required?: boolean
  dataType: string
  description?: string
  dataSpecs?: ThingModelProperty
  dataSpecsList?: ThingModelProperty[]
}
 
/** 物模型事件 */
export interface ThingModelEvent {
  identifier: string
  name: string
  required?: boolean
  type: string
  description?: string
  outputParams?: ThingModelParam[]
  method?: string
}
 
/** 物模型服务 */
export interface ThingModelService {
  identifier: string
  name: string
  required?: boolean
  callType: string
  description?: string
  inputParams?: ThingModelParam[]
  outputParams?: ThingModelParam[]
  method?: string
}
 
/** 物模型参数 */
export interface ThingModelParam {
  identifier: string
  name: string
  direction: string
  paraOrder?: number
  dataType: string
  dataSpecs?: ThingModelProperty
  dataSpecsList?: ThingModelProperty[]
}
 
/** 数值型数据规范 */
export interface ThingModelNumericDataSpec {
  dataType: 'int' | 'float' | 'double'
  max: string
  min: string
  step: string
  precise?: string
  defaultValue?: string
  unit?: string
  unitName?: string
}
 
/** 布尔/枚举型数据规范 */
export interface ThingModelBoolOrEnumDataSpecs {
  dataType: 'bool' | 'enum'
  name: string
  value: number
}
 
/** 文本/时间型数据规范 */
export interface ThingModelDateOrTextDataSpecs {
  dataType: 'text' | 'date'
  length?: number
  defaultValue?: string
}
 
/** 数组型数据规范 */
export interface ThingModelArrayDataSpecs {
  dataType: 'array'
  size: number
  childDataType: string
  dataSpecsList?: ThingModelProperty[]
}
 
/** 结构体型数据规范 */
export interface ThingModelStructDataSpecs {
  dataType: 'struct'
  identifier: string
  name: string
  accessMode: string
  required?: boolean
  childDataType: string
  dataSpecs?: ThingModelProperty
  dataSpecsList?: ThingModelProperty[]
}
 
// IoT 产品物模型 API
export const ThingModelApi = {
  // 查询产品物模型分页
  getThingModelPage: async (params: any) => {
    return await request.get({ url: `/iot/thing-model/page`, params })
  },
 
  // 获得产品物模型列表
  getThingModelList: async (params: any) => {
    return await request.get({ url: `/iot/thing-model/list`, params })
  },
 
  // 获得产品物模型 TSL
  getThingModelTSLByProductId: async (productId: number) => {
    return await request.get({
      url: `/iot/thing-model/get-tsl?productId=${productId}`
    })
  },
 
  // 查询产品物模型详情
  getThingModel: async (id: number) => {
    return await request.get({ url: `/iot/thing-model/get?id=` + id })
  },
 
  // 新增产品物模型
  createThingModel: async (data: ThingModelData) => {
    return await request.post({ url: `/iot/thing-model/create`, data })
  },
 
  // 修改产品物模型
  updateThingModel: async (data: ThingModelData) => {
    return await request.put({ url: `/iot/thing-model/update`, data })
  },
 
  // 删除产品物模型
  deleteThingModel: async (id: number) => {
    return await request.delete({ url: `/iot/thing-model/delete?id=` + id })
  }
}
 
/** 公共校验规则 */
export const ThingModelFormRules = {
  name: [
    { required: true, message: '功能名称不能为空', trigger: 'blur' },
    {
      pattern: /^[\u4e00-\u9fa5a-zA-Z0-9][\u4e00-\u9fa5a-zA-Z0-9\-_/\.]{0,29}$/,
      message:
        '支持中文、大小写字母、日文、数字、短划线、下划线、斜杠和小数点,必须以中文、英文或数字开头,不超过 30 个字符',
      trigger: 'blur'
    }
  ],
  type: [{ required: true, message: '功能类型不能为空', trigger: 'blur' }],
  identifier: [
    { required: true, message: '标识符不能为空', trigger: 'blur' },
    {
      pattern: /^[a-zA-Z0-9_]{1,50}$/,
      message: '支持大小写字母、数字和下划线,不超过 50 个字符',
      trigger: 'blur'
    },
    {
      validator: (_: any, value: string, callback: any) => {
        const reservedKeywords = ['set', 'get', 'post', 'property', 'event', 'time', 'value']
        if (reservedKeywords.includes(value)) {
          callback(
            new Error(
              'set, get, post, property, event, time, value 是系统保留字段,不能用于标识符定义'
            )
          )
        } else if (/^\d+$/.test(value)) {
          callback(new Error('标识符不能是纯数字'))
        } else {
          callback()
        }
      },
      trigger: 'blur'
    }
  ],
  'property.dataSpecs.childDataType': [{ required: true, message: '元素类型不能为空' }],
  'property.dataSpecs.size': [
    { required: true, message: '元素个数不能为空' },
    {
      validator: (_: any, value: any, callback: any) => {
        if (isEmpty(value)) {
          callback(new Error('元素个数不能为空'))
          return
        }
        if (isNaN(Number(value))) {
          callback(new Error('元素个数必须是数字'))
          return
        }
        callback()
      },
      trigger: 'blur'
    }
  ],
  'property.dataSpecs.length': [
    { required: true, message: '请输入文本字节长度', trigger: 'blur' },
    {
      validator: (_: any, value: any, callback: any) => {
        if (isEmpty(value)) {
          callback(new Error('文本长度不能为空'))
          return
        }
        if (isNaN(Number(value))) {
          callback(new Error('文本长度必须是数字'))
          return
        }
        callback()
      },
      trigger: 'blur'
    }
  ],
  'property.accessMode': [{ required: true, message: '请选择读写类型', trigger: 'change' }]
}
 
/** 校验布尔值名称 */
export const validateBoolName = (_: any, value: string, callback: any) => {
  if (isEmpty(value)) {
    callback(new Error('布尔值名称不能为空'))
    return
  }
  // 检查开头字符
  if (!/^[\u4e00-\u9fa5a-zA-Z0-9]/.test(value)) {
    callback(new Error('布尔值名称必须以中文、英文字母或数字开头'))
    return
  }
  // 检查整体格式
  if (!/^[\u4e00-\u9fa5a-zA-Z0-9][a-zA-Z0-9\u4e00-\u9fa5_-]*$/.test(value)) {
    callback(new Error('布尔值名称只能包含中文、英文字母、数字、下划线和短划线'))
    return
  }
  // 检查长度(一个中文算一个字符)
  if (value.length > 20) {
    callback(new Error('布尔值名称长度不能超过 20 个字符'))
    return
  }
 
  callback()
}