appsnbcbweicheng 1.2.25 → 1.2.26

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appsnbcbweicheng",
3
- "version": "1.2.25",
3
+ "version": "1.2.26",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -0,0 +1,83 @@
1
+ <template>
2
+ <div class="expand-text">
3
+ <div ref="text" :class="['text-content', { clamp: !expanded }]">
4
+ {{ text }}
5
+ </div>
6
+
7
+ <span v-if="showToggle" class="toggle-btn" @click="toggle">
8
+ {{ expanded ? "收起" : "展开" }}
9
+ </span>
10
+ </div>
11
+ </template>
12
+
13
+ <script>
14
+ export default {
15
+ name: "ExpandText",
16
+
17
+ props: {
18
+ text: {
19
+ type: String,
20
+ default: ""
21
+ }
22
+ },
23
+
24
+ data() {
25
+ return {
26
+ expanded: false,
27
+ showToggle: false
28
+ }
29
+ },
30
+
31
+ mounted() {
32
+ this.checkOverflow()
33
+ },
34
+
35
+ watch: {
36
+ text() {
37
+ this.$nextTick(() => {
38
+ this.checkOverflow()
39
+ })
40
+ }
41
+ },
42
+
43
+ methods: {
44
+ checkOverflow() {
45
+ const el = this.$refs.text
46
+
47
+ if (!el) return
48
+
49
+ this.showToggle = el.scrollHeight > el.clientHeight
50
+ },
51
+
52
+ toggle() {
53
+ this.expanded = !this.expanded
54
+ }
55
+ }
56
+ }
57
+ </script>
58
+
59
+ <style scoped>
60
+ .expand-text {
61
+ position: relative;
62
+ }
63
+
64
+ .text-content {
65
+ word-break: break-word;
66
+ line-height: 20px;
67
+ }
68
+
69
+ /* 三行限制 */
70
+ .clamp {
71
+ display: -webkit-box;
72
+ -webkit-line-clamp: 3;
73
+ -webkit-box-orient: vertical;
74
+ overflow: hidden;
75
+ }
76
+
77
+ .toggle-btn {
78
+ color: #409eff;
79
+ cursor: pointer;
80
+ font-size: 12px;
81
+ margin-left: 6px;
82
+ }
83
+ </style>
package/readme.md CHANGED
@@ -1,3 +1,4 @@
1
+ 1.2.26 投研平台
1
2
  1.2.25 投研平台
2
3
  1.2.24 投研平台
3
4
  1.2.23 投研平台
