feat: 应付云仓车费流程时间与状态筛选 (#82)
This commit is contained in:
parent
17f5b7719e
commit
255d47f69e
@ -329,8 +329,22 @@ class Pages extends Controller
|
||||
|
||||
protected function contentForDingPayableWorkflows(): array
|
||||
{
|
||||
$normalizeDate = static function (mixed $value): string {
|
||||
$date = trim((string) $value);
|
||||
if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $date, $matches) !== 1
|
||||
|| ! checkdate((int) $matches[2], (int) $matches[3], (int) $matches[1])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $date;
|
||||
};
|
||||
$status = strtoupper(mb_substr(trim((string) request('status', '')), 0, 30));
|
||||
|
||||
$filters = [
|
||||
'process_instance_id' => mb_substr(trim((string) request('process_instance_id', '')), 0, 100),
|
||||
'created_from' => $normalizeDate(request('created_from', '')),
|
||||
'finished_to' => $normalizeDate(request('finished_to', '')),
|
||||
'status' => preg_match('/^[A-Z_]+$/', $status) === 1 ? $status : '',
|
||||
];
|
||||
$page = max((int) request('page', 1), 1);
|
||||
$limit = min(max((int) setting('default.list_limit', 25), 1), 100);
|
||||
|
||||
@ -63,6 +63,9 @@ class DingPayableWorkflowMirrorRepository
|
||||
&& ! str_contains((string) ($workflow['businessId'] ?? ''), (string) $filters['process_instance_id'])) {
|
||||
continue;
|
||||
}
|
||||
if (! $this->matchesWorkflowFilters($workflow, $filters)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$scheme = $this->decode((string) $record->scheme_payload, []);
|
||||
$forms = $this->formFields($scheme);
|
||||
@ -94,6 +97,46 @@ class DingPayableWorkflowMirrorRepository
|
||||
];
|
||||
}
|
||||
|
||||
/** @param array<string,mixed> $workflow @param array<string,mixed> $filters */
|
||||
private function matchesWorkflowFilters(array $workflow, array $filters): bool
|
||||
{
|
||||
$createdFrom = trim((string) ($filters['created_from'] ?? ''));
|
||||
if ($createdFrom !== '') {
|
||||
$createdAt = $this->workflowDate($workflow['createAt'] ?? null);
|
||||
if ($createdAt === null || $createdAt < $createdFrom) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$finishedTo = trim((string) ($filters['finished_to'] ?? ''));
|
||||
if ($finishedTo !== '') {
|
||||
$finishTime = $this->workflowDate($workflow['finishTime'] ?? null);
|
||||
if ($finishTime === null || $finishTime > $finishedTo) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$requestedStatus = strtoupper(trim((string) ($filters['status'] ?? '')));
|
||||
if ($requestedStatus !== '') {
|
||||
$actualStatus = strtoupper(trim((string) ($workflow['status'] ?? '')));
|
||||
$statusMatches = $requestedStatus === 'CANCELED'
|
||||
? in_array($actualStatus, ['CANCELED', 'CANCELLED'], true)
|
||||
: $actualStatus === $requestedStatus;
|
||||
if (! $statusMatches) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function workflowDate(mixed $value): ?string
|
||||
{
|
||||
$date = substr(trim((string) ($value ?? '')), 0, 10);
|
||||
|
||||
return preg_match('/^\d{4}-\d{2}-\d{2}$/', $date) === 1 ? $date : null;
|
||||
}
|
||||
|
||||
/** @return array<string,mixed> */
|
||||
private function formFields(array $rows): array
|
||||
{
|
||||
|
||||
@ -32,6 +32,15 @@
|
||||
'DELETED' => '已删除',
|
||||
][strtoupper($status)] ?? $status;
|
||||
};
|
||||
$statusOptions = [
|
||||
'' => '全部状态',
|
||||
'RUNNING' => '进行中',
|
||||
'COMPLETED' => '已完成',
|
||||
'TERMINATED' => '已终止',
|
||||
'CANCELED' => '已取消',
|
||||
'REJECTED' => '已驳回',
|
||||
'FAILED' => '失败',
|
||||
];
|
||||
@endphp
|
||||
|
||||
<div class="ding-payable-page">
|
||||
@ -40,8 +49,11 @@
|
||||
.ding-payable-toolbar { display:flex; flex-wrap:wrap; align-items:flex-end; gap:.75rem; padding:1rem; margin-bottom:1rem; border:1px solid var(--vip-border,#D8D2C7); border-radius:.5rem; background:var(--vip-surface,#fff); }
|
||||
.ding-payable-field { display:flex; flex-direction:column; gap:.35rem; min-width:16rem; }
|
||||
.ding-payable-field label { color:var(--vip-content-muted,#595959); font-size:.75rem; font-weight:600; }
|
||||
.ding-payable-field input { height:2.25rem; padding:0 .65rem; border:1px solid var(--vip-border,#D8D2C7); border-radius:.5rem; background:#fff; color:var(--vip-content-ink,#171717); }
|
||||
.ding-payable-field input:focus { border-color:var(--vip-content-accent-dark,#856632); outline:none; box-shadow:0 0 0 3px rgba(133,102,50,.2); }
|
||||
.ding-payable-field input,.ding-payable-field select { height:2.25rem; padding:0 .65rem; border:1px solid var(--vip-border,#D8D2C7); border-radius:.5rem; background:#fff; color:var(--vip-content-ink,#171717); }
|
||||
.ding-payable-field input:focus,.ding-payable-field select:focus { border-color:var(--vip-content-accent-dark,#856632); outline:none; box-shadow:0 0 0 3px rgba(133,102,50,.2); }
|
||||
.ding-payable-date-range { display:flex; align-items:center; gap:.5rem; }
|
||||
.ding-payable-date-range input { min-width:9rem; }
|
||||
.ding-payable-date-range span { color:var(--vip-content-muted,#595959); }
|
||||
.ding-payable-actions { display:flex; gap:.5rem; }
|
||||
.ding-payable-button { display:inline-flex; align-items:center; gap:.35rem; height:2.25rem; padding:0 .85rem; border:1px solid var(--vip-border,#D8D2C7); border-radius:.5rem; background:#fff; color:var(--vip-content-ink,#171717); text-decoration:none; font-weight:600; }
|
||||
.ding-payable-button.primary { border-color:var(--vip-content-accent-dark,#856632); background:var(--vip-content-accent-dark,#856632); color:#fff; }
|
||||
@ -66,6 +78,22 @@
|
||||
<label for="ding-payable-process-id">审批编号或流程实例 ID(可选)</label>
|
||||
<input id="ding-payable-process-id" name="process_instance_id" value="{{ $filters['process_instance_id'] ?? '' }}" placeholder="输入钉钉审批编号或流程实例 ID">
|
||||
</div>
|
||||
<div class="ding-payable-field ding-payable-date-field">
|
||||
<label for="ding-payable-created-from">流程时间(创建时间至完成时间)</label>
|
||||
<div class="ding-payable-date-range">
|
||||
<input id="ding-payable-created-from" type="date" name="created_from" value="{{ $filters['created_from'] ?? '' }}" aria-label="创建时间起">
|
||||
<span aria-hidden="true">至</span>
|
||||
<input id="ding-payable-finished-to" type="date" name="finished_to" value="{{ $filters['finished_to'] ?? '' }}" aria-label="完成时间止">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ding-payable-field ding-payable-status-field">
|
||||
<label for="ding-payable-status">状态</label>
|
||||
<select id="ding-payable-status" name="status">
|
||||
@foreach ($statusOptions as $optionValue => $optionLabel)
|
||||
<option value="{{ $optionValue }}" @selected(($filters['status'] ?? '') === $optionValue)>{{ $optionLabel }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="ding-payable-actions">
|
||||
<button class="ding-payable-button primary" type="submit"><span class="material-icons-outlined" aria-hidden="true">search</span>查询</button>
|
||||
<a class="ding-payable-button" href="{{ route('business.pages.show', ['section' => $section['slug'], 'page' => $page['slug']]) }}"><span class="material-icons-outlined" aria-hidden="true">refresh</span>重置</a>
|
||||
|
||||
@ -66,4 +66,39 @@ class DingPayableWorkflowPageTest extends FeatureTestCase
|
||||
->assertSee('钉钉应付流程镜像尚未完成同步,请稍后重试。')
|
||||
->assertSee('镜像读取失败,请稍后重试。');
|
||||
}
|
||||
|
||||
public function test_cloud_warehouse_vehicle_fee_page_passes_workflow_time_and_status_filters(): void
|
||||
{
|
||||
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
|
||||
$repository = Mockery::mock(DingPayableWorkflowMirrorRepository::class);
|
||||
$repository->shouldReceive('paginate')->once()->with(
|
||||
[
|
||||
'process_instance_id' => '',
|
||||
'created_from' => '2026-07-01',
|
||||
'finished_to' => '2026-07-31',
|
||||
'status' => 'COMPLETED',
|
||||
],
|
||||
1,
|
||||
Mockery::type('int'),
|
||||
)->andReturn([
|
||||
'data' => [],
|
||||
'total' => 0,
|
||||
'status' => 'succeeded',
|
||||
'last_synced_at' => '2026-08-29 10:11:24',
|
||||
]);
|
||||
$this->app->instance(DingPayableWorkflowMirrorRepository::class, $repository);
|
||||
|
||||
$this->loginAs()->get(route('business.pages.show', [
|
||||
'section' => 'courier-payables',
|
||||
'page' => 'payable-cloud-warehouse-vehicle-fee',
|
||||
'created_from' => '2026-07-01',
|
||||
'finished_to' => '2026-07-31',
|
||||
'status' => 'completed',
|
||||
]))->assertOk()
|
||||
->assertSee('流程时间(创建时间至完成时间)')
|
||||
->assertSee('2026-07-01')
|
||||
->assertSee('2026-07-31')
|
||||
->assertSee('状态')
|
||||
->assertSee('全部状态');
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user