Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,156 changes: 513 additions & 643 deletions unilabos/devices/liquid_handling/prcxi/prcxi_labware.py

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions unilabos/labware_manager/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,11 @@ def import_from_code() -> LabwareDB:
tip_fitting_depth=tip_depth,
has_filter=tip_filter,
)
# 计算 tip_above_rack_length = tip_length - (size_z - dz)
if grid_data:
_dz = grid_data.get("dz", 0.0)
_above = tip_length - (item.size_z - _dz)
item.tip.tip_above_rack_length = round(_above, 4) if _above > 0 else None

elif type_name == "tube_rack" and children:
if grid_data:
Expand Down
159 changes: 107 additions & 52 deletions unilabos/labware_manager/labware_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,9 @@
"type": "tip_rack",
"function_name": "PRCXI_10ul_eTips",
"docstring": "对应 JSON Code: ZX-001-10+",
"size_x": 122.11,
"size_x": 127.76,
"size_y": 85.48,
"size_z": 58.23,
"size_z": 58.0,
"model": "PRCXI_10ul_eTips",
"category": "tip_rack",
"plate_type": null,
Expand All @@ -327,21 +327,22 @@
"grid": {
"num_items_x": 12,
"num_items_y": 8,
"dx": 7.97,
"dy": 5.0,
"dz": 2.0,
"dx": 10.63,
"dy": 7.49,
"dz": 14.6,
"item_dx": 9.0,
"item_dy": 9.0
},
"well": null,
"volume_functions": null,
"tip": {
"spot_size_x": 7.0,
"spot_size_y": 7.0,
"spot_size_x": 7.5,
"spot_size_y": 7.5,
"spot_size_z": 0.0,
"tip_volume": 300.0,
"tip_length": 60.0,
"tip_fitting_depth": 51.0,
"tip_volume": 10.0,
"tip_length": 52.0,
"tip_fitting_depth": 8.2,
"tip_above_rack_length": 8.6,
"has_filter": false
},
"tube": null,
Expand All @@ -354,9 +355,9 @@
"type": "tip_rack",
"function_name": "PRCXI_300ul_Tips",
"docstring": "对应 JSON Code: ZX-001-300\n吸头盒通常比较特殊,需要定义 Tip 对象",
"size_x": 122.11,
"size_x": 127.76,
"size_y": 85.48,
"size_z": 58.23,
"size_z": 58.0,
"model": "PRCXI_300ul_Tips",
"category": "tip_rack",
"plate_type": null,
Expand All @@ -375,21 +376,22 @@
"grid": {
"num_items_x": 12,
"num_items_y": 8,
"dx": 7.97,
"dy": 5.0,
"dz": 2.0,
"dx": 10.63,
"dy": 7.49,
"dz": 6.6,
"item_dx": 9.0,
"item_dy": 9.0
},
"well": null,
"volume_functions": null,
"tip": {
"spot_size_x": 7.0,
"spot_size_y": 7.0,
"spot_size_x": 7.5,
"spot_size_y": 7.5,
"spot_size_z": 0.0,
"tip_volume": 300.0,
"tip_length": 60.0,
"tip_fitting_depth": 51.0,
"tip_fitting_depth": 8.2,
"tip_above_rack_length": 8.6,
"has_filter": false
},
"tube": null,
Expand Down Expand Up @@ -788,9 +790,9 @@
"type": "tip_rack",
"function_name": "PRCXI_1250uL_Tips",
"docstring": "Code: ZX-001-1250",
"size_x": 118.09,
"size_y": 80.7,
"size_z": 107.67,
"size_x": 127.76,
"size_y": 85.48,
"size_z": 98.0,
"model": "PRCXI_1250uL_Tips",
"category": "tip_rack",
"plate_type": null,
Expand All @@ -809,21 +811,22 @@
"grid": {
"num_items_x": 12,
"num_items_y": 8,
"dx": 5.57,
"dy": 4.875,
"dz": 2.0,
"dx": 10.63,
"dy": 7.49,
"dz": 6.6,
"item_dx": 9.0,
"item_dy": 9.0
},
"well": null,
"volume_functions": null,
"tip": {
"spot_size_x": 7.0,
"spot_size_y": 7.0,
"spot_size_z": 0.0,
"tip_volume": 300.0,
"tip_length": 60.0,
"tip_fitting_depth": 51.0,
"spot_size_x": 7.5,
"spot_size_y": 7.5,
"spot_size_z": 100.0,
"tip_volume": 1250.0,
"tip_length": 100.0,
"tip_fitting_depth": 8.2,
"tip_above_rack_length": 8.6,
"has_filter": false
},
"tube": null,
Expand All @@ -836,9 +839,9 @@
"type": "tip_rack",
"function_name": "PRCXI_10uL_Tips",
"docstring": "Code: ZX-001-10",
"size_x": 120.98,
"size_y": 82.12,
"size_z": 67.0,
"size_x": 127.76,
"size_y": 85.48,
"size_z": 58.0,
"model": "PRCXI_10uL_Tips",
"category": "tip_rack",
"plate_type": null,
Expand All @@ -857,21 +860,22 @@
"grid": {
"num_items_x": 12,
"num_items_y": 8,
"dx": 8.49,
"dy": 7.06,
"dz": 2.0,
"dx": 10.63,
"dy": 7.49,
"dz": 14.6,
"item_dx": 9.0,
"item_dy": 9.0
},
"well": null,
"volume_functions": null,
"tip": {
"spot_size_x": 7.0,
"spot_size_y": 7.0,
"spot_size_x": 7.5,
"spot_size_y": 7.5,
"spot_size_z": 0.0,
"tip_volume": 300.0,
"tip_length": 60.0,
"tip_fitting_depth": 51.0,
"tip_volume": 10.0,
"tip_length": 52.0,
"tip_fitting_depth": 8.2,
"tip_above_rack_length": 8.6,
"has_filter": false
},
"tube": null,
Expand All @@ -884,8 +888,8 @@
"type": "tip_rack",
"function_name": "PRCXI_1000uL_Tips",
"docstring": "Code: ZX-001-1000",
"size_x": 128.09,
"size_y": 85.8,
"size_x": 127.76,
"size_y": 85.48,
"size_z": 98.0,
"model": "PRCXI_1000uL_Tips",
"category": "tip_rack",
Expand All @@ -905,21 +909,22 @@
"grid": {
"num_items_x": 12,
"num_items_y": 8,
"dx": 10.525,
"dy": 7.425,
"dz": 2.0,
"dx": 10.63,
"dy": 7.49,
"dz": 6.6,
"item_dx": 9.0,
"item_dy": 9.0
},
"well": null,
"volume_functions": null,
"tip": {
"spot_size_x": 7.0,
"spot_size_y": 7.0,
"spot_size_z": 0.0,
"tip_volume": 300.0,
"tip_length": 60.0,
"tip_fitting_depth": 51.0,
"spot_size_x": 7.5,
"spot_size_y": 7.5,
"spot_size_z": 100.0,
"tip_volume": 1000.0,
"tip_length": 100.0,
"tip_fitting_depth": 8.2,
"tip_above_rack_length": 8.6,
"has_filter": false
},
"tube": null,
Expand Down Expand Up @@ -968,6 +973,7 @@
"tip_volume": 300.0,
"tip_length": 60.0,
"tip_fitting_depth": 51.0,
"tip_above_rack_length": null,
"has_filter": false
},
"tube": null,
Expand Down Expand Up @@ -1256,6 +1262,55 @@
},
"include_in_template_matching": false,
"template_kind": null
},
{
"id": "5bb65eb2",
"type": "tip_rack",
"function_name": "PRCXI_50uL_tips",
"docstring": "",
"size_x": 127.76,
"size_y": 85.48,
"size_z": 58.0,
"model": "PRCXI_50uL_tips",
"category": null,
"plate_type": null,
"material_info": {
"uuid": "",
"Code": "",
"Name": "",
"materialEnum": null,
"SupplyType": 1
},
"registry_category": [
"prcxi",
"tip_racks"
],
"registry_description": "",
"grid": {
"num_items_x": 12,
"num_items_y": 8,
"dx": 10.63,
"dy": 7.49,
"dz": 13.6,
"item_dx": 9.0,
"item_dy": 9.0
},
"well": null,
"volume_functions": null,
"tip": {
"spot_size_x": 7.5,
"spot_size_y": 7.5,
"spot_size_z": 0.0,
"tip_volume": 50.0,
"tip_length": 53.0,
"tip_fitting_depth": 8.2,
"tip_above_rack_length": 8.6,
"has_filter": false
},
"tube": null,
"adapter": null,
"include_in_template_matching": false,
"template_kind": "tip_rack"
}
]
}
1 change: 1 addition & 0 deletions unilabos/labware_manager/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class TipInfo(BaseModel):
tip_volume: float = 300.0
tip_length: float = 60.0
tip_fitting_depth: float = 51.0
tip_above_rack_length: Optional[float] = None
has_filter: bool = False


