rabin 19 小时之前
父节点
当前提交
1761905822

+ 144 - 0
app/Api/Admin.php

@@ -0,0 +1,144 @@
+<?php namespace Manage\Api;
+use Dever;
+use Manage\Lib\Auth;
+use Manage\Lib\Util;
+class Admin extends Auth
+{
+    public function info()
+    {
+        $this->user['module']['show'] = true;
+        $this->user['module']['id'] = (int) $this->user['select']['module_id'];
+        $this->user['module']['name'] = '当前模块';
+        $this->user['module']['list'] = $this->module();
+        $this->user['module']['login'] = 'login';
+        $this->user['module']['uri'] = ['system' => $this->system['key'], 'number' => $this->system_info['number']];
+        return $this->user;
+    }
+
+    # 获取当前的模块列表
+    public function module()
+    {
+        $where = [];
+        if ($this->user['auth']['module']) {
+            $where['id'] = ['in', $this->user['auth']['module']];
+        } else {
+            $where['system'] = $this->system['key'];
+        }
+        $result = [];
+        $module = Dever::db('manage/system_module')->select($where);
+        $i = 0;
+        foreach ($module as $k => $v) {
+            $data_where = $v['data_where'];
+            if ($data_where) {
+                if (strstr($data_where, '{uid}')) {
+                    $data_where = str_replace('{uid}', $this->user['id'], $data_where);
+                }
+                $data_where = Dever::json_decode($data_where);
+            } else {
+                $data_where = [];
+            }
+            $child = Dever::db($v['data_table'])->select($data_where);
+            
+            if ($child) {
+                $data = [];
+                foreach ($child as $k1 => $v1) {
+                    $v1['select'] = false;
+                    if ($v['id'] == $this->user['select']['module_id'] && $v1['id'] == $this->user['select']['data_id']) {
+                        $this->user['module']['name'] = $v1['name'];
+                        $v1['select'] = true;
+                    }
+                    $key = $v['id'] . '-' . $v1['id'];
+                    if ($this->user['module_data']) {
+                        if (strstr($this->user['module_data'], $key)) {
+                            $data[] = $v1;
+                        }
+                    } else {
+                        $data[] = $v1;
+                    }
+                }
+                if ($data) {
+                    $result[$i] = $v;
+                    $result[$i]['child'] = $data;
+                    $i++;
+                }
+            }
+        }
+        if ($i <= 1) {
+            $this->user['module']['show'] = false;
+        }
+        return $result;
+    }
+
+    # 根据角色获取模块下的数据
+    public function getModuleData($value = false)
+    {
+        if (!$value) {
+            $result['module_data']['option'] = [];
+            return $result;
+        }
+        $result = [];
+        $role = Dever::db($this->system['role_table'])->select(array('id' => ['in', $value]));
+        if ($role) {
+            $info = $module = [];
+            foreach ($role as $k => $v) {
+                if ($v['module']) {
+                    $child = Dever::db('manage/system_module')->select(array('id' => ['in', $v['module']]));
+                    if ($child) {
+                        foreach ($child as $k1 => $v1) {
+                            if (isset($info[$v1['id']])) {
+                                continue;
+                            }
+                            $info[$v1['id']] = true;
+                            $v1['value'] = 's-' . $v1['id'];
+                            $v1['label'] = $v1['name'];
+                            $v1['children'] = [];
+                            $data = Dever::db($v1['data_table'])->select([], array('col' => 'concat('.$v1['id'].', "-", id) as value, name as label'));
+                            if ($data) {
+                                $v1['children'] = array_merge($v1['children'], $data);
+                            }
+                            $module[] = $v1;
+                        }
+                    }
+                }
+            }
+            $result['module_data']['option'] = $module;
+        }
+        
+        return $result;
+    }
+
+    # 切换模块
+    public function setModule()
+    {
+        $module_id = Dever::input('module_id');
+        $this->checkModule($this->user['select']['module_id']);
+        $data_id = Dever::input('data_id');
+        if ($this->user['module_data'] && !strstr($this->user['module_data'], $module_id . '-' . $data_id)) {
+            Dever::error('无模块权限');
+        }
+        $result = Dever::load(Util::class)->token($this->user['id'], $this->user['mobile'], $this->user['select']['partition'], $this->user['select']['system_key'], $this->user['select']['system_id'], $this->user['select']['info_id'], $module_id, $data_id);
+        return $result;
+    }
+
+    # 修改资料
+    public function setInfo()
+    {
+        $username = Dever::input('username');
+        $password = Dever::input('password');
+        $data = [];
+        if ($username) {
+            $data['name'] = $username;
+        }
+        if ($password) {
+            $data += Dever::load(Util::class)->createPwd($password);
+        }
+        $state = false;
+        if ($data) {
+            $state = Dever::db($this->system['user_table'])->update($this->uid, $data);
+        }
+        if (!$state) {
+            Dever::error('修改失败');
+        }
+        return 'yes';
+    }
+}

+ 167 - 0
app/Api/Console.php

@@ -0,0 +1,167 @@
+<?php namespace Manage\Api;
+use Dever;
+use Manage\Lib\Auth;
+class Console extends Auth
+{
+    # 控制台首页
+    public function index()
+    {
+        $config = Dever::config('manage');
+        $data['layout'] = [
+            [
+                'tip' => 24,
+            ],
+        ];
+        $data['tip'] = [
+            'type' => 'tip',
+            'name' => $this->getMsg($this->user['name']),
+            'content' => '您正在使用{title},请通过左侧导航栏选择需要操作的模块。祝你工作愉快!',
+        ];
+        if (isset($config['console']) && $config['console']) {
+            $data = Dever::call($config['console'], [$data]);
+        }
+        return $data;
+    }
+
+    # 问候语
+    private function getMsg($username, $lang = 'zh')
+    {
+        $hour = date('H');
+        if ($hour < 8) {
+            $period = 'morning_early';
+        } elseif ($hour <= 11) {
+            $period = 'morning';
+        } elseif ($hour <= 13) {
+            $period = 'noon';
+        } elseif ($hour < 18) {
+            $period = 'afternoon';
+        } else {
+            $period = 'evening';
+        }
+
+        $greetings = [
+            'zh' => [
+                'morning_early' => [
+                    "新的一天开始啦,{username},愿你充满能量与好心情 🌅",
+                    "早上好,{username}!今天也要元气满满地出发 ☀️",
+                    "又是充满希望的一天,{username},愿你元气满满 ✨",
+                    "清晨的阳光最温柔,祝你一天好心情,{username} 🌞",
+                    "清晨的努力,是成功的开始,加油,{username}!",
+                    "起这么早,是被梦想叫醒的,还是被闹钟吓醒的?⏰,{username}",
+                    "早安,{username},太阳都羡慕你勤劳 🌞",
+                    "日出东方,一切皆静,{username} 🌄",
+                    "时间不语,却回答一切,{username} 🧘",
+                    "越努力,越幸运,新的一天,加油,{username} 💪",
+                    "今天做的每一件小事,都是未来的伏笔,{username} 📝",
+                    "美好的一天从早晨开始,{username},加油!",
+                    "黎明的第一缕光,送给勤奋的你,{username}。",
+                ],
+                'morning' => [
+                    "上午好,{username}!看到你上线真开心 😄",
+                    "今天也要高效完成每一项任务,加油,{username} 💪",
+                    "专注的你,最有魅力,{username} 🧠",
+                    "把事情做到最好,是你的风格,{username} 🔧",
+                    "保持节奏,每一天都值得记录,{username} 📅",
+                    "上午好,{username}!今天也要继续摸鱼计划 🐟",
+                    "再摸一会鱼,就到中午了,加油,{username} ✊",
+                    "你走你的路,花自开,{username} 🌸",
+                    "心静则清,行稳则远,{username} 🌿",
+                    "你正在书写属于你自己的不凡人生,{username} 📖",
+                    "相信自己,你比想象中更强大,{username} ✨",
+                    "每个上午都是新的开始,{username},抓住机会!",
+                    "专注且坚定,{username},你值得赞扬!",
+                ],
+                'noon' => [
+                    "中午好,{username}!记得按时吃饭补充能量 🍱",
+                    "工作再忙,也别忘了照顾自己,{username} ❤️",
+                    "好好吃饭,下午才有力气继续冲,{username} 💼",
+                    "中场休息,补充体力,{username} 🌯",
+                    "饭不吃饱,哪有力气摸鱼,{username} 🐠",
+                    "中午不休息,下午徒伤悲,{username} 😵",
+                    "饭要好好吃,觉要好好睡,{username} 🌿",
+                    "坐看云起时,不争一时高下,{username} ☁️",
+                    "每一次坚持,都是积累能量,{username} 🔋",
+                    "中午短暂放松,是为了更好出发,{username} 🚀",
+                    "阳光正好,{username},午饭别忘了吃饱哦!",
+                    "充能中,{username},下午继续加油!",
+                ],
+                'afternoon' => [
+                    "下午好,{username}!来杯咖啡提提神 ☕",
+                    "再坚持一会儿,胜利就在眼前,{username} 🏁",
+                    "保持专注,继续向前,{username} 💼",
+                    "喝口水,伸个懒腰,继续冲,{username} 💨",
+                    "摸鱼也需要节奏,别太张扬,{username} 😏",
+                    "困了就看老板照片提神,{username} 🧃",
+                    "一花一世界,一念一清净,{username} 🪷",
+                    "茶要慢饮,事要缓做,{username} 🍵",
+                    "你所付出的努力,终将照亮前路,{username} 💡",
+                    "不怕慢,只怕站,坚持走就对了,{username} 🛤️",
+                    "努力的下午,{username},胜利不远了!",
+                    "冲刺时间到,{username},继续燃烧吧!",
+                ],
+                'evening' => [
+                    "晚上好,{username}!愿你天黑有灯,下雨有伞 🌙",
+                    "今天也辛苦啦,好好休息,{username} 🛏️",
+                    "收工啦,放松一下,明天继续努力,{username} ✨",
+                    "一天结束了,给自己点个赞,{username} 👍",
+                    "打卡下班是对生活最基本的尊重,{username} 📤",
+                    "今天摸鱼圆满成功,记得下次继续,{username} 🐳",
+                    "夜深人静时,心要平,{username} 💭",
+                    "万事随心,内心清明,{username} ✨",
+                    "收获不在今天,也会在明天到来,{username} 🌟",
+                    "夜晚是沉淀的时刻,也是蓄力的开始,{username} 🌌",
+                    "星空很美,{username},别忘了好好休息!",
+                    "忙碌一天,{username},放松自己,明天更好!",
+                ],
+            ],
+            'en' => [
+                'morning_early' => [
+                    "Good morning {username}! A new day, a new beginning ☀️",
+                    "Wake up, {username}! The sun is shining just for you 🌞",
+                    "Early bird {username}, you’re catching all the worms! 🐦",
+                    "Rise and shine, {username}! Let's seize the day! ✨",
+                    "Morning, {username}! The world awaits your greatness!",
+                ],
+                'morning' => [
+                    "Good morning {username}! Let's make today productive 💪",
+                    "Hey {username}, rise and grind! ☕",
+                    "Keep pushing forward, {username}. Success awaits! 🚀",
+                    "Stay focused, {username}, and make it happen! 🧠",
+                    "Morning hustle, {username}! Keep that energy high!",
+                    "Seize the morning, {username}! Make it count!",
+                ],
+                'noon' => [
+                    "Hi {username}, don't forget to grab some lunch 🍱",
+                    "Take a break, {username}, recharge your energy! ⚡",
+                    "Refuel well, {username}, the afternoon awaits! 🌟",
+                    "Lunch time, {username}! Enjoy your meal 🍔",
+                    "Midday break, {username}! Stay refreshed!",
+                    "Keep up the great work, {username}! Almost halfway!",
+                ],
+                'afternoon' => [
+                    "Afternoon vibes, {username}! Keep going strong 💼",
+                    "Almost there, {username}! Keep up the great work 🏆",
+                    "Stay hydrated, {username}, and keep focused! 💧",
+                    "You’re doing great, {username}! Keep pushing! 🔥",
+                    "Keep the momentum, {username}! Afternoon grind!",
+                    "Push through, {username}! The finish line is near!",
+                ],
+                'evening' => [
+                    "Good evening {username}! Time to wind down 🌙",
+                    "Relax and recharge, {username}, you earned it 🛏️",
+                    "Well done today, {username}! See you tomorrow 👋",
+                    "Evenings are for rest, {username}. Take care! 🌌",
+                    "Night falls, {username}. Rest well and dream big!",
+                    "Time to relax, {username}. Tomorrow is a new chance!",
+                ],
+            ],
+        ];
+
+        $langGroup = $greetings[$lang] ?? $greetings['zh'];
+        $lines = $langGroup[$period] ?? $langGroup['morning_early'];
+
+        $template = $lines[array_rand($lines)];
+
+        return str_replace('{username}', $username, $template);
+    }
+}

+ 25 - 0
app/Api/Cron.php

@@ -0,0 +1,25 @@
+<?php namespace Manage\Api;
+use Dever;
+use Dever\Helper\Cmd;
+class Cron
+{
+    public function run()
+    {
+        $time = time();
+        # 获取所有的计划任务
+        $data = Dever::db('manage/cron')->load(array('ldate' => ['<=', $time]));
+        if ($data) {
+            foreach ($data as $k => $v) {
+                Cmd::run($v['interface'], [], $v['project']);
+                $param['ldate'] = $v['ldate'] + $v['time'];
+                if ($param['ldate'] < $time) {
+                    $param['ldate'] = $time + $v['time'];
+                }
+                if ($v['time'] <= 0) {
+                    $param['state'] = 2;
+                }
+                Dever::db('manage/cron')->update($v['id'], $param);
+            }
+        }
+    }
+}

+ 17 - 0
app/Api/Icon.php

@@ -0,0 +1,17 @@
+<?php namespace Manage\Api;
+use Dever;
+class Icon
+{
+    public function list()
+    {
+        $set['num'] = Dever::input('pgnum', '', '', 16);
+        $key = Dever::input('title');
+        $where = [];
+        if ($key) {
+            $where['key'] = ['like', $key];
+        }
+        $data['list'] = Dever::db('manage/icon')->select($where, $set);
+        $data['total'] = Dever::page('total');
+        return $data;
+    }
+}

+ 135 - 0
app/Api/Login.php

@@ -0,0 +1,135 @@
+<?php namespace Manage\Api;
+use Dever;
+use Dever\Helper\Str;
+use Dever\Helper\Code;
+use Manage\Lib\Util;
+class Login
+{
+    # 获取系统信息
+    public function getSystem()
+    {
+        $system = Dever::input('system', 'is_string', '系统', 'platform');
+        $system = Dever::db('manage/system')->find(['key' => $system]);
+        if (!$system) {
+            Dever::error('当前系统不存在');
+        }
+        $system['placeholder'] = '请输入' . $system['name'] . '号';
+        return $system;
+    }
+
+    # 登录
+    public function act()
+    {
+        //$this->checkCode();
+        $system = $this->getSystem();
+        $number = Dever::input('number', '', $system['name'] . '号', 'default');
+        $info = Dever::db($system['info_table'])->find(['number' => $number]);
+        if (!$info) {
+            Dever::error('登录失败,当前' . $system['name'] . '号错误');
+        }
+        if ($system['partition'] == 'no') {
+            # 不分库
+            $db = Dever::db($system['user_table']);
+            $role_db = Dever::db($system['role_table']);
+        } else {
+            # 分库
+            $info['info_id'] = $info['id'];
+            $info['partition'] = $system['partition'];
+            $info['system_key'] = $system['key'];
+            $info['system_id'] = $system['id'];
+            $partition = Dever::load(Util::class)->system($info);
+            $db = Dever::db($system['user_table'], '', true, 'default', $partition);
+            $role_db = Dever::db($system['role_table'], '', true, 'default', $partition);
+        }
+        $where['mobile'] = Dever::input('mobile', Dever::rule('mobile'), '手机号');
+        $password = Dever::input('password', 'is_string', '密码');
+        $admin = $db->find($where);
+        if (!$admin) {
+            $total = $db->find(1);
+            if (!$total) {
+                $insert['name'] = Str::hide($where['mobile']);
+                $insert['mobile'] = $where['mobile'];
+                $insert['role'] = 1;
+                $insert += Dever::load(Util::class)->createPwd($password);
+                $id = $db->insert($insert);
+                $admin = $db->find($id);
+            } else {
+                Dever::error('登录失败');
+            }
+        }
+        if (!$admin) {
+            Dever::error('登录失败,管理员信息无效');
+        }
+        if ($admin['status'] == 2) {
+            Dever::error('登录失败,账户已被封禁');
+        }
+        if (Dever::load(Util::class)->hash($password, $admin['salt']) != $admin['password']) {
+            Dever::error('登录失败,账户密码无效');
+        }
+        # 根据角色获取module_id
+        $system_user = Dever::db('manage/system_user')->find(['uid' => $admin['id'], 'system_id' => $system['id'], 'info_id' => $info['id']]);
+        $module_id = $data_id = 0;
+        if ($system_user) {
+            $module_id = $system_user['module_id'];
+            $data_id = $system_user['data_id'];
+        } elseif ($admin['role']) {
+            $module = '';
+            $role = $role_db->select(array('id' => ['in', $admin['role']]));
+            foreach ($role as $k => $v) {
+                if ($v['module']) {
+                    $module .= $v['module'] . ',';
+                }
+            }
+            if ($module) {
+                $where['id'] = ['in', $module];
+            } else {
+                $where['system'] = $system['key'];
+            }
+            $module = Dever::db('manage/system_module')->select($where);
+            if ($module) {
+                $module_id = $module[0]['id'];
+                $child = Dever::db($module[0]['data_table'])->select([]);
+                if ($child) {
+                    if ($admin['module_data']) {
+                        foreach ($child as $k => $v) {
+                            $key = $module_id . '-' . $v['id'];
+                            if (strstr($admin['module_data'], $key)) {
+                                $data_id = $v['id'];
+                                break;
+                            }
+                        }
+                    } else {
+                        $data_id = $child[0]['id'];
+                    }
+                }
+            }
+        }
+        if (!$module_id || !$data_id) {
+            Dever::error('登录失败,账户无效');
+        }
+        return Dever::load(Util::class)->token($admin['id'], $admin['mobile'], $system['partition'], $system['key'], $system['id'], $info['id'], $module_id, $data_id);
+    }
+    private function checkCode()
+    {
+        $code = Dever::input('verificationCode');
+        if (!$code) {
+            Dever::error('请输入验证码');
+        }
+        $save = Dever::session('code');
+        if ($code != $save) {
+            Dever::error('验证码错误');
+        }
+    }
+    public function code()
+    {
+        echo Dever::session('code', Code::create(), 3600);die;
+    }
+    public function out()
+    {
+        return 'ok';
+    }
+    public function loadMenu()
+    {
+        return Dever::load(\Manage\Lib\Menu::class)->init();
+    }
+}

