General.php 12.0 KB
<?php

namespace addons\workorder\library;

use app\common\library\Email;
use app\common\library\Sms as Smslib;
use think\Db;
use think\Validate;

class General
{
    protected static $instance        = null;
    protected        $workorderConfig = [];

    public function __construct($options = [])
    {
        $this->workorderConfig                = $options;
        $this->workorderConfig['notice_mail'] = isset($options['notice_mail']) ? explode(',', $options['notice_mail']) : [];
        $this->workorderConfig['notice_sms']  = isset($options['notice_sms']) ? explode(',', $options['notice_sms']) : [];
    }

    public static function instance($options = [])
    {
        if (is_null(self::$instance)) {
            self::$instance = new static($options);
        }

        return self::$instance;
    }

    /**
     * 计算一个工程师的平均回复时间
     * 通常在有新的回复时调用
     * @param int $engineerId 工程师ID
     * @return float
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public static function calcEngineerAvgResTime($engineerId)
    {
        $workorderTimeStatistics = Db::name('workorder_time_statistics')
            ->where('type', 'in', '1,2')
            ->where('engineer_id', $engineerId)
            ->where('time_consum', '>', '0')
            ->avg('time_consum');

        Db::name('workorder_engineers')->where('id', $engineerId)->update([
            'avg_response_time' => ceil($workorderTimeStatistics)
        ]);

        return $workorderTimeStatistics;
    }

    /**
     * 发送邮件通知
     * @param obj $row 工单
     * @param string $event 事件
     * @return bool
     * @throws \think\exception\DbException
     */
    public static function mailNotice($row, $event, $subject, $message)
    {

        if (!in_array($event, self::$instance->workorderConfig['notice_mail'])) {
            return false;
        }

        if ($event == 'user_order_handle' || $event == 'user_got_reply') {
            if (!isset($row->email) || !isset($row->remind) || !$row->email || ($row->remind != 2)) {
                return false;
            }
        } else {
            if (!$row->engineer_id) {
                return false;
            }
            $row        = \addons\workorder\model\Engineer::get($row->engineer_id);
            $row->email = $row->user->email;
        }

        if (!Validate::is($row->email, "email")) {
            return false;
        }
        $email  = new Email;
        $result = $email->to($row->email)
            ->subject($subject)
            ->message('<div style="min-height:550px; padding: 100px 55px 200px;">' . $message . '</div>')
            ->send();

        if ($result) {
            return true;
        } else {
            //$email->getError();
            return false;
        }
    }

    /**
     * 发送短信通知
     * @param obj $row 工单
     * @param string $event 事件
     * @return bool
     * @throws \think\exception\DbException
     */
    public static function smsNotice($row, $event)
    {
        if (!in_array($event, self::$instance->workorderConfig['notice_sms'])) {
            return false;
        }

        // 最多12个字符
        $msg = mb_strlen($row->title) > 12 ? mb_substr($row->title, 0, 9) . '...' : $row->title;

        // 兼容短信宝和创蓝
        $smsbao = get_addon_info('smsbao');
        $clsms  = get_addon_info('clsms');
        if (($smsbao && $smsbao['state'] == 1) || ($clsms && $clsms['state'] == 1)) {
            switch ($event) {
                case 'user_order_handle':
                    $msg = '工程师已查看您提交的工单:' . $msg . ',正在处理中。';
                    break;
                case 'user_got_reply':
                    $msg = '工程师已回复您提交的工单:' . $msg . ',请您及时查看反馈。';
                    break;
                case 'engineer_new_order':
                    $msg = '尊敬的工程师,您好,您收到了一条新的工单:' . $msg . ',请及时处理。';
                    break;
                case 'engineer_got_reply':
                    $msg = '尊敬的工程师,您好,工单:' . $msg . ',已收到用户反馈,请您及时处理。';
                    break;
                case 'engineer_urging':
                    $msg = '尊敬的工程师,您好,工单:' . $msg . ',用户希望您尽快回复。';
                    break;
                default:
                    $msg = '工单系统无法识别发送情景';
                    break;
            }
        }

        if ($event == 'user_order_handle' || $event == 'user_got_reply') {
            if (!isset($row->mobile) || !isset($row->remind) || !$row->mobile || ($row->remind != 1)) {
                return false;
            }
        } else {
            if (!$row->engineer_id) {
                return false;
            }
            $row         = \addons\workorder\model\Engineer::get($row->engineer_id);
            $row->mobile = $row->user->mobile;
        }

        if (!$row->mobile || !Validate::regex($row->mobile, "^1\d{10}$")) {
            return false;
        }

        if (!\think\Hook::get('sms_send')) {
            return false;
        }

        // 兼容创蓝
        if ($clsms && $clsms['state'] == 1) {
            $clsms  = new \addons\clsms\library\Clsms();
            $result = $clsms->smstype(0)->mobile($row->mobile)->msg($msg)->send();
            if ($result) {
                return true;
            } else {
                return false;
            }
        }

        // 兼容阿里云短信
        $alisms = get_addon_info('alisms');
        if ($alisms && $alisms['state'] == 1) {
            $params = [
                'mobile' => $row->mobile,
                'msg'    => [
                    'title' => $msg
                ],
                'event'  => $event
            ];
            $ret    = \think\Hook::listen('sms_notice', $params, null, true);
        } else {
            $ret = Smslib::notice($row->mobile, $msg, $event);
        }

        if ($ret) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取文件后缀
     * @param string $filename 文件路径/名称
     * @return string
     */
    public static function getFileExtension($filename)
    {
        $filename = explode('.', $filename);
        return end($filename);
    }

    /**
     * 生成文件后缀图片
     * @param string $suffix 后缀
     * @param null $background
     * @return string
     */
    public static function build_suffix_image($suffix, $background = null)
    {
        $suffix = mb_substr(strtoupper($suffix), 0, 4);
        $total  = unpack('L', hash('adler32', $suffix, true))[1];
        $hue    = $total % 360;
        list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);

        $background = $background ? $background : "rgb({$r},{$g},{$b})";

        $icon = <<<EOT
        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
            <path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
            <path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
            <polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
            <path style="fill:{$background};" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16 V416z"/>
            <path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
            <g><text><tspan x="220" y="380" font-size="124" font-family="Verdana, Helvetica, Arial, sans-serif" fill="white" text-anchor="middle">{$suffix}</tspan></text></g>
        </svg>
EOT;
        return $icon;
    }