@@ -1,578 +0,0 @@
1
- <template>
2
- <el-dialog
3
- title="资产板块列表"
4
- :visible.sync="dialogVisible"
5
- width="900px"
6
- :close-on-click-modal="false"
7
- append-to-body
8
- custom-class="asset-config-dialog"
9
- >
10
- <div class="asset-config-container">
11
- <!-- Left Panel: Asset Classes -->
12
- <div class="left-panel">
13
- <div class="panel-header">
14
- <el-button type="primary" size="small" icon="el-icon-plus" @click="addAssetClass">
15
- 新增资产类别
16
- </el-button>
17
- </div>
18
- <div class="asset-list" @dragover.prevent>
19
- <div
20
- v-for="(item, index) in localAssetClasses"
21
- :key="item.tempId || item.id"
22
- class="asset-item"
23
- :class="{ active: selectedAssetId === (item.tempId || item.id) }"
24
- draggable="true"
25
- @dragstart="onDragStart($event, index)"
26
- @dragover="onDragOver($event, index)"
27
- @drop="onDrop($event, index)"
28
- @click="selectAssetClass(item)"
29
- >
30
- <div class="asset-content">
31
- <template v-if="item.isEditing">
32
- <el-input
33
- v-model="item.editName"
34
- size="mini"
35
- ref="assetInput"
36
- @blur="finishEditAsset(item, index)"
37
- @keyup.enter.native="$event.target.blur()"
38
- />
39
- </template>
40
- <template v-else>
41
- <span class="asset-name">{{ item.name }}</span>
42
- </template>
43
- </div>
44
-
45
- <!-- Sort button always visible -->
46
- <div class="asset-actions-always">
47
- <i class="el-icon-sort action-icon drag-handle" title="排序"></i>
48
- </div>
49
-
50
- <!-- Actions shown when selected -->
51
- <div
52
- class="asset-actions"
53
- v-if="selectedAssetId === (item.tempId || item.id) && !item.isEditing"
54
- >
55
- <i
56
- class="el-icon-edit action-icon"
57
- title="编辑"
58
- @click.stop="startEditAsset(item)"
59
- ></i>
60
- <i
61
- class="el-icon-delete action-icon"
62
- title="删除"
63
- @click.stop="deleteAssetClass(index)"
64
- ></i>
65
- </div>
66
- </div>
67
- </div>
68
- </div>
69
-
70
- <!-- Right Panel: Sectors -->
71
- <div class="right-panel">
72
- <div class="panel-header right-header">
73
- <span class="sector-count">包含板块 ({{ currentSectors.length }})</span>
74
- <el-button
75
- type="primary"
76
- size="small"
77
- icon="el-icon-plus"
78
- :disabled="!selectedAssetId"
79
- @click="addSector"
80
- >
81
- 新增板块
82
- </el-button>
83
- </div>
84
- <div class="sector-grid">
85
- <div
86
- v-for="(sector, index) in currentSectors"
87
- :key="sector.tempId || sector.id"
88
- class="sector-item"
89
- >
90
- <div class="sector-content">
91
- <template v-if="sector.isEditing">
92
- <el-input
93
- v-model="sector.editName"
94
- size="mini"
95
- ref="sectorInput"
96
- @blur="finishEditSector(sector, index)"
97
- @keyup.enter.native="$event.target.blur()"
98
- />
99
- </template>
100
- <template v-else>
101
- <span class="sector-name">{{ sector.name }}</span>
102
- </template>
103
- </div>
104
- <div class="sector-actions" v-if="!sector.isEditing">
105
- <i
106
- class="el-icon-edit action-icon"
107
- title="编辑"
108
- @click.stop="startEditSector(sector)"
109
- ></i>
110
- <i
111
- class="el-icon-delete action-icon"
112
- title="删除"
113
- @click.stop="deleteSector(index)"
114
- ></i>
115
- </div>
116
- </div>
117
- </div>
118
- <div v-if="!selectedAssetId" class="empty-tip">请先选择一个资产类别</div>
119
- </div>
120
- </div>
121
-
122
- <span slot="footer" class="dialog-footer">
123
- <el-button size="small" @click="handleCancel">取 消</el-button>
124
- <el-button type="primary" size="small" @click="handleConfirm">确 认</el-button>
125
- </span>
126
- </el-dialog>
127
- </template>
128
-
129
- <script>
130
- export default {
131
- name: 'AssetClassConfiguration',
132
- props: {
133
- visible: {
134
- type: Boolean,
135
- default: false,
136
- },
137
- initialData: {
138
- type: Array,
139
- default: () => [],
140
- },
141
- },
142
- data() {
143
- return {
144
- localAssetClasses: [],
145
- selectedAssetId: null,
146
- draggedIndex: null,
147
- }
148
- },
149
- computed: {
150
- dialogVisible: {
151
- get() {
152
- return this.visible
153
- },
154
- set(val) {
155
- this.$emit('update:visible', val)
156
- },
157
- },
158
- currentAsset() {
159
- return this.localAssetClasses.find(item => (item.tempId || item.id) === this.selectedAssetId)
160
- },
161
- currentSectors() {
162
- return this.currentAsset ? this.currentAsset.sectors : []
163
- },
164
- },
165
- watch: {
166
- visible(val) {
167
- if (val) {
168
- // Transform flat list to hierarchical structure
169
- // Flat structure: { assetName, assetType, assetStatus, sortOrder }
170
- // We assume input list contains only relevant items (or we filter by assetStatus=0)
171
-
172
- const groups = {}
173
- const sortedInput = [...this.initialData].sort((a, b) => a.sortOrder - b.sortOrder)
174
-
175
- sortedInput.forEach(item => {
176
- if (item.assetStatus === 1) return // Skip invalid items
177
-
178
- const catName = item.assetName
179
- if (!groups[catName]) {
180
- groups[catName] = {
181
- name: catName,
182
- sectors: [],
183
- minSortOrder: item.sortOrder,
184
- }
185
- }
186
-
187
- if (item.assetType && item.assetType.trim() !== '') {
188
- groups[catName].sectors.push({
189
- name: item.assetType,
190
- sortOrder: item.sortOrder,
191
- })
192
- }
193
- })
194
-
195
- // Convert to array and sort by minSortOrder (preserve category order)
196
- this.localAssetClasses = Object.values(groups)
197
- //.sort((a, b) => a.minSortOrder - b.minSortOrder) // Already sorted by input order roughly, but let's be safe
198
- // Actually, since we iterate sortedInput, the order of creation in groups object implies order.
199
- // But Object.values order is not guaranteed in all JS engines (though mostly yes).
200
- // Let's rely on array mapping if possible, or just sort.
201
- .sort((a, b) => a.minSortOrder - b.minSortOrder)
202
- .map((g, index) => ({
203
- id: null, // No persistent ID for category in flat mode, rely on name
204
- tempId: 'cat_' + index + '_' + Date.now(),
205
- name: g.name,
206
- editName: g.name,
207
- isEditing: false,
208
- sectors: g.sectors.map((s, sIndex) => ({
209
- id: null,
210
- tempId: 'sec_' + index + '_' + sIndex + '_' + Date.now(),
211
- name: s.name,
212
- editName: s.name,
213
- isEditing: false,
214
- })),
215
- }))
216
-
217
- // Select first one by default if exists
218
- if (this.localAssetClasses.length > 0) {
219
- this.selectedAssetId = this.localAssetClasses[0].tempId
220
- } else {
221
- this.selectedAssetId = null
222
- }
223
- }
224
- },
225
- },
226
- methods: {
227
- // Asset Class Methods
228
- addAssetClass() {
229
- const newId = 'new_' + Date.now()
230
- const newAsset = {
231
- tempId: newId,
232
- id: null, // New item
233
- name: '',
234
- editName: '',
235
- isEditing: true,
236
- sectors: [],
237
- }
238
- this.localAssetClasses.push(newAsset)
239
- this.selectedAssetId = newId
240
- this.$nextTick(() => {
241
- const inputs = this.$refs.assetInput
242
- if (inputs && inputs.length > 0) {
243
- const lastInput = inputs[inputs.length - 1]
244
- if (lastInput) lastInput.focus()
245
- }
246
- })
247
- },
248
- selectAssetClass(item) {
249
- this.selectedAssetId = item.tempId || item.id
250
- },
251
- startEditAsset(item) {
252
- item.editName = item.name
253
- item.isEditing = true
254
- this.$nextTick(() => {
255
- const el = this.$el.querySelector('.asset-item.active .el-input__inner')
256
- if (el) el.focus()
257
- })
258
- },
259
- finishEditAsset(item) {
260
- if (!item.editName.trim()) {
261
- item.name = item.editName
262
- item.isEditing = false
263
- } else {
264
- item.name = item.editName
265
- item.isEditing = false
266
- }
267
- },
268
- deleteAssetClass(index) {
269
- const item = this.localAssetClasses[index]
270
- const isSelected = (item.tempId || item.id) === this.selectedAssetId
271
-
272
- this.$confirm('确定删除该资产类别及其下所有板块吗?', '提示', {
273
- confirmButtonText: '确定',
274
- cancelButtonText: '取消',
275
- type: 'warning',
276
- })
277
- .then(() => {
278
- this.localAssetClasses.splice(index, 1)
279
- if (isSelected) {
280
- if (this.localAssetClasses.length > 0) {
281
- this.selectedAssetId =
282
- this.localAssetClasses[0].tempId || this.localAssetClasses[0].id
283
- } else {
284
- this.selectedAssetId = null
285
- }
286
- }
287
- })
288
- .catch(() => {})
289
- },
290
-
291
- // Drag and Drop for Asset Classes
292
- onDragStart(event, index) {
293
- this.draggedIndex = index
294
- event.dataTransfer.effectAllowed = 'move'
295
- },
296
- onDragOver(event) {
297
- event.preventDefault()
298
- },
299
- onDrop(event, index) {
300
- event.preventDefault()
301
- if (this.draggedIndex !== null && this.draggedIndex !== index) {
302
- const item = this.localAssetClasses.splice(this.draggedIndex, 1)[0]
303
- this.localAssetClasses.splice(index, 0, item)
304
- }
305
- this.draggedIndex = null
306
- },
307
-
308
- // Sector Methods
309
- addSector() {
310
- if (!this.currentAsset) return
311
- const newSector = {
312
- tempId: 'sec_' + Date.now(),
313
- id: null,
314
- name: '',
315
- editName: '',
316
- isEditing: true,
317
- }
318
- this.currentAsset.sectors.push(newSector)
319
- this.$nextTick(() => {
320
- const sectorInputs = this.$refs.sectorInput
321
- if (sectorInputs && sectorInputs.length) {
322
- sectorInputs[sectorInputs.length - 1].focus()
323
- }
324
- })
325
- },
326
- startEditSector(sector) {
327
- sector.editName = sector.name
328
- sector.isEditing = true
329
- this.$nextTick(() => {
330
- const sectorInputs = this.$refs.sectorInput
331
- if (sectorInputs && sectorInputs.length) {
332
- sectorInputs[sectorInputs.length - 1].focus()
333
- }
334
- })
335
- },
336
- finishEditSector(sector) {
337
- sector.name = sector.editName
338
- sector.isEditing = false
339
- },
340
- deleteSector(index) {
341
- if (!this.currentAsset) return
342
- this.$confirm('确定删除该板块吗?', '提示', {
343
- confirmButtonText: '确定',
344
- cancelButtonText: '取消',
345
- type: 'warning',
346
- })
347
- .then(() => {
348
- this.currentAsset.sectors.splice(index, 1)
349
- })
350
- .catch(() => {})
351
- },
352
-
353
- // Dialog Actions
354
- handleCancel() {
355
- this.dialogVisible = false
356
- },
357
- handleConfirm() {
358
- // Convert hierarchical structure back to flat list
359
- // Flat structure: { assetName, assetType, assetStatus, sortOrder }
360
-
361
- const flatList = []
362
- let globalSortOrder = 1
363
-
364
- this.localAssetClasses.forEach(asset => {
365
- const assetName = asset.name ? asset.name.trim() : ''
366
- if (!assetName) return // Skip empty asset names
367
-
368
- const validSectors = asset.sectors.filter(s => s.name && s.name.trim() !== '')
369
-
370
- if (validSectors.length === 0) {
371
- // Asset class with no sectors
372
- flatList.push({
373
- assetName: assetName,
374
- assetType: '',
375
- assetStatus: 0,
376
- sortOrder: globalSortOrder++,
377
- })
378
- } else {
379
- validSectors.forEach(sector => {
380
- flatList.push({
381
- assetName: assetName,
382
- assetType: sector.name,
383
- assetStatus: 0,
384
- sortOrder: globalSortOrder++,
385
- })
386
- })
387
- }
388
- })
389
-
390
- this.$emit('confirm', flatList)
391
- this.dialogVisible = false
392
- },
393
- },
394
- }
395
- </script>
396
-
397
- <style lang="scss" scoped>
398
- .asset-config-container {
399
- display: flex;
400
- height: 500px;
401
- border: 1px solid #dcdfe6;
402
- border-radius: 4px;
403
-
404
- .left-panel {
405
- width: 20%;
406
- border-right: 1px solid #dcdfe6;
407
- display: flex;
408
- flex-direction: column;
409
-
410
- .panel-header {
411
- padding: 10px;
412
- border-bottom: 1px solid #ebeef5;
413
- text-align: center;
414
- }
415
-
416
- .asset-list {
417
- flex: 1;
418
- overflow-y: auto;
419
- padding: 10px 0;
420
-
421
- .asset-item {
422
- padding: 8px 10px;
423
- cursor: pointer;
424
- display: flex;
425
- justify-content: space-between;
426
- align-items: center;
427
- transition: background-color 0.2s;
428
-
429
- &:hover {
430
- background-color: #f5f7fa;
431
- }
432
-
433
- &.active {
434
- background-color: #e6f1fc;
435
- color: #409eff;
436
- }
437
-
438
- .asset-content {
439
- flex: 1;
440
- overflow: hidden;
441
- text-overflow: ellipsis;
442
- white-space: nowrap;
443
- margin-right: 5px;
444
-
445
- .asset-name {
446
- font-size: 14px;
447
- }
448
- }
449
-
450
- .asset-actions-always {
451
- display: flex;
452
- align-items: center;
453
- margin-left: 5px;
454
-
455
- .action-icon {
456
- font-size: 14px;
457
- color: #909399;
458
- cursor: move;
459
- padding: 2px;
460
-
461
- &:hover {
462
- color: #409eff;
463
- }
464
- }
465
- }
466
-
467
- .asset-actions {
468
- display: flex;
469
- align-items: center;
470
- gap: 4px;
471
- margin-left: 5px;
472
-
473
- .action-icon {
474
- font-size: 14px;
475
- color: #909399;
476
- cursor: pointer;
477
- padding: 2px;
478
-
479
- &:hover {
480
- color: #409eff;
481
- }
482
-
483
- &.drag-handle {
484
- cursor: move;
485
- }
486
- }
487
- }
488
- }
489
- }
490
- }
491
-
492
- .right-panel {
493
- width: 80%;
494
- display: flex;
495
- flex-direction: column;
496
-
497
- .panel-header {
498
- padding: 10px 20px;
499
- border-bottom: 1px solid #ebeef5;
500
- display: flex;
501
- justify-content: space-between;
502
- align-items: center;
503
-
504
- .sector-count {
505
- font-size: 14px;
506
- color: #606266;
507
- font-weight: bold;
508
- }
509
- }
510
-
511
- .sector-grid {
512
- flex: 1;
513
- overflow-y: auto;
514
- padding: 20px;
515
- display: flex;
516
- flex-wrap: wrap;
517
- align-content: flex-start;
518
- gap: 15px;
519
-
520
- .sector-item {
521
- width: calc((100% - 30px) / 3); // 3 items per row, 15px gap * 2 = 30px
522
- height: 40px;
523
- border: 1px solid #dcdfe6;
524
- border-radius: 4px;
525
- display: flex;
526
- align-items: center;
527
- padding: 0 10px;
528
- box-sizing: border-box;
529
- justify-content: space-between;
530
- transition: all 0.2s;
531
-
532
- &:hover {
533
- border-color: #409eff;
534
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
535
- }
536
-
537
- .sector-content {
538
- flex: 1;
539
- margin-right: 5px;
540
- overflow: hidden;
541
-
542
- .sector-name {
543
- font-size: 14px;
544
- white-space: nowrap;
545
- overflow: hidden;
546
- text-overflow: ellipsis;
547
- display: block;
548
- }
549
- }
550
-
551
- .sector-actions {
552
- display: flex;
553
- gap: 5px;
554
-
555
- .action-icon {
556
- font-size: 14px;
557
- color: #909399;
558
- cursor: pointer;
559
-
560
- &:hover {
561
- color: #409eff;
562
- }
563
- }
564
- }
565
- }
566
- }
567
-
568
- .empty-tip {
569
- flex: 1;
570
- display: flex;
571
- justify-content: center;
572
- align-items: center;
573
- color: #909399;
574
- font-size: 14px;
575
- }
576
- }
577
- }
578
- </style>