当前位置: 首页 > news >正文

基于MATLAB的雨流计数法疲劳计算GUI可视化系统

1. 系统设计与GUI界面

1.1 主界面设计

classdef FatigueAnalysisGUI < matlab.apps.AppBase% 疲劳分析GUI主类properties (Access = public)UIFigure            matlab.ui.FigureLoadButton          matlab.ui.control.ButtonProcessButton       matlab.ui.control.ButtonExportButton        matlab.ui.control.ButtonDataTable           matlab.ui.control.TableResultsTable        matlab.ui.control.TableAxesRaw             matlab.ui.control.UIAxesAxesRainflow        matlab.ui.control.UIAxesAxesDamage          matlab.ui.control.UIAxesStatusLabel         matlab.ui.control.Label% 数据存储RawData             doubleRainflowResults     structMaterialData        structendmethods (Access = private)% 回调函数和其他方法将在这里定义end
end

1.2 GUI布局代码

function createComponents(app)% 创建主窗口app.UIFigure = uifigure('Position', [100 100 1400 800], ...'Name', '雨流计数法疲劳分析系统', ...'Icon', 'fatigue_icon.png');% 创建按钮面板buttonPanel = uipanel(app.UIFigure, 'Position', [20 700 1360 80], ...'Title', '控制面板');% 加载数据按钮app.LoadButton = uibutton(buttonPanel, 'push', ...'Position', [20 20 100 40], ...'Text', '加载数据', ...'ButtonPushedFcn', createCallbackFcn(app, @LoadButtonPushed, true));% 处理按钮app.ProcessButton = uibutton(buttonPanel, 'push', ...'Position', [140 20 100 40], ...'Text', '雨流计数', ...'ButtonPushedFcn', createCallbackFcn(app, @ProcessButtonPushed, true));% 导出结果按钮app.ExportButton = uibutton(buttonPanel, 'push', ...'Position', [260 20 100 40], ...'Text', '导出结果', ...'ButtonPushedFcn', createCallbackFcn(app, @ExportButtonPushed, true));% 材料选择下拉菜单materialLabel = uilabel(buttonPanel, 'Position', [380 45 60 20], ...'Text', '材料:');app.MaterialDropdown = uidropdown(buttonPanel, ...'Position', [440 20 120 40], ...'Items', {'钢-低碳', '钢-合金', '铝-2024', '铝-7075', '钛合金', '自定义'});% 状态标签app.StatusLabel = uilabel(buttonPanel, 'Position', [600 45 400 20], ...'Text', '就绪', 'FontColor', 'blue');% 创建数据显示区域dataPanel = uipanel(app.UIFigure, 'Position', [20 400 680 280], ...'Title', '载荷数据');app.DataTable = uitable(dataPanel, 'Position', [10 10 660 250]);% 创建结果显示区域resultsPanel = uipanel(app.UIFigure, 'Position', [720 400 660 280], ...'Title', '雨流计数结果');app.ResultsTable = uitable(resultsPanel, 'Position', [10 10 640 250]);% 创建图形显示区域% 原始数据图app.AxesRaw = uiaxes(app.UIFigure, 'Position', [20 50 450 320]);title(app.AxesRaw, '原始载荷时间历程');xlabel(app.AxesRaw, '时间');ylabel(app.AxesRaw, '载荷');grid(app.AxesRaw, 'on');% 雨流矩阵图app.AxesRainflow = uiaxes(app.UIFigure, 'Position', [500 50 450 320]);title(app.AxesRainflow, '雨流计数矩阵');xlabel(app.AxesRainflow, '均值');ylabel(app.AxesRainflow, '幅值');grid(app.AxesRainflow, 'on');% 损伤贡献图app.AxesDamage = uiaxes(app.UIFigure, 'Position', [980 50 400 320]);title(app.AxesDamage, '损伤贡献分布');xlabel(app.AxesDamage, '循环类型');ylabel(app.AxesDamage, '损伤度');grid(app.AxesDamage, 'on');
end

2. 核心算法实现

2.1 雨流计数法核心算法

