CaiWuXiTong/modules/EcommerceFinance/Repositories/StoreAccountMirrorRepository.php
WuYongJie eb1036d0c3 整合业务资料查询与表格交互 (#266)
整合业务资料字段查询、排序、列设置与导出,并保留最新主线的数据隔离和报表修复。
2026-09-24 15:10:33 +08:00

157 lines
6.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Modules\EcommerceFinance\Repositories;
use Modules\EcommerceFinance\Services\BusinessMirrorDatasetRegistry;
use RuntimeException;
class StoreAccountMirrorRepository
{
public const DATASET = 'database_4.external_store_accounts.accounts_v1';
public function __construct(
private readonly BusinessMirrorDatasetRegistry $datasets,
private readonly GenericBusinessMirrorRepository $mirror,
) {}
/** @return array{data:array<int,array<string,mixed>>,total:int} */
public function paginate(int $page, int $perPage, array $filters = []): array
{
$dataset = $this->datasets->get(self::DATASET);
if (! $this->mirror->ready($dataset)) {
throw new RuntimeException('store_account_mirror_not_ready');
}
$page = max($page, 1);
$perPage = min(max($perPage, 1), 100);
$query = $this->mirror->connection()->table($dataset->targetTable());
$columns = [
'store_name' => 'storeName', 'operation_owner' => 'operationOwner',
'operation_department_head' => 'operationDepartmentHead', 'operation_director' => 'operationDirector',
'profit_center' => 'profitCenter', 'account' => 'account', 'bound_phone' => 'boundPhone',
'verification_contact' => 'verificationContact', 'account_group_name' => 'accountGroupName',
];
foreach ($columns as $key => $column) {
$value = mb_substr(trim((string) ($filters[$key] ?? '')), 0, 191);
if ($value !== '') $query->where($column, 'like', '%' . addcslashes($value, '%_\\') . '%');
}
$accountType = trim((string) ($filters['account_type'] ?? ''));
if ($accountType !== '') $query->where('accountType', '=', $accountType === '主账号' ? 'MAIN' : ($accountType === '子账号' ? 'SUB' : $accountType));
$passwordState = trim((string) ($filters['password_configured'] ?? ''));
if (in_array($passwordState, ['已设置', '未设置', '状态未同步'], true)) {
if ($passwordState === '状态未同步') $query->whereNull('passwordConfigured');
else $query->where('passwordConfigured', $passwordState === '已设置');
}
foreach (['created_at' => 'createdAt', 'updated_at' => 'updatedAt'] as $key => $column) {
foreach (['_from' => '>=', '_to' => '<='] as $suffix => $operator) {
$date = trim((string) ($filters[$key . $suffix] ?? ''));
if (preg_match('/^\d{4}-\d{2}-\d{2}$/D', $date)) $query->whereDate($column, $operator, $date);
}
}
$total = (clone $query)->count();
$sortColumns = [
'store_name' => 'storeName', 'operation_owner' => 'operationOwner',
'operation_department_head' => 'operationDepartmentHead', 'operation_director' => 'operationDirector',
'profit_center' => 'profitCenter', 'account_type' => 'accountType', 'account' => 'account',
'password_configured' => 'passwordConfigured', 'bound_phone' => 'boundPhone',
'verification_contact' => 'verificationContact', 'account_group_name' => 'accountGroupName',
'created_at' => 'createdAt', 'updated_at' => 'updatedAt',
];
$sortColumn = $sortColumns[$filters['_sort'] ?? ''] ?? null;
$direction = ($filters['_direction'] ?? 'asc') === 'desc' ? 'desc' : 'asc';
if ($sortColumn !== null) {
$query->orderBy($sortColumn, $direction)->orderByDesc('id');
} else {
$query->orderByDesc('id');
}
$rows = $query
->forPage($page, $perPage)
->get()
->map(fn (object $row): array => [
'id' => $row->id,
'store_name' => $row->storeName,
'operation_owner' => $row->operationOwner,
'operation_department_head' => $row->operationDepartmentHead,
'operation_director' => $row->operationDirector,
'profit_center' => $row->profitCenter,
'account_type' => $this->accountType($row->accountType),
'account' => $row->account,
// Only the safe boolean may enter the mirror, never a password.
'password_configured' => isset($row->passwordConfigured) ? (bool) $row->passwordConfigured : null,
'bound_phone' => $row->boundPhone,
'verification_contact' => $row->verificationContact,
'account_group_name' => $row->accountGroupName,
'created_at' => $row->createdAt,
'updated_at' => $row->updatedAt,
])
->all();
return ['data' => $rows, 'total' => $total];
}
public function containsAccount(string $id): bool
{
$dataset = $this->datasets->get(self::DATASET);
if (! $this->mirror->ready($dataset)) {
throw new RuntimeException('store_account_mirror_not_ready');
}
return $this->mirror->connection()->table($dataset->targetTable())->where('id', $id)->exists();
}
public function containsAccounts(array $ids): bool
{
$ids = array_values(array_unique($ids));
if ($ids === []) {
return false;
}
$dataset = $this->datasets->get(self::DATASET);
if (! $this->mirror->ready($dataset)) {
throw new RuntimeException('store_account_mirror_not_ready');
}
return $this->mirror->connection()->table($dataset->targetTable())
->whereIn('id', $ids)->distinct()->count('id') === count($ids);
}
/**
* 店铺维度报表的归属字段覆盖表,以店铺名称(storeName)为键。
*
* @return array<string,array{operation_owner:string,operation_director:string,profit_center:string}>
*/
public function ownershipByStoreName(): array
{
$dataset = $this->datasets->get(self::DATASET);
if (! $this->mirror->ready($dataset)) {
throw new RuntimeException('store_account_mirror_not_ready');
}
$map = [];
foreach ($this->mirror->connection()->table($dataset->targetTable())
->select('storeName', 'operationOwner', 'operationDirector', 'profitCenter')
->get() as $row) {
$name = trim((string) $row->storeName);
if ($name === '') {
continue;
}
$map[$name] = [
'operation_owner' => trim((string) $row->operationOwner),
'operation_director' => trim((string) $row->operationDirector),
'profit_center' => trim((string) $row->profitCenter),
];
}
return $map;
}
private function accountType(mixed $value): ?string
{
$type = trim((string) $value);
return match (strtoupper($type)) {
'MAIN' => '主账号',
'SUB' => '子账号',
'', '/' => null,
default => $type,
};
}
}