yangkaixiang преди 5 месеца
родител
ревизия
3615d2ee5e
променени са 3 файла, в които са добавени 177 реда и са изтрити 43 реда
  1. 1 1
      package.json
  2. 175 42
      src/pages/Alarm/components/components/Formular.jsx
  3. 1 0
      src/pages/Alarm/components/components/oneNode.js

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "dt-alarm-component",
-  "version": "1.1.19",
+  "version": "1.1.20",
   "description": "",
   "main": "lib/index.js",
   "scripts": {

+ 175 - 42
src/pages/Alarm/components/components/Formular.jsx

@@ -6,6 +6,7 @@ import React, {
   forwardRef,
   useImperativeHandle,
 } from "react";
+import { Spin } from 'antd';
 import HintBox from "./HintBox";
 import styles from "./fomular.module.less";
 import { moveInTextNode, isFirefox } from "./utils";
@@ -19,6 +20,7 @@ const Formular = (props, ref) => {
   const [cursorHtmlRange, setCursorHtmlRange] = useState();
   const [formularText, setFormularText] = useState();
   const [formularHtml, setFormularHtml] = useState();
+  const [loading, setLoading] = useState(false);
   // const [globalRange, setGlobalRange] = useState();
   const rangeCurrent = useRef(); //历史光标range位置
   const globalRangeRef = useRef(); //全局range的记录
@@ -103,18 +105,23 @@ const Formular = (props, ref) => {
       var match = inputStr.match(regx);
       match = match.map((item) => item.replace("[", "").replace("]", ""));
       // const res = await API.energySearchByPointsIds(match)
-      const res = await API2.searchPoint({
+      setLoading(true)
+      API2.searchPoint({
         point_ids: match,
         count: 20,
         type: 1,
-      });
-      if (res.state === 0) {
-        res.data?.forEach((item) => {
-          vars[item.point_id] = item.name;
-        });
-      } else {
-        vars = {};
-      }
+      }).then(res => {
+        if (res.state === 0) {
+          res.data?.forEach((item) => {
+            vars[item.point_id] = item.name;
+          });
+        } else {
+          vars = {};
+        }
+      }).finally(() => {
+        setLoading(false)
+      })
+
       console.log(vars);
       initDisplay({ vars: vars, formula: inputStr });
       outStrRef.current = inputStr;
@@ -302,7 +309,7 @@ const Formular = (props, ref) => {
   const setValue = () => {
     let formula = "";
     const vars = {};
-    
+
     const processNode = (node) => {
       if (node.dataset?.point_id) {
         // 处理点位节点
@@ -324,9 +331,9 @@ const Formular = (props, ref) => {
         }
       }
     };
-    
+
     formulaRef.current.childNodes.forEach(processNode);
-    
+
     const res = {
       formula,
       vars,
@@ -335,14 +342,138 @@ const Formular = (props, ref) => {
     console.log(outStrRef.current);
   };
 
-  const handlePaste = useCallback((e) => {
-    // 允许粘贴,但在粘贴后更新内容
-    setTimeout(() => {
-      setValue();
-      updateCursorLocation();
-    }, 0);
+  const cleanPastedText = useCallback((text) => {
+    if (!text || typeof text !== 'string') return ''
+
+    /** 检测是否包含HTML标签和换行符(用于调试日志) */
+    const hasHtmlTags = /<[^>]*>/g.test(text)
+    const hasLineBreaks = /[\r\n\t]+/g.test(text)
+
+    if (hasHtmlTags) {
+      console.warn('检测到粘贴内容包含HTML标签,已自动清理')
+    }
+    if (hasLineBreaks) {
+      console.warn('检测到粘贴内容包含换行符,已转换为空格')
+    }
+
+    return text
+      /** 移除零宽字符 */
+      .replace(/[\u200B-\u200D\uFEFF]/g, '')
+      /** 移除控制字符 */
+      .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, '')
+      /** 移除HTML标签 */
+      .replace(/<[^>]*>/g, '')
+      /** 统一处理所有空白字符:换行符、制表符、各种空格 → 单个普通空格 */
+      .replace(/[\r\n\t\s\u00A0\u2000-\u200A\u202F\u205F\u3000]+/g, ' ')
+      /** 移除首尾空格 */
+      .trim()
+  }, [])
+
+  /**
+   * 异步获取点位信息并转换文本为HTML,[point_id]转换为img节点,其他保持为文本
+   * @param {string} text - 输入文本,如 "[123]+[456]"
+   * @returns {Promise<string>} - 转换后的HTML字符串
+   */
+  const convertTextToHtmlWithApi = useCallback(async (text) => {
+    // 匹配 [point_id] 模式
+    const pointPattern = /\[([^\[\]]+)\]/g;
+    
+    let match;
+    const matches = [];
+    const pointIds = [];
+    
+    // 收集所有匹配项
+    while ((match = pointPattern.exec(text)) !== null) {
+      matches.push({
+        fullMatch: match[0], // [123]
+        pointId: match[1],   // 123
+        index: match.index
+      });
+      pointIds.push(match[1]);
+    }
+    
+    if (pointIds.length === 0) {
+      // 没有点位变量,直接返回原文本
+      return text;
+    }
+    
+    // 调用API获取点位信息
+    let pointVars = {};
+    try {
+      const res = await API2.searchPoint({
+        point_ids: pointIds,
+        count: 20,
+        type: 1,
+      });
+      
+      if (res.state === 0) {
+        res.data?.forEach((item) => {
+          pointVars[item.point_id] = item.name;
+        });
+      }
+    } catch (error) {
+      console.error('获取点位信息失败:', error);
+      // 如果API调用失败,使用point_id作为name
+      pointIds.forEach(id => {
+        pointVars[id] = id;
+      });
+    }
+    
+    let result = text;
+    
+    // 从后往前替换,避免索引位置变化
+    for (let i = matches.length - 1; i >= 0; i--) {
+      const matchItem = matches[i];
+      const pointName = pointVars[matchItem.pointId] || matchItem.pointId;
+      const imgHtml = oneNode(matchItem.pointId, pointName);
+      result = result.substring(0, matchItem.index) + 
+               imgHtml + 
+               result.substring(matchItem.index + matchItem.fullMatch.length);
+    }
+    
+    return result;
   }, []);
 
+  const handlePaste = useCallback(async (e) => {
+    e.preventDefault()
+    /** 获取剪贴板数据 */
+    const clipboardData = e.clipboardData
+    if (!clipboardData) return false
+
+    /** 获取并清理粘贴的文本内容 */
+    const rawText = clipboardData.getData('text/plain')
+    const cleanedText = cleanPastedText(rawText)
+    /** 如果清理后没有有效文本内容,使用默认行为或阻止粘贴 */
+    if (!cleanedText) {
+      e.preventDefault()
+      return true
+    }
+
+    console.log('原始文本:', cleanedText);
+    
+    try {
+      setLoading(true);
+      
+      /** 异步获取点位信息并转换为HTML格式 */
+      const htmlContent = await convertTextToHtmlWithApi(cleanedText);
+      console.log('转换后的HTML:', htmlContent);
+
+      /** 将转换后的HTML插入到编辑器中 */
+      dtInsertFormular(htmlContent);
+
+      /** 更新输出值 */
+      setTimeout(() => {
+        setValue();
+      }, 0);
+      
+    } catch (error) {
+      console.error('粘贴处理失败:', error);
+    } finally {
+      setLoading(false);
+    }
+
+  }, [convertTextToHtmlWithApi, cleanPastedText]);
+
   const handleCopy = useCallback((e) => {
     // 允许复制操作
     updateCursorLocation();
@@ -358,30 +489,32 @@ const Formular = (props, ref) => {
 
   return (
     <div className={styles.wrapper}>
-      <div
-        id="formulaId"
-        ref={formulaRef}
-        className="editor"
-        contentEditable
-        onClick={handleClick}
-        onKeyUp={handleKeyUp}
-        onKeyDown={handleKeyDown}
-        onCut={handleCut}
-        onBlur={divBlur}
-        onPaste={handlePaste}
-        onCopy={handleCopy}
-      ></div>
-      <div>
-        <HintBox
-          visible={hintVisible}
-          setVis={() => setHintVisible(false)}
-          // hintData={pointData}
-          queryString={queryString}
-          position={position}
-          onPickPoint={handlePickPoint}
-          onClickPoint={handlePickPoint}
-        ></HintBox>
-      </div>
+      <Spin spinning={loading}>
+        <div
+          id="formulaId"
+          ref={formulaRef}
+          className="editor"
+          contentEditable
+          onClick={handleClick}
+          onKeyUp={handleKeyUp}
+          onKeyDown={handleKeyDown}
+          onCut={handleCut}
+          onBlur={divBlur}
+          onPaste={handlePaste}
+          onCopy={handleCopy}
+        ></div>
+        <div>
+          <HintBox
+            visible={hintVisible}
+            setVis={() => setHintVisible(false)}
+            // hintData={pointData}
+            queryString={queryString}
+            position={position}
+            onPickPoint={handlePickPoint}
+            onClickPoint={handlePickPoint}
+          ></HintBox>
+        </div>
+      </Spin>
       {/* <button onClick={backEndInput}>后端输入</button>
       <button onClick={()=>dtInsertFormular('()')}>输入字符</button> */}
     </div>

+ 1 - 0
src/pages/Alarm/components/components/oneNode.js

@@ -6,6 +6,7 @@ export default function oneNode(point_id, name) {
   // window.navigator.clipboard.writeText("${point_id}");
   return `<img 
   title='${point_id}' 
+  alt='[${point_id}]' 
   data-point_id='${point_id}' 
   src=${drawPoint(name)}
     >`