function results = rainflow_analysis(data, varargin)% 雨流计数法分析% 输入:%   data - 载荷时间序列%   varargin - 可选参数% 输出:%   results - 包含分析结果的结构体p = inputParser;addParameter(p, 'Residual', 'conservative', @ischar); % 残余应力处理addParameter(p, 'BinSize', 10, @isnumeric); % 分级大小parse(p, varargin{:});% 数据预处理 - 峰值谷值提取[peaks_valleys, indices] = extract_peaks_valleys(data);% 雨流计数主循环cycles = [];residual = [];history = peaks_valleys;while length(history) > 1i = 2;while i <= length(history)-1% 检查三个连续点是否构成一个循环X = abs(history(i-1) - history(i));Y = abs(history(i) - history(i+1));if X <= Y && i > 1% 找到一个循环range_val = abs(history(i-1) - history(i));mean_val = (history(i-1) + history(i)) / 2;cycle = struct();cycle.range = range_val;cycle.mean = mean_val;cycle.count = 0.5; % 半循环cycle.points = [history(i-1), history(i)];cycles = [cycles; cycle];% 从历史中移除这个循环的点history(i-1:i) = [];i = max(2, i-1);elsei = i + 1;endend% 残余应力处理if length(residual) < length(history)residual = history;elsebreak;endend% 处理残余序列if strcmp(p.Results.Residual, 'conservative')% 将残余序列作为半循环处理for i = 1:length(residual)-1range_val = abs(residual(i) - residual(i+1));mean_val = (residual(i) + residual(i+1)) / 2;cycle = struct();cycle.range = range_val;cycle.mean = mean_val;cycle.count = 0.5;cycle.points = [residual(i), residual(i+1)];cycles = [cycles; cycle];endend% 合并半循环为全循环results = combine_half_cycles(cycles);% 分级统计results.binned_cycles = bin_cycles(results.full_cycles, p.Results.BinSize);% 计算统计信息results.statistics = calculate_statistics(results);
endfunction [peaks_valleys, indices] = extract_peaks_valleys(data)% 提取峰值和谷值点% 找到所有的局部极值点diff1 = diff(data);diff2 = diff(diff1);% 找到转折点 (峰值和谷值)turning_points = [];for i = 2:length(data)-1if (data(i) > data(i-1) && data(i) > data(i+1)) || ... % 峰值(data(i) < data(i-1) && data(i) < data(i+1))       % 谷值turning_points = [turning_points, i];endend% 包括第一个和最后一个点turning_points = [1, turning_points, length(data)];% 移除连续重复的转折点unique_points = turning_points(1);for i = 2:length(turning_points)if data(turning_points(i)) ~= data(unique_points(end))unique_points = [unique_points, turning_points(i)];endendpeaks_valleys = data(unique_points);indices = unique_points;
endfunction results = combine_half_cycles(half_cycles)% 合并半循环为全循环full_cycles = [];used = false(length(half_cycles), 1);for i = 1:length(half_cycles)if used(i), continue; endfor j = i+1:length(half_cycles)if used(j), continue; end% 检查是否构成完整的循环if abs(half_cycles(i).range - half_cycles(j).range) < 1e-6 && ...abs(half_cycles(i).mean - half_cycles(j).mean) < 1e-6full_cycle = half_cycles(i);full_cycle.count = 1.0; % 全循环full_cycles = [full_cycles; full_cycle];used(i) = true;used(j) = true;break;endend% 如果没有找到匹配的半循环,保留为半循环if ~used(i)full_cycles = [full_cycles; half_cycles(i)];endendresults.full_cycles = full_cycles;
endfunction binned_cycles = bin_cycles(full_cycles, bin_size)% 对循环进行分级统计ranges = [full_cycles.range];means = [full_cycles.mean];counts = [full_cycles.count];% 创建分级边界max_range = max(ranges);max_mean = max(means);min_mean = min(means);range_bins = 0:bin_size:ceil(max_range/bin_size)*bin_size;mean_bins = floor(min_mean/bin_size)*bin_size:bin_size:ceil(max_mean/bin_size)*bin_size;% 初始化分级矩阵binned_cycles = zeros(length(mean_bins)-1, length(range_bins)-1);% 统计每个分级的循环次数for i = 1:length(full_cycles)range_idx = find(range_bins(1:end-1) <= full_cycles(i).range & ...range_bins(2:end) > full_cycles(i).range, 1);mean_idx = find(mean_bins(1:end-1) <= full_cycles(i).mean & ...mean_bins(2:end) > full_cycles(i).mean, 1);if ~isempty(range_idx) && ~isempty(mean_idx)binned_cycles(mean_idx, range_idx) = ...binned_cycles(mean_idx, range_idx) + full_cycles(i).count;endendbinned_cycles = struct();binned_cycles.matrix = binned_cycles;binned_cycles.range_bins = range_bins;binned_cycles.mean_bins = mean_bins;
endfunction stats = calculate_statistics(results)% 计算统计信息ranges = [results.full_cycles.range];means = [results.full_cycles.mean];counts = [results.full_cycles.count];stats.total_cycles = sum(counts);stats.max_range = max(ranges);stats.min_range = min(ranges);stats.mean_range = mean(ranges);stats.max_mean = max(means);stats.min_mean = min(means);stats.mean_mean = mean(means);% 等效载荷计算m = 3; % 典型的S-N曲线斜率 (对于钢材)equivalent_load = (sum(ranges.^m .* counts) / sum(counts))^(1/m);stats.equivalent_load = equivalent_load;
end

