page1.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. let cpuChart = null;
  2. let memChart = null;
  3. let diskChart = null;
  4. let sysStatusTimer = null;
  5. let resizeHandler = null;
  6. function getSystemInfo(){
  7. fetch("/api/system/info")
  8. .then(r=>{
  9. if(!r.ok) throw new Error("HTTP "+r.status);
  10. return r.json();
  11. })
  12. .then(d=>{
  13. cpuChart.setOption({
  14. graphic:[{
  15. type:"text",
  16. left:"center",
  17. top:"75%",
  18. style:{
  19. text:`${d.cpu_cores||"--"}核 ${d.cpu_freq||"--"}MHz 温度${d.cpu_temp||"--"}`,
  20. fill:"#aaa",
  21. fontSize:15
  22. }
  23. }],
  24. series:[{data:[{value:d.cpu_usage}]}]
  25. });
  26. memChart.setOption({
  27. graphic:[{
  28. type:"text",
  29. left:"center",
  30. top:"75%",
  31. style:{
  32. text:`${d.mem_used||"--"} / ${d.mem_total||"--"}`,
  33. fill:"#aaa",
  34. fontSize:15
  35. }
  36. }],
  37. series:[{data:[{value:d.mem_percent}]}]
  38. });
  39. diskChart.setOption({
  40. title:{
  41. text:`${d.disk_percent}%`,
  42. subtext:`${d.disk_used||"--"} / ${d.disk_total||"--"}`,
  43. left:"center",
  44. top:"38%",
  45. textStyle:{
  46. fontSize:38,
  47. fontWeight:"bold"
  48. },
  49. subtextStyle:{
  50. fontSize:15
  51. }
  52. },
  53. series:[{
  54. data:[
  55. {value:d.disk_percent,name:"已使用"},
  56. {value:100-d.disk_percent,name:"剩余"}
  57. ]
  58. }]
  59. });
  60. })
  61. .catch(e=>console.error("system info failed:",e));
  62. }
  63. function gaugeOption(){
  64. return {
  65. series:[{
  66. type:"gauge",
  67. radius:"95%",
  68. center:["50%","55%"],
  69. min:0,
  70. max:100,
  71. startAngle:210,
  72. endAngle:-30,
  73. axisLine:{
  74. lineStyle:{
  75. width:22
  76. }
  77. },
  78. progress:{
  79. show:true,
  80. width:22
  81. },
  82. pointer:{show:false},
  83. axisTick:{show:false},
  84. splitLine:{show:false},
  85. axisLabel:{show:false},
  86. detail:{
  87. fontSize:42,
  88. fontWeight:"bold",
  89. offsetCenter:[0,"0%"],
  90. formatter:"{value}%"
  91. },
  92. title:{show:false},
  93. data:[{value:0}]
  94. }]
  95. };
  96. }
  97. function getLoadInfo(){
  98. fetch("/api/system/loadAverage")
  99. .then(async r => {
  100. if (!r.ok) {
  101. throw new Error("HTTP " + r.status);
  102. }
  103. return r.json();
  104. })
  105. .then(data => {
  106. ["load1m","load5m","load15m","runQueue","bootTime","uptime"]
  107. .forEach(id => setText(id, data[id], "page1"));
  108. })
  109. .catch(e => {
  110. console.error("load info failed:", e);
  111. ["load1m","load5m","load15m","runQueue","bootTime","uptime"]
  112. .forEach(id => setText(id, null, "page1"));
  113. });
  114. }
  115. function getServiceInfo(){
  116. fetch("/api/system/serviceStatus")
  117. .then(r => {
  118. if (!r.ok) {
  119. throw new Error("HTTP " + r.status);
  120. }
  121. return r.json();
  122. })
  123. .then(data => {
  124. [
  125. "var1","var2","var3","var4","var5",
  126. "var6","var7","var8","var9",
  127. "var11","var22","var33","var44",
  128. "var55","var66","var77","var88"
  129. ].forEach(id => setText(id, data[id], "page1"));
  130. })
  131. .catch(e => {
  132. console.error("getAllServiceStatus() failed:", e);
  133. [
  134. "var1","var2","var3","var4","var5",
  135. "var6","var7","var8","var9",
  136. "var11","var22","var33","var44",
  137. "var55","var66","var77","var88"
  138. ].forEach(id => setText(id, null, "page1"));
  139. });
  140. }
  141. function startSysStatusRefresh(){
  142. if(sysStatusTimer) return;
  143. getSystemInfo();
  144. getLoadInfo();
  145. getServiceInfo();
  146. sysStatusTimer = setInterval(() => {
  147. getSystemInfo();
  148. getLoadInfo();
  149. getServiceInfo();
  150. }, 5000);
  151. }
  152. function stopSysStatusRefresh(){
  153. if(sysStatusTimer){
  154. clearInterval(sysStatusTimer);
  155. sysStatusTimer=null;
  156. }
  157. }
  158. function resizeSysCharts(){
  159. cpuChart?.resize();
  160. memChart?.resize();
  161. diskChart?.resize();
  162. }
  163. const serviceNames = {
  164. "yfkj-networkd.service": "设备自动联网",
  165. "yfkj-timesyncd.service": "系统时间同步",
  166. "yfkj-gnss.service": "地理坐标定位",
  167. "yfkj-camera-capture.service": "相机图像采集",
  168. "yfkj-sshd-mqtt-bridge.service": "远程运维通道",
  169. "yfkj-app-install.service": "应用安装卸载",
  170. "yfkj-web-ui.service": "统一配置管理",
  171. "yfkj-upgrade.service": "开机自动升级",
  172. };
  173. function switchServiceVersion(service, action)
  174. {
  175. let name = serviceNames[service] || service;
  176. let msg = action === "factory"
  177. ? `确认将【${name}】恢复到出厂版本吗?\n\n警告: 切换过程中服务会自动重启,请勿断开电源!`
  178. : `确认将【${name}】回退到上一版本吗?\n\n警告: 切换过程中服务会自动重启,请勿断开电源!`;
  179. if(!confirm(msg)){
  180. return;
  181. }
  182. let password = prompt("请输入操作密码:");
  183. if(password === null){
  184. return;
  185. }
  186. password = password.trim();
  187. fetch("/api/service/version/switch", {
  188. method:"POST",
  189. headers:{
  190. "Content-Type":"application/json"
  191. },
  192. body:JSON.stringify({
  193. service:service,
  194. action:action,
  195. password:password
  196. })
  197. })
  198. .then(r=>r.json())
  199. .then(d=>{
  200. alert(`【${name}】\n\n${d.status=="ok" ? "✅ 版本切换成功" : "❌ 版本切换失败:" + d.message}`);
  201. })
  202. .catch(e=>{
  203. alert(`【${name}】\n\n❌ 请求失败:${e.message}`);
  204. });
  205. }
  206. function switchAutoUpgrade(action)
  207. {
  208. let msg = action === "enable"
  209. ? "确认要打开 【开机自动升级】 吗?"
  210. : "确认要关闭 【开机自动升级】 吗?";
  211. if(!confirm(msg)){
  212. return;
  213. }
  214. let password = prompt("请输入操作密码:");
  215. if(password === null){
  216. return;
  217. }
  218. password = password.trim();
  219. fetch("/api/upgrade/on-off", {
  220. method:"POST",
  221. headers:{
  222. "Content-Type":"application/json"
  223. },
  224. body:JSON.stringify({
  225. action:action,
  226. password:password
  227. })
  228. })
  229. .then(r=>r.json())
  230. .then(d=>{
  231. alert(`【开机自动升级】\n\n${d.status=="ok" ? (action=="enable" ? "✅ 已打开" : "✅ 已关闭") : "❌ 操作失败: " + d.message}`);
  232. })
  233. .catch(e=>{
  234. alert(`【开机自动升级】\n\n❌ 请求失败: ${e.message}`);
  235. });
  236. }
  237. function initPage1(){
  238. cpuChart=echarts.init(document.getElementById("cpu-chart"));
  239. memChart=echarts.init(document.getElementById("mem-chart"));
  240. diskChart=echarts.init(document.getElementById("disk-chart"));
  241. cpuChart.setOption(gaugeOption());
  242. memChart.setOption(gaugeOption());
  243. diskChart.setOption({
  244. title:{
  245. text:"0%",
  246. subtext:"-- / --",
  247. left:"center",
  248. top:"38%",
  249. textStyle:{
  250. fontSize:38,
  251. fontWeight:"bold"
  252. },
  253. subtextStyle:{
  254. fontSize:15
  255. }
  256. },
  257. series:[{
  258. type:"pie",
  259. radius:["65%","85%"],
  260. label:{show:false},
  261. data:[
  262. {value:0,name:"已使用"},
  263. {value:100,name:"剩余"}
  264. ]
  265. }]
  266. });
  267. startSysStatusRefresh();
  268. resizeHandler = resizeSysCharts;
  269. window.addEventListener(
  270. "resize",
  271. resizeHandler
  272. );
  273. setTimeout(()=>{
  274. resizeSysCharts();
  275. },100);
  276. }
  277. function exitPage1(){
  278. stopSysStatusRefresh();
  279. if(resizeHandler){
  280. window.removeEventListener(
  281. "resize",
  282. resizeHandler
  283. );
  284. resizeHandler=null;
  285. }
  286. cpuChart?.dispose();
  287. memChart?.dispose();
  288. diskChart?.dispose();
  289. cpuChart=null;
  290. memChart=null;
  291. diskChart=null;
  292. }