From 85b449d4bb524e9aca3c0b1c5ea7f2ffaa15f0a4 Mon Sep 17 00:00:00 2001 From: ruibaby Date: Wed, 10 Apr 2019 20:29:41 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84=E6=9B=B4?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 49 ++- package.json | 1 + .../DescriptionList.vue} | 8 +- src/components/DescriptionList/index.js | 2 + src/components/Exception/ExceptionPage.vue | 88 +++++ src/components/Exception/index.js | 2 + src/components/Exception/type.js | 19 + src/components/FooterToolbar/index.md | 15 +- .../{page => GlobalFooter}/GlobalFooter.vue | 0 src/components/GlobalFooter/index.js | 2 + src/components/GlobalHeader/GlobalHeader.vue | 123 +++++++ src/components/GlobalHeader/index.js | 2 + src/components/IconSelector/IconSelector.vue | 53 --- src/components/IconSelector/README.md | 48 --- src/components/IconSelector/icons.js | 26 -- src/components/IconSelector/index.js | 2 - src/components/{menu => Menu}/SideMenu.vue | 7 +- src/components/{menu => Menu}/index.js | 0 src/components/{menu => Menu}/menu.js | 11 +- src/components/{menu => Menu}/menu.render.js | 0 src/components/MultiTab/index.less | 7 +- src/components/NoticeIcon/NoticeIcon.vue | 89 +++++ src/components/NoticeIcon/index.js | 2 + .../{page => PageHeader}/PageHeader.vue | 63 +--- src/components/PageHeader/index.js | 2 + src/components/PageLoading/index.jsx | 10 + .../SettingDrawer.vue | 6 +- .../SettingItem.vue | 2 +- src/components/SettingDrawer/index.js | 2 + src/components/SettingDrawer/settingConfig.js | 95 +++++ src/components/Table/README.md | 333 ++++++++++++++++++ src/components/Table/index.js | 290 +++++++++++++++ src/components/TagSelect/TagSelectOption.jsx | 45 +++ src/components/TagSelect/index.jsx | 102 ++++++ .../{tools => Tools}/Breadcrumb.vue | 18 +- src/components/Tools/DetailList.vue | 5 + src/components/{tools => Tools}/HeadInfo.vue | 0 .../{tools => Tools}/HeaderComment.vue | 0 src/components/{tools => Tools}/Logo.vue | 2 +- src/components/{tools => Tools}/UserMenu.vue | 2 +- src/components/Tools/index.js | 0 src/components/{tools => Tools}/setting.js | 0 src/components/Tree/Tree.jsx | 124 +++++++ src/components/Trend/Trend.vue | 41 +++ src/components/Trend/index.js | 3 + src/components/Trend/index.less | 42 +++ src/components/Trend/index.md | 45 +++ src/components/index.js | 22 +- src/components/layouts/BasicLayout.vue | 53 --- src/components/layouts/PageView.vue | 85 ----- src/components/layouts/index.js | 6 - src/components/page/GlobalHeader.vue | 108 ------ src/components/page/GlobalLayout.vue | 156 -------- src/components/page/PageLayout.vue | 124 ------- src/config/router.config.js | 34 +- src/layouts/BasicLayout.vue | 187 ++++++++++ src/{components => }/layouts/BlankLayout.vue | 0 src/layouts/PageView.vue | 176 +++++++++ src/{components => }/layouts/RouteView.vue | 10 +- src/layouts/index.js | 6 + src/views/attachment/AttachmentList.vue | 96 ++--- src/views/comment/CommentList.vue | 9 +- src/views/dashboard/Dashboard.vue | 44 +-- 63 files changed, 2014 insertions(+), 890 deletions(-) rename src/components/{tools/DetailList.vue => DescriptionList/DescriptionList.vue} (94%) create mode 100644 src/components/DescriptionList/index.js create mode 100644 src/components/Exception/ExceptionPage.vue create mode 100644 src/components/Exception/index.js create mode 100644 src/components/Exception/type.js rename src/components/{page => GlobalFooter}/GlobalFooter.vue (100%) create mode 100644 src/components/GlobalFooter/index.js create mode 100644 src/components/GlobalHeader/GlobalHeader.vue create mode 100644 src/components/GlobalHeader/index.js delete mode 100644 src/components/IconSelector/IconSelector.vue delete mode 100644 src/components/IconSelector/README.md delete mode 100644 src/components/IconSelector/icons.js delete mode 100644 src/components/IconSelector/index.js rename src/components/{menu => Menu}/SideMenu.vue (84%) rename src/components/{menu => Menu}/index.js (100%) rename src/components/{menu => Menu}/menu.js (94%) rename src/components/{menu => Menu}/menu.render.js (100%) create mode 100644 src/components/NoticeIcon/NoticeIcon.vue create mode 100644 src/components/NoticeIcon/index.js rename src/components/{page => PageHeader}/PageHeader.vue (73%) create mode 100644 src/components/PageHeader/index.js create mode 100644 src/components/PageLoading/index.jsx rename src/components/{setting => SettingDrawer}/SettingDrawer.vue (98%) rename src/components/{setting => SettingDrawer}/SettingItem.vue (98%) create mode 100644 src/components/SettingDrawer/index.js create mode 100644 src/components/SettingDrawer/settingConfig.js create mode 100644 src/components/Table/README.md create mode 100644 src/components/Table/index.js create mode 100644 src/components/TagSelect/TagSelectOption.jsx create mode 100644 src/components/TagSelect/index.jsx rename src/components/{tools => Tools}/Breadcrumb.vue (58%) create mode 100644 src/components/Tools/DetailList.vue rename src/components/{tools => Tools}/HeadInfo.vue (100%) rename src/components/{tools => Tools}/HeaderComment.vue (100%) rename src/components/{tools => Tools}/Logo.vue (91%) rename src/components/{tools => Tools}/UserMenu.vue (96%) create mode 100644 src/components/Tools/index.js rename src/components/{tools => Tools}/setting.js (100%) create mode 100644 src/components/Tree/Tree.jsx create mode 100644 src/components/Trend/Trend.vue create mode 100644 src/components/Trend/index.js create mode 100644 src/components/Trend/index.less create mode 100644 src/components/Trend/index.md delete mode 100644 src/components/layouts/BasicLayout.vue delete mode 100644 src/components/layouts/PageView.vue delete mode 100644 src/components/layouts/index.js delete mode 100644 src/components/page/GlobalHeader.vue delete mode 100644 src/components/page/GlobalLayout.vue delete mode 100644 src/components/page/PageLayout.vue create mode 100644 src/layouts/BasicLayout.vue rename src/{components => }/layouts/BlankLayout.vue (100%) create mode 100644 src/layouts/PageView.vue rename src/{components => }/layouts/RouteView.vue (72%) create mode 100644 src/layouts/index.js diff --git a/package-lock.json b/package-lock.json index e927f2ae..3b179b03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7252,7 +7252,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -7273,12 +7274,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7293,17 +7296,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -7420,7 +7426,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -7432,6 +7439,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7446,6 +7454,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7453,12 +7462,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -7477,6 +7488,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -7557,7 +7569,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -7569,6 +7582,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -7654,7 +7668,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -7690,6 +7705,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7709,6 +7725,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7752,12 +7769,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -10691,6 +10710,11 @@ "integrity": "sha1-vsECT4WxvZbL6kBbI8FK1kQ6b4E=", "dev": true }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, "lodash.kebabcase": { "version": "4.1.1", "resolved": "http://registry.npm.taobao.org/lodash.kebabcase/download/lodash.kebabcase-4.1.1.tgz", @@ -13525,7 +13549,8 @@ "version": "4.0.8", "resolved": "http://registry.npm.taobao.org/rx-lite/download/rx-lite-4.0.8.tgz", "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true + "dev": true, + "optional": true }, "rx-lite-aggregates": { "version": "4.0.8", diff --git a/package.json b/package.json index 8ab4fdcd..bb203542 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "ant-design-vue": "~1.3.7", "axios": "^0.18.0", "enquire.js": "^2.1.6", + "lodash.get": "^4.4.2", "mavon-editor": "^2.7.2", "moment": "^2.24.0", "nprogress": "^0.2.0", diff --git a/src/components/tools/DetailList.vue b/src/components/DescriptionList/DescriptionList.vue similarity index 94% rename from src/components/tools/DetailList.vue rename to src/components/DescriptionList/DescriptionList.vue index a3311fab..7f98fec4 100644 --- a/src/components/tools/DetailList.vue +++ b/src/components/DescriptionList/DescriptionList.vue @@ -1,5 +1,5 @@ + + + diff --git a/src/components/NoticeIcon/index.js b/src/components/NoticeIcon/index.js new file mode 100644 index 00000000..659b9ec0 --- /dev/null +++ b/src/components/NoticeIcon/index.js @@ -0,0 +1,2 @@ +import NoticeIcon from './NoticeIcon' +export default NoticeIcon diff --git a/src/components/page/PageHeader.vue b/src/components/PageHeader/PageHeader.vue similarity index 73% rename from src/components/page/PageHeader.vue rename to src/components/PageHeader/PageHeader.vue index 2c9c8658..8212f9ad 100644 --- a/src/components/page/PageHeader.vue +++ b/src/components/PageHeader/PageHeader.vue @@ -1,16 +1,7 @@ + \ No newline at end of file diff --git a/src/components/SettingDrawer/index.js b/src/components/SettingDrawer/index.js new file mode 100644 index 00000000..8260f2d3 --- /dev/null +++ b/src/components/SettingDrawer/index.js @@ -0,0 +1,2 @@ +import SettingDrawer from './SettingDrawer' +export default SettingDrawer diff --git a/src/components/SettingDrawer/settingConfig.js b/src/components/SettingDrawer/settingConfig.js new file mode 100644 index 00000000..52fbbf13 --- /dev/null +++ b/src/components/SettingDrawer/settingConfig.js @@ -0,0 +1,95 @@ +import { message } from 'ant-design-vue/es' +// import defaultSettings from '../defaultSettings'; + +let lessNodesAppended + +const colorList = [ + { + key: '薄暮', color: '#F5222D' + }, + { + key: '火山', color: '#FA541C' + }, + { + key: '日暮', color: '#FAAD14' + }, + { + key: '明青', color: '#13C2C2' + }, + { + key: '极光绿', color: '#52C41A' + }, + { + key: '拂晓蓝(默认)', color: '#1890FF' + }, + { + key: '极客蓝', color: '#2F54EB' + }, + { + key: '酱紫', color: '#722ED1' + } +] + +const updateTheme = primaryColor => { + // Don't compile less in production! + /* if (process.env.NODE_ENV === 'production') { + return; + } */ + // Determine if the component is remounted + if (!primaryColor) { + return + } + const hideMessage = message.loading('正在编译主题!', 0) + function buildIt() { + if (!window.less) { + return + } + setTimeout(() => { + window.less + .modifyVars({ + '@primary-color': primaryColor + }) + .then(() => { + hideMessage() + }) + .catch(() => { + message.error('Failed to update theme') + hideMessage() + }) + }, 200) + } + if (!lessNodesAppended) { + // insert less.js and color.less + const lessStyleNode = document.createElement('link') + const lessConfigNode = document.createElement('script') + const lessScriptNode = document.createElement('script') + lessStyleNode.setAttribute('rel', 'stylesheet/less') + lessStyleNode.setAttribute('href', '/color.less') + lessConfigNode.innerHTML = ` + window.less = { + async: true, + env: 'production', + javascriptEnabled: true + }; + ` + lessScriptNode.src = 'https://gw.alipayobjects.com/os/lib/less.js/3.8.1/less.min.js' + lessScriptNode.async = true + lessScriptNode.onload = () => { + buildIt() + lessScriptNode.onload = null + } + document.body.appendChild(lessStyleNode) + document.body.appendChild(lessConfigNode) + document.body.appendChild(lessScriptNode) + lessNodesAppended = true + } else { + buildIt() + } +} + +const updateColorWeak = colorWeak => { + // document.body.className = colorWeak ? 'colorWeak' : ''; + colorWeak ? document.body.classList.add('colorWeak') : document.body.classList.remove('colorWeak') +} + +export { updateTheme, colorList, updateColorWeak } diff --git a/src/components/Table/README.md b/src/components/Table/README.md new file mode 100644 index 00000000..6db95403 --- /dev/null +++ b/src/components/Table/README.md @@ -0,0 +1,333 @@ +Table 重封装组件说明 +==== + + +封装说明 +---- + +> 基础的使用方式与 API 与 [官方版(Table)](https://vuecomponent.github.io/ant-design-vue/components/table-cn/) 本一致,在其基础上,封装了加载数据的方法。 +> +> 你无需在你是用表格的页面进行分页逻辑处理,仅需向 Table 组件传递绑定 `:data="Promise"` 对象即可 + +该 `table` 由 [@Saraka](https://github.com/saraka-tsukai) 完成封装 + + +例子1 +---- +(基础使用) + +```vue + + + + + +``` + + + +例子2 +---- + +(简单的表格,最后一列是各种操作) + +```vue + + + +``` + + + +内置方法 +---- + +通过 `this.$refs.table` 调用 + +`this.$refs.table.refresh(true)` 刷新列表 (用户新增/修改数据后,重载列表数据) + +> 注意:要调用 `refresh(bool)` 需要给表格组件设定 `ref` 值 +> +> `refresh()` 方法可以传一个 `bool` 值,当有传值 或值为 `true` 时,则刷新时会强制刷新到第一页(常用户页面 搜索 按钮进行搜索时,结果从第一页开始分页) + + +内置属性 +---- +> 除去 `a-table` 自带属性外,还而外提供了一些额外属性属性 + + +| 属性 | 说明 | 类型 | 默认值 | +| -------------- | ----------------------------------------------- | ----------------- | ------ | +| alert | 设置是否显示表格信息栏 | [object, boolean] | null | +| showPagination | 显示分页选择器,可传 'auto' \| boolean | [string, boolean] | 'auto' | +| data | 加载数据方法 必须为 `Promise` 对象 **必须绑定** | Promise | - | + + +`alert` 属性对象: + +```javascript +alert: { + show: Boolean, + clear: [Function, Boolean] +} +``` + +注意事项 +---- + +> 你可能需要为了与后端提供的接口返回结果一致而去修改以下代码: +(需要注意的是,这里的修改是全局性的,意味着整个项目所有使用该 table 组件都需要遵守这个返回结果定义的字段。) + +修改 `@/components/table/index.js` 第 132 行起 + + + +```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 + }) + + // 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页 + if (r.data.length == 0 && this.localPagination.current != 1) { + this.localPagination.current-- + this.loadData() + return + } + + // 这里用于判断接口是否有返回 r.totalCount 或 this.showPagination = false + // 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能 + !r.totalCount && ['auto', false].includes(this.showPagination) && (this.localPagination = false) + this.localDataSource = r.data // 返回结果中的数组数据 + this.localLoading = false +}); +``` +返回 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 +} +``` + + + +更新时间 +---- + +该文档最后更新于: 2019-01-21 AM 08:37 \ No newline at end of file diff --git a/src/components/Table/index.js b/src/components/Table/index.js new file mode 100644 index 00000000..535cd256 --- /dev/null +++ b/src/components/Table/index.js @@ -0,0 +1,290 @@ +import T from 'ant-design-vue/es/table/Table' +import get from 'lodash.get' + +export default { + data() { + return { + needTotalList: [], + + selectedRows: [], + selectedRowKeys: [], + + localLoading: false, + localDataSource: [], + localPagination: Object.assign({}, this.pagination) + } + }, + props: Object.assign({}, T.props, { + rowKey: { + type: [String, Function], + default: 'id' + }, + data: { + type: Function, + required: true + }, + pageNum: { + type: Number, + default: 1 + }, + pageSize: { + type: Number, + default: 10 + }, + showSizeChanger: { + type: Boolean, + default: true + }, + size: { + type: String, + default: 'default' + }, + /** + * { + * show: true, + * clear: Function + * } + */ + alert: { + type: [Object, Boolean], + default: null + }, + rowSelection: { + type: Object, + default: null + }, + /** @Deprecated */ + showAlertInfo: { + type: Boolean, + default: false + }, + showPagination: { + type: String | Boolean, + default: 'auto' + } + }), + watch: { + 'localPagination.current'(val) { + this.$router.push({ + name: this.$route.name, + params: Object.assign({}, this.$route.params, { + pageNo: val + }) + }) + }, + pageNum(val) { + Object.assign(this.localPagination, { + current: val + }) + }, + pageSize(val) { + Object.assign(this.localPagination, { + pageSize: val + }) + }, + showSizeChanger(val) { + Object.assign(this.localPagination, { + showSizeChanger: val + }) + } + }, + created() { + this.localPagination = ['auto', true].includes(this.showPagination) && Object.assign({}, this.localPagination, { + current: this.pageNum, + pageSize: this.pageSize, + showSizeChanger: this.showSizeChanger + }) + this.needTotalList = this.initTotalList(this.columns) + this.loadData() + }, + methods: { + /** + * 表格重新加载方法 + * 如果参数为 true, 则强制刷新到第一页 + * @param Boolean bool + */ + refresh(bool = false) { + bool && (this.localPagination = Object.assign({}, { + current: 1, pageSize: this.pageSize + })) + this.loadData() + }, + /** + * 加载数据方法 + * @param {Object} pagination 分页选项器 + * @param {Object} filters 过滤条件 + * @param {Object} sorter 排序条件 + */ + loadData(pagination, filters, sorter) { + this.localLoading = true + const parameter = Object.assign({ + pageNo: (pagination && pagination.current) || + this.localPagination.current || this.pageNum, + pageSize: (pagination && pagination.pageSize) || + this.localPagination.pageSize || this.pageSize + }, + (sorter && sorter.field && { + sortField: sorter.field + }) || {}, + (sorter && sorter.order && { + sortOrder: sorter.order + }) || {}, { + ...filters + } + ) + const result = this.data(parameter) + // 对接自己的通用数据接口需要修改下方代码中的 r.pageNo, r.totalCount, r.data + // eslint-disable-next-line + if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') { + 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 + }) + // 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页 + if (r.data.length === 0 && this.localPagination.current !== 1) { + this.localPagination.current-- + this.loadData() + return + } + + // 这里用于判断接口是否有返回 r.totalCount 或 this.showPagination = false + // 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能 + + (!this.showPagination || !r.totalCount && this.showPagination === 'auto') && (this.localPagination.hideOnSinglePage = true) + this.localDataSource = r.data // 返回结果中的数组数据 + this.localLoading = false + }) + } + }, + initTotalList(columns) { + const totalList = [] + columns && columns instanceof Array && columns.forEach(column => { + if (column.needTotal) { + totalList.push({ + ...column, + total: 0 + }) + } + }) + return totalList + }, + /** + * 用于更新已选中的列表数据 total 统计 + * @param selectedRowKeys + * @param selectedRows + */ + updateSelect(selectedRowKeys, selectedRows) { + this.selectedRows = selectedRows + this.selectedRowKeys = selectedRowKeys + const list = this.needTotalList + this.needTotalList = list.map(item => { + return { + ...item, + total: selectedRows.reduce((sum, val) => { + const total = sum + parseInt(get(val, item.dataIndex)) + return isNaN(total) ? 0 : total + }, 0) + } + }) + }, + /** + * 清空 table 已选中项 + */ + clearSelected() { + if (this.rowSelection) { + this.rowSelection.onChange([], []) + this.updateSelect([], []) + } + }, + /** + * 处理交给 table 使用者去处理 clear 事件时,内部选中统计同时调用 + * @param callback + * @returns {*} + */ + renderClear(callback) { + if (this.selectedRowKeys.length <= 0) return null + return ( + { + callback() + this.clearSelected() + }}>清空 + ) + }, + renderAlert() { + // 绘制统计列数据 + const needTotalItems = this.needTotalList.map((item) => { + return ( + {item.title}总计 {!item.customRender ? item.total : item.customRender(item.total)} + ) + }) + + // 绘制 清空 按钮 + const clearItem = (typeof this.alert.clear === 'boolean' && this.alert.clear) ? ( + this.renderClear(this.clearSelected) + ) : (this.alert !== null && typeof this.alert.clear === 'function') ? ( + this.renderClear(this.alert.clear) + ) : null + + // 绘制 alert 组件 + return ( + + + + ) + } + }, + + render() { + const props = {} + const localKeys = Object.keys(this.$data) + const showAlert = (typeof this.alert === 'object' && this.alert !== null && this.alert.show) && typeof this.rowSelection.selectedRowKeys !== 'undefined' || this.alert + + Object.keys(T.props).forEach(k => { + const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}` + if (localKeys.includes(localKey)) { + props[k] = this[localKey] + return props[k] + } + if (k === 'rowSelection') { + if (showAlert && this.rowSelection) { + // 如果需要使用alert,则重新绑定 rowSelection 事件 + props[k] = { + selectedRows: this.selectedRows, + selectedRowKeys: this.selectedRowKeys, + onChange: (selectedRowKeys, selectedRows) => { + this.updateSelect(selectedRowKeys, selectedRows) + typeof this[k].onChange !== 'undefined' && this[k].onChange(selectedRowKeys, selectedRows) + } + } + return props[k] + } else if (!this.rowSelection) { + // 如果没打算开启 rowSelection 则清空默认的选择项 + props[k] = null + return props[k] + } + } + props[k] = this[k] + return props[k] + }) + const table = ( + + { Object.keys(this.$slots).map(name => ()) } + + ) + + return ( +
+ { showAlert ? this.renderAlert() : null } + { table } +
+ ) + } +} diff --git a/src/components/TagSelect/TagSelectOption.jsx b/src/components/TagSelect/TagSelectOption.jsx new file mode 100644 index 00000000..f0b098e4 --- /dev/null +++ b/src/components/TagSelect/TagSelectOption.jsx @@ -0,0 +1,45 @@ +import { Tag } from 'ant-design-vue' +const { CheckableTag } = Tag + +export default { + name: 'TagSelectOption', + props: { + prefixCls: { + type: String, + default: 'ant-pro-tag-select-option' + }, + value: { + type: [String, Number, Object], + default: '' + }, + checked: { + type: Boolean, + default: false + } + }, + data() { + return { + localChecked: this.checked || false + } + }, + watch: { + 'checked'(val) { + this.localChecked = val + }, + '$parent.items': { + handler: function(val) { + this.value && val.hasOwnProperty(this.value) && (this.localChecked = val[this.value]) + }, + deep: true + } + }, + render() { + const { $slots, value } = this + const onChange = (checked) => { + this.$emit('change', { value, checked }) + } + return ( + {$slots.default} + ) + } +} diff --git a/src/components/TagSelect/index.jsx b/src/components/TagSelect/index.jsx new file mode 100644 index 00000000..e692b9f8 --- /dev/null +++ b/src/components/TagSelect/index.jsx @@ -0,0 +1,102 @@ +import PropTypes from 'ant-design-vue/es/_util/vue-types' +import Option from './TagSelectOption.jsx' +import { filterEmpty } from '@/components/_util/util' + +export default { + Option, + name: 'TagSelect', + model: { + prop: 'checked', + event: 'change' + }, + props: { + prefixCls: { + type: String, + default: 'ant-pro-tag-select' + }, + defaultValue: { + type: PropTypes.array, + default: null + }, + value: { + type: PropTypes.array, + default: null + }, + expandable: { + type: Boolean, + default: false + }, + hideCheckAll: { + type: Boolean, + default: false + } + }, + data() { + return { + expand: false, + localCheckAll: false, + items: this.getItemsKey(filterEmpty(this.$slots.default)), + val: this.value || this.defaultValue || [] + } + }, + methods: { + onChange(checked) { + const key = Object.keys(this.items).filter(key => key === checked.value) + this.items[key] = checked.checked + const bool = Object.values(this.items).lastIndexOf(false) + if (bool === -1) { + this.localCheckAll = true + } else { + this.localCheckAll = false + } + }, + onCheckAll(checked) { + Object.keys(this.items).forEach(v => { + this.items[v] = checked.checked + }) + }, + getItemsKey(items) { + const totalItem = {} + items.forEach(item => { + totalItem[item.componentOptions.propsData && item.componentOptions.propsData.value] = false + }) + return totalItem + }, + // CheckAll Button + renderCheckAll() { + return !this.hideCheckAll && () || null + }, + // expandable + renderExpandable() { + + }, + // render option + renderTags(items) { + const listeners = { + change: (checked) => { + this.onChange(checked) + this.$emit('change', checked) + } + } + + return items.map(vnode => { + const options = vnode.componentOptions + options.listeners = listeners + return vnode + }) + } + }, + render() { + const { $props: { prefixCls } } = this + const classString = { + [`${prefixCls}`]: true + } + const tagItems = filterEmpty(this.$slots.default) + return ( +
+ {this.renderCheckAll()} + {this.renderTags(tagItems)} +
+ ) + } +} diff --git a/src/components/tools/Breadcrumb.vue b/src/components/Tools/Breadcrumb.vue similarity index 58% rename from src/components/tools/Breadcrumb.vue rename to src/components/Tools/Breadcrumb.vue index 414d30c2..c400edd3 100644 --- a/src/components/tools/Breadcrumb.vue +++ b/src/components/Tools/Breadcrumb.vue @@ -1,9 +1,10 @@