[], 'models'=>[], 'customers'=>[]],默认空 * showOperator bool 是否在表单中显示操作人,默认 true * excludeFields array 排除的字段名列表(不在表单中渲染),默认空 * * 提交方式: * submitMode string 'auto'(扫描字段回车直接提交)| 'button'(需点击按钮),默认 'auto' * submitBtn array 提交按钮配置 ['text'=>'提交', 'icon'=>'fa-check', 'class'=>'btn-success'] * extraBtns array 额外按钮列表,每个元素: ['id'=>'btnId', 'text'=>'...', 'icon'=>'fa-...', 'class'=>'btn-info'] * 注意:为符合 CSP(无 unsafe-inline),额外按钮不再支持内联 onclick, * 请在 customInit/customJs 中按 id 绑定事件(如 $('#btnId').on('click', ...))。 * reloadAfterSubmit bool 提交后是否刷新页面,默认 false(只清空扫描字段) * * 表格显示: * codeFields array 需要用 样式显示的字段名列表,默认 ['serial_no'] * labelFields array 需要用 label 样式显示的字段名列表,格式: ['field_name' => 'label-success|label-warning|label-danger|label-info'] * showRecordBadge bool 是否显示"共 N 条"徽章,默认 true * emptyText string 空记录提示文字,默认"暂无记录" * * 特殊业务: * customHeader string 额外的卡片头部 HTML(如筛选按钮、导出按钮),默认空 * customBeforeForm string 在 renderStationFields 之前插入的 HTML(如固定产品类型字段),默认空 * customInit string 额外的 $(function(){}) 初始化 JS 代码,默认空 * customJs string 完全自定义的额外 JS 代码(放在 script 标签末尾),默认空 * extraCard string 额外的卡片 HTML(插入在记录表格之后),默认空 * * 筛选联动(仅 submitMode='auto' 时可用): * enableFilter bool 是否启用产品类型→型号联动筛选,默认 false * filterUrl string 筛选记录加载的 URL(相对于 BASE_URL),如 '/Front/inbound' * * 内置工位扩展: * bizConfig array 来自 station_business_helper 的业务配置(自动注入) */ function renderStationTemplate($config) { // ========== 从 GLOBALS 获取业务配置 ========== $bizConfig = $GLOBALS['bizConfig'] ?? null; $stationType = $GLOBALS['stationType'] ?? ($config['stationKey'] ?? ''); // 如果有 bizConfig,用它增强基础 config if ($bizConfig && !empty($bizConfig['view'])) { $config = array_merge($config, $bizConfig['view']); } // ========== 默认值合并 ========== $defaults = [ 'cardTitle' => '快速录入', 'tableTitle' => '操作记录', 'dataSources' => ['types' => [], 'models' => [], 'customers' => []], 'showOperator' => true, 'excludeFields' => [], 'submitMode' => 'auto', 'submitBtn' => ['text' => '确认提交', 'icon' => 'fa-check', 'class' => 'btn-success'], 'extraBtns' => [], 'reloadAfterSubmit'=> false, 'codeFields' => ['serial_no'], 'labelFields' => [], 'showRecordBadge' => true, 'emptyText' => '暂无记录', 'customHeader' => '', 'customBeforeForm' => '', 'customInit' => '', 'customJs' => '', 'extraCard' => '', 'enableFilter' => false, 'filterUrl' => '', ]; // 获取外部变量 $activeStation = $stationType; $sysConfig = $GLOBALS['sysConfig'] ?? null; $user = $GLOBALS['user'] ?? []; $fieldConfigs = $GLOBALS['fieldConfigs'] ?? []; $records = $GLOBALS['records'] ?? []; $types = $GLOBALS['types'] ?? []; $models = $GLOBALS['models'] ?? []; $customers = $GLOBALS['customers'] ?? []; $filterType = $GLOBALS['filterType'] ?? ''; $filterModel = $GLOBALS['filterModel'] ?? ''; $todayCount = $GLOBALS['todayCount'] ?? 0; $totalCount = $GLOBALS['totalCount'] ?? count($records); $shellColors = $GLOBALS['shellColors'] ?? []; $stationError = $GLOBALS['stationError'] ?? ''; // 预计算前缀规则(避免在 JS 函数模板中重复创建 SysConfig 对象) $prefixTypeMap = []; if ($sysConfig && is_array($sysConfig)) { try { $sysConfigModel = new \app\models\SysConfig(); $prefixTypeMap = $sysConfigModel->getCodePrefixRules(); } catch (\Throwable $e) { error_log('[renderStationTemplate] getCodePrefixRules failed: ' . $e->getMessage()); $prefixTypeMap = []; } } $codePrefixRulesJson = json_encode($prefixTypeMap, JSON_UNESCAPED_UNICODE); // 前端拼音首字母回退(与后端 SysConfig::pinyinInitials 保持一致), // 用于动态前缀类型在后台未填前缀时,仍能按类型名拼音首字母校验。 $pinyinMapJson = json_encode([ '外壳' => 'WK', '底壳' => 'WK', '包装' => 'BZ', '半成品' => 'BCP', '半成' => 'BCP', '配件' => 'PJ', '成品' => 'CP', '电池' => 'DC', '电芯' => 'DC', 'PCBA' => 'XLB', ], JSON_UNESCAPED_UNICODE); // 前缀 -> 类型 反向映射(用于扫码自动判断产品类型)。键统一为大写前缀 // 注意:SysConfig::getCodePrefixRules() 会对别名(电芯/底壳/半成)做双向自动补全, // 导致同一前缀可能同时对应主类型和别名(如 dc 同时对应 电池 与 电芯)。 // 自动判类型必须唯一命中主类型,故此处分两遍构建:主类型优先占用前缀,别名仅填补空缺。 $aliasTypes = ['电芯', '底壳', '半成']; $prefixToTypeMap = []; foreach ($prefixTypeMap as $type => $prefix) { if (empty($prefix) || in_array($type, $aliasTypes, true)) continue; $prefixToTypeMap[strtoupper($prefix)] = $type; } foreach ($prefixTypeMap as $type => $prefix) { if (empty($prefix) || !in_array($type, $aliasTypes, true)) continue; $k = strtoupper($prefix); if (!isset($prefixToTypeMap[$k])) { $prefixToTypeMap[$k] = $type; } } $prefixToTypeJson = json_encode($prefixToTypeMap, JSON_UNESCAPED_UNICODE); $config = array_merge($defaults, $config); // 确保数据源正确 $config['dataSources'] = array_merge( ['types' => $types, 'models' => $models, 'customers' => $customers], $config['dataSources'] ); // 外壳颜色注入到数据源 if (!empty($shellColors)) { $config['dataSources']['shell_colors'] = $shellColors; } $stationKey = $config['stationKey']; $pageTitle = $config['pageTitle']; $pageIcon = $config['pageIcon']; $operatorName = $config['showOperator'] ? ($user['emp_name'] ?? '') : ''; $submitMode = $config['submitMode']; $enableFilter = $config['enableFilter']; $filterUrl = $config['filterUrl']; $recordCount = count($records); // 构建特殊格式化回调 $specialFormats = []; foreach ($config['codeFields'] as $fn) { $specialFormats[$fn] = function($val) { return $val ? '' . htmlspecialchars($val) . '' : '-'; }; } foreach ($config['labelFields'] as $fn => $cls) { if ($cls === '__dynamic__') { // 动态颜色:根据值自动选择 $specialFormats[$fn] = function($val) { if (!$val) return '-'; $colorMap = ['passed' => 'success', 'failed' => 'danger', 'pending' => 'warning', '通过' => 'success', '失败' => 'danger', '待测试' => 'warning']; $cls = $colorMap[$val] ?? 'default'; return '' . htmlspecialchars($val) . ''; }; } else { $specialFormats[$fn] = function($val) use ($cls) { return $val ? '' . htmlspecialchars($val) . '' : '-'; }; } } // ========== 输出 HTML(含统一框架) ========== // 安全检查:防止 station_header.php 被重复包含 static $headerIncluded = false; if ($headerIncluded) { // 已输出过框架,记录错误但继续(避免双重框架) error_log('[renderStationTemplate] WARNING: station_header already included for ' . $stationKey . ' - possible double render detected'); return; } $headerIncluded = true; include APP_PATH . 'app/views/layouts/station_header.php'; ?>
返回工位选择

0 || $totalCount > 0): ?>
 今日录入: 条  | 总共:

$ef): ?>

筛选: /

筛选结果 条 | 总计 0 && $totalCount != $recordCount): ?> | 总计

请先选择产品型号,系统将自动加载对应记录