Joyber 发布的文章

Options

Core options

Options can be passed via data attributes or JavaScript. For data attributes, append the option name to data-, as in data-style="" or data-selected-text-format="count".

Note: For security reasons, the sanitize, sanitizeFn and whiteList options cannot be supplied using data attributes.

Name    Type    Default    Description
actionsBox    boolean    false    
When set to true, adds two buttons to the top of the dropdown menu (Select All & Deselect All).
container    string | false    false    
When set to a string, appends the select to a specific element or selector, e.g., container: 'body' | '.main-body'
countSelectedText    string | function    function    
Sets the format for the text displayed when selectedTextFormat is count or count > #. {0} is the selected amount. {1} is total available for selection.

When set to a function, the first parameter is the number of selected options, and the second is the total number of options. The function must return a string.
deselectAllText    string    'Deselect All'    
The text on the button that deselects all options when actionsBox is enabled.
dropdownAlignRight    boolean | 'auto'    false    
Align the menu to the right instead of the left. If set to 'auto', the menu will automatically align right if there isn't room for the menu's full width when aligned to the left.
dropupAuto    boolean    true    
checks to see which has more room, above or below. If the dropup has enough room to fully open normally, but there is more room above, the dropup still opens normally. Otherwise, it becomes a dropup. If dropupAuto is set to false, dropups must be called manually.
header    string    false    
adds a header to the top of the menu; includes a close button by default
hideDisabled    boolean    false    
removes disabled options and optgroups from the menu data-hide-disabled: true
iconBase    string    'glyphicon'    
Set the base to use a different icon font instead of Glyphicons. If changing iconBase, you might also want to change tickIcon, in case the new icon font uses a different naming scheme.
liveSearch    boolean    false    
When set to true, adds a search box to the top of the selectpicker dropdown.
liveSearchNormalize    boolean    false    
Setting liveSearchNormalize to true allows for accent-insensitive searching.
liveSearchPlaceholder    string    null    
When set to a string, a placeholder attribute equal to the string will be added to the liveSearch input.
liveSearchStyle    string    'contains'    
When set to 'contains', searching will reveal options that contain the searched text. For example, searching for pl with return both Apple, Plum, and Plantain. When set to 'startsWith', searching for pl will return only Plum and Plantain.
maxOptions    integer | false    false    
When set to an integer and in a multi-select, the number of selected options cannot exceed the given value.

This option can also exist as a data-attribute for an <optgroup>, in which case it only applies to that <optgroup>.
maxOptionsText    string | array | function    function    
The text that is displayed when maxOptions is enabled and the maximum number of options for the given scenario have been selected.

If a function is used, it must return an array. array[0] is the text used when maxOptions is applied to the entire select element. array[1] is the text used when maxOptions is used on an optgroup. If a string is used, the same text is used for both the element and the optgroup.
mobile    boolean    false    
When set to true, enables the device's native menu for select menus.
multipleSeparator    string    ', '    
Set the character displayed in the button that separates selected options.
noneSelectedText    string    'Nothing selected'    
The text that is displayed when a multiple select has no selected options.
noneResultsText    string    'No results matched {0}'    
The text displayed when a search doesn't return any results.
selectAllText    string    'Select All'    
The text on the button that selects all options when actionsBox is enabled.
selectedTextFormat    'values' | 'static' | 'count' | 'count > x' (where x is an integer)    'values'    
Specifies how the selection is displayed with a multiple select.

