Find this useful? Enter your email to receive occasional updates for securing PHP code.

Signing you up...

Thank you for signing up!

PHP Decode

<?php namespace App\Http\Controllers\Api; use App\Tasks\PushTask; use DB; use Hhxsv5\Lar..

Decoded Output download

<?php

namespace App\Http\Controllers\Api;

use App\Tasks\PushTask;
use DB;
use Hhxsv5\LaravelS\Swoole\Task\Task;
use Request;
use Redirect;
use Carbon\Carbon;
use App\Models\File;
use App\Models\User;
use App\Module\Base;
use App\Module\Extranet;
use App\Module\TimeRange;
use App\Models\FileContent;
use App\Models\AbstractModel;
use App\Models\WebSocketDialog;
use App\Models\WebSocketDialogMsg;
use App\Models\WebSocketDialogUser;
use App\Models\WebSocketDialogMsgRead;
use App\Models\WebSocketDialogMsgTodo;

/**
 * @apiDefine dialog
 *
 * 
 */
class DialogController extends AbstractController
{
    /**
     * @api {get} api/dialog/lists          01. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName lists
     *
     * @apiParam {String} [timerange]        1678248944,1678248944
     * - : 
     * - : ID1: deleted_id
     *
     * @apiParam {Number} [page]            :1
     * @apiParam {Number} [pagesize]        :50:100
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function lists()
    {
        $user = User::auth();
        //
        $timerange = TimeRange::parse(Request::input());
        //
        $data = WebSocketDialog::getDialogList($user->userid, $timerange->updated, $timerange->deleted);
        //
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/beyond          02. 
     *
     * @apiDescription token  
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName beyond
     *
     * @apiParam {String} unread_at         
     * - 12021-01-01 00:00:00
     * - 21612051200
     * @apiParam {String} todo_at           
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function beyond()
    {
        $user = User::auth();
        //
        $unreadAt = Request::input('unread_at');
        $todoAt = Request::input('todo_at');
        //
        $unreadAt = Base::isNumber($unreadAt) ? intval($unreadAt) : trim($unreadAt);
        $unreadAt = Carbon::parse($unreadAt)->setTimezone(config('app.timezone'));
        //
        $todoAt = Base::isNumber($todoAt) ? intval($todoAt) : trim($todoAt);
        $todoAt = Carbon::parse($todoAt)->setTimezone(config('app.timezone'));
        //
        $data = WebSocketDialog::getDialogBeyond($user->userid, $unreadAt, $todoAt);
        //
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/search          03. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName search
     *
     * @apiParam {String} key         
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function search()
    {
        $user = User::auth();
        //
        $key = trim(Request::input('key'));
        if (empty($key)) {
            return Base::retError('');
        }
        // 
        $dialogs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
            ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
            ->where('web_socket_dialogs.name', 'LIKE', "%{$key}%")
            ->where('u.userid', $user->userid)
            ->orderByDesc('u.top_at')
            ->orderByDesc('u.last_at')
            ->take(20)
            ->get();
        $dialogs->transform(function (WebSocketDialog $item) use ($user) {
            return $item->formatData($user->userid);
        });
        $list = $dialogs->toArray();
        // 
        if (count($list) < 20 && Base::judgeClientVersion("0.21.60")) {
            $users = User::select(User::$basicField)
                ->where(function ($query) use ($key) {
                    if (str_contains($key, "@")) {
                        $query->where("email", "like", "%{$key}%");
                    } else {
                        $query->where("nickname", "like", "%{$key}%")->orWhere("pinyin", "like", "%{$key}%");
                    }
                })->orderBy('userid')
                ->take(20 - count($list))
                ->get();
            $users->transform(function (User $item) {
                return [
                    'id' => 'u:' . $item->userid,
                    'type' => 'user',
                    'name' => $item->nickname,
                    'dialog_user' => $item,
                    'last_msg' => null,
                ];
            });
            $list = array_merge($list, $users->toArray());
        }
        // 
        if (count($list) < 20) {
            $msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
                ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
                ->join('web_socket_dialog_msgs as m', 'web_socket_dialogs.id', '=', 'm.dialog_id')
                ->where('u.userid', $user->userid)
                ->where('m.key', 'LIKE', "%{$key}%")
                ->orderByDesc('m.id')
                ->take(20 - count($list))
                ->get();
            $msgs->transform(function (WebSocketDialog $item) use ($user) {
                return $item->formatData($user->userid);
            });
            $list = array_merge($list, $msgs->toArray());
        }
        //
        return Base::retSuccess('success', $list);
    }

    /**
     * @api {get} api/dialog/search/tag          04. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName search__tag
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function search__tag()
    {
        $user = User::auth();
        // 
        $msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
            ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
            ->join('web_socket_dialog_msgs as m', 'web_socket_dialogs.id', '=', 'm.dialog_id')
            ->where('u.userid', $user->userid)
            ->where('m.tag', '>', 0)
            ->orderByDesc('m.id')
            ->take(50)
            ->get();
        $msgs->transform(function (WebSocketDialog $item) use ($user) {
            return $item->formatData($user->userid);
        });
        //
        return Base::retSuccess('success', $msgs->toArray());
    }

    /**
     * @api {get} api/dialog/one          05. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName one
     *
     * @apiParam {Number} dialog_id         ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function one()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $item = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
            ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
            ->where('web_socket_dialogs.id', $dialog_id)
            ->where('u.userid', $user->userid)
            ->first();
        if (empty($item)) {
            WebSocketDialogMsgRead::forceRead($dialog_id, $user->userid);
            return Base::retError('', ['dialog_id' => $dialog_id], -4003);
        }
        return Base::retSuccess('success', $item->formatData($user->userid));
    }

    /**
     * @api {get} api/dialog/user          06. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName user
     *
     * @apiParam {Number} dialog_id            ID
     * @apiParam {Number} [getuser]            1: 0: 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function user()
    {
        User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $getuser = intval(Request::input('getuser', 0));
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        //
        if ($getuser === 1) {
            $data = $dialog->dialogUser->toArray();
            $array = [];
            foreach ($data as $item) {
                $res = User::userid2basic($item['userid']);
                if ($res) {
                    $array[] = array_merge($item, $res->toArray());
                }
            }
            $array = array_filter($array, function ($item) {
                return $item['userid'] > 0;
            });
        } else {
            $data = WebSocketDialogUser::select(['web_socket_dialog_users.*', 'users.bot'])
                ->join('users', 'web_socket_dialog_users.userid', '=', 'users.userid')
                ->where('web_socket_dialog_users.dialog_id', $dialog_id)
                ->orderBy('web_socket_dialog_users.id')
                ->get();
            $array = $data->toArray();
        }
        return Base::retSuccess('success', $array);
    }

    /**
     * @api {get} api/dialog/todo          07. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName todo
     *
     * @apiParam {Number} [dialog_id]            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function todo()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $builder = WebSocketDialogMsgTodo::whereUserid($user->userid)->whereDoneAt(null);
        if ($dialog_id > 0) {
            WebSocketDialog::checkDialog($dialog_id);
            $builder->whereDialogId($dialog_id);
        }
        //
        $list = $builder->orderByDesc('id')->take(50)->get();
        return Base::retSuccess("success", $list);
    }

    /**
     * @api {get} api/dialog/top          08. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName top
     *
     * @apiParam {Number} dialog_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function top()
    {
        $user = User::auth();
        $dialogId = intval(Request::input('dialog_id'));
        $dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
        if (!$dialogUser) {
            return Base::retError("");
        }
        $dialogUser->top_at = $dialogUser->top_at ? null : Carbon::now();
        $dialogUser->save();
        return Base::retSuccess("success", [
            'id' => $dialogUser->dialog_id,
            'top_at' => $dialogUser->top_at?->toDateTimeString(),
        ]);
    }



    /**
     * @api {get} api/dialog/hide          09. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName hide
     *
     * @apiParam {Number} dialog_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function hide()
    {
        $user = User::auth();
        $dialogId = intval(Request::input('dialog_id'));
        $dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
        if (!$dialogUser) {
            return Base::retError("");
        }
        if ($dialogUser->top_at) {
            return Base::retError("");
        }
        $dialogUser->hide = 1;
        $dialogUser->save();
        return Base::retSuccess("success", [
            'id' => $dialogUser->dialog_id,
            'hide' => 1,
        ]);
    }

    /**
     * @api {get} api/dialog/tel          10. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName tel
     *
     * @apiParam {Number} dialog_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function tel()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        if ($dialog->type !== 'user') {
            return Base::retError("");
        }
        $dialogUser = $dialog->dialogUser->where('userid', '!=', $user->userid)->first();
        if (empty($dialogUser)) {
            return Base::retError("");
        }
        $callUser = User::find($dialogUser->userid);
        if (empty($callUser) || empty($callUser->tel)) {
            return Base::retError("");
        }
        if ($user->isTemp()) {
            return Base::retError("");
        }
        //
        $add = null;
        $res = WebSocketDialogMsg::sendMsg(null, $dialog->id, 'notice', [
            'notice' => $user->nickname . "  " . $callUser->nickname . " "
        ]);
        if (Base::isSuccess($res)) {
            $add = $res['data'];
        }
        //
        return Base::retSuccess("success", [
            'tel' => $callUser->tel,
            'add' => $add ?: null
        ]);
    }

    /**
     * @api {get} api/dialog/open/user          11. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName open__user
     *
     * @apiParam {Number} userid         ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function open__user()
    {
        $user = User::auth();
        //
        $userid = intval(Request::input('userid'));
        if (empty($userid)) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkUserDialog($user, $userid);
        if (empty($dialog)) {
            return Base::retError('');
        }
        $data = WebSocketDialog::find($dialog->id)?->formatData($user->userid);
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/msg/list          12. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__list
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {Number} [msg_id]          ID
     * @apiParam {Number} [position_id]     ID
     * @apiParam {Number} [prev_id]         ID
     * @apiParam {Number} [next_id]         ID
     * - position_idprev_idnext_id position_id > prev_id > next_id
     * @apiParam {String} [msg_type]        
     * - tag: 
     * - link: 
     * - text: 
     * - image: 
     * - file: 
     * - record: 
     * - meeting: 
     *
     * @apiParam {Number} [take]            :50:100
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__list()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $msg_id = intval(Request::input('msg_id'));
        $position_id = intval(Request::input('position_id'));
        $prev_id = intval(Request::input('prev_id'));
        $next_id = intval(Request::input('next_id'));
        $msg_type = trim(Request::input('msg_type'));
        $take = Base::getPaginate(100, 50);
        $data = [];
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        $reDialog = true;
        //
        $builder = WebSocketDialogMsg::select([
            'web_socket_dialog_msgs.*',
            'read.mention',
            'read.dot',
            'read.read_at',
        ])->leftJoin('web_socket_dialog_msg_reads as read', function ($leftJoin) use ($user) {
            $leftJoin
                ->on('read.userid', '=', DB::raw($user->userid))
                ->on('read.msg_id', '=', 'web_socket_dialog_msgs.id');
        })->where('web_socket_dialog_msgs.dialog_id', $dialog_id);
        //
        if ($msg_type) {
            if ($msg_type === 'tag') {
                $builder->where('tag', '>', 0);
            } elseif ($msg_type === 'todo') {
                $builder->where('todo', '>', 0);
            } elseif ($msg_type === 'link') {
                $builder->whereLink(1);
            } elseif (in_array($msg_type, ['text', 'image', 'file', 'record', 'meeting'])) {
                $builder->whereMtype($msg_type);
            } else {
                return Base::retError('');
            }
            $reDialog = false;
        }
        if ($msg_id > 0) {
            $builder->whereReplyId($msg_id);
            $reDialog = false;
        }
        //
        if ($position_id > 0) {
            $array = $builder->clone()
                ->where('web_socket_dialog_msgs.id', '>=', $position_id)
                ->orderBy('web_socket_dialog_msgs.id')
                ->take(intval($take / 2))
                ->get();
            $prev_id = intval($array->last()?->id);
        }
        //
        $cloner = $builder->clone();
        if ($prev_id > 0) {
            $cloner->where('web_socket_dialog_msgs.id', '<=', $prev_id)->orderByDesc('web_socket_dialog_msgs.id');
            $reDialog = false;
        } elseif ($next_id > 0) {
            $cloner->where('web_socket_dialog_msgs.id', '>=', $next_id)->orderBy('web_socket_dialog_msgs.id');
            $reDialog = false;
        } else {
            $cloner->orderByDesc('web_socket_dialog_msgs.id');
        }
        $list = $cloner->take($take)->get()->sortByDesc('id', SORT_NUMERIC)->values();
        //
        if ($list->isNotEmpty()) {
            $list->transform(function (WebSocketDialogMsg $item) {
                $item->next_id = 0;
                $item->prev_id = 0;
                return $item;
            });
            $first = $list->first();
            $first->next_id = intval($builder->clone()
                ->where('web_socket_dialog_msgs.id', '>', $first->id)
                ->orderBy('web_socket_dialog_msgs.id')
                ->value('id'));
            $last = $list->last();
            $last->prev_id = intval($builder->clone()
                ->where('web_socket_dialog_msgs.id', '<', $last->id)
                ->orderByDesc('web_socket_dialog_msgs.id')
                ->value('id'));
        }
        $data['list'] = $list;
        $data['time'] = Base::time();
        // 
        if ($dialog->type == 'group' && $dialog->group_type == 'task') {
            $user->task_dialog_id = $dialog->id;
            $user->save();
        }
        // 
        $isMarkDialogUser = WebSocketDialogUser::whereDialogId($dialog->id)->whereUserid($user->userid)->whereMarkUnread(1)->first();
        if ($isMarkDialogUser) {
            $isMarkDialogUser->mark_unread = 0;
            $isMarkDialogUser->save();
        }
        //
        if ($reDialog) {
            $data['dialog'] = $dialog->formatData($user->userid, true);
            $data['todo'] = $data['dialog']->todo_num > 0 ? WebSocketDialogMsgTodo::whereDialogId($dialog->id)->whereUserid($user->userid)->whereDoneAt(null)->orderByDesc('id')->take(50)->get() : [];
            $data['top'] = $dialog->top_msg_id ? WebSocketDialogMsg::whereId($dialog->top_msg_id)->first() : null;
        }
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/msg/latest          13. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__latest
     *
     * @apiParam {Array} [dialogs]          ID
     * - [{id:ID, latest_id:ID}, ...]
     * @apiParam {Number} [take]            :25:50
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__latest()
    {
        if (!Base::judgeClientVersion('0.34.47')) {
            return Base::retSuccess('success', ['data' => []]);
        }
        //
        $user = User::auth();
        //
        $dialogs = Request::input('dialogs');
        if (empty($dialogs) || !is_array($dialogs)) {
            return Base::retError('');
        }
        $builder = WebSocketDialogMsg::select([
            'web_socket_dialog_msgs.*',
            'read.mention',
            'read.dot',
            'read.read_at',
        ])->leftJoin('web_socket_dialog_msg_reads as read', function ($leftJoin) use ($user) {
            $leftJoin
                ->on('read.userid', '=', DB::raw($user->userid))
                ->on('read.msg_id', '=', 'web_socket_dialog_msgs.id');
        });
        $data = [];
        $num = 0;
        foreach ($dialogs as $item) {
            $dialog_id = intval($item['id']);
            $latest_id = intval($item['latest_id']);
            if ($dialog_id <= 0) {
                continue;
            }
            if ($num >= 5) {
                break;
            }
            $num++;
            WebSocketDialog::checkDialog($dialog_id);
            //
            $cloner = $builder->clone();
            $cloner->where('web_socket_dialog_msgs.dialog_id', $dialog_id);
            if ($latest_id > 0) {
                $cloner->where('web_socket_dialog_msgs.id', '>', $latest_id);
            }
            $cloner->orderByDesc('web_socket_dialog_msgs.id');
            $list = $cloner->take(Base::getPaginate(50, 25, 'take'))->get();
            if ($list->isNotEmpty()) {
                $data = array_merge($data, $list->toArray());
            }
        }
        return Base::retSuccess('success', compact('data'));
    }

    /**
     * @api {get} api/dialog/msg/search          14. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__search
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {String} key               
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__search()
    {
        User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $key = trim(Request::input('key'));
        //
        if (empty($key)) {
            return Base::retError('');
        }
        //
        WebSocketDialog::checkDialog($dialog_id);
        //
        $data = WebSocketDialogMsg::whereDialogId($dialog_id)
            ->where('key', 'LIKE', "%{$key}%")
            ->take(200)
            ->pluck('id');
        return Base::retSuccess('success', compact('data'));
    }

    /**
     * @api {get} api/dialog/msg/one          15. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__one
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__one()
    {
        User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        return Base::retSuccess('success', $msg);
    }

    /**
     * @api {get} api/dialog/msg/dot          16. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__dot
     *
     * @apiParam {Number} id         ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__dot()
    {
        $user = User::auth();
        //
        $id = intval(Request::input('id'));
        //
        $msg = WebSocketDialogMsg::find($id);
        if (empty($msg)) {
            return Base::retError("");
        }
        //
        WebSocketDialogMsgRead::whereMsgId($id)->whereUserid($user->userid)->change(['dot' => 0]);
        //
        return Base::retSuccess('success', [
            'id' => $msg->id,
            'dot' => 0,
        ]);
    }

    /**
     * @api {get} api/dialog/msg/read          17. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__read
     *
     * @apiParam {Object} id         ID
     * - 1ID1,2,3
     * - 2{"id": "[ID]"}{"2": 0, "3": 10}
     * -- IDid
     * -- 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__read()
    {
        $user = User::auth();
        //
        $id = Request::input('id');
        $ids = $id && is_array($id) ? $id : array_fill_keys(Base::explodeInt($id), 'r');
        //
        $dialogIds = [];
        $markIds = [];
        WebSocketDialogMsg::whereIn('id', array_keys($ids))->chunkById(100, function($list) use ($ids, $user, &$dialogIds, &$markIds) {
            /** @var WebSocketDialogMsg $item */
            foreach ($list as $item) {
                $item->readSuccess($user->userid);
                $dialogIds[$item->dialog_id] = $item->dialog_id;
                if ($ids[$item->id] == $item->dialog_id) {
                    $markIds[$item->dialog_id] = min($item->id, $markIds[$item->dialog_id] ?? 0);
                }
            }
        });
        //
        foreach ($markIds as $dialogId => $msgId) {
            WebSocketDialogMsgRead::whereDialogId($dialogId)
                ->whereUserid($user->userid)
                ->whereReadAt(null)
                ->where('msg_id', '>=', $msgId)
                ->chunkById(100, function ($list) {
                    WebSocketDialogMsgRead::onlyMarkRead($list);
                });
        }
        //
        $data = [];
        $dialogUsers = WebSocketDialogUser::with(['webSocketDialog'])->whereUserid($user->userid)->whereIn('dialog_id', array_values($dialogIds))->get();
        foreach ($dialogUsers as $dialogUser) {
            if (!$dialogUser->webSocketDialog) {
                continue;
            }
            $dialogUser->updated_at = Carbon::now();
            $dialogUser->save();
            //
            $dialogUser->webSocketDialog->generateUnread($user->userid);
            $data[] = [
                'id' => $dialogUser->webSocketDialog->id,
                'unread' => $dialogUser->webSocketDialog->unread,
                'unread_one' => $dialogUser->webSocketDialog->unread_one,
                'mention' => $dialogUser->webSocketDialog->mention,
                'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
                'user_at' =>  Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
                'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf()
            ];
        }
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/msg/unread          18. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__unread
     *
     * @apiParam {Number} dialog_id         ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     * @apiSuccessExample {json} data:
    {
        "id": 43,
        "unread": 308,
        "mention": 11,
        "user_at": "2020-12-12 00:00:00.000",
        "user_ms": 1677558147167,
    }
     */
    public function msg__unread()
    {
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $dialogUser = WebSocketDialogUser::with(['webSocketDialog'])->whereDialogId($dialog_id)->whereUserid(User::userid())->first();
        if (empty($dialogUser?->webSocketDialog)) {
            return Base::retError('');
        }
        $dialogUser->webSocketDialog->generateUnread($dialogUser->userid);
        //
        return Base::retSuccess('success', [
            'id' => $dialogUser->webSocketDialog->id,
            'unread' => $dialogUser->webSocketDialog->unread,
            'unread_one' => $dialogUser->webSocketDialog->unread_one,
            'mention' => $dialogUser->webSocketDialog->mention,
            'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
            'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
            'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf()
        ]);
    }

    /**
     * @api {get} api/dialog/msg/checked          19. checked
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__checked
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {Number} msg_id            ID
     * @apiParam {Number} index             li 
     * @apiParam {Number} checked           
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     * @apiSuccessExample {json} data:
    {
        "id": 43,
        "msg": {
            // ....
        },
    }
     */
    public function msg__checked()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $msg_id = intval(Request::input('msg_id'));
        $index = intval(Request::input('index'));
        $checked = intval(Request::input('checked'));
        //
        $dialogMsg = WebSocketDialogMsg::whereId($msg_id)->whereDialogId($dialog_id)->first();
        if (empty($dialogMsg)) {
            return Base::retError('');
        }
        if ($dialogMsg->userid != $user->userid) {
            return Base::retError('');
        }
        if ($dialogMsg->type !== 'text') {
            return Base::retError('');
        }
        //
        $oldMsg = Base::json2array($dialogMsg->getRawOriginal('msg'));
        $oldText = $oldMsg['text'] ?? '';
        $newText = preg_replace_callback('/<li[^>]*>/i', function ($matches) use ($index, $checked) {
            static $i = 0;
            if ($i++ == $index) {
                $checked = $checked ? 'checked' : 'unchecked';
                return '<li data-list="' . $checked . '">';
            }
            return $matches[0];
        }, $oldText);
        //
        $dialogMsg->updateInstance([
            'msg' => array_merge($oldMsg, ['text' => $newText]),
        ]);
        $dialogMsg->save();
        //
        return Base::retSuccess('success', [
            'id' => $dialogMsg->id,
            'msg' => $dialogMsg->msg,
        ]);
    }

    /**
     * @api {post} api/dialog/msg/stream          20. 
     *
     * @apiDescription EventSource
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__stream
     *
     * @apiParam {Number} dialog_id      ID
     * @apiParam {Number} userid         ID
     * @apiParam {String} stream_url     
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__stream()
    {
        // $dialog_id = intval(Request::input('dialog_id'));
        $userid = intval(Request::input('userid'));
        $stream_url = trim(Request::input('stream_url'));
        //
        if ($userid <= 0) {
            return Base::retError('');
        }
        //
        $params = [
            'userid' => $userid,
            'msg' => [
                'type' => 'msgStream',
                'stream_url' => $stream_url,
            ]
        ];
        $task = new PushTask($params, false);
        Task::deliver($task);
        //
        return Base::retSuccess('success');
    }

    /**
     * @api {post} api/dialog/msg/sendtext          21. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendtext
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {String} text              
     * @apiParam {String} [text_type]       
     * - html: HTML
     * - md: MARKDOWN
     * @apiParam {Number} [update_id]       ID reply_id
     * @apiParam {String} [update_mark]     
     * - no: 
     * - yes: 
     * @apiParam {Number} [reply_id]        ID
     * @apiParam {String} [silence]         
     * - no: 
     * - yes: 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendtext()
    {
        $user = User::auth();
        $user->checkChatInformation();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $dialog_ids = trim(Request::input('dialog_ids'));
        $update_id = intval(Request::input('update_id'));
        $update_mark = !($user->bot && in_array(strtolower(trim(Request::input('update_mark'))), ['no', 'false', '0']));
        $reply_id = intval(Request::input('reply_id'));
        $text = trim(Request::input('text'));
        $text_type = strtolower(trim(Request::input('text_type')));
        $silence = in_array(strtolower(trim(Request::input('silence'))), ['yes', 'true', '1']);
        $markdown = in_array($text_type, ['md', 'markdown']);
        //
        $result = [];
        $dialogIds = $dialog_ids ? explode(',', $dialog_ids) : [$dialog_id ?: 0];
        foreach ($dialogIds as $dialog_id) {
            //
            WebSocketDialog::checkDialog($dialog_id);
            //
            if ($update_id > 0) {
                $action = $update_mark ? "update-$update_id" : "change-$update_id";
            } elseif ($reply_id > 0) {
                $action = "reply-$reply_id";
            } else {
                $action = "";
            }
            //
            if (!$markdown) {
                $text = WebSocketDialogMsg::formatMsg($text, $dialog_id);
            }
            $strlen = mb_strlen($text);
            $noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
            if ($strlen < 1) {
                return Base::retError('');
            }
            if ($noimglen > 200000) {
                return Base::retError('200000');
            }
            if ($noimglen > 5000) {
                // 
                $path = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/";
                Base::makeDir(public_path($path));
                $path = $path . md5($text) . ".htm";
                $file = public_path($path);
                file_put_contents($file, $text);
                $size = filesize(public_path($path));
                if (empty($size)) {
                    return Base::retError('');
                }
                $ext = $markdown ? 'md' : 'htm';
                $fileData = [
                    'name' => "LongText-{$strlen}.{$ext}",
                    'size' => $size,
                    'file' => $file,
                    'path' => $path,
                    'url' => Base::fillUrl($path),
                    'thumb' => '',
                    'width' => -1,
                    'height' => -1,
                    'ext' => $ext,
                ];
                $result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'file', $fileData, $user->userid, false, false, $silence);
            } else {
                $msgData = ['text' => $text];
                if ($markdown) {
                    $msgData['type'] = 'md';
                }
                $result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'text', $msgData, $user->userid, false, false, $silence);
            }
        }
        return $result;
    }

    /**
     * @api {post} api/dialog/msg/sendrecord          22. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendrecord
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Number} [reply_id]            ID
     * @apiParam {String} base64                base64
     * @apiParam {Number} duration              
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendrecord()
    {
        $user = User::auth();
        $user->checkChatInformation();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $reply_id = intval(Request::input('reply_id'));
        //
        WebSocketDialog::checkDialog($dialog_id);
        //
        $action = $reply_id > 0 ? "reply-$reply_id" : "";
        $path = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/";
        $base64 = Request::input('base64');
        $duration = intval(Request::input('duration'));
        if ($duration < 600) {
            return Base::retError('');
        }
        $data = Base::record64save([
            "base64" => $base64,
            "path" => $path,
        ]);
        if (Base::isError($data)) {
            return Base::retError($data['msg']);
        } else {
            $recordData = $data['data'];
            $recordData['size'] *= 1024;
            $recordData['duration'] = $duration;
            return WebSocketDialogMsg::sendMsg($action, $dialog_id, 'record', $recordData, $user->userid);
        }
    }

    /**
     * @api {post} api/dialog/msg/sendfile          23. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendfile
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Number} [reply_id]            ID
     * @apiParam {Number} [image_attachment]    
     * @apiParam {String} [filename]            post-
     * @apiParam {String} [image64]             post-base64
     * @apiParam {File} [files]                 post-
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendfile()
    {
        $user = User::auth();
        //
        $dialogIds = [intval(Request::input('dialog_id'))];
        $replyId = intval(Request::input('reply_id'));
        $imageAttachment = intval(Request::input('image_attachment'));
        $files = Request::file('files');
        $image64 = Request::input('image64');
        $fileName = Request::input('filename');
        return WebSocketDialog::sendMsgFiles($user, $dialogIds, $files, $image64, $fileName, $replyId, $imageAttachment);
    }

    /**
     * @api {post} api/dialog/msg/sendfiles          24. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendfile
     *
     * @apiParam {String} user_ids              ID
     * @apiParam {String} dialog_ids            IDuser_ids 
     * @apiParam {Number} [reply_id]            ID
     * @apiParam {Number} [image_attachment]    
     * @apiParam {String} [filename]            post-
     * @apiParam {String} [image64]             post-base64
     * @apiParam {File} [files]                 post-
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendfiles()
    {
        $user = User::auth();
        //
        $files = Request::file('files');
        $image64 = Request::input('image64');
        $fileName = Request::input('filename');
        $replyId = intval(Request::input('reply_id'));
        $imageAttachment = intval(Request::input('image_attachment'));
        //
        $dialogIds = trim(Request::input('dialog_ids'));
        if ($dialogIds) {
            $dialogIds = explode(',', $dialogIds);
        } else {
            $dialogIds = [];
        }
        // 
        $userIds = trim(Request::input('user_ids'));
        if ($userIds) {
            $userIds = explode(',', $userIds);
            foreach ($userIds as $userId) {
                $dialog = WebSocketDialog::checkUserDialog($user, $userId);
                if (empty($dialog)) {
                    return Base::retError('');
                }
                $dialogIds[] = $dialog->id;
            }
        }
        //
        if (empty($dialogIds)) {
            return Base::retError('');
        }
        //
        return WebSocketDialog::sendMsgFiles($user, $dialogIds, $files, $image64, $fileName, $replyId, $imageAttachment);
    }

    /**
     * @api {get} api/dialog/msg/sendfileid          25. ID
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendfileid
     *
     * @apiParam {Number} file_id           ID
     * @apiParam {Array} dialogids          ID
     * @apiParam {Array} userids            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendfileid()
    {
        $user = User::auth();
        //
        $file_id = intval(Request::input("file_id"));
        $dialogids = Request::input('dialogids');
        $userids = Request::input('userids');
        //
        if (empty($dialogids) && empty($userids)) {
            return Base::retError("");
        }
        //
        $file = File::permissionFind($file_id, $user);
        $fileLink = $file->getShareLink($user->userid);
        $fileMsg = "<a class=\"mention file\" href=\"{{RemoteURL}}single/file/{$fileLink['code']}\" target=\"_blank\">~{$file->getNameAndExt()}</a>";
        //
        return AbstractModel::transaction(function() use ($user, $fileMsg, $userids, $dialogids) {
            $msgs = [];
            $already = [];
            if ($dialogids) {
                if (!is_array($dialogids)) {
                    $dialogids = [$dialogids];
                }
                foreach ($dialogids as $dialogid) {
                    $res = WebSocketDialogMsg::sendMsg(null, $dialogid, 'text', ['text' => $fileMsg], $user->userid);
                    if (Base::isSuccess($res)) {
                        $msgs[] = $res['data'];
                        $already[] = $dialogid;
                    }
                }
            }
            if ($userids) {
                if (!is_array($userids)) {
                    $userids = [$userids];
                }
                foreach ($userids as $userid) {
                    if (!User::whereUserid($userid)->exists()) {
                        continue;
                    }
                    $dialog = WebSocketDialog::checkUserDialog($user, $userid);
                    if ($dialog && !in_array($dialog->id, $already)) {
                        $res = WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $fileMsg], $user->userid);
                        if (Base::isSuccess($res)) {
                            $msgs[] = $res['data'];
                        }
                    }
                }
            }
            return Base::retSuccess('', [
                'msgs' => $msgs
            ]);
        });
    }

    /**
     * @api {post} api/dialog/msg/sendanon          26. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendanon
     *
     * @apiParam {Number} userid            ID
     * @apiParam {String} text              
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendanon()
    {
        User::auth();
        //
        $userid = intval(Request::input('userid'));
        $text = trim(Request::input('text'));
        //
        $anonMessage = Base::settingFind('system', 'anon_message', 'open');
        if ($anonMessage != 'open') {
            return Base::retError("");
        }
        //
        $toUser = User::whereUserid($userid)->first();
        if (empty($toUser) || $toUser->bot) {
            return Base::retError("");
        }
        if ($toUser->isDisable()) {
            return Base::retError("");
        }
        $strlen = mb_strlen($text);
        if ($strlen < 1) {
            return Base::retError('');
        }
        if ($strlen > 2000) {
            return Base::retError('2000');
        }
        //
        $botUser = User::botGetOrCreate('anon-msg');
        if (empty($botUser)) {
            return Base::retError('');
        }
        $dialog = WebSocketDialog::checkUserDialog($botUser, $toUser->userid);
        if (empty($dialog)) {
            return Base::retError('');
        }
        return WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => "<p>{$text}</p>"], $botUser->userid, true);
    }

    /**
     * @api {get} api/dialog/msg/readlist          27. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__readlist
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__readlist()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->whereUserid($user->userid)->first();
        if (empty($msg)) {
            return Base::retError('');
        }
        //
        $read = WebSocketDialogMsgRead::whereMsgId($msg_id)->get();
        return Base::retSuccess('success', $read ?: []);
    }

    /**
     * @api {get} api/dialog/msg/detail          28. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__detail
     *
     * @apiParam {Number} msg_id            ID
     * @apiParam {String} only_update_at    update_at
     * - no ()
     * - yes
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__detail()
    {
        User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        $only_update_at = Request::input('only_update_at', 'no');
        //
        $dialogMsg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($dialogMsg)) {
            return Base::retError("");
        }
        //
        if ($only_update_at == 'yes') {
            return Base::retSuccess('success', [
                'id' => $dialogMsg->id,
                'update_at' => Carbon::parse($dialogMsg->updated_at)->toDateTimeString()
            ]);
        }
        //
        $data = $dialogMsg->toArray();
        //
        if ($data['type'] == 'file') {
            $msg = Base::json2array($dialogMsg->getRawOriginal('msg'));
            $msg = File::formatFileData($msg);
            $data['content'] = $msg['content'];
            $data['file_mode'] = $msg['file_mode'];
        }
        //
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/msg/download          29. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__download
     *
     * @apiParam {Number} msg_id                ID
     * @apiParam {String} down                  
     * - yes: 
     * - preview: 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__download()
    {
        User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        $down = Request::input('down', 'yes');
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            abort(403, "This file not exist.");
        }
        if ($msg->type != 'file') {
            abort(403, "This file not support download.");
        }
        $array = Base::json2array($msg->getRawOriginal('msg'));
        //
        if ($down === 'preview') {
            return Redirect::to(FileContent::toPreviewUrl($array));
        }
        //
        $filePath = public_path($array['path']);
        return Base::streamDownload($filePath, $array['name']);
    }

    /**
     * @api {get} api/dialog/msg/withdraw          30. 
     *
     * @apiDescription 24token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__withdraw
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__withdraw()
    {
        $user = User::auth();
        $msg_id = intval(Request::input("msg_id"));
        $msg = WebSocketDialogMsg::whereId($msg_id)->whereUserid($user->userid)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        $msg->withdrawMsg();
        return Base::retSuccess("success");
    }

    /**
     * @api {get} api/dialog/msg/voice2text          31. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__voice2text
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__voice2text()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        if ($msg->type !== 'record') {
            return Base::retError("");
        }
        $msgData = Base::json2array($msg->getRawOriginal('msg'));
        if ($msgData['text']) {
            $textUserid = is_array($msgData['text_userid']) ? $msgData['text_userid'] : [];
            if (!in_array($user->userid, $textUserid)) {
                $textUserid[] = $user->userid;
                $msg->updateInstance([
                    'msg' => array_merge($msgData, ['text_userid' => $textUserid]),
                ]);
                $msg->save();
            }
            return Base::retSuccess("success", $msg);
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        $res = Extranet::openAItranscriptions(public_path($msgData['path']));
        if (Base::isError($res)) {
            return $res;
        }
        //
        $msg->updateInstance([
            'msg' => array_merge($msgData, ['text' => $res['data'], 'text_userid' => [$user->userid]]),
        ]);
        $msg->save();
        return Base::retSuccess("success", $msg);
    }

    /**
     * @api {get} api/dialog/msg/mark          32. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__mark
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {String} type                  
     * - read: 
     * - unread: 
     * @apiParam {Number} [after_msg_id]        
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__mark()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $type = Request::input('type');
        $after_msg_id = intval(Request::input('after_msg_id'));
        //
        $dialogUser = WebSocketDialogUser::with(['webSocketDialog'])->whereDialogId($dialog_id)->whereUserid($user->userid)->first();
        if (empty($dialogUser?->webSocketDialog)) {
            return Base::retError('');
        }
        switch ($type) {
            case 'read':
                // 
                $builder = WebSocketDialogMsgRead::whereDialogId($dialog_id)->whereUserid($user->userid)->whereReadAt(null);
                if ($after_msg_id > 0) {
                    $builder->where('msg_id', '>=', $after_msg_id);
                }
                $builder->chunkById(100, function ($list) {
                    WebSocketDialogMsgRead::onlyMarkRead($list);
                });
                break;

            case 'unread':
                // 
                break;

            default:
                return Base::retError("");
        }
        $dialogUser->mark_unread = $type == 'unread' ? 1 : 0;
        $dialogUser->save();
        $dialogUser->webSocketDialog->generateUnread($user->userid);
        return Base::retSuccess("success", [
            'id' => $dialogUser->webSocketDialog->id,
            'unread' => $dialogUser->webSocketDialog->unread,
            'unread_one' => $dialogUser->webSocketDialog->unread_one,
            'mention' => $dialogUser->webSocketDialog->mention,
            'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
            'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
            'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf(),
            'mark_unread' => $dialogUser->mark_unread,
        ]);
    }

    /**
     * @api {get} api/dialog/msg/silence          33. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__silence
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {String} type                  
     * - set
     * - cancel
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__silence()
    {
        $user = User::auth();
        $dialogId = intval(Request::input('dialog_id'));
        $type = Request::input('type');
        $dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
        if (!$dialogUser) {
            return Base::retError("");
        }
        //
        $dialogData = WebSocketDialog::find($dialogId);
        if (empty($dialogData)) {
            return Base::retError("");
        }
        if ($dialogData->type === 'group' && $dialogData->group_type !== 'user') {
            return Base::retError("");
        }
        //
        switch ($type) {
            case 'set':
                $data['silence'] = 0;
                WebSocketDialogMsgRead::whereUserid($user->userid)
                    ->whereReadAt(null)
                    ->whereDialogId($dialogId)
                    ->chunkById(100, function ($list) {
                        WebSocketDialogMsgRead::onlyMarkRead($list);
                    });
                $dialogUser->silence = 1;
                $dialogUser->save();
                break;

            case 'cancel':
                $dialogUser->silence = 0;
                $dialogUser->save();
                break;

            default:
                return Base::retError("");
        }
        $data = [
            'id' => $dialogId,
            'silence' => $dialogUser->silence,
        ];
        return Base::retSuccess("success", $data);
    }

    /**
     * @api {get} api/dialog/msg/forward          34. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__forward
     *
     * @apiParam {Number} msg_id                ID
     * @apiParam {Array} dialogids              ID
     * @apiParam {Array} userids                ID
     * @apiParam {Number} show_source           
     * @apiParam {Array} leave_message          
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__forward()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        $dialogids = Request::input('dialogids');
        $userids = Request::input('userids');
        $show_source = intval(Request::input("show_source"));
        $leave_message = Request::input('leave_message');
        //
        if (empty($dialogids) && empty($userids)) {
            return Base::retError("");
        }
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        return $msg->forwardMsg($dialogids, $userids, $user, $show_source, $leave_message);
    }

    /**
     * @api {get} api/dialog/msg/emoji          35. emoji
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__emoji
     *
     * @apiParam {Number} msg_id            ID
     * @apiParam {String} symbol            emoji
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__emoji()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        $symbol = Request::input("symbol");
        //
        if (!preg_match("/^[\u{d800}-\u{dbff}]|[\u{dc00}-\u{dfff}]$/", $symbol)) {
            return Base::retError("");
        }
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        return $msg->emojiMsg($symbol, $user->userid);
    }

    /**
     * @api {get} api/dialog/msg/tag          36. /
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__tag
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__tag()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        return $msg->toggleTagMsg($user->userid);
    }

    /**
     * @api {get} api/dialog/msg/todo          37. /
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__todo
     *
     * @apiParam {Number} msg_id            ID
     * @apiParam {String} type              
     * - all: 
     * - user: 
     * @apiParam {Array} userids            ID
     * - type=user : [userid1, userid2, userid3]
     * -  type=user  userids:[] 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__todo()
    {
        Base::checkClientVersion('0.37.18');
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        $type = trim(Request::input("type", "all"));
        $userids = Request::input('userids');
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        $dialog = WebSocketDialog::checkDialog($msg->dialog_id);
        //
        if ($type === 'all') {
            $userids = $dialog->dialogUser->pluck('userid')->toArray();
        } else {
            $userids = is_array($userids) ? $userids : [];
        }
        return $msg->toggleTodoMsg($user->userid, $userids);
    }

    /**
     * @api {get} api/dialog/msg/todolist          38. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__todolist
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__todolist()
    {
        User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        $todo = WebSocketDialogMsgTodo::whereMsgId($msg_id)->get();
        return Base::retSuccess('success', $todo ?: []);
    }

    /**
     * @api {get} api/dialog/msg/done          39. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__done
     *
     * @apiParam {Number} id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__done()
    {
        $user = User::auth();
        //
        $id = intval(Request::input("id"));
        //
        $add = [];
        $todo = WebSocketDialogMsgTodo::whereId($id)->whereUserid($user->userid)->first();
        if ($todo && empty($todo->done_at)) {
            $todo->done_at = Carbon::now();
            $todo->save();
            //
            $msg = WebSocketDialogMsg::find($todo->msg_id);
            if ($msg) {
                $res = WebSocketDialogMsg::sendMsg(null, $todo->dialog_id, 'todo', [
                    'action' => 'done',
                    'data' => [
                        'id' => $msg->id,
                        'type' => $msg->type,
                        'msg' => $msg->quoteTextMsg(),
                    ]
                ]);
                if (Base::isSuccess($res)) {
                    $add = $res['data'];
                }
                //
                $msg->webSocketDialog?->pushMsg('update', [
                    'id' => $msg->id,
                    'todo' => $msg->todo,
                    'dialog_id' => $msg->dialog_id,
                ]);
            }
        }
        //
        return Base::retSuccess("", [
            'add' => $add ?: null
        ]);
    }

    /**
     * @api {get} api/dialog/msg/color          40. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__color
     *
     * @apiParam {Number} dialog_id          ID
     * @apiParam {String} color              
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__color()
    {
        $user = User::auth();

        $dialogId = intval(Request::input('dialog_id'));
        $color = Request::input('color','');
        $dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
        if (!$dialogUser) {
            return Base::retError("");
        }
        //
        $dialogData = WebSocketDialog::find($dialogId);
        if (empty($dialogData)) {
            return Base::retError("");
        }
        //
        $dialogUser->color = $color;
        $dialogUser->save();
        //
        $data = [
            'id' => $dialogId,
            'color' => $color
        ];
        return Base::retSuccess("success", $data);
    }

    /**
     * @api {get} api/dialog/group/add          41. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__add
     *
     * @apiParam {String} [avatar]              
     * @apiParam {String} [chat_name]           
     * @apiParam {Array} userids                : [userid1, userid2, userid3]
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__add()
    {
        $user = User::auth();
        //
        $avatar = Request::input('avatar');
        $avatar = $avatar ? Base::unFillUrl(is_array($avatar) ? $avatar[0]['path'] : $avatar) : '';
        $chatName = trim(Request::input('chat_name'));
        $userids = Request::input('userids');
        //
        if (!is_array($userids)) {
            return Base::retError('');
        }
        $userids = array_merge([$user->userid], $userids);
        $userids = array_values(array_filter(array_unique($userids)));
        if (count($userids) < 2) {
            return Base::retError('2');
        }
        //
        if (empty($chatName)) {
            $array = [];
            foreach ($userids as $userid) {
                $array[] = User::userid2nickname($userid);
                if (count($array) >= 8 || strlen(implode(", ", $array)) > 100) {
                    $array[] = "...";
                    break;
                }
            }
            $chatName = implode(", ", $array);
        }
        if ($user->isTemp()) {
            return Base::retError('');
        }
        $dialog = WebSocketDialog::createGroup($chatName, $userids, 'user', $user->userid);
        if (empty($dialog)) {
            return Base::retError('');
        }
        if ($avatar) {
            $dialog->avatar = $avatar;
            $dialog->save();
        }
        $data = WebSocketDialog::find($dialog->id)?->formatData($user->userid);
        $userids = array_values(array_diff($userids, [$user->userid]));
        $dialog->pushMsg("groupAdd", null, $userids);
        return Base::retSuccess('', $data);
    }

    /**
     * @api {get} api/dialog/group/edit          42. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__edit
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {String} [avatar]              
     * @apiParam {String} [chat_name]           
     * @apiParam {Number} [admin]               1
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__edit()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $admin = intval(Request::input('admin'));
        //
        if ($admin === 1) {
            $user->checkAdmin();
            $dialog = WebSocketDialog::find($dialog_id);
            if (empty($dialog)) {
                WebSocketDialogMsgRead::forceRead($dialog_id, $user->userid);
                return Base::retError('', ['dialog_id' => $dialog_id], -4003);
            }
        } else {
            $dialog = WebSocketDialog::checkDialog($dialog_id, true);
        }
        //
        $data = ['id' => $dialog->id];
        $array = [];
        if (Request::exists('avatar')) {
            $avatar = Request::input('avatar');
            $avatar = $avatar ? Base::unFillUrl(is_array($avatar) ? $avatar[0]['path'] : $avatar) : '';
            $data['avatar'] = Base::fillUrl($array['avatar'] = $avatar);
        }
        if (Request::exists('chat_name') && $dialog->group_type === 'user') {
            $chatName = trim(Request::input('chat_name'));
            if (mb_strlen($chatName) < 2) {
                return Base::retError('2');
            }
            if (mb_strlen($chatName) > 100) {
                return Base::retError('100');
            }
            $data['name'] = $array['name'] = $chatName;
        }
        //
        if ($array) {
            $dialog->updateInstance($array);
            $dialog->save();
            WebSocketDialogUser::whereDialogId($dialog->id)->change(['updated_at' => Carbon::now()->toDateTimeString('millisecond')]);
        }
        //
        return Base::retSuccess('', $data);
    }

    /**
     * @api {get} api/dialog/group/adduser          43. 
     *
     * @apiDescription  token
     * - 
     * - 
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__adduser
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Array} userids                : [userid1, userid2, userid3]
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__adduser()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $userids = Base::json2array(Request::input('userids'));
        //
        if (!is_array($userids)) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id, "auto");
        //
        $dialog->checkGroup();
        $dialog->joinGroup($userids, $user->userid);
        $dialog->pushMsg("groupJoin", null, $userids);
        return Base::retSuccess('');
    }

    /**
     * @api {get} api/dialog/group/deluser          44. 
     *
     * @apiDescription  token
     * - 
     * - 
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__adduser
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Array} [userids]              : [userid1, userid2, userid3]
     * - 
     * - 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__deluser()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $userids = Base::json2array(Request::input('userids'));
        //
        $type = 'remove';
        if (empty($userids)) {
            $type = 'exit';
            $userids = [$user->userid];
        }
        //
        if (!is_array($userids)) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        //
        $dialog->checkGroup();
        $dialog->exitGroup($userids, $type);
        $dialog->pushMsg("groupExit", null, $userids);
        return Base::retSuccess($type === 'remove' ? '' : '');
    }

    /**
     * @api {get} api/dialog/group/transfer          45. 
     *
     * @apiDescription  token
     * - 
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__transfer
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Number} userid                
     * @apiParam {String} check_owner             yes-  no-
     * @apiParam {String} key                   APP_KEY
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__transfer()
    {
        if (!Base::is_internal_ip(Base::getIp()) || Request::input("key") !== env('APP_KEY')) {
            $user = User::auth();
        }
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $userid = intval(Request::input('userid'));
        $check_owner = trim(Request::input('check_owner', 'yes')) === 'yes';
        //
        if ($check_owner && $userid === $user?->userid) {
            return Base::retError('');
        }
        if (!User::whereUserid($userid)->exists()) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id, $check_owner);
        //
        $dialog->checkGroup($check_owner ? 'user' : null);
        $dialog->owner_id = $userid;
        if ($dialog->save()) {
            $dialog->joinGroup($userid, 0);
            $dialog->pushMsg("groupUpdate", [
                'id' => $dialog->id,
                'owner_id' => $dialog->owner_id,
            ]);
        }
        return Base::retSuccess('');
    }

    /**
     * @api {get} api/dialog/group/disband          46. 
     *
     * @apiDescription  token
     * - 
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__disband
     *
     * @apiParam {Number} dialog_id             ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__disband()
    {
        User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id, true);
        //
        $dialog->checkGroup('user');
        $dialog->deleteDialog();
        return Base::retSuccess('');
    }

    /**
     * @api {get} api/dialog/group/searchuser          47. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__searchuser
     *
     * @apiParam {String} key             
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__searchuser()
    {
        User::auth('admin');
        //
        $key = trim(Request::input('key'));
        //
        $builder = WebSocketDialog::whereType('group')->whereGroupType('user');
        if ($key) {
            $builder->where('name', 'like', "%{$key}%");
        }
        return Base::retSuccess('success', [
            'list' => $builder->take(20)->get()
        ]);
    }

    /**
     * @api {post} api/dialog/okr/add          48. OKR
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName okr__add
     *
     * @apiParam {String} name                   
     * @apiParam {Number} link_id                id
     * @apiParam {Array}  userids                : [userid1, userid2, userid3]
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function okr__add()
    {
        $user = User::auth();
        //
        $name = trim(Request::input('name'));
        $link_id = intval(Request::input('link_id'));
        $userids = Request::input('userids');
        //
        if (empty($name)) {
            return Base::retError('2');
        }
        //
        $dialog = WebSocketDialog::createGroup($name, $userids, 'okr', $user->userid);
        if (empty($dialog)) {
            return Base::retError('');
        }
        if ($link_id) {
            $dialog->link_id = $link_id;
            $dialog->save();
        }
        return Base::retSuccess('', $dialog);
    }

    /**
     * @api {post} api/dialog/okr/push          49. OKR
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName okr__push
     *
     * @apiParam {String}  text                  
     * @apiParam {Number}  userid                ID
     * @apiParam {String}  key                   APP_KEY
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function okr__push()
    {
        if (!Base::is_internal_ip(Base::getIp()) || Request::input("key") !== env('APP_KEY')) {
            User::auth();
        }
        $text = trim(Request::input('text'));
        $userid = intval(Request::input('userid'));
        //
        $botUser = User::botGetOrCreate('okr-alert');
        if (empty($botUser)) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkUserDialog($botUser, $userid);
        if ($dialog) {
            WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid);
        }
        return Base::retSuccess('success', $dialog);
    }

    /**
     * @api {post} api/dialog/msg/wordchain          50. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__wordchain
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {String} uuid              ID
     * @apiParam {String} text              
     * @apiParam {Array}  list              
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__wordchain()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $uuid = trim(Request::input('uuid'));
        $text = trim(Request::input('text'));
        $list = Request::input('list') ?? [];
        //
        WebSocketDialog::checkDialog($dialog_id);
        $strlen = mb_strlen($text);
        $noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
        if ($strlen < 1 || empty($list)) {
            return Base::retError('');
        }
        if ($noimglen > 200000) {
            return Base::retError('200000');
        }
        //
        return AbstractModel::transaction(function () use ($user, $uuid, $dialog_id, $list, $text) {
            if ($uuid) {
                $dialogMsg = WebSocketDialogMsg::whereDialogId($dialog_id)
                    ->lockForUpdate()
                    ->whereType('word-chain')
                    ->orderByDesc('created_at')
                    ->where('msg', 'like', "%$uuid%")
                    ->value('msg');
                //
                $createId = $dialogMsg['createid'] ?? $user->userid;
                // 
                $msgList = $dialogMsg['list'] ?? [];
                $addList = array_udiff($list, $msgList, function($a, $b) {
                    return ($a['id'] ?? 0) - $b['id'];
                });
                foreach ($addList as $key => $item) {
                    $item['id'] = intval(round(microtime(true) * 1000)) + $key;
                    $msgList[] = $item;
                }
                // 
                $lists = array_column($list,null,'id');
                foreach ($msgList as $key => $item) {
                    if (isset($lists[$item['id']]) && $item['userid'] == $user->userid) {
                        $msgList[$key] = $lists[$item['id']];
                    }
                }
                $list = $msgList;
            } else {
                $createId = $user->userid;
                $uuid = Base::generatePassword(36);
                foreach ($list as $key => $item) {
                    $list[$key]['id'] = intval(round(microtime(true) * 1000)) + $key;
                }
            }
            //
            usort($list, function ($a, $b) {
                return $a['id'] - $b['id'];
            });
            //
            $msgData = [
                'text' => $text,
                'list' => $list,
                'userid' => $user->userid,
                'createid' => $createId,
                'uuid' => $uuid,
            ];
            return WebSocketDialogMsg::sendMsg(null, $dialog_id, 'word-chain', $msgData, $user->userid);
        });
    }

    /**
     * @api {post} api/dialog/msg/vote          51. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__vote
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {String} text                  
     * @apiParam {Array}  type                  
     * @apiParam {String} [uuid]                ID
     * @apiParam {Array}  [list]                
     * @apiParam {Number} [multiple]            
     * @apiParam {Number} [anonymous]           
     * @apiParam {Array}  [vote]                
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__vote()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $uuid = trim(Request::input('uuid'));
        $text = trim(Request::input('text'));
        $type = trim(Request::input('type', 'create'));
        $multiple = intval(Request::input('multiple')) ?: 0;
        $anonymous = intval(Request::input('anonymous')) ?: 0;
        $list = Request::input('list');
        $vote = Request::input('vote') ?: [];
        $votes = is_array($vote) ? $vote : [$vote];
        //
        WebSocketDialog::checkDialog($dialog_id);
        //
        $action = null;
        if ($type != 'create') {
            if ($type == 'vote' && empty($votes)) {
                return Base::retError('');
            }
            if (empty($uuid)) {
                return Base::retError('');
            }
            return AbstractModel::transaction(function () use ($user, $uuid, $dialog_id, $type, $votes) {
                //
                $dialogMsgs = WebSocketDialogMsg::whereDialogId($dialog_id)
                    ->lockForUpdate()
                    ->whereType('vote')
                    ->orderByDesc('created_at')
                    ->where('msg', 'like', "%$uuid%")
                    ->get();
                //
                $result = [];
                if ($type == 'again') {
                    $res = WebSocketDialogMsg::sendMsg(null, $dialog_id, 'vote', $dialogMsgs[0]->msg, $user->userid);
                    if (Base::isError($res)) {
                        return $res;
                    }
                    $result[] = $res['data'];
                } else {
                    foreach ($dialogMsgs as $dialogMsg) {
                        $action = "change-{$dialogMsg->id}";
                        $msgData = $dialogMsg->msg;
                        if ($type == 'finish') {
                            $msgData['state'] = 0;
                        } else {
                            $msgDataVotes = $msgData['votes'] ?? [];
                            if (in_array($user->userid, array_column($msgDataVotes, 'userid'))) {
                                return Base::retError('');
                            }
                            $msgDataVotes[] = [
                                'userid' => $user->userid,
                                'votes' => $votes,
                            ];
                            $msgData['votes'] = $msgDataVotes;
                        }
                        //
                        $res = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'vote', $msgData, $user->userid);
                        if (Base::isError($res)) {
                            return $res;
                        }
                        $result[] = $res['data'];
                    }
                }
                //
                return Base::retSuccess('', $result);
            });
        } else {
            $strlen = mb_strlen($text);
            $noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
            if ($strlen < 1) {
                return Base::retError('');
            }
            if ($noimglen > 200000) {
                return Base::retError('200000');
            }
            $msgData = [
                'text' => $text,
                'list' => $list,
                'userid' => $user->userid,
                'uuid' => $uuid ?: Base::generatePassword(36),
                'multiple' => $multiple,
                'anonymous' => $anonymous,
                'votes' => [],
                'state' => 1
            ];
            $res = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'vote', $msgData, $user->userid);
            if (Base::isError($res)) {
                return $res;
            }
            return Base::retSuccess('', [$res['data']]);
        }
    }

    /**
     * @api {get} api/dialog/msg/top          52. /
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__top
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__top()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        $dialog = WebSocketDialog::checkDialog($msg->dialog_id);
        //
        $before = $dialog->top_msg_id;
        $beforeTopUserid = $dialog->top_userid;
        $dialog->top_msg_id = $msg->id == $before ? 0 : $msg->id;
        $dialog->top_userid = $dialog->top_msg_id ? $user->userid : 0;
        $dialog->save();
        //
        $data = [
            'add' => null,
            'update' => [
                'dialog_id' => $dialog->id,
                'top_msg_id' => $dialog->top_msg_id,
                'top_userid' => $dialog->top_userid,
            ]
        ];
        $res = WebSocketDialogMsg::sendMsg(null, $dialog->id, 'top', [
            'action' => $dialog->top_msg_id ? 'add' : 'remove',
            'data' => [
                'id' => $msg->id,
                'type' => $msg->type,
                'msg' => $msg->quoteTextMsg()
            ]
        ], $user->userid);
        if (Base::isSuccess($res)) {
            $data['add'] = $res['data'];
            $dialog->pushMsg('updateTopMsg', $data['update']);
        } else {
            $dialog->top_msg_id = $before;
            $dialog->top_userid = $beforeTopUserid;
            $dialog->save();
        }
        //
        return Base::retSuccess($dialog->top_msg_id ? '' : '', $data);
    }

    /**
     * @api {get} api/dialog/msg/topinfo          53. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__topinfo
     *
     * @apiParam {Number} dialog_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__topinfo()
    {
        User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        //
        $topMsg = WebSocketDialogMsg::whereId($dialog->top_msg_id)->first();
        //
        return Base::retSuccess('success', $topMsg);
    }
}

Did this file decode correctly?

Original Code

<?php

namespace App\Http\Controllers\Api;

use App\Tasks\PushTask;
use DB;
use Hhxsv5\LaravelS\Swoole\Task\Task;
use Request;
use Redirect;
use Carbon\Carbon;
use App\Models\File;
use App\Models\User;
use App\Module\Base;
use App\Module\Extranet;
use App\Module\TimeRange;
use App\Models\FileContent;
use App\Models\AbstractModel;
use App\Models\WebSocketDialog;
use App\Models\WebSocketDialogMsg;
use App\Models\WebSocketDialogUser;
use App\Models\WebSocketDialogMsgRead;
use App\Models\WebSocketDialogMsgTodo;

/**
 * @apiDefine dialog
 *
 * 
 */
