rabin 2 tháng trước cách đây
mục cha
commit
65d7a5624b
16 tập tin đã thay đổi với 1308 bổ sung468 xóa
  1. 167 0
      api/Console.php
  2. 13 80
      api/Page/Data.php
  3. 29 0
      api/Page/Diy.php
  4. 21 0
      api/Page/Pdf.php
  5. 5 2
      api/Page/Update.php
  6. 5 1
      api/Page/View.php
  7. 2 4
      lib/Auth.php
  8. 0 337
      lib/Common.php
  9. 127 0
      lib/Data.php
  10. 207 28
      lib/Page.php
  11. 373 0
      lib/Test.php
  12. 16 9
      manage/admin.php
  13. 9 0
      manage/core.php
  14. 322 0
      manage/diy.php
  15. 11 6
      manage/menu.php
  16. 1 1
      manage/recycler.php

+ 167 - 0
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);
+    }
+}

+ 13 - 80
api/Page/Data.php

@@ -50,6 +50,17 @@ class Data extends Page
                 $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);
@@ -68,6 +79,8 @@ class Data extends Page
         if (isset($this->config['stat'])) {
             $data['stat'] = Dever::call($this->config['stat'], [$where]);
         }
+        
+        $data['bodyButton'] = isset($this->config['data_button']) ? true : false;
         return $data;
     }
 
@@ -148,84 +161,4 @@ class Data extends Page
         }
         return $result;
     }
-
-    private 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'] != 'hidden1') {
-                    $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->where($search, $v, $where);
-                $this->where($set, $v, $where);
-            }
-        }
-        return $result;
-    }
-
-    private function where($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 (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'];
-                        }
-                    }
-                }
-                if ($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']] = ['like', $t];
-                } 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;
-                }
-            }
-        }
-    }
 }

+ 29 - 0
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]);
+        } 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;
+    }
+}

+ 21 - 0
api/Page/Pdf.php

@@ -0,0 +1,21 @@
+<?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]);
+        } else {
+            $data = $this->config;
+        }
+        return $data;
+    }
+}

+ 5 - 2
api/Page/Update.php

@@ -381,6 +381,9 @@ class Update extends Page
         $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();
@@ -437,7 +440,7 @@ class Update extends Page
                 }
                 $result = $this->start($id, $data);
                 if ($result == 'end') {
-                    return '操作成功';
+                    return ['msg' => '操作成功', 'upAdmin' => $this->config['upAdmin']];
                 }
                 if ($id) {
                     $info = $this->db->find($id);
@@ -460,7 +463,7 @@ class Update extends Page
             $this->other($id, $data, $other);
             $this->sku($id, $data, $sku);
             $this->end($id, $data);
-            return '操作成功';
+            return ['msg' => '操作成功', 'upAdmin' => $this->config['upAdmin']];
         }
     }
 

+ 5 - 1
api/Page/View.php

@@ -11,7 +11,11 @@ class View extends Page
     public function get()
     {
         $this->checkFunc();
-        $data = Dever::call($this->config, [$this]);
+        if (is_string($this->config)) {
+            $data = Dever::call($this->config, [$this]);
+        } else {
+            $data = $this->config;
+        }
         return $data;
     }
 }

+ 2 - 4
lib/Auth.php

@@ -10,7 +10,7 @@ class Auth
     protected $info;
     protected $func;
     public $data = [];
-    public function __construct($set = false)
+    public function __construct()
     {
         $info = Dever::load('common', 'manage')->auth();
         if (!$info && $this->login) {
@@ -61,9 +61,7 @@ class Auth
             $this->user['select'] = ['partition' => 'no', 'system_id' => 1, 'info_id' => 1, 'module_id' => 1, 'data_id' => 1];
         }
         $this->checkModule($this->user['select']['module_id']);
-        if ($set) {
-            Dever::$data['muser'] = $this->user;
-        }
+        Dever::$data['muser'] = $this->user;
     }
 
     # 设置功能权限

+ 0 - 337
lib/Common.php