2.2 疲劳损伤计算

function damage_results = fatigue_damage_analysis(rainflow_results, material)% 疲劳损伤分析% 输入:%   rainflow_results - 雨流计数结果%   material - 材料参数full_cycles = rainflow_results.full_cycles;ranges = [full_cycles.range];counts = [full_cycles.count];% 初始化损伤结果damage_results = struct();damage_results.cycle_damage = zeros(size(ranges));damage_results.total_damage = 0;damage_results.life_cycles = Inf;% 根据材料类型选择S-N曲线参数switch material.typecase '钢-低碳'S_ref = 1000; % MPa - 参考应力N_ref = 1e6;  % 参考寿命m = 3.0;      % S-N曲线斜率k = 0;        % 均值应力修正参数case '钢-合金'S_ref = 1200;N_ref = 1e6;m = 3.5;k = 0.1;case '铝-2024'S_ref = 400;N_ref = 5e6;m = 4.0;k = 0.2;case '铝-7075'S_ref = 500;N_ref = 5e6;m = 4.2;k = 0.15;case '钛合金'S_ref = 800;N_ref = 1e6;m = 3.8;k = 0.05;otherwise% 自定义材料参数S_ref = material.S_ref;N_ref = material.N_ref;m = material.m;k = material.k;end% 计算每个循环的损伤total_damage = 0;for i = 1:length(ranges)% 考虑均值应力影响的Goodman修正mean_stress = [full_cycles(i).mean];if mean_stress > 0equivalent_range = ranges(i) / (1 - mean_stress / material.ultimate_strength);elseequivalent_range = ranges(i);end% 计算该应力水平下的寿命N_i = N_ref * (S_ref / equivalent_range)^m;% 计算损伤if N_i > 0cycle_damage = counts(i) / N_i;damage_results.cycle_damage(i) = cycle_damage;total_damage = total_damage + cycle_damage;endenddamage_results.total_damage = total_damage;% 计算预测寿命if total_damage > 0damage_results.life_cycles = 1 / total_damage;end% 损伤贡献分析[~, damage_sort_idx] = sort(damage_results.cycle_damage, 'descend');damage_results.top_damage_contributors = damage_sort_idx(1:min(10, length(damage_sort_idx)));
end

3. GUI回调函数实现

3.1 数据加载回调