    /**
     * 清理xss
     * @param string $val
     * @return string
     */
    public static function removeXss($val)
    {
        $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val);

        $search = 'abcdefghijklmnopqrstuvwxyz';
        $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $search .= '1234567890!@#$%^&*()';
        $search .= '~`";:?+/={}[]-_|\'\\';
        for ($i = 0; $i < strlen($search); $i++) {
            $val = preg_replace('/(&#[xX]0{0,8}' . dechex(ord($search[$i])) . ';?)/i', $search[$i], $val); // with a ;
            $val = preg_replace('/(&#0{0,8}' . ord($search[$i]) . ';?)/', $search[$i], $val); // with a ;
        }

        $ra1   = [
            'javascript',
            'vbscript',
            'expression',
            'applet',
            'meta',
            'xml',
            'blink',
            'link',
            'style',
            'script',
            'embed',
            'object',
            'iframe',
            'frame',
            'frameset',
            'ilayer',
            'layer',
            'bgsound',
            'title',
            'base'
        ];
        $ra2   = [
            'onabort',
            'onactivate',
            'onafterprint',
            'onafterupdate',
            'onbeforeactivate',
            'onbeforecopy',
            'onbeforecut',
            'onbeforedeactivate',
            'onbeforeeditfocus',
            'onbeforepaste',
            'onbeforeprint',
            'onbeforeunload',
            'onbeforeupdate',
            'onblur',
            'onbounce',
            'oncellchange',
            'onchange',
            'onclick',
            'oncontextmenu',
            'oncontrolselect',
            'oncopy',
            'oncut',
            'ondataavailable',
            'ondatasetchanged',
            'ondatasetcomplete',
            'ondblclick',
            'ondeactivate',
            'ondrag',
            'ondragend',
            'ondragenter',
            'ondragleave',
            'ondragover',
            'ondragstart',
            'ondrop',
            'onerror',
            'onerrorupdate',
            'onfilterchange',
            'onfinish',
            'onfocus',
            'onfocusin',
            'onfocusout',
            'onhelp',
            'onkeydown',
            'onkeypress',
            'onkeyup',
            'onlayoutcomplete',
            'onload',
            'onlosecapture',
            'onmousedown',
            'onmouseenter',
            'onmouseleave',
            'onmousemove',
            'onmouseout',
            'onmouseover',
            'onmouseup',
            'onmousewheel',
            'onmove',
            'onmoveend',
            'onmovestart',
            'onpaste',
            'onpropertychange',
            'onreadystatechange',
            'onreset',
            'onresize',
            'onresizeend',
            'onresizestart',
            'onrowenter',
            'onrowexit',
            'onrowsdelete',
            'onrowsinserted',
            'onscroll',
            'onselect',
            'onselectionchange',
            'onselectstart',
            'onstart',
            'onstop',
            'onsubmit',
            'onunload'
        ];
        $ra    = array_merge($ra1, $ra2);
        $found = true;
        while ($found == true) {

            $val_before = $val;
            for ($i = 0; $i < sizeof($ra); $i++) {
                $pattern = '/';
                for ($j = 0; $j < strlen($ra[$i]); $j++) {
                    if ($j > 0) {
                        $pattern .= '(';
                        $pattern .= '(&#[xX]0{0,8}([9ab]);)';
                        $pattern .= '|';
                        $pattern .= '|(&#0{0,8}([9|10|13]);)';
                        $pattern .= ')*';
                    }
                    $pattern .= $ra[$i][$j];
                }
                $pattern     .= '/i';
                $replacement = substr($ra[$i], 0, 2) . '<k>' . substr($ra[$i], 2);
                $val         = preg_replace($pattern, $replacement, $val);
                if ($val_before == $val) {
                    $found = false;
                }
            }
        }
        return $val;
    }
}