class DialogController extends AbstractController
{
    /**
     * @api {get} api/dialog/lists          01. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName lists
     *
     * @apiParam {String} [timerange]        1678248944,1678248944
     * - : 
     * - : ID1: deleted_id
     *
     * @apiParam {Number} [page]            :1
     * @apiParam {Number} [pagesize]        :50:100
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function lists()
    {
        $user = User::auth();
        //
        $timerange = TimeRange::parse(Request::input());
        //
        $data = WebSocketDialog::getDialogList($user->userid, $timerange->updated, $timerange->deleted);
        //
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/beyond          02. 
     *
     * @apiDescription token  
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName beyond
     *
     * @apiParam {String} unread_at         
     * - 12021-01-01 00:00:00
     * - 21612051200
     * @apiParam {String} todo_at           
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function beyond()
    {
        $user = User::auth();
        //
        $unreadAt = Request::input('unread_at');
        $todoAt = Request::input('todo_at');
        //
        $unreadAt = Base::isNumber($unreadAt) ? intval($unreadAt) : trim($unreadAt);
        $unreadAt = Carbon::parse($unreadAt)->setTimezone(config('app.timezone'));
        //
        $todoAt = Base::isNumber($todoAt) ? intval($todoAt) : trim($todoAt);
        $todoAt = Carbon::parse($todoAt)->setTimezone(config('app.timezone'));
        //
        $data = WebSocketDialog::getDialogBeyond($user->userid, $unreadAt, $todoAt);
        //
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/search          03. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName search
     *
     * @apiParam {String} key         
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function search()
    {
        $user = User::auth();
        //
        $key = trim(Request::input('key'));
        if (empty($key)) {
            return Base::retError('');
        }
        // 
        $dialogs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
            ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
            ->where('web_socket_dialogs.name', 'LIKE', "%{$key}%")
            ->where('u.userid', $user->userid)
            ->orderByDesc('u.top_at')
            ->orderByDesc('u.last_at')
            ->take(20)
            ->get();
        $dialogs->transform(function (WebSocketDialog $item) use ($user) {
            return $item->formatData($user->userid);
        });
        $list = $dialogs->toArray();
        // 
        if (count($list) < 20 && Base::judgeClientVersion("0.21.60")) {
            $users = User::select(User::$basicField)
                ->where(function ($query) use ($key) {
                    if (str_contains($key, "@")) {
                        $query->where("email", "like", "%{$key}%");
                    } else {
                        $query->where("nickname", "like", "%{$key}%")->orWhere("pinyin", "like", "%{$key}%");
                    }
                })->orderBy('userid')
                ->take(20 - count($list))
                ->get();
            $users->transform(function (User $item) {
                return [
                    'id' => 'u:' . $item->userid,
                    'type' => 'user',
                    'name' => $item->nickname,
                    'dialog_user' => $item,
                    'last_msg' => null,
                ];
            });
            $list = array_merge($list, $users->toArray());
        }
        // 
        if (count($list) < 20) {
            $msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
                ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
                ->join('web_socket_dialog_msgs as m', 'web_socket_dialogs.id', '=', 'm.dialog_id')
                ->where('u.userid', $user->userid)
                ->where('m.key', 'LIKE', "%{$key}%")
                ->orderByDesc('m.id')
                ->take(20 - count($list))
                ->get();
            $msgs->transform(function (WebSocketDialog $item) use ($user) {
                return $item->formatData($user->userid);
            });
            $list = array_merge($list, $msgs->toArray());
        }
        //
        return Base::retSuccess('success', $list);
    }

    /**
     * @api {get} api/dialog/search/tag          04. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName search__tag
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function search__tag()
    {
        $user = User::auth();
        // 
        $msgs = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at', 'm.id as search_msg_id'])
            ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
            ->join('web_socket_dialog_msgs as m', 'web_socket_dialogs.id', '=', 'm.dialog_id')
            ->where('u.userid', $user->userid)
            ->where('m.tag', '>', 0)
            ->orderByDesc('m.id')
            ->take(50)
            ->get();
        $msgs->transform(function (WebSocketDialog $item) use ($user) {
            return $item->formatData($user->userid);
        });
        //
        return Base::retSuccess('success', $msgs->toArray());
    }

    /**
     * @api {get} api/dialog/one          05. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName one
     *
     * @apiParam {Number} dialog_id         ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function one()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $item = WebSocketDialog::select(['web_socket_dialogs.*', 'u.top_at', 'u.last_at', 'u.mark_unread', 'u.silence', 'u.hide', 'u.color', 'u.updated_at as user_at'])
            ->join('web_socket_dialog_users as u', 'web_socket_dialogs.id', '=', 'u.dialog_id')
            ->where('web_socket_dialogs.id', $dialog_id)
            ->where('u.userid', $user->userid)
            ->first();
        if (empty($item)) {
            WebSocketDialogMsgRead::forceRead($dialog_id, $user->userid);
            return Base::retError('', ['dialog_id' => $dialog_id], -4003);
        }
        return Base::retSuccess('success', $item->formatData($user->userid));
    }

    /**
     * @api {get} api/dialog/user          06. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName user
     *
     * @apiParam {Number} dialog_id            ID
     * @apiParam {Number} [getuser]            1: 0: 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function user()
    {
        User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $getuser = intval(Request::input('getuser', 0));
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        //
        if ($getuser === 1) {
            $data = $dialog->dialogUser->toArray();
            $array = [];
            foreach ($data as $item) {
                $res = User::userid2basic($item['userid']);
                if ($res) {
                    $array[] = array_merge($item, $res->toArray());
                }
            }
            $array = array_filter($array, function ($item) {
                return $item['userid'] > 0;
            });
        } else {
            $data = WebSocketDialogUser::select(['web_socket_dialog_users.*', 'users.bot'])
                ->join('users', 'web_socket_dialog_users.userid', '=', 'users.userid')
                ->where('web_socket_dialog_users.dialog_id', $dialog_id)
                ->orderBy('web_socket_dialog_users.id')
                ->get();
            $array = $data->toArray();
        }
        return Base::retSuccess('success', $array);
    }

    /**
     * @api {get} api/dialog/todo          07. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName todo
     *
     * @apiParam {Number} [dialog_id]            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function todo()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $builder = WebSocketDialogMsgTodo::whereUserid($user->userid)->whereDoneAt(null);
        if ($dialog_id > 0) {
            WebSocketDialog::checkDialog($dialog_id);
            $builder->whereDialogId($dialog_id);
        }
        //
        $list = $builder->orderByDesc('id')->take(50)->get();
        return Base::retSuccess("success", $list);
    }

    /**
     * @api {get} api/dialog/top          08. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName top
     *
     * @apiParam {Number} dialog_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function top()
    {
        $user = User::auth();
        $dialogId = intval(Request::input('dialog_id'));
        $dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
        if (!$dialogUser) {
            return Base::retError("");
        }
        $dialogUser->top_at = $dialogUser->top_at ? null : Carbon::now();
        $dialogUser->save();
        return Base::retSuccess("success", [
            'id' => $dialogUser->dialog_id,
            'top_at' => $dialogUser->top_at?->toDateTimeString(),
        ]);
    }



    /**
     * @api {get} api/dialog/hide          09. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName hide
     *
     * @apiParam {Number} dialog_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function hide()
    {
        $user = User::auth();
        $dialogId = intval(Request::input('dialog_id'));
        $dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
        if (!$dialogUser) {
            return Base::retError("");
        }
        if ($dialogUser->top_at) {
            return Base::retError("");
        }
        $dialogUser->hide = 1;
        $dialogUser->save();
        return Base::retSuccess("success", [
            'id' => $dialogUser->dialog_id,
            'hide' => 1,
        ]);
    }

    /**
     * @api {get} api/dialog/tel          10. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName tel
     *
     * @apiParam {Number} dialog_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function tel()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        if ($dialog->type !== 'user') {
            return Base::retError("");
        }
        $dialogUser = $dialog->dialogUser->where('userid', '!=', $user->userid)->first();
        if (empty($dialogUser)) {
            return Base::retError("");
        }
        $callUser = User::find($dialogUser->userid);
        if (empty($callUser) || empty($callUser->tel)) {
            return Base::retError("");
        }
        if ($user->isTemp()) {
            return Base::retError("");
        }
        //
        $add = null;
        $res = WebSocketDialogMsg::sendMsg(null, $dialog->id, 'notice', [
            'notice' => $user->nickname . "  " . $callUser->nickname . " "
        ]);
        if (Base::isSuccess($res)) {
            $add = $res['data'];
        }
        //
        return Base::retSuccess("success", [
            'tel' => $callUser->tel,
            'add' => $add ?: null
        ]);
    }

    /**
     * @api {get} api/dialog/open/user          11. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName open__user
     *
     * @apiParam {Number} userid         ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function open__user()
    {
        $user = User::auth();
        //
        $userid = intval(Request::input('userid'));
        if (empty($userid)) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkUserDialog($user, $userid);
        if (empty($dialog)) {
            return Base::retError('');
        }
        $data = WebSocketDialog::find($dialog->id)?->formatData($user->userid);
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/msg/list          12. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__list
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {Number} [msg_id]          ID
     * @apiParam {Number} [position_id]     ID
     * @apiParam {Number} [prev_id]         ID
     * @apiParam {Number} [next_id]         ID
     * - position_idprev_idnext_id position_id > prev_id > next_id
     * @apiParam {String} [msg_type]        
     * - tag: 
     * - link: 
     * - text: 
     * - image: 
     * - file: 
     * - record: 
     * - meeting: 
     *
     * @apiParam {Number} [take]            :50:100
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__list()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $msg_id = intval(Request::input('msg_id'));
        $position_id = intval(Request::input('position_id'));
        $prev_id = intval(Request::input('prev_id'));
        $next_id = intval(Request::input('next_id'));
        $msg_type = trim(Request::input('msg_type'));
        $take = Base::getPaginate(100, 50);
        $data = [];
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        $reDialog = true;
        //
        $builder = WebSocketDialogMsg::select([
            'web_socket_dialog_msgs.*',
            'read.mention',
            'read.dot',
            'read.read_at',
        ])->leftJoin('web_socket_dialog_msg_reads as read', function ($leftJoin) use ($user) {
            $leftJoin
                ->on('read.userid', '=', DB::raw($user->userid))
                ->on('read.msg_id', '=', 'web_socket_dialog_msgs.id');
        })->where('web_socket_dialog_msgs.dialog_id', $dialog_id);
        //
        if ($msg_type) {
            if ($msg_type === 'tag') {
                $builder->where('tag', '>', 0);
            } elseif ($msg_type === 'todo') {
                $builder->where('todo', '>', 0);
            } elseif ($msg_type === 'link') {
                $builder->whereLink(1);
            } elseif (in_array($msg_type, ['text', 'image', 'file', 'record', 'meeting'])) {
                $builder->whereMtype($msg_type);
            } else {
                return Base::retError('');
            }
            $reDialog = false;
        }
        if ($msg_id > 0) {
            $builder->whereReplyId($msg_id);
            $reDialog = false;
        }
        //
        if ($position_id > 0) {
            $array = $builder->clone()
                ->where('web_socket_dialog_msgs.id', '>=', $position_id)
                ->orderBy('web_socket_dialog_msgs.id')
                ->take(intval($take / 2))
                ->get();
            $prev_id = intval($array->last()?->id);
        }
        //
        $cloner = $builder->clone();
        if ($prev_id > 0) {
            $cloner->where('web_socket_dialog_msgs.id', '<=', $prev_id)->orderByDesc('web_socket_dialog_msgs.id');
            $reDialog = false;
        } elseif ($next_id > 0) {
            $cloner->where('web_socket_dialog_msgs.id', '>=', $next_id)->orderBy('web_socket_dialog_msgs.id');
            $reDialog = false;
        } else {
            $cloner->orderByDesc('web_socket_dialog_msgs.id');
        }
        $list = $cloner->take($take)->get()->sortByDesc('id', SORT_NUMERIC)->values();
        //
        if ($list->isNotEmpty()) {
            $list->transform(function (WebSocketDialogMsg $item) {
                $item->next_id = 0;
                $item->prev_id = 0;
                return $item;
            });
            $first = $list->first();
            $first->next_id = intval($builder->clone()
                ->where('web_socket_dialog_msgs.id', '>', $first->id)
                ->orderBy('web_socket_dialog_msgs.id')
                ->value('id'));
            $last = $list->last();
            $last->prev_id = intval($builder->clone()
                ->where('web_socket_dialog_msgs.id', '<', $last->id)
                ->orderByDesc('web_socket_dialog_msgs.id')
                ->value('id'));
        }
        $data['list'] = $list;
        $data['time'] = Base::time();
        // 
        if ($dialog->type == 'group' && $dialog->group_type == 'task') {
            $user->task_dialog_id = $dialog->id;
            $user->save();
        }
        // 
        $isMarkDialogUser = WebSocketDialogUser::whereDialogId($dialog->id)->whereUserid($user->userid)->whereMarkUnread(1)->first();
        if ($isMarkDialogUser) {
            $isMarkDialogUser->mark_unread = 0;
            $isMarkDialogUser->save();
        }
        //
        if ($reDialog) {
            $data['dialog'] = $dialog->formatData($user->userid, true);
            $data['todo'] = $data['dialog']->todo_num > 0 ? WebSocketDialogMsgTodo::whereDialogId($dialog->id)->whereUserid($user->userid)->whereDoneAt(null)->orderByDesc('id')->take(50)->get() : [];
            $data['top'] = $dialog->top_msg_id ? WebSocketDialogMsg::whereId($dialog->top_msg_id)->first() : null;
        }
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/msg/latest          13. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__latest
     *
     * @apiParam {Array} [dialogs]          ID
     * - [{id:ID, latest_id:ID}, ...]
     * @apiParam {Number} [take]            :25:50
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__latest()
    {
        if (!Base::judgeClientVersion('0.34.47')) {
            return Base::retSuccess('success', ['data' => []]);
        }
        //
        $user = User::auth();
        //
        $dialogs = Request::input('dialogs');
        if (empty($dialogs) || !is_array($dialogs)) {
            return Base::retError('');
        }
        $builder = WebSocketDialogMsg::select([
            'web_socket_dialog_msgs.*',
            'read.mention',
            'read.dot',
            'read.read_at',
        ])->leftJoin('web_socket_dialog_msg_reads as read', function ($leftJoin) use ($user) {
            $leftJoin
                ->on('read.userid', '=', DB::raw($user->userid))
                ->on('read.msg_id', '=', 'web_socket_dialog_msgs.id');
        });
        $data = [];
        $num = 0;
        foreach ($dialogs as $item) {
            $dialog_id = intval($item['id']);
            $latest_id = intval($item['latest_id']);
            if ($dialog_id <= 0) {
                continue;
            }
            if ($num >= 5) {
                break;
            }
            $num++;
            WebSocketDialog::checkDialog($dialog_id);
            //
            $cloner = $builder->clone();
            $cloner->where('web_socket_dialog_msgs.dialog_id', $dialog_id);
            if ($latest_id > 0) {
                $cloner->where('web_socket_dialog_msgs.id', '>', $latest_id);
            }
            $cloner->orderByDesc('web_socket_dialog_msgs.id');
            $list = $cloner->take(Base::getPaginate(50, 25, 'take'))->get();
            if ($list->isNotEmpty()) {
                $data = array_merge($data, $list->toArray());
            }
        }
        return Base::retSuccess('success', compact('data'));
    }

    /**
     * @api {get} api/dialog/msg/search          14. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__search
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {String} key               
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__search()
    {
        User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $key = trim(Request::input('key'));
        //
        if (empty($key)) {
            return Base::retError('');
        }
        //
        WebSocketDialog::checkDialog($dialog_id);
        //
        $data = WebSocketDialogMsg::whereDialogId($dialog_id)
            ->where('key', 'LIKE', "%{$key}%")
            ->take(200)
            ->pluck('id');
        return Base::retSuccess('success', compact('data'));
    }

    /**
     * @api {get} api/dialog/msg/one          15. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__one
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__one()
    {
        User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        return Base::retSuccess('success', $msg);
    }

    /**
     * @api {get} api/dialog/msg/dot          16. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__dot
     *
     * @apiParam {Number} id         ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__dot()
    {
        $user = User::auth();
        //
        $id = intval(Request::input('id'));
        //
        $msg = WebSocketDialogMsg::find($id);
        if (empty($msg)) {
            return Base::retError("");
        }
        //
        WebSocketDialogMsgRead::whereMsgId($id)->whereUserid($user->userid)->change(['dot' => 0]);
        //
        return Base::retSuccess('success', [
            'id' => $msg->id,
            'dot' => 0,
        ]);
    }

    /**
     * @api {get} api/dialog/msg/read          17. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__read
     *
     * @apiParam {Object} id         ID
     * - 1ID1,2,3
     * - 2{"id": "[ID]"}{"2": 0, "3": 10}
     * -- IDid
     * -- 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__read()
    {
        $user = User::auth();
        //
        $id = Request::input('id');
        $ids = $id && is_array($id) ? $id : array_fill_keys(Base::explodeInt($id), 'r');
        //
        $dialogIds = [];
        $markIds = [];
        WebSocketDialogMsg::whereIn('id', array_keys($ids))->chunkById(100, function($list) use ($ids, $user, &$dialogIds, &$markIds) {
            /** @var WebSocketDialogMsg $item */
            foreach ($list as $item) {
                $item->readSuccess($user->userid);
                $dialogIds[$item->dialog_id] = $item->dialog_id;
                if ($ids[$item->id] == $item->dialog_id) {
                    $markIds[$item->dialog_id] = min($item->id, $markIds[$item->dialog_id] ?? 0);
                }
            }
        });
        //
        foreach ($markIds as $dialogId => $msgId) {
            WebSocketDialogMsgRead::whereDialogId($dialogId)
                ->whereUserid($user->userid)
                ->whereReadAt(null)
                ->where('msg_id', '>=', $msgId)
                ->chunkById(100, function ($list) {
                    WebSocketDialogMsgRead::onlyMarkRead($list);
                });
        }
        //
        $data = [];
        $dialogUsers = WebSocketDialogUser::with(['webSocketDialog'])->whereUserid($user->userid)->whereIn('dialog_id', array_values($dialogIds))->get();
        foreach ($dialogUsers as $dialogUser) {
            if (!$dialogUser->webSocketDialog) {
                continue;
            }
            $dialogUser->updated_at = Carbon::now();
            $dialogUser->save();
            //
            $dialogUser->webSocketDialog->generateUnread($user->userid);
            $data[] = [
                'id' => $dialogUser->webSocketDialog->id,
                'unread' => $dialogUser->webSocketDialog->unread,
                'unread_one' => $dialogUser->webSocketDialog->unread_one,
                'mention' => $dialogUser->webSocketDialog->mention,
                'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
                'user_at' =>  Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
                'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf()
            ];
        }
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/msg/unread          18. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__unread
     *
     * @apiParam {Number} dialog_id         ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     * @apiSuccessExample {json} data:
    {
        "id": 43,
        "unread": 308,
        "mention": 11,
        "user_at": "2020-12-12 00:00:00.000",
        "user_ms": 1677558147167,
    }
     */
    public function msg__unread()
    {
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $dialogUser = WebSocketDialogUser::with(['webSocketDialog'])->whereDialogId($dialog_id)->whereUserid(User::userid())->first();
        if (empty($dialogUser?->webSocketDialog)) {
            return Base::retError('');
        }
        $dialogUser->webSocketDialog->generateUnread($dialogUser->userid);
        //
        return Base::retSuccess('success', [
            'id' => $dialogUser->webSocketDialog->id,
            'unread' => $dialogUser->webSocketDialog->unread,
            'unread_one' => $dialogUser->webSocketDialog->unread_one,
            'mention' => $dialogUser->webSocketDialog->mention,
            'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
            'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
            'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf()
        ]);
    }

    /**
     * @api {get} api/dialog/msg/checked          19. checked
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__checked
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {Number} msg_id            ID
     * @apiParam {Number} index             li 
     * @apiParam {Number} checked           
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     * @apiSuccessExample {json} data:
    {
        "id": 43,
        "msg": {
            // ....
        },
    }
     */
    public function msg__checked()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $msg_id = intval(Request::input('msg_id'));
        $index = intval(Request::input('index'));
        $checked = intval(Request::input('checked'));
        //
        $dialogMsg = WebSocketDialogMsg::whereId($msg_id)->whereDialogId($dialog_id)->first();
        if (empty($dialogMsg)) {
            return Base::retError('');
        }
        if ($dialogMsg->userid != $user->userid) {
            return Base::retError('');
        }
        if ($dialogMsg->type !== 'text') {
            return Base::retError('');
        }
        //
        $oldMsg = Base::json2array($dialogMsg->getRawOriginal('msg'));
        $oldText = $oldMsg['text'] ?? '';
        $newText = preg_replace_callback('/<li[^>]*>/i', function ($matches) use ($index, $checked) {
            static $i = 0;
            if ($i++ == $index) {
                $checked = $checked ? 'checked' : 'unchecked';
                return '<li data-list="' . $checked . '">';
            }
            return $matches[0];
        }, $oldText);
        //
        $dialogMsg->updateInstance([
            'msg' => array_merge($oldMsg, ['text' => $newText]),
        ]);
        $dialogMsg->save();
        //
        return Base::retSuccess('success', [
            'id' => $dialogMsg->id,
            'msg' => $dialogMsg->msg,
        ]);
    }

    /**
     * @api {post} api/dialog/msg/stream          20. 
     *
     * @apiDescription EventSource
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__stream
     *
     * @apiParam {Number} dialog_id      ID
     * @apiParam {Number} userid         ID
     * @apiParam {String} stream_url     
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__stream()
    {
        // $dialog_id = intval(Request::input('dialog_id'));
        $userid = intval(Request::input('userid'));
        $stream_url = trim(Request::input('stream_url'));
        //
        if ($userid <= 0) {
            return Base::retError('');
        }
        //
        $params = [
            'userid' => $userid,
            'msg' => [
                'type' => 'msgStream',
                'stream_url' => $stream_url,
            ]
        ];
        $task = new PushTask($params, false);
        Task::deliver($task);
        //
        return Base::retSuccess('success');
    }

    /**
     * @api {post} api/dialog/msg/sendtext          21. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendtext
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {String} text              
     * @apiParam {String} [text_type]       
     * - html: HTML
     * - md: MARKDOWN
     * @apiParam {Number} [update_id]       ID reply_id
     * @apiParam {String} [update_mark]     
     * - no: 
     * - yes: 
     * @apiParam {Number} [reply_id]        ID
     * @apiParam {String} [silence]         
     * - no: 
     * - yes: 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendtext()
    {
        $user = User::auth();
        $user->checkChatInformation();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $dialog_ids = trim(Request::input('dialog_ids'));
        $update_id = intval(Request::input('update_id'));
        $update_mark = !($user->bot && in_array(strtolower(trim(Request::input('update_mark'))), ['no', 'false', '0']));
        $reply_id = intval(Request::input('reply_id'));
        $text = trim(Request::input('text'));
        $text_type = strtolower(trim(Request::input('text_type')));
        $silence = in_array(strtolower(trim(Request::input('silence'))), ['yes', 'true', '1']);
        $markdown = in_array($text_type, ['md', 'markdown']);
        //
        $result = [];
        $dialogIds = $dialog_ids ? explode(',', $dialog_ids) : [$dialog_id ?: 0];
        foreach ($dialogIds as $dialog_id) {
            //
            WebSocketDialog::checkDialog($dialog_id);
            //
            if ($update_id > 0) {
                $action = $update_mark ? "update-$update_id" : "change-$update_id";
            } elseif ($reply_id > 0) {
                $action = "reply-$reply_id";
            } else {
                $action = "";
            }
            //
            if (!$markdown) {
                $text = WebSocketDialogMsg::formatMsg($text, $dialog_id);
            }
            $strlen = mb_strlen($text);
            $noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
            if ($strlen < 1) {
                return Base::retError('');
            }
            if ($noimglen > 200000) {
                return Base::retError('200000');
            }
            if ($noimglen > 5000) {
                // 
                $path = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/";
                Base::makeDir(public_path($path));
                $path = $path . md5($text) . ".htm";
                $file = public_path($path);
                file_put_contents($file, $text);
                $size = filesize(public_path($path));
                if (empty($size)) {
                    return Base::retError('');
                }
                $ext = $markdown ? 'md' : 'htm';
                $fileData = [
                    'name' => "LongText-{$strlen}.{$ext}",
                    'size' => $size,
                    'file' => $file,
                    'path' => $path,
                    'url' => Base::fillUrl($path),
                    'thumb' => '',
                    'width' => -1,
                    'height' => -1,
                    'ext' => $ext,
                ];
                $result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'file', $fileData, $user->userid, false, false, $silence);
            } else {
                $msgData = ['text' => $text];
                if ($markdown) {
                    $msgData['type'] = 'md';
                }
                $result = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'text', $msgData, $user->userid, false, false, $silence);
            }
        }
        return $result;
    }

    /**
     * @api {post} api/dialog/msg/sendrecord          22. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendrecord
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Number} [reply_id]            ID
     * @apiParam {String} base64                base64
     * @apiParam {Number} duration              
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendrecord()
    {
        $user = User::auth();
        $user->checkChatInformation();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $reply_id = intval(Request::input('reply_id'));
        //
        WebSocketDialog::checkDialog($dialog_id);
        //
        $action = $reply_id > 0 ? "reply-$reply_id" : "";
        $path = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/";
        $base64 = Request::input('base64');
        $duration = intval(Request::input('duration'));
        if ($duration < 600) {
            return Base::retError('');
        }
        $data = Base::record64save([
            "base64" => $base64,
            "path" => $path,
        ]);
        if (Base::isError($data)) {
            return Base::retError($data['msg']);
        } else {
            $recordData = $data['data'];
            $recordData['size'] *= 1024;
            $recordData['duration'] = $duration;
            return WebSocketDialogMsg::sendMsg($action, $dialog_id, 'record', $recordData, $user->userid);
        }
    }

    /**
     * @api {post} api/dialog/msg/sendfile          23. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendfile
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Number} [reply_id]            ID
     * @apiParam {Number} [image_attachment]    
     * @apiParam {String} [filename]            post-
     * @apiParam {String} [image64]             post-base64
     * @apiParam {File} [files]                 post-
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendfile()
    {
        $user = User::auth();
        //
        $dialogIds = [intval(Request::input('dialog_id'))];
        $replyId = intval(Request::input('reply_id'));
        $imageAttachment = intval(Request::input('image_attachment'));
        $files = Request::file('files');
        $image64 = Request::input('image64');
        $fileName = Request::input('filename');
        return WebSocketDialog::sendMsgFiles($user, $dialogIds, $files, $image64, $fileName, $replyId, $imageAttachment);
    }

    /**
     * @api {post} api/dialog/msg/sendfiles          24. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendfile
     *
     * @apiParam {String} user_ids              ID
     * @apiParam {String} dialog_ids            IDuser_ids 
     * @apiParam {Number} [reply_id]            ID
     * @apiParam {Number} [image_attachment]    
     * @apiParam {String} [filename]            post-
     * @apiParam {String} [image64]             post-base64
     * @apiParam {File} [files]                 post-
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendfiles()
    {
        $user = User::auth();
        //
        $files = Request::file('files');
        $image64 = Request::input('image64');
        $fileName = Request::input('filename');
        $replyId = intval(Request::input('reply_id'));
        $imageAttachment = intval(Request::input('image_attachment'));
        //
        $dialogIds = trim(Request::input('dialog_ids'));
        if ($dialogIds) {
            $dialogIds = explode(',', $dialogIds);
        } else {
            $dialogIds = [];
        }
        // 
        $userIds = trim(Request::input('user_ids'));
        if ($userIds) {
            $userIds = explode(',', $userIds);
            foreach ($userIds as $userId) {
                $dialog = WebSocketDialog::checkUserDialog($user, $userId);
                if (empty($dialog)) {
                    return Base::retError('');
                }
                $dialogIds[] = $dialog->id;
            }
        }
        //
        if (empty($dialogIds)) {
            return Base::retError('');
        }
        //
        return WebSocketDialog::sendMsgFiles($user, $dialogIds, $files, $image64, $fileName, $replyId, $imageAttachment);
    }

    /**
     * @api {get} api/dialog/msg/sendfileid          25. ID
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendfileid
     *
     * @apiParam {Number} file_id           ID
     * @apiParam {Array} dialogids          ID
     * @apiParam {Array} userids            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendfileid()
    {
        $user = User::auth();
        //
        $file_id = intval(Request::input("file_id"));
        $dialogids = Request::input('dialogids');
        $userids = Request::input('userids');
        //
        if (empty($dialogids) && empty($userids)) {
            return Base::retError("");
        }
        //
        $file = File::permissionFind($file_id, $user);
        $fileLink = $file->getShareLink($user->userid);
        $fileMsg = "<a class=\"mention file\" href=\"{{RemoteURL}}single/file/{$fileLink['code']}\" target=\"_blank\">~{$file->getNameAndExt()}</a>";
        //
        return AbstractModel::transaction(function() use ($user, $fileMsg, $userids, $dialogids) {
            $msgs = [];
            $already = [];
            if ($dialogids) {
                if (!is_array($dialogids)) {
                    $dialogids = [$dialogids];
                }
                foreach ($dialogids as $dialogid) {
                    $res = WebSocketDialogMsg::sendMsg(null, $dialogid, 'text', ['text' => $fileMsg], $user->userid);
                    if (Base::isSuccess($res)) {
                        $msgs[] = $res['data'];
                        $already[] = $dialogid;
                    }
                }
            }
            if ($userids) {
                if (!is_array($userids)) {
                    $userids = [$userids];
                }
                foreach ($userids as $userid) {
                    if (!User::whereUserid($userid)->exists()) {
                        continue;
                    }
                    $dialog = WebSocketDialog::checkUserDialog($user, $userid);
                    if ($dialog && !in_array($dialog->id, $already)) {
                        $res = WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $fileMsg], $user->userid);
                        if (Base::isSuccess($res)) {
                            $msgs[] = $res['data'];
                        }
                    }
                }
            }
            return Base::retSuccess('', [
                'msgs' => $msgs
            ]);
        });
    }

    /**
     * @api {post} api/dialog/msg/sendanon          26. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__sendanon
     *
     * @apiParam {Number} userid            ID
     * @apiParam {String} text              
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__sendanon()
    {
        User::auth();
        //
        $userid = intval(Request::input('userid'));
        $text = trim(Request::input('text'));
        //
        $anonMessage = Base::settingFind('system', 'anon_message', 'open');
        if ($anonMessage != 'open') {
            return Base::retError("");
        }
        //
        $toUser = User::whereUserid($userid)->first();
        if (empty($toUser) || $toUser->bot) {
            return Base::retError("");
        }
        if ($toUser->isDisable()) {
            return Base::retError("");
        }
        $strlen = mb_strlen($text);
        if ($strlen < 1) {
            return Base::retError('');
        }
        if ($strlen > 2000) {
            return Base::retError('2000');
        }
        //
        $botUser = User::botGetOrCreate('anon-msg');
        if (empty($botUser)) {
            return Base::retError('');
        }
        $dialog = WebSocketDialog::checkUserDialog($botUser, $toUser->userid);
        if (empty($dialog)) {
            return Base::retError('');
        }
        return WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => "<p>{$text}</p>"], $botUser->userid, true);
    }

    /**
     * @api {get} api/dialog/msg/readlist          27. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__readlist
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__readlist()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->whereUserid($user->userid)->first();
        if (empty($msg)) {
            return Base::retError('');
        }
        //
        $read = WebSocketDialogMsgRead::whereMsgId($msg_id)->get();
        return Base::retSuccess('success', $read ?: []);
    }

    /**
     * @api {get} api/dialog/msg/detail          28. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__detail
     *
     * @apiParam {Number} msg_id            ID
     * @apiParam {String} only_update_at    update_at
     * - no ()
     * - yes
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__detail()
    {
        User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        $only_update_at = Request::input('only_update_at', 'no');
        //
        $dialogMsg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($dialogMsg)) {
            return Base::retError("");
        }
        //
        if ($only_update_at == 'yes') {
            return Base::retSuccess('success', [
                'id' => $dialogMsg->id,
                'update_at' => Carbon::parse($dialogMsg->updated_at)->toDateTimeString()
            ]);
        }
        //
        $data = $dialogMsg->toArray();
        //
        if ($data['type'] == 'file') {
            $msg = Base::json2array($dialogMsg->getRawOriginal('msg'));
            $msg = File::formatFileData($msg);
            $data['content'] = $msg['content'];
            $data['file_mode'] = $msg['file_mode'];
        }
        //
        return Base::retSuccess('success', $data);
    }

    /**
     * @api {get} api/dialog/msg/download          29. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__download
     *
     * @apiParam {Number} msg_id                ID
     * @apiParam {String} down                  
     * - yes: 
     * - preview: 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__download()
    {
        User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        $down = Request::input('down', 'yes');
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            abort(403, "This file not exist.");
        }
        if ($msg->type != 'file') {
            abort(403, "This file not support download.");
        }
        $array = Base::json2array($msg->getRawOriginal('msg'));
        //
        if ($down === 'preview') {
            return Redirect::to(FileContent::toPreviewUrl($array));
        }
        //
        $filePath = public_path($array['path']);
        return Base::streamDownload($filePath, $array['name']);
    }

    /**
     * @api {get} api/dialog/msg/withdraw          30. 
     *
     * @apiDescription 24token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__withdraw
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__withdraw()
    {
        $user = User::auth();
        $msg_id = intval(Request::input("msg_id"));
        $msg = WebSocketDialogMsg::whereId($msg_id)->whereUserid($user->userid)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        $msg->withdrawMsg();
        return Base::retSuccess("success");
    }

    /**
     * @api {get} api/dialog/msg/voice2text          31. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__voice2text
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__voice2text()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        if ($msg->type !== 'record') {
            return Base::retError("");
        }
        $msgData = Base::json2array($msg->getRawOriginal('msg'));
        if ($msgData['text']) {
            $textUserid = is_array($msgData['text_userid']) ? $msgData['text_userid'] : [];
            if (!in_array($user->userid, $textUserid)) {
                $textUserid[] = $user->userid;
                $msg->updateInstance([
                    'msg' => array_merge($msgData, ['text_userid' => $textUserid]),
                ]);
                $msg->save();
            }
            return Base::retSuccess("success", $msg);
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        $res = Extranet::openAItranscriptions(public_path($msgData['path']));
        if (Base::isError($res)) {
            return $res;
        }
        //
        $msg->updateInstance([
            'msg' => array_merge($msgData, ['text' => $res['data'], 'text_userid' => [$user->userid]]),
        ]);
        $msg->save();
        return Base::retSuccess("success", $msg);
    }

    /**
     * @api {get} api/dialog/msg/mark          32. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__mark
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {String} type                  
     * - read: 
     * - unread: 
     * @apiParam {Number} [after_msg_id]        
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__mark()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $type = Request::input('type');
        $after_msg_id = intval(Request::input('after_msg_id'));
        //
        $dialogUser = WebSocketDialogUser::with(['webSocketDialog'])->whereDialogId($dialog_id)->whereUserid($user->userid)->first();
        if (empty($dialogUser?->webSocketDialog)) {
            return Base::retError('');
        }
        switch ($type) {
            case 'read':
                // 
                $builder = WebSocketDialogMsgRead::whereDialogId($dialog_id)->whereUserid($user->userid)->whereReadAt(null);
                if ($after_msg_id > 0) {
                    $builder->where('msg_id', '>=', $after_msg_id);
                }
                $builder->chunkById(100, function ($list) {
                    WebSocketDialogMsgRead::onlyMarkRead($list);
                });
                break;

            case 'unread':
                // 
                break;

            default:
                return Base::retError("");
        }
        $dialogUser->mark_unread = $type == 'unread' ? 1 : 0;
        $dialogUser->save();
        $dialogUser->webSocketDialog->generateUnread($user->userid);
        return Base::retSuccess("success", [
            'id' => $dialogUser->webSocketDialog->id,
            'unread' => $dialogUser->webSocketDialog->unread,
            'unread_one' => $dialogUser->webSocketDialog->unread_one,
            'mention' => $dialogUser->webSocketDialog->mention,
            'mention_ids' => $dialogUser->webSocketDialog->mention_ids,
            'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'),
            'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf(),
            'mark_unread' => $dialogUser->mark_unread,
        ]);
    }

    /**
     * @api {get} api/dialog/msg/silence          33. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__silence
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {String} type                  
     * - set
     * - cancel
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__silence()
    {
        $user = User::auth();
        $dialogId = intval(Request::input('dialog_id'));
        $type = Request::input('type');
        $dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
        if (!$dialogUser) {
            return Base::retError("");
        }
        //
        $dialogData = WebSocketDialog::find($dialogId);
        if (empty($dialogData)) {
            return Base::retError("");
        }
        if ($dialogData->type === 'group' && $dialogData->group_type !== 'user') {
            return Base::retError("");
        }
        //
        switch ($type) {
            case 'set':
                $data['silence'] = 0;
                WebSocketDialogMsgRead::whereUserid($user->userid)
                    ->whereReadAt(null)
                    ->whereDialogId($dialogId)
                    ->chunkById(100, function ($list) {
                        WebSocketDialogMsgRead::onlyMarkRead($list);
                    });
                $dialogUser->silence = 1;
                $dialogUser->save();
                break;

            case 'cancel':
                $dialogUser->silence = 0;
                $dialogUser->save();
                break;

            default:
                return Base::retError("");
        }
        $data = [
            'id' => $dialogId,
            'silence' => $dialogUser->silence,
        ];
        return Base::retSuccess("success", $data);
    }

    /**
     * @api {get} api/dialog/msg/forward          34. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__forward
     *
     * @apiParam {Number} msg_id                ID
     * @apiParam {Array} dialogids              ID
     * @apiParam {Array} userids                ID
     * @apiParam {Number} show_source           
     * @apiParam {Array} leave_message          
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__forward()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        $dialogids = Request::input('dialogids');
        $userids = Request::input('userids');
        $show_source = intval(Request::input("show_source"));
        $leave_message = Request::input('leave_message');
        //
        if (empty($dialogids) && empty($userids)) {
            return Base::retError("");
        }
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        return $msg->forwardMsg($dialogids, $userids, $user, $show_source, $leave_message);
    }

    /**
     * @api {get} api/dialog/msg/emoji          35. emoji
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__emoji
     *
     * @apiParam {Number} msg_id            ID
     * @apiParam {String} symbol            emoji
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__emoji()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        $symbol = Request::input("symbol");
        //
        if (!preg_match("/^[\u{d800}-\u{dbff}]|[\u{dc00}-\u{dfff}]$/", $symbol)) {
            return Base::retError("");
        }
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        return $msg->emojiMsg($symbol, $user->userid);
    }

    /**
     * @api {get} api/dialog/msg/tag          36. /
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__tag
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__tag()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        return $msg->toggleTagMsg($user->userid);
    }

    /**
     * @api {get} api/dialog/msg/todo          37. /
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__todo
     *
     * @apiParam {Number} msg_id            ID
     * @apiParam {String} type              
     * - all: 
     * - user: 
     * @apiParam {Array} userids            ID
     * - type=user : [userid1, userid2, userid3]
     * -  type=user  userids:[] 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__todo()
    {
        Base::checkClientVersion('0.37.18');
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        $type = trim(Request::input("type", "all"));
        $userids = Request::input('userids');
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        $dialog = WebSocketDialog::checkDialog($msg->dialog_id);
        //
        if ($type === 'all') {
            $userids = $dialog->dialogUser->pluck('userid')->toArray();
        } else {
            $userids = is_array($userids) ? $userids : [];
        }
        return $msg->toggleTodoMsg($user->userid, $userids);
    }

    /**
     * @api {get} api/dialog/msg/todolist          38. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__todolist
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__todolist()
    {
        User::auth();
        //
        $msg_id = intval(Request::input('msg_id'));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        WebSocketDialog::checkDialog($msg->dialog_id);
        //
        $todo = WebSocketDialogMsgTodo::whereMsgId($msg_id)->get();
        return Base::retSuccess('success', $todo ?: []);
    }

    /**
     * @api {get} api/dialog/msg/done          39. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__done
     *
     * @apiParam {Number} id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__done()
    {
        $user = User::auth();
        //
        $id = intval(Request::input("id"));
        //
        $add = [];
        $todo = WebSocketDialogMsgTodo::whereId($id)->whereUserid($user->userid)->first();
        if ($todo && empty($todo->done_at)) {
            $todo->done_at = Carbon::now();
            $todo->save();
            //
            $msg = WebSocketDialogMsg::find($todo->msg_id);
            if ($msg) {
                $res = WebSocketDialogMsg::sendMsg(null, $todo->dialog_id, 'todo', [
                    'action' => 'done',
                    'data' => [
                        'id' => $msg->id,
                        'type' => $msg->type,
                        'msg' => $msg->quoteTextMsg(),
                    ]
                ]);
                if (Base::isSuccess($res)) {
                    $add = $res['data'];
                }
                //
                $msg->webSocketDialog?->pushMsg('update', [
                    'id' => $msg->id,
                    'todo' => $msg->todo,
                    'dialog_id' => $msg->dialog_id,
                ]);
            }
        }
        //
        return Base::retSuccess("", [
            'add' => $add ?: null
        ]);
    }

    /**
     * @api {get} api/dialog/msg/color          40. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__color
     *
     * @apiParam {Number} dialog_id          ID
     * @apiParam {String} color              
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__color()
    {
        $user = User::auth();

        $dialogId = intval(Request::input('dialog_id'));
        $color = Request::input('color','');
        $dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
        if (!$dialogUser) {
            return Base::retError("");
        }
        //
        $dialogData = WebSocketDialog::find($dialogId);
        if (empty($dialogData)) {
            return Base::retError("");
        }
        //
        $dialogUser->color = $color;
        $dialogUser->save();
        //
        $data = [
            'id' => $dialogId,
            'color' => $color
        ];
        return Base::retSuccess("success", $data);
    }

    /**
     * @api {get} api/dialog/group/add          41. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__add
     *
     * @apiParam {String} [avatar]              
     * @apiParam {String} [chat_name]           
     * @apiParam {Array} userids                : [userid1, userid2, userid3]
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__add()
    {
        $user = User::auth();
        //
        $avatar = Request::input('avatar');
        $avatar = $avatar ? Base::unFillUrl(is_array($avatar) ? $avatar[0]['path'] : $avatar) : '';
        $chatName = trim(Request::input('chat_name'));
        $userids = Request::input('userids');
        //
        if (!is_array($userids)) {
            return Base::retError('');
        }
        $userids = array_merge([$user->userid], $userids);
        $userids = array_values(array_filter(array_unique($userids)));
        if (count($userids) < 2) {
            return Base::retError('2');
        }
        //
        if (empty($chatName)) {
            $array = [];
            foreach ($userids as $userid) {
                $array[] = User::userid2nickname($userid);
                if (count($array) >= 8 || strlen(implode(", ", $array)) > 100) {
                    $array[] = "...";
                    break;
                }
            }
            $chatName = implode(", ", $array);
        }
        if ($user->isTemp()) {
            return Base::retError('');
        }
        $dialog = WebSocketDialog::createGroup($chatName, $userids, 'user', $user->userid);
        if (empty($dialog)) {
            return Base::retError('');
        }
        if ($avatar) {
            $dialog->avatar = $avatar;
            $dialog->save();
        }
        $data = WebSocketDialog::find($dialog->id)?->formatData($user->userid);
        $userids = array_values(array_diff($userids, [$user->userid]));
        $dialog->pushMsg("groupAdd", null, $userids);
        return Base::retSuccess('', $data);
    }

    /**
     * @api {get} api/dialog/group/edit          42. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__edit
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {String} [avatar]              
     * @apiParam {String} [chat_name]           
     * @apiParam {Number} [admin]               1
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__edit()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $admin = intval(Request::input('admin'));
        //
        if ($admin === 1) {
            $user->checkAdmin();
            $dialog = WebSocketDialog::find($dialog_id);
            if (empty($dialog)) {
                WebSocketDialogMsgRead::forceRead($dialog_id, $user->userid);
                return Base::retError('', ['dialog_id' => $dialog_id], -4003);
            }
        } else {
            $dialog = WebSocketDialog::checkDialog($dialog_id, true);
        }
        //
        $data = ['id' => $dialog->id];
        $array = [];
        if (Request::exists('avatar')) {
            $avatar = Request::input('avatar');
            $avatar = $avatar ? Base::unFillUrl(is_array($avatar) ? $avatar[0]['path'] : $avatar) : '';
            $data['avatar'] = Base::fillUrl($array['avatar'] = $avatar);
        }
        if (Request::exists('chat_name') && $dialog->group_type === 'user') {
            $chatName = trim(Request::input('chat_name'));
            if (mb_strlen($chatName) < 2) {
                return Base::retError('2');
            }
            if (mb_strlen($chatName) > 100) {
                return Base::retError('100');
            }
            $data['name'] = $array['name'] = $chatName;
        }
        //
        if ($array) {
            $dialog->updateInstance($array);
            $dialog->save();
            WebSocketDialogUser::whereDialogId($dialog->id)->change(['updated_at' => Carbon::now()->toDateTimeString('millisecond')]);
        }
        //
        return Base::retSuccess('', $data);
    }

    /**
     * @api {get} api/dialog/group/adduser          43. 
     *
     * @apiDescription  token
     * - 
     * - 
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__adduser
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Array} userids                : [userid1, userid2, userid3]
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__adduser()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $userids = Base::json2array(Request::input('userids'));
        //
        if (!is_array($userids)) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id, "auto");
        //
        $dialog->checkGroup();
        $dialog->joinGroup($userids, $user->userid);
        $dialog->pushMsg("groupJoin", null, $userids);
        return Base::retSuccess('');
    }

    /**
     * @api {get} api/dialog/group/deluser          44. 
     *
     * @apiDescription  token
     * - 
     * - 
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__adduser
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Array} [userids]              : [userid1, userid2, userid3]
     * - 
     * - 
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__deluser()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $userids = Base::json2array(Request::input('userids'));
        //
        $type = 'remove';
        if (empty($userids)) {
            $type = 'exit';
            $userids = [$user->userid];
        }
        //
        if (!is_array($userids)) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        //
        $dialog->checkGroup();
        $dialog->exitGroup($userids, $type);
        $dialog->pushMsg("groupExit", null, $userids);
        return Base::retSuccess($type === 'remove' ? '' : '');
    }

    /**
     * @api {get} api/dialog/group/transfer          45. 
     *
     * @apiDescription  token
     * - 
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__transfer
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {Number} userid                
     * @apiParam {String} check_owner             yes-  no-
     * @apiParam {String} key                   APP_KEY
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__transfer()
    {
        if (!Base::is_internal_ip(Base::getIp()) || Request::input("key") !== env('APP_KEY')) {
            $user = User::auth();
        }
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $userid = intval(Request::input('userid'));
        $check_owner = trim(Request::input('check_owner', 'yes')) === 'yes';
        //
        if ($check_owner && $userid === $user?->userid) {
            return Base::retError('');
        }
        if (!User::whereUserid($userid)->exists()) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id, $check_owner);
        //
        $dialog->checkGroup($check_owner ? 'user' : null);
        $dialog->owner_id = $userid;
        if ($dialog->save()) {
            $dialog->joinGroup($userid, 0);
            $dialog->pushMsg("groupUpdate", [
                'id' => $dialog->id,
                'owner_id' => $dialog->owner_id,
            ]);
        }
        return Base::retSuccess('');
    }

    /**
     * @api {get} api/dialog/group/disband          46. 
     *
     * @apiDescription  token
     * - 
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__disband
     *
     * @apiParam {Number} dialog_id             ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__disband()
    {
        User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id, true);
        //
        $dialog->checkGroup('user');
        $dialog->deleteDialog();
        return Base::retSuccess('');
    }

    /**
     * @api {get} api/dialog/group/searchuser          47. 
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName group__searchuser
     *
     * @apiParam {String} key             
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function group__searchuser()
    {
        User::auth('admin');
        //
        $key = trim(Request::input('key'));
        //
        $builder = WebSocketDialog::whereType('group')->whereGroupType('user');
        if ($key) {
            $builder->where('name', 'like', "%{$key}%");
        }
        return Base::retSuccess('success', [
            'list' => $builder->take(20)->get()
        ]);
    }

    /**
     * @api {post} api/dialog/okr/add          48. OKR
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName okr__add
     *
     * @apiParam {String} name                   
     * @apiParam {Number} link_id                id
     * @apiParam {Array}  userids                : [userid1, userid2, userid3]
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function okr__add()
    {
        $user = User::auth();
        //
        $name = trim(Request::input('name'));
        $link_id = intval(Request::input('link_id'));
        $userids = Request::input('userids');
        //
        if (empty($name)) {
            return Base::retError('2');
        }
        //
        $dialog = WebSocketDialog::createGroup($name, $userids, 'okr', $user->userid);
        if (empty($dialog)) {
            return Base::retError('');
        }
        if ($link_id) {
            $dialog->link_id = $link_id;
            $dialog->save();
        }
        return Base::retSuccess('', $dialog);
    }

    /**
     * @api {post} api/dialog/okr/push          49. OKR
     *
     * @apiDescription  token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName okr__push
     *
     * @apiParam {String}  text                  
     * @apiParam {Number}  userid                ID
     * @apiParam {String}  key                   APP_KEY
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function okr__push()
    {
        if (!Base::is_internal_ip(Base::getIp()) || Request::input("key") !== env('APP_KEY')) {
            User::auth();
        }
        $text = trim(Request::input('text'));
        $userid = intval(Request::input('userid'));
        //
        $botUser = User::botGetOrCreate('okr-alert');
        if (empty($botUser)) {
            return Base::retError('');
        }
        //
        $dialog = WebSocketDialog::checkUserDialog($botUser, $userid);
        if ($dialog) {
            WebSocketDialogMsg::sendMsg(null, $dialog->id, 'text', ['text' => $text], $botUser->userid);
        }
        return Base::retSuccess('success', $dialog);
    }

    /**
     * @api {post} api/dialog/msg/wordchain          50. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__wordchain
     *
     * @apiParam {Number} dialog_id         ID
     * @apiParam {String} uuid              ID
     * @apiParam {String} text              
     * @apiParam {Array}  list              
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__wordchain()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $uuid = trim(Request::input('uuid'));
        $text = trim(Request::input('text'));
        $list = Request::input('list') ?? [];
        //
        WebSocketDialog::checkDialog($dialog_id);
        $strlen = mb_strlen($text);
        $noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
        if ($strlen < 1 || empty($list)) {
            return Base::retError('');
        }
        if ($noimglen > 200000) {
            return Base::retError('200000');
        }
        //
        return AbstractModel::transaction(function () use ($user, $uuid, $dialog_id, $list, $text) {
            if ($uuid) {
                $dialogMsg = WebSocketDialogMsg::whereDialogId($dialog_id)
                    ->lockForUpdate()
                    ->whereType('word-chain')
                    ->orderByDesc('created_at')
                    ->where('msg', 'like', "%$uuid%")
                    ->value('msg');
                //
                $createId = $dialogMsg['createid'] ?? $user->userid;
                // 
                $msgList = $dialogMsg['list'] ?? [];
                $addList = array_udiff($list, $msgList, function($a, $b) {
                    return ($a['id'] ?? 0) - $b['id'];
                });
                foreach ($addList as $key => $item) {
                    $item['id'] = intval(round(microtime(true) * 1000)) + $key;
                    $msgList[] = $item;
                }
                // 
                $lists = array_column($list,null,'id');
                foreach ($msgList as $key => $item) {
                    if (isset($lists[$item['id']]) && $item['userid'] == $user->userid) {
                        $msgList[$key] = $lists[$item['id']];
                    }
                }
                $list = $msgList;
            } else {
                $createId = $user->userid;
                $uuid = Base::generatePassword(36);
                foreach ($list as $key => $item) {
                    $list[$key]['id'] = intval(round(microtime(true) * 1000)) + $key;
                }
            }
            //
            usort($list, function ($a, $b) {
                return $a['id'] - $b['id'];
            });
            //
            $msgData = [
                'text' => $text,
                'list' => $list,
                'userid' => $user->userid,
                'createid' => $createId,
                'uuid' => $uuid,
            ];
            return WebSocketDialogMsg::sendMsg(null, $dialog_id, 'word-chain', $msgData, $user->userid);
        });
    }

    /**
     * @api {post} api/dialog/msg/vote          51. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__vote
     *
     * @apiParam {Number} dialog_id             ID
     * @apiParam {String} text                  
     * @apiParam {Array}  type                  
     * @apiParam {String} [uuid]                ID
     * @apiParam {Array}  [list]                
     * @apiParam {Number} [multiple]            
     * @apiParam {Number} [anonymous]           
     * @apiParam {Array}  [vote]                
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__vote()
    {
        $user = User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        $uuid = trim(Request::input('uuid'));
        $text = trim(Request::input('text'));
        $type = trim(Request::input('type', 'create'));
        $multiple = intval(Request::input('multiple')) ?: 0;
        $anonymous = intval(Request::input('anonymous')) ?: 0;
        $list = Request::input('list');
        $vote = Request::input('vote') ?: [];
        $votes = is_array($vote) ? $vote : [$vote];
        //
        WebSocketDialog::checkDialog($dialog_id);
        //
        $action = null;
        if ($type != 'create') {
            if ($type == 'vote' && empty($votes)) {
                return Base::retError('');
            }
            if (empty($uuid)) {
                return Base::retError('');
            }
            return AbstractModel::transaction(function () use ($user, $uuid, $dialog_id, $type, $votes) {
                //
                $dialogMsgs = WebSocketDialogMsg::whereDialogId($dialog_id)
                    ->lockForUpdate()
                    ->whereType('vote')
                    ->orderByDesc('created_at')
                    ->where('msg', 'like', "%$uuid%")
                    ->get();
                //
                $result = [];
                if ($type == 'again') {
                    $res = WebSocketDialogMsg::sendMsg(null, $dialog_id, 'vote', $dialogMsgs[0]->msg, $user->userid);
                    if (Base::isError($res)) {
                        return $res;
                    }
                    $result[] = $res['data'];
                } else {
                    foreach ($dialogMsgs as $dialogMsg) {
                        $action = "change-{$dialogMsg->id}";
                        $msgData = $dialogMsg->msg;
                        if ($type == 'finish') {
                            $msgData['state'] = 0;
                        } else {
                            $msgDataVotes = $msgData['votes'] ?? [];
                            if (in_array($user->userid, array_column($msgDataVotes, 'userid'))) {
                                return Base::retError('');
                            }
                            $msgDataVotes[] = [
                                'userid' => $user->userid,
                                'votes' => $votes,
                            ];
                            $msgData['votes'] = $msgDataVotes;
                        }
                        //
                        $res = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'vote', $msgData, $user->userid);
                        if (Base::isError($res)) {
                            return $res;
                        }
                        $result[] = $res['data'];
                    }
                }
                //
                return Base::retSuccess('', $result);
            });
        } else {
            $strlen = mb_strlen($text);
            $noimglen = mb_strlen(preg_replace("/<img[^>]*?>/i", "", $text));
            if ($strlen < 1) {
                return Base::retError('');
            }
            if ($noimglen > 200000) {
                return Base::retError('200000');
            }
            $msgData = [
                'text' => $text,
                'list' => $list,
                'userid' => $user->userid,
                'uuid' => $uuid ?: Base::generatePassword(36),
                'multiple' => $multiple,
                'anonymous' => $anonymous,
                'votes' => [],
                'state' => 1
            ];
            $res = WebSocketDialogMsg::sendMsg($action, $dialog_id, 'vote', $msgData, $user->userid);
            if (Base::isError($res)) {
                return $res;
            }
            return Base::retSuccess('', [$res['data']]);
        }
    }

    /**
     * @api {get} api/dialog/msg/top          52. /
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__top
     *
     * @apiParam {Number} msg_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__top()
    {
        $user = User::auth();
        //
        $msg_id = intval(Request::input("msg_id"));
        //
        $msg = WebSocketDialogMsg::whereId($msg_id)->first();
        if (empty($msg)) {
            return Base::retError("");
        }
        $dialog = WebSocketDialog::checkDialog($msg->dialog_id);
        //
        $before = $dialog->top_msg_id;
        $beforeTopUserid = $dialog->top_userid;
        $dialog->top_msg_id = $msg->id == $before ? 0 : $msg->id;
        $dialog->top_userid = $dialog->top_msg_id ? $user->userid : 0;
        $dialog->save();
        //
        $data = [
            'add' => null,
            'update' => [
                'dialog_id' => $dialog->id,
                'top_msg_id' => $dialog->top_msg_id,
                'top_userid' => $dialog->top_userid,
            ]
        ];
        $res = WebSocketDialogMsg::sendMsg(null, $dialog->id, 'top', [
            'action' => $dialog->top_msg_id ? 'add' : 'remove',
            'data' => [
                'id' => $msg->id,
                'type' => $msg->type,
                'msg' => $msg->quoteTextMsg()
            ]
        ], $user->userid);
        if (Base::isSuccess($res)) {
            $data['add'] = $res['data'];
            $dialog->pushMsg('updateTopMsg', $data['update']);
        } else {
            $dialog->top_msg_id = $before;
            $dialog->top_userid = $beforeTopUserid;
            $dialog->save();
        }
        //
        return Base::retSuccess($dialog->top_msg_id ? '' : '', $data);
    }

    /**
     * @api {get} api/dialog/msg/topinfo          53. 
     *
     * @apiDescription token
     * @apiVersion 1.0.0
     * @apiGroup dialog
     * @apiName msg__topinfo
     *
     * @apiParam {Number} dialog_id            ID
     *
     * @apiSuccess {Number} ret     10
     * @apiSuccess {String} msg     
     * @apiSuccess {Object} data    
     */
    public function msg__topinfo()
    {
        User::auth();
        //
        $dialog_id = intval(Request::input('dialog_id'));
        //
        $dialog = WebSocketDialog::checkDialog($dialog_id);
        //
        $topMsg = WebSocketDialogMsg::whereId($dialog->top_msg_id)->first();
        //
        return Base::retSuccess('success', $topMsg);
    }
}

Function Calls

None

Variables

None

Stats

MD5 22347a6a04e5ba472f7c47462d1ce0d0
Eval Count 0
Decode Time 186 ms