/*
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})
}