修改成vue3版本
This commit is contained in:
parent
9e547e3b49
commit
ddb4540968
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,571 @@
|
||||||
|
A,B,M,N,K,stack,Layer,x,Depth
|
||||||
|
1.0,4.0,2.0,3.0,6.283185307179586,1.0,1.0,2.5,-0.6
|
||||||
|
1.0,7.0,3.0,5.0,12.566370614359172,1.0,2.0,4.0,-1.2
|
||||||
|
1.0,10.0,4.0,7.0,18.84955592153876,1.0,3.0,5.5,-1.8
|
||||||
|
1.0,13.0,5.0,9.0,25.132741228718345,1.0,4.0,7.0,-2.4
|
||||||
|
1.0,16.0,6.0,11.0,31.41592653589793,1.0,5.0,8.5,-3.0
|
||||||
|
1.0,19.0,7.0,13.0,37.69911184307752,1.0,6.0,10.0,-3.6
|
||||||
|
1.0,22.0,8.0,15.0,43.982297150257104,1.0,7.0,11.5,-4.2
|
||||||
|
1.0,25.0,9.0,17.0,50.26548245743669,1.0,8.0,13.0,-4.8
|
||||||
|
1.0,28.0,10.0,19.0,56.548667764616276,1.0,9.0,14.5,-5.4
|
||||||
|
1.0,31.0,11.0,21.0,62.83185307179586,1.0,10.0,16.0,-6.0
|
||||||
|
1.0,34.0,12.0,23.0,69.11503837897544,1.0,11.0,17.5,-6.6
|
||||||
|
1.0,37.0,13.0,25.0,75.39822368615503,1.0,12.0,19.0,-7.2
|
||||||
|
1.0,40.0,14.0,27.0,81.68140899333461,1.0,13.0,20.5,-7.8
|
||||||
|
1.0,43.0,15.0,29.0,87.96459430051421,1.0,14.0,22.0,-8.4
|
||||||
|
1.0,46.0,16.0,31.0,94.2477796076938,1.0,15.0,23.5,-9.0
|
||||||
|
1.0,49.0,17.0,33.0,100.53096491487338,1.0,16.0,25.0,-9.6
|
||||||
|
1.0,52.0,18.0,35.0,106.81415022205297,1.0,17.0,26.5,-10.2
|
||||||
|
1.0,55.0,19.0,37.0,113.09733552923255,1.0,18.0,28.0,-10.8
|
||||||
|
1.0,58.0,20.0,39.0,119.38052083641215,1.0,19.0,29.5,-11.4
|
||||||
|
2.0,5.0,3.0,4.0,6.283185307179586,1.0,1.0,3.5,-0.6
|
||||||
|
2.0,8.0,4.0,6.0,12.566370614359172,1.0,2.0,5.0,-1.2
|
||||||
|
2.0,11.0,5.0,8.0,18.84955592153876,1.0,3.0,6.5,-1.8
|
||||||
|
2.0,14.0,6.0,10.0,25.132741228718345,1.0,4.0,8.0,-2.4
|
||||||
|
2.0,17.0,7.0,12.0,31.41592653589793,1.0,5.0,9.5,-3.0
|
||||||
|
2.0,20.0,8.0,14.0,37.69911184307752,1.0,6.0,11.0,-3.6
|
||||||
|
2.0,23.0,9.0,16.0,43.982297150257104,1.0,7.0,12.5,-4.2
|
||||||
|
2.0,26.0,10.0,18.0,50.26548245743669,1.0,8.0,14.0,-4.8
|
||||||
|
2.0,29.0,11.0,20.0,56.548667764616276,1.0,9.0,15.5,-5.4
|
||||||
|
2.0,32.0,12.0,22.0,62.83185307179586,1.0,10.0,17.0,-6.0
|
||||||
|
2.0,35.0,13.0,24.0,69.11503837897544,1.0,11.0,18.5,-6.6
|
||||||
|
2.0,38.0,14.0,26.0,75.39822368615503,1.0,12.0,20.0,-7.2
|
||||||
|
2.0,41.0,15.0,28.0,81.68140899333461,1.0,13.0,21.5,-7.8
|
||||||
|
2.0,44.0,16.0,30.0,87.96459430051421,1.0,14.0,23.0,-8.4
|
||||||
|
2.0,47.0,17.0,32.0,94.2477796076938,1.0,15.0,24.5,-9.0
|
||||||
|
2.0,50.0,18.0,34.0,100.53096491487338,1.0,16.0,26.0,-9.6
|
||||||
|
2.0,53.0,19.0,36.0,106.81415022205297,1.0,17.0,27.5,-10.2
|
||||||
|
2.0,56.0,20.0,38.0,113.09733552923255,1.0,18.0,29.0,-10.8
|
||||||
|
2.0,59.0,21.0,40.0,119.38052083641215,1.0,19.0,30.5,-11.4
|
||||||
|
3.0,6.0,4.0,5.0,6.283185307179586,1.0,1.0,4.5,-0.6
|
||||||
|
3.0,9.0,5.0,7.0,12.566370614359172,1.0,2.0,6.0,-1.2
|
||||||
|
3.0,12.0,6.0,9.0,18.84955592153876,1.0,3.0,7.5,-1.8
|
||||||
|
3.0,15.0,7.0,11.0,25.132741228718345,1.0,4.0,9.0,-2.4
|
||||||
|
3.0,18.0,8.0,13.0,31.41592653589793,1.0,5.0,10.5,-3.0
|
||||||
|
3.0,21.0,9.0,15.0,37.69911184307752,1.0,6.0,12.0,-3.6
|
||||||
|
3.0,24.0,10.0,17.0,43.982297150257104,1.0,7.0,13.5,-4.2
|
||||||
|
3.0,27.0,11.0,19.0,50.26548245743669,1.0,8.0,15.0,-4.8
|
||||||
|
3.0,30.0,12.0,21.0,56.548667764616276,1.0,9.0,16.5,-5.4
|
||||||
|
3.0,33.0,13.0,23.0,62.83185307179586,1.0,10.0,18.0,-6.0
|
||||||
|
3.0,36.0,14.0,25.0,69.11503837897544,1.0,11.0,19.5,-6.6
|
||||||
|
3.0,39.0,15.0,27.0,75.39822368615503,1.0,12.0,21.0,-7.2
|
||||||
|
3.0,42.0,16.0,29.0,81.68140899333461,1.0,13.0,22.5,-7.8
|
||||||
|
3.0,45.0,17.0,31.0,87.96459430051421,1.0,14.0,24.0,-8.4
|
||||||
|
3.0,48.0,18.0,33.0,94.2477796076938,1.0,15.0,25.5,-9.0
|
||||||
|
3.0,51.0,19.0,35.0,100.53096491487338,1.0,16.0,27.0,-9.6
|
||||||
|
3.0,54.0,20.0,37.0,106.81415022205297,1.0,17.0,28.5,-10.2
|
||||||
|
3.0,57.0,21.0,39.0,113.09733552923255,1.0,18.0,30.0,-10.8
|
||||||
|
3.0,60.0,22.0,41.0,119.38052083641215,1.0,19.0,31.5,-11.4
|
||||||
|
4.0,7.0,5.0,6.0,6.283185307179586,1.0,1.0,5.5,-0.6
|
||||||
|
4.0,10.0,6.0,8.0,12.566370614359172,1.0,2.0,7.0,-1.2
|
||||||
|
4.0,13.0,7.0,10.0,18.84955592153876,1.0,3.0,8.5,-1.8
|
||||||
|
4.0,16.0,8.0,12.0,25.132741228718345,1.0,4.0,10.0,-2.4
|
||||||
|
4.0,19.0,9.0,14.0,31.41592653589793,1.0,5.0,11.5,-3.0
|
||||||
|
4.0,22.0,10.0,16.0,37.69911184307752,1.0,6.0,13.0,-3.6
|
||||||
|
4.0,25.0,11.0,18.0,43.982297150257104,1.0,7.0,14.5,-4.2
|
||||||
|
4.0,28.0,12.0,20.0,50.26548245743669,1.0,8.0,16.0,-4.8
|
||||||
|
4.0,31.0,13.0,22.0,56.548667764616276,1.0,9.0,17.5,-5.4
|
||||||
|
4.0,34.0,14.0,24.0,62.83185307179586,1.0,10.0,19.0,-6.0
|
||||||
|
4.0,37.0,15.0,26.0,69.11503837897544,1.0,11.0,20.5,-6.6
|
||||||
|
4.0,40.0,16.0,28.0,75.39822368615503,1.0,12.0,22.0,-7.2
|
||||||
|
4.0,43.0,17.0,30.0,81.68140899333461,1.0,13.0,23.5,-7.8
|
||||||
|
4.0,46.0,18.0,32.0,87.96459430051421,1.0,14.0,25.0,-8.4
|
||||||
|
4.0,49.0,19.0,34.0,94.2477796076938,1.0,15.0,26.5,-9.0
|
||||||
|
4.0,52.0,20.0,36.0,100.53096491487338,1.0,16.0,28.0,-9.6
|
||||||
|
4.0,55.0,21.0,38.0,106.81415022205297,1.0,17.0,29.5,-10.2
|
||||||
|
4.0,58.0,22.0,40.0,113.09733552923255,1.0,18.0,31.0,-10.8
|
||||||
|
5.0,8.0,6.0,7.0,6.283185307179586,1.0,1.0,6.5,-0.6
|
||||||
|
5.0,11.0,7.0,9.0,12.566370614359172,1.0,2.0,8.0,-1.2
|
||||||
|
5.0,14.0,8.0,11.0,18.84955592153876,1.0,3.0,9.5,-1.8
|
||||||
|
5.0,17.0,9.0,13.0,25.132741228718345,1.0,4.0,11.0,-2.4
|
||||||
|
5.0,20.0,10.0,15.0,31.41592653589793,1.0,5.0,12.5,-3.0
|
||||||
|
5.0,23.0,11.0,17.0,37.69911184307752,1.0,6.0,14.0,-3.6
|
||||||
|
5.0,26.0,12.0,19.0,43.982297150257104,1.0,7.0,15.5,-4.2
|
||||||
|
5.0,29.0,13.0,21.0,50.26548245743669,1.0,8.0,17.0,-4.8
|
||||||
|
5.0,32.0,14.0,23.0,56.548667764616276,1.0,9.0,18.5,-5.4
|
||||||
|
5.0,35.0,15.0,25.0,62.83185307179586,1.0,10.0,20.0,-6.0
|
||||||
|
5.0,38.0,16.0,27.0,69.11503837897544,1.0,11.0,21.5,-6.6
|
||||||
|
5.0,41.0,17.0,29.0,75.39822368615503,1.0,12.0,23.0,-7.2
|
||||||
|
5.0,44.0,18.0,31.0,81.68140899333461,1.0,13.0,24.5,-7.8
|
||||||
|
5.0,47.0,19.0,33.0,87.96459430051421,1.0,14.0,26.0,-8.4
|
||||||
|
5.0,50.0,20.0,35.0,94.2477796076938,1.0,15.0,27.5,-9.0
|
||||||
|
5.0,53.0,21.0,37.0,100.53096491487338,1.0,16.0,29.0,-9.6
|
||||||
|
5.0,56.0,22.0,39.0,106.81415022205297,1.0,17.0,30.5,-10.2
|
||||||
|
5.0,59.0,23.0,41.0,113.09733552923255,1.0,18.0,32.0,-10.8
|
||||||
|
6.0,9.0,7.0,8.0,6.283185307179586,1.0,1.0,7.5,-0.6
|
||||||
|
6.0,12.0,8.0,10.0,12.566370614359172,1.0,2.0,9.0,-1.2
|
||||||
|
6.0,15.0,9.0,12.0,18.84955592153876,1.0,3.0,10.5,-1.8
|
||||||
|
6.0,18.0,10.0,14.0,25.132741228718345,1.0,4.0,12.0,-2.4
|
||||||
|
6.0,21.0,11.0,16.0,31.41592653589793,1.0,5.0,13.5,-3.0
|
||||||
|
6.0,24.0,12.0,18.0,37.69911184307752,1.0,6.0,15.0,-3.6
|
||||||
|
6.0,27.0,13.0,20.0,43.982297150257104,1.0,7.0,16.5,-4.2
|
||||||
|
6.0,30.0,14.0,22.0,50.26548245743669,1.0,8.0,18.0,-4.8
|
||||||
|
6.0,33.0,15.0,24.0,56.548667764616276,1.0,9.0,19.5,-5.4
|
||||||
|
6.0,36.0,16.0,26.0,62.83185307179586,1.0,10.0,21.0,-6.0
|
||||||
|
6.0,39.0,17.0,28.0,69.11503837897544,1.0,11.0,22.5,-6.6
|
||||||
|
6.0,42.0,18.0,30.0,75.39822368615503,1.0,12.0,24.0,-7.2
|
||||||
|
6.0,45.0,19.0,32.0,81.68140899333461,1.0,13.0,25.5,-7.8
|
||||||
|
6.0,48.0,20.0,34.0,87.96459430051421,1.0,14.0,27.0,-8.4
|
||||||
|
6.0,51.0,21.0,36.0,94.2477796076938,1.0,15.0,28.5,-9.0
|
||||||
|
6.0,54.0,22.0,38.0,100.53096491487338,1.0,16.0,30.0,-9.6
|
||||||
|
6.0,57.0,23.0,40.0,106.81415022205297,1.0,17.0,31.5,-10.2
|
||||||
|
6.0,60.0,24.0,42.0,113.09733552923255,1.0,18.0,33.0,-10.8
|
||||||
|
7.0,10.0,8.0,9.0,6.283185307179586,1.0,1.0,8.5,-0.6
|
||||||
|
7.0,13.0,9.0,11.0,12.566370614359172,1.0,2.0,10.0,-1.2
|
||||||
|
7.0,16.0,10.0,13.0,18.84955592153876,1.0,3.0,11.5,-1.8
|
||||||
|
7.0,19.0,11.0,15.0,25.132741228718345,1.0,4.0,13.0,-2.4
|
||||||
|
7.0,22.0,12.0,17.0,31.41592653589793,1.0,5.0,14.5,-3.0
|
||||||
|
7.0,25.0,13.0,19.0,37.69911184307752,1.0,6.0,16.0,-3.6
|
||||||
|
7.0,28.0,14.0,21.0,43.982297150257104,1.0,7.0,17.5,-4.2
|
||||||
|
7.0,31.0,15.0,23.0,50.26548245743669,1.0,8.0,19.0,-4.8
|
||||||
|
7.0,34.0,16.0,25.0,56.548667764616276,1.0,9.0,20.5,-5.4
|
||||||
|
7.0,37.0,17.0,27.0,62.83185307179586,1.0,10.0,22.0,-6.0
|
||||||
|
7.0,40.0,18.0,29.0,69.11503837897544,1.0,11.0,23.5,-6.6
|
||||||
|
7.0,43.0,19.0,31.0,75.39822368615503,1.0,12.0,25.0,-7.2
|
||||||
|
7.0,46.0,20.0,33.0,81.68140899333461,1.0,13.0,26.5,-7.8
|
||||||
|
7.0,49.0,21.0,35.0,87.96459430051421,1.0,14.0,28.0,-8.4
|
||||||
|
7.0,52.0,22.0,37.0,94.2477796076938,1.0,15.0,29.5,-9.0
|
||||||
|
7.0,55.0,23.0,39.0,100.53096491487338,1.0,16.0,31.0,-9.6
|
||||||
|
7.0,58.0,24.0,41.0,106.81415022205297,1.0,17.0,32.5,-10.2
|
||||||
|
8.0,11.0,9.0,10.0,6.283185307179586,1.0,1.0,9.5,-0.6
|
||||||
|
8.0,14.0,10.0,12.0,12.566370614359172,1.0,2.0,11.0,-1.2
|
||||||
|
8.0,17.0,11.0,14.0,18.84955592153876,1.0,3.0,12.5,-1.8
|
||||||
|
8.0,20.0,12.0,16.0,25.132741228718345,1.0,4.0,14.0,-2.4
|
||||||
|
8.0,23.0,13.0,18.0,31.41592653589793,1.0,5.0,15.5,-3.0
|
||||||
|
8.0,26.0,14.0,20.0,37.69911184307752,1.0,6.0,17.0,-3.6
|
||||||
|
8.0,29.0,15.0,22.0,43.982297150257104,1.0,7.0,18.5,-4.2
|
||||||
|
8.0,32.0,16.0,24.0,50.26548245743669,1.0,8.0,20.0,-4.8
|
||||||
|
8.0,35.0,17.0,26.0,56.548667764616276,1.0,9.0,21.5,-5.4
|
||||||
|
8.0,38.0,18.0,28.0,62.83185307179586,1.0,10.0,23.0,-6.0
|
||||||
|
8.0,41.0,19.0,30.0,69.11503837897544,1.0,11.0,24.5,-6.6
|
||||||
|
8.0,44.0,20.0,32.0,75.39822368615503,1.0,12.0,26.0,-7.2
|
||||||
|
8.0,47.0,21.0,34.0,81.68140899333461,1.0,13.0,27.5,-7.8
|
||||||
|
8.0,50.0,22.0,36.0,87.96459430051421,1.0,14.0,29.0,-8.4
|
||||||
|
8.0,53.0,23.0,38.0,94.2477796076938,1.0,15.0,30.5,-9.0
|
||||||
|
8.0,56.0,24.0,40.0,100.53096491487338,1.0,16.0,32.0,-9.6
|
||||||
|
8.0,59.0,25.0,42.0,106.81415022205297,1.0,17.0,33.5,-10.2
|
||||||
|
9.0,12.0,10.0,11.0,6.283185307179586,1.0,1.0,10.5,-0.6
|
||||||
|
9.0,15.0,11.0,13.0,12.566370614359172,1.0,2.0,12.0,-1.2
|
||||||
|
9.0,18.0,12.0,15.0,18.84955592153876,1.0,3.0,13.5,-1.8
|
||||||
|
9.0,21.0,13.0,17.0,25.132741228718345,1.0,4.0,15.0,-2.4
|
||||||
|
9.0,24.0,14.0,19.0,31.41592653589793,1.0,5.0,16.5,-3.0
|
||||||
|
9.0,27.0,15.0,21.0,37.69911184307752,1.0,6.0,18.0,-3.6
|
||||||
|
9.0,30.0,16.0,23.0,43.982297150257104,1.0,7.0,19.5,-4.2
|
||||||
|
9.0,33.0,17.0,25.0,50.26548245743669,1.0,8.0,21.0,-4.8
|
||||||
|
9.0,36.0,18.0,27.0,56.548667764616276,1.0,9.0,22.5,-5.4
|
||||||
|
9.0,39.0,19.0,29.0,62.83185307179586,1.0,10.0,24.0,-6.0
|
||||||
|
9.0,42.0,20.0,31.0,69.11503837897544,1.0,11.0,25.5,-6.6
|
||||||
|
9.0,45.0,21.0,33.0,75.39822368615503,1.0,12.0,27.0,-7.2
|
||||||
|
9.0,48.0,22.0,35.0,81.68140899333461,1.0,13.0,28.5,-7.8
|
||||||
|
9.0,51.0,23.0,37.0,87.96459430051421,1.0,14.0,30.0,-8.4
|
||||||
|
9.0,54.0,24.0,39.0,94.2477796076938,1.0,15.0,31.5,-9.0
|
||||||
|
9.0,57.0,25.0,41.0,100.53096491487338,1.0,16.0,33.0,-9.6
|
||||||
|
9.0,60.0,26.0,43.0,106.81415022205297,1.0,17.0,34.5,-10.2
|
||||||
|
10.0,13.0,11.0,12.0,6.283185307179586,1.0,1.0,11.5,-0.6
|
||||||
|
10.0,16.0,12.0,14.0,12.566370614359172,1.0,2.0,13.0,-1.2
|
||||||
|
10.0,19.0,13.0,16.0,18.84955592153876,1.0,3.0,14.5,-1.8
|
||||||
|
10.0,22.0,14.0,18.0,25.132741228718345,1.0,4.0,16.0,-2.4
|
||||||
|
10.0,25.0,15.0,20.0,31.41592653589793,1.0,5.0,17.5,-3.0
|
||||||
|
10.0,28.0,16.0,22.0,37.69911184307752,1.0,6.0,19.0,-3.6
|
||||||
|
10.0,31.0,17.0,24.0,43.982297150257104,1.0,7.0,20.5,-4.2
|
||||||
|
10.0,34.0,18.0,26.0,50.26548245743669,1.0,8.0,22.0,-4.8
|
||||||
|
10.0,37.0,19.0,28.0,56.548667764616276,1.0,9.0,23.5,-5.4
|
||||||
|
10.0,40.0,20.0,30.0,62.83185307179586,1.0,10.0,25.0,-6.0
|
||||||
|
10.0,43.0,21.0,32.0,69.11503837897544,1.0,11.0,26.5,-6.6
|
||||||
|
10.0,46.0,22.0,34.0,75.39822368615503,1.0,12.0,28.0,-7.2
|
||||||
|
10.0,49.0,23.0,36.0,81.68140899333461,1.0,13.0,29.5,-7.8
|
||||||
|
10.0,52.0,24.0,38.0,87.96459430051421,1.0,14.0,31.0,-8.4
|
||||||
|
10.0,55.0,25.0,40.0,94.2477796076938,1.0,15.0,32.5,-9.0
|
||||||
|
10.0,58.0,26.0,42.0,100.53096491487338,1.0,16.0,34.0,-9.6
|
||||||
|
11.0,14.0,12.0,13.0,6.283185307179586,1.0,1.0,12.5,-0.6
|
||||||
|
11.0,17.0,13.0,15.0,12.566370614359172,1.0,2.0,14.0,-1.2
|
||||||
|
11.0,20.0,14.0,17.0,18.84955592153876,1.0,3.0,15.5,-1.8
|
||||||
|
11.0,23.0,15.0,19.0,25.132741228718345,1.0,4.0,17.0,-2.4
|
||||||
|
11.0,26.0,16.0,21.0,31.41592653589793,1.0,5.0,18.5,-3.0
|
||||||
|
11.0,29.0,17.0,23.0,37.69911184307752,1.0,6.0,20.0,-3.6
|
||||||
|
11.0,32.0,18.0,25.0,43.982297150257104,1.0,7.0,21.5,-4.2
|
||||||
|
11.0,35.0,19.0,27.0,50.26548245743669,1.0,8.0,23.0,-4.8
|
||||||
|
11.0,38.0,20.0,29.0,56.548667764616276,1.0,9.0,24.5,-5.4
|
||||||
|
11.0,41.0,21.0,31.0,62.83185307179586,1.0,10.0,26.0,-6.0
|
||||||
|
11.0,44.0,22.0,33.0,69.11503837897544,1.0,11.0,27.5,-6.6
|
||||||
|
11.0,47.0,23.0,35.0,75.39822368615503,1.0,12.0,29.0,-7.2
|
||||||
|
11.0,50.0,24.0,37.0,81.68140899333461,1.0,13.0,30.5,-7.8
|
||||||
|
11.0,53.0,25.0,39.0,87.96459430051421,1.0,14.0,32.0,-8.4
|
||||||
|
11.0,56.0,26.0,41.0,94.2477796076938,1.0,15.0,33.5,-9.0
|
||||||
|
11.0,59.0,27.0,43.0,100.53096491487338,1.0,16.0,35.0,-9.6
|
||||||
|
12.0,15.0,13.0,14.0,6.283185307179586,1.0,1.0,13.5,-0.6
|
||||||
|
12.0,18.0,14.0,16.0,12.566370614359172,1.0,2.0,15.0,-1.2
|
||||||
|
12.0,21.0,15.0,18.0,18.84955592153876,1.0,3.0,16.5,-1.8
|
||||||
|
12.0,24.0,16.0,20.0,25.132741228718345,1.0,4.0,18.0,-2.4
|
||||||
|
12.0,27.0,17.0,22.0,31.41592653589793,1.0,5.0,19.5,-3.0
|
||||||
|
12.0,30.0,18.0,24.0,37.69911184307752,1.0,6.0,21.0,-3.6
|
||||||
|
12.0,33.0,19.0,26.0,43.982297150257104,1.0,7.0,22.5,-4.2
|
||||||
|
12.0,36.0,20.0,28.0,50.26548245743669,1.0,8.0,24.0,-4.8
|
||||||
|
12.0,39.0,21.0,30.0,56.548667764616276,1.0,9.0,25.5,-5.4
|
||||||
|
12.0,42.0,22.0,32.0,62.83185307179586,1.0,10.0,27.0,-6.0
|
||||||
|
12.0,45.0,23.0,34.0,69.11503837897544,1.0,11.0,28.5,-6.6
|
||||||
|
12.0,48.0,24.0,36.0,75.39822368615503,1.0,12.0,30.0,-7.2
|
||||||
|
12.0,51.0,25.0,38.0,81.68140899333461,1.0,13.0,31.5,-7.8
|
||||||
|
12.0,54.0,26.0,40.0,87.96459430051421,1.0,14.0,33.0,-8.4
|
||||||
|
12.0,57.0,27.0,42.0,94.2477796076938,1.0,15.0,34.5,-9.0
|
||||||
|
12.0,60.0,28.0,44.0,100.53096491487338,1.0,16.0,36.0,-9.6
|
||||||
|
13.0,16.0,14.0,15.0,6.283185307179586,1.0,1.0,14.5,-0.6
|
||||||
|
13.0,19.0,15.0,17.0,12.566370614359172,1.0,2.0,16.0,-1.2
|
||||||
|
13.0,22.0,16.0,19.0,18.84955592153876,1.0,3.0,17.5,-1.8
|
||||||
|
13.0,25.0,17.0,21.0,25.132741228718345,1.0,4.0,19.0,-2.4
|
||||||
|
13.0,28.0,18.0,23.0,31.41592653589793,1.0,5.0,20.5,-3.0
|
||||||
|
13.0,31.0,19.0,25.0,37.69911184307752,1.0,6.0,22.0,-3.6
|
||||||
|
13.0,34.0,20.0,27.0,43.982297150257104,1.0,7.0,23.5,-4.2
|
||||||
|
13.0,37.0,21.0,29.0,50.26548245743669,1.0,8.0,25.0,-4.8
|
||||||
|
13.0,40.0,22.0,31.0,56.548667764616276,1.0,9.0,26.5,-5.4
|
||||||
|
13.0,43.0,23.0,33.0,62.83185307179586,1.0,10.0,28.0,-6.0
|
||||||
|
13.0,46.0,24.0,35.0,69.11503837897544,1.0,11.0,29.5,-6.6
|
||||||
|
13.0,49.0,25.0,37.0,75.39822368615503,1.0,12.0,31.0,-7.2
|
||||||
|
13.0,52.0,26.0,39.0,81.68140899333461,1.0,13.0,32.5,-7.8
|
||||||
|
13.0,55.0,27.0,41.0,87.96459430051421,1.0,14.0,34.0,-8.4
|
||||||
|
13.0,58.0,28.0,43.0,94.2477796076938,1.0,15.0,35.5,-9.0
|
||||||
|
14.0,17.0,15.0,16.0,6.283185307179586,1.0,1.0,15.5,-0.6
|
||||||
|
14.0,20.0,16.0,18.0,12.566370614359172,1.0,2.0,17.0,-1.2
|
||||||
|
14.0,23.0,17.0,20.0,18.84955592153876,1.0,3.0,18.5,-1.8
|
||||||
|
14.0,26.0,18.0,22.0,25.132741228718345,1.0,4.0,20.0,-2.4
|
||||||
|
14.0,29.0,19.0,24.0,31.41592653589793,1.0,5.0,21.5,-3.0
|
||||||
|
14.0,32.0,20.0,26.0,37.69911184307752,1.0,6.0,23.0,-3.6
|
||||||
|
14.0,35.0,21.0,28.0,43.982297150257104,1.0,7.0,24.5,-4.2
|
||||||
|
14.0,38.0,22.0,30.0,50.26548245743669,1.0,8.0,26.0,-4.8
|
||||||
|
14.0,41.0,23.0,32.0,56.548667764616276,1.0,9.0,27.5,-5.4
|
||||||
|
14.0,44.0,24.0,34.0,62.83185307179586,1.0,10.0,29.0,-6.0
|
||||||
|
14.0,47.0,25.0,36.0,69.11503837897544,1.0,11.0,30.5,-6.6
|
||||||
|
14.0,50.0,26.0,38.0,75.39822368615503,1.0,12.0,32.0,-7.2
|
||||||
|
14.0,53.0,27.0,40.0,81.68140899333461,1.0,13.0,33.5,-7.8
|
||||||
|
14.0,56.0,28.0,42.0,87.96459430051421,1.0,14.0,35.0,-8.4
|
||||||
|
14.0,59.0,29.0,44.0,94.2477796076938,1.0,15.0,36.5,-9.0
|
||||||
|
15.0,18.0,16.0,17.0,6.283185307179586,1.0,1.0,16.5,-0.6
|
||||||
|
15.0,21.0,17.0,19.0,12.566370614359172,1.0,2.0,18.0,-1.2
|
||||||
|
15.0,24.0,18.0,21.0,18.84955592153876,1.0,3.0,19.5,-1.8
|
||||||
|
15.0,27.0,19.0,23.0,25.132741228718345,1.0,4.0,21.0,-2.4
|
||||||
|
15.0,30.0,20.0,25.0,31.41592653589793,1.0,5.0,22.5,-3.0
|
||||||
|
15.0,33.0,21.0,27.0,37.69911184307752,1.0,6.0,24.0,-3.6
|
||||||
|
15.0,36.0,22.0,29.0,43.982297150257104,1.0,7.0,25.5,-4.2
|
||||||
|
15.0,39.0,23.0,31.0,50.26548245743669,1.0,8.0,27.0,-4.8
|
||||||
|
15.0,42.0,24.0,33.0,56.548667764616276,1.0,9.0,28.5,-5.4
|
||||||
|
15.0,45.0,25.0,35.0,62.83185307179586,1.0,10.0,30.0,-6.0
|
||||||
|
15.0,48.0,26.0,37.0,69.11503837897544,1.0,11.0,31.5,-6.6
|
||||||
|
15.0,51.0,27.0,39.0,75.39822368615503,1.0,12.0,33.0,-7.2
|
||||||
|
15.0,54.0,28.0,41.0,81.68140899333461,1.0,13.0,34.5,-7.8
|
||||||
|
15.0,57.0,29.0,43.0,87.96459430051421,1.0,14.0,36.0,-8.4
|
||||||
|
15.0,60.0,30.0,45.0,94.2477796076938,1.0,15.0,37.5,-9.0
|
||||||
|
16.0,19.0,17.0,18.0,6.283185307179586,1.0,1.0,17.5,-0.6
|
||||||
|
16.0,22.0,18.0,20.0,12.566370614359172,1.0,2.0,19.0,-1.2
|
||||||
|
16.0,25.0,19.0,22.0,18.84955592153876,1.0,3.0,20.5,-1.8
|
||||||
|
16.0,28.0,20.0,24.0,25.132741228718345,1.0,4.0,22.0,-2.4
|
||||||
|
16.0,31.0,21.0,26.0,31.41592653589793,1.0,5.0,23.5,-3.0
|
||||||
|
16.0,34.0,22.0,28.0,37.69911184307752,1.0,6.0,25.0,-3.6
|
||||||
|
16.0,37.0,23.0,30.0,43.982297150257104,1.0,7.0,26.5,-4.2
|
||||||
|
16.0,40.0,24.0,32.0,50.26548245743669,1.0,8.0,28.0,-4.8
|
||||||
|
16.0,43.0,25.0,34.0,56.548667764616276,1.0,9.0,29.5,-5.4
|
||||||
|
16.0,46.0,26.0,36.0,62.83185307179586,1.0,10.0,31.0,-6.0
|
||||||
|
16.0,49.0,27.0,38.0,69.11503837897544,1.0,11.0,32.5,-6.6
|
||||||
|
16.0,52.0,28.0,40.0,75.39822368615503,1.0,12.0,34.0,-7.2
|
||||||
|
16.0,55.0,29.0,42.0,81.68140899333461,1.0,13.0,35.5,-7.8
|
||||||
|
16.0,58.0,30.0,44.0,87.96459430051421,1.0,14.0,37.0,-8.4
|
||||||
|
17.0,20.0,18.0,19.0,6.283185307179586,1.0,1.0,18.5,-0.6
|
||||||
|
17.0,23.0,19.0,21.0,12.566370614359172,1.0,2.0,20.0,-1.2
|
||||||
|
17.0,26.0,20.0,23.0,18.84955592153876,1.0,3.0,21.5,-1.8
|
||||||
|
17.0,29.0,21.0,25.0,25.132741228718345,1.0,4.0,23.0,-2.4
|
||||||
|
17.0,32.0,22.0,27.0,31.41592653589793,1.0,5.0,24.5,-3.0
|
||||||
|
17.0,35.0,23.0,29.0,37.69911184307752,1.0,6.0,26.0,-3.6
|
||||||
|
17.0,38.0,24.0,31.0,43.982297150257104,1.0,7.0,27.5,-4.2
|
||||||
|
17.0,41.0,25.0,33.0,50.26548245743669,1.0,8.0,29.0,-4.8
|
||||||
|
17.0,44.0,26.0,35.0,56.548667764616276,1.0,9.0,30.5,-5.4
|
||||||
|
17.0,47.0,27.0,37.0,62.83185307179586,1.0,10.0,32.0,-6.0
|
||||||
|
17.0,50.0,28.0,39.0,69.11503837897544,1.0,11.0,33.5,-6.6
|
||||||
|
17.0,53.0,29.0,41.0,75.39822368615503,1.0,12.0,35.0,-7.2
|
||||||
|
17.0,56.0,30.0,43.0,81.68140899333461,1.0,13.0,36.5,-7.8
|
||||||
|
17.0,59.0,31.0,45.0,87.96459430051421,1.0,14.0,38.0,-8.4
|
||||||
|
18.0,21.0,19.0,20.0,6.283185307179586,1.0,1.0,19.5,-0.6
|
||||||
|
18.0,24.0,20.0,22.0,12.566370614359172,1.0,2.0,21.0,-1.2
|
||||||
|
18.0,27.0,21.0,24.0,18.84955592153876,1.0,3.0,22.5,-1.8
|
||||||
|
18.0,30.0,22.0,26.0,25.132741228718345,1.0,4.0,24.0,-2.4
|
||||||
|
18.0,33.0,23.0,28.0,31.41592653589793,1.0,5.0,25.5,-3.0
|
||||||
|
18.0,36.0,24.0,30.0,37.69911184307752,1.0,6.0,27.0,-3.6
|
||||||
|
18.0,39.0,25.0,32.0,43.982297150257104,1.0,7.0,28.5,-4.2
|
||||||
|
18.0,42.0,26.0,34.0,50.26548245743669,1.0,8.0,30.0,-4.8
|
||||||
|
18.0,45.0,27.0,36.0,56.548667764616276,1.0,9.0,31.5,-5.4
|
||||||
|
18.0,48.0,28.0,38.0,62.83185307179586,1.0,10.0,33.0,-6.0
|
||||||
|
18.0,51.0,29.0,40.0,69.11503837897544,1.0,11.0,34.5,-6.6
|
||||||
|
18.0,54.0,30.0,42.0,75.39822368615503,1.0,12.0,36.0,-7.2
|
||||||
|
18.0,57.0,31.0,44.0,81.68140899333461,1.0,13.0,37.5,-7.8
|
||||||
|
18.0,60.0,32.0,46.0,87.96459430051421,1.0,14.0,39.0,-8.4
|
||||||
|
19.0,22.0,20.0,21.0,6.283185307179586,1.0,1.0,20.5,-0.6
|
||||||
|
19.0,25.0,21.0,23.0,12.566370614359172,1.0,2.0,22.0,-1.2
|
||||||
|
19.0,28.0,22.0,25.0,18.84955592153876,1.0,3.0,23.5,-1.8
|
||||||
|
19.0,31.0,23.0,27.0,25.132741228718345,1.0,4.0,25.0,-2.4
|
||||||
|
19.0,34.0,24.0,29.0,31.41592653589793,1.0,5.0,26.5,-3.0
|
||||||
|
19.0,37.0,25.0,31.0,37.69911184307752,1.0,6.0,28.0,-3.6
|
||||||
|
19.0,40.0,26.0,33.0,43.982297150257104,1.0,7.0,29.5,-4.2
|
||||||
|
19.0,43.0,27.0,35.0,50.26548245743669,1.0,8.0,31.0,-4.8
|
||||||
|
19.0,46.0,28.0,37.0,56.548667764616276,1.0,9.0,32.5,-5.4
|
||||||
|
19.0,49.0,29.0,39.0,62.83185307179586,1.0,10.0,34.0,-6.0
|
||||||
|
19.0,52.0,30.0,41.0,69.11503837897544,1.0,11.0,35.5,-6.6
|
||||||
|
19.0,55.0,31.0,43.0,75.39822368615503,1.0,12.0,37.0,-7.2
|
||||||
|
19.0,58.0,32.0,45.0,81.68140899333461,1.0,13.0,38.5,-7.8
|
||||||
|
20.0,23.0,21.0,22.0,6.283185307179586,1.0,1.0,21.5,-0.6
|
||||||
|
20.0,26.0,22.0,24.0,12.566370614359172,1.0,2.0,23.0,-1.2
|
||||||
|
20.0,29.0,23.0,26.0,18.84955592153876,1.0,3.0,24.5,-1.8
|
||||||
|
20.0,32.0,24.0,28.0,25.132741228718345,1.0,4.0,26.0,-2.4
|
||||||
|
20.0,35.0,25.0,30.0,31.41592653589793,1.0,5.0,27.5,-3.0
|
||||||
|
20.0,38.0,26.0,32.0,37.69911184307752,1.0,6.0,29.0,-3.6
|
||||||
|
20.0,41.0,27.0,34.0,43.982297150257104,1.0,7.0,30.5,-4.2
|
||||||
|
20.0,44.0,28.0,36.0,50.26548245743669,1.0,8.0,32.0,-4.8
|
||||||
|
20.0,47.0,29.0,38.0,56.548667764616276,1.0,9.0,33.5,-5.4
|
||||||
|
20.0,50.0,30.0,40.0,62.83185307179586,1.0,10.0,35.0,-6.0
|
||||||
|
20.0,53.0,31.0,42.0,69.11503837897544,1.0,11.0,36.5,-6.6
|
||||||
|
20.0,56.0,32.0,44.0,75.39822368615503,1.0,12.0,38.0,-7.2
|
||||||
|
20.0,59.0,33.0,46.0,81.68140899333461,1.0,13.0,39.5,-7.8
|
||||||
|
21.0,24.0,22.0,23.0,6.283185307179586,1.0,1.0,22.5,-0.6
|
||||||
|
21.0,27.0,23.0,25.0,12.566370614359172,1.0,2.0,24.0,-1.2
|
||||||
|
21.0,30.0,24.0,27.0,18.84955592153876,1.0,3.0,25.5,-1.8
|
||||||
|
21.0,33.0,25.0,29.0,25.132741228718345,1.0,4.0,27.0,-2.4
|
||||||
|
21.0,36.0,26.0,31.0,31.41592653589793,1.0,5.0,28.5,-3.0
|
||||||
|
21.0,39.0,27.0,33.0,37.69911184307752,1.0,6.0,30.0,-3.6
|
||||||
|
21.0,42.0,28.0,35.0,43.982297150257104,1.0,7.0,31.5,-4.2
|
||||||
|
21.0,45.0,29.0,37.0,50.26548245743669,1.0,8.0,33.0,-4.8
|
||||||
|
21.0,48.0,30.0,39.0,56.548667764616276,1.0,9.0,34.5,-5.4
|
||||||
|
21.0,51.0,31.0,41.0,62.83185307179586,1.0,10.0,36.0,-6.0
|
||||||
|
21.0,54.0,32.0,43.0,69.11503837897544,1.0,11.0,37.5,-6.6
|
||||||
|
21.0,57.0,33.0,45.0,75.39822368615503,1.0,12.0,39.0,-7.2
|
||||||
|
21.0,60.0,34.0,47.0,81.68140899333461,1.0,13.0,40.5,-7.8
|
||||||
|
22.0,25.0,23.0,24.0,6.283185307179586,1.0,1.0,23.5,-0.6
|
||||||
|
22.0,28.0,24.0,26.0,12.566370614359172,1.0,2.0,25.0,-1.2
|
||||||
|
22.0,31.0,25.0,28.0,18.84955592153876,1.0,3.0,26.5,-1.8
|
||||||
|
22.0,34.0,26.0,30.0,25.132741228718345,1.0,4.0,28.0,-2.4
|
||||||
|
22.0,37.0,27.0,32.0,31.41592653589793,1.0,5.0,29.5,-3.0
|
||||||
|
22.0,40.0,28.0,34.0,37.69911184307752,1.0,6.0,31.0,-3.6
|
||||||
|
22.0,43.0,29.0,36.0,43.982297150257104,1.0,7.0,32.5,-4.2
|
||||||
|
22.0,46.0,30.0,38.0,50.26548245743669,1.0,8.0,34.0,-4.8
|
||||||
|
22.0,49.0,31.0,40.0,56.548667764616276,1.0,9.0,35.5,-5.4
|
||||||
|
22.0,52.0,32.0,42.0,62.83185307179586,1.0,10.0,37.0,-6.0
|
||||||
|
22.0,55.0,33.0,44.0,69.11503837897544,1.0,11.0,38.5,-6.6
|
||||||
|
22.0,58.0,34.0,46.0,75.39822368615503,1.0,12.0,40.0,-7.2
|
||||||
|
23.0,26.0,24.0,25.0,6.283185307179586,1.0,1.0,24.5,-0.6
|
||||||
|
23.0,29.0,25.0,27.0,12.566370614359172,1.0,2.0,26.0,-1.2
|
||||||
|
23.0,32.0,26.0,29.0,18.84955592153876,1.0,3.0,27.5,-1.8
|
||||||
|
23.0,35.0,27.0,31.0,25.132741228718345,1.0,4.0,29.0,-2.4
|
||||||
|
23.0,38.0,28.0,33.0,31.41592653589793,1.0,5.0,30.5,-3.0
|
||||||
|
23.0,41.0,29.0,35.0,37.69911184307752,1.0,6.0,32.0,-3.6
|
||||||
|
23.0,44.0,30.0,37.0,43.982297150257104,1.0,7.0,33.5,-4.2
|
||||||
|
23.0,47.0,31.0,39.0,50.26548245743669,1.0,8.0,35.0,-4.8
|
||||||
|
23.0,50.0,32.0,41.0,56.548667764616276,1.0,9.0,36.5,-5.4
|
||||||
|
23.0,53.0,33.0,43.0,62.83185307179586,1.0,10.0,38.0,-6.0
|
||||||
|
23.0,56.0,34.0,45.0,69.11503837897544,1.0,11.0,39.5,-6.6
|
||||||
|
23.0,59.0,35.0,47.0,75.39822368615503,1.0,12.0,41.0,-7.2
|
||||||
|
24.0,27.0,25.0,26.0,6.283185307179586,1.0,1.0,25.5,-0.6
|
||||||
|
24.0,30.0,26.0,28.0,12.566370614359172,1.0,2.0,27.0,-1.2
|
||||||
|
24.0,33.0,27.0,30.0,18.84955592153876,1.0,3.0,28.5,-1.8
|
||||||
|
24.0,36.0,28.0,32.0,25.132741228718345,1.0,4.0,30.0,-2.4
|
||||||
|
24.0,39.0,29.0,34.0,31.41592653589793,1.0,5.0,31.5,-3.0
|
||||||
|
24.0,42.0,30.0,36.0,37.69911184307752,1.0,6.0,33.0,-3.6
|
||||||
|
24.0,45.0,31.0,38.0,43.982297150257104,1.0,7.0,34.5,-4.2
|
||||||
|
24.0,48.0,32.0,40.0,50.26548245743669,1.0,8.0,36.0,-4.8
|
||||||
|
24.0,51.0,33.0,42.0,56.548667764616276,1.0,9.0,37.5,-5.4
|
||||||
|
24.0,54.0,34.0,44.0,62.83185307179586,1.0,10.0,39.0,-6.0
|
||||||
|
24.0,57.0,35.0,46.0,69.11503837897544,1.0,11.0,40.5,-6.6
|
||||||
|
24.0,60.0,36.0,48.0,75.39822368615503,1.0,12.0,42.0,-7.2
|
||||||
|
25.0,28.0,26.0,27.0,6.283185307179586,1.0,1.0,26.5,-0.6
|
||||||
|
25.0,31.0,27.0,29.0,12.566370614359172,1.0,2.0,28.0,-1.2
|
||||||
|
25.0,34.0,28.0,31.0,18.84955592153876,1.0,3.0,29.5,-1.8
|
||||||
|
25.0,37.0,29.0,33.0,25.132741228718345,1.0,4.0,31.0,-2.4
|
||||||
|
25.0,40.0,30.0,35.0,31.41592653589793,1.0,5.0,32.5,-3.0
|
||||||
|
25.0,43.0,31.0,37.0,37.69911184307752,1.0,6.0,34.0,-3.6
|
||||||
|
25.0,46.0,32.0,39.0,43.982297150257104,1.0,7.0,35.5,-4.2
|
||||||
|
25.0,49.0,33.0,41.0,50.26548245743669,1.0,8.0,37.0,-4.8
|
||||||
|
25.0,52.0,34.0,43.0,56.548667764616276,1.0,9.0,38.5,-5.4
|
||||||
|
25.0,55.0,35.0,45.0,62.83185307179586,1.0,10.0,40.0,-6.0
|
||||||
|
25.0,58.0,36.0,47.0,69.11503837897544,1.0,11.0,41.5,-6.6
|
||||||
|
26.0,29.0,27.0,28.0,6.283185307179586,1.0,1.0,27.5,-0.6
|
||||||
|
26.0,32.0,28.0,30.0,12.566370614359172,1.0,2.0,29.0,-1.2
|
||||||
|
26.0,35.0,29.0,32.0,18.84955592153876,1.0,3.0,30.5,-1.8
|
||||||
|
26.0,38.0,30.0,34.0,25.132741228718345,1.0,4.0,32.0,-2.4
|
||||||
|
26.0,41.0,31.0,36.0,31.41592653589793,1.0,5.0,33.5,-3.0
|
||||||
|
26.0,44.0,32.0,38.0,37.69911184307752,1.0,6.0,35.0,-3.6
|
||||||
|
26.0,47.0,33.0,40.0,43.982297150257104,1.0,7.0,36.5,-4.2
|
||||||
|
26.0,50.0,34.0,42.0,50.26548245743669,1.0,8.0,38.0,-4.8
|
||||||
|
26.0,53.0,35.0,44.0,56.548667764616276,1.0,9.0,39.5,-5.4
|
||||||
|
26.0,56.0,36.0,46.0,62.83185307179586,1.0,10.0,41.0,-6.0
|
||||||
|
26.0,59.0,37.0,48.0,69.11503837897544,1.0,11.0,42.5,-6.6
|
||||||
|
27.0,30.0,28.0,29.0,6.283185307179586,1.0,1.0,28.5,-0.6
|
||||||
|
27.0,33.0,29.0,31.0,12.566370614359172,1.0,2.0,30.0,-1.2
|
||||||
|
27.0,36.0,30.0,33.0,18.84955592153876,1.0,3.0,31.5,-1.8
|
||||||
|
27.0,39.0,31.0,35.0,25.132741228718345,1.0,4.0,33.0,-2.4
|
||||||
|
27.0,42.0,32.0,37.0,31.41592653589793,1.0,5.0,34.5,-3.0
|
||||||
|
27.0,45.0,33.0,39.0,37.69911184307752,1.0,6.0,36.0,-3.6
|
||||||
|
27.0,48.0,34.0,41.0,43.982297150257104,1.0,7.0,37.5,-4.2
|
||||||
|
27.0,51.0,35.0,43.0,50.26548245743669,1.0,8.0,39.0,-4.8
|
||||||
|
27.0,54.0,36.0,45.0,56.548667764616276,1.0,9.0,40.5,-5.4
|
||||||
|
27.0,57.0,37.0,47.0,62.83185307179586,1.0,10.0,42.0,-6.0
|
||||||
|
27.0,60.0,38.0,49.0,69.11503837897544,1.0,11.0,43.5,-6.6
|
||||||
|
28.0,31.0,29.0,30.0,6.283185307179586,1.0,1.0,29.5,-0.6
|
||||||
|
28.0,34.0,30.0,32.0,12.566370614359172,1.0,2.0,31.0,-1.2
|
||||||
|
28.0,37.0,31.0,34.0,18.84955592153876,1.0,3.0,32.5,-1.8
|
||||||
|
28.0,40.0,32.0,36.0,25.132741228718345,1.0,4.0,34.0,-2.4
|
||||||
|
28.0,43.0,33.0,38.0,31.41592653589793,1.0,5.0,35.5,-3.0
|
||||||
|
28.0,46.0,34.0,40.0,37.69911184307752,1.0,6.0,37.0,-3.6
|
||||||
|
28.0,49.0,35.0,42.0,43.982297150257104,1.0,7.0,38.5,-4.2
|
||||||
|
28.0,52.0,36.0,44.0,50.26548245743669,1.0,8.0,40.0,-4.8
|
||||||
|
28.0,55.0,37.0,46.0,56.548667764616276,1.0,9.0,41.5,-5.4
|
||||||
|
28.0,58.0,38.0,48.0,62.83185307179586,1.0,10.0,43.0,-6.0
|
||||||
|
29.0,32.0,30.0,31.0,6.283185307179586,1.0,1.0,30.5,-0.6
|
||||||
|
29.0,35.0,31.0,33.0,12.566370614359172,1.0,2.0,32.0,-1.2
|
||||||
|
29.0,38.0,32.0,35.0,18.84955592153876,1.0,3.0,33.5,-1.8
|
||||||
|
29.0,41.0,33.0,37.0,25.132741228718345,1.0,4.0,35.0,-2.4
|
||||||
|
29.0,44.0,34.0,39.0,31.41592653589793,1.0,5.0,36.5,-3.0
|
||||||
|
29.0,47.0,35.0,41.0,37.69911184307752,1.0,6.0,38.0,-3.6
|
||||||
|
29.0,50.0,36.0,43.0,43.982297150257104,1.0,7.0,39.5,-4.2
|
||||||
|
29.0,53.0,37.0,45.0,50.26548245743669,1.0,8.0,41.0,-4.8
|
||||||
|
29.0,56.0,38.0,47.0,56.548667764616276,1.0,9.0,42.5,-5.4
|
||||||
|
29.0,59.0,39.0,49.0,62.83185307179586,1.0,10.0,44.0,-6.0
|
||||||
|
30.0,33.0,31.0,32.0,6.283185307179586,1.0,1.0,31.5,-0.6
|
||||||
|
30.0,36.0,32.0,34.0,12.566370614359172,1.0,2.0,33.0,-1.2
|
||||||
|
30.0,39.0,33.0,36.0,18.84955592153876,1.0,3.0,34.5,-1.8
|
||||||
|
30.0,42.0,34.0,38.0,25.132741228718345,1.0,4.0,36.0,-2.4
|
||||||
|
30.0,45.0,35.0,40.0,31.41592653589793,1.0,5.0,37.5,-3.0
|
||||||
|
30.0,48.0,36.0,42.0,37.69911184307752,1.0,6.0,39.0,-3.6
|
||||||
|
30.0,51.0,37.0,44.0,43.982297150257104,1.0,7.0,40.5,-4.2
|
||||||
|
30.0,54.0,38.0,46.0,50.26548245743669,1.0,8.0,42.0,-4.8
|
||||||
|
30.0,57.0,39.0,48.0,56.548667764616276,1.0,9.0,43.5,-5.4
|
||||||
|
30.0,60.0,40.0,50.0,62.83185307179586,1.0,10.0,45.0,-6.0
|
||||||
|
31.0,34.0,32.0,33.0,6.283185307179586,1.0,1.0,32.5,-0.6
|
||||||
|
31.0,37.0,33.0,35.0,12.566370614359172,1.0,2.0,34.0,-1.2
|
||||||
|
31.0,40.0,34.0,37.0,18.84955592153876,1.0,3.0,35.5,-1.8
|
||||||
|
31.0,43.0,35.0,39.0,25.132741228718345,1.0,4.0,37.0,-2.4
|
||||||
|
31.0,46.0,36.0,41.0,31.41592653589793,1.0,5.0,38.5,-3.0
|
||||||
|
31.0,49.0,37.0,43.0,37.69911184307752,1.0,6.0,40.0,-3.6
|
||||||
|
31.0,52.0,38.0,45.0,43.982297150257104,1.0,7.0,41.5,-4.2
|
||||||
|
31.0,55.0,39.0,47.0,50.26548245743669,1.0,8.0,43.0,-4.8
|
||||||
|
31.0,58.0,40.0,49.0,56.548667764616276,1.0,9.0,44.5,-5.4
|
||||||
|
32.0,35.0,33.0,34.0,6.283185307179586,1.0,1.0,33.5,-0.6
|
||||||
|
32.0,38.0,34.0,36.0,12.566370614359172,1.0,2.0,35.0,-1.2
|
||||||
|
32.0,41.0,35.0,38.0,18.84955592153876,1.0,3.0,36.5,-1.8
|
||||||
|
32.0,44.0,36.0,40.0,25.132741228718345,1.0,4.0,38.0,-2.4
|
||||||
|
32.0,47.0,37.0,42.0,31.41592653589793,1.0,5.0,39.5,-3.0
|
||||||
|
32.0,50.0,38.0,44.0,37.69911184307752,1.0,6.0,41.0,-3.6
|
||||||
|
32.0,53.0,39.0,46.0,43.982297150257104,1.0,7.0,42.5,-4.2
|
||||||
|
32.0,56.0,40.0,48.0,50.26548245743669,1.0,8.0,44.0,-4.8
|
||||||
|
32.0,59.0,41.0,50.0,56.548667764616276,1.0,9.0,45.5,-5.4
|
||||||
|
33.0,36.0,34.0,35.0,6.283185307179586,1.0,1.0,34.5,-0.6
|
||||||
|
33.0,39.0,35.0,37.0,12.566370614359172,1.0,2.0,36.0,-1.2
|
||||||
|
33.0,42.0,36.0,39.0,18.84955592153876,1.0,3.0,37.5,-1.8
|
||||||
|
33.0,45.0,37.0,41.0,25.132741228718345,1.0,4.0,39.0,-2.4
|
||||||
|
33.0,48.0,38.0,43.0,31.41592653589793,1.0,5.0,40.5,-3.0
|
||||||
|
33.0,51.0,39.0,45.0,37.69911184307752,1.0,6.0,42.0,-3.6
|
||||||
|
33.0,54.0,40.0,47.0,43.982297150257104,1.0,7.0,43.5,-4.2
|
||||||
|
33.0,57.0,41.0,49.0,50.26548245743669,1.0,8.0,45.0,-4.8
|
||||||
|
33.0,60.0,42.0,51.0,56.548667764616276,1.0,9.0,46.5,-5.4
|
||||||
|
34.0,37.0,35.0,36.0,6.283185307179586,1.0,1.0,35.5,-0.6
|
||||||
|
34.0,40.0,36.0,38.0,12.566370614359172,1.0,2.0,37.0,-1.2
|
||||||
|
34.0,43.0,37.0,40.0,18.84955592153876,1.0,3.0,38.5,-1.8
|
||||||
|
34.0,46.0,38.0,42.0,25.132741228718345,1.0,4.0,40.0,-2.4
|
||||||
|
34.0,49.0,39.0,44.0,31.41592653589793,1.0,5.0,41.5,-3.0
|
||||||
|
34.0,52.0,40.0,46.0,37.69911184307752,1.0,6.0,43.0,-3.6
|
||||||
|
34.0,55.0,41.0,48.0,43.982297150257104,1.0,7.0,44.5,-4.2
|
||||||
|
34.0,58.0,42.0,50.0,50.26548245743669,1.0,8.0,46.0,-4.8
|
||||||
|
35.0,38.0,36.0,37.0,6.283185307179586,1.0,1.0,36.5,-0.6
|
||||||
|
35.0,41.0,37.0,39.0,12.566370614359172,1.0,2.0,38.0,-1.2
|
||||||
|
35.0,44.0,38.0,41.0,18.84955592153876,1.0,3.0,39.5,-1.8
|
||||||
|
35.0,47.0,39.0,43.0,25.132741228718345,1.0,4.0,41.0,-2.4
|
||||||
|
35.0,50.0,40.0,45.0,31.41592653589793,1.0,5.0,42.5,-3.0
|
||||||
|
35.0,53.0,41.0,47.0,37.69911184307752,1.0,6.0,44.0,-3.6
|
||||||
|
35.0,56.0,42.0,49.0,43.982297150257104,1.0,7.0,45.5,-4.2
|
||||||
|
35.0,59.0,43.0,51.0,50.26548245743669,1.0,8.0,47.0,-4.8
|
||||||
|
36.0,39.0,37.0,38.0,6.283185307179586,1.0,1.0,37.5,-0.6
|
||||||
|
36.0,42.0,38.0,40.0,12.566370614359172,1.0,2.0,39.0,-1.2
|
||||||
|
36.0,45.0,39.0,42.0,18.84955592153876,1.0,3.0,40.5,-1.8
|
||||||
|
36.0,48.0,40.0,44.0,25.132741228718345,1.0,4.0,42.0,-2.4
|
||||||
|
36.0,51.0,41.0,46.0,31.41592653589793,1.0,5.0,43.5,-3.0
|
||||||
|
36.0,54.0,42.0,48.0,37.69911184307752,1.0,6.0,45.0,-3.6
|
||||||
|
36.0,57.0,43.0,50.0,43.982297150257104,1.0,7.0,46.5,-4.2
|
||||||
|
36.0,60.0,44.0,52.0,50.26548245743669,1.0,8.0,48.0,-4.8
|
||||||
|
37.0,40.0,38.0,39.0,6.283185307179586,1.0,1.0,38.5,-0.6
|
||||||
|
37.0,43.0,39.0,41.0,12.566370614359172,1.0,2.0,40.0,-1.2
|
||||||
|
37.0,46.0,40.0,43.0,18.84955592153876,1.0,3.0,41.5,-1.8
|
||||||
|
37.0,49.0,41.0,45.0,25.132741228718345,1.0,4.0,43.0,-2.4
|
||||||
|
37.0,52.0,42.0,47.0,31.41592653589793,1.0,5.0,44.5,-3.0
|
||||||
|
37.0,55.0,43.0,49.0,37.69911184307752,1.0,6.0,46.0,-3.6
|
||||||
|
37.0,58.0,44.0,51.0,43.982297150257104,1.0,7.0,47.5,-4.2
|
||||||
|
38.0,41.0,39.0,40.0,6.283185307179586,1.0,1.0,39.5,-0.6
|
||||||
|
38.0,44.0,40.0,42.0,12.566370614359172,1.0,2.0,41.0,-1.2
|
||||||
|
38.0,47.0,41.0,44.0,18.84955592153876,1.0,3.0,42.5,-1.8
|
||||||
|
38.0,50.0,42.0,46.0,25.132741228718345,1.0,4.0,44.0,-2.4
|
||||||
|
38.0,53.0,43.0,48.0,31.41592653589793,1.0,5.0,45.5,-3.0
|
||||||
|
38.0,56.0,44.0,50.0,37.69911184307752,1.0,6.0,47.0,-3.6
|
||||||
|
38.0,59.0,45.0,52.0,43.982297150257104,1.0,7.0,48.5,-4.2
|
||||||
|
39.0,42.0,40.0,41.0,6.283185307179586,1.0,1.0,40.5,-0.6
|
||||||
|
39.0,45.0,41.0,43.0,12.566370614359172,1.0,2.0,42.0,-1.2
|
||||||
|
39.0,48.0,42.0,45.0,18.84955592153876,1.0,3.0,43.5,-1.8
|
||||||
|
39.0,51.0,43.0,47.0,25.132741228718345,1.0,4.0,45.0,-2.4
|
||||||
|
39.0,54.0,44.0,49.0,31.41592653589793,1.0,5.0,46.5,-3.0
|
||||||
|
39.0,57.0,45.0,51.0,37.69911184307752,1.0,6.0,48.0,-3.6
|
||||||
|
39.0,60.0,46.0,53.0,43.982297150257104,1.0,7.0,49.5,-4.2
|
||||||
|
40.0,43.0,41.0,42.0,6.283185307179586,1.0,1.0,41.5,-0.6
|
||||||
|
40.0,46.0,42.0,44.0,12.566370614359172,1.0,2.0,43.0,-1.2
|
||||||
|
40.0,49.0,43.0,46.0,18.84955592153876,1.0,3.0,44.5,-1.8
|
||||||
|
40.0,52.0,44.0,48.0,25.132741228718345,1.0,4.0,46.0,-2.4
|
||||||
|
40.0,55.0,45.0,50.0,31.41592653589793,1.0,5.0,47.5,-3.0
|
||||||
|
40.0,58.0,46.0,52.0,37.69911184307752,1.0,6.0,49.0,-3.6
|
||||||
|
41.0,44.0,42.0,43.0,6.283185307179586,1.0,1.0,42.5,-0.6
|
||||||
|
41.0,47.0,43.0,45.0,12.566370614359172,1.0,2.0,44.0,-1.2
|
||||||
|
41.0,50.0,44.0,47.0,18.84955592153876,1.0,3.0,45.5,-1.8
|
||||||
|
41.0,53.0,45.0,49.0,25.132741228718345,1.0,4.0,47.0,-2.4
|
||||||
|
41.0,56.0,46.0,51.0,31.41592653589793,1.0,5.0,48.5,-3.0
|
||||||
|
41.0,59.0,47.0,53.0,37.69911184307752,1.0,6.0,50.0,-3.6
|
||||||
|
42.0,45.0,43.0,44.0,6.283185307179586,1.0,1.0,43.5,-0.6
|
||||||
|
42.0,48.0,44.0,46.0,12.566370614359172,1.0,2.0,45.0,-1.2
|
||||||
|
42.0,51.0,45.0,48.0,18.84955592153876,1.0,3.0,46.5,-1.8
|
||||||
|
42.0,54.0,46.0,50.0,25.132741228718345,1.0,4.0,48.0,-2.4
|
||||||
|
42.0,57.0,47.0,52.0,31.41592653589793,1.0,5.0,49.5,-3.0
|
||||||
|
42.0,60.0,48.0,54.0,37.69911184307752,1.0,6.0,51.0,-3.6
|
||||||
|
43.0,46.0,44.0,45.0,6.283185307179586,1.0,1.0,44.5,-0.6
|
||||||
|
43.0,49.0,45.0,47.0,12.566370614359172,1.0,2.0,46.0,-1.2
|
||||||
|
43.0,52.0,46.0,49.0,18.84955592153876,1.0,3.0,47.5,-1.8
|
||||||
|
43.0,55.0,47.0,51.0,25.132741228718345,1.0,4.0,49.0,-2.4
|
||||||
|
43.0,58.0,48.0,53.0,31.41592653589793,1.0,5.0,50.5,-3.0
|
||||||
|
44.0,47.0,45.0,46.0,6.283185307179586,1.0,1.0,45.5,-0.6
|
||||||
|
44.0,50.0,46.0,48.0,12.566370614359172,1.0,2.0,47.0,-1.2
|
||||||
|
44.0,53.0,47.0,50.0,18.84955592153876,1.0,3.0,48.5,-1.8
|
||||||
|
44.0,56.0,48.0,52.0,25.132741228718345,1.0,4.0,50.0,-2.4
|
||||||
|
44.0,59.0,49.0,54.0,31.41592653589793,1.0,5.0,51.5,-3.0
|
||||||
|
45.0,48.0,46.0,47.0,6.283185307179586,1.0,1.0,46.5,-0.6
|
||||||
|
45.0,51.0,47.0,49.0,12.566370614359172,1.0,2.0,48.0,-1.2
|
||||||
|
45.0,54.0,48.0,51.0,18.84955592153876,1.0,3.0,49.5,-1.8
|
||||||
|
45.0,57.0,49.0,53.0,25.132741228718345,1.0,4.0,51.0,-2.4
|
||||||
|
45.0,60.0,50.0,55.0,31.41592653589793,1.0,5.0,52.5,-3.0
|
||||||
|
46.0,49.0,47.0,48.0,6.283185307179586,1.0,1.0,47.5,-0.6
|
||||||
|
46.0,52.0,48.0,50.0,12.566370614359172,1.0,2.0,49.0,-1.2
|
||||||
|
46.0,55.0,49.0,52.0,18.84955592153876,1.0,3.0,50.5,-1.8
|
||||||
|
46.0,58.0,50.0,54.0,25.132741228718345,1.0,4.0,52.0,-2.4
|
||||||
|
47.0,50.0,48.0,49.0,6.283185307179586,1.0,1.0,48.5,-0.6
|
||||||
|
47.0,53.0,49.0,51.0,12.566370614359172,1.0,2.0,50.0,-1.2
|
||||||
|
47.0,56.0,50.0,53.0,18.84955592153876,1.0,3.0,51.5,-1.8
|
||||||
|
47.0,59.0,51.0,55.0,25.132741228718345,1.0,4.0,53.0,-2.4
|
||||||
|
48.0,51.0,49.0,50.0,6.283185307179586,1.0,1.0,49.5,-0.6
|
||||||
|
48.0,54.0,50.0,52.0,12.566370614359172,1.0,2.0,51.0,-1.2
|
||||||
|
48.0,57.0,51.0,54.0,18.84955592153876,1.0,3.0,52.5,-1.8
|
||||||
|
48.0,60.0,52.0,56.0,25.132741228718345,1.0,4.0,54.0,-2.4
|
||||||
|
49.0,52.0,50.0,51.0,6.283185307179586,1.0,1.0,50.5,-0.6
|
||||||
|
49.0,55.0,51.0,53.0,12.566370614359172,1.0,2.0,52.0,-1.2
|
||||||
|
49.0,58.0,52.0,55.0,18.84955592153876,1.0,3.0,53.5,-1.8
|
||||||
|
50.0,53.0,51.0,52.0,6.283185307179586,1.0,1.0,51.5,-0.6
|
||||||
|
50.0,56.0,52.0,54.0,12.566370614359172,1.0,2.0,53.0,-1.2
|
||||||
|
50.0,59.0,53.0,56.0,18.84955592153876,1.0,3.0,54.5,-1.8
|
||||||
|
51.0,54.0,52.0,53.0,6.283185307179586,1.0,1.0,52.5,-0.6
|
||||||
|
51.0,57.0,53.0,55.0,12.566370614359172,1.0,2.0,54.0,-1.2
|
||||||
|
51.0,60.0,54.0,57.0,18.84955592153876,1.0,3.0,55.5,-1.8
|
||||||
|
52.0,55.0,53.0,54.0,6.283185307179586,1.0,1.0,53.5,-0.6
|
||||||
|
52.0,58.0,54.0,56.0,12.566370614359172,1.0,2.0,55.0,-1.2
|
||||||
|
53.0,56.0,54.0,55.0,6.283185307179586,1.0,1.0,54.5,-0.6
|
||||||
|
53.0,59.0,55.0,57.0,12.566370614359172,1.0,2.0,56.0,-1.2
|
||||||
|
54.0,57.0,55.0,56.0,6.283185307179586,1.0,1.0,55.5,-0.6
|
||||||
|
54.0,60.0,56.0,58.0,12.566370614359172,1.0,2.0,57.0,-1.2
|
||||||
|
55.0,58.0,56.0,57.0,6.283185307179586,1.0,1.0,56.5,-0.6
|
||||||
|
56.0,59.0,57.0,58.0,6.283185307179586,1.0,1.0,57.5,-0.6
|
||||||
|
57.0,60.0,58.0,59.0,6.283185307179586,1.0,1.0,58.5,-0.6
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,36 @@
|
||||||
|
import{c as n,d as _,a as o,b as e,F as c,r as d,o as s,t as l,n as r,e as u,u as v,f as y,g as f,h as F}from"./index-C436_g8x.js";import{S as w}from"./server-Del2gqI5.js";import{C}from"./clock-gKlC1TlO.js";import{U as S}from"./upload-DdEqBuGd.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const D=n("circle-check-big",[["path",{d:"M21.801 10A10 10 0 1 1 17 3.335",key:"yps3ct"}],["path",{d:"m9 11 3 3L22 4",key:"1pflzl"}]]);/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const N=n("package-check",[["path",{d:"m16 16 2 2 4-4",key:"gfu2re"}],["path",{d:"M21 10V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l2-1.14",key:"e7tb2h"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}],["polyline",{points:"3.29 7 12 12 20.71 7",key:"ousv84"}],["line",{x1:"12",x2:"12",y1:"22",y2:"12",key:"a4e8g8"}]]);/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const z=n("target",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"6",key:"1vlfrh"}],["circle",{cx:"12",cy:"12",r:"2",key:"1c9p78"}]]);/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const A=n("trending-down",[["polyline",{points:"22 17 13.5 8.5 8.5 13.5 2 7",key:"1r2t7k"}],["polyline",{points:"16 17 22 17 22 11",key:"11uiuu"}]]);/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const V=n("trending-up",[["polyline",{points:"22 7 13.5 15.5 8.5 10.5 2 17",key:"126l90"}],["polyline",{points:"16 7 22 7 22 13",key:"kwv8wd"}]]);/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const M=n("wifi",[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]]);/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const j=n("wrench",[["path",{d:"M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z",key:"cbrjhi"}]]),B={class:"p-6"},L={class:"grid grid-cols-4 gap-6 mb-6"},T={class:"flex items-start justify-between"},U={class:"flex-1"},W={class:"text-sm mb-2",style:{color:"rgba(0, 0, 0, 0.65)"}},E={class:"text-3xl font-semibold mb-2"},G={class:"text-sm"},I={class:"bg-white p-6 rounded-lg mb-6",style:{"box-shadow":"0 1px 2px rgba(0, 0, 0, 0.05)"}},P={style:{display:"flex","flex-direction":"column",gap:"16px"}},R={style:{width:"60px","text-align":"right","font-size":"14px",color:"rgba(0,0,0,0.65)","flex-shrink":"0"}},q={style:{flex:"1","background-color":"#F5F5F5","border-radius":"4px",height:"24px",overflow:"hidden"}},H={style:{width:"40px","font-size":"14px",color:"rgba(0,0,0,0.85)"}},J={class:"bg-white p-6 rounded-lg",style:{"box-shadow":"0 1px 2px rgba(0, 0, 0, 0.05)"}},K={class:"grid grid-cols-2 gap-6"},O={class:"flex items-center justify-between mb-4"},Q={class:"text-base font-medium"},X={class:"px-2 py-1 rounded text-xs",style:{"background-color":"#F0F2F5",color:"rgba(0, 0, 0, 0.65)"}},Y={class:"flex-1"},Z={class:"text-sm mb-1"},$={class:"text-sm",style:{color:"rgba(0, 0, 0, 0.45)"}},ee={class:"flex items-center gap-3"},te={key:0,class:"text-xs",style:{color:"rgba(0, 0, 0, 0.45)"}},se={key:0,class:"w-full mt-3 text-center text-sm",style:{color:"#1890FF"}},ce=_({__name:"Dashboard",setup(le){const b=[{label:"设备总数",value:"5,234",trend:"up",trendValue:"+5.2%",color:"#1890FF",icon:w},{label:"装配中",value:"4,856",trend:"up",trendValue:"+2.8%",color:"#52C41A",icon:M},{label:"已激活",value:"4,912",trend:"up",trendValue:"+1.5%",color:"#1890FF",icon:D},{label:"有新版本",value:"156",color:"#722ED1",icon:N},{label:"维修中",value:"23",trend:"down",trendValue:"-12.3%",color:"#FF4D4F",icon:j},{label:"报废",value:"56",color:"#FA8C16",icon:z},{label:"授权即将到期",value:"45",color:"#FAAD14",icon:C},{label:"升级中",value:"8",color:"#13C2C2",icon:S}],x=[{name:"已装配",value:45,color:"#52C41A"},{name:"已出厂",value:378,color:"#FF4D4F"},{name:"已激活",value:286,color:"#FAAD14"},{name:"报废",value:7,color:"#8C8C8C"}],m=F(()=>Math.max(...x.map(h=>h.value))),g=[{title:"固件升级通知",count:8,tasks:[{deviceSN:"SN2024030710",description:"固件版本v2.3.5可用",time:"1天前"},{deviceSN:"SN2024030711",description:"固件版本v2.3.5可用",time:"1天前"}]},{title:"维修工单",count:5,tasks:[{deviceSN:"SN2024030530",description:"设备故障报修",time:"4小时前"},{deviceSN:"SN2024030531",description:"电池故障",time:"6小时前"}]}];return(h,a)=>(s(),o("div",B,[a[3]||(a[3]=e("div",{class:"mb-6"},[e("h2",{class:"text-2xl font-semibold mb-1"},"首页"),e("p",{class:"text-sm",style:{color:"rgba(0, 0, 0, 0.45)"}},"设备管理数据总览")],-1)),e("div",L,[(s(),o(c,null,d(b,(t,p)=>e("div",{key:p,class:"bg-white p-6 rounded-lg",style:{"box-shadow":"0 1px 2px rgba(0, 0, 0, 0.05)"}},[e("div",T,[e("div",U,[e("div",W,l(t.label),1),e("div",E,l(t.value),1),t.trend&&t.trendValue?(s(),o("div",{key:0,class:"flex items-center gap-1",style:r({color:t.trend==="up"?"#52C41A":"#FF4D4F"})},[t.trend==="up"?(s(),u(v(V),{key:0,size:14})):(s(),u(v(A),{key:1,size:14})),e("span",G,l(t.trendValue),1)],4)):y("",!0)]),e("div",{class:"w-12 h-12 rounded-lg flex items-center justify-center",style:r({backgroundColor:t.color+"15"})},[(s(),u(f(t.icon),{size:24,style:r({color:t.color})},null,8,["style"]))],4)])])),64))]),e("div",I,[a[0]||(a[0]=e("h3",{class:"text-lg font-semibold mb-6"},"设备状态分布",-1)),e("div",P,[(s(),o(c,null,d(x,t=>e("div",{key:t.name,style:{display:"flex","align-items":"center",gap:"12px"}},[e("div",R,l(t.name),1),e("div",q,[e("div",{style:r({width:t.value/m.value*100+"%",height:"100%",backgroundColor:t.color,borderRadius:"0 4px 4px 0",transition:"width 0.3s ease",minWidth:t.value>0?"2px":"0"})},null,4)]),e("div",H,l(t.value),1)])),64))])]),e("div",J,[a[2]||(a[2]=e("h3",{class:"text-lg font-semibold mb-6"},"待处理任务",-1)),e("div",K,[(s(),o(c,null,d(g,(t,p)=>e("div",{key:p},[e("div",O,[e("h4",Q,l(t.title),1),e("span",X,l(t.count),1)]),e("div",null,[(s(!0),o(c,null,d(t.tasks,(i,k)=>(s(),o("div",{key:k,class:"flex items-start justify-between py-3",style:{"border-bottom":"1px solid #F0F0F0"}},[e("div",Y,[e("div",Z,l(i.deviceSN),1),e("div",$,l(i.description),1)]),e("div",ee,[i.time?(s(),o("span",te,l(i.time),1)):y("",!0),a[1]||(a[1]=e("button",{class:"text-sm",style:{color:"#1890FF"}},"处理",-1))])]))),128))]),t.tasks.length<t.count?(s(),o("button",se," 查看全部 "+l(t.count)+" 项 ",1)):y("",!0)])),64))])])]))}});export{ce as default};
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
||||||
|
import{d as o,a,b as e,t as l,o as r}from"./index-C436_g8x.js";const n={class:"p-6"},d={class:"text-2xl font-semibold mb-4"},c=o({__name:"PlaceholderPage",props:{title:{}},setup(s){return(i,t)=>(r(),a("div",n,[e("h2",d,l(s.title),1),t[0]||(t[0]=e("div",{class:"bg-white p-6 rounded-lg",style:{"box-shadow":"0 1px 2px rgba(0,0,0,0.05)"}},[e("p",{style:{color:"rgba(0,0,0,0.45)"}},"此页面正在开发中...")],-1))]))}});export{c as default};
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c as e}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const t=e("arrow-left",[["path",{d:"m12 19-7-7 7-7",key:"1l729n"}],["path",{d:"M19 12H5",key:"x3x0zl"}]]);export{t as A};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const r=c("circle-check",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]]);export{r as C};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const r=c("circle-stop",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["rect",{x:"9",y:"9",width:"6",height:"6",rx:"1",key:"1ssd4o"}]]);export{r as C};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const o=c("clock",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["polyline",{points:"12 6 12 12 16 14",key:"68esgv"}]]);export{o as C};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c as o}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const a=o("download",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"7 10 12 15 17 10",key:"2ggqvy"}],["line",{x1:"12",x2:"12",y1:"15",y2:"3",key:"1vk2je"}]]);export{a as D};
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const o=c("info",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]]);export{o as I};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c as e}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const a=e("plus",[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]]);export{a as P};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const r=c("search",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]]);export{r as S};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c as e}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const y=e("server",[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]]);export{y as S};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c as e}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const a=e("trash-2",[["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6",key:"4alrt4"}],["path",{d:"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2",key:"v07s0e"}],["line",{x1:"10",x2:"10",y1:"11",y2:"17",key:"1uufr5"}],["line",{x1:"14",x2:"14",y1:"11",y2:"17",key:"xtxkd"}]]);export{a as T};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c as e}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const t=e("triangle-alert",[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]]);export{t as T};
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import{c as o}from"./index-C436_g8x.js";/**
|
||||||
|
* @license lucide-vue-next v0.487.0 - ISC
|
||||||
|
*
|
||||||
|
* This source code is licensed under the ISC license.
|
||||||
|
* See the LICENSE file in the root directory of this source tree.
|
||||||
|
*/const a=o("upload",[["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["polyline",{points:"17 8 12 3 7 8",key:"t8dd8p"}],["line",{x1:"12",x2:"12",y1:"3",y2:"15",key:"widbto"}]]);export{a as U};
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>设备管理平台</title>
|
||||||
|
<script type="module" crossorigin src="/assets/index-C436_g8x.js"></script>
|
||||||
|
<link rel="stylesheet" crossorigin href="/assets/index-CHZHmOOh.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
27
index.html
27
index.html
|
|
@ -1,15 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
<!DOCTYPE html>
|
<html lang="zh-CN">
|
||||||
<html lang="en">
|
<head>
|
||||||
<head>
|
<meta charset="UTF-8" />
|
||||||
<meta charset="UTF-8" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<title>设备管理平台</title>
|
||||||
<title>Enterprise SaaS Dashboard Design</title>
|
</head>
|
||||||
</head>
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
<body>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
<div id="root"></div>
|
</body>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
</html>
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
84
package.json
84
package.json
|
|
@ -1,90 +1,22 @@
|
||||||
{
|
{
|
||||||
"name": "@figma/my-make-file",
|
"name": "device-management-platform",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"dev": "vite"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "11.14.0",
|
"vue": "^3.5.13",
|
||||||
"@emotion/styled": "11.14.1",
|
"vue-router": "^4.5.0",
|
||||||
"@mui/icons-material": "7.3.5",
|
"lucide-vue-next": "^0.487.0"
|
||||||
"@mui/material": "7.3.5",
|
|
||||||
"@popperjs/core": "2.11.8",
|
|
||||||
"@radix-ui/react-accordion": "1.2.3",
|
|
||||||
"@radix-ui/react-alert-dialog": "1.1.6",
|
|
||||||
"@radix-ui/react-aspect-ratio": "1.1.2",
|
|
||||||
"@radix-ui/react-avatar": "1.1.3",
|
|
||||||
"@radix-ui/react-checkbox": "1.1.4",
|
|
||||||
"@radix-ui/react-collapsible": "1.1.3",
|
|
||||||
"@radix-ui/react-context-menu": "2.2.6",
|
|
||||||
"@radix-ui/react-dialog": "1.1.6",
|
|
||||||
"@radix-ui/react-dropdown-menu": "2.1.6",
|
|
||||||
"@radix-ui/react-hover-card": "1.1.6",
|
|
||||||
"@radix-ui/react-label": "2.1.2",
|
|
||||||
"@radix-ui/react-menubar": "1.1.6",
|
|
||||||
"@radix-ui/react-navigation-menu": "1.2.5",
|
|
||||||
"@radix-ui/react-popover": "1.1.6",
|
|
||||||
"@radix-ui/react-progress": "1.1.2",
|
|
||||||
"@radix-ui/react-radio-group": "1.2.3",
|
|
||||||
"@radix-ui/react-scroll-area": "1.2.3",
|
|
||||||
"@radix-ui/react-select": "2.1.6",
|
|
||||||
"@radix-ui/react-separator": "1.1.2",
|
|
||||||
"@radix-ui/react-slider": "1.2.3",
|
|
||||||
"@radix-ui/react-slot": "1.1.2",
|
|
||||||
"@radix-ui/react-switch": "1.1.3",
|
|
||||||
"@radix-ui/react-tabs": "1.1.3",
|
|
||||||
"@radix-ui/react-toggle-group": "1.1.2",
|
|
||||||
"@radix-ui/react-toggle": "1.1.2",
|
|
||||||
"@radix-ui/react-tooltip": "1.1.8",
|
|
||||||
"canvas-confetti": "1.9.4",
|
|
||||||
"class-variance-authority": "0.7.1",
|
|
||||||
"clsx": "2.1.1",
|
|
||||||
"cmdk": "1.1.1",
|
|
||||||
"date-fns": "3.6.0",
|
|
||||||
"embla-carousel-react": "8.6.0",
|
|
||||||
"input-otp": "1.4.2",
|
|
||||||
"lucide-react": "0.487.0",
|
|
||||||
"motion": "12.23.24",
|
|
||||||
"next-themes": "0.4.6",
|
|
||||||
"react-day-picker": "8.10.1",
|
|
||||||
"react-dnd": "16.0.1",
|
|
||||||
"react-dnd-html5-backend": "16.0.1",
|
|
||||||
"react-hook-form": "7.55.0",
|
|
||||||
"react-popper": "2.3.0",
|
|
||||||
"react-resizable-panels": "2.1.7",
|
|
||||||
"react-responsive-masonry": "2.7.1",
|
|
||||||
"react-router": "7.13.0",
|
|
||||||
"react-slick": "0.31.0",
|
|
||||||
"recharts": "2.15.2",
|
|
||||||
"sonner": "2.0.3",
|
|
||||||
"tailwind-merge": "3.2.0",
|
|
||||||
"tw-animate-css": "1.3.8",
|
|
||||||
"vaul": "1.1.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^5.2.3",
|
||||||
"@tailwindcss/vite": "4.1.12",
|
"@tailwindcss/vite": "4.1.12",
|
||||||
"@vitejs/plugin-react": "4.7.0",
|
|
||||||
"tailwindcss": "4.1.12",
|
"tailwindcss": "4.1.12",
|
||||||
"vite": "6.3.5"
|
"vite": "6.3.5"
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "18.3.1",
|
|
||||||
"react-dom": "18.3.1"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"react": {
|
|
||||||
"optional": true
|
|
||||||
},
|
|
||||||
"react-dom": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pnpm": {
|
|
||||||
"overrides": {
|
|
||||||
"vite": "6.3.5"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
/**
|
|
||||||
* PostCSS Configuration
|
|
||||||
*
|
|
||||||
* Tailwind CSS v4 (via @tailwindcss/vite) automatically sets up all required
|
|
||||||
* PostCSS plugins — you do NOT need to include `tailwindcss` or `autoprefixer` here.
|
|
||||||
*
|
|
||||||
* This file only exists for adding additional PostCSS plugins, if needed.
|
|
||||||
* For example:
|
|
||||||
*
|
|
||||||
* import postcssNested from 'postcss-nested'
|
|
||||||
* export default { plugins: [postcssNested()] }
|
|
||||||
*
|
|
||||||
* Otherwise, you can leave this file empty.
|
|
||||||
*/
|
|
||||||
export default {}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
import { RouterProvider } from "react-router";
|
|
||||||
import { router } from "./routes";
|
|
||||||
|
|
||||||
export default function App() {
|
|
||||||
return <RouterProvider router={router} />;
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<template>
|
||||||
|
<router-view />
|
||||||
|
</template>
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import { Outlet } from "react-router";
|
|
||||||
import { Sidebar } from "./components/Sidebar";
|
|
||||||
|
|
||||||
export function Layout() {
|
|
||||||
return (
|
|
||||||
<div className="flex h-screen overflow-hidden">
|
|
||||||
<Sidebar />
|
|
||||||
<main className="flex-1 overflow-auto" style={{ backgroundColor: '#F0F2F5' }}>
|
|
||||||
<Outlet />
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<template>
|
||||||
|
<div class="flex h-screen overflow-hidden">
|
||||||
|
<Sidebar />
|
||||||
|
<div class="flex-1 flex flex-col overflow-hidden">
|
||||||
|
<Header />
|
||||||
|
<main class="flex-1 overflow-auto" style="background-color: #F0F2F5">
|
||||||
|
<router-view />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Sidebar from './components/Sidebar.vue'
|
||||||
|
import Header from './components/Header.vue'
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
<template>
|
||||||
|
<header class="h-12 flex items-center justify-end px-6 flex-shrink-0 gap-4"
|
||||||
|
style="background-color: #fff; border-bottom: 1px solid #e8e8e8">
|
||||||
|
<router-link to="/reports" class="text-gray-500 hover:text-gray-900 transition-colors" title="数据统计">
|
||||||
|
<BarChart3 :size="20" />
|
||||||
|
</router-link>
|
||||||
|
<router-link to="/cost-reports" class="text-gray-500 hover:text-gray-900 transition-colors" title="运营报告">
|
||||||
|
<FileText :size="20" />
|
||||||
|
</router-link>
|
||||||
|
<div class="w-px h-5 bg-gray-200" />
|
||||||
|
<div ref="menuRef" class="relative">
|
||||||
|
<button @click="open = !open" class="flex items-center gap-2 cursor-pointer">
|
||||||
|
<div class="w-8 h-8 rounded-full flex items-center justify-center text-white text-sm"
|
||||||
|
style="background-color: #1890FF">管</div>
|
||||||
|
<span class="text-sm text-gray-700">管理员</span>
|
||||||
|
</button>
|
||||||
|
<div v-if="open" class="absolute right-0 top-10 w-36 rounded shadow-lg py-1 z-50"
|
||||||
|
style="background-color: #fff; border: 1px solid #e8e8e8">
|
||||||
|
<router-link v-for="item in systemMenuItems" :key="item.path" :to="item.path" @click="open = false"
|
||||||
|
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-colors">
|
||||||
|
{{ item.label }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { BarChart3, FileText } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
const open = ref(false)
|
||||||
|
const menuRef = ref<HTMLDivElement>()
|
||||||
|
|
||||||
|
const systemMenuItems = [
|
||||||
|
{ path: '/users', label: '用户管理' },
|
||||||
|
{ path: '/roles', label: '角色权限' },
|
||||||
|
{ path: '/logs', label: '操作日志' },
|
||||||
|
{ path: '/settings', label: '系统设置' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const handleClick = (e: MouseEvent) => {
|
||||||
|
if (menuRef.value && !menuRef.value.contains(e.target as Node)) open.value = false
|
||||||
|
}
|
||||||
|
onMounted(() => document.addEventListener('mousedown', handleClick))
|
||||||
|
onUnmounted(() => document.removeEventListener('mousedown', handleClick))
|
||||||
|
</script>
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
import { Link, useLocation } from "react-router";
|
|
||||||
import {
|
|
||||||
LayoutDashboard,
|
|
||||||
Server,
|
|
||||||
Settings,
|
|
||||||
FileText,
|
|
||||||
Users,
|
|
||||||
BarChart3,
|
|
||||||
ClipboardList,
|
|
||||||
Database,
|
|
||||||
Key,
|
|
||||||
Smartphone,
|
|
||||||
Gauge,
|
|
||||||
Trash2,
|
|
||||||
FileCode,
|
|
||||||
Sliders,
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
const menuItems = [
|
|
||||||
{ path: "/", icon: LayoutDashboard, label: "首页" },
|
|
||||||
{ path: "/models", icon: Server, label: "型号管理" },
|
|
||||||
{ path: "/devices", icon: Database, label: "设备列表" },
|
|
||||||
{
|
|
||||||
path: "/registration",
|
|
||||||
icon: ClipboardList,
|
|
||||||
label: "设备登记",
|
|
||||||
},
|
|
||||||
{ path: "/licenses", icon: Key, label: "授权管理" },
|
|
||||||
{ path: "/activation", icon: Smartphone, label: "激活管理" },
|
|
||||||
{ path: "/calibration", icon: Gauge, label: "校准管理" },
|
|
||||||
{ path: "/scrap", icon: Trash2, label: "报废管理" },
|
|
||||||
{ path: "/config-files", icon: FileCode, label: "配置文件" },
|
|
||||||
{ path: "/reports", icon: BarChart3, label: "数据报表" },
|
|
||||||
{ path: "/logs", icon: FileText, label: "操作日志" },
|
|
||||||
{ path: "/settings", icon: Settings, label: "系统设置" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export function Sidebar() {
|
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<aside
|
|
||||||
className="w-[240px] h-screen flex-shrink-0"
|
|
||||||
style={{ backgroundColor: "#001529" }}
|
|
||||||
>
|
|
||||||
<div className="flex flex-col h-full">
|
|
||||||
{/* Logo */}
|
|
||||||
<div
|
|
||||||
className="h-16 flex items-center px-6"
|
|
||||||
style={{
|
|
||||||
borderBottom: "1px solid rgba(255,255,255,0.1)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<h1 className="text-white text-xl font-semibold">
|
|
||||||
设备管理平台
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Menu Items */}
|
|
||||||
<nav className="flex-1 py-6">
|
|
||||||
{menuItems.map((item) => {
|
|
||||||
const Icon = item.icon;
|
|
||||||
const isActive = location.pathname === item.path;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
key={item.path}
|
|
||||||
to={item.path}
|
|
||||||
className="flex items-center gap-3 px-6 py-3 transition-colors"
|
|
||||||
style={{
|
|
||||||
color: isActive
|
|
||||||
? "#fff"
|
|
||||||
: "rgba(255, 255, 255, 0.85)",
|
|
||||||
backgroundColor: isActive
|
|
||||||
? "#1890FF"
|
|
||||||
: "transparent",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon size={18} />
|
|
||||||
<span>{item.label}</span>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
{/* User Info */}
|
|
||||||
<div
|
|
||||||
className="p-6"
|
|
||||||
style={{
|
|
||||||
borderTop: "1px solid rgba(255,255,255,0.1)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<div
|
|
||||||
className="w-8 h-8 rounded-full flex items-center justify-center"
|
|
||||||
style={{ backgroundColor: "#1890FF" }}
|
|
||||||
>
|
|
||||||
<span className="text-white text-sm">管</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-white text-sm">管理员</div>
|
|
||||||
<div
|
|
||||||
className="text-xs"
|
|
||||||
style={{ color: "rgba(255, 255, 255, 0.65)" }}
|
|
||||||
>
|
|
||||||
admin@example.com
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
<template>
|
||||||
|
<aside class="w-[200px] h-screen flex-shrink-0 overflow-y-auto" style="background-color: #001529">
|
||||||
|
<div class="h-1" style="background-color: #1890FF" />
|
||||||
|
<router-link to="/" class="block px-4 py-3 text-sm font-medium transition-colors"
|
||||||
|
:style="{ color: route.path === '/' ? '#fff' : 'rgba(255,255,255,0.85)', backgroundColor: route.path === '/' ? '#1890FF' : 'transparent', borderBottom: '1px solid rgba(255,255,255,0.06)' }">
|
||||||
|
首页
|
||||||
|
</router-link>
|
||||||
|
<nav class="py-0">
|
||||||
|
<div v-for="group in menuGroups" :key="group.title">
|
||||||
|
<button @click="toggleGroup(group.title)"
|
||||||
|
class="w-full text-left px-4 py-2.5 text-sm font-medium cursor-pointer"
|
||||||
|
style="color: rgba(255,255,255,0.85); border-bottom: 1px solid rgba(255,255,255,0.06)">
|
||||||
|
{{ group.title }}
|
||||||
|
</button>
|
||||||
|
<template v-if="!collapsedGroups.has(group.title)">
|
||||||
|
<router-link v-for="item in group.items" :key="item.path" :to="item.path"
|
||||||
|
class="block px-8 py-2 text-sm transition-colors"
|
||||||
|
:style="{ color: route.path === item.path ? '#fff' : 'rgba(255,255,255,0.65)', backgroundColor: route.path === item.path ? '#1890FF' : 'transparent' }">
|
||||||
|
{{ item.label }}
|
||||||
|
</router-link>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const collapsedGroups = ref(new Set<string>())
|
||||||
|
|
||||||
|
const toggleGroup = (title: string) => {
|
||||||
|
if (collapsedGroups.value.has(title)) collapsedGroups.value.delete(title)
|
||||||
|
else collapsedGroups.value.add(title)
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuGroups = [
|
||||||
|
{ title: '设备', items: [{ path: '/devices', label: '设备列表' }, { path: '/models', label: '型号管理' }] },
|
||||||
|
{ title: '授权', items: [{ path: '/licenses', label: '授权管理' }, { path: '/activation', label: '激活管理' }] },
|
||||||
|
{ title: '固件', items: [{ path: '/firmware', label: '固件库' }, { path: '/firmware-upgrade', label: '升级任务' }] },
|
||||||
|
{ title: '配置', items: [{ path: '/config-files', label: '配置管理' }] },
|
||||||
|
{ title: '校准', items: [{ path: '/calibration', label: '校准记录' }] },
|
||||||
|
{ title: '维修', items: [{ path: '/repair-orders', label: '维修工单' }, { path: '/repair-stats', label: '维修统计' }, { path: '/scrap', label: '报废回收' }] },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import React, { useState } from 'react'
|
|
||||||
|
|
||||||
const ERROR_IMG_SRC =
|
|
||||||
'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iODgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgc3Ryb2tlPSIjMDAwIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBvcGFjaXR5PSIuMyIgZmlsbD0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIzLjciPjxyZWN0IHg9IjE2IiB5PSIxNiIgd2lkdGg9IjU2IiBoZWlnaHQ9IjU2IiByeD0iNiIvPjxwYXRoIGQ9Im0xNiA1OCAxNi0xOCAzMiAzMiIvPjxjaXJjbGUgY3g9IjUzIiBjeT0iMzUiIHI9IjciLz48L3N2Zz4KCg=='
|
|
||||||
|
|
||||||
export function ImageWithFallback(props: React.ImgHTMLAttributes<HTMLImageElement>) {
|
|
||||||
const [didError, setDidError] = useState(false)
|
|
||||||
|
|
||||||
const handleError = () => {
|
|
||||||
setDidError(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const { src, alt, style, className, ...rest } = props
|
|
||||||
|
|
||||||
return didError ? (
|
|
||||||
<div
|
|
||||||
className={`inline-block bg-gray-100 text-center align-middle ${className ?? ''}`}
|
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
<div className="flex items-center justify-center w-full h-full">
|
|
||||||
<img src={ERROR_IMG_SRC} alt="Error loading image" {...rest} data-original-url={src} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<img src={src} alt={alt} className={className} style={style} {...rest} onError={handleError} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,492 +0,0 @@
|
||||||
import {
|
|
||||||
Info,
|
|
||||||
Smartphone,
|
|
||||||
Wifi,
|
|
||||||
Download,
|
|
||||||
CheckCircle2,
|
|
||||||
FileText,
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
interface ActivationRecord {
|
|
||||||
sn: string;
|
|
||||||
model: string;
|
|
||||||
activationDate: string;
|
|
||||||
status: "已激活" | "激活失败" | "待激活";
|
|
||||||
operator: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ActivationManagement() {
|
|
||||||
const activationRecords: ActivationRecord[] = [
|
|
||||||
{
|
|
||||||
sn: "GD30-2025-000001",
|
|
||||||
model: "GD30 高密度电法仪",
|
|
||||||
activationDate: "2025-02-10 14:30",
|
|
||||||
status: "已激活",
|
|
||||||
operator: "王工程师",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sn: "GT20-2025-000045",
|
|
||||||
model: "GT20 瞬变电磁仪",
|
|
||||||
activationDate: "2025-02-09 10:15",
|
|
||||||
status: "已激活",
|
|
||||||
operator: "李工程师",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sn: "GM10-2025-000023",
|
|
||||||
model: "GM10 大地电磁仪",
|
|
||||||
activationDate: "2025-02-08 16:20",
|
|
||||||
status: "待激活",
|
|
||||||
operator: "张工程师",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getStatusStyle = (
|
|
||||||
status: ActivationRecord["status"],
|
|
||||||
) => {
|
|
||||||
switch (status) {
|
|
||||||
case "已激活":
|
|
||||||
return {
|
|
||||||
backgroundColor: "#F6FFED",
|
|
||||||
color: "#52C41A",
|
|
||||||
border: "1px solid #B7EB8F",
|
|
||||||
};
|
|
||||||
case "激活失败":
|
|
||||||
return {
|
|
||||||
backgroundColor: "#FFF1F0",
|
|
||||||
color: "#FF4D4F",
|
|
||||||
border: "1px solid #FFCCC7",
|
|
||||||
};
|
|
||||||
case "待激活":
|
|
||||||
return {
|
|
||||||
backgroundColor: "#FFFBE6",
|
|
||||||
color: "#FAAD14",
|
|
||||||
border: "1px solid #FFE58F",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<h2 className="text-2xl font-semibold mb-1">
|
|
||||||
激活管理
|
|
||||||
</h2>
|
|
||||||
<p
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.45)" }}
|
|
||||||
>
|
|
||||||
管理设备激活流程与记录
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info Banner */}
|
|
||||||
<div
|
|
||||||
className="mb-6 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#E6F7FF",
|
|
||||||
border: "1px solid #91D5FF",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Info
|
|
||||||
size={20}
|
|
||||||
style={{
|
|
||||||
color: "#1890FF",
|
|
||||||
flexShrink: 0,
|
|
||||||
marginTop: 2,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div style={{ color: "#0050B3" }}>
|
|
||||||
<div className="font-medium mb-1">
|
|
||||||
APP激活流程说明
|
|
||||||
</div>
|
|
||||||
<div className="text-sm">
|
|
||||||
APP开机时自动读取设备UID → 与后台SN匹配 →
|
|
||||||
下载授权文件和配置 → 生成设备配置 →
|
|
||||||
激活设备。激活成功后,设备每次开机会自动检测授权文件更新。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filter Card */}
|
|
||||||
<div
|
|
||||||
className="bg-white p-6 rounded-lg mb-6"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div className="grid grid-cols-4 gap-4">
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
设备SN号
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: "#D9D9D9" }}
|
|
||||||
placeholder="输入设备SN号搜索"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
激活状态
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>已激活</option>
|
|
||||||
<option>待激活</option>
|
|
||||||
<option>激活失败</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
激活日期
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="date"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: "#D9D9D9" }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-end">
|
|
||||||
<button
|
|
||||||
className="w-full px-4 py-2 rounded text-white"
|
|
||||||
style={{ backgroundColor: "#1890FF" }}
|
|
||||||
>
|
|
||||||
查询
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Activation Records List */}
|
|
||||||
<div
|
|
||||||
className="bg-white rounded-lg mb-6"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="p-6 border-b"
|
|
||||||
style={{ borderColor: "#F0F0F0" }}
|
|
||||||
>
|
|
||||||
<h3 className="text-lg font-semibold">激活记录</h3>
|
|
||||||
</div>
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead style={{ backgroundColor: "#FAFAFA" }}>
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
设备SN号
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
型号
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
激活日期
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
操作人员
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
状态
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
操作
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{activationRecords.map((record, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className="border-b"
|
|
||||||
style={{ borderColor: "#F0F0F0" }}
|
|
||||||
>
|
|
||||||
<td className="px-6 py-4">{record.sn}</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{record.model}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{record.activationDate}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{record.operator}
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={getStatusStyle(record.status)}
|
|
||||||
>
|
|
||||||
{record.status}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
详情
|
|
||||||
</button>
|
|
||||||
{record.status === "待激活" && (
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#52C41A" }}
|
|
||||||
>
|
|
||||||
激活
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Activation Process Card */}
|
|
||||||
<div
|
|
||||||
className="bg-white p-6 rounded-lg mb-4"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">
|
|
||||||
APP激活流程 & 开机授权检测
|
|
||||||
</h3>
|
|
||||||
<div className="flex items-center justify-between gap-6">
|
|
||||||
<div
|
|
||||||
className="flex-1 p-6 rounded-lg text-center"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#E6F7FF",
|
|
||||||
border: "2px solid #1890FF",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#1890FF",
|
|
||||||
color: "#fff",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
①
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="font-medium mb-2"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
读取UID
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#0050B3" }}
|
|
||||||
>
|
|
||||||
APP读取设备UID
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ color: "#D9D9D9", fontSize: "24px" }}>
|
|
||||||
→
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="flex-1 p-6 rounded-lg text-center"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#F9F0FF",
|
|
||||||
border: "2px solid #722ED1",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#722ED1",
|
|
||||||
color: "#fff",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
②
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="font-medium mb-2"
|
|
||||||
style={{ color: "#722ED1" }}
|
|
||||||
>
|
|
||||||
SN匹配
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#531DAB" }}
|
|
||||||
>
|
|
||||||
后台SN匹配验证
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ color: "#D9D9D9", fontSize: "24px" }}>
|
|
||||||
→
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="flex-1 p-6 rounded-lg text-center"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#F6FFED",
|
|
||||||
border: "2px solid #52C41A",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#52C41A",
|
|
||||||
color: "#fff",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
③
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="font-medium mb-2"
|
|
||||||
style={{ color: "#52C41A" }}
|
|
||||||
>
|
|
||||||
下载文件
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#389E0D" }}
|
|
||||||
>
|
|
||||||
下载授权和配置
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ color: "#D9D9D9", fontSize: "24px" }}>
|
|
||||||
→
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="flex-1 p-6 rounded-lg text-center"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#FFFBE6",
|
|
||||||
border: "2px solid #FAAD14",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#FAAD14",
|
|
||||||
color: "#fff",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
④
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="font-medium mb-2"
|
|
||||||
style={{ color: "#FAAD14" }}
|
|
||||||
>
|
|
||||||
生成配置
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#D46B08" }}
|
|
||||||
>
|
|
||||||
生成设备配置文件
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ color: "#D9D9D9", fontSize: "24px" }}>
|
|
||||||
→
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="flex-1 p-6 rounded-lg text-center"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#E6FFFB",
|
|
||||||
border: "2px solid #13C2C2",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#13C2C2",
|
|
||||||
color: "#fff",
|
|
||||||
fontSize: "20px",
|
|
||||||
fontWeight: "bold",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
⑤
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="font-medium mb-2"
|
|
||||||
style={{ color: "#13C2C2" }}
|
|
||||||
>
|
|
||||||
激活设备
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#006D75" }}
|
|
||||||
>
|
|
||||||
完成激活流程
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Boot Auth Check Banner */}
|
|
||||||
<div
|
|
||||||
className="p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#FFFBE6",
|
|
||||||
border: "1px solid #FFE58F",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Info
|
|
||||||
size={20}
|
|
||||||
style={{
|
|
||||||
color: "#FAAD14",
|
|
||||||
flexShrink: 0,
|
|
||||||
marginTop: 2,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div style={{ color: "#D46B08" }}>
|
|
||||||
<div className="font-medium">开机授权检测机制</div>
|
|
||||||
<div className="text-sm mt-1">
|
|
||||||
设备每次开机 → APP自动连接 → 检测授权文件是否有更新
|
|
||||||
→ 有更新则自动下载
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Info } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
interface ActivationRecord {
|
||||||
|
sn: string
|
||||||
|
model: string
|
||||||
|
activationDate: string
|
||||||
|
status: '已激活' | '激活失败' | '待激活'
|
||||||
|
operator: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const activationRecords: ActivationRecord[] = [
|
||||||
|
{
|
||||||
|
sn: 'GD30-2025-000001',
|
||||||
|
model: 'GD30 高密度电法仪',
|
||||||
|
activationDate: '2025-02-10 14:30',
|
||||||
|
status: '已激活',
|
||||||
|
operator: '王工程师',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sn: 'GT20-2025-000045',
|
||||||
|
model: 'GT20 瞬变电磁仪',
|
||||||
|
activationDate: '2025-02-09 10:15',
|
||||||
|
status: '已激活',
|
||||||
|
operator: '李工程师',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sn: 'GM10-2025-000023',
|
||||||
|
model: 'GM10 大地电磁仪',
|
||||||
|
activationDate: '2025-02-08 16:20',
|
||||||
|
status: '待激活',
|
||||||
|
operator: '张工程师',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const getStatusStyle = (status: ActivationRecord['status']) => {
|
||||||
|
switch (status) {
|
||||||
|
case '已激活':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#F6FFED',
|
||||||
|
color: '#52C41A',
|
||||||
|
border: '1px solid #B7EB8F',
|
||||||
|
}
|
||||||
|
case '激活失败':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#FFF1F0',
|
||||||
|
color: '#FF4D4F',
|
||||||
|
border: '1px solid #FFCCC7',
|
||||||
|
}
|
||||||
|
case '待激活':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#FFFBE6',
|
||||||
|
color: '#FAAD14',
|
||||||
|
border: '1px solid #FFE58F',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-2xl font-semibold mb-1">激活管理</h2>
|
||||||
|
<p class="text-sm" style="color: rgba(0, 0, 0, 0.45)">管理设备激活流程与记录</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Banner -->
|
||||||
|
<div
|
||||||
|
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
style="background-color: #E6F7FF; border: 1px solid #91D5FF"
|
||||||
|
>
|
||||||
|
<Info :size="20" style="color: #1890FF; flex-shrink: 0; margin-top: 2px" />
|
||||||
|
<div style="color: #0050B3">
|
||||||
|
<div class="font-medium mb-1">APP激活流程说明</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
APP读取设备UID → 与后台SN匹配 → 下载授权文件和配置 → 生成设备配置 →
|
||||||
|
激活设备。激活成功后,设备每次开机会自动检测授权文件更新。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="grid grid-cols-4 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">设备SN号</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
placeholder="输入设备SN号搜索"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">激活状态</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>已激活</option>
|
||||||
|
<option>待激活</option>
|
||||||
|
<option>激活失败</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">激活日期</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end">
|
||||||
|
<button class="w-full px-4 py-2 rounded text-white" style="background-color: #1890FF">
|
||||||
|
查询
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Activation Records List -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="p-6 border-b" style="border-color: #F0F0F0">
|
||||||
|
<h3 class="text-lg font-semibold">激活记录</h3>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead style="background-color: #FAFAFA">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">设备SN号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">型号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">激活日期</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">操作人员</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">状态</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(record, index) in activationRecords"
|
||||||
|
:key="index"
|
||||||
|
class="border-b"
|
||||||
|
style="border-color: #F0F0F0"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4">{{ record.sn }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ record.model }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ record.activationDate }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ record.operator }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span class="px-2 py-1 rounded text-xs" :style="getStatusStyle(record.status)">
|
||||||
|
{{ record.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" style="color: #1890FF">详情</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Activation Process Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-4" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">APP激活流程 & 开机授权检测</h3>
|
||||||
|
<div class="flex items-center justify-between gap-6">
|
||||||
|
<div
|
||||||
|
class="flex-1 p-6 rounded-lg text-center"
|
||||||
|
style="background-color: #E6F7FF; border: 2px solid #1890FF"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
||||||
|
style="background-color: #1890FF; color: #fff; font-size: 20px; font-weight: bold"
|
||||||
|
>①</div>
|
||||||
|
<div class="font-medium mb-2" style="color: #1890FF">读取UID</div>
|
||||||
|
<div class="text-sm" style="color: #0050B3">APP读取设备UID</div>
|
||||||
|
</div>
|
||||||
|
<div style="color: #D9D9D9; font-size: 24px">→</div>
|
||||||
|
<div
|
||||||
|
class="flex-1 p-6 rounded-lg text-center"
|
||||||
|
style="background-color: #F9F0FF; border: 2px solid #722ED1"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
||||||
|
style="background-color: #722ED1; color: #fff; font-size: 20px; font-weight: bold"
|
||||||
|
>②</div>
|
||||||
|
<div class="font-medium mb-2" style="color: #722ED1">SN匹配</div>
|
||||||
|
<div class="text-sm" style="color: #531DAB">后台SN匹配验证</div>
|
||||||
|
</div>
|
||||||
|
<div style="color: #D9D9D9; font-size: 24px">→</div>
|
||||||
|
<div
|
||||||
|
class="flex-1 p-6 rounded-lg text-center"
|
||||||
|
style="background-color: #F6FFED; border: 2px solid #52C41A"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
||||||
|
style="background-color: #52C41A; color: #fff; font-size: 20px; font-weight: bold"
|
||||||
|
>③</div>
|
||||||
|
<div class="font-medium mb-2" style="color: #52C41A">下载文件</div>
|
||||||
|
<div class="text-sm" style="color: #389E0D">下载授权和配置</div>
|
||||||
|
</div>
|
||||||
|
<div style="color: #D9D9D9; font-size: 24px">→</div>
|
||||||
|
<div
|
||||||
|
class="flex-1 p-6 rounded-lg text-center"
|
||||||
|
style="background-color: #FFFBE6; border: 2px solid #FAAD14"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
||||||
|
style="background-color: #FAAD14; color: #fff; font-size: 20px; font-weight: bold"
|
||||||
|
>④</div>
|
||||||
|
<div class="font-medium mb-2" style="color: #FAAD14">生成配置</div>
|
||||||
|
<div class="text-sm" style="color: #D46B08">生成设备配置文件</div>
|
||||||
|
</div>
|
||||||
|
<div style="color: #D9D9D9; font-size: 24px">→</div>
|
||||||
|
<div
|
||||||
|
class="flex-1 p-6 rounded-lg text-center"
|
||||||
|
style="background-color: #E6FFFB; border: 2px solid #13C2C2"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-3"
|
||||||
|
style="background-color: #13C2C2; color: #fff; font-size: 20px; font-weight: bold"
|
||||||
|
>⑤</div>
|
||||||
|
<div class="font-medium mb-2" style="color: #13C2C2">激活设备</div>
|
||||||
|
<div class="text-sm" style="color: #006D75">完成激活流程</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Boot Auth Check Banner -->
|
||||||
|
<div
|
||||||
|
class="p-4 rounded-lg flex items-start gap-3"
|
||||||
|
style="background-color: #FFFBE6; border: 1px solid #FFE58F"
|
||||||
|
>
|
||||||
|
<Info :size="20" style="color: #FAAD14; flex-shrink: 0; margin-top: 2px" />
|
||||||
|
<div style="color: #D46B08">
|
||||||
|
<div class="font-medium">开机授权检测机制</div>
|
||||||
|
<div class="text-sm mt-1">
|
||||||
|
设备每次开机 → APP自动连接 → 检测授权文件是否有更新 → 有更新则自动下载
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,444 +0,0 @@
|
||||||
import {
|
|
||||||
Info,
|
|
||||||
AlertTriangle,
|
|
||||||
Clock,
|
|
||||||
Download,
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
interface CalibrationRecord {
|
|
||||||
boardSn: string;
|
|
||||||
deviceSn: string;
|
|
||||||
calibrationDate: string;
|
|
||||||
calibrator: string;
|
|
||||||
expiryDate: string;
|
|
||||||
status: "合格" | "不合格" | "待校准";
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CalibrationRecords() {
|
|
||||||
const calibrationRecords: CalibrationRecord[] = [
|
|
||||||
{
|
|
||||||
boardSn: "AC20240308001",
|
|
||||||
deviceSn: "GD30-2025-000001",
|
|
||||||
calibrationDate: "2024-03-01",
|
|
||||||
calibrator: "王工程师",
|
|
||||||
expiryDate: "2025-03-01",
|
|
||||||
status: "合格",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
boardSn: "AC20240308002",
|
|
||||||
deviceSn: "GT20-2025-000045",
|
|
||||||
calibrationDate: "2024-03-05",
|
|
||||||
calibrator: "李工程师",
|
|
||||||
expiryDate: "2025-03-05",
|
|
||||||
status: "合格",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
boardSn: "AC20240308003",
|
|
||||||
deviceSn: "GTXD-2025-000023",
|
|
||||||
calibrationDate: "2024-03-08",
|
|
||||||
calibrator: "张工程师",
|
|
||||||
expiryDate: "2025-03-08",
|
|
||||||
status: "合格",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getStatusStyle = (
|
|
||||||
status: CalibrationRecord["status"],
|
|
||||||
) => {
|
|
||||||
switch (status) {
|
|
||||||
case "合格":
|
|
||||||
return {
|
|
||||||
backgroundColor: "#F6FFED",
|
|
||||||
color: "#52C41A",
|
|
||||||
border: "1px solid #B7EB8F",
|
|
||||||
};
|
|
||||||
case "不合格":
|
|
||||||
return {
|
|
||||||
backgroundColor: "#FFF1F0",
|
|
||||||
color: "#FF4D4F",
|
|
||||||
border: "1px solid #FFCCC7",
|
|
||||||
};
|
|
||||||
case "待校准":
|
|
||||||
return {
|
|
||||||
backgroundColor: "#FFFBE6",
|
|
||||||
color: "#FAAD14",
|
|
||||||
border: "1px solid #FFE58F",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<h2 className="text-2xl font-semibold mb-1">
|
|
||||||
采集板校准记录
|
|
||||||
</h2>
|
|
||||||
<p
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.45)" }}
|
|
||||||
>
|
|
||||||
管理采集板校准数据
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info Banner */}
|
|
||||||
<div
|
|
||||||
className="mb-6 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#F9F0FF",
|
|
||||||
border: "1px solid #D3ADF7",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Info
|
|
||||||
size={20}
|
|
||||||
style={{
|
|
||||||
color: "#722ED1",
|
|
||||||
flexShrink: 0,
|
|
||||||
marginTop: 2,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div style={{ color: "#531DAB" }}>
|
|
||||||
<div className="font-medium">校准说明</div>
|
|
||||||
<div className="text-sm mt-1">
|
|
||||||
校准仅针对采集板,其他板卡无需校准。采集板校准有效期为1年,到期前需重新校准。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Stat Cards */}
|
|
||||||
<div className="grid grid-cols-4 gap-6 mb-6">
|
|
||||||
<div
|
|
||||||
className="bg-white p-6 rounded-lg"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.45)" }}
|
|
||||||
>
|
|
||||||
采集板校准总数
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-3xl font-semibold"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
1,245
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="bg-white p-6 rounded-lg"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.45)" }}
|
|
||||||
>
|
|
||||||
待校准采集板
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-3xl font-semibold"
|
|
||||||
style={{ color: "#FAAD14" }}
|
|
||||||
>
|
|
||||||
23
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="bg-white p-6 rounded-lg"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.45)" }}
|
|
||||||
>
|
|
||||||
校准中
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-3xl font-semibold"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
8
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="bg-white p-6 rounded-lg"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.45)" }}
|
|
||||||
>
|
|
||||||
校准即将到期
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="text-3xl font-semibold"
|
|
||||||
style={{ color: "#FF4D4F" }}
|
|
||||||
>
|
|
||||||
15
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filter Card */}
|
|
||||||
<div
|
|
||||||
className="bg-white p-6 rounded-lg mb-6"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div className="grid grid-cols-4 gap-4">
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
采集板SN号
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: "#D9D9D9" }}
|
|
||||||
placeholder="输入采集板SN号搜索"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
校准状态
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>合格</option>
|
|
||||||
<option>不合格</option>
|
|
||||||
<option>待校准</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
校准人员
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>王工程师</option>
|
|
||||||
<option>李工程师</option>
|
|
||||||
<option>张工程师</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-end">
|
|
||||||
<button
|
|
||||||
className="w-full px-4 py-2 rounded text-white"
|
|
||||||
style={{ backgroundColor: "#1890FF" }}
|
|
||||||
>
|
|
||||||
查询
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Calibration Records List */}
|
|
||||||
<div
|
|
||||||
className="bg-white rounded-lg mb-6"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="p-6 border-b"
|
|
||||||
style={{ borderColor: "#F0F0F0" }}
|
|
||||||
>
|
|
||||||
<h3 className="text-lg font-semibold">校准记录</h3>
|
|
||||||
</div>
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead style={{ backgroundColor: "#FAFAFA" }}>
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
采集板SN号
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
所属设备
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
校准日期
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
到期日期
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
校准人员
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
状态
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
操作
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{calibrationRecords.map((record, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className="border-b"
|
|
||||||
style={{ borderColor: "#F0F0F0" }}
|
|
||||||
>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
{record.boardSn}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{record.deviceSn}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{record.calibrationDate}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{record.expiryDate}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{record.calibrator}
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={getStatusStyle(record.status)}
|
|
||||||
>
|
|
||||||
{record.status}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
详情
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
下载报告
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
重新校准
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Pagination */}
|
|
||||||
<div
|
|
||||||
className="bg-white p-4 rounded-lg flex items-center justify-between"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
显示 1-10 / 共 1,245 条
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.45)",
|
|
||||||
}}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
上一页
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#1890FF",
|
|
||||||
color: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
1
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.85)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
2
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.85)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
3
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.85)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
下一页
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,219 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Info } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
interface CalibrationRecord {
|
||||||
|
boardSn: string
|
||||||
|
deviceSn: string
|
||||||
|
calibrationDate: string
|
||||||
|
calibrator: string
|
||||||
|
expiryDate: string
|
||||||
|
status: '合格' | '不合格' | '待校准'
|
||||||
|
}
|
||||||
|
|
||||||
|
const calibrationRecords: CalibrationRecord[] = [
|
||||||
|
{
|
||||||
|
boardSn: 'AC20240308001',
|
||||||
|
deviceSn: 'GD30-2025-000001',
|
||||||
|
calibrationDate: '2024-03-01',
|
||||||
|
calibrator: '王工程师',
|
||||||
|
expiryDate: '2025-03-01',
|
||||||
|
status: '合格',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
boardSn: 'AC20240308002',
|
||||||
|
deviceSn: 'GT20-2025-000045',
|
||||||
|
calibrationDate: '2024-03-05',
|
||||||
|
calibrator: '李工程师',
|
||||||
|
expiryDate: '2025-03-05',
|
||||||
|
status: '合格',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
boardSn: 'AC20240308003',
|
||||||
|
deviceSn: 'GTXD-2025-000023',
|
||||||
|
calibrationDate: '2024-03-08',
|
||||||
|
calibrator: '张工程师',
|
||||||
|
expiryDate: '2025-03-08',
|
||||||
|
status: '合格',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const getStatusStyle = (status: CalibrationRecord['status']) => {
|
||||||
|
switch (status) {
|
||||||
|
case '合格':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#F6FFED',
|
||||||
|
color: '#52C41A',
|
||||||
|
border: '1px solid #B7EB8F',
|
||||||
|
}
|
||||||
|
case '不合格':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#FFF1F0',
|
||||||
|
color: '#FF4D4F',
|
||||||
|
border: '1px solid #FFCCC7',
|
||||||
|
}
|
||||||
|
case '待校准':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#FFFBE6',
|
||||||
|
color: '#FAAD14',
|
||||||
|
border: '1px solid #FFE58F',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-2xl font-semibold mb-1">采集板校准记录</h2>
|
||||||
|
<p class="text-sm" style="color: rgba(0, 0, 0, 0.45)">管理采集板校准数据</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Banner -->
|
||||||
|
<div
|
||||||
|
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
style="background-color: #F9F0FF; border: 1px solid #D3ADF7"
|
||||||
|
>
|
||||||
|
<Info :size="20" style="color: #722ED1; flex-shrink: 0; margin-top: 2px" />
|
||||||
|
<div style="color: #531DAB">
|
||||||
|
<div class="font-medium">校准说明</div>
|
||||||
|
<div class="text-sm mt-1">
|
||||||
|
校准仅针对采集板,其他板卡无需校准。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stat Cards -->
|
||||||
|
<div class="grid grid-cols-4 gap-6 mb-6">
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">采集板校准总数</div>
|
||||||
|
<div class="text-3xl font-semibold" style="color: #1890FF">1,245</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">待校准采集板</div>
|
||||||
|
<div class="text-3xl font-semibold" style="color: #FAAD14">23</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">校准中</div>
|
||||||
|
<div class="text-3xl font-semibold" style="color: #1890FF">8</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">校准即将到期</div>
|
||||||
|
<div class="text-3xl font-semibold" style="color: #FF4D4F">15</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="grid grid-cols-4 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">采集板SN号</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
placeholder="输入采集板SN号搜索"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">校准状态</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>合格</option>
|
||||||
|
<option>不合格</option>
|
||||||
|
<option>待校准</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">校准人员</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>王工程师</option>
|
||||||
|
<option>李工程师</option>
|
||||||
|
<option>张工程师</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end">
|
||||||
|
<button class="w-full px-4 py-2 rounded text-white" style="background-color: #1890FF">
|
||||||
|
查询
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Calibration Records List -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="p-6 border-b" style="border-color: #F0F0F0">
|
||||||
|
<h3 class="text-lg font-semibold">校准记录</h3>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead style="background-color: #FAFAFA">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">采集板SN号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">所属设备</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">校准日期</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">到期日期</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">校准人员</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">状态</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(record, index) in calibrationRecords"
|
||||||
|
:key="index"
|
||||||
|
class="border-b"
|
||||||
|
style="border-color: #F0F0F0"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4">{{ record.boardSn }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ record.deviceSn }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ record.calibrationDate }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ record.expiryDate }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ record.calibrator }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span class="px-2 py-1 rounded text-xs" :style="getStatusStyle(record.status)">
|
||||||
|
{{ record.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" style="color: #1890FF">详情</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">下载报告</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">重新校准</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<div
|
||||||
|
class="bg-white p-4 rounded-lg flex items-center justify-between"
|
||||||
|
style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)"
|
||||||
|
>
|
||||||
|
<div class="text-sm" style="color: rgba(0, 0, 0, 0.65)">显示 1-10 / 共 1,245 条</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.45)"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
上一页
|
||||||
|
</button>
|
||||||
|
<button class="px-3 py-1 rounded" style="background-color: #1890FF; color: #fff">1</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">2</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">3</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">下一页</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,391 +0,0 @@
|
||||||
import {
|
|
||||||
Info,
|
|
||||||
Plus,
|
|
||||||
Download,
|
|
||||||
Upload,
|
|
||||||
Search,
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
interface ConfigFile {
|
|
||||||
configId: string;
|
|
||||||
model: string;
|
|
||||||
version: string;
|
|
||||||
createdTime: string;
|
|
||||||
status: "生效" | "已停用";
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ConfigFileManagement() {
|
|
||||||
const configFiles: ConfigFile[] = [
|
|
||||||
{
|
|
||||||
configId: "CFG-GD30-v1.2.0",
|
|
||||||
model: "GD30 高密度电法仪",
|
|
||||||
version: "v1.2.0",
|
|
||||||
createdTime: "2024-03-01 10:30",
|
|
||||||
status: "生效",
|
|
||||||
description: "优化采集参数,提升数据精度",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
configId: "CFG-GT20-v1.5.3",
|
|
||||||
model: "GT20 瞬变电磁仪",
|
|
||||||
version: "v1.5.3",
|
|
||||||
createdTime: "2024-02-28 14:20",
|
|
||||||
status: "生效",
|
|
||||||
description: "增加新的波形配置选项",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getStatusStyle = (status: ConfigFile["status"]) => {
|
|
||||||
switch (status) {
|
|
||||||
case "生效":
|
|
||||||
return {
|
|
||||||
backgroundColor: "#F6FFED",
|
|
||||||
color: "#52C41A",
|
|
||||||
border: "1px solid #B7EB8F",
|
|
||||||
};
|
|
||||||
case "已停用":
|
|
||||||
return {
|
|
||||||
backgroundColor: "#FAFAFA",
|
|
||||||
color: "rgba(0, 0, 0, 0.45)",
|
|
||||||
border: "1px solid #D9D9D9",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<div className="flex items-center justify-between mb-2">
|
|
||||||
<h2 className="text-2xl font-semibold">
|
|
||||||
配置文件管理
|
|
||||||
</h2>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{
|
|
||||||
border: "1px solid #D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.85)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Upload size={16} />
|
|
||||||
上传配置
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded text-white flex items-center gap-2"
|
|
||||||
style={{ backgroundColor: "#1890FF" }}
|
|
||||||
>
|
|
||||||
<Plus size={16} />
|
|
||||||
新建配置
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.45)" }}
|
|
||||||
>
|
|
||||||
管理设备型号配置文件
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info Banner */}
|
|
||||||
<div
|
|
||||||
className="mb-6 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#E6F7FF",
|
|
||||||
border: "1px solid #91D5FF",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Info
|
|
||||||
size={20}
|
|
||||||
style={{
|
|
||||||
color: "#1890FF",
|
|
||||||
flexShrink: 0,
|
|
||||||
marginTop: 2,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div style={{ color: "#0050B3" }}>
|
|
||||||
<div className="font-medium mb-1">配置文件说明</div>
|
|
||||||
<div className="text-sm">
|
|
||||||
配置文件按设备型号绑定适配,包含发射参数、采集参数、网络参数等。每个型号可以有1个配置版本。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filter Card */}
|
|
||||||
<div
|
|
||||||
className="bg-white p-6 rounded-lg mb-6"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div className="grid grid-cols-4 gap-4">
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
适配型号
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option>全部型号</option>
|
|
||||||
<option>GD30 地质探测仪</option>
|
|
||||||
<option>GT20 物探仪</option>
|
|
||||||
<option>GTXD 探测仪</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
配置版本
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
backgroundColor: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option>全部版本</option>
|
|
||||||
<option>v1.0.x</option>
|
|
||||||
<option>v1.1.x</option>
|
|
||||||
<option>v1.2.x</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="block text-sm mb-2"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
关键字
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: "#D9D9D9" }}
|
|
||||||
placeholder="搜索配置ID或描述"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-end">
|
|
||||||
<button
|
|
||||||
className="w-full px-4 py-2 rounded text-white flex items-center justify-center gap-2"
|
|
||||||
style={{ backgroundColor: "#1890FF" }}
|
|
||||||
>
|
|
||||||
<Search size={16} />
|
|
||||||
查询
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Config File List */}
|
|
||||||
<div
|
|
||||||
className="bg-white rounded-lg mb-6"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="p-6 border-b"
|
|
||||||
style={{ borderColor: "#F0F0F0" }}
|
|
||||||
>
|
|
||||||
<h3 className="text-lg font-semibold">
|
|
||||||
配置文件列表
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead style={{ backgroundColor: "#FAFAFA" }}>
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
配置ID
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
适配型号
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
版本
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
创建时间
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
描述
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
状态
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
className="px-6 py-3 text-left text-sm font-medium"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.85)" }}
|
|
||||||
>
|
|
||||||
操作
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{configFiles.map((config, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className="border-b"
|
|
||||||
style={{ borderColor: "#F0F0F0" }}
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
{config.configId}
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">{config.model}</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{config.version}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{config.createdTime}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className="px-6 py-4"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
{config.description}
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={getStatusStyle(config.status)}
|
|
||||||
>
|
|
||||||
{config.status}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
详情
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
下发
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#1890FF" }}
|
|
||||||
>
|
|
||||||
下载
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "#FF4D4F" }}
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Pagination */}
|
|
||||||
<div
|
|
||||||
className="bg-white p-4 rounded-lg flex items-center justify-between"
|
|
||||||
style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="text-sm"
|
|
||||||
style={{ color: "rgba(0, 0, 0, 0.65)" }}
|
|
||||||
>
|
|
||||||
显示 1-10 / 共 48 条
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.45)",
|
|
||||||
}}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
上一页
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded"
|
|
||||||
style={{
|
|
||||||
backgroundColor: "#1890FF",
|
|
||||||
color: "#fff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
1
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.85)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
2
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.85)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
3
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{
|
|
||||||
borderColor: "#D9D9D9",
|
|
||||||
color: "rgba(0, 0, 0, 0.85)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
下一页
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,201 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Info, Plus, Search } from 'lucide-vue-next'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
interface ConfigFile {
|
||||||
|
configId: string
|
||||||
|
model: string
|
||||||
|
version: string
|
||||||
|
createdTime: string
|
||||||
|
status: '生效' | '已停用'
|
||||||
|
}
|
||||||
|
|
||||||
|
const configFiles: ConfigFile[] = [
|
||||||
|
{
|
||||||
|
configId: 'CFG-GD30-v1.2.0',
|
||||||
|
model: 'GD30 高密度电法仪',
|
||||||
|
version: 'v1.2.0',
|
||||||
|
createdTime: '2024-03-01 10:30',
|
||||||
|
status: '生效',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
configId: 'CFG-GT20-v1.5.3',
|
||||||
|
model: 'GT20 瞬变电磁仪',
|
||||||
|
version: 'v1.5.3',
|
||||||
|
createdTime: '2024-02-28 14:20',
|
||||||
|
status: '生效',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const getStatusStyle = (status: ConfigFile['status']) => {
|
||||||
|
switch (status) {
|
||||||
|
case '生效':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#F6FFED',
|
||||||
|
color: '#52C41A',
|
||||||
|
border: '1px solid #B7EB8F',
|
||||||
|
}
|
||||||
|
case '已停用':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#FAFAFA',
|
||||||
|
color: 'rgba(0, 0, 0, 0.45)',
|
||||||
|
border: '1px solid #D9D9D9',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<h2 class="text-2xl font-semibold">配置文件管理</h2>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded text-white flex items-center gap-2"
|
||||||
|
style="background-color: #1890FF"
|
||||||
|
@click="router.push('/config-files/new')"
|
||||||
|
>
|
||||||
|
<Plus :size="16" />
|
||||||
|
新建配置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm" style="color: rgba(0, 0, 0, 0.45)">管理设备型号配置文件</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Banner -->
|
||||||
|
<div
|
||||||
|
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
style="background-color: #E6F7FF; border: 1px solid #91D5FF"
|
||||||
|
>
|
||||||
|
<Info :size="20" style="color: #1890FF; flex-shrink: 0; margin-top: 2px" />
|
||||||
|
<div style="color: #0050B3">
|
||||||
|
<div class="font-medium mb-1">配置文件说明</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
配置文件按设备型号绑定适配,包含发射参数、采集参数、网络参数等。每个型号可以有1个配置版本。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="grid grid-cols-4 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">适配型号</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部型号</option>
|
||||||
|
<option>GD30 高密度电法仪</option>
|
||||||
|
<option>GT20 瞬变电磁仪</option>
|
||||||
|
<option>GM10 大地电磁仪</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">配置版本</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部版本</option>
|
||||||
|
<option>v1.0.x</option>
|
||||||
|
<option>v1.1.x</option>
|
||||||
|
<option>v1.2.x</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">关键字</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
placeholder="搜索配置ID或描述"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end">
|
||||||
|
<button
|
||||||
|
class="w-full px-4 py-2 rounded text-white flex items-center justify-center gap-2"
|
||||||
|
style="background-color: #1890FF"
|
||||||
|
>
|
||||||
|
<Search :size="16" />
|
||||||
|
查询
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Config File List -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="p-6 border-b" style="border-color: #F0F0F0">
|
||||||
|
<h3 class="text-lg font-semibold">配置文件列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead style="background-color: #FAFAFA">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">配置ID</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">适配型号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">版本</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">创建时间</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">状态</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(config, index) in configFiles"
|
||||||
|
:key="index"
|
||||||
|
class="border-b"
|
||||||
|
style="border-color: #F0F0F0"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4" style="color: #1890FF">{{ config.configId }}</td>
|
||||||
|
<td class="px-6 py-4">{{ config.model }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ config.version }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ config.createdTime }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span class="px-2 py-1 rounded text-xs" :style="getStatusStyle(config.status)">
|
||||||
|
{{ config.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" style="color: #1890FF">详情</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">编辑</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">下发</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">下载</button>
|
||||||
|
<button class="text-sm" style="color: #FF4D4F">删除</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<div
|
||||||
|
class="bg-white p-4 rounded-lg flex items-center justify-between"
|
||||||
|
style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)"
|
||||||
|
>
|
||||||
|
<div class="text-sm" style="color: rgba(0, 0, 0, 0.65)">显示 1-10 / 共 48 条</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.45)"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
上一页
|
||||||
|
</button>
|
||||||
|
<button class="px-3 py-1 rounded" style="background-color: #1890FF; color: #fff">1</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">2</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">3</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">下一页</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,187 +0,0 @@
|
||||||
import {
|
|
||||||
TrendingUp,
|
|
||||||
TrendingDown,
|
|
||||||
Server,
|
|
||||||
Wifi,
|
|
||||||
CheckCircle,
|
|
||||||
PackageCheck,
|
|
||||||
Wrench,
|
|
||||||
Target,
|
|
||||||
Clock,
|
|
||||||
Upload
|
|
||||||
} from "lucide-react";
|
|
||||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell } from "recharts";
|
|
||||||
|
|
||||||
interface MetricCardProps {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
trend?: "up" | "down";
|
|
||||||
trendValue?: string;
|
|
||||||
color?: string;
|
|
||||||
icon: React.ElementType;
|
|
||||||
}
|
|
||||||
|
|
||||||
function MetricCard({ label, value, trend, trendValue, color = "#1890FF", icon: Icon }: MetricCardProps) {
|
|
||||||
return (
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="flex items-start justify-between">
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{label}</div>
|
|
||||||
<div className="text-3xl font-semibold mb-2">{value}</div>
|
|
||||||
{trend && trendValue && (
|
|
||||||
<div className="flex items-center gap-1" style={{ color: trend === "up" ? "#52C41A" : "#FF4D4F" }}>
|
|
||||||
{trend === "up" ? <TrendingUp size={14} /> : <TrendingDown size={14} />}
|
|
||||||
<span className="text-sm">{trendValue}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="w-12 h-12 rounded-lg flex items-center justify-center" style={{ backgroundColor: `${color}15` }}>
|
|
||||||
<Icon size={24} style={{ color }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TaskItemProps {
|
|
||||||
deviceSN: string;
|
|
||||||
description: string;
|
|
||||||
time?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function TaskItem({ deviceSN, description, time }: TaskItemProps) {
|
|
||||||
return (
|
|
||||||
<div className="flex items-start justify-between py-3" style={{ borderBottom: '1px solid #F0F0F0' }}>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="text-sm mb-1">{deviceSN}</div>
|
|
||||||
<div className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>{description}</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
{time && <span className="text-xs" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>{time}</span>}
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>处理</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Dashboard() {
|
|
||||||
const metrics = [
|
|
||||||
{ label: "设备总数", value: "5,234", trend: "up" as const, trendValue: "+5.2%", color: "#1890FF", icon: Server },
|
|
||||||
{ label: "在线设备", value: "4,856", trend: "up" as const, trendValue: "+2.8%", color: "#52C41A", icon: Wifi },
|
|
||||||
{ label: "已激活", value: "4,912", trend: "up" as const, trendValue: "+1.5%", color: "#1890FF", icon: CheckCircle },
|
|
||||||
{ label: "有新版本", value: "156", color: "#722ED1", icon: PackageCheck },
|
|
||||||
{ label: "维修中", value: "23", trend: "down" as const, trendValue: "-12.3%", color: "#FF4D4F", icon: Wrench },
|
|
||||||
{ label: "待校准", value: "56", color: "#FA8C16", icon: Target },
|
|
||||||
{ label: "授权即将到期", value: "45", color: "#FAAD14", icon: Clock },
|
|
||||||
{ label: "升级中", value: "8", color: "#13C2C2", icon: Upload },
|
|
||||||
];
|
|
||||||
|
|
||||||
const deviceStatusData = [
|
|
||||||
{ name: "在线", value: 4856, color: "#52C41A" },
|
|
||||||
{ name: "离线", value: 378, color: "#FF4D4F" },
|
|
||||||
{ name: "维修", value: 23, color: "#FAAD14" },
|
|
||||||
{ name: "报废", value: 77, color: "#8C8C8C" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const taskGroups = [
|
|
||||||
{
|
|
||||||
title: "待校准设备",
|
|
||||||
count: 12,
|
|
||||||
tasks: [
|
|
||||||
{ deviceSN: "SN2024030801", description: "温度传感器校准到期", time: "2小时前" },
|
|
||||||
{ deviceSN: "SN2024030802", description: "压力传感器校准到期", time: "3小时前" },
|
|
||||||
{ deviceSN: "SN2024030803", description: "湿度传感器校准到期", time: "5小时前" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "固件升级通知",
|
|
||||||
count: 8,
|
|
||||||
tasks: [
|
|
||||||
{ deviceSN: "SN2024030710", description: "固件版本v2.3.5可用", time: "1天前" },
|
|
||||||
{ deviceSN: "SN2024030711", description: "固件版本v2.3.5可用", time: "1天前" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "待授权审批",
|
|
||||||
count: 15,
|
|
||||||
tasks: [
|
|
||||||
{ deviceSN: "SN2024030620", description: "设备授权申请待审批", time: "30分钟前" },
|
|
||||||
{ deviceSN: "SN2024030621", description: "设备授权申请待审批", time: "1小时前" },
|
|
||||||
{ deviceSN: "SN2024030622", description: "设备授权延期申请", time: "2小时前" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "维修工单",
|
|
||||||
count: 5,
|
|
||||||
tasks: [
|
|
||||||
{ deviceSN: "SN2024030530", description: "设备故障报修", time: "4小时前" },
|
|
||||||
{ deviceSN: "SN2024030531", description: "定期维护到期", time: "6小时前" },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<h2 className="text-2xl font-semibold mb-1">首页</h2>
|
|
||||||
<p className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>设备管理数据总览</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Metric Cards */}
|
|
||||||
<div className="grid grid-cols-4 gap-6 mb-6">
|
|
||||||
{metrics.map((metric, index) => (
|
|
||||||
<MetricCard key={index} {...metric} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Device Status Chart */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">设备状态分布</h3>
|
|
||||||
<ResponsiveContainer width="100%" height={300}>
|
|
||||||
<BarChart data={deviceStatusData} layout="vertical">
|
|
||||||
<CartesianGrid strokeDasharray="3 3" stroke="#F0F0F0" />
|
|
||||||
<XAxis type="number" />
|
|
||||||
<YAxis dataKey="name" type="category" width={60} />
|
|
||||||
<Tooltip />
|
|
||||||
<Bar dataKey="value" radius={[0, 4, 4, 0]}>
|
|
||||||
{deviceStatusData.map((entry) => (
|
|
||||||
<Cell key={`bar-cell-${entry.name}`} fill={entry.color} />
|
|
||||||
))}
|
|
||||||
</Bar>
|
|
||||||
</BarChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Pending Tasks */}
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">待处理任务</h3>
|
|
||||||
<div className="grid grid-cols-2 gap-6">
|
|
||||||
{taskGroups.map((group, groupIndex) => (
|
|
||||||
<div key={groupIndex}>
|
|
||||||
<div className="flex items-center justify-between mb-4">
|
|
||||||
<h4 className="text-base font-medium">{group.title}</h4>
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={{ backgroundColor: '#F0F2F5', color: 'rgba(0, 0, 0, 0.65)' }}
|
|
||||||
>
|
|
||||||
{group.count}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{group.tasks.map((task, taskIndex) => (
|
|
||||||
<TaskItem key={taskIndex} {...task} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
{group.tasks.length < group.count && (
|
|
||||||
<button className="w-full mt-3 text-center text-sm" style={{ color: '#1890FF' }}>
|
|
||||||
查看全部 {group.count} 项
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-2xl font-semibold mb-1">首页</h2>
|
||||||
|
<p class="text-sm" style="color: rgba(0, 0, 0, 0.45)">设备管理数据总览</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Metric Cards -->
|
||||||
|
<div class="grid grid-cols-4 gap-6 mb-6">
|
||||||
|
<div
|
||||||
|
v-for="(metric, index) in metrics"
|
||||||
|
:key="index"
|
||||||
|
class="bg-white p-6 rounded-lg"
|
||||||
|
style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)"
|
||||||
|
>
|
||||||
|
<div class="flex items-start justify-between">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">{{ metric.label }}</div>
|
||||||
|
<div class="text-3xl font-semibold mb-2">{{ metric.value }}</div>
|
||||||
|
<div
|
||||||
|
v-if="metric.trend && metric.trendValue"
|
||||||
|
class="flex items-center gap-1"
|
||||||
|
:style="{ color: metric.trend === 'up' ? '#52C41A' : '#FF4D4F' }"
|
||||||
|
>
|
||||||
|
<TrendingUp v-if="metric.trend === 'up'" :size="14" />
|
||||||
|
<TrendingDown v-else :size="14" />
|
||||||
|
<span class="text-sm">{{ metric.trendValue }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-lg flex items-center justify-center"
|
||||||
|
:style="{ backgroundColor: metric.color + '15' }"
|
||||||
|
>
|
||||||
|
<component :is="metric.icon" :size="24" :style="{ color: metric.color }" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Device Status Chart (CSS-based horizontal bars replacing recharts) -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">设备状态分布</h3>
|
||||||
|
<div style="display: flex; flex-direction: column; gap: 16px;">
|
||||||
|
<div
|
||||||
|
v-for="item in deviceStatusData"
|
||||||
|
:key="item.name"
|
||||||
|
style="display: flex; align-items: center; gap: 12px;"
|
||||||
|
>
|
||||||
|
<div style="width: 60px; text-align: right; font-size: 14px; color: rgba(0,0,0,0.65); flex-shrink: 0;">
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1; background-color: #F5F5F5; border-radius: 4px; height: 24px; overflow: hidden;">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
width: (item.value / maxStatusValue * 100) + '%',
|
||||||
|
height: '100%',
|
||||||
|
backgroundColor: item.color,
|
||||||
|
borderRadius: '0 4px 4px 0',
|
||||||
|
transition: 'width 0.3s ease',
|
||||||
|
minWidth: item.value > 0 ? '2px' : '0'
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div style="width: 40px; font-size: 14px; color: rgba(0,0,0,0.85);">
|
||||||
|
{{ item.value }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pending Tasks -->
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">待处理任务</h3>
|
||||||
|
<div class="grid grid-cols-2 gap-6">
|
||||||
|
<div v-for="(group, groupIndex) in taskGroups" :key="groupIndex">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<h4 class="text-base font-medium">{{ group.title }}</h4>
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded text-xs"
|
||||||
|
style="background-color: #F0F2F5; color: rgba(0, 0, 0, 0.65)"
|
||||||
|
>
|
||||||
|
{{ group.count }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
v-for="(task, taskIndex) in group.tasks"
|
||||||
|
:key="taskIndex"
|
||||||
|
class="flex items-start justify-between py-3"
|
||||||
|
style="border-bottom: 1px solid #F0F0F0"
|
||||||
|
>
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="text-sm mb-1">{{ task.deviceSN }}</div>
|
||||||
|
<div class="text-sm" style="color: rgba(0, 0, 0, 0.45)">{{ task.description }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span v-if="task.time" class="text-xs" style="color: rgba(0, 0, 0, 0.45)">{{ task.time }}</span>
|
||||||
|
<button class="text-sm" style="color: #1890FF">处理</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
v-if="group.tasks.length < group.count"
|
||||||
|
class="w-full mt-3 text-center text-sm"
|
||||||
|
style="color: #1890FF"
|
||||||
|
>
|
||||||
|
查看全部 {{ group.count }} 项
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import {
|
||||||
|
TrendingUp,
|
||||||
|
TrendingDown,
|
||||||
|
Server,
|
||||||
|
Wifi,
|
||||||
|
CheckCircle,
|
||||||
|
PackageCheck,
|
||||||
|
Wrench,
|
||||||
|
Target,
|
||||||
|
Clock,
|
||||||
|
Upload,
|
||||||
|
} from 'lucide-vue-next'
|
||||||
|
|
||||||
|
const metrics = [
|
||||||
|
{ label: '设备总数', value: '5,234', trend: 'up' as const, trendValue: '+5.2%', color: '#1890FF', icon: Server },
|
||||||
|
{ label: '装配中', value: '4,856', trend: 'up' as const, trendValue: '+2.8%', color: '#52C41A', icon: Wifi },
|
||||||
|
{ label: '已激活', value: '4,912', trend: 'up' as const, trendValue: '+1.5%', color: '#1890FF', icon: CheckCircle },
|
||||||
|
{ label: '有新版本', value: '156', color: '#722ED1', icon: PackageCheck },
|
||||||
|
{ label: '维修中', value: '23', trend: 'down' as const, trendValue: '-12.3%', color: '#FF4D4F', icon: Wrench },
|
||||||
|
{ label: '报废', value: '56', color: '#FA8C16', icon: Target },
|
||||||
|
{ label: '授权即将到期', value: '45', color: '#FAAD14', icon: Clock },
|
||||||
|
{ label: '升级中', value: '8', color: '#13C2C2', icon: Upload },
|
||||||
|
]
|
||||||
|
|
||||||
|
const deviceStatusData = [
|
||||||
|
{ name: '已装配', value: 45, color: '#52C41A' },
|
||||||
|
{ name: '已出厂', value: 378, color: '#FF4D4F' },
|
||||||
|
{ name: '已激活', value: 286, color: '#FAAD14' },
|
||||||
|
{ name: '报废', value: 7, color: '#8C8C8C' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const maxStatusValue = computed(() => Math.max(...deviceStatusData.map((d) => d.value)))
|
||||||
|
|
||||||
|
const taskGroups = [
|
||||||
|
{
|
||||||
|
title: '固件升级通知',
|
||||||
|
count: 8,
|
||||||
|
tasks: [
|
||||||
|
{ deviceSN: 'SN2024030710', description: '固件版本v2.3.5可用', time: '1天前' },
|
||||||
|
{ deviceSN: 'SN2024030711', description: '固件版本v2.3.5可用', time: '1天前' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '维修工单',
|
||||||
|
count: 5,
|
||||||
|
tasks: [
|
||||||
|
{ deviceSN: 'SN2024030530', description: '设备故障报修', time: '4小时前' },
|
||||||
|
{ deviceSN: 'SN2024030531', description: '电池故障', time: '6小时前' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
@ -1,268 +0,0 @@
|
||||||
import { ArrowLeft, StopCircle, Edit2, Download, Clock } from "lucide-react";
|
|
||||||
import { useNavigate } from "react-router";
|
|
||||||
|
|
||||||
export default function DeviceDetail() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const maintenanceHistory = [
|
|
||||||
{ date: "2024-03-01", type: "固件升级", operator: "王工程师", description: "升级固件至v2.3.5,解决数据采集异常问题" },
|
|
||||||
{ date: "2024-02-15", type: "主板更换", operator: "李工程师", description: "更换主控板(旧:MB20231215001 → 新:MB20240215001)" },
|
|
||||||
{ date: "2024-01-20", type: "常规保养", operator: "张工程师", description: "清洁设备,检查线路连接,测试功能正常" },
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<div className="flex items-center gap-4 mb-2">
|
|
||||||
<button
|
|
||||||
onClick={() => navigate(-1)}
|
|
||||||
className="p-2 rounded hover:bg-gray-100 transition-colors"
|
|
||||||
style={{ color: 'rgba(0, 0, 0, 0.65)' }}
|
|
||||||
>
|
|
||||||
<ArrowLeft size={20} />
|
|
||||||
</button>
|
|
||||||
<h2 className="text-2xl font-semibold">GD30-2025-000001</h2>
|
|
||||||
<span
|
|
||||||
className="px-3 py-1 rounded text-sm"
|
|
||||||
style={{ backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' }}
|
|
||||||
>
|
|
||||||
已激活
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-3 ml-12">
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Edit2 size={16} />
|
|
||||||
编辑信息
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Download size={16} />
|
|
||||||
导出数据
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #FF4D4F', color: '#FF4D4F' }}
|
|
||||||
>
|
|
||||||
<StopCircle size={16} />
|
|
||||||
设备下线
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Basic Info Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">基本信息</h3>
|
|
||||||
<div className="grid grid-cols-3 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>设备型号</div>
|
|
||||||
<div>GD30 地质探测仪</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>主机SN号</div>
|
|
||||||
<div>GD30-2025-000001</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>设备状态</div>
|
|
||||||
<span
|
|
||||||
className="inline-block px-2 py-1 rounded text-xs"
|
|
||||||
style={{ backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' }}
|
|
||||||
>
|
|
||||||
已激活
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>生产日期</div>
|
|
||||||
<div>2025-01-15</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>出厂日期</div>
|
|
||||||
<div>2025-02-01</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>激活日期</div>
|
|
||||||
<div>2025-02-10</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>装配人员</div>
|
|
||||||
<div>张工程师</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>测试人员</div>
|
|
||||||
<div>李工程师</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>客户名称</div>
|
|
||||||
<div>北京地质研究院</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Hardware Topology Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">硬件拓扑</h3>
|
|
||||||
<div className="flex items-center justify-center gap-8">
|
|
||||||
<div className="text-center">
|
|
||||||
<div
|
|
||||||
className="w-32 h-32 rounded-lg flex flex-col items-center justify-center mb-3"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', border: '2px solid #1890FF' }}
|
|
||||||
>
|
|
||||||
<div className="text-lg font-semibold" style={{ color: '#1890FF' }}>主板</div>
|
|
||||||
<div className="text-xs mt-2" style={{ color: '#1890FF' }}>MB-V2.3</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-xs" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>MB20240308001</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ color: '#D9D9D9', fontSize: '24px' }}>→</div>
|
|
||||||
<div className="text-center">
|
|
||||||
<div
|
|
||||||
className="w-32 h-32 rounded-lg flex flex-col items-center justify-center mb-3"
|
|
||||||
style={{ backgroundColor: '#F0F5FF', border: '2px solid #597EF7' }}
|
|
||||||
>
|
|
||||||
<div className="text-lg font-semibold" style={{ color: '#597EF7' }}>采集板</div>
|
|
||||||
<div className="text-xs mt-2" style={{ color: '#597EF7' }}>AC-V1.8</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-xs" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>AC20240308002</div>
|
|
||||||
</div>
|
|
||||||
<div style={{ color: '#D9D9D9', fontSize: '24px' }}>→</div>
|
|
||||||
<div className="text-center">
|
|
||||||
<div
|
|
||||||
className="w-32 h-32 rounded-lg flex flex-col items-center justify-center mb-3"
|
|
||||||
style={{ backgroundColor: '#F6FFED', border: '2px solid #52C41A' }}
|
|
||||||
>
|
|
||||||
<div className="text-lg font-semibold" style={{ color: '#52C41A' }}>测控板</div>
|
|
||||||
<div className="text-xs mt-2" style={{ color: '#52C41A' }}>CT-V1.5</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-xs" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>CT20240308003</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* License Info Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">授权信息</h3>
|
|
||||||
<div className="grid grid-cols-3 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>授权ID</div>
|
|
||||||
<div>LIC-2025-0001</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>授权状态</div>
|
|
||||||
<span
|
|
||||||
className="inline-block px-2 py-1 rounded text-xs"
|
|
||||||
style={{ backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' }}
|
|
||||||
>
|
|
||||||
已激活
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>授权类型</div>
|
|
||||||
<div>正式授权</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>生效日期</div>
|
|
||||||
<div>2025-02-10</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>到期日期</div>
|
|
||||||
<div>2026-02-10</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>剩余天数</div>
|
|
||||||
<div style={{ color: '#52C41A' }}>317天</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>授权功能模块</div>
|
|
||||||
<div>基础功能, 高级分析, 数据导出</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>授权文件</div>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>auth_gd30_v2.3.lic</button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>操作</div>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>续期</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Firmware Info Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">固件信息</h3>
|
|
||||||
<div className="grid grid-cols-3 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>当前固件版本</div>
|
|
||||||
<div>v2.3.5</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>最后更新时间</div>
|
|
||||||
<div>2024-03-01 10:30</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>更新方式</div>
|
|
||||||
<div>远程OTA</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>配置文件版本</div>
|
|
||||||
<div>v1.2.0</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>配置同步时间</div>
|
|
||||||
<div>2024-03-01 10:35</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>操作</div>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>推送固件</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>下发配置</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Maintenance History Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="flex items-center justify-between mb-6">
|
|
||||||
<h3 className="text-lg font-semibold">维修历史</h3>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>查看全部</button>
|
|
||||||
</div>
|
|
||||||
<div className="relative">
|
|
||||||
{/* Timeline line */}
|
|
||||||
<div
|
|
||||||
className="absolute left-6 top-6 bottom-6 w-0.5"
|
|
||||||
style={{ backgroundColor: '#F0F0F0' }}
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<div className="space-y-6">
|
|
||||||
{maintenanceHistory.map((entry, index) => (
|
|
||||||
<div key={index} className="flex gap-4">
|
|
||||||
<div className="flex flex-col items-center flex-shrink-0">
|
|
||||||
<div
|
|
||||||
className="w-12 h-12 rounded-full flex items-center justify-center relative z-10"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', border: '2px solid #1890FF' }}
|
|
||||||
>
|
|
||||||
<Clock size={20} style={{ color: '#1890FF' }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 pt-2">
|
|
||||||
<div className="flex items-center gap-3 mb-2">
|
|
||||||
<span className="font-medium">{entry.type}</span>
|
|
||||||
<span className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>{entry.date}</span>
|
|
||||||
<span className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>操作人:{entry.operator}</span>
|
|
||||||
</div>
|
|
||||||
<div className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
{entry.description}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,234 @@
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center gap-4 mb-2">
|
||||||
|
<button
|
||||||
|
class="p-2 rounded hover:bg-gray-100 transition-colors"
|
||||||
|
style="color: rgba(0, 0, 0, 0.65)"
|
||||||
|
@click="router.go(-1)"
|
||||||
|
>
|
||||||
|
<ArrowLeft :size="20" />
|
||||||
|
</button>
|
||||||
|
<h2 class="text-2xl font-semibold">GD30-2025-000001</h2>
|
||||||
|
<span
|
||||||
|
class="px-3 py-1 rounded text-sm"
|
||||||
|
style="background-color: #F6FFED; color: #52C41A; border: 1px solid #B7EB8F"
|
||||||
|
>
|
||||||
|
已激活
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Basic Info Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">基本信息</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">设备型号</div>
|
||||||
|
<div>GD30 高密度电法仪</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">主机SN号</div>
|
||||||
|
<div>GD30-2025-000001</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">设备状态</div>
|
||||||
|
<span
|
||||||
|
class="inline-block px-2 py-1 rounded text-xs"
|
||||||
|
style="background-color: #F6FFED; color: #52C41A; border: 1px solid #B7EB8F"
|
||||||
|
>
|
||||||
|
已激活
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">生产日期</div>
|
||||||
|
<div>2025-01-15</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">出厂日期</div>
|
||||||
|
<div>2025-02-01</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">激活日期</div>
|
||||||
|
<div>2025-02-10</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">装配人员</div>
|
||||||
|
<div>张工程师</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">测试人员</div>
|
||||||
|
<div>李工程师</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">客户名称</div>
|
||||||
|
<div>北京地质研究院</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hardware Topology Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">硬件拓扑</h3>
|
||||||
|
<div class="flex items-center justify-center gap-6">
|
||||||
|
<template v-for="(board, i) in boards" :key="board.name">
|
||||||
|
<div class="flex items-center gap-6">
|
||||||
|
<div class="text-center">
|
||||||
|
<div
|
||||||
|
class="w-28 h-28 rounded-lg flex flex-col items-center justify-center mb-3"
|
||||||
|
:style="{ backgroundColor: board.bg, border: '2px solid ' + board.color }"
|
||||||
|
>
|
||||||
|
<div class="text-base font-semibold" :style="{ color: board.color }">{{ board.name }}</div>
|
||||||
|
<div class="text-xs mt-2" :style="{ color: board.color }">{{ board.version }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-xs" style="color: rgba(0, 0, 0, 0.45)">{{ board.sn }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="Number(i) < boards.length - 1" style="color: #D9D9D9; font-size: 24px">→</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- License Info Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">授权信息</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">授权ID</div>
|
||||||
|
<div>LIC-2025-0001</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">授权状态</div>
|
||||||
|
<span
|
||||||
|
class="inline-block px-2 py-1 rounded text-xs"
|
||||||
|
style="background-color: #F6FFED; color: #52C41A; border: 1px solid #B7EB8F"
|
||||||
|
>
|
||||||
|
已激活
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">授权类型</div>
|
||||||
|
<div>正式授权</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">生效日期</div>
|
||||||
|
<div>2025-02-10</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">到期日期</div>
|
||||||
|
<div>2026-02-10</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">剩余天数</div>
|
||||||
|
<div style="color: #52C41A">317天</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">授权功能模块</div>
|
||||||
|
<div>1D(SP/VES/IP) / 2D(SP/ERT/IP) / 3D(SP/ERT/IP)</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">授权文件</div>
|
||||||
|
<button class="text-sm" style="color: #1890FF">auth_gd30_v2.3.lic</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">操作</div>
|
||||||
|
<button class="text-sm" style="color: #1890FF">续期</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Firmware Info Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">固件信息</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">当前固件版本</div>
|
||||||
|
<div>v2.3.5</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">最后更新时间</div>
|
||||||
|
<div>2024-03-01 10:30</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">更新方式</div>
|
||||||
|
<div>远程OTA</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">配置文件版本</div>
|
||||||
|
<div>v1.2.0</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">配置同步时间</div>
|
||||||
|
<div>2024-03-01 10:35</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">操作</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" style="color: #1890FF">推送固件</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">下发配置</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Maintenance History Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<h3 class="text-lg font-semibold">维修历史</h3>
|
||||||
|
<button class="text-sm" style="color: #1890FF">查看全部</button>
|
||||||
|
</div>
|
||||||
|
<div class="relative">
|
||||||
|
<!-- Timeline line -->
|
||||||
|
<div
|
||||||
|
class="absolute left-6 top-6 bottom-6 w-0.5"
|
||||||
|
style="background-color: #F0F0F0"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div v-for="(entry, index) in maintenanceHistory" :key="index" class="flex gap-4">
|
||||||
|
<div class="flex flex-col items-center flex-shrink-0">
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-full flex items-center justify-center relative z-10"
|
||||||
|
style="background-color: #E6F7FF; border: 2px solid #1890FF"
|
||||||
|
>
|
||||||
|
<Clock :size="20" style="color: #1890FF" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 pt-2">
|
||||||
|
<div class="flex items-center gap-3 mb-2">
|
||||||
|
<span class="font-medium">{{ entry.type }}</span>
|
||||||
|
<span class="text-sm" style="color: rgba(0, 0, 0, 0.45)">{{ entry.date }}</span>
|
||||||
|
<span class="text-sm" style="color: rgba(0, 0, 0, 0.45)">操作人:{{ entry.operator }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm" style="color: rgba(0, 0, 0, 0.65)">
|
||||||
|
{{ entry.description }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ArrowLeft, StopCircle, Edit2, Download, Clock } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const boards = [
|
||||||
|
{ name: '主板', version: 'MB-V2.3', sn: 'MB20240308001', bg: '#E6F7FF', color: '#1890FF' },
|
||||||
|
{ name: '采集板', version: 'RX-V1.8', sn: 'RX20240308002', bg: '#F0F5FF', color: '#597EF7' },
|
||||||
|
{ name: '发射板', version: 'TX-V1.2', sn: 'TX20240308003', bg: '#FFF7E6', color: '#FA8C16' },
|
||||||
|
{ name: '测控板', version: 'MC-V1.5', sn: 'MC20240308004', bg: '#F6FFED', color: '#52C41A' },
|
||||||
|
{ name: '升压板', version: 'BO-V1.0', sn: 'BO20240308005', bg: '#FFF0F6', color: '#EB2F96' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const maintenanceHistory = [
|
||||||
|
{ date: '2024-03-01', type: '固件升级', operator: '王工程师', description: '升级固件至v2.3.5,解决数据采集异常问题' },
|
||||||
|
{ date: '2024-02-15', type: '主板更换', operator: '李工程师', description: '更换主控板(旧:MB20231215001 → 新:MB20240215001)' },
|
||||||
|
{ date: '2024-01-20', type: '常规保养', operator: '张工程师', description: '清洁设备,检查线路连接,测试功能正常' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
@ -1,281 +0,0 @@
|
||||||
import { useState } from "react";
|
|
||||||
import {
|
|
||||||
Plus,
|
|
||||||
Upload,
|
|
||||||
Download,
|
|
||||||
Search,
|
|
||||||
StopCircle
|
|
||||||
} from "lucide-react";
|
|
||||||
import { useNavigate } from "react-router";
|
|
||||||
|
|
||||||
interface Device {
|
|
||||||
sn: string;
|
|
||||||
model: string;
|
|
||||||
status: "已激活" | "已出厂" | "装配中";
|
|
||||||
firmwareVersion: string;
|
|
||||||
registrationDate: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function DeviceList() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [currentPage] = useState(1);
|
|
||||||
const [pageSize] = useState(10);
|
|
||||||
const totalDevices = 5234;
|
|
||||||
|
|
||||||
const devices: Device[] = [
|
|
||||||
{
|
|
||||||
sn: "GD30-20240308-001",
|
|
||||||
model: "GD30 地质探测仪",
|
|
||||||
status: "已激活",
|
|
||||||
firmwareVersion: "v2.3.5",
|
|
||||||
registrationDate: "2024-03-08 14:30",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sn: "GT20-20240307-045",
|
|
||||||
model: "GT20 物探仪",
|
|
||||||
status: "已出厂",
|
|
||||||
firmwareVersion: "v1.8.2",
|
|
||||||
registrationDate: "2024-03-07 10:15",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sn: "GD30-20240308-002",
|
|
||||||
model: "GD30 地质探测仪",
|
|
||||||
status: "装配中",
|
|
||||||
firmwareVersion: "v2.3.4",
|
|
||||||
registrationDate: "2024-03-08 16:20",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getStatusStyle = (status: Device["status"]) => {
|
|
||||||
switch (status) {
|
|
||||||
case "已激活":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#F6FFED',
|
|
||||||
color: '#52C41A',
|
|
||||||
border: '1px solid #B7EB8F'
|
|
||||||
};
|
|
||||||
case "已出厂":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#FFF7E6',
|
|
||||||
color: '#FA8C16',
|
|
||||||
border: '1px solid #FFD591'
|
|
||||||
};
|
|
||||||
case "装配中":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#E6F7FF',
|
|
||||||
color: '#1890FF',
|
|
||||||
border: '1px solid #91D5FF'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const startIndex = (currentPage - 1) * pageSize + 1;
|
|
||||||
const endIndex = Math.min(currentPage * pageSize, totalDevices);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<div className="flex items-center justify-between mb-2">
|
|
||||||
<h2 className="text-2xl font-semibold">设备列表</h2>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Upload size={16} />
|
|
||||||
BOM导入
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Download size={16} />
|
|
||||||
导出
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded text-white flex items-center gap-2"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
onClick={() => navigate('/registration')}
|
|
||||||
>
|
|
||||||
<Plus size={16} />
|
|
||||||
登记设备
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>管理所有设备信息</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filter Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="grid grid-cols-5 gap-4">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
设备型号
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>GD30 地质探测仪</option>
|
|
||||||
<option>GT20 物探仪</option>
|
|
||||||
<option>GTXD 探测仪</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
设备状态
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>已激活</option>
|
|
||||||
<option>已出厂</option>
|
|
||||||
<option>装配中</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
生产日期
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="date"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
产品型号
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>GD30-2024</option>
|
|
||||||
<option>GT20-2023</option>
|
|
||||||
<option>GTXD-2022</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-end">
|
|
||||||
<button
|
|
||||||
className="w-full px-4 py-2 rounded text-white flex items-center justify-center gap-2"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
>
|
|
||||||
<Search size={16} />
|
|
||||||
搜索
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Device List */}
|
|
||||||
<div className="space-y-4 mb-6">
|
|
||||||
{devices.map((device, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className="bg-white rounded-lg p-6"
|
|
||||||
style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}
|
|
||||||
>
|
|
||||||
<div className="flex items-start justify-between mb-4">
|
|
||||||
<div className="flex-1 grid grid-cols-5 gap-4">
|
|
||||||
<div>
|
|
||||||
<div className="text-xs mb-1" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>设备SN号</div>
|
|
||||||
<div className="font-medium">{device.sn}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-xs mb-1" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>型号</div>
|
|
||||||
<div>{device.model}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-xs mb-1" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>状态</div>
|
|
||||||
<span
|
|
||||||
className="inline-block px-2 py-1 rounded text-xs"
|
|
||||||
style={getStatusStyle(device.status)}
|
|
||||||
>
|
|
||||||
{device.status}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-xs mb-1" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>固件版本</div>
|
|
||||||
<div>{device.firmwareVersion}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-xs mb-1" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>录入日期</div>
|
|
||||||
<div style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{device.registrationDate}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-3 pt-4 border-t" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>详情</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>BOM</button>
|
|
||||||
{device.status === "已激活" && (
|
|
||||||
<>
|
|
||||||
<span style={{ color: '#D9D9D9' }}>|</span>
|
|
||||||
<button
|
|
||||||
className="text-sm flex items-center gap-1"
|
|
||||||
style={{ color: '#FF4D4F' }}
|
|
||||||
>
|
|
||||||
<StopCircle size={14} />
|
|
||||||
下线
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Pagination */}
|
|
||||||
<div className="bg-white p-4 rounded-lg flex items-center justify-between" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
显示 {startIndex}-{endIndex} / 共 {totalDevices.toLocaleString()} 台
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.45)' }}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
上一页
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded"
|
|
||||||
style={{ backgroundColor: '#1890FF', color: '#fff' }}
|
|
||||||
>
|
|
||||||
1
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
2
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
3
|
|
||||||
</button>
|
|
||||||
<span style={{ color: 'rgba(0, 0, 0, 0.45)' }}>...</span>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
524
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
下一页
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<h2 class="text-2xl font-semibold">设备列表</h2>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded flex items-center gap-2"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
>
|
||||||
|
<Upload :size="16" />
|
||||||
|
BOM导入
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded flex items-center gap-2"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
>
|
||||||
|
<Download :size="16" />
|
||||||
|
导出
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded text-white flex items-center gap-2"
|
||||||
|
style="background-color: #1890FF"
|
||||||
|
@click="router.push('/registration')"
|
||||||
|
>
|
||||||
|
<Plus :size="16" />
|
||||||
|
登记设备
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm" style="color: rgba(0, 0, 0, 0.45)">管理所有设备信息</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="grid grid-cols-5 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">设备型号</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>GD30 高密度电法仪</option>
|
||||||
|
<option>GT20 瞬变电磁仪</option>
|
||||||
|
<option>GM10 大地电磁仪</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">设备状态</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>已激活</option>
|
||||||
|
<option>已出厂</option>
|
||||||
|
<option>装配中</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">生产日期</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">产品型号</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>GD30-2024</option>
|
||||||
|
<option>GT20-2023</option>
|
||||||
|
<option>GTXD-2022</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end">
|
||||||
|
<button
|
||||||
|
class="w-full px-4 py-2 rounded text-white flex items-center justify-center gap-2"
|
||||||
|
style="background-color: #1890FF"
|
||||||
|
>
|
||||||
|
<Search :size="16" />
|
||||||
|
搜索
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Device List -->
|
||||||
|
<div class="space-y-4 mb-6">
|
||||||
|
<div
|
||||||
|
v-for="(device, index) in devices"
|
||||||
|
:key="index"
|
||||||
|
class="bg-white rounded-lg p-6"
|
||||||
|
style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)"
|
||||||
|
>
|
||||||
|
<div class="flex items-start justify-between mb-4">
|
||||||
|
<div class="flex-1 grid grid-cols-5 gap-4">
|
||||||
|
<div>
|
||||||
|
<div class="text-xs mb-1" style="color: rgba(0, 0, 0, 0.45)">设备SN号</div>
|
||||||
|
<div class="font-medium">{{ device.sn }}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-xs mb-1" style="color: rgba(0, 0, 0, 0.45)">型号</div>
|
||||||
|
<div>{{ device.model }}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-xs mb-1" style="color: rgba(0, 0, 0, 0.45)">状态</div>
|
||||||
|
<span
|
||||||
|
class="inline-block px-2 py-1 rounded text-xs"
|
||||||
|
:style="getStatusStyle(device.status)"
|
||||||
|
>
|
||||||
|
{{ device.status }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-xs mb-1" style="color: rgba(0, 0, 0, 0.45)">固件版本</div>
|
||||||
|
<div>{{ device.firmwareVersion }}</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-xs mb-1" style="color: rgba(0, 0, 0, 0.45)">生产日期</div>
|
||||||
|
<div style="color: rgba(0, 0, 0, 0.65)">{{ device.registrationDate }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3 pt-4 border-t" style="border-color: #F0F0F0">
|
||||||
|
<button class="text-sm" style="color: #1890FF" @click="router.push('/devices/' + device.sn)">详情</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">BOM</button>
|
||||||
|
<template v-if="device.status === '已激活'">
|
||||||
|
<span style="color: #D9D9D9">|</span>
|
||||||
|
<button class="text-sm flex items-center gap-1" style="color: #FF4D4F">
|
||||||
|
<StopCircle :size="14" />
|
||||||
|
下线
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<div
|
||||||
|
class="bg-white p-4 rounded-lg flex items-center justify-between"
|
||||||
|
style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)"
|
||||||
|
>
|
||||||
|
<div class="text-sm" style="color: rgba(0, 0, 0, 0.65)">
|
||||||
|
显示 {{ startIndex }}-{{ endIndex }} / 共 {{ totalDevices.toLocaleString() }} 台
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.45)"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
上一页
|
||||||
|
</button>
|
||||||
|
<button class="px-3 py-1 rounded" style="background-color: #1890FF; color: #fff">1</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">2</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">3</button>
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.45)">...</span>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">524</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">下一页</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { Plus, Upload, Download, Search, StopCircle } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
interface Device {
|
||||||
|
sn: string
|
||||||
|
model: string
|
||||||
|
status: '已激活' | '已出厂' | '装配中'
|
||||||
|
firmwareVersion: string
|
||||||
|
registrationDate: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const totalDevices = 5234
|
||||||
|
|
||||||
|
const devices: Device[] = [
|
||||||
|
{
|
||||||
|
sn: 'GD30-20240308-001',
|
||||||
|
model: 'GD30 高密度电法仪',
|
||||||
|
status: '已激活',
|
||||||
|
firmwareVersion: 'v2.3.5',
|
||||||
|
registrationDate: '2024-03-08 14:30',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sn: 'GT20-20240307-045',
|
||||||
|
model: 'GT20 瞬变电磁仪',
|
||||||
|
status: '已出厂',
|
||||||
|
firmwareVersion: 'v1.8.2',
|
||||||
|
registrationDate: '2024-03-07 10:15',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sn: 'GD30-20240308-002',
|
||||||
|
model: 'GD30 高密度电法仪',
|
||||||
|
status: '装配中',
|
||||||
|
firmwareVersion: 'v2.3.4',
|
||||||
|
registrationDate: '2024-03-08 16:20',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
function getStatusStyle(status: Device['status']) {
|
||||||
|
switch (status) {
|
||||||
|
case '已激活':
|
||||||
|
return { backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' }
|
||||||
|
case '已出厂':
|
||||||
|
return { backgroundColor: '#FFF7E6', color: '#FA8C16', border: '1px solid #FFD591' }
|
||||||
|
case '装配中':
|
||||||
|
return { backgroundColor: '#E6F7FF', color: '#1890FF', border: '1px solid #91D5FF' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const startIndex = computed(() => (currentPage.value - 1) * pageSize.value + 1)
|
||||||
|
const endIndex = computed(() => Math.min(currentPage.value * pageSize.value, totalDevices))
|
||||||
|
</script>
|
||||||
|
|
@ -1,331 +0,0 @@
|
||||||
import { useState } from "react";
|
|
||||||
import {
|
|
||||||
Info,
|
|
||||||
Server,
|
|
||||||
CheckCircle2,
|
|
||||||
AlertTriangle,
|
|
||||||
Layers,
|
|
||||||
Camera,
|
|
||||||
ShieldCheck
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
interface StatCardProps {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
icon: React.ElementType;
|
|
||||||
color?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function StatCard({ label, value, icon: Icon, color = "#1890FF" }: StatCardProps) {
|
|
||||||
return (
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{label}</div>
|
|
||||||
<div className="text-3xl font-semibold">{value}</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-12 h-12 rounded-lg flex items-center justify-center" style={{ backgroundColor: `${color}15` }}>
|
|
||||||
<Icon size={24} style={{ color }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function DeviceModelManagement() {
|
|
||||||
const [activeTab, setActiveTab] = useState("GD30");
|
|
||||||
|
|
||||||
const stats = [
|
|
||||||
{ label: "型号总数", value: "12", icon: Server, color: "#1890FF" },
|
|
||||||
{ label: "在产型号", value: "8", icon: CheckCircle2, color: "#52C41A" },
|
|
||||||
{ label: "停产型号", value: "3", icon: AlertTriangle, color: "#FAAD14" },
|
|
||||||
{ label: "关联设备总数", value: "5,234", icon: Layers, color: "#722ED1" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const modelData = [
|
|
||||||
{
|
|
||||||
name: "GD30 地质探测仪",
|
|
||||||
code: "GD30-2024",
|
|
||||||
authFile: "auth_gd30_v2.3.lic",
|
|
||||||
configFile: "config_gd30_v1.5.json",
|
|
||||||
firmwareVersion: "v2.3.5",
|
|
||||||
deviceCount: 2456,
|
|
||||||
status: "在产" as const,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "GT20 物探仪",
|
|
||||||
code: "GT20-2023",
|
|
||||||
authFile: "auth_gt20_v1.8.lic",
|
|
||||||
configFile: "config_gt20_v1.2.json",
|
|
||||||
firmwareVersion: "v1.8.2",
|
|
||||||
deviceCount: 1823,
|
|
||||||
status: "在产" as const,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "GTXD 探测仪",
|
|
||||||
code: "GTXD-2022",
|
|
||||||
authFile: "auth_gtxd_v1.5.lic",
|
|
||||||
configFile: "config_gtxd_v1.0.json",
|
|
||||||
firmwareVersion: "v1.5.1",
|
|
||||||
deviceCount: 955,
|
|
||||||
status: "停产" as const,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const checklistData = {
|
|
||||||
GD30: [
|
|
||||||
{ id: 1, item: "主板安装及固定", needPhoto: true, versionCheck: true },
|
|
||||||
{ id: 2, item: "采集板连接", needPhoto: true, versionCheck: true },
|
|
||||||
{ id: 3, item: "测控板安装", needPhoto: true, versionCheck: true },
|
|
||||||
{ id: 4, item: "电源线连接检查", needPhoto: true, versionCheck: false },
|
|
||||||
{ id: 5, item: "外壳密封性检测", needPhoto: true, versionCheck: false },
|
|
||||||
],
|
|
||||||
GT20: [
|
|
||||||
{ id: 1, item: "核心板安装", needPhoto: true, versionCheck: true },
|
|
||||||
{ id: 2, item: "扩展板连接", needPhoto: true, versionCheck: true },
|
|
||||||
{ id: 3, item: "信号线路检测", needPhoto: true, versionCheck: false },
|
|
||||||
{ id: 4, item: "天线模块安装", needPhoto: true, versionCheck: false },
|
|
||||||
{ id: 5, item: "整体功能测试", needPhoto: false, versionCheck: false },
|
|
||||||
],
|
|
||||||
GTXD: [
|
|
||||||
{ id: 1, item: "主控板安装", needPhoto: true, versionCheck: true },
|
|
||||||
{ id: 2, item: "传感器模块连接", needPhoto: true, versionCheck: false },
|
|
||||||
{ id: 3, item: "接口板安装", needPhoto: true, versionCheck: true },
|
|
||||||
{ id: 4, item: "线缆整理", needPhoto: true, versionCheck: false },
|
|
||||||
{ id: 5, item: "系统初始化检测", needPhoto: false, versionCheck: false },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const boardVersionData = [
|
|
||||||
{
|
|
||||||
boardType: "主板",
|
|
||||||
requiredVersion: "v2.3.x",
|
|
||||||
validationRule: "版本号前缀必须为 v2.3",
|
|
||||||
status: "active",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
boardType: "采集板",
|
|
||||||
requiredVersion: "v1.8.x",
|
|
||||||
validationRule: "版本号前缀必须为 v1.8",
|
|
||||||
status: "active",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
boardType: "测控板",
|
|
||||||
requiredVersion: "v1.5.x",
|
|
||||||
validationRule: "版本号前缀必须为 v1.5",
|
|
||||||
status: "active",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<h2 className="text-2xl font-semibold mb-1">设备型号管理</h2>
|
|
||||||
<p className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>管理设备型号及相关配置</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info Banner */}
|
|
||||||
<div
|
|
||||||
className="mb-6 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', border: '1px solid #91D5FF' }}
|
|
||||||
>
|
|
||||||
<Info size={20} style={{ color: '#1890FF', flexShrink: 0, marginTop: 2 }} />
|
|
||||||
<div style={{ color: '#0050B3' }}>
|
|
||||||
型号管理是平台核心枢纽,每个型号关联授权文件、配置文件和固件版本
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Stat Cards */}
|
|
||||||
<div className="grid grid-cols-4 gap-6 mb-6">
|
|
||||||
{stats.map((stat, index) => (
|
|
||||||
<StatCard key={index} {...stat} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Model Table */}
|
|
||||||
<div className="bg-white rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="p-6 border-b" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h3 className="text-lg font-semibold">型号列表</h3>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded text-white"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
>
|
|
||||||
新增型号
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead style={{ backgroundColor: '#FAFAFA' }}>
|
|
||||||
<tr>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>型号名称</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>编码</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>授权文件</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>配置文件</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>固件版本</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>设备数</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>状态</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>操作</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{modelData.map((model, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className="border-b"
|
|
||||||
style={{ borderColor: '#F0F0F0' }}
|
|
||||||
>
|
|
||||||
<td className="px-6 py-4">{model.name}</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{model.code}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>{model.authFile}</button>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>{model.configFile}</button>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>{model.firmwareVersion}</button>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">{model.deviceCount.toLocaleString()}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={{
|
|
||||||
backgroundColor: model.status === "在产" ? '#F6FFED' : '#FFFBE6',
|
|
||||||
color: model.status === "在产" ? '#52C41A' : '#FAAD14',
|
|
||||||
border: `1px solid ${model.status === "在产" ? '#B7EB8F' : '#FFE58F'}`
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{model.status}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>编辑</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>授权</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>配置</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>固件</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Assembly Checklist */}
|
|
||||||
<div className="bg-white rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="p-6 border-b" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
<h3 className="text-lg font-semibold">装配Checklist模板</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Tabs */}
|
|
||||||
<div className="flex border-b" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
{Object.keys(checklistData).map((model) => (
|
|
||||||
<button
|
|
||||||
key={model}
|
|
||||||
onClick={() => setActiveTab(model)}
|
|
||||||
className="px-6 py-3 text-sm font-medium transition-colors"
|
|
||||||
style={{
|
|
||||||
color: activeTab === model ? '#1890FF' : 'rgba(0, 0, 0, 0.65)',
|
|
||||||
borderBottom: activeTab === model ? '2px solid #1890FF' : 'none',
|
|
||||||
marginBottom: activeTab === model ? '-1px' : '0',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{model}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Checklist Content */}
|
|
||||||
<div className="p-6">
|
|
||||||
<div className="space-y-3">
|
|
||||||
{checklistData[activeTab as keyof typeof checklistData].map((item) => (
|
|
||||||
<div
|
|
||||||
key={item.id}
|
|
||||||
className="flex items-center gap-4 p-4 rounded"
|
|
||||||
style={{ backgroundColor: '#FAFAFA' }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0"
|
|
||||||
style={{ backgroundColor: '#1890FF', color: 'white' }}
|
|
||||||
>
|
|
||||||
{item.id}
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">{item.item}</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
{item.needPhoto && (
|
|
||||||
<span
|
|
||||||
className="px-3 py-1 rounded text-xs flex items-center gap-1"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', color: '#1890FF' }}
|
|
||||||
>
|
|
||||||
<Camera size={12} />
|
|
||||||
需拍照
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{item.versionCheck && (
|
|
||||||
<span
|
|
||||||
className="px-3 py-1 rounded text-xs flex items-center gap-1"
|
|
||||||
style={{ backgroundColor: '#F9F0FF', color: '#722ED1' }}
|
|
||||||
>
|
|
||||||
<ShieldCheck size={12} />
|
|
||||||
版本校验
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Board Version Requirements */}
|
|
||||||
<div className="bg-white rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="p-6 border-b" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
<h3 className="text-lg font-semibold">板卡版本要求</h3>
|
|
||||||
</div>
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead style={{ backgroundColor: '#FAFAFA' }}>
|
|
||||||
<tr>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>板卡类型</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>要求固件版本</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>校验规则</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>操作</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{boardVersionData.map((board, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className="border-b"
|
|
||||||
style={{ borderColor: '#F0F0F0' }}
|
|
||||||
>
|
|
||||||
<td className="px-6 py-4">{board.boardType}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={{ backgroundColor: '#F0F2F5', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
{board.requiredVersion}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{board.validationRule}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>编辑</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>测试</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,416 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import {
|
||||||
|
Info,
|
||||||
|
Server,
|
||||||
|
CheckCircle2,
|
||||||
|
AlertTriangle,
|
||||||
|
Layers,
|
||||||
|
Plus,
|
||||||
|
Trash2,
|
||||||
|
GripVertical,
|
||||||
|
} from 'lucide-vue-next'
|
||||||
|
|
||||||
|
interface ChecklistItem {
|
||||||
|
id: number
|
||||||
|
text: string
|
||||||
|
type: 'text' | 'bool'
|
||||||
|
required: boolean
|
||||||
|
note: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ChecklistData {
|
||||||
|
[key: string]: ChecklistItem[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeTab = ref('GD30')
|
||||||
|
|
||||||
|
const stats = [
|
||||||
|
{ label: '型号总数', value: '12', icon: Server, color: '#1890FF' },
|
||||||
|
{ label: '在产型号', value: '8', icon: CheckCircle2, color: '#52C41A' },
|
||||||
|
{ label: '停产型号', value: '3', icon: AlertTriangle, color: '#FAAD14' },
|
||||||
|
{ label: '关联设备总数', value: '5,234', icon: Layers, color: '#722ED1' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const modelData = [
|
||||||
|
{
|
||||||
|
name: 'GD30 高密度电法仪',
|
||||||
|
code: 'GD30-2024',
|
||||||
|
authFile: 'auth_gd30_v2.3.lic',
|
||||||
|
configFile: 'config_gd30_v1.5.json',
|
||||||
|
firmwareVersion: 'v2.3.5',
|
||||||
|
deviceCount: 2456,
|
||||||
|
status: '在产' as const,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'GT20 瞬变电磁仪',
|
||||||
|
code: 'GT20-2023',
|
||||||
|
authFile: 'auth_gt20_v1.8.lic',
|
||||||
|
configFile: 'config_gt20_v1.2.json',
|
||||||
|
firmwareVersion: 'v1.8.2',
|
||||||
|
deviceCount: 1823,
|
||||||
|
status: '在产' as const,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'GM10 大地电磁仪',
|
||||||
|
code: 'GM10-2022',
|
||||||
|
authFile: 'auth_gm10_v1.5.lic',
|
||||||
|
configFile: 'config_gm10_v1.0.json',
|
||||||
|
firmwareVersion: 'v1.5.1',
|
||||||
|
deviceCount: 955,
|
||||||
|
status: '停产' as const,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const checklistData = ref<ChecklistData>({
|
||||||
|
GD30: [
|
||||||
|
{ id: 1, text: '主板SN扫码绑定主机', type: 'text', required: true, note: '唯一SN' },
|
||||||
|
{ id: 2, text: '采集板SN录入', type: 'text', required: true, note: '1/6/12通道' },
|
||||||
|
{ id: 3, text: '发射板SN录入', type: 'text', required: true, note: '' },
|
||||||
|
{ id: 4, text: '内置升压模块检查', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 5, text: 'GPS/北斗检测', type: 'bool', required: true, note: '授时正常' },
|
||||||
|
{ id: 6, text: '电池安装与容量检测', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 7, text: '输入电压12~48V测试', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 8, text: '接收电压精度校验', type: 'bool', required: true, note: '按型号量程' },
|
||||||
|
{ id: 9, text: '自电补偿±10V', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 10, text: '输入阻抗≥100MΩ', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 11, text: '恒压/恒流模式', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 12, text: '最大发射电流达标', type: 'bool', required: true, note: '6A/10A/10A' },
|
||||||
|
{ id: 13, text: '脉冲宽度配置', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 14, text: '调级输出电压', type: 'bool', required: true, note: '100~600V' },
|
||||||
|
{ id: 15, text: '系统启动正常', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 16, text: '采集APP连接', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 17, text: 'Geometa账号配置', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 18, text: '授权文件校验', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 19, text: 'USB/WiFi/网口/SD', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 20, text: 'IP66防护与密封', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 21, text: '过流/过压/短路保护', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 22, text: '出厂装箱核对', type: 'bool', required: true, note: '' },
|
||||||
|
],
|
||||||
|
GT20: [
|
||||||
|
{ id: 1, text: '主板SN扫码绑定主机', type: 'text', required: true, note: '唯一SN' },
|
||||||
|
{ id: 2, text: '采集板SN录入', type: 'text', required: true, note: '' },
|
||||||
|
{ id: 3, text: 'GPS/北斗检测', type: 'bool', required: true, note: '授时正常' },
|
||||||
|
{ id: 4, text: '系统启动正常', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 5, text: '整体功能测试', type: 'bool', required: true, note: '' },
|
||||||
|
],
|
||||||
|
GTXD: [
|
||||||
|
{ id: 1, text: '主板SN扫码绑定主机', type: 'text', required: true, note: '唯一SN' },
|
||||||
|
{ id: 2, text: '传感器模块连接', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 3, text: '接口板安装', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 4, text: '线缆整理', type: 'bool', required: true, note: '' },
|
||||||
|
{ id: 5, text: '系统初始化检测', type: 'bool', required: true, note: '' },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const editingCell = ref<{ model: string; id: number; field: string } | null>(null)
|
||||||
|
|
||||||
|
const updateChecklistItem = (model: string, id: number, field: keyof ChecklistItem, value: string | boolean) => {
|
||||||
|
checklistData.value = {
|
||||||
|
...checklistData.value,
|
||||||
|
[model]: checklistData.value[model].map((item: ChecklistItem) =>
|
||||||
|
item.id === id ? { ...item, [field]: value } : item
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addChecklistItem = (model: string) => {
|
||||||
|
const items = checklistData.value[model]
|
||||||
|
const newId = items.length > 0 ? Math.max(...items.map((i: ChecklistItem) => i.id)) + 1 : 1
|
||||||
|
checklistData.value = {
|
||||||
|
...checklistData.value,
|
||||||
|
[model]: [...items, { id: newId, text: '新检查项', type: 'bool' as const, required: true, note: '' }],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteChecklistItem = (model: string, id: number) => {
|
||||||
|
checklistData.value = {
|
||||||
|
...checklistData.value,
|
||||||
|
[model]: checklistData.value[model].filter((item: ChecklistItem) => item.id !== id).map((item: ChecklistItem, i: number) => ({ ...item, id: i + 1 })),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEditBlur = (e: Event, model: string, id: number) => {
|
||||||
|
updateChecklistItem(model, id, 'text', (e.target as HTMLInputElement).value)
|
||||||
|
editingCell.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEditKeydown = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Enter') (e.target as HTMLInputElement).blur()
|
||||||
|
}
|
||||||
|
|
||||||
|
const boardVersionData = [
|
||||||
|
{
|
||||||
|
boardType: '主板',
|
||||||
|
requiredVersion: 'v2.3.x',
|
||||||
|
validationRule: '版本号前缀必须为 v2.3',
|
||||||
|
status: 'active',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
boardType: '采集板',
|
||||||
|
requiredVersion: 'v1.8.x',
|
||||||
|
validationRule: '版本号前缀必须为 v1.8',
|
||||||
|
status: 'active',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
boardType: '测控板',
|
||||||
|
requiredVersion: 'v1.5.x',
|
||||||
|
validationRule: '版本号前缀必须为 v1.5',
|
||||||
|
status: 'active',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-2xl font-semibold mb-1">设备型号管理</h2>
|
||||||
|
<p class="text-sm" :style="{ color: 'rgba(0, 0, 0, 0.45)' }">管理设备型号及相关配置</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Banner -->
|
||||||
|
<div
|
||||||
|
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
:style="{ backgroundColor: '#E6F7FF', border: '1px solid #91D5FF' }"
|
||||||
|
>
|
||||||
|
<Info :size="20" :style="{ color: '#1890FF', flexShrink: 0, marginTop: '2px' }" />
|
||||||
|
<div :style="{ color: '#0050B3' }">
|
||||||
|
型号管理是平台核心枢纽,每个型号关联授权文件、配置文件和固件版本
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stat Cards -->
|
||||||
|
<div class="grid grid-cols-4 gap-6 mb-6">
|
||||||
|
<div
|
||||||
|
v-for="(stat, index) in stats"
|
||||||
|
:key="index"
|
||||||
|
class="bg-white p-6 rounded-lg"
|
||||||
|
:style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ stat.label }}</div>
|
||||||
|
<div class="text-3xl font-semibold">{{ stat.value }}</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-lg flex items-center justify-center"
|
||||||
|
:style="{ backgroundColor: `${stat.color}15` }"
|
||||||
|
>
|
||||||
|
<component :is="stat.icon" :size="24" :style="{ color: stat.color }" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Model Table -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<div class="p-6 border-b" :style="{ borderColor: '#F0F0F0' }">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-lg font-semibold">型号列表</h3>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded text-white"
|
||||||
|
:style="{ backgroundColor: '#1890FF' }"
|
||||||
|
>
|
||||||
|
新增型号
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead :style="{ backgroundColor: '#FAFAFA' }">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">型号名称</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">编码</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">授权文件</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">配置文件</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">固件版本</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">设备数</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">状态</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(model, index) in modelData"
|
||||||
|
:key="index"
|
||||||
|
class="border-b"
|
||||||
|
:style="{ borderColor: '#F0F0F0' }"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4">{{ model.name }}</td>
|
||||||
|
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ model.code }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">{{ model.authFile }}</button>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">{{ model.configFile }}</button>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">{{ model.firmwareVersion }}</button>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">{{ model.deviceCount.toLocaleString() }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded text-xs"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: model.status === '在产' ? '#F6FFED' : '#FFFBE6',
|
||||||
|
color: model.status === '在产' ? '#52C41A' : '#FAAD14',
|
||||||
|
border: `1px solid ${model.status === '在产' ? '#B7EB8F' : '#FFE58F'}`,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ model.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">编辑</button>
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">授权</button>
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">配置</button>
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">固件</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Assembly Checklist -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<div class="p-6 border-b" :style="{ borderColor: '#F0F0F0' }">
|
||||||
|
<h3 class="text-lg font-semibold">装配Checklist模板</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tabs -->
|
||||||
|
<div class="flex border-b" :style="{ borderColor: '#F0F0F0' }">
|
||||||
|
<button
|
||||||
|
v-for="model in Object.keys(checklistData)"
|
||||||
|
:key="model"
|
||||||
|
@click="activeTab = model"
|
||||||
|
class="px-6 py-3 text-sm font-medium transition-colors"
|
||||||
|
:style="{
|
||||||
|
color: activeTab === model ? '#1890FF' : 'rgba(0, 0, 0, 0.65)',
|
||||||
|
borderBottom: activeTab === model ? '2px solid #1890FF' : 'none',
|
||||||
|
marginBottom: activeTab === model ? '-1px' : '0',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ model }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Checklist Content -->
|
||||||
|
<div class="p-6">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead :style="{ backgroundColor: '#FAFAFA' }">
|
||||||
|
<tr>
|
||||||
|
<th class="px-3 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)', width: '50px' }">序号</th>
|
||||||
|
<th class="px-3 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">项目名称</th>
|
||||||
|
<th class="px-3 py-3 text-center text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)', width: '70px' }">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="item in checklistData[activeTab]"
|
||||||
|
:key="item.id"
|
||||||
|
class="border-b"
|
||||||
|
:style="{ borderColor: '#F0F0F0' }"
|
||||||
|
>
|
||||||
|
<td class="px-3 py-3 text-sm" :style="{ color: 'rgba(0, 0, 0, 0.45)' }">
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<GripVertical :size="14" :style="{ color: '#D9D9D9' }" />
|
||||||
|
{{ item.id }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-3 text-sm">
|
||||||
|
<input
|
||||||
|
v-if="editingCell?.model === activeTab && editingCell?.id === item.id && editingCell?.field === 'text'"
|
||||||
|
autofocus
|
||||||
|
class="w-full px-2 py-1 border rounded text-sm"
|
||||||
|
:style="{ borderColor: '#1890FF' }"
|
||||||
|
:value="item.text"
|
||||||
|
@blur="handleEditBlur($event, activeTab, item.id)"
|
||||||
|
@keydown="handleEditKeydown"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="cursor-pointer hover:text-blue-500"
|
||||||
|
@click="editingCell = { model: activeTab, id: item.id, field: 'text' }"
|
||||||
|
>
|
||||||
|
{{ item.text }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-3 text-center">
|
||||||
|
<button
|
||||||
|
@click="deleteChecklistItem(activeTab, item.id)"
|
||||||
|
class="text-gray-400 hover:text-red-500 transition-colors"
|
||||||
|
>
|
||||||
|
<Trash2 :size="15" />
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="mt-4 flex items-center justify-between">
|
||||||
|
<button
|
||||||
|
@click="addChecklistItem(activeTab)"
|
||||||
|
class="px-4 py-2 text-sm flex items-center gap-1 rounded transition-colors"
|
||||||
|
:style="{ color: '#1890FF', border: '1px dashed #1890FF' }"
|
||||||
|
>
|
||||||
|
<Plus :size="14" />
|
||||||
|
添加检查项
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 text-sm rounded text-white"
|
||||||
|
:style="{ backgroundColor: '#1890FF' }"
|
||||||
|
>
|
||||||
|
确认保存
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Board Version Requirements -->
|
||||||
|
<div class="bg-white rounded-lg" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<div class="p-6 border-b" :style="{ borderColor: '#F0F0F0' }">
|
||||||
|
<h3 class="text-lg font-semibold">板卡版本要求</h3>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead :style="{ backgroundColor: '#FAFAFA' }">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">板卡类型</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">要求固件版本</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">校验规则</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(board, index) in boardVersionData"
|
||||||
|
:key="index"
|
||||||
|
class="border-b"
|
||||||
|
:style="{ borderColor: '#F0F0F0' }"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4">{{ board.boardType }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded text-xs"
|
||||||
|
:style="{ backgroundColor: '#F0F2F5', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
{{ board.requiredVersion }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ board.validationRule }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">编辑</button>
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">测试</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,337 +0,0 @@
|
||||||
import { useState } from "react";
|
|
||||||
import {
|
|
||||||
CheckCircle2,
|
|
||||||
AlertTriangle,
|
|
||||||
Camera,
|
|
||||||
Upload,
|
|
||||||
X,
|
|
||||||
Check
|
|
||||||
} from "lucide-react";
|
|
||||||
|
|
||||||
export default function DeviceRegistration() {
|
|
||||||
const [selectedModel, setSelectedModel] = useState("GD30");
|
|
||||||
const [checklistItems, setChecklistItems] = useState([
|
|
||||||
{ id: 1, text: "主板安装及固定", completed: true, photos: 3, needPhoto: true, versionCheck: true, versionMatch: true },
|
|
||||||
{ id: 2, text: "采集板连接", completed: true, photos: 2, needPhoto: true, versionCheck: true, versionMatch: true },
|
|
||||||
{ id: 3, text: "测控板安装", completed: true, photos: 2, needPhoto: true, versionCheck: true, versionMatch: false },
|
|
||||||
{ id: 4, text: "电源线连接检查", completed: false, photos: 0, needPhoto: true, versionCheck: false, versionMatch: true },
|
|
||||||
{ id: 5, text: "外壳密封性检测", completed: false, photos: 0, needPhoto: true, versionCheck: false, versionMatch: true },
|
|
||||||
]);
|
|
||||||
|
|
||||||
const bomData = [
|
|
||||||
{ code: "MB-2024-001", name: "主控板", sn: "MB20240308001", spec: "GD30-MB-V2.3", calibration: "已校准", quantity: 1 },
|
|
||||||
{ code: "AC-2024-002", name: "采集板", sn: "AC20240308002", spec: "GD30-AC-V1.8", calibration: "已校准", quantity: 1 },
|
|
||||||
{ code: "CT-2024-003", name: "测控板", sn: "CT20240308003", spec: "GD30-CT-V1.5", calibration: "已校准", quantity: 1 },
|
|
||||||
{ code: "PS-2024-004", name: "电源模块", sn: "PS20240308004", spec: "DC24V-5A", calibration: "无需校准", quantity: 1 },
|
|
||||||
{ code: "CS-2024-005", name: "外壳组件", sn: "-", spec: "AL6061-T6", calibration: "无需校准", quantity: 1 },
|
|
||||||
];
|
|
||||||
|
|
||||||
const completedCount = checklistItems.filter(item => item.completed).length;
|
|
||||||
const totalCount = checklistItems.length;
|
|
||||||
|
|
||||||
const toggleChecklistItem = (id: number) => {
|
|
||||||
setChecklistItems(items =>
|
|
||||||
items.map(item =>
|
|
||||||
item.id === id ? { ...item, completed: !item.completed } : item
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<h2 className="text-2xl font-semibold mb-1">设备登记</h2>
|
|
||||||
<p className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>登记新设备信息及装配记录</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Installation Info Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">装机信息</h3>
|
|
||||||
<div className="grid grid-cols-3 gap-6">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
设备型号 <span style={{ color: '#FF4D4F' }}>*</span>
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
value={selectedModel}
|
|
||||||
onChange={(e) => setSelectedModel(e.target.value)}
|
|
||||||
>
|
|
||||||
<option value="GD30">GD30 地质探测仪</option>
|
|
||||||
<option value="GT20">GT20 物探仪</option>
|
|
||||||
<option value="GTXD">GTXD 探测仪</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
主机SN号 <span style={{ color: '#FF4D4F' }}>*</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
placeholder="请输入主机SN号"
|
|
||||||
defaultValue="GD30-20240308-001"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
主板SN号 <span style={{ color: '#FF4D4F' }}>*</span>
|
|
||||||
</label>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="flex-1 px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
placeholder="请输入主板SN号"
|
|
||||||
defaultValue="MB20240308001"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs whitespace-nowrap"
|
|
||||||
style={{ backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' }}
|
|
||||||
>
|
|
||||||
已绑定
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
装机测试状态
|
|
||||||
</label>
|
|
||||||
<div className="flex items-center gap-2 px-3 py-2 border rounded" style={{ borderColor: '#D9D9D9', backgroundColor: '#FAFAFA' }}>
|
|
||||||
<CheckCircle2 size={16} style={{ color: '#52C41A' }} />
|
|
||||||
<span style={{ color: '#52C41A' }}>测试通过</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
登记日期
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="date"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="2024-03-08"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
登记人
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#FAFAFA' }}
|
|
||||||
defaultValue="张工程师"
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Success Banner */}
|
|
||||||
<div
|
|
||||||
className="mb-4 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{ backgroundColor: '#F6FFED', border: '1px solid #B7EB8F' }}
|
|
||||||
>
|
|
||||||
<CheckCircle2 size={20} style={{ color: '#52C41A', flexShrink: 0, marginTop: 2 }} />
|
|
||||||
<div>
|
|
||||||
<div style={{ color: '#389E0D', fontWeight: 500 }}>型号已匹配:GD30</div>
|
|
||||||
<div className="text-sm mt-1" style={{ color: '#52C41A' }}>
|
|
||||||
授权文件:auth_gd30_v2.3.lic | 配置文件:config_gd30_v1.5.json | 固件版本:v2.3.5
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Warning Banner (Optional - shown when model doesn't match) */}
|
|
||||||
<div
|
|
||||||
className="mb-6 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{ backgroundColor: '#FFFBE6', border: '1px solid #FFE58F', display: 'none' }}
|
|
||||||
>
|
|
||||||
<AlertTriangle size={20} style={{ color: '#FAAD14', flexShrink: 0, marginTop: 2 }} />
|
|
||||||
<div>
|
|
||||||
<div style={{ color: '#D46B08', fontWeight: 500 }}>未匹配到型号关联信息</div>
|
|
||||||
<div className="text-sm mt-1" style={{ color: '#FAAD14' }}>
|
|
||||||
请先在型号管理中配置该型号的授权文件、配置文件和固件版本
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* BOM List Card */}
|
|
||||||
<div className="bg-white rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="p-6 border-b" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h3 className="text-lg font-semibold">设备BOM清单</h3>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Upload size={16} />
|
|
||||||
批量导入
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead style={{ backgroundColor: '#FAFAFA' }}>
|
|
||||||
<tr>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>物料编码</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>物料名称</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>SN号</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>规格型号</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>校准状态</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>数量</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>操作</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{bomData.map((item, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className="border-b"
|
|
||||||
style={{ borderColor: '#F0F0F0' }}
|
|
||||||
>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{item.code}</td>
|
|
||||||
<td className="px-6 py-4">{item.name}</td>
|
|
||||||
<td className="px-6 py-4">{item.sn}</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{item.spec}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={{
|
|
||||||
backgroundColor: item.calibration === "已校准" ? '#F6FFED' : '#F0F2F5',
|
|
||||||
color: item.calibration === "已校准" ? '#52C41A' : 'rgba(0, 0, 0, 0.65)',
|
|
||||||
border: `1px solid ${item.calibration === "已校准" ? '#B7EB8F' : '#D9D9D9'}`
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.calibration}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">{item.quantity}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>编辑</button>
|
|
||||||
<button className="text-sm" style={{ color: '#FF4D4F' }}>删除</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div className="p-4 border-t" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>+ 添加物料</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Assembly Checklist Card */}
|
|
||||||
<div className="bg-white rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="p-6 border-b" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h3 className="text-lg font-semibold">装配Checklist (GD30 模板)</h3>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>完成进度</span>
|
|
||||||
<span className="text-sm font-semibold" style={{ color: '#1890FF' }}>
|
|
||||||
{completedCount}/{totalCount}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="p-6">
|
|
||||||
<div className="space-y-3">
|
|
||||||
{checklistItems.map((item) => (
|
|
||||||
<div
|
|
||||||
key={item.id}
|
|
||||||
className="flex items-center gap-4 p-4 rounded border"
|
|
||||||
style={{
|
|
||||||
backgroundColor: item.completed ? '#F6FFED' : '#FAFAFA',
|
|
||||||
borderColor: item.completed ? '#B7EB8F' : '#F0F0F0'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
onClick={() => toggleChecklistItem(item.id)}
|
|
||||||
className="w-6 h-6 rounded border flex items-center justify-center flex-shrink-0 transition-colors"
|
|
||||||
style={{
|
|
||||||
borderColor: item.completed ? '#52C41A' : '#D9D9D9',
|
|
||||||
backgroundColor: item.completed ? '#52C41A' : '#fff'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.completed && <Check size={16} color="#fff" />}
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
className="w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0"
|
|
||||||
style={{ backgroundColor: item.completed ? '#52C41A' : '#D9D9D9', color: 'white' }}
|
|
||||||
>
|
|
||||||
{item.id}
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span style={{ color: item.completed ? 'rgba(0, 0, 0, 0.85)' : 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
{item.text}
|
|
||||||
</span>
|
|
||||||
{item.versionCheck && !item.versionMatch && (
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs flex items-center gap-1"
|
|
||||||
style={{ backgroundColor: '#FFF1F0', color: '#FF4D4F', border: '1px solid #FFCCC7' }}
|
|
||||||
>
|
|
||||||
<AlertTriangle size={12} />
|
|
||||||
版本不一致!
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
{item.needPhoto && item.completed && item.photos > 0 && (
|
|
||||||
<span
|
|
||||||
className="px-3 py-1 rounded text-xs flex items-center gap-1"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', color: '#1890FF' }}
|
|
||||||
>
|
|
||||||
<Camera size={12} />
|
|
||||||
已上传 {item.photos}张
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{item.needPhoto && !item.completed && (
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded text-xs flex items-center gap-1"
|
|
||||||
style={{ backgroundColor: '#1890FF', color: '#fff' }}
|
|
||||||
>
|
|
||||||
<Camera size={12} />
|
|
||||||
拍照上传
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Action Bar */}
|
|
||||||
<div
|
|
||||||
className="flex items-center justify-end gap-3 p-4 bg-white rounded-lg sticky bottom-0"
|
|
||||||
style={{ boxShadow: '0 -2px 8px rgba(0, 0, 0, 0.05)' }}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
取消
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
保存草稿
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded text-white"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
>
|
|
||||||
提交
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,331 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import {
|
||||||
|
CheckCircle2,
|
||||||
|
AlertTriangle,
|
||||||
|
Camera,
|
||||||
|
Upload,
|
||||||
|
Check,
|
||||||
|
} from 'lucide-vue-next'
|
||||||
|
|
||||||
|
const selectedModel = ref('GD30')
|
||||||
|
const checklistItems = ref([
|
||||||
|
{ id: 1, text: '主板安装及固定', completed: true, photos: 3, needPhoto: true, versionCheck: true, versionMatch: true },
|
||||||
|
{ id: 2, text: '采集板连接', completed: true, photos: 2, needPhoto: true, versionCheck: true, versionMatch: true },
|
||||||
|
{ id: 3, text: '测控板安装', completed: true, photos: 2, needPhoto: true, versionCheck: true, versionMatch: false },
|
||||||
|
{ id: 4, text: '电源线连接检查', completed: false, photos: 0, needPhoto: true, versionCheck: false, versionMatch: true },
|
||||||
|
{ id: 5, text: '外壳密封性检测', completed: false, photos: 0, needPhoto: true, versionCheck: false, versionMatch: true },
|
||||||
|
])
|
||||||
|
|
||||||
|
const bomData = [
|
||||||
|
{ code: 'MB-2024-001', name: '主控板', sn: 'MB20240308001', spec: 'GD30-MB-V2.3', calibration: '无需校准', quantity: 1 },
|
||||||
|
{ code: 'RX-2024-002', name: '采集板', sn: 'RX20240308002', spec: 'GD30-RX-V1.8', calibration: '已校准', quantity: 2 },
|
||||||
|
{ code: 'MC-2024-003', name: '测控板', sn: 'MC20240308003', spec: 'GD30-MC-V1.5', calibration: '无需校准', quantity: 1 },
|
||||||
|
{ code: 'TX-2024-003', name: '发射板', sn: 'TX20240308003', spec: 'GD30-TX-V1.5', calibration: '无需校准', quantity: 1 },
|
||||||
|
{ code: 'BO-2024-004', name: '升压板', sn: 'BO20240308004', spec: 'BP600', calibration: '无需校准', quantity: 1 },
|
||||||
|
{ code: 'CS-2024-005', name: '外壳机箱', sn: '-', spec: 'AL6061-T6', calibration: '无需校准', quantity: 1 },
|
||||||
|
]
|
||||||
|
|
||||||
|
const completedCount = computed(() => checklistItems.value.filter((item: typeof checklistItems.value[number]) => item.completed).length)
|
||||||
|
const totalCount = computed(() => checklistItems.value.length)
|
||||||
|
|
||||||
|
const toggleChecklistItem = (id: number) => {
|
||||||
|
checklistItems.value = checklistItems.value.map((item: typeof checklistItems.value[number]) =>
|
||||||
|
item.id === id ? { ...item, completed: !item.completed } : item
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h2 class="text-2xl font-semibold mb-1">设备登记</h2>
|
||||||
|
<p class="text-sm" :style="{ color: 'rgba(0, 0, 0, 0.45)' }">登记新设备信息及装配记录</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Installation Info Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">装机信息</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||||||
|
设备型号 <span :style="{ color: '#FF4D4F' }">*</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
v-model="selectedModel"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
:style="{ borderColor: '#D9D9D9', backgroundColor: '#fff' }"
|
||||||
|
>
|
||||||
|
<option value="GD30">GD30 高密度电法仪</option>
|
||||||
|
<option value="GT20">GT20 瞬变电磁仪</option>
|
||||||
|
<option value="GTXD">GM10 大地电磁仪</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||||||
|
主机SN号 <span :style="{ color: '#FF4D4F' }">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
:style="{ borderColor: '#D9D9D9' }"
|
||||||
|
placeholder="请输入主机SN号"
|
||||||
|
value="GD30-20240308-001"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||||||
|
主板SN号 <span :style="{ color: '#FF4D4F' }">*</span>
|
||||||
|
</label>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="flex-1 px-3 py-2 border rounded"
|
||||||
|
:style="{ borderColor: '#D9D9D9' }"
|
||||||
|
placeholder="请输入主板SN号"
|
||||||
|
value="MB20240308001"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded text-xs whitespace-nowrap"
|
||||||
|
:style="{ backgroundColor: '#F6FFED', color: '#52C41A', border: '1px solid #B7EB8F' }"
|
||||||
|
>
|
||||||
|
已绑定
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||||||
|
装机测试状态
|
||||||
|
</label>
|
||||||
|
<div class="flex items-center gap-2 px-3 py-2 border rounded" :style="{ borderColor: '#D9D9D9', backgroundColor: '#FAFAFA' }">
|
||||||
|
<select>
|
||||||
|
<option><span :style="{ color: '#52C41A' }">测试通过</span></option>
|
||||||
|
<option><span :style="{ color: '#c41a1aff' }">测试不通过</span></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||||||
|
生产日期
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
:style="{ borderColor: '#D9D9D9' }"
|
||||||
|
value="2024-03-08"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">
|
||||||
|
登记人
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
:style="{ borderColor: '#D9D9D9', backgroundColor: '#FAFAFA' }"
|
||||||
|
value="张工程师"
|
||||||
|
readonly
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Success Banner -->
|
||||||
|
<div
|
||||||
|
class="mb-4 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
:style="{ backgroundColor: '#F6FFED', border: '1px solid #B7EB8F' }"
|
||||||
|
>
|
||||||
|
<CheckCircle2 :size="20" :style="{ color: '#52C41A', flexShrink: 0, marginTop: '2px' }" />
|
||||||
|
<div>
|
||||||
|
<div :style="{ color: '#389E0D', fontWeight: 500 }">型号已匹配:GD30</div>
|
||||||
|
<div class="text-sm mt-1" :style="{ color: '#52C41A' }">
|
||||||
|
授权文件:auth_gd30_v2.3.lic | 配置文件:config_gd30_v1.5.json | 固件版本:v2.3.5
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Warning Banner (Optional - shown when model doesn't match) -->
|
||||||
|
<div
|
||||||
|
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
:style="{ backgroundColor: '#FFFBE6', border: '1px solid #FFE58F', display: 'none' }"
|
||||||
|
>
|
||||||
|
<AlertTriangle :size="20" :style="{ color: '#FAAD14', flexShrink: 0, marginTop: '2px' }" />
|
||||||
|
<div>
|
||||||
|
<div :style="{ color: '#D46B08', fontWeight: 500 }">未匹配到型号关联信息</div>
|
||||||
|
<div class="text-sm mt-1" :style="{ color: '#FAAD14' }">
|
||||||
|
请先在型号管理中配置该型号的授权文件、配置文件和固件版本
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- BOM List Card -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<div class="p-6 border-b" :style="{ borderColor: '#F0F0F0' }">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-lg font-semibold">设备BOM清单</h3>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded flex items-center gap-2"
|
||||||
|
:style="{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
<Upload :size="16" />
|
||||||
|
导入
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead :style="{ backgroundColor: '#FAFAFA' }">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">物料编码</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">物料名称</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">SN号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">规格型号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">校准状态</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">数量</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(item, index) in bomData"
|
||||||
|
:key="index"
|
||||||
|
class="border-b"
|
||||||
|
:style="{ borderColor: '#F0F0F0' }"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ item.code }}</td>
|
||||||
|
<td class="px-6 py-4">{{ item.name }}</td>
|
||||||
|
<td class="px-6 py-4">{{ item.sn }}</td>
|
||||||
|
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ item.spec }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded text-xs"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: item.calibration === '已校准' ? '#F6FFED' : '#F0F2F5',
|
||||||
|
color: item.calibration === '已校准' ? '#52C41A' : 'rgba(0, 0, 0, 0.65)',
|
||||||
|
border: `1px solid ${item.calibration === '已校准' ? '#B7EB8F' : '#D9D9D9'}`,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ item.calibration }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">{{ item.quantity }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">编辑</button>
|
||||||
|
<button class="text-sm" :style="{ color: '#FF4D4F' }">删除</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="p-4 border-t" :style="{ borderColor: '#F0F0F0' }">
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">+ 添加物料</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Assembly Checklist Card -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<div class="p-6 border-b" :style="{ borderColor: '#F0F0F0' }">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-lg font-semibold">装配Checklist</h3>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="text-sm" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">完成进度</span>
|
||||||
|
<span class="text-sm font-semibold" :style="{ color: '#1890FF' }">
|
||||||
|
{{ completedCount }}/{{ totalCount }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div
|
||||||
|
v-for="item in checklistItems"
|
||||||
|
:key="item.id"
|
||||||
|
class="flex items-center gap-4 p-4 rounded border"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: item.completed ? '#F6FFED' : '#FAFAFA',
|
||||||
|
borderColor: item.completed ? '#B7EB8F' : '#F0F0F0',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
@click="toggleChecklistItem(item.id)"
|
||||||
|
class="w-6 h-6 rounded border flex items-center justify-center flex-shrink-0 transition-colors"
|
||||||
|
:style="{
|
||||||
|
borderColor: item.completed ? '#52C41A' : '#D9D9D9',
|
||||||
|
backgroundColor: item.completed ? '#52C41A' : '#fff',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<Check v-if="item.completed" :size="16" color="#fff" />
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
class="w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0"
|
||||||
|
:style="{ backgroundColor: item.completed ? '#52C41A' : '#D9D9D9', color: 'white' }"
|
||||||
|
>
|
||||||
|
{{ item.id }}
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span :style="{ color: item.completed ? 'rgba(0, 0, 0, 0.85)' : 'rgba(0, 0, 0, 0.65)' }">
|
||||||
|
{{ item.text }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-if="item.versionCheck && !item.versionMatch"
|
||||||
|
class="px-2 py-1 rounded text-xs flex items-center gap-1"
|
||||||
|
:style="{ backgroundColor: '#FFF1F0', color: '#FF4D4F', border: '1px solid #FFCCC7' }"
|
||||||
|
>
|
||||||
|
<AlertTriangle :size="12" />
|
||||||
|
版本不一致!
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span
|
||||||
|
v-if="item.needPhoto && item.completed && item.photos > 0"
|
||||||
|
class="px-3 py-1 rounded text-xs flex items-center gap-1"
|
||||||
|
:style="{ backgroundColor: '#E6F7FF', color: '#1890FF' }"
|
||||||
|
>
|
||||||
|
<Camera :size="12" />
|
||||||
|
已上传 {{ item.photos }}张
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
v-if="item.needPhoto && !item.completed"
|
||||||
|
class="px-3 py-1 rounded text-xs flex items-center gap-1"
|
||||||
|
:style="{ backgroundColor: '#1890FF', color: '#fff' }"
|
||||||
|
>
|
||||||
|
<Camera :size="12" />
|
||||||
|
拍照上传
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Bar -->
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-end gap-3 p-4 bg-white rounded-lg sticky bottom-0"
|
||||||
|
:style="{ boxShadow: '0 -2px 8px rgba(0, 0, 0, 0.05)' }"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded"
|
||||||
|
:style="{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded"
|
||||||
|
:style="{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
更新
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded text-white"
|
||||||
|
:style="{ backgroundColor: '#1890FF' }"
|
||||||
|
>
|
||||||
|
提交
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Upload } from 'lucide-vue-next'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
interface Firmware {
|
||||||
|
version: string
|
||||||
|
releaseDate: string
|
||||||
|
status: '已发布' | '草稿'
|
||||||
|
fileSize: string
|
||||||
|
downloads: number
|
||||||
|
md5?: string
|
||||||
|
sha256?: string
|
||||||
|
model?: string
|
||||||
|
hardwareRange?: string
|
||||||
|
upgradeType?: string
|
||||||
|
signed?: boolean
|
||||||
|
notes?: string[]
|
||||||
|
expanded: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const firmwares = ref<Firmware[]>([
|
||||||
|
{
|
||||||
|
version: 'v2.3.0',
|
||||||
|
releaseDate: '2024-02-20',
|
||||||
|
status: '已发布',
|
||||||
|
fileSize: '12.5MB',
|
||||||
|
downloads: 1234,
|
||||||
|
md5: 'a1b2c3d4e5f6...',
|
||||||
|
sha256: '...',
|
||||||
|
model: 'GD30',
|
||||||
|
hardwareRange: 'A1-A3',
|
||||||
|
upgradeType: '可选',
|
||||||
|
signed: true,
|
||||||
|
notes: [
|
||||||
|
'修复OTA升级流程中的断点续传Bug',
|
||||||
|
'优化设备心跳上报频率',
|
||||||
|
'新增配置文件远程下发功能',
|
||||||
|
'增强安全性,升级前强制验证固件签名',
|
||||||
|
],
|
||||||
|
expanded: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: 'v2.2.0',
|
||||||
|
releaseDate: '2024-01-15',
|
||||||
|
status: '已发布',
|
||||||
|
fileSize: '12.0MB',
|
||||||
|
downloads: 2456,
|
||||||
|
expanded: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: 'v2.1.0',
|
||||||
|
releaseDate: '2023-12-01',
|
||||||
|
status: '已发布',
|
||||||
|
fileSize: '11.5MB',
|
||||||
|
downloads: 3587,
|
||||||
|
expanded: false,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<h2 class="text-2xl font-semibold">固件库</h2>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="px-4 py-2 rounded text-white flex items-center gap-2" style="background-color: #1890FF">
|
||||||
|
<Upload :size="16" />
|
||||||
|
上传固件
|
||||||
|
</button>
|
||||||
|
<button class="px-4 py-2 rounded flex items-center gap-2" style="border: 1px solid #D9D9D9; color: rgba(0,0,0,0.85)">
|
||||||
|
发布固件
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Firmware Version List -->
|
||||||
|
<div class="bg-white rounded-lg" style="box-shadow: 0 1px 2px rgba(0,0,0,0.05)">
|
||||||
|
<div class="p-6 border-b" style="border-color: #F0F0F0">
|
||||||
|
<h3 class="text-base font-medium">固件版本库</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="divide-y" style="border-color: #F0F0F0">
|
||||||
|
<div v-for="fw in firmwares" :key="fw.version" class="p-6">
|
||||||
|
<!-- Header row -->
|
||||||
|
<div class="flex items-center gap-4 mb-2">
|
||||||
|
<span class="text-lg font-semibold">版本: {{ fw.version }}</span>
|
||||||
|
<span class="text-sm" style="color: rgba(0,0,0,0.45)">发布日期: {{ fw.releaseDate }}</span>
|
||||||
|
<span class="text-sm" style="color: #52C41A">{{ fw.status }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Basic info -->
|
||||||
|
<div class="text-sm mb-1" style="color: rgba(0,0,0,0.65)">
|
||||||
|
文件大小: {{ fw.fileSize }} 下载次数: {{ fw.downloads.toLocaleString() }}次
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Expanded detail -->
|
||||||
|
<template v-if="fw.expanded && fw.md5">
|
||||||
|
<div class="text-sm mb-1" style="color: rgba(0,0,0,0.65)">
|
||||||
|
MD5: {{ fw.md5 }} SHA256: {{ fw.sha256 }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm mb-3" style="color: rgba(0,0,0,0.65)">
|
||||||
|
适用型号: {{ fw.model }} 硬件版本范围: {{ fw.hardwareRange }} 升级类型: {{ fw.upgradeType }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Signature -->
|
||||||
|
<div v-if="fw.signed" class="mb-3">
|
||||||
|
<span class="text-sm" style="color: #52C41A">数字签名: 已签名</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Release notes -->
|
||||||
|
<div v-if="fw.notes && fw.notes.length" class="mb-4">
|
||||||
|
<div class="text-sm font-medium mb-1" style="color: rgba(0,0,0,0.85)">发布说明:</div>
|
||||||
|
<ul class="text-sm list-disc pl-5" style="color: rgba(0,0,0,0.65)">
|
||||||
|
<li v-for="(note, i) in fw.notes" :key="i">{{ note }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Actions (expanded) -->
|
||||||
|
<div class="flex items-center gap-6 pt-2">
|
||||||
|
<button class="text-sm" style="color: #1890FF">下载</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">编辑</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">撤回发布</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">查看升级任务</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- Collapsed actions -->
|
||||||
|
<template v-else>
|
||||||
|
<div class="flex items-center gap-6 pt-3">
|
||||||
|
<button class="text-sm" style="color: #1890FF">下载</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF" @click="fw.expanded = true">查看详情</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft, Info } from 'lucide-vue-next'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const selectedModel = ref('GD-10 Supreme')
|
||||||
|
const expiryType = ref('永久')
|
||||||
|
const expiryDate = ref('')
|
||||||
|
|
||||||
|
interface AuthItem {
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const authItems = ref<AuthItem[]>([
|
||||||
|
{ name: '1D SP' },
|
||||||
|
{ name: '2D SP' },
|
||||||
|
{ name: '3D SP' },
|
||||||
|
{ name: '1D VES' },
|
||||||
|
{ name: '2D ERT' },
|
||||||
|
{ name: '3D ERT' },
|
||||||
|
{ name: '1D IP'},
|
||||||
|
{ name: '2D IP' },
|
||||||
|
{ name: '3D IP'},
|
||||||
|
{ name: '跨孔(Cross-Hole)' },
|
||||||
|
{ name: '水上(Marine)'},
|
||||||
|
])
|
||||||
|
|
||||||
|
const availableItems = computed(() => {
|
||||||
|
return authItems.value.map(item => {
|
||||||
|
let available = false
|
||||||
|
return { ...item, available }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const checkedItems = ref(new Set<string>())
|
||||||
|
|
||||||
|
const toggleItem = (name: string) => {
|
||||||
|
if (checkedItems.value.has(name)) checkedItems.value.delete(name)
|
||||||
|
else checkedItems.value.add(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectAll = () => {
|
||||||
|
availableItems.value.forEach(item => {
|
||||||
|
if (item.available) checkedItems.value.add(item.name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearAll = () => {
|
||||||
|
checkedItems.value.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedCount = computed(() => {
|
||||||
|
return availableItems.value.filter(i => i.available && checkedItems.value.has(i.name)).length
|
||||||
|
})
|
||||||
|
|
||||||
|
const totalAvailable = computed(() => {
|
||||||
|
return availableItems.value.filter(i => i.available).length
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center gap-4 mb-2">
|
||||||
|
<button @click="router.go(-1)" class="p-2 rounded hover:bg-gray-100 transition-colors" style="color: rgba(0,0,0,0.65)">
|
||||||
|
<ArrowLeft :size="20" />
|
||||||
|
</button>
|
||||||
|
<h2 class="text-2xl font-semibold">选择授权项生成</h2>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm ml-12" style="color: rgba(0,0,0,0.45)">选择设备型号和授权功能模块,生成授权文件</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Banner -->
|
||||||
|
<div class="mb-6 p-4 rounded-lg flex items-start gap-3" style="background-color: #E6F7FF; border: 1px solid #91D5FF">
|
||||||
|
<Info :size="20" style="color: #1890FF; flex-shrink: 0; margin-top: 2px" />
|
||||||
|
<div style="color: #0050B3">
|
||||||
|
<div class="text-sm">
|
||||||
|
不同设备型号支持不同的授权功能模块。选择型号后,下方表格会显示该型号可用的授权项。生成的授权文件将在设备APP激活时自动下载到对应设备。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Model & Expiry Selection -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0,0,0,0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">基本信息</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0,0,0,0.85)">设备型号 <span style="color: #FF4D4F">*</span></label>
|
||||||
|
<select v-model="selectedModel" class="w-full px-3 py-2 border rounded" style="border-color: #D9D9D9; background-color: #fff" @change="clearAll()">
|
||||||
|
<option>GD-10 Supreme</option>
|
||||||
|
<option>GD-20 Supreme</option>
|
||||||
|
<option>GD-30 Supreme</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0,0,0,0.85)">授权有效期</label>
|
||||||
|
<select v-model="expiryType" class="w-full px-3 py-2 border rounded" style="border-color: #D9D9D9; background-color: #fff">
|
||||||
|
<option>永久</option>
|
||||||
|
<option>1年</option>
|
||||||
|
<option>2年</option>
|
||||||
|
<option>自定义</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div v-if="expiryType === '自定义'">
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0,0,0,0.85)">到期日期</label>
|
||||||
|
<input type="date" v-model="expiryDate" class="w-full px-3 py-2 border rounded" style="border-color: #D9D9D9" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Authorization Items Table -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0,0,0,0.05)">
|
||||||
|
<div class="p-6 border-b flex items-center justify-between" style="border-color: #F0F0F0">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<h3 class="text-lg font-semibold">功能授权项选择</h3>
|
||||||
|
<span class="text-sm" style="color: rgba(0,0,0,0.45)">已选 {{ selectedCount }} / {{ totalAvailable }} 项</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" style="color: #1890FF" @click="selectAll">全选可用项</button>
|
||||||
|
<button class="text-sm" style="color: rgba(0,0,0,0.45)" @click="clearAll">清空</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead style="background-color: #FAFAFA">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0,0,0,0.85); width: 150px">选择</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0,0,0,0.85)">授权项名称</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(item, index) in availableItems" :key="index" class="border-b" style="border-color: #F0F0F0">
|
||||||
|
<td class="px-6 py-3">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="w-4 h-4"
|
||||||
|
style="accent-color: #1890FF"
|
||||||
|
:checked="checkedItems.has(item.name)"
|
||||||
|
:disabled="!item.available"
|
||||||
|
@change="toggleItem(item.name)"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-3 text-sm">{{ item.name }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Bar -->
|
||||||
|
<div class="flex items-center justify-end gap-3 p-4 bg-white rounded-lg sticky bottom-0" style="box-shadow: 0 -2px 8px rgba(0,0,0,0.05)">
|
||||||
|
<button class="px-6 py-2 rounded" style="border: 1px solid #D9D9D9; color: rgba(0,0,0,0.85)" @click="router.go(-1)">取消</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded text-white"
|
||||||
|
:style="{ backgroundColor: selectedCount > 0 ? '#52C41A' : '#D9D9D9' }"
|
||||||
|
:disabled="selectedCount === 0"
|
||||||
|
@click="router.push('/licenses')"
|
||||||
|
>
|
||||||
|
生成授权文件({{ selectedCount }}项)
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,249 +0,0 @@
|
||||||
import { useState } from "react";
|
|
||||||
import { Plus, Upload, Download, Info } from "lucide-react";
|
|
||||||
|
|
||||||
interface License {
|
|
||||||
sn: string;
|
|
||||||
licenseId: string;
|
|
||||||
status: "已激活" | "已生成" | "待激活";
|
|
||||||
generationDate: string;
|
|
||||||
expiryDate: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function LicenseManagement() {
|
|
||||||
const licenses: License[] = [
|
|
||||||
{
|
|
||||||
sn: "GD30-2025-000001",
|
|
||||||
licenseId: "LIC-2025-0001",
|
|
||||||
status: "已激活",
|
|
||||||
generationDate: "2025-02-01",
|
|
||||||
expiryDate: "2026-02-01",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sn: "GT20-2025-000045",
|
|
||||||
licenseId: "LIC-2025-0045",
|
|
||||||
status: "已生成",
|
|
||||||
generationDate: "2025-02-05",
|
|
||||||
expiryDate: "2026-02-05",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sn: "GTXD-2025-000023",
|
|
||||||
licenseId: "LIC-2025-0023",
|
|
||||||
status: "待激活",
|
|
||||||
generationDate: "2025-02-08",
|
|
||||||
expiryDate: "2026-02-08",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getStatusStyle = (status: License["status"]) => {
|
|
||||||
switch (status) {
|
|
||||||
case "已激活":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#F6FFED',
|
|
||||||
color: '#52C41A',
|
|
||||||
border: '1px solid #B7EB8F'
|
|
||||||
};
|
|
||||||
case "已生成":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#E6F7FF',
|
|
||||||
color: '#1890FF',
|
|
||||||
border: '1px solid #91D5FF'
|
|
||||||
};
|
|
||||||
case "待激活":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#FFFBE6',
|
|
||||||
color: '#FAAD14',
|
|
||||||
border: '1px solid #FFE58F'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<div className="flex items-center justify-between mb-2">
|
|
||||||
<h2 className="text-2xl font-semibold">授权管理</h2>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Upload size={16} />
|
|
||||||
批量生成
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Download size={16} />
|
|
||||||
导出
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded text-white flex items-center gap-2"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
>
|
|
||||||
<Plus size={16} />
|
|
||||||
选择授权项生成
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>管理设备授权文件</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info Banner */}
|
|
||||||
<div
|
|
||||||
className="mb-6 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{ backgroundColor: '#E6FFFB', border: '1px solid #87E8DE' }}
|
|
||||||
>
|
|
||||||
<Info size={20} style={{ color: '#13C2C2', flexShrink: 0, marginTop: 2 }} />
|
|
||||||
<div style={{ color: '#006D75' }}>
|
|
||||||
<div className="font-medium mb-1">授权说明</div>
|
|
||||||
<div className="text-sm">
|
|
||||||
授权文件按型号关联,点击选择授权项生成可勾选功能模块和有效期。生产装配阶段有配置无授权,授权在出厂阶段生成。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filter Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="grid grid-cols-4 gap-4">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
设备SN号
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
placeholder="输入设备SN号搜索"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
授权状态
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>已激活</option>
|
|
||||||
<option>已生成</option>
|
|
||||||
<option>待激活</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
设备型号
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>GD30 地质探测仪</option>
|
|
||||||
<option>GT20 物探仪</option>
|
|
||||||
<option>GTXD 探测仪</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-end">
|
|
||||||
<button
|
|
||||||
className="w-full px-4 py-2 rounded text-white"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
>
|
|
||||||
查询
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* License List */}
|
|
||||||
<div className="bg-white rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead style={{ backgroundColor: '#FAFAFA' }}>
|
|
||||||
<tr>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>设备SN号</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>授权ID</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>状态</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>生成日期</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>到期日期</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>操作</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{licenses.map((license, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className="border-b"
|
|
||||||
style={{ borderColor: '#F0F0F0' }}
|
|
||||||
>
|
|
||||||
<td className="px-6 py-4">{license.sn}</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{license.licenseId}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={getStatusStyle(license.status)}
|
|
||||||
>
|
|
||||||
{license.status}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{license.generationDate}</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{license.expiryDate}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>详情</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>下载</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>续期</button>
|
|
||||||
<button className="text-sm" style={{ color: '#FF4D4F' }}>撤销</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Pagination */}
|
|
||||||
<div className="bg-white p-4 rounded-lg flex items-center justify-between" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
显示 1-10 / 共 156 条
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.45)' }}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
上一页
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded"
|
|
||||||
style={{ backgroundColor: '#1890FF', color: '#fff' }}
|
|
||||||
>
|
|
||||||
1
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
2
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
3
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
下一页
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,251 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Plus, Upload, Download, Info } from 'lucide-vue-next'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
interface License {
|
||||||
|
sn: string
|
||||||
|
licenseId: string
|
||||||
|
status: '已激活' | '已生成' | '待激活'
|
||||||
|
generationDate: string
|
||||||
|
expiryDate: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const licenses: License[] = [
|
||||||
|
{
|
||||||
|
sn: 'GD30-2025-000001',
|
||||||
|
licenseId: 'LIC-2025-0001',
|
||||||
|
status: '已激活',
|
||||||
|
generationDate: '2025-02-01',
|
||||||
|
expiryDate: '2026-02-01',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sn: 'GT20-2025-000045',
|
||||||
|
licenseId: 'LIC-2025-0045',
|
||||||
|
status: '已生成',
|
||||||
|
generationDate: '2025-02-05',
|
||||||
|
expiryDate: '2026-02-05',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sn: 'GTXD-2025-000023',
|
||||||
|
licenseId: 'LIC-2025-0023',
|
||||||
|
status: '待激活',
|
||||||
|
generationDate: '2025-02-08',
|
||||||
|
expiryDate: '2026-02-08',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const getStatusStyle = (status: License['status']) => {
|
||||||
|
switch (status) {
|
||||||
|
case '已激活':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#F6FFED',
|
||||||
|
color: '#52C41A',
|
||||||
|
border: '1px solid #B7EB8F',
|
||||||
|
}
|
||||||
|
case '已生成':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#E6F7FF',
|
||||||
|
color: '#1890FF',
|
||||||
|
border: '1px solid #91D5FF',
|
||||||
|
}
|
||||||
|
case '待激活':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#FFFBE6',
|
||||||
|
color: '#FAAD14',
|
||||||
|
border: '1px solid #FFE58F',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<h2 class="text-2xl font-semibold">授权管理</h2>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded flex items-center gap-2"
|
||||||
|
:style="{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
<Upload :size="16" />
|
||||||
|
批量生成
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded flex items-center gap-2"
|
||||||
|
:style="{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
<Download :size="16" />
|
||||||
|
导出
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded text-white flex items-center gap-2"
|
||||||
|
:style="{ backgroundColor: '#1890FF' }"
|
||||||
|
@click="router.push('/licenses/generate')"
|
||||||
|
>
|
||||||
|
<Plus :size="16" />
|
||||||
|
选择授权项生成
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm" :style="{ color: 'rgba(0, 0, 0, 0.45)' }">管理设备授权文件</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Banner -->
|
||||||
|
<div
|
||||||
|
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
:style="{ backgroundColor: '#E6FFFB', border: '1px solid #87E8DE' }"
|
||||||
|
>
|
||||||
|
<Info :size="20" :style="{ color: '#13C2C2', flexShrink: 0, marginTop: '2px' }" />
|
||||||
|
<div :style="{ color: '#006D75' }">
|
||||||
|
<div class="font-medium mb-1">授权说明</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
授权文件按型号关联,点击选择授权项生成可勾选功能模块和有效期。生产装配阶段有配置无授权,授权在出厂阶段生成。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<div class="grid grid-cols-4 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">
|
||||||
|
设备SN号
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
:style="{ borderColor: '#D9D9D9' }"
|
||||||
|
placeholder="输入设备SN号搜索"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">
|
||||||
|
授权状态
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
:style="{ borderColor: '#D9D9D9', backgroundColor: '#fff' }"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>已激活</option>
|
||||||
|
<option>已生成</option>
|
||||||
|
<option>待激活</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">
|
||||||
|
设备型号
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
:style="{ borderColor: '#D9D9D9', backgroundColor: '#fff' }"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>GD30 高密度电法仪</option>
|
||||||
|
<option>GT20 瞬变电磁仪</option>
|
||||||
|
<option>GM10 大地电磁仪</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end">
|
||||||
|
<button
|
||||||
|
class="w-full px-4 py-2 rounded text-white"
|
||||||
|
:style="{ backgroundColor: '#1890FF' }"
|
||||||
|
>
|
||||||
|
查询
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- License List -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead :style="{ backgroundColor: '#FAFAFA' }">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">设备SN号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">授权ID</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">状态</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">生成日期</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">到期日期</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" :style="{ color: 'rgba(0, 0, 0, 0.85)' }">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(license, index) in licenses"
|
||||||
|
:key="index"
|
||||||
|
class="border-b"
|
||||||
|
:style="{ borderColor: '#F0F0F0' }"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4">{{ license.sn }}</td>
|
||||||
|
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ license.licenseId }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span
|
||||||
|
class="px-2 py-1 rounded text-xs"
|
||||||
|
:style="getStatusStyle(license.status)"
|
||||||
|
>
|
||||||
|
{{ license.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ license.generationDate }}</td>
|
||||||
|
<td class="px-6 py-4" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">{{ license.expiryDate }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">详情</button>
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">下载</button>
|
||||||
|
<button class="text-sm" :style="{ color: '#1890FF' }">续期</button>
|
||||||
|
<button class="text-sm" :style="{ color: '#FF4D4F' }">撤销</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<div class="bg-white p-4 rounded-lg flex items-center justify-between" :style="{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }">
|
||||||
|
<div class="text-sm" :style="{ color: 'rgba(0, 0, 0, 0.65)' }">
|
||||||
|
显示 1-10 / 共 156 条
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
:style="{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.45)' }"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
上一页
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded"
|
||||||
|
:style="{ backgroundColor: '#1890FF', color: '#fff' }"
|
||||||
|
>
|
||||||
|
1
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
:style="{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
2
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
:style="{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
3
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
:style="{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }"
|
||||||
|
>
|
||||||
|
下一页
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,310 +0,0 @@
|
||||||
import { ArrowLeft, Eye } from "lucide-react";
|
|
||||||
import { useNavigate } from "react-router";
|
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
export default function ParameterConfiguration() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [transmissionVoltage, setTransmissionVoltage] = useState("1500V");
|
|
||||||
const [transmissionCurrent, setTransmissionCurrent] = useState("10A");
|
|
||||||
const [pulseWidthOptions] = useState([
|
|
||||||
{ value: "0.25s", checked: true },
|
|
||||||
{ value: "0.5s", checked: true },
|
|
||||||
{ value: "1s", checked: true },
|
|
||||||
{ value: "2s", checked: true },
|
|
||||||
{ value: "4s", checked: true },
|
|
||||||
{ value: "8s", checked: true },
|
|
||||||
{ value: "16s", checked: true },
|
|
||||||
{ value: "32s", checked: true },
|
|
||||||
{ value: "64s", checked: true },
|
|
||||||
]);
|
|
||||||
const [waveformOptions] = useState([
|
|
||||||
{ value: "0+0-", checked: true },
|
|
||||||
{ value: "+0-0", checked: true },
|
|
||||||
{ value: "+-", checked: true },
|
|
||||||
]);
|
|
||||||
const [samplingRateOptions] = useState([
|
|
||||||
{ value: "50Hz", checked: true },
|
|
||||||
{ value: "60Hz", checked: true },
|
|
||||||
{ value: "100Hz", checked: true },
|
|
||||||
{ value: "1000Hz", checked: true },
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<div className="flex items-center gap-4 mb-2">
|
|
||||||
<button
|
|
||||||
onClick={() => navigate(-1)}
|
|
||||||
className="p-2 rounded hover:bg-gray-100 transition-colors"
|
|
||||||
style={{ color: 'rgba(0, 0, 0, 0.65)' }}
|
|
||||||
>
|
|
||||||
<ArrowLeft size={20} />
|
|
||||||
</button>
|
|
||||||
<h2 className="text-2xl font-semibold">参数配置</h2>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm ml-12" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>配置设备型号的详细参数</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Model Info Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">型号信息</h3>
|
|
||||||
<div className="grid grid-cols-3 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>适配型号</div>
|
|
||||||
<div className="font-medium">GD30 地质探测仪</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>当前配置版本</div>
|
|
||||||
<div style={{ color: '#1890FF' }}>v1.2.0</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>最后更新时间</div>
|
|
||||||
<div style={{ color: 'rgba(0, 0, 0, 0.65)' }}>2024-03-01 10:30</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Transmission Parameters Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">发射参数</h3>
|
|
||||||
<div className="grid grid-cols-2 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
最大发射电压
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
value={transmissionVoltage}
|
|
||||||
onChange={(e) => setTransmissionVoltage(e.target.value)}
|
|
||||||
>
|
|
||||||
<option>500V</option>
|
|
||||||
<option>800V</option>
|
|
||||||
<option>1000V</option>
|
|
||||||
<option>1200V</option>
|
|
||||||
<option>1500V</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
最大发射电流
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
value={transmissionCurrent}
|
|
||||||
onChange={(e) => setTransmissionCurrent(e.target.value)}
|
|
||||||
>
|
|
||||||
<option>2A</option>
|
|
||||||
<option>5A</option>
|
|
||||||
<option>8A</option>
|
|
||||||
<option>10A</option>
|
|
||||||
<option>15A</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2">
|
|
||||||
<label className="block text-sm mb-3" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
发射脉宽
|
|
||||||
</label>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
{pulseWidthOptions.map((option) => (
|
|
||||||
<label
|
|
||||||
key={option.value}
|
|
||||||
className="px-4 py-2 rounded border cursor-pointer transition-colors"
|
|
||||||
style={{
|
|
||||||
borderColor: option.checked ? '#1890FF' : '#D9D9D9',
|
|
||||||
backgroundColor: option.checked ? '#E6F7FF' : '#fff',
|
|
||||||
color: option.checked ? '#1890FF' : 'rgba(0, 0, 0, 0.65)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input type="checkbox" className="hidden" checked={option.checked} readOnly />
|
|
||||||
{option.value}
|
|
||||||
</label>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2">
|
|
||||||
<label className="block text-sm mb-3" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
发射波形
|
|
||||||
</label>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
{waveformOptions.map((option) => (
|
|
||||||
<label
|
|
||||||
key={option.value}
|
|
||||||
className="px-4 py-2 rounded border cursor-pointer transition-colors"
|
|
||||||
style={{
|
|
||||||
borderColor: option.checked ? '#1890FF' : '#D9D9D9',
|
|
||||||
backgroundColor: option.checked ? '#E6F7FF' : '#fff',
|
|
||||||
color: option.checked ? '#1890FF' : 'rgba(0, 0, 0, 0.65)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input type="checkbox" className="hidden" checked={option.checked} readOnly />
|
|
||||||
{option.value}
|
|
||||||
</label>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Acquisition Parameters Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">采集参数</h3>
|
|
||||||
<div className="grid grid-cols-2 gap-x-12 gap-y-6">
|
|
||||||
<div className="col-span-2">
|
|
||||||
<label className="block text-sm mb-3" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
采样率
|
|
||||||
</label>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
{samplingRateOptions.map((option) => (
|
|
||||||
<label
|
|
||||||
key={option.value}
|
|
||||||
className="px-4 py-2 rounded border cursor-pointer transition-colors"
|
|
||||||
style={{
|
|
||||||
borderColor: option.checked ? '#1890FF' : '#D9D9D9',
|
|
||||||
backgroundColor: option.checked ? '#E6F7FF' : '#fff',
|
|
||||||
color: option.checked ? '#1890FF' : 'rgba(0, 0, 0, 0.65)'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input type="checkbox" className="hidden" checked={option.checked} readOnly />
|
|
||||||
{option.value}
|
|
||||||
</label>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
支持通道数
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="32"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
迭代次数范围
|
|
||||||
</label>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
className="flex-1 px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="1"
|
|
||||||
/>
|
|
||||||
<span style={{ color: 'rgba(0, 0, 0, 0.45)' }}>-</span>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
className="flex-1 px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="256"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Network Parameters Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">网络参数</h3>
|
|
||||||
<div className="grid grid-cols-2 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
WiFi SSID
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="GD30_Device"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
WiFi密码
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="12345678"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
默认IP地址
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="192.168.1.100"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
子网掩码
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="255.255.255.0"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
默认网关
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="192.168.1.1"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
DNS服务器
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
defaultValue="8.8.8.8"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Action Bar */}
|
|
||||||
<div
|
|
||||||
className="flex items-center justify-end gap-3 p-4 bg-white rounded-lg sticky bottom-0"
|
|
||||||
style={{ boxShadow: '0 -2px 8px rgba(0, 0, 0, 0.05)' }}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
重置默认
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Eye size={16} />
|
|
||||||
预览配置
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded text-white"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
>
|
|
||||||
下发配置
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,429 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft, Eye } from 'lucide-vue-next'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const isNew = computed(() => route.params.configId === 'new')
|
||||||
|
const selectedModel = ref('GD30')
|
||||||
|
const configVersion = ref('v1.0.0')
|
||||||
|
const transmissionVoltage = ref('1500V')
|
||||||
|
const transmissionCurrent = ref('10A')
|
||||||
|
const voltageMeasureOptions = ref([
|
||||||
|
{ value: '±2.5V', checked: true },
|
||||||
|
{ value: '±80V', checked: true },
|
||||||
|
{ value: '±600V', checked: false },
|
||||||
|
])
|
||||||
|
const supportFullWaveform = ref(true)
|
||||||
|
const supportDuty50 = ref(true)
|
||||||
|
const supportDuty100 = ref(true)
|
||||||
|
const overvoltageProtection = ref(true)
|
||||||
|
const overvoltageThreshold = ref('1600')
|
||||||
|
const overcurrentProtection = ref(true)
|
||||||
|
const overcurrentThreshold = ref('12')
|
||||||
|
const shortCircuitProtection = ref(true)
|
||||||
|
const highTempProtection = ref(true)
|
||||||
|
const highTempThreshold = ref('75')
|
||||||
|
const pulseWidthOptions = ref([
|
||||||
|
{ value: '0.25s', checked: true },
|
||||||
|
{ value: '0.5s', checked: true },
|
||||||
|
{ value: '1s', checked: true },
|
||||||
|
{ value: '2s', checked: true },
|
||||||
|
{ value: '4s', checked: true },
|
||||||
|
{ value: '8s', checked: true },
|
||||||
|
{ value: '16s', checked: true },
|
||||||
|
{ value: '32s', checked: true },
|
||||||
|
{ value: '64s', checked: true },
|
||||||
|
])
|
||||||
|
const waveformOptions = ref([
|
||||||
|
{ value: '0+0-', checked: true },
|
||||||
|
{ value: '+0-0', checked: true },
|
||||||
|
{ value: '+-', checked: true },
|
||||||
|
])
|
||||||
|
const samplingRateOptions = ref([
|
||||||
|
{ value: '50Hz', checked: true },
|
||||||
|
{ value: '60Hz', checked: true },
|
||||||
|
{ value: '100Hz', checked: true },
|
||||||
|
{ value: '1000Hz', checked: true },
|
||||||
|
])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center gap-4 mb-2">
|
||||||
|
<button
|
||||||
|
@click="router.go(-1)"
|
||||||
|
class="p-2 rounded hover:bg-gray-100 transition-colors"
|
||||||
|
style="color: rgba(0, 0, 0, 0.65)"
|
||||||
|
>
|
||||||
|
<ArrowLeft :size="20" />
|
||||||
|
</button>
|
||||||
|
<h2 class="text-2xl font-semibold">{{ isNew ? '新建配置文件' : '参数配置' }}</h2>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm ml-12" style="color: rgba(0, 0, 0, 0.45)">{{ isNew ? '选择设备型号和参数,生成配置文件' : '配置设备型号的详细参数' }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Model Info Card (new mode: editable, edit mode: readonly) -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">型号信息</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">适配型号</label>
|
||||||
|
<select v-if="isNew" v-model="selectedModel" class="w-full px-3 py-2 border rounded" style="border-color: #D9D9D9; background-color: #fff">
|
||||||
|
<option value="GD30">GD30 高密度电法仪</option>
|
||||||
|
<option value="GT20">GT20 瞬变电磁仪</option>
|
||||||
|
<option value="GM10">GM10 大地电磁仪</option>
|
||||||
|
</select>
|
||||||
|
<div v-else class="font-medium">GD30 高密度电法仪</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">配置文件版本</label>
|
||||||
|
<input v-if="isNew" type="text" v-model="configVersion" class="w-full px-3 py-2 border rounded" style="border-color: #D9D9D9" placeholder="如 v1.0.0" />
|
||||||
|
<div v-else style="color: #1890FF">v1.2.0</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">{{ isNew ? '状态' : '最后更新时间' }}</div>
|
||||||
|
<span v-if="isNew" class="px-2 py-1 rounded text-xs" style="background-color: #FFFBE6; color: #FAAD14; border: 1px solid #FFE58F">待生成</span>
|
||||||
|
<div v-else style="color: rgba(0, 0, 0, 0.65)">2024-03-01 10:30</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Transmission Parameters Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">发射参数</h3>
|
||||||
|
<div class="grid grid-cols-2 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
最大发射电压
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
v-model="transmissionVoltage"
|
||||||
|
>
|
||||||
|
<option>500V</option>
|
||||||
|
<option>800V</option>
|
||||||
|
<option>1000V</option>
|
||||||
|
<option>1200V</option>
|
||||||
|
<option>1500V</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
最大发射电流
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
v-model="transmissionCurrent"
|
||||||
|
>
|
||||||
|
<option>2A</option>
|
||||||
|
<option>5A</option>
|
||||||
|
<option>8A</option>
|
||||||
|
<option>10A</option>
|
||||||
|
<option>15A</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-2">
|
||||||
|
<label class="block text-sm mb-3" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
发射脉宽
|
||||||
|
</label>
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<label
|
||||||
|
v-for="option in pulseWidthOptions"
|
||||||
|
:key="option.value"
|
||||||
|
class="px-4 py-2 rounded border cursor-pointer transition-colors"
|
||||||
|
:style="{
|
||||||
|
borderColor: option.checked ? '#1890FF' : '#D9D9D9',
|
||||||
|
backgroundColor: option.checked ? '#E6F7FF' : '#fff',
|
||||||
|
color: option.checked ? '#1890FF' : 'rgba(0, 0, 0, 0.65)',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<input type="checkbox" class="hidden" :checked="option.checked" readonly />
|
||||||
|
{{ option.value }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-2">
|
||||||
|
<label class="block text-sm mb-3" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
发射波形
|
||||||
|
</label>
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<label
|
||||||
|
v-for="option in waveformOptions"
|
||||||
|
:key="option.value"
|
||||||
|
class="px-4 py-2 rounded border cursor-pointer transition-colors"
|
||||||
|
:style="{
|
||||||
|
borderColor: option.checked ? '#1890FF' : '#D9D9D9',
|
||||||
|
backgroundColor: option.checked ? '#E6F7FF' : '#fff',
|
||||||
|
color: option.checked ? '#1890FF' : 'rgba(0, 0, 0, 0.65)',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<input type="checkbox" class="hidden" :checked="option.checked" readonly />
|
||||||
|
{{ option.value }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">支持全波形测量</label>
|
||||||
|
<label class="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="supportFullWaveform" class="w-4 h-4" style="accent-color: #1890FF" />
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.65)">{{ supportFullWaveform ? '是' : '否' }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">占空比支持</label>
|
||||||
|
<div class="flex items-center gap-6">
|
||||||
|
<label class="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="supportDuty50" class="w-4 h-4" style="accent-color: #1890FF" />
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.65)">50% 占空比</span>
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="supportDuty100" class="w-4 h-4" style="accent-color: #1890FF" />
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.65)">100% 占空比</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Acquisition Parameters Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">采集参数</h3>
|
||||||
|
<div class="grid grid-cols-2 gap-x-12 gap-y-6">
|
||||||
|
<div class="col-span-2">
|
||||||
|
<label class="block text-sm mb-3" style="color: rgba(0, 0, 0, 0.85)">电压测量范围</label>
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<label
|
||||||
|
v-for="option in voltageMeasureOptions"
|
||||||
|
:key="option.value"
|
||||||
|
class="px-4 py-2 rounded border cursor-pointer transition-colors"
|
||||||
|
:style="{
|
||||||
|
borderColor: option.checked ? '#1890FF' : '#D9D9D9',
|
||||||
|
backgroundColor: option.checked ? '#E6F7FF' : '#fff',
|
||||||
|
color: option.checked ? '#1890FF' : 'rgba(0, 0, 0, 0.65)',
|
||||||
|
}"
|
||||||
|
@click="option.checked = !option.checked"
|
||||||
|
>
|
||||||
|
{{ option.value }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-2">
|
||||||
|
<label class="block text-sm mb-3" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
采样率
|
||||||
|
</label>
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<label
|
||||||
|
v-for="option in samplingRateOptions"
|
||||||
|
:key="option.value"
|
||||||
|
class="px-4 py-2 rounded border cursor-pointer transition-colors"
|
||||||
|
:style="{
|
||||||
|
borderColor: option.checked ? '#1890FF' : '#D9D9D9',
|
||||||
|
backgroundColor: option.checked ? '#E6F7FF' : '#fff',
|
||||||
|
color: option.checked ? '#1890FF' : 'rgba(0, 0, 0, 0.65)',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<input type="checkbox" class="hidden" :checked="option.checked" readonly />
|
||||||
|
{{ option.value }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
支持通道数
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="12"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
迭代次数范围
|
||||||
|
</label>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="flex-1 px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="1"
|
||||||
|
/>
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.45)">-</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="flex-1 px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="256"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Protection Parameters Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">保护参数</h3>
|
||||||
|
<div class="grid grid-cols-2 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">过压保护</label>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<label class="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="overvoltageProtection" class="w-4 h-4" style="accent-color: #1890FF" />
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.65)">启用</span>
|
||||||
|
</label>
|
||||||
|
<input v-if="overvoltageProtection" type="number" class="w-32 px-3 py-1 border rounded text-sm" style="border-color: #D9D9D9" v-model="overvoltageThreshold" />
|
||||||
|
<span v-if="overvoltageProtection" class="text-sm" style="color: rgba(0, 0, 0, 0.45)">V</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">过流保护</label>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<label class="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="overcurrentProtection" class="w-4 h-4" style="accent-color: #1890FF" />
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.65)">启用</span>
|
||||||
|
</label>
|
||||||
|
<input v-if="overcurrentProtection" type="number" class="w-32 px-3 py-1 border rounded text-sm" style="border-color: #D9D9D9" v-model="overcurrentThreshold" />
|
||||||
|
<span v-if="overcurrentProtection" class="text-sm" style="color: rgba(0, 0, 0, 0.45)">A</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">短路保护</label>
|
||||||
|
<label class="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="shortCircuitProtection" class="w-4 h-4" style="accent-color: #1890FF" />
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.65)">{{ shortCircuitProtection ? '已启用' : '未启用' }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">高温保护</label>
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<label class="flex items-center gap-2 cursor-pointer">
|
||||||
|
<input type="checkbox" v-model="highTempProtection" class="w-4 h-4" style="accent-color: #1890FF" />
|
||||||
|
<span style="color: rgba(0, 0, 0, 0.65)">启用</span>
|
||||||
|
</label>
|
||||||
|
<input v-if="highTempProtection" type="number" class="w-32 px-3 py-1 border rounded text-sm" style="border-color: #D9D9D9" v-model="highTempThreshold" />
|
||||||
|
<span v-if="highTempProtection" class="text-sm" style="color: rgba(0, 0, 0, 0.45)">°C</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Network Parameters Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">网络参数</h3>
|
||||||
|
<div class="grid grid-cols-2 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">WiFi SSID</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="GD30_Device"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">WiFi密码</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="12345678"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">默认IP地址</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="192.168.1.100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">子网掩码</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="255.255.255.0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">默认网关</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="192.168.1.1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">DNS服务器</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
value="8.8.8.8"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Bar -->
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-end gap-3 p-4 bg-white rounded-lg sticky bottom-0"
|
||||||
|
style="box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05)"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
@click="router.go(-1)"
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<template v-if="isNew">
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded flex items-center gap-2"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
>
|
||||||
|
<Eye :size="16" />
|
||||||
|
预览配置
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded text-white"
|
||||||
|
style="background-color: #52C41A"
|
||||||
|
@click="router.push('/config-files')"
|
||||||
|
>
|
||||||
|
确认生成配置文件
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
>
|
||||||
|
重置默认
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded flex items-center gap-2"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
>
|
||||||
|
<Eye :size="16" />
|
||||||
|
预览配置
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded text-white"
|
||||||
|
style="background-color: #1890FF"
|
||||||
|
>
|
||||||
|
下发配置
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
export default function PlaceholderPage({ title }: { title: string }) {
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
<h2 className="text-2xl font-semibold mb-4">{title}</h2>
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<p style={{ color: 'rgba(0, 0, 0, 0.45)' }}>此页面正在开发中...</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<h2 class="text-2xl font-semibold mb-4">{{ title }}</h2>
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0,0,0,0.05)">
|
||||||
|
<p style="color: rgba(0,0,0,0.45)">此页面正在开发中...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{ title: string }>()
|
||||||
|
</script>
|
||||||
|
|
@ -1,322 +0,0 @@
|
||||||
import { ArrowLeft, Clock, AlertTriangle, ArrowRight, Trash2 } from "lucide-react";
|
|
||||||
import { useNavigate } from "react-router";
|
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
export default function RepairOrderDetail() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [regenerateAuth, setRegenerateAuth] = useState(false);
|
|
||||||
const [pushFirmware, setPushFirmware] = useState(false);
|
|
||||||
|
|
||||||
const processingTimeline = [
|
|
||||||
{ time: "2024-03-08 09:00", operator: "张工程师", action: "创建工单", description: "客户报修,设备无法开机" },
|
|
||||||
{ time: "2024-03-08 10:30", operator: "李工程师", action: "故障诊断", description: "初步诊断为主控板故障" },
|
|
||||||
{ time: "2024-03-08 14:00", operator: "王工程师", action: "板卡更换", description: "更换主控板,测试正常" },
|
|
||||||
{ time: "2024-03-08 16:00", operator: "李工程师", action: "测试完成", description: "功能测试通过,等待客户确认" },
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<div className="flex items-center gap-4 mb-2">
|
|
||||||
<button
|
|
||||||
onClick={() => navigate(-1)}
|
|
||||||
className="p-2 rounded hover:bg-gray-100 transition-colors"
|
|
||||||
style={{ color: 'rgba(0, 0, 0, 0.65)' }}
|
|
||||||
>
|
|
||||||
<ArrowLeft size={20} />
|
|
||||||
</button>
|
|
||||||
<h2 className="text-2xl font-semibold">维修工单详情</h2>
|
|
||||||
<span className="text-xl" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>WO-2024-0001</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Work Order Info Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">工单信息</h3>
|
|
||||||
<div className="grid grid-cols-3 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>工单ID</div>
|
|
||||||
<div>WO-2024-0001</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>工单状态</div>
|
|
||||||
<span
|
|
||||||
className="inline-block px-2 py-1 rounded text-xs"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', color: '#1890FF', border: '1px solid #91D5FF' }}
|
|
||||||
>
|
|
||||||
处理中
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>优先级</div>
|
|
||||||
<span
|
|
||||||
className="inline-block px-2 py-1 rounded text-xs"
|
|
||||||
style={{ backgroundColor: '#FFF1F0', color: '#FF4D4F', border: '1px solid #FFCCC7' }}
|
|
||||||
>
|
|
||||||
高
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>创建时间</div>
|
|
||||||
<div>2024-03-08 09:00</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>负责人</div>
|
|
||||||
<div>李工程师</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>预计完成时间</div>
|
|
||||||
<div>2024-03-09 18:00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Device Info Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">设备信息</h3>
|
|
||||||
<div className="grid grid-cols-3 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>设备SN号</div>
|
|
||||||
<div>GD30-2025-000001</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>设备型号</div>
|
|
||||||
<div>GD30 地质探测仪</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>固件版本</div>
|
|
||||||
<div>v2.3.5</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>客户名称</div>
|
|
||||||
<div>北京地质研究院</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>联系方式</div>
|
|
||||||
<div>010-12345678</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>购买日期</div>
|
|
||||||
<div>2025-02-01</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Fault Info Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">故障信息</h3>
|
|
||||||
<div className="grid grid-cols-2 gap-x-12 gap-y-6">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>故障类型</div>
|
|
||||||
<div>硬件故障</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>故障症状</div>
|
|
||||||
<div>设备无法开机,指示灯不亮</div>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2">
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>故障描述</div>
|
|
||||||
<div className="p-3 rounded" style={{ backgroundColor: '#FAFAFA', color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
设备在野外作业时突然关机,之后无法重新启动。检查电源连接正常,充电器工作正常,初步判断为主控板损坏。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Processing Timeline Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">处理记录</h3>
|
|
||||||
<div className="relative">
|
|
||||||
{/* Timeline line */}
|
|
||||||
<div
|
|
||||||
className="absolute left-6 top-6 bottom-6 w-0.5"
|
|
||||||
style={{ backgroundColor: '#F0F0F0' }}
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<div className="space-y-6">
|
|
||||||
{processingTimeline.map((entry, index) => (
|
|
||||||
<div key={index} className="flex gap-4">
|
|
||||||
<div className="flex flex-col items-center flex-shrink-0">
|
|
||||||
<div
|
|
||||||
className="w-12 h-12 rounded-full flex items-center justify-center relative z-10"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', border: '2px solid #1890FF' }}
|
|
||||||
>
|
|
||||||
<Clock size={20} style={{ color: '#1890FF' }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex-1 pt-2">
|
|
||||||
<div className="flex items-center gap-3 mb-2">
|
|
||||||
<span className="font-medium">{entry.action}</span>
|
|
||||||
<span className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>{entry.time}</span>
|
|
||||||
<span className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>操作人:{entry.operator}</span>
|
|
||||||
</div>
|
|
||||||
<div className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
{entry.description}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Board Replacement Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">板卡更换记录</h3>
|
|
||||||
<div className="p-4 rounded-lg" style={{ backgroundColor: '#FAFAFA' }}>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>旧板卡</div>
|
|
||||||
<div className="font-medium">主控板 MB20231215001</div>
|
|
||||||
</div>
|
|
||||||
<ArrowRight size={24} style={{ color: '#1890FF' }} />
|
|
||||||
<div>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>新板卡</div>
|
|
||||||
<div className="font-medium">主控板 MB20240308001</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-right">
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>更换时间</div>
|
|
||||||
<div style={{ color: 'rgba(0, 0, 0, 0.65)' }}>2024-03-08 14:00</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-right">
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>操作人</div>
|
|
||||||
<div>王工程师</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* License Processing Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">授权处理</h3>
|
|
||||||
<div className="space-y-3">
|
|
||||||
<label className="flex items-center gap-3 cursor-pointer">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
className="w-5 h-5 rounded"
|
|
||||||
style={{ accentColor: '#1890FF' }}
|
|
||||||
checked={regenerateAuth}
|
|
||||||
onChange={(e) => setRegenerateAuth(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<span>重新生成授权文件(板卡更换后需重新绑定授权)</span>
|
|
||||||
</label>
|
|
||||||
<label className="flex items-center gap-3 cursor-pointer">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
className="w-5 h-5 rounded"
|
|
||||||
style={{ accentColor: '#1890FF' }}
|
|
||||||
checked={pushFirmware}
|
|
||||||
onChange={(e) => setPushFirmware(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<span>推送适配固件(如更换板卡型号不同,需推送兼容固件)</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Scrap Processing Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<h3 className="text-lg font-semibold mb-6">报废处理</h3>
|
|
||||||
|
|
||||||
{/* Warning Banner */}
|
|
||||||
<div
|
|
||||||
className="mb-6 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{ backgroundColor: '#FFF1F0', border: '1px solid #FFCCC7' }}
|
|
||||||
>
|
|
||||||
<AlertTriangle size={20} style={{ color: '#FF4D4F', flexShrink: 0, marginTop: 2 }} />
|
|
||||||
<div>
|
|
||||||
<div className="font-medium" style={{ color: '#CF1322' }}>警告:报废操作不可逆</div>
|
|
||||||
<div className="text-sm mt-1" style={{ color: '#FF4D4F' }}>
|
|
||||||
报废后设备将无法恢复使用,请谨慎操作
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-x-12 gap-y-6 mb-6">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
报废原因 <span style={{ color: '#FF4D4F' }}>*</span>
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
>
|
|
||||||
<option>请选择报废原因</option>
|
|
||||||
<option>主板损坏无法修复</option>
|
|
||||||
<option>多个核心部件损坏</option>
|
|
||||||
<option>维修成本超过设备价值</option>
|
|
||||||
<option>设备老化严重</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
残值评估 (元)
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
placeholder="输入残值评估金额"
|
|
||||||
defaultValue="500"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-2">
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>
|
|
||||||
可回收物料
|
|
||||||
</label>
|
|
||||||
<div className="p-3 rounded border" style={{ borderColor: '#D9D9D9', backgroundColor: '#FAFAFA' }}>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
|
||||||
<span className="px-3 py-1 rounded text-sm" style={{ backgroundColor: '#E6F7FF', color: '#1890FF' }}>
|
|
||||||
采集板 AC20240308002
|
|
||||||
</span>
|
|
||||||
<span className="px-3 py-1 rounded text-sm" style={{ backgroundColor: '#E6F7FF', color: '#1890FF' }}>
|
|
||||||
测控板 CT20240308003
|
|
||||||
</span>
|
|
||||||
<span className="px-3 py-1 rounded text-sm" style={{ backgroundColor: '#E6F7FF', color: '#1890FF' }}>
|
|
||||||
电源模块 PS20240308004
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Scrap Process Flow */}
|
|
||||||
<div
|
|
||||||
className="p-4 rounded-lg flex items-center gap-3"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', border: '1px solid #91D5FF' }}
|
|
||||||
>
|
|
||||||
<div className="text-sm" style={{ color: '#0050B3' }}>
|
|
||||||
<span className="font-medium">报废流程:</span>
|
|
||||||
申请报废 → 创建报废单 → 报废审批 → 物料回收 → 入库
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Action Bar */}
|
|
||||||
<div
|
|
||||||
className="flex items-center justify-end gap-3 p-4 bg-white rounded-lg sticky bottom-0"
|
|
||||||
style={{ boxShadow: '0 -2px 8px rgba(0, 0, 0, 0.05)' }}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
取消
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded text-white"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
>
|
|
||||||
关闭工单
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-6 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #FF4D4F', color: '#FF4D4F' }}
|
|
||||||
>
|
|
||||||
<Trash2 size={16} />
|
|
||||||
申请报废
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,318 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ArrowLeft, Clock, AlertTriangle, ArrowRight, Trash2 } from 'lucide-vue-next'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const regenerateAuth = ref(false)
|
||||||
|
const pushFirmware = ref(false)
|
||||||
|
|
||||||
|
const processingTimeline = [
|
||||||
|
{ time: '2024-03-08 09:00', operator: '张工程师', action: '创建工单', description: '客户报修,设备无法开机' },
|
||||||
|
{ time: '2024-03-08 10:30', operator: '李工程师', action: '故障诊断', description: '初步诊断为主控板故障' },
|
||||||
|
{ time: '2024-03-08 14:00', operator: '王工程师', action: '板卡更换', description: '更换主控板,测试正常' },
|
||||||
|
{ time: '2024-03-08 16:00', operator: '李工程师', action: '测试完成', description: '功能测试通过,等待客户确认' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center gap-4 mb-2">
|
||||||
|
<button
|
||||||
|
@click="router.go(-1)"
|
||||||
|
class="p-2 rounded hover:bg-gray-100 transition-colors"
|
||||||
|
style="color: rgba(0, 0, 0, 0.65)"
|
||||||
|
>
|
||||||
|
<ArrowLeft :size="20" />
|
||||||
|
</button>
|
||||||
|
<h2 class="text-2xl font-semibold">维修工单详情</h2>
|
||||||
|
<span class="text-xl" style="color: rgba(0, 0, 0, 0.45)">WO-2024-0001</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Work Order Info Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">工单信息</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">工单ID</div>
|
||||||
|
<div>WO-2024-0001</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">工单状态</div>
|
||||||
|
<span
|
||||||
|
class="inline-block px-2 py-1 rounded text-xs"
|
||||||
|
style="background-color: #E6F7FF; color: #1890FF; border: 1px solid #91D5FF"
|
||||||
|
>
|
||||||
|
处理中
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">优先级</div>
|
||||||
|
<span
|
||||||
|
class="inline-block px-2 py-1 rounded text-xs"
|
||||||
|
style="background-color: #FFF1F0; color: #FF4D4F; border: 1px solid #FFCCC7"
|
||||||
|
>
|
||||||
|
高
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">创建时间</div>
|
||||||
|
<div>2024-03-08 09:00</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">负责人</div>
|
||||||
|
<div>李工程师</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">预计完成时间</div>
|
||||||
|
<div>2024-03-09 18:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Device Info Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">设备信息</h3>
|
||||||
|
<div class="grid grid-cols-3 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">设备SN号</div>
|
||||||
|
<div>GD30-2025-000001</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">设备型号</div>
|
||||||
|
<div>GD30 地质探测仪</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">固件版本</div>
|
||||||
|
<div>v2.3.5</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">客户名称</div>
|
||||||
|
<div>北京地质研究院</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">联系方式</div>
|
||||||
|
<div>010-12345678</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">购买日期</div>
|
||||||
|
<div>2025-02-01</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fault Info Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">故障信息</h3>
|
||||||
|
<div class="grid grid-cols-2 gap-x-12 gap-y-6">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">故障类型</div>
|
||||||
|
<div>硬件故障</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">故障症状</div>
|
||||||
|
<div>设备无法开机,指示灯不亮</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-2">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">故障描述</div>
|
||||||
|
<div class="p-3 rounded" style="background-color: #FAFAFA; color: rgba(0, 0, 0, 0.65)">
|
||||||
|
设备在野外作业时突然关机,之后无法重新启动。检查电源连接正常,充电器工作正常,初步判断为主控板损坏。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Processing Timeline Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">处理记录</h3>
|
||||||
|
<div class="relative">
|
||||||
|
<!-- Timeline line -->
|
||||||
|
<div
|
||||||
|
class="absolute left-6 top-6 bottom-6 w-0.5"
|
||||||
|
style="background-color: #F0F0F0"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div v-for="(entry, index) in processingTimeline" :key="index" class="flex gap-4">
|
||||||
|
<div class="flex flex-col items-center flex-shrink-0">
|
||||||
|
<div
|
||||||
|
class="w-12 h-12 rounded-full flex items-center justify-center relative z-10"
|
||||||
|
style="background-color: #E6F7FF; border: 2px solid #1890FF"
|
||||||
|
>
|
||||||
|
<Clock :size="20" style="color: #1890FF" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 pt-2">
|
||||||
|
<div class="flex items-center gap-3 mb-2">
|
||||||
|
<span class="font-medium">{{ entry.action }}</span>
|
||||||
|
<span class="text-sm" style="color: rgba(0, 0, 0, 0.45)">{{ entry.time }}</span>
|
||||||
|
<span class="text-sm" style="color: rgba(0, 0, 0, 0.45)">操作人:{{ entry.operator }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm" style="color: rgba(0, 0, 0, 0.65)">
|
||||||
|
{{ entry.description }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Board Replacement Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">板卡更换记录</h3>
|
||||||
|
<div class="p-4 rounded-lg" style="background-color: #FAFAFA">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">旧板卡</div>
|
||||||
|
<div class="font-medium">主控板 MB20231215001</div>
|
||||||
|
</div>
|
||||||
|
<ArrowRight :size="24" style="color: #1890FF" />
|
||||||
|
<div>
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">新板卡</div>
|
||||||
|
<div class="font-medium">主控板 MB20240308001</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">更换时间</div>
|
||||||
|
<div style="color: rgba(0, 0, 0, 0.65)">2024-03-08 14:00</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">操作人</div>
|
||||||
|
<div>王工程师</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- License Processing Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">授权处理</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<label class="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="w-5 h-5 rounded"
|
||||||
|
style="accent-color: #1890FF"
|
||||||
|
v-model="regenerateAuth"
|
||||||
|
/>
|
||||||
|
<span>重新生成授权文件(板卡更换后需重新绑定授权)</span>
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center gap-3 cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="w-5 h-5 rounded"
|
||||||
|
style="accent-color: #1890FF"
|
||||||
|
v-model="pushFirmware"
|
||||||
|
/>
|
||||||
|
<span>推送适配固件(如更换板卡型号不同,需推送兼容固件)</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scrap Processing Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<h3 class="text-lg font-semibold mb-6">报废处理</h3>
|
||||||
|
|
||||||
|
<!-- Warning Banner -->
|
||||||
|
<div
|
||||||
|
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
style="background-color: #FFF1F0; border: 1px solid #FFCCC7"
|
||||||
|
>
|
||||||
|
<AlertTriangle :size="20" style="color: #FF4D4F; flex-shrink: 0; margin-top: 2px" />
|
||||||
|
<div>
|
||||||
|
<div class="font-medium" style="color: #CF1322">警告:报废操作不可逆</div>
|
||||||
|
<div class="text-sm mt-1" style="color: #FF4D4F">
|
||||||
|
报废后设备将无法恢复使用,请谨慎操作
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-x-12 gap-y-6 mb-6">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
报废原因 <span style="color: #FF4D4F">*</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>请选择报废原因</option>
|
||||||
|
<option>主板损坏无法修复</option>
|
||||||
|
<option>多个核心部件损坏</option>
|
||||||
|
<option>维修成本超过设备价值</option>
|
||||||
|
<option>设备老化严重</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
残值评估 (元)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
placeholder="输入残值评估金额"
|
||||||
|
value="500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-2">
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.85)">
|
||||||
|
可回收物料
|
||||||
|
</label>
|
||||||
|
<div class="p-3 rounded border" style="border-color: #D9D9D9; background-color: #FAFAFA">
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<span class="px-3 py-1 rounded text-sm" style="background-color: #E6F7FF; color: #1890FF">
|
||||||
|
采集板 AC20240308002
|
||||||
|
</span>
|
||||||
|
<span class="px-3 py-1 rounded text-sm" style="background-color: #E6F7FF; color: #1890FF">
|
||||||
|
测控板 CT20240308003
|
||||||
|
</span>
|
||||||
|
<span class="px-3 py-1 rounded text-sm" style="background-color: #E6F7FF; color: #1890FF">
|
||||||
|
电源模块 PS20240308004
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scrap Process Flow -->
|
||||||
|
<div
|
||||||
|
class="p-4 rounded-lg flex items-center gap-3"
|
||||||
|
style="background-color: #E6F7FF; border: 1px solid #91D5FF"
|
||||||
|
>
|
||||||
|
<div class="text-sm" style="color: #0050B3">
|
||||||
|
<span class="font-medium">报废流程:</span>
|
||||||
|
申请报废 → 创建报废单 → 报废审批 → 物料回收 → 入库
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Bar -->
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-end gap-3 p-4 bg-white rounded-lg sticky bottom-0"
|
||||||
|
style="box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05)"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded text-white"
|
||||||
|
style="background-color: #1890FF"
|
||||||
|
>
|
||||||
|
关闭工单
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-6 py-2 rounded flex items-center gap-2"
|
||||||
|
style="border: 1px solid #FF4D4F; color: #FF4D4F"
|
||||||
|
>
|
||||||
|
<Trash2 :size="16" />
|
||||||
|
申请报废
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,272 +0,0 @@
|
||||||
import { Info, Download, Upload, Link as LinkIcon } from "lucide-react";
|
|
||||||
|
|
||||||
interface ScrapDevice {
|
|
||||||
sn: string;
|
|
||||||
model: string;
|
|
||||||
scrapDate: string;
|
|
||||||
status: "待审批" | "已审批" | "已回收";
|
|
||||||
sourceOrder: string;
|
|
||||||
reason: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ScrapManagement() {
|
|
||||||
const scrapDevices: ScrapDevice[] = [
|
|
||||||
{
|
|
||||||
sn: "GD30-2023-001234",
|
|
||||||
model: "GD30 地质探测仪",
|
|
||||||
scrapDate: "2024-03-01",
|
|
||||||
status: "已回收",
|
|
||||||
sourceOrder: "WO-2024-0001",
|
|
||||||
reason: "主板损坏无法修复",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sn: "GT20-2023-000567",
|
|
||||||
model: "GT20 物探仪",
|
|
||||||
scrapDate: "2024-03-05",
|
|
||||||
status: "已审批",
|
|
||||||
sourceOrder: "WO-2024-0025",
|
|
||||||
reason: "多个核心部件损坏",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sn: "GTXD-2023-000890",
|
|
||||||
model: "GTXD 探测仪",
|
|
||||||
scrapDate: "2024-03-08",
|
|
||||||
status: "待审批",
|
|
||||||
sourceOrder: "WO-2024-0048",
|
|
||||||
reason: "维修成本超过设备价值",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const getStatusStyle = (status: ScrapDevice["status"]) => {
|
|
||||||
switch (status) {
|
|
||||||
case "已回收":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#F6FFED',
|
|
||||||
color: '#52C41A',
|
|
||||||
border: '1px solid #B7EB8F'
|
|
||||||
};
|
|
||||||
case "已审批":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#E6F7FF',
|
|
||||||
color: '#1890FF',
|
|
||||||
border: '1px solid #91D5FF'
|
|
||||||
};
|
|
||||||
case "待审批":
|
|
||||||
return {
|
|
||||||
backgroundColor: '#FFFBE6',
|
|
||||||
color: '#FAAD14',
|
|
||||||
border: '1px solid #FFE58F'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
{/* Page Header */}
|
|
||||||
<div className="mb-6">
|
|
||||||
<div className="flex items-center justify-between mb-2">
|
|
||||||
<h2 className="text-2xl font-semibold">报废管理</h2>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Upload size={16} />
|
|
||||||
批量导入
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-4 py-2 rounded flex items-center gap-2"
|
|
||||||
style={{ border: '1px solid #D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
<Download size={16} />
|
|
||||||
导出
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>管理报废设备与物料回收</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info Banner */}
|
|
||||||
<div
|
|
||||||
className="mb-6 p-4 rounded-lg flex items-start gap-3"
|
|
||||||
style={{ backgroundColor: '#E6F7FF', border: '1px solid #91D5FF' }}
|
|
||||||
>
|
|
||||||
<Info size={20} style={{ color: '#1890FF', flexShrink: 0, marginTop: 2 }} />
|
|
||||||
<div style={{ color: '#0050B3' }}>
|
|
||||||
<div className="font-medium mb-1">报废流程说明</div>
|
|
||||||
<div className="text-sm">
|
|
||||||
报废单由维修工单中申请报废创建,关联来源维修工单。报废设备需经过审批流程,审批通过后进行物料回收和入库。
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Stat Cards */}
|
|
||||||
<div className="grid grid-cols-4 gap-6 mb-6">
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>报废设备总数</div>
|
|
||||||
<div className="text-3xl font-semibold" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>156</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>待审批</div>
|
|
||||||
<div className="text-3xl font-semibold" style={{ color: '#FAAD14' }}>12</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>已审批待回收</div>
|
|
||||||
<div className="text-3xl font-semibold" style={{ color: '#1890FF' }}>8</div>
|
|
||||||
</div>
|
|
||||||
<div className="bg-white p-6 rounded-lg" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.45)' }}>已回收入库</div>
|
|
||||||
<div className="text-3xl font-semibold" style={{ color: '#52C41A' }}>136</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Filter Card */}
|
|
||||||
<div className="bg-white p-6 rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="grid grid-cols-4 gap-4">
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
设备SN号
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
placeholder="输入设备SN号搜索"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
报废状态
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9', backgroundColor: '#fff' }}
|
|
||||||
>
|
|
||||||
<option>全部</option>
|
|
||||||
<option>待审批</option>
|
|
||||||
<option>已审批</option>
|
|
||||||
<option>已回收</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm mb-2" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
报废日期
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="date"
|
|
||||||
className="w-full px-3 py-2 border rounded"
|
|
||||||
style={{ borderColor: '#D9D9D9' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-end">
|
|
||||||
<button
|
|
||||||
className="w-full px-4 py-2 rounded text-white"
|
|
||||||
style={{ backgroundColor: '#1890FF' }}
|
|
||||||
>
|
|
||||||
查询
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Scrap Device List */}
|
|
||||||
<div className="bg-white rounded-lg mb-6" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="p-6 border-b" style={{ borderColor: '#F0F0F0' }}>
|
|
||||||
<h3 className="text-lg font-semibold">报废设备列表</h3>
|
|
||||||
</div>
|
|
||||||
<div className="overflow-x-auto">
|
|
||||||
<table className="w-full">
|
|
||||||
<thead style={{ backgroundColor: '#FAFAFA' }}>
|
|
||||||
<tr>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>设备SN号</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>型号</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>报废日期</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>报废原因</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>状态</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>来源工单</th>
|
|
||||||
<th className="px-6 py-3 text-left text-sm font-medium" style={{ color: 'rgba(0, 0, 0, 0.85)' }}>操作</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{scrapDevices.map((device, index) => (
|
|
||||||
<tr
|
|
||||||
key={index}
|
|
||||||
className="border-b"
|
|
||||||
style={{ borderColor: '#F0F0F0' }}
|
|
||||||
>
|
|
||||||
<td className="px-6 py-4">{device.sn}</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{device.model}</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{device.scrapDate}</td>
|
|
||||||
<td className="px-6 py-4" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>{device.reason}</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<span
|
|
||||||
className="px-2 py-1 rounded text-xs"
|
|
||||||
style={getStatusStyle(device.status)}
|
|
||||||
>
|
|
||||||
{device.status}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<button className="text-sm flex items-center gap-1" style={{ color: '#1890FF' }}>
|
|
||||||
<LinkIcon size={14} />
|
|
||||||
{device.sourceOrder}
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
<td className="px-6 py-4">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>查看详情</button>
|
|
||||||
<button className="text-sm" style={{ color: '#1890FF' }}>物料检测</button>
|
|
||||||
{device.status === "已审批" && (
|
|
||||||
<button className="text-sm" style={{ color: '#52C41A' }}>回收入库</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Pagination */}
|
|
||||||
<div className="bg-white p-4 rounded-lg flex items-center justify-between" style={{ boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)' }}>
|
|
||||||
<div className="text-sm" style={{ color: 'rgba(0, 0, 0, 0.65)' }}>
|
|
||||||
显示 1-10 / 共 156 条
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.45)' }}
|
|
||||||
disabled
|
|
||||||
>
|
|
||||||
上一页
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded"
|
|
||||||
style={{ backgroundColor: '#1890FF', color: '#fff' }}
|
|
||||||
>
|
|
||||||
1
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
2
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
3
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="px-3 py-1 rounded border"
|
|
||||||
style={{ borderColor: '#D9D9D9', color: 'rgba(0, 0, 0, 0.85)' }}
|
|
||||||
>
|
|
||||||
下一页
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,238 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Info, Download, Upload, Link as LinkIcon } from 'lucide-vue-next'
|
||||||
|
|
||||||
|
interface ScrapDevice {
|
||||||
|
sn: string
|
||||||
|
model: string
|
||||||
|
scrapDate: string
|
||||||
|
status: '待审批' | '已审批' | '已回收'
|
||||||
|
sourceOrder: string
|
||||||
|
reason: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrapDevices: ScrapDevice[] = [
|
||||||
|
{
|
||||||
|
sn: 'GD30-2023-001234',
|
||||||
|
model: 'GD30 地质探测仪',
|
||||||
|
scrapDate: '2024-03-01',
|
||||||
|
status: '已回收',
|
||||||
|
sourceOrder: 'WO-2024-0001',
|
||||||
|
reason: '主板损坏无法修复',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sn: 'GT20-2023-000567',
|
||||||
|
model: 'GT20 物探仪',
|
||||||
|
scrapDate: '2024-03-05',
|
||||||
|
status: '已审批',
|
||||||
|
sourceOrder: 'WO-2024-0025',
|
||||||
|
reason: '多个核心部件损坏',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sn: 'GTXD-2023-000890',
|
||||||
|
model: 'GTXD 探测仪',
|
||||||
|
scrapDate: '2024-03-08',
|
||||||
|
status: '待审批',
|
||||||
|
sourceOrder: 'WO-2024-0048',
|
||||||
|
reason: '维修成本超过设备价值',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const getStatusStyle = (status: ScrapDevice['status']) => {
|
||||||
|
switch (status) {
|
||||||
|
case '已回收':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#F6FFED',
|
||||||
|
color: '#52C41A',
|
||||||
|
border: '1px solid #B7EB8F',
|
||||||
|
}
|
||||||
|
case '已审批':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#E6F7FF',
|
||||||
|
color: '#1890FF',
|
||||||
|
border: '1px solid #91D5FF',
|
||||||
|
}
|
||||||
|
case '待审批':
|
||||||
|
return {
|
||||||
|
backgroundColor: '#FFFBE6',
|
||||||
|
color: '#FAAD14',
|
||||||
|
border: '1px solid #FFE58F',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="p-6">
|
||||||
|
<!-- Page Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<h2 class="text-2xl font-semibold">报废管理</h2>
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded flex items-center gap-2"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
>
|
||||||
|
<Upload :size="16" />
|
||||||
|
批量导入
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="px-4 py-2 rounded flex items-center gap-2"
|
||||||
|
style="border: 1px solid #D9D9D9; color: rgba(0, 0, 0, 0.85)"
|
||||||
|
>
|
||||||
|
<Download :size="16" />
|
||||||
|
导出
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm" style="color: rgba(0, 0, 0, 0.45)">管理报废设备与物料回收</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Info Banner -->
|
||||||
|
<div
|
||||||
|
class="mb-6 p-4 rounded-lg flex items-start gap-3"
|
||||||
|
style="background-color: #E6F7FF; border: 1px solid #91D5FF"
|
||||||
|
>
|
||||||
|
<Info :size="20" style="color: #1890FF; flex-shrink: 0; margin-top: 2px" />
|
||||||
|
<div style="color: #0050B3">
|
||||||
|
<div class="font-medium mb-1">报废流程说明</div>
|
||||||
|
<div class="text-sm">
|
||||||
|
报废单由维修工单中申请报废创建,关联来源维修工单。报废设备需经过审批流程,审批通过后进行物料回收和入库。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stat Cards -->
|
||||||
|
<div class="grid grid-cols-4 gap-6 mb-6">
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">报废设备总数</div>
|
||||||
|
<div class="text-3xl font-semibold" style="color: rgba(0, 0, 0, 0.85)">156</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">待审批</div>
|
||||||
|
<div class="text-3xl font-semibold" style="color: #FAAD14">12</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">已审批待回收</div>
|
||||||
|
<div class="text-3xl font-semibold" style="color: #1890FF">8</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white p-6 rounded-lg" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="text-sm mb-2" style="color: rgba(0, 0, 0, 0.45)">已回收入库</div>
|
||||||
|
<div class="text-3xl font-semibold" style="color: #52C41A">136</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="grid grid-cols-4 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">设备SN号</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
placeholder="输入设备SN号搜索"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">报废状态</label>
|
||||||
|
<select
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9; background-color: #fff"
|
||||||
|
>
|
||||||
|
<option>全部</option>
|
||||||
|
<option>待审批</option>
|
||||||
|
<option>已审批</option>
|
||||||
|
<option>已回收</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm mb-2" style="color: rgba(0, 0, 0, 0.65)">报废日期</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
class="w-full px-3 py-2 border rounded"
|
||||||
|
style="border-color: #D9D9D9"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end">
|
||||||
|
<button class="w-full px-4 py-2 rounded text-white" style="background-color: #1890FF">
|
||||||
|
查询
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scrap Device List -->
|
||||||
|
<div class="bg-white rounded-lg mb-6" style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)">
|
||||||
|
<div class="p-6 border-b" style="border-color: #F0F0F0">
|
||||||
|
<h3 class="text-lg font-semibold">报废设备列表</h3>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead style="background-color: #FAFAFA">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">设备SN号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">型号</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">报废日期</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">报废原因</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">状态</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">来源工单</th>
|
||||||
|
<th class="px-6 py-3 text-left text-sm font-medium" style="color: rgba(0, 0, 0, 0.85)">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-for="(device, index) in scrapDevices"
|
||||||
|
:key="index"
|
||||||
|
class="border-b"
|
||||||
|
style="border-color: #F0F0F0"
|
||||||
|
>
|
||||||
|
<td class="px-6 py-4">{{ device.sn }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ device.model }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ device.scrapDate }}</td>
|
||||||
|
<td class="px-6 py-4" style="color: rgba(0, 0, 0, 0.65)">{{ device.reason }}</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<span class="px-2 py-1 rounded text-xs" :style="getStatusStyle(device.status)">
|
||||||
|
{{ device.status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<button class="text-sm flex items-center gap-1" style="color: #1890FF">
|
||||||
|
<LinkIcon :size="14" />
|
||||||
|
{{ device.sourceOrder }}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button class="text-sm" style="color: #1890FF">查看详情</button>
|
||||||
|
<button class="text-sm" style="color: #1890FF">物料检测</button>
|
||||||
|
<button v-if="device.status === '已审批'" class="text-sm" style="color: #52C41A">回收入库</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<div
|
||||||
|
class="bg-white p-4 rounded-lg flex items-center justify-between"
|
||||||
|
style="box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)"
|
||||||
|
>
|
||||||
|
<div class="text-sm" style="color: rgba(0, 0, 0, 0.65)">显示 1-10 / 共 156 条</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
class="px-3 py-1 rounded border"
|
||||||
|
style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.45)"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
上一页
|
||||||
|
</button>
|
||||||
|
<button class="px-3 py-1 rounded" style="background-color: #1890FF; color: #fff">1</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">2</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">3</button>
|
||||||
|
<button class="px-3 py-1 rounded border" style="border-color: #D9D9D9; color: rgba(0, 0, 0, 0.85)">下一页</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import Layout from './Layout.vue'
|
||||||
|
|
||||||
|
export const router = createRouter({
|
||||||
|
history: createWebHistory(),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
|
{ path: '', component: () => import('./pages/Dashboard.vue') },
|
||||||
|
{ path: 'models', component: () => import('./pages/DeviceModelManagement.vue') },
|
||||||
|
{ path: 'devices', component: () => import('./pages/DeviceList.vue') },
|
||||||
|
{ path: 'devices/:id', component: () => import('./pages/DeviceDetail.vue') },
|
||||||
|
{ path: 'registration', component: () => import('./pages/DeviceRegistration.vue') },
|
||||||
|
{ path: 'licenses', component: () => import('./pages/LicenseManagement.vue') },
|
||||||
|
{ path: 'licenses/generate', component: () => import('./pages/LicenseGenerate.vue') },
|
||||||
|
{ path: 'activation', component: () => import('./pages/ActivationManagement.vue') },
|
||||||
|
{ path: 'calibration', component: () => import('./pages/CalibrationRecords.vue') },
|
||||||
|
{ path: 'repair/:orderId', component: () => import('./pages/RepairOrderDetail.vue') },
|
||||||
|
{ path: 'scrap', component: () => import('./pages/ScrapManagement.vue') },
|
||||||
|
{ path: 'firmware', component: () => import('./pages/FirmwareLibrary.vue') },
|
||||||
|
{ path: 'config-files', component: () => import('./pages/ConfigFileManagement.vue') },
|
||||||
|
{ path: 'config-files/:configId', component: () => import('./pages/ParameterConfiguration.vue') },
|
||||||
|
{ path: 'reports', component: () => import('./pages/PlaceholderPage.vue'), props: { title: '数据报表' } },
|
||||||
|
{ path: 'logs', component: () => import('./pages/PlaceholderPage.vue'), props: { title: '操作日志' } },
|
||||||
|
{ path: 'settings', component: () => import('./pages/PlaceholderPage.vue'), props: { title: '系统设置' } },
|
||||||
|
{ path: ':pathMatch(.*)*', component: () => import('./pages/PlaceholderPage.vue'), props: { title: '页面未找到' } },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
import { createBrowserRouter } from "react-router";
|
|
||||||
import { Layout } from "./Layout";
|
|
||||||
import Dashboard from "./pages/Dashboard";
|
|
||||||
import DeviceModelManagement from "./pages/DeviceModelManagement";
|
|
||||||
import DeviceList from "./pages/DeviceList";
|
|
||||||
import DeviceRegistration from "./pages/DeviceRegistration";
|
|
||||||
import DeviceDetail from "./pages/DeviceDetail";
|
|
||||||
import LicenseManagement from "./pages/LicenseManagement";
|
|
||||||
import ActivationManagement from "./pages/ActivationManagement";
|
|
||||||
import CalibrationRecords from "./pages/CalibrationRecords";
|
|
||||||
import RepairOrderDetail from "./pages/RepairOrderDetail";
|
|
||||||
import ScrapManagement from "./pages/ScrapManagement";
|
|
||||||
import ConfigFileManagement from "./pages/ConfigFileManagement";
|
|
||||||
import ParameterConfiguration from "./pages/ParameterConfiguration";
|
|
||||||
import PlaceholderPage from "./pages/PlaceholderPage";
|
|
||||||
|
|
||||||
export const router = createBrowserRouter([
|
|
||||||
{
|
|
||||||
path: "/",
|
|
||||||
Component: Layout,
|
|
||||||
children: [
|
|
||||||
{ index: true, Component: Dashboard },
|
|
||||||
{ path: "models", Component: DeviceModelManagement },
|
|
||||||
{ path: "devices", Component: DeviceList },
|
|
||||||
{ path: "devices/:id", Component: DeviceDetail },
|
|
||||||
{ path: "registration", Component: DeviceRegistration },
|
|
||||||
{ path: "licenses", Component: LicenseManagement },
|
|
||||||
{ path: "activation", Component: ActivationManagement },
|
|
||||||
{ path: "calibration", Component: CalibrationRecords },
|
|
||||||
{ path: "repair/:orderId", Component: RepairOrderDetail },
|
|
||||||
{ path: "scrap", Component: ScrapManagement },
|
|
||||||
{ path: "config-files", Component: ConfigFileManagement },
|
|
||||||
{ path: "config-files/:configId", Component: ParameterConfiguration },
|
|
||||||
{ path: "reports", element: <PlaceholderPage title="数据报表" /> },
|
|
||||||
{ path: "logs", element: <PlaceholderPage title="操作日志" /> },
|
|
||||||
{ path: "settings", element: <PlaceholderPage title="系统设置" /> },
|
|
||||||
{ path: "*", element: <PlaceholderPage title="页面未找到" /> },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
/// <reference types="vite/client" />
|
||||||
|
declare module '*.vue' {
|
||||||
|
import type { DefineComponent } from 'vue'
|
||||||
|
const component: DefineComponent<{}, {}, any>
|
||||||
|
export default component
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { createApp } from 'vue'
|
||||||
|
import App from './app/App.vue'
|
||||||
|
import { router } from './app/router'
|
||||||
|
import './styles/index.css'
|
||||||
|
|
||||||
|
createApp(App).use(router).mount('#app')
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
|
|
||||||
import { createRoot } from "react-dom/client";
|
|
||||||
import App from "./app/App.tsx";
|
|
||||||
import "./styles/index.css";
|
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(<App />);
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,2 @@
|
||||||
@import 'tailwindcss' source(none);
|
@import 'tailwindcss' source(none);
|
||||||
@source '../**/*.{js,ts,jsx,tsx}';
|
@source '../**/*.{js,ts,vue}';
|
||||||
|
|
||||||
@import 'tw-animate-css';
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,13 @@
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import tailwindcss from '@tailwindcss/vite'
|
import tailwindcss from '@tailwindcss/vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [vue(), tailwindcss()],
|
||||||
// The React and Tailwind plugins are both required for Make, even if
|
|
||||||
// Tailwind is not being actively used – do not remove them
|
|
||||||
react(),
|
|
||||||
tailwindcss(),
|
|
||||||
],
|
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
// Alias @ to the src directory
|
|
||||||
'@': path.resolve(__dirname, './src'),
|
'@': path.resolve(__dirname, './src'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// File types to support raw imports. Never add .css, .tsx, or .ts files to this.
|
|
||||||
assetsInclude: ['**/*.svg', '**/*.csv'],
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue