chengkun
2025-08-29 73cdff843994b42beef7a22844326f83fee104de
提交
19 files modified
17 files added
3 files deleted
26712 ■■■■■ changed files
app/admin/controller/Blog.php 101 ●●●●● patch | view | raw | blame | history
app/admin/controller/Common.php 65 ●●●● patch | view | raw | blame | history
app/admin/controller/Login.php 125 ●●●● patch | view | raw | blame | history
app/admin/controller/Upload.php 13 ●●●●● patch | view | raw | blame | history
app/admin/util/Opadmin.php 90 ●●●●● patch | view | raw | blame | history
app/admin/view/blog/add.html 330 ●●●●● patch | view | raw | blame | history
app/admin/view/blog/index.html 63 ●●●●● patch | view | raw | blame | history
app/admin/view/common/element-plus.html 2 ●●● patch | view | raw | blame | history
app/admin/view/common/guide.html 11 ●●●● patch | view | raw | blame | history
app/admin/view/common/left.html 79 ●●●● patch | view | raw | blame | history
app/admin/view/common/title.html 3 ●●●● patch | view | raw | blame | history
app/admin/view/index/index.html 50 ●●●●● patch | view | raw | blame | history
app/admin/view/login/index.html 198 ●●●● patch | view | raw | blame | history
app/home/view/index/index.html 3 ●●●● patch | view | raw | blame | history
config/filesystem.php 4 ●●●● patch | view | raw | blame | history
public/static/admin/css/reset.css 114 ●●●●● patch | view | raw | blame | history
public/static/admin/js/blog/add.js 113 ●●●●● patch | view | raw | blame | history
public/static/admin/js/blog/index.js 66 ●●●●● patch | view | raw | blame | history
public/static/admin/login/fontawesome-webfont.eot patch | view | raw | blame | history
public/static/admin/login/forget.css 308 ●●●●● patch | view | raw | blame | history
public/static/admin/login/form-bg.png patch | view | raw | blame | history
public/static/admin/login/icon.png patch | view | raw | blame | history
public/static/admin/login/login-bg.jpg patch | view | raw | blame | history
public/static/admin/login/login.css 574 ●●●●● patch | view | raw | blame | history
public/static/admin/login/logo-m.png patch | view | raw | blame | history
public/static/admin/login/register.css 209 ●●●●● patch | view | raw | blame | history
public/static/element/index_other.css 26 ●●●●● patch | view | raw | blame | history
public/static/home/css/index/index.css 9 ●●●●● patch | view | raw | blame | history
public/static/home/images/collaborators-1.png patch | view | raw | blame | history
public/static/home/images/collaborators-2.png patch | view | raw | blame | history
public/static/home/images/collaborators-3.png patch | view | raw | blame | history
public/static/home/images/img-1.png patch | view | raw | blame | history
public/static/home/images/img-2.png patch | view | raw | blame | history
public/static/home/images/img-3.png patch | view | raw | blame | history
public/static/images/logo-no-bg.png patch | view | raw | blame | history
public/static/images/logo.jpg patch | view | raw | blame | history
public/static/images/logo.png patch | view | raw | blame | history
public/static/plugin/wangeditor/index.js 24129 ●●●●● patch | view | raw | blame | history
public/static/plugin/wangeditor/style.css 27 ●●●●● patch | view | raw | blame | history
app/admin/controller/Blog.php
New file
@@ -0,0 +1,101 @@
<?php
namespace app\admin\controller;
use think\Exception;
use think\exception\ValidateException;
use think\facade\Filesystem;
use think\facade\View;
use think\response\Json;
class Blog extends Common {
    public function index(): string {
        return View::fetch('index');
    }
    public function add(): string {
        header('Content-Type:text/html;charset=utf-8');
        View::assign('menuitem', strtolower('Blog-index'));
        return View::fetch('add');
    }
    /**
     * 上传图片
     * @return Json
     */
    public function upload_img(): Json {
        try {
            if (!request()->isPost()) {
                throw new Exception('请求方式错误');
            }
            $file    = request()->file('image');
            $files[] = $file;
            validate(['image' => 'fileSize:10240|fileExt:jpg'])->check($files);
            // 上传到本地服务器
            $savename = (new Filesystem)::disk('public')->putFile('/images', $file);
            $savename = (new Filesystem)::disk('public')->url($savename); // 获取上传后的文件路径
            if (!$savename) {
                throw new Exception('上传失败');
            }
            $result = [
                'errno' => 0,
                'data'  => [
                    'url' => $savename,
                ],
            ];
        } catch (ValidateException $e) {
            return Json([
                'errno'   => 1,
                'message' => $e->getMessage(),
            ]);
        } catch (Exception $exc) {
            $result = [
                'errno'   => 1,
                'message' => $exc->getMessage(),
            ];
        }
        return json($result);
    }
    /**
     * 上传图片
     * @return Json
     */
    public function upload_cover_img(): Json {
        try {
            if (!request()->isPost()) {
                throw new Exception('请求方式错误');
            }
            $file    = request()->file('file');
            $files[] = $file;
            validate(['image' => 'fileSize:10240|fileExt:jpg'])->check($files);
            // 上传到本地服务器
            $savename = (new Filesystem)::disk('public')->putFile('/images', $file);
            $savename = (new Filesystem)::disk('public')->url($savename); // 获取上传后的文件路径
            if (!$savename) {
                throw new Exception('上传失败');
            }
            $result = [
                'code' => 200,
                'data' => [
                    'url' => $savename,
                ],
            ];
        } catch (ValidateException $e) {
            return Json([
                'code'    => $e->getCode(),
                'message' => $e->getMessage(),
            ]);
        } catch (Exception $exc) {
            $result = [
                'code'    => $exc->getCode(),
                'message' => $exc->getMessage(),
            ];
        }
        return json($result);
    }
}
app/admin/controller/Common.php
@@ -2,6 +2,7 @@
namespace app\admin\controller;
use app\admin\util\Opadmin;
use think\facade\View;
use think\facade\Request;
@@ -13,33 +14,31 @@
use think\facade\Log;
use think\facade\Session;
class Common extends BaseController
{
    public $Opadmin = null;
    public $admin_id = null;
    public $cinfo = null;
    public function __construct()
    {
class Common extends BaseController {
    public ?Opadmin $Opadmin  = NULL;
    public mixed    $admin_id = NULL;
    public mixed    $cinfo    = NULL;
    public function __construct() {
        Log::record(getcurrurl());
        header('Content-Type:text/html;charset=utf-8');
        $this->Opadmin = new \app\admin\util\Opadmin();
        $this->Opadmin = new Opadmin();
        if (!$this->Opadmin->islogin()) {
            $this->redirect(url('/admin/login/index')->build());
        }
        $this->cinfo = $this->Opadmin->info;
        $this->cinfo    = $this->Opadmin->info;
        $this->admin_id = $this->Opadmin->info['id'];
        $menulist = $this->Opadmin->menu();
        $menulist       = $this->Opadmin->menu();
        View::assign('menulist', $menulist);
        View::assign('cinfo', $this->Opadmin->info);
        View::assign('menuitem', Request()->controller(true) . '-' . Request()->action(true));
        View::assign('menuitem', Request()->controller(TRUE) . '-' . Request()->action(TRUE));
    }
    protected function getCountrychildrenids($id)
    {
    protected function getCountrychildrenids($id): array {
        $where['father_id'] = $id;
        $result = Db::name('country_code')->field('id as value,cate_name as label')->where($where)->cacheAlways(TRUE, 0, 'country_codes')->order('order_id asc,id asc')->select()->toArray();
        $result             = Db::name('country_code')->field('id as value,cate_name as label')->where($where)->cacheAlways(TRUE, 0, 'country_codes')->order('order_id asc,id asc')->select()->toArray();
        if ($result) {
            foreach ($result as &$val) {
                $val['children'] = $this->getCountrychildrenids($val['value']); ////
@@ -49,26 +48,32 @@
            return [];
        }
    }
    //////上传文件到cos/////////////////
    protected function uploadFileToCos($file = '')
    {
    /**
     * 上传文件到cos
     * @param string $file
     * @return object|string|void
     */
    protected function uploadFileToCos(string $file = '') {
        if ($file && Config::get('qcloud.isopencos') == 1) {
            $key = getCosName($file);
            $key       = getCosName($file);
            $localPath = '.' . $file;
            $cos = new \common\Uploadcos();
            $result = $cos->cosUpload($key, $localPath);
            return $result;
            $cos       = new \common\Uploadcos();
            return $cos->cosUpload($key, $localPath);
        }
    }
    //////删除cos中的文件/////////////////
    protected function deleteFileFromCos($file = '', $versionId = '')
    {
    /**
     * 删除cos中的文件
     * @param string $file
     * @param string $versionId
     * @return object|string|void
     */
    protected function deleteFileFromCos(string $file = '', string $versionId = '') {
        if ($file && Config::get('qcloud.isopencos') == 1) {
            $key = getCosName($file);
            $cos = new \common\Uploadcos();
            $result = $cos->cosDelete($key, $versionId);
            return $result;
            return $cos->cosDelete($key, $versionId);
        }
    }
}
app/admin/controller/Login.php
@@ -2,6 +2,8 @@
namespace app\admin\controller;
use app\admin\util\Opadmin;
use think\Exception;
use think\facade\Db;
use think\facade\View;
use think\facade\Request;
@@ -9,60 +11,65 @@
use think\captcha\facade\Captcha;
use app\BaseController;
class Login extends BaseController
{
    public function index()
    {
class Login extends BaseController {
    public function index() {
        header('Content-Type:text/html;charset=utf-8');
        $Opadmin = new \app\admin\util\Opadmin();
        $Opadmin = new Opadmin();
        if ($Opadmin->islogin()) {
            $this->redirect(url('/admin/')->build());
        }
        return View::fetch();
    }
    public function login()
    {
        if (request()->isPost()) {
            $Opadmin = new \app\admin\util\Opadmin(Request::post('username'), Request::post('password')); //////企业账号/////////////
            $returnmsg = $Opadmin->login();
            if ($returnmsg['code'] == 400) {
                return $returnmsg;
            } elseif ($returnmsg['code'] == 200) {
    /**
     * 登录
     * @return bool|array
     */
    public function login(): bool|array {
        try {
            if (!request()->isPost()) {
                throw new Exception("请求方式错误!");
            }
            $Opadmin = new Opadmin(Request::post('username'), Request::post('password')); //////企业账号/////////////
            $result = $Opadmin->login();
            if ($result['code'] == 400) {
                throw new Exception($result['message'], $result['code']);
            }
            if ($result['code'] == 200) {
                $backurl = Request::post('backurl');
                if (empty($backurl)) {
                    $returnmsg['url'] = url('/admin/index/index')->build();
                    $result['url'] = url('/admin/index/index')->build();
                } else {
                    $returnmsg['url'] = $backurl;
                    $result['url'] = $backurl;
                }
                return $returnmsg;
            }
        } else {
            $d['code'] = 0;
            $d['des'] = '参数有误!';
            return $d;
        } catch (Exception $exc) {
            $result = [
                'code' => $exc->getCode(),
                'des'  => $exc->getMessage(),
            ];
        }
        return $result;
    }
    public function logout()
    {
        $Opadmin = new \app\admin\util\Opadmin();
    public function logout() {
        $Opadmin = new Opadmin();
        $Opadmin->loginout();
        $this->redirect(url('/admin/login/index')->build());
    }
    public function captcha()
    {
    public function captcha() {
        return Captcha::create();
    }
    public function captchaCheck()
    {
    public function captchaCheck() {
        if (!Request::isPost()) {
            return $this->errorResponse(lang('request_method_incorrect'));
        }
        $code = trim(Request::post('captcha'));
        // 检测输入的验证码是否正确,$value为用户输入的验证码字符串
        $captcha = new Captcha();
        if (!$captcha->check($code)) {
@@ -71,19 +78,18 @@
        }
        return $this->successResponse(lang('captcha_success'));
    }
    public function captchaCheckAndMsg()
    {
    public function captchaCheckAndMsg() {
        if (!Request::isPost()) {
            return $this->errorResponse(lang('request_method_incorrect'));
        }
        try {
            $code = trim(Request::post('captcha'));
            $code  = trim(Request::post('captcha'));
            $phone = trim(Request::post('phone'));
            //        echo $phone;
            //        exit();
            // 检测输入的验证码是否正确,$value为用户输入的验证码字符串
            //            $captcha = new Captcha();
            if (!captcha_check($code)) {
@@ -91,28 +97,28 @@
                throw new \Exception(lang('captcha_is_incorrect'), 400);
                //                return $this->errorResponse(lang('captcha_is_incorrect'));
            }
            //查询120秒内是否已有发送
            $localTime = time();
            $where = [
            $where     = [
                ['phone', '=', $phone],
                ['add_time', '>=', $localTime - 120],
                ['type', '=', 1],
            ];
            $info = Db::name('phone_msg')->field('*')->where($where)->find();
            $info      = Db::name('phone_msg')->field('*')->where($where)->find();
            if ($info) {
                throw new \Exception("二分钟内,只能发送一次", 400);
            }
            $phoneCode = randomkeys(4, 'regCode');
            $cred = new \TencentCloud\Common\Credential(Config::get('qcloud.Qcloud.SecretId'), Config::get('qcloud.Qcloud.SecretKey'));
            // 实例化一个http选项,可选的,没有特殊需求可以跳过
            $httpProfile = new \TencentCloud\Common\Profile\HttpProfile();
            // 配置代理(无需要直接忽略)
            // $httpProfile->setProxy("https://ip:port");
            $httpProfile->setReqMethod("GET");  // get请求(默认为post请求)
            $httpProfile->setReqTimeout(10);    // 请求超时时间,单位为秒(默认60秒)
            $httpProfile->setReqMethod("GET");                     // get请求(默认为post请求)
            $httpProfile->setReqTimeout(10);                       // 请求超时时间,单位为秒(默认60秒)
            $httpProfile->setEndpoint("sms.tencentcloudapi.com");  // 指定接入地域域名(默认就近接入)
            // 实例化一个client选项,可选的,没有特殊需求可以跳过
            $clientProfile = new \TencentCloud\Common\Profile\ClientProfile();
@@ -139,10 +145,10 @@
            // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
            $req->TemplateId = Config::get('qcloud.Qcloud.TemplateId');
            /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空*/
            $req->TemplateParamSet = array($phoneCode, '2');
            $req->TemplateParamSet = [$phoneCode, '2'];
            /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
             * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号*/
            $req->PhoneNumberSet = array("+86" . $phone);
            $req->PhoneNumberSet = ["+86" . $phone];
            /* 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回 */
            $req->SessionContext = "";
            /* 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手] */
@@ -156,17 +162,17 @@
            //            print_r($resp->TotalCount);
            //            print_r($resp->toJsonString());
            //            exit();
            $newdata = [
                'phone' => $phone,
                'code' => $phoneCode,
                'type' => 1,
                'is_use' => 0,
                'phone'    => $phone,
                'code'     => $phoneCode,
                'type'     => 1,
                'is_use'   => 0,
                'add_time' => $localTime,
            ];
            $id = Db::name('phone_msg')->insertGetId($newdata);
            $result = [
                'id' => $id,
            $id      = Db::name('phone_msg')->insertGetId($newdata);
            $result  = [
                'id'  => $id,
                //                'phonecode' => $phoneCode,
                'msg' => 'ok',
            ];
@@ -175,17 +181,16 @@
            return $this->errorResponse($e->getMessage());
        }
    }
    public function getLanguageList()
    {
    public function getLanguageList() {
        ////////
        try {
            if (!Request::isPost()) {
                throw new Exception(lang('request_method_incorrect'));
            }
            $condition['is_show'] = 1;
            $order = 'order_id asc,id asc';
            $list = Db::name('language')->field("*")->where($condition)->order($order)->select()->toArray();
            $order                = 'order_id asc,id asc';
            $list                 = Db::name('language')->field("*")->where($condition)->order($order)->select()->toArray();
            if (!$list) {
                $list = [];
            }
app/admin/controller/Upload.php
New file
@@ -0,0 +1,13 @@
<?php
namespace app\admin\controller;
use think\facade\Filesystem;
class Upload extends Common {
    public function index() {
        $file = request()->file('image');
        // 上传到本地服务器
        $savename = (new Filesystem)::disk('public')->putFile('/images', $file);
    }
}
app/admin/util/Opadmin.php
@@ -13,13 +13,13 @@
class Opadmin {
    
    public string $user_name; //用户名
    private string $password; //密码
    private mixed $session_prefix; //SESSION前缀
    public string  $user_name;      //用户名
    private string $password;       //密码
    private mixed  $session_prefix; //SESSION前缀
    
    private string $kinfo = 'admininfo';
    public mixed $info;
    public string $commfield = 'id,user_name,real_name,ban_access,initialize,start_time,end_time';
    private string $kinfo     = 'admininfo';
    public mixed   $info;
    public string  $commfield = 'id,user_name,real_name,ban_access,initialize,start_time,end_time';
    
    /**
     * +----------------------------------------------------------
@@ -27,7 +27,7 @@
     * +----------------------------------------------------------
     * @param string $username 用户名
     * @param string $password 密码
     * +----------------------------------------------------------
     *                         +----------------------------------------------------------
     */
    public function __construct(string $username = '', string $password = '') {
        $this->session_prefix = Config::get('app.session_admin_prefix');
@@ -35,7 +35,7 @@
        $this->kinfo = $this->session_prefix . $this->kinfo;
        //用于登陆的时候初始化变量
        $this->user_name = $username;
        $this->password = joinmd5($password);
        $this->password  = joinmd5($password);
        //判断session是否存在,存在就赋值
        if (session('?' . $this->kinfo)) {
            $this->info = session($this->kinfo);
@@ -57,13 +57,13 @@
//        $subwhere['password'] = $this->password;
        $tempinfo = Db::name('administrators')->field('id,password,ban_access,login_lock_time,login_try_num')->where($subwhere)->find();
        if (!$tempinfo) {
            $d['code'] = 400;
            $d['code']    = 400;
            $d['message'] = '账号或密码错误、请重试';
            return $d;
        }
        
        if ($tempinfo['login_lock_time'] != '' && time() - $tempinfo['login_lock_time'] < 600) {
            $d['code'] = 400;
            $d['code']    = 400;
            $d['message'] = '该账号已被锁定、请10分钟后重试';
            return $d;
        }
@@ -72,14 +72,14 @@
            // 次数 小于等于 1 -> 锁定登录操作
            if ($tempinfo['login_try_num'] <= 1) {
                $upd_data['login_lock_time'] = time();
                $upd_data['login_try_num'] = 5;
                $upd_data['login_try_num']   = 5;
                Db::name('administrators')->where($upd_where)->save($upd_data);
                $d['code'] = 400;
                $d['code']    = 400;
                $d['message'] = '该账号已被锁定、请10分钟后重试';
            } else {
                // 次数 小于2 次数-1 -> 账号密码错误
                Db::name('administrators')->where($upd_where)->dec('login_try_num')->update();
                $d['code'] = 400;
                $d['code']    = 400;
                $d['message'] = '账号或密码错误、剩余' . ($tempinfo['login_try_num'] - 1) . '次';
            }
            return $d;
@@ -87,21 +87,28 @@
        /////以下密码正确,成功登陆///////////
        Db::name('administrators')->where($upd_where)->save(['login_try_num' => 5]);
        if ($tempinfo['ban_access'] == 0) {
            $msg['code'] = 400;
            $msg['code']    = 400;
            $msg['message'] = '该账号已被禁止登录';
            return $msg;
        }
        return $this->getlogininfo($tempinfo['id']);
    }
    
    //////获取用户登录信息///////////
    /**
     * 获取用户登录信息
     * @param $id
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getlogininfo($id = ''): array {
        $subwhere['id'] = $id;
        $info = Db::name('administrators')->field($this->commfield)->where($subwhere)->find();
        $info           = Db::name('administrators')->field($this->commfield)->where($subwhere)->find();
        if ($info) {
            if ($info['initialize'] == 0 && ($info['start_time'] > time() || $info['end_time'] < time())) {
                $this->loginout();
                $msg['code'] = 400;
                $msg['code']    = 400;
                $msg['message'] = '账号已过期,请联系管理员!';
                return $msg;
            }
@@ -111,44 +118,49 @@
            $this->writelogs();
            //更新登陆信息
            if ($this->updateInfo()) {
                $msg['code'] = 200;
                $msg['code']    = 200;
                $msg['message'] = '登录成功';
            } else {
                $msg['code'] = 400;
                $msg['code']    = 400;
                $msg['message'] = '登录失败';
            }
        } else {
            $msg['code'] = 400;
            $msg['code']    = 400;
            $msg['message'] = '用户名或密码不正确';
        }
        return $msg;
    }
    
    /////账号登录信息///////////////
    /**
     * 更新用户信息
     * @return bool
     */
    private function updateInfo(): bool {
        $temp['login_time'] = time();
        $temp['login_ip'] = getIP();
        $where['id'] = $this->info['id'];
        $count = Db::name('administrators')->where($where)->save($temp);
        $temp['login_ip']   = getIP();
        $where['id']        = $this->info['id'];
        $count              = Db::name('administrators')->where($where)->save($temp);
        if ($count > 0)
            return TRUE;
        else
            return FALSE;
    }
    
    /**
     * 写入登陆日志
     * @return void
     */
    private function writelogs(): void {
        //////登陆记录//////////
        $d['login_ip'] = getIP();
        $d['login_ip']   = getIP();
        $d['login_time'] = time();
        $d['admin_id'] = $this->info['id'];
        $d['admin_id']   = $this->info['id'];
        Db::name('admin_login_logs')->insert($d);
    }
    
    /**
     * +----------------------------------------------------------
     * 保存session
     * +----------------------------------------------------------
     * +----------------------------------------------------------
     * @return void
     */
    public function saveSession(): void {
        session($this->kinfo, $this->info);
@@ -156,11 +168,8 @@
    }
    
    /**
     * +----------------------------------------------------------
     * 判断用户是否登陆
     * @return bool
     * +----------------------------------------------------------
     * +----------------------------------------------------------
     */
    public function islogin(): bool {
        if (isset($this->info['id']) && $this->info['id'] != '')
@@ -170,11 +179,8 @@
    }
    
    /**
     * +----------------------------------------------------------
     * 用户退出
     * @return bool
     * +----------------------------------------------------------
     * +----------------------------------------------------------
     */
    public function loginout(): bool {
        $this->info = "";
@@ -185,12 +191,16 @@
        return TRUE;
    }
    
    /**
     * 获取菜单
     * @return array
     */
    public function menu(): array {
        $condition['show_menu'] = 1;
        $order = 'order_id asc,id asc';
        $list = Db::name('admin_menu')
        $order                  = 'order_id asc,id asc';
        $list                   = Db::name('admin_menu')
            ->field("id,title,menu_index,menu_icon,show_menu,menu_url,father_id")
            ->cacheAlways(TRUE, 0, 'admin_menu')
            ->cache(60)
            ->where($condition)
            ->order($order)
            ->withAttr('menu_index', function ($value) {
@@ -203,7 +213,7 @@
    
    /**
     * 获取菜单列表
     * @param $result
     * @param        $result
     * @param string $one_field
     * @return array
     */
@@ -215,7 +225,7 @@
            }
            return $result_arr;
        } else {
            return array();
            return [];
        }
    }
    
app/admin/view/blog/add.html
New file
@@ -0,0 +1,330 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <include file="common:title" />
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <include file="common:element-plus" />
    <!-- 富文本编辑器 -->
    <link rel="stylesheet" href="/static/plugin/wangeditor/style.css" media="all">
    <script type="text/javascript" src="/static/plugin/wangeditor/index.js"></script>
    <style>
        .editor—wrapper {
            border: 1px solid #ccc;
            z-index: 100;
            width: 100%;
            /* 按需定义 */
        }
        .toolbar-container {
            border-bottom: 1px solid #ccc;
        }
        .avatar-uploader .avatar {
            width: 178px;
            height: 178px;
            display: block;
        }
        .avatar-uploader .el-upload {
            border: 1px dashed var(--el-border-color);
            border-radius: 6px;
            cursor: pointer;
            position: relative;
            overflow: hidden;
            transition: var(--el-transition-duration-fast);
        }
        .avatar-uploader .el-upload:hover {
            border-color: var(--el-color-primary);
        }
        .el-icon.avatar-uploader-icon {
            font-size: 28px;
            color: #8c939d;
            width: 178px;
            height: 178px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div id="vue_item" v-cloak>
        <el-container>
            <el-aside class="el-menu-container" :width="el_aside_width">
                <!-- 侧边菜单 -->
                <include file="common:side_menu" />
            </el-aside>
            <el-container>
                <el-header>
                    <include file="common:guide" one_word="首页" two_word="文章管理" />
                </el-header>
                <el-main>
                    <el-card>
                        <template #header>
                            <div class="card-header">
                                <span>添加文章</span>
                                &emsp;
                                <el-link href="/admin/blog/index.html" type="primary" class="header_add_btn" icon="ArrowLeftBold" :underline="false">返回</el-link>
                            </div>
                        </template>
                        <el-form :model="addBlogForm" label-width="auto" size="large">
                            <el-form-item label="标题(中文)">
                                <el-input v-model="addBlogForm.title"></el-input>
                            </el-form-item>
                            <el-form-item label="标题(英文)">
                                <el-input v-model="addBlogForm.en_title"></el-input>
                            </el-form-item>
                            <el-form-item label="简介(中文)">
                                <el-input v-model="addBlogForm.desc" type="textarea" :rows="3"></el-input>
                            </el-form-item>
                            <el-form-item label="简介(英文)">
                                <el-input v-model="addBlogForm.en_desc" type="textarea" :rows="3"></el-input>
                            </el-form-item>
                            <el-form-item label="内容(中文)">
                                <div id="editor—wrapper" class="editor—wrapper" style="height: 500px; z-index: 101;">
                                    <div id="toolbar-container"><!-- 工具栏 --></div>
                                    <div id="editor-container" style="height: calc(100% - 40px);"><!-- 编辑器 --></div>
                                </div>
                                <!-- <div id="editer_data" style="width: 100%;">{{addBlogForm.content}}</div>
                                <textarea name="content" id="content" style="display:none;" v-model="addBlogForm.content"></textarea> -->
                            </el-form-item>
                            <el-form-item label="内容(英文)">
                                <div id="editor—wrapper-en" class="editor—wrapper" style="height: 500px;">
                                    <div id="toolbar-container-en"><!-- 工具栏 --></div>
                                    <div id="editor-container-en" style="height: calc(100% - 40px);"><!-- 编辑器 --></div>
                                </div>
                            </el-form-item>
                            <el-form-item label="封面图">
                                <el-upload class="avatar-uploader" action="/admin/blog/upload_cover_img.html" :show-file-list="false" :on-success="handleCoverImgSuccess" :before-upload="beforeCoverImgUpload">
                                    <template v-if="addBlogForm.cover_img">
                                        <div>
                                            <img :src="addBlogForm.cover_img" class="avatar" />
                                            <el-button type="danger" icon="Delete"></el-button>
                                        </div>
                                    </template>
                                    <el-icon v-else class="avatar-uploader-icon">
                                        <Plus />
                                    </el-icon>
                                </el-upload>
                            </el-form-item>
                            <el-form-item label="&emsp;">
                                <el-button type="primary" class="btn-min-width-120" @click="onSubmit" :disabled="submitDisabled">提交</el-button>
                            </el-form-item>
                        </el-form>
                    </el-card>
                </el-main>
                <el-footer></el-footer>
            </el-container>
        </el-container>
    </div>
</body>
<!-- 共用的方法 -->
<script src="/static/vue/mixin_admin.js"></script>
<script src="/static/admin/js/blog/add.js"></script>
<!-- 富文本编辑器和上传插件设置 -->
<script>
    const { createEditor, createToolbar } = window.wangEditor
    const editorConfig = {
        placeholder: '请输入中文内容...',
        onChange(editor) {
            const html = editor.getHtml();
            setHtmlValue(html);
        },
        MENU_CONF: {},
    }
    editorConfig.MENU_CONF['uploadImage'] = {
        server: '/admin/blog/upload_img.html',//上传图片服务端地址
        timeout: 5 * 1000, // 5s
        fieldName: 'image', // 服务端获取图片数据的参数名
        // meta: { token: 'xxx', a: 100 }, // 其它参数
        metaWithUrl: true, // join params to url
        headers: { Accept: 'text/x-json' },
        maxFileSize: 10 * 1024 * 1024, // 10M
        base64LimitSize: 10 * 1024, // insert base64 format, if file's size less than 5kb
        onBeforeUpload(file) {
            console.log('onBeforeUpload', file)
            return file // will upload this file
            // return false // prevent upload
        },
        onProgress(progress) {
            console.log('onProgress', progress)
        },
        onSuccess(file, res) {
            console.log('onSuccess', file, res)
        },
        onFailed(file, res) {
            // alert(res.message)
            console.log('onFailed', file, res)
        },
        onError(file, err, res) {
            // alert(err.message)
            console.error('onError', file, err, res)
        },
    }
    const editor = createEditor({
        selector: '#editor-container',
        html: '<p><br></p>',
        config: editorConfig,
        mode: 'default', // or 'simple'
    });
    const toolbarConfig = {}
    ///// 排除菜单组,写菜单组 key 的值即可/////
    toolbarConfig.excludeKeys = [
        'group-video',
        "emotion",
        "fullScreen",
    ];
    const toolbar = createToolbar({
        editor,
        selector: '#toolbar-container',
        config: toolbarConfig,
        mode: 'default', // or 'simple'
    })
    // console.log(toolbar.getConfig());
    ///////////////英文版///////////
    const editorConfigEn = {
        placeholder: '请输入英文内容...',
        onChange(editor) {
            const html = editor.getHtml();
            setHtmlValue(html, 2);
        },
        MENU_CONF: {},
    }
    editorConfigEn.MENU_CONF['uploadImage'] = {
        server: '/admin/blog/upload_img.html',//上传图片服务端地址
        timeout: 5 * 1000, // 5s
        fieldName: 'image', // 上传图片的参数名
        // meta: { token: 'xxx', a: 100 }, // 参数
        metaWithUrl: true, // join params to url
        headers: { Accept: 'text/x-json' },
        maxFileSize: 10 * 1024 * 1024, // 10M
        base64LimitSize: 10 * 1024, // insert base64 format, if file's size less than 5kb
        onBeforeUpload(file) {
            console.log('onBeforeUpload', file)
            return file // will upload this file
            // return false // prevent upload
        },
        onProgress(progress) {
            console.log('onProgress', progress)
        },
        onSuccess(file, res) {
            console.log('onSuccess', file, res)
        },
        onFailed(file, res) {
            // alert(res.message)
            console.log('onFailed', file, res)
        },
        onError(file, err, res) {
            // alert(err.message)
            console.error('onError', file, err, res)
        },
    }
    const editor_en = createEditor({
        selector: '#editor-container-en',
        html: '<p><br></p>',
        config: editorConfigEn,
        mode: 'default', // or 'simple'
    })
    const toolbarConfigEn = {
    }
    ///// 排除菜单组,写菜单组 key 的值即可/////
    toolbarConfigEn.excludeKeys = [
        'group-video',
        "emotion",
        "fullScreen",
    ];
    const toolbar_en = createToolbar({
        editor: editor_en,
        selector: '#toolbar-container-en',
        config: toolbarConfigEn,
        mode: 'default', // or 'simple'
    })
</script>
<script>
    /**
     * 富文本编辑器
     */
    // var E = window.wangEditor
    // const editor = new E('#editer_data')
    // var textarea = $('#content')
    // editor.config.onchange = function (html) {
    //     // 监控变化,同步更新到 textarea
    //     textarea.val(html)
    // }
    // // editor.config.onblur = function (html) {
    // //     // 编辑区域失去焦点后的操作,保存内容
    // //     save_reading_data();
    // // }
    // //设置提示文字
    // editor.config.placeholder = '请输入文章内容...'
    // //设置编辑区域z-index
    // editor.config.zIndex = 100
    // // 自定义菜单配置
    // editor.config.menus = [
    //     'bold',
    //     'fontSize',
    //     'italic',
    //     'underline',
    //     'strikeThrough',
    //     'indent',
    //     'lineHeight',
    //     'foreColor',
    //     'backColor',
    //     'link',
    //     'list',
    //     'justify',
    //     'image',
    // ]
    // //粘贴内容去掉图片
    // editor.config.pasteIgnoreImg = true
    // // 配置粘贴文本的内容处理
    // editor.config.pasteTextHandle = function (pasteStr) {
    //     // 对粘贴的文本进行处理,然后返回处理后的结果
    //     return pasteStr.replace(/<[^>]+>/g, "");
    // }
    // //上传图片服务端地址
    // editor.config.uploadImgServer = "/admin/upload/index_v1.html"
    // // 隐藏“网络图片”tab
    // editor.config.showLinkImg = false
    // // 将图片大小限制为 10M
    // editor.config.uploadImgMaxSize = 20 * 1024 * 1024
    // // 限制一次最多上传 20 张图片
    // editor.config.uploadImgMaxLength = 20
    // //编辑器初始化
    // editor.create()
    // // 初始化 textarea 的值
    // textarea.val(editor.txt.html())
    ////////////////////////////////////////富文本编辑器-end//////////////////////////////////
</script>
</html>
app/admin/view/blog/index.html
New file
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <include file="common:title" />
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <include file="common:element-plus">
</head>
<body>
    <div id="vue_item" v-cloak>
        <el-container>
            <el-aside class="el-menu-container" :width="el_aside_width">
                <!-- 侧边菜单 -->
                <include file="common:side_menu" />
            </el-aside>
            <el-container>
                <el-header>
                    <include file="common:guide" one_word="首页" two_word="文章管理" />
                </el-header>
                <el-main>
                    <el-card>
                        <template #header>
                            <div class="card-header">
                                <span>文章列表</span>
                                &emsp;
                                <el-link href="/admin/blog/add.html" type="primary" class="header_add_btn" icon="CirclePlusFilled" :underline="false">添加</el-link>
                            </div>
                        </template>
                        <el-table :data="list" :tree-props="{children: 'children'}" row-key="id" default-expand-all border style="width: 100%" ref="tableRef">
                            <el-table-column label="名称" prop="title"></el-table-column>
                            <!-- <el-table-column label="菜单索引" prop="menu_index"></el-table-column> -->
                            <el-table-column label="添加时间" prop="create_time" width="150">
                                <template #default="scope">
                                   {{formatDate(scope.row['create_time'])}}
                                </template>
                            </el-table-column>
                            <el-table-column label="状态" width="150" align="center">
                                <template #default="scope">
                                    <el-switch v-model="scope.row.show_menu" style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ccc" :active-value="1" :inactive-value="0" inline-prompt active-text="发布" inactive-text="下架" @change="updateShowMenu(scope.row)" />
                                </template>
                            </el-table-column>
                            <el-table-column label="操作选项" fixed="right" width="150" :align="alignValue(200)">
                                <template #default="scope">
                                    <el-button icon="edit" type="primary" @click="Edit(scope.row)"></el-button>
                                </template>
                            </el-table-column>
                        </el-table>
                    </el-card>
                </el-main>
                <el-footer></el-footer>
            </el-container>
        </el-container>
    </div>
</body>
<!-- 共用的方法 -->
<script src="/static/vue/mixin_admin.js"></script>
<script src="/static/admin/js/blog/index.js"></script>
</html>
app/admin/view/common/element-plus.html
@@ -1,6 +1,6 @@
<link rel="stylesheet" href="/static/element/index.css" media="all">
<link rel="stylesheet" href="/static/element/index_other.css" media="all">
<link rel="stylesheet" href="/static/supplier/css/reset.css" media="all">
<link rel="stylesheet" href="/static/admin/css/reset.css" media="all">
<script type="text/javascript" src="/static/vue/vue.global.prod.js"></script>
<script type="text/javascript" src="/static/element/index.full.js"></script>
<script type="text/javascript" src="/static/element/zh-cn.js"></script>
app/admin/view/common/guide.html
@@ -18,7 +18,7 @@
<div class="guide_right_item">
    <!-- 默认语言 -->
    <input type="hidden" id="languageType" value="{$_COOKIE.think_lang|default='zh-cn'}">
    <el-dropdown>
    <!-- <el-dropdown>
        <el-button type="default">
            {$_COOKIE.think_lang|getLanguage}
            <el-icon class="el-icon--right"><arrow-down /></el-icon>
@@ -29,8 +29,8 @@
                <el-dropdown-item @click="switchLanguage('en-us')">English</el-dropdown-item>
            </el-dropdown-menu>
        </template>
    </el-dropdown>
    &emsp;&emsp;
    </el-dropdown> -->
    <!-- &emsp;&emsp;
    <el-link href="https://element-plus.org" :underline="false">
        <el-icon size="20">
            <bell></bell>
@@ -42,9 +42,8 @@
            <message></message>
        </el-icon>
    </el-link>
    &emsp;&emsp;
    <el-link type="danger" href="{:url('/admin/login/logout')}" icon="SwitchButton" :underline="false"
        style="font-size: 18px;">
    &emsp;&emsp; -->
    <el-link type="danger" href="{:url('/admin/login/logout')}" icon="SwitchButton" :underline="false" style="font-size: 18px;">
        <span data-i18n="sign_out">退出</span>
    </el-link>
</div>
app/admin/view/common/left.html
@@ -1,66 +1,21 @@
<div class="layui-side layui-side-menu">
  <div class="layui-side-scroll">
    <div class="layui-logo" lay-href=""> <span><a href="{:url('/supplier/index/index')}"><img id="adminlogo" src="{$cinfo.logourl|default='/static/supplier/images/logo.png'}" style="height: 45px;" /></a></span> </div>
    <ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
      <volist name="menulist" id="menu">
        <li class="layui-nav-item"> <a href="javascript:;" class="nav-top-item" lay-tips="{$menu.info.parent}"> <i class="layui-icon {$menu.info.parentid|getlayuiicon}"></i> <cite>{$menu.info.parent}</cite> <span class="layui-nav-more"></span></a> <span class="layui-nav-bar"></span>
          <dl class="layui-nav-child">
            <volist name="menu.list" id="item">
                      <dd> <a href="{$item['url']}" id="{$item['id']}">{$item['title']}</a> </dd>
    <div class="layui-side-scroll">
        <div class="layui-logo" lay-href=""> <span><a href="{:url('/supplier/index/index')}"><img id="adminlogo" src="{$cinfo.logourl|default='/static/supplier/images/logo.png'}" style="height: 45px;" /></a></span> </div>
        <ul class="layui-nav layui-nav-tree" lay-shrink="all" id="LAY-system-side-menu" lay-filter="layadmin-system-side-menu">
            <volist name="menulist" id="menu">
                <li class="layui-nav-item"> <a href="javascript:;" class="nav-top-item" lay-tips="{$menu.info.parent}"> <i class="layui-icon {$menu.info.parentid|getlayuiicon}"></i> <cite>{$menu.info.parent}</cite> <span class="layui-nav-more"></span></a> <span class="layui-nav-bar"></span>
                    <dl class="layui-nav-child">
                        <volist name="menu.list" id="item">
                            <dd> <a href="{$item['url']}" id="{$item['id']}">{$item['title']}</a> </dd>
                        </volist>
                    </dl>
                </li>
            </volist>
          </dl>
        </li>
      </volist>
    </ul>
  </div>
        </ul>
    </div>
</div>
<div class="layui-layer layui-layer-tips" id="left-layui-layer" type="tips" showtime="-1" contype="object" style="z-index: 19891081; position: absolute; display:none;">
  <div id="" class="layui-layer-content"></div>
  <span class="layui-layer-setwin"></span></div>
<input type="hidden" id="t" value="{$menuitem}" />
<!-- <el-menu
        background-color="#545c64"
        class="el-menu-vertical-demo"
        :default-active="active"
        text-color="#fff"
        active-text-color="#fff"
      >
      <div class="left_logo_item">
        <el-image style="width: 55px; height: 55px" src="/static/supplier/images/logo.png"/>
    </div>
        <el-sub-menu index="1">
          <template #title>
            <span class="layui-nav-bar"></span>
            <el-icon><location /></el-icon>
            <span>Navigator One</span>
          </template>
            <el-menu-item index="supplier-index"><el-link href="/admin/supplier/index.html" :underline="false">item one</el-link></el-menu-item>
            <el-menu-item index="admin-index"><el-link href="/admin/admin/index.html" :underline="false">item two</el-link></el-menu-item>
            <el-menu-item index="1-3">item three</el-menu-item>
        </el-sub-menu>
        <el-sub-menu index="2">
          <template #title>
            <span class="layui-nav-bar"></span>
            <el-icon><location /></el-icon>
            <span>Navigator Two</span>
          </template>
            <el-menu-item index="2-1">item one</el-menu-item>
            <el-menu-item index="2-2">item two</el-menu-item>
        </el-sub-menu>
        <el-menu-item index="3">
          <el-icon><document /></el-icon>
          <span>Navigator Three</span>
        </el-menu-item>
        <el-menu-item index="4">
          <el-icon><setting /></el-icon>
          <span>Navigator Four</span>
        </el-menu-item>
      </el-menu>
<input type="hidden" id="t" value="supplier-index"> -->
    <div id="" class="layui-layer-content"></div>
    <span class="layui-layer-setwin"></span>
</div>
<input type="hidden" id="t" value="{$menuitem}" />
app/admin/view/common/title.html
@@ -1 +1,2 @@
<title>正和仓-总管理后台</title>
<link rel="shortcut icon" href="/favicon.ico">
<title>Cpark-总管理后台</title>
app/admin/view/index/index.html
@@ -22,56 +22,8 @@
                    <include file="common:guide" one_word="首页" two_word="控制台" />
                </el-header>
                <el-main>
                    <div class="flex justify_content_between">
                        <el-card style="width: 30%">
                            <template #header>
                                <div class="card-header">
                                    <span data-i18n="supplier_info_title">供应商信息</span>
                                </div>
                            </template>
                        </el-card>
                        <el-card style="width: 69%">
                            <template #header>
                                <div class="card-header">
                                    <span data-i18n="to_do_items">待办事项</span>
                                </div>
                            </template>
                        </el-card>
                    </div>
                    <br />
                    <el-card style="width: 100%">
                        <template #header>
                            <div class="card-header">
                                <span>数据汇总</span>
                            </div>
                        </template>
                    </el-card>
                    <br />
                    <el-card style="width: 100%">
                        <template #header>
                            <div class="card-header">
                                <span>通知公告</span>
                            </div>
                        </template>
                    </el-card>
                    <br />
                    <el-card style="width: 100%">
                        <template #header>
                            <div class="card-header">
                                <span>订单走势</span>
                            </div>
                        </template>
                    </el-card>
                    <br />
                    <el-card style="width: 100%">
                        <template #header>
                            <div class="card-header">
                                <span>销量排名</span>
                            </div>
                        </template>
                    </el-card>
                </el-main>
                <el-footer>Footer</el-footer>
                <el-footer></el-footer>
            </el-container>
        </el-container>
    </div>
app/admin/view/login/index.html
@@ -1,112 +1,112 @@
<!DOCTYPE HTML>
<html>
    <head>
        <title>账号登录</title>
        <link rel="shortcut icon" href="/favicon.ico">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <link rel="stylesheet" href="/static/supplier/login/login.css?x=1">
        <include file="common:element-plus">
    </head>
<head>
    <title>账号登录</title>
    <link rel="shortcut icon" href="/favicon.ico">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link rel="stylesheet" href="/static/admin/login/login.css?x=1">
    <include file="common:element-plus">
</head>
    <body>
        <div class="loginbg"></div>
        <input type="hidden" id="backurl" value="{$SERVER.HTTP_REFERER|default=''}">
        <div id="login_app" class="login-bg">
            <div class="login-register">
                <div class="register-form">
                    <div class="text-center font-size-20 mb30">
                        <div class="mt45">
                            <img src="/static/supplier/login/logo-m.png" style="height:100px;border-radius: 49%;" />
                        </div>
                        <p class="mt10">总管理后台登录</p>
<body>
    <div class="loginbg"></div>
    <input type="hidden" id="backurl" value="{$SERVER.HTTP_REFERER|default=''}">
    <div id="login_app" class="login-bg">
        <div class="login-register">
            <div class="register-form">
                <div class="text-center font-size-20 mb30">
                    <div class="mt45">
                        <img src="/static/admin/login/logo-m.png" style="width: 200px;" />
                    </div>
                    <br />
                    <el-form :model="form" label-width="auto" style="max-width: 600px"  @keydown.enter="login">
                        <el-form-item>
                            <el-input v-model="userdata.username" placeholder="请输入账号" size="large" prefix-icon="user"></el-input>
                        </el-form-item>
                        <el-form-item>
                            <el-input v-model="userdata.password" type="password" placeholder="请输入密码" size="large" prefix-icon="lock"></el-input>
                        </el-form-item>
                        <br />
                        <el-button type="primary" @click="login" size="large" class="btn_block">登录</el-button>
                    </el-form>
                    <p class="mt10">总管理后台登录</p>
                </div>
                <br />
                <el-form :model="form" label-width="auto" style="max-width: 600px" @keydown.enter="login">
                    <el-form-item>
                        <el-input v-model="userdata.username" placeholder="请输入账号" size="large" prefix-icon="user"></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-input v-model="userdata.password" type="password" placeholder="请输入密码" size="large" prefix-icon="lock"></el-input>
                    </el-form-item>
                    <br />
                    <el-button type="primary" @click="login" size="large" class="btn_block">登录</el-button>
                </el-form>
            </div>
        </div>
    </div>
        <script>
            var backurl = $('#backurl').val();
            const { ElMessage } = ElementPlus;
            const App = {
                data() {
                    return {
                        userdata: {
                            username: '',
                            password: '',
                            backurl: backurl,
                        },
                    };
                },
                mounted() { },
                created() { },
                methods: {
                    login() {
                        let that = this;
                        if (that.userdata.username == '') {
                            ElMessage({
                                message: "请输入账号",
                                type: 'error',
                                plain: true,
                                duration: 2000,
                            });
                            return;
                        }
                        if (that.userdata.password == '') {
                            ElMessage({
                                message: "请输入密码",
                                type: 'error',
                                plain: true,
                                duration: 2000,
                            });
                            return;
                        }
                        let url = "/admin/login/login.html"
                        postRequest(url, that.userdata).then(res => {
                            if (res.data.code == 200) {
                                that.$message({
                                    message: res.data.message,
                                    type: 'success',
                                    plain: true,
                                    duration: 500,
                                    onClose: function () {
                                        document.location = res.data.url;
                                    },
                                })
                                //
                            }
                            else {
                                that.$message({
                                    message: res.data.message,
                                    type: 'error',
                                    plain: true,
                                    duration: 3000,
                                })
                            }
                        });
    <script>
        var backurl = $('#backurl').val();
        const { ElMessage } = ElementPlus;
        const App = {
            data() {
                return {
                    userdata: {
                        username: '',
                        password: '',
                        backurl: backurl,
                    },
                }
            };
            const app = Vue.createApp(App);
            for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
                app.component(key, component)
                };
            },
            mounted() { },
            created() { },
            methods: {
                login() {
                    let that = this;
                    if (that.userdata.username == '') {
                        ElMessage({
                            message: "请输入账号",
                            type: 'error',
                            plain: true,
                            duration: 2000,
                        });
                        return;
                    }
                    if (that.userdata.password == '') {
                        ElMessage({
                            message: "请输入密码",
                            type: 'error',
                            plain: true,
                            duration: 2000,
                        });
                        return;
                    }
                    let url = "/admin/login/login.html"
                    postRequest(url, that.userdata).then(res => {
                        if (res.data.code == 200) {
                            that.$message({
                                message: res.data.message,
                                type: 'success',
                                plain: true,
                                duration: 500,
                                onClose: function () {
                                    document.location = res.data.url;
                                },
                            })
                            //
                        }
                        else {
                            that.$message({
                                message: res.data.message,
                                type: 'error',
                                plain: true,
                                duration: 3000,
                            })
                        }
                    });
                },
            }
            app.use(ElementPlus, {
                locale: ElementPlusLocaleZhCn,
            });
            app.mount("#login_app");
        </script>
    </body>
        };
        const app = Vue.createApp(App);
        for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
            app.component(key, component)
        }
        app.use(ElementPlus, {
            locale: ElementPlusLocaleZhCn,
        });
        app.mount("#login_app");
    </script>
</body>
</html>
app/home/view/index/index.html
@@ -213,7 +213,7 @@
                        <div class="single_image_area">
                            <div class="single_image single_line_option  ">
                                <!-- image -->
                                <img src="/static/home/assets/images/about-img.png" alt="image">
                                <img src="/static/home/images/img-1.png" alt="image">
                            </div>
                        </div>
                    </div>
@@ -589,7 +589,6 @@
                                                    <!-- <span></span> -->
                                                </div>
                                            </div> <!-- team sec -->
                                        </div>
                                    </div>
                                </div>
config/filesystem.php
@@ -13,9 +13,9 @@
            // 磁盘类型
            'type'       => 'local',
            // 磁盘路径
            'root'       => app()->getRootPath() . 'public/static',
            'root'       => app()->getRootPath() . 'public/static/upload',
            // 磁盘路径对应的外部URL路径
            'url'        => '/static',
            'url'        => '/static/upload',
            // 可见性
            'visibility' => 'public',
        ],
public/static/admin/css/reset.css
New file
@@ -0,0 +1,114 @@
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
font,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td {
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    font-weight: inherit;
    font-style: inherit;
    font-size: 100%;
    vertical-align: baseline;
    font-family: 'Microsoft YaHei';
}
a {
    text-decoration: none;
}
/* remember to define focus styles! */
:focus {
    outline: 0;
}
body {
    line-height: 1;
    background: white;
}
ol,
ul {
    list-style: none;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
    border-collapse: separate;
    border-spacing: 0;
}
caption,
th,
td {
    /* text-align: left; */
    font-weight: normal;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
    content: "";
}
blockquote,
q {
    quotes: """";
}
public/static/admin/js/blog/add.js
New file
@@ -0,0 +1,113 @@
const App = {
    mixins: [sharedMixin],/////共用的方法/////
    data() {
        return {
            addBlogForm: {
                title: '',
                en_title: '',
                content: '',
                en_content: '',
                desc: '',
                en_desc: '',
                cover_img: '',
            },
            submitDisabled: false,// 按钮禁用
        };
    },
    mounted() {
    },
    created() {
        window.setHtmlValue = this.setHtmlValue;
    },
    methods: {
        /////获取富文本内容/////
        setHtmlValue(value, type = 1) {
            if (type == 1) {
                this.addBlogForm.content = value;
            } else {
                this.addBlogForm.en_content = value;
            }
        },
        handleCoverImgSuccess(response, uploadFile) {
            if (response.code != 200) {
                this.$message({
                    message: response.message,
                    type: 'error',
                    duration: 1500,
                });
                return false;
            }
            this.addBlogForm.cover_img = response.data.url;
            // console.log(response,uploadFile);
            // this.addBlogForm.cover_img = arguments[0].url;
        },
        handleRemove(){},
        beforeCoverImgUpload(rawFile) {
            // console.log(rawFile);
            if (rawFile.type !== 'image/jpeg') {
                this.$message({
                    message: "图片格式错误",
                    type: 'error',
                    duration: 1500,
                    center: true
                });
                return false;
            } else if (rawFile.size / 1024 / 1024 > 10) {
                this.$message({
                    message: "图片大小过大",
                    type: 'error',
                    duration: 1500,
                    center: true
                });
                return false;
            }
            return true;
        },
        /////保存/////
        onSubmit() {
            var that = this;
            that.submitDisabled = true;
            const loading = this.$loading({
                lock: true,
                text: '提交中',
                spinner: 'el-icon-loading',
                background: 'rgba(0, 0, 0, 0.2)'
            });
            let url = "/admin/blog/save_blog.html";
            postRequest(url, that.addBlogForm).then(res => {
                loading.close();
                if (res.data.code == 200) {
                    that.$message({
                        message: res.data.message,
                        type: 'success',
                        duration: 1000,
                        center: true,
                        onClose: function () {
                            window.location.href = "/admin/blog/index.html";
                        }
                    });
                } else {
                    that.submitDisabled = false;
                    that.$message({
                        message: res.data.message,
                        type: 'error',
                        duration: 1500,
                        center: true
                    });
                }
            });
        },
    }
};
const app = Vue.createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
}
app.use(ElementPlus, {
    locale: ElementPlusLocaleZhCn,
});
app.mount("#vue_item");
public/static/admin/js/blog/index.js
New file
@@ -0,0 +1,66 @@
const App = {
    mixins: [sharedMixin],/////共用的方法/////
    data() {
        return {
            list: [],
        };
    },
    mounted() {
    },
    created() { },
    methods: {
        index() {
            let that = this;
            let url = "/admin/adminmenu/index.html"
            postRequest(url, {}).then(res => {
                if (res.data.code == 200) {
                    that.list = res.data.list;
                }
            });
        },
        /////保存菜单/////
        saveMenu() {
            var that = this;
            if (that.ifsubmit) {
                return false;
            }
            that.ifsubmit = true;
            let url = "/admin/adminmenu/saveMenu.html";
            postRequest(url, that.Add_form).then(res => {
                if (res.data.code == 200) {
                    that.$message({
                        message: res.data.message,
                        type: 'success',
                        duration: 1000,
                        center: true,
                        onClose: function () {
                            that.ifsubmit = false;
                            that.dialogVisible_menu = false;
                            that.index();
                        }
                    });
                }
                else {
                    that.ifsubmit = false;
                    that.$message({
                        message: res.data.message,
                        type: 'error',
                        duration: 1500,
                        center: true
                    });
                }
            });
        },
    }
};
const app = Vue.createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
}
app.use(ElementPlus, {
    locale: ElementPlusLocaleZhCn,
});
app.mount("#vue_item");
public/static/admin/login/fontawesome-webfont.eot
Binary files differ
public/static/admin/login/forget.css
New file
@@ -0,0 +1,308 @@
* {
    margin: 0;
    padding: 0;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
:focus {
    outline: 0 !important;
}
body {
    margin: 0;
    width: 100%;
    font-size: 14px;
    /*background:#F9F9F9;*/
    font-family: 'Microsoft YaHei', '微软雅黑';
    min-width: 960px;
}
ul li {
    list-style: none;
}
h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
    font-family: inherit;
    font-weight: 500;
    line-height: 1.1;
    color: inherit;
}
h1,
.h1,
h2,
.h2,
h3,
.h3 {
    margin-top: 20px;
    margin-bottom: 10px;
}
h4,
.h4,
h5,
.h5,
h6,
.h6 {
    margin-top: 10px;
    margin-bottom: 10px;
}
h1,
.h1 {
    font-size: 36px
}
h2,
.h2 {
    font-size: 28px
}
h3,
.h3 {
    font-size: 24px;
}
h4,
.h4 {
    font-size: 18px
}
h5,
.h5 {
    font-size: 14px
}
h6,
.h6 {
    font-size: 12px
}
a {
    color: #333333;
    text-decoration: none;
}
a:hover {
    color: #79c061;
    text-decoration: none;
}
.loginbg {
    position: fixed;
    top: 0px;
    bottom: 0px;
    left: 0px;
    right: 0px;
    background: url(/static/seller/login/login-bg.jpg) #f2f2f2 center top repeat;
}
.login-bg {
    margin-top: 100px;
    width: 100%;
    background: url(/static/seller/login/login-bg.jpg);
}
.login-register .register-form {
    margin: 0px auto;
    position: relative;
    padding: 20px 58px;
    margin-top: 0px;
    width: 506px;
    min-height: 576px;
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    overflow: hidden;
    border: 1px solid #ddd;
}
.font-size-20 {
    font-size: 20px;
}
.text-center {
    text-align: center;
}
p {
    margin: 0 0 10px;
}
.mt10 {
    margin-top: 10px;
}
.mt30 {
    margin-top: 30px;
}
.login-register .has-icon-before {
    position: relative;
}
.fl {
    float: left;
}
.fr {
    float: right;
}
.mt45 {
    margin-top: 45px;
}
.mb20 {
    margin-bottom: 20px;
    overflow: hidden;
}
.mb30 {
    margin-bottom: 30px;
    overflow: hidden;
}
.mb60 {
    margin-bottom: 60px;
    overflow: hidden;
}
.login-register .login-ico {
    display: inline-block;
    width: 48px;
    height: 46px;
    background-color: #f4f4f4;
    border-right: 1px solid #ddd;
}
.login-register .has-icon-before .form-icon-before {
    position: absolute;
    left: 1px;
    top: 1px;
    z-index: 1;
}
.login-register .login-ico:after {
    content: '';
    position: absolute;
    left: 17px;
    top: 17px;
    width: 14px;
    height: 14px;
    background: url(/static/seller/login/icon.png) -1px 0 no-repeat;
}
.login-register .login-ico.user:after {
    background-position: -1px -42px;
}
.pr {
    position: relative;
}
.font-size-12,
.fontsize12 {
    font-size: 12px;
}
.form-control {
    display: block;
    width: 100%;
    height: 34px;
    padding: 6px 12px;
    font-size: 14px;
    line-height: 1.42857143;
    color: #555;
    background-color: #fff;
    background-image: none;
    border: 1px solid #ccc;
    border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
    -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
    -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
    transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.form-control {
    -webkit-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    -moz-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    -o-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
}
.login-register .form-group .form-control {
    position: relative;
    height: 48px;
    line-height: 18px;
    box-shadow: none;
    background-color: #fff;
    border-radius: 4px;
    border-color: #ddd;
}
.login-register .has-icon-before .form-control {
    padding-left: 54px;
}
.login-register .login-ico.psd:after {
    background-position: -1px -84px;
}
.loginbtn {
    margin-bottom: 0;
    font-weight: 400;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -ms-touch-action: manipulation;
    touch-action: manipulation;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    background-image: none;
    border: 1px solid transparent;
    border-radius: 4px;
    display: block;
    width: 100%;
    color: #fff;
    background-color: #428ece;
    border-color: #428ece;
    font-size: 18px;
    line-height: 50px;
    border-radius: 6px;
}
.font-color-red {
    color: #aa0000;
}
.login-register .login-col {
    font-size: 14px;
    line-height: 32px;
}
.login-register .login-col img {
    height: 50px;
    width: 150px;
}
public/static/admin/login/form-bg.png
public/static/admin/login/icon.png
public/static/admin/login/login-bg.jpg
public/static/admin/login/login.css
New file
@@ -0,0 +1,574 @@
* {
    margin: 0;
    padding: 0;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
:focus {
    outline: 0 !important;
}
body {
    margin: 0;
    width: 100%;
    font-size: 14px;
    /*background:#F9F9F9;*/
    font-family: 'Microsoft YaHei', '微软雅黑';
    min-width: 960px;
}
ul li {
    list-style: none;
}
h1,
h2,
h3,
h4,
h5,
h6,
.h1,
.h2,
.h3,
.h4,
.h5,
.h6 {
    font-family: inherit;
    font-weight: 500;
    line-height: 1.1;
    color: inherit;
}
h1,
.h1,
h2,
.h2,
h3,
.h3 {
    margin-top: 20px;
    margin-bottom: 10px;
}
h4,
.h4,
h5,
.h5,
h6,
.h6 {
    margin-top: 10px;
    margin-bottom: 10px;
}
h1,
.h1 {
    font-size: 36px
}
h2,
.h2 {
    font-size: 28px
}
h3,
.h3 {
    font-size: 24px;
}
h4,
.h4 {
    font-size: 18px
}
h5,
.h5 {
    font-size: 14px
}
h6,
.h6 {
    font-size: 12px
}
a {
    color: #333333;
    text-decoration: none;
}
a:hover {
    color: #79c061;
    text-decoration: none;
}
.loginbg {
    position: fixed;
    top: 0px;
    bottom: 0px;
    left: 0px;
    right: 0px;
    background: url(/static/admin/login/login-bg.jpg) #f2f2f2 center top repeat;
}
.login-bg {
    padding-top: 100px;
    width: 100%;
}
.login-register .register-form {
    margin: 0px auto;
    position: relative;
    padding: 20px 58px;
    margin-top: 0px;
    width: 506px;
    height: 576px;
    background: url(/static/admin/login/form-bg.png) center top no-repeat;
}
.font-size-20 {
    font-size: 20px;
}
.text-center {
    text-align: center;
}
p {
    margin: 0 0 10px;
}
.mt10 {
    margin-top: 10px;
}
.mt30 {
    margin-top: 30px;
}
.login-register .has-icon-before {
    position: relative;
}
.mt45 {
    margin-top: 45px;
}
.mb20 {
    margin-bottom: 20px;
    overflow: hidden;
}
.mb30 {
    margin-bottom: 30px;
    overflow: hidden;
}
.mb60 {
    margin-bottom: 60px;
    overflow: hidden;
}
.login-register .login-ico {
    display: inline-block;
    width: 48px;
    height: 46px;
    background-color: #f4f4f4;
    border-right: 1px solid #ddd;
}
.login-register .has-icon-before .form-icon-before {
    position: absolute;
    left: 1px;
    top: 1px;
    z-index: 1;
}
.login-register .login-ico:after {
    content: '';
    position: absolute;
    left: 17px;
    top: 17px;
    width: 14px;
    height: 14px;
    background: url(/static/supplier/login/icon.png) -1px 0 no-repeat;
}
.login-register .login-ico.user:after {
    background-position: -1px -42px;
}
.pr {
    position: relative;
}
.font-size-12,
.fontsize12 {
    font-size: 12px;
}
.form-control {
    display: block;
    width: 100%;
    height: 34px;
    padding: 6px 12px;
    font-size: 14px;
    line-height: 1.42857143;
    color: #555;
    background-color: #fff;
    background-image: none;
    border: 1px solid #ccc;
    border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
    -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
    -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
    transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.form-control {
    -webkit-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    -moz-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    -o-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
}
.login-register .form-group .form-control {
    position: relative;
    height: 48px;
    line-height: 18px;
    box-shadow: none;
    background-color: #fff;
    border-radius: 4px;
    border-color: #ddd;
}
.login-register .has-icon-before .form-control {
    padding-left: 54px;
}
.login-register .login-ico.psd:after {
    background-position: -1px -84px;
}
.loginbtn {
    margin-bottom: 0;
    font-weight: 400;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -ms-touch-action: manipulation;
    touch-action: manipulation;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    background-image: none;
    border: 1px solid transparent;
    border-radius: 4px;
    display: block;
    width: 100%;
    color: #fff;
    background-color: #428ece;
    border-color: #428ece;
    font-size: 18px;
    line-height: 50px;
    border-radius: 6px;
}
.fl {
    float: left;
}
.fr {
    float: right;
}
public/static/admin/login/logo-m.png
public/static/admin/login/register.css
New file
@@ -0,0 +1,209 @@
* {
    margin: 0;
    padding: 0;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
:focus {
    outline: 0 !important;
}
body {
    margin: 0;
    width: 100%;
    font-size: 14px;
    /*background:#F9F9F9;*/
    font-family: 'Microsoft YaHei', '微软雅黑';
    min-width: 960px;
}
ul li {
    list-style: none;
}
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: inherit;
    font-weight: 500;
    line-height: 1.1;
    color: inherit;
}
h1, .h1, h2, .h2, h3, .h3 {
    margin-top: 20px;
    margin-bottom: 10px;
}
h4, .h4, h5, .h5, h6, .h6 {
    margin-top: 10px;
    margin-bottom: 10px;
}
h1, .h1 {
    font-size: 36px
}
h2, .h2 {
    font-size: 28px
}
h3, .h3 {
    font-size: 24px;
}
h4, .h4 {
    font-size: 18px
}
h5, .h5 {
    font-size: 14px
}
h6, .h6 {
    font-size: 12px
}
a {
    color: #333333;
    text-decoration: none;
}
a:hover {
    color: #79c061;
    text-decoration: none;
}
.loginbg{position: fixed; top:0px;bottom: 0px; left: 0px; right: 0px;background: url(/static/supplier/login/login-bg.jpg) #f2f2f2 center top repeat;}
.login-bg {padding-top:30px;width: 100%;}
.login-register .register-form {
   margin:0px auto;
    position:relative;
    padding: 20px 58px;
    margin-top:0px;
    width: 800px;
    background: #fff;
    border-radius: 10px;
}
.font-size-20 {
    font-size: 20px;
}
.text-center {
    text-align: center;
}
p {
    margin: 0 0 10px;
}
.mt10 {
    margin-top: 10px;
}
.mt30 {
    margin-top: 30px;
}
.login-register .has-icon-before {
    position: relative;
}
.mt45 {
    margin-top: 45px;
}
.mb20 {
    margin-bottom: 20px;overflow:hidden;
}
.mb30 {
    margin-bottom: 30px;overflow:hidden;
}
.mb60 {
    margin-bottom: 60px;overflow:hidden;
}
.login-register .login-ico {
    display: inline-block;
    width: 48px;
    height: 46px;
    background-color: #f4f4f4;
    border-right: 1px solid #ddd;
}
.login-register .has-icon-before .form-icon-before {
    position: absolute;
    left: 1px;
    top: 1px;
    z-index: 1;
}
.login-register .login-ico:after {
    content: '';
    position: absolute;
    left: 17px;
    top: 17px;
    width: 14px;
    height: 14px;
    background: url(/static/supplier/login/icon.png) -1px 0 no-repeat;
}
.login-register .login-ico.user:after {
    background-position: -1px -42px;
}
.pr {
    position: relative;
}
.font-size-12, .fontsize12 {
    font-size: 12px;
}
.form-control {
    display: block;
    width: 100%;
    height: 34px;
    padding: 6px 12px;
    font-size: 14px;
    line-height: 1.42857143;
    color: #555;
    background-color: #fff;
    background-image: none;
    border: 1px solid #ccc;
    border-radius: 4px;
    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
    box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
    -webkit-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
    -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
    transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
}
.form-control {
    -webkit-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    -moz-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    -o-box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
    box-shadow: inset 0 1px 1px rgba(248, 248, 248, 0.075);
}
.login-register .form-group .form-control {
    position: relative;
    height: 48px;
    line-height: 18px;
    box-shadow: none;
    background-color: #fff;
    border-radius: 4px;
    border-color: #ddd;
}
.login-register .has-icon-before .form-control {
    padding-left: 54px;
}
.login-register .login-ico.psd:after {
    background-position: -1px -84px;
}
.loginbtn{
    margin-bottom: 0;
    font-weight: 400;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -ms-touch-action: manipulation;
    touch-action: manipulation;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    background-image: none;
    border: 1px solid transparent;
    border-radius: 4px;
    display: block;
    width: 100%;
    color: #fff;
    background-color: #428ece ;
    border-color: #428ece ;
    font-size: 18px;
    line-height: 50px;
    border-radius: 6px;
    }
public/static/element/index_other.css
@@ -77,8 +77,14 @@
    color: #fff;
}
.el-sub-menu__title .parentmenu{font-weight: bolder; color: #fff;}
.el-menu-item .submenu{margin-left: 10px !important;}
.el-sub-menu__title .parentmenu {
    font-weight: bolder;
    color: #fff;
}
.el-menu-item .submenu {
    margin-left: 10px !important;
}
.left_logo_item {
    text-align: center;
@@ -170,4 +176,20 @@
.el-main {
    overflow: unset;
}
.btn-width-100 {
    width: 100px;
}
.btn-min-width-100 {
    min-width: 100px;
}
.btn-width-120 {
    width: 120px;
}
.btn-min-width-120 {
    min-width: 120px;
}
public/static/home/css/index/index.css
@@ -5,4 +5,13 @@
a {
    text-decoration: none;
}
.post_team_p11 {
    padding: 15px 0;
    height: 100px;
    /* line-height: 100px; */
    display: flex;
    justify-content: center;
    align-items: center;
}
public/static/home/images/collaborators-1.png

public/static/home/images/collaborators-2.png

public/static/home/images/collaborators-3.png

public/static/home/images/img-1.png

public/static/home/images/img-2.png
Binary files differ
public/static/home/images/img-3.png

public/static/images/logo-no-bg.png
Binary files differ
public/static/images/logo.jpg
Binary files differ
public/static/images/logo.png

public/static/plugin/wangeditor/index.js
New file
Diff too large
public/static/plugin/wangeditor/style.css
New file
@@ -0,0 +1,27 @@
:root,
:host {
  --w-e-textarea-bg-color: #fff;
  --w-e-textarea-color: #333;
  --w-e-textarea-border-color: #ccc;
  --w-e-textarea-slight-border-color: #e8e8e8;
  --w-e-textarea-slight-color: #d4d4d4;
  --w-e-textarea-slight-bg-color: #f5f2f0;
  --w-e-textarea-selected-border-color: #B4D5FF;
  --w-e-textarea-handler-bg-color: #4290f7;
  --w-e-toolbar-color: #595959;
  --w-e-toolbar-bg-color: #fff;
  --w-e-toolbar-active-color: #333;
  --w-e-toolbar-active-bg-color: #f1f1f1;
  --w-e-toolbar-disabled-color: #999;
  --w-e-toolbar-border-color: #e8e8e8;
  --w-e-modal-button-bg-color: #fafafa;
  --w-e-modal-button-border-color: #d9d9d9;
}
.w-e-text-container *,.w-e-toolbar *{box-sizing:border-box;margin:0;outline:none;padding:0}.w-e-text-container blockquote,.w-e-text-container li,.w-e-text-container p,.w-e-text-container td,.w-e-text-container th,.w-e-toolbar *{line-height:1.5}.w-e-text-container{background-color:var(--w-e-textarea-bg-color);color:var(--w-e-textarea-color);height:100%;position:relative}.w-e-text-container .w-e-scroll{-webkit-overflow-scrolling:touch;height:100%}.w-e-text-container [data-slate-editor]{word-wrap:break-word;border-top:1px solid transparent;min-height:100%;outline:0;padding:0 10px;white-space:pre-wrap}.w-e-text-container [data-slate-editor] p{margin:15px 0}.w-e-text-container [data-slate-editor] h1,.w-e-text-container [data-slate-editor] h2,.w-e-text-container [data-slate-editor] h3,.w-e-text-container [data-slate-editor] h4,.w-e-text-container [data-slate-editor] h5{margin:20px 0}.w-e-text-container [data-slate-editor] img{cursor:default;display:inline!important;max-width:100%;min-height:20px;min-width:20px}.w-e-text-container [data-slate-editor] span{text-indent:0}.w-e-text-container [data-slate-editor] [data-selected=true]{box-shadow:0 0 0 2px var(--w-e-textarea-selected-border-color)}.w-e-text-placeholder{font-style:italic;left:10px;top:17px;width:90%}.w-e-max-length-info,.w-e-text-placeholder{color:var(--w-e-textarea-slight-color);pointer-events:none;position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none}.w-e-max-length-info{bottom:.5em;right:1em}.w-e-bar{background-color:var(--w-e-toolbar-bg-color);color:var(--w-e-toolbar-color);font-size:14px;padding:0 5px}.w-e-bar svg{fill:var(--w-e-toolbar-color);height:14px;width:14px}.w-e-bar-show{display:flex}.w-e-bar-hidden{display:none}.w-e-hover-bar{border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 5px #0000001f;position:absolute}.w-e-toolbar{flex-wrap:wrap;position:relative}.w-e-bar-divider{background-color:var(--w-e-toolbar-border-color);display:inline-flex;height:40px;margin:0 5px;width:1px}.w-e-bar-item{display:flex;height:40px;padding:4px;position:relative;text-align:center}.w-e-bar-item,.w-e-bar-item button{align-items:center;justify-content:center}.w-e-bar-item button{background:transparent;border:none;color:var(--w-e-toolbar-color);cursor:pointer;display:inline-flex;height:32px;overflow:hidden;padding:0 8px;white-space:nowrap}.w-e-bar-item button:hover{background-color:var(--w-e-toolbar-active-bg-color);color:var(--w-e-toolbar-active-color)}.w-e-bar-item button .title{margin-left:5px}.w-e-bar-item .active{background-color:var(--w-e-toolbar-active-bg-color);color:var(--w-e-toolbar-active-color)}.w-e-bar-item .disabled{color:var(--w-e-toolbar-disabled-color);cursor:not-allowed}.w-e-bar-item .disabled svg{fill:var(--w-e-toolbar-disabled-color)}.w-e-bar-item .disabled:hover{background-color:var(--w-e-toolbar-bg-color);color:var(--w-e-toolbar-disabled-color)}.w-e-bar-item .disabled:hover svg{fill:var(--w-e-toolbar-disabled-color)}.w-e-menu-tooltip-v5:before{background-color:var(--w-e-toolbar-active-color);border-radius:5px;color:var(--w-e-toolbar-bg-color);content:attr(data-tooltip);font-size:.75em;opacity:0;padding:5px 10px;position:absolute;text-align:center;top:40px;transition:opacity .6s;visibility:hidden;white-space:pre;z-index:1}.w-e-menu-tooltip-v5:after{border:5px solid transparent;border-bottom:5px solid var(--w-e-toolbar-active-color);content:"";opacity:0;position:absolute;top:30px;transition:opacity .6s;visibility:hidden}.w-e-menu-tooltip-v5:hover:after,.w-e-menu-tooltip-v5:hover:before{opacity:1;visibility:visible}.w-e-menu-tooltip-v5.tooltip-right:before{left:100%;top:10px}.w-e-menu-tooltip-v5.tooltip-right:after{border-bottom-color:transparent;border-left-color:transparent;border-right-color:var(--w-e-toolbar-active-color);border-top-color:transparent;left:100%;margin-left:-10px;top:16px}.w-e-bar-item-group .w-e-bar-item-menus-container{background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 10px #0000001f;display:none;left:0;margin-top:40px;position:absolute;top:0;z-index:1}.w-e-bar-item-group:hover .w-e-bar-item-menus-container{display:block}.w-e-select-list{background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 10px #0000001f;left:0;margin-top:40px;max-height:350px;min-width:100px;overflow-y:auto;position:absolute;top:0;z-index:1}.w-e-select-list ul{line-height:1;list-style:none}.w-e-select-list ul .selected{background-color:var(--w-e-toolbar-active-bg-color)}.w-e-select-list ul li{cursor:pointer;padding:7px 0 7px 25px;position:relative;text-align:left;white-space:nowrap}.w-e-select-list ul li:hover{background-color:var(--w-e-toolbar-active-bg-color)}.w-e-select-list ul li svg{left:0;margin-left:5px;margin-top:-7px;position:absolute;top:50%}.w-e-bar-bottom .w-e-select-list{bottom:0;margin-bottom:40px;margin-top:0;top:inherit}.w-e-drop-panel{background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 10px #0000001f;margin-top:40px;min-width:200px;padding:10px;position:absolute;top:0;z-index:1}.w-e-bar-bottom .w-e-drop-panel{bottom:0;margin-bottom:40px;margin-top:0;top:inherit}.w-e-modal{background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 10px #0000001f;color:var(--w-e-toolbar-color);font-size:14px;min-height:40px;min-width:100px;padding:20px 15px 0;position:absolute;text-align:left;z-index:1}.w-e-modal .btn-close{cursor:pointer;line-height:1;padding:5px;position:absolute;right:8px;top:7px}.w-e-modal .btn-close svg{fill:var(--w-e-toolbar-color);height:10px;width:10px}.w-e-modal .babel-container{display:block;margin-bottom:15px}.w-e-modal .babel-container span{display:block;margin-bottom:10px}.w-e-modal .button-container{margin-bottom:15px}.w-e-modal button{background-color:var(--w-e-modal-button-bg-color);border:1px solid var(--w-e-modal-button-border-color);border-radius:4px;color:var(--w-e-toolbar-color);cursor:pointer;font-weight:400;height:32px;padding:4.5px 15px;text-align:center;touch-action:manipulation;transition:all .3s cubic-bezier(.645,.045,.355,1);-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.w-e-modal input[type=number],.w-e-modal input[type=text],.w-e-modal textarea{font-feature-settings:"tnum";background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-modal-button-border-color);border-radius:4px;color:var(--w-e-toolbar-color);font-variant:tabular-nums;padding:4.5px 11px;transition:all .3s;width:100%}.w-e-modal textarea{min-height:60px}body .w-e-modal,body .w-e-modal *{box-sizing:border-box}.w-e-progress-bar{background-color:var(--w-e-textarea-handler-bg-color);height:1px;position:absolute;transition:width .3s;width:0}.w-e-full-screen-container{bottom:0!important;display:flex!important;flex-direction:column!important;height:100%!important;left:0!important;margin:0!important;padding:0!important;position:fixed;right:0!important;top:0!important;width:100%!important}.w-e-full-screen-container [data-w-e-textarea=true]{flex:1!important}
.w-e-text-container [data-slate-editor] code{background-color:var(--w-e-textarea-slight-bg-color);border-radius:3px;font-family:monospace;padding:3px}.w-e-panel-content-color{list-style:none;text-align:left;width:230px}.w-e-panel-content-color li{border:1px solid var(--w-e-toolbar-bg-color);border-radius:3px 3px;cursor:pointer;display:inline-block;padding:2px}.w-e-panel-content-color li:hover{border-color:var(--w-e-toolbar-color)}.w-e-panel-content-color li .color-block{border:1px solid var(--w-e-toolbar-border-color);border-radius:3px 3px;height:17px;width:17px}.w-e-panel-content-color .active{border-color:var(--w-e-toolbar-color)}.w-e-panel-content-color .clear{line-height:1.5;margin-bottom:5px;width:100%}.w-e-panel-content-color .clear svg{height:16px;margin-bottom:-4px;width:16px}.w-e-text-container [data-slate-editor] blockquote{background-color:var(--w-e-textarea-slight-bg-color);border-left:8px solid var(--w-e-textarea-selected-border-color);display:block;font-size:100%;line-height:1.5;margin:10px 0;padding:10px}.w-e-panel-content-emotion{font-size:20px;list-style:none;text-align:left;width:300px}.w-e-panel-content-emotion li{border-radius:3px 3px;cursor:pointer;display:inline-block;padding:0 5px}.w-e-panel-content-emotion li:hover{background-color:var(--w-e-textarea-slight-bg-color)}.w-e-textarea-divider{border-radius:3px;margin:20px auto;padding:20px}.w-e-textarea-divider hr{background-color:var(--w-e-textarea-border-color);border:0;display:block;height:1px}.w-e-text-container [data-slate-editor] pre>code{background-color:var(--w-e-textarea-slight-bg-color);border:1px solid var(--w-e-textarea-slight-border-color);border-radius:4px 4px;display:block;font-size:14px;padding:10px;text-indent:0}.w-e-text-container [data-slate-editor] .w-e-image-container{display:inline-block;margin:0 3px}.w-e-text-container [data-slate-editor] .w-e-image-container:hover{box-shadow:0 0 0 2px var(--w-e-textarea-selected-border-color)}.w-e-text-container [data-slate-editor] .w-e-selected-image-container{overflow:hidden;position:relative}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .w-e-image-dragger{background-color:var(--w-e-textarea-handler-bg-color);height:7px;position:absolute;width:7px}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .left-top{cursor:nwse-resize;left:0;top:0}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .right-top{cursor:nesw-resize;right:0;top:0}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .left-bottom{bottom:0;cursor:nesw-resize;left:0}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .right-bottom{bottom:0;cursor:nwse-resize;right:0}.w-e-text-container [data-slate-editor] .w-e-selected-image-container:hover{box-shadow:none}.w-e-text-container [contenteditable=false] .w-e-image-container:hover{box-shadow:none}
.w-e-text-container [data-slate-editor] .table-container{border:1px dashed var(--w-e-textarea-border-color);border-radius:5px;margin-top:10px;overflow-x:auto;padding:10px;width:100%}.w-e-text-container [data-slate-editor] table{border-collapse:collapse}.w-e-text-container [data-slate-editor] table td,.w-e-text-container [data-slate-editor] table th{border:1px solid var(--w-e-textarea-border-color);line-height:1.5;min-width:30px;padding:3px 5px;text-align:left}.w-e-text-container [data-slate-editor] table th{background-color:var(--w-e-textarea-slight-bg-color);font-weight:700;text-align:center}.w-e-panel-content-table{background-color:var(--w-e-toolbar-bg-color)}.w-e-panel-content-table table{border-collapse:collapse}.w-e-panel-content-table td{border:1px solid var(--w-e-toolbar-border-color);cursor:pointer;height:15px;padding:3px 5px;width:20px}.w-e-panel-content-table td.active{background-color:var(--w-e-toolbar-active-bg-color)}
.w-e-textarea-video-container{background-image:linear-gradient(45deg,#eee 25%,transparent 0,transparent 75%,#eee 0,#eee),linear-gradient(45deg,#eee 25%,#fff 0,#fff 75%,#eee 0,#eee);background-position:0 0,10px 10px;background-size:20px 20px;border:1px dashed var(--w-e-textarea-border-color);border-radius:5px;margin:10px auto 0;padding:10px 0;text-align:center}
.w-e-text-container [data-slate-editor] pre>code{word-wrap:normal;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;-webkit-hyphens:none;hyphens:none;line-height:1.5;margin:.5em 0;overflow:auto;padding:1em;-moz-tab-size:4;-o-tab-size:4;tab-size:4;text-align:left;text-shadow:0 1px #fff;white-space:pre;word-break:normal;word-spacing:normal}.w-e-text-container [data-slate-editor] pre>code .token.cdata,.w-e-text-container [data-slate-editor] pre>code .token.comment,.w-e-text-container [data-slate-editor] pre>code .token.doctype,.w-e-text-container [data-slate-editor] pre>code .token.prolog{color:#708090}.w-e-text-container [data-slate-editor] pre>code .token.punctuation{color:#999}.w-e-text-container [data-slate-editor] pre>code .token.namespace{opacity:.7}.w-e-text-container [data-slate-editor] pre>code .token.boolean,.w-e-text-container [data-slate-editor] pre>code .token.constant,.w-e-text-container [data-slate-editor] pre>code .token.deleted,.w-e-text-container [data-slate-editor] pre>code .token.number,.w-e-text-container [data-slate-editor] pre>code .token.property,.w-e-text-container [data-slate-editor] pre>code .token.symbol,.w-e-text-container [data-slate-editor] pre>code .token.tag{color:#905}.w-e-text-container [data-slate-editor] pre>code .token.attr-name,.w-e-text-container [data-slate-editor] pre>code .token.builtin,.w-e-text-container [data-slate-editor] pre>code .token.char,.w-e-text-container [data-slate-editor] pre>code .token.inserted,.w-e-text-container [data-slate-editor] pre>code .token.selector,.w-e-text-container [data-slate-editor] pre>code .token.string{color:#690}.w-e-text-container [data-slate-editor] pre>code .language-css .token.string,.w-e-text-container [data-slate-editor] pre>code .style .token.string,.w-e-text-container [data-slate-editor] pre>code .token.entity,.w-e-text-container [data-slate-editor] pre>code .token.operator,.w-e-text-container [data-slate-editor] pre>code .token.url{color:#9a6e3a}.w-e-text-container [data-slate-editor] pre>code .token.atrule,.w-e-text-container [data-slate-editor] pre>code .token.attr-value,.w-e-text-container [data-slate-editor] pre>code .token.keyword{color:#07a}.w-e-text-container [data-slate-editor] pre>code .token.class-name,.w-e-text-container [data-slate-editor] pre>code .token.function{color:#dd4a68}.w-e-text-container [data-slate-editor] pre>code .token.important,.w-e-text-container [data-slate-editor] pre>code .token.regex,.w-e-text-container [data-slate-editor] pre>code .token.variable{color:#e90}.w-e-text-container [data-slate-editor] pre>code .token.bold,.w-e-text-container [data-slate-editor] pre>code .token.important{font-weight:700}.w-e-text-container [data-slate-editor] pre>code .token.italic{font-style:italic}.w-e-text-container [data-slate-editor] pre>code .token.entity{cursor:help}