Commit b1fcdaebabecd8a0623b3be0a3c5424fa745a9f6
1 parent
441f73b9
Exists in
master
and in
3 other branches
feat: 优化Scheme自定义渲染及详情和删除接口
Showing
7 changed files
with
255 additions
and
48 deletions
Show diff stats
examples/styles/index.scss
| @@ -53,6 +53,21 @@ body { | @@ -53,6 +53,21 @@ body { | ||
| 53 | } | 53 | } |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | +.zee-scheme__view { | ||
| 57 | + .el-form-item { | ||
| 58 | + font-weight: normal !important; | ||
| 59 | + margin-bottom: 0 !important; | ||
| 60 | + &__label { | ||
| 61 | + line-height: 1.5 !important; | ||
| 62 | + color: #595959 !important; | ||
| 63 | + } | ||
| 64 | + &__content { | ||
| 65 | + line-height: 1.5 !important; | ||
| 66 | + color: #000 !important; | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | +} | ||
| 70 | + | ||
| 56 | @media only screen and (min-width: 1400px) { | 71 | @media only screen and (min-width: 1400px) { |
| 57 | .code-snippet-box { | 72 | .code-snippet-box { |
| 58 | .code-snippet { | 73 | .code-snippet { |
examples/views/docs/component/scheme.md
| @@ -111,6 +111,18 @@ export default { | @@ -111,6 +111,18 @@ export default { | ||
| 111 | <template> | 111 | <template> |
| 112 | <z-scheme ref="scheme" :list="list" url="/customer" :http="$http" :alias="{ getUrl: '/getCustomerByCode', getKey: 'code' }" auto real-selection> | 112 | <z-scheme ref="scheme" :list="list" url="/customer" :http="$http" :alias="{ getUrl: '/getCustomerByCode', getKey: 'code' }" auto real-selection> |
| 113 | <el-table-column type="selection" align="center" width="40"></el-table-column> | 113 | <el-table-column type="selection" align="center" width="40"></el-table-column> |
| 114 | + <template #render-code="{ value, row, openView }"> | ||
| 115 | + <el-link type="primary" @click="openView(row)">{{ value }}</el-link> | ||
| 116 | + </template> | ||
| 117 | + <template #view-name="{ value }"> | ||
| 118 | + <el-tag size="mini">{{ value }}</el-tag> | ||
| 119 | + </template> | ||
| 120 | + <template #cell-name="{ value }"> | ||
| 121 | + <el-tag size="mini" type="danger">{{ value }}</el-tag> | ||
| 122 | + </template> | ||
| 123 | + <template #form-id="{ value }"> | ||
| 124 | + <el-tag size="mini">{{ value }}</el-tag> | ||
| 125 | + </template> | ||
| 114 | </z-scheme> | 126 | </z-scheme> |
| 115 | </template> | 127 | </template> |
| 116 | 128 |
packages/filter/index.vue
| 1 | <template> | 1 | <template> |
| 2 | - <z-form v-model="model" class="zee-filter" :list="formattedList" :span="span" :labelWidth="labelWidth" :colClass="colVisibleRender" :size="size"> | 2 | + <z-form v-model="model" class="zee-filter" :list="formattedList" :span="span" :labelWidth="labelWidth" :colClass="colVisibleRender" :size="size" :formProps="formProps"> |
| 3 | <div slot="$operation" class="zee-filter__button-group"> | 3 | <div slot="$operation" class="zee-filter__button-group"> |
| 4 | <el-button-group :size="size"> | 4 | <el-button-group :size="size"> |
| 5 | - <el-button type="primary" @click="handleSearch" :loading="loading"><span>查询</span></el-button> | 5 | + <el-button type="primary" @click="handleSearch" :loading="loading" icon="el-icon-search"><span>查询</span></el-button> |
| 6 | <el-button @click="handleReset"><span>重置</span></el-button> | 6 | <el-button @click="handleReset"><span>重置</span></el-button> |
| 7 | <el-button v-if="showCollapsed" @click="collapsed = !collapsed"> | 7 | <el-button v-if="showCollapsed" @click="collapsed = !collapsed"> |
| 8 | <span>{{ collapsed ? '展开' : '收起' }}</span> | 8 | <span>{{ collapsed ? '展开' : '收起' }}</span> |
| 9 | - <!-- <i :class="`el-icon-arrow-${collapsed ? 'down' : 'up'}`" class="el-icon--right"></i> --> | ||
| 10 | </el-button> | 9 | </el-button> |
| 11 | </el-button-group> | 10 | </el-button-group> |
| 12 | </div> | 11 | </div> |
| @@ -36,6 +35,10 @@ export default { | @@ -36,6 +35,10 @@ export default { | ||
| 36 | default: 3, | 35 | default: 3, |
| 37 | }, | 36 | }, |
| 38 | loading: Boolean, | 37 | loading: Boolean, |
| 38 | + formProps: { | ||
| 39 | + type: Object, | ||
| 40 | + default: () => ({}), | ||
| 41 | + }, | ||
| 39 | }, | 42 | }, |
| 40 | data() { | 43 | data() { |
| 41 | return { | 44 | return { |
packages/form/form-render.vue
| @@ -47,7 +47,7 @@ | @@ -47,7 +47,7 @@ | ||
| 47 | :class="colClassRender(item, index, colClass)" | 47 | :class="colClassRender(item, index, colClass)" |
| 48 | > | 48 | > |
| 49 | <el-form-item :label="item.label" :label-width="item.labelWidth" :prop="item.fullKey" :rules="item.rules" :class="itemClass || 'zee-form__item'"> | 49 | <el-form-item :label="item.label" :label-width="item.labelWidth" :prop="item.fullKey" :rules="item.rules" :class="itemClass || 'zee-form__item'"> |
| 50 | - <slot v-if="$slots[item.fullKey]" :name="item.fullKey" :value="itemValue(item)" :model="value"></slot> | 50 | + <slot v-if="$scopedSlots[item.fullKey]" :name="item.fullKey" :value="itemValue(item)" :model1="value"></slot> |
| 51 | <template v-else> | 51 | <template v-else> |
| 52 | <!-- 自定义组件 --> | 52 | <!-- 自定义组件 --> |
| 53 | <dynamic-render | 53 | <dynamic-render |
packages/form/index.vue
| @@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
| 16 | </style> | 16 | </style> |
| 17 | 17 | ||
| 18 | <template> | 18 | <template> |
| 19 | - <el-form ref="form" :size="size" :class="formClass" :model="formModel" :label-width="labelWidth" :label-position="labelPosition || labelWidth ? 'right' : 'top'"> | 19 | + <el-form ref="form" :size="size" :class="formClass" :model="formModel" :label-width="labelWidth" :label-position="labelPosition || labelWidth ? 'right' : 'top'" v-bind="formProps"> |
| 20 | <form-render | 20 | <form-render |
| 21 | :title-class="titleClass" | 21 | :title-class="titleClass" |
| 22 | :content-class="contentClass" | 22 | :content-class="contentClass" |
| @@ -64,15 +64,23 @@ export default { | @@ -64,15 +64,23 @@ export default { | ||
| 64 | type: Number, | 64 | type: Number, |
| 65 | default: 24, | 65 | default: 24, |
| 66 | }, | 66 | }, |
| 67 | + formProps: { | ||
| 68 | + type: Object, | ||
| 69 | + default: () => ({}), | ||
| 70 | + }, | ||
| 67 | }, | 71 | }, |
| 68 | data() { | 72 | data() { |
| 69 | return { | 73 | return { |
| 70 | - slotKeys: Object.keys(this.$slots), | ||
| 71 | model: {}, | 74 | model: {}, |
| 72 | formModel: {}, | 75 | formModel: {}, |
| 73 | formList: [], | 76 | formList: [], |
| 74 | }; | 77 | }; |
| 75 | }, | 78 | }, |
| 79 | + computed: { | ||
| 80 | + slotKeys() { | ||
| 81 | + return Object.keys(this.$scopedSlots); | ||
| 82 | + }, | ||
| 83 | + }, | ||
| 76 | watch: { | 84 | watch: { |
| 77 | value: { | 85 | value: { |
| 78 | handler(val = {}) { | 86 | handler(val = {}) { |
packages/scheme/index.vue
| @@ -4,44 +4,80 @@ | @@ -4,44 +4,80 @@ | ||
| 4 | 4 | ||
| 5 | <template> | 5 | <template> |
| 6 | <div class="zee-scheme"> | 6 | <div class="zee-scheme"> |
| 7 | + <!-- 头部内容 --> | ||
| 7 | <div v-if="$scopedSlots.header || $slots.header" class="zee-scheme__header"> | 8 | <div v-if="$scopedSlots.header || $slots.header" class="zee-scheme__header"> |
| 8 | <slot name="header" :filterModel="filterModel" v-bind="_slotScope"></slot> | 9 | <slot name="header" :filterModel="filterModel" v-bind="_slotScope"></slot> |
| 9 | </div> | 10 | </div> |
| 11 | + <!-- 筛选组件 --> | ||
| 10 | <div class="zee-scheme__filter"> | 12 | <div class="zee-scheme__filter"> |
| 11 | - <z-filter v-if="filter" :value="_filterModel" :list="listMap.filter | noRulesFilter" :size="size" @input="onFilterInput" @search="search" :loading="loading"></z-filter> | 13 | + <z-filter |
| 14 | + v-if="filter" | ||
| 15 | + :value="_filterModel" | ||
| 16 | + :list="filterList || listMap.filter | noRulesFilter" | ||
| 17 | + :size="size" | ||
| 18 | + @input="onFilterInput" | ||
| 19 | + @search="search" | ||
| 20 | + :loading="loading" | ||
| 21 | + v-bind="filterProps" | ||
| 22 | + ></z-filter> | ||
| 12 | </div> | 23 | </div> |
| 24 | + <!-- 按钮区 --> | ||
| 13 | <div v-if="action" class="zee-scheme__action"> | 25 | <div v-if="action" class="zee-scheme__action"> |
| 14 | <slot v-if="hadSlot('action')" name="action" v-bind="_slotScope"></slot> | 26 | <slot v-if="hadSlot('action')" name="action" v-bind="_slotScope"></slot> |
| 15 | <template v-else> | 27 | <template v-else> |
| 16 | <el-button :size="size" type="primary" @click="openNew">新增</el-button> | 28 | <el-button :size="size" type="primary" @click="openNew">新增</el-button> |
| 17 | - <slot name="button" :size="size" v-bind="_slotScope"></slot> | 29 | + <el-button :size="size" plain :disabled="selection.length === 0" @click="handleDeleteMul(selection)">删除</el-button> |
| 30 | + <slot name="button" v-bind="_slotScope"></slot> | ||
| 18 | </template> | 31 | </template> |
| 19 | </div> | 32 | </div> |
| 33 | + <!-- 表格内容 --> | ||
| 20 | <div class="zee-scheme__table"> | 34 | <div class="zee-scheme__table"> |
| 21 | <z-table | 35 | <z-table |
| 22 | ref="table" | 36 | ref="table" |
| 23 | v-model="tableData" | 37 | v-model="tableData" |
| 24 | v-loading="loading" | 38 | v-loading="loading" |
| 25 | - :list="listMap.table" | 39 | + :list="tableList || listMap.table" |
| 26 | :tableProps="{ border: true, 'row-key': 'id', ...tableProps }" | 40 | :tableProps="{ border: true, 'row-key': 'id', ...tableProps }" |
| 27 | :size="size" | 41 | :size="size" |
| 28 | @selection-change="onTableSelectionChange" | 42 | @selection-change="onTableSelectionChange" |
| 29 | @selection="onTableSelection" | 43 | @selection="onTableSelection" |
| 30 | > | 44 | > |
| 31 | <slot></slot> | 45 | <slot></slot> |
| 46 | + <!-- 表格列内容渲染 --> | ||
| 47 | + <template v-for="(item, index) in renderList"> | ||
| 48 | + <template v-if="$scopedSlots[`cell-${item.fullKey}`]"> | ||
| 49 | + <el-table-column :slot="item.fullKey" v-bind="item" :prop="item.agentKey || item.key" :key="`table-cell-${index}`"> | ||
| 50 | + <template slot-scope="{ row, column, $index }"> | ||
| 51 | + <slot :name="`cell-${item.fullKey}`" v-bind="{ ...item, ..._slotScope }" :row="row" :value="row[item.key]" :column="column" :index="$index"></slot> | ||
| 52 | + </template> | ||
| 53 | + </el-table-column> | ||
| 54 | + </template> | ||
| 55 | + <template v-else-if="$scopedSlots[`render-${item.fullKey}`]"> | ||
| 56 | + <el-table-column :slot="item.fullKey" v-bind="item" :prop="item.agentKey || item.key" :key="`table-render-${index}`"> | ||
| 57 | + <template slot-scope="{ row, column, $index }"> | ||
| 58 | + <slot :name="`render-${item.fullKey}`" v-bind="{ ...item, ..._slotScope }" :row="row" :value="row[item.key]" :column="column" :index="$index"></slot> | ||
| 59 | + </template> | ||
| 60 | + </el-table-column> | ||
| 61 | + </template> | ||
| 62 | + </template> | ||
| 63 | + <slot slot="column-append" name="column-append" v-bind="_slotScope"></slot> | ||
| 64 | + <!-- 表格尾追加操作列 --> | ||
| 32 | <template #column-end> | 65 | <template #column-end> |
| 33 | - <el-table-column prop="$operation" label="操作" :width="140" fixed="right"> | 66 | + <slot slot="column-end" name="column-end" v-bind="_slotScope"></slot> |
| 67 | + <el-table-column v-if="operation" prop="$operation" label="操作" v-bind="{ width: 100, fixed: 'right', ...operationProps }"> | ||
| 34 | <div class="zee-scheme__table-operation" slot-scope="slotScope"> | 68 | <div class="zee-scheme__table-operation" slot-scope="slotScope"> |
| 35 | - <el-button type="text" icon="el-icon-edit" title="编辑" @click="openEdit(slotScope)"></el-button> | ||
| 36 | - <el-popconfirm confirmButtonText="确定" cancelButtonText="取消" title="确定删除吗?" placement="top" @onConfirm="handleDelete(slotScope)"> | 69 | + <el-button type="text" icon="el-icon-edit" title="编辑" @click="openEdit(slotScope.row)"></el-button> |
| 70 | + <el-popconfirm confirmButtonText="确定" cancelButtonText="取消" title="确定删除吗?" placement="top" @onConfirm="handleDelete([slotScope.row])"> | ||
| 37 | <el-button slot="reference" type="text" icon="el-icon-delete" title="删除"></el-button> | 71 | <el-button slot="reference" type="text" icon="el-icon-delete" title="删除"></el-button> |
| 38 | </el-popconfirm> | 72 | </el-popconfirm> |
| 73 | + <slot name="operation-button" v-bind="_slotScope"></slot> | ||
| 39 | </div> | 74 | </div> |
| 40 | </el-table-column> | 75 | </el-table-column> |
| 41 | </template> | 76 | </template> |
| 42 | </z-table> | 77 | </z-table> |
| 43 | </div> | 78 | </div> |
| 44 | - <div v-if="pagination" class="zee-scheme__footer"> | 79 | + <!-- 底部区域 --> |
| 80 | + <div class="zee-scheme__footer"> | ||
| 45 | <div v-if="selection.length > 0" class="selection-info"> | 81 | <div v-if="selection.length > 0" class="selection-info"> |
| 46 | <span>已选中</span> | 82 | <span>已选中</span> |
| 47 | <span class="num">{{ selection.length }}</span> | 83 | <span class="num">{{ selection.length }}</span> |
| @@ -50,7 +86,9 @@ | @@ -50,7 +86,9 @@ | ||
| 50 | <el-button slot="reference" :size="size" type="text">清除</el-button> | 86 | <el-button slot="reference" :size="size" type="text">清除</el-button> |
| 51 | </el-popconfirm> | 87 | </el-popconfirm> |
| 52 | </div> | 88 | </div> |
| 89 | + <!-- 分页器 --> | ||
| 53 | <el-pagination | 90 | <el-pagination |
| 91 | + v-if="pagination" | ||
| 54 | @size-change="handleSizeChange" | 92 | @size-change="handleSizeChange" |
| 55 | @current-change="handleCurrentChange" | 93 | @current-change="handleCurrentChange" |
| 56 | :current-page="currentPage" | 94 | :current-page="currentPage" |
| @@ -61,12 +99,62 @@ | @@ -61,12 +99,62 @@ | ||
| 61 | > | 99 | > |
| 62 | </el-pagination> | 100 | </el-pagination> |
| 63 | </div> | 101 | </div> |
| 64 | - <el-dialog :visible.sync="dialogVisible" :title="dialogTitle" destroy-on-close append-to-body :lock-scroll="false" :close-on-click-modal="false" @closed="onDialogClosed"> | 102 | + <!-- 弹出框 --> |
| 103 | + <el-dialog | ||
| 104 | + :visible.sync="dialogVisible" | ||
| 105 | + :title="dialogTitle" | ||
| 106 | + destroy-on-close | ||
| 107 | + append-to-body | ||
| 108 | + :lock-scroll="false" | ||
| 109 | + :close-on-click-modal="false" | ||
| 110 | + @closed="onDialogClosed" | ||
| 111 | + v-bind="dialogProps" | ||
| 112 | + > | ||
| 65 | <div v-loading="dialogLoading"> | 113 | <div v-loading="dialogLoading"> |
| 114 | + <!-- 自定义弹出框标题 --> | ||
| 66 | <slot v-if="hadSlot('dialog-title')" slot="title" name="dialog-title" :dialogType="dialogType" v-bind="_slotScope"></slot> | 115 | <slot v-if="hadSlot('dialog-title')" slot="title" name="dialog-title" :dialogType="dialogType" v-bind="_slotScope"></slot> |
| 67 | <template v-if="dialogRender"> | 116 | <template v-if="dialogRender"> |
| 117 | + <!-- 自定义弹出框内容 --> | ||
| 68 | <slot v-if="hadSlot(`dialog-${dialogType}`)" :name="`dialog-${dialogType}`" :model="_formModel" v-bind="_slotScope"></slot> | 118 | <slot v-if="hadSlot(`dialog-${dialogType}`)" :name="`dialog-${dialogType}`" :model="_formModel" v-bind="_slotScope"></slot> |
| 69 | - <z-form v-else ref="form" :value="_formModel" :list="listMap.form" label-width="80px" :span="12" @input="onFormInput" @validate="onFormValidate"></z-form> | 119 | + <!-- 内置弹出框新增修改表单 --> |
| 120 | + <template v-if="['new', 'edit'].includes(dialogType)"> | ||
| 121 | + <z-form | ||
| 122 | + ref="form" | ||
| 123 | + :value="_formModel" | ||
| 124 | + :list="formList || listMap.form" | ||
| 125 | + @input="onFormInput" | ||
| 126 | + @validate="onFormValidate" | ||
| 127 | + v-bind="{ span: 12, 'label-width': '80px', ...formProps }" | ||
| 128 | + > | ||
| 129 | + <!-- 表单自定义插槽 --> | ||
| 130 | + <template v-for="item in renderList"> | ||
| 131 | + <template v-if="$scopedSlots[`form-${item.fullKey}`]"> | ||
| 132 | + <slot :slot="item.fullKey" :name="`form-${item.fullKey}`" :value="get(_formModel, item.fullKey)" :row="_formModel" :model="_formModel" v-bind="_slotScope"></slot> | ||
| 133 | + </template> | ||
| 134 | + </template> | ||
| 135 | + </z-form> | ||
| 136 | + </template> | ||
| 137 | + <!-- 内置弹出框详情表单 --> | ||
| 138 | + <template v-else> | ||
| 139 | + <z-form | ||
| 140 | + ref="form" | ||
| 141 | + class="zee-scheme__view" | ||
| 142 | + :value="_formModel" | ||
| 143 | + :list="viewList || listMap.form | viewTypeFilter | noRulesFilter" | ||
| 144 | + v-bind="{ span: 12, 'label-width': '80px', ...viewProps }" | ||
| 145 | + > | ||
| 146 | + <!-- 详情自定义插槽渲染 --> | ||
| 147 | + <template v-for="item in renderList"> | ||
| 148 | + <template v-if="$scopedSlots[`view-${item.fullKey}`]"> | ||
| 149 | + <slot :slot="item.fullKey" :name="`view-${item.fullKey}`" :value="get(_formModel, item.fullKey)" :row="_formModel" :model="_formModel" v-bind="_slotScope"></slot> | ||
| 150 | + </template> | ||
| 151 | + <template v-else-if="$scopedSlots[`render-${item.fullKey}`]"> | ||
| 152 | + <slot :slot="item.fullKey" :name="`render-${item.fullKey}`" :value="get(_formModel, item.fullKey)" :row="_formModel" :model="_formModel" v-bind="_slotScope"></slot> | ||
| 153 | + </template> | ||
| 154 | + </template> | ||
| 155 | + </z-form> | ||
| 156 | + </template> | ||
| 157 | + <!-- 内置弹出框新增修改按钮 --> | ||
| 70 | <div class="zee-scheme__dialog-button" v-if="['new', 'edit'].includes(dialogType)"> | 158 | <div class="zee-scheme__dialog-button" v-if="['new', 'edit'].includes(dialogType)"> |
| 71 | <el-button :size="size" type="primary" @click="handleConfirm" :loading="submitting">确定</el-button> | 159 | <el-button :size="size" type="primary" @click="handleConfirm" :loading="submitting">确定</el-button> |
| 72 | <el-button :size="size" plain @click="closeDialog">取消</el-button> | 160 | <el-button :size="size" plain @click="closeDialog">取消</el-button> |
| @@ -78,47 +166,52 @@ | @@ -78,47 +166,52 @@ | ||
| 78 | </template> | 166 | </template> |
| 79 | 167 | ||
| 80 | <script> | 168 | <script> |
| 81 | -import { cloneDeep } from '../_utils'; | 169 | +import { cloneDeep, get } from '../_utils'; |
| 82 | import { clear } from '../_utils/param'; | 170 | import { clear } from '../_utils/param'; |
| 83 | 171 | ||
| 172 | +let propsMap = {}; | ||
| 173 | +const propsKeys = ['tableProps', 'filterProps', 'formProps', 'viewProps', 'dialogProps', 'operationProps']; | ||
| 174 | +propsKeys.forEach(key => { | ||
| 175 | + propsMap[key] = { | ||
| 176 | + type: Object, | ||
| 177 | + default: function() { | ||
| 178 | + return {}; | ||
| 179 | + }, | ||
| 180 | + }; | ||
| 181 | +}); | ||
| 182 | +const apiKeys = ['searchApi', 'submitApi', 'addApi', 'modifyApi', 'getApi', 'viewApi', 'deleteApi']; | ||
| 183 | +apiKeys.forEach(key => { | ||
| 184 | + propsMap[key] = { | ||
| 185 | + type: Function, | ||
| 186 | + }; | ||
| 187 | +}); | ||
| 188 | +const blockKeys = ['filter', 'action', 'pagination', 'operation']; | ||
| 189 | +blockKeys.forEach(key => { | ||
| 190 | + propsMap[key] = { | ||
| 191 | + type: Boolean, | ||
| 192 | + default: true, | ||
| 193 | + }; | ||
| 194 | +}); | ||
| 195 | + | ||
| 84 | export default { | 196 | export default { |
| 85 | name: 'Scheme', | 197 | name: 'Scheme', |
| 86 | props: { | 198 | props: { |
| 199 | + ...propsMap, | ||
| 87 | list: Array, | 200 | list: Array, |
| 88 | - filter: { | ||
| 89 | - type: Boolean, | ||
| 90 | - default: true, | ||
| 91 | - }, | ||
| 92 | - action: { | ||
| 93 | - type: Boolean, | ||
| 94 | - default: true, | ||
| 95 | - }, | ||
| 96 | - pagination: { | ||
| 97 | - type: Boolean, | ||
| 98 | - default: true, | ||
| 99 | - }, | 201 | + filterList: Array, |
| 202 | + tableList: Array, | ||
| 203 | + formList: Array, | ||
| 204 | + viewList: Array, | ||
| 100 | size: { | 205 | size: { |
| 101 | type: String, | 206 | type: String, |
| 102 | default: 'mini', | 207 | default: 'mini', |
| 103 | }, | 208 | }, |
| 104 | - tableProps: { | ||
| 105 | - type: Object, | ||
| 106 | - default: () => ({}), | ||
| 107 | - }, | ||
| 108 | formModel: Object, | 209 | formModel: Object, |
| 109 | filterModel: Object, | 210 | filterModel: Object, |
| 110 | auto: Boolean, | 211 | auto: Boolean, |
| 111 | realSelection: Boolean, | 212 | realSelection: Boolean, |
| 112 | - /* 模板API */ | ||
| 113 | url: String, // 请求地址 | 213 | url: String, // 请求地址 |
| 114 | http: [Function, Promise], // http库 | 214 | http: [Function, Promise], // http库 |
| 115 | - /* 自定义API */ | ||
| 116 | - searchApi: Function, // 搜索 | ||
| 117 | - submitApi: Function, // 提交 | ||
| 118 | - addApi: Function, // 新增 | ||
| 119 | - modifyApi: Function, // 修改 | ||
| 120 | - getApi: Function, // 查询详情 | ||
| 121 | - deleteApi: Function, // 删除 | ||
| 122 | alias: Object, // 别名配置 | 215 | alias: Object, // 别名配置 |
| 123 | }, | 216 | }, |
| 124 | data() { | 217 | data() { |
| @@ -161,6 +254,17 @@ export default { | @@ -161,6 +254,17 @@ export default { | ||
| 161 | clearRules(list); | 254 | clearRules(list); |
| 162 | return list; | 255 | return list; |
| 163 | }, | 256 | }, |
| 257 | + // 详情类型过滤器 | ||
| 258 | + viewTypeFilter(val = []) { | ||
| 259 | + let list = cloneDeep(val); | ||
| 260 | + const clearRules = list => { | ||
| 261 | + list.forEach(item => { | ||
| 262 | + item.type = (h, { model, config }) => h('span', config, model[item.key]); | ||
| 263 | + }); | ||
| 264 | + }; | ||
| 265 | + clearRules(list); | ||
| 266 | + return list; | ||
| 267 | + }, | ||
| 164 | }, | 268 | }, |
| 165 | computed: { | 269 | computed: { |
| 166 | listMap() { | 270 | listMap() { |
| @@ -199,6 +303,28 @@ export default { | @@ -199,6 +303,28 @@ export default { | ||
| 199 | }); | 303 | }); |
| 200 | return array; | 304 | return array; |
| 201 | }, | 305 | }, |
| 306 | + renderList() { | ||
| 307 | + // 深度克隆传入的列表,避免原始值被修改 | ||
| 308 | + const newList = cloneDeep(this.list); | ||
| 309 | + // 生成列表值的全路径key,即列表项为对象时,对象内的key与上一级的key合并作为全路径key | ||
| 310 | + const generateFullKey = (list, parentKey) => { | ||
| 311 | + list.forEach(item => { | ||
| 312 | + if (item.group && item.list) { | ||
| 313 | + if (item.group.key) { | ||
| 314 | + item.fullKey = `${parentKey ? `${parentKey}-${item.group.key}` : item.group.key}`; | ||
| 315 | + } else { | ||
| 316 | + item.fullKey = parentKey || item.key; | ||
| 317 | + } | ||
| 318 | + generateFullKey(item.list, item.fullKey); | ||
| 319 | + } else { | ||
| 320 | + item.fullKey = `${parentKey ? `${parentKey}-${item.key}` : item.key}`; | ||
| 321 | + } | ||
| 322 | + }); | ||
| 323 | + }; | ||
| 324 | + // 生成fullKey | ||
| 325 | + generateFullKey(newList); | ||
| 326 | + return newList; | ||
| 327 | + }, | ||
| 202 | _filterModel() { | 328 | _filterModel() { |
| 203 | return this.filterModel || this.filterForm || {}; | 329 | return this.filterModel || this.filterForm || {}; |
| 204 | }, | 330 | }, |
| @@ -209,6 +335,9 @@ export default { | @@ -209,6 +335,9 @@ export default { | ||
| 209 | return { | 335 | return { |
| 210 | openDialog: this.openDialog, | 336 | openDialog: this.openDialog, |
| 211 | closeDialog: this.closeDialog, | 337 | closeDialog: this.closeDialog, |
| 338 | + openView: this.openView, | ||
| 339 | + handleDelete: this.handleDelete, | ||
| 340 | + size: this.size, | ||
| 212 | }; | 341 | }; |
| 213 | }, | 342 | }, |
| 214 | _alias() { | 343 | _alias() { |
| @@ -221,6 +350,7 @@ export default { | @@ -221,6 +350,7 @@ export default { | ||
| 221 | }, | 350 | }, |
| 222 | }, | 351 | }, |
| 223 | methods: { | 352 | methods: { |
| 353 | + get, | ||
| 224 | // 空Promise | 354 | // 空Promise |
| 225 | emptyPromise() { | 355 | emptyPromise() { |
| 226 | return new Promise(resolve => resolve()); | 356 | return new Promise(resolve => resolve()); |
| @@ -367,17 +497,44 @@ export default { | @@ -367,17 +497,44 @@ export default { | ||
| 367 | return undefined; | 497 | return undefined; |
| 368 | }, | 498 | }, |
| 369 | // 打开编辑弹出框 | 499 | // 打开编辑弹出框 |
| 370 | - openEdit({ row }) { | 500 | + openEdit(row) { |
| 371 | this.dialogLoading = true; | 501 | this.dialogLoading = true; |
| 372 | this.openDialog('edit', '编辑'); | 502 | this.openDialog('edit', '编辑'); |
| 373 | const getRow = () => | 503 | const getRow = () => |
| 374 | new Promise(resolve => { | 504 | new Promise(resolve => { |
| 375 | - resolve({ ...row }); | 505 | + resolve(row); |
| 376 | }); | 506 | }); |
| 377 | const getAPI = this.getApi || this._getAPI || getRow; | 507 | const getAPI = this.getApi || this._getAPI || getRow; |
| 378 | getAPI(row) | 508 | getAPI(row) |
| 379 | .then(result => { | 509 | .then(result => { |
| 380 | - this.editForm = { ...result }; | 510 | + this.editForm = result; |
| 511 | + }) | ||
| 512 | + .finally(() => { | ||
| 513 | + this.dialogLoading = false; | ||
| 514 | + }); | ||
| 515 | + }, | ||
| 516 | + // 内置查询详情接口 | ||
| 517 | + _viewAPI(row) { | ||
| 518 | + if (this.url && (this.http || this.zHttp)) { | ||
| 519 | + const _http = this.http || this.zHttp; | ||
| 520 | + const _viewKey = this._alias.viewKey || this._alias.getKey || this._alias.primaryKey || 'id'; | ||
| 521 | + const _resultKey = this._alias.result || 'result'; | ||
| 522 | + return _http({ url: `${clear(this.url)}/${this._alias.getUrl || 'queryById'}`, params: { [_viewKey]: row[_viewKey] } }).then(response => response[_resultKey] || {}); | ||
| 523 | + } | ||
| 524 | + return undefined; | ||
| 525 | + }, | ||
| 526 | + // 打开详情弹出框 | ||
| 527 | + openView(row) { | ||
| 528 | + this.dialogLoading = true; | ||
| 529 | + this.openDialog('view', '详情'); | ||
| 530 | + const getRow = () => | ||
| 531 | + new Promise(resolve => { | ||
| 532 | + resolve(row); | ||
| 533 | + }); | ||
| 534 | + const viewAPI = this.viewApi || this.getApi || this._viewAPI || this._getAPI || getRow; | ||
| 535 | + viewAPI(row) | ||
| 536 | + .then(result => { | ||
| 537 | + this.editForm = result; | ||
| 381 | }) | 538 | }) |
| 382 | .finally(() => { | 539 | .finally(() => { |
| 383 | this.dialogLoading = false; | 540 | this.dialogLoading = false; |
| @@ -392,7 +549,7 @@ export default { | @@ -392,7 +549,7 @@ export default { | ||
| 392 | return undefined; | 549 | return undefined; |
| 393 | }, | 550 | }, |
| 394 | // 删除 | 551 | // 删除 |
| 395 | - handleDelete({ row, $index }) { | 552 | + handleDelete(selection) { |
| 396 | const loading = this.$loading({ | 553 | const loading = this.$loading({ |
| 397 | text: '处理中', | 554 | text: '处理中', |
| 398 | spinner: 'el-icon-loading', | 555 | spinner: 'el-icon-loading', |
| @@ -400,7 +557,7 @@ export default { | @@ -400,7 +557,7 @@ export default { | ||
| 400 | }); | 557 | }); |
| 401 | const deleteAPI = this.deleteApi || this._deleteAPI || this.emptyPromise; | 558 | const deleteAPI = this.deleteApi || this._deleteAPI || this.emptyPromise; |
| 402 | const _deleteKey = this._alias.deleteKey || this._alias.primaryKey || 'id'; | 559 | const _deleteKey = this._alias.deleteKey || this._alias.primaryKey || 'id'; |
| 403 | - const keys = [row[_deleteKey]]; | 560 | + const keys = selection.map(i => i[_deleteKey]); |
| 404 | deleteAPI(keys) | 561 | deleteAPI(keys) |
| 405 | .then(() => { | 562 | .then(() => { |
| 406 | this.search(); | 563 | this.search(); |
| @@ -410,16 +567,30 @@ export default { | @@ -410,16 +567,30 @@ export default { | ||
| 410 | loading.close(); | 567 | loading.close(); |
| 411 | }); | 568 | }); |
| 412 | }, | 569 | }, |
| 570 | + // 批量删除 | ||
| 571 | + handleDeleteMul(selection) { | ||
| 572 | + this.$confirm(`是否删除这 [${selection.length}] 项?`, '提示', { | ||
| 573 | + confirmButtonText: '确定', | ||
| 574 | + cancelButtonText: '取消', | ||
| 575 | + type: 'warning', | ||
| 576 | + }) | ||
| 577 | + .then(() => { | ||
| 578 | + this.handleDelete(selection); | ||
| 579 | + }) | ||
| 580 | + .catch(() => {}); | ||
| 581 | + }, | ||
| 413 | // 打开弹出框 | 582 | // 打开弹出框 |
| 414 | openDialog(type, title) { | 583 | openDialog(type, title) { |
| 415 | this.dialogVisible = true; | 584 | this.dialogVisible = true; |
| 416 | this.dialogRender = true; | 585 | this.dialogRender = true; |
| 417 | this.dialogType = type; | 586 | this.dialogType = type; |
| 418 | this.dialogTitle = title; | 587 | this.dialogTitle = title; |
| 588 | + this.$emit('dialog-change', type); | ||
| 419 | }, | 589 | }, |
| 420 | // 关闭弹出框 | 590 | // 关闭弹出框 |
| 421 | closeDialog() { | 591 | closeDialog() { |
| 422 | this.dialogVisible = false; | 592 | this.dialogVisible = false; |
| 593 | + this.$emit('dialog-change', 'none'); | ||
| 423 | }, | 594 | }, |
| 424 | // 清空表单 | 595 | // 清空表单 |
| 425 | clearEditForm() { | 596 | clearEditForm() { |
packages/table/index.vue
| @@ -82,9 +82,7 @@ export default { | @@ -82,9 +82,7 @@ export default { | ||
| 82 | // 表格参数 | 82 | // 表格参数 |
| 83 | tableProps: { | 83 | tableProps: { |
| 84 | type: Object, | 84 | type: Object, |
| 85 | - default() { | ||
| 86 | - return {}; | ||
| 87 | - }, | 85 | + default: () => ({}), |
| 88 | }, | 86 | }, |
| 89 | // 表格事件 | 87 | // 表格事件 |
| 90 | tableEvents: Object, | 88 | tableEvents: Object, |