vue-wiring-diagram 1.1.19 → 1.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@
6
6
  <div class="control">
7
7
  <el-collapse v-model="activeName" accordion>
8
8
  <el-collapse-item title="文本内容" name="0" v-if="payload.data.type === 'text'">
9
- <el-input ref="inputRef" type="textarea" v-model="text" @input="changeContent" @focus="setFocus"
9
+ <el-input ref="inputRef" type="textarea" v-model="text" @input="changeContent" @blur="leaveInput"
10
10
  :rows="10"></el-input>
11
11
  <el-alert type="info" title="提示"
12
12
  description="请先选择设备,再选择字段,最后点击确定按钮,即可绑定设备数据。绑定完成后会由 $<> 进行包裹!"
@@ -158,7 +158,7 @@
158
158
  </template>
159
159
 
160
160
  <script setup>
161
- import {onMounted, reactive, ref,} from "vue";
161
+ import {nextTick, onMounted, reactive, ref,} from "vue";
162
162
  import {DeleteFilled} from '@element-plus/icons-vue'
163
163
  import {getFieldList, showPorts} from "../common.js";
164
164
  import {ElMessageBox} from "element-plus";
@@ -228,7 +228,13 @@ const checkField = (row) => {
228
228
  }).then(() => {
229
229
  const unit = row.unit ?? ''
230
230
  const content = props.payload.data.content
231
- props.payload.data.content = text.value = content + '${' + currentDevice.deviceName + '.' + row.name + '}' + unit
231
+ console.log(cursorPosition.value)
232
+ if (cursorPosition.value) {
233
+ // 在记录的光标位置后面添加字段
234
+ props.payload.data.content = text.value = content.slice(0, cursorPosition.value) + '${' + currentDevice.deviceName + '.' + row.name + '}' + unit + content.slice(cursorPosition.value)
235
+ } else {
236
+ props.payload.data.content = text.value = content + '${' + currentDevice.deviceName + '.' + row.name + '}' + unit
237
+ }
232
238
  // 查找所有${}
233
239
  const matches = content.match(defaultMatch)
234
240
  const index = matches?.length || 0
@@ -237,8 +243,10 @@ const checkField = (row) => {
237
243
  deviceName: currentDevice.deviceName,
238
244
  deviceCode: currentDevice.deviceCode,
239
245
  field: row.dataField,
246
+ fieldName: row.name,
240
247
  })
241
248
  props.payload.label = replace(props.payload.data.content)
249
+ console.log(props.payload.data.content, props.payload.data.fields)
242
250
  })
243
251
  }
244
252
 
@@ -271,42 +279,83 @@ const changeText = () => {
271
279
  }
272
280
 
273
281
  const inputRef = ref(null)
282
+ const forbiddenRegex = /[\$\{|\}]/g;
274
283
 
275
284
  /**
276
285
  * 编辑内容
277
286
  */
