Commit b8413d198fa68bd543cbde6543f90886bacfdc5b

Authored by Aaron
1 parent 841b3ab4
Exists in master and in 1 other branch legacy

新式表格支持行内新增编辑

examples/views/page/other.vue
... ... @@ -13,7 +13,7 @@
13 13 <template>
14 14 <div>
15 15 <pre>{{ model }}</pre>
16   - <eg-table v-model="tableData" :list="option.list" :tableProps="{ border: true }" editable>
  16 + <eg-table v-model="tableData" :list="option.list" :tableProps="{ border: true }" editable @cell-edit="onCellEdit">
17 17 <el-table-column type="selection"></el-table-column>
18 18 <template #value-location-locationMin="{ value }">
19 19 <el-tag v-if="value" size="mini" disable-transitions>{{ value }}</el-tag>
... ... @@ -27,10 +27,8 @@
27 27 </el-table-column>
28 28 </template> -->
29 29 </eg-table>
30   - <!-- <p>这是一个非markdown页面</p>
31   - <pre>{{ model }}</pre>
32 30 <el-button size="mini" @click="handleGetValue">校验</el-button>
33   - <eg-form ref="form" v-model="model" :list="option.list" @validate="onValidate" label-width="80px" :span="6" type="div"></eg-form> -->
  31 + <!-- <eg-form ref="form" v-model="model" :list="option.list" @validate="onValidate" label-width="80px" :span="6" type="div"></eg-form> -->
