canArchiveAbandon(); $canDetails = $this->hasProcuremenSiblingPerm(['details']); $this->view->assign('canArchiveAbandon', $canArchiveAbandon); $this->assignconfig('procuremenAuth', [ 'details' => $canDetails, 'archiveabandon' => $canArchiveAbandon, ]); } /** * 历史存证「重新下发」权限(规则名在 procuremen 控制器下) */ protected function canArchiveAbandon(): bool { if ($this->hasProcuremenSiblingPerm(['archiveabandon', 'archiveAbandon'])) { return true; } return $this->hasProcuremenSiblingPerm(['auditabandon', 'auditAbandon']); } /** * @param string[] $actions */ protected function hasProcuremenSiblingPerm(array $actions): bool { foreach ($actions as $action) { $action = strtolower(trim((string)$action)); if ($action === '') { continue; } if (strpos($action, 'procuremen/') !== 0) { $action = 'procuremen/' . $action; } if ($this->auth->check($action)) { return true; } } $suffixes = []; foreach ($actions as $action) { $action = strtolower(trim((string)$action)); $action = preg_replace('#^procuremen/#', '', $action); if ($action !== '') { $suffixes[$action] = true; } } if ($suffixes === []) { return false; } try { foreach ($this->auth->getRuleList() as $rule) { $rule = strtolower((string)$rule); if (strpos($rule, 'procuremen/') !== 0) { continue; } foreach (array_keys($suffixes) as $suffix) { if ($rule === 'procuremen/' . $suffix || strpos($rule, 'procuremen/' . $suffix . '/') === 0) { return true; } } } } catch (\Throwable $e) { } return false; } /** purchase_order.status 为已完结(兼容 varchar / 数字 / 首尾空格) */ protected function applyPurchaseOrderCompletedWhere($query): void { $query->whereRaw(ProcuremenStatus::sqlPoCompleted('status')); } public function index() { $this->relationSearch = false; $this->request->filter(['strip_tags', 'trim']); if ($this->request->isAjax()) { list($where, $sort, $order, $offset, $limit) = $this->buildparams(); $limit = max(10, min(500, (int)$limit)); $offset = max(0, (int)$offset); $applyFilters = function ($query) use ($where) { $this->applyPurchaseOrderCompletedWhere($query); if (!empty($where)) { $query->where($where); } }; $sortField = preg_match('/^[a-zA-Z0-9_]+$/', (string)$sort) ? $sort : 'id'; $orderDir = strtoupper((string)$order) === 'ASC' ? 'ASC' : 'DESC'; $listQuery = Db::table('purchase_order'); $applyFilters($listQuery); $rows = $listQuery ->field('id,scydgy_id,CCYDH,CYJMC,CGYMC,pick_company_name,createtime,dStamp,pick_time') ->order($sortField, $orderDir) ->select(); if (!is_array($rows)) { $rows = []; } $sidList = []; foreach ($rows as $r) { if (!is_array($r)) { continue; } $sid = (int)($r['scydgy_id'] ?? 0); if ($sid !== 0) { $sidList[$sid] = true; } } $completeTsMap = ProcuremenTime::loadOperLogTimestampMap( array_keys($sidList), ['purchase_confirm', 'mark_complete'] ); $out = []; foreach ($rows as $r) { if (!is_array($r)) { continue; } $sid = (int)($r['scydgy_id'] ?? 0); $done = ProcuremenTime::resolveCompletedDone($r, $completeTsMap); $out[] = [ 'id' => (int)($r['id'] ?? 0), 'scydgy_id' => $sid, 'CCYDH' => trim((string)($r['CCYDH'] ?? '')), 'CYJMC' => trim((string)($r['CYJMC'] ?? '')), 'CGYMC' => trim((string)($r['CGYMC'] ?? '')), 'pick_company_name' => trim((string)($r['pick_company_name'] ?? '')), 'createtime' => $done['ts'], 'createtime_text' => $done['text'], ]; } $merged = $this->collapseArchiveRowsByOrder($out); $nMerged = count($merged); if ($nMerged > 1 && $sortField === 'id') { usort($merged, function ($a, $b) use ($orderDir) { $cmp = ((int)($a['id'] ?? 0)) <=> ((int)($b['id'] ?? 0)); if ($cmp === 0) { return strcmp((string)($a['CCYDH'] ?? ''), (string)($b['CCYDH'] ?? '')); } return $orderDir === 'ASC' ? $cmp : -$cmp; }); } elseif ($nMerged > 1 && $sortField === 'createtime') { usort($merged, function ($a, $b) use ($orderDir) { $ta = (int)($a['createtime'] ?? 0); $tb = (int)($b['createtime'] ?? 0); if ($ta === $tb) { return ((int)($b['id'] ?? 0)) <=> ((int)($a['id'] ?? 0)); } return $orderDir === 'ASC' ? ($ta <=> $tb) : ($tb <=> $ta); }); } $pageRows = array_slice($merged, $offset, $limit); return json(['total' => $nMerged, 'rows' => $pageRows]); } return $this->view->fetch(); } /** * 历史存证:同一订单号 CCYDH 合并为一行(与审批/确认列表一致) * * @param array> $rows * @return array> */ protected function collapseArchiveRowsByOrder(array $rows): array { if ($rows === []) { return []; } $groups = []; foreach ($rows as $row) { if (!is_array($row)) { continue; } $dh = trim((string)($row['CCYDH'] ?? '')); $key = $dh !== '' ? $dh : ('_id_' . (int)($row['id'] ?? 0)); if (!isset($groups[$key])) { $groups[$key] = []; } $groups[$key][] = $row; } $out = []; foreach ($groups as $groupRows) { if ($groupRows === []) { continue; } usort($groupRows, function ($a, $b) { return ((int)($a['id'] ?? 0)) <=> ((int)($b['id'] ?? 0)); }); $head = $groupRows[0]; $gymcList = []; $supplierList = []; foreach ($groupRows as $r) { $g = trim((string)($r['CGYMC'] ?? '')); if ($g !== '' && !in_array($g, $gymcList, true)) { $gymcList[] = $g; } $sn = trim((string)($r['pick_company_name'] ?? '')); if ($sn !== '' && !in_array($sn, $supplierList, true)) { $supplierList[] = $sn; } } $merged = $head; if (count($groupRows) > 1) { $merged['CGYMC'] = implode('、', $gymcList); } $merged['pick_company_name'] = implode('、', $supplierList); $merged['process_count'] = count($groupRows); $latestTs = 0; $latestText = ''; foreach ($groupRows as $r) { $ts = (int)($r['createtime'] ?? 0); if ($ts <= 0 && !empty($r['createtime_text'])) { $ts = (int)strtotime((string)$r['createtime_text']); } if ($ts > $latestTs) { $latestTs = $ts; $latestText = trim((string)($r['createtime_text'] ?? '')); } } if ($latestTs > 0) { $merged['createtime'] = $latestTs; if ($latestText === '') { $latestText = date('Y-m-d H:i:s', $latestTs); } $merged['createtime_text'] = ProcuremenTime::formatDisplayDateTime($latestText); } $maxId = (int)($head['id'] ?? 0); foreach ($groupRows as $r) { $maxId = max($maxId, (int)($r['id'] ?? 0)); } $merged['id'] = $maxId; $out[] = $merged; } return $out; } }