分享一个自用的表格式流程编辑软件源码

By admin at 2021-11-19 • 1人收藏 • 1485人看过

image.png

screenshots.gif

有时候客户需要灵活修改部分功能, 于是就需要你每次提需求改代码改功能, 太麻烦了有木有?


有了这款软件只需要你在你的主程序里解析编写好的流程文件, 然后按照一定的逻辑执行.

这个是我项目里一直再使用的, 给客户在你既定的功能上编写玩的, 然后你的主程序对编好的程序文件进行解析就可以了.


为了能灵活配置自动功能项 , 我把自动完成和自动提示功能用fsys.table来实现, 这样即使客户需要你增加其他功能的流程编辑功能, 只需要修改 流程数据/program.table 这个文件内容即可.

好了, 不藏私, 分享给大家 , 代码难免有一些不简洁的地方, 希望大家能留言共同改进!

表格控件使用了flexcell 6.3.4版本, 库代码在其他帖里找, 表格控件自己去百度.

使用方法:

  1. 先在左侧新增流程

  2. 右侧鼠标点击右键 , 看到好多菜单, 新增10行

  3. 双击[功能名称]那列, 会出现下拉菜单, 选择后, 在双击它后面的那列,继续选择, 后面那些参数会自动填充,

  4. 单击你编好的任意一行, 标题栏会自动改变每列的标题为此列的提示信息.

  5. 没啥可说了, 看代码吧

  6. 有用得到的人吱一声, 当然能留言继续改进更多功能就更赞了.

  7. 对了, 附上program.table文件

    流程数据.zip

import process.mutex;
var mutex = process.mutex("6908C972-AB73-4CDE-9DD7-9B5360C7E544") 
if( mutex.conflict ){
    import win.ui.atom;
    var atom,hwndConflict = win.ui.atom.find("E9CB8A6C-4F72-4B2F-8352-DFB3D083FF04")
    if( hwndConflict ) 
    {
    	win.setForeground(hwndConflict);
    	return;
    }
} 

import win.ui;
/*DSG{{*/
mainForm = win.form(text="流程编辑";right=1323;bottom=613;border="thin")
mainForm.add(
leftList={cls="static";left=7;top=9;right=240;bottom=568;bgcolor=12639424;db=1;dl=1;dt=1;z=1};
rightList={cls="static";left=245;top=9;right=1321;bottom=568;bgcolor=12632256;db=1;dr=1;dt=1;z=2};
splitter={cls="splitter";left=242;top=9;right=247;bottom=568;db=1;dt=1;frame=1;z=7};
保存={cls="button";text="保 存";left=1011;top=575;right=1159;bottom=610;db=1;dr=1;font=LOGFONT(h=-20);z=3};
取消={cls="button";text="取 消";left=1170;top=575;right=1318;bottom=610;db=1;dr=1;font=LOGFONT(h=-20);z=4};
新增={cls="button";text="新 增";left=245;top=575;right=334;bottom=610;db=1;dl=1;font=LOGFONT(h=-20);z=6};
新增名称={cls="edit";left=6;top=575;right=238;bottom=610;border=1;db=1;dl=1;font=LOGFONT(h=-20);z=5}
)
/*}}*/

import win.ui.atom; 
mainForm.atom("E9CB8A6C-4F72-4B2F-8352-DFB3D083FF04"); 

mainForm.splitter.split(mainForm.leftList,mainForm.rightList);

import fsys.table;
import FlexCellLib;
import win.ui.menu;
import string.database;
//定义左右两侧窗口
var flcLeft,flcRight;
//定义重命名前文件名
var preText;
//定义左侧右键删除项
var deleteRow;
//判断是否有需要保存的数据
var saveFlag = false;

flcLeft = FlexCellLib(mainForm.leftList,1,2);
flcRight = FlexCellLib(mainForm.rightList,1,11);

var 方程集 = fsys.table("\流程数据\progrem.table");

/*点击改变文本颜色{{*/
var rowTextColorChange = function(rowIndex){
    if(flcLeft.Rows>1){
    	for(i=1;flcLeft.Rows-1;1){
			if(rowIndex == i){
				flcLeft.Cell(rowIndex,1).ForeColor = 0x0000FF;
				flcLeft.Cell(rowIndex,1).Font.setBold(true);
			}else {
				flcLeft.Cell(i,1).ForeColor = 0x000000;
				flcLeft.Cell(i,1).Font.setBold(false);
			}
		}
    }
}
/*}}*/