function LoadButtonPushed(app, ~)% 加载数据按钮回调函数try% 打开文件选择对话框[filename, pathname] = uigetfile({...'*.txt;*.csv;*.xlsx;*.xls', '数据文件 (*.txt, *.csv, *.xlsx, *.xls)'; ...'*.txt', '文本文件 (*.txt)'; ...'*.csv', 'CSV文件 (*.csv)'; ...'*.xlsx', 'Excel文件 (*.xlsx)'}, ...'选择载荷数据文件');if isequal(filename, 0)app.StatusLabel.Text = '用户取消选择';app.StatusLabel.FontColor = 'blue';return;endfullpath = fullfile(pathname, filename);app.StatusLabel.Text = sprintf('正在加载文件: %s', filename);drawnow;% 根据文件类型加载数据[~, ~, ext] = fileparts(filename);switch lower(ext)case {'.txt', '.csv'}% 加载文本或CSV文件data = load(fullpath);if size(data, 2) > 1% 如果有多列,使用第一列作为时间,第二列作为载荷app.RawData = data(:, 2);time_vector = data(:, 1);elseapp.RawData = data;time_vector = (1:length(data))';endcase {'.xlsx', '.xls'}% 加载Excel文件data = readtable(fullpath);app.RawData = table2array(data(:, 2)); % 假设第二列是载荷time_vector = table2array(data(:, 1)); % 假设第一列是时间otherwiseerror('不支持的文件格式');end% 更新数据表格table_data = [time_vector, app.RawData];app.DataTable.Data = array2table(table_data, ...'VariableNames', {'时间', '载荷'});% 绘制原始数据plot(app.AxesRaw, time_vector, app.RawData, 'b-', 'LineWidth', 1);title(app.AxesRaw, sprintf('原始载荷数据 - %s', filename));xlabel(app.AxesRaw, '时间');ylabel(app.AxesRaw, '载荷');grid(app.AxesRaw, 'on');app.StatusLabel.Text = sprintf('数据加载成功: %d 个数据点', length(app.RawData));app.StatusLabel.FontColor = 'green';catch MEapp.StatusLabel.Text = sprintf('加载失败: %s', ME.message);app.StatusLabel.FontColor = 'red';uialert(app.UIFigure, ME.message, '数据加载错误');end
end

3.2 雨流计数处理回调

function ProcessButtonPushed(app, ~)% 雨流计数处理按钮回调函数if isempty(app.RawData)uialert(app.UIFigure, '请先加载数据', '数据错误');return;endtryapp.StatusLabel.Text = '正在进行雨流计数分析...';drawnow;% 执行雨流计数分析app.RainflowResults = rainflow_analysis(app.RawData, 'BinSize', 10);% 更新结果表格cycles_data = [];for i = 1:length(app.RainflowResults.full_cycles)cycle = app.RainflowResults.full_cycles(i);cycles_data(i, :) = [cycle.range, cycle.mean, cycle.count];endapp.ResultsTable.Data = array2table(cycles_data, ...'VariableNames', {'应力幅值', '平均应力', '循环次数'});% 绘制雨流矩阵图plot_rainflow_matrix(app);% 进行疲劳损伤分析material = get_material_parameters(app.MaterialDropdown.Value);damage_results = fatigue_damage_analysis(app.RainflowResults, material);% 绘制损伤贡献图plot_damage_contribution(app, damage_results);% 显示统计信息show_statistics_dialog(app, damage_results);app.StatusLabel.Text = sprintf('分析完成 - 总损伤: %.6f', damage_results.total_damage);app.StatusLabel.FontColor = 'green';catch MEapp.StatusLabel.Text = sprintf('分析失败: %s', ME.message);app.StatusLabel.FontColor = 'red';uialert(app.UIFigure, ME.message, '分析错误');end
endfunction plot_rainflow_matrix(app)% 绘制雨流计数矩阵图binned = app.RainflowResults.binned_cycles;matrix = binned.matrix;% 创建热图imagesc(app.AxesRainflow, matrix);% 设置坐标轴标签range_centers = (binned.range_bins(1:end-1) + binned.range_bins(2:end)) / 2;mean_centers = (binned.mean_bins(1:end-1) + binned.mean_bins(2:end)) / 2;[X, Y] = meshgrid(range_centers, mean_centers);contourf(app.AxesRainflow, X, Y, matrix, 20, 'LineColor', 'none');colorbar(app.AxesRainflow);title(app.AxesRainflow, '雨流计数矩阵');xlabel(app.AxesRainflow, '应力幅值');ylabel(app.AxesRainflow, '平均应力');% 添加等高线hold(app.AxesRainflow, 'on');contour(app.AxesRainflow, X, Y, matrix, 10, 'LineColor', 'black', 'LineWidth', 0.5);hold(app.AxesRainflow, 'off');
endfunction plot_damage_contribution(app, damage_results)% 绘制损伤贡献分布图top_contributors = damage_results.top_damage_contributors;cycle_damage = damage_results.cycle_damage(top_contributors);% 创建条形图bar(app.AxesDamage, cycle_damage, 'FaceColor', 'red', 'EdgeColor', 'black');% 添加标签labels = cell(length(top_contributors), 1);for i = 1:length(top_contributors)idx = top_contributors(i);cycle = app.RainflowResults.full_cycles(idx);labels{i} = sprintf('%.1f/%.1f', cycle.range, cycle.mean);endset(app.AxesDamage, 'XTickLabel', labels);xtickangle(app.AxesDamage, 45);title(app.AxesDamage, '前10大损伤贡献循环');xlabel(app.AxesDamage, '循环类型 (幅值/均值)');ylabel(app.AxesDamage, '损伤度');grid(app.AxesDamage, 'on');
end

