Browse Source

优化样式及LIS功能

master
LiLongLong 1 month ago
parent
commit
879ec183bc
  1. 1
      components.d.ts
  2. 1
      src/assets/alarm/default-normal.svg
  3. 1
      src/assets/alarm/default-status.svg
  4. 1
      src/assets/alarm/error-1.svg
  5. 2
      src/assets/alarm/error.svg
  6. 1
      src/assets/alarm/light.svg
  7. 1
      src/assets/alarm/normal-2.svg
  8. 2
      src/assets/alarm/normal.svg
  9. 1
      src/assets/alarm/warn.svg
  10. 4
      src/assets/pre.svg
  11. 3
      src/assets/un-pre.svg
  12. 4
      src/components/SoftKeyboard.vue
  13. 26
      src/components/dialogs/AlarmModal.vue
  14. 8
      src/components/dialogs/AlarmModalHistory.vue
  15. 43
      src/components/dialogs/PreReactionBall.vue
  16. 2
      src/main.ts
  17. 53
      src/pages/Index/History.vue
  18. 40
      src/pages/Index/Index.vue
  19. 3
      src/pages/Index/Regular/Consumables.vue
  20. 1
      src/pages/Index/Regular/Running.vue
  21. 37
      src/pages/Index/Settings/Device.vue
  22. 357
      src/pages/Index/Settings/EditLis.vue
  23. 242
      src/pages/Index/Settings/Lis.vue
  24. 7
      src/pages/Index/Settings/NavBar.vue
  25. 501
      src/pages/Index/Settings/Network.vue
  26. 4
      src/pages/Index/Settings/Version.vue
  27. 1
      src/pages/Index/components/Consumables/SpttingPlates.vue
  28. 34
      src/pages/Index/components/Running/LittleBufferDisplay.vue
  29. 1
      src/pages/Index/components/TestTube/Tube.vue
  30. 4
      src/router/router.ts
  31. 2
      src/services/Index/settings/settings.ts
  32. 1
      src/services/osControl/os.ts
  33. 6
      src/store/modules/consumables.ts
  34. 4
      src/store/modules/device.ts
  35. 7
      src/store/modules/running.ts
  36. 1
      src/store/modules/useSystemStore.ts
  37. 8
      src/utils/getServerInfo.ts
  38. 1
      src/websocket/socket.ts

1
components.d.ts

