|
|
@@ -15,7 +15,8 @@ use think\Validate;
|
|
|
|
|
|
/**
|
|
|
* 手机端:协助明细(purchase_order_detail)验证码 / 账号密码登录 + 列表
|
|
|
- * 普通用户:customer 表(手机号验证码 或 登录账号+密码);管理员:admin 表账号密码(看全部、仅查看)
|
|
|
+ * 普通用户(customer):登录后进报价列表,可填单价/交期
|
|
|
+ * 管理员(admin):登录后进「外协入库评分」,对待入库订单选合格/不合格
|
|
|
*/
|
|
|
class Index extends Frontend
|
|
|
{
|
|
|
@@ -125,6 +126,9 @@ class Index extends Frontend
|
|
|
protected function mprocLoadUserByToken(string $token): ?array
|
|
|
{
|
|
|
if ($this->mprocIsSignedAuthToken($token)) {
|
|
|
+ if ($this->mprocIsAuthTokenRevoked($token)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
$user = $this->mprocUserFromSignedToken($token);
|
|
|
if (!$user) {
|
|
|
return null;
|
|
|
@@ -295,8 +299,12 @@ class Index extends Frontend
|
|
|
if ($raw === null || $raw === '') {
|
|
|
return null;
|
|
|
}
|
|
|
+ $raw = (string)$raw;
|
|
|
+ if ($this->mprocIsAuthTokenRevoked($raw)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
- return $this->mprocUserFromSignedToken((string)$raw);
|
|
|
+ return $this->mprocUserFromSignedToken($raw);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -324,6 +332,7 @@ class Index extends Frontend
|
|
|
'company_name' => '',
|
|
|
'username' => $uname,
|
|
|
'customer_user_id' => 0,
|
|
|
+ 'admin_id' => (int)($row['id'] ?? 0),
|
|
|
'login_type' => 'remember',
|
|
|
'is_admin' => 1,
|
|
|
'login_time' => $loginTime,
|
|
|
@@ -359,21 +368,89 @@ class Index extends Frontend
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ protected function mprocAuthRevokeCacheKey(string $token): string
|
|
|
+ {
|
|
|
+ return 'mproc_revoked_' . md5($token);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function mprocRevokeAuthToken(string $token): void
|
|
|
+ {
|
|
|
+ $token = trim($token);
|
|
|
+ if ($token === '') {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Cache::set($this->mprocAuthRevokeCacheKey($token), 1, $this->mprocTtlSeconds + 86400);
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function mprocIsAuthTokenRevoked(string $token): bool
|
|
|
+ {
|
|
|
+ $token = trim($token);
|
|
|
+ if ($token === '') {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return (bool)Cache::get($this->mprocAuthRevokeCacheKey($token));
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按与写入时相同的 path/secure/samesite 清除 Cookie,避免仅 delete 时删不掉
|
|
|
+ */
|
|
|
+ protected function mprocExpireAuthCookies(): void
|
|
|
+ {
|
|
|
+ $opts = $this->mprocCookieOptions();
|
|
|
+ $opts['expire'] = -3600;
|
|
|
+ try {
|
|
|
+ Cookie::set('mproc_token', '', $opts);
|
|
|
+ Cookie::set('mproc_remember', '', $opts);
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Cookie::delete('mproc_token');
|
|
|
+ Cookie::delete('mproc_remember');
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ unset($_COOKIE['mproc_token'], $_COOKIE['mproc_remember']);
|
|
|
+ $prefix = (string)Config::get('cookie.prefix');
|
|
|
+ if ($prefix !== '') {
|
|
|
+ unset($_COOKIE[$prefix . 'mproc_token'], $_COOKIE[$prefix . 'mproc_remember']);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
protected function mprocClearLogin($token)
|
|
|
{
|
|
|
- if ($token !== null && $token !== '') {
|
|
|
- Cache::rm($this->mprocAuthCacheKey((string)$token));
|
|
|
- if (!$this->mprocIsSignedAuthToken((string)$token)) {
|
|
|
- Cache::rm('mproc_u_' . $token);
|
|
|
+ $token = trim((string)($token ?? ''));
|
|
|
+ if ($token !== '') {
|
|
|
+ $this->mprocRevokeAuthToken($token);
|
|
|
+ try {
|
|
|
+ Cache::rm($this->mprocAuthCacheKey($token));
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ if (!$this->mprocIsSignedAuthToken($token)) {
|
|
|
+ try {
|
|
|
+ Cache::rm('mproc_u_' . $token);
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 同时作废 remember / 另一份 cookie 里可能残留的签名令牌
|
|
|
+ foreach (['mproc_token', 'mproc_remember'] as $ck) {
|
|
|
+ $raw = Cookie::get($ck);
|
|
|
+ if ($raw !== null && $raw !== '' && (string)$raw !== $token) {
|
|
|
+ $this->mprocRevokeAuthToken((string)$raw);
|
|
|
}
|
|
|
}
|
|
|
Session::delete('mproc_token');
|
|
|
- Cookie::delete('mproc_token');
|
|
|
- Cookie::delete('mproc_remember');
|
|
|
+ $this->mprocExpireAuthCookies();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 登录成功后的回跳地址校验(仅允许本站「协助明细订单页」路径,防止开放重定向)
|
|
|
+ * 登录成功后的回跳地址校验(仅允许本站手机端首页 / 入库评分页,防止开放重定向)
|
|
|
*
|
|
|
* @param string $raw GET/POST 的 redirect 或当前 REQUEST_URI
|
|
|
*/
|
|
|
@@ -407,7 +484,9 @@ class Index extends Frontend
|
|
|
if (strpos($s, '//') === 0) {
|
|
|
return '';
|
|
|
}
|
|
|
- if (stripos($s, 'index/index/index') === false) {
|
|
|
+ $okHome = stripos($s, 'index/index/index') !== false;
|
|
|
+ $okInbound = stripos($s, 'index/index/inboundscore') !== false;
|
|
|
+ if (!$okHome && !$okInbound) {
|
|
|
return '';
|
|
|
}
|
|
|
if (stripos($s, 'index/index/login') !== false) {
|
|
|
@@ -562,8 +641,8 @@ class Index extends Frontend
|
|
|
$allowed['main_tab'] = $mt;
|
|
|
}
|
|
|
$tb = isset($q['tab']) ? trim((string)$q['tab']) : '';
|
|
|
- if (in_array($tb, ['draft', 'submitted', 'done', 'me'], true)) {
|
|
|
- $allowed['tab'] = $tb;
|
|
|
+ if ($tb === 'me' || in_array($this->mprocNormalizeListTab($tb), $this->mprocListTabWhitelist(), true)) {
|
|
|
+ $allowed['tab'] = ($tb === 'me') ? 'me' : $this->mprocNormalizeListTab($tb);
|
|
|
}
|
|
|
if (isset($q['q']) && trim((string)$q['q']) !== '') {
|
|
|
$allowed['q'] = substr(trim((string)$q['q']), 0, 120);
|
|
|
@@ -593,6 +672,36 @@ class Index extends Frontend
|
|
|
return $base . $path . $qs;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 按登录身份决定首页:供应商→报价列表;管理员→外协入库评分
|
|
|
+ *
|
|
|
+ * @param array<string, mixed> $user
|
|
|
+ * @param string $redirectPathOrUrl
|
|
|
+ */
|
|
|
+ protected function mprocBuildAfterLoginHomeUrl(array $user, $redirectPathOrUrl = '')
|
|
|
+ {
|
|
|
+ if (!empty($user['is_admin'])) {
|
|
|
+ $raw = $this->mprocSanitizeRedirectUrl($redirectPathOrUrl);
|
|
|
+ if ($raw !== '' && stripos($raw, 'inboundscore') !== false) {
|
|
|
+ $base = rtrim($this->request->root(true), '/');
|
|
|
+ $path = parse_url($raw, PHP_URL_PATH);
|
|
|
+ $query = parse_url($raw, PHP_URL_QUERY);
|
|
|
+ if (!is_string($path) || $path === '') {
|
|
|
+ return url('index/index/inboundscore', '', '', true);
|
|
|
+ }
|
|
|
+ if (stripos($path, 'inboundscore') === false) {
|
|
|
+ return url('index/index/inboundscore', '', '', true);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $base . $path . (is_string($query) && $query !== '' ? ('?' . $query) : '');
|
|
|
+ }
|
|
|
+
|
|
|
+ return url('index/index/inboundscore', '', '', true);
|
|
|
+ }
|
|
|
+
|
|
|
+ return $this->mprocBuildAfterLoginIndexUrl($redirectPathOrUrl);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 从 purchase_order_detail 表解析真实列名(SHOW COLUMNS 只查一次,按候选小写名匹配第一条)
|
|
|
*
|
|
|
@@ -888,7 +997,7 @@ class Index extends Frontend
|
|
|
$sessR = $this->mprocSanitizeRedirectUrl((string)Session::get('mproc_intended_url', ''));
|
|
|
Session::delete('mproc_intended_url');
|
|
|
$raw = $postR !== '' ? $postR : $sessR;
|
|
|
- $jump = $this->mprocBuildAfterLoginIndexUrl($raw);
|
|
|
+ $jump = $this->mprocBuildAfterLoginHomeUrl($userData, $raw);
|
|
|
$this->success('登录成功', $jump, [
|
|
|
'mproc_token' => $token,
|
|
|
'keep_hours' => $this->mprocKeepHours(),
|
|
|
@@ -999,10 +1108,9 @@ class Index extends Frontend
|
|
|
}
|
|
|
if ($cn !== '') {
|
|
|
try {
|
|
|
+ // customer 表无 name 列,勿用 whereOr('name')
|
|
|
$hit = Db::table('customer')
|
|
|
- ->where(function ($q) use ($cn) {
|
|
|
- $q->where('company_name', $cn)->whereOr('name', $cn);
|
|
|
- })
|
|
|
+ ->where('company_name', $cn)
|
|
|
->order('id', 'desc')
|
|
|
->find();
|
|
|
} catch (\Throwable $e) {
|
|
|
@@ -1652,10 +1760,20 @@ class Index extends Frontend
|
|
|
*/
|
|
|
protected function mprocAssertQuoteStillEditable(?array $po, string $label = '', ?array $row = null): void
|
|
|
{
|
|
|
+ $sid = 0;
|
|
|
+ if (is_array($row)) {
|
|
|
+ $sid = (int)($row['scydgy_id'] ?? $row['SCYDGY_ID'] ?? 0);
|
|
|
+ }
|
|
|
+ if ($sid === 0 && is_array($po)) {
|
|
|
+ $sid = (int)($po['scydgy_id'] ?? $po['SCYDGY_ID'] ?? 0);
|
|
|
+ }
|
|
|
+ // 手工询价无招标截止、不开标
|
|
|
+ if ($sid < 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
$this->mprocAssertQuoteNotDeadlineReached($po, $label);
|
|
|
$freshPo = is_array($po) ? $po : null;
|
|
|
if (is_array($po)) {
|
|
|
- $sid = (int)($po['scydgy_id'] ?? $po['SCYDGY_ID'] ?? 0);
|
|
|
if ($this->mprocIsValidScydgyRowId($sid)) {
|
|
|
try {
|
|
|
$got = Db::table('purchase_order')->where('scydgy_id', $sid)->find();
|
|
|
@@ -1695,21 +1813,31 @@ class Index extends Frontend
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 手机端左侧 Tab:draft|submitted|done
|
|
|
+ * 手机端左侧 Tab:
|
|
|
+ * 询价:rfq / rfq_submitted(手工单 scydgy_id<0,仅未提交/已提交)
|
|
|
+ * 报价:draft / submitted / done(协助下发)
|
|
|
*
|
|
|
* @param array<string, mixed> $row
|
|
|
* @param array<string, mixed>|null $po
|
|
|
*/
|
|
|
protected function mprocResolveListTabForRow(array $row, ?array $po, string $effectiveSn): string
|
|
|
{
|
|
|
- if (in_array($effectiveSn, ['已完成', '未通过', '已废弃'], true)) {
|
|
|
- return 'done';
|
|
|
+ $sid = (int)($row['scydgy_id'] ?? $row['SCYDGY_ID'] ?? 0);
|
|
|
+ // 手工询价:无招标截止;仅未提交/已提交(对应待报价/已报价)
|
|
|
+ if ($sid < 0) {
|
|
|
+ if ($effectiveSn === '已提交'
|
|
|
+ || in_array($effectiveSn, ['已完成', '未通过', '已废弃'], true)) {
|
|
|
+ return 'rfq_submitted';
|
|
|
+ }
|
|
|
+
|
|
|
+ return 'rfq';
|
|
|
}
|
|
|
- // 已开标或已过招标截止 →「已完成」(含已报价),角标「已截止」或中标结果
|
|
|
- if ($this->mprocIsBidOpenVerifiedForPoOrRow($po, $row)) {
|
|
|
+ if (in_array($effectiveSn, ['已完成', '未通过', '已废弃'], true)) {
|
|
|
return 'done';
|
|
|
}
|
|
|
- if ($this->mprocIsQuoteDeadlineReachedForPo($po)) {
|
|
|
+ if ($this->mprocIsBidOpenVerifiedForPoOrRow($po, $row)
|
|
|
+ || $this->mprocIsQuoteDeadlineReachedForPo($po)) {
|
|
|
+ // 已开标或已过招标截止 →「已完成」
|
|
|
return 'done';
|
|
|
}
|
|
|
if ($effectiveSn === '已提交') {
|
|
|
@@ -1719,6 +1847,57 @@ class Index extends Frontend
|
|
|
return 'draft';
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * @return string[]
|
|
|
+ */
|
|
|
+ protected function mprocListTabWhitelist(): array
|
|
|
+ {
|
|
|
+ return ['rfq', 'rfq_submitted', 'draft', 'submitted', 'done'];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 兼容旧地址 tab=rfq_done → 询价已提交
|
|
|
+ */
|
|
|
+ protected function mprocNormalizeListTab(string $tab): string
|
|
|
+ {
|
|
|
+ if ($tab === 'rfq_done') {
|
|
|
+ return 'rfq_submitted';
|
|
|
+ }
|
|
|
+ if (!in_array($tab, $this->mprocListTabWhitelist(), true)) {
|
|
|
+ return 'draft';
|
|
|
+ }
|
|
|
+
|
|
|
+ return $tab;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function mprocIsDoneListTab(string $tab): bool
|
|
|
+ {
|
|
|
+ return $tab === 'done';
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function mprocIsRfqListTab(string $tab): bool
|
|
|
+ {
|
|
|
+ return $tab === 'rfq' || $tab === 'rfq_submitted';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 复合 Tab → 状态维度:draft|submitted|done
|
|
|
+ */
|
|
|
+ protected function mprocStatusFromListTab(string $tab): string
|
|
|
+ {
|
|
|
+ if ($tab === 'rfq' || $tab === 'draft') {
|
|
|
+ return 'draft';
|
|
|
+ }
|
|
|
+ if ($tab === 'rfq_submitted' || $tab === 'submitted') {
|
|
|
+ return 'submitted';
|
|
|
+ }
|
|
|
+ if ($this->mprocIsDoneListTab($tab)) {
|
|
|
+ return 'done';
|
|
|
+ }
|
|
|
+
|
|
|
+ return 'draft';
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 同一订单号 + 供应商合并为一张卡片
|
|
|
*
|
|
|
@@ -1856,7 +2035,7 @@ class Index extends Frontend
|
|
|
if ($userWhere !== []) {
|
|
|
$query->where($userWhere);
|
|
|
}
|
|
|
- if (trim((string)$q) === '' && $tab === 'done' && $statusNameCol !== null) {
|
|
|
+ if (trim((string)$q) === '' && $this->mprocIsDoneListTab((string)$tab) && $statusNameCol !== null) {
|
|
|
$this->mprocSyncLegacyApprovedStatusNames($user, $statusNameCol);
|
|
|
}
|
|
|
$this->mprocApplySearchKeywordToDetailQuery($query, $q);
|
|
|
@@ -1944,12 +2123,24 @@ class Index extends Frontend
|
|
|
}
|
|
|
$listTab = $this->mprocResolveListTabForRow($row, $poRow, $effectiveSn);
|
|
|
$row['mproc_list_tab'] = $listTab;
|
|
|
- $row['mproc_deadline_reached'] = $this->mprocIsQuoteDeadlineReachedForPo($poRow) ? 1 : 0;
|
|
|
- $row['mproc_pick_result'] = $this->mprocResolvePickResultText($row, $poRow);
|
|
|
- $row['mproc_bid_open_verified'] = $this->mprocIsBidOpenVerifiedForPoOrRow($poRow, $row) ? 1 : 0;
|
|
|
+ $row['mproc_is_rfq'] = ((int)($row['scydgy_id'] ?? $row['SCYDGY_ID'] ?? 0) < 0) ? 1 : 0;
|
|
|
+ if ((int)$row['mproc_is_rfq'] === 1) {
|
|
|
+ // 手工询价不展示招标/交货截止,也不走开标截止逻辑
|
|
|
+ $row['mproc_bid_deadline'] = '';
|
|
|
+ $row['mproc_bid_deadline_display'] = '';
|
|
|
+ $row['mproc_delivery_deadline'] = '';
|
|
|
+ $row['mproc_delivery_deadline_display'] = '';
|
|
|
+ $row['mproc_deadline_reached'] = 0;
|
|
|
+ $row['mproc_bid_open_verified'] = 0;
|
|
|
+ $row['mproc_pick_result'] = '';
|
|
|
+ } else {
|
|
|
+ $row['mproc_deadline_reached'] = $this->mprocIsQuoteDeadlineReachedForPo($poRow) ? 1 : 0;
|
|
|
+ $row['mproc_pick_result'] = $this->mprocResolvePickResultText($row, $poRow);
|
|
|
+ $row['mproc_bid_open_verified'] = $this->mprocIsBidOpenVerifiedForPoOrRow($poRow, $row) ? 1 : 0;
|
|
|
+ }
|
|
|
if ($row['mproc_pick_result'] !== '') {
|
|
|
$row['mproc_done_label'] = $row['mproc_pick_result'];
|
|
|
- } elseif ($listTab === 'done' && (
|
|
|
+ } elseif ($this->mprocIsDoneListTab($listTab) && (
|
|
|
(int)$row['mproc_deadline_reached'] === 1
|
|
|
|| (int)$row['mproc_bid_open_verified'] === 1
|
|
|
)) {
|
|
|
@@ -1982,7 +2173,14 @@ class Index extends Frontend
|
|
|
$row['amount_missing'] = ($am === null || $am === '' || (is_string($am) && trim($am) === '')) ? 1 : 0;
|
|
|
$row['delivery_missing'] = ($dv === '' || preg_match('/^0000-00-00/i', $dv)) ? 1 : 0;
|
|
|
$this->mprocEnrichLeadDaysDisplay($row);
|
|
|
- $this->mprocEnrichOrderDeadlineDisplay($row);
|
|
|
+ if ((int)$row['mproc_is_rfq'] === 1) {
|
|
|
+ $row['mproc_bid_deadline'] = '';
|
|
|
+ $row['mproc_bid_deadline_display'] = '';
|
|
|
+ $row['mproc_delivery_deadline'] = '';
|
|
|
+ $row['mproc_delivery_deadline_display'] = '';
|
|
|
+ } else {
|
|
|
+ $this->mprocEnrichOrderDeadlineDisplay($row);
|
|
|
+ }
|
|
|
$row['mproc_fill_hint'] = '';
|
|
|
$row['mproc_this_quantity_display'] = $this->mprocResolveDisplayThisQuantity($row);
|
|
|
$row['mproc_remark'] = $this->mprocResolveDetailRemark($row);
|
|
|
@@ -1999,13 +2197,13 @@ class Index extends Frontend
|
|
|
return is_array($r) && trim((string)($r['mproc_list_tab'] ?? '')) === $tab;
|
|
|
}));
|
|
|
// 「已完成」仅保留近三个月(按招标截止日,缺省则交货截止/创建时间)
|
|
|
- if ($tab === 'done') {
|
|
|
+ if ($this->mprocIsDoneListTab((string)$tab)) {
|
|
|
$rows = array_values(array_filter($rows, function ($r) {
|
|
|
return is_array($r) && $this->mprocIsWithinRecentMonths($r, 3);
|
|
|
}));
|
|
|
}
|
|
|
// 按招标截止日期排序:未提交/已提交截止近的在前;已完成最近截止的在前
|
|
|
- $rows = $this->mprocSortRowsByBidDeadline($rows, $tab === 'done' ? 'desc' : 'asc');
|
|
|
+ $rows = $this->mprocSortRowsByBidDeadline($rows, $this->mprocIsDoneListTab((string)$tab) ? 'desc' : 'asc');
|
|
|
|
|
|
$groups = $this->mprocGroupRowsByOrder($rows);
|
|
|
|
|
|
@@ -2282,7 +2480,7 @@ class Index extends Frontend
|
|
|
$row['mproc_bid_open_verified'] = $this->mprocIsBidOpenVerifiedForPoOrRow(is_array($poRow) ? $poRow : null, $row) ? 1 : 0;
|
|
|
if ($row['mproc_pick_result'] !== '') {
|
|
|
$row['mproc_done_label'] = $row['mproc_pick_result'];
|
|
|
- } elseif ($listTab === 'done' && (
|
|
|
+ } elseif ($this->mprocIsDoneListTab($listTab) && (
|
|
|
(int)$row['mproc_deadline_reached'] === 1
|
|
|
|| (int)$row['mproc_bid_open_verified'] === 1
|
|
|
)) {
|
|
|
@@ -2512,6 +2710,12 @@ class Index extends Frontend
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
+ // 管理员进外协入库评分,不进供应商报价列表
|
|
|
+ if (!empty($user['is_admin'])) {
|
|
|
+ $this->redirect(url('index/index/inboundscore', '', '', true));
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
$user = $this->mprocSyncSessionCustomerUser($user);
|
|
|
|
|
|
$tabParamRaw = $this->request->get('tab', null);
|
|
|
@@ -2525,10 +2729,7 @@ class Index extends Frontend
|
|
|
if (!in_array($mainTab, ['orders', 'me'], true)) {
|
|
|
$mainTab = 'orders';
|
|
|
}
|
|
|
- $tab = $tabParam === 'me' ? 'draft' : $tabParam;
|
|
|
- if (!in_array($tab, ['draft', 'submitted', 'done'], true)) {
|
|
|
- $tab = 'draft';
|
|
|
- }
|
|
|
+ $tab = $tabParam === 'me' ? 'draft' : $this->mprocNormalizeListTab($tabParam);
|
|
|
$q = trim((string)$this->request->get('q', ''));
|
|
|
|
|
|
$mprocFocusEid = 0;
|
|
|
@@ -2561,6 +2762,8 @@ class Index extends Frontend
|
|
|
|
|
|
$this->view->assign('mprocMainTab', $mainTab);
|
|
|
$this->view->assign('mprocTab', $tab);
|
|
|
+ $this->view->assign('mprocIsRfqTab', $this->mprocIsRfqListTab($tab) ? 1 : 0);
|
|
|
+ $this->view->assign('mprocStatusTab', $this->mprocStatusFromListTab($tab));
|
|
|
$this->view->assign('mprocSearchQ', $q);
|
|
|
$this->view->assign('mprocProfile', $profile);
|
|
|
$this->view->assign('mprocIsAdmin', !empty($user['is_admin']) ? 1 : 0);
|
|
|
@@ -2607,10 +2810,7 @@ class Index extends Frontend
|
|
|
if (!in_array($mainTab, ['orders', 'me'], true)) {
|
|
|
$mainTab = 'orders';
|
|
|
}
|
|
|
- $tab = $tabParam === 'me' ? 'draft' : $tabParam;
|
|
|
- if (!in_array($tab, ['draft', 'submitted', 'done'], true)) {
|
|
|
- $tab = 'draft';
|
|
|
- }
|
|
|
+ $tab = $tabParam === 'me' ? 'draft' : $this->mprocNormalizeListTab($tabParam);
|
|
|
$q = trim((string)$this->request->request('q', ''));
|
|
|
|
|
|
if ($mainTab === 'me') {
|
|
|
@@ -2658,8 +2858,9 @@ class Index extends Frontend
|
|
|
public function login()
|
|
|
{
|
|
|
$redirect = $this->mprocSanitizeRedirectUrl($this->request->get('redirect', ''));
|
|
|
- if ($this->mprocGetUser()) {
|
|
|
- $this->redirect($this->mprocBuildAfterLoginIndexUrl($redirect));
|
|
|
+ $user = $this->mprocGetUser();
|
|
|
+ if ($user) {
|
|
|
+ $this->redirect($this->mprocBuildAfterLoginHomeUrl($user, $redirect));
|
|
|
}
|
|
|
if ($redirect !== '') {
|
|
|
Session::set('mproc_intended_url', $redirect);
|
|
|
@@ -2788,7 +2989,7 @@ class Index extends Frontend
|
|
|
}
|
|
|
$token = $this->mprocTouchLoginState($user, $token !== '' ? $token : $this->mprocPackSignedAuthToken($user));
|
|
|
$redirect = $this->mprocSanitizeRedirectUrl($this->request->post('redirect', ''));
|
|
|
- $jump = $this->mprocBuildAfterLoginIndexUrl($redirect);
|
|
|
+ $jump = $this->mprocBuildAfterLoginHomeUrl($user, $redirect);
|
|
|
$this->success('ok', $jump, [
|
|
|
'mproc_token' => $token,
|
|
|
'keep_hours' => $this->mprocKeepHours(),
|
|
|
@@ -2823,7 +3024,7 @@ class Index extends Frontend
|
|
|
$row = null;
|
|
|
try {
|
|
|
$row = Db::name('admin')
|
|
|
- ->field('id,username,password,salt,status,loginfailure,updatetime')
|
|
|
+ ->field('id,username,password,salt,status,loginfailure,updatetime,mobile')
|
|
|
->where('username', $username)
|
|
|
->find();
|
|
|
} catch (\Throwable $e) {
|
|
|
@@ -2871,6 +3072,7 @@ class Index extends Frontend
|
|
|
'company_name' => '',
|
|
|
'username' => $username,
|
|
|
'customer_user_id' => 0,
|
|
|
+ 'admin_id' => $id,
|
|
|
'login_type' => 'pwd',
|
|
|
'is_admin' => 1,
|
|
|
]);
|
|
|
@@ -2889,11 +3091,15 @@ class Index extends Frontend
|
|
|
if (in_array($sn, ['已完成', '未通过', '已废弃'], true)) {
|
|
|
return false;
|
|
|
}
|
|
|
- if ($this->mprocIsQuoteDeadlineReachedForPo($po)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- if ($this->mprocIsBidOpenVerifiedForPoOrRow($po, $row)) {
|
|
|
- return false;
|
|
|
+ $sid = (int)($row['scydgy_id'] ?? $row['SCYDGY_ID'] ?? 0);
|
|
|
+ // 手工询价无招标截止/开标限制
|
|
|
+ if ($sid >= 0) {
|
|
|
+ if ($this->mprocIsQuoteDeadlineReachedForPo($po)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if ($this->mprocIsBidOpenVerifiedForPoOrRow($po, $row)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
$uCo = trim((string)($user['company_name'] ?? ''));
|
|
|
if ($uCo === '') {
|
|
|
@@ -3108,18 +3314,26 @@ class Index extends Frontend
|
|
|
$hasAmt = $amountRaw !== '';
|
|
|
$hasLead = $leadRaw !== '';
|
|
|
$hasDel = $deliveryRaw !== '';
|
|
|
- $filledCount = ($hasAmt ? 1 : 0) + ($hasLead ? 1 : 0) + ($hasDel ? 1 : 0);
|
|
|
- if ($filledCount === 0) {
|
|
|
- throw new \InvalidArgumentException($label . '请填写单价、工期、交期');
|
|
|
- }
|
|
|
- if ($filledCount < 3) {
|
|
|
+ $isManualRfq = ($sid < 0);
|
|
|
+ if ($isManualRfq) {
|
|
|
+ // 手工询价:只需填写单价
|
|
|
if (!$hasAmt) {
|
|
|
throw new \InvalidArgumentException($label . '请填写单价');
|
|
|
}
|
|
|
- if (!$hasLead) {
|
|
|
- throw new \InvalidArgumentException($label . '请填写工期');
|
|
|
+ } else {
|
|
|
+ $filledCount = ($hasAmt ? 1 : 0) + ($hasLead ? 1 : 0) + ($hasDel ? 1 : 0);
|
|
|
+ if ($filledCount === 0) {
|
|
|
+ throw new \InvalidArgumentException($label . '请填写单价、工期、交期');
|
|
|
+ }
|
|
|
+ if ($filledCount < 3) {
|
|
|
+ if (!$hasAmt) {
|
|
|
+ throw new \InvalidArgumentException($label . '请填写单价');
|
|
|
+ }
|
|
|
+ if (!$hasLead) {
|
|
|
+ throw new \InvalidArgumentException($label . '请填写工期');
|
|
|
+ }
|
|
|
+ throw new \InvalidArgumentException($label . '请填写交期');
|
|
|
}
|
|
|
- throw new \InvalidArgumentException($label . '请填写交期');
|
|
|
}
|
|
|
|
|
|
$leadDays = null;
|
|
|
@@ -3186,8 +3400,18 @@ class Index extends Frontend
|
|
|
$data['lead_days'] = $leadDays;
|
|
|
|
|
|
$dcCol = $this->mprocResolveProcuremenColumn(['delivery_createtime', 'deliverycreatetime']);
|
|
|
- if ($dcCol !== null && array_key_exists('delivery', $data) && $data['delivery'] !== null && $data['delivery'] !== '') {
|
|
|
- $data[$dcCol] = date('Y-m-d H:i:s');
|
|
|
+ if ($dcCol !== null) {
|
|
|
+ $shouldStampQuoteTime = false;
|
|
|
+ if (array_key_exists('delivery', $data) && $data['delivery'] !== null && $data['delivery'] !== '') {
|
|
|
+ $shouldStampQuoteTime = true;
|
|
|
+ }
|
|
|
+ // 手工询价只填单价:有单价也记报价时间
|
|
|
+ if ($isManualRfq && array_key_exists('amount', $data) && $data['amount'] !== null && $data['amount'] !== '') {
|
|
|
+ $shouldStampQuoteTime = true;
|
|
|
+ }
|
|
|
+ if ($shouldStampQuoteTime) {
|
|
|
+ $data[$dcCol] = date('Y-m-d H:i:s');
|
|
|
+ }
|
|
|
}
|
|
|
$upCol = $this->mprocResolveProcuremenColumn(['updatetime']);
|
|
|
if ($upCol !== null) {
|
|
|
@@ -3495,7 +3719,10 @@ class Index extends Frontend
|
|
|
if ($token === null || $token === '') {
|
|
|
$token = Cookie::get('mproc_token');
|
|
|
}
|
|
|
- $this->mprocClearLogin(preg_replace('/[^a-f0-9]/i', '', (string)$token));
|
|
|
+ if ($token === null || $token === '') {
|
|
|
+ $token = Cookie::get('mproc_remember');
|
|
|
+ }
|
|
|
+ $this->mprocClearLogin((string)$token);
|
|
|
$this->success('密码已修改,请重新登录', url('index/index/login'));
|
|
|
}
|
|
|
|
|
|
@@ -3508,9 +3735,11 @@ class Index extends Frontend
|
|
|
if ($token === null || $token === '') {
|
|
|
$token = Cookie::get('mproc_token');
|
|
|
}
|
|
|
- if ($token) {
|
|
|
- $this->mprocClearLogin(preg_replace('/[^a-f0-9]/i', '', (string)$token));
|
|
|
+ if ($token === null || $token === '') {
|
|
|
+ $token = Cookie::get('mproc_remember');
|
|
|
}
|
|
|
+ // 无论有无 token 都清 Cookie/Session,避免「记住登录」把用户又带回来
|
|
|
+ $this->mprocClearLogin((string)$token);
|
|
|
$this->redirect(url('index/index/login'));
|
|
|
}
|
|
|
|
|
|
@@ -3560,4 +3789,506 @@ class Index extends Frontend
|
|
|
}
|
|
|
Log::record('smsbao 发送成功 phone=' . $phone . ' content=' . $content, 'info');
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 外协入库评分页(仅管理员)
|
|
|
+ */
|
|
|
+ public function inboundscore()
|
|
|
+ {
|
|
|
+ $user = $this->mprocGetUser();
|
|
|
+ if (!$user) {
|
|
|
+ $uri = isset($_SERVER['REQUEST_URI']) ? (string)$_SERVER['REQUEST_URI'] : '';
|
|
|
+ $safe = $this->mprocSanitizeRedirectUrl($uri);
|
|
|
+ if ($safe !== '') {
|
|
|
+ Session::set('mproc_intended_url', $safe);
|
|
|
+ }
|
|
|
+ $this->redirect($this->mprocBuildLoginUrl($safe));
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (empty($user['is_admin'])) {
|
|
|
+ $this->redirect(url('index/index/index', '', '', true));
|
|
|
+
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $this->mprocEnsureInboundScoreTable();
|
|
|
+ $q = trim((string)$this->request->get('q', ''));
|
|
|
+ $profile = $this->mprocProfileForUser($user);
|
|
|
+ $this->view->assign('mprocSearchQ', $q);
|
|
|
+ $this->view->assign('mprocProfile', $profile);
|
|
|
+ $this->view->assign('mprocBootstrapToken', trim((string)($user['token'] ?? '')));
|
|
|
+ $this->view->assign('mprocBootstrapKeepHours', $this->mprocKeepHours());
|
|
|
+ $this->view->assign('rows', $this->mprocLoadInboundScoreRows('pending', $q, (int)($user['admin_id'] ?? 0)));
|
|
|
+
|
|
|
+ return $this->view->fetch();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 外协入库评分列表 JSON(仅管理员;tab=pending|pass|fail)
|
|
|
+ * pass/fail 仅返回当前账号操作过的记录
|
|
|
+ */
|
|
|
+ public function inboundscorelist()
|
|
|
+ {
|
|
|
+ $user = $this->mprocRequireAdminUser();
|
|
|
+ $this->mprocEnsureInboundScoreTable();
|
|
|
+ $q = trim((string)$this->request->request('q', ''));
|
|
|
+ $tab = trim((string)$this->request->request('tab', 'pending'));
|
|
|
+ if (!in_array($tab, ['pending', 'pass', 'fail'], true)) {
|
|
|
+ $tab = 'pending';
|
|
|
+ }
|
|
|
+ $adminId = (int)($user['admin_id'] ?? 0);
|
|
|
+ $rows = $this->mprocLoadInboundScoreRows($tab, $q, $adminId);
|
|
|
+ $this->success('ok', '', [
|
|
|
+ 'tab' => $tab,
|
|
|
+ 'q' => $q,
|
|
|
+ 'rows' => $rows,
|
|
|
+ 'count' => count($rows),
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存外协入库评分(仅管理员,POST:ccydh 或 scydgy_id、result=合格|不合格)
|
|
|
+ * 同一订单号下多道工序一并评分、一并完结(与历史存证一单一行一致)
|
|
|
+ */
|
|
|
+ public function inboundscoresave()
|
|
|
+ {
|
|
|
+ $user = $this->mprocRequireAdminUser();
|
|
|
+ if (!$this->request->isPost()) {
|
|
|
+ $this->error('请使用 POST');
|
|
|
+ }
|
|
|
+ $this->mprocEnsureInboundScoreTable();
|
|
|
+ $ccydh = trim((string)$this->request->post('ccydh', ''));
|
|
|
+ $sid = (int)$this->request->post('scydgy_id', 0);
|
|
|
+ $result = trim((string)$this->request->post('result', ''));
|
|
|
+ if ($result !== '合格' && $result !== '不合格') {
|
|
|
+ $this->error('请选择合格或不合格');
|
|
|
+ }
|
|
|
+ $approvedVals = ProcuremenStatus::wflowApprovedValues();
|
|
|
+ $approvedIn = implode(',', array_map(static function ($v) {
|
|
|
+ return "'" . str_replace("'", "''", (string)$v) . "'";
|
|
|
+ }, $approvedVals));
|
|
|
+ try {
|
|
|
+ $q = Db::table('purchase_order')
|
|
|
+ ->where('scydgy_id', '>', 0)
|
|
|
+ ->whereRaw('(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')')
|
|
|
+ ->whereRaw("pick_time IS NOT NULL AND CAST(pick_time AS CHAR) NOT LIKE '0000-00-00%' AND TRIM(CAST(pick_time AS CHAR)) <> ''")
|
|
|
+ ->whereRaw("pick_company_name IS NOT NULL AND TRIM(pick_company_name) <> ''")
|
|
|
+ ->whereRaw('TRIM(CAST(wflow_status AS CHAR)) IN (' . $approvedIn . ')')
|
|
|
+ ->field('id,scydgy_id,CCYDH,CYJMC,CGYMC,pick_company_name,pick_time,wflow_status,status');
|
|
|
+ if ($ccydh !== '') {
|
|
|
+ $q->where('CCYDH', $ccydh);
|
|
|
+ } elseif ($sid > 0) {
|
|
|
+ $one = Db::table('purchase_order')->where('scydgy_id', $sid)->field('CCYDH')->find();
|
|
|
+ $ccydh = is_array($one) ? trim((string)($one['CCYDH'] ?? '')) : '';
|
|
|
+ if ($ccydh === '') {
|
|
|
+ $this->error('缺少订单号');
|
|
|
+ }
|
|
|
+ $q->where('CCYDH', $ccydh);
|
|
|
+ } else {
|
|
|
+ $this->error('缺少订单号');
|
|
|
+ }
|
|
|
+ $poRows = $q->order('id', 'asc')->select();
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ $poRows = [];
|
|
|
+ }
|
|
|
+ if (!is_array($poRows) || $poRows === []) {
|
|
|
+ $this->error('未找到可评分的已审核订单');
|
|
|
+ }
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ $adminId = (int)($user['admin_id'] ?? 0);
|
|
|
+ // 操作日志记昵称,不用登录账号
|
|
|
+ $adminName = '';
|
|
|
+ if ($adminId > 0) {
|
|
|
+ try {
|
|
|
+ $adminRow = Db::name('admin')->where('id', $adminId)->field('nickname,username')->find();
|
|
|
+ if (is_array($adminRow)) {
|
|
|
+ $adminName = trim((string)($adminRow['nickname'] ?? ''));
|
|
|
+ if ($adminName === '') {
|
|
|
+ $adminName = trim((string)($adminRow['username'] ?? ''));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($adminName === '') {
|
|
|
+ $adminName = trim((string)($user['username'] ?? ''));
|
|
|
+ }
|
|
|
+ if ($adminName === '') {
|
|
|
+ $adminName = '管理员';
|
|
|
+ }
|
|
|
+ $saved = 0;
|
|
|
+ $firstSid = 0;
|
|
|
+ $firstPoId = 0;
|
|
|
+ try {
|
|
|
+ Db::startTrans();
|
|
|
+ foreach ($poRows as $po) {
|
|
|
+ if (!is_array($po)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $rowSid = (int)($po['scydgy_id'] ?? 0);
|
|
|
+ if ($rowSid <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ($firstSid <= 0) {
|
|
|
+ $firstSid = $rowSid;
|
|
|
+ $firstPoId = (int)($po['id'] ?? 0);
|
|
|
+ }
|
|
|
+ $g = trim((string)($po['CGYMC'] ?? ''));
|
|
|
+ $data = [
|
|
|
+ 'scydgy_id' => $rowSid,
|
|
|
+ 'purchase_order_id' => (int)($po['id'] ?? 0),
|
|
|
+ 'ccydh' => trim((string)($po['CCYDH'] ?? $ccydh)),
|
|
|
+ 'cyjmc' => trim((string)($po['CYJMC'] ?? '')),
|
|
|
+ 'cgymc' => $g,
|
|
|
+ 'company_name' => trim((string)($po['pick_company_name'] ?? '')),
|
|
|
+ 'result' => $result,
|
|
|
+ 'admin_id' => $adminId,
|
|
|
+ 'admin_name' => $adminName,
|
|
|
+ 'updatetime' => $now,
|
|
|
+ ];
|
|
|
+ $exist = Db::table('purchase_order_inbound_score')->where('scydgy_id', $rowSid)->find();
|
|
|
+ if (is_array($exist) && $exist !== []) {
|
|
|
+ Db::table('purchase_order_inbound_score')->where('scydgy_id', $rowSid)->update($data);
|
|
|
+ } else {
|
|
|
+ $data['createtime'] = $now;
|
|
|
+ Db::table('purchase_order_inbound_score')->insert($data);
|
|
|
+ }
|
|
|
+ Db::table('purchase_order')->where('scydgy_id', $rowSid)->update([
|
|
|
+ 'status' => ProcuremenStatus::PO_COMPLETED,
|
|
|
+ ]);
|
|
|
+ $saved++;
|
|
|
+ }
|
|
|
+ if ($saved < 1) {
|
|
|
+ throw new \RuntimeException('没有可保存的工序');
|
|
|
+ }
|
|
|
+ Db::commit();
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ try {
|
|
|
+ Db::rollback();
|
|
|
+ } catch (\Throwable $e2) {
|
|
|
+ }
|
|
|
+ Log::record('inboundscoresave fail: ' . $e->getMessage(), 'error');
|
|
|
+ $this->error('保存失败,请稍后重试');
|
|
|
+ }
|
|
|
+ \app\common\library\ProcuremenOperLog::write(
|
|
|
+ $firstSid,
|
|
|
+ 'inbound_score',
|
|
|
+ '入库评分:' . $result,
|
|
|
+ $firstPoId > 0 ? $firstPoId : null,
|
|
|
+ [$adminId, $adminName]
|
|
|
+ );
|
|
|
+ // 按入库合格/不合格重算该供应商当月质量得分
|
|
|
+ $companyName = '';
|
|
|
+ foreach ($poRows as $po) {
|
|
|
+ if (!is_array($po)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $companyName = trim((string)($po['pick_company_name'] ?? ''));
|
|
|
+ if ($companyName !== '') {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $scoreYm = date('Y-m', strtotime($now) ?: time());
|
|
|
+ if ($companyName !== '') {
|
|
|
+ try {
|
|
|
+ \app\common\library\ProcuremenSupplierScore::syncQualityScoreFromInbound($scoreYm, $companyName);
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ Log::record('inboundscoresave quality sync: ' . $e->getMessage(), 'error');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $this->success('操作成功', '', [
|
|
|
+ 'ccydh' => $ccydh,
|
|
|
+ 'result' => $result,
|
|
|
+ 'count' => $saved,
|
|
|
+ 'status' => '已完结',
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @return array<string, mixed>
|
|
|
+ */
|
|
|
+ protected function mprocRequireAdminUser(): array
|
|
|
+ {
|
|
|
+ $user = $this->mprocGetUser();
|
|
|
+ if (!$user) {
|
|
|
+ $this->error('请先登录', url('index/index/login'));
|
|
|
+ }
|
|
|
+ if (empty($user['is_admin'])) {
|
|
|
+ $this->error('仅系统管理员可操作');
|
|
|
+ }
|
|
|
+
|
|
|
+ return $user;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function mprocEnsureInboundScoreTable(): void
|
|
|
+ {
|
|
|
+ static $ok = false;
|
|
|
+ if ($ok) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Db::query('SELECT 1 FROM `purchase_order_inbound_score` LIMIT 1');
|
|
|
+ $ok = true;
|
|
|
+
|
|
|
+ return;
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ Db::execute("CREATE TABLE IF NOT EXISTS `purchase_order_inbound_score` (
|
|
|
+ `id` int unsigned NOT NULL AUTO_INCREMENT,
|
|
|
+ `scydgy_id` int NOT NULL DEFAULT 0 COMMENT '工序ID',
|
|
|
+ `purchase_order_id` int unsigned NOT NULL DEFAULT 0 COMMENT 'purchase_order.id',
|
|
|
+ `ccydh` varchar(64) NOT NULL DEFAULT '' COMMENT '订单号',
|
|
|
+ `cyjmc` varchar(255) NOT NULL DEFAULT '' COMMENT '印件名称',
|
|
|
+ `cgymc` varchar(255) NOT NULL DEFAULT '' COMMENT '工序名称',
|
|
|
+ `company_name` varchar(255) NOT NULL DEFAULT '' COMMENT '中标供应商',
|
|
|
+ `result` varchar(16) NOT NULL DEFAULT '' COMMENT '合格/不合格',
|
|
|
+ `admin_id` int unsigned NOT NULL DEFAULT 0,
|
|
|
+ `admin_name` varchar(64) NOT NULL DEFAULT '',
|
|
|
+ `remark` varchar(500) NOT NULL DEFAULT '',
|
|
|
+ `createtime` datetime DEFAULT NULL,
|
|
|
+ `updatetime` datetime DEFAULT NULL,
|
|
|
+ PRIMARY KEY (`id`),
|
|
|
+ UNIQUE KEY `uk_scydgy_id` (`scydgy_id`),
|
|
|
+ KEY `idx_ccydh` (`ccydh`),
|
|
|
+ KEY `idx_result` (`result`),
|
|
|
+ KEY `idx_updatetime` (`updatetime`)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='外协入库评分'");
|
|
|
+ $ok = true;
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ Log::record('mprocEnsureInboundScoreTable: ' . $e->getMessage(), 'error');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 外协入库评分列表:按订单号合并(一单一行,工序顿号合并)
|
|
|
+ * tab=pending 待评分;pass/fail 仅当前管理员操作过的合格/不合格
|
|
|
+ *
|
|
|
+ * @return array<int, array<string, mixed>>
|
|
|
+ */
|
|
|
+ protected function mprocLoadInboundScoreRows(string $tab, string $keyword = '', int $adminId = 0): array
|
|
|
+ {
|
|
|
+ $this->mprocEnsureInboundScoreTable();
|
|
|
+ $keyword = trim($keyword);
|
|
|
+ if (!in_array($tab, ['pending', 'pass', 'fail'], true)) {
|
|
|
+ $tab = 'pending';
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ $approvedVals = ProcuremenStatus::wflowApprovedValues();
|
|
|
+ $approvedIn = implode(',', array_map(static function ($v) {
|
|
|
+ return "'" . str_replace("'", "''", (string)$v) . "'";
|
|
|
+ }, $approvedVals));
|
|
|
+ $poRows = Db::table('purchase_order')
|
|
|
+ ->where('scydgy_id', '>', 0)
|
|
|
+ ->whereRaw('(mod_rq IS NULL OR TRIM(CAST(mod_rq AS CHAR(32))) = \'\' OR TRIM(CAST(mod_rq AS CHAR(32))) LIKE \'0000-00-00%\')')
|
|
|
+ ->whereRaw("pick_time IS NOT NULL AND CAST(pick_time AS CHAR) NOT LIKE '0000-00-00%' AND TRIM(CAST(pick_time AS CHAR)) <> ''")
|
|
|
+ ->whereRaw("pick_company_name IS NOT NULL AND TRIM(pick_company_name) <> ''")
|
|
|
+ ->whereRaw('TRIM(CAST(wflow_status AS CHAR)) IN (' . $approvedIn . ')')
|
|
|
+ ->field('id,scydgy_id,CCYDH,CYJMC,CGYMC,CCLBMMC,CDW,This_quantity,pick_company_name,pick_time,wflow_status,status')
|
|
|
+ ->order('pick_time', 'desc')
|
|
|
+ ->order('id', 'asc')
|
|
|
+ ->limit(800)
|
|
|
+ ->select();
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ Log::record('mprocLoadInboundScoreRows: ' . $e->getMessage(), 'error');
|
|
|
+
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ if (!is_array($poRows) || $poRows === []) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $sids = [];
|
|
|
+ foreach ($poRows as $po) {
|
|
|
+ if (!is_array($po)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $sid = (int)($po['scydgy_id'] ?? 0);
|
|
|
+ if ($sid > 0) {
|
|
|
+ $sids[$sid] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $scoreMap = [];
|
|
|
+ if ($sids !== []) {
|
|
|
+ try {
|
|
|
+ $scores = Db::table('purchase_order_inbound_score')
|
|
|
+ ->where('scydgy_id', 'in', array_keys($sids))
|
|
|
+ ->field('scydgy_id,result,admin_id,admin_name,updatetime,createtime')
|
|
|
+ ->select();
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ $scores = [];
|
|
|
+ }
|
|
|
+ if (is_array($scores)) {
|
|
|
+ foreach ($scores as $sc) {
|
|
|
+ if (!is_array($sc)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $sid = (int)($sc['scydgy_id'] ?? 0);
|
|
|
+ if ($sid > 0) {
|
|
|
+ $scoreMap[$sid] = $sc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** @var array<string, array<string, mixed>> $groups */
|
|
|
+ $groups = [];
|
|
|
+ foreach ($poRows as $po) {
|
|
|
+ if (!is_array($po)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $sid = (int)($po['scydgy_id'] ?? 0);
|
|
|
+ $ccydh = trim((string)($po['CCYDH'] ?? ''));
|
|
|
+ if ($sid <= 0 || $ccydh === '') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!isset($groups[$ccydh])) {
|
|
|
+ $pickRaw = trim((string)($po['pick_time'] ?? ''));
|
|
|
+ $pickDisp = $pickRaw !== '' ? \app\common\library\ProcuremenTime::formatDisplayDateTime($pickRaw) : '';
|
|
|
+ $groups[$ccydh] = [
|
|
|
+ 'CCYDH' => $ccydh,
|
|
|
+ 'scydgy_id' => $sid,
|
|
|
+ 'scydgy_ids' => [],
|
|
|
+ 'CYJMC' => trim((string)($po['CYJMC'] ?? '')),
|
|
|
+ 'CCLBMMC' => trim((string)($po['CCLBMMC'] ?? '')),
|
|
|
+ 'CGYMC_list' => [],
|
|
|
+ 'pick_company_name' => trim((string)($po['pick_company_name'] ?? '')),
|
|
|
+ 'pick_time' => $pickDisp !== '' ? $pickDisp : $pickRaw,
|
|
|
+ 'pick_time_raw' => $pickRaw,
|
|
|
+ 'process_count' => 0,
|
|
|
+ 'results' => [],
|
|
|
+ 'score_admin_ids' => [],
|
|
|
+ 'score_time_raw' => '',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ $g = &$groups[$ccydh];
|
|
|
+ $g['scydgy_ids'][] = $sid;
|
|
|
+ $g['process_count']++;
|
|
|
+ if ($g['scydgy_id'] <= 0) {
|
|
|
+ $g['scydgy_id'] = $sid;
|
|
|
+ }
|
|
|
+ if ($g['CYJMC'] === '') {
|
|
|
+ $g['CYJMC'] = trim((string)($po['CYJMC'] ?? ''));
|
|
|
+ }
|
|
|
+ if ($g['CCLBMMC'] === '') {
|
|
|
+ $g['CCLBMMC'] = trim((string)($po['CCLBMMC'] ?? ''));
|
|
|
+ }
|
|
|
+ if ($g['pick_company_name'] === '') {
|
|
|
+ $g['pick_company_name'] = trim((string)($po['pick_company_name'] ?? ''));
|
|
|
+ }
|
|
|
+ $pt = trim((string)($po['pick_time'] ?? ''));
|
|
|
+ if ($pt !== '' && ($g['pick_time_raw'] === '' || strcmp($pt, $g['pick_time_raw']) > 0)) {
|
|
|
+ $g['pick_time_raw'] = $pt;
|
|
|
+ $disp = \app\common\library\ProcuremenTime::formatDisplayDateTime($pt);
|
|
|
+ $g['pick_time'] = $disp !== '' ? $disp : $pt;
|
|
|
+ }
|
|
|
+ $gymc = trim((string)($po['CGYMC'] ?? ''));
|
|
|
+ if ($gymc !== '' && !in_array($gymc, $g['CGYMC_list'], true)) {
|
|
|
+ $g['CGYMC_list'][] = $gymc;
|
|
|
+ }
|
|
|
+ $sc = $scoreMap[$sid] ?? null;
|
|
|
+ $res = is_array($sc) ? trim((string)($sc['result'] ?? '')) : '';
|
|
|
+ $g['results'][] = $res;
|
|
|
+ if (is_array($sc) && $res !== '') {
|
|
|
+ $aid = (int)($sc['admin_id'] ?? 0);
|
|
|
+ if ($aid > 0) {
|
|
|
+ $g['score_admin_ids'][$aid] = true;
|
|
|
+ }
|
|
|
+ $st = trim((string)($sc['updatetime'] ?? ''));
|
|
|
+ if ($st === '') {
|
|
|
+ $st = trim((string)($sc['createtime'] ?? ''));
|
|
|
+ }
|
|
|
+ if ($st !== '' && ($g['score_time_raw'] === '' || strcmp($st, $g['score_time_raw']) > 0)) {
|
|
|
+ $g['score_time_raw'] = $st;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ unset($g);
|
|
|
+ }
|
|
|
+
|
|
|
+ $out = [];
|
|
|
+ foreach ($groups as $ccydh => $g) {
|
|
|
+ $gymcList = is_array($g['CGYMC_list'] ?? null) ? $g['CGYMC_list'] : [];
|
|
|
+ $company = (string)($g['pick_company_name'] ?? '');
|
|
|
+ $cyjmc = (string)($g['CYJMC'] ?? '');
|
|
|
+ if ($keyword !== '') {
|
|
|
+ $blob = $ccydh . ' ' . $cyjmc . ' ' . implode('、', $gymcList) . ' ' . $company;
|
|
|
+ if (mb_stripos($blob, $keyword) === false) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $results = is_array($g['results'] ?? null) ? $g['results'] : [];
|
|
|
+ $uniq = [];
|
|
|
+ $allScored = true;
|
|
|
+ foreach ($results as $r) {
|
|
|
+ $r = trim((string)$r);
|
|
|
+ if ($r === '') {
|
|
|
+ $allScored = false;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $uniq[$r] = true;
|
|
|
+ }
|
|
|
+ $orderResult = '';
|
|
|
+ if ($allScored && count($uniq) === 1) {
|
|
|
+ $keys = array_keys($uniq);
|
|
|
+ $orderResult = (string)($keys[0] ?? '');
|
|
|
+ } elseif ($allScored && count($uniq) > 1) {
|
|
|
+ $orderResult = '';
|
|
|
+ }
|
|
|
+ if ($tab === 'pending' && $orderResult !== '') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ($tab === 'pass' && $orderResult !== '合格') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ($tab === 'fail' && $orderResult !== '不合格') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 合格/不合格:仅当前账号操作过的
|
|
|
+ if ($tab === 'pass' || $tab === 'fail') {
|
|
|
+ if ($adminId <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $adminIds = is_array($g['score_admin_ids'] ?? null) ? $g['score_admin_ids'] : [];
|
|
|
+ if (empty($adminIds[$adminId])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $scoreTimeRaw = trim((string)($g['score_time_raw'] ?? ''));
|
|
|
+ $scoreTime = $scoreTimeRaw !== ''
|
|
|
+ ? \app\common\library\ProcuremenTime::formatDisplayDateTime($scoreTimeRaw)
|
|
|
+ : '';
|
|
|
+ $out[] = [
|
|
|
+ 'CCYDH' => $ccydh,
|
|
|
+ 'scydgy_id' => (int)($g['scydgy_id'] ?? 0),
|
|
|
+ 'scydgy_ids' => array_values(array_unique(array_map('intval', $g['scydgy_ids'] ?? []))),
|
|
|
+ 'CYJMC' => $cyjmc,
|
|
|
+ 'CGYMC' => $gymcList !== [] ? implode('、', $gymcList) : '',
|
|
|
+ 'CCLBMMC' => (string)($g['CCLBMMC'] ?? ''),
|
|
|
+ 'pick_company_name' => $company,
|
|
|
+ 'pick_time' => (string)($g['pick_time'] ?? ''),
|
|
|
+ 'score_time' => $scoreTime !== '' ? $scoreTime : $scoreTimeRaw,
|
|
|
+ 'score_time_raw' => $scoreTimeRaw,
|
|
|
+ 'process_count' => (int)($g['process_count'] ?? 0),
|
|
|
+ 'result' => $orderResult,
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ usort($out, static function ($a, $b) use ($tab) {
|
|
|
+ if ($tab === 'pass' || $tab === 'fail') {
|
|
|
+ $ta = (string)($a['score_time_raw'] ?? '');
|
|
|
+ $tb = (string)($b['score_time_raw'] ?? '');
|
|
|
+ if ($ta !== $tb) {
|
|
|
+ return strcmp($tb, $ta);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $ta = (string)($a['pick_time'] ?? '');
|
|
|
+ $tb = (string)($b['pick_time'] ?? '');
|
|
|
+ if ($ta !== $tb) {
|
|
|
+ return strcmp($tb, $ta);
|
|
|
+ }
|
|
|
+
|
|
|
+ return strcmp((string)($a['CCYDH'] ?? ''), (string)($b['CCYDH'] ?? ''));
|
|
|
+ });
|
|
|
+
|
|
|
+ return $out;
|
|
|
+ }
|
|
|
}
|