/*CVS文件解析{{*/
var csvPara = function(fileName){
    //还原字符串
	var toStr = function(str){
		return string.fromto(str,936,65001)
	}
	var txt = string.load("\流程数据\"+fileName+".csv");
	var strDb = string.database(",");
	var data = strDb.parse(txt); //解析数据
	flcRight.AutoRedraw = false;
	if(flcRight.Rows>1){
		flcRight.Range(1,0,flcRight.Rows-1,0).DeleteByRow();
	}
	for(i=1;#data;1){
		if(i>(flcRight.Rows-1)){
			flcRight.AddItem("",false);
		}
		for(j=1;#data[i];1){
			flcRight.Cell(i,j).Text = toStr(data[i][j]);
		}
		if( data[i][1]=="" or data[i][1]==null ) flcRight.Range(i,1,i,flcRight.Cols-1).BackColor = 0x8273FF;			
	}
	flcRight.AutoRedraw = true;
	flcRight.Refresh();
}
/*}}*/

/*右键菜单{{*/
mainForm.Leftpopmenu = win.ui.popmenu(mainForm);//创建弹出菜单
mainForm.Leftpopmenu.add('移除此流程',function(id){
    if( deleteRow ){
    	var Text = flcLeft.Cell(deleteRow,1).Text;
    	var ret = fsys.delete("\流程数据\"++ Text ++ ".csv");
    	if(ret){
    		flcLeft.RemoveItem(deleteRow)
    		if(deleteRow < (flcLeft.Rows-1)){
    			rowTextColorChange(deleteRow);
    			csvPara(flcLeft.Cell(deleteRow,1).Text);
    		}else {
    			rowTextColorChange(flcLeft.Rows-1);
    			csvPara(flcLeft.Cell(flcLeft.Rows-1,1).Text);
    		}
    		mainForm.msgbox("删除 "++ Text ++" 流程成功!")
    	}else {
    		mainForm.msgboxErr("删除失败!")
    	}
    	deleteRow = null;	
    }
});
flcLeft.MouseUp = function(Button , Shift, x, y){
	if(Button == 2){
		if( flcLeft.HitTest(x,y) ){
			if(saveFlag){
    			var ret = mainForm.msgboxTest("发现有未保存的数据,是否需要返回并手动保存?");
    			if(ret){
    				return;
    			}
    			saveFlag = false;
    		}
    
			deleteRow = flcLeft.HitTest(x,y).Row;
			mainForm.Leftpopmenu.popup();	
		}
    }
}
//--------------------------------------------------------
mainForm.Rightpopmenu = win.ui.popmenu(mainForm);//创建弹出菜单
mainForm.Rightpopmenu.add('新增一行',function(id){
    //在下面输入菜单响应代码
    if(flcLeft.ActiveCell().Text !=""){
    	flcRight.AddItem("",true);
    	flcRight.Range(flcRight.Rows-1,1,flcRight.Rows-1,flcRight.Cols-1).BackColor = 0x8273FF;
    }else {
    	mainForm.msgboxErr('请先从左边中选择一个需要编辑的流程\n或者在左侧创建新的流程!');
    }
});
mainForm.Rightpopmenu.add('新增十行',function(id){
    //在下面输入菜单响应代码
    if(flcLeft.ActiveCell().Text !=""){
        for(i=1;10;1){
        	flcRight.AddItem("",true);
        	flcRight.Range(flcRight.Rows-1,1,flcRight.Rows-1,flcRight.Cols-1).BackColor = 0x8273FF;
        }	
    }else {
    	mainForm.msgboxErr('请先从左边中选择一个需要编辑的流程\n或者在左侧创建新的流程!');
    }
});
mainForm.Rightpopmenu.add('插入行',function(id){
    //在下面输入菜单响应代码
    if(flcRight.ActiveCell().Text != ""){
    	flcRight.Selection.InsertRows();
    	flcRight.Selection.BackColor = 0x8273FF;
    }else {
    	if(flcLeft.ActiveCell().Text !=""){
    		flcRight.AddItem("",true);
    		flcRight.Range(flcRight.ActiveCell().Row-1,1,flcRight.ActiveCell().Row-1,flcRight.Cols-1).BackColor = 0x8273FF;
    	}else {
    		mainForm.msgboxErr('请先从左边中选择一个需要编辑的流程\n或者在左侧创建新的流程!');
    	}
    } 
});
mainForm.Rightpopmenu.add('剪切',function(id){
    //在下面输入菜单响应代码
    flcRight.Selection.CutData();
});
mainForm.Rightpopmenu.add('复制',function(id){
    //在下面输入菜单响应代码
    flcRight.Selection.CopyData();
});
mainForm.Rightpopmenu.add('粘贴',function(id){
    //在下面输入菜单响应代码
    flcRight.Selection.PasteData();
});
mainForm.Rightpopmenu.add('移除选中行',function(id){
    //在下面输入菜单响应代码
    flcRight.Selection.DeleteByRow();
});
mainForm.Rightpopmenu.add('清除选中行内容',function(id){
    //在下面输入菜单响应代码
    flcRight.Selection.ClearText();
});

flcRight.MouseUp = function(Button , Shift, x, y){
	if(Button == 2){
		mainForm.Rightpopmenu.popup();
    }
}

/*}}*/

/*初始化界面{{*/
var setListStyle = function(flcobj){
    flcobj.BackColorScrollBar = 0xD3AF1C;
    flcobj.BackColorActiveCellSel = 0x8273FF;
	flcobj.BackColorFixedSel = 0xCCC899;
	flcobj.BackColorSel = 0x8273FF;
	flcobj.SelectionMode = 1/*_cellSelectionByRow*/;
	flcobj.DefaultFont.setSize(15)
}
var setColStyle = function(flcobj,Col,Width,Align=0xA,Text){
    if(Width != null){
    	flcobj.Column(Col).Width = Width;
    }
	flcobj.Column(Col).Alignment = Align;
	flcobj.Cell(0,Col).Text = Text;
}

//----------------
setListStyle(flcLeft);
setColStyle(flcLeft,0,0);
setColStyle(flcLeft,1,,6,"流程名称");
//---------------
setListStyle(flcRight);
setColStyle(flcRight,1,40,,"");
setColStyle(flcRight,2,400,6/*_cellLeftCenter*/,"备  注");
setColStyle(flcRight,3,150,,"功能名称");
setColStyle(flcRight,4,250,,"方法名称");
setColStyle(flcRight,5,150,,"参数一");
setColStyle(flcRight,6,130,,"参数二");
setColStyle(flcRight,7,130,,"参数三");
setColStyle(flcRight,8,130,,"参数四");
setColStyle(flcRight,9,130,,"参数五");
setColStyle(flcRight,10,130,,"参数六");

flcRight.ComboBox(0).Font.setSize(14);
flcRight.Column(1).CellType = 2/*_cellCheckBox*/;
flcRight.Column(3).CellType = 1/*_cellComboBox*/;
flcRight.Column(4).CellType = 1/*_cellComboBox*/;
flcRight.ComboBox(3).Font.setSize(14);
flcRight.ComboBox(4).Font.setSize(14);
/*}}*/

/*枚举所有流程文件{{*/
try{
	fsys.enum( "/流程数据", "*.csv",
		function(dirpath,dirname){
			flcLeft.AddItem(string.replace(dirname,".csv",""),true);
		}
	);	
}
/*}}*/

/*填充默认数据{{*/
if(flcLeft.Rows>1){
    //默认选中第一个流程
	flcLeft.Range(1,0,1,0).Selected();
	rowTextColorChange(1);
	csvPara(flcLeft.Cell(1,1).Text);
}
/*}}*/

/*重命名流程功能{{*/
flcLeft.DblClick = function(){
    var cellDD = flcLeft.HitTest(flcLeft.MouseRow,flcLeft.MouseCol);
    if( cellDD ){
    	preText = flcLeft.Cell(flcLeft.MouseRow,flcLeft.MouseCol).Text;
    }
}
flcLeft.CellChange = function(Row,Col){
	if(flcLeft.Cell(Row,Col).Text != ""){
		var ret = fsys.rename("\流程数据\"++ preText ++ ".csv","\流程数据\"++ flcLeft.Cell(Row,Col).Text ++ ".csv");	
	}else {
		flcLeft.Cell(Row,Col).Text = preText;
	}	
}
/*}}*/

/*左侧单击功能{{*/
flcLeft.Click = function(){
	if(flcLeft.HitTest(flcLeft.MouseRow,flcLeft.MouseCol)){
		rowTextColorChange(flcLeft.MouseRow);
		csvPara(flcLeft.Cell(flcLeft.MouseRow,1).Text);
	}	
}
/*}}*/

/*拦截左侧列表项改变{{*/
flcLeft.LeaveCell = function(Row,Col,newRow,newCol,Cancel){
	if(saveFlag){
		var ret = mainForm.msgboxTest("发现有未保存的数据,是否需要返回并手动保存?")
		if(ret){
			return newRow,newCol,true;//;
		}
		saveFlag = false;
		//改变颜色和选项
		rowTextColorChange(newRow);
		csvPara(flcLeft.Cell(newRow,1).Text);
	}
}
/*}}*/

/*保存功能{{*/
mainForm.保存.oncommand = function(id,event){
    var fileName = flcLeft.ActiveCell().Text;
    if(fileName != null and fileName != ""){
        saveFlag = false;
    	flcRight.ExportToCSV(fsys.getCurDir()++"\流程数据\"++ fileName ++ ".csv");
    }
}
/*}}*/

/*新增流程{{*/
mainForm.新增.oncommand = function(id,event){
    if(saveFlag){
    	var ret = mainForm.msgboxTest("发现有未保存的数据,是否需要返回并手动保存?");
    	if(ret){
    		return;
    	}
    	saveFlag = false;
    }
    
	if(mainForm.新增名称.text != null and mainForm.新增名称.text != ""){
		var ret = io.exist( "\流程数据\"++ mainForm.新增名称.text ++ ".csv" );
		if(ret == null){
			var ret = string.save("\流程数据\"++ mainForm.新增名称.text ++ ".csv","");
			if(ret){
				flcLeft.AddItem(mainForm.新增名称.text,true)
				flcLeft.Range(flcLeft.Rows-1,0,flcLeft.Rows-1,0).Selected();
				rowTextColorChange(flcLeft.Rows-1);
				flcLeft.Cell(flcLeft.Rows-1,1).EnsureVisible();
				csvPara(mainForm.新增名称.text);
				mainForm.msgbox("创建 "++ mainForm.新增名称.text ++" 流程成功!" )
			}	
		}else {
			mainForm.msgbox( "流程已存在!" );
		}	
	}
}
/*}}*/

/*方程集的数据表处理{{*/
var 获取参数类型和值 = function(tab,...){
    var namesTab = {...};
    if(#namesTab!=0){
        var tempTab = tab;
        for(i=1;#namesTab;1){
        	tempTab = tempTab[namesTab[i]]
        }
        select(tempTab.类型) {
        	case "下拉框" {
        		return 1/*_cellComboBox*/,tempTab.值;	
        	}
        	case "文本框" {
        		return 0/*_cellTextBox*/,tempTab.值;
        	}
        	case "复选框" {
        		return 2/*_cellCheckBox*/,tempTab.值; 
        	}
        	else {
        		return null; 
        	}
        }	
    }
	return null;	
}

var 获取参数提示 = function(tab,...){
    var namesTab = {...};
    if(namesTab[1]=="" and namesTab[2]=="" and namesTab[3]=="" and namesTab[4]=="" and namesTab[5]=="" and namesTab[6]==""){
    	return {"参数一","参数二","参数三","参数四","参数五","参数六";}	
    }
    if(#namesTab!=0){
        var tempTab = tab;
        for(i=1;#namesTab;1){
        	tempTab = tempTab[namesTab[i]]
        }
        return {(tempTab.参数一.提示=="")?"参数一":tempTab.参数一.提示,(tempTab.参数二.提示=="")?"参数二":tempTab.参数二.提示,(tempTab.参数三.提示=="")?"参数三":tempTab.参数三.提示,(tempTab.参数四.提示=="")?"参数四":tempTab.参数四.提示,(tempTab.参数五.提示=="")?"参数五":tempTab.参数五.提示,(tempTab.参数六.提示=="")?"参数六":tempTab.参数六.提示,tempTab.参数一.类型,tempTab.参数二.类型,tempTab.参数三.类型,tempTab.参数四.类型,tempTab.参数五.类型,tempTab.参数六.类型};
    }
	return {"参数一","参数二","参数三","参数四","参数五","参数六","文本框","文本框","文本框","文本框","文本框","文本框"};	
}

var 获取表名 = function(tab,...){
	var namesTab = {...};
	var keyNameTab={};
	if(#namesTab!=0){
        var tempTab = tab;
        for(i=1;#namesTab;1){
        	tempTab = tempTab[namesTab[i]]
        }
        
    	for(k,v in tempTab){
			table.push(keyNameTab,k);
		}
    }else {
    	for(k,v in tab){
			table.push(keyNameTab,k);
		}
    } 
	return keyNameTab;	
}
/*}}*/

/*右侧流程界面智能提示功能{{*/
flcRight.ComboDropDown = function(Row,Col){
    if(Col == 3){
        flcRight.ComboBox(3).Clear();
        var names = 获取表名(方程集);
        for(i=1;#names;1){
        	flcRight.ComboBox(3).AddItem(names[i]); 
        }
    }
    if(Col == 4){
        flcRight.ComboBox(4).Clear();
        var names = 获取表名(方程集,flcRight.Cell(Row,3).Text);
        for(i=1;#names;1){
        	flcRight.ComboBox(4).AddItem(names[i]); 
        }
    }
    var 设置下拉参数和值 = function(name){
    	var ret1,ret2 = 获取参数类型和值(方程集,flcRight.Cell(Row,3).Text,flcRight.Cell(Row,4).Text,name)
        for(i=1;#ret2;1){
        	flcRight.ComboBox(0).AddItem(ret2[i]); 
        }
    }
    
    if(Col == 5){
       设置下拉参数和值("参数一");
    }
    if(Col == 6){
       设置下拉参数和值("参数二");
    }
    if(Col == 7){
       设置下拉参数和值("参数三");
    }
    if(Col == 8){
       设置下拉参数和值("参数四");
    }
    if(Col == 9){
       设置下拉参数和值("参数五");
    }
    if(Col == 10){
       设置下拉参数和值("参数六");
    }
}

flcRight.DblClick = function(){
   	//防止双击到空白处
    if(flcRight.MouseRow != -1){
    	saveFlag = true;
    }
    
	if(flcRight.Cell(flcRight.MouseRow,flcRight.MouseCol).CellType == 6/*_cellDefault*/){
		win.delay(200)
        flcRight.ComboBox(flcRight.MouseCol).DropDown()	
	}elseif(flcRight.Cell(flcRight.MouseRow,flcRight.MouseCol).CellType == 1/*_cellComboBox*/){
		win.delay(200)
        flcRight.ComboBox(0).DropDown()
	}
}

flcRight.CellChange = function(Row,Col){
    if(Col==1){
        if(Row!=0){
        	if( !flcRight.Cell(Row,1).BooleanValue ) flcRight.Range(Row,1,Row,flcRight.Cols-1).BackColor = 0x8273FF;
			else flcRight.Range(Row,1,Row,flcRight.Cols-1).BackColor = (Row%2==0)?flcRight.BackColor2:flcRight.BackColor1;		
        }
    };
	if(Col==3){
		flcRight.Range(Row,4,Row,flcRight.Cols-1).ClearText()
		for(i=4;flcRight.Cols-1;1){
			flcRight.Cell(Row,i).text = "";	
		}
	}
	if(Col==4){
		flcRight.Range(Row,5,Row,flcRight.Cols-1).ClearText();
		if(flcRight.Cell(Row,3).Text!=""){
			var retTable = 获取参数提示(方程集,flcRight.Cell(Row,3).Text,flcRight.Cell(Row,4).Text);
			for(i=5;flcRight.Cols-1;1){
				flcRight.Cell(0,i).Text = retTable[i-4];
			}
			///--------------------------------------------------------------
			var 设置参数类型和值 = function(selcol,name){
				var ret1,ret2 = 获取参数类型和值(方程集,flcRight.Cell(Row,3).Text,flcRight.Cell(Row,4).Text,name)
				if(ret1 != null){
					
					flcRight.Cell(Row,selcol).CellType = ret1;
					if(type(ret2) == type.table){
						flcRight.Cell(Row,selcol).text = ret2[1];
					}else {
						flcRight.Cell(Row,selcol).text = ret2;
					}
				}else {
					flcRight.Cell(Row,selcol).text = "------";
					flcRight.Cell(Row,selcol).CellType = 0/*_cellTextBox*/;
				}
			}
			设置参数类型和值(5,"参数一");
			设置参数类型和值(6,"参数二");
			设置参数类型和值(7,"参数三");
			设置参数类型和值(8,"参数四");
			设置参数类型和值(9,"参数五");
			设置参数类型和值(10,"参数六");	
		}
	}
}
/*}}*/

/*流程界面行点击改变表头提示功能{{*/
flcRight.Click = function(){
	if( flcRight.HitTest(flcRight.MouseRow,flcRight.MouseCol) ){
		var retTable = 获取参数提示(方程集,flcRight.Cell(flcRight.MouseRow,3).Text,flcRight.Cell(flcRight.MouseRow,4).Text);
		for(i=5;flcRight.Cols-1;1){
			flcRight.Cell(0,i).Text = retTable[i-4];
		}
		var styleTab={};
		for(i=5;flcRight.Cols-1;1){
			table.push(styleTab,retTable[i-4+6]);
		}
		//-------------------
		for(i=1;6;1){	
			select(styleTab[i]) {
        		case "下拉框" {
        			flcRight.Cell(flcRight.MouseRow,i+4).CellType = 1;	
        		}
        	}
		}
	}
}
/*}}*/

mainForm.取消.oncommand = function(id,event){
    saveFlag = false;
   	if(flcLeft.ActiveCell().Text){
   		csvPara(flcLeft.ActiveCell().Text);
   	}
}

mainForm.onClose = function(hwnd,message,wParam,lParam){
    if(saveFlag){
    	var ret = mainForm.msgboxTest("发现有未保存的数据,是否需要返回并手动保存?");
    	if(ret){
    		//阻止关闭窗口
    		return true;
    	}
    	saveFlag = false;
    	//继续关闭	
    }
}


mainForm.show();
return win.loopMessage();


4 个回复 | 最后更新于 2021-11-22
2021-11-22   #1

会不会是不知道怎么使用? 感觉没人感兴趣

生成流程后使用方法:

通过string.database解析流程文件(例如 demo.csv)为table表,

然后写一个解析每行数据的函数就可以了.

var doLine = function(lineTab){
	select(lineTab[3]) {//我上面是从第三列开始是首程序函数名,后面是参数1,参数2...
		case "硬件控制" {
			select(lineTab[4]) {
				case "脉冲发生器" {
					select(lineTab[5]) {
						case "启动" {
							启动(...);
						}
						case "停止" {
							停止(...);
						}
						case "单次运行" {
							单次运行(...);
						}
						else {
						}
					}
				}
				case "IO控制" {
					select(lineTab[5]) {
						case "demo1" {
							你的函数(demo1);
						}
						case "demo2" {
							你的函数(demo2);
						}
						else {
						}
					}
				}
				else {
				}
			}
		}
		case "运动控制" {
			select(lineTab[4]) {
				case "相对运动" {
					var 轴号 = 返回轴号(lineTab[5]);
					var 速度 = tonumber(lineTab[6]);
					var 距离 = tonumber(lineTab[7]);
					你的运动函数(轴号,速度,距离);
				}
				case ... {
					你的函数(...)
				}
				else {
				}
			}
		}
		case "方法调用" {
			...
		}
		else {
		}
	}
}


2021-11-24   #2

回复#1 @admin :

没仔细看,看你这else都是空的,不用select,直接遍历表去执行预配置的方法表可能更方便   list[i]  ==>   isFunc(funcTab[[list[i]]])  and funcTab[[list[i]]]()

2021-11-24   #3

2021-11-24   #4

回复#2 @nlysh007 :

这样写会限制功能名,用case是可能有更多函数明情况,而且不需要同名指定。可能实际使用更灵活一点。

登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...