duy 5 hónapja
szülő
commit
aeff257bdd

+ 1 - 1
public/version.json

@@ -1,3 +1,3 @@
 {
-  "value": "20250325102557"
+  "value": "20250421160619"
 }

+ 169 - 0
src/assets/view/notableform copy.svg

@@ -0,0 +1,169 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 1024 1024" height="1024px" width="1024px">
+    <title>没有收藏</title>
+    <defs>
+        <linearGradient id="linearGradient-1" y2="44.0501254%" x2="50%" y1="-29.88559%" x1="50%">
+            <stop offset="0%" stop-color="#CFDFFA"></stop>
+            <stop offset="100%" stop-opacity="0" stop-color="#EAF0FC"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-2" y2="69.8229089%" x2="53.6226986%" y1="33.7484636%" x1="50%">
+            <stop offset="0%" stop-color="#CFDFFA"></stop>
+            <stop offset="100%" stop-opacity="0" stop-color="#EAF0FC"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-3" y2="66.4977364%" x2="53.6226986%" y1="36.47456%" x1="50%">
+            <stop offset="0%" stop-color="#CFDFFA"></stop>
+            <stop offset="100%" stop-opacity="0" stop-color="#EAF0FC"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-4" y2="100%" x2="57.28025%" y1="11.4973736%" x1="50%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-5" y2="131.881015%" x2="51.9400923%" y1="11.4973736%" x1="50%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-6" y2="128.49897%" x2="74.2827921%" y1="13.0877007%" x1="50%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-7" y2="131.881015%" x2="54.0733641%" y1="11.4973736%" x1="50%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-8" y2="131.881015%" x2="51.9795749%" y1="11.4973736%" x1="50%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-9" y2="131.881015%" x2="55.3643684%" y1="11.4973736%" x1="50%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-10" y2="53.7022797%" x2="74.2827921%" y1="48.2590898%" x1="50%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-11" y2="93.8707843%" x2="51.9359856%" y1="-91.6326561%" x1="54.5180881%">
+            <stop offset="0%" stop-color="#5792F0"></stop>
+            <stop offset="100%" stop-opacity="0" stop-color="#BFD4FA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-12" y2="-1.23255816%" x2="-17.9385803%" y1="119.605122%" x1="118.461169%">
+            <stop offset="0%" stop-color="#5792F0"></stop>
+            <stop offset="100%" stop-color="#BFD4FA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-13" y2="50%" x2="-11.3176499%" y1="50%" x1="146.853724%">
+            <stop offset="0%" stop-opacity="0" stop-color="#EAF0FC"></stop>
+            <stop offset="100%" stop-color="#CFDFFA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-14" y2="50%" x2="-11.3176499%" y1="50%" x1="146.853724%">
+            <stop offset="0%" stop-opacity="0" stop-color="#EAF0FC"></stop>
+            <stop offset="100%" stop-color="#CFDFFA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-15" y2="30.1198066%" x2="-17.9385803%" y1="77.0094511%" x1="118.461169%">
+            <stop offset="0%" stop-color="#5792F0"></stop>
+            <stop offset="100%" stop-color="#BFD4FA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-16" y2="134.19466%" x2="25.7283138%" y1="3.55271368e-13%" x1="64.3532982%">
+            <stop offset="0%" stop-color="#CFDFFA"></stop>
+            <stop offset="100%" stop-opacity="0" stop-color="#EAF0FC"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-17" y2="50%" x2="-11.3176499%" y1="50%" x1="146.853724%">
+            <stop offset="0%" stop-opacity="0" stop-color="#EAF0FC"></stop>
+            <stop offset="100%" stop-color="#CFDFFA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-18" y2="50%" x2="-11.3176499%" y1="50%" x1="146.853724%">
+            <stop offset="0%" stop-opacity="0" stop-color="#EAF0FC"></stop>
+            <stop offset="100%" stop-color="#CFDFFA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-19" y2="-11.5290622%" x2="-17.9385803%" y1="188.087506%" x1="219.196164%">
+            <stop offset="0%" stop-color="#5792F0"></stop>
+            <stop offset="100%" stop-color="#BFD4FA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-20" y2="-11.5290622%" x2="-17.9385803%" y1="173.082361%" x1="228.328534%">
+            <stop offset="0%" stop-color="#5792F0"></stop>
+            <stop offset="100%" stop-color="#BFD4FA"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-21" y2="73.6326896%" x2="100%" y1="11.7098971%" x1="14.3474826%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-22" y2="93.1271749%" x2="50%" y1="-31.010887%" x1="43.707299%">
+            <stop offset="0%" stop-color="#BFD4FA"></stop>
+            <stop offset="100%" stop-color="#5792F0"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-23" y2="100%" x2="50%" y1="12.9243097%" x1="50%">
+            <stop offset="0%" stop-color="#FFCDA5"></stop>
+            <stop offset="100%" stop-color="#FFE8D1"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-24" y2="100%" x2="88.72%" y1="0%" x1="42.3145579%">
+            <stop offset="0%" stop-color="#FFF2DF"></stop>
+            <stop offset="100%" stop-color="#FEE0BC"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-25" y2="61.3220709%" x2="210.359568%" y1="25.7376426%" x1="35.6067948%">
+            <stop offset="0%" stop-color="#FEE127"></stop>
+            <stop offset="100%" stop-color="#F9AB21"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-26" y2="100%" x2="50%" y1="0%" x1="50%">
+            <stop offset="0%" stop-color="#FEE127"></stop>
+            <stop offset="100%" stop-color="#F9AB21"></stop>
+        </linearGradient>
+        <linearGradient id="linearGradient-27" y2="38.1816114%" x2="126.959811%" y1="25.7376426%" x1="33.2709467%">
+            <stop offset="0%" stop-color="#FEE127"></stop>
+            <stop offset="100%" stop-color="#F9AB21"></stop>
+        </linearGradient>
+    </defs>
+    <g fill-rule="evenodd" fill="none" stroke-width="1" stroke="none" id="没有收藏">
+        <rect height="1024" width="1024" y="0" x="0" id="矩形"></rect>
+        <g transform="translate(32.000000, 149.000000)" id="编组">
+            <g id="背景">
+                <ellipse ry="250" rx="480" cy="766" cx="480" fill="url(#linearGradient-1)" id="椭圆形"></ellipse>
+                <path fill="url(#linearGradient-2)" id="云" d="M814,116.212121 C814,130.606061 800.181818,142.121212 782.727273,142.121212 L686,142.121212 C668.545455,140.969697 654,130.030303 654,115.060606 C654,105.272727 660.545455,96.6363636 670,92.030303 C669.272727,90.3030303 668.545455,88.5757576 668.545455,86.8484848 C668.545455,77.0606061 678,68.4242424 690.363636,68.4242424 C695.454545,68.4242424 699.818182,70.1515152 703.454545,72.4545455 C712.181818,59.2121212 728.181818,50 747.090909,50 C773.272727,50 794.363636,67.8484848 794.363636,89.7272727 L794.363636,92.030303 C806,96.0606061 814,105.272727 814,116.212121 Z"></path>
+                <path fill="url(#linearGradient-3)" id="云" d="M166.222222,0 C190.894883,0 211.8847,15.7681262 219.664106,37.7768098 L256.5,37.7777778 C266.164983,37.7777778 274,45.6127947 274,55.2777778 L274,98.0555556 C274,107.720539 266.164983,115.555556 256.5,115.555556 L78.1666667,115.555556 C68.5016835,115.555556 60.6666667,107.720539 60.6666667,98.0555556 L60.6669111,85.6467185 C56.4406838,78.8453656 54,70.81882 54,62.2222222 C54,37.6762333 73.8984556,17.7777778 98.4444444,17.7777778 C106.377692,17.7777778 113.825468,19.8563268 120.272891,23.4985432 C130.565544,9.26259942 147.312185,0 166.222222,0 Z"></path>
+                <g transform="translate(170.000000, 570.000000)" id="草">
+                    <ellipse ry="4" rx="12.8" cy="78" cx="26.8" fill="#CCDCF6" id="椭圆形"></ellipse>
+                    <path fill-rule="nonzero" fill="url(#linearGradient-4)" id="路径-42" d="M13.2096985,76.4334696 C14.9527214,47.3262499 22.2548023,30.479152 35.1159413,25.892176 C40.1793835,25.2161532 45.8226773,24.1997042 41.8878028,30.7617951 C37.9529282,37.3238861 27.4160559,34.7701422 16.879533,76.4161198 C15.9265298,78.1966928 14.7032516,78.202476 13.2096985,76.4334696 Z"></path>
+                    <path fill-rule="nonzero" fill="url(#linearGradient-5)" id="路径-41" d="M12.9692534,76.0688036 C9.54744327,48.8820916 6.74680699,31.7849012 4.56734456,24.7772324 C1.2981509,14.2657291 -5.66257226,-5.963969 8.82439601,1.68943966 C23.3113643,9.34284832 25.0241679,48.6011298 18.327685,72.4929976 C16.2462776,78.5387167 14.4601337,79.730652 12.9692534,76.0688036 Z"></path>
+                </g>
+                <g fill-rule="nonzero" transform="translate(686.120225, 515.426704)" id="草">
+                    <path fill="url(#linearGradient-6)" id="路径-43" d="M65.8576891,95.4430222 C63.3395468,83.9806553 55.9856639,75.9680543 43.7960405,71.4052192 C29.8759357,66.9305791 22.2494886,61.6117041 30.9599814,57.7550267 C38.3155159,57.1703291 54.0022982,51.4419217 65.8576891,85.6583003 C66.6827635,88.9740418 66.6827635,92.2356158 65.8576891,95.4430222 Z"></path>
+                    <path fill="url(#linearGradient-7)" id="路径-44" d="M66.4764949,97.2611071 C59.1454779,69.8960192 50.8174439,49.9170768 41.4923928,37.3242799 C34.6452589,28.7188412 35.1250476,16.405104 41.4923928,13.6218727 C48.0100381,12.8970718 60.0222617,11.7760378 69.0669112,58.9373338 C69.6381527,62.1812743 72.8251647,81.1589956 69.0669112,93.4066801 C68.5106318,95.0875751 67.6471596,96.3723841 66.4764949,97.2611071 Z"></path>
+                    <path fill="url(#linearGradient-8)" id="路径-45" d="M68.1696321,91.0804085 C71.4853494,78.835463 71.0643832,62.8586309 66.9067333,43.1499123 C60.5471905,24.0440706 49.6921744,0.541796566 69.4774519,0 C77.5044316,1.09154868 87.1972186,9.50543486 83.5347739,51.4392686 C81.3029234,68.3604083 77.4213217,78.3565362 73.3477064,91.0804085 C71.9266832,91.8737887 70.2006584,91.8737887 68.1696321,91.0804085 Z"></path>
+                    <path fill="url(#linearGradient-9)" id="路径-46" d="M72.0427224,95.836031 C70.7154818,61.2121058 77.0522244,36.363996 91.0529503,21.2917016 C94.833726,16.2551414 109.217459,11.5380494 109.163159,27.3263959 C107.661554,34.1152854 104.448437,48.6087163 85.9202741,70.7214245 C79.8162941,78.7025415 75.8046094,90.365172 75.7655073,93.0996265 C75.7394392,94.9225962 74.4985109,95.834731 72.0427224,95.836031 Z"></path>
+                    <path fill="url(#linearGradient-10)" id="路径-47" d="M0,100.407711 C13.8643816,97.8236334 21.5103995,95.6299697 22.9380537,93.8267198 C25.0795349,91.1218449 43.9450099,79.5080271 55.7094426,89.2905093 C58.2703723,85.9992821 66.4835238,83.4391237 71.1837342,89.2905093 C73.3341085,80.0524096 86.7490663,74.1360276 92.583369,75.0945046 C99.1537088,74.5803177 118.55034,74.7942504 120,100.407711 C114.707841,100.530921 74.7078414,100.530921 0,100.407711 Z"></path>
+                </g>
+            </g>
+            <g transform="translate(236.000000, 178.000000)" id="文件夹">
+                <polygon points="153.754575 263.865464 313.39591 447.002576 369.92636 670.058761 126.332242 631.651818" transform="translate(248.129301, 466.962113) rotate(-50.000000) translate(-248.129301, -466.962113)" opacity="0.3" fill-rule="nonzero" fill="url(#linearGradient-11)" id="路径"></polygon>
+                <path fill-rule="nonzero" fill="url(#linearGradient-12)" id="矩形" d="M20.8,126 L100.736372,126 L114.018551,147.042432 L244.743075,146.809884 C262.416159,146.778445 276.76851,161.079824 276.799949,178.752908 C276.799983,178.771883 276.8,178.790858 276.8,178.809833 L276.8,359.6 L276.8,359.6 L20.8,359.6 L20.8,126 Z"></path>
+                <rect height="230.4" width="208" y="177.2" x="48" fill="url(#linearGradient-13)" id="矩形"></rect>
+                <rect height="203.2" width="217.6" y="199.6" x="43.2" fill="#FFFFFF" id="矩形"></rect>
+                <rect height="187.2" width="225.6" y="214" x="41.6" fill="url(#linearGradient-14)" id="矩形"></rect>
+                <polygon points="0 234.8 304 234.8 276.363636 407.6 27.6363636 407.6" fill-rule="nonzero" fill="url(#linearGradient-15)" id="矩形"></polygon>
+                <rect rx="5.6" height="11.2" width="11.2" y="310" x="176" fill="url(#linearGradient-16)" id="矩形"></rect>
+                <rect rx="5.6" height="11.2" width="49.6" y="310" x="198.4" fill="url(#linearGradient-17)" id="矩形"></rect>
+                <rect rx="5.6" height="11.2" width="72" y="334" x="174.4" fill="url(#linearGradient-18)" id="矩形备份-2"></rect>
+                <circle r="24" cy="114.8" cx="136" fill-rule="nonzero" fill="url(#linearGradient-19)" id="椭圆形"></circle>
+                <polygon points="136 122.8 126.595436 127.744272 128.391548 117.272136 120.783096 109.855728 131.297718 108.327864 136 98.8 140.702282 108.327864 151.216904 109.855728 143.608452 117.272136 145.404564 127.744272" fill="#FFFFFF" id="星形"></polygon>
+                <circle r="51.2" cy="51.2" cx="264.8" fill-rule="nonzero" fill="url(#linearGradient-20)" id="椭圆形"></circle>
+                <path fill-rule="nonzero" fill="#FFFFFF" id="形状" d="M261.6,61.4 L261.6,54.6 L264.8,54.6 C270.24,54.6 274.4,50.18 274.4,44.4 L274.4,41 C274.4,35.22 270.24,30.8 264.8,30.8 C259.36,30.8 255.2,35.22 255.2,41 L255.2,44.4 L248.8,44.4 L248.8,41 C248.8,31.48 255.84,24 264.8,24 C273.76,24 280.8,31.48 280.8,41 L280.8,44.4 C280.8,52.56 275.36,59.36 268,61.06 L268,68.2 L261.6,68.2 L261.6,61.4 L261.6,61.4 Z M261.6,71.6 L268,71.6 L268,78.4 L261.6,78.4 L261.6,71.6 Z"></path>
+            </g>
+            <g transform="translate(584.000000, 353.200000)" id="人物">
+                <ellipse ry="16" rx="50" cy="246.8" cx="54" fill="#CCDCF6" id="椭圆形"></ellipse>
+                <path fill-rule="nonzero" fill="url(#linearGradient-21)" id="路径-52" d="M38.6300477,235.235362 L37.8007519,240.654984 C34.4234067,240.760606 30.750592,241.753363 26.7823078,243.633257 C24.2287309,245.271596 24.1150782,246.01393 24.0328715,247.424613 C23.9780671,248.365068 31.1929355,248.365068 45.6774767,247.424613 L45.6774767,233.249114 L38.6300477,235.235362 Z"></path>
+                <path fill-rule="nonzero" fill="url(#linearGradient-21)" id="路径-52备份-2" d="M70.6300477,235.235362 L69.8007519,240.654984 C66.4234067,240.760606 62.750592,241.753363 58.7823078,243.633257 C56.2287309,245.271596 56.1150782,246.01393 56.0328715,247.424613 C55.9780671,248.365068 63.1929355,248.365068 77.6774767,247.424613 L77.6774767,233.249114 L70.6300477,235.235362 Z"></path>
+                <path fill-rule="nonzero" fill="url(#linearGradient-22)" id="腿" d="M63.4798058,123.785314 C68.6750615,123.805568 72.8281177,124.432399 72.8281177,124.432399 C72.8281177,124.432399 71.3760846,143.047994 72.5330361,163.348918 C74.4320731,196.615503 79.3228235,238.234089 79.3228235,238.234089 L68.9920634,238.234089 C68.9920634,238.234089 52.013417,182.003971 52.1927293,145.31426 C46.0431551,176.221219 46.8317641,238.771761 46.8317641,238.771761 L35.9634303,237.694667 C35.9634303,237.694667 32.1302975,199.819086 31.1837007,169.374698 C30.4182428,144.709705 32.5013401,126.250105 32.5013401,126.250105 C37.8190756,125.533357 43.2048111,125.470098 48.5379757,126.061745 C48.5519929,126.063397 48.5660146,126.065057 48.5800408,126.066726 C50.9329551,125.295295 53.8831978,124.50135 56.8908161,124.137612 C58.9422461,123.889246 61.0228754,123.792804 62.9738901,123.785314 L63.4798058,123.785314 Z"></path>
+                <g transform="translate(59.617349, 26.476940) scale(-1, 1) translate(-59.617349, -26.476940) translate(39.617349, 0.000000)" id="头">
+                    <rect height="14.7259384" width="14.7259384" y="38.2279411" x="15.9030099" fill="url(#linearGradient-23)" id="矩形"></rect>
+                    <ellipse ry="16.7340209" rx="14.7259384" cy="26.8488069" cx="25.2740616" fill="url(#linearGradient-24)" id="椭圆形"></ellipse>
+                    <path fill="#483029" id="路径-53" d="M38.633377,16.179698 C34.5465891,21.8060201 29.9159912,25.1974521 24.7415832,26.3539941 C22.9496901,27.2264212 19.0354404,24.5262489 18.2108894,28.1619803 C17.9766837,30.5999513 19.3518129,33.9457585 21.2979246,33.3437386 C20.6077901,35.4939378 18.6707419,37.9181311 15.4867798,40.6163185 C12.2024395,41.904943 8.88101335,41.4257987 5.52250136,39.1788855 C0.957681042,34.8920992 -4.44906325,20.6753232 6.06580044,8.46502605 C6.39150047,8.27630082 18.4960557,-3.32957295 33.4895535,6.58602551 C37.2526076,9.03034944 38.9672155,12.2282403 38.633377,16.179698 Z"></path>
+                    <circle r="7.43734262" cy="7.43734262" cx="7.87067988" fill="#483029" id="椭圆形"></circle>
+                </g>
+                <g transform="translate(0.000000, 45.644812)" id="上半身">
+                    <path fill="url(#linearGradient-25)" id="胳膊" d="M47.4943933,1.16269478 C47.4943933,1.16269478 40.7649057,4.14935926 37.465851,9.66511959 C32.0297096,18.7573381 28.911665,34.2935028 28.911665,34.2935028 C28.911665,34.2935028 28.6605865,39.0199718 25.0783387,45.7277882 C21.1807829,53.0245285 19.770656,53.937346 19.770656,53.937346 C19.770656,53.937346 14.2031364,57.7156215 12.6908264,58.0421248 C10.8456914,58.44112 6.49852997,60.3876713 6.49852997,60.3876713 L9.44724254,69.4752506 C9.44724254,69.4752506 21.5807569,68.3516263 30.0940696,64.4910003 C36.4527785,61.6055345 38.9402073,53.9361861 38.9402073,53.9361861 L47.4943933,1.16269478 Z"></path>
+                    <path fill="url(#linearGradient-26)" id="衣服" d="M50.7916593,7.13421412 L63.7101596,0 C63.7101596,0 64.9070727,1.1067661 65.3932869,1.63451783 C66.3496868,2.31558043 67.1981191,2.98015972 67.1981191,2.98015972 C67.1981191,2.98015972 70.4627421,4.85369773 72.269418,7.90617719 C74.4346737,11.564497 74.333517,24.0315557 74.333517,24.0315557 C74.333517,24.0315557 73.9659562,33.3514762 74.6283877,43.0890847 C75.7725088,59.9074319 76.2900544,79.8255612 76.2900544,79.8255612 C76.2900544,79.8255612 62.8670572,80.5482145 52.7450904,80.6198363 C42.0888519,80.6949385 31.8632971,80.0315143 31.8632971,80.0315143 L38.3504648,20.5133809 C38.3504648,20.5133809 39.3314227,10.3500227 43.0713244,4.38771248 C44.7150127,1.76292735 48.8987557,0.667910149 48.8987557,0.667910149 L50.7916593,7.13421412 Z"></path>
+                    <path fill="url(#linearGradient-27)" id="胳膊-2" d="M67.5514778,3.21508422 C67.5514778,3.21508422 73.4956155,7.02380631 75.5159214,10.5448807 C78.5638975,15.8602736 79.9389901,39.864067 79.9389901,39.864067 C79.9389901,39.864067 80.4586643,43.9378194 78.4646339,47.1938636 C76.3333859,50.6734726 56.933193,62.4400607 56.933193,62.4400607 L41.0072256,71.2356426 L35.9914948,60.0942243 L63.1254894,40.1572241 C63.1254894,40.1572241 64.3721233,39.1745245 64.6027652,37.8116776 C64.81589,36.5387206 62.2408757,21.6860092 62.2408757,21.6860092 C62.2408757,21.6860092 61.1986079,15.7524057 62.8306181,11.424352 C64.2845379,7.57039496 67.5514778,3.21508422 67.5514778,3.21508422 Z"></path>
+                    <path fill="#483029" id="iPad" d="M2.07254159,46.0209453 L32.4530396,46.0209453 C32.8442956,46.0211759 33.2194344,46.1757666 33.4959299,46.4507091 C33.7724253,46.7256516 33.9276283,47.0984239 33.9273959,47.4870206 L34.8120102,67.4240207 C34.8120102,67.8126411 34.6571414,68.1854579 34.3806292,68.4604175 C34.1041169,68.7353764 33.7289331,68.8900965 33.3376534,68.8900965 L4.13664039,68.8900965 C3.74536069,68.8900965 3.37017684,68.7353764 3.09366461,68.4604175 C2.81715237,68.1854579 2.66197427,67.8126411 2.6622841,67.4240207 L0.598185043,47.4870206 C0.598185043,47.0984239 0.753155943,46.7256516 1.0296514,46.4507091 C1.30614685,46.1757666 1.68128568,46.0211759 2.07254159,46.0209453 L2.07254159,46.0209453 Z"></path>
+                    <path fill="#FEE0BC" id="手" d="M35.9914948,60.3876713 L27.5599285,60.6527015 C27.5599285,60.6527015 26.7979344,60.6184854 26.7716587,61.9793025 C26.783305,62.3212404 26.9860204,62.6281685 27.2971719,62.7749731 L29.3963049,63.5709337 C28.3653918,63.8457659 27.3106608,64.0233369 26.2461456,64.1012841 C24.8478345,64.1796035 23.4461908,64.1796035 22.0478796,64.1012841 C22.0478796,64.1012841 21.1340707,64.0082046 21.2596099,65.4275951 C21.3968272,66.9241167 21.7851231,69.141498 21.7851231,69.141498 C21.7851231,69.141498 21.9632136,70.6557078 23.8842561,70.9972897 C26.3541678,71.4377502 32.2807881,71.52764 32.2807881,71.52764 C33.7723166,71.5472061 35.2632918,71.4585301 36.7418107,71.2623196 C37.95633,71.073841 40.4145636,70.2013291 40.4145636,70.2013291 C40.4145636,70.2013291 39.3547787,67.5536361 38.3329476,65.0088822 C37.6686297,63.4130751 36.8859963,61.8684301 35.9914948,60.3876713 Z M2.48127403,60.5167068 L9.65744782,60.0919046 C9.65744782,60.0919046 10.2997417,59.9985351 10.4194418,61.2857005 C10.4427467,61.6002286 10.2959827,61.9033567 10.0340655,62.081661 L8.30863078,63.0040474 C9.20139076,63.1815884 10.1104494,63.2655592 11.0208624,63.2545793 C12.2140537,63.2164637 13.4036613,63.1040254 14.5826736,62.9179271 C14.5826736,62.9179271 15.3534262,62.7561252 15.3476529,64.111433 C15.3417482,65.5403925 15.1694966,67.672523 15.1694966,67.672523 C15.0904664,68.5970274 14.4309134,69.3705458 13.5258083,69.6002264 C11.4617096,70.2161175 6.4372201,70.7763345 6.4372201,70.7763345 C5.17417585,70.9141637 3.90193154,70.9496572 2.63308893,70.8824627 C2.16888567,70.8459267 1.54702846,70.9465451 1.10910085,70.6504884 C0.732184525,70.3464167 0.438072494,69.9533105 0.253682253,69.5071469 C-0.0941210224,67.7368613 -0.0841970439,65.9155718 0.282877427,64.1491287 C0.454830137,63.3267759 0.68806028,62.5182478 0.980642087,61.7302205 C1.18585627,61.0602717 1.77914639,60.5804967 2.48127403,60.5167068 L2.48127403,60.5167068 Z"></path>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 2 - 2
src/config/index.json

