*/ 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'] = '