/* NAME: DESCRIPTION: 客户数据分析 PARAMETER: [ { name : 'step_filter', title : 'Step过滤', type : 'LineEdit', property : {tool_tip : '过滤step信息'} }, { name : 'erf', title : 'erf名称', type : 'LineEdit', property : {tool_tip : ''} }, { name : 'auto_save', title : '自动保存', type : 'RadioBox', property : { item_list:[ {name:'yes',text:'YES'}, {name:'no',text:'NO'}, ], tool_tip:'是否自动保存料号开关' } } ] VERSION_HISTORY: V1.00 2020 3-30 Scott HELP:

功能简介

客户数据分析


参数配置

客户参数

注意事项

● 无


*/ // 引入模块 包 var $ = require('topcam.scriptfunc').argv(); var fs = require('fs'); var _ = require('lodash'); var IKM = $.ikm; var GEN = $.gen; var GUI = $.gui; var Job = $.job; var JobId = $.job_id; var mode = "develop" // 运行模式 develop 开发模式 方便调试 try { var par = { job:"i3", job_info : { // todo tmp vc_src_01005_pad_result: ".smd", depth_drill: "depth_drill", depth_routing: "depth_routing", cavity: "cavity" } } var job = par.job.toLowerCase(),pcs_step="cad",array_step="stp" // todo // 料号验证 err = beforeStart({job:job});if(err){ throw err }; // matrix分析 var matrixInfo = getMatrixInfo({job:job}) var matrix_analysis = UPLOAD_LAYER_MATRIX({job:job,matrixInfo:matrixInfo}) // 分析matrix var matrix = matrixInfo.matrix // jobinfo分析 // var jobInfo = saveJobInfo({job:job,pcs_step:pcs_step,array_step:array_step,matrixInfo:matrixInfo,matrix_analysis:matrix_analysis},par) // IKM.msg(jobInfo) // 分析钻孔属性 // todo 镭射切割长度 // analysis_drill({job:job,pcs_step:pcs_step,array_step:array_step,matrixInfo:matrixInfo,matrix_analysis:matrix_analysis},par) // layer分析 GUI.msg("Done") return 'Done'; } catch (error) { GUI.msg(error); return 'Error'; } function beforeStart(props){ // 脚本开始前的料号判断 var job = props.job,j = {job:job} if(!GEN.isJobExists(j)){return "job: "+job+" is not exist"} if(!GEN.isJobOpen(j)){GEN.openJob(j)} if(GEN.checkInout({job:job,mode:"test"}) != 0){ if (mode != "develop"){ return "the job checked" } } GEN.checkInout({job:job,mode:"out"}) } function getMatrixInfo(props){ // 获取matrix各种信息 var job = props.job var matrix = GEN.getMatrix({job:job}) var res = { matrix: matrix, // matrix matrixVal: [], // matrix 的 value数组 mSignal: {}, // board的signal层 {} mSignals: [], // board的signal层 [] mDrill: {}, // board的drill层 mDrills: [], // board的drill层 mSolderMask: {}, // 防焊层 mSolderMasks: [], // 防焊层 mOuters: [], // 外层和对于的防旱 mBoardLayer: [] // board层 } for (var key in matrix) { var value = matrix[key] res.matrixVal.push(value) if(value.context == "board"){ res.mBoardLayer.push(key) switch (value.layer_type) { case "signal": res.mSignal[key] = value res.mSignals.push(value) break; case "drill": res.mDrill[key] = value res.mDrills.push(value) break; case "solder_mask": res.mSolderMask[key] = value res.mSolderMasks.push(value) break; } } } res.matrixVal = res.matrixVal.sort(function(a,b){return Number(a.row) - Number(b.row)}) res.mSignals = res.mSignals.sort(function(a,b){return Number(a.row) - Number(b.row)}) res.mDrills = res.mDrills.sort(function(a,b){return Number(a.row) - Number(b.row)}) // 找出外层 以及外层对应的防焊层 [{signalL:"top", solderL:"smt"}] res.mOuters = res.mSignals.reduce(function(a,b){ if(b.tl_type == "outer"){ var solderLayers = res.mSolderMasks.filter(function(v){ return v.side == b.side }) a.push({ signalL: b.name, solderL: solderLayers.length >0 ? solderLayers[0]["name"] : null }) } return a },[]) return res } function UPLOAD_LAYER_MATRIX(props){ var matrixInfo = props.matrixInfo var job = props.job props.jobcategory = props.jobcategory || "work" var matrix = ANALYSIS_STACKUP({job:job, matrixInfo:matrixInfo, jobcategory:props.jobcategory}); var func = 'function(ARGV)\ {\ var jobId = ARGV["job_id"];\ var tableName = "pdm_job_" + ARGV["jobcategory"] + "_layer";\ //GUI.msgbox({text: TDataParse.variant2JsonStr(tableName)});\ var db = new TSqlQueryV2(T_SQLCNT_POOL.getSqlDatabase());\ db.begin();\ try{\ var oLayers = db.selectMapMap({table:tableName, field:["odb_name","release_status"], where:{job_id:jobId}, uniquefield:"odb_name"});\ if (db.lastError().isValid()) throw db.lastError();\ //GUI.msgbox({text: TDataParse.variant2JsonStr(oLayers)});\ \ db.deleteRow({table:tableName, where:{job_id:jobId}});\ if (db.lastError().isValid()) throw db.lastError();\ \ var fieldLst = ["name", "odb_context", "odb_type", "odb_polarity", "odb_side", "drl_start", "drl_end",\ "row_num", "type", "drl_start_num", "drl_end_num", "drl_from_num", "drl_to_num", "drl_connect_to", \ "odb_name", "side", "stackup_num", "customer_field", "input_file_name", "odb_row_num"];\ \ for (var i=0;i0\ && ARGV["releasestatus"][layerInfo["odb_name"]] != undefined && ARGV["releasestatus"][layerInfo["odb_name"]] != null )\ {\ tmpData["release_status"] = ARGV["releasestatus"];\ }\ else\ {\ tmpData["release_status"] = oLayers.hasOwnProperty(layerInfo["odb_name"]) ? oLayers[layerInfo["odb_name"]]["release_status"] : null;\ }\ for (n = 0; n < fieldLst.length; n++)\ {\ tmpData[fieldLst[n]] = layerInfo[fieldLst[n]];\ }\ //GUI.msgbox({text: TDataParse.variant2JsonStr(tmpData)});\ db.insertRow({table:tableName, data:tmpData});\ if (db.lastError().isValid()) throw db.lastError();\ }\ db.commit();\ return new TDataResponse();\ }\ catch (err)\ {\ print(err.text());\ db.rollback();\ return new TDataResponse(err, "");\ }\ }'; IKM.msg(matrix) var ret = IKM.command( func, { job_id :JobId, matrix:matrix, layers: Object.keys(matrix).sort(function(a,b){return matrix[a]["row"] - matrix[b]["row"]}), jobcategory:props.jobcategory}, 1); IKM.msg(ret) if (ret.errText) { return { jobcategory:props.jobcategory, errText :ret.errText, errCode :ret.errCode, }; } return matrix } function ANALYSIS_STACKUP(props){ var job = props.job if(!props.hasOwnProperty("jobcategory")){ props.jobcategory = 'work' } var matrix = GEN.getMatrix({job:job}) var layer_count = IKM.get_jobinfo({jobname:JobId,jobcategory:props.jobcategory,jobinfo:'layer_count'}); if(!layer_count){ layer_count = GEN.getLayerCount({job:job}) } IKM.save_job_info({jobid:JobId,jobcategory:props.jobcategory,jobinfohash:{TL_layer_count:layer_count}}); _.values(matrix).sort(function(a,b){return a.row-b.row}).forEach(function(layer){ layer.odb_name = layer.name; layer.name = layer.tl_name; layer.odb_context = layer.context; layer.odb_type = layer.layer_type; layer.odb_polarity = layer.polarity; layer.odb_side = layer.side; layer.row_num = layer.tl_num; layer.type = layer.tl_type; layer.side = layer.enum_tl_side; layer.input_file_name = layer.file_name; layer.odb_row_num = layer.row; if (layer.odb_name == 'drill'){ layer.name = 'drill'; layer.drl_start_num = 1; layer.drl_end_num = layer_count; layer.drl_from_num = 1; layer.drl_to_num = layer_count; layer.type = 'main_drill'; } else if (/^d(\d+)\-(\d+)$/.test(layer.odb_name)){ var tmp = /^d(\d+)\-(\d+)$/.exec(layer.odb_name) var drl_star = tmp[1]; var drl_end = tmp[2]; layer.name = 'drill' + drl_star + '-' + drl_end; layer.drl_start_num = drl_star; layer.drl_end_num = drl_end; layer.drl_from_num = drl_star; layer.drl_to_num = drl_end; if( drl_star == 1 || drl_end == layer_count ){ layer.type = 'blind_drill'; // 埋孔 } else{ layer.type = 'bury_drill'; // 盲孔 } } else if (/^d(\d+)\-(\d+)$/.test(layer.odb_name)){ var tmp = /^d(\d+)\-(\d+)$/.exec(layer.odb_name) var drl_star = tmp[1]; var drl_end = tmp[2]; layer.name = 'd'+drl_star+'-'+drl_end; layer.drl_start_num = drl_star; layer.drl_end_num = drl_end; layer.drl_from_num = drl_star; layer.drl_to_num = drl_end; layer.type = 'laser_drill'; // 镭射孔 } else if (/\-a$/.test(layer.odb_name)){ layer.side = 'top'; if(!layer.name){ layer.name = '__'+layer.odb_name+'__' } if(!layer.type){ layer.type = 'other' } } else if (/\-b$/.test(layer.odb_name)){ layer.side = 'bottom'; if(!layer.name){ layer.name = '__'+layer.odb_name+'__' } if(!layer.type){ layer.type = 'other' } } else{ if(!layer.name){ layer.name = '__'+layer.odb_name+'__' } if(!layer.type){ layer.type = 'other' } } }) return matrix; } function saveJobInfo(props,par){ var job = props.job var pcs = props.pcs_step var arr = props.array_step var matrix_analysis = props.matrix_analysis var matrixInfo = props.matrixInfo var matrix = matrixInfo.matrix var info = { layer_count: "", // Board属性的signal或者power_ground层 vc_card_size_w: "", // card短边尺寸 vc_card_size_l: "", // card长边尺寸 vc_array_size_w: "", // array短边尺寸 vc_array_size_l: "", // array长边尺寸 vc_pcs_count_on_panel: "", // todo array中pcs的数量 stack_vias_number: "", // via孔连续叠加的层数 stack_vias_more: "", // yes|no : 14层板以上时,Stack Vias >=12时,存yes depth_drilling: "", // yes|no :存在depth_drill 层时,存yes depth_routing: "", // yes|no :存在depth_routing 层时,存yes laser_via_on_buried_hole: "", // todo yes|no:via孔在埋孔上时,存yes milling_bit_size: "", // todo 检查array中pcs的最小间距值 milling_length: "", // todo 检查array中铣切长度 vc_src_01005_pad_result: "", // yes|no:board层中检查存在01005属性物件时,存yes ATS_technology_25dc: "", // yes|no:存在cavity层别时存yes ATS_technology_25dr: "", // yes|no:存在cavity层别时存yes vc_src_EDGE_PLATING: "", // yes|no:检查线路外形是否存在物件,存在则存yes edge_plating_length: "", // todo glod_finger: "", // todo glod_finger_area: "", // todo solder_mask_side: "", // top|bot|both:检查防焊层所在面次 silk_screen_side: "", // top|bot|both:检查文字层所在面次 } info.layer_count = matrixInfo.mSignals.length // 10 var pcs_profileLimits = GEN.getProfileLimits({job:job,step:pcs}) var array_profileLimits = GEN.getProfileLimits({job:job,step:arr}) info.vc_card_size_w = pcs_profileLimits.xsize.toFixed(3) info.vc_card_size_l = pcs_profileLimits.ysize.toFixed(3) info.vc_array_size_w = array_profileLimits.xsize.toFixed(3) info.vc_array_size_l = array_profileLimits.ysize.toFixed(3) // IKM.msg(GEN.getRepeat({job:"1",step:"stp1"})) // ? // 找出 镭射孔 var laser_layers = [] for (var key in matrix_analysis) { var val = matrix_analysis[key] if(val.type == "laser_drill"){ laser_layers.push(val) } } GEN.openStep({job:job,name:pcs}) laser_layers = laser_layers.sort(function(a,b){return Number(a.row)-Number(b.row)}) var laser_info = {} for(var i = 0; i < laser_layers.length-1; i++){ var start_layer = laser_layers[i].name var cover_layer = laser_layers[i+1].name GEN.workLayer({name:start_layer,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:cover_layer,use:'filter',mode:'cover'}) var count = GEN.getSelectCount() if(count>0){ if(!laser_info[start_layer]){ laser_info[start_layer] = {} } laser_info[start_layer].drill_connect_layer = cover_layer laser_info[start_layer].drill_connect_point = count } } // via孔连续叠加的层数 var via_vias_info = [] function analysis_via_number(layers){ if(layers.length < 2){return} var startlayer = layers[0].name + "_cover" GEN.selClearFeature() GEN.workLayer({name:layers[0].name,display_number:2,clear_before:'yes'}) GEN.selAllFeat() selCopyLayer({job:job,layer:startlayer}) var end_index = start_cover_next(startlayer,layers,0) via_vias_info.push(end_index+1) analysis_via_number(layers.slice(end_index)) } function start_cover_next(start, layers, end_index){ if(layers.length < 2){ GEN.deleteLayer({job:job,layer:start}) return end_index } layers = layers.slice(1) GEN.workLayer({name:start,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:layers[0].name,use:'filter',mode:'cover'}) var count = GEN.getSelectCount() if (count < 1) { GEN.deleteLayer({job:job,layer:start}) return ++end_index } var nextstartlayer = layers[0].name + "_cover" selCopyLayer({job:job,layer:nextstartlayer}) GEN.deleteLayer({job:job,layer:start}) return start_cover_next(nextstartlayer,layers,++end_index) } analysis_via_number(laser_layers.slice()) if (via_vias_info.length == 1){ info.stack_vias_number = via_vias_info[0] }else{ info.stack_vias_number = via_vias_info.reduce(function(a,b){return a-b>0?a :b}) } info.stack_vias_more = "no" if(GEN.getLayerCount({job:job}) > 14 && info.stack_vias_number >= 12){ info.stack_vias_more = "yes" } // via孔在埋孔上? info.depth_drilling = matrix.hasOwnProperty(par.jobInfo.depth_drilling) ? "yes" : "no" info.depth_routing = matrix.hasOwnProperty(par.jobInfo.depth_routing) ? "yes" : "no" var is_cavity = matrix.hasOwnProperty(par.jobInfo.cavity) ? "yes" : "no" info.ATS_technology_25dc = is_cavity // no info.ATS_technology_25dr = is_cavity // no var solder_paste_layers = _.values(matrix).filter(function(v){return v.layer_type == "solder_paste"}) var solder_solder_mask = _.values(matrix).filter(function(v){return v.layer_type == "solder_mask"}) var solder_paste_info= solder_paste_layers.map(function(v){return v.side}).reduce(function(a,b){ if(a.indexOf(b)<0){ a.push(b) } return a },[]) var solder_solder_info= solder_solder_mask.map(function(v){return v.side}).reduce(function(a,b){ if(a.indexOf(b)<0){ a.push(b) } return a },[]) if(solder_paste_info.length == 0){ info.solder_mask_side = "no" } else if (solder_paste_info.length == 1) { info.solder_mask_side = solder_paste_info[0] } else { info.solder_mask_side = "both" } if(solder_solder_info.length == 0){ info.silk_screen_side = "no" } else if (solder_solder_info.length == 1) { info.silk_screen_side = solder_solder_info[0] } else { info.silk_screen_side = "both" } // 线路外形 info.vc_src_EDGE_PLATING = "no" GEN.affectedLayer({affected:'no',mode:'all'}) try { matrixInfo.mSignals.forEach(function(v){ GEN.workLayer({name:v.name,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selRefFeat({layers:"rout",mode:"touch",use:"filter"}) if( GEN.getSelectCount()>0){ throw "yes" } }) } catch (msg) { info.vc_src_EDGE_PLATING = msg GEN.affectedLayer({affected:'no',mode:'all'}) GEN.selClearFeature() } info = Object.keys(info).reduce(function(a,b){// 过滤结果 if(info[b] != ""){ a[b] = info[b] } return a },{}) // 有无属性vc_src_01005_pad_result GEN.openStep({job:job,name:pcs}) GEN.affectedLayer({affected:'yes',layer:matrixInfo.mBoardLayer,clear_before:'yes'}); GEN.selClearFeature() GEN.selectByFilter({attribute:par.job_info.vc_src_01005_pad_result}) info.is_01005_pad = GEN.getSelectCount() > 0? "yes" : "no" GEN.affectedLayer({affected:'no',mode:'all'}); GEN.closeStep() IKM.save_job_info({ jobid: JobId, jobinfohash:info }) return {info:info,laser_info:laser_info} } function selCopyLayer(props){ // 拷贝选择的到辅助层 var layer = props.layer var job = props.job if(GEN.isLayerExists({job:job,layer:layer})){ GEN.deleteLayer({job:job,layer:layer}) } GEN.selCopyOther({dest:'layer_name',target_layer:layer}) } function analysis_drill(props){ var job = props.job var pcs = props.pcs_step var arr = props.array_step var matrix_analysis = props.matrix_analysis var matrixInfo = props.matrixInfo var matrix = matrixInfo.matrix // 设置层的孔属性 } function set_drill_attr(props){ // 镭射孔via,无铜孔npth,其余孔pth var layer = props.layer var attr = props.attr GEN.workLayer({name:layer,display_number:2,clear_before:'yes'}) GEN.selClearFeature() GEN.selAllFeat() GEN.selAddAttr({attribute:attr}) }