UserConfigController.php 8.94 KB
<?php

namespace App\Http\Container\AdminSection\Controllers\System\Broker;

use App\Helpers\OperationLog;
use App\Http\Container\AdminSection\Requests\System\BrokerPushLevelRecordRequest;
use App\Http\Container\AdminSection\Requests\System\BrokerUserConfigRequest;
use App\Jobs\BrokerPushLevelRecordCreateJob;
use App\Models\BrokerUserConfig;
use App\Models\BrokerUserConfigItem;
use App\Models\User;
use Arr;
use Auth;
use Carbon\Carbon;
use Hikoon\LaravelApi\Facades\Response;
use Hikoon\LaravelApi\Support\ApiCode;
use Hikoon\LaravelApi\Support\ApiController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\LazyCollection;
use Str;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Vtiful\Kernel\Excel;

class UserConfigController extends ApiController
{
    /**
     * @param \Illuminate\Http\Request $request
     * @return \Hikoon\LaravelApi\Facades\Response
     */
    public function index(Request $request): Response
    {
        $pageSize  = $request->get('pageSize', 20);
        $fetchType = $request->get('fetchType', 'page');
        $filter    = $request->except(['page', 'pageSize', 'fetchType']);
        $build     = BrokerUserConfig::query()->filter($filter);

        if ($fetchType === 'all') {
            return $this->successWithData($build->get());
        }

        return $this->successWithData($build->paginate($pageSize));
    }

    /**
     * @param \App\Http\Container\AdminSection\Requests\System\BrokerUserConfigRequest $request
     * @return \Hikoon\LaravelApi\Facades\Response
     */
    public function store(BrokerUserConfigRequest $request): Response
    {
        if (!RateLimiter::attempt('user-' . Auth::id() . '-create-broker', $perMinute = 1, static fn() => NULL, 3)) {
            return $this->fail(ApiCode::REQUEST_LIMIT_ERROR);
        }

        $attribute = $request->safe(['title', 'begin_at', 'end_at', 'push_type', 'push_at']) + ['user_id' => Auth::id()];
        $items     = $request->input('items', []);

        $userConfig = DB::transaction(static function () use ($attribute, $items) {
            $config = BrokerUserConfig::query()->create(Arr::except($attribute, ['push_type', 'push_at']));

            BrokerUserConfigItem::query()->upsert(
                Arr::map($items, static fn($item) => Arr::only($item + ['config_id' => $config->getKey()], ['user_id', 'identifier', 'singer_num', 'config_id'])),
                ['config_id', 'user_id'], ['singer_num', 'identifier']
            );

            BrokerUserConfigItem::query()
                ->leftJoin('users', 'users.id', 'broker_user_config_items.user_id')
                ->where('broker_user_config_items.config_id', $config->getKey())
                ->whereIn('users.identity', [2, 3])
                ->update(['broker_user_config_items.status' => DB::raw('CASE WHEN users.`status`= 1 THEN 1 ELSE 0 END')]);

            BrokerPushLevelRecordCreateJob::dispatchIf($attribute['push_type'] !== 0, $config, Auth::id(), Carbon::parse($attribute['push_at']), $attribute['push_type'] === 2);
            OperationLog::admin()->subject($config)->createAction()->content('经纪人配置《%s》', Str::limit($config->getAttribute('title')));

            return $config;
        });

        return $this->successWithData($userConfig, ApiCode::CREATE_SUCCESS);
    }

    /**
     * @param \App\Models\BrokerUserConfig $userConfig
     * @return \Hikoon\LaravelApi\Facades\Response
     */
    public function show(BrokerUserConfig $userConfig): Response
    {
        $userConfig->load(['user:id,nick_name,real_name,identity', 'items:id,user_id,config_id,identifier,singer_num,status', 'items.user:id,nick_name,real_name,identity']);

        return $this->successWithData($userConfig);
    }

