ProcuremenTime.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <?php
  2. namespace app\common\library;
  3. use think\Db;
  4. /**
  5. * 协助采购时间:操作日志、完结时间统一为可读 YYYY-MM-DD HH:mm:ss(不再显示 Unix 时间戳)
  6. */
  7. class ProcuremenTime
  8. {
  9. public static function nowDateTime(): string
  10. {
  11. return date('Y-m-d H:i:s');
  12. }
  13. /** @deprecated 使用 {@see nowDateTime} */
  14. public static function todayYmd(): string
  15. {
  16. return self::nowDateTime();
  17. }
  18. /** 列表/详情展示:年月日 + 时分秒 */
  19. public static function formatDisplayDateTime($value): string
  20. {
  21. if ($value === null || $value === '') {
  22. return '';
  23. }
  24. if (is_numeric($value) && (int)$value > 946684800) {
  25. return date('Y-m-d H:i:s', (int)$value);
  26. }
  27. $s = trim((string)$value);
  28. if ($s === '' || preg_match('/^0000-00-00/i', $s)) {
  29. return '';
  30. }
  31. if (preg_match('/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/', $s, $m)) {
  32. return $m[1];
  33. }
  34. if (preg_match('/^(\d{4}-\d{2}-\d{2})$/', $s, $m)) {
  35. return $m[1] . ' 00:00:00';
  36. }
  37. if (preg_match('/^(\d{4}-\d{2}-\d{2})/', $s, $m)) {
  38. $ts = strtotime($s);
  39. return ($ts !== false && $ts > 0) ? date('Y-m-d H:i:s', $ts) : $m[1] . ' 00:00:00';
  40. }
  41. $ts = strtotime($s);
  42. return ($ts !== false && $ts > 0) ? date('Y-m-d H:i:s', $ts) : $s;
  43. }
  44. /** 兼容旧调用:与 formatDisplayDateTime 相同 */
  45. public static function formatDisplayDate($value): string
  46. {
  47. return self::formatDisplayDateTime($value);
  48. }
  49. /** 排序/月份统计用 Unix 时间 */
  50. public static function parseToTimestamp($value): int
  51. {
  52. if ($value === null || $value === '') {
  53. return 0;
  54. }
  55. if (is_numeric($value) && (int)$value > 946684800) {
  56. return (int)$value;
  57. }
  58. $s = trim((string)$value);
  59. if ($s === '' || preg_match('/^0000-00-00/i', $s)) {
  60. return 0;
  61. }
  62. if (preg_match('/^(\d{4}-\d{2}-\d{2})(?:\s+\d{2}:\d{2}:\d{2})?/', $s)) {
  63. $ts = strtotime($s);
  64. return ($ts !== false && $ts > 0) ? $ts : 0;
  65. }
  66. $ts = strtotime($s);
  67. return ($ts !== false && $ts > 0) ? $ts : 0;
  68. }
  69. /**
  70. * @param int[] $scydgyIds
  71. * @param array<int,string> $actions
  72. * @return array<int, int> scydgy_id => unix
  73. */
  74. public static function loadOperLogTimestampMap(array $scydgyIds, array $actions): array
  75. {
  76. $out = [];
  77. $scydgyIds = array_values(array_unique(array_filter(array_map('intval', $scydgyIds))));
  78. $actions = array_values(array_filter(array_map('strval', $actions)));
  79. if ($scydgyIds === [] || $actions === []) {
  80. return $out;
  81. }
  82. try {
  83. $logs = Db::table('purchase_order_oper_log')
  84. ->where('scydgy_id', 'in', $scydgyIds)
  85. ->where('action', 'in', $actions)
  86. ->field('scydgy_id,createtime')
  87. ->order('id', 'asc')
  88. ->select();
  89. } catch (\Throwable $e) {
  90. return $out;
  91. }
  92. if (!is_array($logs)) {
  93. return $out;
  94. }
  95. foreach ($logs as $log) {
  96. if (!is_array($log)) {
  97. continue;
  98. }
  99. $sid = (int)($log['scydgy_id'] ?? 0);
  100. $ct = self::parseToTimestamp($log['createtime'] ?? null);
  101. if ($sid > 0 && $ct > 946684800) {
  102. $out[$sid] = isset($out[$sid]) ? max($out[$sid], $ct) : $ct;
  103. }
  104. }
  105. return $out;
  106. }
  107. /**
  108. * 已完结时间:与详情进度一致,优先采购确认/直接完结操作日志
  109. *
  110. * @param array<string, mixed> $row
  111. * @param array<int, int> $completeTsMap
  112. * @return array{ts:int, text:string}
  113. */
  114. public static function resolveCompletedDone(array $row, array $completeTsMap = []): array
  115. {
  116. $sid = (int)($row['scydgy_id'] ?? 0);
  117. $ts = 0;
  118. $text = '';
  119. if ($sid > 0 && isset($completeTsMap[$sid]) && (int)$completeTsMap[$sid] > 946684800) {
  120. $ts = (int)$completeTsMap[$sid];
  121. }
  122. if ($ts <= 0) {
  123. foreach (['pick_time', 'createtime', 'dStamp'] as $key) {
  124. $t = self::parseToTimestamp($row[$key] ?? null);
  125. if ($t > $ts) {
  126. $ts = $t;
  127. }
  128. }
  129. }
  130. if ($ts > 0) {
  131. $text = date('Y-m-d H:i:s', $ts);
  132. }
  133. return ['ts' => $ts, 'text' => $text];
  134. }
  135. /**
  136. * 操作记录展示文案:统一步骤用语(下发 / 确认供应商 / 审核确认供应商)
  137. */
  138. public static function formatOperLogContent(string $content, string $action = ''): string
  139. {
  140. $content = trim($content);
  141. if ($content === '') {
  142. return '';
  143. }
  144. $action = trim($action);
  145. if ($action === 'purchase_confirm') {
  146. if (preg_match('/[「『](.+?)[」』]/u', $content, $m)) {
  147. return '审核确认供应商:已选定「' . trim($m[1]) . '」';
  148. }
  149. }
  150. if ($action === 'audit_select') {
  151. if (preg_match('/选定[::]\s*(.+)$/u', $content, $m)) {
  152. $name = trim($m[1]);
  153. if (preg_match('/^确认供应商/u', $content) && preg_match('/订单([^),]+)/u', $content, $om)) {
  154. return '确认供应商(订单' . trim($om[1]) . '):已选定「' . $name . '」';
  155. }
  156. return '确认供应商:已选定「' . $name . '」';
  157. }
  158. }
  159. if ($action === 'bid_open_verify') {
  160. if (preg_match('/开标验证/u', $content)) {
  161. return $content;
  162. }
  163. return '开标验证:' . $content;
  164. }
  165. if ($action === 'issue_submit') {
  166. if (preg_match('/通知供应商[((](\d+)\s*家[))].*?[::]\s*(.+)$/u', $content, $m)) {
  167. return '下发:通知供应商(' . $m[1] . ' 家):' . trim($m[2]);
  168. }
  169. }
  170. $content = preg_replace('/^采购确认:已选中供应商/u', '审核确认供应商:已选定', $content);
  171. $content = preg_replace('/^采购确认:/u', '审核确认供应商:', $content);
  172. $content = preg_replace('/已选中供应商/u', '已选定', $content);
  173. $content = preg_replace('/^(合并)?(协助|外发)初选/u', '下发', $content);
  174. $content = preg_replace('/^采购终审驳回/u', '审核驳回', $content);
  175. $content = preg_replace('/退回外发初选/u', '退回协助初选', $content);
  176. $content = preg_replace('/^重新下发(([^)]+)),/u', '重新下发($1):', $content);
  177. $content = preg_replace('/;+$/u', '', $content);
  178. return trim($content);
  179. }
  180. }