|
|
@@ -0,0 +1,164 @@
|
|
|
+import * as React from 'react';
|
|
|
+import { observer } from 'mobx-react';
|
|
|
+// import workSrc from '@/assets/workbench/work.png';
|
|
|
+// import store from './store';
|
|
|
+// import './style.less';
|
|
|
+import { Input } from 'antd';
|
|
|
+
|
|
|
+const Workbench: React.FC = () => {
|
|
|
+ // const {
|
|
|
+ // state,
|
|
|
+ // init,
|
|
|
+ // reset
|
|
|
+ // } = store;
|
|
|
+ // const {
|
|
|
+ // pageLoading
|
|
|
+ // } = state;
|
|
|
+
|
|
|
+ React.useEffect(() => {
|
|
|
+ // init();
|
|
|
+ // return () => reset();
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const [value, setValue] = React.useState('');
|
|
|
+
|
|
|
+ // 处理鼠标悬停事件
|
|
|
+ const handleMouseOver = (e: React.MouseEvent<HTMLTextAreaElement>) => {
|
|
|
+ const textarea = e.target as HTMLTextAreaElement;
|
|
|
+ const text = textarea.value;
|
|
|
+
|
|
|
+ // 获取鼠标位置
|
|
|
+ const rect = textarea.getBoundingClientRect();
|
|
|
+ const mouseX = e.clientX - rect.left;
|
|
|
+ const mouseY = e.clientY - rect.top;
|
|
|
+
|
|
|
+ // 获取textarea的样式信息
|
|
|
+ const computedStyle = window.getComputedStyle(textarea);
|
|
|
+ const fontSize = parseInt(computedStyle.fontSize);
|
|
|
+ const fontFamily = computedStyle.fontFamily;
|
|
|
+ const lineHeight = parseInt(computedStyle.lineHeight) || fontSize * 1.2;
|
|
|
+ const paddingTop = parseInt(computedStyle.paddingTop);
|
|
|
+ const paddingLeft = parseInt(computedStyle.paddingLeft);
|
|
|
+
|
|
|
+ // 创建canvas来测量文本
|
|
|
+ const canvas = document.createElement('canvas');
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ if (!ctx) return;
|
|
|
+
|
|
|
+ ctx.font = `${fontSize}px ${fontFamily}`;
|
|
|
+
|
|
|
+ // 获取光标位置(字符索引)
|
|
|
+ const caretPosition = getCaretPosition(textarea, mouseX, mouseY);
|
|
|
+
|
|
|
+ // 查找所有"打印"的位置
|
|
|
+ const printPositions: {start: number, end: number, isPrinter: boolean}[] = [];
|
|
|
+ let startIndex = 0;
|
|
|
+ while (startIndex < text.length) {
|
|
|
+ const printIndex = text.indexOf('打印', startIndex);
|
|
|
+ if (printIndex === -1) break;
|
|
|
+
|
|
|
+ // 检查是否是"打印机"
|
|
|
+ const isPrinter = text.substring(printIndex, printIndex + 3) === '富文本';
|
|
|
+ printPositions.push({
|
|
|
+ start: printIndex,
|
|
|
+ end: printIndex + (isPrinter ? 3 : 2),
|
|
|
+ isPrinter
|
|
|
+ });
|
|
|
+
|
|
|
+ startIndex = printIndex + 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查光标是否在任何一个"打印"文本上
|
|
|
+ let isOnPrint = false;
|
|
|
+ for (const pos of printPositions) {
|
|
|
+ if (caretPosition >= pos.start && caretPosition <= pos.end && !pos.isPrinter) {
|
|
|
+ isOnPrint = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isOnPrint) {
|
|
|
+ console.log('鼠标悬停在"打印"上');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取光标位置的辅助函数(字符索引)
|
|
|
+ const getCaretPosition = (element: HTMLTextAreaElement, x: number, y: number) => {
|
|
|
+ const computedStyle = window.getComputedStyle(element);
|
|
|
+ const lineHeight = parseInt(computedStyle.lineHeight) || parseInt(computedStyle.fontSize) * 1.2;
|
|
|
+ const paddingTop = parseInt(computedStyle.paddingTop);
|
|
|
+ const paddingLeft = parseInt(computedStyle.paddingLeft);
|
|
|
+ const fontSize = parseInt(computedStyle.fontSize);
|
|
|
+ const fontFamily = computedStyle.fontFamily;
|
|
|
+
|
|
|
+ // 计算行号
|
|
|
+ const row = Math.floor((y - paddingTop) / lineHeight);
|
|
|
+
|
|
|
+ // 获取每行文本
|
|
|
+ const lines = element.value.split('\n');
|
|
|
+
|
|
|
+ // 计算到目标行之前的字符数
|
|
|
+ let position = 0;
|
|
|
+ for (let i = 0; i < row && i < lines.length; i++) {
|
|
|
+ position += lines[i].length + 1; // +1 for \n
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算列位置(字符索引)
|
|
|
+ const canvas = document.createElement('canvas');
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ if (!ctx) return position;
|
|
|
+
|
|
|
+ ctx.font = `${fontSize}px ${fontFamily}`;
|
|
|
+ const currentLine = lines[row] || '';
|
|
|
+
|
|
|
+ // 计算每个字符的位置,找到最接近鼠标位置的字符
|
|
|
+ let currentWidth = paddingLeft;
|
|
|
+ let col = 0;
|
|
|
+
|
|
|
+ while (col < currentLine.length) {
|
|
|
+ const charWidth = ctx.measureText(currentLine[col]).width;
|
|
|
+ // 如果鼠标位置在当前字符的中间之前,则选择当前字符位置
|
|
|
+ if (currentWidth + charWidth / 2 > x) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ currentWidth += charWidth;
|
|
|
+ col++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return position + col;
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className='workbench'>
|
|
|
+ <div className='workbench-top'>
|
|
|
+ <div className='workbench-top-style'>
|
|
|
+ <div className='workbench-top-style-welcome'>
|
|
|
+ <div className='workbench-top-style-welcome-text'>
|
|
|
+ <div className='workbench-top-style-welcome-text-first'>
|
|
|
+ 欢迎使用
|
|
|
+ </div>
|
|
|
+ <div className='workbench-top-style-welcome-text-second'>
|
|
|
+ React框架
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div className='workbench-top-style-welcome-picture'>
|
|
|
+ {/* <img src={workSrc} /> */}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div className='workbench-top-style-fast'></div>
|
|
|
+ </div>
|
|
|
+ <div className='workbench-top-weather'>
|
|
|
+ <Input.TextArea
|
|
|
+ style={{ height: 200 }}
|
|
|
+ value={value}
|
|
|
+ onChange={(e) => setValue(e.target.value)}
|
|
|
+ onMouseMove={handleMouseOver}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div className='workbench-bottom'></div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default observer(Workbench);
|