@@ -260,341 +260,4 @@ class Common
         }
         return $result;
     }
-
-    # 仅为测试用
-    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;
-    }
-
-    # 仅为测试用,展示表格更多内容
-    public function show($data)
-    {
-        # 返回类型:string字符串,table表格,card卡片,desc描述,list列表
-        $result['type'] = 'string';
-        $result['content'] = 'ddddd';
-
-        $result['type'] = 'table';
-        $result['head'] = ['id' => 'id', 'name' => '姓名'];
-        $result['body'] = array
-        (
-            ['id' => '1', 'name' => 'test'],
-            ['id' => '2', 'name' => 'test2'],
-        );
-
-        $result['type'] = 'card';
-        $result['content'][] = array
-        (
-            'title' => '订单信息',
-            'shadow' => 'never',//always | never | hover
-            'content' => [
-                '1111',
-                '2222',
-            ], 
-        );
-
-        $result['type'] = 'list';
-        $result['content'] = array
-        (
-            ['日志类型', 'test'],
-            ['姓名', 'test1'],
-        );
-        return $result;
-    }
-
-    # 仅为测试用,展示详情
-    public function view($page)
-    {
-        # 这里获取基本信息
-        //print_r($page->info);die;
-        $info[] = array
-        (
-            # 类型,desc描述 table表格,表格有head和body即可
-            'type' => 'desc',
-            'name' => '基本信息',
-            # 每行展示数量
-            'column' => 4,
-            # 是否有边框
-            'border' => true,
-            # 排列方向:horizontal横向 vertical纵向
-            'direction' => 'vertical',
-            # 右侧按钮
-            '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 ['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',
-            ],
-        );
-    }
 }

+ 127 - 0
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',
+                ],
+            ];
+        }
+    }
+}

+ 207 - 28
lib/Page.php

@@ -25,7 +25,7 @@ class Page extends Auth
         if ($this->menu && $this->menu['show'] == 1) {
             $this->checkMenu($this->menu['id'], false);
         }
-        $this->config = $this->db->config['manage'][$key] ?? [];
+        $this->config = $this->db->config['manage'][$key] ?? $this->db->config['manage'];
         if ($config) {
             $this->config = array_merge($this->config, $config);
         }
@@ -50,7 +50,7 @@ class Page extends Auth
         if ($field && is_string($field) && strstr($field, 'dever_')) {
             $field = '';
         }
-        return $this->setData($setting, $data, $field, $type, $disable);
+        return $this->setData($key, $setting, $data, $field, $type, $disable);
     }
 
     # 获取某个数据的具体展示值
@@ -109,9 +109,9 @@ class Page extends Auth
         return [];
     }
 
-    public function getShow($show, $data)
+    public function getShow($show, $data, $state = false)
     {
-        return \Dever\Helper\Str::val($show, $data);
+        return \Dever\Helper\Str::val($show, $data, $state);
     }
 
     # 获取菜单标题
@@ -206,10 +206,11 @@ class Page extends Auth
         }
     }
 
