fix: 店铺流程当前审批人显示全量候选 #970
@ -68,11 +68,19 @@ class UpstreamBusinessInformation
|
||||
private function shopInfoFlowPage(int $page, int $perPage): array
|
||||
{
|
||||
try {
|
||||
return app(\Modules\EcommerceFinance\Repositories\ShopInfoFlowMirrorRepository::class)->paginate(
|
||||
$repository = app(\Modules\EcommerceFinance\Repositories\ShopInfoFlowMirrorRepository::class);
|
||||
$filters = $this->pageFilters('financial-risk-control', 'process-statistics');
|
||||
$payload = $repository->paginate(
|
||||
$page,
|
||||
$perPage,
|
||||
$this->pageFilters('financial-risk-control', 'process-statistics'),
|
||||
$filters,
|
||||
);
|
||||
request()->attributes->set(
|
||||
'process-statistics.current-approvers',
|
||||
$repository->currentApproverOptions($filters),
|
||||
);
|
||||
|
||||
return $payload;
|
||||
} catch (\RuntimeException $exception) {
|
||||
report($exception);
|
||||
|
||||
|
||||
@ -116,6 +116,37 @@ class ShopInfoFlowMirrorRepository
|
||||
return ['data' => $rows, 'total' => $total];
|
||||
}
|
||||
|
||||
/** @param array<string,mixed> $filters
|
||||
* @return list<string>
|
||||
*/
|
||||
public function currentApproverOptions(array $filters = []): array
|
||||
{
|
||||
if (! $this->ready()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$connection = $this->mirror->connection();
|
||||
$form = $this->datasets->get(self::FORM_DATASET)->targetTable();
|
||||
$flow = $this->datasets->get(self::FLOW_DATASET)->targetTable();
|
||||
unset($filters['current_approver']);
|
||||
|
||||
$query = $connection->table($form . ' as f')
|
||||
->leftJoin($flow . ' as o', 'o.flowId', '=', 'f.flowId')
|
||||
->whereNotNull('o.approver')
|
||||
->where('o.approver', '!=', '');
|
||||
$this->applyFilters($query, $filters);
|
||||
|
||||
return $query
|
||||
->pluck('o.approver')
|
||||
->flatMap(static fn (mixed $value): array => preg_split('/[,,]/u', (string) $value, -1, PREG_SPLIT_NO_EMPTY) ?: [])
|
||||
->map(static fn (mixed $value): string => trim((string) $value))
|
||||
->filter(static fn (string $value): bool => $value !== '')
|
||||
->unique()
|
||||
->sort(static fn (string $left, string $right): int => strnatcasecmp($left, $right))
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
/** @param array<string,mixed> $filters */
|
||||
private function applyFilters(Builder $query, array $filters): void
|
||||
{
|
||||
|
||||
@ -1921,6 +1921,12 @@
|
||||
default => [],
|
||||
};
|
||||
$directoryMultiSelectFields = array_keys($directoryMultiSelectOptions);
|
||||
$directoryQuerySuggestionOptions = match (($section['slug'] ?? '') . '/' . ($page['slug'] ?? '')) {
|
||||
'financial-risk-control/process-statistics' => [
|
||||
'current_approver' => (array) request()->attributes->get('process-statistics.current-approvers', []),
|
||||
],
|
||||
default => [],
|
||||
};
|
||||
$directoryColumnNames = collect($directoryFields)->pluck('name')->all();
|
||||
$requestedDirectoryColumns = array_values(array_intersect(
|
||||
array_filter(explode(',', (string) request('columns', ''))),
|
||||
@ -2033,7 +2039,7 @@
|
||||
@endforeach
|
||||
</select>
|
||||
@else
|
||||
<input type="search" form="{{ $directoryQueryFormId }}" name="{{ $field['name'] }}" value="{{ request($field['name']) }}" autocomplete="off" placeholder="{{ $field['placeholder'] ?? ('搜索' . $field['label']) }}" data-directory-query-input="{{ $field['name'] }}" aria-label="搜索{{ $field['label'] }}">
|
||||
<input type="search" form="{{ $directoryQueryFormId }}" name="{{ $field['name'] }}" value="{{ request($field['name']) }}" autocomplete="off" placeholder="{{ $field['placeholder'] ?? ('搜索' . $field['label']) }}" data-directory-query-input="{{ $field['name'] }}" data-directory-server-options="{{ json_encode($directoryQuerySuggestionOptions[$field['name']] ?? [], JSON_UNESCAPED_UNICODE) }}" aria-label="搜索{{ $field['label'] }}">
|
||||
<ul class="directory-query-suggestions" data-directory-query-suggestions="{{ $field['name'] }}" hidden></ul>
|
||||
@endif
|
||||
</label>
|
||||
@ -2088,7 +2094,7 @@
|
||||
@endforeach
|
||||
</select>
|
||||
@else
|
||||
<input type="search" form="{{ $directoryQueryFormId }}" name="{{ $field['name'] }}" value="{{ request($field['name']) }}" autocomplete="off" placeholder="{{ $field['placeholder'] ?? ('搜索' . $field['label']) }}" data-directory-query-input="{{ $field['name'] }}" aria-label="搜索{{ $field['label'] }}">
|
||||
<input type="search" form="{{ $directoryQueryFormId }}" name="{{ $field['name'] }}" value="{{ request($field['name']) }}" autocomplete="off" placeholder="{{ $field['placeholder'] ?? ('搜索' . $field['label']) }}" data-directory-query-input="{{ $field['name'] }}" data-directory-server-options="{{ json_encode($directoryQuerySuggestionOptions[$field['name']] ?? [], JSON_UNESCAPED_UNICODE) }}" aria-label="搜索{{ $field['label'] }}">
|
||||
<ul class="directory-query-suggestions" data-directory-query-suggestions="{{ $field['name'] }}" hidden></ul>
|
||||
@endif
|
||||
</label>
|
||||
@ -3717,11 +3723,19 @@
|
||||
if (!list) return;
|
||||
const key = field.dataset.directoryQueryField;
|
||||
const needle = value.trim().toLocaleLowerCase();
|
||||
let serverOptions = [];
|
||||
try {
|
||||
serverOptions = JSON.parse(field.querySelector('[data-directory-server-options]')?.dataset.directoryServerOptions || '[]') || [];
|
||||
} catch (_) {
|
||||
serverOptions = [];
|
||||
}
|
||||
const candidates = key === 'related_people'
|
||||
? rows().flatMap((row) => ['legal_representative', 'shareholders', 'supervisor', 'billing_officer']
|
||||
.map((column) => (row.querySelector(`[data-column-key="${column}"]`)?.textContent || '').trim()))
|
||||
: rows().map((row) => fieldValues(row, key));
|
||||
const values = [...new Set(candidates.filter((item) => item && item !== '—' && (!needle || item.toLocaleLowerCase().includes(needle))))].slice(0, 8);
|
||||
const values = [...new Set([...serverOptions, ...candidates].filter(
|
||||
(item) => item && item !== '—' && (!needle || String(item).toLocaleLowerCase().includes(needle)),
|
||||
))].slice(0, 8);
|
||||
list.innerHTML = values.map((item) => `<li><button type="button" data-directory-suggestion-value="${item.replaceAll('&','&').replaceAll('\"','"').replaceAll('<','<').replaceAll('>','>')}">${item.replaceAll('&','&').replaceAll('<','<').replaceAll('>','>')}</button></li>`).join('');
|
||||
list.hidden = values.length === 0;
|
||||
list.querySelectorAll('button').forEach((button) => button.addEventListener('click', () => {
|
||||
|
||||
@ -139,6 +139,46 @@ class ShopInfoFlowMirrorRepositoryTest extends TestCase
|
||||
$this->assertSame(0, $this->repository->paginate(1, 10, ['flow_id' => '不存在'])['total']);
|
||||
}
|
||||
|
||||
public function test_current_approver_options_include_all_rows_matching_other_filters(): void
|
||||
{
|
||||
$db = DB::connection('business_mirror');
|
||||
foreach ([
|
||||
[10, 'approver-1', '查查'],
|
||||
[11, 'approver-2', '玉兔'],
|
||||
[12, 'approver-3', '查查,常仪'],
|
||||
] as [$id, $flowId, $approver]) {
|
||||
$this->insertApplication(
|
||||
$id,
|
||||
$flowId,
|
||||
10,
|
||||
'京东',
|
||||
'审批人测试' . $id,
|
||||
'ERP-审批人测试' . $id,
|
||||
'申请人' . $id,
|
||||
'2026-10-05 09:00:00',
|
||||
);
|
||||
$db->table('oa_flow_flow')->insert([
|
||||
'Id' => $id,
|
||||
'flowId' => $flowId,
|
||||
'flowType' => 10,
|
||||
'flowStatus' => 1,
|
||||
'subject' => '[店铺关店-审批人测试' . $id . ']',
|
||||
'approver' => $approver,
|
||||
'updateTime' => '2026-10-05 10:00:00',
|
||||
]);
|
||||
}
|
||||
|
||||
$options = $this->repository->currentApproverOptions([
|
||||
'flow_type' => ['店铺关店'],
|
||||
'current_approver' => '玉兔',
|
||||
]);
|
||||
|
||||
$this->assertEqualsCanonicalizing(['查查', '玉兔', '常仪'], $options);
|
||||
$this->assertSame(['审核人A'], $this->repository->currentApproverOptions([
|
||||
'flow_type' => ['店铺变更'],
|
||||
]));
|
||||
}
|
||||
|
||||
public function test_it_groups_waiting_time_by_days_and_filters_selected_day_buckets(): void
|
||||
{
|
||||
Carbon::setTestNow('2026-11-05 12:00:00');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user