+ 105 - 0
app/Api/Menu.php

@@ -0,0 +1,105 @@
+<?php namespace Manage\Api;
+use Dever;
+use Manage\Lib\Auth;
+class Menu extends Auth
+{
+    protected $top;
+    protected $opened;
+    public function info()
+    {
+        # 如果后续增加Root,就要这里置为false
+        $this->top = true;
+        $top = Dever::db('manage/menu')->select(['parent_id' => '0', 'module_id' => $this->user['select']['module_id']]);
+        $result = $menu = [];
+        $result[] = array
+        (
+            'path' => '/',
+            'name' => 'Root',
+            'component' => 'Layout',
+            'meta' => [
+                'title' => '首页',
+                'icon' => 'home-2-line',
+                'breadcrumbHidden' => true,
+            ],
+            'children' => array
+            (
+                array
+                (
+                    'path' => 'index',
+                    'name' => 'Index',
+                    'component' => '@/dever/index/index',
+                    'meta' => [
+                        'title' => '控制台',
+                        'icon' => 'home-2-line',
+                        'noClosable' => true,
+                    ]
+                ),
+            )
+        );
+        $this->opened = [];
+        foreach ($top as $v) {
+            $v = $this->getMenu($v, '');
+            if ($v) {
+                $result[] = $v;
+            }
+        }
+        return ['list' => $result, 'opened' => $this->opened];
+    }
+    private function getMenu($v, $parent = '')
+    {
+        $info = array
+        (
+            'path' => $parent ? '/' . $parent . '/' . $v['key'] : $v['key'],
+            'name' => $parent ? $parent . '_' . $v['key'] : $v['key'],
+            'meta' => [
+                'title' => $v['name'],
+                'icon' => $v['icon'],
+                //'noClosable' => true,
+                'breadcrumbHidden' => false,
+                'dynamicNewTab' => true,
+            ]
+        );
+        if ($v['show'] > 1) {
+            $info['meta']['hidden'] = true;
+        }
+        if (isset($v['active']) && $v['active']) {
+            $info['meta']['activeMenu'] = $v['active'];
+        }
+        if ($v['parent_id'] <= 0) {
+            if ($this->top) {
+                $info['path'] = '/' . $v['key'];
+            } else {
+                $this->top = true;
+                $info['path'] = '/';
+            }
+            $info['component'] = 'Layout';
+        }
+        $where = ['parent_id' => $v['id'], 'module_id' => $this->user['select']['module_id']];
+        $child = Dever::db('manage/menu')->select($where);
+        if ($child) {
+            foreach ($child as $v1) {
+                if ($v1['level'] == 3 && $v1['show'] <= 2 && $this->checkMenu($v1['id'])) {
+                    continue;
+                }
+                if (!$parent) {
+                    $this->opened[] = '/' . $v['key'] . '/' . $v1['key'];
+                }
+                $children = $this->getMenu($v1, $v['key']);
+                if ($children) {
+                    $info['children'][] = $children;
+                }
+            }
+            if (empty($info['children'])) {
+                return [];
+            }
+        } elseif ($v['path']) {
+            $info['component'] = '@/dever/page/' . $v['path'];
+        }
+        if (!$child) {
+            if ($v['level'] == 3 && $v['show'] <= 2 && $this->checkMenu($v['id'])) {
+                return false;
+            }
+        }
+        return $info;
+    }
+}

+ 181 - 0
app/Api/Page/Data.php

@@ -0,0 +1,181 @@
+<?php namespace Manage\Api\Page;
+use Dever;
+use Manage\Lib\Page;
+use Manage\Lib\Util;
+# 数据获取
+class Data extends Page
+{
+    private $expand = false;
+    public function __construct($load = '')
+    {
+        parent::__construct('list', $load);
+    }
+    public function list()
+    {
+        if ($this->menu && $this->menu['show'] == 1 && !$this->getFunc('list', '列表', 1)) {
+            Dever::error('无访问权限');
+        }
+        $data['title'] = $this->config['title'] ?? '';
+        $data['recycler'] = $this->recycler;
+
+        $where = [];
+        if (isset($this->config['where']) && $this->config['where']) {
+            foreach ($this->config['where'] as $k => $v) {
+                if (is_numeric($k) || $k == $v) {
+                    $where[$v] = Dever::load(Util::class)->request($v);
+                } else {
+                    $where[$k] = $this->getShow($v, []);
+                }
+            }
+        }
+        $data['button'] = $this->button('button', $where);
+        $data = array_merge($data, $this->out($where));
+        $data['total'] = Dever::page('total');
+        $data['height'] = $this->config['height'] ?? '100%';
+        $data['type'] = $this->config['type'] ?? 'table';
+        $data['desc'] = $this->config['desc'] ?? '';
+        $data['layout'] = $this->config['layout'] ?? [];
+        $data['exportButton'] = $this->export();
+        $data['show'] = [
+            'selection' => $this->config['selection'] ?? false,
+            'expand' => $this->expand,
+            'index' => $this->config['index'] ?? false,
+        ];
+        $this->column($data);
+        return $data;
+    }
+    public function out($where)
+    {
+        $set = $this->config['set'] ?? [];
+        $data['field'] = $data['head'] = [];
+        $data['search'] = $this->search($where);
+        $ids = Dever::input('ids');
+        if ($ids) {
+            $where['id'] = ['in', $ids];
+        }
+        $set['num'] = Dever::input('pgnum', '', '', 10);
+        $order_col = Dever::input('order_col');
+        if ($order_col) {
+            $order_value = Dever::input('order_value');
+            if ($order_value) {
+                $set['order'] = $order_col . ' ' . $order_value . ', id desc';
+            }
+        }
+        $data['filter'] = [];
+        if (isset($this->config['filter'])) {
+            $data['filter'] = Dever::call($this->config['filter'], [$where]);
+            if ($data['filter']) {
+                $filter = Dever::input('filter', '', '', 0);
+                if (isset($data['filter'][$filter])) {
+                    $where = array_merge($where, $data['filter'][$filter]['where']);
+                }
+            }
+        }
+
+        if (isset($this->config['data'])) {
+            $result = Dever::call($this->config['data'], [$where, $set]);
+            $data = array_merge($data, $result);
+        } else {
+            $data['field'] = $this->setting('field', $data['head'], true, 'show');
+            $data['body'] = $this->data($where, $set);
+        }
+        $method = Dever::input('method');
+        if ($method && strstr($method, '.')) {
+            $result = Dever::call($method, [$data]);
+            unset($data);
+            $data['field'] = $result['head'];
+            $data['body'] = $result['body'];
+        }
+        $data['stat'] = [];
+        if (isset($this->config['stat'])) {
+            $data['stat'] = Dever::call($this->config['stat'], [$where]);
+        }
+        
+        $data['bodyButton'] = (isset($this->config['data_button']) && $this->config['data_button']) || isset($this->config['data_button_list']) ? true : false;
+        return $data;
+    }
+
+    private function data($where, $set = [])
+    {
+        if (isset($this->config['tree'])) {
+            return $this->db->tree($where, $this->config['tree'], [$this, 'handleData']);
+        }
+        $data = $this->db->select($where, $set);
+        $result = [];
+        if ($data) {
+            foreach ($data as $k => $v) {
+                $result[$k] = $this->handleData($k, $v);
+            }
+        }
+        return $result;
+    }
+
+    public function handleData($k, $v)
+    {
+        $result = $v;
+        $result['index'] = $k+1*Dever::input('pg', '', '', 1);
+        $button = $this->button('data_button', $v);
+        if ($button) {
+            $result['button'] = $button;
+        }
+        $button = $this->button('data_button_list', $v, false);
+        if ($button) {
+            $result['button_list'] = $button;
+        }
+        
+        # 是否保留html代码,1是保留,2是不保留
+        $html = Dever::input('html', '', '', 1);
+        if (isset($v['_id'])) {
+            $result['id'] = $v['_id'];
+        } elseif (isset($v['id'])) {
+            $result['id'] = $v['id'];
+        }
+        $result['cdate'] = $v['cdate'];
+        foreach ($this->field as $value) {
+            $key = $value['key'];
+            if (isset($v[$key])) {
+                $result[$key] = $this->getValue($key, $v[$key], $v, $value);
+            } elseif (strpos($key, '/')) {
+                $other = $this->getOther($key, $value, $v);
+                if ($other) {
+                    $otherName = [];
+                    foreach ($other as $k1 => $v1) {
+                        if (isset($v1['name'])) {
+                            $otherName[] = $v1['name'];
+                        }
+                    }
+                    if ($otherName) {
+                        $result[$key] = implode('、', $otherName);
+                    } else {
+                        $result[$key] = $other;
+                    }
+                }
+            } elseif (isset($value['show'])) {
+                $result[$key] = $this->getShow($value['show'], $v);
+            }
+            if ($html == 2 && is_string($result[$key])) {
+                $result[$key] = strip_tags($result[$key]);
+            }
+        }
+        if (isset($this->config['expand']) && $this->config['expand']) {
+            $result['expand'] = Dever::call($this->config['expand'], [$v]);
+            $this->expand = true;
+        }
+        return $result;
+    }
+
+    private function export()
+    {
+        $result = false;
+        if (isset($this->config['export']) && $this->config['export']) {
+            $result = [];
+            foreach ($this->config['export'] as $k => $v) {
+                $func = $this->getFunc($k, $v, 300);
+                if ($func) {
+                    $result[$k] = $v;
+                }
+            }
+        }
+        return $result;
+    }
+}

+ 29 - 0
app/Api/Page/Diy.php

@@ -0,0 +1,29 @@
+<?php namespace Manage\Api\Page;
+use Dever;
+use Manage\Lib\Page;
+# 自定义页面
+class Diy extends Page
+{
+    public function __construct($load = '', $input = true, $id = false)
+    {
+        parent::__construct('diy', $load, $input);
+    }
+    public function get()
+    {
+        $this->checkFunc();
+        if (is_string($this->config)) {
+            $data = Dever::call($this->config, [$this->info]);
+        } else {
+            $data = $this->config;
+        }
+        $where = $this->config['where'] ?? [];
+        if (isset($data['search'])) {
+            $data['search'] = $this->search($where);
+            $data['search']['type'] = 'search';
+        }
+        if (isset($data['data']) && $data['data']) {
+            $data = Dever::call($data['data'], [$where, $data]);
+        }
+        return $data;
+    }
+}

+ 107 - 0
app/Api/Page/Oper.php

@@ -0,0 +1,107 @@
+<?php namespace Manage\Api\Page;
+use Dever;
+use Manage\Lib\Page;
+# 操作
+class Oper extends Page
+{
+    public function __construct()
+    {
+        parent::__construct('oper');
+        $this->id = Dever::input('id');
+        if (!$this->id) {
+            Dever::error('无效数据');
+        }
+        $this->checkFunc();
+    }
+
+    # 更改某个字段的值
+    public function up_commit(){}
+    public function up()
+    {
+        $input = Dever::input();
+        $field = Dever::input('field');
+        if (is_array($field)) {
+            $field = $field['field'];
+        }
+        $field = explode(',', $field);
+        foreach ($field as $k => $v) {
+            if (isset($input[$v]) && $value = $input[$v]) {
+                if (is_array($value)) {
+                    $value = implode(',', $value);
+                }
+                $data[$v] = $value;
+            }
+        }
+        if (isset($this->config['up_start']) && $this->config['up_start']) {
+            list($this->id, $data) = Dever::call($this->config['up_start'], [$this->id, $data]);
+        }
+        $where['id'] = ['in', $this->id];
+        $state = $this->db->update($where, $data);
+        if ($state) {
+            if (isset($this->config['up_end']) && $this->config['up_end']) {
+                Dever::call($this->config['up_end'], [$this->id, $data]);
+            }
+            return ['msg' => '操作成功', 'upAdmin' => false];
+        } else {
+            Dever::error('操作失败');
+        }
+    }
+
+    # 删除 删除到回收站
+    public function recycle_commit(){}
+    public function recycle()
+    {
+        $where['id'] = ['in', $this->id];
+        $data = $this->db->select($where);
+        if ($data) {
+            foreach ($data as $k => $v) {
+                $insert['table'] = $this->db->config['load'];
+                $insert['table_id'] = $v['id'];
+                $insert['content'] = Dever::json_encode($v);
+                $state = Dever::db('manage/recycler')->insert($insert);
+                if (!$state) {
+                    Dever::error('删除失败,请重试');
+                }
+                $state = $this->db->delete($v['id']);
+                if (!$state) {
+                    Dever::error('删除失败,请重试');
+                }
+            }
+        }
+        return '操作成功';
+    }
+
+    # 从回收站恢复
+    public function recover_commit(){}
+    public function recover()
+    {
+        $where['id'] = ['in', $this->id];
+        $data = $this->db->select($where);
+        if ($data) {
+            foreach ($data as $k => $v) {
+                $v['content'] = Dever::json_decode($v['content']);
+                $state = Dever::db($v['table'])->insert($v['content']);
+                if (!$state) {
+                    Dever::error('恢复失败,请重试');
+                }
+                $state = $this->db->delete($v['id']);
+                if (!$state) {
+                    Dever::error('恢复失败,请重试');
+                }
+            }
+        }
+        return '操作成功';
+    }
+
+    # 直接删除
+    public function delete_commit(){}
+    public function delete()
+    {
+        $where['id'] = ['in', $this->id];
+        $state = $this->db->delete($where);
+        if (!$state) {
+            Dever::error('删除失败,请重试');
+        }
+        return '操作成功';
+    }
+}

+ 34 - 0
app/Api/Page/Pdf.php

@@ -0,0 +1,34 @@
+<?php namespace Manage\Api\Page;
+use Dever;
+use Manage\Lib\Page;
+# pdf编辑器
+class Pdf extends Page
+{
+    public function __construct($load = '', $input = true, $id = false)
+    {
+        parent::__construct('pdf', $load, $input);
+    }
+    public function get()
+    {
+        $this->checkFunc();
+        if (is_string($this->config)) {
+            $data = Dever::call($this->config, [$this->info]);
+        } else {
+            $data = $this->config;
+        }
+        if (isset($data['upload'])) {
+            $upload = $this->getUpload($data['upload']);
+            if (is_array($data['upload'])) {
+                $upload += $data['upload'];
+            } else {
+                $upload += ['id' => $data['upload']];
+            }
+            if (empty($upload['id'])) {
+                Dever::error('上传配置错误');
+            }
+            $upload['wh'] = '500*500';
+            $data['upload'] = ['set' => Dever::url('image/manage.set', $upload, true)];
+        }
+        return $data;
+    }
+}

+ 11 - 0
app/Api/Page/Stat.php

@@ -0,0 +1,11 @@
+<?php namespace Manage\Api;
+use Dever;
+use Manage\Lib\Page;
+# 统计页
+class Stat extends Page
+{
+    public function get()
+    {
+        
+    }
+}

+ 751 - 0
app/Api/Page/Update.php