-    private function setData($setting, &$data, $field, $type, $disable)
+    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;
@@ -267,6 +268,9 @@ class Page extends Auth
 
     private function setField(&$data, $key, $value, $field, $type = 'show', $disable = false)
     {
+        if (empty($value['align'])) {
+            $value['align'] = 'center';
+        }
         $value['key'] = $key;
         $this->setName($value);
         # 对每个字段进行权限设置
@@ -323,8 +327,8 @@ class Page extends Auth
                 $value['remote'] = Dever::url($value['remote']);
             }
             if ($type == 'show') {
-                if (!isset($value['tip'])) {
-                    $value['tip'] = false;
+                if (!isset($value['truncate'])) {
+                    $value['truncate'] = false;
                 }
                 $in = ['switch', 'select', 'input'];
                 if (in_array($value['type'], $in)) {
@@ -350,6 +354,39 @@ class Page extends Auth
         }
     }
 
+    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' => '75px',
+            ];
+        } elseif ($key != 'search' && $v == 'status') {
+            $k = $v;
+            $v = [
+                'type' => 'switch',
+                'show'  => '{status}',
+                'active_value' => 1,
+                'inactive_value' => 2,
+                'width' => '75px',
+            ];
+        }
+    }
+
     private function setShow(&$value)
     {
         if ($value['type'] == 'hidden') {
@@ -379,6 +416,13 @@ class Page extends Auth
         }
         if (empty($value['width'])) {
             $value['width'] = 'auto';
+            if ($this->key == 'update') {
+                $fast = Dever::input('fast');
+                $value['width'] = '50%';
+                if ($fast == 1) {
+                    $value['width'] = '100%';
+                } 
+            }
         }
         if (isset($value['upload']) && Dever::project('upload')) {
             $upload = $this->getUpload($value['key']);
@@ -450,12 +494,28 @@ class Page extends Auth
         $value['disable'] = $disable;
     }
 
+    # 设置值
     private function setForm(&$value)
     {
         if (empty($value['value'])) {
             $value['value'] = Dever::input('search')[$value['key']] ?? '';
         }
-        if (is_array($value['value'])) {
+        # (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'])) {
+                $value['shortcuts'] = Dever::load('data', 'manage')->getShortcuts($value['date_type']);
+            }
+        } elseif (is_array($value['value'])) {
             foreach ($value['value'] as &$v) {
                 $v = (float) $v;
             }
@@ -470,18 +530,20 @@ class Page extends Auth
         if (isset($value['option']) && $value['option']) {
             $this->db->config['option'][$value['key']] = $value['option'];
         }
-        $send = $this->info;
-        $send['table'] = $this->db->config['load'];
-        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 (!is_array($value['value']) && $value['value']) {
-                $value['value'] = (float) $value['value'];
+        if (isset($this->db->config['load'])) {
+            $send = $this->info;
+            $send['table'] = $this->db->config['load'];
+            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 (!is_array($value['value']) && $value['value']) {
+                    $value['value'] = (float) $value['value'];
+                }
             }
         }
     }
@@ -549,14 +611,18 @@ class Page extends Auth
             if (is_array($v)) {
                 if (isset($v[3]) && $data) {
                     $d = $v[3];
-                    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 (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;
+                                    }
                                 }
                             }
                         }
@@ -582,6 +648,9 @@ class Page extends Auth
             } 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'])) {
@@ -622,6 +691,7 @@ class Page extends Auth
             } elseif ($v == 'link') {
                 $icon = 'Link';
                 $button = 'success';
+                $p = $this->getShow($p, $data);
             } elseif ($v == 'route') {
                 $icon = 'Link';
                 $button = 'success';
@@ -654,4 +724,113 @@ class Page extends Auth
         }
         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 (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'];
+                        }
+                    }
+                }
+                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 ($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']] = ['like', $t];
+                } 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;
+                }
+            }
+        }
+    }
 }

+ 373 - 0
lib/Test.php

@@ -0,0 +1,373 @@
+<?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;
+    }
+
+    # 仅为测试用,展示表格更多内容
+    public function show($data)
+    {
+        # 返回类型:string字符串,table表格,card卡片,desc描述,list列表
+        $result['type'] = 'string';
+        $result['content'] = 'ddddd';
+
+        $result['type'] = 'table';
+        $result['head'] = ['id' => 'id', 'name' => '姓名'];
+        $result['body'] = array
+        (
+            ['id' => '1', 'name' => 'test'],
+            ['id' => '2', 'name' => 'test2'],
+        );
+
+        $result['type'] = 'card';
+        $result['content'] = array();
+        $result['content'][] = array
+        (
+            'title' => '订单信息',
+            'shadow' => 'never',//always | never | hover
+            'content' => [
+                '1111',
+                '2222',
+            ], 
+        );
+
+        $result['type'] = 'list';
+        $result['content'] = array
+        (
+            ['日志类型', 'test'],
+            ['姓名', 'test1'],
+        );
+        return $result;
+    }
+
+    # 仅为测试用,展示表格更多内容
+    public function show2($data)
+    {
+        return ['name' => '查看详情', 'content' => $this->show($data)];
+    }
+
+    # 仅为测试用,展示详情
+    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',
+            ],
+        );
+    }
+
+    # 自定义页面
+    public function diy($data = [])
+    {
+        # 里面的类型参考diy.php
+        return $result;
+    }
+}

