|
@@ -0,0 +1,473 @@
|
|
|
|
|
+// 伺服驱动选型工具 - 核心计算逻辑
|
|
|
|
|
+class ServoSizer {
|
|
|
|
|
+ constructor() {
|
|
|
|
|
+ this.currentType = 'ballScrew';
|
|
|
|
|
+ this.init();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ init() {
|
|
|
|
|
+ this.bindEvents();
|
|
|
|
|
+ this.updateUI();
|
|
|
|
|
+ this.loadDefaults();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bindEvents() {
|
|
|
|
|
+ // 传动类型切换
|
|
|
|
|
+ document.querySelectorAll('.transmission-type').forEach(btn => {
|
|
|
|
|
+ btn.addEventListener('click', (e) => {
|
|
|
|
|
+ this.currentType = e.target.dataset.type;
|
|
|
|
|
+ this.updateUI();
|
|
|
|
|
+ this.clearResults();
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 输入验证
|
|
|
|
|
+ document.querySelectorAll('input[type="number"]').forEach(input => {
|
|
|
|
|
+ input.addEventListener('input', () => {
|
|
|
|
|
+ this.validateInput(input);
|
|
|
|
|
+ });
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 计算按钮
|
|
|
|
|
+ document.getElementById('calculateBtn').addEventListener('click', () => {
|
|
|
|
|
+ this.calculate();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 重置按钮
|
|
|
|
|
+ document.getElementById('resetBtn').addEventListener('click', () => {
|
|
|
|
|
+ this.resetForm();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 导出按钮
|
|
|
|
|
+ document.getElementById('exportBtn').addEventListener('click', () => {
|
|
|
|
|
+ this.exportResults();
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ validateInput(input) {
|
|
|
|
|
+ const value = parseFloat(input.value);
|
|
|
|
|
+ const min = parseFloat(input.min) || -Infinity;
|
|
|
|
|
+ const max = parseFloat(input.max) || Infinity;
|
|
|
|
|
+
|
|
|
|
|
+ if (value < min || value > max) {
|
|
|
|
|
+ input.classList.add('error');
|
|
|
|
|
+ } else {
|
|
|
|
|
+ input.classList.remove('error');
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ loadDefaults() {
|
|
|
|
|
+ // 加载默认值
|
|
|
|
|
+ const defaults = {
|
|
|
|
|
+ friction: 0.1,
|
|
|
|
|
+ efficiency: 0.9,
|
|
|
|
|
+ safetyFactor: 1.5,
|
|
|
|
|
+ inertiaRatio: 10
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ Object.keys(defaults).forEach(key => {
|
|
|
|
|
+ const input = document.querySelector(`[name="${key}"]`);
|
|
|
|
|
+ if (input) input.value = defaults[key];
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateUI() {
|
|
|
|
|
+ // 隐藏所有传动类型表单
|
|
|
|
|
+ document.querySelectorAll('.transmission-form').forEach(form => {
|
|
|
|
|
+ form.style.display = 'none';
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 显示当前选中的传动类型表单
|
|
|
|
|
+ const currentForm = document.getElementById(`${this.currentType}Form`);
|
|
|
|
|
+ if (currentForm) currentForm.style.display = 'block';
|
|
|
|
|
+
|
|
|
|
|
+ // 更新按钮状态
|
|
|
|
|
+ document.querySelectorAll('.transmission-type').forEach(btn => {
|
|
|
|
|
+ btn.classList.remove('active');
|
|
|
|
|
+ });
|
|
|
|
|
+ document.querySelector(`[data-type="${this.currentType}"]`).classList.add('active');
|
|
|
|
|
+
|
|
|
|
|
+ // 更新标题
|
|
|
|
|
+ const titles = {
|
|
|
|
|
+ ballScrew: '滚珠丝杠传动',
|
|
|
|
|
+ timingBelt: '同步带传动',
|
|
|
|
|
+ gearbox: '减速机传动',
|
|
|
|
|
+ turntable: '转盘传动',
|
|
|
|
|
+ winding: '收放卷传动',
|
|
|
|
|
+ directDrive: '直接驱动'
|
|
|
|
|
+ };
|
|
|
|
|
+ document.getElementById('currentTypeTitle').textContent = titles[this.currentType] || '伺服驱动选型';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 滚珠丝杠计算
|
|
|
|
|
+ calculateBallScrew(params) {
|
|
|
|
|
+ const {
|
|
|
|
|
+ loadMass, screwDiameter, screwLead, friction, efficiency,
|
|
|
|
|
+ maxSpeed, accelerationTime, travelDistance
|
|
|
|
|
+ } = params;
|
|
|
|
|
+
|
|
|
|
|
+ // 转换为标准单位
|
|
|
|
|
+ const lead = screwLead / 1000; // mm to m
|
|
|
|
|
+ const diameter = screwDiameter / 1000; // mm to m
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 负载转矩计算
|
|
|
|
|
+ const gravity = 9.81;
|
|
|
|
|
+ const frictionForce = loadMass * gravity * friction;
|
|
|
|
|
+ const frictionTorque = (frictionForce * diameter) / 2;
|
|
|
|
|
+
|
|
|
|
|
+ // 推力转矩 (忽略效率先)
|
|
|
|
|
+ const thrustTorque = (loadMass * gravity * lead) / (2 * Math.PI);
|
|
|
|
|
+ const totalTorque = (thrustTorque + frictionTorque) / efficiency;
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 转速计算
|
|
|
|
|
+ const maxRpm = (maxSpeed * 60) / (lead * 1000); // mm/s to rpm
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 惯量计算
|
|
|
|
|
+ const screwInertia = (Math.PI * 7800 * Math.pow(diameter, 4) * travelDistance) / (32 * Math.pow(lead, 2));
|
|
|
|
|
+ const loadInertia = loadMass * Math.pow(lead / (2 * Math.PI), 2);
|
|
|
|
|
+ const totalInertia = screwInertia + loadInertia;
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 加速度转矩
|
|
|
|
|
+ const angularAccel = (maxRpm * 2 * Math.PI / 60) / accelerationTime;
|
|
|
|
|
+ const accelTorque = totalInertia * angularAccel;
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 峰值转矩
|
|
|
|
|
+ const peakTorque = totalTorque + accelTorque;
|
|
|
|
|
+
|
|
|
|
|
+ // 6. 功率计算
|
|
|
|
|
+ const power = (peakTorque * maxRpm * 2 * Math.PI) / 60;
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ speedRange: { min: 0, max: maxRpm },
|
|
|
|
|
+ torque: { continuous: totalTorque, peak: peakTorque },
|
|
|
|
|
+ inertia: { motor: 0, load: totalInertia, ratio: totalInertia / 0.001 }, // 假设电机惯量
|
|
|
|
|
+ power: { required: power, rated: power * 1.2 }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 同步带计算
|
|
|
|
|
+ calculateTimingBelt(params) {
|
|
|
|
|
+ const {
|
|
|
|
|
+ loadMass, pulleyDiameter, friction, efficiency,
|
|
|
|
|
+ maxSpeed, accelerationTime
|
|
|
|
|
+ } = params;
|
|
|
|
|
+
|
|
|
|
|
+ const radius = pulleyDiameter / 2000; // mm to m
|
|
|
|
|
+
|
|
|
|
|
+ // 负载转矩
|
|
|
|
|
+ const gravity = 9.81;
|
|
|
|
|
+ const frictionForce = loadMass * gravity * friction;
|
|
|
|
|
+ const loadTorque = (loadMass * gravity * radius + frictionForce * radius) / efficiency;
|
|
|
|
|
+
|
|
|
|
|
+ // 转速
|
|
|
|
|
+ const maxRpm = (maxSpeed * 60) / (Math.PI * pulleyDiameter);
|
|
|
|
|
+
|
|
|
|
|
+ // 惯量
|
|
|
|
|
+ const pulleyInertia = 0.5 * 0.1 * Math.pow(radius, 2); // 假设滑轮质量0.1kg
|
|
|
|
|
+ const loadInertia = loadMass * Math.pow(radius, 2);
|
|
|
|
|
+ const totalInertia = pulleyInertia + loadInertia;
|
|
|
|
|
+
|
|
|
|
|
+ // 加速度转矩
|
|
|
|
|
+ const angularAccel = (maxRpm * 2 * Math.PI / 60) / accelerationTime;
|
|
|
|
|
+ const accelTorque = totalInertia * angularAccel;
|
|
|
|
|
+
|
|
|
|
|
+ const peakTorque = loadTorque + accelTorque;
|
|
|
|
|
+ const power = (peakTorque * maxRpm * 2 * Math.PI) / 60;
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ speedRange: { min: 0, max: maxRpm },
|
|
|
|
|
+ torque: { continuous: loadTorque, peak: peakTorque },
|
|
|
|
|
+ inertia: { motor: 0, load: totalInertia, ratio: totalInertia / 0.001 },
|
|
|
|
|
+ power: { required: power, rated: power * 1.2 }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 减速机计算
|
|
|
|
|
+ calculateGearbox(params) {
|
|
|
|
|
+ const {
|
|
|
|
|
+ loadInertia, loadTorque, gearRatio, efficiency,
|
|
|
|
|
+ maxSpeed, accelerationTime
|
|
|
|
|
+ } = params;
|
|
|
|
|
+
|
|
|
|
|
+ // 折算到电机侧
|
|
|
|
|
+ const reflectedInertia = loadInertia / Math.pow(gearRatio, 2);
|
|
|
|
|
+ const reflectedTorque = loadTorque / (gearRatio * efficiency);
|
|
|
|
|
+
|
|
|
|
|
+ // 电机转速
|
|
|
|
|
+ const motorRpm = maxSpeed * gearRatio;
|
|
|
|
|
+
|
|
|
|
|
+ // 加速度转矩
|
|
|
|
|
+ const angularAccel = (motorRpm * 2 * Math.PI / 60) / accelerationTime;
|
|
|
|
|
+ const accelTorque = reflectedInertia * angularAccel;
|
|
|
|
|
+
|
|
|
|
|
+ const peakTorque = reflectedTorque + accelTorque;
|
|
|
|
|
+ const power = (peakTorque * motorRpm * 2 * Math.PI) / 60;
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ speedRange: { min: 0, max: motorRpm },
|
|
|
|
|
+ torque: { continuous: reflectedTorque, peak: peakTorque },
|
|
|
|
|
+ inertia: { motor: 0, load: reflectedInertia, ratio: reflectedInertia / 0.001 },
|
|
|
|
|
+ power: { required: power, rated: power * 1.2 }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 转盘计算
|
|
|
|
|
+ calculateTurntable(params) {
|
|
|
|
|
+ const {
|
|
|
|
|
+ tableMass, tableRadius, friction, efficiency,
|
|
|
|
|
+ maxSpeed, accelerationTime
|
|
|
|
|
+ } = params;
|
|
|
|
|
+
|
|
|
|
|
+ const radius = tableRadius / 1000; // mm to m
|
|
|
|
|
+
|
|
|
|
|
+ // 转盘惯量 (实心圆盘)
|
|
|
|
|
+ const tableInertia = 0.5 * tableMass * Math.pow(radius, 2);
|
|
|
|
|
+
|
|
|
|
|
+ // 摩擦转矩
|
|
|
|
|
+ const gravity = 9.81;
|
|
|
|
|
+ const frictionTorque = tableMass * gravity * friction * radius;
|
|
|
|
|
+
|
|
|
|
|
+ // 转速
|
|
|
|
|
+ const maxRpm = maxSpeed;
|
|
|
|
|
+
|
|
|
|
|
+ // 加速度转矩
|
|
|
|
|
+ const angularAccel = (maxRpm * 2 * Math.PI / 60) / accelerationTime;
|
|
|
|
|
+ const accelTorque = tableInertia * angularAccel;
|
|
|
|
|
+
|
|
|
|
|
+ const peakTorque = (frictionTorque + accelTorque) / efficiency;
|
|
|
|
|
+ const power = (peakTorque * maxRpm * 2 * Math.PI) / 60;
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ speedRange: { min: 0, max: maxRpm },
|
|
|
|
|
+ torque: { continuous: frictionTorque / efficiency, peak: peakTorque },
|
|
|
|
|
+ inertia: { motor: 0, load: tableInertia, ratio: tableInertia / 0.001 },
|
|
|
|
|
+ power: { required: power, rated: power * 1.2 }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 收放卷计算
|
|
|
|
|
+ calculateWinding(params) {
|
|
|
|
|
+ const {
|
|
|
|
|
+ materialDensity, materialWidth, initialDiameter, finalDiameter,
|
|
|
|
|
+ lineSpeed, tension, accelerationTime
|
|
|
|
|
+ } = params;
|
|
|
|
|
+
|
|
|
|
|
+ const initialRadius = initialDiameter / 2000; // mm to m
|
|
|
|
|
+ const finalRadius = finalDiameter / 2000;
|
|
|
|
|
+ const width = materialWidth / 1000;
|
|
|
|
|
+
|
|
|
|
|
+ // 卷筒惯量 (空心圆柱)
|
|
|
|
|
+ const initialMass = materialDensity * Math.PI * (Math.pow(finalRadius, 2) - Math.pow(initialRadius, 2)) * width;
|
|
|
|
|
+ const initialInertia = 0.5 * initialMass * (Math.pow(finalRadius, 2) + Math.pow(initialRadius, 2));
|
|
|
|
|
+
|
|
|
|
|
+ // 张力转矩
|
|
|
|
|
+ const tensionTorque = tension * finalRadius;
|
|
|
|
|
+
|
|
|
|
|
+ // 转速范围
|
|
|
|
|
+ const minRpm = (lineSpeed * 60) / (Math.PI * finalDiameter);
|
|
|
|
|
+ const maxRpm = (lineSpeed * 60) / (Math.PI * initialDiameter);
|
|
|
|
|
+
|
|
|
|
|
+ // 加速度转矩 (使用最大惯量)
|
|
|
|
|
+ const angularAccel = (maxRpm * 2 * Math.PI / 60) / accelerationTime;
|
|
|
|
|
+ const accelTorque = initialInertia * angularAccel;
|
|
|
|
|
+
|
|
|
|
|
+ const peakTorque = tensionTorque + accelTorque;
|
|
|
|
|
+ const power = (peakTorque * maxRpm * 2 * Math.PI) / 60;
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ speedRange: { min: minRpm, max: maxRpm },
|
|
|
|
|
+ torque: { continuous: tensionTorque, peak: peakTorque },
|
|
|
|
|
+ inertia: { motor: 0, load: initialInertia, ratio: initialInertia / 0.001 },
|
|
|
|
|
+ power: { required: power, rated: power * 1.2 }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 直接驱动计算
|
|
|
|
|
+ calculateDirectDrive(params) {
|
|
|
|
|
+ const {
|
|
|
|
|
+ loadInertia, frictionTorque, maxSpeed, accelerationTime
|
|
|
|
|
+ } = params;
|
|
|
|
|
+
|
|
|
|
|
+ // 直接驱动,无传动比
|
|
|
|
|
+ const motorRpm = maxSpeed;
|
|
|
|
|
+
|
|
|
|
|
+ // 加速度转矩
|
|
|
|
|
+ const angularAccel = (motorRpm * 2 * Math.PI / 60) / accelerationTime;
|
|
|
|
|
+ const accelTorque = loadInertia * angularAccel;
|
|
|
|
|
+
|
|
|
|
|
+ const peakTorque = frictionTorque + accelTorque;
|
|
|
|
|
+ const power = (peakTorque * motorRpm * 2 * Math.PI) / 60;
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ speedRange: { min: 0, max: motorRpm },
|
|
|
|
|
+ torque: { continuous: frictionTorque, peak: peakTorque },
|
|
|
|
|
+ inertia: { motor: 0, load: loadInertia, ratio: loadInertia / 0.001 },
|
|
|
|
|
+ power: { required: power, rated: power * 1.2 }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ getFormValues() {
|
|
|
|
|
+ const form = document.getElementById(`${this.currentType}Form`);
|
|
|
|
|
+ const inputs = form.querySelectorAll('input[type="number"]');
|
|
|
|
|
+ const values = {};
|
|
|
|
|
+
|
|
|
|
|
+ inputs.forEach(input => {
|
|
|
|
|
+ const name = input.name;
|
|
|
|
|
+ const value = parseFloat(input.value) || 0;
|
|
|
|
|
+ values[name] = value;
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 获取通用参数
|
|
|
|
|
+ const friction = parseFloat(document.querySelector('[name="friction"]').value) || 0.1;
|
|
|
|
|
+ const efficiency = parseFloat(document.querySelector('[name="efficiency"]').value) || 0.9;
|
|
|
|
|
+ const safetyFactor = parseFloat(document.querySelector('[name="safetyFactor"]').value) || 1.5;
|
|
|
|
|
+ const inertiaRatio = parseFloat(document.querySelector('[name="inertiaRatio"]').value) || 10;
|
|
|
|
|
+
|
|
|
|
|
+ return { ...values, friction, efficiency, safetyFactor, inertiaRatio };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ calculate() {
|
|
|
|
|
+ const params = this.getFormValues();
|
|
|
|
|
+
|
|
|
|
|
+ // 验证输入
|
|
|
|
|
+ if (!this.validateInputs(params)) {
|
|
|
|
|
+ this.showAlert('请检查输入参数是否有效', 'error');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let results;
|
|
|
|
|
+ try {
|
|
|
|
|
+ switch (this.currentType) {
|
|
|
|
|
+ case 'ballScrew':
|
|
|
|
|
+ results = this.calculateBallScrew(params);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'timingBelt':
|
|
|
|
|
+ results = this.calculateTimingBelt(params);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'gearbox':
|
|
|
|
|
+ results = this.calculateGearbox(params);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'turntable':
|
|
|
|
|
+ results = this.calculateTurntable(params);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'winding':
|
|
|
|
|
+ results = this.calculateWinding(params);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 'directDrive':
|
|
|
|
|
+ results = this.calculateDirectDrive(params);
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ throw new Error('未知的传动类型');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 应用安全系数
|
|
|
|
|
+ results.torque.continuous *= params.safetyFactor;
|
|
|
|
|
+ results.torque.peak *= params.safetyFactor;
|
|
|
|
|
+ results.power.rated *= params.safetyFactor;
|
|
|
|
|
+
|
|
|
|
|
+ this.displayResults(results);
|
|
|
|
|
+ this.showAlert('计算完成!', 'success');
|
|
|
|
|
+
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('计算错误:', error);
|
|
|
|
|
+ this.showAlert('计算出错: ' + error.message, 'error');
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ validateInputs(params) {
|
|
|
|
|
+ // 基本验证
|
|
|
|
|
+ for (let key in params) {
|
|
|
|
|
+ if (params[key] < 0) return false;
|
|
|
|
|
+ if (isNaN(params[key])) return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ displayResults(results) {
|
|
|
|
|
+ const resultsDiv = document.getElementById('results');
|
|
|
|
|
+ resultsDiv.innerHTML = `
|
|
|
|
|
+ <div class="result-card">
|
|
|
|
|
+ <h3>计算结果</h3>
|
|
|
|
|
+ <div class="result-grid">
|
|
|
|
|
+ <div class="result-item">
|
|
|
|
|
+ <label>转速范围 (RPM)</label>
|
|
|
|
|
+ <div class="result-value">${results.speedRange.min.toFixed(1)} - ${results.speedRange.max.toFixed(1)}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="result-item">
|
|
|
|
|
+ <label>连续转矩 (N·m)</label>
|
|
|
|
|
+ <div class="result-value">${results.torque.continuous.toFixed(3)}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="result-item">
|
|
|
|
|
+ <label>峰值转矩 (N·m)</label>
|
|
|
|
|
+ <div class="result-value">${results.torque.peak.toFixed(3)}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="result-item">
|
|
|
|
|
+ <label>负载惯量 (kg·m²)</label>
|
|
|
|
|
+ <div class="result-value">${results.inertia.load.toExponential(3)}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="result-item">
|
|
|
|
|
+ <label>惯量比</label>
|
|
|
|
|
+ <div class="result-value">${results.inertia.ratio.toFixed(1)}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="result-item">
|
|
|
|
|
+ <label>所需功率 (W)</label>
|
|
|
|
|
+ <div class="result-value">${results.power.required.toFixed(1)}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="result-item">
|
|
|
|
|
+ <label>额定功率 (W)</label>
|
|
|
|
|
+ <div class="result-value">${results.power.rated.toFixed(1)}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ `;
|
|
|
|
|
+ resultsDiv.style.display = 'block';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ clearResults() {
|
|
|
|
|
+ document.getElementById('results').style.display = 'none';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ resetForm() {
|
|
|
|
|
+ document.querySelectorAll('input[type="number"]').forEach(input => {
|
|
|
|
|
+ input.value = input.defaultValue || '';
|
|
|
|
|
+ input.classList.remove('error');
|
|
|
|
|
+ });
|
|
|
|
|
+ this.clearResults();
|
|
|
|
|
+ this.loadDefaults();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ exportResults() {
|
|
|
|
|
+ const resultsDiv = document.getElementById('results');
|
|
|
|
|
+ if (resultsDiv.style.display === 'none') {
|
|
|
|
|
+ this.showAlert('请先进行计算', 'warning');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const results = resultsDiv.innerText;
|
|
|
|
|
+ const blob = new Blob([results], { type: 'text/plain' });
|
|
|
|
|
+ const url = URL.createObjectURL(blob);
|
|
|
|
|
+ const a = document.createElement('a');
|
|
|
|
|
+ a.href = url;
|
|
|
|
|
+ a.download = `servo_sizing_results_${new Date().toISOString().slice(0, 10)}.txt`;
|
|
|
|
|
+ document.body.appendChild(a);
|
|
|
|
|
+ a.click();
|
|
|
|
|
+ document.body.removeChild(a);
|
|
|
|
|
+ URL.revokeObjectURL(url);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ showAlert(message, type = 'info') {
|
|
|
|
|
+ const alertDiv = document.createElement('div');
|
|
|
|
|
+ alertDiv.className = `alert alert-${type}`;
|
|
|
|
|
+ alertDiv.textContent = message;
|
|
|
|
|
+ document.body.appendChild(alertDiv);
|
|
|
|
|
+
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ alertDiv.remove();
|
|
|
|
|
+ }, 3000);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 初始化应用
|
|
|
|
|
+document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
|
+ new ServoSizer();
|
|
|
|
|
+});
|