@@ -0,0 +1,751 @@
+<?php namespace Manage\Api\Page;
+use Dever;
+use Manage\Lib\Page;
+ini_set("memory_limit", -1);
+set_time_limit(0);
+# 更新页 项目着急上线 以后优化并封装
+class Update extends Page
+{
+    public function __construct($load = '', $input = true)
+    {
+        parent::__construct('update', $load, $input);
+    }
+    public function get(&$value = [], &$option = [])
+    {
+        $func = $this->checkFunc();
+        $remote = $show = $spec = $source = $default = [];
+        $data['update'] = $data['field'] = $data['option'] = [];
+        $this->setting('field', $data['update'], true, 'text');
+        foreach ($data['update'] as $k => $v) {
+            if ($v['type'] == 'tree' || $v['type'] == 'upload' || $v['type'] == 'cascader' || $v['type'] == 'checkbox' || isset($v['multiple'])) {
+                if (isset($v['value']) && $v['value']) {
+                    $v['value'] = explode(',', $v['value']);
+                    foreach ($v['value'] as $k1 => $v1) {
+                        if (is_numeric($v1)) {
+                            $v['value'][$k1] = (float) $v1;
+                        }
+                    }
+                } else {
+                    $v['value'] = [];
+                }
+            }
+            if (isset($v['source'])) {
+                $source[$v['key']] = $v['source'];
+            }
+            if (isset($v['remote'])) {
+                $remote[$v['key']] = [$k, $v['remote'], $v['key']];
+                if (isset($v['remote_default']) && !$v['remote_default']) {
+                    unset($remote[$v['key']][2]);
+                }
+            }
+            if (isset($v['spec_data'])) {
+                $spec[$v['key']] = [$k, $v['spec_data'], $v['key'] . '_spec', $v['spec'], $v['spec_field'], $v['spec_template'] ?? ''];
+            }
+            if (isset($v['show']) && is_string($v['show'])) {
+                $show[$v['key']] = [$k, $v['show']];
+            }
+            if (isset($v['default']) && is_string($v['default']) && strstr($v['default'], '(')) {
+                $default[$v['key']] = [$k, $v['default']];
+            }
+            $data['field'][$v['key']] = $v['value'];
+            if ($v['type'] == 'sku') {
+                $data['field'][$v['key'] . '_spec'] = [];
+            }
+            if (isset($v['option'])) {
+                $data['option'][$v['key']] = $v['option'];
+                unset($data['update'][$k]['option']);
+            }
+        }
+        $active = $this->column($data);
+        $data['info_id'] = false;
+        if (!$this->info && $active) {
+            $this->info = $this->db->find($active);
+            if ($this->info) {
+                $data['info_id'] = $this->info['id'];
+                if (!$func) {
+                    $func = $this->getFunc('edit', '编辑', 1);
+                    if (!$func && $this->menu && $this->menu['show'] == 1) {
+                        Dever::error('无操作权限');
+                    }
+                }
+            }
+        } elseif (!$func) {
+            $func = $this->getFunc('update', '更新', 1);
+            if (!$func && $this->menu && $this->menu['show'] == 1) {
+                Dever::error('无操作权限');
+            }
+        }
+        if ($this->info) {
+            $info = $this->info;
+            $this->setInfo($info, $data, $remote, $show, $source, $default, 1, $this->config['field']);
+            if ($spec) {
+                foreach ($spec as $k => $v) {
+                    $data['update'][$v[0]]['remote'] = Dever::url($v[1], ['value' => '', 'table' => $this->db->config['load'], 'id' => false]);
+                    $result = Dever::call($v[1], [$v[3], $v[4], $this->info['id']]);
+                    if ($result) {
+                        $data['field'][$v[2]] = $result;
+                    }
+                }
+            }
+        } elseif ($value) {
+            $field = [];
+            if (isset($this->config['field']) && $this->config['field']) {
+                foreach ($this->config['field'] as $k => $v) {
+                    if (isset($v['field'])) {
+                        $field[$v['field']] = $v;
+                        if (!isset($field[$v['field']]['index'])) {
+                            $field[$v['field']]['index'][] = $k;
+                        }
+                    } else {
+                        $field[$k] = $v;
+                    }
+                }
+            }
+            foreach ($value as $k => &$v) {
+                $this->setInfo($v, $data, $remote, $show, $source, $default, 2, $field);
+                $option[$k] = $data['option'];
+            }
+            if (isset($data['reset'])) {
+                foreach ($data['reset'] as $k1 => $v1) {
+                    if (isset($data['option'][$k1])) {
+                        unset($data['option'][$k1]);
+                        $data['field'][$k1] = $v1;
+                    }
+                }
+            }
+        } else {
+            if ($remote) {
+                $info = [];
+                foreach ($remote as $k => $v) {
+                    $data['update'][$v[0]]['remote'] = Dever::url($v[1], ['value' => '', 'table' => $this->db->config['load'], 'id' => false]);
+                    if (isset($v[2]) && isset($data['option'][$v[2]]) && $data['option'][$v[2]] && $m = Dever::issets($data['option'][$v[2]][0], 'id')) {
+                        $result = Dever::call($v[1], [$m, $this->db->config['load'], false]);
+                        if ($result) {
+                            $this->setUpdate($info, $data, $result);
+                        }
+                    }
+                }
+            }
+            if ($show) {
+                foreach ($show as $k => $v) {
+                    $data['update'][$v[0]]['show'] = true;
+                }
+            }
+
+            if ($default) {
+                foreach ($default as $k => $v) {
+                    $data['update'][$v[0]]['value'] = $this->getShow($v[1], []);
+                    $data['field'][$k] = $data['update'][$v[0]]['value'];
+                }
+            }
+        }
+        
+        $data['desc'] = $this->config['desc'] ?? '';
+        $data['drag'] = $this->config['drag'] ?? false;
+        $this->layout($data);
+        $data['control'] = $this->control($data);
+        $this->tab($data, 'step');
+        if (!$data['step']) {
+            $this->tab($data);
+        }
+        return $data;
+    }
+
+    private function setInfo(&$info, &$data, $remote, $show, $source, $default, $type = 1, $field = [])
+    {
+        if ($source) {
+            foreach ($source as $k => $v) {
+                $t = [];
+                foreach ($v as $v1) {
+                    $t[] = $info[$v1] ?? '';
+                }
+                $info[$k] = implode(',', $t);
+            }
+        }
+        foreach ($info as $k => $v) {
+            if ($v === null) {
+                $v = '';
+            }
+            if (isset($data['field'][$k])) {
+                if (is_array($data['field'][$k])) {
+                    if ($v) {
+                        $v = explode(',', $v);
+                        foreach ($v as $k1 => $v1) {
+                            if (is_numeric($v1)) {
+                                $v[$k1] = (float) $v1;
+                            }
+                        }
+                    } else {
+                        $v = [];
+                    }
+                    $info[$k] = $v;
+                }
+                # 处理一下select,后续优化
+                if (isset($field[$k]) && isset($field[$k]['type']) && $field[$k]['type'] == 'select' && !$v) {
+                    $v = $info[$k] = '';
+                }
+
+                if (isset($field[$k]) && isset($field[$k]['update'])) {
+                    $v = $field[$k]['update'];
+                }
+                if ($k == 'cdate') {
+                   $field[$k]['type'] = 'date';
+                }
+                if (isset($field[$k]) && isset($field[$k]['type']) && $field[$k]['type'] == 'date' && $v) {
+                    $v = date('Y-m-d H:i:s', $v);
+                }
+                if ($type == 1) {
+                    $data['field'][$k] = $v;
+                }
+                if (isset($remote[$k])) {
+                    $data['update'][$remote[$k][0]]['remote'] = Dever::url($remote[$k][1], ['value' => '', 'table' => $this->db->config['load'], 'id' => false]);
+                    if ($field[$k]['type'] == 'cascader' && !isset($field[$k]['option'])) {
+                        
+                    } else {
+                        $result = Dever::call($remote[$k][1], [$v, $this->db->config['load'], $info['id'] ?? false]);
+                        if ($result) {
+                            $this->setUpdate($info, $data, $result);
+                        }
+                    }
+                }
+                if (isset($show[$k])) {
+                    $data['update'][$show[$k][0]]['show'] = $this->getShow($show[$k][1], $info);
+                    $info[$k] = $data['update'][$show[$k][0]]['show'];
+                }
+            }
+            if (isset($field[$k]) && isset($field[$k]['index'])) {
+                foreach ($field[$k]['index'] as $v1) {
+                    $info[$v1] = $v;
+                }
+            }
+        }
+        if ($default) {
+            foreach ($default as $k => $v) {
+                $data['update'][$v[0]]['value'] = $this->getShow($v[1], $info);
+                $info[$k] = $data['field'][$k] = $data['update'][$v[0]]['value'];
+            }
+        }
+    }
+
+    private function setUpdate(&$info, &$data, $result, $remote = [])
+    {
+        foreach ($data['update'] as $k => $v) {
+            if (isset($result[$v['key']])) {
+                # 批量更新时,默认数据需要重置
+                if (!isset($data['reset'][$v['key']])) {
+                    $data['reset'][$v['key']] = $data['field'][$v['key']];
+                }
+                if (isset($result[$v['key']]['option'])) {
+                    $data['option'][$v['key']] = $result[$v['key']]['option'];
+                    unset($result[$v['key']]['option']);
+                }
+                if (empty($data['field'][$v['key']]) && isset($result[$v['key']]['value'])) {
+                    if (is_array($data['field'][$v['key']]) && !is_array($result[$v['key']]['value'])) {
+                        $data['field'][$v['key']] = explode(',', $result[$v['key']]['value']);
+                    } else {
+                        $data['field'][$v['key']] = $result[$v['key']]['value'];
+                    }
+                }
+                if (isset($result[$v['key']]['set']) && $info) {
+                    $info = array_merge($info, $result[$v['key']]['set']);
+                }
+                $data['update'][$k] = array_merge($data['update'][$k], $result[$v['key']]);
+            }
+        }
+    }
+
+    private function control(&$data)
+    {
+        $result = [];
+        if (isset($this->config['control']) && $this->config['control']) {
+            foreach ($this->config['control'] as $k => $v) {
+                if (is_string($v)) {
+                    parse_str($v, $v);
+                }
+                if (strstr($k, ',')) {
+                    $k = explode(',', $k);
+                    foreach ($k as $k2) {
+                        if (isset($data['update'])) $this->controlShow($data, $k2, $v);
+                        $result[$k2] = $v;
+                    }
+                } else {
+                    if (isset($data['update'])) $this->controlShow($data, $k, $v);
+                    $result[$k] = $v;
+                }
+            }
+        }
+        return $result;
+    }
+
+    private function controlShow(&$data, $k, $v)
+    {
+        foreach ($data['update'] as $k1 => $v1) {
+            if ($v1['key'] == $k) {
+                $show = true;
+                foreach ($v as $k2 => $v2) {
+                    if (is_array($v2)) {
+                        $temp = false;
+                        foreach ($v2 as $k3 => $v3) {
+                            if (is_array($data['field'][$k2]) && in_array($v3, $data['field'][$k2])) {
+                                $temp = true;
+                            } elseif ($data['field'][$k2] == $v3) {
+                                $temp = true;
+                            }
+                        }
+                        $show = $temp;
+                    } else {
+                        if (is_array($data['field'][$k2]) && !in_array($v2, $data['field'][$k2])) {
+                            $show = false;
+                        } elseif ($data['field'][$k2] != $v2) {
+                            $show = false;
+                        }
+                    }
+                }
+                $data['update'][$k1]['show'] = $show;
+                if ($show == false && isset($data['update'][$k1]['field'])) {
+                    # 对重新命名的字段删除
+                    if ($data['update'][$k1]['type'] == 'editor') {
+                        $data['field'][$v1['key']] = '';
+                    } else {
+                        unset($data['field'][$v1['key']]);
+                    }
+                }
+            }
+        }
+    }
+
+    private function tab(&$data, $type = 'tab')
+    {
+        $field = $this->input('field', '');
+        $data[$type] = [];
+        //if (empty($data['layout']) && !$field && isset($this->config[$type])) {
+        if (empty($data['layout']) && isset($this->config[$type])) {
+            foreach ($this->config[$type] as $k => $v) {
+                if (is_string($v)) {
+                    $field = [];
+                    $data[$type][] = array
+                    (
+                        'name' => $k,
+                        'update' => $this->getUpdate($v, $data['update'], $field),
+                        'field' => $field,
+                    );
+                } else {
+                    $field = [];
+                    $result = [];
+                    $result['name'] = $k;
+                    foreach ($v as $v1) {
+                        $result['layout'][] = $this->getUpdate($v1, $data['update'], $field);
+                    }
+                    $result['field'] = $field;
+                    $data[$type][] = $result;
+                }
+            }
+            $data['update'] = [];
+        }
+    }
+
+    private function layout(&$data)
+    {
+        $field = $this->input('field', '');
+        $data['layout'] = [];
+        if (isset($this->config['layout'])) {
+            foreach ($this->config['layout'] as $k => $v) {
+                $field = [];
+                $data['layout'][] = $this->getUpdate($v, $data['update'], $field, '100%');
+            }
+            $data['update'] = [];
+        }
+    }
+
+    private function getUpdate($set, $update, &$field, $width = '')
+    {
+        $result = [];
+        if (is_string($set)) {
+            $set = explode(',', $set);
+            foreach ($set as $k => $v) {
+                foreach ($update as $value) {
+                    if ($value['key'] == $v) {
+                        $width && $value['width'] = $width;
+                        $result[] = $value;
+                        $field[] = $v;
+                    }
+                }
+            }
+        } else {
+            foreach ($set as $k => $v) {
+                foreach ($update as $value) {
+                    if ($value['key'] == $k) {
+                        $width && $value['width'] = $width;
+                        $result[] = array('span' => $v, 'update' => [$value]);
+                        $field[] = $k;
+                    }
+                }
+            }
+        }
+        return $result;
+    }
+
+    public function do_commit(){}
+    public function do()
+    {
+        $this->checkFunc();
+        $update = [];
+        $this->setting('field', $update, true, 'text');
+        if (empty($this->config['upAdmin'])) {
+            $this->config['upAdmin'] = false;
+        }
+        if ($update) {
+            $data = $other = $sku = [];
+            $input = Dever::input();
+            $id = false;
+            if (isset($input['id']) && $input['id'] > 0) {
+                $id = $input['id'];
+            }
+            $control = $this->control($data);
+            foreach ($update as $k => $v) {
+                if (isset($input[$v['key']])) {
+                    if (isset($v['rules'])) {
+                        $this->checkRules($v, $input[$v['key']]);
+                    }
+                    if ($v['type'] == 'sku') {
+                        if (isset($input[$v['key'] . '_spec']) && isset($input[$v['key']])) {
+                            $sku[$v['key']] = [$v['where'], $v['content']['field'], $v['spec'], $v['spec_field'], $input[$v['key'] . '_spec'], $input[$v['key']]];
+                        }
+                        
+                    } elseif (strpos($v['key'], '/') && $v['type'] != 'hidden') {
+                        if (isset($v['field'])) {
+                            $value = $input[$v['key']] ?? false;
+                            if (strpos($v['key'], '#')) {
+                                $v['key'] = str_replace('#', '', $v['key']);
+                            }
+                            $other_id = $input[$v['key'] . '_id'] ?? 0;
+                            $value = array
+                            (
+                                0 => ['id' => $other_id, $v['field'] => $value]
+                            );
+                            if (isset($other[$v['key']])) {
+                                $other[$v['key']][3][0] += $value[0];
+                            } else {
+                                $other[$v['key']] = [$v['where'], false, false, $value];
+                            }
+                        } else {
+                            $other[$v['key']] = [$v['where'], $v['content']['field'], $v['content']['drag'], $input[$v['key']]];
+                        }
+                    } else {
+                        $this->doData($data, $v['key'], $input[$v['key']], $this->config['field'], $control);
+                    }
+                } elseif ($id) {
+                    $data[$v['key']] = '';
+                }
+                if (isset($data[$v['key']]) && !$data[$v['key']] && isset($v['empty']) && !$v['empty']) {
+                    unset($data[$v['key']]);
+                }
+            }
+            if (!$data && !$other && !$sku) {
+                Dever::error('无效数据');
+            }
+            if ($data) {
+                if (isset($this->config['check']) && $this->config['check']) {
+                    $this->exists($this->db, $this->config['check'], $id, $data, $this->config['field']);
+                }
+                $result = $this->start($id, $data);
+                if ($result == 'end') {
+                    return ['msg' => '操作成功', 'upAdmin' => $this->config['upAdmin']];
+                }
+                if ($id) {
+                    $info = $this->db->find($id);
+                    if ($info) {
+                        $state = $this->db->update($info['id'], $data);
+                        if ($state) {
+                            $id = $info['id'];
+                        }
+                    } else {
+                        $data['id'] = $id;
+                        $id = $this->db->insert($data);
+                    }
+                } else {
+                    $id = $this->db->insert($data);
+                }
+            }
+            if (!$id) {
+                Dever::error('操作失败');
+            }
+            $this->other($id, $data, $other);
+            $this->sku($id, $data, $sku);
+            $this->end($id, $data);
+            return ['msg' => '操作成功', 'upAdmin' => $this->config['upAdmin']];
+        }
+    }
+
+    private function doData(&$data, $key, $value, $field = [], $control = [])
+    {
+        if (is_array($value)) {
+            # 用最傻的办法做,往往是最好的。。
+            if (isset($value[0]) && !is_array($value[0])) {
+                $value = implode(',', $value);
+            } else {
+                $value = Dever::json_encode($value);
+            }
+        }
+        if (isset($field[$key]) && isset($field[$key]['field'])) {
+            if ($control && isset($control[$key])) {
+                # 如果有重命名字段并且是控制项,需要单独设置
+                $state = true;
+                foreach ($control[$key] as $k => $v) {
+                    if ($data[$k] != $v) {
+                        //$state = false;
+                    }
+                }
+                if ($state) {
+                    $key = $field[$key]['field'];
+                }
+            } else {
+                $key = $field[$key]['field'];
+            }
+        }
+        if ($value && isset($field[$key]) && $handle = Dever::issets($field[$key], 'handle')) {
+            $value = Dever::call($handle, [$value]);
+            if (is_array($value) && isset($value[$key])) {
+                foreach ($value as $k => $v) {
+                    $data[$k] = trim($v);
+                }
+                return;
+            }
+        } elseif (isset($field[$key]) && isset($field[$key]['type']) && $field[$key]['type'] == 'date' && $value) {
+            $value = \Dever\Helper\Date::mktime($value);
+        }
+        /*
+        if (empty($data[$key])) {
+            $data[$key] = trim($value);
+        }
+        */
+        $data[$key] = trim($value);
+    }
+
+    private function exists($db, $check, $id, $data, $field)
+    {
+        $check = explode(',', $check);
+        $where = [];
+        $name = [];
+        foreach ($check as $k => $v) {
+            if (isset($data[$v]) && $data[$v]) {
+                if (isset($field[$v]) && isset($field[$v]['name'])) {
+                    $n = $field[$v]['name'];
+                } elseif (isset($db->config['struct'][$v])) {
+                    $n = $db->config['struct'][$v]['name'];
+                } else {
+                    $n = $v;
+                }
+                $where[$v] = $data[$v];
+                $name[] = $n;
+            }
+        }
+        if ($where) {
+            if ($id) {
+                $where['id'] = ['!=', $id];
+            }
+            $info = $db->find($where);
+            if ($info) {
+                $name = implode('、', $name);
+                Dever::error($name . '已存在');
+            }
+        }
+    }
+
+    private function start($id, &$data)
+    {
+        if (isset($this->config['start']) && $this->config['start']) {
+            $data['id'] = $id;
+            if (is_array($this->config['start'])) {
+                $result = $data;
+                foreach ($this->config['start'] as $k => $v) {
+                    $result = Dever::call($v, [$this->db, $result]);
+                }
+            } else {
+                $result = Dever::call($this->config['start'], [$this->db, $data]);
+            }
+            if ($result) {
+                if ($result == 'end') {
+                    return $result;
+                }
+                if (is_object($result)) {
+                    $this->db = $result;
+                } else {
+                    $data = $result;
+                }
+            }
+        }
+    }
+
+    private function end($id, $data)
+    {
+        if (isset($this->config['end']) && $this->config['end']) {
+            $data['id'] = $id;
+            if (is_array($this->config['end'])) {
+                foreach ($this->config['end'] as $k => $v) {
+                    Dever::call($v, [$this->db, $data]);
+                }
+            } else {
+                Dever::call($this->config['end'], [$this->db, $data]);
+            }
+        }
+    }
+
+    private function other($rid, $data, $other)
+    {
+        if ($other) {
+            foreach ($other as $k => $v) {
+                if (strpos($k, '#')) {
+                    $k = str_replace('#', '', $k);
+                }
+                $set = new Update($k, false);
+                $common = $v[0];
+                $update = $v[1];
+                $drag = $v[2];
+                $input = $v[3];
+                $value = [];
+                foreach ($input as $k1 => $v1) {
+                    if (isset($v1['id']) && $v1['id']) {
+                        $value['id'] = $v1['id'];
+                    }
+                    foreach ($common as $k2 => $v2) {
+                        if (!is_array($v2)) {
+                            if ($v2 == 'id') {
+                                $value[$k2] = $rid;
+                            } elseif (isset($data[$v2])) {
+                                $value[$k2] = $data[$v2];
+                            } else {
+                                $value[$k2] = $v2;
+                            }
+                        }
+                    }
+                    if ($update) {
+                        foreach ($update as $k2 => $v2) {
+                            if (isset($v1[$k2])) {
+                                $this->doData($value, $k2, $v1[$k2], $set->config['field']);
+                            } else {
+                                $value[$k2] = '';
+                            }
+                        }
+                    } else {
+                        $value += $v1;
+                    }
+                    if ($drag) {
+                        $value[$drag] = $k1+1;
+                    }
+                    $db = Dever::db($k);
+                    if (isset($db->config['manage']['update']['check'])) {
+                        $this->exists($db, $db->config['manage']['update']['check'], $value['id'], $value, $db->config['manage']['update']['field']);
+                    }
+                    if (isset($value['id']) && $value['id'] > 0) {
+                        $id = $value['id'];
+                        unset($value['id']);
+                        $db->update($id, $value);
+                    } else {
+                        $db->insert($value);
+                    }
+                }
+            }
+        }
+    }
+
+    private function sku($rid, $data, $sku)
+    {
+        if ($sku) {
+            if (isset($data['spec_type']) && $data['spec_type'] <= 2) {
+                return;
+            }
+            foreach ($sku as $k => $v) {
+                if (strpos($k, '#')) {
+                    $k = str_replace('#', '', $k);
+                }
+                $common = $v[0];
+                $update = $v[1];
+                $spec_table = $v[2];
+                $spec_value_table = $spec_table . '_value';
+                $spec_field = $v[3];
+                $spec = $v[4];
+                $input = $v[5];
+                $spec_value = [];
+                Dever::db($spec_table)->update([$spec_field => $rid], ['state' => 2]);
+                Dever::db($spec_value_table)->update([$spec_field => $rid], ['state' => 2]);
+                foreach ($spec as $k1 => &$v1) {
+                    $spec_data = [];
+                    $spec_data['state'] = 1;
+                    $spec_data[$spec_field] = $rid;
+                    $spec_data['name'] = $v1['name'];
+                    $spec_data['sort'] = $k1+1;
+                    if (isset($v1['id']) && $v1['id']) {
+                        Dever::db($spec_table)->update($v1['id'], $spec_data);
+                    } else {
+                        $v1['id'] = Dever::db($spec_table)->insert($spec_data);
+                    }
+                    if ($v1['id']) {
+                        foreach ($v1['value'] as $k2 => &$v2) {
+                            $spec_value_data = [];
+                            $spec_value_data['state'] = 1;
+                            $spec_value_data[$spec_field] = $rid;
+                            $spec_value_data['spec_id'] = $v1['id'];
+                            $spec_value_data['value'] = $v2['value'] ?? $v2['name'];
+                            $spec_value_data['pic'] = $v2['pic'] ?? '';
+                            $spec_value_data['sort'] = $k2+1;
+                            $spec_value_data['is_checked'] = $v2['checked'] == 'true' ? 1 : 2;
+                            if (isset($v2['id']) && $v2['id']) {
+                                Dever::db($spec_value_table)->update($v2['id'], $spec_value_data);
+                            } else {
+                                $v2['id'] = Dever::db($spec_value_table)->insert($spec_value_data);
+                            }
+                            $spec_value[$v1['key']][$spec_value_data['value']] = [$v2['id'], $spec_data['sort']];
+                        }
+                    }
+                }
+                Dever::db($spec_table)->delete([$spec_field => $rid, 'state' => 2]);
+                Dever::db($spec_value_table)->delete([$spec_field => $rid, 'state' => 2]);
+                Dever::db($k)->update([$spec_field => $rid], ['state' => 2]);
+                foreach ($input as $k1 => $v1) {
+                    $value = [];
+                    if (isset($v1['id'])) {
+                        $value['id'] = $v1['id'];
+                    }
+                    foreach ($common as $k2 => $v2) {
+                        if (!is_array($v2)) {
+                            if ($v2 == 'id') {
+                                $value[$k2] = $rid;
+                            } elseif (isset($data[$v2])) {
+                                $value[$k2] = $data[$v2];
+                            } else {
+                                $value[$k2] = $v2;
+                            }
+                        }
+                    }
+                    foreach ($update as $k2 => $v2) {
+                        if (isset($v1[$k2])) {
+                            if (is_array($v1[$k2])) {
+                                $v1[$k2] = implode(',', $v1[$k2]);
+                            }
+                            $value[$k2] = $v1[$k2];
+                        }
+                    }
+                    $value['key'] = [];
+                    foreach ($v1 as $k2 => $v2) {
+                        if (isset($spec_value[$k2]) && isset($spec_value[$k2][$v2])) {
+                            $value['key'][$spec_value[$k2][$v2][1]] = $spec_value[$k2][$v2][0];
+                        }
+                    }
+                    if ($value['key']) {
+                        $value['key'] = implode(',' , $value['key']);
+                    }
+                    $value['state'] = 1;
+                    if (isset($value['id']) && $value['id'] > 0) {
+                        $id = $value['id'];
+                        unset($value['id']);
+                        Dever::db($k)->update($id, $value);
+                    } else {
+                        Dever::db($k)->insert($value);
+                    }
+                }
+                Dever::db($k)->delete([$spec_field => $rid, 'state' => 2]);
+            }
+        }
+    }
+}

