Ver Fonte

fixed table

Sendya há 6 anos atrás
pai
commit
a82d9cd1bf

+ 25 - 0
idea.config.js

@@ -0,0 +1,25 @@
+'use strict'
+const path = require('path')
+
+function resolve(dir) {
+    return path.join(__dirname, '.', dir)
+}
+
+module.exports = {
+    context: path.resolve(__dirname, './'),
+    resolve: {
+        extensions: ['.js', '.vue', '.json'],
+        alias: {
+            'vue$': 'vue/dist/vue.esm.js',
+            'config': resolve('config'),
+            '@': resolve('src'),
+            '@views': resolve('src/views'),
+            '@comp': resolve('src/components'),
+            '@core': resolve('src/core'),
+            '@utils': resolve('src/utils'),
+            '@entry': resolve('src/entry'),
+            '@router': resolve('src/router'),
+            '@store': resolve('src/store')
+        }
+    },
+}

+ 2 - 32
src/components/layout/LayoutMain.vue

@@ -175,37 +175,7 @@
   }
 
   // 数据列表 样式
-  .tableList {
-
-    .table-search {
-
-      &.open-more-condition {
-        .more-condition {
-          display: block;
-        }
-      }
-
-      .more-condition {
-        display: none;
-      }
-
-      .ant-form-item {
-        display: flex;
-        margin-bottom: 24px;
-
-        & > .ant-form-item-label {
-          flex: unset;
-        }
-
-        .ant-form-item-control-wrapper {
-          flex: 1 1;
-        }
-      }
-    }
-
-    .ant-alert, .table-operator {
-      margin-bottom: 16px;
-    }
-
+  .table-alert {
+    margin-bottom: 16px;
   }
 </style>

+ 249 - 0
src/components/table/README.md

@@ -0,0 +1,249 @@
+#### Table 重封装组件说明
+
+
+说明:
+
+>  基础的使用方式与 API 与 [官方版(Table)](https://vuecomponent.github.io/ant-design-vue/components/table-cn/) 本一致,在其基础上,封装了加载数据的方法。
+>
+> 你无需在你是用表格的页面进行分页逻辑处理,仅需向 Table 组件传递绑定 `:data="Promise"` 对象即可
+
+
+
+例子1(基础使用):
+
+```vue
+<template>
+    <s-table
+      size="default"
+      :columns="columns"
+      :data="loadData"
+    >
+    </s-table>
+</template>
+
+<script>
+  	import STable from '@/components/table/'
+    export default {
+    	components: {
+    		STable
+    	},
+        data () {
+            return {
+                columns: [
+                  {
+                    title: '规则编号',
+                    dataIndex: 'no'
+                  },
+                  {
+                    title: '描述',
+                    dataIndex: 'description'
+                  },
+                  {
+                    title: '服务调用次数',
+                    dataIndex: 'callNo',
+                    sorter: true,
+                    needTotal: true,
+                    customRender: (text) => text + ' 次'
+                  },
+                  {
+                    title: '状态',
+                    dataIndex: 'status',
+                    needTotal: true
+                  },
+                  {
+                    title: '更新时间',
+                    dataIndex: 'updatedAt',
+                    sorter: true
+                  }
+                ],
+                // 查询条件参数
+                queryParam: {},
+                // 加载数据方法 必须为 Promise 对象
+                loadData: parameter => {
+                  return this.$http.get('/service', {
+                    params: Object.assign(parameter, this.queryParam)
+                  }).then(res => {
+                    return res.result
+                  })
+                },
+            }
+    }
+</script>
+
+```
+
+
+
+例子2(简单的表格,最后一列是各种操作。):
+
+```vue
+<template>
+    <s-table
+      size="default"
+      :columns="columns"
+      :data="loadData"
+    >
+        <span slot="action" slot-scope="text, record">
+          <a>编辑</a>
+          <a-divider type="vertical" />
+          <a-dropdown>
+            <a class="ant-dropdown-link">
+              更多 <a-icon type="down" />
+            </a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a href="javascript:;">1st menu item</a>
+              </a-menu-item>
+              <a-menu-item>
+                <a href="javascript:;">2nd menu item</a>
+              </a-menu-item>
+              <a-menu-item>
+                <a href="javascript:;">3rd menu item</a>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+    </s-table>
+</template>
+
+<script>
+  	import STable from '@/components/table/'
+    export default {
+    	components: {
+    		STable
+    	},
+        data () {
+            return {
+                columns: [
+                    {
+                        title: '规则编号',
+                        dataIndex: 'no'
+                    },
+                    {
+                        title: '描述',
+                        dataIndex: 'description'
+                    },
+                    {
+                        title: '服务调用次数',
+                        dataIndex: 'callNo',
+                    },
+                    {
+                        title: '状态',
+                        dataIndex: 'status',
+                    },
+                    {
+                        title: '更新时间',
+                        dataIndex: 'updatedAt',
+                    },
+                    {
+						table: '操作',
+                        dataIndex: 'action',
+                        scopedSlots: { customRender: 'action' },
+                    }
+                ],
+                // 查询条件参数
+                queryParam: {},
+                // 加载数据方法 必须为 Promise 对象
+                loadData: parameter => {
+                  return this.$http.get('/service', {
+                    params: Object.assign(parameter, this.queryParam)
+                  }).then(res => {
+                    return res.result
+                  })
+                },
+            }
+    }
+</script>
+```
+
+
+
+
+
+### 注意事项:
+
+你可能需要为了与后端提供的接口返回结果一致而去修改以下代码:
+(需要注意的是,这里的修改是全局性的,意味着整个项目所有使用该 table 组件都需要遵守这个返回结果定义的字段。)
+`@/components/table/index.js`  第 89 行起
+
+
+
+```javascript
+result.then(r => {
+  this.localPagination = Object.assign({}, this.localPagination, {
+      current: r.pageNo, // 返回结果中的当前分页数
+      total: r.totalCount, // 返回结果中的总记录数
+      showSizeChanger: this.showSizeChanger,
+      pageSize: (pagination && pagination.pageSize) ||
+      this.localPagination.pageSize
+  });
+  this.localDataSource = r.data; // 返回结果中的数组数据
+})
+```
+返回 JSON 例子:
+```json
+{
+  "message": "",
+  "result": {
+    "data": [{
+        id: 1,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
+        title: 'Alipay',
+        description: '那是一种内在的东西, 他们到达不了,也无法触及的',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 2,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
+        title: 'Angular',
+        description: '希望是一个好东西,也许是最好的,好东西是不会消亡的',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 3,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png',
+        title: 'Ant Design',
+        description: '城镇中有那么多的酒馆,她却偏偏走进了我的酒馆',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 4,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png',
+        title: 'Ant Design Pro',
+        description: '那时候我只会想自己想要什么,从不想自己拥有什么',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 5,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
+        title: 'Bootstrap',
+        description: '凛冬将至',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      },
+      {
+        id: 6,
+        cover: 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png',
+        title: 'Vue',
+        description: '生命就像一盒巧克力,结果往往出人意料',
+        status: 1,
+        updatedAt: '2018-07-26 00:00:00'
+      }
+    ],
+    "pageSize": 10,
+    "pageNo": 0,
+    "totalPage": 6,
+    "totalCount": 57
+  },
+  "status": 200,
+  "timestamp": 1534955098193
+}
+```
+
+
+
+最后更新于: 2018-08-30 AM

+ 80 - 15
src/components/table/index.js

@@ -1,13 +1,9 @@
-// import table from './datatable.vue';
-// import table from './table.vue';
-// export default table;
-
-
-
 import T from "ant-design-vue/es/table/Table";
 export default {
   data() {
     return {
+      needTotalList: [],
+      localLoading: false,
       localDataSource: [],
       localPagination: Object.assign({}, T.props.pagination)
     };
@@ -61,6 +57,9 @@ export default {
       pageSize: this.pageSize,
       showSizeChanger: this.showSizeChanger
     });
+
+    this.needTotalList = this.initTotalList(this.columns)
+
     this.loadData();
   },
   methods: {
@@ -68,7 +67,8 @@ export default {
       this.loadData();
     },
     loadData(pagination, filters, sorter) {
-      var result = this.data(
+      this.localLoading = true
+      const result = this.data(
         Object.assign({
             pageNo:
               (pagination && pagination.current) ||
@@ -91,38 +91,103 @@ export default {
       if (result instanceof Promise) {
         result.then(r => {
           this.localPagination = Object.assign({}, this.localPagination, {
-            current: r.current_page, //current: r.pageNo,
-            total: r.total, //total: r.totalCount,            
+            current: r.pageNo,  // 返回结果中的当前分页数
+            total: r.totalCount, // 返回结果中的总记录数
             showSizeChanger: this.showSizeChanger,
             pageSize: (pagination && pagination.pageSize) ||
               this.localPagination.pageSize
           });
-          this.localDataSource = r.data; // this.localDataSource = r.result;
+          this.localDataSource = r.data; // 返回结果中的数组数据
+          this.localLoading = false
+        }).catch(() => {
+          this.localLoading = false
         });
       }
+    },
+    initTotalList (columns) {
+      const totalList = []
+      columns.forEach(column => {
+        if (column.needTotal) {
+          totalList.push({ ...column, total: 0 })
+        }
+      })
+      return totalList
+    },
+    updateSelect (selectedRowKeys, selectedRows) {
+      this.selectedRowKeys = selectedRowKeys
+      let list = this.needTotalList
+      this.needTotalList = list.map(item => {
+        return {
+          ...item,
+          total: selectedRows.reduce((sum, val) => {
+            return sum + val[item.dataIndex]
+          }, 0)
+        }
+      })
+      this.$emit('change', selectedRowKeys, selectedRows)
+    },
+    onClearSelected () {
+      this.selectedRowKeys = []
+      this.updateSelect([], [])
+    },
+    renderMsg(h) {
+      let d = this.needTotalList.map(item => {
+        return h('span', `${item.title} 总计 ${item.customRender ? item.customRender(item.total) : item.total}`)
+      })
+      return d
+    },
+    renderAlert(h) {
+
+      return h('span', {
+        slot: 'message'
+      }, this.renderMsg(h))
     }
   },
   render(h) {
-    var _vm = this
+    const _vm = this
 
-    var props = {},
+    let props = {},
       localKeys = Object.keys(this.$data);
 
     Object.keys(T.props).forEach(k => {
-      var localKey = `local${k.substring(0,1).toUpperCase()}${k.substring(1)}`;
+      let localKey = `local${k.substring(0,1).toUpperCase()}${k.substring(1)}`;
       if (localKeys.includes(localKey)) {
         return props[k] = _vm[localKey];
       }
       return props[k] = _vm[k];
     })
 
-    return h("a-table", {
+    /*return h("a-table", {
       tag: "component",
       attrs: props,
       on: {
         change: _vm.loadData
       },
       scopedSlots: this.$scopedSlots
-    });
+    });*/
+
+    return h('div', {
+
+    }, [
+      h("a-alert", {
+        style: {
+          marginBottom: '16px'
+        },
+        props: {
+          type: 'info',
+          showIcon: true
+        }
+      }, [ _vm.renderAlert(h) ]),
+      h("a-table", {
+        tag: "component",
+        attrs: props,
+        on: {
+          change: _vm.loadData
+        },
+        scopedSlots: this.$scopedSlots
+      })
+    ]);
+
+
   }
 };

+ 5 - 2
src/views/dashboard/Workplace.vue

@@ -27,7 +27,10 @@
             <div>
               <a-card-grid :key="i" v-for="(item, i) in projects">
                 <a-card :bordered="false" :body-style="{ padding: 0 }">
-                  <a-card-meta :description="item.description">
+                  <a-card-meta>
+                    <div slot="description" class="card-description">
+                      {{ item.description }}
+                    </div>
                     <div slot="title" class="card-title">
                       <a-avatar size="small" :src="item.cover"/>
                       <a>{{ item.title }}</a>
@@ -256,7 +259,7 @@
         float: right;
       }
     }
-    .ant-card-meta-description {
+    .ant-card-meta-description, .card-description {
       color: rgba(0, 0, 0, 0.45);
       height: 44px;
       line-height: 22px;

+ 139 - 110
src/views/list/TableList.vue

@@ -1,117 +1,122 @@
 <template>
-    <a-card :bordered="false">
-        <div :class="advanced ? 'search' : null">
-            <a-form layout="horizontal">
-                <div :class="advanced ? null : 'fold'">
-                    <a-row :gutter="48">
-                        <a-col :md="8" :sm="24" >
-                            <a-form-item
-                                    label="规则编号"
-                                    :labelCol="{span: 5}"
-                                    :wrapperCol="{span: 18, offset: 1}"
-                            >
-                                <a-input placeholder="请输入" />
-                            </a-form-item>
-                        </a-col>
-                        <a-col :md="8" :sm="24" >
-                            <a-form-item
-                                    label="使用状态"
-                                    :labelCol="{span: 5}"
-                                    :wrapperCol="{span: 18, offset: 1}"
-                            >
-                                <a-select placeholder="请选择">
-                                    <a-select-option value="1">关闭</a-select-option>
-                                    <a-select-option value="2">运行中</a-select-option>
-                                </a-select>
-                            </a-form-item>
-                        </a-col>
-                        <a-col :md="8" :sm="24" >
-                            <a-form-item
-                                    label="调用次数"
-                                    :labelCol="{span: 5}"
-                                    :wrapperCol="{span: 18, offset: 1}"
-                            >
-                                <a-input-number style="width: 100%" placeholder="请输入" />
-                            </a-form-item>
-                        </a-col>
-                    </a-row>
+  <a-card :bordered="false">
+    <div :class="advanced ? 'search' : null">
+      <a-form layout="horizontal">
+        <div :class="advanced ? null : 'fold'">
+          <a-row :gutter="48">
+            <a-col :md="8" :sm="24">
+              <a-form-item
+                label="规则编号"
+                :labelCol="{span: 5}"
+                :wrapperCol="{span: 18, offset: 1}"
+              >
+                <a-input placeholder="请输入"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item
+                label="使用状态"
+                :labelCol="{span: 5}"
+                :wrapperCol="{span: 18, offset: 1}"
+              >
+                <a-select placeholder="请选择">
+                  <a-select-option value="1">关闭</a-select-option>
+                  <a-select-option value="2">运行中</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item
+                label="调用次数"
+                :labelCol="{span: 5}"
+                :wrapperCol="{span: 18, offset: 1}"
+              >
+                <a-input-number style="width: 100%" placeholder="请输入"/>
+              </a-form-item>
+            </a-col>
+          </a-row>
 
-                    <a-row :gutter="48" v-if="advanced">
-                        <a-col :md="8" :sm="24" >
-                            <a-form-item
-                                    label="更新日期"
-                                    :labelCol="{span: 5}"
-                                    :wrapperCol="{span: 18, offset: 1}">
-                                <a-date-picker style="width: 100%" placeholder="请输入更新日期" />
-                            </a-form-item>
-                        </a-col>
-                        <a-col :md="8" :sm="24" >
-                            <a-form-item
-                                    label="使用状态"
-                                    :labelCol="{span: 5}"
-                                    :wrapperCol="{span: 18, offset: 1}">
-                                <a-select placeholder="请选择">
-                                    <a-select-option value="1">关闭</a-select-option>
-                                    <a-select-option value="2">运行中</a-select-option>
-                                </a-select>
-                            </a-form-item>
-                        </a-col>
-                        <a-col :md="8" :sm="24" >
-                            <a-form-item
-                                    label="描述"
-                                    :labelCol="{span: 5}"
-                                    :wrapperCol="{span: 18, offset: 1}"
-                            >
-                                <a-input placeholder="请输入" />
-                            </a-form-item>
-                        </a-col>
-                    </a-row>
-                </div>
+          <a-row :gutter="48" v-if="advanced">
+            <a-col :md="8" :sm="24">
+              <a-form-item
+                label="更新日期"
+                :labelCol="{span: 5}"
+                :wrapperCol="{span: 18, offset: 1}">
+                <a-date-picker style="width: 100%" placeholder="请输入更新日期"/>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item
+                label="使用状态"
+                :labelCol="{span: 5}"
+                :wrapperCol="{span: 18, offset: 1}">
+                <a-select placeholder="请选择">
+                  <a-select-option value="1">关闭</a-select-option>
+                  <a-select-option value="2">运行中</a-select-option>
+                </a-select>
+              </a-form-item>
+            </a-col>
+            <a-col :md="8" :sm="24">
+              <a-form-item
+                label="描述"
+                :labelCol="{span: 5}"
+                :wrapperCol="{span: 18, offset: 1}"
+              >
+                <a-input placeholder="请输入"/>
+              </a-form-item>
+            </a-col>
+          </a-row>
+        </div>
 
-                <span style="float: right; margin-top: 3px;">
+        <span style="float: right; margin-top: 3px;">
                   <a-button type="primary">查询</a-button>
                   <a-button style="margin-left: 8px">重置</a-button>
                   <a @click="toggleAdvanced" style="margin-left: 8px">
                     {{ advanced ? '收起' : '展开' }}
-                    <a-icon :type="advanced ? 'up' : 'down'" />
+                    <a-icon :type="advanced ? 'up' : 'down'"/>
                   </a>
                 </span>
-            </a-form>
-        </div>
+      </a-form>
+    </div>
+
+    <s-table
+      size="default"
+      :columns="columns"
+      :data="loadData"
+      :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onChange }"
+    >
+      <span slot="action" slot-scope="text, record">
+        <a>编辑</a>
+        <a-divider type="vertical" />
+        <a-dropdown>
+          <a class="ant-dropdown-link">
+            更多 <a-icon type="down" />
+          </a>
+          <a-menu slot="overlay">
+            <a-menu-item>
+              <a href="javascript:;">1st menu item</a>
+            </a-menu-item>
+            <a-menu-item>
+              <a href="javascript:;">2nd menu item</a>
+            </a-menu-item>
+            <a-menu-item>
+              <a href="javascript:;">3rd menu item</a>
+            </a-menu-item>
+          </a-menu>
+        </a-dropdown>
+      </span>
+    </s-table>
 
-        <standard-table
-            size="default"
-            :columns="columns"
-            :data="loadData"
-            :selectedRows="selectedRows"
-            @change="onChange"
-        >
-        </standard-table>
-    </a-card>
+  </a-card>
 </template>
 
 <script>
-  import StandardTable from '@/components/table/StandardTable'
-  import AForm from "ant-design-vue/es/form/Form";
-
-  const data = []
-
-  for (let i = 0; i < 100; i++) {
-    data.push({
-      key: i,
-      no: 'NO ' + i,
-      description: '这是一段描述',
-      callNo: Math.floor(Math.random() * 1000),
-      status: Math.floor(Math.random() * 10) % 4,
-      updatedAt: '2018-07-26'
-    })
-  }
+  import STable from '@/components/table/'
 
   export default {
     name: "TableList",
     components: {
-      AForm,
-      StandardTable
+      STable
     },
     data () {
       return {
@@ -145,6 +150,12 @@
             title: '更新时间',
             dataIndex: 'updatedAt',
             sorter: true
+          },
+          {
+            table: '操作',
+            dataIndex: 'action',
+            width: '150px',
+            scopedSlots: { customRender: 'action' },
           }
         ],
         // 加载数据方法 必须为 Promise 对象
@@ -155,6 +166,7 @@
             return res.result
           })
         },
+
         selectedRowKeys: [],
         selectedRows: []
       }
@@ -164,28 +176,45 @@
       onChange (selectedRowKeys, selectedRows) {
         this.selectedRowKeys = selectedRowKeys
         this.selectedRows = selectedRows
+
+        console.log(this.selectedRowKeys, this.selectedRows)
       },
       toggleAdvanced () {
         this.advanced = !this.advanced
       },
+    },
+    watch: {
+      'selectedRows': function (selectedRows) {
+        this.needTotalList = this.needTotalList.map(item => {
+          return {
+            ...item,
+            total: selectedRows.reduce( (sum, val) => {
+              return sum + val[item.dataIndex]
+            }, 0)
+          }
+        })
+      }
     }
   }
 </script>
 
 <style lang="scss" scoped>
-    .search {
-        margin-bottom: 54px;
-    }
+  .search {
+    margin-bottom: 54px;
+  }
+
+  .fold {
+    width: calc(100% - 216px);
+    display: inline-block
+  }
+
+  .operator {
+    margin-bottom: 18px;
+  }
+
+  @media screen and (max-width: 900px) {
     .fold {
-        width: calc(100% - 216px);
-        display: inline-block
-    }
-    .operator{
-        margin-bottom: 18px;
-    }
-    @media screen and (max-width: 900px) {
-        .fold {
-            width: 100%;
-        }
+      width: 100%;
     }
+  }
 </style>