pageRepeatability.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. // repeatability.js - 重复性测试相关功能
  2. // 重复性测试时间数组
  3. let repeatabilityTimes = [];
  4. // 图表相关变量
  5. let repeatabilityCtx = null;
  6. let repeatabilityChartInstance = null;
  7. function initializeRepeatabilityPage() {
  8. // 生成重复性标签页内容
  9. generateRepeatabilityTabContent();
  10. // 加载重复性数据
  11. loadRepeatabilityData();
  12. }
  13. // 生成重复性标签页内容
  14. function generateRepeatabilityTabContent() {
  15. console.log('generateRepeatabilityTabContent');
  16. const repeatabilityTab = document.createElement('div');
  17. repeatabilityTab.id = 'repeatability';
  18. repeatabilityTab.className = 'tab-content active';
  19. // 创建内容容器
  20. const contentContainer = document.createElement('div');
  21. contentContainer.className = 'content-container';
  22. // 创建输入部分
  23. const inputSection = document.createElement('div');
  24. inputSection.className = 'input-section';
  25. // 创建输入组
  26. const inputGroup = document.createElement('div');
  27. inputGroup.className = 'input-group';
  28. inputGroup.id = 'repeatability-inputs';
  29. // 添加默认的6个输入行
  30. for (let i = 1; i <= 6; i++) {
  31. const row = createInputRow(i, 'repeatability', recordTimeAndCalculateRepeatability, deleteRepeatabilityInput);
  32. inputGroup.appendChild(row);
  33. }
  34. // 添加按钮
  35. const addInputBtn = document.createElement('div');
  36. addInputBtn.className = 'add-input-btn';
  37. addInputBtn.onclick = addRepeatabilityInput;
  38. const addInputSpan = document.createElement('span');
  39. addInputSpan.textContent = '+ 添加输入';
  40. addInputBtn.appendChild(addInputSpan);
  41. // 组装输入部分
  42. inputSection.appendChild(inputGroup);
  43. inputSection.appendChild(addInputBtn);
  44. // 创建结果部分
  45. const resultsSection = document.createElement('div');
  46. resultsSection.className = 'results-section';
  47. // 创建结果显示
  48. const results = document.createElement('div');
  49. results.className = 'results';
  50. // 添加结果项
  51. const resultItems = [
  52. { label: '极差R:', id: 'range' },
  53. { label: '平均值x̄:', id: 'mean' },
  54. { label: '方差s<sup>2</sup>:', id: 'variance' },
  55. { label: '标准差s:', id: 'stdDev' },
  56. { label: '相对标准偏差RSD(%):', id: 'rsd' }
  57. ];
  58. resultItems.forEach(item => {
  59. const resultItem = document.createElement('div');
  60. resultItem.className = 'result-item';
  61. resultItem.innerHTML = `${item.label} <span id="${item.id}">-</span>`;
  62. results.appendChild(resultItem);
  63. });
  64. // 创建图表容器
  65. const chartContainer = document.createElement('div');
  66. chartContainer.className = 'chart-container';
  67. const canvas = document.createElement('canvas');
  68. canvas.id = 'lineChart';
  69. chartContainer.appendChild(canvas);
  70. repeatabilityCtx = canvas.getContext('2d');
  71. // 组装结果部分
  72. resultsSection.appendChild(results);
  73. resultsSection.appendChild(chartContainer);
  74. // 组装整个内容
  75. contentContainer.appendChild(inputSection);
  76. contentContainer.appendChild(resultsSection);
  77. repeatabilityTab.appendChild(contentContainer);
  78. if (document.getElementById('container')) {
  79. console.log('appendChild repeatabilityTab');
  80. document.getElementById('container').appendChild(repeatabilityTab);
  81. }
  82. // document.querySelectorAll('#repeatability-inputs .input-row').forEach((row, index) => {
  83. // const deleteBtn = row.querySelector('.delete-btn');
  84. // if (deleteBtn) {
  85. // deleteBtn.style.display = index < 0 ? 'none' : '';
  86. // }
  87. // });
  88. }
  89. // 添加重复性输入行
  90. function addRepeatabilityInput() {
  91. const container = document.getElementById('repeatability-inputs');
  92. const newIndex = container.children.length + 1;
  93. const row = createInputRow(newIndex, 'repeatability', recordTimeAndCalculateRepeatability, deleteRepeatabilityInput);
  94. container.appendChild(row);
  95. }
  96. // 删除重复性输入行
  97. function deleteRepeatabilityInput(btn) {
  98. const row = btn.parentNode;
  99. const container = row.parentNode;
  100. const index = Array.from(container.children).indexOf(row);
  101. // 移除对应的时间记录
  102. repeatabilityTimes.splice(index, 1);
  103. // 移除输入行
  104. container.removeChild(row);
  105. // 更新剩余输入行的索引
  106. const rows = container.querySelectorAll('.input-row');
  107. rows.forEach((row, i) => {
  108. const timeSpan = row.querySelector(`span[id^="repeatability-time-text-"]`);
  109. const input = row.querySelector(`input[id^="repeatability-value-"]`);
  110. // 更新ID和文本
  111. const newIndex = i + 1;
  112. timeSpan.id = `repeatability-time-text-${newIndex}`;
  113. input.id = `repeatability-value-${newIndex}`;
  114. // 如果有保存的时间,则显示时间,否则显示索引
  115. if (repeatabilityTimes[i]) {
  116. timeSpan.textContent = `${parseUnixTime(repeatabilityTimes[i])}: `;
  117. } else {
  118. timeSpan.textContent = `${newIndex}: `;
  119. }
  120. // 更新输入事件
  121. input.oninput = function () { recordTimeAndCalculateRepeatability(newIndex); };
  122. });
  123. document.querySelectorAll('#repeatability-inputs input[type="number"]').forEach((input) => {
  124. input.placeholder = `输入值`;
  125. });
  126. calculateRepeatability();
  127. saveRepeatabilityData();
  128. }
  129. // 清除重复性数据
  130. function clearRepeatabilityData() {
  131. // 清除重复性数据
  132. const repeatabilityInputs = document.querySelectorAll('#repeatability-inputs .input-row');
  133. for (let i = 6; i < repeatabilityInputs.length; i++) {
  134. repeatabilityInputs[i].remove();
  135. }
  136. document.querySelectorAll('#repeatability-inputs input[type="number"]').forEach(input => {
  137. input.value = '';
  138. });
  139. repeatabilityTimes = [];
  140. // 重置重复性时间标签
  141. for (let i = 1; i <= 6; i++) {
  142. const timeSpan = document.getElementById(`repeatability-time-text-${i}`);
  143. if (timeSpan) {
  144. timeSpan.textContent = `${i}: `;
  145. }
  146. }
  147. // 重置图表
  148. if (repeatabilityChartInstance) {
  149. repeatabilityChartInstance.destroy();
  150. repeatabilityChartInstance = null;
  151. }
  152. }
  153. // 记录重复性时间并计算
  154. function recordTimeAndCalculateRepeatability(index) {
  155. recordTimeAndCalculate('repeatability', index, repeatabilityTimes, calculateRepeatability);
  156. }
  157. // 重复性计算
  158. function calculateRepeatability() {
  159. const values = getNumericInputs('#repeatability-inputs input[type="number"]');
  160. if (values.length >= 2) {
  161. // 计算统计量
  162. const max = Math.max(...values);
  163. const min = Math.min(...values);
  164. const range = max - min;
  165. const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
  166. // 计算方差和标准差
  167. const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length;
  168. const stdDev = Math.sqrt(variance);
  169. const rsd = (stdDev / mean) * 100; // 相对标准偏差,以百分比表示
  170. // 更新结果显示
  171. updateResultDisplay('range', range);
  172. updateResultDisplay('mean', mean);
  173. updateResultDisplay('variance', variance);
  174. updateResultDisplay('stdDev', stdDev);
  175. updateResultDisplay('rsd', rsd);
  176. // 保存数据
  177. saveRepeatabilityData();
  178. // 更新图表
  179. updateRepeatabilityChart(values);
  180. } else {
  181. // 清空结果显示
  182. document.querySelectorAll('#repeatability .result-item span').forEach(span => {
  183. span.innerText = '-';
  184. });
  185. // 清空图表
  186. if (repeatabilityChartInstance) {
  187. repeatabilityChartInstance.data.labels = [];
  188. repeatabilityChartInstance.data.datasets[0].data = [];
  189. repeatabilityChartInstance.update();
  190. }
  191. }
  192. }
  193. // 重复性图表更新
  194. function updateRepeatabilityChart(values) {
  195. // 获取时间标签
  196. const timeLabels = [];
  197. repeatabilityTimes.forEach((time) => {
  198. // 使用已保存的时间戳生成标签
  199. if (time > 9999) {
  200. timeLabels.push(parseUnixTime(time));
  201. }
  202. });
  203. // 使用通用图表创建函数
  204. repeatabilityChartInstance = createOrUpdateChart(repeatabilityChartInstance, repeatabilityCtx, timeLabels, values, '重复性');
  205. }
  206. // 重复性数据保存
  207. function saveRepeatabilityData() {
  208. collectAndSaveData('#repeatability-inputs input[type="number"]', repeatabilityTimes, {
  209. range: 'range',
  210. mean: 'mean',
  211. variance: 'variance',
  212. stdDev: 'stdDev',
  213. rsd: 'rsd'
  214. }, 'repeatabilityData');
  215. }
  216. // 重复性数据加载
  217. function loadRepeatabilityData() {
  218. const savedRepeatabilityData = getLocalStorage('repeatabilityData');
  219. if (savedRepeatabilityData) {
  220. try {
  221. const data = JSON.parse(savedRepeatabilityData);
  222. // 清除现有的额外输入框(保留前6个)
  223. const repeatabilityInputs = document.querySelectorAll('#repeatability-inputs .input-row');
  224. for (let i = 6; i < repeatabilityInputs.length; i++) {
  225. repeatabilityInputs[i].remove();
  226. }
  227. // 清除现有输入值
  228. document.querySelectorAll('#repeatability-inputs input[type="number"]').forEach(input => {
  229. input.value = '';
  230. });
  231. // 填充保存的数据
  232. if (data.inputs && data.inputs.length > 0) {
  233. data.inputs.forEach((item, index) => {
  234. const time = typeof item === 'object' ? item.time : '';
  235. const value = typeof item === 'object' ? item.value : '';
  236. // 如果索引超出现有输入框数量,添加新的输入框
  237. if (index >= 6) {
  238. addRepeatabilityInput();
  239. }
  240. // 设置时间
  241. if (time) {
  242. const timeSpan = document.getElementById(`repeatability-time-text-${index + 1}`);
  243. if (timeSpan) {
  244. timeSpan.textContent = parseUnixTime(time) + ': ';
  245. repeatabilityTimes[index] = time;
  246. }
  247. }
  248. // 设置值
  249. const input = document.querySelector(`#repeatability-inputs .input-row:nth-child(${index + 1}) input`);
  250. if (input) {
  251. input.value = value;
  252. }
  253. });
  254. // 计算结果
  255. calculateRepeatability();
  256. }
  257. } catch (e) {
  258. console.error('加载重复性数据失败:', e);
  259. }
  260. }
  261. }