+ 21 - 0
app/Api/Page/View.php

@@ -0,0 +1,21 @@
+<?php namespace Manage\Api\Page;
+use Dever;
+use Manage\Lib\Page;
+# 详情页
+class View extends Page
+{
+    public function __construct($load = '', $input = true, $id = false)
+    {
+        parent::__construct('view', $load, $input);
+    }
+    public function get()
+    {
+        $this->checkFunc();
+        if (is_string($this->config)) {
+            $data = Dever::call($this->config, [$this->info]);
+        } else {
+            $data = $this->config;
+        }
+        return $data;
+    }
+}

+ 167 - 0
app/Lib/Auth.php

@@ -0,0 +1,167 @@
+<?php namespace Manage\Lib;
+use Dever;
+class Auth
+{
+    protected $login = true;
+    public $uid;
+    protected $user;
+    protected $system;
+    protected $system_info;
+    protected $info;
+    protected $func;
+    public $data = [];
+    public function __construct()
+    {
+        $info = Dever::load(Util::class)->auth();
+        if (!$info && $this->login) {
+            $info['uid'] = 1;
+            $info['extend']['system_id'] = 'no';
+            $info['extend']['system_id'] = 1;
+            $info['extend']['info_id'] = 1;
+            $info['extend']['module_id'] = 1;
+            $info['extend']['data_id'] = 1;
+            Dever::error('请先登录');
+        }
+        $this->system = Dever::db('manage/system')->find($info['extend']['system_id']);
+        if (!$this->system) {
+            Dever::error('当前系统不存在');
+        }
+        $this->system_info = Dever::db($this->system['info_table'])->find($info['extend']['info_id']);
+        if (!$this->system) {
+            Dever::error('当前系统设置错误');
+        }
+
+        $this->uid = $info['uid'];
+        $this->user = Dever::db($this->system['user_table'])->find($this->uid);
+        if (!$this->user) {
+            Dever::error('请先登录');
+        }
+        $this->user['table'] = $this->system['user_table'];
+        $this->user['auth'] = ['module' => '', 'menu' => '', 'func' => ''];
+        if ($this->user['role']) {
+            $role = Dever::db($this->system['role_table'])->select(array('id' => ['in', $this->user['role']]));
+            foreach ($role as $k => $v) {
+                $this->user['auth']['module'] .= $v['module'] . ',';
+                $this->user['auth']['menu'] .= $v['menu'] . ',';
+                $this->user['auth']['func'] .= $v['auth'] . ',';
+            }
+        }
+        if ($this->user['auth']['module']) {
+            $this->user['auth']['module'] = rtrim($this->user['auth']['module'], ',');
+        }
+        if ($this->user['auth']['menu']) {
+            $this->user['auth']['menu'] = rtrim($this->user['auth']['menu'], ',');
+        }
+        if ($this->user['auth']['func']) {
+            $this->user['auth']['func'] = ',' . $this->user['auth']['func'];
+        }
+        $this->user['select'] = $info['extend'] ?? false;
+        if (!$this->user['select']) {
+            # 分别为系统id,系统基本信息id,模块id,模块数据id
+            $this->user['select'] = ['partition' => 'no', 'system_id' => 1, 'info_id' => 1, 'module_id' => 1, 'data_id' => 1];
+        }
+        $this->checkModule($this->user['select']['module_id']);
+        Dever::setData('muser', $this->user);
+    }
+
+    # 设置功能权限
+    public function getFunc($key, $name, $sort = 1, $param = '')
+    {
+
+        if (!$key) {
+            $key = md5(base64_encode($name));
+        }
+        /*
+        if ($param) {
+            if (is_array($param)) {
+                $param = Dever::json_encode($name);
+            }
+            $key = $key . '_' . md5($param);
+        }*/
+
+        if (!$this->menu) {
+            return false;
+        }
+        $data['menu_id'] = $this->menu['id'];
+        $data['key'] = $key;
+        $key = $key . $data['menu_id'];
+        if (isset($this->func[$key]['id'])) {
+            return $this->func[$key]['id'];
+        }
+        $this->func[$key] = Dever::db('manage/menu_func')->find($data);
+        $name = $this->menu['name'] . '-' . $name;
+        if (!$this->func[$key]) {
+            $data['name'] = $name;
+            $data['sort'] = $sort;
+            $id = Dever::db('manage/menu_func')->insert($data);
+            Dever::db('manage/menu')->update($this->menu['id'], ['func' => 1]);
+        } else {
+            /*
+            if ($info['name'] != $name) {
+                $data['name'] = $name;
+                $data['sort'] = $sort;
+                Dever::db('manage/menu_func')->update($info['id'], $data);
+                Dever::db('manage/menu')->update($this->menu['id'], ['func' => 1]);
+            }*/
+            $id = $this->func[$key]['id'];
+        }
+
+        if ($this->user['id'] == 1) {
+            return $id;
+        }
+        if ($this->user['auth']['func'] && strstr($this->user['auth']['func'], ',' . $id . ',')) {
+            return $id;
+        }
+        return false;
+    }
+
+    # 检测系统模块权限
+    protected function checkModule($module_id)
+    {
+        if ($this->user['id'] == 1) {
+            return;
+        }
+        if ($this->user['auth']['module'] && !Dever::check($this->user['auth']['module'], $module_id)) {
+            Dever::error('无系统权限');
+        }
+    }
+
+    # 检测菜单权限
+    protected function checkMenu($menu, $result = true)
+    {
+        if ($this->user['id'] == 1) {
+            if ($result) {
+                return false;
+            }
+            return;
+        }
+        if ($this->user['auth']['menu'] && !Dever::check($this->user['auth']['menu'], $menu)) {
+            if ($result) {
+                return true;
+            }
+            Dever::error('无菜单访问权限');
+        }
+        if ($result) {
+            return false;
+        }
+    }
+
+    # 检测功能权限
+    protected function checkFunc()
+    {
+        $id = Dever::input('func');
+        if (!$id) {
+            return false;
+        }
+        if ($this->user['id'] == 1) {
+            return $id;
+        }
+        if ($this->user['auth']['func'] && strstr($this->user['auth']['func'], ',' . $id . ',')) {
+            return $id;
+        }
+        if (isset($this->menu) && $this->menu && $this->menu['show'] != 1) {
+            return $id;
+        }
+        Dever::error('无操作权限');
+    }
+}

+ 16 - 0
app/Lib/Config.php

@@ -0,0 +1,16 @@
+<?php namespace Manage\Lib;
+use Dever;
+class Config extends Auth
+{
+    public function getTree()
+    {
+        $data = Dever::db('manage/config')->select([]);
+        $result = [];
+        $result[] = [
+            'id' => 'root',
+            'name' => '全部配置',
+            'children' => $data,
+        ];
+        return $result;
+    }
+}

+ 127 - 0
app/Lib/Data.php