3.3 材料参数获取

function material = get_material_parameters(material_name)% 根据材料名称获取材料参数material = struct();material.type = material_name;switch material_namecase '钢-低碳'material.S_ref = 1000;  % MPamaterial.N_ref = 1e6;material.m = 3.0;material.k = 0;material.ultimate_strength = 400;case '钢-合金'material.S_ref = 1200;material.N_ref = 1e6;material.m = 3.5;material.k = 0.1;material.ultimate_strength = 800;case '铝-2024'material.S_ref = 400;material.N_ref = 5e6;material.m = 4.0;material.k = 0.2;material.ultimate_strength = 300;case '铝-7075'material.S_ref = 500;material.N_ref = 5e6;material.m = 4.2;material.k = 0.15;material.ultimate_strength = 350;case '钛合金'material.S_ref = 800;material.N_ref = 1e6;material.m = 3.8;material.k = 0.05;material.ultimate_strength = 900;case '自定义'% 弹出对话框让用户输入自定义参数material = get_custom_material_parameters();end
endfunction material = get_custom_material_parameters()% 获取自定义材料参数prompt = {...'参考应力 S_ref (MPa):', ...'参考寿命 N_ref:', ...'S-N曲线斜率 m:', ...'均值应力修正系数 k:', ...'极限强度 (MPa):'};dlgtitle = '自定义材料参数';dims = [1 35];definput = {'1000', '1000000', '3.0', '0', '500'};answer = inputdlg(prompt, dlgtitle, dims, definput);if isempty(answer)error('用户取消了材料参数输入');endmaterial = struct();material.type = '自定义';material.S_ref = str2double(answer{1});material.N_ref = str2double(answer{2});material.m = str2double(answer{3});material.k = str2double(answer{4});material.ultimate_strength = str2double(answer{5});
end

4. 结果导出与报告生成

function ExportButtonPushed(app, ~)% 导出结果按钮回调函数if isempty(app.RainflowResults)uialert(app.UIFigure, '请先进行雨流计数分析', '数据错误');return;endtry% 选择保存位置[filename, pathname] = uiputfile({...'*.xlsx', 'Excel文件 (*.xlsx)'; ...'*.pdf', 'PDF报告 (*.pdf)'; ...'*.mat', 'MAT文件 (*.mat)'}, ...'保存分析结果');if isequal(filename, 0)return;endfullpath = fullfile(pathname, filename);[~, ~, ext] = fileparts(filename);app.StatusLabel.Text = '正在导出结果...';drawnow;switch lower(ext)case '.xlsx'export_to_excel(app, fullpath);case '.pdf'export_to_pdf(app, fullpath);case '.mat'export_to_mat(app, fullpath);otherwiseerror('不支持的导出格式');endapp.StatusLabel.Text = sprintf('结果已导出: %s', filename);app.StatusLabel.FontColor = 'green';catch MEapp.StatusLabel.Text = sprintf('导出失败: %s', ME.message);app.StatusLabel.FontColor = 'red';uialert(app.UIFigure, ME.message, '导出错误');end
endfunction export_to_excel(app, filename)% 导出结果到Excel文件% 创建Excel文件warning('off', 'MATLAB:xlswrite:AddSheet');% 写入原始数据xlswrite(filename, {'时间', '载荷'}, '原始数据');xlswrite(filename, app.DataTable.Data, '原始数据', 'A2');% 写入雨流计数结果header = {'应力幅值', '平均应力', '循环次数'};xlswrite(filename, header, '雨流计数结果');xlswrite(filename, app.ResultsTable.Data, '雨流计数结果', 'A2');% 写入统计信息stats = app.RainflowResults.statistics;stat_data = {...'总循环数', stats.total_cycles; ...'最大应力幅值', stats.max_range; ...'最小应力幅值', stats.min_range; ...'平均应力幅值', stats.mean_range; ...'等效载荷', stats.equivalent_load};xlswrite(filename, {'统计信息', ''}, '统计信息');xlswrite(filename, stat_data, '统计信息', 'A2');warning('on', 'MATLAB:xlswrite:AddSheet');
end

