*/ class Builder extends ZBuilder { /** * @var string 当前模型名称 */ private $_module = ''; /** * @var string 当前控制器名称 */ private $_controller = ''; /** * @var string 当前操作名称 */ private $_action = ''; /** * @var string 数据表名 */ private $_table_name = ''; /** * @var string 插件名称 */ private $_plugin_name = ''; /** * @var string 模板路径 */ private $_template = ''; /** * @var array 要替换的右侧按钮内容 */ private $_replace_right_buttons = []; /** * @var bool 有分页数据 */ private $_has_pages = true; /** * @var array 存储字段筛选选项 */ private $_filter_options = []; /*** * @var array 存储字段筛选列表 */ private $_filter_list = []; /** * @var array 存储字段筛选类型 */ private $_filter_type = []; /** * @var array 列名 */ private $_field_name = []; /** * @var array 存储搜索框数据 */ private $_search = []; /** * @var array 顶部下拉菜单默认选项集合 */ private $_select_list_default = []; /** * @var array 行class */ private $_tr_class = []; /** * @var int 前缀模式:0-不含表前缀,1-含表前缀,2-使用模型 */ private $_prefix = 1; /** * @var mixed 表格原始数据 */ private $data; /** * @var array 使用原始数据的字段 */ protected $rawField = []; /** * @var array 模板变量 */ private $_vars = [ 'page_title' => '', // 页面标题 'page_tips' => '', // 页面提示 'tips_type' => '', // 提示类型 'tab_nav' => [], // 页面Tab导航 'hide_checkbox' => false, // 是否隐藏第一列多选 'extra_html' => '', // 额外HTML代码 'extra_js' => '', // 额外JS代码 'extra_css' => '', // 额外CSS代码 'order_columns' => [], // 需要排序的列表头 'filter_columns' => [], // 需要筛选功能的列表头 'filter_map' => [], // 字段筛选的排序条件 '_field_display' => [], // 字段筛选的默认选项 '_filter_content' => [], // 字段筛选的默认选中值 '_filter' => [], // 字段筛选的默认字段名 'top_buttons' => [], // 顶部栏按钮 'right_buttons' => [], // 表格右侧按钮 'search' => [], // 搜索参数 'search_button' => false, // 搜索按钮 'columns' => [], // 表格列集合 'pages' => '', // 分页数据 'row_list' => [], // 表格数据列表 '_page_info' => '', // 分页信息 'primary_key' => 'id', // 表格主键名称 '_table' => '', // 表名 'js_list' => [], // js文件名 'css_list' => [], // css文件名 'validate' => '', // 快速编辑的验证器名 '_js_files' => [], // js文件 '_css_files' => [], // css文件 '_select_list' => [], // 顶部下拉菜单列表 '_filter_time' => [], // 时间段筛选 'empty_tips' => '暂无数据', // 没有数据时的提示信息 '_search_area' => [], // 搜索区域 '_search_area_url' => '', // 搜索区域url '_search_area_op' => '', // 搜索区域匹配方式 'builder_height' => 'fixed', // 表格高度 'fixed_right_column' => 0, // 固定右边列数量 'fixed_left_column' => 0, // 固定左边列数量 'column_width' => [], // 列宽度 'column_hide' => [], // 隐藏列 ]; /** * 初始化 * @author 蔡伟明 <314013107@qq.com> */ public function initialize() { $this->_module = $this->request->module(); $this->_controller = parse_name($this->request->controller()); $this->_action = $this->request->action(); $this->_table_name = strtolower($this->_module.'_'.$this->_controller); $this->_template = Env::get('app_path'). 'common/builder/table/layout.html'; // 默认加载快速编辑所需js和css $this->_vars['_js_files'][] = 'editable_js'; $this->_vars['_css_files'][] = 'editable_css'; } /** * 模板变量赋值 * @param mixed $name 要显示的模板变量 * @param string $value 变量的值 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function assign($name, $value = '') { if (is_array($name)) { $this->_vars = array_merge($this->_vars, $name); } else { $this->_vars[$name] = $value; } return $this; } /** * 设置页面标题 * @param string $page_title 页面标题 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setPageTitle($page_title = '') { if ($page_title != '') { $this->_vars['page_title'] = $page_title; } return $this; } /** * 隐藏第一列多选框 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function hideCheckbox($status = true) { $this->_vars['hide_checkbox'] = $status; return $this; } /** * 设置页面提示 * @param string $tips 提示信息 * @param string $type 提示类型:success/info/warning/danger,默认info * @param string $pos 提示位置:top,button * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setPageTips($tips = '', $type = 'info', $pos = 'top') { if ($tips != '') { $this->_vars['page_tips_'.$pos] = $tips; $this->_vars['tips_type'] = $type != '' ? trim($type) : 'info'; } return $this; } /** * 添加顶部下拉框 * @param string $name 表单名,即name值 * @param string $title 第一个下来菜单项标题,不写则不显示 * @param array $options 表单项内容,传递数组形式,如:array([2015] => '2015年', [2016] => '2016年') * @param string $default 默认选项,初始化时,默认选中的菜单项 * @param string $ignore 生成url时,需要忽略的参数,用于有父子关系的下拉菜单,比如省份和地区,省份URL不应该带有地区参数的, * 所以可以在定义省份下拉菜单时,传入地区的下拉列表名, * 如需忽略多个参数,用逗号隔开 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addTopSelect($name = '', $title = '', $options = [], $default = '', $ignore = '') { if ($name != '') { $this->_vars['_select_list'][$name] = [ 'name' => $name, 'title' => $title, 'options' => $options, 'ignore' => $ignore, 'current' => '', ]; if ($default != '') { $this->_select_list_default[$name] = $default; } $this->_vars['_js_files'][] = 'select2_js'; $this->_vars['_css_files'][] = 'select2_css'; $this->_vars['_js_init'][] = 'select2'; } return $this; } /** * 添加表头排序 * @param array|string $column 表头排序字段,多个以逗号隔开 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addOrder($column = []) { if (!empty($column)) { $column = is_array($column) ? $column : explode(',', $column); $this->_vars['order_columns'] = array_merge($this->_vars['order_columns'], $column); } return $this; } /** * 添加表头筛选 * @param array|string $columns 表头筛选字段,多个以逗号隔开 * @param array $options 选项,供有些字段值需要另外显示的,比如字段值是数字,但显示的时候是其他文字。 * @param array $default 默认选项,['字段名' => '字段值,字段值...'] * @param string $type 筛选类型,默认为CheckBox,也可以是radio * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addFilter($columns = [], $options = [], $default = [], $type = 'checkbox') { if (!empty($columns)) { $columns = is_array($columns) ? $columns : explode(',', $columns); $this->_vars['filter_columns'] = array_merge($this->_vars['filter_columns'], $columns); // 存储对应的字段选项 if (!empty($options) && is_array($options)) { foreach ($columns as $key => $column) { if (is_numeric($key)) { if (strpos($column, '.')) { $column = explode('.', $column)[1]; } cache('filter_options_'.$column, $options); $this->_filter_options[$column] = 'filter_options_'.$column; } else { cache('filter_options_'.$key, $options); $this->_filter_options[$key] = 'filter_options_'.$key; } } } // 处理默认选项和值 if (!empty($default) && is_array($default)) { foreach ($default as $display => $content) { if (strpos($display, '|')) { list($display, $filter) = explode('|', $display); } else { $filter = $display; } if (strpos($display, '.')) { $display = explode('.', $display)[1]; } $this->_vars['_field_display'][] = $display; $this->_vars['_filter'][] = $filter; $this->_vars['_filter_content'][] = is_array($content) ? implode(',', $content) : $content; } } // 处理筛选类型 foreach ($columns as $column) { $this->_filter_type[$column] = $type; } } return $this; } /** * 添加表头筛选列表 * @param string $field 表头筛选字段 * @param array $list 需要显示的列表 * @param string $default 默认值,一维数组或逗号隔开的字符串 * @param string $type 筛选类型,默认为CheckBox,也可以是radio * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addFilterList($field = '', $list = [], $default = '', $type = 'checkbox') { if ($field != '' && !empty($list)) { $this->_vars['filter_columns'][] = $field; $this->_filter_type[$field] = $type; $this->_filter_list[$field] = md5('_filter_list_'.$this->_module.'_'.$this->_controller.'_'.$this->_action.'_'.session('user_auth.uid').'_'.$field); Cache::set($this->_filter_list[$field], $list); // 处理默认选项和值 if ($default != '') { $this->_vars['_field_display'][] = $field; $this->_vars['_filter'][] = $field; $this->_vars['_filter_content'][] = is_array($default) ? implode(',', $default) : $default; } } return $this; } /** * 添加表头筛选条件 * @param string $fields 字段名,多个可以用逗号隔开 * @param array $map 查询条件 * @author caiweiming <314013107@qq.com> * @return $this */ public function addFilterMap($fields = '', $map = []) { if ($fields != '') { if (is_array($fields)) { $this->_vars['filter_map'] = array_merge($this->_vars['filter_map'], $fields); } else { $map = $this->buildFilterMap($map); if (strpos($fields, ',')) { $fields = explode(',', $fields); foreach ($fields as $field) { if (isset($this->_vars['filter_map'][$field])) { $this->_vars['filter_map'][$field] = array_merge($this->_vars['filter_map'][$field], $map); } else { $this->_vars['filter_map'][$field] = $map; } } } else { if (isset($this->_vars['filter_map'][$fields])) { $this->_vars['filter_map'][$fields] = array_merge($this->_vars['filter_map'][$fields], $map); } else { $this->_vars['filter_map'][$fields] = $map; } } } } return $this; } /** * 组合筛选条件 * @param string $map 筛选条件 * @author 蔡伟明 <314013107@qq.com> * @return array */ private function buildFilterMap($map = '') { if (is_array($map)) return $map; $_map = []; $_filter = $this->request->param('_filter'); $_filter = explode('|', $_filter); $_pos = array_search($map, $_filter); if ($_pos !== false) { $_filter_content = $this->request->param('_filter_content'); $_filter_content = explode('|', $_filter_content); if (strpos($map, '.')) { $_field = explode('.', $map)[1]; } else { $_field = $map; } $_map[] = isset($_filter_content[$_pos]) ? [$_field, 'in', $_filter_content[$_pos]] : [$_field, 'eq', '']; } return $_map; } /** * 时间段过滤 * @param string $field 字段名 * @param string|array $date 默认的开始日期和结束日期 * @param string|array $tips 开始日期和结束日期的提示 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addTimeFilter($field = '', $date = '', $tips = '') { if ($field != '') { $date_start = ''; $date_end = ''; $tips_start = '开始日期'; $tips_end = '结束日期'; if (!empty($date)) { if (!is_array($date)) { if (strpos($date, ',')) { list($date_start, $date_end) = explode(',', $date); } else { $date_start = $date_end = $date; } } else { list($date_start, $date_end) = $date; } } if (!empty($tips)) { if (!is_array($tips)) { if (strpos($tips, ',')) { list($tips_start, $tips_end) = explode(',', $tips); } else { $tips_start = $tips_end = $tips; } } else { list($tips_start, $tips_end) = $tips; } } $this->_vars['_js_files'][] = 'datepicker_js'; $this->_vars['_css_files'][] = 'datepicker_css'; $this->_vars['_js_init'][] = 'datepicker'; $this->_vars['_filter_time'] = [ 'field' => $field, 'tips_start' => $tips_start, 'tips_end' => $tips_end, 'date_start' => $date_start, 'date_end' => $date_end, ]; } return $this; } /** * 添加快捷编辑的验证器 * @param string $validate 验证器名 * @param string $fields 要验证的字段,多个用逗号隔开,并且在验证器中要定义该字段名对应的场景 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addValidate($validate = '', $fields = '') { if ($validate != '') { $this->_vars['validate'] = $validate; $this->_vars['validate_fields'] = $fields; } return $this; } /** * 替换右侧按钮 * @param array $map 条件,格式为:['字段名' => '字段值', '字段名' => '字段值'....] * @param string $content 要替换的内容 * @param null $target 要替换的目标按钮 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function replaceRightButton($map = [], $content = '', $target = null) { if (!empty($map)) { $maps = []; $target = is_string($target) ? explode(',', $target) : $target; if (is_callable($map)) { $maps[] = [$map, $content, $target]; } else { foreach ($map as $key => $value) { if (is_array($value)) { $op = strtolower($value[0]); switch ($op) { case '=': $op = 'eq'; break; case '<>': $op = 'neq'; break; case '>': $op = 'gt'; break; case '<': $op = 'lt'; break; case '>=': $op = 'egt'; break; case '<=': $op = 'elt'; break; case 'in': case 'not in': case 'between': case 'not between': $value[1] = is_array($value[1]) ? $value[1] : explode(',', $value[1]); break; } $maps[] = [$key, $op, $value[1]]; } else { $maps[] = [$key, 'eq', $value]; } } } $this->_replace_right_buttons[] = [ 'maps' => $maps, 'content' => $content, 'target' => $target ]; } return $this; } /** * 自动创建新增页面 * @param array $items 表单项 * @param string $table 表名 * @param string $validate 验证器名 * @param string $auto_time 自动添加时间,默认有两个create_time和update_time * @param string $format 时间格式 * @param bool $pop 弹窗显示 * @author caiweiming <314013107@qq.com> * @return $this */ public function autoAdd($items = [], $table = '', $validate = '', $auto_time = '', $format = '', $pop = false) { if (!empty($items)) { // 默认属性 $btn_attribute = [ 'title' => '新增', 'icon' => 'fa fa-plus-circle', 'class' => 'btn btn-primary'.($pop === true ? ' pop' : ''), 'href' => url( $this->_module.'/'.$this->_controller.'/add' ).($pop === true ? '?_pop=1' : ''), ]; // 判断当前用户是否有权限,没有权限则不生成按钮 if (session('user_auth.role') != 1 && substr($btn_attribute['href'], 0, 4) != 'http' && $btn_attribute['href'] != 'javascript:history.back(-1);') { if ($this->checkButtonAuth($btn_attribute) === false) { return $this; } } // 缓存名称 $cache_name = strtolower($this->_module.'/'.$this->_controller.'/add'); // 自动插入时间 if ($auto_time != '') { $auto_time = $auto_time === true ? ['create_time', 'update_time'] : explode(',', $auto_time); } // 表单缓存数据 $form = [ 'items' => $items, 'table' => $table == '' ? strtolower($this->_module . '_' . $this->_controller) : $table, 'validate' => $validate === true ? ucfirst($this->_controller) : $validate, 'auto_time' => $auto_time, 'format' => $format, 'go_back' => $this->request->server('REQUEST_URI') ]; // 开发模式 if (config('develop_mode')) { Cache::set($cache_name, $form); } if (!Cache::get($cache_name)) { Cache::set($cache_name, $form); } // 添加到按钮组 $this->_vars['top_buttons'][] = $btn_attribute; } return $this; } /** * 获取默认url * @param string $type 按钮类型:add/enable/disable/delete * @param array $params 参数 * @author 蔡伟明 <314013107@qq.com> * @return string */ private function getDefaultUrl($type = '', $params = []) { $url = $this->_module.'/'.$this->_controller.'/'.$type; $MenuModel = new Menu(); $menu = $MenuModel->where('url_value', $url)->find(); if ($menu['params'] != '') { $url_params = explode('&', trim($menu['params'], '&')); if (!empty($url_params)) { foreach ($url_params as $item) { list($key, $value) = explode('=', $item); $params[$key] = $value; } } } if (!empty($params) && config('url_common_param')) { $params = array_filter($params, function($v){return $v !== '';}); } return $menu['url_type'] == 'module_home' ? home_url($url, $params) : url($url, $params); } /** * 添加一个顶部按钮 * @param string $type 按钮类型:add/enable/disable/back/delete/custom * @param array $attribute 按钮属性 * @param bool $pop 是否使用弹出框形式 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addTopButton($type = '', $attribute = [], $pop = false) { if ($type == '') { return $this; } // 表单名,用于替换 if (isset($attribute['table'])) { if (isset($attribute['prefix'])) { $table_token = $this->createTableToken($attribute['table'], $attribute['prefix']); } else { $table_token = $this->createTableToken($attribute['table'], $this->_prefix); } } else { $table_token = '__table__'; } // 自定义字段 $field = isset($attribute['field']) ? $attribute['field'] : ''; // 这个专门为插件准备的属性,是插件名称 $plugin_name = isset($attribute['plugin_name']) ? $attribute['plugin_name'] : $this->_plugin_name; switch ($type) { // 新增按钮 case 'add': // 默认属性 $btn_attribute = [ 'title' => '新增', 'icon' => 'fa fa-plus-circle', 'class' => 'btn btn-primary', 'href' => $this->getDefaultUrl($type, ['plugin_name' => $plugin_name]) ]; break; // 启用按钮 case 'enable': // 默认属性 $btn_attribute = [ 'title' => '启用', 'icon' => 'fa fa-check-circle-o', 'class' => 'btn btn-success ajax-post confirm', 'target-form' => 'ids', 'href' => $this->getDefaultUrl($type, ['_t' => $table_token, 'field' => $field]) ]; break; // 禁用按钮 case 'disable': // 默认属性 $btn_attribute = [ 'title' => '禁用', 'icon' => 'fa fa-ban', 'class' => 'btn btn-warning ajax-post confirm', 'target-form' => 'ids', 'href' => $this->getDefaultUrl($type, ['_t' => $table_token, 'field' => $field]) ]; break; // 返回按钮 case 'back': // 默认属性 $btn_attribute = [ 'title' => '返回', 'icon' => 'fa fa-reply', 'class' => 'btn btn-info', 'href' => 'javascript:history.back(-1);' ]; break; // 删除按钮(不可恢复) case 'delete': // 默认属性 $btn_attribute = [ 'title' => '删除', 'icon' => 'fa fa-times-circle-o', 'class' => 'btn btn-danger ajax-post confirm', 'target-form' => 'ids', 'href' => $this->getDefaultUrl($type, ['_t' => $table_token]) ]; break; // 自定义按钮 default: // 默认属性 $btn_attribute = [ 'title' => '定义按钮', 'class' => 'btn btn-default', 'target-form' => 'ids', 'href' => 'javascript:void(0);' ]; break; } // 合并自定义属性 if ($attribute && is_array($attribute)) { $btn_attribute = array_merge($btn_attribute, $attribute); } // 判断当前用户是否有权限,没有权限则不生成按钮 if (session('user_auth.role') != 1 && substr($btn_attribute['href'], 0, 4) != 'http' && $btn_attribute['href'] != 'javascript:history.back(-1);') { if ($this->checkButtonAuth($btn_attribute) === false) { return $this; } } // 是否为弹出框方式 if ($pop !== false) { $btn_attribute['class'] .= ' pop'; $btn_attribute['href'] .= (strpos($btn_attribute['href'], '?') ? '&' : '?').'_pop=1'; if (is_array($pop) && !empty($pop)) { $btn_attribute['data-layer'] = json_encode($pop); } } $this->_vars['top_buttons'][] = $btn_attribute; return $this; } /** * 检查是否有按钮权限 * @param array $btn_attribute 按钮属性 * @author 蔡伟明 <314013107@qq.com> * @return bool */ private function checkButtonAuth($btn_attribute = []) { if (preg_match('/\/(index.php|'.ADMIN_FILE.')\/(.*)/', $btn_attribute['href'], $match)) { $url_value = explode('/', $match[2]); if (strpos($url_value[2], '.')) { $url_value[2] = substr($url_value[2], 0, strpos($url_value[2], '.')); } $url_value = $url_value[0].'/'.$url_value[1].'/'.$url_value[2]; $url_value = strtolower($url_value); return Role::checkAuth($url_value, true); } return true; } /** * 一次性添加多个顶部按钮 * @param array|string $buttons 按钮类型 * 例如: * $builder->addTopButtons('add'); * $builder->addTopButtons('add,delete'); * $builder->addTopButtons(['add', 'delete']); * $builder->addTopButtons(['add' => ['table' => '__USER__'], 'delete']); * * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addTopButtons($buttons = []) { if (!empty($buttons)) { $buttons = is_array($buttons) ? $buttons : explode(',', $buttons); foreach ($buttons as $key => $value) { if (is_numeric($key)) { $this->addTopButton($value); } else { $this->addTopButton($key, $value); } } } return $this; } /** * 自动创建编辑页面 * @param array $items 表单项 * @param string $table 表名 * @param string $validate 验证器名 * @param string $auto_time 自动添加时间,默认有两个create_time和update_time * @param string $format 时间格式 * @param bool $pop 弹窗显示 * @param array $extra 额外参数,设置按钮样式 * @author caiweiming <314013107@qq.com> * @return $this */ public function autoEdit($items = [], $table = '', $validate = '', $auto_time = '', $format = '', $pop = false, $extra = []) { if (!empty($items)) { // 按钮样式 $btn_style = array_merge(config('zbuilder.right_button'), $extra); // 默认属性 $btn_attribute = [ 'title' => '编辑', 'icon' => 'fa fa-pencil', 'class' => 'btn btn-'.$btn_style['size'].' btn-'.$btn_style['style'].($pop === true ? ' pop' : ''), 'href' => url( $this->_module.'/'.$this->_controller.'/edit', ['id' => '__id__'] ), 'target' => '_self', '_style' => $btn_style ]; // 是否弹窗显示 if ($pop === true) { $btn_attribute['href'] .= (strpos($btn_attribute['href'], '?') ? '&' : '?').'_pop=1'; } // 判断当前用户是否有权限,没有权限则不生成按钮 if (session('user_auth.role') != 1 && substr($btn_attribute['href'], 0, 4) != 'http') { if ($this->checkButtonAuth($btn_attribute) === false) { return $this; } } // 缓存名称 $cache_name = strtolower($this->_module.'/'.$this->_controller.'/edit'); // 自动插入时间 if ($auto_time != '') { $auto_time = $auto_time === true ? ['update_time'] : explode(',', $auto_time); } // 表单缓存数据 $form = [ 'items' => $items, 'table' => $table == '' ? strtolower($this->_module . '_' . $this->_controller) : $table, 'validate' => $validate === true ? ucfirst($this->_controller) : $validate, 'auto_time' => $auto_time, 'format' => $format, 'go_back' => $this->request->server('REQUEST_URI') ]; // 开发模式 if (config('develop_mode')) { Cache::set($cache_name, $form); } if (!Cache::get($cache_name)) { Cache::set($cache_name, $form); } // 添加到按钮组 $this->_vars['right_buttons'][] = $btn_attribute; } return $this; } /** * 创建表名Token * @param string $table 表名 * @param int $prefix 前缀类型:0使用Db类(不添加表前缀),1使用Db类(添加表前缀),2使用模型 * @author 蔡伟明 <314013107@qq.com> * @return bool|string */ private function createTableToken($table = '', $prefix = 1) { $data = [ 'table' => $table, // 表名或模型名 'prefix' => $prefix, 'module' => $this->_module, 'controller' => $this->_controller, 'action' => $this->_action, ]; $table_token = substr(sha1($this->_module.'-'.$this->_controller.'-'.$this->_action.'-'.$table), 0, 8); session($table_token, $data); return $table_token; } /** * 添加一个右侧按钮 * @param string $type 按钮类型:edit/enable/disable/delete/custom * @param array $attribute 按钮属性 * @param bool $pop 是否使用弹出框形式 * @param array $extra 扩展参数,设置按钮样式 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addRightButton($type = '', $attribute = [], $pop = false, $extra = []) { if ($type == '') { return $this; } // 表单名,用于替换 if (isset($attribute['table'])) { if (isset($attribute['prefix'])) { $table_token = $this->createTableToken($attribute['table'], $attribute['prefix']); } else { $table_token = $this->createTableToken($attribute['table'], $this->_prefix); } } else { $table_token = '__table__'; } // 这个专门为插件准备的属性,是插件名称 $plugin_name = isset($attribute['plugin_name']) ? $attribute['plugin_name'] : $this->_plugin_name; // 自定义字段名 $field = isset($attribute['field']) ? $attribute['field'] : ''; // 按钮样式 $btn_style = array_merge(config('zbuilder.right_button'), $extra); switch ($type) { // 编辑按钮 case 'edit': // 默认属性 $btn_attribute = [ 'title' => '编辑', 'icon' => 'fa fa-pencil', 'class' => 'btn btn-'.$btn_style['size'].' btn-'.$btn_style['style'], 'href' => $this->getDefaultUrl($type, ['id' => '__id__', 'plugin_name' => $plugin_name]), 'target' => '_self' ]; break; // 启用按钮 case 'enable': // 默认属性 $btn_attribute = [ 'title' => '启用', 'icon' => 'fa fa-check', 'class' => 'btn btn-'.$btn_style['size'].' btn-'.$btn_style['style'].' ajax-get confirm', 'href' => $this->getDefaultUrl($type, ['ids' => '__id__', '_t' => $table_token, 'field' => $field]) ]; break; // 禁用按钮 case 'disable': // 默认属性 $btn_attribute = [ 'title' => '禁用', 'icon' => 'fa fa-ban', 'class' => 'btn btn-'.$btn_style['size'].' btn-'.$btn_style['style'].' ajax-get confirm', 'href' => $this->getDefaultUrl($type, ['ids' => '__id__', '_t' => $table_token, 'field' => $field]) ]; break; // 删除按钮(不可恢复) case 'delete': // 默认属性 $btn_attribute = [ 'title' => '删除', 'icon' => 'fa fa-times', 'class' => 'btn btn-'.$btn_style['size'].' btn-'.$btn_style['style'].' ajax-get confirm', 'href' => $this->getDefaultUrl($type, ['ids' => '__id__', '_t' => $table_token]) ]; break; // 自定义按钮 default: // 默认属性 $btn_attribute = [ 'title' => '自定义按钮', 'icon' => 'fa fa-smile-o', 'class' => 'btn btn-'.$btn_style['size'].' btn-'.$btn_style['style'], 'href' => 'javascript:void(0);' ]; break; } // 合并自定义属性 if ($attribute && is_array($attribute)) { $btn_attribute = array_merge($btn_attribute, $attribute); } // 判断当前用户是否有权限,没有权限则不生成按钮 if (session('user_auth.role') != 1 && substr($btn_attribute['href'], 0, 4) != 'http') { if ($this->checkButtonAuth($btn_attribute) === false) { return $this; } } // 是否为弹出框方式 if ($pop !== false) { $btn_attribute['class'] .= ' pop'; $btn_attribute['href'] .= (strpos($btn_attribute['href'], '?') ? '&' : '?').'_pop=1'; if (is_array($pop) && !empty($pop)) { $btn_attribute['data-layer'] = json_encode($pop); } } // 添加按钮样式 $btn_attribute['_style'] = $btn_style; // 添加按钮标签 $btn_attribute['_tag'] = $type; $this->_vars['right_buttons'][] = $btn_attribute; return $this; } /** * 一次性添加多个右侧按钮 * @param array|string $buttons 按钮类型 * 例如: * $builder->addRightButtons('edit'); * $builder->addRightButtons('edit,delete'); * $builder->addRightButtons(['edit', 'delete']); * $builder->addRightButtons(['edit' => ['table' => 'admin_user'], 'delete']); * * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addRightButtons($buttons = []) { if (!empty($buttons)) { $buttons = is_array($buttons) ? $buttons : explode(',', $buttons); foreach ($buttons as $key => $value) { if (is_numeric($key)) { $this->addRightButton($value); } else { $this->addRightButton($key, $value); } } } return $this; } /** * 设置表格高度 * @param string $height 高度:fixed/auto/具体数值 * @author 蔡伟明 <314013107@qq.com> * @return $this * @since 1.3.0 */ public function setHeight($height = 'fixed') { $this->_vars['builder_height'] = $height; return $this; } /** * 固定左侧列数 * @param int $num 数量 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function fixedRight($num = 0) { $this->_vars['fixed_right_column'] = $num; return $this; } /** * 固定右侧列数 * @param int $num 数量 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function fixedLeft($num = 0) { $this->_vars['fixed_left_column'] = $num; return $this; } /** * 设置搜索参数 * @param array $fields 参与搜索的字段 * @param string $placeholder 提示符 * @param string $url 提交地址 * @param null $search_button 提交按钮 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setSearch($fields = [], $placeholder = '', $url = '', $search_button = null) { if (!empty($fields)) { $this->_search = [ 'fields' => is_string($fields) ? explode(',', $fields) : $fields, 'placeholder' => $placeholder, 'url' => $url, ]; $this->_vars['search_button'] = $search_button !== null ? $search_button : config('zbuilder.search_button'); } return $this; } /** * 设置搜索区域 * @param array $items * @param string $url * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setSearchArea($items = [], $url = '') { if (!empty($items)) { $_op = []; $_defaults = []; $_s = $this->request->param('_s', ''); if ($_s != '') { $_s = explode('|', $_s); foreach ($_s as $v) { list($field, $value) = explode('=', $v); $_defaults[$field] = $value; } } foreach ($items as &$item) { $layout = 3; if (strpos($item[0], ':')) { list($item[0], $layout) = explode(':', $item[0]); } $type = $item[0]; $name = $item[1]; $label = $item[2]; $op = isset($item[3]) ? $item[3] : 'eq'; $item[4] = isset($_defaults[$name]) ? $_defaults[$name] : (isset($item[4]) ? $item[4] : ''); // 默认值 $item[5] = isset($item[5]) ? $item[5] : []; switch ($op) { case '=': $op = 'eq'; break; case '<>': $op = 'neq'; break; case '>': $op = 'gt'; break; case '<': $op = 'lt'; break; case '>=': $op = 'egt'; break; case '<=': $op = 'elt'; break; default: $op = $op == '' ? 'eq' : $op; } switch ($type) { case 'text': break; case 'select': $this->_vars['_js_files'][] = 'select2_js'; $this->_vars['_css_files'][] = 'select2_css'; $this->_vars['_js_init'][] = 'select2'; break; case 'daterange': $this->_vars['_js_files'][] = 'moment_js'; $this->_vars['_js_files'][] = 'daterangepicker_js'; $this->_vars['_css_files'][] = 'daterangepicker_css'; $this->_vars['_js_init'][] = 'daterangepicker'; $op = $op == 'eq' ? 'between time' : $op . ' time'; $params = []; if (!empty($item[5])) { foreach ($item[5] as $key => $param) { $params[] = 'data-'.strtolower($key).'="'.$param.'"'; } } $item[5] = implode(' ', $params); break; default: } $_op[] = $name.'='.strtolower($op); $this->_vars['_search_area_layout'][$name] = $layout; } $this->_vars['_search_area_op'] = implode('|', $_op); $this->_vars['_search_area'] = $items; $this->_vars['_search_area_url'] = $url == '' ? $this->request->baseUrl(true) : $url; } return $this; } /** * 引入模块js文件 * @param string $files_name js文件名,多个文件用逗号隔开 * @param string $module 指定模块 * @author caiweiming <314013107@qq.com> * @return $this */ public function js($files_name = '', $module = '') { if ($files_name != '') { $this->loadFile('js', $files_name, $module); } return $this; } /** * 引入模块css文件 * @param string $files_name css文件名,多个文件用逗号隔开 * @param string $module 指定模块 * @author caiweiming <314013107@qq.com> * @return $this */ public function css($files_name = '', $module = '') { if ($files_name != '') { $this->loadFile('css', $files_name, $module); } return $this; } /** * 引入css或js文件 * @param string $type 类型:css/js * @param string $files_name 文件名,多个用逗号隔开 * @param string $module 指定模块 * @author caiweiming <314013107@qq.com> */ private function loadFile($type = '', $files_name = '', $module = '') { if ($files_name != '') { $module = $module == '' ? $this->_module : $module; if (!is_array($files_name)) { $files_name = explode(',', $files_name); } foreach ($files_name as $item) { if (strpos($item, '/')) { $this->_vars[$type.'_list'][] = PUBLIC_PATH. 'static/'. $item.'.'.$type; } else { $this->_vars[$type.'_list'][] = PUBLIC_PATH. 'static/'. $module .'/'.$type.'/'.$item.'.'.$type; } } } } /** * 设置数据库表名 * @param string $table 数据库表名,不含前缀,如果为true则使用模型方式 * @param int $prefix 前缀类型:0使用Db类(不添加表前缀),1使用Db类(添加表前缀),2使用模型 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setTableName($table = '', $prefix = 1) { if ($table === true) { $this->_prefix = 2; $this->_table_name = strtolower($this->_module.'/'.$this->_controller); } else { $this->_prefix = $prefix === true ? 2 : $prefix; if ($this->_prefix == 2) { $this->_table_name = strpos($table, '/') ? $table : strtolower($this->_module.'/'.$table); } else { $this->_table_name = $table; } } return $this; } /** * 设置插件名称(此方法只供制作插件时用) * @param string $plugin_name 插件名 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setPluginName($plugin_name = '') { if ($plugin_name != '') { $this->_plugin_name = $plugin_name; } return $this; } /** * 添加一列 * @param string $name 字段名称 * @param string $title 列标题 * @param string $type 单元格类型 * @param string $default 默认值 * @param string $param 额外参数 * @param string $class css类名 * @param string $extra 扩展参数 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addColumn($name = '', $title = '', $type = '', $default = '', $param = '', $class = '', $extra = '') { $field = $name; $table = ''; // 判断是否有字段别名 if (strpos($name, '|')) { list($name, $field) = explode('|', $name); // 判断是否有表名 if (strpos($field, '.')) { list($table, $field) = explode('.', $field); } } $column = [ 'name' => $name, 'title' => $title, 'type' => $type, 'default' => $default, 'param' => $param, 'class' => $class, 'extra' => $extra, 'field' => $field, 'table' => $table, ]; $args = array_slice(func_get_args(), 7); $column = array_merge($column, $args); $this->_vars['columns'][] = $column; $this->_field_name[$name] = $title; return $this; } /** * 一次性添加多列 * @param array $columns 数据列 * @author caiweiming <314013107@qq.com> * @return $this */ public function addColumns($columns = []) { if (!empty($columns)) { foreach ($columns as $column) { call_user_func_array([$this, 'addColumn'], $column); } } return $this; } /** * 设置列宽 * @param string $column 列名,即字段名 * @param int $width 宽度,默认为100 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setColumnWidth($column = '', $width = 100) { if ($column != '') { if (is_array($column)) { foreach ($column as $field => $width) { $this->_vars['column_width'][$field] = $width; } } else { if (strpos($column, ',')) { $columns = explode(',', $column); foreach ($columns as $column) { $this->_vars['column_width'][$column] = $width; } } else { $this->_vars['column_width'][$column] = $width; } } } return $this; } /** * 隐藏列 * @param string $column 列名,即字段名 * @param string $screen 屏幕,xs/sm/md/lg * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function hideColumn($column = '', $screen = '') { if ($column != '') { if (is_array($column)) { foreach ($column as $field => $screen) { $screens = is_array($screen) ? $screen : explode(',', $screen); foreach ($screens as $key => $value) { $screens[$key] = 'hidden-'.$value; } $screens = implode(' ', $screens); $this->_vars['column_hide'][$field] = $screens; } } else { $screens = is_array($screen) ? $screen : explode(',', $screen); foreach ($screens as &$screen) { $screen = 'hidden-'.$screen; } $screens = implode(' ', $screens); if (strpos($column, ',')) { $columns = explode(',', $column); foreach ($columns as $column) { $this->_vars['column_hide'][$column] = isset($this->_vars['column_hide'][$column]) ? $this->_vars['column_hide'][$column]. ' ' . $screen : $screens; } } else { $this->_vars['column_hide'][$column] = isset($this->_vars['column_hide'][$column]) ? $this->_vars['column_hide'][$column]. ' ' . $screen : $screens; } } } return $this; } /** * 设置表格数据列表 * @param array|object $row_list 表格数据 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setRowList($row_list = null) { if ($row_list !== null) { // 原始表格数据 $this->data = $row_list; // 转为数组后的表格数据 $this->_vars['row_list'] = $this->toArray($row_list); if ($row_list instanceof \think\paginator) { $this->_vars['_page_info'] = $row_list; // 设置分页 $this->setPages($row_list->render()); } } if (empty($this->_vars['row_list'])) { $params = $this->request->param(); if (isset($params['page'])) { unset($params['page']); $url = url($this->_module.'/'.$this->_controller.'/'.$this->_action).'?'.http_build_query($params); $this->redirect($url); } } return $this; } /** * 将表格数据转换为纯数组 * @param array|object $row_list 数据 * @author 蔡伟明 <314013107@qq.com> * @return array */ private function toArray($row_list) { if ($row_list instanceof \think\paginator) { return $row_list->toArray()['data']; } elseif ($row_list instanceof \think\model\Collection) { return $row_list->toArray(); } else { return $row_list; } } /** * 获取原始数据 * @param string $index 索引 * @param string $field 字段名 * @author 蔡伟明 <314013107@qq.com> * @return mixed */ private function getData($index = '', $field = '') { if (is_object($this->data) && is_object(current($this->data->getIterator()))) { try { $result = $this->data[$index]->getData($field); } catch (\Exception $e) { $result = isset($this->data[$index][$field]) ? $this->data[$index][$field] : ''; } return $result; } else { return isset($this->data[$index][$field]) ? $this->data[$index][$field] : ''; } } /** * 设置需要使用原始数据的字段 * @param string|array $field 字段名 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function raw($field = '') { if (is_array($field)) { $this->rawField = array_merge($this->rawField, $field); } else { $this->rawField = array_merge($this->rawField, explode(',', $field)); } return $this; } /** * 设置表格主键 * @param string $key 主键名称 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setPrimaryKey($key = '') { if ($key != '') { $this->_vars['primary_key'] = $key; } return $this; } /** * 设置Tab按钮列表 * @param array $tab_list Tab列表 ['title' => '标题', 'href' => 'http://www.dolphinphp.com'] * @param string $curr_tab 当前tab * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setTabNav($tab_list = [], $curr_tab = '') { if (!empty($tab_list)) { $this->_vars['tab_nav'] = [ 'tab_list' => $tab_list, 'curr_tab' => $curr_tab, ]; } return $this; } /** * 设置分页 * @param string $pages 分页数据 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setPages($pages = '') { if ($pages != '') { $this->_vars['pages'] = $pages; } return $this; } /** * 设置为无分页 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function noPages() { $this->_has_pages = false; return $this; } /** * 设置额外代码 * @param string $extra_html 额外代码 * @param string $tag 标记 * @author 蔡伟明 <314013107@qq.com> * @alter 小乌 <82950492@qq.com> * @return $this */ public function setExtraHtml($extra_html = '', $tag = '') { if ($extra_html != '') { $tag != '' && $tag = '_'.$tag; $this->_vars['extra_html'.$tag] = $extra_html; } return $this; } /** * 通过文件设置额外代码 * @param string $template 模板文件名 * @param string $tag 标记 * @param array $vars 模板输出变量 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setExtraHtmlFile($template = '', $tag = '', $vars = []) { $template = $template == '' ? $this->_action : $template; $file = Env::get('app_path'). $this->_module.'/view/admin/'.$this->_controller.'/'.$template.'.html'; if (file_exists($file)) { $content = file_get_contents($file); $content = $this->view->display($content, $vars); } else { $content = '模板文件不存在:'.$file; } $tag != '' && $tag = '_'.$tag; $this->_vars['extra_html'.$tag] = $content; return $this; } /** * 设置额外JS代码 * @param string $extra_js 额外JS代码 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setExtraJs($extra_js = '') { if ($extra_js != '') { $this->_vars['extra_js'] = $extra_js; } return $this; } /** * 设置额外CSS代码 * @param string $extra_css 额外CSS代码 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setExtraCss($extra_css = '') { if ($extra_css != '') { $this->_vars['extra_css'] = $extra_css; } return $this; } /** * 设置页面模版 * @param string $template 模版 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function setTemplate($template = '') { if ($template != '') { $this->_template = $template; } return $this; } /** * 列class * @param string $class class名 * @param mixed $field 字段名 * @param null $op 表达式 * @param null $condition 查询条件 * @author 蔡伟明 <314013107@qq.com> * @return $this */ public function addTrClass($class = '', $field, $op = null, $condition = null) { if ($class != '') { if (is_callable($field)) { $args = array_slice(func_get_args(), 2); $this->_tr_class[$class][] = [$field, $args]; } elseif (!is_null($op)) { $op = strtolower($op); if (is_null($condition)) { $this->_tr_class[$class][] = [$field, 'eq', $op]; } else { switch ($op) { case '=': $op = 'eq'; break; case '<>': $op = 'neq'; break; case '>': $op = 'gt'; break; case '<': $op = 'lt'; break; case '>=': $op = 'egt'; break; case '<=': $op = 'elt'; break; case 'in': case 'not in': case 'between': case 'not between': $condition = is_array($condition) ? $condition : explode(',', $condition); break; } $this->_tr_class[$class][] = [$field, $op, $condition]; } } } return $this; } /** * 编译HTML属性 * @param array $attr 要编译的数据 * @author 蔡伟明 <314013107@qq.com> * @return array|string */ private function compileHtmlAttr($attr = []) { $result = []; if ($attr) { foreach ($attr as $key => &$value) { if ($key == 'title') { $value = trim(htmlspecialchars(strip_tags(trim($value)))); } else { $value = htmlspecialchars($value); } array_push($result, "$key=\"$value\""); } } return implode(' ', $result); } /** * 编译表格数据row_list的值 * @author 蔡伟明 <314013107@qq.com> */ private function compileRows() { foreach ($this->_vars['row_list'] as $key => &$row) { // 处理行class if ($this->_tr_class) { $_tr_class = $this->parseTrClass($row); if (!empty($_tr_class)) { $row['_tr_class'] = implode(' ', $_tr_class); } } // 编译右侧按钮 if ($this->_vars['right_buttons']) { // 默认给列添加个空的右侧按钮 if (!isset($row['right_button'])) { $row['right_button'] = ''; } foreach ($this->_vars['right_buttons'] as $index => $button) { // 处理按钮替换 if (!empty($this->_replace_right_buttons)) { foreach ($this->_replace_right_buttons as $replace_right_button) { // 是否能匹配到条件 $_button_match = true; foreach ($replace_right_button['maps'] as $condition) { if (is_string($condition[0])) { if (!isset($row[$condition[0]])) { $_button_match = false; continue; } $_button_match = $this->parseCondition($row, $condition) ? $_button_match : false; } elseif (is_callable($condition[0])) { $_button_match = call_user_func($condition[0], $row) ? $_button_match : false; } } // 替换按钮内容支持数据变量 if ($replace_right_button['content'] != '') { if (preg_match_all('/__(.*?)__/', $replace_right_button['content'], $matches)) { $replace_to = []; $pattern = []; foreach ($matches[1] as $match) { $pattern[] = '/__'. $match .'__/i'; $replace_to[] = $row[$match]; } $replace_right_button['content'] = preg_replace($pattern, $replace_to, $replace_right_button['content']); } } if ($_button_match) { if ($replace_right_button['target'] === null) { $row['right_button'] = $replace_right_button['content']; break(2); } else { if (in_array($button['_tag'], $replace_right_button['target'])) { $row['right_button'] .= $replace_right_button['content']; continue(2); } } } } } // 处理主键变量值 $button['href'] = preg_replace( '/__id__/i', $row[$this->_vars['primary_key']], $button['href'] ); // 处理表名变量值 if (strpos($button['href'], '__table__') !== false) { $button['href'] = preg_replace( '/__table__/i', $this->createTableToken($this->_table_name, $this->_prefix), $button['href'] ); } // 替换其他字段值 if (preg_match_all('/__(.*?)__/', $button['href'], $matches)) { // 要替换的字段名 $replace_to = []; $pattern = []; foreach ($matches[1] as $match) { $replace = in_array($match, $this->rawField) ? $this->getData($key, $match) : (isset($row[$match]) ? $row[$match] : ''); if (isset($row[$match])) { $pattern[] = '/__'. $match .'__/i'; $replace_to[] = $replace; } } $button['href'] = preg_replace( $pattern, $replace_to, $button['href'] ); } $button_style = $button['_style']; unset($button['_style']); // 编译按钮属性 $button['attribute'] = $this->compileHtmlAttr($button); if ($button_style['title']) { $row['right_button'] .= ''; if ($button_style['icon']) { $row['right_button'] .= ' '; } $row['right_button'] .= $button['title'].''; } else { $row['right_button'] .= ''; } } $row['right_button'] = '
'. $row['right_button'] .'
'; } // 编译单元格数据类型 if ($this->_vars['columns']) { // 另外拷贝一份主键值,以免将主键设置为快速编辑的时候解析出错 $row['_primary_key_value'] = isset($row[$this->_vars['primary_key']]) ? $row[$this->_vars['primary_key']] : ''; foreach ($this->_vars['columns'] as $column) { $_name = $column['field']; $_table_name = $column['table']; // 如果需要显示编号 if ($column['name'] == '__INDEX__') { $row[$column['name']] = $key + 1; } if (in_array($column['name'], $this->rawField)) { $row[$column['name']] = $this->getData($key, $column['name']); } // 备份原数据 if (isset($row[$column['name']])) { $row['__'.$column['name'].'__'] = $row[$column['name']]; } switch ($column['type']) { case 'link': // 链接 if ($column['default'] != '') { // 要替换的字段名 $replace_to = []; $pattern = []; $url = $column['default']; $target = $column['param'] == '' ? '_self' : $column['param']; if (preg_match_all('/__(.*?)__/', $column['default'], $matches)) { foreach ($matches[1] as $match) { $pattern[] = '/__'. $match .'__/i'; $replace_to[] = $row[$match]; } $url = preg_replace($pattern, $replace_to, $url); } $url = $column['class'] == 'pop' ? $url.(strpos($url, '?') ? '&' : '?').'_pop=1' : $url; if ($column['extra'] != '') { $title = $column['extra'] === true ? $column['title'] : $column['extra']; } else { $title = $row[$column['name']]; } $row[$column['name'].'__'.$column['type']] = ''.$row[$column['name']].''; } break; case 'switch': // 开关 switch ($row[$column['name']]) { case '0': // 关闭 $row[$column['name'].'__'.$column['type']] = ''; break; case '1': // 开启 $row[$column['name'].'__'.$column['type']] = ''; break; } break; case 'status': // 状态 $status = $row[$column['name']]; $list_status = !empty($column['param']) ? $column['param'] : ['禁用:warning', '启用:success']; if (isset($list_status[$status])) { switch ($status) { case '0': $class = 'warning';break; case '1': $class = 'success';break; case '2': $class = 'primary';break; case '3': $class = 'info';break; default: $class = 'default'; } if (strpos($list_status[$status], ':')) { list($label, $class) = explode(':', $list_status[$status]); } else { $label = $list_status[$status]; } $row[$column['name'].'__'.$column['type']] = ''.$label.''; } break; case 'yesno': // 是/否 switch ($row[$column['name']]) { case '0': // 否 $row[$column['name'].'__'.$column['type']] = ''; break; case '1': // 是 $row[$column['name'].'__'.$column['type']] = ''; break; } break; case 'text.edit': // 可编辑的单行文本 $row[$column['name'].'__'.$column['type']] = ''.$row[$column['name']].''; break; case 'textarea.edit': // 可编辑的多行文本 $row[$column['name'].'__'.$column['type']] = ''.$row[$column['name']].''; break; case 'password': // 密码框 $column['param'] = $column['param'] != '' ? $column['param'] : $column['name']; $row[$column['name'].'__'.$column['type']] = '******'; break; case 'email': // 邮箱地址 case 'url': // 链接地址 case 'tel': // 电话 case 'number': // 数字 case 'range': // 范围 $column['param'] = $column['param'] != '' ? $column['param'] : $column['name']; $row[$column['name'].'__'.$column['type']] = ''.$row[$column['name']].''; break; case 'icon': // 图标 if ($row[$column['name']] === '') { $row[$column['name'].'__'.$column['type']] = ''; } else { $row[$column['name'].'__'.$column['type']] = ''; } break; case 'byte': // 字节 if ($row[$column['name']] === '') { $row[$column['name'].'__'.$column['type']] = $column['default']; } else { $row[$column['name'].'__'.$column['type']] = format_bytes($row[$column['name']], $column['param']); } break; case 'date': // 日期 case 'datetime': // 日期时间 case 'time': // 时间 // 默认格式 $format = 'Y-m-d H:i'; switch ($column['type']) { case 'date': $format = 'Y-m-d';break; case 'datetime': $format = 'Y-m-d H:i';break; case 'time': $format = 'H:i';break; } // 格式 $format = $column['param'] == '' ? $format : $column['param']; if ($row[$column['name']] == '') { $row[$column['name'].'__'.$column['type']] = $column['default']; } else { $row[$column['name'].'__'.$column['type']] = format_time($row[$column['name']], $format); } break; case 'date.edit': // 可编辑日期时间,默认发送的是格式化好的 case 'datetime.edit': // 可编辑日期时间,默认发送的是格式化好的 case 'time.edit': // 可编辑时间,默认发送的是格式化好的 // 默认格式 $format = 'YYYY-MM-DD HH:mm'; switch ($column['type']) { case 'date.edit': $format = 'YYYY-MM-DD';break; case 'datetime.edit': $format = 'YYYY-MM-DD HH:mm';break; case 'time.edit': $format = 'HH:mm';break; } // 格式 $format = $column['param'] == '' ? $format : $column['param']; // 时间戳 $timestamp = $row[$column['name']]; $row[$column['name'].'__'.$column['type']] = ''; if ($row[$column['name']] == '') { $row[$column['name'].'__'.$column['type']] .= $column['default'].''; } else { $row[$column['name'].'__'.$column['type']] .= format_moment($timestamp, $format).''; } // 加载moment.js $this->_vars['_js_files'][] = 'moment_js'; break; case 'avatar': // 头像 break; case 'img_url': // 外链图片 if ($row[$column['name']] != '') { $row[$column['name'].'__'.$column['type']] = ''; } break; case 'picture': // 单张图片 $row[$column['name'].'__'.$column['type']] = ''; break; case 'pictures': // 多张图片 if ($row[$column['name']] === '') { $row[$column['name'].'__'.$column['type']] = !empty($column['default']) ? $column['default'] : '暂无图片'; } else { $list_img = is_array($row[$column['name']]) ? $row[$column['name']] : explode(',', $row[$column['name']]); $imgs = ''; } break; case 'files': if ($row[$column['name']] === '') { $row[$column['name'].'__'.$column['type']] = !empty($column['default']) ? $column['default'] : '暂无文件'; } else { $list_file = is_array($row[$column['name']]) ? $row[$column['name']] : explode(',', $row[$column['name']]); $files = '
'; foreach ($list_file as $k => $file) { if ($column['param'] != '' && $k == $column['param']) { break; } $files .= ' ['.get_file_name($file).']'; } $row[$column['name'].'__'.$column['type']] = $files.'
'; } break; case 'select': // 下拉框 if ($column['default']) { if (isset($column['default'][$row[$column['name']]])) { $prepend = $column['default'][$row[$column['name']]] != '' ? $column['default'][$row[$column['name']]] : '空值'; } else { $prepend = '无对应值'; } $class = ($prepend == '无对应值' || $prepend == '空值') ? 'select-edit text-danger' : 'select-edit'; $source = json_encode($column['default'], JSON_FORCE_OBJECT); $row[$column['name'].'__'.$column['type']] = ''.$prepend.''; } break; case 'select2': // tag编辑(有BUG) // if ($column['default']) { // $source = json_encode($column['default']); // $row[$column['name'].'__'.$column['type']] = ''.$row[$column['name']].''; // } break; case 'callback': // 调用回调方法 unset($column['field']); unset($column['table']); $params = array_slice($column, 4); $params = array_filter($params, function($v){return $v !== '';}); if (isset($row[$column['name']]) || array_key_exists($column['name'], $row)) { $params = array_merge([$row[$column['name']]], $params); } if (!empty($params)) { foreach ($params as &$param) { if ($param === '__data__') $param = $row; } } $row[$column['name'].'__'.$column['type']] = call_user_func_array($column['default'], $params); break; case 'popover': $length = empty($column['default']) ? 10 : $column['default']; $placement = empty($column['param']) ? 'top' : $column['param']; $row[$column['name'].'__'.$column['type']] = mb_substr($row[$column['name']], 0, $length, 'utf-8').'... '; break; case 'text': default: // 默认 // 设置默认值 if (!isset($row[$column['name']]) && !empty($column['default'])) { $row[$column['name']] = $column['default']; } if (is_array($column['type']) && !empty($column['type'])) { if (isset($column['type'][$row[$column['name']]])) { $row[$column['name']] = $column['type'][$row[$column['name']]]; } } else { if (!empty($column['param'])) { if (isset($column['param'][$row[$column['name']]])) { $row[$column['name']] = $column['param'][$row[$column['name']]]; } } else { if (isset($row[$column['name']]) && $row[$column['name']] == '' && $column['default'] != '') { $row[$column['name']] = $column['default']; } } } } } } } } /** * 分析行class * @param mixed $row 行数据 * @author 蔡伟明 <314013107@qq.com> * @return array */ private function parseTrClass($row) { $_tr_class = []; foreach ($this->_tr_class as $tr_class => $conditions) { $match = true; foreach ($conditions as $condition) { if (is_callable($condition[0])) { $params = array_merge([$row], $condition[1]); $match = call_user_func_array($condition[0], $params) ? $match : false; continue; } if (!isset($row[$condition[0]])) { $match = false; continue; } $match = $this->parseCondition($row, $condition) ? $match : false; } if ($match) { $_tr_class[] = $tr_class; } } return $_tr_class; } /** * 分析条件 * @param mixed $row 行数据 * @param array $condition 对比条件 * @author 蔡伟明 <314013107@qq.com> * @return bool */ private function parseCondition($row, $condition = []) { $match = true; switch ($condition[1]) { case 'eq': $row[$condition[0]] != $condition[2] && $match = false; break; case 'neq': $row[$condition[0]] == $condition[2] && $match = false; break; case 'gt': $row[$condition[0]] <= $condition[2] && $match = false; break; case 'lt': $row[$condition[0]] >= $condition[2] && $match = false; break; case 'egt': $row[$condition[0]] < $condition[2] && $match = false; break; case 'elt': $row[$condition[0]] > $condition[2] && $match = false; break; case 'in': !in_array($row[$condition[0]], $condition[2]) && $match = false; break; case 'not in': in_array($row[$condition[0]], $condition[2]) && $match = false; break; case 'between': ($row[$condition[0]] < $condition[2][0] || $row[$condition[0]] > $condition[2][1]) && $match = false; break; case 'not between': ($row[$condition[0]] >= $condition[2][0] && $row[$condition[0]] <= $condition[2][1]) && $match = false; break; } return $match; } /** * 创建筛选Token * @param string $table 表名 * @param string $field 字段 * @author 蔡伟明 <314013107@qq.com> * @return bool|string */ private function createFilterToken($table = '', $field = '') { $table_token = substr(sha1($table.'-'.$field.'-'.session('user_auth.last_login_ip').'-'.session('user_auth.uid').'-'.session('user_auth.last_login_time')), 0, 8); session($table_token, ['table' => $table, 'field' => $field]); return $table_token; } /** * 编译表格数据 * @author 蔡伟明 <314013107@qq.com> */ private function compileTable(){ // 设置表名 $this->_vars['_table'] = $this->_table_name; // 处理字段筛选 if ($this->_vars['filter_columns']) { // 要筛选的字段 $filter_columns = []; // 要筛选的字段条件 $filter_maps = []; // 处理字段筛选条件 if (!empty($this->_vars['filter_map'])) { foreach ($this->_vars['filter_map'] as $fields => $map) { if (strpos($fields, ',')) { $fields = explode(',', $fields); foreach ($fields as $field) { if (isset($filter_maps[$field])) { // 如果某字段的条件已存在,则合并条件 $filter_maps[$field] = array_merge($filter_maps[$field], $map); } else { $filter_maps[$field] = $map; } } } else { if (isset($filter_maps[$fields])) { // 如果某字段的条件已存在,则合并条件 $filter_maps[$fields] = array_merge($filter_maps[$fields], $map); } else { $filter_maps[$fields] = $map; } } } // 将条件转换为json格式 foreach ($filter_maps as &$filter_map) { $filter_map = json_encode($filter_map); } } // 组合字段筛选 foreach ($this->_vars['filter_columns'] as $key => $value) { if (is_numeric($key)) { if (strpos($value, '.')) { list($table, $field) = explode('.', $value); $_filter_token = $this->createFilterToken($table, $field); $filter_columns[$field] = [ 'token' => $_filter_token, 'type' => $this->_filter_type[$value], 'filter' => $value, 'map' => isset($filter_maps[$field]) ? $filter_maps[$field] : '', 'options' => isset($this->_filter_options[$field]) ? $this->_filter_options[$field] : '', 'list' => isset($this->_filter_list[$field]) ? $this->_filter_list[$field] : '' ]; } else { $_filter_token = $this->createFilterToken($this->_table_name, $value); $filter_columns[$value] = [ 'token' => $_filter_token, 'type' => $this->_filter_type[$value], 'filter' => $value, 'map' => isset($filter_maps[$value]) ? $filter_maps[$value] : '', 'options' => isset($this->_filter_options[$value]) ? $this->_filter_options[$value] : '', 'list' => isset($this->_filter_list[$value]) ? $this->_filter_list[$value] : '' ]; } } else { if (strpos($value, '.')) { list($table, $field) = explode('.', $value); $_filter_token = $this->createFilterToken($table, $field); $filter_columns[$key] = [ 'token' => $_filter_token, 'type' => $this->_filter_type[$value], 'filter' => $value, 'map' => isset($filter_maps[$key]) ? $filter_maps[$key] : '', 'options' => isset($this->_filter_options[$key]) ? $this->_filter_options[$key] : '', 'list' => isset($this->_filter_list[$key]) ? $this->_filter_list[$key] : '' ]; } else { $_filter_token = $this->createFilterToken($value, $key); $filter_columns[$key] = [ 'token' => $_filter_token, 'type' => $this->_filter_type[$value], 'filter' => $value . '.' . $key, 'map' => isset($filter_maps[$key]) ? $filter_maps[$key] : '', 'options' => isset($this->_filter_options[$key]) ? $this->_filter_options[$key] : '', 'list' => isset($this->_filter_list[$key]) ? $this->_filter_list[$key] : '' ]; } } } $this->_vars['filter_columns'] = $filter_columns; } // 处理字段筛选默认选项 $this->_vars['_filter_content'] = implode('|', $this->_vars['_filter_content']); $this->_vars['_field_display'] = implode(',', $this->_vars['_field_display']); $this->_vars['_filter'] = implode('|', $this->_vars['_filter']); // 处理字段排序 if ($this->_vars['order_columns']) { $order_columns = []; foreach ($this->_vars['order_columns'] as $key => $value) { if (is_numeric($key)) { if (strpos($value, '.')) { $tmp = explode('.', $value); $order_columns[$tmp[1]] = $value; } else { $order_columns[$value] = $value; } } else { if (strpos($value, '.')) { $order_columns[$key] = $value; } else { $order_columns[$key] = $value. '.' .$key; } } } $this->_vars['order_columns'] = $order_columns; } // 编译顶部按钮 if ($this->_vars['top_buttons']) { foreach ($this->_vars['top_buttons'] as &$button) { // 处理表名变量值 if (strpos($button['href'], '__table__')) { $button['href'] = preg_replace( '/__table__/i', $this->createTableToken($this->_table_name, $this->_prefix), $button['href'] ); } $button['attribute'] = $this->compileHtmlAttr($button); $new_button = ""; if (isset($button['icon']) && $button['icon'] != '') { $new_button .= ' '; } $new_button .= "{$button['title']}"; $button = $new_button; } } // 编译顶部下拉菜单 if ($this->_vars['_select_list']) { foreach ($this->_vars['_select_list'] as $name => &$select) { // 当前url参数 $url_params = $this->request->param(); // 要搜索的字段 $select_field = $this->request->param('_select_field', ''); $select_field = $select_field != '' ? explode('|', $select_field) : []; // 对应的值 $select_value = $this->request->param('_select_value', ''); $select_value = $select_value != '' ? explode('|', $select_value) : []; // 合并默认值 if ($this->_select_list_default) { foreach ($this->_select_list_default as $field => $value) { if (!in_array($field, $select_field)) { array_push($select_field, $field); array_push($select_value, $value); } } } // 当前选中值 if (in_array($name, $select_field)) { $select['current'] = $select_value[array_search($name, $select_field)]; } // 剔除要忽略的参数 if ($select['ignore'] !== '') { $ignores = explode(',', $select['ignore']); foreach ($ignores as $ignore) { if (array_search($ignore, $select_field) !== false) { $pos = array_search($ignore, $select_field); array_splice($select_field, $pos, 1); array_splice($select_value, $pos, 1); } } } // 生成除默认选项的下拉项的跳转url if (!empty($select_field)) { if (!in_array($name, $select_field)) { array_push($select_field, $name); } $url_params['_select_field'] = implode('|', $select_field); foreach ($select['options'] as $key => $option) { $select_value[array_search($name, $select_field)] = $key; $url_params['_select_value'] = implode('|', $select_value); $select['url'][$key] = url('').'?'.http_build_query($url_params); } } else { $url_params['_select_field'] = $name; foreach ($select['options'] as $key => $option) { $url_params['_select_value'] = $key; // 添加下拉菜单项查询参数 $select['url'][$key] = url('').'?'.http_build_query($url_params); } } // 生成默认选项的url if (isset($this->_select_list_default[$name])) { $url_params['_select_field'] = implode('|', $select_field); $select_value[array_search($name, $select_field)] = '_all'; $url_params['_select_value'] = implode('|', $select_value); } else { if (array_search($name, $select_field) !== false) { $pos = array_search($name, $select_field); unset($select_value[$pos]); unset($select_field[$pos]); if (empty($select_field)) { unset($url_params['_select_field']); unset($url_params['_select_value']); } else { $url_params['_select_field'] = implode('|', $select_field); $url_params['_select_value'] = implode('|', $select_value); } } } $select['default_url'] = url('').'?'.http_build_query($url_params); } } // 处理搜索框 if ($this->_search) { $_temp_fields = []; foreach ($this->_search['fields'] as $key => $field) { if (is_numeric($key)) { if (strpos($field, '.')) { $_field = explode('.', $field)[1]; } else { $_field = $field; } $_temp_fields[$field] = isset($this->_field_name[$_field]) ? $this->_field_name[$_field] : ''; } else { $_temp_fields[$key] = $field; } } $this->_vars['search'] = [ 'fields' => $_temp_fields, 'field_all' => implode('|', array_keys($_temp_fields)), 'placeholder' => $this->_search['placeholder'] != '' ? $this->_search['placeholder'] : '请输入'. implode('/', $_temp_fields), 'url' => $this->_search['url'] == '' ? $this->request->baseUrl(true) : $this->_search['url'] ]; } // 编译表格数据row_list的值 $this->compileRows(); // 处理页面标题 if ($this->_vars['page_title'] == '') { $location = get_location('', false, false); if ($location) { $curr_location = end($location); $this->_vars['page_title'] = $curr_location['title']; } } // 处理是否有分页数据 if (!$this->_has_pages) { $this->_vars['pages'] = ''; } // 处理js和css合并的参数 if (!empty($this->_vars['_js_files'])) { $this->_vars['_js_files'] = array_unique($this->_vars['_js_files']); } if (!empty($this->_vars['_css_files'])) { $this->_vars['_css_files'] = array_unique($this->_vars['_css_files']); sort($this->_vars['_css_files']); } if (!empty($this->_vars['_js_init'])) { $this->_vars['_js_init'] = array_unique($this->_vars['_js_init']); sort($this->_vars['_js_init']); $this->_vars['_js_init'] = json_encode($this->_vars['_js_init']); } } /** * 加载模板输出 * @param string $template 模板文件名 * @param array $vars 模板输出变量 * @param array $config 模板参数 * @author 蔡伟明 <314013107@qq.com> * @return mixed */ public function fetch($template = '', $vars = [], $config = []) { // 编译表格数据 $this->compileTable(); if ($template != '') { $this->_template = $template; } if (!empty($vars)) { $this->_vars = array_merge($this->_vars, $vars); } // 实例化视图并渲染 return parent::fetch($this->_template, $this->_vars, $config); } }