Procuremenarchive.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?php
  2. namespace app\admin\controller;
  3. use app\common\controller\Backend;
  4. use app\common\library\ProcuremenStatus;
  5. use app\common\library\ProcuremenTime;
  6. use think\Db;
  7. /**
  8. * 协助采购 — 历史存证档案查询(已完结工序 + 操作记录详情)
  9. *
  10. * @icon fa fa-archive
  11. */
  12. class Procuremenarchive extends Backend
  13. {
  14. protected $searchFields = 'CCYDH,CYJMC,CGYMC,pick_company_name';
  15. public function _initialize()
  16. {
  17. parent::_initialize();
  18. $canArchiveAbandon = $this->canArchiveAbandon();
  19. $canDetails = $this->hasProcuremenSiblingPerm(['details']);
  20. $this->view->assign('canArchiveAbandon', $canArchiveAbandon);
  21. $this->assignconfig('procuremenAuth', [
  22. 'details' => $canDetails,
  23. 'auditabandon' => $canArchiveAbandon,
  24. 'archiveabandon' => $canArchiveAbandon,
  25. ]);
  26. }
  27. /**
  28. * 历史存证「重新下发」权限:与审批列表统一为 auditabandon
  29. */
  30. protected function canArchiveAbandon(): bool
  31. {
  32. if ($this->hasProcuremenSiblingPerm(['auditabandon', 'auditAbandon'])) {
  33. return true;
  34. }
  35. return $this->hasProcuremenSiblingPerm(['archiveabandon', 'archiveAbandon']);
  36. }
  37. /**
  38. * @param string[] $actions
  39. */
  40. protected function hasProcuremenSiblingPerm(array $actions): bool
  41. {
  42. foreach ($actions as $action) {
  43. $action = strtolower(trim((string)$action));
  44. if ($action === '') {
  45. continue;
  46. }
  47. if (strpos($action, 'procuremen/') !== 0) {
  48. $action = 'procuremen/' . $action;
  49. }
  50. if ($this->auth->check($action)) {
  51. return true;
  52. }
  53. }
  54. $suffixes = [];
  55. foreach ($actions as $action) {
  56. $action = strtolower(trim((string)$action));
  57. $action = preg_replace('#^procuremen/#', '', $action);
  58. if ($action !== '') {
  59. $suffixes[$action] = true;
  60. }
  61. }
  62. if ($suffixes === []) {
  63. return false;
  64. }
  65. try {
  66. foreach ($this->auth->getRuleList() as $rule) {
  67. $rule = strtolower((string)$rule);
  68. if (strpos($rule, 'procuremen/') !== 0) {
  69. continue;
  70. }
  71. foreach (array_keys($suffixes) as $suffix) {
  72. if ($rule === 'procuremen/' . $suffix || strpos($rule, 'procuremen/' . $suffix . '/') === 0) {
  73. return true;
  74. }
  75. }
  76. }
  77. } catch (\Throwable $e) {
  78. }
  79. return false;
  80. }
  81. /** purchase_order.status 为已完结(兼容 varchar / 数字 / 首尾空格) */
  82. protected function applyPurchaseOrderCompletedWhere($query): void
  83. {
  84. $query->whereRaw(ProcuremenStatus::sqlPoCompleted('status'));
  85. }
  86. public function index()
  87. {
  88. $this->relationSearch = false;
  89. $this->request->filter(['strip_tags', 'trim']);
  90. if ($this->request->isAjax()) {
  91. list($where, $sort, $order, $offset, $limit) = $this->buildparams();
  92. $limit = max(10, min(500, (int)$limit));
  93. $offset = max(0, (int)$offset);
  94. $applyFilters = function ($query) use ($where) {
  95. $this->applyPurchaseOrderCompletedWhere($query);
  96. if (!empty($where)) {
  97. $query->where($where);
  98. }
  99. };
  100. $sortField = preg_match('/^[a-zA-Z0-9_]+$/', (string)$sort) ? $sort : 'id';
  101. $orderDir = strtoupper((string)$order) === 'ASC' ? 'ASC' : 'DESC';
  102. $listQuery = Db::table('purchase_order');
  103. $applyFilters($listQuery);
  104. $rows = $listQuery
  105. ->field('id,scydgy_id,CCYDH,CYJMC,CGYMC,pick_company_name,createtime,dStamp,pick_time')
  106. ->order($sortField, $orderDir)
  107. ->select();
  108. if (!is_array($rows)) {
  109. $rows = [];
  110. }
  111. $sidList = [];
  112. foreach ($rows as $r) {
  113. if (!is_array($r)) {
  114. continue;
  115. }
  116. $sid = (int)($r['scydgy_id'] ?? 0);
  117. if ($sid !== 0) {
  118. $sidList[$sid] = true;
  119. }
  120. }
  121. $completeTsMap = ProcuremenTime::loadOperLogTimestampMap(
  122. array_keys($sidList),
  123. ['purchase_confirm', 'mark_complete']
  124. );
  125. $out = [];
  126. foreach ($rows as $r) {
  127. if (!is_array($r)) {
  128. continue;
  129. }
  130. $sid = (int)($r['scydgy_id'] ?? 0);
  131. $done = ProcuremenTime::resolveCompletedDone($r, $completeTsMap);
  132. $out[] = [
  133. 'id' => (int)($r['id'] ?? 0),
  134. 'scydgy_id' => $sid,
  135. 'CCYDH' => trim((string)($r['CCYDH'] ?? '')),
  136. 'CYJMC' => trim((string)($r['CYJMC'] ?? '')),
  137. 'CGYMC' => trim((string)($r['CGYMC'] ?? '')),
  138. 'pick_company_name' => trim((string)($r['pick_company_name'] ?? '')),
  139. 'createtime' => $done['ts'],
  140. 'createtime_text' => $done['text'],
  141. ];
  142. }
  143. $merged = $this->collapseArchiveRowsByOrder($out);
  144. $nMerged = count($merged);
  145. if ($nMerged > 1 && $sortField === 'id') {
  146. usort($merged, function ($a, $b) use ($orderDir) {
  147. $cmp = ((int)($a['id'] ?? 0)) <=> ((int)($b['id'] ?? 0));
  148. if ($cmp === 0) {
  149. return strcmp((string)($a['CCYDH'] ?? ''), (string)($b['CCYDH'] ?? ''));
  150. }
  151. return $orderDir === 'ASC' ? $cmp : -$cmp;
  152. });
  153. } elseif ($nMerged > 1 && $sortField === 'createtime') {
  154. usort($merged, function ($a, $b) use ($orderDir) {
  155. $ta = (int)($a['createtime'] ?? 0);
  156. $tb = (int)($b['createtime'] ?? 0);
  157. if ($ta === $tb) {
  158. return ((int)($b['id'] ?? 0)) <=> ((int)($a['id'] ?? 0));
  159. }
  160. return $orderDir === 'ASC' ? ($ta <=> $tb) : ($tb <=> $ta);
  161. });
  162. }
  163. $pageRows = array_slice($merged, $offset, $limit);
  164. return json(['total' => $nMerged, 'rows' => $pageRows]);
  165. }
  166. return $this->view->fetch();
  167. }
  168. /**
  169. * 历史存证:同一订单号 CCYDH 合并为一行(与审批/确认列表一致)
  170. *
  171. * @param array<int, array<string, mixed>> $rows
  172. * @return array<int, array<string, mixed>>
  173. */
  174. protected function collapseArchiveRowsByOrder(array $rows): array
  175. {
  176. if ($rows === []) {
  177. return [];
  178. }
  179. $groups = [];
  180. foreach ($rows as $row) {
  181. if (!is_array($row)) {
  182. continue;
  183. }
  184. $dh = trim((string)($row['CCYDH'] ?? ''));
  185. $key = $dh !== '' ? $dh : ('_id_' . (int)($row['id'] ?? 0));
  186. if (!isset($groups[$key])) {
  187. $groups[$key] = [];
  188. }
  189. $groups[$key][] = $row;
  190. }
  191. $out = [];
  192. foreach ($groups as $groupRows) {
  193. if ($groupRows === []) {
  194. continue;
  195. }
  196. usort($groupRows, function ($a, $b) {
  197. return ((int)($a['id'] ?? 0)) <=> ((int)($b['id'] ?? 0));
  198. });
  199. $head = $groupRows[0];
  200. $gymcList = [];
  201. $supplierList = [];
  202. foreach ($groupRows as $r) {
  203. $g = trim((string)($r['CGYMC'] ?? ''));
  204. if ($g !== '' && !in_array($g, $gymcList, true)) {
  205. $gymcList[] = $g;
  206. }
  207. $sn = trim((string)($r['pick_company_name'] ?? ''));
  208. if ($sn !== '' && !in_array($sn, $supplierList, true)) {
  209. $supplierList[] = $sn;
  210. }
  211. }
  212. $merged = $head;
  213. if (count($groupRows) > 1) {
  214. $merged['CGYMC'] = implode('、', $gymcList);
  215. }
  216. $merged['pick_company_name'] = implode('、', $supplierList);
  217. $merged['process_count'] = count($groupRows);
  218. $latestTs = 0;
  219. $latestText = '';
  220. foreach ($groupRows as $r) {
  221. $ts = (int)($r['createtime'] ?? 0);
  222. if ($ts <= 0 && !empty($r['createtime_text'])) {
  223. $ts = (int)strtotime((string)$r['createtime_text']);
  224. }
  225. if ($ts > $latestTs) {
  226. $latestTs = $ts;
  227. $latestText = trim((string)($r['createtime_text'] ?? ''));
  228. }
  229. }
  230. if ($latestTs > 0) {
  231. $merged['createtime'] = $latestTs;
  232. if ($latestText === '') {
  233. $latestText = date('Y-m-d H:i:s', $latestTs);
  234. }
  235. $merged['createtime_text'] = ProcuremenTime::formatDisplayDateTime($latestText);
  236. }
  237. $maxId = (int)($head['id'] ?? 0);
  238. foreach ($groupRows as $r) {
  239. $maxId = max($maxId, (int)($r['id'] ?? 0));
  240. }
  241. $merged['id'] = $maxId;
  242. $out[] = $merged;
  243. }
  244. return $out;
  245. }
  246. }