34 32 <eg-form
35 33 ref="form" v-model="model" :list="option.list" @validate="onValidate" :span="4"
36 34 form-class="custom-form" title-class="custom-title" content-class="custom-content" item-class="custom-item"
... ... @@ -73,9 +71,10 @@ export default {
73 71 {
74 72 group: { key: 'district' },
75 73 list: [
76   - { type: 'eagle-select', label: '省', key: 'province', props: { dataSource: [{ label: '上海', value: '上海' }, { label: '北京', value: '北京' }] }, rules: [{ required: true, message: '请输入省', trigger: 'change' }], minWidth: 120 },
  74 + { type: 'eagle-select', label: '省', key: 'province', props: { dataSource: [{ label: '新疆', value: '新疆' }, { label: '四川', value: '四川' }] }, rules: [{ required: true, message: '请输入省', trigger: 'change' }], minWidth: 120 },
77 75 // { type: 'el-input', label: '市', key: 'city', render: { type: 'el-tag', props: { type: 'danger', size: 'mini' } } },
78   - { type: 'el-input', label: '市', key: 'city',
  76 + { type: 'eagle-select', label: '市', key: 'city',
  77 + props: { dataSource: [{ label: '上海', value: '上海' }, { label: '北京', value: '北京' }] },
79 78 render: {
80 79 type: 'a', props: { href: 'https:///www.baidu.com/', target: '_blank' }, style: { color: 'red' },
81 80 children({ row }) {
... ... @@ -161,6 +160,9 @@ export default {
161 160 },
162 161 handleGetValue() {
163 162 this.$refs.form.validate();
  163 + },
  164 + onCellEdit(e) {
  165 + console.log(e)
164 166 }
165 167 }
166 168 }
... ...
examples/views/page/table-new/cell-editable.vue
... ... @@ -18,9 +18,9 @@
18 18 <component
19 19 :value="$_get(row, item.fullKey)"
20 20 :is="item.type" v-bind="item.props" :style="item.style" size="mini"
21   - @input="v => $emit('update', { value: v, row, key: item.fullKey })"
  21 + @input="v => $emit('update', { oldValue, value: v, row, key: item.key, fullKey: item.fullKey })"
22 22 ></component>
23   - <span @click="$emit('done')">
  23 + <span v-if="btnVisible !== false" @click="$emit('done')">
24 24 <svg class="eagle-table-cell-editable__icon" viewBox="0 0 1024 1024" width="24" height="24">
25 25 <path d="M235.946667 472.938667l-45.226667 45.312 210.090667 209.514666 432.362666-427.690666-45.013333-45.482667-387.157333 382.976z"></path>
26 26 </svg>
... ... @@ -49,9 +49,23 @@ export default {
49 49 row: Object,
50 50 item: Object,
51 51 editable: Boolean,
  52 + btnVisible: Boolean,
52 53 },
53 54 methods: {
54 55 $_get: get,
  56 + },
  57 + data() {
  58 + return {
  59 + oldValue: undefined,
  60 + }
  61 + },
  62 + watch: {
  63 + editable: {
  64 + handler() {
  65 + this.oldValue = get(this.row, this.item.agentKey || this.item.fullKey);
  66 + },
  67 + immediate: true,
  68 + }
55 69 }
56 70 }
57 71 </script>
58 72 \ No newline at end of file
... ...
examples/views/page/table-new/index.vue
... ... @@ -5,8 +5,16 @@
5 5 </style>
6 6  
7 7 <template>
8   - <div @keyup.enter="editCell = {}">
9   - <el-table class="eagle-table" ref="table" :data="tableData" v-bind="{ size: 'small', ...tableProps }" v-on="tableEvents" @cell-dblclick="onCellDblclick">
  8 + <div @keyup.enter="tableEditCell = {}">
  9 + <div style="padding-bottom: 10px;">
  10 + <el-button @click="handleNew" size="mini">新增</el-button>
  11 + <el-button @click="handleEdit" size="mini" v-if="!rowEditable && tableSelection.length > 0">编辑</el-button>
  12 + <el-button @click="handleSave" size="mini" type="primary" v-if="rowEditable">完成</el-button>
  13 + <el-button @click="handleCancel" size="mini" type="plain" v-if="rowNew">取消</el-button>
  14 + </div>
  15 + <el-table class="eagle-table" ref="table" :data="tableData" v-bind="{ size: 'small', ...tableProps }"
  16 + v-on="tableEvents" @cell-dblclick="onCellDblclick" @selection-change="onSelectionChange"
  17 + >
10 18 <!-- 默认表格插槽 -->
11 19 <slot name="default"></slot>
12 20 <!-- 根据配置列表生成表格列 -->
... ... @@ -16,11 +24,11 @@
16 24 <!-- 如果有表格列具名插槽 -->
17 25 <slot v-if="$scopedSlots[item.keyPath.join('-')]" :name="item.keyPath.join('-')" v-bind="item"></slot>
18 26 <!-- 默认表格列渲染 -->
19   - <el-table-column v-else v-bind="item" :prop="item.agentKey || item.fullKey || item.key" :key="index" :min-width="item.minWidth || item['min-width'] || 140">
  27 + <el-table-column v-else v-bind="item" :prop="item.fullKey || item.key" :key="index" :min-width="minWidth || item.minWidth || item['min-width'] || (editable ? 140 : undefined)">
20 28 <template #default="{ row, column, $index }">
21 29 <cell-editable
22   - :editable="editable && (editCell.index === row.$index && editCell.key === (item.agentKey || item.fullKey || item.key))"
23   - :row="row" :item="item" @update="onCellUpdate" @done="editCell = {}"
  30 + :editable="row.$editable || (editable && (tableEditCell.index === row.$index && tableEditCell.key === (item.agentKey || item.fullKey || item.key)))"
  31 + :row="row" :item="item" @update="onCellUpdate" @done="onCellUpdateDone" :btn-visible="!row.$editable"
24 32 >
25 33 <!-- 如果有表格列值渲染具名插槽 -->
26 34 <slot v-if="$scopedSlots[`value-${item.keyPath.join('-')}`]" :name="`value-${item.keyPath.join('-')}`" v-bind="item"
... ... @@ -69,12 +77,16 @@ export default {
69 77 tableEvents: Object,
70 78 // 是否可编辑
71 79 editable: Boolean,
  80 + // 列宽
  81 + minWidth: Number,
72 82 },
73 83 data() {
74 84 return {
75   - tableList: [],
76   - tableData: [],
77   - editCell: {},
  85 + tableList: [], // 表格配置列表
  86 + tableData: [], // 表格数据
  87 + tableRowTemplate: { $editable: true }, // 行数据模板
  88 + tableEditCell: {}, // 正在编辑的单元格
  89 + tableSelection: [], // 表格已选中
78 90 };
79 91 },
80 92 computed: {
... ... @@ -83,6 +95,28 @@ export default {
83 95 get() {
84 96 return this.$refs.table;
85 97 }
  98 + },
  99 + // 行编辑状态
  100 + rowEditable() {
  101 + let result = false;
  102 + for (const row of this.tableData) {
  103 + if (row.$editable) {
  104 + result = true;
  105 + break;
  106 + }
  107 + }
  108 + return result;
  109 + },
  110 + // 存在新行
  111 + rowNew() {
  112 + let result = false;
  113 + for (const row of this.tableData) {
  114 + if (row.$new) {
  115 + result = true;
  116 + break;
  117 + }
  118 + }
  119 + return result;
86 120 }
87 121 },
88 122 watch: {
... ... @@ -115,6 +149,7 @@ export default {
115 149 generateFullKey(newList);
116 150 // 创建输出列表
117 151 const result = [];
  152 + const tableRowTemplate = {};
118 153 // 生成列表值的全路径key,即列表项为对象时,对象内的key与上一级的key合并作为全路径key
119 154 const generateFlatList = (list) => {
120 155 list.forEach(item => {
... ... @@ -122,17 +157,59 @@ export default {
122 157 generateFlatList(item.list);
123 158 } else if (!item.group && !item.list) {
124 159 result.push({ ...item, keyPath: item.fullKey.split('.') });
  160 + set(tableRowTemplate, item.fullKey, undefined);
  161 + tableRowTemplate.$editable = true;
125 162 }
126 163 });
127 164 };
128 165 generateFlatList(newList);
129 166 this.tableList = result;
  167 + this.tableRowTemplate = tableRowTemplate;
130 168 },
131 169 immediate: true
132 170 }
133 171 },
134 172 methods: {
135 173 $_get: get,
  174 + handleNew() {
  175 + const tableData = cloneDeep(this.tableData);
  176 + tableData.push({ ...this.tableRowTemplate, $new: true });
  177 + this.tableEditCell = {};
  178 + this.emitTableData(tableData);
  179 + },
  180 + handleEdit() {
  181 + const tableData = cloneDeep(this.tableData);
  182 + const selectionIndexArr = this.tableSelection.map(i => i.$index);
  183 + tableData.forEach((r, i) => {
  184 + if (selectionIndexArr.includes(r.$index)) {
  185 + tableData[i].$editable = true;
  186 + }
  187 + });
  188 + this.tableEditCell = {};
  189 + this.emitTableData(tableData);
  190 + },
  191 + handleSave() {
  192 + const tableData = cloneDeep(this.tableData);
  193 + tableData.forEach((r, i) => {
  194 + delete tableData[i].$editable;
  195 + delete tableData[i].$new;
  196 + });
  197 + this.tableEditCell = {};
  198 + this.emitTableData(tableData);
  199 + },
  200 + handleCancel() {
  201 + let tableData = cloneDeep(this.tableData);
  202 + tableData = tableData.filter(row => !row.$new);
  203 + this.emitTableData(tableData);
  204 + },
  205 + // 更新表格数据
  206 + emitTableData(tableData) {
  207 + if (this.$listeners['input']) {
  208 + this.$emit('input', tableData);
  209 + } else {
  210 + this.tableData = tableData;
  211 + }
  212 + },
136 213 // 绑定表格列显示隐藏状态
137 214 bindItemVisible(visible = true) {
138 215 let result = visible;
... ... @@ -147,19 +224,35 @@ export default {
147 224 },
148 225 // 双击单元格
149 226 onCellDblclick(row, column, cell, event) {
150   - this.editCell = { index: row.$index, key: column.property };
  227 + if (this.editable) {
  228 + this.tableEditCell = { index: row.$index, key: column.property };
  229 + }
151 230 },
152 231 // 编辑表格更新值
153   - onCellUpdate({ value, row, key }) {
  232 + onCellUpdate({ oldValue, value, row, key, fullKey }) {
154 233 const tableData = cloneDeep(this.tableData);
155 234 const tableRow = tableData[row.$index];
156   - set(tableRow, key, value);
  235 + set(tableRow, fullKey, value);
157 236 tableData[row.$index] = tableRow;
158 237 if (this.$listeners['input']) {
159   - this.$emit('input', tableData);
  238 + if (this.$listeners['input']) {
  239 + this.$set(this.tableData, row.$index, tableRow);
  240 + this.$emit('cell-edit', { row: tableRow, key, fullKey, oldValue, value });
  241 + } else {
  242 + this.$emit('input', tableData);
  243 + }
160 244 } else {
161 245 this.$set(this.tableData, row.$index, tableRow);
162 246 }
  247 + },
  248 + // 编辑表格确认
  249 + onCellUpdateDone() {
  250 + this.tableEditCell = {}
  251 + },
  252 + // 表格选中
  253 + onSelectionChange(selection) {
  254 + this.tableSelection = selection;
  255 + this.$emit('selection', selection);
163 256 }
164 257 }
165 258 };
... ...