@ -32,6 +32,7 @@ declare module 'vue' {
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTag: typeof import('element-plus/es')['ElTag']

1
src/assets/alarm/default-normal.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="37" height="37" viewBox="0 0 37 37"><g><g><ellipse cx="18.5" cy="18.5" rx="18.5" ry="18.5" fill="#D9D9D9" fill-opacity="1"/></g><g><ellipse cx="18.5" cy="18.5" rx="12.5" ry="12.5" fill="#D9D9D9" fill-opacity="1"/><ellipse cx="18.5" cy="18.5" rx="12.5" ry="12.5" fill-opacity="0" stroke-opacity="1" stroke="#FFFFFF" fill="none" stroke-width="4"/></g></g></svg>

1
src/assets/alarm/default-status.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="106" height="106" viewBox="0 0 106 106"><g><g style="opacity:0.10000000149011612;"><ellipse cx="53" cy="53" rx="53" ry="53" fill="#D9D9D9" fill-opacity="0.41999998688697815"/></g><g><ellipse cx="53" cy="53" rx="46" ry="46" fill="#D9D9D9" fill-opacity="0.4300000071525574"/></g><g><ellipse cx="53" cy="53" rx="44" ry="44" fill="#D9D9D9" fill-opacity="1"/></g><g><ellipse cx="53.5" cy="52.5" rx="18.5" ry="18.5" fill="#FFFFFF" fill-opacity="1"/></g><g transform="matrix(-1,0,0,1,112,0)"><path d="M60.62969,56.0266C60.50625,57.373400000000004,59.65,58.0031,58.80469,58.0031C58.17656,58.0031,58.80469,58.0031,58.80469,58.0031C58.00156,57.851600000000005,57.37812,57.5094,57.10469,56.1469L56,43.4125C56,42.13281,57.55625,41,58.87656,41C60.19687,41,61.61875,42.18437,61.61875,43.4625L60.62969,56.0266ZM58.80938,59.668800000000005C57.48906,59.668800000000005,56.417189,60.7391,56.417189,62.060900000000004C56.417189,63.3828,57.4875,64.4547,58.80938,64.4547C60.13125,64.4547,61.20156,63.3828,61.20156,62.060900000000004C61.20156,60.7406,60.13125,59.668800000000005,58.80938,59.668800000000005Z" fill="#D9D9D9" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>

1
src/assets/alarm/error-1.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="106" height="106" viewBox="0 0 106 106"><defs><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg0_74_359"><stop offset="0%" stop-color="#F34447" stop-opacity="1"/><stop offset="100%" stop-color="#DB1819" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg1_77_0329"><stop offset="0%" stop-color="#FFCCCD" stop-opacity="1"/><stop offset="100%" stop-color="#FFD3D3" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg2_77_347"><stop offset="0%" stop-color="#FA7073" stop-opacity="1"/><stop offset="96.66661024093628%" stop-color="#F95455" stop-opacity="1"/></linearGradient></defs><g><g style="opacity:0.10000000149011612;"><ellipse cx="53" cy="53" rx="53" ry="53" fill="url(#master_svg0_74_359)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="46" ry="46" fill="url(#master_svg1_77_0329)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="44" ry="44" fill="url(#master_svg2_77_347)" fill-opacity="1"/></g><g><path d="M42.63686,69.2431L39.8802,69.2431L39.8802,56.4975C39.8802,49.2658,45.750299999999996,43.399879999999996,52.9966,43.399879999999996C60.2429,43.399879999999996,66.113,49.2616,66.113,56.4975L66.113,69.2431L63.0888,69.2431M53.943799999999996,48.6805L47.4748,59.3223L52.6526,59.3223L51.3571,67.3047L57.8261,56.6629L52.6526,56.6629L53.943799999999996,48.6805ZM63.8661,36.99104C64.4735,37.34308,64.6816,38.11927,64.3291,38.73004L62.005700000000004,42.7679L59.8097,41.49547L62.137299999999996,37.4576C62.485600000000005,36.85107,63.258700000000005,36.64324,63.8661,36.99104ZM52.9924,34.000816397C53.727199999999996,33.9753677,54.3431,34.547964,54.3686,35.28174L54.3686,39.85826L51.6162,39.85826L51.6162,35.28174C51.6417,34.547964,52.2575,33.9753677,52.9924,34.000816397ZM42.12715,36.99104C42.7303,36.64324,43.5076,36.84683,43.8559,37.45336C43.8559,37.45336,43.8559,37.4576,43.860150000000004,37.4576L46.187799999999996,41.49547L43.991820000000004,42.7679L41.66417,38.73004C41.31162,38.123509999999996,41.51975,37.347319999999996,42.12715,36.99104ZM34.171496,44.9692C34.519795,44.362700000000004,35.29285,44.1549,35.90025,44.498400000000004C35.90025,44.498400000000004,35.90449,44.498400000000004,35.90449,44.502700000000004L39.93542,46.835499999999996L38.6654,49.0368L34.638726,46.704C34.0270794,46.3562,33.81895,45.58,34.171496,44.9692ZM71.83019999999999,44.9692C72.1785,45.5757,71.9747,46.3519,71.3673,46.7082L67.3363,49.041L66.0663,46.8397L70.093,44.5069C70.7004,44.1591,71.4734,44.362700000000004,71.82169999999999,44.9692C71.82169999999999,44.965,71.826,44.965,71.83019999999999,44.9692ZM35.38629,69.2431L70.6112,69.2431C71.3758,69.2431,71.9916,69.8623,71.9916,70.6215C71.9916,71.38499999999999,71.3715,72,70.6112,72L35.38629,72C34.621736,72,34.00584162,71.38069999999999,34.00584162,70.6215C34.00159407,69.8623,34.621736,69.2431,35.38629,69.2431Z" fill="#FFFFFF" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>

2
src/assets/alarm/error.svg

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="106" height="106" viewBox="0 0 106 106"><defs><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg0_74_359"><stop offset="0%" stop-color="#F34447" stop-opacity="1"/><stop offset="100%" stop-color="#DB1819" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg1_77_0329"><stop offset="0%" stop-color="#FFCCCD" stop-opacity="1"/><stop offset="100%" stop-color="#FFD3D3" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg2_77_347"><stop offset="0%" stop-color="#FA7073" stop-opacity="1"/><stop offset="96.66661024093628%" stop-color="#F95455" stop-opacity="1"/></linearGradient></defs><g><g style="opacity:0.10000000149011612;"><ellipse cx="53" cy="53" rx="53" ry="53" fill="url(#master_svg0_74_359)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="46" ry="46" fill="url(#master_svg1_77_0329)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="44" ry="44" fill="url(#master_svg2_77_347)" fill-opacity="1"/></g><g><path d="M42.63686,69.2431L39.8802,69.2431L39.8802,56.4975C39.8802,49.2658,45.750299999999996,43.399879999999996,52.9966,43.399879999999996C60.2429,43.399879999999996,66.113,49.2616,66.113,56.4975L66.113,69.2431L63.0888,69.2431M53.943799999999996,48.6805L47.4748,59.3223L52.6526,59.3223L51.3571,67.3047L57.8261,56.6629L52.6526,56.6629L53.943799999999996,48.6805ZM63.8661,36.99104C64.4735,37.34308,64.6816,38.11927,64.3291,38.73004L62.005700000000004,42.7679L59.8097,41.49547L62.137299999999996,37.4576C62.485600000000005,36.85107,63.258700000000005,36.64324,63.8661,36.99104ZM52.9924,34.000816397C53.727199999999996,33.9753677,54.3431,34.547964,54.3686,35.28174L54.3686,39.85826L51.6162,39.85826L51.6162,35.28174C51.6417,34.547964,52.2575,33.9753677,52.9924,34.000816397ZM42.12715,36.99104C42.7303,36.64324,43.5076,36.84683,43.8559,37.45336C43.8559,37.45336,43.8559,37.4576,43.860150000000004,37.4576L46.187799999999996,41.49547L43.991820000000004,42.7679L41.66417,38.73004C41.31162,38.123509999999996,41.51975,37.347319999999996,42.12715,36.99104ZM34.171496,44.9692C34.519795,44.362700000000004,35.29285,44.1549,35.90025,44.498400000000004C35.90025,44.498400000000004,35.90449,44.498400000000004,35.90449,44.502700000000004L39.93542,46.835499999999996L38.6654,49.0368L34.638726,46.704C34.0270794,46.3562,33.81895,45.58,34.171496,44.9692ZM71.83019999999999,44.9692C72.1785,45.5757,71.9747,46.3519,71.3673,46.7082L67.3363,49.041L66.0663,46.8397L70.093,44.5069C70.7004,44.1591,71.4734,44.362700000000004,71.82169999999999,44.9692C71.82169999999999,44.965,71.826,44.965,71.83019999999999,44.9692ZM35.38629,69.2431L70.6112,69.2431C71.3758,69.2431,71.9916,69.8623,71.9916,70.6215C71.9916,71.38499999999999,71.3715,72,70.6112,72L35.38629,72C34.621736,72,34.00584162,71.38069999999999,34.00584162,70.6215C34.00159407,69.8623,34.621736,69.2431,35.38629,69.2431Z" fill="#FFFFFF" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="106" height="106" viewBox="0 0 106 106"><defs><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg0_74_359"><stop offset="0%" stop-color="#F34447" stop-opacity="1"/><stop offset="100%" stop-color="#DB1819" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg1_77_0329"><stop offset="0%" stop-color="#FFCCCD" stop-opacity="1"/><stop offset="100%" stop-color="#FFD3D3" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg2_77_347"><stop offset="0%" stop-color="#FA7073" stop-opacity="1"/><stop offset="96.66661024093628%" stop-color="#F95455" stop-opacity="1"/></linearGradient><clipPath id="master_svg3_84_893"><rect x="78" y="28" width="50" height="50" rx="0"/></clipPath></defs><g><g style="opacity:0.10000000149011612;"><ellipse cx="53" cy="53" rx="53" ry="53" fill="url(#master_svg0_74_359)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="46" ry="46" fill="url(#master_svg1_77_0329)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="44" ry="44" fill="url(#master_svg2_77_347)" fill-opacity="1"/></g><g transform="matrix(-1,0,0,1,156,0)" clip-path="url(#master_svg3_84_893)"><g transform="matrix(-1,0,0,1,244,0)"><path d="M140.83350000000002,35C130.47402,35,122,43.474019999999996,122,53.8335C122,64.193,130.47402,72.667,140.83350000000002,72.667C151.193,72.667,159.667,64.193,159.667,53.8335C159.667,43.474019999999996,151.193,35,140.83350000000002,35ZM149.8324,60.3213C150.4623,60.9512,150.4623,62.1018,149.8324,62.7274C149.51749999999998,63.0424,149.1018,63.252300000000005,148.5769,63.252300000000005C148.1569,63.252300000000005,147.6362,63.0424,147.3213,62.7274L141.2534,56.6596L135.1855,62.7274C134.5557,63.357299999999995,133.4051,63.357299999999995,132.7794,62.7274C132.15370000000001,62.0976,132.1495,60.947,132.7794,60.3213L138.8473,54.2534L132.7794,48.1855C132.4645,47.870599999999996,132.2545,47.4549,132.2545,46.93C132.2545,46.5101,132.4645,45.9894,132.7794,45.6744C133.4093,45.0445,134.5599,45.0445,135.1855,45.6744L141.2534,51.7423L147.3213,45.6744C147.6362,45.3595,148.052,45.1495,148.5769,45.1495C148.9968,45.1495,149.51749999999998,45.3595,149.8324,45.6744C150.1474,45.9894,150.3573,46.4051,150.3573,46.93C150.3573,47.3499,150.1474,47.870599999999996,149.8324,48.1855L143.7646,54.2534L149.8324,60.3213Z" fill="#FFFFFF" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></g></svg>

1
src/assets/alarm/light.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="37" height="37" viewBox="0 0 37 37"><g><g><ellipse cx="18.5" cy="18.5" rx="18.5" ry="18.5" fill="#52D375" fill-opacity="1"/></g><g><ellipse cx="18.5" cy="18.5" rx="12.5" ry="12.5" fill="#52D375" fill-opacity="1"/><ellipse cx="18.5" cy="18.5" rx="12.5" ry="12.5" fill-opacity="0" stroke-opacity="1" stroke="#FFFFFF" fill="none" stroke-width="4"/></g></g></svg>

1
src/assets/alarm/normal-2.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="106" height="106" viewBox="0 0 106 106"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_77_496"><stop offset="0%" stop-color="#08DBB2" stop-opacity="1"/><stop offset="100%" stop-color="#18D899" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg1_77_0177"><stop offset="11.533631384372711%" stop-color="#A6FFEE" stop-opacity="1"/><stop offset="90.39525389671326%" stop-color="#B5F7DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg2_77_772"><stop offset="11.533631384372711%" stop-color="#08DBB2" stop-opacity="1"/><stop offset="90.39525389671326%" stop-color="#1ED78F" stop-opacity="1"/></linearGradient></defs><g><g style="opacity:0.10000000149011612;"><ellipse cx="53" cy="53" rx="53" ry="53" fill="url(#master_svg0_77_496)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="46" ry="46" fill="url(#master_svg1_77_0177)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="44" ry="44" fill="url(#master_svg2_77_772)" fill-opacity="1"/></g><g><path d="M42.63686,69.2431L39.8802,69.2431L39.8802,56.4975C39.8802,49.2658,45.750299999999996,43.399879999999996,52.9966,43.399879999999996C60.2429,43.399879999999996,66.113,49.2616,66.113,56.4975L66.113,69.2431L63.0888,69.2431M53.943799999999996,48.6805L47.4748,59.3223L52.6526,59.3223L51.3571,67.3047L57.8261,56.6629L52.6526,56.6629L53.943799999999996,48.6805ZM63.8661,36.99104C64.4735,37.34308,64.6816,38.11927,64.3291,38.73004L62.005700000000004,42.7679L59.8097,41.49547L62.137299999999996,37.4576C62.485600000000005,36.85107,63.258700000000005,36.64324,63.8661,36.99104ZM52.9924,34.000816397C53.727199999999996,33.9753677,54.3431,34.547964,54.3686,35.28174L54.3686,39.85826L51.6162,39.85826L51.6162,35.28174C51.6417,34.547964,52.2575,33.9753677,52.9924,34.000816397ZM42.12715,36.99104C42.7303,36.64324,43.5076,36.84683,43.8559,37.45336C43.8559,37.45336,43.8559,37.4576,43.860150000000004,37.4576L46.187799999999996,41.49547L43.991820000000004,42.7679L41.66417,38.73004C41.31162,38.123509999999996,41.51975,37.347319999999996,42.12715,36.99104ZM34.171496,44.9692C34.519795,44.362700000000004,35.29285,44.1549,35.90025,44.498400000000004C35.90025,44.498400000000004,35.90449,44.498400000000004,35.90449,44.502700000000004L39.93542,46.835499999999996L38.6654,49.0368L34.638726,46.704C34.0270794,46.3562,33.81895,45.58,34.171496,44.9692ZM71.83019999999999,44.9692C72.1785,45.5757,71.9747,46.3519,71.3673,46.7082L67.3363,49.041L66.0663,46.8397L70.093,44.5069C70.7004,44.1591,71.4734,44.362700000000004,71.82169999999999,44.9692C71.82169999999999,44.965,71.826,44.965,71.83019999999999,44.9692ZM35.38629,69.2431L70.6112,69.2431C71.3758,69.2431,71.9916,69.8623,71.9916,70.6215C71.9916,71.38499999999999,71.3715,72,70.6112,72L35.38629,72C34.621736,72,34.00584162,71.38069999999999,34.00584162,70.6215C34.00159407,69.8623,34.621736,69.2431,35.38629,69.2431Z" fill="#FFFFFF" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>

2
src/assets/alarm/normal.svg

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="106" height="106" viewBox="0 0 106 106"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_77_496"><stop offset="0%" stop-color="#08DBB2" stop-opacity="1"/><stop offset="100%" stop-color="#18D899" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg1_77_0177"><stop offset="11.533631384372711%" stop-color="#A6FFEE" stop-opacity="1"/><stop offset="90.39525389671326%" stop-color="#B5F7DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg2_77_772"><stop offset="11.533631384372711%" stop-color="#08DBB2" stop-opacity="1"/><stop offset="90.39525389671326%" stop-color="#1ED78F" stop-opacity="1"/></linearGradient></defs><g><g style="opacity:0.10000000149011612;"><ellipse cx="53" cy="53" rx="53" ry="53" fill="url(#master_svg0_77_496)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="46" ry="46" fill="url(#master_svg1_77_0177)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="44" ry="44" fill="url(#master_svg2_77_772)" fill-opacity="1"/></g><g><path d="M42.63686,69.2431L39.8802,69.2431L39.8802,56.4975C39.8802,49.2658,45.750299999999996,43.399879999999996,52.9966,43.399879999999996C60.2429,43.399879999999996,66.113,49.2616,66.113,56.4975L66.113,69.2431L63.0888,69.2431M53.943799999999996,48.6805L47.4748,59.3223L52.6526,59.3223L51.3571,67.3047L57.8261,56.6629L52.6526,56.6629L53.943799999999996,48.6805ZM63.8661,36.99104C64.4735,37.34308,64.6816,38.11927,64.3291,38.73004L62.005700000000004,42.7679L59.8097,41.49547L62.137299999999996,37.4576C62.485600000000005,36.85107,63.258700000000005,36.64324,63.8661,36.99104ZM52.9924,34.000816397C53.727199999999996,33.9753677,54.3431,34.547964,54.3686,35.28174L54.3686,39.85826L51.6162,39.85826L51.6162,35.28174C51.6417,34.547964,52.2575,33.9753677,52.9924,34.000816397ZM42.12715,36.99104C42.7303,36.64324,43.5076,36.84683,43.8559,37.45336C43.8559,37.45336,43.8559,37.4576,43.860150000000004,37.4576L46.187799999999996,41.49547L43.991820000000004,42.7679L41.66417,38.73004C41.31162,38.123509999999996,41.51975,37.347319999999996,42.12715,36.99104ZM34.171496,44.9692C34.519795,44.362700000000004,35.29285,44.1549,35.90025,44.498400000000004C35.90025,44.498400000000004,35.90449,44.498400000000004,35.90449,44.502700000000004L39.93542,46.835499999999996L38.6654,49.0368L34.638726,46.704C34.0270794,46.3562,33.81895,45.58,34.171496,44.9692ZM71.83019999999999,44.9692C72.1785,45.5757,71.9747,46.3519,71.3673,46.7082L67.3363,49.041L66.0663,46.8397L70.093,44.5069C70.7004,44.1591,71.4734,44.362700000000004,71.82169999999999,44.9692C71.82169999999999,44.965,71.826,44.965,71.83019999999999,44.9692ZM35.38629,69.2431L70.6112,69.2431C71.3758,69.2431,71.9916,69.8623,71.9916,70.6215C71.9916,71.38499999999999,71.3715,72,70.6112,72L35.38629,72C34.621736,72,34.00584162,71.38069999999999,34.00584162,70.6215C34.00159407,69.8623,34.621736,69.2431,35.38629,69.2431Z" fill="#FFFFFF" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="106" height="106" viewBox="0 0 106 106"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_77_496"><stop offset="0%" stop-color="#08DBB2" stop-opacity="1"/><stop offset="100%" stop-color="#18D899" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg1_77_0177"><stop offset="11.533631384372711%" stop-color="#A6FFEE" stop-opacity="1"/><stop offset="90.39525389671326%" stop-color="#B5F7DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg2_77_772"><stop offset="11.533631384372711%" stop-color="#08DBB2" stop-opacity="1"/><stop offset="90.39525389671326%" stop-color="#1ED78F" stop-opacity="1"/></linearGradient><clipPath id="master_svg3_84_38"><rect x="34" y="34" width="38" height="38" rx="0"/></clipPath></defs><g><g style="opacity:0.10000000149011612;"><ellipse cx="53" cy="53" rx="53" ry="53" fill="url(#master_svg0_77_496)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="46" ry="46" fill="url(#master_svg1_77_0177)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="44" ry="44" fill="url(#master_svg2_77_772)" fill-opacity="1"/></g><g clip-path="url(#master_svg3_84_38)"><g><path d="M53,34C42.50658,34,34,42.50658,34,53C34,63.4934,42.50658,72,53,72C63.4934,72,72,63.4934,72,53C72,42.50658,63.4934,34,53,34ZM62.7428,48.1541L51.1971,59.6999C51.060199999999995,59.8371,50.8949,59.9427,50.712900000000005,60.009299999999996C50.2288,60.209199999999996,49.6511,60.1126,49.2577,59.7192L43.27489,53.7365C42.75317,53.2148,42.75317,52.3689,43.27489,51.8472C43.79661,51.3254,44.6425,51.3254,45.1642,51.8472L50.2177,56.9007L60.8536,46.2648C61.375299999999996,45.7431,62.221199999999996,45.7431,62.7429,46.2648C63.2646,46.7866,63.2646,47.632400000000004,62.7428,48.1541Z" fill="#FFFFFF" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></g></svg>

1
src/assets/alarm/warn.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="106" height="106" viewBox="0 0 106 106"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_77_799"><stop offset="5.238037183880806%" stop-color="#E8C199" stop-opacity="1"/><stop offset="100%" stop-color="#FA7640" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg1_77_0466"><stop offset="11.533631384372711%" stop-color="#FFDCC5" stop-opacity="1"/><stop offset="90.39525389671326%" stop-color="#FFD6C5" stop-opacity="1"/></linearGradient><linearGradient x1="0.21183465421199799" y1="0.0819903314113617" x2="0.7641705870628356" y2="0.910494387149811" id="master_svg2_77_787"><stop offset="11.533631384372711%" stop-color="#FB9A5B" stop-opacity="1"/><stop offset="90.39525389671326%" stop-color="#FA7640" stop-opacity="1"/></linearGradient></defs><g><g style="opacity:0.10000000149011612;"><ellipse cx="53" cy="53" rx="53" ry="53" fill="url(#master_svg0_77_799)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="46" ry="46" fill="url(#master_svg1_77_0466)" fill-opacity="1"/></g><g><ellipse cx="53" cy="53" rx="44" ry="44" fill="url(#master_svg2_77_787)" fill-opacity="1"/></g><g><ellipse cx="53.5" cy="52.5" rx="18.5" ry="18.5" fill="#FFFFFF" fill-opacity="1"/></g><g transform="matrix(-1,0,0,1,112,0)"><path d="M60.62969,56.0266C60.50625,57.373400000000004,59.65,58.0031,58.80469,58.0031C58.17656,58.0031,58.80469,58.0031,58.80469,58.0031C58.00156,57.851600000000005,57.37812,57.5094,57.10469,56.1469L56,43.4125C56,42.13281,57.55625,41,58.87656,41C60.19687,41,61.61875,42.18437,61.61875,43.4625L60.62969,56.0266ZM58.80938,59.668800000000005C57.48906,59.668800000000005,56.417189,60.7391,56.417189,62.060900000000004C56.417189,63.3828,57.4875,64.4547,58.80938,64.4547C60.13125,64.4547,61.20156,63.3828,61.20156,62.060900000000004C61.20156,60.7406,60.13125,59.668800000000005,58.80938,59.668800000000005Z" fill="#ED6A0C" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>

4
src/assets/pre.svg

@ -1,3 +1,3 @@
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.50049 33C7.01356 33.0001 6.53394 32.8816 6.10303 32.6549C5.67212 32.4282 5.30288 32.0999 5.02718 31.6986C4.75149 31.2972 4.57764 30.8348 4.52063 30.3512C4.46363 29.8676 4.52518 29.3775 4.69999 28.923L5.73949 26.223C7.14378 26.6577 8.60447 26.8831 10.0745 26.892C12.7663 26.9003 15.3916 26.0566 17.5745 24.4815C22.748 20.817 27.971 23.4015 29.9105 24.6315L31.5605 28.926C31.7344 29.3797 31.7956 29.8689 31.7387 30.3515C31.6817 30.834 31.5084 31.2956 31.2337 31.6964C30.9589 32.0971 30.5909 32.4252 30.1613 32.6523C29.7317 32.8793 29.2534 32.9987 28.7675 33H7.50049ZM6.81499 23.427L10.6355 13.5H18.8855C18.2888 13.5 17.7165 13.7371 17.2945 14.159C16.8725 14.581 16.6355 15.1533 16.6355 15.75C16.6355 16.3467 16.8725 16.919 17.2945 17.341C17.7165 17.7629 18.2888 18 18.8855 18C19.4822 18 20.0545 17.7629 20.4765 17.341C20.8984 16.919 21.1355 16.3467 21.1355 15.75C21.1355 15.1533 20.8984 14.581 20.4765 14.159C20.0545 13.7371 19.4822 13.5 18.8855 13.5H25.6355L28.3355 20.535C26.2918 19.7276 24.0792 19.4419 21.8974 19.7038C19.7157 19.9657 17.6335 20.7669 15.839 22.035C14.1589 23.2593 12.1338 23.9189 10.055 23.919C8.95746 23.9114 7.86675 23.7457 6.81649 23.427H6.81499ZM10.6355 13.5V6H9.13549C8.73766 6 8.35613 5.84197 8.07483 5.56066C7.79352 5.27936 7.63549 4.89782 7.63549 4.5C7.63549 4.10218 7.79352 3.72064 8.07483 3.43934C8.35613 3.15804 8.73766 3 9.13549 3H27.1355C27.5333 3 27.9148 3.15804 28.1961 3.43934C28.4775 3.72064 28.6355 4.10218 28.6355 4.5C28.6355 4.89782 28.4775 5.27936 28.1961 5.56066C27.9148 5.84197 27.5333 6 27.1355 6H25.6355V13.5H10.6355Z" fill="#0C56A6"/>
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M29.1037 25.8149L21.3832 11.87V5.93945H22.6522C23.32 5.93945 23.8543 5.40517 23.8543 4.7373C23.8543 4.06944 23.32 3.53516 22.6522 3.53516H9.56215C8.89428 3.53516 8.36 4.06947 8.36 4.7373C8.36 5.40513 8.89432 5.93945 9.56215 5.93945H10.8311V11.8834L3.21751 25.5878C2.95035 26.082 2.75 26.6297 2.75 27.2307C2.75 28.9004 3.96552 30.2495 5.47485 30.2495H27.0199C28.3824 30.0892 29.4643 28.7935 29.4643 27.2307C29.4643 26.7098 29.3173 26.2423 29.1037 25.8149ZM12.8079 12.7249C12.9557 12.4739 13.0341 12.1881 13.035 11.8968V5.93945H19.1793V11.87C19.1793 12.1639 19.2594 12.4444 19.4064 12.6982L20.5952 15.2227H11.6459L12.8079 12.7249V12.7249ZM12.2469 25.3608C11.9957 25.3527 11.7579 25.2457 11.5852 25.0631C11.4126 24.8805 11.3192 24.637 11.3253 24.3857C11.3303 24.1428 11.429 23.9113 11.6008 23.7395C11.7725 23.5678 12.0041 23.469 12.2469 23.464C12.7679 23.464 13.1953 23.8915 13.1953 24.4124C13.1953 24.9334 12.7679 25.3608 12.2469 25.3608ZM16.0136 20.3118C16.0136 20.5135 15.9739 20.7132 15.8967 20.8996C15.8195 21.086 15.7064 21.2553 15.5637 21.3979C15.4211 21.5406 15.2518 21.6537 15.0654 21.7309C14.879 21.8081 14.6793 21.8478 14.4776 21.8478C14.2758 21.8478 14.0761 21.8081 13.8897 21.7309C13.7034 21.6537 13.534 21.5406 13.3914 21.3979C13.2488 21.2553 13.1356 21.086 13.0584 20.8996C12.9812 20.7132 12.9415 20.5135 12.9415 20.3118C12.9415 19.9044 13.1033 19.5137 13.3914 19.2256C13.6795 18.9375 14.0702 18.7757 14.4776 18.7757C14.885 18.7757 15.2757 18.9375 15.5637 19.2256C15.8518 19.5137 16.0136 19.9044 16.0136 20.3118ZM18.9255 26.1488C18.6974 26.1492 18.4714 26.1046 18.2605 26.0175C18.0497 25.9304 17.8581 25.8025 17.6968 25.6412C17.5354 25.4799 17.4075 25.2883 17.3204 25.0774C17.2333 24.8666 17.1887 24.6406 17.1891 24.4124C17.1891 23.4507 17.9638 22.676 18.9255 22.676C19.8872 22.676 20.6619 23.4507 20.6619 24.4124C20.6619 25.3741 19.8872 26.1488 18.9255 26.1488Z" fill="#4AA71B"/>
</svg>

3
src/assets/un-pre.svg

@ -0,0 +1,3 @@
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M29.1037 25.8149L21.3832 11.87V5.93945H22.6522C23.32 5.93945 23.8543 5.40517 23.8543 4.7373C23.8543 4.06944 23.32 3.53516 22.6522 3.53516H9.56215C8.89428 3.53516 8.36 4.06947 8.36 4.7373C8.36 5.40513 8.89432 5.93945 9.56215 5.93945H10.8311V11.8834L3.21751 25.5878C2.95035 26.082 2.75 26.6297 2.75 27.2307C2.75 28.9004 3.96552 30.2495 5.47485 30.2495H27.0199C28.3824 30.0892 29.4643 28.7935 29.4643 27.2307C29.4643 26.7098 29.3173 26.2423 29.1037 25.8149ZM12.8079 12.7249C12.9557 12.4739 13.0341 12.1881 13.035 11.8968V5.93945H19.1793V11.87C19.1793 12.1639 19.2594 12.4444 19.4064 12.6982L20.5952 15.2227H11.6459L12.8079 12.7249V12.7249ZM12.2469 25.3608C11.9957 25.3527 11.7579 25.2457 11.5852 25.0631C11.4126 24.8805 11.3192 24.637 11.3253 24.3857C11.3303 24.1428 11.429 23.9113 11.6008 23.7395C11.7725 23.5678 12.0041 23.469 12.2469 23.464C12.7679 23.464 13.1953 23.8915 13.1953 24.4124C13.1953 24.9334 12.7679 25.3608 12.2469 25.3608ZM16.0136 20.3118C16.0136 20.5135 15.9739 20.7132 15.8967 20.8996C15.8195 21.086 15.7064 21.2553 15.5637 21.3979C15.4211 21.5406 15.2518 21.6537 15.0654 21.7309C14.879 21.8081 14.6793 21.8478 14.4776 21.8478C14.2758 21.8478 14.0761 21.8081 13.8897 21.7309C13.7034 21.6537 13.534 21.5406 13.3914 21.3979C13.2488 21.2553 13.1356 21.086 13.0584 20.8996C12.9812 20.7132 12.9415 20.5135 12.9415 20.3118C12.9415 19.9044 13.1033 19.5137 13.3914 19.2256C13.6795 18.9375 14.0702 18.7757 14.4776 18.7757C14.885 18.7757 15.2757 18.9375 15.5637 19.2256C15.8518 19.5137 16.0136 19.9044 16.0136 20.3118ZM18.9255 26.1488C18.6974 26.1492 18.4714 26.1046 18.2605 26.0175C18.0497 25.9304 17.8581 25.8025 17.6968 25.6412C17.5354 25.4799 17.4075 25.2883 17.3204 25.0774C17.2333 24.8666 17.1887 24.6406 17.1891 24.4124C17.1891 23.4507 17.9638 22.676 18.9255 22.676C19.8872 22.676 20.6619 23.4507 20.6619 24.4124C20.6619 25.3741 19.8872 26.1488 18.9255 26.1488Z" fill="#8D8D8D"/>
</svg>

4
src/components/SoftKeyboard.vue

@ -63,7 +63,9 @@ const handleKeyPress = (key: string) => {
}, 150)
if (key === 'del') {
emits('update:modelValue', props.modelValue.slice(0, -1))
const value = props.modelValue.slice(0, -1)
console.log('value--------', value)
emits('update:modelValue', value)
}
else if (key === 'enter') {
emits('confirm', props.modelValue)

26
src/components/dialogs/AlarmModal.vue

@ -8,10 +8,19 @@
:key="index"
class="alarm-item"
>
<div v-if="alarm.state">
<div v-if="alarm.flagType === AlARM_STATUS_MAP.NormalFlag">
<div>
<img v-if="alarm.state" :src="lightSvg" style="width: 7rem" alt="" />
<img v-else :src="defaultNormalSvg" style="width: 7rem" alt="" />
</div>
<div>
<div>{{ alarm.state ? alarm.notTriggeredDisName : alarm.triggeredStateName }}</div>
</div>
</div>
<div v-else-if="alarm.state">
<div>
<img v-if="alarm.flagType === AlARM_STATUS_MAP.NormalFlag" :src="normalSvg" style="width: 7rem" alt="" />
<img v-else-if="alarm.flagType === AlARM_STATUS_MAP.WarningFlag" :src="warningSvg" style="width: 7rem" alt="" />
<img v-else-if="alarm.flagType === AlARM_STATUS_MAP.WarningFlag" :src="warnSvg" style="width: 7rem" alt="" />
<img v-else-if="alarm.flagType === AlARM_STATUS_MAP.ErrorFlag" :src="errorSvg" style="width: 7rem" @click="handleItemClick(alarm)" alt=""/>
</div>
<div >
@ -35,13 +44,15 @@
<script lang="ts" setup>
import { useDeviceStore } from '@/store'
import type { WarningState } from '@/websocket/socket'
import { ref, watchEffect } from 'vue'
import { onMounted, ref, watchEffect } from 'vue'
import { clearFlagState } from '@/services'
import message from 'element-plus/es/components/message/index.mjs'
import AlarmDetailByType from './AlarmDetailByType.vue'
import normalSvg from '@/assets/alarm/normal.svg'
import warningSvg from '@/assets/alarm/warning.svg'
import warnSvg from '@/assets/alarm/warn.svg'
import errorSvg from '@/assets/alarm/error.svg'
import defaultNormalSvg from '@/assets/alarm/default-normal.svg'
import lightSvg from '@/assets/alarm/light.svg'
import { AlARM_STATUS_MAP } from '@/constant'
const deviceStore = useDeviceStore()
@ -66,9 +77,12 @@ const clearAlarm = (alarm: WarningState,index: number) => {
})
};
onMounted(() => {
console.log('=====alarmmodal=============')
})
watchEffect(() => {
console.log('deviceStore.alarmList--', deviceStore.alarmList)
alarmList.value = deviceStore.alarmList
alarmList.value = deviceStore.alarmList || []
})
</script>

