精华内容
下载资源
问答
  • 最近公司前端数据需要用到表格展示,又要在前端做筛选过滤排序。 考虑到表格性能原因,最终选择了vxe-table 第一步 先打开

       最近公司前端数据需要用到表格展示,又要在前端做筛选过滤排序。

        考虑到表格性能原因,最终选择了vxe-table 

      自定义筛选样例。类似的请自行实现。

        第一步

       npm install xe-utils@3 vxe-table@next 

    第二main.ts里面

     import { App, createApp } = 'vue'
            import 'xe-utils'
            import VXETable from 'vxe-table'
            import 'vxe-table/lib/style.css'
    
            function useTable (app: App) {
              app.use(VXETable)
    
            }
    
            createApp(App).use(useTable).mount('#app')

     第三,新建vue文件,注册全局组件,filter-render与自定义组件名字一样就行。filters为传过去的参数。

       <vxe-table
              border
              height="400"
              :data="tableData">
              <vxe-column type="seq" width="60"></vxe-column>
              <vxe-column field="name" title="文本筛选" :filters="[{data: null}]" :filter-render="{name: 'FilterInput'}"></vxe-column>
              <vxe-column field="role" title="实现条件的筛选" :filters="[{data: {type: 'has', name: ''}}]" :filter-render="{name: 'FilterComplex'}"></vxe-column>
              <vxe-column field="age" title="实现内容的筛选" :filters="[{data: {vals: [], sVal: ''}}]" :filter-render="{name: 'FilterContent'}"></vxe-column>
              <vxe-column field="address" title="实现Excel复杂的筛选" sortable :filters="[{data: {vals: [], sVal: '', fMenu: '', f1Type:'', f1Val: '', fMode: 'and', f2Type: '', f2Val: ''}}]" :filter-render="{name: 'FilterExcel'}"></vxe-column>
            </vxe-table>
       import { defineComponent, ref } from 'vue'
    
            export default defineComponent({
              setup  () {
                const tableData = ref([
                  { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: '28', address: 'Shenzhen' },
                  { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: '22', address: 'Guangzhou' },
                  { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: '32', address: 'Shanghai' },
                  { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: '23', address: 'Shenzhen' },
                  { id: 10005, name: 'Test5', role: 'Develop', sex: 'Women', age: '30', address: 'Shanghai' },
                  { id: 10006, name: 'Test6', role: 'Designer', sex: 'Women', age: '21', address: 'Shenzhen' },
                  { id: 10007, name: 'Test7', role: 'Test', sex: 'Man', age: '29', address: 'Shenzhen' },
                  { id: 10008, name: 'Test8', role: 'Develop', sex: 'Man', age: '35', address: 'Shenzhen' }
                ])
    
                return {
                  tableData
                }
              }
            })
    import FilterInput from '@/components/filter-methods/FilterInput.vue'
    
    
    //全局组件
    app.component(FilterInput.name, FilterInput)

    第四,新建js文件,将模板与重置方法,筛选方法填进去。这里筛选方法请自行根据要求来过滤。

    import XEUtils from 'xe-utils'
    import VXETable from 'vxe-table'
    
    // 创建一个简单的输入框筛选
    VXETable.renderer.add('FilterInput', {
      // 筛选模板
      renderFilter(renderOpts, params) {
        return [
          <filter-input key={params.columnIndex} params={params}></filter-input>
        ]
      },
      showFilterFooter: false,
      // 重置数据方法
      filterResetMethod(params) {
        const { options } = params
        options.forEach(option => {
          option.data = ''
        })
      },
      // 重置筛选复原方法(当未点击确认时,该选项将被恢复为默认值)
      filterRecoverMethod(option) {
        option.data = ''
      },
      // 筛选方法
      filterMethod(params) {
        const { option, row, column } = params
        const { data } = option
        if (!data) {
          return false
        }
        //切割空格
        let arr = data.split(' ')
        if (arr.length > 1) {
          arr = arr.filter(item => item)
        }
        let cellValue = XEUtils.get(row, column.property)
        if (cellValue) {
          let value = false
          for (let index = 0; index < arr.length; index++) {
            const element = arr[index]
            if (cellValue.toUpperCase().indexOf(element.toUpperCase()) > -1) {
              value = true
              return true
            }
          }
          return value
        }
      }
    })

    页面

    <template>
      <div class="my-filter-input">
        <vxe-input type="text" v-model="demo1.option.data" placeholder="支持回车筛选" @keyup="keyupEvent" @input="changeOptionEvent"></vxe-input>
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, PropType, reactive } from 'vue'
    import { VxeInputEvents, VxeGlobalRendererHandles } from '../../../../../types/index'
    
    export default defineComponent({
      name: 'FilterInput',
      props: {
        params: Object as PropType<VxeGlobalRendererHandles.RenderFilterParams>
      },
      setup (props) {
        const demo1 = reactive({
          option: null as any
        })
    
        const load = () => {
          const { params } = props
          if (params) {
            const { column } = params
            const option = column.filters[0]
            demo1.option = option
          }
        }
    
        const changeOptionEvent = () => {
          const { params } = props
          const { option } = demo1
          if (params && option) {
            const { $panel } = params
            const checked = !!option.data
            $panel.changeOption(null, checked, option)
          }
        }
    
        const keyupEvent: VxeInputEvents.Keyup = ({ $event }) => {
          const { params } = props
          if (params) {
            const { $panel } = params
            if ($event.keyCode === 13) {
              $panel.confirmFilter($event)
            }
          }
        }
    
        load()
    
        return {
          demo1,
          changeOptionEvent,
          keyupEvent
        }
      }
    })
    </script>
    
    <style scoped>
    .my-filter-input {
      padding: 10px;
    }
    </style>
    

    参考来源https://gitee.com/xuliangzhan_admin/vxe-table/blob/master/examples/plugins/table/renderer/components/FilterInput.vue#

    展开全文
  • 201703:SuiteCRM自定义筛选界面

    千次阅读 2017-04-04 22:15:02
    SuiteCRM自定义筛选界面 (Popup) 筛选界面显示自定义 自定义筛选条件字段 关于列表排序

    SuiteCRM自定义筛选界面 (Popup)


    1. 筛选界面显示自定义
    2. 自定义筛选条件字段
    3. 关于列表排序

    Popup视图关系图

    这里写图片描述

    1. 筛选界面显示自定义

    定义文件结构

    <?php
    $popupMeta = array (
        'moduleMain' => 'HAC_Bank_Accounts',
        'varName' => 'HAC_Bank_Accounts',
        //排序字段,可以扩展成多个字段
        'orderBy' => 'hac_bank_accounts.name',
        'whereClauses' => array (
              //请求参数到数据库字段的映射
    ),
        //追加查询语句
        'whereStatement' => ''
        'searchInputs' => array (
      //请求参数名
    ),
        'searchdefs' => array (
      //搜索字段定义
    ),
        'listviewdefs' => array (
      //结果列表字段定义
    )
    );
    

    1.增加字段和自定义

    在对应定义添加字段定义即可:

    'CONTRACT_NAME' =>
           array (
                //字段类型
                'type' => 'relate',
                'default' => true,
                //是否在工作室中显示
                'studio' => 'visible',
                //标签名,可自定义
                'label' => 'LBL_CONTRACT_NAME_1',
                //宽度
                'width' => '24%',
                //对应模块字段名,可省略
                'name'  => 'contract_name'
                //附加参数
                'displayParams'=> array() 
                //...
            ),
    

    对于列表定义注意需设置
    'default' => true,,否则不会显示列

    2. Popup视图的调用

    前端调用

    open_popup(
        module_name, //模块名
        width,       //窗口宽度
        height,      //窗口高度
        initial_filter,       //追加查询条件
        close_popup,          //是否自动关闭,,默认true
        hide_clear_button,    //是否隐藏清除按钮,默认true
        popup_request_data,   //请求报文,处理选择后的回调
        popup_mode,           //POPUP模式(多选和单选),多选时,返回记录ID为键数组
        create,               //默认false,是否可创建模块
        metadata              //指定使用的popup定义文件名称
    )

    请求报文定义,可附加在编辑界面的字段定义中

    popupRequestData = {
              "call_back_function" : "setFuncReturn",//回调函数
              "form_name" : "EditView",
              //返回值和页面元素映射
              "field_to_name_array" : {
                   "id":"line_function_id",
                   "name":"line_function_name",
                   "func_icon":"line_func_icon",
              }
         }

    3. Popup列表添加字段
    包括在自定义列表表头和添加非本模块字段,修改表头通过添加label可以实现,添加字段包块以下两步:
    其一、在popupdef的listviewdefs中添加字段定义

    'CONTRACT_NUMBER' =>
            array(
                'type'  => 'varchar',
                'label' => 'LBL_CONTRACT_NUMBER',
                'width' => '10%',
                'name'  => 'contract_number',
                'studio' => 'visible',
                'default' => true,
           ),

    其二、对其进行赋值

    重写模块的get_list_view_data方法:

    function get_list_view_data() {
            global $app_list_strings,$db;
            //get_list_view_array与get_list_view_data相同
            $line_fields = $this->get_list_view_array();
            if(isset($_REQUEST['popuptype']) && $_REQUEST['popuptype'] == '<特定List>'){
                    //获取当前
                    $line_fields['<自定义字段(大写)>'] = <要附的值>;
                }
            }
            return $line_fields;
        }

    后端控制

    在后台PopupView中,通过设置请求参数中的metadata,sqlClause参数控制Popup视图的调用和控制条件

    class <ModuleName>ViewPopup extends ViewPopup
    {
         function Display() {
              if ($_REQUEST['<Params>']!= <Value>){
                  $_REQUEST['metadata'] = '<Def文件名>';
                  //可以附加其他参数
              }
              parent::Display();
          }
    }
    

    3. 自定义筛选条件字段

    主要针对非本模块字段,对于本模块字段在searchdefs中添加即可

    几点注意:
    1. 对于非数据库字段,只要在verdefs中有定义,框架仍会当成本模块字段来拼接SQL语句,除非它为空,所以一般只在popupdef中定义字段
    2. 关联字段创建必须有id属性,无论是在verdef还是popupdef中
    3. 对于非本模块字段的查询条件需要手动处理,追加SQL条件,常用过的有EXISTS语句
    4. 对于非本模块字段在查询结果界面不会保留上次查询条件,需要查询字段的回写,即在查询结果页面保留查询条件

    1. 添加一般类型字段

    第一步 在popupdef中添加字段定义,不需要添加到verdefs中

    'contract_number' =>
            array(
                'type'  => 'varchar',
                'label' => 'LBL_CONTRACT_NUMBER',
                'width' => '10%',
                'name'  => 'contract_number',
            ),

    第二步 在PopupView中设置处理查询参数和字段回写
    处理REQUEST参数,并在页面嵌入js代码实现查询条件回写

    //字段名有advanced后缀
    if(isset($_REQUEST['<字段名>']) && $_REQUEST['<字段名>'] != ''){
                //对字段参数进行预处理,保存到重命名字段中,并清空原字段
                $origin_value = $_REQUEST['<字段名>'];
                $_REQUEST['<重命名字段名>'] = $_REQUEST['<字段名>'];
                $_REQUEST['<字段名>'] = '';
                parent::Display();
                echo '<script>$("#<字段名>").val("'.origin_value .'");</script>';
    }

    第三步 追加查询条件
    在popupdef中根据传入参数是否为空,拼接where条件并添加到whereStatement属性中

    $condition = "";
    if(isset($_REQUEST['<重命名字段名>']) && $_REQUEST['<重命名字段名>']!=""){
        $condition .= " EXISTS (<SQL语句>) ";
    }
    ...
    'whereStatement'=>....$condition,
    

    2. 添加关联字段
    对于查询字段是关联字段的需要在popupdef中定义关联字段和id字段,并且组合的查询条件相比于一般字段更加复杂

    第一步 在popupdef中定义字段

    'hit_racks_s' =>
            array (
                    'name' => 'hit_racks_s',
                    'vname' => 'LBL_HIT_RACKS_S',
                    'type' => 'relate',
                    'default' => true,
                    'id_name' => 'hit_racks_id_s',
                    'ext2'   => 'HIT_Racks',
                    'module' => 'HIT_Racks',
                    'rname' => 'name',
                    'quicksearch' => 'enabled',
                    'studio' => 'visible',
                    'width'  => '10%'
           ),
    'hit_racks_id_s' =>
        array (
                'name' => 'hit_racks_id_s',
                'vname' => 'LBL_HIT_RACKS_ID_S',
                'type' => 'id',
                'len' => 36,
                'size' => '20',
     ),
    

    第二步和第三步与一般字段类似;

    3. 添加布尔值字段

    popupdef中定义:

    'has_sub_location' =>
        array(
            'type' => 'bool',
            'label' => 'LBL_HAS_SUB_LOCATION',
            'width' => '10%',
            'default' => true,
            'name' => 'has_sub_location',   
        ),

    bool类型的查询条件在界面上以下拉列表呈现,且以“0”、“1”多为值,未选择时为空,不会加入查询条件

    3. 关于列表排序

    1. 默认排序
    排序字段:在popupdef中通过“orderBy”定义
    排序方式:

    //默认排序方式 asc
     $desc = $this->getSessionVariable($varName, $sortBy."S");
    
        if (empty($desc))
            {
                $desc = $defaultOrder;
            }
            $defaultOrder = $desc ? 'desc' : 'asc';
            $orderByValue = $defaultOrder;
    
    //ListView的setQuery方法可设置order by
    if(!$allowOrderByOveride) {
            $this->query_orderby = $orderBy;
            return;
        }
        $this->getOrderBy($varName, $orderBy);
    
    ...
    
    //通过请求参数修改排序方式
    http://....lvso=DESC&HAT_Assets2_HAT_ASSETS_ORDER_BY=asset_group
    
    

    注:
    对于列表中有非本模块字段的,框架并不会进行排序,可以去掉排序功能,或在PopupView中进行处理

    
    //一种参考
    <script>
     $(".list.view thead tr th:eq(<所在列>)").children().eq(1).hide();
    $(".list.view thead tr th:eq(<所在列>)").children().eq(0).children().eq(0).attr("href","#");
    </script>
    展开全文
  • vue 自定义 移动端筛选条件

    千次阅读 2018-04-15 21:01:00
    1.创建组件 components/FilterBar/FilterBar.vue &lt;template&gt; &lt;div class="filterbar" :style="{'top': top + 'px'}"&gt; &lt;div class="container"...

    1.创建组件

    components/FilterBar/FilterBar.vue

    <template>
      <div class="filterbar" :style="{'top': top + 'px'}">
        <div class="container">
          <div class="row">
            <div
              class="col"
              :class="{'selected': index == selectedIndexMenu}"
              @click="handleShowDialog(barMenu, index)"
              v-for="(barMenu, index) in barMenus"
              :key="index"
            >
              {{barMenu.name}}<span :class="index == selectedIndexMenu ? barMenu.selectIcon : barMenu.defaultIcon"></span>
            </div>
          </div>
          <filter-bar-pop
            :filterTop="top"
            :show-dialog="isShow"
            :hasTabHeader="hasTabHeader"
            :menu="selectedMenu"
            @changeTab="handleChangeTab"
            @changeMainItem="handleChangeMainItem"
            @changeSelect="changeSelect"
            @closeDialog="handleCloseDialog"
          ></filter-bar-pop>
        </div>
      </div>
    </template>
    
    <script>
      import FilterBarPop from './FilterBarPop'
      export default {
        props: {
          barMenus: {
            type: Array,
            required: true,
            validator: function (value) {
              //TODO:验证数据有效性
              return true;
            }
          },
          top: String
        },
        data() {
          return {
            isShow: false,
            hasTabHeader: false,
            selectedMenu: {},
            selectedIndexMenu: undefined
          }
        },
        methods: {
          handleShowDialog(menu, index) {
            this.isShow = true;
            this.selectedMenu = menu;
            this.selectedIndexMenu = index;
            if (menu.showTabHeader) {
              this.hasTabHeader = true;
            } else {
              this.hasTabHeader = false;
            }
            let _menu = JSON.parse(JSON.stringify(menu));
            _menu.tabs = {};
            this.$emit('showDialog', _menu);
          },
          handleChangeTab(tab) {
            this.$emit('changeTab', tab.index);
          },
          handleChangeMainItem(mainItem) {
            let _mainItem = JSON.parse(JSON.stringify(mainItem));
            this.$emit('changeMainItem', _mainItem);
          },
          handleCloseDialog() {
            this.isShow = false;
            this.selectedIndexMenu = -1;
            this.$emit('closeDialog');
          },
          changeSelect() {
            var selectData = [];
            this.barMenus.forEach(function (barMenu, index, arr) {
              let _selectBarData = {};
              // console.log("barMenu.name: " + barMenu.name);
              _selectBarData.name = barMenu.name;
              _selectBarData.value = barMenu.value;
              _selectBarData.tab = {};
              let tab = barMenu.tabs[barMenu.selectIndex];
              // console.log("tab.name: " + tab.name);
              _selectBarData.tab.name = tab.name;
              _selectBarData.tab.value = tab.value;
              let mainItem = tab.detailList[tab.selectIndex];
              _selectBarData.tab.mainItem = {}
              // console.log("mainItem.name: " + mainItem.name);
              _selectBarData.tab.mainItem.name = mainItem.name;
              _selectBarData.tab.mainItem.value = mainItem.vaule;
              let subItem = false;
              if (mainItem.list) {
                subItem = mainItem.list[mainItem.selectIndex];
                _selectBarData.tab.mainItem.subItem = {};
                // console.log("subItem.name: " + subItem.name);
                _selectBarData.tab.mainItem.subItem.name = subItem.name;
                _selectBarData.tab.mainItem.subItem.value = subItem.value;
              } else {
                _selectBarData.tab.mainItem.subItem = subItem;
              }
              selectData.push(_selectBarData);
            });
            this.$emit('changeSelect', selectData);
          }
        },
        components: {
          'filter-bar-pop': FilterBarPop
        }
      }
    </script>
    
    <style lang="scss">
      .filterbar {
        width: 100%;
        background: #fff;
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        .container {
          width: 100%;
          outline: 1px solid #DBDCDE;
          position: relative;
          .row {
            display: flex;
            display: -ms-flexbox;
            display: -moz-box;
            display: -webkit-box;
            display: -webkit-flex;
            flex-direction: row;
            -webkit-flex-direction: row;
            justify-content: space-around;
            -webkit-box-pack: space-around;
            -moz-box-pack: space-around;
            -ms-flex-pack: space-around;
            width: 90%;
            height: 40px;
            margin: 0 auto;
            line-height: 40px;
            .selected {
              color: orange;
            }
            .col {
              span {
                margin-left: 5px;
                vertical-align: middle;
              }
            }
          }
        }
      }
    </style>

    components/FilterBar/FilterBarPop.vue

    <template>
      <transition name="fade">
        <div class="filterbarpop-wrap" v-if="visible" :style="{'top': bgTop + 'px'}">
          <div class="filterbarpop-bg" @click="closeDialog" :style="{'top': bgTop + 'px'}"></div>
          <div class="filterbarpop">
            <div class="tab-bar" v-show="hasTabHeader">
              <a href="javascript:;" :style="{'flex': column}" role="button" @click="clickTab(tab, index)" v-for="(tab, index) in menu.tabs"
                :class="{'selected': selectIndexTab == index}"><span :class="tab.icon"></span>{{tab.name}}</a>
            </div>
            <div class="main">
              <div class="main-sidebar" :class="{'full-line': !items,'bg-style':items,'line-style':!items,}">
                <div v-if="menu.type !== 'filter'" class="item" @click="clickSidebar(sidemenu, index)" v-for="(sidemenu, index) in sideMenus.detailList"
                  :class="{'selected': currentSelectIndex == index}">
                  <span :class="sidemenu.icon"></span>{{ sidemenu.name }}
                </div>
                <div v-if="menu.type == 'filter'" v-for="(sm, _index) in menu.tabs">
                  <div class="filter-name">{{sm.name}}</div>
                  <div class="filter-item">
                    <span v-for="(sidemenu, index) in sm.detailList" class="item-operation" @click="clickFilterbar(sm, _index, index)" :class="{'multi-selected': sidemenu.selectIndex == index}">
                    {{ sidemenu.name }}
                    </span>
                  </div>
                </div>
                <div v-if="menu.type == 'filter'" class="filter-btns">
                  <a href="javascript:;" role="button" @click="handleClean">取消</a>
                  <a href="javascript:;" role="button" @click="handleEnsure">确认</a>
                </div>
              </div>
              <div class="main-list line-style" v-if="items">
                <span class="item" @click="clickItem(item, index)" v-for="(item, index) in items.list" :class="{'selected': currentSelectIndex == sideMenus.selectIndex && items.selectIndex == index}">{{item.name}}</span>
              </div>
            </div>
          </div>
        </div>
      </transition>
    </template>
    
    <script>
      export default {
        props: {
          menu: {
            type: Object
          },
          showDialog: {
            type: Boolean,
            default: true
          },
          hasTabHeader: {
            type: Boolean,
            default: true
          },
          filterTop: {
            type: String
          }
        },
        data() {
          return {
            selectIndexTab: 0,
            currentSelectIndex: 0,
            sideMenus: {},
            items: {},
            column: '',
            visible: false,
            top: 1,
            bgTop: 0,
            range: {}
          }
        },
        mounted() {
          this.bgTop = document.querySelector('.filterbar').offsetHeight + this.filterTop / 1;
        },
        watch: {
          showDialog(v) {
            this.visible = v;
            if (v) {
              //初始化数据
              this.initData();
            }
          },
          menu(m) {
            //根据tabs数量计算列宽
            this.column = '0 0 ' + 100 / m.tabs.length + '%';
            //初始化数据
            this.initData();
          }
        },
        methods: {
          //初始化数据
          initData(tabIndex) {
            var tmpTabIndx = 0;
            tabIndex === undefined ? tmpTabIndx = this.menu.selectIndex : tmpTabIndx = tabIndex
            //判断tabindex的范围是否在数组内
            if (tmpTabIndx >= 0 && tmpTabIndx < this.menu.tabs.length) {
              this.selectIndexTab = tmpTabIndx;
            } else {
              this.selectIndexTab = 0;
            }
            //确认选中tab的一级列表
            this.sideMenus = this.menu.tabs[this.selectIndexTab];
            //如果当前选中tab是对应选中结果的tab
            // debugger;
            if (this.selectIndexTab == this.menu.selectIndex) {
              this.currentSelectIndex = this.sideMenus.selectIndex;
            }
            // else{
            //   this.sideMenus.selectIndex = -1;
            //   this.currentSelectIndex = -1;
            // }
            //判断是否包含二级列表,包含则赋值
            //如果一级列表的选中状态正确,则查询二级列表
            if (this.currentSelectIndex >= 0 && this.currentSelectIndex < this.sideMenus.detailList.length) {
              //判断是否有二级列表
              if (this.sideMenus.detailList[this.currentSelectIndex].list) {
                this.items = this.sideMenus.detailList[this.currentSelectIndex];
              } else {
                //不显示二级列表
                this.items = false;
              }
            } else { //如果一级列表选中状态不正确,按第一项的的数据判断
              //判断是否有二级列表
              if (this.sideMenus.detailList[0].list) {
                //显示空的二级列表
                this.items = [];
              } else {
                //不显示二级列表
                this.items = false;
              }
            }
          },
          //修改选项
          changeSelect(index) {
            //记录tabIndex
            this.menu.selectIndex = this.selectIndexTab;
            //记录一级列表选项
            this.sideMenus.selectIndex = this.currentSelectIndex;
            if (this.items) {
              //确认二级列表选项
              this.items.selectIndex = index;
              //显示名称
              this.menu.name = this.items.list[this.items.selectIndex].name;
              this.menu.value = this.items.list[this.items.selectIndex].value;
            } else {
              //显示名称
              this.menu.name = this.sideMenus.detailList[this.sideMenus.selectIndex].name;
              this.menu.value = this.sideMenus.detailList[this.sideMenus.selectIndex].value;
            }
            this.$emit('changeSelect');
            this.closeDialog();
          },
          // 帅选修改选项
          changeRangeSelect() {
            this.menu.name = '筛选';
            for(var i in this.range){
              if(Object.keys(this.range[i].value).length == 0){
                delete this.range[i]
              }
            }
    
            this.menu.value = Object.keys(this.range).length > 0 ? this.range : '';
            this.$emit('changeSelect');
            this.closeDialog();
          },
          // 选择Tab菜单
          clickTab(tab, index) {
            if (index !== this.selectIndexTab) {
              //根据选中的tab初始化数据
              this.initData(index);
              this.$emit('changeTab', {
                tab,
                index
              })
            }
          },
          // 筛选方法
          clickFilterbar(v, I, i) {
            v.detailList[i].selectIndex = i;
            // debugger
            if(!this.range[I]){
              this.range[I] = {name: v.name, value: {}};
              this.range[I].value[i] = v.detailList[i].value;
            } else {
              if(!this.range[I].value[i]){
                this.range[I].value[i] = v.detailList[i].value;
              } else {
                delete this.range[I].value[i];
                v.detailList[i].selectIndex = -1;
              }
            }
          },
          // 点击左侧列表
          clickSidebar(v, i) {
            if (this.currentSelectIndex !== i) {
              this.currentSelectIndex = i;
              //存在二级列表
              if (this.sideMenus.detailList[this.currentSelectIndex].list) {
                this.items = this.sideMenus.detailList[this.currentSelectIndex];
              } else {
                //只有一级列表,记录选项,退出
                this.changeSelect();
              }
              this.$emit('changeMainItem', {
                v,
                i
              });
            }
          },
          // 点击右侧列表
          clickItem(v, i) {
            //只有一级列表,记录选项,退出
            this.changeSelect(i);
          },
          // 关闭弹框
          closeDialog() {
            this.visible = false;
            this.$emit('closeDialog');
          },
          // 提交已选内容
          handleEnsure() {
            this.changeRangeSelect();
            this.$emit('changeMainItem', this.range);
            // this.closeDialog();
          },
          // 清除已选内容
          handleClean() {
            this.menu.tabs.map(item => {
              item.detailList.map(_item => {
                _item.selectIndex = -1;
              })
            });
            this.range = {};
          }
        }
      }
      /**
        TODOS:
        1. 需要一个属性去辨别帅选项
        2. 多选
        3. 添加多选框
    
       */
    </script>
    
    <style lang="scss">
      .fade-enter-active,
      .fade-leave-active {
        transition: opacity .5s
      }
      .fade-enter,
      .fade-leave-active {
        opacity: 0
      }
      .filterbarpop-wrap {
        position: fixed;
        width: 100%;
        top: 0;
        bottom: 0;
        left: 0;
        overflow: hidden;
        max-height: 100%;
        .filterbarpop-bg {
          position: fixed;
          top: 0;
          bottom: 0;
          left: 0;
          width: 100%;
          background: rgba(0, 0, 0, .6);
        }
        .filterbarpop {
          position: absolute;
          width: 100%;
          border-top: 1px solid #ccc;
          .tab-bar {
            width: 100%;
            display: flex;
            display: -ms-flexbox;
            display: -moz-box;
            display: -webkit-box;
            display: -webkit-flex;
            flex-directives: row;
            -webkit-flex-direction: row;
            align-items: center;
            -webkit-align-items: center;
            -webkit-box-align: center;
            -moz-box-align: center;
            -ms-flex-align: center;
            height: 40px;
            .selected {
              border-bottom: 2px solid orange;
              box-sizing: border-box;
            }
            a {
              background: #fff;
              height: 100%;
              line-height: 40px;
              text-decoration: none;
              color: #323232;
              text-align: center;
            }
          }
          .main {
            display: flex;
            display: -webkit-flex;
            flex-direction: row;
            -webkit-flex-direction: row;
            height: 250px;
            background: #fff;
            .main-sidebar {
              flex: 0 0 50%;
              overflow: auto;
              width: 100%;
            }
            .full-line {
              flex: 0 0 100%;
              div {
                text-align: left; // text-indent: 1.5em;
              }
            }
            .item-operation {
              display: inline-block;
              padding: 10px 4px 10px 4px;
              border: 1px solid rgb(91, 149, 255);
              border-radius: 3px;
              height: 0;
              line-height: 1px;
            }
            .multi-selected {
              background: rgb(91, 149, 255);
              color: #fff !important;
            }
            .filter-item {
              border-top: 1px solid #ccc;
              border-bottom: 1px solid #ccc;
              padding: 13px 0 5px 10px;
              span {
                margin-right: 8px;
                margin-bottom: 8px;
              }
            }
            .filter-name {
              padding: 10px 0 10px 10px;
            }
            .filter-btns {
              display: flex;
              display: -webkit-flex;
              flex-direction: row;
              -webkit-flex-direction: row;
              justify-content: space-around;
              -webkit-box-pack: space-around;
              -moz-box-pack: space-around;
              -ms-flex-pack: space-around;
              position: absolute;
              bottom: -40px;
              width: 100%;
              line-height: 40px;
              z-index: 100;
              background: #fff;
              a {
                display: block;
                width: 100%;
                text-align: center;
                text-decoration: none;
                color: #ccc;
                border-top: 1px solid #ccc;
                &:last-child {
                  background: #39f;
                  color: #fff;
                }
              }
            }
            .main-list {
              flex: 0 0 50%;
              overflow: auto;
              span:active {
                background: #f5f5f5;
              }
            }
            .line-style {
              .item {
                text-align: left;
                margin-left: 10px;
                padding-left: 15px;
                border-bottom: 1px solid #ccc;
                position: relative;
                &.selected {
                  color: orange;
                  border-color: orange;
                  span {
                    color: orange;
                  }
                }
                .checkbox {
                  position: absolute;
                  right: 50px;
                  top: 10px;
                }
              }
            }
            .bg-style {
              .item {
                background-color: #f5f5f5;
                &.selected {
                  background-color: #FFF;
                }
              }
            }
            .item {
              display: inline-block;
              height: 40px;
              background: #fff;
              line-height: 40px;
              width: 100%;
              text-decoration: none;
              color: #444;
              span {
                font-size: 14px;
                color: #888;
                margin-right: 10px;
                vertical-align: middle;
              }
              &:active {
                color: #fff;
              }
            }
          }
        }
      }
    </style>

    2.页面调用

    pages/FilterBarTest

    <!-- 移动端筛选条件 测试页 -->
    <template>
      <div>
        <!-- 标题栏 -->
        <x-header title="移动端筛选条件 测试页"></x-header>
        <!-- 内容部分 -->
        <FilterBar
          top="40"
          :barMenus="barMenus"
          @showDialog="handleShowDialog"
          @closeDialog="handleCloseDialog"
          @changeTab="handleChangeTab"
          @changeMainItem="handleChangeMainItem"
          @changeSelect="changeData">
        </FilterBar>
      </div>
    </template>
    
    <script>
      import { XHeader } from 'vux'
      // 引入组件
      import FilterBar from '../../components/FilterBar/FilterBar.vue'
      // 引入假数据
      import barMenus from './data.js';
    
      export default {
        name: 'FilterBarTest',
        components: {
          XHeader,
          FilterBar,
        },
        data(){
          return {
            barMenus: barMenus
          }
        },
        methods: {
          handleShowDialog(v) {
            // console.log(v);
          },
          handleCloseDialog(v) {
            // console.log(v);
          },
          handleChangeTab(v) {
            // console.log(v);
          },
          handleChangeMainItem(v) {
            // console.log(v)
          },
          changeData(v) {
            console.log(v);
          }
        }
      }
    </script>
    
    <style lang="scss" scoped>
      //
    </style>
    

    data.js

    export default [
    {
      name: '附近',
      icon: '',
      value: 'area',
      showTabHeader: true,
      defaultIcon: '',
      selectIcon: '',
      selectIndex: 0,
      tabs: [
        {
          icon: '',
          name: '商圈',
          selectIndex: 0,
          detailList: [
            {
              name: '附近',
              icon: '',
              selectIndex: 0,
              list: [{
                name: '默认',
                value: 'all'
              }, {
                name: '500米',
                value: '500'
              }, {
                name: '1000米',
                value: '1000'
              }]
            },
            {
              name: '朝阳区',
              icon: '',
              selectIndex: 1,
              list: [{
                name: '全部',
                value: 'all'
              }, {
                name: '建国门',
                value: 'jianguomen'
              }, {
                name: '亚运村',
                value: 'yayuncun'
              }]
            },
            {
              name: '海淀区',
              icon: '',
              selectIndex: 2,
              list: [{
                name: '全部',
                value: 'all'
              }, {
                name: '中关村',
                value: 'zhongguancun'
              }, {
                name: '五道口',
                value: 'wudaokou'
              }]
            }
          ]
        },
        {
          icon: '',
          name: '地铁沿线',
          selectIndex: 1,
          detailList: [
            {
              name: '1号线',
              icon: '',
              selectIndex: 0,
              list: [{
                name: '平果圆',
                value: 'pingguoyuan'
              }, {
                name: '古城',
                value: 'gucheng'
              }, {
                name: '八角游乐园',
                value: 'bajiaoyouleyuan'
              }]
            },
            {
              name: '2号线',
              icon: '',
              selectIndex: 1,
              list: [{
                name: '积水潭',
                value: 'jishuitan'
              }, {
                name: '鼓楼大街',
                value: 'guloudajie'
              }, {
                name: '安定门',
                value: 'andingmen'
              }]
            },
            {
              name: '4号线',
              icon: '',
              selectIndex: 2,
              list: [{
                name: '安和桥北',
                value: 'anheqiaobei'
              }, {
                name: '北宫门',
                value: 'beigongmen'
              }, {
                name: '西宛',
                value: 'xiwan'
              }]
            }
          ]
        }
      ]
    },
    {
      name: '菜系',
      icon: '',
      value: 'food',
      showTabHeader: false,
      defaultIcon: '',
      selectIcon: '',
      selectIndex: 0,
      tabs: [
        {
          icon: '',
          name: '',
          selectIndex: 0,
          detailList: [
            {
              name: '全部',
              icon: '',
              value: '全部',
              selectIndex: 0,
              list: [{
                name: "全部",
                value: 'all'
              }]
            },
            {
              name: '中餐馆',
              icon: '',
              value: '中餐馆',
              selectIndex: 1,
              list: [{
                name: '全部',
                value: 'all'
              }, {
                name: '火锅',
                value: 'hot pot'
              }, {
                name: '川菜',
                value: 'Sichuan cuisine'
              }]
            },
            {
              name: '西餐馆',
              icon: '',
              value: '西餐管',
              selectIndex: 2,
              list: [{
                name: '全部',
                value: 'all'
              }, {
                name: '披萨',
                value: 'pizza'
              }, {
                name: '牛排',
                value: 'steak'
              }]
            }
          ]
        }
      ]
    },
    {
      name: '排序',
      icon: '',
      value: 'compositor',
      showTabHeader: false,
      defaultIcon: '',
      selectIcon: '',
      selectIndex: 0,
      tabs: [
        {
          icon: '',
          name: '',
          selectIndex: 0,
          detailList: [
            {
              name: '只能排序',
              icon: '',
              value: '0',
              selectIndex: 0
            },
            {
              name: '离我最近',
              icon: '',
              value: '1',
              selectIndex: 1
            },
            {
              name: '评价最好',
              icon: '',
              value: '2',
              selectIndex: 2
            }
          ]
        }
      ]
    },
    {
      name: '筛选',
      icon: '',
      value: 'filter',
      type: 'filter',
      showTabHeader: false,
      defaultIcon: '',
      selectIcon: '',
      selectIndex: 0,
      tabs: [
        {
          icon: '',
          name: '价格',
          selectIndex: 0,
          detailList: [
            {
              name: '0-50',
              value: '0-50',
              selectIndex: -1
            },
            {
              name: '50-100',
              value: '50-100',
              selectIndex: -1
            },
            {
              name: '100-150',
              value: '100-150',
              selectIndex: -1
            },
            {
              name: '150-200',
              value: '150-200',
              selectIndex: -1
            },
            {
              name: '200-250',
              value: '200-250',
              selectIndex: -1
            },
            {
              name: '300-350',
              value: '300-350',
              selectIndex: -1
            }
          ]
        },{
          icon: '',
          name: '入住类型',
          selectIndex: 1,
          detailList: [
            {
              name: '不限',
              value: 'all',
              selectIndex: -1
            }, {
                name: '全日房',
                value: 'daily',
                selectIndex: -1
            }, {
                name: '钟点房',
                value: 'time',
                selectIndex: -1
            },
            {
              name: '支持团购',
              value: 'group buy',
              selectIndex: -1
            }
          ]
        }
      ]
    }]
    

    3.效果图

      

    .

    展开全文
  • 添加自定义筛选、分组时加载所需字段 需求: 在筛选、分组中添加自定义条件时默认加载所有model中的字段,这样不是很友好,那怎么样才能只加载所需的字段呢? 方案: 创建一个my_bass_model子应用,进入项目根目录 ...

    添加自定义筛选、分组时加载所需字段

    点我下载完整odoo的demo

    需求

    在筛选、分组中添加自定义条件时默认加载所有model中的字段,这样不是很友好,那怎么样才能只加载所需的字段呢?

    在这里插入图片描述

    方案

    创建一个my_bass_model子应用,进入项目根目录

    cd myproject

    python D:\learn\odoo_learn\odoo\odoo-bin scaffold my_base_model .
    

    在models中添加一个fields_filter.py

    使用钩子重写AbstractModel中的fields_get()函数,当加载页面时会先调用fields_get()函数,在每个字段中有

    searchable(筛选)和sortable(分组)两个布尔属性,这两个属性都默认为True,所以把字段中的这两个属性修

    改为False即可让这个字段不出现在筛选、分组中。

    代码

    # -*- coding: utf-8 -*-
    
    import json
    from odoo import models, fields, api
    
    class FieldsFilter(models.AbstractModel):
        _name = 'fields.filter'
    
        @api.model
        def _register_hook(self):
            # 注册钩子函数
            origin_fields_get = models.AbstractModel.fields_get
    
            def parse_fields(res, fields, key='searchable'):
                if fields:
                    for s in fields.split(','):
                        # 筛选
                        s = s.strip()
                        if s not in res:
                            continue
    
                        res[s][key] = True
    
            @api.model
            def fields_get(self, allfields=None, attributes=None):
                res = origin_fields_get(self, allfields, attributes)
                # 通过系统参数获取需要显示的字段
                fields_filter = self.env['ir.config_parameter'].sudo().get_param('show_fields_filter') or "{}"
                try:
                    fields_filters = json.loads(fields_filter)
                except:
                    return res
    
                # TODO  列表视图字段筛选、分组自定义需要的字段
                if self._name not in fields_filters:
                    return res
    
                for key in res.keys():
                    res[key]['searchable'] = False
                    res[key]['sortable'] = False
    
                parse_fields(res, fields_filters[self._name].get('searchable'))
                parse_fields(res, fields_filters[self._name].get('sortable'), 'sortable')
    
                return res
    
            models.AbstractModel.fields_get = fields_get
            return super(FieldsFilter, self)._register_hook()
    
    

    debug模式下,【设置】->【技术】->【系统参数】,在系统参数中定义一个json格式的参数,如:

    show_fields_filter	值	{
        "res.company":{
            "searchable":"name,phone,partner_id,website,create_uid",
            "sortable":"name, phone,partner_id,create_uid"
        }
    }
    

    意思就是res.company这个model中的这些字段才显示在筛选、分组中的添加自定义条件中。

    注意:需要你安装这个应用才会被系统调用到钩子函数。

    效果:

    在这里插入图片描述

    给所有的model添加一个通用的方法

    
    class BaseModelExtend(models.AbstractModel):
        _name = 'basemodel.extend'
    
        @api.model
        def _register_hook(self):
            '''
            Register method in BaseModel
            '''
            @api.model
            def funcA(self, **kwargs):
                #code
                return True
    
            models.BaseModel.funcA = funcA #将此方法传递给BaseModel
            return super(BaseModelExtend, self)._register_hook()
    
    

    后记

    【后记】为了让大家能够轻松学编程,我创建了一个公众号【轻松学编程】,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。

    也可加我微信【1257309054】,拉你进群,大家一起交流学习。
    如果文章对您有帮助,请我喝杯咖啡吧!

    公众号

    公众号

    赞赏码

    关注我,我们一起成长~~

    展开全文
  • 原文:http://coolketang.com/staticOffice/5a97f32b756571454f26c19f.html1. 本节课将为您演示,如何进行自定义筛选操作,并获得筛选后的内容。首先点击数据选项卡,进入数据功能面板。 2. 接着在[排序和筛选]...
  • 通过查找资料将elementui组件增加了部分功能 1、分页(注意分页使用的是先查询出全部数据,再使用js进行算法分页,因为如果...Modal v-model="isShow" @on-cancel="cancle" title="创建自定义模块" width="720"> &
  • 关于MongoDB的自定义条件查询OR/AND

    千次阅读 2019-01-10 14:36:02
    以前没接触过MongoDB 最近...业务场景 根据创建人ID,未删除 以及自定义查询条件(name,address)的模糊查询来获取station集合 //2019-01-10获取当前登录人自己建的场站 BasicDBList queryList = new BasicDBList()...
  • 创建自定义RSS馈送汇集器

    千次阅读 2005-01-16 18:10:00
    浏览站点摘要而且不用常常转移图表、广告和附加的外来资料,是一个投资时间最少、迅速筛选所需信息的重要方法。 ·普遍性: 基于XML的格式清楚的划分了数据和表达式,从而易于转换以广泛适应不同媒体分布出口(标准...
  • crm创建基于fetch的自定义报表
  • 转载请注明出处 ...在本文中我将介绍如何使用Business Intelligence Development Studio来创建一个自定义报表。CRM的报表有两种,基于SQL和基于Fetch的。On-Premise两种都可以使用,而Online只可以使用...
  • 创建 过滤器筛选填好条件,点击“应用”,找到“保存”然后点击 跳转到页面 填好保存即可,就会出现在右侧“我的自定义查询” 编辑 点击自定义查询列表跳转到对应查询,bug的清单上方找到“编辑”,修改对应的...
  • 首先可以在GameFiles的Environment里面创建一个筛选器,把我们以后要写的都放进去,我这里起名 MyTestEntity,然后在里面添加一个类,我这边:类名:MyTestEntity2,它的父类填写: CGameObjectExtensionHelper , ...
  • 前台使用的是layui ... 自定义字段输出 因此时间create_time方面会出现问题,template定义的有解决方法. 前台部分代码 table.render({ elem: '#demo', url: server + 'orders/getAllOrders'...
  • 自定义的右侧弹出筛选

    千次阅读 2015-05-14 16:33:12
    工作中用到一个右侧弹出的筛选框,自己写了一个,有2个代理方法回调确认和取消,记录一下,如果后面要用就直接拿来用 .h 文件 #import @protocol categorizeSiftDelegate; @interface ...
  • 前言:近期项目重构,公司对项目结构进行了调整,增加了条件筛选的功能。在网上也看到了很多自定义的控件实现类似美团的附近筛选功能,实现方式基本都是自定义view继承自LinearLayout等布局控件,于是自己在Button的...
  • 我们经常在网上看到一些网站,拥有多重筛选功能。例如一些房产网站上,就会经常使用多条件筛选功能,...创建自定义分类,增加多个筛选条件。复制下面的代码,你可以直接复制粘贴到functions.php文件中。 ...
  • 例如项目中加入如下注入器代码后,查询条件中不再添加逻辑删除字段限定条件 /** * 自定义Sql注入 * * @author nieqiurong 2018/8/11 20:23. */ @Component public class MySqlInjector extends ...
  • 要求:订单管理导出excel表格要有自定义(选择字段)和筛选功能。 PHP代码 /** * @title 订单Excel内容生成 * @description 订单Excel内容生成 * @author * @url /order/order/get_Excel * @method * * @...
  • 那么问题来了 不能每个小应用都配置一个 logstash 服务来传输日志...也不需要用时间来分割(因为日志量不大),又希望查询方便(不要告诉我查询的时候多一个筛选条件就可以了,俺就是不想那样嫌乱不好找)。所有有...
  • 点击下图中的 配额制新的SQL视图2、创建自定义SQL视图3、设置坐标、边框、经纬度相关操作d 点击保存。4、点击Layer Preview ,由于这是自定义SQL弄得视图,所以不能像往常一样看到他的地形图,只能让前端访问我们的...
  • 在日常业务系统开发中,我们往往...所以要把所有的筛选条件都考虑进去的话,if else的方式会很麻烦(需要写很多if else判断)而且代码会很乱。这时,巧妙利用表达式树就可以轻松解决这个问题,尤其是在使用EF等OR...
  • Mybatis plus之条件构造器及无法使用lambda做自定义sql查询问题前言1. WHERE 语句条件的一些方法1.1 and()、or()和nested()1.2 select()和excludeColumns()1.3 apply()2. 踩坑经验分享 前言 本章接讲解MP的条件构造...
  • tableau的筛选功能,一般是针对维度的取值,比如topN、range(a,b),这篇文章介绍另一种筛选:维度筛选,以创建参数实现。在涉及多变量两两间的相关关系的图形展示时,非常有用。 数据是怎样的 数据来源于tableau ...
  • DataView 表示用于排序、筛选、搜索、编辑和导航的 DataTable 的可绑定数据的自定义视图。 DataView 使您能够创建 DataTable 中所存储的数据的不同视图,这种功能通常用于数据绑定应用程序。使用 DataView,您可以...
  • 现在JSON用于数据的封装和管理越来越流行,一直想着通过JSON实现很多的小工具,比如多条件筛选、表格定制化、数据验证、tree树等等,最近没事就用JSON和JQuery实现了类似于京东和淘宝多条件筛选功能,下面会对代码...
  • zabbix3.0 模板和自定义键值

    万次阅读 2016-12-05 08:54:07
    zabbix3.0 模板和自定义键值 一、添加主机 1、Configuration---Hosts---Createhost Host name:这个应该是agent配置文件定义的Hostname,我们这是192.168.142.10。 Visible name:这个就是显示名称,自定义...
  • 先说背景,由于本人工作需要创建很多小应用程序,而且在微服务的大环境下,服务越来越多,然后就导致日志四分五裂,到处都有,然后就有的elk,那么问题来了 不能每个小应用都配置一个 logstash 服务来传输日志吧,...
  • 3. 定义sql字符,后面接上get_wave_query_param函数返回的筛选条件,通常情况下PL/SQL是不能直接运行的,需要用到execute immediate执行SQL,写入临时表,最后从临时表读取数据,(如果直接用execute immediate ...
  • 创建自定义SQL注入器CustomerSqlInjector3.自定义基础CustomerMapper继承BaseMapper4.自定义基础Service继承IService及实现类5.增加或MybatisPlus配置类,加载自定义sql注入器总结 前言 虽然MyBats-Plus的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,338
精华内容 14,535
关键字:

创建自定义筛选条件