Expand Down
55 changes: 55 additions & 0 deletions unilabos/labware_manager/static/form_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ function collectFormData() {
tip_volume: g('f-tip_vol') || 300,
tip_length: g('f-tip_len') || 60,
tip_fitting_depth: g('f-tip_dep') || 51,
tip_above_rack_length: g('f-tip_above'),
has_filter: g('f-tip_filter') || false,
};
}
Expand Down Expand Up @@ -155,6 +156,60 @@ document.addEventListener('DOMContentLoaded', () => {
if (!form) return;
form.addEventListener('input', updatePreview);
form.addEventListener('change', updatePreview);

// tip_above_rack_length 与 dz 互算
// 公式: tip_length = tip_above_rack_length + size_z - dz
// 规则: 填 tip_above → 自动算 dz;填 dz → 自动算 tip_above
// 改 size_z / tip_length → 优先重算 tip_above(若有值),否则算 dz

function _getVal(id) {
const el = document.getElementById(id);
return (el && el.value !== '') ? parseFloat(el.value) : null;
}
function _setVal(id, v) {
const el = document.getElementById(id);
if (el) el.value = Math.round(v * 1000) / 1000;
}

function autoCalcTipAbove(changedId) {
const typeEl = document.getElementById('f-type');
if (!typeEl || typeEl.value !== 'tip_rack') return;

const tipLen = _getVal('f-tip_len');
const sizeZ = _getVal('f-size_z');
const dz = _getVal('f-grid_dz');
const above = _getVal('f-tip_above');

// 需要 tip_length 和 size_z 才能计算
if (tipLen == null || sizeZ == null) return;

if (changedId === 'f-tip_above') {
// 用户填了 tip_above → 算 dz
if (above != null) _setVal('f-grid_dz', above + sizeZ - tipLen);
} else if (changedId === 'f-grid_dz') {
// 用户填了 dz → 算 tip_above
if (dz != null) _setVal('f-tip_above', tipLen - sizeZ + dz);
} else {
// size_z 或 tip_length 变了 → 优先重算 tip_above(若已有值或 dz 已有值)
if (dz != null) {
_setVal('f-tip_above', tipLen - sizeZ + dz);
} else if (above != null) {
_setVal('f-grid_dz', above + sizeZ - tipLen);
}
}
}

// 绑定 input 事件
for (const id of ['f-tip_len', 'f-size_z', 'f-grid_dz', 'f-tip_above']) {
const el = document.getElementById(id);
if (el) el.addEventListener('input', () => autoCalcTipAbove(id));
}

// 编辑已有 tip_rack 条目时自动补算 tip_above_rack_length
const typeEl = document.getElementById('f-type');
if (typeEl && typeEl.value === 'tip_rack') {
autoCalcTipAbove('f-grid_dz');
}
});

// 自动居中:根据板尺寸和孔阵列参数计算 dx/dy
Expand Down
Loading