8
src/components/dialogs/AlarmModalHistory.vue

@ -20,7 +20,7 @@
</template>
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
import { onMounted, ref, watchEffect } from 'vue'
import { useSystemStore } from '@/store/modules/useSystemStore.ts'
import { formatDate } from '@/utils/formDate.ts'
import StatusDetail from '@/components/dialogs/StatusDetail.vue'
@ -48,9 +48,13 @@ const onHandleStatusData = () => {
})
statusList.value = notifyList
}
onMounted(() => {
console.log('=====alarmmodal=======history======')
})
watchEffect(() => {
console.log('systemStore.statusList---', systemStore.statusList)
onHandleStatusData()
// onHandleStatusData()
})
</script>

43
src/components/dialogs/PreReactionBall.vue

@ -6,15 +6,19 @@
:key="index"
class="ball"
>
<div v-if="isOccupied(item)" class="inner-circle" :style="{ backgroundColor: ballColor }">
<div v-if="isOccupied(item)" class="inner-circle" :key="ballColor" :style="{ background: ballColor }">
<div class="inner-user">
{{ item.sampleInfo.userid }}
<span v-if="item.reactionRemainingTime">{{ formatRemainTime(item.reactionRemainingTime) }}</span>
</div>
</div>
<div v-else class="inner-circle" :style="{ backgroundColor: '#e4e4e4' }">
<img src="@/assets/running/stop_s.svg" alt="empty" style="width:6rem"/>
<div v-if="item.state === 'USED'">
</div>
<img v-else src="@/assets/running/stop_s.svg" alt="empty" style="width:6rem"/>
</div>
<div>{{ ballStateMap[item.state] }}</div>
</div>
</div>
@ -23,12 +27,14 @@
<script lang="ts" setup>
import { useRunningStore } from '@/store/modules/running';
import { watchEffect, ref, computed } from 'vue'
import { watchEffect, ref, computed, onMounted, nextTick } from 'vue'
import { type PreReactionPosGroupState } from '@/websocket/socket'
import { useConsumablesStore } from '@/store';
import { formatRemainTime } from '../../pages/Index/utils'
const consumableStore = useConsumablesStore()
const props = defineProps<{
bgColor: string
}>()
const runningStore = useRunningStore()
const preReactoinGroup = ref<PreReactionPosGroupState>(runningStore.preReactoinGroup)
const ballColor = ref()
@ -41,13 +47,17 @@ const ballStateMap = {
}
watchEffect(() => {
console.log('runningStore.preReactoinGroup---', runningStore.preReactoinGroup)
preReactoinGroup.value = runningStore.preReactoinGroup
ballColor.value = consumableStore.ballColor
console.log('props.bgColor---', props.bgColor)
if(props.bgColor !== ballColor.value){
ballColor.value = props.bgColor
}
})
const isOccupied = (item): boolean => {
if(item.state === 'REACTING' || item.state === 'REACTION_COMPLETED'){
console.log('item.state--', item.state)
if(item.state === 'REACTING' || item.state === 'REACTION_COMPLETED' || item.state === 'TO_BE_USED'){
return true
}
return false
@ -69,7 +79,26 @@ const isOccupied = (item): boolean => {
position: absolute;
padding: 15px;
font-size: 15px;
color: #ffffff;
}
}
}
.tube-circle {
width: 6rem;
height: 6rem;
border-radius: 999px;
border: solid 1px gray;
background-color: #fff;
display: flex;
justify-content: center;
align-items: center;
.add-symbol {
color: black;
font-size: 20px;
}
margin-bottom: 6px;
}
</style>

