|
|
@@ -6,10 +6,153 @@ use think\Db;
|
|
|
use think\Log;
|
|
|
|
|
|
/**
|
|
|
- * 协助采购操作日志(下发 / 确认供应商 / 审核确认供应商 等追溯)
|
|
|
+ * 协助采购操作日志(purchase_order_oper_log)
|
|
|
+ *
|
|
|
+ * 表字段为英文;写入时「action」存中文操作类型,查询时兼容历史英文码。
|
|
|
*/
|
|
|
class ProcuremenOperLog
|
|
|
{
|
|
|
+ public const COL_SCYDGY_ID = 'scydgy_id';
|
|
|
+ public const COL_PO_ID = 'purchase_order_id';
|
|
|
+ public const COL_ADMIN_ID = 'admin_id';
|
|
|
+ public const COL_ADMIN_NAME = 'admin_name';
|
|
|
+ public const COL_ACTION = 'action';
|
|
|
+ public const COL_CONTENT = 'content';
|
|
|
+ public const COL_TIME = 'createtime';
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 英文码 => 中文操作类型(入库展示用;与库中已有中文值对齐)
|
|
|
+ *
|
|
|
+ * @return array<string, string>
|
|
|
+ */
|
|
|
+ public static function actionLabelMap(): array
|
|
|
+ {
|
|
|
+ return [
|
|
|
+ 'issue_submit' => '下发通知',
|
|
|
+ 'audit_select' => '确认供应商',
|
|
|
+ 'purchase_confirm' => '审核确认供应商',
|
|
|
+ 'purchase_reject' => '审核驳回',
|
|
|
+ 'bid_open_verify' => '开标验证',
|
|
|
+ 'audit_append_supplier' => '补加供应商',
|
|
|
+ 'audit_resend_sms' => '重发短信',
|
|
|
+ 'audit_resend_email' => '重发邮件',
|
|
|
+ 'manual_add' => '手工新增',
|
|
|
+ 'pick_soft_delete' => '初选删除',
|
|
|
+ 'save_qty_price' => '保存数量限价',
|
|
|
+ 'mark_complete' => '直接完结',
|
|
|
+ 'audit_abandon' => '审批重新下发',
|
|
|
+ 'archive_abandon' => '历史重新下发',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 同一业务动作的可选别名(查询时一并匹配)
|
|
|
+ *
|
|
|
+ * @return array<string, string[]>
|
|
|
+ */
|
|
|
+ public static function actionAliases(): array
|
|
|
+ {
|
|
|
+ return [
|
|
|
+ 'issue_submit' => ['下发通知', '下发', 'issue_submit'],
|
|
|
+ 'audit_select' => ['确认供应商', 'audit_select'],
|
|
|
+ 'purchase_confirm' => ['审核确认供应商', 'purchase_confirm'],
|
|
|
+ 'purchase_reject' => ['审核驳回', 'purchase_reject'],
|
|
|
+ 'bid_open_verify' => ['开标验证', 'bid_open_verify'],
|
|
|
+ 'audit_append_supplier' => ['补加供应商', 'audit_append_supplier'],
|
|
|
+ 'audit_resend_sms' => ['重发短信', 'audit_resend_sms'],
|
|
|
+ 'audit_resend_email' => ['重发邮件', 'audit_resend_email'],
|
|
|
+ 'manual_add' => ['手工新增', 'manual_add'],
|
|
|
+ 'pick_soft_delete' => ['初选删除', 'pick_soft_delete'],
|
|
|
+ 'save_qty_price' => ['保存数量限价', 'save_qty_price'],
|
|
|
+ 'mark_complete' => ['直接完结', '完结', 'mark_complete'],
|
|
|
+ 'audit_abandon' => ['审批重新下发', '重新下发', 'audit_abandon'],
|
|
|
+ 'archive_abandon' => ['历史重新下发', '存证重新下发', 'archive_abandon'],
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ public static function toActionLabel(string $action): string
|
|
|
+ {
|
|
|
+ $action = trim($action);
|
|
|
+ if ($action === '') {
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+ $map = self::actionLabelMap();
|
|
|
+ if (isset($map[$action])) {
|
|
|
+ return $map[$action];
|
|
|
+ }
|
|
|
+ // 已是中文别名时,归一到主标签
|
|
|
+ foreach (self::actionAliases() as $code => $aliases) {
|
|
|
+ if (in_array($action, $aliases, true)) {
|
|
|
+ return $map[$code] ?? $action;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $action;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询用:同时匹配中文标签、别名与历史英文码
|
|
|
+ *
|
|
|
+ * @param string|array<int, string> $actions
|
|
|
+ * @return string[]
|
|
|
+ */
|
|
|
+ public static function expandActionQueryValues($actions): array
|
|
|
+ {
|
|
|
+ $aliases = self::actionAliases();
|
|
|
+ $map = self::actionLabelMap();
|
|
|
+ $out = [];
|
|
|
+ foreach ((array)$actions as $a) {
|
|
|
+ $a = trim((string)$a);
|
|
|
+ if ($a === '') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $out[$a] = true;
|
|
|
+ $code = $a;
|
|
|
+ if (!isset($aliases[$code])) {
|
|
|
+ foreach ($aliases as $c => $list) {
|
|
|
+ if (in_array($a, $list, true) || (isset($map[$c]) && $map[$c] === $a)) {
|
|
|
+ $code = $c;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (isset($aliases[$code])) {
|
|
|
+ foreach ($aliases[$code] as $v) {
|
|
|
+ $out[$v] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (isset($map[$code])) {
|
|
|
+ $out[$map[$code]] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return array_keys($out);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装入库行(英文字段,操作类型存中文)
|
|
|
+ *
|
|
|
+ * @return array<string, mixed>
|
|
|
+ */
|
|
|
+ public static function buildInsertRow(
|
|
|
+ int $scydgyId,
|
|
|
+ string $action,
|
|
|
+ string $content,
|
|
|
+ ?int $purchaseOrderId,
|
|
|
+ int $adminId,
|
|
|
+ string $adminName
|
|
|
+ ): array {
|
|
|
+ return [
|
|
|
+ self::COL_SCYDGY_ID => $scydgyId,
|
|
|
+ self::COL_PO_ID => $purchaseOrderId,
|
|
|
+ self::COL_ADMIN_ID => $adminId,
|
|
|
+ self::COL_ADMIN_NAME => self::cut($adminName !== '' ? $adminName : '未知用户', 64),
|
|
|
+ self::COL_ACTION => self::cut(self::toActionLabel($action), 64),
|
|
|
+ self::COL_CONTENT => self::cut($content, 1000),
|
|
|
+ self::COL_TIME => ProcuremenTime::nowDateTime(),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* @param array{0:int,1:string} $admin [id, name]
|
|
|
*/
|
|
|
@@ -19,22 +162,45 @@ class ProcuremenOperLog
|
|
|
return;
|
|
|
}
|
|
|
$adminId = (int)($admin[0] ?? 0);
|
|
|
- $adminName = self::cut((string)($admin[1] ?? '未知用户'), 64);
|
|
|
+ $adminName = (string)($admin[1] ?? '未知用户');
|
|
|
try {
|
|
|
- Db::table('purchase_order_oper_log')->insert([
|
|
|
- 'scydgy_id' => $scydgyId,
|
|
|
- 'purchase_order_id' => $purchaseOrderId,
|
|
|
- 'admin_id' => $adminId,
|
|
|
- 'admin_name' => $adminName,
|
|
|
- 'action' => self::cut($action, 64),
|
|
|
- 'content' => self::cut($content, 1000),
|
|
|
- 'createtime' => ProcuremenTime::nowDateTime(),
|
|
|
- ]);
|
|
|
+ Db::table('purchase_order_oper_log')->insert(
|
|
|
+ self::buildInsertRow($scydgyId, $action, $content, $purchaseOrderId, $adminId, $adminName)
|
|
|
+ );
|
|
|
} catch (\Throwable $e) {
|
|
|
Log::write('procuremen oper log: ' . $e->getMessage(), 'error');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 查询结果规范化(兼容偶发中文列名 → 英文键)
|
|
|
+ *
|
|
|
+ * @param array<string, mixed> $log
|
|
|
+ * @return array<string, mixed>
|
|
|
+ */
|
|
|
+ public static function normalizeRow(array $log): array
|
|
|
+ {
|
|
|
+ $map = [
|
|
|
+ '工序ID' => 'scydgy_id',
|
|
|
+ '采购订单ID' => 'purchase_order_id',
|
|
|
+ '操作人ID' => 'admin_id',
|
|
|
+ '操作人' => 'admin_name',
|
|
|
+ '操作类型' => 'action',
|
|
|
+ '操作内容' => 'content',
|
|
|
+ '创建时间' => 'createtime',
|
|
|
+ ];
|
|
|
+ foreach ($map as $cn => $en) {
|
|
|
+ if (array_key_exists($cn, $log) && !array_key_exists($en, $log)) {
|
|
|
+ $log[$en] = $log[$cn];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (isset($log['action'])) {
|
|
|
+ $log['action'] = self::toActionLabel((string)$log['action']);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $log;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* @param string|array<int, string> $actions
|
|
|
*/
|
|
|
@@ -43,18 +209,18 @@ class ProcuremenOperLog
|
|
|
if (!ProcuremenGuard::isValidScydgyId($scydgyId)) {
|
|
|
return '';
|
|
|
}
|
|
|
- $acts = is_array($actions) ? $actions : [$actions];
|
|
|
- $acts = array_values(array_filter(array_map('strval', $acts)));
|
|
|
+ $acts = self::expandActionQueryValues($actions);
|
|
|
if ($acts === []) {
|
|
|
return '';
|
|
|
}
|
|
|
try {
|
|
|
$log = Db::table('purchase_order_oper_log')
|
|
|
- ->where('scydgy_id', $scydgyId)
|
|
|
- ->where('action', 'in', $acts)
|
|
|
+ ->where(self::COL_SCYDGY_ID, $scydgyId)
|
|
|
+ ->where(self::COL_ACTION, 'in', $acts)
|
|
|
->order('id', 'desc')
|
|
|
->find();
|
|
|
if (is_array($log)) {
|
|
|
+ $log = self::normalizeRow($log);
|
|
|
$text = ProcuremenTime::formatDisplayDateTime($log['createtime'] ?? null);
|
|
|
if ($text !== '') {
|
|
|
return $text;
|
|
|
@@ -81,6 +247,7 @@ class ProcuremenOperLog
|
|
|
if (!is_array($lg)) {
|
|
|
continue;
|
|
|
}
|
|
|
+ $lg = self::normalizeRow($lg);
|
|
|
$lg['createtime_text'] = ProcuremenTime::formatDisplayDateTime($lg['createtime'] ?? null);
|
|
|
$lg['content'] = ProcuremenTime::formatOperLogContent(
|
|
|
(string)($lg['content'] ?? ''),
|