'values' displays a list of the selected options (separated by multipleSeparator. 'static' simply displays the select element's title. 'count' displays the total number of selected options. 'count > x' behaves like 'values' until the number of selected options is greater than x; after that, it behaves like 'count'.
selectOnTab    boolean    false    
When set to true, treats the tab character like the enter or space characters within the selectpicker dropdown.
showContent    boolean    true    
When set to true, display custom HTML associated with selected option(s) in the button. When set to false, the option value will be displayed instead.
showIcon    boolean    true    
When set to true, display icon(s) associated with selected option(s) in the button.
showSubtext    boolean    false    
When set to true, display subtext associated with a selected option in the button.
showTick    boolean    false    
Show checkmark on selected option (for items without multiple attribute).
size    'auto' | integer | false    'auto'    
When set to 'auto', the menu always opens up to show as many items as the window will allow without being cut off.

When set to an integer, the menu will show the given number of items, even if the dropdown is cut off.

When set to false, the menu will always show all items.
style    string | null    Bootstrap 4: 'btn-light' Bootstrap 3: 'btn-default'    
When set to a string, add the value to the button's style.
styleBase    string | null    'btn'    
The default class applied to the button. When using the setStyle method, this class will always remain.

Hint: If you want to style the element as a form control, set style to '' and styleBase to 'form-control'.
tickIcon    string    'glyphicon-ok'    
Set which icon to use to display as the "tick" next to selected options.
title    string | null    null    
The default title for the selectpicker.
virtualScroll    boolean | integer    600    
If enabled, the items in the dropdown will be rendered using virtualization (i.e. only the items that are within the viewport will be rendered). This drastically improves performance for selects with a large number of options. Set to an integer to only use virtualization if the select has at least that number of options.
width    'auto' | 'fit' | css-width | false (where css-width is a CSS width with units, e.g. 100px)    false    
When set to auto, the width of the selectpicker is automatically adjusted to accommodate the widest option.

When set to a css-width, the width of the selectpicker is forced inline to the given value.

When set to false, all width information is removed.
windowPadding    integer | array    0    
This is useful in cases where the window has areas that the dropdown menu should not cover - for instance a fixed header. When set to an integer, the same padding will be added to all sides. Alternatively, an array of integers can be used in the format [top, right, bottom, left].
sanitize    boolean    true    
Enable or disable the sanitization. If activated, 'data-content' on individual options will be sanitized.
whiteList    object    Default value    
Object which contains allowed attributes and tags
sanitizeFn    null | function    null    
Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization.

Default settings

You can change the default settings for bootstrap-select by modifying its Constructor.DEFAULTS object:

$.fn.selectpicker.Constructor.DEFAULTS.multipleSeparator = ' | ';

Events

Bootstrap-select exposes a few events for hooking into select functionality.

hide.bs.select, hidden.bs.select, show.bs.select, and shown.bs.select all have a relatedTarget property, whose value is the toggling anchor element.

Event Type    Description
show.bs.select    This event fires immediately when the show instance method is called.
shown.bs.select    This event is fired when the dropdown has been made visible to the user (will wait for CSS transitions, to complete).
hide.bs.select    This event is fired immediately when the hide instance method has been called.
hidden.bs.select    This event is fired when the dropdown has finished being hidden from the user (will wait for CSS transitions, to complete).
loaded.bs.select    This event fires after the select has been initialized.
rendered.bs.select    This event fires after the render instance has been called.
refreshed.bs.select    This event fires after the refresh instance has been called.
changed.bs.select    
This event fires after the select's value has been changed. It passes through event, clickedIndex, isSelected, previousValue.

previousValue is the value of the select prior to being changed. If the select's value has been changed either via the .selectpicker('val'), .selectpicker('selectAll'), or .selectpicker('deselectAll') methods, clickedIndex and isSelected will be null.

Methods

.selectpicker('val')
.selectpicker('selectAll')
.selectpicker('deselectAll')
.selectpicker('render')
.selectpicker('mobile')
.selectpicker('setStyle')
.selectpicker('refresh')
.selectpicker('toggle')
.selectpicker('hide')
.selectpicker('show')
.selectpicker('destroy')

Centos 7默认gcc版本为4.8,有时需要更高版本的,这里以升级至8.3.1版本为例,分别执行下面三条命令即可,无需手动下载源码编译

PS:我在安装的时候已经可以使用11这个版本了

1、安装centos-release-scl

sudo yum install centos-release-scl

2、安装devtoolset,注意,如果想安装7.版本的,就改成devtoolset-7-gcc,以此类推

sudo yum install devtoolset-8-gcc*

3、激活对应的devtoolset,所以你可以一次安装多个版本的devtoolset,需要的时候用下面这条命令切换到对应的版本

scl enable devtoolset-8 bash

大功告成,查看一下gcc版本

gcc -v

显示为 gcc version 8.3.1 20190311 (Red Hat 8.3.1-3) (GCC)

补充:这条激活命令只对本次会话有效,重启会话后还是会变回原来的4.8.5版本,要想随意切换可按如下操作。

**首先,安装的devtoolset是在 /opt/rh 目录下的

每个版本的目录下面都有个 enable 文件,如果需要启用某个版本,只需要执行

source ./enable

所以要想切换到某个版本,只需要执行

source /opt/rh/devtoolset-8/enable

可以将对应版本的切换命令写个shell文件放在配了环境变量的目录下,需要时随时切换,或者开机自启

4、直接替换旧的gcc

旧的gcc是运行的 /usr/bin/gcc,所以将该目录下的gcc/g++替换为刚安装的新版本gcc软连接,免得每次enable

mv /usr/bin/gcc /usr/bin/gcc-4.8.5
ln -s /opt/rh/devtoolset-8/root/bin/gcc /usr/bin/gcc
mv /usr/bin/g++ /usr/bin/g++-4.8.5
ln -s /opt/rh/devtoolset-8/root/bin/g++ /usr/bin/g++
gcc --version
g++ --version

$f = fopen('curl_debug', 'wb');
curl_setopt($ch,CURLOPT_VERBOSE,true);//默认是标准错误输出中
curl_setopt($ch,CURLOPT_STDERR ,$f);//有了该指令,请求过程记录会写到该文件中

记录的文件内容大致如下 :

*   Trying 14.215.177.39...
* TCP_NODELAY set
* Connected to www.baidu.com (14.215.177.39) port 80 (#0)
> GET / HTTP/1.1
Host: www.baidu.com
Accept: */*

< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: no-cache
< Connection: keep-alive
< Content-Length: 14615
< Content-Type: text/html
< Date: Tue, 02 Nov 2023 16:34:39 GMT
< Pragma: no-cache
< Server: BWS/1.1
< Vary: Accept-Encoding
< 
* Connection #0 to host www.baidu.com left intact

curl本身的bug导致如果CURLINFO_HEADER_OUT设置为true时(即开启输出响应头), CURLOPT_VERBOSE会不生效.所以你需要将CURLINFO_HEADER_OUT配置去掉.

“ubuntu从17.10开始,已放弃在 /etc/network/interfaces 里固定IP的配置,即使配置也不会生效,而是改成netplan方式 ,配置写在 /etc/netplan/01-netcfg.yaml 或者类似名称的yaml文件里”

步骤一,修改配置

# 具体文件可能有变化,但一定在 netplan 下
sudo vim /etc/netplan/00-installer-config.yaml

步骤二,修改内容即可: 以下是启用dhcp的情况下,其它自定义IP可以搜索下格式

# This is the network config written by 'subiquity'
network:
  ethernets:
    ens3:
      dhcp4: true
    ens4:
      dhcp4: true
  version: 2

一个基于使用了PHPExcel类的生成excel表格下载文件的PHP用例代码,使用了一些比如设置单元格格式、跨列跨行的功能,作一下记录:

//xls下载
        $sitename = zmf::config('sitename');
        $filename = zmf::time($planInfo['planTime'], 'md') . $planInfo->areaInfo->title . $planInfo->styleInfo->title . Plans::exTypes($planInfo->type).'物料'.$groupByTitle.'清单';
        $charterArr = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');
//引入phpexcel相关库类文件
        Yii::import('application.vendors.phpexcel.*');
        require_once 'PHPExcel.php';
        $objPHPExcel = new PHPExcel();
        // Set document properties
        $objPHPExcel->getProperties()->setCreator($sitename)
            ->setLastModifiedBy($sitename)
            ->setTitle($sitename);

        if($groupBy=='userDetail'){
            $attrKeys = array(
                array(
                    'title' => $groupByTitle,
                    'width' => 20,
                    'field' => $groupByField
                ),
                array(
                    'title' => '服务项目',
                    'width' => 40,
                    'field' => 'userTitle',
                    'color' => 'FF0000',
                ),
                array(
                    'title' => '介绍',
                    'width' => 50,
                    'field' => 'userDesc'
                ),
                array(
                    'title' => '数量',
                    'width' => 10,
                    'field' => 'userNum'
                ),
                array(
                    'title' => '单位',
                    'width' => 20,
                    'field' => 'userUnit'
                ),
                array(
                    'title' => '单价',
                    'width' => 20,
                    'field' => 'userPrice'
                ),
                array(
                    'title' => '总价',
                    'width' => 20,
                    'field' => 'userPriceTotal'
                ),
            );
        }else{
            $attrKeys = array(
                array(
                    'title' => '分区',
                    'width' => 20,
                    'field' => 'zone'
                ),
                array(
                    'title' => '名称',
                    'width' => 40,
                    'field' => 'title'
                ),
                array(
                    'title' => '数量',
                    'width' => 10,
                    'field' => 'num'
                ),
                array(
                    'title' => '单位',
                    'width' => 10,
                    'field' => 'unit'
                ),
//                array(
//                    'title' => '规格',
//                    'width' => 10,
//                    'field' => 'size'
//                ),
//                array(
//                    'title' => '形状',
//                    'width' => 10,
//                    'field' => 'shape'
//                ),
//                array(
//                    'title' => '颜色',
//                    'width' => 10,
//                    'field' => 'color'
//                ),
//                array(
//                    'title' => '材质/种类',
//                    'width' => 10,
//                    'field' => 'material'
//                ),
                array(
                    'title' => '备注',
                    'width' => 50,
                    'field' => '_desc',
                    'horizontal_center'=>false,  //水平居中
                    'mergeColumn'=>5, //横向合并后面单元格数量
                ),
            );
        }

        $attrKeysLen = count($attrKeys);
        $maxCharIdx = $attrKeysLen-1 + array_sum(array_column($attrKeys, 'mergeColumn'));
        $maxChar=$charterArr[$maxCharIdx];
        if($groupBy=='userDetail'){
            //表头
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A1', 'Quotation');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A1')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A1')->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
            $objPHPExcel->getActiveSheet()->getRowDimension('1')->setRowHeight(50);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('A1:' . $charterArr[$attrKeysLen-1] . '1');
            $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(20);
            $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A1')->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID);
            //$objPHPExcel->setActiveSheetIndex(0)->getStyle('A1')->getFill()->getStartColor()->setRGB('F2DCDB');

            //简介
            $str='To:'.$planInfo->userInfo->truename.PHP_EOL.'惊喜时间 Date:'.zmf::time($planInfo->planTime, 'Y/m/d').PHP_EOL.'惊喜地点 Venue: '.$planInfo->areaInfo->title.PHP_EOL.'Tel:400-000-0000'.PHP_EOL.'Email:vip@tell520.com';
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A2', $str);
            $objPHPExcel->getActiveSheet()->getRowDimension('2')->setRowHeight(120);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('A2:' . $charterArr[$attrKeysLen-1] . '2');
            $objPHPExcel->getActiveSheet()->getStyle('A2')->getFont()->setSize(16);
            $objPHPExcel->getActiveSheet()->getStyle('A2')->getFont()->setBold(true);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A2')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->getActiveSheet()->getStyle('A2')->getAlignment()->setWrapText(true);
            //第三排
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A3', '本场惊喜,从活动策划+物料采购+制作设计+惊喜统筹+现场惊喜服务人员:预计'.$userNum.'人');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A3')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A3')->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
            $objPHPExcel->getActiveSheet()->getRowDimension('3')->setRowHeight(50);
            $objPHPExcel->getActiveSheet()->getStyle('A3')->getFont()->setSize(14);
            $objPHPExcel->getActiveSheet()->getStyle('A3')->getFont()->setBold(true);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('A3:' . $charterArr[$attrKeysLen-1] . '3');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A3')->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID);
            //$objPHPExcel->setActiveSheetIndex(0)->getStyle('A3')->getFill()->getStartColor()->setRGB('F2DCDB');

        }else{
            //表头
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A1', $filename);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A1')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A1')->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
            $objPHPExcel->getActiveSheet()->getRowDimension('1')->setRowHeight(50);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('A1:' . $charterArr[$maxCharIdx] . '1');
            $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(20);
            $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setBold(true);
            /*设置公共信息*/
            //第一排
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A2', '日期:' . zmf::time($planInfo->planTime, 'Y/m/d'));
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A2')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('B2', '求婚时间:'.($qiuHunTimeInfo ? $qiuHunTimeInfo['results'] : ''));
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('B2')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('C2', '主角:' . $planInfo->userInfo->truename);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('C2')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('C2:D2');
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('E2', '总部统筹:' . $excUserinfo->truename . '/' . $excUserinfo->phone);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('E2')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('E2:F2');
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('G2', '紧急联系:周旭');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('G2')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('G2:H2');
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('I2', '总部监督:王沛如');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('I2')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('I2:J2');

            //第二排
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A3', '城市:' . $planInfo->areaInfo->title);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A3')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('B3', '场地:' . $placeInfo['title']);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('B3')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('C3', '彩排时间:');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('C3')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('C3:D3');
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('E3', '执行策划:' . $partnerInfo['title'] . '/' . $contactInfo['name'] . '/' . $contactInfo['phone'] . ($contactInfo['otherPhone'] != '' ? '/' . $contactInfo['otherPhone'] : ''));
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('E3')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('E3:F3');
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('G3', '电话:18888888888');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('G3')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('G3:H3');
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('I3', '电话:13888888888');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('I3')->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells('I3:J3');
            $objPHPExcel->getActiveSheet()->getRowDimension('2')->setRowHeight(35);
            $objPHPExcel->getActiveSheet()->getRowDimension('3')->setRowHeight(35);
        }

        //设置标题
        $tkey=4;
        $jump = 0;
        foreach ($attrKeys as $k => $_attr) {
            $_char = $charterArr[$k+$jump];
            $_mergeColumn = $_attr['mergeColumn']??0;
            $_horizontal_center = $_attr['horizontal_center']??true;
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue($_char . $tkey, $_attr['title']);
            $objPHPExcel->setActiveSheetIndex(0)->getColumnDimension($_char)->setWidth($_attr['width']);
            //加粗
            $objPHPExcel->getActiveSheet()->getStyle($_char . $tkey)->getFont()->setBold(true);
            //水平垂直居中
            $objPHPExcel->setActiveSheetIndex(0)->getStyle($_char . $tkey)->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            if ($_horizontal_center) $objPHPExcel->setActiveSheetIndex(0)->getStyle($_char . $tkey)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
            //设置背景色
            $objPHPExcel->setActiveSheetIndex(0)->getStyle($_char . $tkey)->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID);
            //$objPHPExcel->setActiveSheetIndex(0)->getStyle($_char .$tkey)->getFill()->getStartColor()->setRGB('FFFF00');

            if ($_mergeColumn>0) {
                //合并列
                $jump+=$_mergeColumn;
                $_charEnd = $charterArr[$k+$jump];
                $objPHPExcel->setActiveSheetIndex(0)->mergeCells($_char . $tkey.':'.$_charEnd . $tkey);
            }
        }
        $objPHPExcel->getActiveSheet()->getRowDimension($tkey)->setRowHeight(30);
        $pk = 4;
        $colorIndex = 0;
        $totalPrice=0;
        if($groupBy=='userDetail'){
            foreach(['normal','senior','luxury'] as $ver){
                $suppArr=$suppliesArr[$ver];
                if(!$suppArr) continue;
                self::setVersionRow($objPHPExcel,$pk,$suppArr,$ver,$attrKeys,$zoneArr,$charterArr,$versionMoney,$totalMoney,$planInfo);
            }
            //价格汇总
            $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A'.($pk+1), '价格汇总');
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A'.($pk+1))->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A'.($pk+1))->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
            $objPHPExcel->getActiveSheet()->getRowDimension($pk+1)->setRowHeight(40);
            $objPHPExcel->getActiveSheet()->getStyle('A' . ($pk + 1))->getFont()->getColor()->setRGB('FF0000');
            $objPHPExcel->setActiveSheetIndex(0)->mergeCells("A".($pk + 1).":G".($pk + 1));
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A' . ($pk + 1))->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID);
            $objPHPExcel->setActiveSheetIndex(0)->getStyle('A'. ($pk + 1))->getFill()->getStartColor()->setRGB('fdeada');
            $pk++;

            foreach(['normal','senior','luxury'] as $ver){
                if(! $suppArr=$suppliesArr[$ver]) continue;
                $versionName=PlanSupplies::exVersion($ver);
                $vName=$versionName.'价格';
                $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A'.($pk+1), $vName);
                $objPHPExcel->setActiveSheetIndex(0)->getStyle('A'.($pk+1))->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
                $objPHPExcel->setActiveSheetIndex(0)->getStyle('A'.($pk+1))->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
                $objPHPExcel->getActiveSheet()->getRowDimension($pk+1)->setRowHeight(40);
                $objPHPExcel->getActiveSheet()->getStyle('A' . ($pk + 1))->getFont()->getColor()->setRGB('FF0000');
                $objPHPExcel->setActiveSheetIndex(0)->mergeCells("A".($pk + 1).":F".($pk + 1));

                $objPHPExcel->setActiveSheetIndex(0)->setCellValue('G'.($pk+1), $totalMoney[$ver]);
                $objPHPExcel->setActiveSheetIndex(0)->getStyle('G'.($pk+1))->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
                $objPHPExcel->setActiveSheetIndex(0)->getStyle('G' . ($pk+1))->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
                $objPHPExcel->getActiveSheet()->getRowDimension($pk+1)->setRowHeight(40);
                $objPHPExcel->getActiveSheet()->getStyle('G' . ($pk + 1))->getFont()->getColor()->setRGB('FF0000');
                $pk++;
            }
            foreach(['self','add','wait','del'] as $ver){
                $suppArr=$suppliesArr[$ver];
                if(!$suppArr) continue;
                self::setVersionRow($objPHPExcel,$pk,$suppArr,$ver,$attrKeys,$zoneArr,$charterArr,$versionMoney,$totalMoney,$planInfo);
            }
        }else{
            foreach ($suppliesArr as $ver=>$suppArr) {//分类数组
                $versionName=PlanSupplies::exVersion($ver);
                if ($ver!='normal') {
                    $vName = $ver == 'normal' ? $versionName . '物料' : $versionName . '增加物料';
                    //版本分类
                    $objPHPExcel->setActiveSheetIndex(0)->setCellValue('A' . ($pk + 1), $vName);
                    $objPHPExcel->setActiveSheetIndex(0)->getStyle('A' . ($pk + 1))->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
                    $objPHPExcel->setActiveSheetIndex(0)->getStyle('A' . ($pk + 1))->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
                    $objPHPExcel->getActiveSheet()->getRowDimension($pk + 1)->setRowHeight(40);
                    $objPHPExcel->getActiveSheet()->getStyle('A' . ($pk + 1))->getFont()->getColor()->setRGB('FF0000');
                    $objPHPExcel->setActiveSheetIndex(0)->mergeCells("A" . ($pk + 1) . ":I" . ($pk + 1));
                    $pk++;
                }
                foreach ($suppArr as $arr) {//分类数组
                    $pre = $pk + 1;
                    $_row = 0;
                    foreach ($arr as $val) {
                        if (trim($val['title']) == '') continue; //物料名称是空的行跳过
                        $_row++;
                        $jump = 0;
                        foreach ($attrKeys as $k => $_attr) {
                            if ($_attr['field'] != '') {
                                $_value = $val[$_attr['field']];
                                switch ($_attr['field']) {
                                    case 'type':
                                        if($_value==999999){
                                            $_value='其他相关服务';
                                        }elseif($_value==999998){
                                            $_value='工具类';
                                        }else{
                                            $_value=$typeArr[$_value];
                                        }
                                        break;
                                    case 'zone':
                                        $_value = $_value > 0 ? $zoneArr[$_value] : '其他项目';
                                        break;
                                    case 'num':
                                        if($groupBy=='userDetail'){
                                            $_value .= Supplies::exUnits($val['unit']);
                                        }
                                        break;
                                    case 'unit':
                                        $_value = Supplies::exUnits($val['unit']);
                                        break;
                                    case '_desc':
                                        $_value = $_value != '' ? $_value : ($val['size']);
                                        break;
                                    default:
                                        break;
                                }
                            } else {
                                $_value = '';
                            }

                            //设置内容
                            $_char = $charterArr[$k+$jump];
                            $_cell = $_char . ($pk + 1);
                            $_mergeColumn = $_attr['mergeColumn']??0;
                            $_horizontal_center = $_attr['horizontal_center']??true;
                            $objPHPExcel->setActiveSheetIndex(0)->setCellValue($_cell, $_value);
                            //水平垂直居中
                            $objPHPExcel->setActiveSheetIndex(0)->getStyle($_cell)->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
//                            if ($_attr['field'] != 'desc' && $_attr['field'] != 'field') {
                            if ($_horizontal_center) {
                                $objPHPExcel->setActiveSheetIndex(0)->getStyle($_cell)->getAlignment()->setHorizontal(PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
                            }
                            if ($_mergeColumn>0) {
                                //合并列
                                $jump+=$_mergeColumn;
                                $_charEnd = $charterArr[$k+$jump];
                                $objPHPExcel->setActiveSheetIndex(0)->mergeCells($_cell.':'.$_charEnd . ($pk + 1));
                            }
                        }
                        $totalPrice+=$val['userPrice']*$val['num'];
                        ++$pk;
                        $objPHPExcel->getActiveSheet()->getRowDimension($pk)->setRowHeight(30);
                    }
                    ++$colorIndex;
                    if ($_row > 1) {
                        //合并单元格
                        $objPHPExcel->setActiveSheetIndex(0)->mergeCells('A' . $pre . ':A' . $pk);
                    }
                }
            }
        }
        $styleArray = array(
            'borders' => array(
                'allborders' => array(
                    'style' => PHPExcel_Style_Border::BORDER_THIN
                )
            )
        );
        $objPHPExcel->getActiveSheet()->getStyle('A1:'.$maxChar.($pk))->applyFromArray($styleArray);

        /*
          // 实例化插入图片类
          $objDrawing = new PHPExcel_Worksheet_Drawing();
          // 设置图片路径 切记:只能是本地图片
          $objDrawing->setPath('');
          // 设置图片高度
          $objDrawing->setWidth(200);
          // 设置图片要插入的单元格
          $objDrawing->setCoordinates('A18');
          // 设置图片所在单元格的格式
          $objDrawing->setOffsetX(10);
          $objDrawing->setOffsetY(10);
          $objDrawing->setRotation(0);
          $objDrawing->getShadow()->setVisible(true);
          $objDrawing->getShadow()->setDirection(50);
          $objDrawing->setWorksheet($objPHPExcel->getActiveSheet());
         */


        // Rename worksheet
        $objPHPExcel->getActiveSheet()->setTitle('活动策划公司');
        // Set active sheet index to the first sheet, so Excel opens this as the first sheet
        $objPHPExcel->setActiveSheetIndex(0);
        // Redirect output to a client’s web browser (Excel2007)
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $filename . '.xlsx"');
        header('Cache-Control: max-age=0');
        // If you're serving to IE 9, then the following may be needed
        header('Cache-Control: max-age=1');
        // If you're serving to IE over SSL, then the following may be needed
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
        header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
        header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
        header('Pragma: public'); // HTTP/1.0
        $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
        $objWriter->save('php://output');