278
- const changeContent = () => {
279
- //判断字符串是否进行了删除操作
280
- if (props.payload.data.content.length > text.value.length) {
281
- // 判断是否删除的是}
282
- if (props.payload.data.content.endsWith('}')) {
283
- // 找出所有的${}
284
- const matches = props.payload.data.content.match(defaultMatch)
285
- if (matches) {
286
- const index = matches.length - 1
287
- // 删除数组中最后一个元素
288
- props.payload.data.fields.splice(index, 1)
289
- // 删除字符串中最后一个${}
290
- text.value = props.payload.data.content.substring(0, props.payload.data.content.lastIndexOf('${'))
291
- }
287
+ const changeContent = (currentValue) => {
288
+ if (forbiddenRegex.test(currentValue)) {
289
+ text.value = text.value.slice(0, -1)
290
+ }
291
+ const content = props.payload.data.content
292
+
293
+ if (currentValue.length < content.length) {
294
+ const {deleted, start, end} = getDeletedSubstring(content, currentValue);
295
+ if (deleted === '}') {
296
+ // 找到前面的"${" 删除
297
+ const startIndex = content.lastIndexOf('${', start)
298
+ const deleteContent = content.substring(startIndex, start) + '}'
299
+ text.value = content.replace(deleteContent, '')
300
+ // 字符串去掉'${'和'}'
301
+ const matchedContent = deleteContent.replace(/[${}]/g, '')
302
+ props.payload.data.fields = props.payload.data.fields.filter(item => {
303
+ return item.deviceName + '.' + item.fieldName !== matchedContent
304
+ })
292
305
  }
293
306
  }
294
- props.payload.data.content = text.value
295
- props.payload.label = replace(text.value)
307
+
308
+ // 正常更新
309
+ props.payload.data.content = text.value;
310
+ props.payload.label = replace(text.value);
311
+ console.log(props.payload.data.content, props.payload.data.fields);
296
312
  }
297
313
 
298
- /**
299
- * 设置焦点
300
- */
301
- const setFocus = () => {
302
- if (inputRef.value) {
303
- const inputElement = inputRef.value.$refs.textarea; // 获取原生输入元素
304
- inputElement.focus();
305
- const length = text.value.length;
306
- inputElement.setSelectionRange(length, length);
314
+ const getDeletedSubstring = (oldStr, newStr) => {
315
+ let i = 0;
316
+ let j = 0;
317
+
318
+ // 找到第一个不相同的字符位置
319
+ while (i < oldStr.length && j < newStr.length && oldStr[i] === newStr[j]) {
320
+ i++;
321
+ j++;
322
+ }
323
+
324
+ // 如果新字符串已经结束,则后续都是被删除的内容
325
+ if (j === newStr.length && i < oldStr.length) {
326
+ return {
327
+ deleted: oldStr.slice(i),
328
+ start: i,
329
+ end: oldStr.length
330
+ };
331
+ }
332
+
333
+ // 向后尝试匹配剩余部分,找到最短删除范围
334
+ let k = oldStr.length - 1;
335
+ let l = newStr.length - 1;
336
+
337
+ while (k > i && l > j && oldStr[k] === newStr[l]) {
338
+ k--;
339
+ l--;
307
340
  }
341
+
342
+ const deleted = oldStr.slice(i, k);
343
+ return {
344
+ deleted,
345
+ start: i,
346
+ end: k
347
+ };
308
348
  }
309
349
 
350
+ // 记录光标位置
351
+ const cursorPosition = ref(null)
352
+
353
+ const leaveInput = () => {
354
+ const inputElement = inputRef.value?.$refs.textarea;
355
+ cursorPosition.value = inputElement.selectionStart;
356
+ }
357
+
358
+
310
359
  const ports = ref([]) // 连接桩数据
311
360
 
312
361
  /**
@@ -373,11 +422,32 @@ const deletePort = (id) => {
373
422
  onMounted(() => {
374
423
  getPorts()
375
424
  getDevices()
376
- document.addEventListener('selectionchange', () => {
377
- // 判断是否在输入框内
378
- if (document.activeElement.tagName === 'TEXTAREA') {
379
- setFocus()
380
- }
425
+
426
+ nextTick(() => {
427
+ document.addEventListener('selectionchange', () => {
428
+ if (!inputRef.value) {
429
+ return false;
430
+ }
431
+ const inputElement = inputRef.value?.$refs.textarea;
432
+ const cursorPosition = inputElement.selectionStart;
433
+ const content = text.value;
434
+ const regex = /\$\{.*?\}/g;
435
+ let match;
436
+
437
+ while ((match = regex.exec(content)) !== null) {
438
+ const start = match.index;
439
+ const end = regex.lastIndex;
440
+
441
+ if (cursorPosition > start && cursorPosition < end) {
442
+ console.log('光标位于字段:', match[0]);
443
+ // 设置光标到往后的第一个}符号后面
444
+ inputElement.setSelectionRange(end, end);
445
+ return true; // 光标在 ${...} 内
446
+ }
447
+ }
448
+ console.log('光标不在任何字段内');
449
+ return false;
450
+ })
381
451
  })
382
452
  })
383
453
  </script>
@@ -228,7 +228,7 @@ export const setMathRandom = () => {
228
228
  export const defaultText = '--'
229
229
 
230
230
  // 默认匹配字符串
231
- export const defaultMatch = /\$\{(.*?)\}/g
231
+ export const defaultMatch = /\$\{([^}]+)\}/g
232
232
 
233
233
  // 默认条件管道单个配置
234
234
  export const defaultPipeCondition = {