arms-app 1.0.67 → 1.0.69
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/package.json +1 -1
- package/view/{555.vue → index.vue} +43 -59
- package/view/1.js +0 -23
- package/view/1.vue +0 -117
- package/view/111.js +0 -35
- package/view/2.js +0 -90
- package/view/2.vue +0 -129
- package/view/3.js +0 -289
- package/view/3.vue +0 -289
- package/view/4.vue +0 -473
- package/view/CallRecordDetail.vue +0 -101
- package/view/ListedCompaniesView copy.vue +0 -238
- package/view/ListedCompaniesView.vue +0 -224
- package/view/ListedEnterprisesView.vue +0 -206
- package/view/ListedIncrementalEnterprisesView.vue +0 -195
- package/view/index.html +0 -51
- package/view//345/205/250/345/261/217.png +0 -0
- package/view//351/200/200/345/207/272/345/205/250/345/261/217.png +0 -0
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<!--
|
|
2
|
+
<!-- 列拖拽示例页面:支持通过拖拽表头调整列顺序 -->
|
|
3
3
|
<section class="draggable-columns-table-page">
|
|
4
|
-
<!--
|
|
4
|
+
<!-- 标题与说明文案 -->
|
|
5
5
|
<h1>列拖拽表格</h1>
|
|
6
6
|
<p class="desc">通过拖拽表头,使用 sortablejs 实现列换位。</p>
|
|
7
7
|
|
|
8
|
-
<!-- 表格:通过 columns
|
|
8
|
+
<!-- 表格:通过 columns 数组驱动所有可拖拽列(含序号/操作列),rows 负责行数据 -->
|
|
9
9
|
<el-table
|
|
10
10
|
ref="draggableTable"
|
|
11
11
|
:key="tableKey"
|
|
@@ -15,13 +15,10 @@
|
|
|
15
15
|
style="width: 100%"
|
|
16
16
|
height="420"
|
|
17
17
|
>
|
|
18
|
-
<!--
|
|
19
|
-
<el-table-column type="index" label="#" width="60" />
|
|
20
|
-
|
|
21
|
-
<!-- 动态业务列:所有可拖拽的列 -->
|
|
18
|
+
<!-- 所有列(包含序号列/业务列/操作列)均由 columns 数组统一驱动,可参与拖拽 -->
|
|
22
19
|
<el-table-column
|
|
23
20
|
v-for="col in columns"
|
|
24
|
-
:key="col.prop"
|
|
21
|
+
:key="col.key || col.prop"
|
|
25
22
|
:prop="col.prop"
|
|
26
23
|
:label="col.label"
|
|
27
24
|
:width="col.width"
|
|
@@ -29,15 +26,25 @@
|
|
|
29
26
|
:align="col.align || 'left'"
|
|
30
27
|
:header-align="col.headerAlign || col.align || 'left'"
|
|
31
28
|
>
|
|
32
|
-
<!--
|
|
29
|
+
<!-- 表头插槽:渲染拖拽手柄(handle),供 sortablejs 使用 -->
|
|
33
30
|
<template slot="header">
|
|
34
31
|
<div class="header-draggable">
|
|
35
32
|
<span class="header-label">{{ col.label }}</span>
|
|
36
33
|
</div>
|
|
37
34
|
</template>
|
|
38
|
-
<!--
|
|
35
|
+
<!-- 单元格插槽:根据是否为操作列渲染不同内容 -->
|
|
39
36
|
<template slot-scope="scope">
|
|
40
|
-
<
|
|
37
|
+
<template v-if="col.isOperation">
|
|
38
|
+
<el-button type="text" size="mini" @click="onView(scope.row)">查看</el-button>
|
|
39
|
+
<el-button type="text" size="mini" @click="onEdit(scope.row)">编辑</el-button>
|
|
40
|
+
<el-button type="text" size="mini" @click="onDelete(scope.row)">删除</el-button>
|
|
41
|
+
</template>
|
|
42
|
+
<template v-else-if="col.isIndex">
|
|
43
|
+
<span>{{ scope.$index + 1 }}</span>
|
|
44
|
+
</template>
|
|
45
|
+
<template v-else>
|
|
46
|
+
<span>{{ scope.row[col.prop] }}</span>
|
|
47
|
+
</template>
|
|
41
48
|
</template>
|
|
42
49
|
</el-table-column>
|
|
43
50
|
</el-table>
|
|
@@ -51,7 +58,7 @@ export default {
|
|
|
51
58
|
name: "DraggableColumnsTableView",
|
|
52
59
|
data() {
|
|
53
60
|
return {
|
|
54
|
-
//
|
|
61
|
+
// 表格行数据:示例客户信息(实际项目中可从接口或 Vuex 获取)
|
|
55
62
|
rows: [
|
|
56
63
|
{
|
|
57
64
|
id: 1,
|
|
@@ -86,29 +93,32 @@ export default {
|
|
|
86
93
|
],
|
|
87
94
|
// 列配置:用于驱动 el-table-column 渲染,同时作为拖拽排序的数据源
|
|
88
95
|
columns: [
|
|
89
|
-
{
|
|
90
|
-
{ prop: "
|
|
91
|
-
{ prop: "
|
|
92
|
-
{ prop: "
|
|
93
|
-
{ prop: "
|
|
94
|
-
{ prop: "
|
|
95
|
-
{ prop: "
|
|
96
|
+
{ key: "index", label: "#", width: 60, align: "center", isIndex: true },
|
|
97
|
+
{ key: "name", prop: "name", label: "姓名", width: 160, align: "center" },
|
|
98
|
+
{ key: "customerTag", prop: "customerTag", label: "客户标签", width: 120, align: "center" },
|
|
99
|
+
{ key: "manager", prop: "manager", label: "客户人", width: 160, align: "center" },
|
|
100
|
+
{ key: "contribution", prop: "contribution", label: "贡献积分", width: 120, align: "right", headerAlign: "center" },
|
|
101
|
+
{ key: "pass1", prop: "pass1", label: "通关1", width: 100, align: "center" },
|
|
102
|
+
{ key: "pass2", prop: "pass2", label: "通关2", width: 100, align: "center" },
|
|
103
|
+
{ key: "pass3", prop: "pass3", label: "通关3", width: 100, align: "center" },
|
|
104
|
+
{ key: "operation", prop: "__operation__", label: "操作", width: 180, align: "center", headerAlign: "center", isOperation: true },
|
|
96
105
|
],
|
|
97
|
-
// sortablejs
|
|
106
|
+
// sortablejs 实例引用,用于在组件销毁或重建时手动销毁,避免内存泄露
|
|
98
107
|
headerSortable: null,
|
|
99
|
-
// 用于强制重建 el-table
|
|
108
|
+
// 用于强制重建 el-table(修改 key),确保列顺序变更后 ElementUI 内部状态与 DOM 同步
|
|
100
109
|
tableKey: 0,
|
|
110
|
+
// 标识组件是否已经进入销毁流程,避免销毁后仍然去访问 DOM 或创建 sortable 实例
|
|
101
111
|
isDestroyed: false,
|
|
102
112
|
};
|
|
103
113
|
},
|
|
104
114
|
mounted() {
|
|
105
|
-
//
|
|
115
|
+
// 组件挂载后,在下一个渲染周期中初始化表头拖拽能力
|
|
106
116
|
this.$nextTick(() => {
|
|
107
117
|
this.initColumnDrag();
|
|
108
118
|
});
|
|
109
119
|
},
|
|
110
120
|
beforeDestroy() {
|
|
111
|
-
//
|
|
121
|
+
// 组件销毁前:设置销毁标记并清理 sortable 实例,避免内存泄露
|
|
112
122
|
this.isDestroyed = true;
|
|
113
123
|
if (this.headerSortable && this.headerSortable.destroy) {
|
|
114
124
|
this.headerSortable.destroy();
|
|
@@ -116,37 +126,38 @@ export default {
|
|
|
116
126
|
}
|
|
117
127
|
},
|
|
118
128
|
methods: {
|
|
119
|
-
//
|
|
129
|
+
// 初始化列拖拽:在 ElementUI 表格头部行(thead > tr)上绑定 sortable 实例
|
|
120
130
|
initColumnDrag() {
|
|
131
|
+
// 若组件已处于销毁阶段,直接返回,避免无意义的 DOM 访问
|
|
121
132
|
if (this.isDestroyed) return;
|
|
122
|
-
//
|
|
133
|
+
// 若已存在 sortable 实例,先销毁,避免重复绑定导致的事件堆积与内存泄露
|
|
123
134
|
if (this.headerSortable && this.headerSortable.destroy) {
|
|
124
135
|
this.headerSortable.destroy();
|
|
125
136
|
this.headerSortable = null;
|
|
126
137
|
}
|
|
127
138
|
|
|
139
|
+
// 通过 ref 获取 ElementUI 表格实例,再访问内部根元素
|
|
128
140
|
const table = this.$refs.draggableTable;
|
|
129
141
|
if (!table || !table.$el) return;
|
|
130
142
|
|
|
131
|
-
// ElementUI 表头 DOM:thead 里的第一行 tr
|
|
143
|
+
// ElementUI 表头 DOM:thead 里的第一行 tr,作为 sortable 容器
|
|
132
144
|
const headerRow = table.$el.querySelector(".el-table__header-wrapper thead tr");
|
|
133
145
|
if (!headerRow) return;
|
|
134
146
|
|
|
135
147
|
this.headerSortable = Sortable.create(headerRow, {
|
|
136
148
|
// 拖拽动画时长(毫秒)
|
|
137
149
|
animation: 150,
|
|
138
|
-
// 只允许拖拽 header-draggable
|
|
150
|
+
// 只允许拖拽 header-draggable 区域作为手柄,避免误拖整个表头
|
|
139
151
|
handle: ".header-draggable",
|
|
140
|
-
//
|
|
152
|
+
// 可被拖动的元素:表头单元格 th(索引列因没有 handle 实际不可拖拽)
|
|
141
153
|
draggable: "th",
|
|
142
154
|
// 拖拽结束时回调:根据新旧索引更新 columns 顺序
|
|
143
155
|
onEnd: (evt) => {
|
|
144
156
|
const { oldIndex, newIndex } = evt;
|
|
145
157
|
if (oldIndex == null || newIndex == null) return;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
const to = newIndex - 1;
|
|
158
|
+
if (oldIndex === newIndex) return;
|
|
159
|
+
const from = oldIndex;
|
|
160
|
+
const to = newIndex;
|
|
150
161
|
if (from < 0 || to < 0 || from >= this.columns.length || to >= this.columns.length) return;
|
|
151
162
|
|
|
152
163
|
// 交换 columns 中两列的位置,实现“换列”
|
|
@@ -167,30 +178,3 @@ export default {
|
|
|
167
178
|
};
|
|
168
179
|
</script>
|
|
169
180
|
|
|
170
|
-
<style scoped>
|
|
171
|
-
.draggable-columns-table-page {
|
|
172
|
-
padding: 24px;
|
|
173
|
-
}
|
|
174
|
-
h1 {
|
|
175
|
-
margin: 0 0 12px;
|
|
176
|
-
font-size: 20px;
|
|
177
|
-
}
|
|
178
|
-
.desc {
|
|
179
|
-
margin: 0 0 16px;
|
|
180
|
-
color: #666;
|
|
181
|
-
}
|
|
182
|
-
.header-draggable {
|
|
183
|
-
display: inline-flex;
|
|
184
|
-
align-items: center;
|
|
185
|
-
cursor: move;
|
|
186
|
-
user-select: none;
|
|
187
|
-
}
|
|
188
|
-
.drag-icon {
|
|
189
|
-
margin-right: 4px;
|
|
190
|
-
font-size: 14px;
|
|
191
|
-
color: #999;
|
|
192
|
-
}
|
|
193
|
-
.header-label {
|
|
194
|
-
white-space: nowrap;
|
|
195
|
-
}
|
|
196
|
-
</style>
|
package/view/1.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// vue.config.js
|
|
2
|
-
const { merge } = require('webpack-merge');
|
|
3
|
-
const baseConfig = require('./build/webpack.base.config');
|
|
4
|
-
const baseProxy = require('./build/base.proxy');
|
|
5
|
-
const persionProxy = require('./build/persio n.proxy');
|
|
6
|
-
|
|
7
|
-
module.exports = merge(baseConfig, {
|
|
8
|
-
devServer: {
|
|
9
|
-
historyApiFallback: true,
|
|
10
|
-
port: 8081,
|
|
11
|
-
proxy: {
|
|
12
|
-
...baseProxy,
|
|
13
|
-
...persionProxy,
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
// 新增:sourcemap 配置
|
|
17
|
-
configureWebpack: {
|
|
18
|
-
// 根据环境自动切换 sourcemap
|
|
19
|
-
devtool: process.env.NODE_ENV === 'development'
|
|
20
|
-
? 'cheap-module-source-map' // 开发环境
|
|
21
|
-
: false // 生产环境
|
|
22
|
-
}
|
|
23
|
-
});
|
package/view/1.vue
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="page">
|
|
3
|
-
<h3>悬停停自动,手动仍可滚(无缝)</h3>
|
|
4
|
-
|
|
5
|
-
<vue-seamless-scroll
|
|
6
|
-
ref="ss"
|
|
7
|
-
class="warp"
|
|
8
|
-
:data="list"
|
|
9
|
-
:class-option="option"
|
|
10
|
-
@mouseenter.native="hovering = true"
|
|
11
|
-
@mouseleave.native="hovering = false"
|
|
12
|
-
@mousewheel.native.prevent="onWheel"
|
|
13
|
-
@touchstart.native.passive="onTouchStart"
|
|
14
|
-
@touchmove.native.prevent="onTouchMove"
|
|
15
|
-
>
|
|
16
|
-
<div class="list">
|
|
17
|
-
<div class="item" v-for="(item, index) in list" :key="index">
|
|
18
|
-
{{ item }}
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
</vue-seamless-scroll>
|
|
22
|
-
</div>
|
|
23
|
-
</template>
|
|
24
|
-
|
|
25
|
-
<script>
|
|
26
|
-
import VueSeamlessScroll from "vue-seamless-scroll";
|
|
27
|
-
|
|
28
|
-
export default {
|
|
29
|
-
name: "SeamlessHoverManualView",
|
|
30
|
-
components: {
|
|
31
|
-
VueSeamlessScroll,
|
|
32
|
-
},
|
|
33
|
-
data() {
|
|
34
|
-
return {
|
|
35
|
-
list: [],
|
|
36
|
-
lastTouchY: 0,
|
|
37
|
-
hovering: false,
|
|
38
|
-
autoStep: 0.3,
|
|
39
|
-
};
|
|
40
|
-
},
|
|
41
|
-
computed: {
|
|
42
|
-
option() {
|
|
43
|
-
return {
|
|
44
|
-
step: this.hovering ? 0 : this.autoStep,
|
|
45
|
-
direction: 1,
|
|
46
|
-
hoverStop: false,
|
|
47
|
-
limitMoveNum: 1,
|
|
48
|
-
openWatch: true,
|
|
49
|
-
};
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
mounted() {
|
|
53
|
-
this.fetchData();
|
|
54
|
-
},
|
|
55
|
-
methods: {
|
|
56
|
-
async fetchData() {
|
|
57
|
-
// 模拟接口请求
|
|
58
|
-
console.log('开始获取数据...');
|
|
59
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
60
|
-
const data = Array.from({ length: 5000 }, (_, i) => `列表项 ${i + 1}`);
|
|
61
|
-
// 使用 Object.freeze 冻结数据,避免 Vue 深度监听,显著提升大数据量下的渲染性能
|
|
62
|
-
this.list = Object.freeze(data);
|
|
63
|
-
console.log('数据获取完成,共', this.list.length, '条');
|
|
64
|
-
this.$nextTick(() => {
|
|
65
|
-
if (this.$refs.ss && this.$refs.ss.reset) this.$refs.ss.reset();
|
|
66
|
-
});
|
|
67
|
-
},
|
|
68
|
-
onWheel(e) {
|
|
69
|
-
const ss = this.$refs.ss;
|
|
70
|
-
if (!ss) return;
|
|
71
|
-
|
|
72
|
-
ss.yPos -= e.deltaY;
|
|
73
|
-
|
|
74
|
-
if (ss.yPos > 0) ss.yPos = 0;
|
|
75
|
-
|
|
76
|
-
if (ss.realBoxHeight && Math.abs(ss.yPos) > ss.realBoxHeight / 2) {
|
|
77
|
-
ss.yPos = 0;
|
|
78
|
-
}
|
|
79
|
-
},
|
|
80
|
-
onTouchStart(e) {
|
|
81
|
-
this.lastTouchY = e.touches[0].clientY;
|
|
82
|
-
},
|
|
83
|
-
onTouchMove(e) {
|
|
84
|
-
const y = e.touches[0].clientY;
|
|
85
|
-
const delta = this.lastTouchY - y;
|
|
86
|
-
this.lastTouchY = y;
|
|
87
|
-
this.onWheel({ deltaY: delta });
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
</script>
|
|
92
|
-
|
|
93
|
-
<style scoped>
|
|
94
|
-
.page {
|
|
95
|
-
padding: 20px;
|
|
96
|
-
font-family: Arial, Helvetica, sans-serif;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.warp {
|
|
100
|
-
height: 260px;
|
|
101
|
-
overflow: hidden;
|
|
102
|
-
border: 1px solid #ccc;
|
|
103
|
-
border-radius: 4px;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.list {
|
|
107
|
-
padding: 0 12px;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.item {
|
|
111
|
-
height: 40px;
|
|
112
|
-
line-height: 40px;
|
|
113
|
-
border-bottom: 1px dashed #ddd;
|
|
114
|
-
box-sizing: border-box;
|
|
115
|
-
}
|
|
116
|
-
</style>
|
|
117
|
-
|
package/view/111.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
function deepEqual(a, b, seen = new WeakMap()) {
|
|
2
|
-
if (Object.is(a, b)) return true
|
|
3
|
-
|
|
4
|
-
if (
|
|
5
|
-
typeof a !== 'object' ||
|
|
6
|
-
typeof b !== 'object' ||
|
|
7
|
-
a === null ||
|
|
8
|
-
b === null
|
|
9
|
-
) return false
|
|
10
|
-
|
|
11
|
-
if (seen.get(a) === b) return true
|
|
12
|
-
seen.set(a, b)
|
|
13
|
-
|
|
14
|
-
if (a.constructor !== b.constructor) return false
|
|
15
|
-
|
|
16
|
-
if (a instanceof Date) {
|
|
17
|
-
return a.getTime() === b.getTime()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (a instanceof RegExp) {
|
|
21
|
-
return a.source === b.source && a.flags === b.flags
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const keysA = Reflect.ownKeys(a)
|
|
25
|
-
const keysB = Reflect.ownKeys(b)
|
|
26
|
-
|
|
27
|
-
if (keysA.length !== keysB.length) return false
|
|
28
|
-
|
|
29
|
-
for (const key of keysA) {
|
|
30
|
-
if (!keysB.includes(key)) return false
|
|
31
|
-
if (!deepEqual(a[key], b[key], seen)) return false
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return true
|
|
35
|
-
}
|
package/view/2.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
function traverseChildren(arr) {
|
|
2
|
-
if (!Array.isArray(arr)) return;
|
|
3
|
-
|
|
4
|
-
for (let i = 0; i < arr.length; i++) {
|
|
5
|
-
const item = arr[i];
|
|
6
|
-
|
|
7
|
-
// 处理当前节点
|
|
8
|
-
console.log('当前节点:', item.name || item.id);
|
|
9
|
-
|
|
10
|
-
// 如果有children,递归遍历
|
|
11
|
-
if (item.children && Array.isArray(item.children) && item.children.length > 0) {
|
|
12
|
-
console.log(`进入 ${item.name} 的子节点:`);
|
|
13
|
-
traverseChildren(item.children);
|
|
14
|
-
console.log(`离开 ${item.name} 的子节点`);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function getAllNodes(arr) {
|
|
19
|
-
let result = [];
|
|
20
|
-
|
|
21
|
-
function traverse(nodes) {
|
|
22
|
-
if (!Array.isArray(nodes)) return;
|
|
23
|
-
|
|
24
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
25
|
-
const node = nodes[i];
|
|
26
|
-
|
|
27
|
-
// 将当前节点添加到结果数组
|
|
28
|
-
result.push(node);
|
|
29
|
-
|
|
30
|
-
// 递归处理子节点
|
|
31
|
-
if (node.children && Array.isArray(node.children)) {
|
|
32
|
-
traverse(node.children);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
traverse(arr);
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function flattenIterative(arr, childrenKey = 'children') {
|
|
42
|
-
const result = [];
|
|
43
|
-
const stack = [...arr]; // 使用栈来模拟递归
|
|
44
|
-
|
|
45
|
-
while (stack.length > 0) {
|
|
46
|
-
const node = stack.pop();
|
|
47
|
-
|
|
48
|
-
if (!node) continue;
|
|
49
|
-
|
|
50
|
-
// 添加当前节点
|
|
51
|
-
result.push(node);
|
|
52
|
-
|
|
53
|
-
// 将子节点逆序压入栈中(保持原顺序)
|
|
54
|
-
const children = node[childrenKey];
|
|
55
|
-
if (Array.isArray(children) && children.length > 0) {
|
|
56
|
-
// 从后往前压栈,这样前面出来的顺序是正确的
|
|
57
|
-
for (let i = children.length - 1; i >= 0; i--) {
|
|
58
|
-
stack.push(children[i]);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return result;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
function getAllOrgIds(arr) {
|
|
70
|
-
let result = [];
|
|
71
|
-
|
|
72
|
-
function traverse(nodes) {
|
|
73
|
-
if (!Array.isArray(nodes)) return;
|
|
74
|
-
|
|
75
|
-
for (let node of nodes) {
|
|
76
|
-
// 如果当前节点有 orgid,添加到结果中
|
|
77
|
-
if (node.orgid !== undefined && node.orgid !== null) {
|
|
78
|
-
result.push(node.orgid);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// 如果当前节点有 children,递归遍历
|
|
82
|
-
if (node.children && Array.isArray(node.children) && node.children.length > 0) {
|
|
83
|
-
traverse(node.children);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
traverse(arr);
|
|
89
|
-
return result;
|
|
90
|
-
}
|
package/view/2.vue
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<el-dialog
|
|
3
|
-
:visible.sync="visibleInner"
|
|
4
|
-
title="列表"
|
|
5
|
-
width="800px"
|
|
6
|
-
:close-on-click-modal="false"
|
|
7
|
-
@open="onOpen"
|
|
8
|
-
@closed="onClosed"
|
|
9
|
-
>
|
|
10
|
-
<!-- 表格只渲染当前页 rows(10条) -->
|
|
11
|
-
<el-table
|
|
12
|
-
:data="rows"
|
|
13
|
-
height="400"
|
|
14
|
-
border
|
|
15
|
-
row-key="id"
|
|
16
|
-
>
|
|
17
|
-
<el-table-column prop="id" label="ID" width="120" />
|
|
18
|
-
<el-table-column prop="name" label="名称" />
|
|
19
|
-
<el-table-column prop="status" label="状态" width="120" />
|
|
20
|
-
</el-table>
|
|
21
|
-
|
|
22
|
-
<div style="margin-top: 12px; text-align: right;">
|
|
23
|
-
<el-pagination
|
|
24
|
-
background
|
|
25
|
-
layout="total, prev, pager, next, sizes"
|
|
26
|
-
:total="total"
|
|
27
|
-
:current-page.sync="page"
|
|
28
|
-
:page-size.sync="pageSize"
|
|
29
|
-
:page-sizes="[10, 20, 50, 100]"
|
|
30
|
-
@current-change="refreshPage"
|
|
31
|
-
@size-change="onSizeChange"
|
|
32
|
-
/>
|
|
33
|
-
</div>
|
|
34
|
-
|
|
35
|
-
<span slot="footer" class="dialog-footer">
|
|
36
|
-
<el-button @click="close">关闭</el-button>
|
|
37
|
-
</span>
|
|
38
|
-
</el-dialog>
|
|
39
|
-
</template>
|
|
40
|
-
|
|
41
|
-
<script>
|
|
42
|
-
export default {
|
|
43
|
-
name: "ChildDialog",
|
|
44
|
-
props: {
|
|
45
|
-
// 只控制显隐,不要用 props 传 5000 条
|
|
46
|
-
visible: { type: Boolean, default: false }
|
|
47
|
-
},
|
|
48
|
-
data() {
|
|
49
|
-
return {
|
|
50
|
-
// 内部 visible(避免直接改 props)
|
|
51
|
-
visibleInner: false,
|
|
52
|
-
|
|
53
|
-
// 只存 UI 需要的(轻量)
|
|
54
|
-
page: 1,
|
|
55
|
-
pageSize: 10,
|
|
56
|
-
total: 0,
|
|
57
|
-
rows: []
|
|
58
|
-
};
|
|
59
|
-
},
|
|
60
|
-
|
|
61
|
-
watch: {
|
|
62
|
-
// 父组件控制打开/关闭
|
|
63
|
-
visible: {
|
|
64
|
-
immediate: true,
|
|
65
|
-
handler(v) {
|
|
66
|
-
this.visibleInner = v;
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
// 同步回父组件(:visible.sync)
|
|
70
|
-
visibleInner(v) {
|
|
71
|
-
this.$emit("update:visible", v);
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
created() {
|
|
76
|
-
// 非响应式大数据容器(不要放 data 里)
|
|
77
|
-
this._rawList = [];
|
|
78
|
-
this._hasData = false;
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
methods: {
|
|
82
|
-
/** 父组件 open 后调用:this.$refs.dlg.setData(bigList) */
|
|
83
|
-
setData(list) {
|
|
84
|
-
// 关键:不放 data,不做深拷贝,不 deep watch
|
|
85
|
-
this._rawList = Array.isArray(list) ? list : [];
|
|
86
|
-
this._hasData = true;
|
|
87
|
-
|
|
88
|
-
// 初始化分页
|
|
89
|
-
this.page = 1;
|
|
90
|
-
this.total = this._rawList.length;
|
|
91
|
-
|
|
92
|
-
// 如果 dialog 已经打开,立刻刷新;否则等 onOpen 再刷
|
|
93
|
-
if (this.visibleInner) this.refreshPage();
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
onOpen() {
|
|
97
|
-
// dialog 打开后,如果数据已设置,刷新一次(渲染10条)
|
|
98
|
-
if (this._hasData) this.refreshPage();
|
|
99
|
-
},
|
|
100
|
-
|
|
101
|
-
onClosed() {
|
|
102
|
-
// 关闭时只清理轻量状态,避免销毁/重建造成卡顿
|
|
103
|
-
this.rows = [];
|
|
104
|
-
this.page = 1;
|
|
105
|
-
// 如果你希望下次打开仍复用数据,就别清 _rawList
|
|
106
|
-
// this._rawList = [];
|
|
107
|
-
// this._hasData = false;
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
refreshPage() {
|
|
111
|
-
const start = (this.page - 1) * this.pageSize;
|
|
112
|
-
const end = start + this.pageSize;
|
|
113
|
-
|
|
114
|
-
// 只 slice 当前页,rows 才是响应式的
|
|
115
|
-
this.rows = this._rawList.slice(start, end);
|
|
116
|
-
this.total = this._rawList.length;
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
onSizeChange() {
|
|
120
|
-
this.page = 1;
|
|
121
|
-
this.refreshPage();
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
close() {
|
|
125
|
-
this.visibleInner = false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
</script>
|