@@ -0,0 +1,127 @@
+<?php namespace Manage\Lib;
+use Dever;
+# 配置一些常用的数据
+class Data
+{
+    public function getShortcuts($type)
+    {
+        if (strstr($type, 'range')) {
+            return [
+                [
+                    'text' => '今天',
+                    'func' => 'return [new Date(new Date().setHours(0,0,0,0)), new Date()]',
+                ],
+                [
+                    'text' => '昨天',
+                    'func' => 'const now = new Date(); const start = new Date(now.setDate(now.getDate() - 1)); start.setHours(0,0,0,0); const end = new Date(start); end.setHours(23,59,59,999); return [start, end]',
+                ],
+                [
+                    'text' => '本周',
+                    'func' => 'const now = new Date(); const day = now.getDay() || 7; const start = new Date(now); start.setDate(now.getDate() - day + 1); start.setHours(0,0,0,0); return [start, new Date()]',
+                ],
+                [
+                    'text' => '上周',
+                    'func' => 'const now = new Date(); const day = now.getDay() || 7; const end = new Date(now); end.setDate(now.getDate() - day); end.setHours(23,59,59,999); const start = new Date(end); start.setDate(end.getDate() - 6); start.setHours(0,0,0,0); return [start, end]',
+                ],
+                [
+                    'text' => '本月',
+                    'func' => 'const now = new Date(); const start = new Date(now.getFullYear(), now.getMonth(), 1); return [start, new Date()]',
+                ],
+                [
+                    'text' => '上月',
+                    'func' => 'const now = new Date(); const start = new Date(now.getFullYear(), now.getMonth() - 1, 1); const end = new Date(now.getFullYear(), now.getMonth(), 0); end.setHours(23,59,59,999); return [start, end]',
+                ],
+                [
+                    'text' => '最近7天',
+                    'func' => 'const start = new Date(); start.setDate(start.getDate() - 6); start.setHours(0,0,0,0); return [start, new Date()]',
+                ],
+                [
+                    'text' => '最近30天',
+                    'func' => 'const start = new Date(); start.setDate(start.getDate() - 29); start.setHours(0,0,0,0); return [start, new Date()]',
+                ],
+                [
+                    'text' => '最近90天',
+                    'func' => 'const start = new Date(); start.setDate(start.getDate() - 89); start.setHours(0,0,0,0); return [start, new Date()]',
+                ],
+                [
+                    'text' => '最近1年',
+                    'func' => 'const start = new Date(); start.setFullYear(start.getFullYear() - 1); start.setDate(start.getDate() + 1); start.setHours(0,0,0,0); return [start, new Date()]',
+                ],
+                [
+                    'text' => '本年',
+                    'func' => 'const now = new Date(); const start = new Date(now.getFullYear(), 0, 1); return [start, new Date()]',
+                ],
+                [
+                    'text' => '去年',
+                    'func' => 'const now = new Date(); const start = new Date(now.getFullYear() - 1, 0, 1); const end = new Date(now.getFullYear() - 1, 11, 31, 23, 59, 59, 999); return [start, end]',
+                ],
+            ];
+        } else {
+            return [
+                // --- 过去 ---
+                [
+                    'text' => '今天',
+                    'func' => 'return new Date()',
+                ],
+                [
+                    'text' => '昨天',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() - 1); return d',
+                ],
+                [
+                    'text' => '前天',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() - 2); return d',
+                ],
+                [
+                    'text' => '三天前',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() - 3); return d',
+                ],
+                [
+                    'text' => '五天前',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() - 5); return d',
+                ],
+                [
+                    'text' => '一周前',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() - 7); return d',
+                ],
+                [
+                    'text' => '一个月前',
+                    'func' => 'const d = new Date(); d.setMonth(d.getMonth() - 1); return d',
+                ],
+                [
+                    'text' => '一年前',
+                    'func' => 'const d = new Date(); d.setFullYear(d.getFullYear() - 1); return d',
+                ],
+
+                // --- 未来 ---
+                [
+                    'text' => '明天',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() + 1); return d',
+                ],
+                [
+                    'text' => '后天',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() + 2); return d',
+                ],
+                [
+                    'text' => '三天后',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() + 3); return d',
+                ],
+                [
+                    'text' => '五天后',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() + 5); return d',
+                ],
+                [
+                    'text' => '一周后',
+                    'func' => 'const d = new Date(); d.setDate(d.getDate() + 7); return d',
+                ],
+                [
+                    'text' => '一个月后',
+                    'func' => 'const d = new Date(); d.setMonth(d.getMonth() + 1); return d',
+                ],
+                [
+                    'text' => '一年后',
+                    'func' => 'const d = new Date(); d.setFullYear(d.getFullYear() + 1); return d',
+                ],
+            ];
+        }
+    }
+}

+ 76 - 0
app/Lib/Group.php

@@ -0,0 +1,76 @@
+<?php namespace Manage\Lib;
+use Dever;
+use Dever\Helper\Str;
+class Group extends Auth
+{
+    public function getTree()
+    {
+        $data = Dever::db('manage/group')->select([]);
+        $result = [];
+        $result[] = [
+            'id' => 'root',
+            'name' => '全部集团',
+            'children' => $data,
+        ];
+        return $result;
+    }
+
+    # 后续废弃,转移到system中
+    public function update($data)
+    {
+        if ($data['mobile']) {
+            $system = Dever::db('manage/system')->find(2);
+            $data['system_key'] = $system['key'];
+            $data['system_id'] = $system['id'];
+            $data['info_id'] = $data['id'];
+            $data['partition'] = $system['partition'];
+            $db = Dever::db($system['user_table'], 'default', Dever::load(Util::class)->system($data));
+            $info = $db->find(1);
+            if (!$info) {
+                $password = '123456';
+                $insert['name'] = Str::hide($data['mobile']);
+                $insert['mobile'] = $data['mobile'];
+                $insert['role'] = 1;
+                $insert += Dever::load(util::class)->createPwd($password);
+                $db->insert($insert);
+            }
+        }
+    }
+    
+    # 后续废弃,转移到system中
+    # 创建账户
+    public function createUser($module, $data_id, $name, $mobile, $password, $state = false)
+    {
+        if ($mobile && $password) {
+            $system = Dever::db('manage/system')->find(2);
+            $data['system_key'] = $system['key'];
+            $data['system_id'] = $system['id'];
+            $data['info_id'] = 1;
+            $data['partition'] = $system['partition'];
+            $db = Dever::db($system['user_table'], 'default', Dever::load(Util::class)->system($data));
+
+            $info = $db->find(['mobile' => $mobile]);
+            if ($state && $info) {
+                Dever::error('手机号' . $mobile . '已存在,请更换手机号');
+            }
+
+            $module = Dever::db('manage/system_module')->find(['key' => $module, 'system' => 'group']);
+            $insert['name'] = $name;
+            $insert['mobile'] = $mobile;
+            $insert['role'] = 2;
+            $insert['module_data'] = $module['id'] . '-' . $data_id;
+            if (!$info) {
+                $insert += Dever::load(Util::class)->createPwd($password);
+                $db->insert($insert);
+            } else {
+                $insert += Dever::load(Util::class)->createPwd($password);
+                $module_data = $insert['module_data'];
+                unset($insert['module_data']);
+                if (!strstr($info['module_data'], $module_data)) {
+                    $insert['module_data'] = $module_data . ',' . $info['module_data'];
+                }
+                $db->update($info['id'], $insert);
+            }
+        }
+    }
+}

+ 136 - 0
app/Lib/Menu.php

@@ -0,0 +1,136 @@
+<?php namespace Manage\Lib;
+use Dever;
+use Dever\Project;
+class Menu
+{
+    protected $icon;
+    # 初始化菜单
+    public function init($name = '')
+    {
+        echo 11;die;
+        $config = Dever::config('manage');
+        if ($config) {
+            $this->add('manage', $config);
+        }
+        if ($name) {
+            $app = array($name => Dever::get(Project::class)->load($name));
+        } else {
+            $app = Dever::get(Project::class)->read();
+        }
+        print_r($app);die;
+        foreach ($app as $k => $v) {
+            $base = $v['path'] . 'manage/core.php';
+            if (is_file($base)) {
+                $core = include $base;
+                if ($core) {
+                    $this->add($k, $core);
+                }
+            }
+        }
+        return 'ok';
+    }
+    private function add($app, $core)
+    {
+        if (isset($core['system'])) {
+            foreach ($core['system'] as $k => $v) {
+                $where = [];
+                $where['key'] = $k;
+                $data = $where;
+                $data['name'] = $v['name'];
+                $data['sort'] = $v['sort'];
+                $data['partition'] = $v['partition'] ?? 'no';
+                $data['info_table'] = $v['info_table'];
+                $data['user_table'] = $v['user_table'];
+                $data['role_table'] = $v['role_table'];
+                Dever::db('manage/system')->up($where, $data);
+            }
+        }
+        if (isset($core['module'])) {
+            foreach ($core['module'] as $k => $v) {
+                $where = [];
+                $where['key'] = $k;
+                $data = $where;
+                $data['name'] = $v['name'];
+                $data['sort'] = $v['sort'];
+                $data['system'] = $v['system'];
+                $data['data_table'] = $v['data_table'];
+                if (isset($v['data_where']) && $v['data_where']) {
+                    $data['data_where'] = Dever::json_encode($v['data_where']);
+                }
+                Dever::db('manage/system_module')->up($where, $data);
+            }
+        }
+        if (isset($core['menu'])) {
+            foreach ($core['menu'] as $k => $v) {
+                $where = [];
+                if (isset($v['app'])) {
+                    $app = $v['app'];
+                }
+                $where['app'] = $app;
+                $where['key'] = $k;
+                if (isset($v['parent'])) {
+                    $parent = Dever::db('manage/menu')->find(['key' => $v['parent']]);
+                    if ($parent) {
+                        $where['parent_id'] = $parent['id'];
+                        $where['module_id'] = $parent['module_id'];
+                        $where['level'] = 2;
+                        if ($parent['parent_id']) {
+                            $where['level'] = 3;
+                        }
+                    }
+                } else {
+                    $where['level'] = 1;
+                }
+                if (isset($v['module'])) {
+                    $module = Dever::db('manage/system_module')->find(['key' => $v['module']]);
+                    if ($module) {
+                        $where['module_id'] = $module['id'];
+                    }
+                }
+                $data = $where;
+                $data['name'] = $v['name'];
+                if (isset($v['icon']) && $v['icon']) {
+                    $data['icon'] = $v['icon'];
+                } else {
+                    # 随机抽取
+                    $data['icon'] = $this->getIcon();
+                }
+                $data['sort'] = $v['sort'];
+                if (isset($v['show'])) {
+                    $data['show'] = $v['show'];
+                }
+                if (isset($v['badge'])) {
+                    $data['badge'] = $v['badge'];
+                }
+                if (isset($v['path'])) {
+                    $data['path'] = $v['path'];
+                } else {
+                    $data['path'] = 'main';
+                }
+                if (isset($v['link'])) {
+                    $data['link'] = $v['link'];
+                }
+                Dever::db('manage/menu')->up($where, $data);
+            }
+        }
+    }
+    public function getAll()
+    {
+        $data = Dever::db('manage/menu')->select(['parent_id' => '0']);
+        return $data;
+    }
+
+    public function getIcon()
+    {
+        if (empty($this->icon)) {
+            $this->icon = Dever::db('manage/icon')->select([]);
+        }
+        $key = array_rand($this->icon, 1);
+        $icon = $this->icon[$key]['key'];
+        $info = Dever::db('manage/menu')->find(['icon' => $icon]);
+        if ($info) {
+            return $this->getIcon();
+        }
+        return $icon;
+    }
+}

+ 16 - 0
app/Lib/Module.php

@@ -0,0 +1,16 @@
+<?php namespace Manage\Lib;
+use Dever;
+class Module extends Auth
+{
+    public function getTree()
+    {
+        $data = Dever::db('manage/system_module')->select([]);
+        $result = [];
+        $result[] = [
+            'id' => 'root',
+            'name' => '系统模块',
+            'children' => $data,
+        ];
+        return $result;
+    }
+}

+ 873 - 0
app/Lib/Page.php

