wkjp-list-page 1.0.21 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -89,7 +89,7 @@ deviceListApi(params) {
89
89
  **情况:** 运营想自定义表头、列太多想藏起来。
90
90
  **默认:** **`columns` 达到 10 列及以上**(可用 **`column-config-auto-min`** 改阈值)时,表格最右侧自动出现 **表头设置** 齿轮;悬停齿轮显示 **「配置字段」** 提示(可用 **`column-config-tooltip`** 修改)。
91
91
  **可选:** `:enable-column-config="true"` 强制开启;`:enable-column-config="false"` 强制关闭。
92
- **作用:** 弹层内可 **搜索字段**、**显示/未显示** 分组、开关显隐、拖拽排序;**复选框列(`type: selection`)不出现在设置里**且表格始终保留;**固定列**左侧显示「固定」且不可拖不可关。点 **确认** 后才会作用到表格并触发 **`columns-change`**,点 **取消** / 关闭 / 再次点齿轮则放弃本次修改。
92
+ **作用:** 弹层内可 **搜索字段**、**显示/未显示** 分组、开关显隐、拖拽排序;**复选框列(`type: selection`)不出现在设置里**且表格始终保留;列上 **`showInColumnConfig: false`** 可排除在表头设置外(表格仍显示该列);**固定列**左侧显示「固定」且不可拖不可关。点 **确认** 后才会作用到表格并触发 **`columns-change`**,点 **取消** / 关闭 / 再次点齿轮则放弃本次修改。
93
93
 
94
94
  ### 2.2 不想要「查询」按钮,或想改按钮上的字
95
95
 
@@ -344,6 +344,8 @@ deviceListTransformList(list) {
344
344
  | `emptyText` / `defaultText` | 空值时显示文案;**`emptyText` 优先**;都不设则用 **`cell-empty-text`**(默认 `--`)。 |
345
345
  | `width` / `minWidth` | 显式指定后不再自动算宽;仍可配合上面的 tooltip 规则。 |
346
346
  | `showOverflowTooltip` | 显式 `true` / `false` 时优先于自动规则。 |
347
+ | `showInColumnConfig` | 是否出现在 **表头设置** 弹层,默认 **`true`**;为 **`false`** 时不出现在设置里(不可被用户隐藏),表格仍渲染。兼容 **`columnConfigShow`**。 |
348
+ | `configFixed` | 在表头设置中视为固定列,不可拖、不可关(常与 `fixed` 联用)。 |
347
349
 
348
350
  ---
349
351
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wkjp-list-page",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "Vue2 + ElementUI CommonListPage component",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -60,6 +60,7 @@
60
60
  :type="item.type || 'date'"
61
61
  :unlink-panels="resolveSearchUnlinkPanels(item)"
62
62
  :editable="item.editable === true"
63
+ :clearable="item.clearable !== false"
63
64
  :range-separator="item.rangeSeparator || '至'"
64
65
  :style="{ width: `${item.width || (item.type === 'daterange' || item.type === 'datetimerange' ? 300 : 150)}px` }"
65
66
  :label="floatingLabelFor(item)"
@@ -194,7 +195,11 @@
194
195
  <div class="column-config-panel__body">
195
196
  <div class="column-config-panel__section">
196
197
  <div class="column-config-panel__section-title">显示字段</div>
197
- <ul v-if="visibleConfigIndexes.length" class="column-config-panel__list">
198
+ <ul
199
+ v-if="visibleConfigIndexes.length"
200
+ ref="columnConfigSortableList"
201
+ class="column-config-panel__list column-config-panel__list--sortable"
202
+ >
198
203
  <li
199
204
  v-for="idx in visibleConfigIndexes"
200
205
  :key="configColumns[idx]._configKey"
@@ -202,21 +207,27 @@
202
207
  class="column-config-panel__item"
203
208
  :class="{
204
209
  'column-config-panel__item--fixed': isFixedColumn(configColumns[idx]),
205
- 'column-config-panel__item--dragging': dragFromIndex === idx,
206
- 'column-config-panel__item--drag-over': dragOverIndex === idx
210
+ 'column-config-panel__item--dragging': isColumnDragRow(configColumns[idx]),
211
+ 'column-config-panel__item--shift': !!columnDragKey && !isColumnDragRow(configColumns[idx])
207
212
  }"
213
+ :style="getColumnDragShiftStyle(idx)"
214
+ @mousedown="onColumnRowMouseDown(idx, $event)"
208
215
  >
209
216
  <span
210
217
  v-if="isFixedColumn(configColumns[idx])"
211
218
  class="column-config-panel__fixed-tag"
212
219
  >{{ columnConfigFixedText }}</span>
213
- <i
220
+ <span
214
221
  v-else
215
- class="column-config-panel__drag el-icon-rank"
216
- @mousedown.prevent="onDragMouseDown(idx)"
217
- ></i>
222
+ class="column-config-panel__drag"
223
+ title="拖动排序"
224
+ @mousedown.prevent.stop="onDragMouseDown(idx, $event)"
225
+ >
226
+ <i v-for="dot in 6" :key="'dot-' + idx + '-' + dot"></i>
227
+ </span>
218
228
  <span class="column-config-panel__label">{{ columnConfigLabel(configColumns[idx]) }}</span>
219
229
  <el-switch
230
+ class="column-config-panel__switch"
220
231
  :value="configColumns[idx]._visible !== false"
221
232
  :disabled="isFixedColumn(configColumns[idx])"
222
233
  @input="(val) => setColumnVisible(idx, val)"
@@ -248,6 +259,20 @@
248
259
  <el-button size="small" @click="cancelColumnConfig">{{ columnConfigCancelText }}</el-button>
249
260
  <el-button type="primary" size="small" @click="confirmColumnConfig">{{ columnConfigConfirmText }}</el-button>
250
261
  </div>
262
+ <div
263
+ v-show="!!columnDragKey"
264
+ class="column-config-panel__row-ghost"
265
+ :style="columnDragGhostStyle"
266
+ >
267
+ <span class="column-config-panel__drag column-config-panel__drag--ghost">
268
+ <i v-for="dot in 6" :key="'ghost-dot-' + dot"></i>
269
+ </span>
270
+ <span class="column-config-panel__label">{{ columnDragGhostLabel }}</span>
271
+ <span
272
+ class="column-config-panel__ghost-switch"
273
+ :class="{ 'is-on': columnDragGhostSwitchOn }"
274
+ ></span>
275
+ </div>
251
276
  </div>
252
277
  </el-popover>
253
278
 
@@ -343,9 +368,14 @@ export default {
343
368
  showQueryButton: { type: Boolean, default: true },
344
369
  /** 主查询按钮文案 */
345
370
  queryButtonText: { type: String, default: "查询" },
346
- /** 是否显示「清除查询」按钮(在查询按钮右侧):将 `filters` 恢复为进入页面时的快照并重新查询 */
371
+ /** 是否显示「重置」按钮(在查询按钮右侧):将 `filters` 恢复为进入页面时的快照 */
347
372
  showClearQueryButton: { type: Boolean, default: true },
348
- clearQueryButtonText: { type: String, default: "清除查询" },
373
+ clearQueryButtonText: { type: String, default: "重置" },
374
+ /**
375
+ * 点击「重置」后是否自动 `fetchList`。默认 **true**:恢复查询条件后重新拉表。
376
+ * 带「请选择…再查询」等前置校验的页面请设为 **false**,仅重置条件不请求。
377
+ */
378
+ fetchOnClearQuery: { type: Boolean, default: true },
349
379
  /**
350
380
  * 搜索区折叠:显式 `true` / `false` 强制开/关;
351
381
  * 未传时 **`searchOption` 超过 `searchVisibleMax`(默认 6)** 自动显示「展开查询」。
@@ -397,12 +427,25 @@ export default {
397
427
  },
398
428
  columnConfigVisible: false,
399
429
  columnConfigKeyword: "",
400
- dragFromIndex: -1,
430
+ /** 正在被拖起的列(用 _configKey 跟踪,拖动中会实时换位) */
431
+ columnDragKey: "",
401
432
  dragOverIndex: -1,
433
+ columnDragGhostLabel: "",
434
+ columnDragGhostSwitchOn: true,
435
+ columnDragGhostX: 0,
436
+ columnDragGhostY: 0,
437
+ columnDragGhostWidth: 0,
438
+ columnDragGhostOffsetX: 0,
439
+ columnDragGhostOffsetY: 0,
440
+ /** 拖动开始时在可拖列表中的序号 */
441
+ columnDragStartOrderIndex: -1,
442
+ /** 当前插入槽位(0 ~ 可拖项数量) */
443
+ columnDragInsertAt: -1,
444
+ columnDragRowHeight: 42,
402
445
  columnConfigPanelMaxHeight: null,
403
446
  configColumns: [],
404
447
  appliedColumns: [],
405
- /** 进入页时 filters 的快照,用于「清除查询」 */
448
+ /** 进入页时 filters 的快照,用于「重置」 */
406
449
  initialFiltersSnapshot: null,
407
450
  initialFiltersCaptured: false
408
451
  };
@@ -459,6 +502,13 @@ export default {
459
502
  columnConfigSearchActive() {
460
503
  return String(this.columnConfigKeyword || "").trim() !== "";
461
504
  },
505
+ columnDragGhostStyle() {
506
+ return {
507
+ width: this.columnDragGhostWidth > 0 ? this.columnDragGhostWidth + "px" : "auto",
508
+ transform:
509
+ "translate3d(" + this.columnDragGhostX + "px," + this.columnDragGhostY + "px,0)"
510
+ };
511
+ },
462
512
  mergedHeaderCellStyle() {
463
513
  const baseBg = this.tableHeaderBg || "#e5e9f2";
464
514
  const base = { backgroundColor: baseBg };
@@ -609,9 +659,12 @@ export default {
609
659
  isBuiltinCellColumn(col) {
610
660
  return col && ["selection", "index", "expand"].indexOf(col.type) !== -1;
611
661
  },
612
- /** 复选框列不参与表头设置 */
662
+ /** 复选框、展开列及 showInColumnConfig:false 不参与表头设置 */
613
663
  isConfigPanelColumn(col) {
614
- return col && col.type !== "selection";
664
+ if (!col) return false;
665
+ if (col.type === "selection" || col.type === "expand") return false;
666
+ if (col.showInColumnConfig === false) return false;
667
+ return true;
615
668
  },
616
669
  textDisplayLength(text) {
617
670
  return String(text == null ? "" : text).length;
@@ -687,7 +740,11 @@ export default {
687
740
  captureInitialFilters() {
688
741
  if (this.initialFiltersCaptured || !this.filters) return;
689
742
  try {
690
- this.initialFiltersSnapshot = JSON.parse(JSON.stringify(this.filters));
743
+ const snap = {};
744
+ Object.keys(this.filters).forEach((key) => {
745
+ snap[key] = this.cloneFilterValue(this.filters[key]);
746
+ });
747
+ this.initialFiltersSnapshot = snap;
691
748
  this.initialFiltersCaptured = true;
692
749
  } catch (e) {
693
750
  this.initialFiltersSnapshot = null;
@@ -706,14 +763,34 @@ export default {
706
763
  const snap = this.initialFiltersSnapshot;
707
764
  const f = this.filters;
708
765
  if (!snap || !f) return;
709
- Object.keys(snap).forEach((key) => {
710
- this.$set(f, key, this.cloneFilterValue(snap[key]));
766
+ Object.keys(f).forEach((key) => {
767
+ const val = Object.prototype.hasOwnProperty.call(snap, key)
768
+ ? snap[key]
769
+ : undefined;
770
+ this.$set(f, key, this.cloneFilterValue(val));
771
+ });
772
+ },
773
+ resetListWithoutFetch() {
774
+ this.innerPagination.page = 1;
775
+ this.innerTableData = [];
776
+ this.innerPagination.total = 0;
777
+ this.syncPaginationToFilters();
778
+ this.$emit("fetched", {
779
+ list: [],
780
+ total: 0,
781
+ page: this.innerPagination.page,
782
+ pageSize: this.innerPagination.pageSize,
783
+ raw: null,
711
784
  });
712
785
  },
713
786
  handleClearQueryClick() {
714
787
  this.applyInitialFiltersSnapshot();
715
- this.fetchList({ resetPage: true });
716
788
  this.$emit("clear-query");
789
+ if (this.fetchOnClearQuery) {
790
+ this.fetchList({ resetPage: true });
791
+ } else {
792
+ this.resetListWithoutFetch();
793
+ }
717
794
  },
718
795
  resolveValue(item) {
719
796
  if (Object.prototype.hasOwnProperty.call(item, "value")) return item.value;
@@ -978,8 +1055,12 @@ export default {
978
1055
  closeColumnConfigPopover() {
979
1056
  this.columnConfigVisible = false;
980
1057
  this.columnConfigKeyword = "";
981
- this.dragFromIndex = -1;
1058
+ this.columnDragKey = "";
1059
+ this.columnDragStartOrderIndex = -1;
1060
+ this.columnDragInsertAt = -1;
982
1061
  this.dragOverIndex = -1;
1062
+ this.columnDragGhostLabel = "";
1063
+ this.columnDragGhostWidth = 0;
983
1064
  this.columnConfigPanelMaxHeight = null;
984
1065
  this.removeColumnDragListeners();
985
1066
  this.unbindColumnConfigResize();
@@ -1018,7 +1099,9 @@ export default {
1018
1099
  },
1019
1100
  onColumnConfigShow() {
1020
1101
  this.columnConfigKeyword = "";
1021
- this.dragFromIndex = -1;
1102
+ this.columnDragKey = "";
1103
+ this.columnDragStartOrderIndex = -1;
1104
+ this.columnDragInsertAt = -1;
1022
1105
  this.dragOverIndex = -1;
1023
1106
  this.configColumns = this.cloneConfigColumnsFrom(this.appliedColumns);
1024
1107
  },
@@ -1097,44 +1180,227 @@ export default {
1097
1180
  document.removeEventListener("mouseup", this._columnDragUpHandler);
1098
1181
  this._columnDragUpHandler = null;
1099
1182
  }
1183
+ if (this._columnDragRaf && typeof window !== "undefined" && window.cancelAnimationFrame) {
1184
+ window.cancelAnimationFrame(this._columnDragRaf);
1185
+ this._columnDragRaf = null;
1186
+ }
1187
+ this._columnDragLastEvent = null;
1188
+ if (typeof document !== "undefined") {
1189
+ document.body.classList.remove("wkjp-column-dragging");
1190
+ document.body.style.cursor = "";
1191
+ document.body.style.userSelect = "";
1192
+ }
1193
+ },
1194
+ getVisibleDraggableOrder() {
1195
+ const order = [];
1196
+ for (let i = 0; i < this.visibleConfigIndexes.length; i++) {
1197
+ const idx = this.visibleConfigIndexes[i];
1198
+ if (this.canDragConfigIndex(idx)) order.push(idx);
1199
+ }
1200
+ return order;
1201
+ },
1202
+ getConfigIndexAfterVisibleDraggable(lastIdx) {
1203
+ for (let i = lastIdx + 1; i <= this.configColumns.length; i++) {
1204
+ if (i >= this.configColumns.length) return this.configColumns.length;
1205
+ const col = this.configColumns[i];
1206
+ if (!col) return i;
1207
+ if (this.isColumnDragRow(col)) return i;
1208
+ if (this.isFixedColumn(col)) return i;
1209
+ if (col._visible === false) continue;
1210
+ return i;
1211
+ }
1212
+ return lastIdx + 1;
1213
+ },
1214
+ /** 拖动中:计算插入槽位(order 下标 0~length,不在此阶段改 configColumns) */
1215
+ resolveConfigDragInsertOrderIndex(e) {
1216
+ const order = this.getVisibleDraggableOrder();
1217
+ if (!order.length) return 0;
1218
+ const from = this.getColumnDragCurrentIndex();
1219
+ const without = from >= 0 ? order.filter((idx) => idx !== from) : order.slice();
1220
+ if (!without.length) return 0;
1221
+
1222
+ const listEl = this.getColumnConfigSortableListEl();
1223
+ if (!listEl) return this.columnDragStartOrderIndex >= 0 ? this.columnDragStartOrderIndex : 0;
1224
+
1225
+ const y = e.clientY;
1226
+ let slotInWithout = without.length;
1227
+ for (let i = 0; i < without.length; i++) {
1228
+ const row = listEl.querySelector('[data-config-idx="' + without[i] + '"]');
1229
+ if (!row) continue;
1230
+ const rect = row.getBoundingClientRect();
1231
+ if (y < rect.top + rect.height / 2) {
1232
+ slotInWithout = i;
1233
+ break;
1234
+ }
1235
+ }
1236
+
1237
+ if (slotInWithout >= without.length) return order.length;
1238
+ return order.indexOf(without[slotInWithout]);
1239
+ },
1240
+ resolveConfigDragTargetIndexFromInsert(insertOrderIndex) {
1241
+ const order = this.getVisibleDraggableOrder();
1242
+ if (!order.length) return -1;
1243
+ const from = this.getColumnDragCurrentIndex();
1244
+ if (from < 0) return -1;
1245
+ if (insertOrderIndex >= order.length) {
1246
+ return this.getConfigIndexAfterVisibleDraggable(order[order.length - 1]);
1247
+ }
1248
+ return order[insertOrderIndex];
1249
+ },
1250
+ getColumnDragShiftStyle(idx) {
1251
+ if (!this.columnDragKey || this.columnDragInsertAt < 0) return {};
1252
+ const col = this.configColumns[idx];
1253
+ if (!col || this.isColumnDragRow(col) || !this.canDragConfigIndex(idx)) return {};
1254
+
1255
+ const order = this.getVisibleDraggableOrder();
1256
+ const orderIndex = order.indexOf(idx);
1257
+ if (orderIndex < 0) return {};
1258
+
1259
+ const dragStart = this.columnDragStartOrderIndex;
1260
+ const insertAt = this.columnDragInsertAt;
1261
+ const h = this.columnDragRowHeight || 42;
1262
+ let translateY = 0;
1263
+
1264
+ if (dragStart < insertAt) {
1265
+ if (orderIndex > dragStart && orderIndex < insertAt) translateY = -h;
1266
+ } else if (dragStart > insertAt) {
1267
+ if (orderIndex >= insertAt && orderIndex < dragStart) translateY = h;
1268
+ }
1269
+
1270
+ if (!translateY) return {};
1271
+ return {
1272
+ transform: "translate3d(0," + translateY + "px,0)"
1273
+ };
1274
+ },
1275
+ getColumnConfigPopperRoot() {
1276
+ const pop = this.$refs.columnConfigPopover;
1277
+ return pop && pop.popperElm ? pop.popperElm : null;
1278
+ },
1279
+ getColumnConfigSortableListEl() {
1280
+ const root = this.getColumnConfigPopperRoot();
1281
+ if (root) {
1282
+ return root.querySelector(".column-config-panel__list--sortable");
1283
+ }
1284
+ const ref = this.$refs.columnConfigSortableList;
1285
+ return ref || null;
1286
+ },
1287
+ isColumnDragRow(col) {
1288
+ return !!(col && this.columnDragKey && col._configKey === this.columnDragKey);
1289
+ },
1290
+ getColumnDragCurrentIndex() {
1291
+ if (!this.columnDragKey) return -1;
1292
+ for (let i = 0; i < this.configColumns.length; i++) {
1293
+ if (this.configColumns[i]._configKey === this.columnDragKey) return i;
1294
+ }
1295
+ return -1;
1296
+ },
1297
+ updateColumnDragGhostPosition(e) {
1298
+ if (!e) return;
1299
+ this.columnDragGhostX = e.clientX - this.columnDragGhostOffsetX;
1300
+ this.columnDragGhostY = e.clientY - this.columnDragGhostOffsetY;
1301
+ },
1302
+ onColumnRowMouseDown(idx, e) {
1303
+ if (!e || e.button !== 0) return;
1304
+ if (e.target.closest(".el-switch") || e.target.closest(".column-config-panel__drag")) return;
1305
+ if (!this.canDragConfigIndex(idx)) return;
1306
+ e.preventDefault();
1307
+ this.onDragMouseDown(idx, e);
1100
1308
  },
1101
- onDragMouseDown(idx) {
1309
+ onDragMouseDown(idx, e) {
1102
1310
  if (!this.canDragConfigIndex(idx)) return;
1103
- this.dragFromIndex = idx;
1311
+ const rowEl =
1312
+ e && e.currentTarget
1313
+ ? e.currentTarget.closest("[data-config-idx]")
1314
+ : null;
1315
+ if (rowEl) {
1316
+ const rect = rowEl.getBoundingClientRect();
1317
+ this.columnDragGhostWidth = rect.width;
1318
+ this.columnDragGhostOffsetX = e.clientX - rect.left;
1319
+ this.columnDragGhostOffsetY = e.clientY - rect.top;
1320
+ } else {
1321
+ this.columnDragGhostWidth = 0;
1322
+ this.columnDragGhostOffsetX = 12;
1323
+ this.columnDragGhostOffsetY = 20;
1324
+ }
1325
+ const listEl = this.getColumnConfigSortableListEl();
1326
+ const listRect = listEl ? listEl.getBoundingClientRect() : null;
1327
+ if (listRect && listRect.width > 0) {
1328
+ this.columnDragGhostWidth = listRect.width;
1329
+ }
1330
+ const col = this.configColumns[idx];
1331
+ const order = this.getVisibleDraggableOrder();
1332
+ const startOrder = order.indexOf(idx);
1333
+ this.columnDragKey = col._configKey || "";
1334
+ this.columnDragStartOrderIndex = startOrder;
1335
+ this.columnDragInsertAt = startOrder >= 0 ? startOrder : 0;
1336
+ if (rowEl) {
1337
+ const rh = rowEl.offsetHeight || rowEl.getBoundingClientRect().height;
1338
+ if (rh > 0) this.columnDragRowHeight = Math.round(rh);
1339
+ }
1104
1340
  this.dragOverIndex = idx;
1105
- this._columnDragMoveHandler = (e) => this.onDragMouseMove(e);
1341
+ this.columnDragGhostLabel = this.columnConfigLabel(col);
1342
+ this.columnDragGhostSwitchOn = col && col._visible !== false;
1343
+ this.updateColumnDragGhostPosition(e);
1344
+ if (typeof document !== "undefined") {
1345
+ document.body.classList.add("wkjp-column-dragging");
1346
+ document.body.style.cursor = "grabbing";
1347
+ document.body.style.userSelect = "none";
1348
+ }
1349
+ this._columnDragMoveHandler = (ev) => this.onDragMouseMove(ev);
1106
1350
  this._columnDragUpHandler = () => this.onDragMouseUp();
1107
1351
  document.addEventListener("mousemove", this._columnDragMoveHandler);
1108
1352
  document.addEventListener("mouseup", this._columnDragUpHandler);
1109
1353
  },
1354
+ handleDragMouseMove(e) {
1355
+ if (!this.columnDragKey || !e) return;
1356
+ this.updateColumnDragGhostPosition(e);
1357
+ const insertOrder = this.resolveConfigDragInsertOrderIndex(e);
1358
+ if (insertOrder >= 0 && insertOrder !== this.columnDragInsertAt) {
1359
+ this.columnDragInsertAt = insertOrder;
1360
+ }
1361
+ },
1110
1362
  onDragMouseMove(e) {
1111
- if (this.dragFromIndex < 0) return;
1112
- const target = document.elementFromPoint(e.clientX, e.clientY);
1113
- if (!target) return;
1114
- const row = target.closest("[data-config-idx]");
1115
- if (!row) return;
1116
- const overIdx = Number(row.getAttribute("data-config-idx"));
1117
- if (!Number.isFinite(overIdx) || !this.canDragConfigIndex(overIdx)) return;
1118
- this.dragOverIndex = overIdx;
1363
+ if (!this.columnDragKey) return;
1364
+ this._columnDragLastEvent = e;
1365
+ if (this._columnDragRaf) return;
1366
+ const schedule =
1367
+ typeof window !== "undefined" && window.requestAnimationFrame
1368
+ ? window.requestAnimationFrame.bind(window)
1369
+ : function (fn) {
1370
+ return setTimeout(fn, 16);
1371
+ };
1372
+ this._columnDragRaf = schedule(() => {
1373
+ this._columnDragRaf = null;
1374
+ this.handleDragMouseMove(this._columnDragLastEvent);
1375
+ });
1119
1376
  },
1120
1377
  onDragMouseUp() {
1378
+ const from = this.getColumnDragCurrentIndex();
1379
+ const insertOrder = this.columnDragInsertAt;
1380
+ const targetIdx =
1381
+ insertOrder >= 0 ? this.resolveConfigDragTargetIndexFromInsert(insertOrder) : -1;
1121
1382
  this.removeColumnDragListeners();
1122
- if (
1123
- this.dragFromIndex >= 0 &&
1124
- this.dragOverIndex >= 0 &&
1125
- this.dragFromIndex !== this.dragOverIndex
1126
- ) {
1127
- this.moveConfigColumnByIndex(this.dragFromIndex, this.dragOverIndex);
1383
+ if (from >= 0 && targetIdx >= 0 && targetIdx !== from) {
1384
+ this.moveConfigColumnByIndex(from, targetIdx);
1128
1385
  }
1129
- this.dragFromIndex = -1;
1386
+ this.columnDragKey = "";
1387
+ this.columnDragStartOrderIndex = -1;
1388
+ this.columnDragInsertAt = -1;
1130
1389
  this.dragOverIndex = -1;
1390
+ this.columnDragGhostLabel = "";
1391
+ this.columnDragGhostWidth = 0;
1131
1392
  },
1132
1393
  moveConfigColumnByIndex(from, to) {
1394
+ if (from === to) return;
1133
1395
  const cols = this.configColumns.slice();
1134
- if (this.isFixedColumn(cols[from]) || this.isFixedColumn(cols[to])) return;
1396
+ if (!cols[from] || this.isFixedColumn(cols[from])) return;
1135
1397
  const moving = cols[from];
1136
1398
  cols.splice(from, 1);
1137
- cols.splice(to, 0, moving);
1399
+ let insertAt = to;
1400
+ if (from < to) insertAt = to - 1;
1401
+ if (insertAt < 0) insertAt = 0;
1402
+ if (insertAt > cols.length) insertAt = cols.length;
1403
+ cols.splice(insertAt, 0, moving);
1138
1404
  this.configColumns = cols;
1139
1405
  },
1140
1406
  applyColumnConfig() {
@@ -1418,11 +1684,15 @@ export default {
1418
1684
  color: #409eff;
1419
1685
  }
1420
1686
 
1421
- /* ---------- 列表表格(政务/后台列表:浅表头、无竖线、细横线) ---------- */
1687
+ /* ---------- 列表表格(浅表头、细横线;空数据用极细外框,不用 border 网格) ---------- */
1422
1688
  .common-list-page /deep/ .el-table {
1423
1689
  overflow: hidden;
1424
1690
  font-size: 12px;
1425
1691
  color: #606266;
1692
+ border: none;
1693
+ border-radius: 2px;
1694
+ outline: 1px solid #ebeef5;
1695
+ outline-offset: -1px;
1426
1696
  }
1427
1697
 
1428
1698
  .common-list-page /deep/ .el-table::before,
@@ -1431,6 +1701,25 @@ export default {
1431
1701
  display: none;
1432
1702
  }
1433
1703
 
1704
+ .common-list-page /deep/ .el-table__empty-block {
1705
+ min-height: 120px;
1706
+ width: 100% !important;
1707
+ }
1708
+
1709
+ .common-list-page /deep/ .el-table__fixed-right-patch {
1710
+ border-bottom: 1px solid #ebeef5;
1711
+ }
1712
+
1713
+ .common-list-page /deep/ .el-table__fixed::before,
1714
+ .common-list-page /deep/ .el-table__fixed-right::before {
1715
+ background-color: #ebeef5;
1716
+ }
1717
+
1718
+ .common-list-page /deep/ .el-table__fixed .el-table__body tr td.el-table__cell,
1719
+ .common-list-page /deep/ .el-table__fixed-right .el-table__body tr td.el-table__cell {
1720
+ border-bottom: 1px solid #f0f2f5 !important;
1721
+ }
1722
+
1434
1723
  .common-list-page /deep/ .el-table th.el-table__cell,
1435
1724
  .common-list-page /deep/ .el-table td.el-table__cell {
1436
1725
  border-right: none !important;
@@ -1441,7 +1730,7 @@ export default {
1441
1730
  font-weight: 600;
1442
1731
  font-size: 12px;
1443
1732
  padding: 10px 12px;
1444
- border-bottom: 1px solid #dde3eb !important;
1733
+ border-bottom: 1px solid #ebeef5 !important;
1445
1734
  }
1446
1735
 
1447
1736
  .common-list-page /deep/ .el-table td.el-table__cell {
@@ -1451,6 +1740,10 @@ export default {
1451
1740
  vertical-align: middle;
1452
1741
  }
1453
1742
 
1743
+ .common-list-page /deep/ .el-table__body tr:last-child td.el-table__cell {
1744
+ border-bottom: 1px solid #f0f2f5 !important;
1745
+ }
1746
+
1454
1747
  .common-list-page /deep/ .el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell {
1455
1748
  background: #fafbfc;
1456
1749
  }
@@ -1582,10 +1875,10 @@ export default {
1582
1875
 
1583
1876
  .column-config-panel__body {
1584
1877
  flex: 1;
1878
+ min-width: 0;
1585
1879
  min-height: 0;
1880
+ overflow-x: hidden;
1586
1881
  overflow-y: auto;
1587
- margin-right: -4px;
1588
- padding-right: 4px;
1589
1882
  }
1590
1883
 
1591
1884
  .column-config-panel__head {
@@ -1633,48 +1926,153 @@ export default {
1633
1926
  margin: 0;
1634
1927
  padding: 0;
1635
1928
  list-style: none;
1929
+ min-width: 0;
1930
+ max-width: 100%;
1931
+ }
1932
+
1933
+ .column-config-panel__list--sortable {
1934
+ min-width: 0;
1935
+ }
1936
+
1937
+ .column-config-panel__list--sortable .column-config-panel__item {
1938
+ transition: background-color 0.15s ease;
1939
+ }
1940
+
1941
+ .column-config-panel__list--sortable .column-config-panel__item--shift {
1942
+ transition: transform 0.22s cubic-bezier(0.2, 0, 0.2, 1), background-color 0.15s ease;
1943
+ will-change: transform;
1636
1944
  }
1637
1945
 
1638
1946
  .column-config-panel__item {
1947
+ position: relative;
1639
1948
  display: flex;
1640
1949
  align-items: center;
1641
- gap: 8px;
1642
- min-height: 36px;
1643
- padding: 4px 2px;
1644
- border-radius: 4px;
1645
- }
1646
-
1647
- .column-config-panel__item--dragging {
1648
- background: #ecf5ff;
1950
+ gap: 10px;
1951
+ min-width: 0;
1952
+ max-width: 100%;
1953
+ min-height: 40px;
1954
+ padding: 0 10px;
1955
+ margin-bottom: 2px;
1956
+ border-radius: 6px;
1957
+ box-sizing: border-box;
1958
+ background: transparent;
1649
1959
  }
1650
1960
 
1651
- .column-config-panel__item--drag-over {
1652
- background: #f5f7fa;
1961
+ .column-config-panel__item:not(.column-config-panel__item--fixed):not(.column-config-panel__item--dragging):hover {
1962
+ background: #f5f8fc;
1653
1963
  }
1654
1964
 
1655
- .column-config-panel__item[draggable="true"] {
1656
- cursor: move;
1965
+ .column-config-panel__item--dragging {
1966
+ visibility: hidden;
1657
1967
  }
1658
1968
 
1659
1969
  .column-config-panel__item--fixed {
1660
1970
  cursor: default;
1661
1971
  }
1662
1972
 
1973
+ .column-config-panel__item--hidden {
1974
+ opacity: 0.85;
1975
+ }
1976
+
1663
1977
  .column-config-panel__drag {
1664
1978
  flex-shrink: 0;
1665
- width: 16px;
1666
- font-size: 14px;
1667
- color: #c0c4cc;
1979
+ display: grid;
1980
+ grid-template-columns: repeat(2, 2px);
1981
+ grid-template-rows: repeat(3, 2px);
1982
+ gap: 3px;
1983
+ width: 7px;
1984
+ padding: 6px 8px 6px 2px;
1668
1985
  cursor: grab;
1669
1986
  touch-action: none;
1987
+ user-select: none;
1988
+ }
1989
+
1990
+ .column-config-panel__drag i {
1991
+ display: block;
1992
+ width: 2px;
1993
+ height: 2px;
1994
+ border-radius: 50%;
1995
+ background: #b8bcc4;
1996
+ transition: background-color 0.15s ease;
1997
+ }
1998
+
1999
+ .column-config-panel__item:hover .column-config-panel__drag i,
2000
+ .column-config-panel__drag:hover i {
2001
+ background: #909399;
1670
2002
  }
1671
2003
 
1672
2004
  .column-config-panel__drag:active {
1673
2005
  cursor: grabbing;
1674
2006
  }
1675
2007
 
2008
+ .column-config-panel__row-ghost {
2009
+ position: fixed;
2010
+ left: 0;
2011
+ top: 0;
2012
+ z-index: 4000;
2013
+ display: flex;
2014
+ align-items: center;
2015
+ gap: 10px;
2016
+ min-height: 40px;
2017
+ padding: 0 10px;
2018
+ box-sizing: border-box;
2019
+ font-size: 13px;
2020
+ color: #303133;
2021
+ background: #fff;
2022
+ border-radius: 6px;
2023
+ border: 1px solid #e8ecf2;
2024
+ box-shadow: 0 8px 20px rgba(15, 23, 42, 0.14);
2025
+ pointer-events: none;
2026
+ cursor: grabbing;
2027
+ will-change: transform;
2028
+ }
2029
+
2030
+ .column-config-panel__drag--ghost {
2031
+ cursor: grabbing;
2032
+ }
2033
+
2034
+ .column-config-panel__row-ghost .column-config-panel__label {
2035
+ flex: 1;
2036
+ min-width: 0;
2037
+ overflow: hidden;
2038
+ text-overflow: ellipsis;
2039
+ white-space: nowrap;
2040
+ }
2041
+
2042
+ .column-config-panel__ghost-switch {
2043
+ flex-shrink: 0;
2044
+ position: relative;
2045
+ width: 36px;
2046
+ height: 20px;
2047
+ border-radius: 10px;
2048
+ background: #dcdfe6;
2049
+ transition: background-color 0.15s ease;
2050
+ }
2051
+
2052
+ .column-config-panel__ghost-switch::after {
2053
+ content: "";
2054
+ position: absolute;
2055
+ top: 2px;
2056
+ left: 2px;
2057
+ width: 16px;
2058
+ height: 16px;
2059
+ border-radius: 50%;
2060
+ background: #fff;
2061
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
2062
+ transition: transform 0.15s ease;
2063
+ }
2064
+
2065
+ .column-config-panel__ghost-switch.is-on {
2066
+ background: #409eff;
2067
+ }
2068
+
2069
+ .column-config-panel__ghost-switch.is-on::after {
2070
+ transform: translateX(16px);
2071
+ }
2072
+
1676
2073
  .column-config-panel__drag--placeholder {
1677
2074
  visibility: hidden;
2075
+ pointer-events: none;
1678
2076
  }
1679
2077
 
1680
2078
  .column-config-panel__fixed-tag {
@@ -1717,14 +2115,25 @@ export default {
1717
2115
 
1718
2116
  <style>
1719
2117
  .common-list-page-column-config-popper {
1720
- padding: 12px 14px !important;
1721
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12) !important;
2118
+ padding: 14px 16px !important;
2119
+ border-radius: 8px !important;
2120
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12) !important;
1722
2121
  z-index: 3000 !important;
1723
2122
  overflow: hidden !important;
2123
+ overflow-x: hidden !important;
1724
2124
  margin: 0 !important;
1725
2125
  box-sizing: border-box !important;
1726
2126
  }
1727
2127
 
2128
+ .common-list-page-column-config-popper .column-config-panel__row-ghost {
2129
+ max-width: calc(100vw - 32px);
2130
+ }
2131
+
2132
+ .common-list-page-column-config-popper .column-config-panel__switch.el-switch {
2133
+ transform: scale(0.92);
2134
+ transform-origin: center right;
2135
+ }
2136
+
1728
2137
  .common-list-page-column-config-popper .el-switch {
1729
2138
  pointer-events: auto !important;
1730
2139
  }
@@ -1739,4 +2148,13 @@ export default {
1739
2148
  .common-list-page-column-config-popper .column-config-panel__switch .el-switch {
1740
2149
  pointer-events: auto;
1741
2150
  }
2151
+
2152
+ body.wkjp-column-dragging {
2153
+ cursor: grabbing !important;
2154
+ user-select: none !important;
2155
+ }
2156
+
2157
+ body.wkjp-column-dragging .column-config-panel__item--dragging {
2158
+ visibility: hidden !important;
2159
+ }
1742
2160
  </style>