2
src/main.ts

@ -18,7 +18,7 @@ const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.config.warnHandler = () => null
// app.config.warnHandler = () => null
app.component('Confirm', Confirm)
app.use(router)
app.use(pinia)

53
src/pages/Index/History.vue

@ -32,8 +32,7 @@
<el-table-column prop="lotId" label="批次" ></el-table-column>
<el-table-column prop="results" label="结果" width="150px">
<template #default="scope">
<div v-for="(r, idx) in scope.row.results" :key="idx">
{{ showResult(r) }}
<div v-for="(r, idx) in scope.row.results" :key="idx" v-html="showResult(r)">
</div>
</template>
</el-table-column>
@ -107,6 +106,7 @@
<div v-if="rowData" class="result-group">
<p style="font-weight: 600">结果</p>
<div
class="result-sub"
v-for="(r, idx) in rowData.results"
@ -114,15 +114,26 @@
>
<div>{{ r.subProjName + ':' }}</div>
<div class="result-success" v-if="r.status === 'SUCCESS'">
<span>结果</span>
<span
class="res-unit"
v-for="res in r.resultConverters"
:key="res.uint"
>
{{ (r.result * res.A + res.B).toFixed(2) }}
{{ res.uintstr + '; ' }}
</span>
<div style="display: flex">
<div>单位</div>
<div
class="res-unit"
v-for="res in r.resultConverters"
:key="res.uint"
>
<div class="uint-result">{{ res.uintstr}}</div>
</div>
</div>
<div style="display: flex; margin-top: 5px;">
<div>结果</div>
<div
class="res-unit"
v-for="res in r.resultConverters"
:key="res.uint"
>
<div class="uint-result">{{ (r.result * res.A + res.B).toFixed(2) }}</div>
</div>
</div>
</div>
<div class="result-error" v-else>
<div>结果错误</div>
@ -174,9 +185,12 @@ const showResult = (t: ResultItem) => {
return '错误'
}
const unit1 = t.resultConverters[0]
return (
t.subProjName + ' ' + (t.result * unit1.A + unit1.B).toFixed(2) + ' ' + unit1.uintstr
)
const html = `<div style="display: flex">
<div style="width: 54px; white-space: nowrap;text-overflow: ellipsis;overflow: hidden">${t.subProjName}:</div>
<div>${(t.result * unit1.A + unit1.B).toFixed(2)}</div>
<div>${unit1.uintstr}</div>
</div>`
return html
}
@ -324,6 +338,7 @@ const load = () => {
if (currentPage.value > totalPage.value) {
disabled.value = true
}
systemStore.clearReactionRecordList()
}).catch(() => {
eMessage.error("获取数据失败")
}).finally(() => {
@ -485,8 +500,14 @@ watchEffect(() => {
margin-left: 20px;
}
.result-success {
display: flex;
gap: 12px;
margin-left: 10px;
.uint-result{
width: 8rem;
background: #e9e9e9;
margin-left: 5px;
text-align: center;
padding: 0 10px;
}
}
.result-error {
color: red;

40
src/pages/Index/Index.vue

@ -42,13 +42,16 @@
data-tab="常规"
>常规</router-link
>
<router-link
to="/index/history"
class="nav-tab"
:class="{ active: currentRoute.name === 'history'}"
data-tab="历史"
<el-badge :value="badgeValue" class="item">
<router-link
to="/index/history"
class="nav-tab"
:class="{ active: currentRoute.name === 'history'}"
data-tab="历史"
>历史</router-link
>
>
</el-badge>
<router-link
to="/index/setting"
class="nav-tab"
@ -363,7 +366,7 @@
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router'
import { ref, onMounted, computed, watch, nextTick, useTemplateRef } from 'vue'
import { ref, onMounted, computed, watch, nextTick, useTemplateRef, watchEffect } from 'vue'
import { ElDialog, ElMessageBox } from 'element-plus'
import { Time, InitWarn, LoadingModal } from './components/Consumables'
import {
@ -428,7 +431,7 @@ const router = useRouter()
//
const currentRoute = computed(() => router.currentRoute.value)
console.log(currentRoute.value)
const badgeValue = ref()
const debug = useTemplateRef('debug')
console.log(debug.value)
@ -797,6 +800,7 @@ const handleEmergencyPosState = (data: EmergencyPosStateMessage['data']) => {
}
const handleAppWarningFlagState = (data: AppFlagStateListMessage['data']) => {
console.log('data---AppFlagStateListMessage-', data)
if (data && data.states && data.states.length) {
// showWarnModal
isTriggerAlarm.value = true
@ -806,6 +810,7 @@ const handleAppWarningFlagState = (data: AppFlagStateListMessage['data']) => {
}
const handlePreReactionPosStateState = (data: PreReactionPosGroupStateMessage['data']) => {
console.log('data---PreReactionPosGroupStateListMessage-', data)
runningStore.setPreReactoinGroupMap(data)
}
@ -824,7 +829,11 @@ const getBloodTypeList = async () => {
onMounted(() => {
eventBus.on('initDevice', showInitDeviceAlert)
eventBus.on('socketClosed', handleSocketClose)
//
wsState.subscribe<PreReactionPosGroupStateMessage>(
'PreReactionPosGroupState',
handlePreReactionPosStateState,
)
wsEvent.subscribe<AppEventMessage>('AppEvent', handleAppEvent)
wsEvent.connect()
wsState.subscribe<ConsumablesStateMessage>(
@ -867,11 +876,6 @@ onMounted(() => {
handleAppWarningFlagState,
)
//
wsState.subscribe<PreReactionPosGroupStateMessage>(
'PreReactionPosGroupState',
handlePreReactionPosStateState,
)
wsState.connect()
@ -1104,6 +1108,14 @@ watch(
}
},
)
watchEffect(() => {
if(systemStore.reactionRecordList && systemStore.reactionRecordList.length){
badgeValue.value = systemStore.reactionRecordList.length
}else{
badgeValue.value = undefined
}
})
</script>
<style scoped lang="less">

3
src/pages/Index/Regular/Consumables.vue

@ -108,9 +108,8 @@
@close="confirmWarn"
@confirm="confirmWarn"
/>
<ConfirmModal v-if="confirmVisible" :confirmInfo="confirmInfo"/>
</div>
<ConfirmModal v-if="confirmVisible" :confirmInfo="confirmInfo"/>
</template>
<script setup lang="ts">

1
src/pages/Index/Regular/Running.vue

@ -62,6 +62,7 @@
/>
</div>
<span
v-if="runningStore.optScanModuleState"
class="scan-men"
:style="`background-color:${consumablesStore.projIdColorMap[runningStore.optScanModuleState.projId]}`"
>

37
src/pages/Index/Settings/Device.vue

@ -102,43 +102,6 @@
</div>
</div>
<div class="setting-item" style="border-radius: 0">
<span class="label">DHCP</span>
<div class="options">
<button
:class="{
active: settings.DHCP,
}"
@click="updateSetting('DHCP', true)"
>
开启
</button>
<button
:class="{
active: !settings.DHCP,
}"
@click="updateSetting('DHCP', false)"
>
关闭
</button>
</div>
</div>
<div v-if="!settings.DHCP" class="setting-item">
<span class="label">WAN连接类型</span>
<div class="options">
<button
v-for="(item, index) in networkModeList"
:key="index"
:class="{
active: selectedNetworkModel === item.value,
}"
@click="updateNetworkModel(item)"
>
{{ item.label }}
</button>
</div>
</div>
<div class="setting-item">
<span class="label">打印</span>
<div class="options">

357
src/pages/Index/Settings/EditLis.vue

@ -0,0 +1,357 @@
<template>
<div class="lis-setting">
<div class="setting-item">
<span class="label">类型</span>
<div class="options">
<button
v-for="(item, idx) in LISTypeItems"
:key="idx"
:class="{ active: lisForm && lisForm.lisType === item[0] }"
@click="setLisForm('lisType', item[0])"
>
{{ item[1] }}
</button>
</div>
</div>
<div class="setting-item">
<span class="label">协议</span>
<div class="options">
<button
:class="{
active: lisForm && lisForm.lisProtocol === 'Boditech',
}"
@click="setLisForm('lisProtocol', 'Boditech')"
>
Boditech
</button>
<!-- <button-->
<!-- :class="{-->
<!-- active: lisSettings && lisSettings.lisProtocol === 'Simens',-->
<!-- }"-->
<!-- @click="updLisProtocol('Simens')"-->
<!-- >-->
<!-- Simens-->
<!-- </button>-->
</div>
</div>
<div class="setting-item">
<span class="label">接口</span>
<div class="options">
<button
v-for="(item, idx) in LISInterfaceItems"
:key="idx"
:class="{ active: lisForm && lisForm.lisIf === item[0] }"
@click="setLisForm('lisIf',item[0])"
>
{{ item[1] }}
</button>
</div>
</div>
<div
v-if="lisForm && lisForm.lisIf === 'NETWORK'"
class="setting-item"
>
<span class="label">Host's IP</span>
<div class="options">
<input
style="min-width: 250px"
v-model="lisForm.lisNetIp"
type="text"
name='ip'
@focus="showKeyboard('ip')"
readonly
/>
</div>
</div>
<div
v-if="lisForm && lisForm.lisIf === 'NETWORK'"
class="setting-item"
>
<span class="label">Host's Port</span>
<div class="options">
<input
type="text"
name='port'
v-model="lisForm.LISNetPortStr"
@focus="showKeyboard('port')"
readonly
/>
</div>
</div>
<div
v-if="lisForm && lisForm.lisIf === 'SERIAL'"
class="setting-item"
>
<span class="label">传输速度</span>
<div class="options">
<button
v-for="(item, idx) in LISSerialBaudrateItems"
:key="idx"
:class="{
active: lisForm && lisForm.lisSerialBaudrate === item[0],
}"
@click="setLisForm('lisSerialBaudrate', item[0])"
>
{{ item[1] }}
</button>
</div>
</div>
<div class="save-btn">
<el-button @click="onCancel" class="lis-cancel">取消</el-button>
<el-button type="primary" @click="saveLisForm" class="lis-save" :loading="saveLoading">保存</el-button>
</div>
</div>
<!-- 键盘 -->
<transition name="slide-up">
<div class="keyboard" v-if="keyboardVisible">
<SoftKeyboard
ref="softKeyboardRef"
v-model="inputValue"
:is-visible="keyboardVisible"
:keyboard-type="keyboardType"
@update-keyboard-visible="(visible) => keyboardVisible = visible"
@confirm="()=>{}"
@close="keyboardVisible = false"
/>
</div>
</transition>
</template>
<script setup lang="ts">
import {
getLISSetting,
LISInterfaceMap,
LISSerialBaudrateMap, LISSettings,
LISTypeMap, setSetting
} from '@/services'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import * as R from 'ramda'
import { eMessage, isValidIPv4 } from '../utils'
import SoftKeyboard from '@/components/SoftKeyboard.vue'
import message from 'element-plus/es/components/message/index.mjs'
const emits = defineEmits(['saveSuccess', 'close'])
const inputValue = ref('')
const keyboardType = ref<'text' | 'number'>('number')
const softKeyboardRef = ref()
const LISInterfaceItems = R.toPairs(LISInterfaceMap)
const LISSerialBaudrateItems = R.toPairs(LISSerialBaudrateMap)
const LISTypeItems = R.toPairs(LISTypeMap)
const lisForm = ref<Record<string, any>>({})
const saveLoading = ref(false)
const getLisSetting = async () => {
const res = await getLISSetting()
if (res && res.success) {
lisForm.value = {
...res.data,
LISNetPortStr: res.data.lisNetPort.toString(),
}
}
}
const setLisForm = async (type: string, value: string) => {
lisForm.value[type] = value
}
const saveLisForm = async () => {
console.log('lisForm.lisIf00===', lisForm.value.lisIf)
if(lisForm && lisForm.value.lisIf === 'NETWORK'){
const p = lisForm.value.LISNetPortStr.toString().trim()
if (!/^\d+$/.test(p)) {
eMessage.error('请输入合法的端口值')
return
}
lisForm.value.lisNetPort = lisForm.value.LISNetPortStr
let addr = lisForm.value.lisNetIp.trim()
if (!isValidIPv4(addr)) {
eMessage.error('请输入合法的IP地址')
return
}
}
saveLoading.value = true
setSetting(lisForm.value as LISSettings).then(res => {
saveLoading.value = false
if(res.success) {
emits('saveSuccess')
}
}).catch(e => {
saveLoading.value = false
message.error(e.message)
})
}
const onCancel = () => {
emits('close')
}
onMounted(async () => {
console.log()
await getLisSetting()
})
//
const keyboardVisible = ref(false)
const currentInputValue = ref('')
const currentInputField = ref<'ip' | 'port' | ''>('')
//
const showKeyboard = (field: 'ip' | 'port') => {
//
if (field === 'ip') {
inputValue.value = lisForm.value?.lisNetIp || ''
}
if (field === 'port') {
inputValue.value = lisForm.value?.LISNetPortStr || ''
}
currentInputField.value = field
keyboardVisible.value = true
}
//
const handleKeyboardInput = (value: string) => {
//
inputValue.value = value
//
if (currentInputField.value === 'ip') {
lisForm.value!.lisNetIp = value
} else if(currentInputField.value === 'port'){
lisForm.value!.LISNetPortStr = value
}
}
watch(inputValue, (newVal: string) => {
handleKeyboardInput(newVal)
})
//
const hideKeyboard = () => {
keyboardVisible.value = false
currentInputField.value = ''
currentInputValue.value = ''
}
//
onUnmounted(() => {
hideKeyboard()
})
</script>
<style lang="less" scoped>
.lis-setting {
background-color: #f5f7fa;
width: 100%;
height: 45vh;
box-sizing: border-box;
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
.setting-item {
background-color: #fff;
border-radius: 12px;
padding: 24px 32px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
.label {
font-size: 28px;
font-weight: 500;
color: #303133;
}
input {
padding: 8px;
border: 1px solid #ccc;
font-size: 30px;
transition: box-shadow 0.2s ease;
border-radius: 10px;
}
.options {
display: flex;
gap: 12px;
flex-wrap: wrap;
button {
min-width: 120px;
height: 56px;
padding: 0 24px;
border: 1px solid #dcdfe6;
background-color: #fff;
border-radius: 8px;
font-size: 24px;
color: #606266;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
&.active {
color: #fff;
background-color: #409eff;
border-color: #409eff;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
}
}
}
}
}
.keyboard {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 300px;
background-color: #f5f7fa;
border-top-left-radius: 16px;
border-top-right-radius: 16px;
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.save-btn{
width: 100%;
display: flex;
justify-content: center;
}
.lis-save{
width: 50%;
height: 4rem;
padding: 0 24px;
background-color: #409eff;
border-radius: 8px;
font-size: 24px;
color: #fff;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
.lis-cancel{
width: 50%;
height: 4rem;
padding: 0 24px;
border-radius: 8px;
font-size: 24px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
}
//
.slide-up-enter-active,
.slide-up-leave-active {
transition: transform 0.3s ease;
}
.slide-up-enter-from,
.slide-up-leave-to {
transform: translateY(100%);
}
</style>

242
src/pages/Index/Settings/Lis.vue

@ -4,12 +4,9 @@
<span class="label">类型</span>
<div class="options">
<button
v-for="(item, idx) in LISTypeItems"
:key="idx"
:class="{ active: lisSettings && lisSettings.lisType === item[0] }"
@click="updLisType(item[0])"
class="active"
>
{{ item[1] }}
{{ LISTypeMap[lisSettings && lisSettings.lisType || ''] }}
</button>
</div>
</div>
@ -17,33 +14,19 @@
<span class="label">协议</span>
<div class="options">
<button
:class="{
active: lisSettings && lisSettings.lisProtocol === 'Boditech',
}"
@click="updLisProtocol('Boditech')"
class="active"
>
Boditech
</button>
<!-- <button-->
<!-- :class="{-->
<!-- active: lisSettings && lisSettings.lisProtocol === 'Simens',-->
<!-- }"-->
<!-- @click="updLisProtocol('Simens')"-->
<!-- >-->
<!-- Simens-->
<!-- </button>-->
</div>
</div>
<div class="setting-item">
<span class="label">接口</span>
<div class="options">
<button
v-for="(item, idx) in LISInterfaceItems"
:key="idx"
:class="{ active: lisSettings && lisSettings.lisIf === item[0] }"
@click="updLisInterface(item[0])"
class="active"
>
{{ item[1] }}
{{ LISInterfaceMap[lisSettings && lisSettings.lisIf || ''] }}
</button>
</div>
</div>
@ -53,15 +36,7 @@
>
<span class="label">Host's IP</span>
<div class="options">
<input
style="min-width: 250px"
v-model="lisSettings.lisNetIp"
type="text"
name='ip'
@focus="showKeyboard('ip')"
readonly
/>
<button @click="updLisIP(lisSettings.lisNetIp)">设置</button>
{{ lisSettings.lisNetIp }}
</div>
</div>
<div
@ -70,14 +45,7 @@
>
<span class="label">Host's Port</span>
<div class="options">
<input
type="text"
name='port'
v-model="lisSettings.LISNetPortStr"
@focus="showKeyboard('port')"
readonly
/>
<button @click="updLisPort(lisSettings.LISNetPortStr)">设置</button>
{{ lisSettings.LISNetPortStr }}
</div>
</div>
<div
@ -87,38 +55,20 @@
<span class="label">传输速度</span>
<div class="options">
<button
v-for="(item, idx) in LISSerialBaudrateItems"
:key="idx"
:class="{
active: lisSettings && lisSettings.lisSerialBaudrate === item[0],
}"
@click="updLisSerialBaudrate(item[0])"
class="active"
>
{{ item[1] }}
{{ LISSerialBaudrateMap[lisSettings && lisSettings.lisSerialBaudrate || '']}}
</button>
</div>
</div>
<div class="setting-item">
<span class="label">导出</span>
<div class="options">
<button
:class="{
active: lisSettings && lisSettings.lisAutoExport,
}"
@click="updLisAutoExport(true)"
>
自动
</button>
<button
:class="{
active: lisSettings && !lisSettings.lisAutoExport,
}"
@click="updLisAutoExport(false)"
>
手动
</button>
</div>
<div>
<button class="edit-lis" @click="onEditList" >
编辑LIS
</button>
</div>
<el-dialog v-model="lisVisible" title="编辑LIS" width="98vw">
<EditLis @save-success="saveSuccess" @close="onCloseDialog"/>
</el-dialog>
</div>
<!-- 键盘 -->
<transition name="slide-up">
@ -139,42 +89,19 @@
<script setup lang="ts">
import {
getLISSetting,
LISInterface,
LISInterfaceMap,
LISProtocol,
LISSerialBaudrate,
LISSerialBaudrateMap,
LISSettings,
LISType,
LISTypeMap,
setLISAutoExport,
setLISInterface,
setLISNetIp,
setLISNetPort,
setLISProtocol,
setLISSerialBaudrate,
setLISType,
} from '@/services'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import * as R from 'ramda'
import { eMessage, isValidIPv4 } from '../utils'
import SoftKeyboard from '@/components/SoftKeyboard.vue'
import EditLis from '@/pages/Index/Settings/EditLis.vue'
const layout = ref()
const inputValue = ref('')
const keyboardType = ref<'text' | 'number'>('number')
const softKeyboardRef = ref()
const numericLayout = {
default: [
'1 2 3',
'4 5 6',
'7 8 9',
'. 0 {bksp}', //
],
}
const LISInterfaceItems = R.toPairs(LISInterfaceMap)
const LISSerialBaudrateItems = R.toPairs(LISSerialBaudrateMap)
const LISTypeItems = R.toPairs(LISTypeMap)
const lisVisible = ref(false)
const lisSettings = ref<(LISSettings & { LISNetPortStr: string }) | undefined>(
undefined,
)
@ -185,83 +112,10 @@ const getLisSetting = async () => {
...res.data,
LISNetPortStr: res.data.lisNetPort.toString(),
}
}
}
const updLisType = async (type: LISType) => {
const res = await setLISType(type)
if (res && res.success) {
getLisSetting()
} else {
res && res.data && res.data.info && eMessage.error(res.data.info)
}
}
const updLisProtocol = async (p: LISProtocol) => {
const res = await setLISProtocol(p)
if (res && res.success) {
getLisSetting()
} else {
res && res.data && res.data.info && eMessage.error(res.data.info)
}
}
const updLisInterface = async (f: LISInterface) => {
const res = await setLISInterface(f)
if (res && res.success) {
getLisSetting()
} else {
res && res.data && res.data.info && eMessage.error(res.data.info)
}
}
const updLisSerialBaudrate = async (s: LISSerialBaudrate) => {
const res = await setLISSerialBaudrate(s)
if (res && res.success) {
getLisSetting()
} else {
res && res.data && res.data.info && eMessage.error(res.data.info)
}
}
const updLisAutoExport = async (auto: boolean) => {
const res = await setLISAutoExport(auto)
if (res && res.success) {
getLisSetting()
} else {
res && res.data && res.data.info && eMessage.error(res.data.info)
}
}
const updLisIP = async (ip: string) => {
const addr = ip.trim()
if (!isValidIPv4(addr)) {
eMessage.error('请输入合法的IP地址')
return
}
hideKeyboard()
const res = await setLISNetIp(addr)
if (res && res.success) {
getLisSetting()
} else {
res && res.data && res.data.info && eMessage.error(res.data.info)
}
}
const updLisPort = async (port: string) => {
const p = port.toString().trim()
if (!/^\d+$/.test(p)) {
eMessage.error('请输入合法的端口值')
return
}
hideKeyboard()
const res = await setLISNetPort(p)
if (res && res.success) {
getLisSetting()
} else {
res && res.data && res.data.info && eMessage.error(res.data.info)
}
}
onMounted(() => {
console.log()
@ -272,20 +126,6 @@ const keyboardVisible = ref(false)
const currentInputValue = ref('')
const currentInputField = ref<'ip' | 'port' | ''>('')
//
const showKeyboard = (field: 'ip' | 'port') => {
//
if (field === 'ip') {
console.log('---', lisSettings.value?.lisNetIp)
inputValue.value = lisSettings.value?.lisNetIp || ''
}
if (field === 'port') {
inputValue.value = lisSettings.value?.LISNetPortStr || ''
}
currentInputField.value = field
keyboardVisible.value = true
}
//
const handleKeyboardInput = (value: string) => {
if (!inputValue.value) return
@ -305,19 +145,6 @@ watch(inputValue, (newVal: string) => {
handleKeyboardInput(newVal)
}
})
//
const handleKeyPress = (button: string) => {
if (button === '{enter}') {
hideKeyboard()
} else if (button === '{bksp}') {
// 退
const value = inputValue.value
if (value.length > 0) {
const newValue = value.slice(0, -1)
handleKeyboardInput(newValue)
}
}
}
//
const hideKeyboard = () => {
@ -326,6 +153,20 @@ const hideKeyboard = () => {
currentInputValue.value = ''
}
const onEditList = () => {
lisVisible.value = true
}
const saveSuccess = () => {
onCloseDialog()
getLisSetting()
}
const onCloseDialog = () => {
lisVisible.value = false
}
//
onUnmounted(() => {
hideKeyboard()
@ -371,7 +212,7 @@ onUnmounted(() => {
display: flex;
gap: 12px;
flex-wrap: wrap;
font-size: 2rem;
button {
min-width: 120px;
height: 56px;
@ -397,6 +238,21 @@ onUnmounted(() => {
}
}
}
.edit-lis{
width: 100%;
height: 5rem;
padding: 0 24px;
border: 1px solid #dcdfe6;
border-radius: 8px;
font-size: 24px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background-color: #409eff;
}
.keyboard {
position: fixed;
bottom: 0;

7
src/pages/Index/Settings/NavBar.vue

@ -19,9 +19,10 @@ const userInfo = JSON.parse(sessionStorage.getItem('token') || '{}')
//
const navItems = [
{id:1, label: '设备', route: '/index/setting/device' },
{id:2, label: '用户管理', route: '/index/setting/users' },
{id:3, label: '系统信息', route: '/index/setting/version' },
{id:4, label: 'LIS', route: '/index/setting/lis' },
{id:2, label: '网络', route: '/index/setting/network' },
{id:3, label: '用户', route: '/index/setting/users' },
{id:4, label: '系统', route: '/index/setting/version' },
{id:5, label: 'LIS', route: '/index/setting/lis' },
]
const currentRoute = ref(navItems[0].route) //

501
src/pages/Index/Settings/Network.vue

@ -0,0 +1,501 @@
<template>
<div class="device-management">
<div class="setting-item">
<span class="label">WAN连接类型</span>
<div class="options">
<button
v-for="(item, index) in networkModeList"
:key="index"
:class="{
active: networkForm.networkMode === item.value,
}"
@click="updateNetworkModel(item)"
>
{{ item.label }}
</button>
</div>
</div>
<template v-if="networkForm.networkMode === 'STATIC_IP'">
<div class="setting-item">
<span class="label">IP地址</span>
<div>
<input
style="width: 20rem"
v-model="networkForm.ip"
name="ip"
@focus="openKeyboard"
readonly
/>
</div>
</div>
<div class="setting-item">
<span class="label">子网掩码</span>
<div>
<input
style="width: 20rem"
v-model="networkForm.netmask"
name="netmask"
@focus="openKeyboard"
readonly
/>
</div>
</div>
<div class="setting-item">
<span class="label">网关</span>
<div>
<input
style="width: 20rem"
v-model="networkForm.gateway"
name="gateway"
@focus="openKeyboard"
readonly
/>
</div>
</div>
<div
class="setting-item"
v-for="(dns, index) in networkForm.dnsList"
:key="index"
>
<span class="label">{{ index === 0 ? '首先DNS' : '备选DNS' }}</span>
<div>
<el-input
style="width: 21rem"
v-model="networkForm.dnsList[index]"
name="firstDns"
@focus="e=>openKeyboard(e, index)"
readonly
>
<template #append>
<el-icon v-if="index === 0 && networkForm.dnsList.length !== 3" @click="onAddDns()"><Plus /></el-icon>
<el-icon v-else @click="onDelDns(index)"><Minus /></el-icon>
</template>
</el-input>
</div>
</div>
</template>
<div v-if="networkForm.networkMode === 'DYNAMIC_IP'" class="setting-item">
<span class="label">DNS获取方式</span>
<div class="options">
<!-- <el-switch-->
<!-- v-model="networkForm.autoDns"-->
<!-- size="large"-->
<!-- active-text="自动获取"-->
<!-- inactive-text="手动获取"-->
<!-- />-->
<button
:class="{
active: networkForm.autoDns,
}"
@click="updateAutoModel(true)"
>
自动获取
</button>
<button
:class="{
active: !networkForm.autoDns,
}"
@click="updateAutoModel(false)"
>
手动获取
</button>
</div>
</div>
<template v-if="!networkForm.autoDns && networkForm.networkMode === 'DYNAMIC_IP'">
<div
class="setting-item"
v-for="(dns, index) in networkForm.dnsList"
:key="index"
>
<span class="label">{{ index === 0 ? '首先DNS' : '备选DNS' }}</span>
<div>
<el-input
style="width: 21rem"
v-model="networkForm.dnsList[index]"
name="firstDns"
@focus="(e) => openKeyboard(e, index)"
readonly
>
<template #append>
<el-icon v-if="index === 0 && networkForm.dnsList.length !== 3" @click="onAddDns('dynamicIpConfig')"
><Plus
/></el-icon>
<el-icon v-else @click="onDelDns('dynamicIpConfig')"
><Minus
/></el-icon>
</template>
</el-input>
</div>
</div>
</template>
<div>
<button class="save-network" @click="onSaveNetwork" >
保存
</button>
</div>
</div>
<!-- 键盘 -->
<transition name="slide-up">
<SoftKeyboard
ref="softKeyboardRef"
v-model="inputValue"
:is-visible="keyboardVisible"
:keyboard-type="keyboardType"
@update-keyboard-visible="(visible) => (keyboardVisible = visible)"
@confirm="() => {}"
@close="keyboardVisible = false"
/>
</transition>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue'
import { setNetworkSetting, getNetworkSetting } from '@/services'
import message from 'element-plus/es/components/message/index.mjs'
import SoftKeyboard from '@/components/SoftKeyboard.vue'
const inputValue = ref('')
const keyboardType = ref<'text' | 'number'>('number')
const softKeyboardRef = ref()
type Network = 'STATIC_IP' | 'DYNAMIC_IP'
const networkVisible = ref(false)
const dnsIndex = ref<number | null>(0)
interface NetworkForm {
id: string
firstRun: boolean
networkMode: Network
ip: string
netmask: string
gateway: string
autoDns: boolean
dnsList: string[]
}
const networkForm = ref<NetworkForm>({
id: '',
firstRun: false,
networkMode: 'STATIC_IP',
ip: '0.0.0.0',
netmask: '0.0.0.0',
gateway: '0.0.0.0',
autoDns: false,
dnsList: [],
})
const defaultDnsData = ref()
const networkModeList = [
{
label: '固定IP地址',
value: 'STATIC_IP',
},
{
label: '动态获取IP地址',
value: 'DYNAMIC_IP',
},
]
const updateNetworkModel = (network) => {
console.log('network---', network)
if(network.value === 'STATIC_IP') {
networkForm.value.dnsList = [...defaultDnsData.value.staticIPConfig.dnsList]
}else if(network.value === 'DYNAMIC_IP') {
networkForm.value.dnsList = [...defaultDnsData.value.dynamicIpConfig.dnsList]
}
networkForm.value.networkMode = network.value
networkVisible.value = true
}
const getNetwork = () => {
getNetworkSetting().then((res) => {
if (res.success) {
const dnsData = res.data
defaultDnsData.value = {
...res.data,
}
networkForm.value = {
id: dnsData.id,
firstRun: dnsData.firstRun,
networkMode: dnsData.networkMode,
ip: dnsData.staticIPConfig.ip,
netmask: dnsData.staticIPConfig.netmask,
gateway: dnsData.staticIPConfig.gateway,
autoDns: dnsData.dynamicIpConfig.autoDns,
dnsList:
dnsData.networkMode === 'STATIC_IP'
? dnsData.staticIPConfig.dnsList
: dnsData.dynamicIpConfig.dnsList,
}
console.log('networkForm--', networkForm.value)
}
})
}
const onAddDns = () => {
const list = networkForm.value.dnsList
console.log('list = ', list)
list.push('255.255.255.0')
}
const onDelDns = (index) => {
const list = networkForm.value.dnsList
list.splice(index, 1)
}
const onSaveNetwork = () => {
console.log('onSaveNetwork==setForm=== ', networkForm.value)
const { ip, gateway, netmask, networkMode, autoDns, dnsList } = networkForm.value
if (networkMode === 'STATIC_IP') {
if (!ip) {
message.error('请输入IP地址')
return
}
if (!gateway) {
message.error('请输入网关地址')
return
}
if (!netmask) {
message.error('请输入子网掩码地址')
return
}
}
const params = {
id: networkForm.value.id,
networkMode: networkMode,
staticIPConfig: {},
dynamicIpConfig: {},
}
const staticConfig = {
...defaultDnsData.value.staticIPConfig,
}
if(networkForm.value.networkMode === 'STATIC_IP') {
staticConfig.ip = ip
staticConfig.gateway = gateway
staticConfig.netmask = netmask
staticConfig.dnsList = dnsList
}
params.staticIPConfig = staticConfig
const dynamicIpConfig = {
...defaultDnsData.value.dynamicIpConfig,
}
if(networkForm.value.networkMode === 'DYNAMIC_IP') {
dynamicIpConfig.autoDns = autoDns
dynamicIpConfig.dnsList = dnsList
}
params.dynamicIpConfig = dynamicIpConfig
console.log('params===', params)
setNetworkSetting(params).then((res) => {
if (res.success) {
message.success('设置成功')
networkVisible.value = false
getNetwork()
}
})
}
const updateAutoModel = (value) => {
networkForm.value.autoDns = value
}
/**
* 当前聚焦的输入字段名称
*/
const focusedInput = ref<string | null>(null)
const openKeyboard = (e, index?: number) => {
keyboardVisible.value = true
const labelName: string = e.target.name
let formValue = ''
if (index || index === 0) {
formValue = networkForm.value.dnsList[index]
inputValue.value = formValue ? formValue.toString() : ''
focusedInput.value = index.toString()
dnsIndex.value = index
} else {
dnsIndex.value = null
formValue = networkForm.value[labelName]
inputValue.value = formValue ? formValue.toString() : ''
focusedInput.value = labelName
}
}
//
onMounted(async () => {
//
getNetwork()
})
//
const keyboardVisible = ref(false)
const currentInputValue = ref('')
//
const hideKeyboard = () => {
keyboardVisible.value = false
currentInputValue.value = ''
}
watch(inputValue, (newVal: string | number) => {
if (focusedInput.value) {
console.log('focusedInput.value--', focusedInput.value)
if(dnsIndex.value || dnsIndex.value === 0){
networkForm.value.dnsList[dnsIndex.value] = newVal
}else{
networkForm.value[focusedInput.value] = newVal
}
}
})
//
onUnmounted(() => {
hideKeyboard()
})
</script>
<style scoped lang="less">
.device-management {
width: 100%;
height: 87vh;
padding: 20px;
box-sizing: border-box;
background-color: #f5f7fa;
display: flex;
flex-direction: column;
gap: 20px;
.setting-item-netword {
background-color: #fff;
}
.setting-item-box > :nth-child(2) {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
}
.setting-item-no-border {
border-radius: 0 !important;
box-shadow: none !important;
}
.setting-item-netword {
background-color: #fff;
}
.setting-item {
background-color: #fff;
border-radius: 12px;
padding: 24px 32px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
.label {
font-size: 28px;
font-weight: 500;
color: #303133;
display: flex;
align-items: center;
.option-tag {
font-size: 25px;
padding: 20px 10px;
margin: 0 10px;
}
}
.value {
font-size: 28px;
color: #606266;
}
input {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 30px;
transition: box-shadow 0.2s ease;
border-radius: 10px;
}
.options {
display: flex;
gap: 12px;
flex-wrap: wrap;
button {
min-width: 120px;
height: 56px;
padding: 0 24px;
border: 1px solid #dcdfe6;
background-color: #fff;
border-radius: 8px;
font-size: 24px;
color: #606266;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
&.active {
color: #fff;
background-color: #409eff;
border-color: #409eff;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
}
}
}
}
}
.keyboard {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 300px;
background-color: #f5f7fa;
border-top-left-radius: 16px;
border-top-right-radius: 16px;
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
:deep(.el-switch__label span) {
font-size: 1.8rem;
}
:deep(.el-input__inner) {
height: 50px;
width: 4rem;
font-size: 2rem;
color: black;
}
//
.slide-up-enter-active,
.slide-up-leave-active {
transition: transform 0.3s ease;
}
.slide-up-enter-from,
.slide-up-leave-to {
transform: translateY(100%);
}
:deep(.date-input) {
width: 250px;
margin-right: 30px;
.el-input__wrapper {
height: 40px;
}
.el-input__inner {
font-size: 18px;
}
}
.save-network{
width: 100%;
height: 5rem;
padding: 0 24px;
border: 1px solid #dcdfe6;
border-radius: 8px;
font-size: 24px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background-color: #409eff;
}
</style>

4
src/pages/Index/Settings/Version.vue

@ -5,6 +5,10 @@
<span class="value">{{ info?.sn }}</span>
</div>
<div class="setting-item">
<span class="label">资产ID</span>
<span class="value">{{ info?.assetId }}</span>
</div>
<div class="setting-item">
<span class="label">App</span>
<span class="value">{{ info?.appVersion }}</span>
</div>

1
src/pages/Index/components/Consumables/SpttingPlates.vue

@ -233,6 +233,7 @@ const updateSliderEndVal = async (plateNum, order) => {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 1.5rem;
}
.project-number {
flex: 0 0 auto;

34
src/pages/Index/components/Running/LittleBufferDisplay.vue

@ -1,21 +1,13 @@
<template>
<div class="buffer-solution-grid">
<div class="buffer-solution-grid" v-if="bufferData && bufferData.length > 0">
<div v-for="(item, index) in bufferData" :key="index" style="position: relative;">
<!-- <div v-if="item.group && preReactoinGroupMap[item.group].inReacting && item.group === preReactoinGroupMap[item.group].group" class="buffer-item-reaction" @click="showPreReactoinModal(item)">
<div class="buffer-text">
<img :src="PreSvg" class="pre-img" />
<div class="num">{{ item.projName ? `${item.num}/25` : '/' }}</div>
<div class="proj-name" v-if="item.projName">{{ item.projName }}</div>
</div>
</div> -->
<div style="display: flex;align-items: flex-start;">
<img
v-if="item.group &&
v-if="item.group && preReactoinGroupMap[item.group] &&
preReactoinGroupMap[item.group].inReacting &&
item.group === preReactoinGroupMap[item.group].group"
:src="PreSvg" class="pre-img" />
<img v-else :src="PreSvg" class="pre-img" />
<img v-else :src="UnPreSvg" class="pre-img" />
<div class="buffer-item" @click="showPreReactoinModal(item)">
<div class="buffer-fill" :style="item.projName? getFillStyle(item) : 'background: #c8c8c8'"></div>
@ -27,7 +19,7 @@
</div>
</div>
<el-dialog v-model="preVisible" width="600" title="小缓冲液预反应状态">
<PreReactionModal />
<PreReactionModal :bgColor="currentSelectColor" />
</el-dialog>
</div>
</template>
@ -39,13 +31,16 @@ import { ref, watchEffect } from 'vue';
import { useRunningStore } from '@/store/modules/running';
import PreReactionModal from '@/components/dialogs/PreReactionBall.vue'
import PreSvg from '@/assets/pre.svg'
import UnPreSvg from '@/assets/un-pre.svg'
const consumableStore = useConsumablesStore()
// props
const props = defineProps<{ bufferData: LittleBottleGroup[] }>()
// const props = defineProps<{ bufferData: LittleBottleGroup[] }>()
const runningStore = useRunningStore()
const preReactoinGroupMap = ref<PreReactionPosGroupStateMap>(runningStore.preReactoinGroupMap)
const preVisible = ref(false)
const bufferData = ref<LittleBottleGroup[]>([])
const currentSelectColor = ref()
//
const getFillStyle = (item: LittleBottleGroup) => {
//@ts-ignore
@ -57,11 +52,16 @@ const getFillStyle = (item: LittleBottleGroup) => {
watchEffect(() => {
preReactoinGroupMap.value = runningStore.preReactoinGroupMap
if (consumableStore.consumableData && consumableStore.consumableData.littBottleGroup) {
bufferData.value = consumableStore.consumableData.littBottleGroup
console.log('bufferData.value--littBottleGroup-', bufferData.value)
}
})
const showPreReactoinModal = (item) => {
console.log('-----', preReactoinGroupMap.value[item.group])
runningStore.setPreReactoinGroup(preReactoinGroupMap.value[item.group])
consumableStore.setBallColor(getFillStyle(item).background)
currentSelectColor.value = consumableStore.projIdColorMap[item.projId!]
preVisible.value = true
}
</script>
@ -90,10 +90,8 @@ const showPreReactoinModal = (item) => {
}
.pre-img{
position: absolute;
width: 20px;
left:0.5rem;
top: 1rem;
margin-top:5px;
width: 1.2rem;
}
.buffer-item {
position: relative;

1
src/pages/Index/components/TestTube/Tube.vue

@ -82,7 +82,6 @@ watch(
(newVal) => {
tubeData.value = props.tube
const projIds = projIdsOfTube(props.tube)
console.log('projIds===', projIds, props.tube)
if (projIds.length > 0) {
nextTick(() => {
if (canvas.value) {

4
src/router/router.ts

@ -58,6 +58,10 @@ const routes = [
redirect: '/index/setting/device',
},
{
path: 'network',
component: () => import('@/pages/Index/Settings/Network.vue'),
},
{
path: 'device', //设备
component: () => import('@/pages/Index/Settings/Device.vue'),
},

2
src/services/Index/settings/settings.ts

@ -163,8 +163,8 @@ export const setLISType = async (data: LISType) => {
export type LISSerialBaudrate = 'B9600' | 'B12800' | 'B19200' | 'B115200'
export const LISSerialBaudrateMap = {
B9600: '9,600bps',
B12800: '12,800bps',
B19200: '19,200bps',
B38400: '38,400bps',
B115200: '115,200bps',
}
// 设置LIS串口波特率

1
src/services/osControl/os.ts

@ -64,6 +64,7 @@ export type DeviceInfo = {
mcuVersion: string;
sn: string;
ip: string;
assetId: string;
}
export const getDeviceInfo = async () => {
try {

6
src/store/modules/consumables.ts

@ -175,6 +175,11 @@ export const useConsumablesStore = defineStore(
return color
}
const setBallColor = (color: string) => {
console.log('color--', color)
ballColor.value = color
}
return {
setIdCardInserted,
isIdCardInserted,
@ -196,6 +201,7 @@ export const useConsumablesStore = defineStore(
ballColor,
getBallColor,
setBallColor,
}
},
// {

4
src/store/modules/device.ts

@ -27,13 +27,13 @@ export const useDeviceStore = defineStore('device', () => {
}
}
const sensorState = ref<SensorStateMessage['data']>({
const sensorState = ref<Record<string, any>>({
pboxTemperature: 20,
incubateBoxTemperature: 20,
wasteBinFullFlag: false,
})
const setSensorState = (data: SensorStateMessage['data']) => {
if (!R.equals(data, sensorState.value)) {
if (data && !R.equals(data, sensorState.value)) {
sensorState.value = {...data}
}
}

7
src/store/modules/running.ts

@ -64,8 +64,11 @@ export const useRunningStore = defineStore('running', () => {
}
const setPreReactoinGroupMap = (data: PreReactionPosGroupStateMessage['data']) => {
const key = data.group
preReactoinGroupMap.value[key] = data
if(data){
const key = data.group
preReactoinGroupMap.value[key] = data
}
}
const setPreReactoinGroup = (data: PreReactionPosGroupStateMessage['data']) => {

1
src/store/modules/useSystemStore.ts

@ -21,7 +21,6 @@ export const useSystemStore = defineStore('system', () => {
const statusList = ref<Record<string, any>[]>([])
const updateStatusList = (status) => {
console.log('status--', status)
statusList.value.push(status)
}

8
src/utils/getServerInfo.ts

@ -8,12 +8,12 @@ export function getServerInfo(wsPath: string = '/api/v1/app/ws/state') {
const host = window.location.hostname;
// const host = window.location.host;
// const host = "192.168.8.175";
const port = '8082' // 使用固定的后端端口;由于本地开发时,8080被占用导致ws连接失败,所以使用8082
// const port = "80"
// const port = '8082' // 使用固定的后端端口;由于本地开发时,8080被占用导致ws连接失败,所以使用8082
const port = "80"
// 构建 WebSocket URL
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
const wsUrl = `${wsProtocol}//${host}:${port}${wsPath}`
// const wsUrl = `${wsProtocol}//${host}${wsPath}`
// const wsUrl = `${wsProtocol}//${host}:${port}${wsPath}`
const wsUrl = `${wsProtocol}//${host}${wsPath}`
// 构建 HTTP URL
const httpUrl = `${window.location.protocol}//${host}:${port}` // 例如: "http://192.168.1.100:8082" 或 "http://localhost:8082"

1
src/websocket/socket.ts

@ -443,6 +443,7 @@ class WebSocketClient {
)
this.messageHandlers.set(messageType, new Set())
}
console.log('messageType---', messageType)
this.messageHandlers.get(messageType)?.add(handler)
}

Loading…
Cancel
Save