482 lines
48 KiB
PHP
482 lines
48 KiB
PHP
@php
|
||
/** @var \App\Models\Business\CourierOnboarding $onboarding */
|
||
$status = $onboarding->status;
|
||
$expired = $onboarding->linkExpired() && in_array($status, ['invited', 'returned'], true);
|
||
$badge = match ($status) {
|
||
'submitted', 'first_approved', 'approved' => 'is-pending',
|
||
'returned' => 'is-warning',
|
||
'activated' => 'is-success',
|
||
'rejected', 'cancelled' => 'is-muted',
|
||
default => 'is-info',
|
||
};
|
||
$show = static fn ($value): string => filled($value) ? (string) $value : '—';
|
||
$num = static fn ($v): string => $v === null || $v === '' ? '—' : rtrim(rtrim(number_format((float) $v, 4, '.', ''), '0'), '.');
|
||
$quoteColumns = $onboarding->quoteColumns();
|
||
$quoteRows = $onboarding->quoteRowList();
|
||
$quoteSheet = $onboarding->files->where('kind', \App\Models\Business\CourierOnboardingFile::QUOTE_SHEET_KIND)->last();
|
||
$quoteUrl = route('business.pages.show', ['section' => 'courier-payables', 'page' => 'quote-management']);
|
||
@endphp
|
||
<x-layouts.admin>
|
||
<x-slot name="title">快递入驻 {{ $onboarding->number }}</x-slot>
|
||
<x-slot name="content">
|
||
<style>
|
||
.cod { --ink:var(--vip-content-ink,#171717); --muted:var(--vip-content-muted,#595959); --gold:var(--vip-content-accent-dark,#856632); --soft:var(--vip-content-accent-soft,#F7F0DE); --line:var(--vip-border,#D8D2C7); margin:24px 40px; color:var(--ink); font-family:"JetBrains Mono","Microsoft YaHei","PingFang SC",monospace; font-size:13px; }
|
||
.cod * { box-sizing:border-box; }
|
||
.cod__toolbar { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px; margin-bottom:16px; }
|
||
.cod__back { display:inline-flex; align-items:center; gap:5px; color:var(--gold); font-size:12px; text-decoration:none; }
|
||
.cod__heading { display:flex; align-items:center; flex-wrap:wrap; gap:10px; margin:6px 0 0; font-size:18px; font-weight:700; }
|
||
.cod__heading small { color:var(--muted); font-size:12px; font-weight:500; font-variant-numeric:tabular-nums; }
|
||
.cod__badge { display:inline-flex; align-items:center; padding:3px 10px; border-radius:999px; font-size:12px; font-weight:700; }
|
||
.cod__badge.is-pending { background:#fff4df; color:#935f07; } .cod__badge.is-warning { background:#fde9d4; color:#8a4a06; } .cod__badge.is-success { background:#edf5e8; color:#53793e; } .cod__badge.is-muted { background:#f1efea; color:#595959; } .cod__badge.is-info { background:#e8f2f8; color:#006395; }
|
||
.cod__layout { display:grid; grid-template-columns:minmax(0,1fr) 360px; gap:16px; align-items:start; }
|
||
.cod__main, .cod__side { display:grid; gap:16px; min-width:0; }
|
||
.cod__side { position:sticky; top:16px; }
|
||
.cod__panel { overflow:hidden; border:1px solid var(--line); border-radius:8px; background:#fff; }
|
||
.cod__panel-head { display:flex; align-items:center; justify-content:space-between; gap:8px; padding:12px 16px; border-bottom:1px solid var(--line); }
|
||
.cod__panel-title { display:flex; align-items:center; gap:8px; margin:0; font-size:14px; font-weight:600; }
|
||
.cod__panel-title .material-icons-outlined { color:var(--gold); font-size:19px; }
|
||
.cod__panel-body { padding:16px; }
|
||
.cod__meta { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:14px 18px; margin:0; }
|
||
.cod__meta dt { color:var(--muted); font-size:11px; }
|
||
.cod__meta dd { margin:4px 0 0; font-size:12.5px; word-break:break-all; font-variant-numeric:tabular-nums; }
|
||
.cod__meta .is-wide { grid-column:span 3; }
|
||
.cod__alert { display:flex; align-items:flex-start; gap:8px; margin-bottom:16px; padding:10px 12px; border:1px solid #D9BD88; border-radius:8px; background:#FFF8E8; color:#704800; font-size:12px; line-height:1.6; }
|
||
.cod__alert.is-success { border-color:#b7cda8; background:#f1f7ec; color:#2f4a22; }
|
||
.cod__alert.is-error { border-color:#e3b0b0; background:#fdf1f1; color:#7a1010; }
|
||
.cod__alert .material-icons-outlined { flex:none; font-size:18px; }
|
||
.cod__alert ul { margin:4px 0 0; padding-left:18px; }
|
||
.cod__button { display:inline-flex; align-items:center; justify-content:center; gap:6px; height:34px; padding:0 14px; border:1px solid var(--line); border-radius:8px; background:#fff; color:var(--ink); font:inherit; font-weight:500; text-decoration:none; white-space:nowrap; cursor:pointer; }
|
||
.cod__button--primary { border-color:var(--gold); background:var(--gold); color:#fff; } .cod__button--primary:hover { background:#6A5129; }
|
||
.cod__button--danger { border-color:#B80000; color:#8A1515; }
|
||
.cod__button .material-icons-outlined { font-size:17px; }
|
||
.cod__button[disabled] { cursor:not-allowed; opacity:.55; }
|
||
.cod__stack { display:grid; gap:10px; }
|
||
.cod__row { display:flex; flex-wrap:wrap; gap:8px; }
|
||
.cod__field { display:grid; gap:5px; } .cod__field label { color:var(--muted); font-size:11px; font-weight:600; }
|
||
.cod__field input, .cod__field textarea, .cod__field select { width:100%; min-height:34px; padding:6px 10px; border:1px solid var(--line); border-radius:8px; background:#fff; color:var(--ink); font:inherit; }
|
||
.cod__field textarea { min-height:64px; resize:vertical; }
|
||
.cod__field input:focus, .cod__field textarea:focus { border-color:var(--gold); outline:none; box-shadow:0 0 0 3px rgba(133,102,50,.18); }
|
||
.cod__help { color:var(--muted); font-size:11px; line-height:1.55; }
|
||
.cod__divider { height:1px; margin:4px 0; background:var(--line); }
|
||
.cod__qr { display:grid; justify-items:center; gap:10px; }
|
||
.cod__qr img { width:220px; height:220px; border:1px solid var(--line); border-radius:8px; image-rendering:pixelated; }
|
||
.cod__link { display:flex; gap:6px; width:100%; }
|
||
.cod__link input { flex:1; min-width:0; height:34px; padding:0 8px; border:1px solid var(--line); border-radius:8px; background:#fffdf8; color:var(--muted); font:inherit; font-size:11px; }
|
||
.cod table { width:100%; border-collapse:collapse; font-size:12.5px; }
|
||
.cod th { padding:9px 12px; border-bottom:1px solid var(--line); background:var(--soft); font-size:12px; font-weight:600; text-align:left; white-space:nowrap; }
|
||
.cod td { padding:8px 12px; border-bottom:1px solid #ECE8E0; }
|
||
.cod tbody tr:last-child td { border-bottom:0; }
|
||
.cod .is-number { text-align:right; font-variant-numeric:tabular-nums; }
|
||
.cod__files { display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:10px; }
|
||
.cod__file { display:grid; gap:6px; padding:8px; border:1px solid var(--line); border-radius:8px; background:#fffdf8; color:var(--ink); text-decoration:none; }
|
||
.cod__file-thumb { display:grid; height:96px; place-items:center; overflow:hidden; border-radius:6px; background:#f1ede4; color:var(--gold); }
|
||
.cod__file-thumb img { width:100%; height:100%; object-fit:cover; }
|
||
.cod__file-kind { color:var(--gold); font-size:11px; font-weight:700; }
|
||
.cod__file-name { overflow:hidden; font-size:11.5px; text-overflow:ellipsis; white-space:nowrap; }
|
||
.cod__file-size { color:var(--muted); font-size:10.5px; }
|
||
.cod__timeline { display:grid; }
|
||
.cod__event { position:relative; display:grid; grid-template-columns:120px 1fr; gap:14px; padding:0 0 16px 22px; }
|
||
.cod__event::before { position:absolute; top:4px; bottom:-4px; left:6px; width:1px; background:var(--line); content:''; }
|
||
.cod__event::after { position:absolute; top:4px; left:2px; width:9px; height:9px; border:2px solid var(--gold); border-radius:50%; background:#fff; content:''; }
|
||
.cod__event:last-child::before { display:none; }
|
||
.cod__event-time { color:var(--muted); font-size:11px; font-variant-numeric:tabular-nums; }
|
||
.cod__event-title { font-weight:600; }
|
||
.cod__event-note { margin-top:3px; color:var(--muted); font-size:12px; white-space:pre-wrap; }
|
||
details.cod__more summary { color:var(--gold); cursor:pointer; font-size:12px; }
|
||
details.cod__more[open] summary { margin-bottom:10px; }
|
||
@media (max-width:1200px) { .cod { margin:16px; } .cod__layout { grid-template-columns:1fr; } .cod__side { position:static; } .cod__meta { grid-template-columns:repeat(2,minmax(0,1fr)); } .cod__meta .is-wide { grid-column:span 2; } }
|
||
</style>
|
||
|
||
<div class="cod">
|
||
<div class="cod__toolbar">
|
||
<div>
|
||
<a class="cod__back" href="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-onboarding']) }}"><span class="material-icons-outlined" aria-hidden="true" style="font-size:16px">arrow_back</span>返回快递入驻</a>
|
||
<h1 class="cod__heading">{{ $onboarding->displayName() }}<span class="cod__badge {{ $badge }}">{{ $expired ? '链接已过期' : $onboarding->statusLabel() }}</span><small>{{ $onboarding->number }}</small></h1>
|
||
</div>
|
||
</div>
|
||
|
||
@if (session('success'))
|
||
<div class="cod__alert is-success" role="status"><span class="material-icons-outlined" aria-hidden="true">check_circle</span><span>{{ session('success') }}</span></div>
|
||
@endif
|
||
@if ($errors->any())
|
||
<div class="cod__alert is-error" role="alert"><span class="material-icons-outlined" aria-hidden="true">error_outline</span><div>操作未完成<ul>@foreach ($errors->all() as $message)<li>{{ $message }}</li>@endforeach</ul></div></div>
|
||
@endif
|
||
@if ($status === 'returned' && $onboarding->return_reason)
|
||
<div class="cod__alert" role="status"><span class="material-icons-outlined" aria-hidden="true">assignment_return</span><span>已退回补件:{{ $onboarding->return_reason }}</span></div>
|
||
@endif
|
||
|
||
<div class="cod__layout">
|
||
<div class="cod__main">
|
||
@if (in_array($status, ['invited', 'returned'], true) && blank($onboarding->company_full_name))
|
||
<div class="cod__panel"><div class="cod__panel-body cod__help">快递方还没有填写资料。把右侧二维码发给对方,扫码后即可在手机上填写;填写过程中可以随时暂存。</div></div>
|
||
@endif
|
||
|
||
<section class="cod__panel" aria-labelledby="cod-company">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-company"><span class="material-icons-outlined" aria-hidden="true">{{ $onboarding->isPerson() ? 'person' : 'apartment' }}</span>入驻主体与联系人</h2><span class="cod__badge {{ $onboarding->isPerson() ? 'is-warning' : 'is-info' }}">{{ $onboarding->entityLabel() }}入驻</span></div>
|
||
<div class="cod__panel-body">
|
||
<dl class="cod__meta">
|
||
<div class="is-wide"><dt>{{ $onboarding->subjectLabel() }}</dt><dd>{{ $show($onboarding->company_full_name) }}</dd></div>
|
||
@if ($onboarding->isPerson())
|
||
<div><dt>身份证号</dt><dd>{{ $show($onboarding->maskedIdNumber()) }}</dd></div>
|
||
@else
|
||
<div><dt>统一社会信用代码</dt><dd>{{ $show($onboarding->unified_social_credit_code) }}</dd></div>
|
||
<div><dt>法定代表人</dt><dd>{{ $show($onboarding->legal_representative) }}</dd></div>
|
||
@endif
|
||
<div><dt>快递品牌 / 业务类型</dt><dd>{{ $show($onboarding->carrier_brand) }} · {{ $show($onboarding->service_type) }}</dd></div>
|
||
<div><dt>网点名称</dt><dd>{{ $show($onboarding->network_name) }}</dd></div>
|
||
<div class="is-wide" style="grid-column:span 2"><dt>经营地址</dt><dd>{{ $show($onboarding->business_address) }}</dd></div>
|
||
<div><dt>业务对接人</dt><dd>{{ $show($onboarding->contact_name) }} {{ $onboarding->contact_phone }}</dd></div>
|
||
<div><dt>财务对账人</dt><dd>{{ $show($onboarding->finance_contact_name) }} {{ $onboarding->finance_contact_phone }}</dd></div>
|
||
<div><dt>e签宝签署人</dt><dd>{{ $show($onboarding->esign_operator_name) }} {{ $onboarding->esign_account }}</dd></div>
|
||
<div><dt>提交时间</dt><dd>{{ $onboarding->submitted_at?->format('Y-m-d H:i') ?? '—' }}</dd></div>
|
||
<div class="is-wide"><dt>可揽收仓库 / 区域</dt><dd>{{ $show($onboarding->pickup_warehouses) }}</dd></div>
|
||
</dl>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="cod__panel" aria-labelledby="cod-settle">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-settle"><span class="material-icons-outlined" aria-hidden="true">account_balance</span>结算与开票</h2></div>
|
||
<div class="cod__panel-body">
|
||
@php
|
||
$accountChecks = $onboarding->accountChecks();
|
||
$checkBadge = static fn (?bool $ok, string $okText, string $badText): string => $ok === null ? '' : '<span style="margin-left:6px;font-size:12px;color:' . ($ok ? '#2F6B2A' : '#A1281F') . '">' . e($ok ? '✓ ' . $okText : '✗ ' . $badText) . '</span>';
|
||
@endphp
|
||
<dl class="cod__meta">
|
||
<div><dt>对公户名</dt><dd>{{ $show($onboarding->bank_account_name) }}{!! $checkBadge($accountChecks['corporate'], '与营业执照公司全称一致', '与公司全称不一致') !!}</dd></div>
|
||
<div><dt>对公开户行</dt><dd>{{ $show($onboarding->bank_name) }}</dd></div>
|
||
<div><dt>对公账号</dt><dd>{{ $show($onboarding->bank_account_number) }}</dd></div>
|
||
<div><dt>对私收款人</dt><dd>{{ $show($onboarding->private_account_name) }}{!! $checkBadge($accountChecks['private'], $onboarding->isPerson() ? '与本人姓名一致' : '与法定代表人一致', $onboarding->isPerson() ? '与本人姓名不一致' : '与法定代表人不一致') !!}</dd></div>
|
||
<div><dt>对私开户行</dt><dd>{{ $show($onboarding->private_bank_name) }}</dd></div>
|
||
<div><dt>对私卡号</dt><dd>{{ $show($onboarding->private_account_number) }}</dd></div>
|
||
<div><dt>开票类型</dt><dd>{{ $show($onboarding->invoice_type) }}</dd></div>
|
||
<div><dt>税率</dt><dd>{{ $onboarding->tax_rate !== null ? $num($onboarding->tax_rate) . '%' : '—' }}</dd></div>
|
||
<div><dt>结算周期</dt><dd>{{ $show($onboarding->settlement_cycle) }}</dd></div>
|
||
</dl>
|
||
<p class="cod__help" style="margin:12px 0 0">核对依据:快递填写的营业执照公司全称 / 法定代表人{{ $onboarding->isPerson() ? '(个人入驻为本人姓名)' : '' }}。请对照下方营业执照、身份证和银行卡照片确认填写无误。</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="cod__panel" aria-labelledby="cod-quote">
|
||
<div class="cod__panel-head">
|
||
<h2 class="cod__panel-title" id="cod-quote"><span class="material-icons-outlined" aria-hidden="true">request_quote</span>{{ $quoteVersions->count() > 1 ? "入驻首版报价" : "报价" }}</h2>
|
||
@if ($onboarding->quoteVersion)
|
||
<a class="cod__button" href="{{ $quoteUrl }}"><span class="material-icons-outlined" aria-hidden="true">open_in_new</span>报价管理 {{ $onboarding->quoteVersion->version_code }}</a>
|
||
@endif
|
||
</div>
|
||
<div class="cod__panel-body">
|
||
<dl class="cod__meta" style="margin-bottom:14px">
|
||
<div><dt>计费方式</dt><dd><strong>{{ $show($onboarding->quoteModeLabel()) }}</strong></dd></div>
|
||
<div><dt>执行日期</dt><dd>{{ $onboarding->quote_effective_date?->format('Y-m-d') ?? '—' }}</dd></div>
|
||
<div><dt>重量取整</dt><dd>{{ \App\Support\CourierQuoteStructure::ROUNDING[$onboarding->weight_rounding ?? 'none'] ?? '不取整' }}</dd></div>
|
||
<div class="is-wide"><dt>计费规则</dt><dd>@foreach ($onboarding->quoteRuleLines() as $rule)<div>{{ $rule }}</div>@endforeach</dd></div>
|
||
<div class="is-wide"><dt>报价备注</dt><dd>{{ $show($onboarding->quote_note) }}</dd></div>
|
||
</dl>
|
||
@if ($onboarding->quote_mode === 'other')
|
||
<div class="cod__alert" style="margin:0"><span class="material-icons-outlined" aria-hidden="true">upload_file</span><span>特殊计费,快递上传了报价表{{ $quoteSheet ? ':' . $quoteSheet->original_name : '' }}。复审通过后请在「报价管理」里按报价表录入首版报价,再发起报价确认。</span></div>
|
||
@if ($quoteSheet)<p style="margin:10px 0 0"><a class="cod__button" href="{{ route('business.courier-onboardings.file', [$onboarding, $quoteSheet]) }}?download=1"><span class="material-icons-outlined" aria-hidden="true">download</span>下载报价表</a></p>@endif
|
||
@elseif ($quoteRows === [])
|
||
<p class="cod__help">快递方还没有填写报价明细。</p>
|
||
@else
|
||
<div style="overflow-x:auto">
|
||
<table aria-label="报价明细">
|
||
<thead><tr><th>省份 / 区域</th>@foreach ($quoteColumns as $column)<th class="is-number">{{ $column['label'] }}</th>@endforeach</tr></thead>
|
||
<tbody>
|
||
@foreach ($quoteRows as $row)
|
||
<tr><td>{{ $row['region'] }}</td>@foreach (\App\Support\CourierQuoteStructure::rowValues($row, $quoteColumns) as $cell)<td class="is-number">{{ $num($cell) }}</td>@endforeach</tr>
|
||
@endforeach
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<p class="cod__help" style="margin:10px 0 0">共 {{ count($quoteRows) }} 个地区。复审通过后这份报价会作为首版报价写进报价管理,并生成报价确认单推送 e签宝。</p>
|
||
@endif
|
||
</div>
|
||
</section>
|
||
|
||
<section class="cod__panel" aria-labelledby="cod-files">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-files"><span class="material-icons-outlined" aria-hidden="true">attach_file</span>资料附件</h2><span class="cod__help">{{ $onboarding->files->count() }} 个</span></div>
|
||
<div class="cod__panel-body">
|
||
@if ($onboarding->files->isEmpty())
|
||
<p class="cod__help">暂未上传附件。</p>
|
||
@else
|
||
<div class="cod__files">
|
||
@foreach ($onboarding->files as $file)
|
||
@php $fileUrl = route('business.courier-onboardings.file', [$onboarding, $file]); @endphp
|
||
<a class="cod__file" href="{{ $fileUrl }}" target="_blank" rel="noopener">
|
||
<span class="cod__file-thumb">
|
||
@if ($file->isImage())
|
||
<img src="{{ $fileUrl }}" alt="{{ \App\Models\Business\CourierOnboardingFile::labelFor($file->kind, $onboarding->entity_type) }}" loading="lazy">
|
||
@else
|
||
<span class="material-icons-outlined" aria-hidden="true" style="font-size:34px">description</span>
|
||
@endif
|
||
</span>
|
||
<span class="cod__file-kind">{{ \App\Models\Business\CourierOnboardingFile::labelFor($file->kind, $onboarding->entity_type) }}</span>
|
||
<span class="cod__file-name" title="{{ $file->original_name }}">{{ $file->original_name }}</span>
|
||
<span class="cod__file-size">{{ $file->sizeLabel() }} · {{ $file->created_at?->format('m-d H:i') }}</span>
|
||
</a>
|
||
@endforeach
|
||
</div>
|
||
@endif
|
||
</div>
|
||
</section>
|
||
|
||
<section class="cod__panel" aria-labelledby="cod-timeline">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-timeline"><span class="material-icons-outlined" aria-hidden="true">history</span>处理记录</h2></div>
|
||
<div class="cod__panel-body">
|
||
<div class="cod__timeline">
|
||
@foreach ($onboarding->events->sortByDesc('id') as $event)
|
||
<div class="cod__event">
|
||
<span class="cod__event-time">{{ $event->created_at?->format('Y-m-d H:i') }}</span>
|
||
<div><div class="cod__event-title">{{ $event->eventLabel() }} · {{ $event->actorLabel() }}</div>@if ($event->note)<div class="cod__event-note">{{ $event->note }}</div>@endif</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
<aside class="cod__side">
|
||
<section class="cod__panel" aria-label="指定审核人员">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title">指定审核人员</h2></div>
|
||
<div class="cod__panel-body cod__stack">
|
||
<p class="cod__help" style="margin:0">初审:{{ implode('、', array_column($reviewerSettings['first'], 'display_name')) ?: '尚未配置' }}</p>
|
||
<p class="cod__help" style="margin:0">复审:{{ implode('、', array_column($reviewerSettings['final'], 'display_name')) ?: '尚未配置' }}</p>
|
||
<p class="cod__help" style="margin:0">各环节任意一人通过即可,初审与复审须由不同人员完成。</p>
|
||
@if ($isAdmin)<a class="cod__button" href="{{ route('system-settings.workflow-reviewers.index') }}">设置审核人员</a>@endif
|
||
</div>
|
||
</section>
|
||
@if (in_array($status, ['invited', 'returned'], true))
|
||
<section class="cod__panel" aria-labelledby="cod-qr">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-qr"><span class="material-icons-outlined" aria-hidden="true">qr_code_2</span>入驻二维码</h2><span class="cod__help">{{ $onboarding->expires_at ? '有效期至 ' . $onboarding->expires_at->format('Y-m-d') : '' }}</span></div>
|
||
<div class="cod__panel-body cod__qr">
|
||
@if ($expired)
|
||
<div class="cod__alert" style="margin:0;width:100%"><span class="material-icons-outlined" aria-hidden="true">schedule</span><span>链接已过期,延期后原二维码即可继续使用。</span></div>
|
||
@endif
|
||
<img src="{{ route('business.courier-onboardings.qr', $onboarding) }}" alt="快递入驻二维码" width="220" height="220">
|
||
<div class="cod__link">
|
||
<input type="text" value="{{ $formUrl }}" readonly aria-label="入驻链接" data-copy-source>
|
||
<button type="button" class="cod__button" data-copy-button><span class="material-icons-outlined" aria-hidden="true">content_copy</span>复制</button>
|
||
</div>
|
||
<div class="cod__row">
|
||
<a class="cod__button" href="{{ route('business.courier-onboardings.qr', [$onboarding, 'download' => 1]) }}"><span class="material-icons-outlined" aria-hidden="true">download</span>下载二维码</a>
|
||
<form method="POST" action="{{ route('business.courier-onboardings.extend', $onboarding) }}">@csrf<button type="submit" class="cod__button"><span class="material-icons-outlined" aria-hidden="true">update</span>延期 30 天</button></form>
|
||
</div>
|
||
<form method="POST" action="{{ route('business.courier-onboardings.cancel', $onboarding) }}" data-confirm="作废后原二维码将无法打开,确认作废?">@csrf<button type="submit" class="cod__button cod__button--danger"><span class="material-icons-outlined" aria-hidden="true">block</span>作废邀请</button></form>
|
||
</div>
|
||
</section>
|
||
@endif
|
||
|
||
@if ($status === 'submitted')
|
||
<section class="cod__panel" aria-labelledby="cod-first">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-first"><span class="material-icons-outlined" aria-hidden="true">fact_check</span>初审</h2></div>
|
||
<div class="cod__panel-body cod__stack">
|
||
<p class="cod__help" style="margin:0">核对营业执照、开户证明和盖章报价单是否与填写一致。</p>
|
||
@if ($canFirstReview)
|
||
<form method="POST" action="{{ route('business.courier-onboardings.first-approve', $onboarding) }}" class="cod__stack">
|
||
@csrf
|
||
<div class="cod__field"><label for="cod-first-note">初审意见(选填)</label><textarea id="cod-first-note" name="note" maxlength="1000"></textarea></div>
|
||
<button type="submit" class="cod__button cod__button--primary"><span class="material-icons-outlined" aria-hidden="true">done</span>初审通过</button>
|
||
</form>
|
||
@include('business.pages.courier-payables.partials.courier-onboarding-return', ['onboarding' => $onboarding])
|
||
@else
|
||
<p class="cod__help" style="margin:0">{{ $reviewAccess['message'] }}</p>
|
||
@endif
|
||
</div>
|
||
</section>
|
||
@elseif ($status === 'first_approved')
|
||
<section class="cod__panel" aria-labelledby="cod-final">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-final"><span class="material-icons-outlined" aria-hidden="true">verified</span>财务复审</h2></div>
|
||
<div class="cod__panel-body cod__stack">
|
||
@if ($canFinalReview)
|
||
<form method="POST" action="{{ route('business.courier-onboardings.final-approve', $onboarding) }}" class="cod__stack">
|
||
@csrf
|
||
@if ($onboarding->courier_name)
|
||
<div class="cod__field">
|
||
<label>系统快递名称</label>
|
||
<div style="font-size:15px;font-weight:700">{{ $onboarding->courier_name }}</div>
|
||
<span class="cod__help">生成二维码时已定好;复审通过后锁定,首版报价和 e签宝报价确认单都用这个名称。如需更正,请先在下方「内部信息」修改。</span>
|
||
</div>
|
||
@else
|
||
<div class="cod__field">
|
||
<label for="cod-courier-name">系统快递名称 *</label>
|
||
<input id="cod-courier-name" name="courier_name" type="text" maxlength="100" required value="{{ old('courier_name') }}">
|
||
<span class="cod__help">必须与报价名、发货数据里的「快递名称」完全一致,复审后不可再改。</span>
|
||
</div>
|
||
@endif
|
||
<div class="cod__field"><label for="cod-reconciler">对账人</label><input id="cod-reconciler" name="reconciler" type="text" maxlength="100" value="{{ old('reconciler', $onboarding->reconciler) }}"></div>
|
||
<div class="cod__field"><label for="cod-final-note">复审意见(选填)</label><textarea id="cod-final-note" name="note" maxlength="1000"></textarea></div>
|
||
<button type="submit" class="cod__button cod__button--primary"><span class="material-icons-outlined" aria-hidden="true">verified</span>复审通过,生成首版报价</button>
|
||
</form>
|
||
@include('business.pages.courier-payables.partials.courier-onboarding-return', ['onboarding' => $onboarding])
|
||
@else
|
||
<p class="cod__help" style="margin:0">{{ $reviewAccess['message'] }}</p>
|
||
@endif
|
||
</div>
|
||
</section>
|
||
@elseif ($status === 'approved')
|
||
@php
|
||
$quoteSigned = $quoteSignature?->status === 'archived';
|
||
$canPush = $isAdmin && $esignReady && $onboarding->quoteVersion && (! $quoteSignature || $quoteSignature->canSend());
|
||
@endphp
|
||
<section class="cod__panel" aria-labelledby="cod-sign">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-sign"><span class="material-icons-outlined" aria-hidden="true">draw</span>报价确认 · 开通</h2></div>
|
||
<div class="cod__panel-body cod__stack">
|
||
<dl class="cod__meta" style="grid-template-columns:1fr 1fr">
|
||
<div><dt>报价确认单</dt><dd>{{ $onboarding->quoteVersion?->version_code ?? '—' }}</dd></div>
|
||
<div><dt>e签宝状态</dt><dd><strong>{{ $quoteSignature?->statusLabel() ?? '未推送' }}</strong></dd></div>
|
||
<div style="grid-column:span 2"><dt>签署方</dt><dd>{{ $show($onboarding->company_full_name) }}<br>{{ $show($onboarding->esign_operator_name) }} · {{ $show($onboarding->esign_account) }}</dd></div>
|
||
</dl>
|
||
@if ($quoteSignature?->last_error)
|
||
<div class="cod__alert is-error" style="margin:0"><span class="material-icons-outlined" aria-hidden="true">error_outline</span><span>{{ $quoteSignature->last_error }}</span></div>
|
||
@endif
|
||
@unless ($esignReady)
|
||
<p class="cod__help" style="margin:0">E 签宝尚未配置(本地预览环境正常现象),报价确认单无法推送;线下签署后填写说明即可开通。</p>
|
||
@endunless
|
||
<div class="cod__row">
|
||
@if ($canPush)
|
||
<form method="POST" action="{{ route('business.courier-onboardings.push-quote', $onboarding) }}">@csrf<button type="submit" class="cod__button cod__button--primary"><span class="material-icons-outlined" aria-hidden="true">send</span>{{ $quoteSignature ? '重新推送' : '推送到 e签宝' }}</button></form>
|
||
@endif
|
||
@if ($quoteSignature?->esign_sign_flow_id && ! $quoteSigned)
|
||
<form method="POST" action="{{ route('business.courier-onboardings.sync-quote', $onboarding) }}">@csrf<button type="submit" class="cod__button"><span class="material-icons-outlined" aria-hidden="true">sync</span>同步签署状态</button></form>
|
||
<form method="POST" action="{{ route('business.courier-onboardings.sign-url', $onboarding) }}">@csrf<button type="submit" class="cod__button"><span class="material-icons-outlined" aria-hidden="true">link</span>获取签署链接</button></form>
|
||
@endif
|
||
@if ($quoteSigned && $quoteSignature->signed_pdf_path)
|
||
<a class="cod__button" href="{{ route('business.courier-quote-signatures.download', [$quoteSignature, 'signed']) }}"><span class="material-icons-outlined" aria-hidden="true">task</span>回签单 PDF</a>
|
||
<a class="cod__button" href="{{ route('business.courier-quote-signatures.sheet', $onboarding->quoteVersion) }}"><span class="material-icons-outlined" aria-hidden="true">table_view</span>导出电子档</a>
|
||
@endif
|
||
@if ($quoteSignature?->source_pdf_path)
|
||
<a class="cod__button" href="{{ route('business.courier-quote-signatures.download', [$quoteSignature, 'source']) }}"><span class="material-icons-outlined" aria-hidden="true">picture_as_pdf</span>报价确认单 PDF</a>
|
||
@endif
|
||
</div>
|
||
@if (session('quote_sign_url'))
|
||
<div class="cod__stack" style="gap:8px;padding:12px;border:1px dashed var(--cod-line, #d9cfb8);border-radius:10px">
|
||
<strong style="font-size:13px">签署链接(签署人 {{ $show($onboarding->esign_operator_name) }} 用手机扫码或打开)</strong>
|
||
<div style="width:150px;height:150px">{!! \App\Support\QrCode::svg(session('quote_sign_url'), 4, 2) !!}</div>
|
||
<input type="text" readonly value="{{ session('quote_sign_url') }}" onclick="this.select()" style="width:100%;font-size:13px;padding:6px 8px;border:1px solid #ddd;border-radius:6px">
|
||
<p class="cod__help" style="margin:0">可以直接把链接或二维码发给快递。打开后需先用 {{ $show($onboarding->esign_account) }} 登录 / 实名{{ $onboarding->isPerson() ? '' : ',并以「' . $onboarding->company_full_name . '」企业身份签署' }}。</p>
|
||
</div>
|
||
@endif
|
||
@if ($quoteSignature?->esign_sign_flow_id && ! $quoteSigned && ! $onboarding->isPerson())
|
||
<p class="cod__help" style="margin:0">企业签署的任务在 e签宝里归属「{{ $show($onboarding->company_full_name) }}」这家企业:签署人会收到短信;在 e签宝 App 里要切换到这家企业才能看到待签任务。企业名称必须和营业执照完全一致、且已在 e签宝完成企业认证(或由签署人当场认证),否则无法签署。</p>
|
||
@endif
|
||
<div class="cod__divider"></div>
|
||
@if ($isAdmin)
|
||
<form method="POST" action="{{ route('business.courier-onboardings.activate', $onboarding) }}" class="cod__stack">
|
||
@csrf
|
||
@unless ($quoteSigned || $signedAgreement)
|
||
<div class="cod__field"><label for="cod-offline">线下签署说明</label><textarea id="cod-offline" name="offline_note" maxlength="1000" placeholder="报价确认单未在 e签宝签完时必填,如:已线下盖章,原件在财务处">{{ old('offline_note') }}</textarea></div>
|
||
@endunless
|
||
<button type="submit" class="cod__button cod__button--primary"><span class="material-icons-outlined" aria-hidden="true">how_to_reg</span>确认开通</button>
|
||
@if ($quoteSigned)<span class="cod__help">报价确认单已签署归档,可以直接开通。</span>@endif
|
||
</form>
|
||
@else
|
||
<p class="cod__help" style="margin:0">推送和开通需要管理员账号。</p>
|
||
@endif
|
||
</div>
|
||
</section>
|
||
@elseif ($status === 'activated')
|
||
<section class="cod__panel"><div class="cod__panel-body cod__stack">
|
||
<div class="cod__alert is-success" style="margin:0"><span class="material-icons-outlined" aria-hidden="true">how_to_reg</span><span>{{ $onboarding->activated_at?->format('Y-m-d H:i') }} 已开通,可在快递资料「入驻快递」查看。</span></div>
|
||
<a class="cod__button" href="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-information', 'courier_tab' => 'onboarded']) }}"><span class="material-icons-outlined" aria-hidden="true">open_in_new</span>快递资料 · 入驻快递</a>
|
||
<a class="cod__button" href="{{ $quoteUrl }}"><span class="material-icons-outlined" aria-hidden="true">price_change</span>报价管理 · 快递报价(变价)</a>
|
||
@if ($quoteSignature?->status === 'archived' && $quoteSignature->signed_pdf_path)
|
||
<div class="cod__row">
|
||
<a class="cod__button" href="{{ route('business.courier-quote-signatures.download', [$quoteSignature, 'signed']) }}"><span class="material-icons-outlined" aria-hidden="true">task</span>回签单 PDF</a>
|
||
<a class="cod__button" href="{{ route('business.courier-quote-signatures.sheet', $onboarding->quoteVersion) }}"><span class="material-icons-outlined" aria-hidden="true">table_view</span>导出电子档</a>
|
||
</div>
|
||
@endif
|
||
</div></section>
|
||
@endif
|
||
|
||
<section class="cod__panel" aria-labelledby="cod-internal">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-internal"><span class="material-icons-outlined" aria-hidden="true">badge</span>内部信息</h2></div>
|
||
<div class="cod__panel-body">
|
||
@if (in_array($status, ['activated', 'rejected', 'cancelled'], true) || $onboarding->quote_version_id)
|
||
<dl class="cod__meta" style="grid-template-columns:1fr 1fr">
|
||
<div><dt>系统快递名称</dt><dd>{{ $show($onboarding->courier_name) }}</dd></div>
|
||
<div><dt>对账人</dt><dd>{{ $show($onboarding->reconciler) }}</dd></div>
|
||
</dl>
|
||
@else
|
||
<form method="POST" action="{{ route('business.courier-onboardings.internal', $onboarding) }}" class="cod__stack">
|
||
@csrf
|
||
<div class="cod__field"><label for="cod-internal-name">系统快递名称</label><input id="cod-internal-name" name="courier_name" type="text" maxlength="100" value="{{ $onboarding->courier_name }}" placeholder="如:新北中通"></div>
|
||
<div class="cod__field"><label for="cod-internal-reconciler">对账人</label><input id="cod-internal-reconciler" name="reconciler" type="text" maxlength="100" value="{{ $onboarding->reconciler }}"></div>
|
||
<button type="submit" class="cod__button">保存</button>
|
||
</form>
|
||
@endif
|
||
</div>
|
||
</section>
|
||
<section class="cod__panel" aria-labelledby="cod-profile">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-profile"><span class="material-icons-outlined" aria-hidden="true">local_shipping</span>快递资料(我方填写)</h2></div>
|
||
<div class="cod__panel-body">
|
||
<form method="POST" action="{{ route('business.courier-onboardings.internal', $onboarding) }}" class="cod__stack">
|
||
@csrf
|
||
<p class="cod__help" style="margin:0">快递方看不到。保存后对齐到快递资料(扣款方式、网点代码等),代码 {{ $onboarding->workplatform_expcode ?: '未填' }}。</p>
|
||
@foreach (\App\Models\Business\CourierOnboarding::PROFILE_FIELDS as $field => [$label, $options])
|
||
<div class="cod__field">
|
||
<label for="cod-profile-{{ $field }}">{{ $label }} *</label>
|
||
@if ($options !== null)
|
||
<select id="cod-profile-{{ $field }}" name="{{ $field }}" required>
|
||
<option value=""></option>
|
||
@foreach ($options as $option)
|
||
<option value="{{ $option }}" @selected(old($field, $onboarding->{$field}) === $option)>{{ $option }}</option>
|
||
@endforeach
|
||
</select>
|
||
@else
|
||
<input id="cod-profile-{{ $field }}" name="{{ $field }}" required type="{{ $field === 'courier_email' ? 'email' : 'text' }}" maxlength="{{ $field === 'network_code' ? 64 : 191 }}" value="{{ old($field, $onboarding->{$field}) }}">
|
||
@endif
|
||
@error($field)<span class="cod__help" style="color:#b80000">{{ $message }}</span>@enderror
|
||
</div>
|
||
@endforeach
|
||
<button type="submit" class="cod__button">保存快递资料</button>
|
||
</form>
|
||
</div>
|
||
</section>
|
||
@if ($status === 'activated')
|
||
<section class="cod__panel" aria-labelledby="cod-erp">
|
||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-erp"><span class="material-icons-outlined" aria-hidden="true">hub</span>ERP 开通</h2>
|
||
@if ($onboarding->erpPending())<span class="cod__pill" style="margin-left:auto;padding:2px 8px;border-radius:6px;font-size:12px;background:#FFF6E5;color:#935F07">待 ERP 开通</span>@else<span class="cod__pill" style="margin-left:auto;padding:2px 8px;border-radius:6px;font-size:12px;background:#EEF6EA;color:#2F6B2A">已开通</span>@endif
|
||
</div>
|
||
<div class="cod__panel-body cod__stack">
|
||
@if ($onboarding->erpPending())
|
||
<p class="cod__help" style="margin:0">下一步:ERP 专员开通发货系统账号后,在下方「手动补录」里填 ERP账户ID 保存即可(快递公司代码沿用生成二维码时填的)。快递类型、扣款方式等在上方「快递资料(我方填写)」维护,直接对齐到快递资料。</p>
|
||
@else
|
||
<dl class="cod__meta" style="grid-template-columns:1fr 1fr">
|
||
<div><dt>快递代码</dt><dd>{{ $onboarding->workplatform_expcode }}</dd></div>
|
||
<div><dt>ERP账户ID</dt><dd>{{ $onboarding->erp_account_id ?: '—' }}</dd></div>
|
||
<div><dt>开通时间</dt><dd>{{ $onboarding->erp_opened_at?->format('Y-m-d H:i') ?? '—' }}</dd></div>
|
||
<div><dt>来源</dt><dd>{{ $onboarding->erpSourceLabel() ?: '—' }}</dd></div>
|
||
</dl>
|
||
@endif
|
||
<details>
|
||
<summary class="cod__help" style="cursor:pointer">手动补录 ERP 开通信息</summary>
|
||
<form method="POST" action="{{ route('business.courier-onboardings.erp-opening', $onboarding) }}" class="cod__stack" style="margin-top:10px">
|
||
@csrf
|
||
<div class="cod__field"><label for="cod-erp-code">快递代码</label><input id="cod-erp-code" name="workplatform_expcode" type="text" maxlength="64" value="{{ $onboarding->workplatform_expcode }}" placeholder="ERP 开通后的快递代码"></div>
|
||
<div class="cod__field"><label for="cod-erp-account">ERP账户ID</label><input id="cod-erp-account" name="erp_account_id" type="text" maxlength="64" value="{{ $onboarding->erp_account_id }}"></div>
|
||
<button type="submit" class="cod__button">保存</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
</section>
|
||
@endif
|
||
</aside>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.querySelectorAll('.cod [data-copy-button]').forEach(function (button) {
|
||
button.addEventListener('click', function () {
|
||
var input = document.querySelector('.cod [data-copy-source]');
|
||
if (!input) return;
|
||
input.select();
|
||
var done = function () { button.lastChild.textContent = '已复制'; setTimeout(function () { button.lastChild.textContent = '复制'; }, 1600); };
|
||
if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(input.value).then(done); } else { document.execCommand('copy'); done(); }
|
||
});
|
||
});
|
||
document.querySelectorAll('.cod form[data-confirm]').forEach(function (form) {
|
||
form.addEventListener('submit', function (event) { if (!window.confirm(form.getAttribute('data-confirm'))) event.preventDefault(); });
|
||
});
|
||
</script>
|
||
</x-slot>
|
||
</x-layouts.admin>
|