@@ -1,12 +1,12 @@
 {
     "version": "202304141558",
     "target6": "http://219.151.181.73:8090",
-    "target": "http://192.168.0.109:8090",
+    "target77": "http://192.168.0.109:8090",
     "target22": "http://219.151.185.227:8090",
     "target11": "http://39.108.216.210:8090",
     "target2": "http://219.151.185.227:8090",
     "target7": "http://192.168.0.114:8090",
-    "targe77t": "http://192.168.0.110:8090",
+    "target": "http://192.168.0.109:8090",
     "target8": "http://183.247.216.148:28090",
     "socket": "wss://measure.hczcxx.cn/websocket",
     "localModel": false,

+ 2 - 0
src/global/components/index.js

@@ -5,6 +5,7 @@ import HcReportExperts from './hc-report-experts/index.vue'
 import HcTasksUser from './hc-tasks-user/index.vue'
 import HcBorderNeon from './hc-border-neon/index.vue'
 import HcPdfs from './hc-pdfs/pdfs.vue'
+// import HcTableForm from './table-form/index.vue'
 
 //注册全局组件
 export const setupComponents = (App) => {
@@ -15,4 +16,5 @@ export const setupComponents = (App) => {
     App.component('HcTasksUser', HcTasksUser)
     App.component('HcBorderNeon', HcBorderNeon)
     App.component('HcPdfs', HcPdfs)
+    // App.component('HcTableForm', HcTableForm)
 }

+ 518 - 0
src/global/components/table-form/index.vue

@@ -0,0 +1,518 @@
+<template>
+    <div :id="`table-form-item-${keyId}`" v-loading="isLoading" :class="{ 'no-scroll-bar': !isTableForm }" :style="tableFormStyle" class="hc-table-form-data-item">
+        <el-scrollbar v-if="isScroll" class="table-form-item-scrollbar">
+            <div :id="`table-form-${keyId}`" class="hc-excel-table-form" @click.capture="excelTableFormClick" />
+        </el-scrollbar>
+        <div v-else :id="`table-form-${keyId}`" class="hc-excel-table-form" @click.capture="excelTableFormClick" />
+        <div v-if="!isTableForm" class="hc-no-table-form">
+            <div class="table-form-no">
+                <img :src="notableform" alt="">
+                <div class="desc">{{ noTips }}</div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
+import HTableForm from '~src/plugins/HTableForm'
+import notableform from '~src/assets/view/notableform.svg'
+import { delStoreValue, getStoreValue, setStoreValue } from '~uti/storage'
+import { arrIndex, deepClone, getArrValue, getObjVal, isNullES, isString } from 'js-fast-way'
+
+// Props 定义
+const props = defineProps({
+    pkey: { type: [String, Number], required: true },
+    noTip: { type: String, default: '暂无表单数据' },
+    html: String,
+    form: { type: Object, default: () => ({}) },
+    cols: { type: Array, default: () => ([]) },
+    loading: Boolean,
+    scroll: { type: Boolean, default: true },
+    height: { type: String, default: '100%' },
+    width: { type: String, default: 'auto' },
+    isMessage: { type: Boolean, default: true },
+    pid: { type: String, default: '' },
+})
+
+// Emits 定义
+const emit = defineEmits(['rightTap', 'render', 'excelBodyTap'])
+
+// 响应式数据
+const keyId = ref(props.pkey)
+const noTips = ref(props.noTip)
+const isScroll = ref(props.scroll)
+const isLoading = ref(props.loading)
+const activeKey = ref(props.pid)
+const excelHtml = ref(props.html)
+const excelForm = ref(props.form)
+const colsKeys = ref(props.cols)
+const tableFormApp = ref(null)
+const tableFormVM = ref(null)
+const isTableForm = ref(false)
+const isCtrlKey = ref(false)
+const checkKeyList = ref([])
+const formRegExpJson = ref({})
+
+// 计算属性
+const tableFormStyle = computed(() => `width: ${props.width}; height: ${props.height};`)
+
+// 监听属性变化
+watch(() => [props.pkey, props.noTip, props.scroll, props.loading, props.pid], ([pkey, tip, scroll, loading, pid]) => {
+    keyId.value = pkey
+    noTips.value = tip
+    isScroll.value = scroll
+    isLoading.value = loading
+    activeKey.value = pid
+})
+
+watch(() => props.html, (html) => {
+    excelHtml.value = html
+    setExcelHtml()
+})
+
+watch(() => props.form, (val) => {
+    excelForm.value = val
+    setPickerKey()
+    setFormData(val)
+}, { deep: true })
+
+watch(() => props.cols, (cols) => {
+    colsKeys.value = cols
+}, { deep: true })
+
+// 生命周期钩子
+onMounted(() => {
+    setPickerKey()
+    nextTick(() => {
+        getExcelHtml()
+    })
+})
+
+onUnmounted(() => {
+    // 清理工作
+    unmountHtml()
+})
+
+// 方法定义
+const excelTableFormClick = () => {
+    emit('excelBodyTap', keyId.value)
+}
+
+const setPickerKey = () => {
+    HTableForm.setPickerKey(excelForm.value)
+}
+
+const setExcelHtml = () => {
+    setPickerKey()
+    if (tableFormApp.value) {
+        tableFormApp.value?.unmount()
+        tableFormApp.value = null
+        nextTick(() => {
+            getExcelHtml()
+        })
+    } else {
+        getExcelHtml()
+    }
+}
+
+const getExcelHtml = async () => {
+    const pkeyId = keyId.value, pid = activeKey.value
+    const temp = isString(excelHtml.value) ? excelHtml.value : ''
+    if (isNullES(temp) || isNullES(pkeyId)) {
+        isTableForm.value = false
+        excelForm.value.isRenderForm = false
+        emit('render', excelForm.value)
+        return
+    }
+
+    try {
+        await getAppTableId(`table-form-${pkeyId}`)
+        isTableForm.value = true
+        const { app, vm } = HTableForm.createForm({
+            pid,
+            template: temp,
+            keys: colsKeys.value,
+            tableForm: excelForm.value,
+            appId: `#table-form-${pkeyId}`,
+            onFormDataChange: (form) => {
+                excelForm.value = form
+                emit('render', form)
+            },
+            onRight: (event, KeyName) => {
+                onRightClick(pkeyId, event, KeyName, pid)
+            },
+            onLeftClick: (key) => {
+                setShiftTableForm(key, pid)
+            },
+        })
+        tableFormApp.value = app
+        tableFormVM.value = vm
+        excelForm.value.isRenderForm = true
+        await nextTick()
+        HTableForm.setByClassKeyup(colsKeys.value, pid)
+        emit('render', excelForm.value)
+    } catch (error) {
+        console.error('Error in getExcelHtml:', error)
+        isTableForm.value = false
+        excelForm.value.isRenderForm = false
+        emit('render', excelForm.value)
+    }
+}
+
+const getAppTableId = async (key, maxAttempts = 10, interval = 500) => {
+    return new Promise((resolve, reject) => {
+        let attempts = 0
+        const checkElement = () => {
+            const dom = document.getElementById(key)
+            if (dom) {
+                resolve(dom)
+            } else if (++attempts < maxAttempts) {
+                setTimeout(checkElement, interval)
+            } else {
+                reject(new Error(`Element ${key} not found after ${maxAttempts} attempts`))
+            }
+        }
+        checkElement()
+    })
+}
+
+const setTableFormBlurReg = (pkeyId, event, key, reg, val, msg, pid) => {
+    const dom = document.getElementById(key)?.parentElement
+    if (dom) {
+        if (val && reg) {
+            let regx = new RegExp(reg)
+            let state = regx.test(val)
+            if (state) {
+                delete formRegExpJson.value[key]
+                HTableForm.setFormStyle(key, 'hc-red-border', pid)
+            } else {
+                formRegExpJson.value[key] = { key, reg, val, msg, state }
+                HTableForm.setFormStyle(key, 'hc-red-border', pid, true)
+                if (props.isMessage) {
+                    window?.$message?.warning(msg)
+                }
+            }
+        } else {
+            delete formRegExpJson.value[key]
+            HTableForm.setFormStyle(key, 'hc-red-border', pid)
+        }
+    } else {
+        delete formRegExpJson.value[key]
+    }
+}
+
+const onRightClick = async (pkeyId, event, KeyName, pid) => {
+    try {
+        const specialDom = await HTableForm.getQuerySelector(KeyName, pid)
+        const startPos = specialDom?.selectionStart || 0
+        const endPos = specialDom?.selectionEnd || 0
+        emit('rightTap', { event, KeyName, startPos, endPos, pkeyId, pid })
+    } catch (error) {
+        console.error('Error in onRightClick:', error)
+    }
+}
+
+const setShiftTableForm = (key, pid) => {
+    if (isCtrlKey.value) {
+        const form = excelForm.value
+        const keys = checkKeyList.value
+        const index = arrIndex(keys, 'key', key)
+        if (index === -1) {
+            keys.push({ key: key, val: form[key] })
+        } else {
+            keys.splice(index, 1)
+        }
+        checkKeyList.value = keys
+        HTableForm.setCheckKeyStyle(key, pid, index !== -1)
+    }
+}
+
+const setIsCtrlKey = (state) => {
+    isCtrlKey.value = state
+}
+
+const setCopyKeyList = (event) => {
+    const pid = activeKey.value
+    const keysList = deepClone(checkKeyList.value)
+    if (keysList.length > 0) {
+        event.preventDefault()
+        setStoreValue('TableFormCopyKeys', keysList)
+        keysList.forEach(item => {
+            HTableForm.setCheckKeyStyle(item['key'], pid, true)
+        })
+        checkKeyList.value = []
+    }
+}
+
+const setPasteKeyList = async (event) => {
+    let keysList = getArrValue(getStoreValue('TableFormCopyKeys'))
+    const checkList = checkKeyList.value
+    if (checkList.length > 0) {
+        event.preventDefault()
+        if (checkList.length > 1 && keysList.length > 1) {
+            await setMultipleCheckValue(checkList, keysList)
+        } else if (checkList.length > 1 && keysList.length === 1) {
+            await setSingleCopyValue(checkList, keysList)
+        } else if (checkList.length === 1 && keysList.length >= 1) {
+            await setCopySingleValue(checkList, keysList)
+        }
+        checkKeyList.value = []
+        delStoreValue('TableFormCopyKeys')
+    }
+}
+
+const setCopySingleValue = async (checkList, keysList) => {
+    const keys = deepClone(keysList)
+    let form_val = '', key = checkList[0]['key']
+    for (let i = 0; i < keys.length; i++) {
+        const val = keys[i]['val']
+        form_val = form_val ? form_val + '、' + val : val
+        keys.splice(0, 1)
+    }
+    await setTableFormInfoValue(key, form_val)
+    HTableForm.setCheckKeyStyle(key, activeKey.value, true)
+}
+
+const setSingleCopyValue = async (checkList, keysList) => {
+    const keys = deepClone(keysList)
+    const form_val = keys[0]['val']
+    for (let i = 0; i < checkList.length; i++) {
+        const { key } = checkList[i]
+        await setTableFormInfoValue(key, form_val)
+        HTableForm.setCheckKeyStyle(key, activeKey.value, true)
+    }
+    keys.splice(0, 1)
+}
+
+const setMultipleCheckValue = async (checkList, keysList) => {
+    const keys = deepClone(keysList)
+    for (let i = 0; i < checkList.length; i++) {
+        const { key, val } = checkList[i]
+        if (keys.length > 0) {
+            const form_val = keys[0]['val']
+            await setTableFormInfoValue(key, form_val ? form_val : val)
+            keys.splice(0, 1)
+        } else {
+            await setTableFormInfoValue(key, val)
+        }
+        HTableForm.setCheckKeyStyle(key, activeKey.value, true)
+    }
+}
+
+const setTableFormInfoValue = async (key, value) => {
+    return new Promise((resolve) => {
+        setTimeout(() => {
+            excelForm.value[key] = value
+            resolve(true)
+        }, 100)
+    })
+}
+
+const getFormData = () => {
+    return excelForm.value
+}
+
+const setFormData = (data) => {
+    excelForm.value = data
+    tableFormVM.value?.setFormData(excelForm.value)
+}
+
+const getRegExpJson = () => {
+    return deepClone(formRegExpJson.value)
+}
+
+const isFormRegExp = async () => {
+    const isRegExp = !!getObjVal(formRegExpJson.value)
+    if (!isRegExp) {
+        return true
+    } else {
+        if (props.isMessage) {
+            window?.$message?.warning('请先修改完红色输入框的数据')
+        }
+        return false
+    }
+}
+
+const unmountHtml = () => {
+    if (tableFormApp.value) {
+        tableFormApp.value?.unmount()
+    }
+}
+
+// 暴露方法
+defineExpose({
+    getFormData,
+    setFormData,
+    getRegExpJson,
+    isFormRegExp,
+    setExcelHtml,
+    unmountHtml,
+    setIsCtrlKey,
+    setCopyKeyList,
+    setPasteKeyList,
+})
+</script>
+
+<style lang="scss">
+//插入特殊字符弹窗的输入框
+.hc-table-form-data-item .hc-excel-table-form td,
+.hc-table-form-data-item .hc-excel-table-form td .el-input .el-input__wrapper .el-input__inner,
+.el-form-item.special-form-item .el-form-item__content .el-input .el-input__wrapper .el-input__inner {
+    font-family: "hc-eudc", hc-sans, 宋体, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
+}
+
+.hc-table-form-data-item {
+    position: relative;
+    padding: 12px;
+    height: 100%;
+    overflow: hidden;
+    background-color: white;
+    &.no-scroll-bar .el-scrollbar {
+        display: none;
+    }
+    .hc-excel-table-form {
+        position: relative;
+        display: flex;
+        padding: 10px;
+        justify-content: center;
+        td {
+            position: relative;
+            padding: 6px;
+            background-clip: padding-box;
+            .el-input {
+                clear: both;
+                color: #606266;
+                border-radius: 3px;
+                height: $initials;
+                background-color: #ffffff !important;
+                .el-input__wrapper {
+                    background-color: inherit;
+                    caret-color: var(--el-color-primary);
+                }
+                .el-input__suffix-inner {
+                    width: 18px;
+                }
+            }
+            .el-textarea {
+                width: 100%;
+                height: 100%;
+                .el-textarea__inner {
+                    min-height: $initials;
+                    background-color: #ffffff;
+                    border-radius: 3px;
+                    color: #606266;
+                    height: 100%;
+                    caret-color: var(--el-color-primary);
+                }
+            }
+            //日期选择框
+            .el-date-editor.el-input .el-input__wrapper,
+            .el-date-editor.el-date-editor--datetimerange.el-input__wrapper {
+                width: 100%;
+                height: $initials;
+                clear: both;
+            }
+            //焦点
+            .el-input .el-input__wrapper.is-focus, .el-input .el-input__wrapper:hover,
+            .el-textarea .el-textarea__inner:hover {
+                box-shadow: 0 0 0 1.5px var(--el-input-focus-border-color) inset;
+                background-color: #eddac4;
+            }
+            //公式
+            &[gscolor] {
+                .el-input, .el-textarea .el-textarea__inner {
+                    background-color: #dcdcdc !important;
+                }
+                .el-date-editor.el-input__wrapper{
+                    background-color: #dcdcdc !important;
+                }
+                .el-select .el-select__wrapper {
+                    background: #dcdcdc !important;
+                }
+            }
+            //文本选中颜色
+            .el-input .el-input__wrapper input,
+            .el-textarea textarea {
+                &::selection {
+                    background: var(--el-color-primary-light-9);
+                    color: var(--el-color-primary);
+                }
+                &::-moz-selection {
+                    background: var(--el-color-primary-light-9);
+                    color: var(--el-color-primary);
+                }
+            }
+            //下拉框
+            .el-select {
+                width: 100%;
+                height: $initials;
+                clear: both;
+            }
+            .el-select .el-select__wrapper.is-focused {
+                background: var(--el-color-primary-light-9);
+                color: var(--el-color-primary);
+            }
+            //表单上传
+            .hc-upload-table-form {
+                position: absolute;
+                top: 0;
+                bottom: 0;
+                left: 6px;
+                right: 6px;
+                .el-upload {
+                    justify-content: unset;
+                    height: calc(100% - 10px);
+                }
+                .hc-table-form-img {
+                    width: auto;
+                    max-width: 100%;
+                    height: 100%;
+                }
+            }
+        }
+        //列合并的单元格
+        td[rowspan] {
+            height: $initials;
+        }
+        //非输入框颜色
+        td:not([titlexx]), td[titlexx*=''],
+        td:not([title]), td[title*=''] {
+            background-color: white !important;
+            user-select: none;
+        }
+    }
+    .hc-no-table-form {
+        position: relative;
+        height: 100%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        .table-form-no {
+            position: relative;
+            img {
+                width: 350px;
+            }
+            .desc {
+                text-align: center;
+                font-size: 20px;
+                color: #aaa;
+            }
+        }
+    }
+}
+
+.hc-red-border {
+    &.el-textarea__inner, &.el-input .el-input__wrapper {
+        --el-input-border-color: #fe0000 !important;
+        box-shadow: 0 0 0 2px #fe0000 inset !important;
+    }
+}
+
+.hc-green-border {
+    &.el-textarea__inner, &.el-input .el-input__wrapper {
+        --el-input-border-color: #1ECC95 !important;
+        box-shadow: 0 0 0 2px #1ECC95 inset !important;
+    }
+}
+</style>

+ 470 - 0
src/plugins/HTableForm.js

@@ -0,0 +1,470 @@
+// 使用了奇乐AI(https://ai.qilepan.com/auth?type=register&invite=NjM4) claude-3.5模型,优化了本文件的代码。
+
+import { createApp } from 'vue/dist/vue.esm-bundler.js'
+import { getHeader } from 'hc-vue3-ui'
+import { isArray, toParse } from 'js-fast-way'
+
+// 导入自定义组件或二次封装的组件
+import HcTableFormUpload from '~com/plugins/table-form/hc-form-upload.vue'
+import HcFormSelectSearch from '~com/plugins/table-form/hc-form-select-search.vue'
+import HcFormSelectSearch2 from '~com/plugins/table-form/hc-form-select-search2.vue'
+import HcFormCheckboxGroup from '~com/plugins/table-form/hc-form-checkbox-group.vue'
+import ElTimePicker from '~com/plugins/table-form/hc-time-picker.vue'
+import ElDatePicker from '~com/plugins/table-form/hc-date-picker-1.vue'
+import ElRadioGroup from '~com/plugins/table-form/hc-form-radio-group.vue'
+import HcEchart from '~com/plugins/table-form/echart.vue'
+
+import ElementPlus from 'element-plus'
+import zhCn from 'element-plus/es/locale/lang/zh-cn'
+
+// 定义组件对象
+const components = {
+    ElDatePicker, ElTimePicker, HcTableFormUpload, ElRadioGroup,
+    HcFormSelectSearch, HcFormSelectSearch2, HcFormCheckboxGroup, HcEchart,
+}
+
+// 定义键盘事件常量
+const ARROW_UP = 'ArrowUp'
+const ARROW_DOWN = 'ArrowDown'
+const ARROW_LEFT = 'ArrowLeft'
+const ARROW_RIGHT = 'ArrowRight'
+
+/**
+ * HTableForm类:用于创建和管理表单
+ */
+export default class HTableForm {
+    static tableFormApp = null
+    static tableFormVM = null
+    static vEnableBulk = true
+
+    /**
+     * 创建表单
+     * @param {Object} options - 配置选项
+     * @param {string} options.template - Vue模板
+     * @param {Object} options.tableForm - 表单数据
+     * @param {Array} options.keys - 键值数组
+     * @param {string} options.appId - 应用ID
+     * @param {string} options.pid - 父级ID
+     * @param {Function} options.onRight - 右键点击回调
+     * @param {Function} options.onBlur - 失焦回调
+     * @param {Function} options.onLeftClick - 左键点击回调
+     * @param {Function} options.onFormDataChange - 表单数据变化回调
+     * @param {Function} options.onChartRefs - 图表引用回调
+     * @returns {Object} 返回创建的Vue应用和VM实例
+     */
+    static createForm({ template, tableForm, keys, appId, pid, onRight, onBlur, onLeftClick, onFormDataChange, onChartRefs }) {
+        if (!template || !tableForm || !appId) {
+            throw new Error('渲染失败')
+        }
+
+        const app = createApp({
+            components,
+            data() {
+                return {
+                    getTokenHeader: getHeader(),
+                    formData: tableForm,
+                }
+            },
+            watch: {
+                formData: {
+                    handler(obj) {
+                        tableForm = obj
+                        this.formDataChange(obj)
+                    },
+                    deep: true,
+                },
+            },
+            methods: {
+                // 表单数据变化处理
+                formDataChange(obj) {
+                    if (onFormDataChange) {
+                        onFormDataChange(obj)
+                    }
+                },
+                // 设置表单数据
+                setFormData(obj) {
+                    this.formData = obj
+                },
+                // 右键菜单点击处理
+                contextmenuClick(a, b, c, d, e, f, event) {
+                    event.preventDefault()
+                },
+                // 右键点击处理
+                RightClick(a, b, c, d, e, f, event) {
+                    setTimeout(() => {
+                        const KeyName = event?.target?.getAttribute('keyname') || ''
+                        if (onRight) {
+                            event.preventDefault()
+                            onRight(event, KeyName)
+                        }
+                    }, 100)
+                },
+                // 获取信息(待实现)
+                getInformation() {
+                    // 实现获取信息的逻辑
+                },
+                // 日期选择器变化处理
+                datePickerChange(val, key) {
+                    this.formData[key] = val
+                },
+                // 表单上传成功处理
+                formUploadSuccess({ src, key }) {
+                    this.formData[key] = src
+                },
+                // 删除表单文件
+                delTableFormFile(key) {
+                    this.formData[key] = ''
+                },
+                // 正则表达式验证
+                getRegularExpression(event, reg, msg, a, b, leng, type, c, d) {
+                    const KeyName = event?.target?.getAttribute('keyname') || ''
+                    if (onBlur) {
+                        onBlur(event, KeyName, reg, this.formData[KeyName], msg, leng, type)
+                    }
+                },
+                // 远程表单变化处理
+                formRemoteChange(data) {
+                    Object.keys(data).forEach(key => {
+                        this.formData[key] = data[key]
+                    })
+                },
+                // 复选框组变化处理
+                checkboxGroupChange({ key, val }) {
+                    this.formData[key] = val
+                },
+                // 向上键处理
+                keyupShiftUp(event) {
+                    HTableForm.setKeyupData(event, 'up', keys, pid)
+                },
+                // 向下键处理
+                keyupShiftDown(event) {
+                    HTableForm.setKeyupData(event, 'down', keys, pid)
+                },
+                // 向左键处理
+                keyupShiftLeft(event) {
+                    HTableForm.setKeyupData(event, 'left', keys, pid)
+                },
+                // 向右键处理
+                keyupShiftRight(event) {
+                    HTableForm.setKeyupData(event, 'right', keys, pid)
+                },
+                // 日期键盘事件处理
+                dateKeydown({ type, name }) {
+                    HTableForm.setKeyupData({ target: { id: name } }, type, keys, pid)
+                },
+                // 输入框左键点击处理
+                inputLeftClick(event, key) {
+                    setTimeout(() => {
+                        if (onLeftClick) {
+                            onLeftClick(key)
+                        }
+                    }, 100)
+                },
+                // 设置图表引用
+                setChartRefs(el, pKeyId, key) {
+                    if (onChartRefs) onChartRefs(el, pKeyId, key)
+                },
+            },
+            template,
+        })
+
+        app.use(ElementPlus, {
+            locale: zhCn,
+        })
+
+        const vm = app.mount(appId)
+        this.tableFormApp = app
+        this.tableFormVM = vm
+        return { app, vm }
+    }
+
+    /**
+     * 设置日期选择器的键值
+     * @param {Object} data - 包含pickerKey的数据对象
+     * @returns {Object} 处理后的数据对象
+     */
+    static setPickerKey(data) {
+        const pickerKey = data['pickerKey'] || ''
+        if (pickerKey) {
+            const pickerKeys = pickerKey.split(',')
+            for (let i = 0; i < pickerKeys.length; i++) {
+                const val = data[pickerKeys[i]] || ''
+                if (val) {
+                    const dataVal = val.replace(/'/g, '"')
+                    data[pickerKeys[i]] = toParse(dataVal) || []
+                } else {
+                    data[pickerKeys[i]] = []
+                }
+            }
+        }
+        return data
+    }
+
+    /**
+     * 设置日期选择器的键盘事件
+     * @param {Array} keys - 键值数组
+     * @param {string} pid - 父级ID
+     */
+    static setByClassKeyup(keys, pid = '') {
+        try {
+            const poppers = document.querySelectorAll('.hc-table-form-date-picker')
+            poppers.forEach(item => {
+                let key = ''
+                const ids = item.getAttribute('class').split('-form-id-')
+                if (ids.length >= 1) {
+                    key = ids[1]
+                }
+                if (ids) {
+                    const panels = item.querySelectorAll('.el-picker-panel__content')
+                    this.setElementsEvent(panels, key, keys, pid)
+                }
+            })
+        } catch (e) {
+            console.error('Error in setByClassKeyup:', e)
+        }
+    }
+
+    /**
+     * 为元素设置键盘事件
+     * @param {NodeList} elements - 需要设置事件的元素列表
+     * @param {string} key - 键值
+     * @param {Array} keys - 键值数组
+     * @param {string} pid - 父级ID
+     */
+    static setElementsEvent(elements, key, keys, pid = '') {
+        if (elements.length > 0) {
+            const _this = this
+            elements[0].addEventListener('keydown', e => {
+                e.stopPropagation()
+                switch (e.key) {
+                    case ARROW_UP:
+                        _this.setKeyupData({ target: { id: key } }, 'up', keys, pid)
+                        break
+                    case ARROW_DOWN:
+                        _this.setKeyupData({ target: { id: key } }, 'down', keys, pid)
+                        break
+                    case ARROW_LEFT:
+                        _this.setKeyupData({ target: { id: key } }, 'left', keys, pid)
+                        break
+                    case ARROW_RIGHT:
+                        _this.setKeyupData({ target: { id: key } }, 'right', keys, pid)
+                        break
+                }
+            }, {
+                capture: true,
+            })
+        }
+    }
+
+    /**
+     * 设置键盘事件数据
+     * @param {Object} target - 目标对象
+     * @param {string} type - 事件类型
+     * @param {Array} keys - 键值数组
+     * @param {string} pid - 父级ID
+     */
+    static setKeyupData({ target }, type, keys, pid = '') {
+        const key = target.id
+        if (key && type && isArray(keys)) {
+            let left = -1, top = -1
+            for (let i = 0; i < keys.length; i++) {
+                if (isArray(keys[i])) {
+                    const index = keys[i].findIndex(id => id === key)
+                    if (index !== -1) {
+                        left = index
+                        top = i
+                        break
+                    }
+                }
+            }
+
+            let newKey = ''
+            switch (type) {
+                case 'up':
+                    if (top > 0) {
+                        const tops = keys[top - 1]
+                        newKey = tops[Math.min(left, tops.length - 1)]
+                    }
+                    break
+                case 'down':
+                    if (top < keys.length - 1) {
+                        const bottoms = keys[top + 1]
+                        newKey = bottoms[Math.min(left, bottoms.length - 1)]
+                    }
+                    break
+                case 'left':
+                    if (left > 0) {
+                        newKey = keys[top][left - 1]
+                    }
+                    break
+                case 'right':
+                    if (left < keys[top].length - 1) {
+                        newKey = keys[top][left + 1]
+                    }
+                    break
+            }
+            if (newKey) {
+                this.setElementFocus(newKey, pid)
+            }
+        }
+    }
+
+    /**
+     * 设置元素焦点
+     * @param {string} key - 元素的key
+     * @param {string} pid - 父级ID
+     */
+    static setElementFocus(key, pid) {
+        if (key) {
+            try {
+                const element = this.getQuerySelector(key, pid)
+                if (element) {
+                    element.focus()
+                }
+            } catch (e) {
+                console.error('Error in setElementFocus:', e)
+            }
+        }
+    }
+
+    /**
+     * 获取查询选择器
+     * @param {string} key - 元素的key
+     * @param {string} pid - 父级ID
+     * @returns {Element|null} 返回查询到的元素或null
+     */
+    static getQuerySelector(key, pid = '') {
+        if (pid) {
+            return document.querySelector(`#${pid} #${key.toString()}`)
+        } else {
+            return document.getElementById(key.toString())
+        }
+    }
+
+    /**
+     * 设置表单样式
+     * @param {string} key - 元素的key
+     * @param {string} name - 样式名称
+     * @param {string} pid - 父级ID
+     * @param {boolean} add - 是否添加样式
+     */
+    static async setFormStyle(key, name = 'hc-red-border', pid = '', add = false) {
+        const dom = await this.getQuerySelector(key, pid)
+        if (!dom) return
+
+        const parent = dom.parentElement
+        if (dom.tagName === 'INPUT') {
+            const parentElement = parent?.parentElement
+            if (parentElement) {
+                this.setFormClass(parentElement, name, add)
+            }
+        } else if (dom.tagName === 'TEXTAREA') {
+            this.setFormClass(dom, name, add)
+        }
+    }
+
+    /**
+     * 设置表单类名
+     * @param {Element} dom - DOM元素
+     * @param {string} name - 类名
+     * @param {boolean} add - 是否添加类名
+     */
+    static setFormClass(dom, name = 'hc-red-border', add = false) {
+        const classStr = dom.getAttribute('class') || ''
+        const classArr = classStr.split(' ')
+        const index = classArr.indexOf(name)
+        if (index === -1 && add) {
+            classArr.push(name)
+        } else if (index !== -1 && !add) {
+            classArr.splice(index, 1)
+        }
+        dom.setAttribute('class', classArr.join(' '))
+    }
+
+    /**
+     * 设置选中键的样式
+     * @param {string} key - 元素的key
+     * @param {string} pid - 父级ID
+     * @param {boolean} remove - 是否移除样式
+     */
+    static setCheckKeyStyle(key, pid = '', remove = false) {
+        this.setFormStyle(key, 'hc-green-border', pid, !remove)
+    }
+
+    //设置是否批量复制
+    static setEnableBulk(val = true) {
+        this.vEnableBulk = val
+    }
+
+    /**
+     * 设置全局键盘事件
+     * @param {Object} options - 配置选项
+     * @param {Function} options.onCtrlDown - Ctrl键按下回调
+     * @param {Function} options.onCtrlDownC - Ctrl+C按下回调
+     * @param {Function} options.onCtrlDownV - Ctrl+V按下回调
+     * @param {Function} options.onCtrlUp - Ctrl键抬起回调
+     * @returns {Function} 返回一个用于清理事件监听器的函数
+     */
+    static setOnEventKey({ onCtrlDown, onCtrlDownC, onCtrlDownV, onCtrlUp }) {
+        const handleKeyDown = (event) => {
+            if (!this.vEnableBulk) return
+            const { key, ctrlKey, metaKey } = event
+            const isCtrl = window.isMac ? metaKey : window.isWin ? ctrlKey : false
+            if (isCtrl) {
+                if (onCtrlDown && key === window?.isCtrl) {
+                    onCtrlDown(event)
+                } else if (onCtrlDownC && key === 'c') {
+                    onCtrlDownC(event)
+                } else if (onCtrlDownV && key === 'v') {
+                    onCtrlDownV(event)
+                }
+            }
+        }
+
+        const handleKeyUp = (event) => {
+            if (!this.vEnableBulk) return
+            const { key, ctrlKey, metaKey } = event
+            const isCtrl = window.isMac ? metaKey : window.isWin ? ctrlKey : false
+            if (!isCtrl && key === window?.isCtrl && onCtrlUp) {
+                onCtrlUp(event)
+            }
+        }
+
+        //是否可用
+        if (this.vEnableBulk) {
+            document.addEventListener('keydown', handleKeyDown)
+            document.addEventListener('keyup', handleKeyUp)
+        } else {
+            document.removeEventListener('keydown', handleKeyDown)
+            document.removeEventListener('keyup', handleKeyUp)
+        }
+
+        // 返回一个清理函数
+        return () => {
+            document.removeEventListener('keydown', handleKeyDown)
+            document.removeEventListener('keyup', handleKeyUp)
+        }
+    }
+
+    /**
+     * 卸载事件监听器(已废弃)
+     * 使用setOnEventKey返回的清理函数代替
+     */
+    static unmountEventKey() {
+        // 这个方法现在不需要了,因为setOnEventKey返回了一个清理函数
+        document.onkeydown = null
+        document.onkeyup = null
+    }
+
+    /**
+     * 卸载表单应用
+     * 清理Vue应用实例和相关引用
+     */
+    static unmountFormApp() {
+        if (this.tableFormApp) {
+            this.tableFormApp.unmount()
+            this.tableFormApp = null
+            this.tableFormVM = null
+        }
+    }
+}

+ 5 - 5
src/router/modules/base.js

@@ -140,31 +140,31 @@ export default [
                     {
                         path: '/archives/manage/query',
                         name: 'archives-manage-query',
-                        meta: { title: '案查询' },
+                        meta: { title: '案查询' },
                         component: () => import('~src/views/archives/manage/query.vue'),
                     },
                     {
                         path: '/archives/manage/inspects',
                         name: 'archives-manage-inspects',
-                        meta: { title: '档案巡检' },
+                        meta: { title: '案卷检查' },
                         component: () => import('~src/views/archives/manage/inspects.vue'),
                     },
                     {
                         path: '/archives/manage/early',
                         name: 'archives-manage-early',
-                        meta: { title: '案预警' },
+                        meta: { title: '案预警' },
                         component: () => import('~src/views/archives/manage/early.vue'),
                     },
                     {
                         path: '/archives/manage/early/admin',
                         name: 'archives-manage-early-admin',
-                        meta: { title: '案预警(总管)' },
+                        meta: { title: '案预警(总管)' },
                         component: () => import('~src/views/archives/manage/early-admin.vue'),
                     },
                     {
                         path: '/archives/manage/tuning',
                         name: 'archives-manage-tuning',
-                        meta: { title: '案调整' },
+                        meta: { title: '案调整' },
                         component: () => import('~src/views/archives/manage/tuning.vue'),
                     },
                   

+ 5 - 6
src/router/modules/token.js

@@ -14,10 +14,9 @@ export default [
     'transfer-writing-conclusion',
     'transfer-write-report',
     'test-index',
-   'custody-save', //案卷保管
-   'custody-ledger', //案卷台账
-   'using-borrow-query',
-   'using-borrow-borrow',
-   'using-borrow-ledger',
-   'using-backup',
+
+ 
+ 
+ 
+ 
 ]

+ 6 - 1
src/views/file/records.vue

@@ -29,7 +29,7 @@
                     <el-button type="primary" hc-btn @click="movesClick">跨目录移动</el-button>
                 </HcTooltip>
                 <HcTooltip keys="file_records_btn_split">
-                    <el-button hc-btn style="background-color: #8B5CF6; border-color: #8B5CF6; color:white" @click="movesClick">分解文件</el-button>
+                    <el-button hc-btn style="background-color: #8B5CF6; border-color: #8B5CF6; color:white" @click="splitClick">分解文件</el-button>
                 </HcTooltip>
             </template>
             <HcTable
@@ -1392,6 +1392,11 @@ const onmousedown = () => {
         document.onmouseup = null
     }
 }
+
+const splitClick = ()=>{
+    console.log('分解文件')
+    
+}
 </script>
 
 <style lang="scss">

+ 1 - 1
src/views/using/backup.vue

@@ -46,7 +46,7 @@
                                             <div class="td-item">数据取回费用</div>
                                         </div>
                                         <div class="td-item-tr">
-                                            <div class="td-item">-</div>
+                                            <div class="td-item" style="border-top: 1px solid #A3D9EA;">-</div>
                                             <div class="td-item">-</div>
                                             <div class="td-item">-</div>
                                             <div class="td-item">-</div>