@@ -0,0 +1,873 @@
+<?php namespace Manage\Lib;
+use Dever;
+# 通用页面 项目着急上线 以后优化并封装
+class Page extends Auth
+{
+    protected $db;
+    protected $key;
+    protected $id = 0;
+    protected $input = false;
+    protected $recycler = false;
+    protected $menu = [];
+    protected $config = [];
+    protected $field = [];
+    public $info = [];
+    public function __construct($key = '', $load = '', $input = true, $config = [])
+    {
+        parent::__construct();
+        $this->key = $key;
+        $this->input = $input;
+        $this->id = $this->input('id', 0);
+        if (!$load) {
+            $load = Dever::input('load');
+        }
+        list($this->db, $this->menu) = Dever::load(Util::class)->db($load);
+        if ($this->menu && $this->menu['show'] == 1) {
+            $this->checkMenu($this->menu['id'], false);
+        }
+        $this->config = $this->db->config['manage'][$key] ?? $this->db->config['manage'];
+        if ($config) {
+            $this->config = array_merge($this->config, $config);
+        }
+        if ($this->id && !strstr($this->id, ',')) {
+            $this->info = $this->db->find($this->id);
+        }
+    }
+
+    public function setting($key, &$data, $struct = true, $type = 'show', $disable = false)
+    {
+        if (empty($this->config[$key]) && $struct && isset($this->db->config['struct']) && $this->db->config['struct']) {
+            $this->config[$key] = $this->db->config['struct'];
+        }
+        if (empty($this->config[$key])) {
+            return;
+        }
+        $setting = $this->config[$key];
+        if (is_string($setting)) {
+            $setting = explode(',', $setting);
+        }
+        $field = $this->input('field', '');
+        if ($field && is_string($field) && strstr($field, 'dever_')) {
+            $field = '';
+        }
+        return $this->setData($key, $setting, $data, $field, $type, $disable);
+    }
+
+    # 获取某个数据的具体展示值
+    public function getValue($key, $value, $data, $field = [])
+    {
+        if ($key == 'cdate') {
+            $this->db->config['manage']['update']['field'][$key]['type'] = 'date';
+        }
+        $update = $this->db->config['manage']['update']['field'] ?? [];
+        if ($show = Dever::issets($field, 'show')) {
+            $value = $this->getShow($show, $data);
+        } elseif ($value && isset($this->db->config['struct'][$key]['value']) && $this->db->config['struct'][$key]['value']) {
+            $value = $this->db->value($key, $value);
+        } elseif ($value && (isset($update[$key]) && isset($update[$key]['type']) && $update[$key]['type'] == 'date')) {
+            if (isset($update[$key]['date_type']) && $update[$key]['date_type'] == 'year') {
+                if ($update[$key]['date_type'] == 'year') {
+                    $value = date('Y', $value);
+                } elseif ($update[$key]['date_type'] == 'month') {
+                    $value = date('Ym', $value);
+                } else {
+                    $value = date('Ymd', $value);
+                }
+            } else {
+                if (strstr($value, 'T')) {
+                    $value = date('Y-m-d H:i:s', strtotime($value));
+                } elseif (is_numeric($value)) {
+                    $value = date('Y-m-d H:i:s', $value);
+                } else {
+                    $value = '-';
+                }
+            }
+        }
+        
+        return $value;
+    }
+
+    # 获取关联数据
+    public function getOther($key, $set, $data)
+    {
+        $where = $config = [];
+        if (isset($set['where'])) {
+            foreach ($set['where'] as $k => $v) {
+                if (!is_array($v) && isset($data[$v])) {
+                    $where[$k] = $data[$v];
+                } else {
+                    $where[$k] = $v;
+                }
+            }
+        }
+        if (isset($set['col'])) {
+            $config['col'] = $set['col'];
+        }
+        if ($where) {
+            return Dever::db($key)->select($where, $config);
+        }
+        return [];
+    }
+
+    public function getShow($show, $data, $state = false)
+    {
+        return \Dever\Helper\Str::val($show, $data, $state);
+    }
+
+    # 获取菜单标题
+    public function getTitle()
+    {
+        return $this->menu['name'];
+    }
+
+    # 获取左侧分栏
+    protected function column(&$data, $name = '左侧分栏')
+    {
+        $data['column'] = false;
+        if (isset($this->config['column'])) {
+            if (empty($this->config['column']['hidden'])) {
+                $data['column'] = $this->config['column'];
+                if (isset($this->config['column']['add'])) {
+                    $data['column']['add'] = array('name' => $this->config['column']['add'], 'func' => $this->getFunc('column_add', $name . '-' . $this->config['column']['add'], 101));
+                }
+                if (isset($this->config['column']['edit'])) {
+                    $data['column']['edit'] = array('name' => '编辑', 'func' => $this->getFunc('column_edit', $name . '-编辑', 102));
+                }
+                if (isset($this->config['column']['delete'])) {
+                    $data['column']['delete'] = array('name' => '删除', 'func' => $this->getFunc('column_delete', $name . '-删除', 103));
+                }
+                $data['column']['data'] = $this->config['column']['data'];
+                if (is_string($data['column']['data'])) {
+                    $data['column']['data'] = Dever::call($data['column']['data']);
+                }
+                $data['height'] = '100%';
+            }
+            
+            if (isset($this->config['column']['active']) && $this->config['column']['where'] == 'id') {
+                return $this->config['column']['active'];
+            }
+        }
+    }
+
+    # 通用的规则验证 一般为更新数据时使用
+    protected function checkRules($set, $data)
+    {
+        if ($set['rules']) {
+            if (!is_array($set['rules'])) {
+                $set['rules'] = array
+                (
+                    [
+                        'required' => true,
+                        'trigger' => 'blur',
+                        'message' => $set['name'] . '不能为空',
+                    ],
+                );
+            }
+            foreach ($set['rules'] as $k => $v) {
+                if (isset($v['required']) && $v['required'] && !$data && $data !== '0') {
+                    Dever::error($v['message']);
+                }
+                if ($data || $data === '0') {
+                    if (isset($v['pattern']) && $v['pattern'] && !preg_match('/' . $v['pattern'] . '/', $data)) {
+                        Dever::error($v['message']);
+                    }
+                    if (isset($v['type']) && $v['type']) {
+                        if ($v['type'] == 'number' && !is_numeric($data)) {
+                            Dever::error($v['message']);
+                        } elseif ($v['type'] == 'array' && !is_array($data)) {
+                            Dever::error($v['message']);
+                        } elseif ($v['type'] == 'integer' && !is_int($data)) {
+                            Dever::error($v['message']);
+                        } elseif ($v['type'] == 'float' && !is_float($data)) {
+                            Dever::error($v['message']);
+                        } elseif ($v['type'] == 'string' && !is_string($data)) {
+                            Dever::error($v['message']);
+                        } elseif ($v['type'] == 'boolean' && !is_bool($data)) {
+                            Dever::error($v['message']);
+                        } elseif ($v['type'] == 'url' && !filter_var($data, FILTER_VALIDATE_URL)) {
+                            Dever::error($v['message']);
+                        } elseif ($v['type'] == 'email' && !filter_var($data, FILTER_VALIDATE_EMAIL)) {
+                            Dever::error($v['message']);
+                        } elseif ($v['type'] == 'enum' && isset($v['enum']) && !in_array($data, $v['enum'])) {
+                            Dever::error($v['message']);
+                        }
+                    }
+                    if (isset($v['len']) && $v['len'] && strlen($data) > $v['len']) {
+                        Dever::error($v['message']);
+                    }
+                    if (isset($v['min']) && $v['min'] && strlen($data) < $v['min']) {
+                        Dever::error($v['message']);
+                    }
+                    if (isset($v['max']) && $v['max'] && strlen($data) > $v['max']) {
+                        Dever::error($v['message']);
+                    }
+                }
+            }
+        }
+    }
+
+    private function setData($key, $setting, &$data, $field, $type, $disable)
+    {
+        $result = [];
+        foreach ($setting as $k => $v) {
+            $this->setDefault($key, $k, $v);
+            if (!is_array($v)) {
+                if (is_numeric($k)) {
+                    $k = $v;
+                    $v = $type;
+                }
+                if ($k == 'id') {
+                    $v = ['name' => 'ID', 'type' => $v];
+                } elseif ($k == 'cdate') {
+                    $v = ['name' => '创建时间', 'type' => $v];
+                } elseif(isset($this->db->config['struct'][$k])) {
+                    $v = ['name' => $this->db->config['struct'][$k]['name'], 'type' => $v];
+                } else {
+                    $v = ['name' => $v];
+                }
+            } else {
+                if (isset($v['only'])) {
+                    if ($v['only'] == 'edit' && !$this->id) {
+                        continue;
+                    } elseif ($v['only'] == 'add' && $this->id) {
+                        continue;
+                    }
+                }
+            }
+            if ($field) {
+                if (is_string($field) && (strstr($field, '{') || strstr($field, '%7B'))) {
+                    $field = htmlspecialchars_decode($field);
+                    $field = Dever::json_decode($field);
+                }
+                if (is_array($field)) {
+                    if (isset($field['param'])) {
+                        if (isset($field['param']['set'])) {
+                            $field = array_merge($field, $field['param']['set']);
+                        }
+                        if (isset($field['param']['search'])) {
+                            $field = array_merge($field, $field['param']['search']);
+                        }
+                    } elseif (isset($field['field']) && !Dever::check($field['field'], $k)) {
+                        continue;
+                    }
+                    if (isset($field[$k]) && $field[$k] != $k) {
+                        $v['default'] = $field[$k];
+                        $v['type'] = 'hidden';
+                    }
+                } elseif (!Dever::check($field, $k)) {
+                    continue;
+                }
+            }
+            $info = $this->setField($data, $k, $v, $field, $type, $disable);
+            if ($info) {
+                $result[] = $info;
+            }
+        }
+        return $result;
+    }
+
+    private function setField(&$data, $key, $value, $field, $type = 'show', $disable = false)
+    {
+        if (empty($value['align'])) {
+            $value['align'] = 'center';
+        }
+        $value['key'] = $key;
+        $this->setName($value);
+        # 对每个字段进行权限设置
+        if (isset($value['func']) && $value['func']) {
+            $func = $this->getFunc('field_' . $value['key'], '字段-' . $value['name'], 200);
+            if (!$func) {
+                return false;
+            }
+        }
+        if (strpos($key, '/') && $this->key == 'update') {
+            $this->setType($value, 'table');
+            $this->setShow($value);
+            if (strpos($key, '#')) {
+                $key = str_replace('#', '', $key);
+            }
+            $sku = $value['type'] == 'sku' ? true : false;
+            $value['value'] = $this->getOther($key, $value, $this->info);
+            if (isset($value['default'])) {
+                $value['value'] += $value['default'];
+            }
+            if (isset($value['field'])) {
+                list($app, $table) = explode('/', $key);
+                $set = Dever::project($app);
+                $manage = @include($set['path'] . 'manage/'.$table.'.php');
+                if (isset($manage['update']['field'][$value['field']])) {
+                    $value = array_merge($value, $manage['update']['field'][$value['field']]);
+                }
+                if ($value['value']) {
+                    $data[$key . '_id'] = [
+                        'key' => $key . '_id',
+                        'type' => 'hidden',
+                        'value' => $value['value'][0]['id'],
+                    ];
+                    $value['value'] = $value['value'][0][$value['field']];
+                }
+                $this->setRules($value);
+                $this->setForm($value, $field);
+                $data[] = $value;
+                return $value['name'] ?? 'test';
+            }
+            $update = new \Manage\Api\Page\Update($key, false);
+            $value['option'] = [];
+            $value['content'] = $update->get($value['value'], $value['option'], $sku);
+            $data[] = $value;
+            return $value['name'];
+        } else {
+            $this->setType($value, $type);
+            $this->setDisable($value, $disable);
+            if ($this->key == 'update') {
+                # 一般为更新页面需要的参数
+                $this->setShow($value);
+                $this->setRules($value);
+            } elseif (isset($value['remote']) && !strstr($value['remote'], 'Dever')) {
+                $value['remote'] = Dever::url($value['remote']);
+            }
+            if ($type == 'show') {
+                if (!isset($value['truncate'])) {
+                    $value['truncate'] = false;
+                }
+                $in = ['switch', 'select', 'input'];
+                if (in_array($value['type'], $in)) {
+                    $value['func'] = $this->getFunc('list_edit_' . $value['key'], '列表更新-' . $value['name'], 104);
+                    if (!$value['func']) {
+                        $value['type'] = 'show';
+                        if (isset($value['show'])) {
+                            unset($value['show']);
+                        }
+                    }
+                }
+                if (isset($value['child'])) {
+                    $child = [];
+                    $this->setData($value['child'], $child, $field, $type, $disable);
+                    $value['child'] = $child;
+                } else {
+                    $this->field[$key] = $value;
+                }
+            }
+            $this->setForm($value, $field);
+            if (empty($value['width'])) {
+                $value['width'] = 'auto';
+                if ($this->key == 'update') {
+                    $fast = Dever::input('fast');
+                    $value['width'] = '50%';
+                    if (!$this->input || (empty($value['option']) && $fast == 1) || $value['type'] == 'editor') {
+                        $value['width'] = '100%';
+                    }
+                }
+            }
+            $data[] = $value;
+            return $value['name'] ?? 'test';
+        }
+    }
+
+    private function setDefault($key, &$k, &$v)
+    {
+        if ($v == 'cdate') {
+            $k = $v;
+            $v = [
+                'name' => '创建时间',
+                'type' => 'date',
+                'date_type' => 'datetimerange',
+                'value_format' => 'YYYY-MM-DD HH:mm:ss',
+                'start_placeholder' => '开始日期',
+                'end_placeholder' => '结束日期',
+                'range_separator' => '至',
+                'truncate' => true,
+            ];
+        } elseif ($v == 'sort') {
+            $k = $v;
+            $v = [
+                'type' => 'input',
+                'tip' => '双击修改,正序排序',
+                'width' => '90px',
+            ];
+        } elseif ($key != 'search' && $v == 'status') {
+            if (isset($this->db->config['struct']['status']['value']) && count($this->db->config['struct']['status']['value']) == 2) {
+                $k = $v;
+                $v = [
+                    'type' => 'switch',
+                    'show'  => '{status}',
+                    'active_value' => 1,
+                    'inactive_value' => 2,
+                    'width' => '75px',
+                ];
+            }
+        }
+    }
+
+    private function setShow(&$value)
+    {
+        if ($value['type'] == 'hidden') {
+            $value['show'] = false;
+        } elseif (!isset($value['show'])) {
+            $value['show'] = true;
+        }
+    }
+
+    private function setName(&$value)
+    {
+        if (empty($value['name']) && isset($this->db->config['struct'][$value['key']])) {
+            $value['name'] = $this->db->config['struct'][$value['key']]['name'];
+        }
+        if (empty($value['placeholder']) && isset($value['name'])) {
+            $value['placeholder'] = $value['name'];
+        }
+    }
+
+    private function setType(&$value, $type)
+    {
+        if (empty($value['type'])) {
+            $value['type'] = $type;
+        }
+        if (strpos($value['type'], '(')) {
+            $value['type'] = $type;
+        }
+        if (isset($value['upload']) && Dever::project('upload')) {
+            $upload = $this->getUpload($value['key']);
+            if (is_array($value['upload'])) {
+                $upload += $value['upload'];
+            } else {
+                $upload += ['id' => $value['upload']];
+            }
+            if (empty($upload['id'])) {
+                Dever::error('上传配置错误');
+            }
+            $value['config'] = Dever::load(\Upload\Lib\Save::class)->get($upload['id']);
+            $value['yun'] = false;
+            if ($value['config']['method'] == 2) {
+                $value['yun'] = true;
+            }
+            $value['url'] = Dever::url('upload/save.act', $upload, true);
+            $upload['wh'] = $value['wh'] ?? '500*500';
+            $value['set'] = Dever::url('image/manage.set', $upload, true);
+            if (isset($value['multiple']) && $value['multiple']) {
+                $value['limit'] = 10;
+            } else {
+                $value['limit'] = 1;
+            }
+        }
+        if (isset($value['editorMenu'])) {
+            $this->setEditorUpload($value, ['uploadImage', 'uploadVideo']);
+        }
+
+        if (isset($value['date_type']) && $value['date_type'] == 'datetimerange' && empty($value['default_time'])) {
+            $value['default_time'] = array(\Dever\Helper\Date::mktime(date('Y-m-d 00:00:00'))*1000, \Dever\Helper\Date::mktime(date('Y-m-d 23:59:59'))*1000);
+        }
+    }
+
+    protected function getUpload($key)
+    {
+        $upload['cate_id'] = 1;
+        $upload['group_key'] = $this->db->config['table'] . '-' . $key;
+        $upload['group_name'] = $this->db->config['name'];
+        $upload['user_token'] = Dever::load(Util::class)->getToken();
+        $upload['user_table'] = $this->user['table'];
+        $upload['user_id'] = $this->user['id'];
+        return $upload;
+    }
+
+    protected function setEditorUpload(&$value, $key)
+    {
+        $upload = $this->getUpload($value['key']);
+        foreach ($key as $k) {
+            if ($v = Dever::issets($value['editorMenu'], $k)) {
+                if (!is_array($v)) {
+                    $v = ['upload' => $v];
+                }
+                $upload['id'] = $v['upload'];
+                $v['server'] = Dever::url('upload/save.wangEditor', $upload, true);
+                if (empty($v['fieldName'])) {
+                    $v['fieldName'] = 'file';
+                }
+                $value['editorMenu'][$k] = $v;
+            }
+        }
+    }
+
+    private function setDisable(&$value, $disable)
+    {
+        if (isset($value['disable'])) {
+            $disable = $value['disable'];
+        }
+        $value['disable'] = $disable;
+    }
+
+    # 设置值
+    private function setForm(&$value, $field)
+    {
+        if (empty($value['value'])) {
+            $value['value'] = Dever::input('search')[$value['key']] ?? '';
+        }
+        # (float) 转换一下是为了前端select使用,必须是数字类型
+        # 这个比较特殊
+        if ($value['type'] == 'select_text') {
+            if ($value['value']) {
+                if (is_string($value['value'])) {
+                    $value['value'] = explode('|', $v['value']);
+                }
+                $value['value'][0] = (float) $value['value'][0];
+            } else {
+                $value['value'] = [1,''];
+            }
+        } elseif ($value['type'] == 'date') {
+            if (empty($value['shortcuts']) && isset($value['date_type'])) {
+                $value['shortcuts'] = Dever::load(Data::class)->getShortcuts($value['date_type']);
+            }
+        } elseif (is_array($value['value'])) {
+            foreach ($value['value'] as &$v) {
+                $v = (float) $v;
+            }
+        }
+        if (!$value['value']) {
+            if (isset($value['default']) && !strstr($value['default'], '{')) {
+                $value['value'] = $value['default'];
+            } elseif ($this->key == 'update' && isset($this->db->config['struct'][$value['key']]['default'])) {
+                $value['value'] = $this->db->config['struct'][$value['key']]['default'];
+            }
+        }
+        if (isset($value['option']) && $value['option']) {
+            $this->db->config['option'][$value['key']] = $value['option'];
+        }
+        if (isset($this->db->config['load'])) {
+            $send = $this->info;
+            $send['table'] = $this->db->config['load'];
+            if ($field && is_array($field)) {
+                $send += $field;
+            }
+            if ($option = $this->db->value($value['key'], false, 'id,name', $send)) {
+                if ($value['type'] == 'checkbox') {
+                    $value['value'] = $value['value'] ? explode(',', $value['value']) : [];
+                }
+                $value['option'] = $option;
+                if ($value['type'] == 'text') {
+                    $value['type'] = 'select';
+                }
+                if (empty($value['clearable'])) {
+                    $value['clearable'] = true;
+                }
+                if (isset($this->db->config['struct'][$value['key']]['type']) && !is_array($value['value']) && $value['value'] && !strstr($this->db->config['struct'][$value['key']]['type'], 'char')) {
+                    $value['value'] = (float) $value['value'];
+                }
+            }
+        }
+    }
+
+    private function setRules(&$value)
+    {
+        if (isset($value['rules']) && $value['rules']) {
+            if (!is_array($value['rules'])) {
+                $value['rules'] = array
+                (
+                    [
+                        'required' => true,
+                        'trigger' => 'blur',
+                        'message' => $value['name'] . '不能为空',
+                    ],
+                );
+            }
+            foreach ($value['rules'] as $k => $v) {
+                if (isset($v['only'])) {
+                    if ($v['only'] == 'edit' && !$this->id) {
+                        unset($value['rules'][$k]);
+                        break;
+                    } elseif ($v['only'] == 'add' && $this->id) {
+                        unset($value['rules'][$k]);
+                        break;
+                    }
+                }
+            }
+            if (!isset($value['rules'][0])) {
+                $value['rules'] = array_values($value['rules']);
+            }
+        }
+    }
+
+    protected function input($key, $value = '')
+    {
+        return $this->input ? Dever::input($key) : $value;
+    }
+
+    public function button($key = 'button', $data = [], $default = true)
+    {
+        if (empty($this->config[$key])) {
+            $num = 0;
+            if (isset($this->db->config['manage']['update']['field'])) {
+                $num = count($this->db->config['manage']['update']['field']);
+            } elseif (isset($this->db->config['struct']) && $this->db->config['struct']) {
+                $num = count($this->db->config['struct']);
+            }
+            $fast = 'fast';
+            if ($num > 8) {
+                $fast = '';
+            }
+            if ($key == 'button') {
+                $this->config[$key] = ['新增' => $fast . 'add'];
+            } elseif ($key == 'data_button') {
+                $this->config[$key] = ['编辑' => $fast . 'edit'];
+            } else {
+                $this->config[$key] = [];
+            }
+        }
+        $result = [];
+        $sort = 1;
+        foreach ($this->config[$key] as $k => $v) {
+            $d = '';
+            $p = '';
+            $i = '';
+            if (is_array($v)) {
+                if (isset($v[3]) && $data) {
+                    $d = $v[3];
+                    if (strstr($d, '{')) {
+                        $state = $this->getShow($d, $data, true);
+                    } else {
+                        parse_str($d, $t);
+                        $state = false;
+                        foreach ($t as $k1 => $v1) {
+                            if (isset($data[$k1])) {
+                                $v1 = explode(',', $v1);
+                                foreach ($v1 as $v2) {
+                                    if ($data[$k1] == $v2) {
+                                        $state = true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if (!$state) {
+                        continue;
+                    }
+                }
+                if (isset($v[2])) {
+                    $i = $v[2];
+                }
+                if (isset($v[1])) {
+                    $p = $v[1];
+                    # 针对数据隔离做单独的处理
+                    if (is_array($p) && isset($p['param']['set']['authorization'])) {
+                        $value = explode(',', $p['param']['set']['authorization']);
+                        if (empty($value[3])) {
+                            $value[3] = 0;
+                        }
+                        $p['param']['set']['authorization'] = Dever::load(Util::class)->setAuth($value[0], $value[1], $data[$value[2]] ?? $temvaluep[2], $data[$value[3]] ?? $value[3]);
+                    }
+                }
+                $v = $v[0];
+            }
+            if (strstr($v, 'add')) {
+                $icon = 'Plus';
+                $button = 'primary';
+            } elseif (strstr($v, 'edit')) {
+                $icon = 'Edit';
+                $button = 'primary';
+            } elseif (strstr($v, 'view')) {
+                $icon = 'View';
+                $button = '';
+            } elseif (strstr($v, 'drawer')) {
+                $icon = 'Drawer';
+                $button = '';
+            } elseif ($v == 'delete') {
+                if ($key == 'button') {
+                    if (isset($this->config['layout'])) {
+                        continue;
+                    }
+                    $this->config['selection'] = true;
+                }
+                $icon = 'Delete';
+                $button = 'danger';
+            } elseif ($v == 'recycle') {
+                if ($key == 'button') {
+                    if (isset($this->config['layout'])) {
+                        continue;
+                    }
+                    $this->config['selection'] = true;
+                }
+                $icon = 'Delete';
+                $button = 'danger';
+            } elseif ($v == 'oper') {
+                if ($key == 'button') {
+                    if (isset($this->config['layout'])) {
+                        continue;
+                    }
+                    $this->config['selection'] = true;
+                }
+                $icon = 'Notification';
+                $button = 'warning';
+            } elseif ($v == 'api') {
+                if ($key == 'button') {
+                    if (isset($this->config['layout'])) {
+                        continue;
+                    }
+                    $this->config['selection'] = true;
+                }
+                $p = Dever::url($p);
+                $icon = 'Notification';
+                $button = 'warning';
+            } elseif ($v == 'link') {
+                $icon = 'Link';
+                $button = 'success';
+                $p = $this->getShow($p, $data);
+            } elseif ($v == 'route') {
+                $icon = 'Link';
+                $button = 'success';
+            } elseif ($v == 'recover') {
+                $icon = 'CirclePlus';
+                $button = 'info';
+            } else {
+                continue;
+            }
+            # 权限验证
+            $sort++;
+            $func = $this->getFunc($v, $k, $sort, $p);
+            if ($this->menu && $this->menu['show'] == 1 && !$func) {
+                continue;
+            }
+            if ($i) {
+                $icon = $i;
+            }
+            if ($key == 'button' && $data) {
+                if (!$p) {
+                    $p = [];
+                }
+                $p += $data;
+            }
+            $result[] = [
+                'name' => $k,
+                'type' => $v,
+                'param' => $p,
+                'icon' => $icon,
+                'button' => $button,
+                'func' => $func,
+            ];
+            if (!$this->recycler && $v == 'recycle') {
+                $this->recycler = true;
+            }
+        }
+        return $result;
+    }
+
+    # 构造搜索
+    protected function search(&$where)
+    {
+        $search = Dever::input('search');
+        $set = Dever::input('set');
+        $list_search = $result = [];
+        $result['form'] = $result['field'] = $result['option'] = [];
+        $this->setting('search', $list_search, false, 'text');
+        if ($list_search) {
+            foreach ($list_search as $v) {
+                if ($v['type'] != 'hidden') {
+                    $result['form'][] = $v;
+                    if (is_numeric($v['value'])) {
+                        $v['value'] = (float) $v['value'];
+                    }
+                    $result['field'][$v['key']] = $v['value'];
+                    if ($v['type'] == 'sku') {
+                        $result['field'][$v['key'] . '_spec'] = [];
+                    }
+                    if (isset($v['option'])) {
+                        $result['option'][$v['key']] = $v['option'];
+                    }
+                }
+                $this->searchWhere($search, $v, $where);
+                $this->searchWhere($set, $v, $where);
+            }
+        }
+        return $result;
+    }
+
+    protected function searchWhere($value, $v, &$where)
+    {
+        if ($value) {
+            if ($value = Dever::issets($value, $v['key'])) {
+                if (isset($v['search'])) {
+                    if (is_callable($v['search'])) {
+                        $value = $v['search']($v['key'], $v['type'], $value);
+                    } elseif (is_array($v['search']) && isset($v['search']['table'])) {
+                        $v['search']['where'] = Dever::json_decode(str_replace('{value}', $value, Dever::json_encode($v['search']['where'])));
+                        $search = Dever::db($v['search']['table'])->select($v['search']['where'], $v['search']['set'] ?? []);
+                        $value = [];
+                        if ($search) {
+                            foreach ($search as $v1) {
+                                $value[] = $v1[$v['search']['field']];
+                            }
+                        }
+                        $value = implode(',', $value);
+                        $v['type'] = 'in';
+                        if (isset($v['search']['key'])) {
+                            $v['key'] = $v['search']['key'];
+                        }
+                    } else {
+                        $r = Dever::call($v['search'], [$value]);
+                        $v['key'] = $r[0];
+                        $v['type'] = $r[1];
+                        $value = $r[2];
+                    }
+                }
+                if ($v['type'] == 'select_text') {
+                    if ($value[1] === '') {
+                        return;
+                    }
+                    $result = current(array_filter($v['option'], function($item) use($value) {
+                        return $item['id'] == $value[0];
+                    }));
+                    if (!$result) {
+                        return;
+                    }
+                    $v['key'] = $result['value'];
+                    $v['type'] = '';
+                    if (strstr($v['key'], '.')) {
+                        $r = Dever::call($v['key'], $value[1]);
+                        if ($r) {
+                            $v['key'] = $r[0];
+                            $v['type'] = $r[1];
+                            $value = $r[2];
+                        }
+                    } else {
+                        if (strstr($v['key'], ' ')) {
+                            $temp = explode(' ', $v['key']);
+                            $v['key'] = $temp[0];
+                            $v['type'] = $temp[1];
+                        }
+                        $value = $value[1];
+                    }
+                }
+                if (isset($v['col'])) {
+                    $temp = explode(',', $v['col']);
+                    $value = explode(',', $value);
+                    foreach ($temp as $tk => $tv) {
+                        $where[$tv] = $value[$tk];
+                    }
+                } elseif ($v['type'] == 'group') {
+                    $where[$v['key']] = ['group', $value];
+                } elseif ($v['type'] == 'selects') {
+                    $where[$v['key']] = ['group', $value];
+                } elseif ($v['type'] == 'cascader') {
+                    $t = $value;
+                    if (is_array($value)) {
+                        $t = implode(',', $value);
+                    }
+                    $where[$v['key']] = ['group', $t];
+                    //$where[$v['key']] = $t;
+                    //print_r($where);die;
+                } elseif ($v['type'] == 'like') {
+                    $where[$v['key']] = ['like', $value];
+                } elseif ($v['type'] == 'in') {
+                    $where[$v['key']] = ['in', $value];
+                } elseif ($v['type'] == 'date') {
+                    if (strstr($v['date_type'], 'range')) {
+                        $where[$v['key']] = array('>=', \Dever\Helper\Date::mktime($value[0]));
+                        $where[$v['key'] . '#'] = array('<=', \Dever\Helper\Date::mktime($value[1]));
+                    } else {
+                        $where[$v['key']] = $value;
+                    }
+                } else {
+                    $where[$v['key']] = $value;
+                }
+            }
+        }
+    }
+}

+ 39 - 0
app/Lib/Recycler.php

@@ -0,0 +1,39 @@
+<?php namespace Manage\Lib;
+use Dever;
+class Recycler extends Auth
+{
+    # 获取后台展示需要的数据
+    public function getData($where)
+    {
+        if (empty($where['table'])) {
+            Dever::error('参数错误');
+        }
+        $data['head'] = $data['body'] = [];
+        $page = new Page('list', $where['table']);
+        $data['title'] = $page->getTitle() . '【回收站】';
+        $data['field'] = $page->setting('field', $data['head']);
+
+        $set['num'] = Dever::input('pgnum', '', '', 10);
+        list($db, $menu) = Dever::load(Util::Class)->db($where['table']);
+        $recycler = Dever::db('manage/recycler')->select(['table' => $db->config['load']], $set);
+        foreach ($recycler as $k => $v) {
+            $content = Dever::json_decode($v['content']);
+            foreach ($content as $key => $value) {
+                $content[$key] = $page->getValue($key, $value, $content);
+            }
+            $content['id'] = $v['id'];
+            $data['body'][] = $content;
+        }
+        if ($data['head']) {
+            $head = [];
+            foreach ($data['head'] as $k => $v) {
+                if ($v['type'] == 'show') {
+                    $head[] = $v;
+                }
+            }
+            $data['head'] = $head;
+        }
+
+        return $data;
+    }
+}

+ 91 - 0
app/Lib/Role.php

@@ -0,0 +1,91 @@
+<?php namespace Manage\Lib;
+use Dever;
+class Role extends Auth
+{
+    public function update($db, $data)
+    {
+        if ($data['auth']) {
+            $auth = explode(',', $data['auth']);
+            $data['auth'] = [];
+            $module = $menu = $func = [];
+            foreach ($auth as $k => $v) {
+                if (!strstr($v, '-')) {
+                    if (strstr($v, 'v')) {
+                        $menu[] = trim($v, 'v');
+                    } else {
+                        $func[] = $v;
+                    }
+                    $data['auth'][] = $v;
+                }
+            }
+            if ($func) {
+                $funcData = Dever::db('manage/menu_func')->select(array('id' => ['in', $func]), ['group' => 'menu_id']);
+                foreach ($funcData as $k => $v) {
+                    $menu[] = $v['menu_id'];
+                }
+                $menuData = Dever::db('manage/menu')->select(array('id' => ['in', $menu]), ['group' => 'module_id']);
+                foreach ($menuData as $k => $v) {
+                    $module[] = $v['module_id'];
+                }
+            }
+            $data['auth'] = implode(',', $data['auth']);
+            $data['menu'] = implode(',', $menu);
+            $data['module'] = implode(',', $module);
+        }
+        return $data;
+    }
+
+    public function getAuthData()
+    {
+        $result = [];
+        $extend = Dever::load(Util::class)->extend();
+        if ($extend && $extend['system_id']) {
+            $system_id = $extend['system_id'];
+        } else {
+            $system_id = 1;
+        }
+        $info = Dever::db('manage/system')->find($system_id);
+        $where = [];
+        $where['system'] = $info['key'];
+        $module = Dever::db('manage/system_module')->select($where);
+        foreach ($module as $k => $v) {
+            $result[$k]['value'] = 's-' . $v['id'];
+            $result[$k]['label'] = $v['name'];
+            $result[$k]['children'] = Dever::db('manage/menu')->tree(array('module_id' => $v['id'], 'show' => ['<', '3']), ['parent_id', '0', 'id'], [$this, 'getAuthInfo'], ['col' => 'id,name as label,parent_id,`key`,func']);
+        }
+        return $result;
+    }
+    public function getAuthInfo($k, $info)
+    {
+        if ($info['func'] == 1) {
+            $info['value'] = 'm-' . $info['id'];
+            $info['children'] = Dever::db('manage/menu_func')->select(['menu_id' => $info['id']], ['col' => 'id as value,name as label']);
+            if (!$info['children']) {
+                return [];
+            }
+        } else {
+            $info['value'] = 'v' . $info['id'];
+        }
+        return $info;
+    }
+    # 展示系统
+    public function showSystem($data)
+    {
+        return Dever::db('manage/system')->show(array('id' => ['in', $data]));
+    }
+    # 展示系统模块
+    public function showModule($data)
+    {
+        return Dever::db('manage/system_module')->show(array('id' => ['in', $data]));
+    }
+    # 展示菜单
+    public function showMenu($data)
+    {
+        return Dever::db('manage/menu')->show(array('id' => ['in', $data]));
+    }
+    # 展示权限
+    public function showFunc($data)
+    {
+        return Dever::db('manage/menu_func')->show(array('id' => ['in', $data]));
+    }
+}

+ 87 - 0
app/Lib/System.php

@@ -0,0 +1,87 @@
+<?php namespace Manage\Lib;
+use Dever;
+use Dever\Project;
+use Dever\Helper\Str;
+class System extends Auth
+{
+    public function getTree()
+    {
+        $data = Dever::db('manage/system')->select([]);
+        $result = [];
+        $result[] = [
+            'id' => 'root',
+            'name' => '全部系统',
+            'children' => $data,
+        ];
+        return $result;
+    }
+
+    # 创建管理员
+    public function update($system, $db, $data)
+    {
+        if (isset($data['mobile']) && $data['mobile']) {
+            $system = Dever::db('manage/system')->find(['key' => $system]);
+            $data['system_key'] = $system['key'];
+            $data['system_id'] = $system['id'];
+            $data['info_id'] = $data['id'];
+            $data['partition'] = $system['partition'];
+            $db = Dever::db($system['user_table'], '', true, 'default', Dever::load(Util::class)->system($data));
+            $info = $db->find(['mobile' => $data['mobile']]);
+            if (!$info) {
+                $password = '123456';
+                $insert['name'] = Str::hide($data['mobile']);
+                $insert['mobile'] = $data['mobile'];
+                $insert['role'] = 1;
+                $insert += Dever::load(Util::class)->createPwd($password);
+                $db->insert($insert);
+            }
+
+            $db = Dever::db($system['role_table'], '', true, 'default', Dever::load(Util::class)->system($data));
+            $info = $db->find(['id' => 1]);
+            if (!$info) {
+                $insert = [];
+                $insert['name'] = '超级管理员';
+                $db->insert($insert);
+            }
+        }
+    }
+
+    # 创建账户
+    public function createUser($data, $state = true)
+    {
+        if (isset($data['mobile']) && $data['mobile'] && isset($data['password']) && $data['password']) {
+            $info = Dever::db($data['table'])->find($data['id']);
+            if ($info) {
+                $system = Dever::db('manage/system')->find(['key' => $data['system']]);
+                $set['system_key'] = $system['key'];
+                $set['system_id'] = $system['id'];
+                $set['info_id'] = 1;
+                $set['partition'] = $system['partition'];
+                $db = Dever::db($system['user_table'], '', 'default', Dever::load(Util::class)->system($set));
+
+                $user = $db->find(['mobile' => $data['mobile']]);
+                if ($state && $user) {
+                    Dever::error('手机号' . $data['mobile'] . '已存在,请更换手机号');
+                }
+
+                $module = Dever::db('manage/system_module')->find(['key' => $data['module'], 'system' => 'group']);
+                $insert['name'] = $info['name'];
+                $insert['mobile'] = $data['mobile'];
+                $insert['role'] = 2;
+                $insert['module_data'] = $module['id'] . '-' . $info['id'];
+                $insert += Dever::load(Util::class)->createPwd($data['password']);
+                if (!$user) {
+                    $db->insert($insert);
+                } else {
+                    $module_data = $insert['module_data'];
+                    unset($insert['module_data']);
+                    if (!strstr($user['module_data'], $module_data)) {
+                        $insert['module_data'] = $module_data . ',' . $user['module_data'];
+                    }
+                    $db->update($user['id'], $insert);
+                }
+            }
+        }
+        return $data;
+    }
+}

+ 380 - 0
app/Lib/Test.php

@@ -0,0 +1,380 @@
+<?php namespace Manage\Lib;
+use Dever;
+use Dever\Helper\Str;
+use Dever\Helper\Env;
+use Dever\Helper\Secure;
+use Dever\Helper\Date;
+class Test
+{
+    # 仅为测试用
+    public function out($data)
+    {
+        $result = [];
+        $result['head'] = ['id', '姓名', '时间'];
+        $result['body'] = [];
+        foreach ($data['body'] as $k => $v) {
+            $result['body'][$k] = [$v['id'], $v['name'], $v['cdate']];
+        }
+        return $result;
+    }
+
+    # 仅为测试用,展示表格更多内容,类型参考diy.php
+    public function show($data)
+    {
+        $result['type'] = 'list';
+        $result['content'] = [
+            ['name'=>'标题', 'content'=>'内容'],
+            ['name'=>'标题', 'content'=>'内容'],
+            ['name'=>'标题', 'content'=>'内容'],
+        ];
+        return $result;
+    }
+
+    # 仅为测试用,展示表格更多内容
+    public function show2($data)
+    {
+        return ['name' => '查看详情', 'content' => $this->show($data)];
+    }
+
+    # 仅为测试用,展示详情,类型参考diy.php
+    public function view($page)
+    {
+        # 这里获取基本信息
+        //print_r($page->info);die;
+        $info[] = array
+        (
+            # 类型,info信息 desc描述 table表格,表格有head和body即可
+            /*
+            'type' => 'info',
+            'name' => '资源订单',
+            'info' => '订单',
+            # 右侧按钮
+            'button' => $button,
+            # 具体内容
+            'content' => [
+                ['name' => '订单状态', 'value' => '未完成'],
+                ['name' => '实际支付', 'value' => '¥ 15.00'],
+                ['name' => '支付方式', 'value' => '余额'],
+                ['name' => '支付时间', 'value' => '2025-06-03 06:46:15'],
+            ],*/
+
+            'type' => 'desc',
+            'name' => '基本信息',
+            # 每行展示数量
+            'column' => 4,
+            # 是否有边框
+            'border' => true,
+            # 排列方向:horizontal横向 vertical纵向
+            'direction' => 'horizontal',
+            # 右侧按钮
+            'button' => array
+            (
+                array
+                (
+                    'name' => '编辑',
+                    # fastedit、fastadd、oper、api、link、route,参数与list里的data_button一致,多了一个load,可以单独设置路由
+                    'type' => 'fastedit',
+                    'path' => 'platform/role',
+                    # 增加权限,第三个参数是排序,建议大一些
+                    //'func' => $page->getFunc('view_fastedit', '详情页-编辑角色', 1000),
+                    # 这里是按钮用到的参数数据
+                    'row' => [
+                        'id' => 1,
+                    ],
+                ),
+            ),
+            # 具体内容
+            'content' => array
+            (
+                [
+                    'name' => '标题',
+                    # 类型,text普通文本,tag标签,link链接,image图片 progress进度条 stat统计 timeline时间线 table表格
+                    'type' => 'text',
+                    'content' => '内容',
+                    # 样式primary success warning danger info exception
+                    'style' => 'primary',
+                ],
+                [
+                    'name' => '标题',
+                    'type' => 'tag',
+                    'content' => '内容',
+                    'style' => 'warning',
+                ],
+                [
+                    'name' => '标题',
+                    'type' => 'link',
+                    'content' => '内容',
+                ],
+                [
+                    'name' => '图片',
+                    'type' => 'image',
+                    'content' => 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
+                    # 'fill', 'contain', 'cover', 'none', 'scale-down'
+                    'fit' => 'fill',
+                ],
+                [
+                    'name' => '进度条',
+                    'type' => 'progress',
+                    'content' => '10',
+                    'style' => 'exception',
+                    'width' => '20',
+                    'inside' => true,
+                    # line dashboard 仪表盘 circle 圆形
+                    'show' => 'line',
+                    # 开启条纹
+                    'striped' => true,
+                    # 开启动画
+                    'indeterminate' => true,
+                ],
+                array
+                (
+                    'name' => '统计',
+                    'type' => 'stat',
+                    'content' => array
+                    (
+                        [
+                            # 一共24
+                            'span' => '6',
+                            'name' => '测试',
+                            'value' => '1000',
+                        ],
+                        [
+                            'span' => '6',
+                            'name' => '测试1',
+                            'value' => '1000',
+                        ],
+                        [
+                            'span' => '6',
+                            'name' => '测试2',
+                            'value' => '1000',
+                        ],
+                        [
+                            'span' => '6',
+                            'name' => '测试2',
+                            'value' => '1000',
+                        ],
+                    ),
+                ),
+
+                array
+                (
+                    'name' => '时间线',
+                    'type' => 'timeline',
+                    'content' => array
+                    (
+                        [
+                            'time' => '2020-10-11',
+                            'name' => '测试',
+                            'color' => '#0bbd87',
+                            'size' => 'large',
+                            'type' => 'primary',
+                            'hollow' => true,
+                        ],
+                        [
+                            'time' => '2020-10-11',
+                            'name' => '测试',
+                        ],
+                        [
+                            'time' => '2020-10-11',
+                            'name' => '测试',
+                        ],
+                        [
+                            'time' => '2020-10-11',
+                            'name' => '测试',
+                        ],
+                    ),
+                ),
+
+                array
+                (
+                    'name' => '表格',
+                    'type' => 'table',
+                    'border' => true,
+                    'height' => '200',
+                    'head' => array
+                    (
+                        [
+                            'key' => 'name',
+                            'name' => '姓名',
+                            'fixed' => 'fixed',
+                        ],
+                        [
+                            'key' => 'desc',
+                            'name' => '描述',
+                            'fixed' => 'fixed',
+                        ],
+                    ),
+                    'button' => array
+                    (
+                        [
+                            'name' => '编辑',
+                            'type' => 'fastedit',
+                            'load' => 'platform/role',
+                        ],
+                    ),
+                    'body' => array
+                    (
+                        [
+                            'id' => 1,
+                            'name' => 'test',
+                            'desc' => 'dfdf',
+                        ],
+                    ),
+                ),
+            ),
+        );
+
+        $info[] = array
+        (
+            'type' => 'table',
+            'name' => '表格信息',
+            'border' => true,
+            'height' => '200',
+            'head' => array
+            (
+                [
+                    'key' => 'name',
+                    'name' => '姓名',
+                    'fixed' => 'fixed',
+                ],
+                [
+                    'key' => 'desc',
+                    'name' => '描述',
+                    'fixed' => 'fixed',
+                ],
+            ),
+            'button' => array
+            (
+                array
+                (
+                    'name' => '编辑',
+                    'type' => 'fastedit',
+                    'load' => 'platform/role',
+                    # 增加权限,第三个参数是排序,建议大一些
+                    'func' => $page->getFunc('view_fastedit', '详情页-编辑角色', 1000),
+                ),
+            ),
+            'body' => array
+            (
+                [
+                    'id' => 1,
+                    'name' => 'test',
+                    'desc' => 'dfdf',
+                ],
+            ),
+        );
+        $tab = array
+        (
+            'active' => 'table1',
+            'content' => array
+            (
+                'table1' => [
+                    # 这里跟desc一样
+                    'name' => '标题',
+                    'type' => 'text',
+                    'content' => '内容',
+                    'style' => 'primary',
+                ],
+
+                'tab2' => array
+                (
+                    'name' => '表格',
+                    'type' => 'table',
+                    'border' => true,
+                    'height' => '200',
+                    'head' => array
+                    (
+                        [
+                            'key' => 'name',
+                            'name' => '姓名',
+                            'fixed' => 'fixed',
+                        ],
+                        [
+                            'key' => 'desc',
+                            'name' => '描述',
+                            'fixed' => 'fixed',
+                        ],
+                    ),
+                    'button' => array
+                    (
+                        [
+                            'name' => '编辑',
+                            'type' => 'fastedit',
+                            'load' => 'platform/role',
+                        ],
+                    ),
+                    'body' => array
+                    (
+                        [
+                            'id' => 1,
+                            'name' => 'test',
+                            'desc' => 'dfdf',
+                        ],
+                    ),
+                ),
+            )
+        );
+        return ['title' => '详情', 'info' => $info, 'tab' => $tab];
+    }
+
+    public function stat($where)
+    {
+        return array
+        (
+            [
+                # 一共24
+                'span' => '8',
+                'name' => '测试',
+                'value' => '1000',
+            ],
+            [
+                'span' => '8',
+                'name' => '测试1',
+                'value' => '1000',
+            ],
+            [
+                'span' => '8',
+                'name' => '测试2',
+                'value' => '1000',
+            ],
+        );
+    }
+
+    # 对diy页面进行赋值
+    public function getDiy($where, $data)
+    {
+        $data['name']['body'] = [
+            [
+                'id' => 1,
+                'name' => 'test',
+                'desc' => 'dfdf',
+            ],
+        ];
+        return $data;
+    }
+
+    # 获取过滤选项
+    public function getFilter($where)
+    {
+        $result = [];
+        $result[] = [
+            'name' => '全部',
+            'where' => [],
+        ];
+        $where['status'] = 1;
+        $count = Dever::db('source', 'place_order')->count($where);
+        $result[] = [
+            'name' => '待支付('.$count.')',
+            'where' => $where,
+        ];
+
+        $where['status'] = 2;
+        $count = Dever::db('source', 'place_order')->count($where);
+        $result[] = [
+            'name' => '待发货('.$count.')',
+            'where' => $where,
+        ];
+
+        return $result;
+    }
+}

+ 324 - 0
app/Lib/Util.php

@@ -0,0 +1,324 @@
+<?php namespace Manage\Lib;
+use Dever;
+use Dever\Helper\Str;
+use Dever\Helper\Env;
+use Dever\Helper\Secure;
+use Dever\Helper\Date;
+class Util
+{
+    # 获取后台传入的数据
+    public function request($col, $other = '')
+    {
+        $info = Dever::input(['field', 'set'])[$col] ?? 0;
+        if ($other && !$info) {
+            $info = Dever::input($other);
+        }
+        return $info;
+    }
+
+    # 快速生成tip
+    public function createTip($call)
+    {
+        $name = '-';
+        $content = [];
+        $call($name, $content);
+        $result['name'] = $name;
+        if ($content) {
+            $result['content'] = ['type' => 'line', 'content' => $content];
+        }
+        return $result;
+    }
+
+    # 加入cron
+    public function cron($name, $project, $api, $time = 3600)
+    {
+        $data = ['project' => $project, 'interface' => $api];
+        $info = Dever::db('manage/cron')->find($data);
+        if (!$info) {
+            $data['name'] = $name;
+            $data['ldate'] = time();
+            $data['time'] = 3600;
+            Dever::db('manage/cron')->insert($data);
+        }
+    }
+
+    # 快速使用tip里的content
+    public function getTip($data, $key)
+    {
+        return $data['content']['content'][$key]['content'] ?? '';
+    }
+
+    public function info()
+    {
+        $auth = $this->auth();
+        $system = Dever::db('manage/system')->find($auth['extend']['system_id']);
+        return Dever::db($system['user_table'])->find($auth['uid']);
+    }
+
+    public function auth()
+    {
+        $auth = Dever::input('authorization');
+        if ($auth) {
+            $auth = Str::decode($auth);
+        }
+        if (!$auth) {
+            $auth = Env::header('authorization');
+        }
+        if ($auth) {
+            $auth = str_replace('Bearer ', '', $auth);
+            Dever::session('auth', $auth);
+            $info = Secure::checkLogin($auth);
+            return $info;
+        }
+        return false;
+    }
+
+    # 获取当前的扩展数据
+    public function extend()
+    {
+        # 先从query的set中获取,这个不影响用户登录
+        $auth = $this->request('authorization');
+        if ($auth) {
+            $auth = Str::decode($auth);
+            $info = Secure::checkLogin($auth);
+            if ($info) {
+                return $info['extend'];
+            }
+        }
+        # 从登录里获取
+        $info = $this->auth();
+        if (!$info) {
+            $auth = Dever::session('auth');
+            if (!$auth) {
+                return false;
+            }
+            $info = Secure::checkLogin($auth);
+        }
+        if ($info && isset($info['extend'])) {
+            return $info['extend'];
+        }
+        return false;
+    }
+
+    # 获取页面类
+    public function page($load, $config = [], $key = 'list', $input = true)
+    {
+        $page = new Page($key, $load, $input, $config);
+        return $page;
+    }
+
+    # 获取当前使用的系统 一般为数据库隔离使用
+    public function system($info = false, $module = true, $field = false)
+    {
+        if (!$info) {
+            # 单独的数据库隔离,不影响当前登录状态
+            $info = $this->extend();
+        }
+        if ($info && isset($info['info_id']) && isset($info['partition'])) {
+            # 这里后续增加从数据库中获取
+            $value = $info['system_id'] . '_' . $info['info_id'];
+            $result = [];
+            if (strpos($info['partition'], '.')) {
+                $temp = explode('.', $info['partition']);
+                $result = $this->partition($result, $temp[0], $info['system_key'], $value);
+                if ($module && isset($info['data_id']) && $info['data_id']) {
+                    if ($temp[0] == $temp[1]) {
+                        $value .= '/' . $info['module_id'] . '_' . $info['data_id'];
+                        $result = $this->partition($result, $temp[0], $info['system_key'], $value);
+                    } else {
+                        $result = $this->partition($result, $temp[1], $info['system_key'], $info['module_id'] . '_' . $info['data_id']);
+                    }
+                }
+            } else {
+                $result = $this->partition($result, $info['partition'], $info['system_key'], $value);
+            }
+            if ($field) {
+                $result['field'] = Dever::call($field);
+            }
+            return $result;
+        }
+        return false;
+    }
+
+    # 设置数据隔离
+    private function partition(&$result, $type, $key, $value)
+    {
+        if ($type == 'field') {
+            $result[$type] = [
+                'type' => 'key',
+                'field' => $key,
+                'value' => $value,
+            ];
+        } elseif ($type == 'where') {
+            $result[$type] = [
+                $key => $value
+            ];
+        } else {
+            $result[$type] = $value;
+        }
+        return $result;
+    }
+
+    # 获取token需要用到的key
+    public function getToken()
+    {
+        $extend = $this->extend();
+        if ($extend) {
+            return implode('-', array_values($extend));
+        }
+        return '';
+    }
+
+    # 将token设置到route权限中,方便后续读取
+    # 系统、模块、模块账户、数据id
+    public function setAuth($system, $module_id, $info_id, $data_id = '')
+    {
+        if (is_string($system)) {
+            $system = Dever::db('manage/system')->find(['key' => $system]);
+        }
+        if (is_string($module_id)) {
+            $module_id = Dever::db('manage/system_module')->column(['key' => $module_id], 'id');
+        }
+        $token = $this->token(-1, '', $system['partition'], $system['key'], $system['id'], $info_id, $module_id, $data_id);
+        return Dever::get(\Dever\Route::class)->data['authorization'] = Secure::encode($token['token']);
+    }
+
+    # 生成token
+    public function token($uid, $mobile, $partition, $system_key, $system_id, $info_id, $module_id, $data_id)
+    {
+        $extend['partition'] = $partition;
+        $extend['system_key'] = $system_key;
+        $extend['system_id'] = $system_id;
+        $extend['info_id'] = $info_id;
+        $extend['module_id'] = $module_id;
+        $extend['data_id'] = $data_id;
+        if ($uid && $uid > 0) {
+            $select['uid'] = $uid;
+            $select['system_id'] = $system_id;
+            $select['info_id'] = $info_id;
+            $info = Dever::db('manage/system_user')->find($select);
+            $select += $extend;
+            if (!$info) {
+                Dever::db('manage/system_user')->insert($select);
+            } else {
+                Dever::db('manage/system_user')->update($info['id'], $select);
+            }
+        }
+        return array('token' => Secure::login($uid, $extend));
+    }
+
+    # 生成密码
+    public function createPwd($password)
+    {
+        $data['salt'] = Str::salt(8);
+        $data['password'] = $this->hash($password, $data['salt']);
+        return $data;
+    }
+
+    # 生成时间
+    public function crateDate($date)
+    {
+        return Date::mktime($date);
+    }
+
+    # hash加密
+    public function hash($password, $salt)
+    {
+        return hash('sha256', $password . $salt);
+    }
+
+    # 自动更新key
+    public function updateKey($db, $data)
+    {
+        if ($data['name'] && !$data['key']) {
+            if (Dever::project('pinyin')) {
+                $where = [];
+                if (isset($data['id']) && $data['id']) {
+                    $where['id'] = ['!=', $data['id']];
+                }
+                $data['key'] = Dever::load(\Pinyin\Lib\Convert::class)->getPinyin($data['name']);
+
+                # 检查是否存在
+                $where['key'] = $data['key'];
+                $info = $db->find($where);
+                if ($info) {
+                    $data['key'] .= '-' . date('YmdHis');
+                }
+            }
+        }
+        return $data;
+    }
+
+    # 设置联动
+    public function cascader($total, $func)
+    {
+        $total = Dever::input('total', 'is_numeric', '联动总数', $total);
+        $level = Dever::input('level', 'is_numeric', '联动级别', 1);
+        $parent = Dever::input('parent', 'isset', '联动ID', 0);
+        if ($parent < 0) {
+            Dever::error('error');
+        }
+        $data = $func($level, $parent);
+        if ($level >= $total) {
+            foreach ($data as &$v) {
+                $v['leaf'] = true;
+            }
+        }
+        $result['total'] = $total;
+        $result['list'] = $data;
+        return $result;
+    }
+
+    # 根据load获取db
+    public function db($load)
+    {
+        $menu = [];
+        $load = explode('/', ltrim($load, '/'));
+        if (isset($load[2])) {
+            $app = $load[1];
+            $table = $load[2];
+        } else {
+            $app = $load[0];
+            $table = $load[1];
+        }
+        $parent = Dever::db('manage/menu')->find(['key' => $app]);
+        if ($parent) {
+            $menu = Dever::db('manage/menu')->find(['parent_id' => $parent['id'], 'key' => $table]);
+            if ($menu) {
+                $app = $menu['app'];
+            }
+        }
+        $set = Dever::project($app);
+        $file = $set['path'] . 'manage/'.$table.'.php';
+        $manage = [];
+        if (is_file($file)) {
+            $manage = include $file;
+            if ($source = Dever::issets($manage, 'source')) {
+                if (strpos($source, '/')) {
+                    $source = explode('/', $source);
+                    $app = $source[0];
+                    $table = $source[1];
+                } else {
+                    $table = $source;
+                }
+            }
+        }
+        $db = Dever::db($app . '/' . $table);
+        $db->config['manage'] = $manage;
+        return [$db, $menu];
+    }
+
+    # 获取项目
+    public function project()
+    {
+        $result = [];
+        $app = Dever::get(\Dever\Project::class)->read();
+        foreach ($app as $k => $v) {
+            $result[] = [
+                'id' => $k,
+                'name' => $v['lang'] ?? $k,
+            ];
+        }
+        return $result;
+    }
+}