skyffire 1 жил өмнө
parent
commit
42e333d87e

+ 1 - 1
example/main.js

@@ -75,7 +75,7 @@ function createWindow() {
   win.loadFile(index); // 确保路径正确
 
   // 打开调试工具
-  win.webContents.openDevTools();
+  if (isDev) win.webContents.openDevTools();
 
   // 创建菜单模板,只包含一个刷新按钮
   const menuTemplate = [

+ 1 - 1
example/package.json

@@ -1,7 +1,7 @@
 {
   "name": "heatmap",
   "homepage": ".",
-  "version": "1.0.9",
+  "version": "1.1.0",
   "private": true,
   "main": "main.js",
   "scripts": {

+ 132 - 10
example/src/App.js

@@ -4,9 +4,12 @@ import '@rongmz/react-stock-heatmap/example/src/index.css';
 import toast, { Toaster } from 'react-hot-toast';
 import { v4 as uuidv4 } from 'uuid';
 import axios from 'axios';
+import { Select, Button, Input, Space } from 'tdesign-react';
+import { DeleteIcon } from 'tdesign-icons-react';
+import 'tdesign-react/es/style/index.css';
+import value from "d3-interpolate/src/value";
 
-const path = require('path');
-const fs = require('fs');
+const {Option} = Select;
 
 function formatTimestamp(timestamp) {
   // 创建一个新的 Date 对象
@@ -83,6 +86,7 @@ function parseStockData(data) {
 export default () => {
   const [isActivation, setIsActivation] = React.useState(false);
   const [activationCode, setActivationCode] = React.useState();
+  const [loginSymbol,setLoginSymbol]= React.useState();
   const [loading, setLoading] = React.useState(true);
   const progressRef = React.useRef(null);
   /** @type {React.MutableRefObject<StockHeatmap>} */
@@ -94,9 +98,61 @@ export default () => {
     setAutoScroll(value);
   };
 
+  // 下拉框部分
+  const [symbolOptions, setSymbolOptions] = React.useState([]);
+  const [editOrCreate, toggleEditOrCreate] = React.useState('edit');
+
+  const [inputSymbol, changeInputSymbol] = React.useState({ });
+
+  const handleClickConfirm = async () => {
+    toast.remove()
+    if (!inputSymbol.symbol) return toast.error("品种不能为空!")
+    if (!inputSymbol.port) return toast.error("端口号不能为空!")
+
+    const options = {...inputSymbol, id: uuidv4()};
+    const newOptions = [...symbolOptions, options];
+    setSymbolOptions(newOptions);
+    changeInputSymbol({symbol:"",port:""});
+    toggleEditOrCreate('edit');
+    await window.electronAPI.setSymbolData(newOptions)
+  };
+  const handleDeleteSymbolOption= async (option)=>{
+    const newOptions = symbolOptions.filter(item=>item.id !== option.id)
+    setSymbolOptions(newOptions)
+    if(loginSymbol === option.id) setLoginSymbol(undefined)
+    await window.electronAPI.setSymbolData(newOptions)
+  }
+
   // ------------ Load data -------------
-  React.useEffect(() => {
-    const ws = new WebSocket('ws://localhost:6789');
+  // React.useEffect(() => {
+  //   const symbolInfo = symbolOptions.find((item)=> item.id == loginSymbol)
+  //   const ws = new WebSocket(`ws://localhost:${symbolInfo.port}`);
+  //   let ref = heatmapRef.current
+  //
+  //   console.log('ws创建完成')
+  //   ws.onmessage = function(event) {
+  //     const message = JSON.parse(event.data);
+  //
+  //     let stock = parseStockData(message)
+  //
+  //     ref.addData(stock)
+  //
+  //     if (progressRef.current !== null) {
+  //       progressRef.current.innerHTML = ` 等待数据推送 ${(100 * ref.data.length / ref.windowLength + 1).toFixed(0)}% ...`
+  //
+  //       if (ref.data.length >= ref.windowLength) {
+  //         setLoading(false)
+  //       }
+  //     }
+  //   };
+  //
+  //   ws.onerror = function(event) {
+  //     console.error("WebSocket error observed:", event);
+  //   };
+  // }, []);
+  const connectWebSocket = ()=>{
+    const symbolInfo = symbolOptions.find((item)=> item.id === loginSymbol)
+    const ws = new WebSocket(`ws://localhost:${symbolInfo.port}`);
     let ref = heatmapRef.current
 
     console.log('ws创建完成')
@@ -119,7 +175,7 @@ export default () => {
     ws.onerror = function(event) {
       console.error("WebSocket error observed:", event);
     };
-  }, []);
+  }
 
   // ------------ Load data -------------
   const checkStatus = async ()=>{
@@ -155,13 +211,14 @@ export default () => {
         checkStatus()
       },5000)
       setIsActivation(true)
+      connectWebSocket()
     }else{
       toast.error(response.data.msg);
     }
   }
 
   // ---------- window update ------------
-  React.useEffect(async () => {
+  React.useEffect( async () => {
     // 处理是否有登录信息
     let loginInfo = await window.electronAPI.getLoginInfoData();
     if(loginInfo.loginInfo) {
@@ -176,6 +233,12 @@ export default () => {
       }
     }
 
+    // 处理品种选择
+    let symbolInfo = await window.electronAPI.getSymbolData();
+    if(symbolInfo.length > 0) {
+      setSymbolOptions(symbolInfo)
+    }
+
     const updateFn = () => {
       setWindowDim([
         window.innerWidth,
@@ -251,10 +314,69 @@ export default () => {
             <div className="title">
               软件登录
             </div>
-            <div className="iptWp">
-              <input placeholder="请输入登录码" value={activationCode || ''} onChange={(e)=>{
-                setActivationCode(e.target.value)
-              }} />
+            <div className="iptWp customIpt">
+              <Input className="password ipt" placeholder="请输入登录码" type="password" value={activationCode || ''} onChange={(value)=>{setActivationCode(value)}} />
+              <Select
+                placeholder="请选择品种"
+                className="symbol ipt"
+                clearable
+                value={loginSymbol}
+                onChange={(value)=>{setLoginSymbol(value)}}
+                panelBottomContent={
+                  <div
+                    className="select-panel-footer"
+                    style={{
+                      position: 'sticky',
+                      bottom: 0,
+                      backgroundColor: 'var(--td-bg-color-container)',
+                      zIndex: 2,
+                    }}
+                  >
+                    {editOrCreate === 'edit' ? (
+                      <div
+                        style={{
+                          padding: '8px 6px',
+                          borderTop: '1px solid var(--td-border-level-2-color)',
+                        }}
+                      >
+                        <Button theme="primary" size="small" variant="text" onClick={() => toggleEditOrCreate('create')}>
+                          新增选项
+                        </Button>
+                      </div>
+                    ) : (
+                      <div style={{ padding: 8, borderTop: '1px solid var(--td-border-level-2-color)' }}>
+                        <Space>
+                          <Input placeholder="请输入品种" size="small" autofocus value={inputSymbol.symbol} onChange={(value) => changeInputSymbol({...inputSymbol,symbol:value})}></Input>
+                          <Input placeholder="请输入端口号" size="small" autofocus value={inputSymbol.port} onChange={(value) => changeInputSymbol({...inputSymbol,port:value})}></Input>
+                        </Space>
+                        <Button size="small" style={{ marginTop: '12px' }} onClick={handleClickConfirm}>
+                          确认
+                        </Button>
+                        <Button
+                          theme="default"
+                          size="small"
+                          style={{ marginTop: '12px', marginLeft: '8px' }}
+                          onClick={() => toggleEditOrCreate('edit')}
+                        >
+                          取消
+                        </Button>
+                      </div>
+                    )}
+                  </div>
+                }
+              >
+                {symbolOptions.map((option) => (
+                  <Option key={option.id} value={option.id} label={`${option.symbol}:${option.port}`}>
+                    <div style={{ display: 'flex', alignItems: 'center' }}>
+                      <div style={{ flex:"1",paddingRight:"10px",boxSizing:"border-box" }}>{`${option.symbol}:${option.port}`}</div>
+                      <DeleteIcon style={{ width:"16px"}} onClick={(e)=>{
+                        e.stopPropagation();
+                        handleDeleteSymbolOption(option)
+                      }}/>
+                    </div>
+                  </Option>
+                  ))}
+              </Select>
             </div>
             <div className="btnWp">
               <div className="btn" onClick={handleActivation}>登 录</div>

+ 17 - 3
example/src/index.css

@@ -138,7 +138,7 @@ code {
   width: 100%;
   height: 100%;
   background-color: rgba(0,0,0,0.5);
-  z-index: 9999;
+  z-index: 999;
 }
 .layoutContainer .activationBox{
   box-sizing: border-box;
@@ -155,11 +155,17 @@ code {
 .layoutContainer .activationBox .iptWp{
   padding: 20px 0;
 }
-.iptWp input{
+.layoutContainer .activationBox .iptWp .password{
   width: 300px;
-  height: 30px;
+}
+.layoutContainer .activationBox .iptWp .ipt{
+  padding-bottom: 10px;
+}
+.layoutContainer .activationBox .iptWp .ipt:last-child{
+  padding-bottom: 0;
 }
 
+
 .layoutContainer .activationBox .btnWp{
   text-align: right;
 }
@@ -191,3 +197,11 @@ code {
 .toasterWp{
   z-index: 10000;
 }
+
+.t-input__inner{
+  width: 100%;
+}
+
+.t-select-option span{
+  flex: 1;
+}