+ 16 - 9
manage/admin.php

@@ -38,7 +38,7 @@ return [
             'mobile' => [
                 'sort' => true,
                 # 多余字符按照...提示
-                'tip' => true,
+                'truncate' => true,
             ],
             'role',
             /*
@@ -47,11 +47,12 @@ return [
                 //'show' => 'Dever::db("role", "manage")->find("{id}")["name"]',
                 # 气泡卡片展示
                 'type' => 'popover',
-                # title
-                'title' => '查看更多',
                 # 位置:top/top-start/top-end/bottom/bottom-start/bottom-end/left/left-start/left-end/right/right-start/right-end
                 'location' => 'right',
-                'show' => 'Dever::load("common")->show("{role}")',
+                # 是否用标签形式展示
+                'tag' => true,
+                # 返回一个数组['name' => '', 'content' => []],这样可以展示多条[['name' => '', 'content' => []]]
+                'show' => 'Dever::load("common")->show2("{role}")',
             ],*/
             'status' => [
                 'type' => 'switch',
@@ -134,7 +135,7 @@ return [
             //'彻底删除' => 'delete',
             //'操作' => ['oper', 'role'],
             //'接口操作' => ['api', 'api'],
-            //'详情' => ['view', 'platform/admin?type=view&id=id'],
+            //'详情' => ['view', 'platform/admin?type=view&id=id'],//view可以改成drawer,在本页右侧出现
             //'链接跳转' => ['link', 'https://www.baidu.com/'],
             # 第三个参数可以自定义图标:https://element-plus.org/zh-CN/component/icon.html#icon-collection
             # 第四个参数是判断是否展示该按钮,字段名=字段值& 如name=1&id=2
@@ -162,6 +163,8 @@ return [
     
     # 更新页配置
     'update' => [
+        # 更新后是否更新后台用户登录信息,用于修改后台常用的配置
+        'upAdmin' => true,
         # 更新页描述
         'desc' => '',
         # 自定义标签 支持分栏
@@ -212,7 +215,7 @@ return [
                 # 是否支持多选
                 'multiple' => false,
                 # 提示
-                'tip' => '2222',
+                'truncate' => '2222',
                 # 展示类型 默认为list 列表 input 可输入地址 pic图片模式
                 'style' => 'pic',
                 # 裁剪时的默认宽度高度
@@ -303,6 +306,7 @@ return [
             cascader:级联选择器,可以做地区等
             select:选择器
             select_tree:选择器,多选的树形模式
+            select_text:选择器+文本
             set:
             clearable:是否可清空选择,true/false
             multiple:开启多选,true/false
@@ -327,11 +331,11 @@ return [
             set:
             disable_func:禁止选择方法,需要根据不同的date_type实现不同的方法,默认为不能选择今天之后的日期:return time.getTime() > Date.now()
             format:格式化展示,YYYY-MM-DD,参考:https://day.js.org/docs/en/display/format#list-of-all-available-formats
-            shortcuts:默认展示的日期,值如:
+            shortcuts:默认展示的日期,如果没有填写则会吐出默认值,值如:
             [
                 [
                     'text' => '今天',
-                    'func' => 'return new Date()',
+                    'func' => 'return new Date()',//这里是js代码,怎么弄找ai要就行
                 ],
             ],
             start_placeholder:开始日期文字描述
@@ -465,5 +469,8 @@ return [
     ],
 
     # 详情页配置
-    'view' => 'common.view',
+    'view' => 'manage/common.view',
+
+    # 自定义页配置
+    //'diy1' => 'manage/test.diy',
 ];

+ 9 - 0
manage/core.php

@@ -70,6 +70,15 @@ return [
             'badge'     => 'test.badge',
         ],
 
+        /*
+        'admin_diy' => [
+            'parent'    => 'platform',
+            'name'      => '自定义页面',
+            'sort'      => '6',
+            'path'      => 'diy',
+        ],
+        */
+
         'role' => [
             'parent'    => 'platform',
             'name'      => '角色管理',

+ 322 - 0
manage/diy.php

@@ -0,0 +1,322 @@
+<?php
+# 自定义页面,还缺搜索、分页、按钮等,这里也支持定义'diy' => 'manage/test.diy',参考view
+
+# type:table、chart、stat、trend、data、desc、info、timeline、progress、image、link、tag、text、button
+$config['layout'] = [
+    [
+        'data1' => 6,
+        'data2' => 6,
+        'data3' => 6,
+        'data4' => 6,
+    ],
+    [
+        'name' => 12,//这里也支持不同屏幕的,用数组[xs,sm,md,lg,xl]
+        'test' => 12,
+    ],
+    [
+        'chart' => 8,
+        'stat' => 8,
+        'timeline' => 8,
+    ],
+];
+
+$config['name'] = [
+
+    # 类型
+    'type' => 'table',
+
+    # 比view页面多出了header和footer
+    # 头部信息
+    'header' => [
+        'left' => '左侧标题',
+        'left_icon' => 'alert-line',
+        'left_tips' => '提示',
+        'right' => '右侧标题',
+        # 右侧样式
+        'right_type' => 'success',
+    ],
+    
+    # 尾部信息,同头部信息
+    'footer' => [
+        'left' => '左侧',
+        'right' => '右侧',
+        # 右侧样式
+        'right_type' => 'success',
+    ],
+
+    # 中间内容设置 这里和manage/test.view一致
+    'name' => '',
+    'border' => false,
+    'height' => 'auto',
+
+    'head' => array
+    (
+        [
+            'key' => 'name',
+            'name' => '姓名',
+            'fixed' => 'fixed',
+        ],
+        [
+            'key' => 'desc',
+            'name' => '描述',
+            'fixed' => 'fixed',
+        ],
+    ),
+    'button' => array
+    (
+        array
+        (
+            'name' => '编辑',
+            'type' => 'fastedit',
+            'load' => 'platform/role',
+        ),
+    ),
+    'body' => array
+    (
+        [
+            'id' => 1,
+            'name' => 'test',
+            'desc' => 'dfdf',
+        ],
+    ),
+];
+
+$config['test'] = [
+
+    # 类型
+    'type' => 'table',
+
+    # 比view页面多出了header和footer
+    # 头部信息
+    'header' => [
+        'left' => '左侧标题',
+        'left_icon' => 'alert-line',
+        'left_tips' => '提示',
+        'right' => '当前版本:V16.6.0   部署时间:2025-06-13 17:34:17',
+        # 右侧样式
+        'right_type' => 'success',
+    ],
+    
+    # 尾部信息,同头部信息
+    'footer' => [
+        'left' => '左侧',
+        'right' => '右侧',
+        # 右侧样式
+        'right_type' => 'success',
+    ],
+
+    # 中间内容设置 这里和manage/test.view一致
+    'name' => '',
+    'border' => false,
+    'height' => 'auto',
+
+    'head' => array
+    (
+        [
+            'key' => 'name',
+            'name' => '姓名',
+            'fixed' => 'fixed',
+        ],
+        [
+            'key' => 'desc',
+            'name' => '描述',
+            'fixed' => 'fixed',
+        ],
+    ),
+    'button' => array
+    (
+        array
+        (
+            'name' => '编辑',
+            'type' => 'fastedit',
+            'load' => 'platform/role',
+        ),
+    ),
+    'body' => array
+    (
+        [
+            'id' => 1,
+            'name' => 'test',
+            'desc' => 'dfdf',
+        ],
+    ),
+];
+
+$config['stat'] = [
+
+    # 类型
+    'type' => 'stat',
+
+    # 比view页面多出了header和footer
+    # 头部信息
+    'header' => [
+        'left' => '趋势',
+    ],
+
+    'name' => '统计',
+    '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,
+        ],
+    ),
+];
+
+$config['timeline'] = [
+
+    # 类型
+    'type' => 'stat',
+
+    # 比view页面多出了header和footer
+    # 头部信息
+    'header' => [
+        'left' => '趋势',
+    ],
+
+    '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' => '测试',
+        ],
+    ),
+];
+$config['chart'] = [
+
+    # 类型
+    'type' => 'chart',
+
+    # 比view页面多出了header和footer
+    # 头部信息
+    'header' => [
+        'left' => '趋势',
+    ],
+
+    # 中间内容设置 这里和manage/test.view一致
+    'height' => '300',
+
+    # echarts配置
+    'initOptions' => [
+        'renderer' => 'svg',
+    ],
+    'option' => [
+        'tooltip' => [
+            'trigger' => 'item',
+        ],
+        'series' => [
+            [
+                'name' => '访问来源',
+                'type' => 'pie',
+                'radius' => ['50%', '70%'],
+                'itemStyle' => [
+                    'borderRadius' => 10,
+                    'borderColor' => '#fff',
+                    'borderWidth' => 2,
+                ],
+                'emphasis' => [
+                    'label' => [
+                        'show' => true,
+                    ],
+                ],
+                'data' => [
+                    ['value' => 1048, 'name' => '搜索引擎'],
+                    ['value' => 735,  'name' => '直接访问'],
+                    ['value' => 580,  'name' => '邮件营销'],
+                    ['value' => 484,  'name' => '联盟广告'],
+                    ['value' => 300,  'name' => '视频广告'],
+                ],
+            ]
+        ]
+    ]
+];
+
+$config['data1'] = [
+
+    # 趋势
+    'type' => 'trend',
+    'name' => '总销量',
+    'icon' => 'album-line',
+    'number' => [
+        # 展示的值
+        'value' => 1000,
+        # 从零开始
+        'start' => 0,
+        # 前缀
+        'prefix' => '¥',
+        # 后缀
+        'suffix' => '',
+        # 间隔符
+        'separator' => '',
+        # 时间间隔
+        'duration' => 8000,
+    ],
+    'bottom' => [
+        'left' => '自上周以来',
+        'right' => '10%',
+        'right_icon' => 'arrow-up-line',
+        'right_type' => 'success',
+    ],
+];
+
+$config['data2'] = [
+
+    # 数据
+    'type' => 'data',
+    'name' => '订单销售额',
+    'icon' => 'album-line',
+    'number' => [
+        # 展示的值
+        'value' => 1000,
+        # 从零开始
+        'start' => 0,
+        # 前缀
+        'prefix' => '¥',
+        # 后缀
+        'suffix' => '',
+        # 间隔符
+        'separator' => '',
+        # 时间间隔
+        'duration' => 8000,
+    ],
+    # 渐变背景颜色 浅色
+    'bg1' => '#e4ecff',
+    # 渐变背景颜色 深色
+    'bg2' => '#4d7cfe',
+];
+return $config;

+ 11 - 6
manage/menu.php

@@ -25,14 +25,19 @@ return [
         ],
         # 展示的字段
         'field'      => [
-            'name' => [
-                'width' => '300',
+            'name',
+            'key' => [
+                'width' => '120px',
             ],
-            'key',
             //'path',
-            'icon' => 'icon',
-            'sort' => 'input',
-            'show',
+            'icon' => [
+                'type' => 'icon',
+                'width' => '75px',
+            ],
+            'sort',
+            'show' => [
+                'width' => '100px',
+            ],
             /*
             'show' => [
                 # 行中修改 仅支持switch、select、input,太复杂的咱就别在行中修改了吧

+ 1 - 1
manage/recycler.php

@@ -2,7 +2,7 @@
 return [
     'list' => [
         # 设置数据来源
-        'data'      => 'recycler.getData', 
+        'data'      => 'manage/recycler.getData', 
         'search'    => [
             'table' => 'hidden',
         ],