5. 使用示例

% 主程序启动函数
function start_fatigue_analysis_gui()% 启动疲劳分析GUI% 检查是否在App Designer环境中运行if exist('matlab.apps.AppBase', 'class')% 在App Designer中运行app = FatigueAnalysisGUI();else% 在传统GUI中运行create_legacy_gui();end
end% 传统GUI版本(兼容旧版MATLAB)
function create_legacy_gui()% 创建传统版本的GUIfig = figure('Position', [100 100 1400 800], ...'Name', '雨流计数法疲劳分析系统', ...'NumberTitle', 'off', ...'MenuBar', 'none', ...'ToolBar', 'none');% 创建简单的界面组件uicontrol('Style', 'pushbutton', ...'Position', [20 750 100 30], ...'String', '加载数据', ...'Callback', @load_data_callback);uicontrol('Style', 'pushbutton', ...'Position', [140 750 100 30], ...'String', '雨流计数', ...'Callback', @rainflow_analysis_callback);% 添加其他组件...% 存储应用数据appdata = struct();appdata.fig = fig;guidata(fig, appdata);
end% 启动GUI
start_fatigue_analysis_gui();

参考代码 雨流计数法疲劳计算GUI可视化 www.youwenfan.com/contentcni/64596.html

6. 系统特点

  1. 用户友好界面:直观的GUI设计,便于工程技术人员使用
  2. 完整分析流程:从数据加载到疲劳寿命预测的全流程分析
  3. 多种材料支持:内置常见工程材料的疲劳参数
  4. 丰富可视化:提供多种图形展示分析结果
  5. 灵活数据导出:支持多种格式的结果导出
  6. 专业算法:基于标准的雨流计数法和Miner线性累积损伤理论
http://www.hskmm.com/?act=detail&tid=27371

相关文章:

  • 2025 年园林剪刀源头厂家最新推荐排行榜:电动 / 修枝 / 果树 / 精密 / 修树 / 高枝 / 专业园艺 / 入门级 / 多功能工具选购指南
  • 离散数学与结构 Part2
  • [NOI2001] 炮兵阵地 - 洛谷
  • 告别 “能源黑箱”:MyEMS 如何让中小企业的能耗数据 “会说话”?
  • 实用指南:赛思金融授时服务器 从《捕风追影》纳秒困局到数字安全,赛思以全链路时钟同步方案夯实时序安全底座
  • 企业级 Java AI 开发首选!JBoltAI 带 RAG 知识库 + Agent 智能体,轻松改造老系统
  • CH585通过SPI驱动TFT屏
  • 机械手偏差,极坐标与直角坐标转换
  • 2025 年造雪机厂家最新推荐排行榜:国产优质厂家深度解析,助力滑雪场与冰雪乐园精准选购
  • 当 MyEMS 遇上数字孪生:园区能源 “透明化” 能有多极致?
  • 2025雷蒙磨粉机厂家推荐榜:定制化生产与高效研磨口碑之选
  • 技术复习要点清单
  • res-downloader v2.1.2 全平台资源下载工具深度指南:支持视频号/抖音/音视频嗅探,附常见问题解决方案
  • 从设备监控到全局调控,MyEMS 如何构建 “全链路” 能源管理体系?
  • 题解:AT_mujin_pc_2017_d Oriented Tree
  • Redis缓存穿透优化
  • 元空间的两个重要参数
  • 工作电压2.4V-5.5V*低功耗单路触摸/单键触控感应芯片VKD233HR DFN6L
  • 2025.10.9——1橙
  • 抽象函数的定义域
  • GEO优化系统哪个最好?
  • 6G多站多智能超表面(RIS)
  • 缓冲区管理
  • Oracle故障处理:ASM手动修复磁盘头
  • 智慧考试微信小程序系统:一站式在线考试解决方案
  • 深入解析:【双光相机配准】可见光相机内参标定流程
  • oracle中引号的使用总结与报错信息
  • 2025 年电线电缆厂家最新推荐:实力厂家榜单重磅发布,涵盖多品类线缆及专业选择指南国标/朝阳/低压/阻燃/耐火/北京电线电缆厂家推荐
  • 5分钟,15分钟,差距大,做5分钟线要严格止损
  • 家政服务小程序系统:一站式家政服务解决方案