    /**
     * @param \App\Http\Container\AdminSection\Requests\System\BrokerUserConfigRequest $request
     * @param \App\Models\BrokerUserConfig                                             $userConfig
     * @return \Hikoon\LaravelApi\Facades\Response
     */
    public function update(BrokerUserConfigRequest $request, BrokerUserConfig $userConfig): Response
    {
        $attribute = $request->safe(['title', 'begin_at', 'end_at']) + ['user_id' => Auth::id()];
        $items     = $request->input('items', []);

        DB::transaction(static function () use ($userConfig, $attribute, $items) {
            $userConfig->update($attribute);
            $itemIds = Arr::pluck($items, 'user_id');
            //删除不在此次用户数据
            BrokerUserConfigItem::query()->where('config_id', $userConfig->getKey())->whereNotIn('user_id', $itemIds)->delete();
            //新增与更新数据
            BrokerUserConfigItem::query()->upsert(
                Arr::map($items, static fn($item) => Arr::only($item + ['config_id' => $userConfig->getKey()], ['user_id', 'identifier', 'singer_num', 'config_id'])),
                ['config_id', 'user_id'], ['singer_num', 'identifier']
            );
            //同步经纪人匹配状态
            BrokerUserConfigItem::query()
                ->leftJoin('users', 'users.id', 'broker_user_config_items.user_id')
                ->where('broker_user_config_items.config_id', $userConfig->getKey())
                ->whereIn('users.identity', [2, 3])
                ->update(['broker_user_config_items.status' => DB::raw('CASE WHEN users.`status`= 1 AND users.`identity` IN (2,3) THEN 1 ELSE 0 END')]);
            OperationLog::admin()->subject($userConfig)->updateAction()->content('经纪人配置《%s》', Str::limit($userConfig->getAttribute('title')));
        });


        return $this->successWithData($userConfig, ApiCode::CREATE_SUCCESS);
    }

    /**
     * @param \App\Models\BrokerUserConfig $userConfig
     * @return \Hikoon\LaravelApi\Facades\Response
     */
    public function destroy(BrokerUserConfig $userConfig): Response
    {
        $userConfig->delete();
        $userConfig->items()->delete();
        OperationLog::admin()->subject($userConfig)->deleteAction()->content('经纪人配置《%s》', Str::limit($userConfig->getAttribute('title')));
        return $this->success(ApiCode::DELETE_SUCCESS);
    }

    /**
     * @param \App\Http\Container\AdminSection\Requests\System\BrokerPushLevelRecordRequest $request
     * @param \App\Models\BrokerUserConfig                                                  $userConfig
     * @return \Hikoon\LaravelApi\Facades\Response
     */
    public function storeLevelRecord(BrokerPushLevelRecordRequest $request, BrokerUserConfig $userConfig): Response
    {
        $attribute = $request->safe()->toArray();
        BrokerPushLevelRecordCreateJob::dispatchSync($userConfig, Auth::id(), Carbon::parse($attribute['publish_at']), (bool)$attribute['is_alert']);
        return $this->success(ApiCode::CREATE_SUCCESS);
    }

    /**
     * @param \Illuminate\Http\Request $request
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
     */
    public function upload(Request $request): StreamedResponse
    {
        ignore_user_abort(true);
        return \Response::stream(static function () use ($request) {
            LazyCollection::make(static function () use ($request) {
                $filePath = $request->file('file')?->path();
                $excel    = new Excel(['path' => dirname($filePath)]);
                $excel->openFile(basename($filePath))->openSheet()->setSkipRows(0);

                while (($row = $excel->nextRow()) !== NULL) {
                    yield $row;
                }
            })->chunk(1000)->each(function (LazyCollection $items) {
                $users = User::withTrashed()->whereIn('id', Arr::pluck($items, 0))->get(['id', 'identity', 'nick_name', 'status'])->groupBy('id');
                $items->reject(fn($item) => array_filter($item) === [])->each(function ($item) use ($users) {
                    if (isset($item[0], $item[1], $item[2]) && is_int($item[0]) && (is_int($item[2]) || empty($item[2]))) {
                        $user = $users->get($item[0])?->first();

                        echo "id: " . $item[0] . PHP_EOL . "event: item" . PHP_EOL . "data: " . json_encode([
                                'user'       => ['id' => $item[0], 'nick_name' => $user?->getRawOriginal('nick_name', '')],
                                'identifier' => $item[1],
                                'singer_num' => $item[2],
                                'status'     => ($user?->getRawOriginal('status') === 1 && in_array($user?->getRawOriginal('identity'), [2, 3], false)) ? 1 : 0
                            ], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE) . PHP_EOL . 'retry: 5000' . PHP_EOL . PHP_EOL;
                        ob_flush();
                        flush();
                    }
                });
            });

            echo "id: 0" . PHP_EOL . "event: finish" . PHP_EOL . "data: {}" . PHP_EOL . 'retry: 0' . PHP_EOL . PHP_EOL;
            ob_flush();
            flush();

        }, 200, ['Cache-Control' => 'no-cache', 'Content-Type' => 'text/event-stream', 'X-Accel-Buffering' => 'no']);
    }
}