appsnbcbweicheng 1.2.25 → 1.2.27

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.
@@ -1,731 +0,0 @@
1
- <template>
2
- <div class="event-interpretation">
3
- <!-- 筛选区域 -->
4
- <el-card class="filter-card" shadow="never">
5
- <el-form
6
- :inline="true"
7
- :model="searchForm"
8
- class="search-form"
9
- label-width="100px"
10
- size="small"
11
- >
12
- <!-- 研究对象:多选二级下拉 -->
13
- <el-form-item label="研究对象">
14
- <el-cascader
15
- v-model="searchForm.opinionTargets"
16
- :options="opinionTargetOptions"
17
- :props="{ multiple: true, checkStrictly: false, emitPath: true }"
18
- clearable
19
- collapse-tags
20
- placeholder="请选择资产类别 / 研究对象"
21
- style="width: 320px"
22
- />
23
- </el-form-item>
24
- <!-- 未来6个月观点:单选下拉 -->
25
- <el-form-item label="未来6个月观点">
26
- <el-select
27
- v-model="searchForm.sentiment"
28
- placeholder="请选择观点方向"
29
- clearable
30
- style="width: 160px"
31
- >
32
- <el-option
33
- v-for="item in emotionOptions"
34
- :key="item.value"
35
- :label="item.label"
36
- :value="item.value"
37
- />
38
- </el-select>
39
- </el-form-item>
40
- <!-- 所属机构:单选下拉 -->
41
- <el-form-item label="所属机构">
42
- <el-select
43
- v-model="searchForm.opinionInstitution"
44
- placeholder="请选择机构"
45
- clearable
46
- filterable
47
- style="width: 200px"
48
- >
49
- <el-option
50
- v-for="item in institutionOptions"
51
- :key="item.value"
52
- :label="item.label"
53
- :value="item.value"
54
- />
55
- </el-select>
56
- </el-form-item>
57
- <!-- 更新时间:日期区间 -->
58
- <el-form-item label="更新时间">
59
- <el-date-picker
60
- v-model="searchForm.dateRange"
61
- type="daterange"
62
- range-separator="至"
63
- start-placeholder="开始日期"
64
- end-placeholder="结束日期"
65
- value-format="yyyy-MM-dd"
66
- clearable
67
- style="width: 260px"
68
- />
69
- </el-form-item>
70
- <el-form-item>
71
- <el-button type="primary" @click="handleSearch">查询</el-button>
72
- <el-button @click="handleReset">重置</el-button>
73
- </el-form-item>
74
- </el-form>
75
- </el-card>
76
-
77
- <!-- 展示区域 -->
78
- <el-card class="display-card" shadow="never">
79
- <!-- 描述部分 -->
80
- <div class="description-section">
81
- <div class="description-left">
82
- <span class="fund-summary">{{ fundSummary }}</span>
83
- </div>
84
- <div class="description-right">
85
- <span class="text">示例数据用于展示机构观点解读效果。</span>
86
- <el-button type="primary" size="small" @click="openCreate">新增观点</el-button>
87
- <el-button type="primary" size="small" @click="openStatisticsDialog">数据统计</el-button>
88
- </div>
89
- </div>
90
-
91
- <!-- 表格 -->
92
- <el-table
93
- :data="tableData"
94
- border
95
- stripe
96
- class="result-table"
97
- size="small"
98
- :default-sort="{ prop: 'gmtModified', order: 'descending' }"
99
- @sort-change="handleSortChange"
100
- >
101
- <!-- 固定前三列 -->
102
- <el-table-column type="index" label="序号" width="60" fixed="left" />
103
- <el-table-column prop="month" label="观点月份" min-width="120" fixed="left" />
104
- <el-table-column prop="assetsType" label="资产类别" min-width="120" fixed="left" />
105
- <el-table-column prop="opinionTarget" label="研究对象" min-width="180" fixed="left" />
106
-
107
- <el-table-column prop="sentiment" label="未来6个月观点" width="130" />
108
- <el-table-column prop="interpretation" label="观点说明" min-width="260">
109
- <template slot-scope="{ row }">
110
- <div class="expandable-content">
111
- <div
112
- :class="{
113
- 'content-collapse': !row.expandOpinionDescription,
114
- 'content-expanded': row.expandOpinionDescription,
115
- }"
116
- >
117
- {{ row.interpretation }}
118
- </div>
119
- <el-button
120
- v-if="shouldShowExpand(row.interpretation)"
121
- type="text"
122
- size="mini"
123
- @click="toggleExpand(row, 'interpretation')"
124
- >
125
- {{ row.expandOpinionDescription ? '收起' : '展开' }}
126
- </el-button>
127
- </div>
128
- </template>
129
- </el-table-column>
130
- <!-- <el-table-column prop="argumentDetail" label="论据详情" min-width="260">
131
- <template slot-scope="{ row }">
132
- <div class="expandable-content">
133
- <div
134
- :class="{
135
- 'content-collapse': !row.expandArgumentDetail,
136
- 'content-expanded': row.expandArgumentDetail,
137
- }"
138
- >
139
- {{ row.argumentDetail }}
140
- </div>
141
- <el-button
142
- v-if="shouldShowExpand(row.argumentDetail)"
143
- type="text"
144
- size="mini"
145
- @click="toggleExpand(row, 'argumentDetail')"
146
- >
147
- {{ row.expandArgumentDetail ? '收起' : '展开' }}
148
- </el-button>
149
- </div>
150
- </template>
151
- </el-table-column>
152
- <el-table-column prop="opinion" label="机构" min-width="160" />
153
- <el-table-column prop="gmtCreate" label="创建时间" width="160" />
154
- <el-table-column prop="gmtModified" label="更新时间" width="160" sortable="custom" /> -->
155
- <el-table-column prop="explainTime" label="解读时间" min-width="140" />
156
- </el-table>
157
- <div class="pagination-container">
158
- <el-pagination
159
- background
160
- @size-change="handleSizeChange"
161
- @current-change="handleCurrentChange"
162
- :current-page="currentPage"
163
- :page-sizes="[10, 20, 50, 100]"
164
- :page-size="pageSize"
165
- layout="total, sizes, prev, pager, next, jumper"
166
- :total="total"
167
- >
168
- </el-pagination>
169
- </div>
170
- </el-card>
171
-
172
- <!-- 数据统计弹窗 -->
173
- <el-dialog
174
- title="数据统计"
175
- :visible.sync="statisticsDialogVisible"
176
- width="900px"
177
- :close-on-click-modal="false"
178
- >
179
- <!-- 上部分:概要信息 -->
180
- <div class="statistics-top">
181
- <div class="statistics-row">
182
- <div class="statistics-item-left">
183
- <span class="label">当前统计时间:</span>
184
- <span class="value">{{ searchForm.timeCycle || '-' }}</span>
185
- </div>
186
- <div class="statistics-item-right">
187
- <el-button type="primary" size="small" @click="handleExport"> 数据导出 </el-button>
188
- </div>
189
- </div>
190
- </div>
191
-
192
- <!-- 下部分:数据统计表 -->
193
- <div class="statistics-bottom">
194
- <el-table :data="statisticsTableData" border style="width: 100%; margin-bottom: 20px">
195
- <el-table-column type="index" label="序号" width="80" />
196
- <el-table-column prop="blockName" label="资产类别" min-width="120" />
197
- <el-table-column prop="plateName" label="资产名称" min-width="160" />
198
- <el-table-column prop="nums" label="解读数量" min-width="100" />
199
- <el-table-column prop="autoApprovedRate" label="审核完成率" min-width="120" />
200
- <el-table-column prop="auditApprovedRate" label="审核通过率" min-width="120" />
201
- </el-table>
202
- </div>
203
-
204
- <span slot="footer" class="dialog-footer">
205
- <el-button @click="statisticsDialogVisible = false">关 闭</el-button>
206
- </span>
207
- </el-dialog>
208
- <SectorAnalysisViewpointSummaryCreate
209
- v-if="createVisible"
210
- :existing-data="originalTableData"
211
- @close="createVisible = false"
212
- />
213
- </div>
214
- </template>
215
-
216
- <script>
217
- import SectorAnalysisViewpointSummaryCreate from './SectorAnalysisViewpointSummaryCreate.vue'
218
- export default {
219
- name: 'InstitutionViewpoint',
220
- components: {
221
- SectorAnalysisViewpointSummaryCreate,
222
- },
223
- data() {
224
- return {
225
- // 筛选表单
226
- searchForm: {
227
- opinionTargets: [],
228
- sentiment: '',
229
- opinionInstitution: '',
230
- dateRange: [],
231
- },
232
- // 分页配置
233
- currentPage: 1,
234
- pageSize: 10,
235
- total: 0,
236
- tableData: [], // 当前页数据
237
-
238
- // 研究对象二级选项(示例)
239
- opinionTargetOptions: [
240
- {
241
- value: '股票',
242
- label: '股票',
243
- children: [
244
- { value: '上证指数', label: '上证指数' },
245
- { value: '沪深300', label: '沪深300' },
246
- ],
247
- },
248
- {
249
- value: '债券',
250
- label: '债券',
251
- children: [
252
- { value: '国债指数', label: '国债指数' },
253
- { value: '信用债指数', label: '信用债指数' },
254
- ],
255
- },
256
- {
257
- value: '商品',
258
- label: '商品',
259
- children: [
260
- { value: '黄金指数', label: '黄金指数' },
261
- { value: '原油指数', label: '原油指数' },
262
- ],
263
- },
264
- ],
265
- // 情绪方向选项
266
- emotionOptions: [
267
- { label: '利空', value: '利空' },
268
- { label: '利好', value: '利好' },
269
- { label: '中性', value: '中性' },
270
- ],
271
- // 所属机构选项(示例)
272
- institutionOptions: [
273
- { label: '机构A', value: '机构A' },
274
- { label: '机构B', value: '机构B' },
275
- { label: '机构C', value: '机构C' },
276
- ],
277
- // 一句话描述
278
- fundSummary: '按筛选条件展示机构对各资产类别研究对象的未来6个月观点及论据。',
279
- // 原始表格数据(示例)
280
- originalTableData: [
281
- {
282
- id: 1,
283
- assetsType: '股票',
284
- opinionTarget: '沪深300',
285
- month: '沪深300指数',
286
- sentiment: '利好',
287
- interpretation:
288
- '机构A认为未来6个月沪深300基本面有望改善,盈利预期上修,海外流动性宽松叠加国内政策友好,整体风险偏好有望回升。该结论基于宏观、估值与资金面多维度分析,具备一定前瞻性假设与不确定性。',
289
- argumentDetail:
290
- '1)宏观层面,预计未来两个季度名义GDP增速回升,对盈利形成支撑;2)盈利端,当前盈利预期处于下修尾部,未来存在上修弹性;3)估值端,沪深300市盈率处于近五年历史分位数偏低位置,性价比较高;4)资金面,海外流动性拐点及国内政策持续发力,有望带来增量资金;5)风险提示:外部环境不确定性、企业盈利修复不及预期等。',
291
- opinion: '机构A',
292
- gmtCreate: '2024-01-10 09:00:00',
293
- gmtModified: '2024-01-20 10:30:00',
294
- explainTime: '内部研究',
295
- expandOpinionDescription: false,
296
- expandArgumentDetail: false,
297
- },
298
- {
299
- id: 2,
300
- assetsType: '债券',
301
- opinionTarget: '国债指数',
302
- month: '中证国债指数',
303
- sentiment: '中性',
304
- interpretation: '机构B认为未来6个月国债收益率窄幅震荡,配置价值仍存但弹性有限。',
305
- argumentDetail:
306
- '在经济增速温和与通胀中枢较低的背景下,货币政策保持中性略宽松,利率债收益率中枢或小幅下移但空间有限。长端收益率受期限溢价与供给压力制约,收益与风险比相对均衡。整体看,更适合作为组合底仓与流动性管理工具。',
307
- opinion: '机构B',
308
- gmtCreate: '2024-01-12 14:20:00',
309
- gmtModified: '2024-01-18 09:15:00',
310
- explainTime: '外部研报',
311
- expandOpinionDescription: false,
312
- expandArgumentDetail: false,
313
- },
314
- {
315
- id: 3,
316
- assetsType: '商品',
317
- opinionTarget: '黄金指数',
318
- month: 'COMEX黄金指数',
319
- sentiment: '利空',
320
- interpretation: '机构C认为未来6个月黄金在实际利率上行背景下承压,避险需求边际回落。',
321
- argumentDetail:
322
- '若美联储货币政策维持偏紧或降息节奏弱于预期,实际利率存在抬升压力,对无息资产黄金估值形成压制。同时,若全球金融市场波动收敛、避险情绪回落,黄金的配置需求将有所减弱。但中长期仍需关注地缘政治等尾部风险带来的阶段性对冲需求。',
323
- opinion: '机构C',
324
- gmtCreate: '2024-02-01 11:00:00',
325
- gmtModified: '2024-02-05 14:00:00',
326
- explainTime: '公募基金季报',
327
- expandOpinionDescription: false,
328
- expandArgumentDetail: false,
329
- },
330
- ],
331
- // 排序配置
332
- sortConfig: {
333
- prop: 'gmtModified',
334
- order: 'descending',
335
- },
336
- // 统计弹窗显示状态
337
- statisticsDialogVisible: false,
338
- // 统计表格数据
339
- statisticsTableData: [
340
- {
341
- blockName: '股票',
342
- plateName: '沪深300',
343
- nums: 15,
344
- autoApprovedRate: '90%',
345
- auditApprovedRate: '85%',
346
- },
347
- {
348
- blockName: '债券',
349
- plateName: '国债',
350
- nums: 10,
351
- autoApprovedRate: '80%',
352
- auditApprovedRate: '75%',
353
- },
354
- ],
355
- createVisible: false,
356
- }
357
- },
358
- mounted() {
359
- // 初始化原始数据
360
- this.originalTableData = JSON.parse(JSON.stringify(this.originalTableData))
361
- // 模拟更多数据以测试分页
362
- const baseData = [...this.originalTableData]
363
- for (let i = 0; i < 4; i++) {
364
- baseData.forEach(item => {
365
- this.originalTableData.push({
366
- ...item,
367
- id: this.originalTableData.length + 1,
368
- })
369
- })
370
- }
371
- this.fetchData()
372
- },
373
- methods: {
374
- openCreate() {
375
- this.createVisible = true
376
- },
377
- // 获取数据(模拟接口)
378
- fetchData() {
379
- let data = [...this.originalTableData]
380
-
381
- // 研究对象多选筛选(二维 path:[[assetsType, opinionTarget], ...])
382
- if (this.searchForm.opinionTargets && this.searchForm.opinionTargets.length > 0) {
383
- const selections = this.searchForm.opinionTargets
384
- data = data.filter(item => {
385
- return selections.some(path => {
386
- const [assetsType, opinionTarget] = path
387
- const matchAssetsType = !assetsType || item.assetsType === assetsType
388
- const matchOpinionTarget = !opinionTarget || item.opinionTarget === opinionTarget
389
- return matchAssetsType && matchOpinionTarget
390
- })
391
- })
392
- }
393
-
394
- // 未来6个月观点筛选
395
- if (this.searchForm.sentiment) {
396
- data = data.filter(item => item.sentiment === this.searchForm.sentiment)
397
- }
398
-
399
- // 所属机构筛选
400
- if (this.searchForm.opinionInstitution) {
401
- data = data.filter(item => item.opinion === this.searchForm.opinionInstitution)
402
- }
403
-
404
- // 更新时间日期区间筛选(按 gmtModified 的日期部分 yyyy-MM-dd)
405
- if (this.searchForm.dateRange && this.searchForm.dateRange.length === 2) {
406
- const [start, end] = this.searchForm.dateRange
407
- data = data.filter(item => {
408
- if (!item.gmtModified) return false
409
- const dateStr = item.gmtModified.slice(0, 10)
410
- return dateStr >= start && dateStr <= end
411
- })
412
- }
413
-
414
- // 排序
415
- if (this.sortConfig.prop) {
416
- data.sort((a, b) => {
417
- const aVal = a[this.sortConfig.prop]
418
- const bVal = b[this.sortConfig.prop]
419
- if (this.sortConfig.order === 'ascending') {
420
- return aVal > bVal ? 1 : aVal < bVal ? -1 : 0
421
- } else {
422
- return aVal < bVal ? 1 : aVal > bVal ? -1 : 0
423
- }
424
- })
425
- }
426
-
427
- // 分页逻辑
428
- this.total = data.length
429
- const start = (this.currentPage - 1) * this.pageSize
430
- const end = start + this.pageSize
431
- this.tableData = data.slice(start, end)
432
- },
433
- // 分页大小改变
434
- handleSizeChange(val) {
435
- this.pageSize = val
436
- this.currentPage = 1
437
- this.fetchData()
438
- },
439
- // 当前页改变
440
- handleCurrentChange(val) {
441
- this.currentPage = val
442
- this.fetchData()
443
- },
444
- // 查询
445
- handleSearch() {
446
- this.currentPage = 1
447
- this.fetchData()
448
- },
449
- // 重置
450
- handleReset() {
451
- this.searchForm = {
452
- opinionTargets: [],
453
- sentiment: '',
454
- opinionInstitution: '',
455
- dateRange: [],
456
- }
457
- this.currentPage = 1
458
- this.fetchData()
459
- },
460
- // 表格排序
461
- handleSortChange({ prop, order }) {
462
- if (!prop || !order) {
463
- this.sortConfig = { prop: 'gmtModified', order: 'descending' }
464
- } else {
465
- this.sortConfig = { prop, order }
466
- }
467
- this.fetchData()
468
- },
469
- // 判断是否需要显示展开按钮(超过3行)
470
- shouldShowExpand(content) {
471
- if (!content) return false
472
- // 简单的判断:如果内容长度超过某个阈值,认为超过3行
473
- // 实际可以使用更精确的方法,比如计算实际行数
474
- return content.length > 100
475
- },
476
- // 切换展开/收起
477
- toggleExpand(row, field) {
478
- const expandField = `expand${field.charAt(0).toUpperCase() + field.slice(1)}`
479
- this.$set(row, expandField, !row[expandField])
480
- },
481
- // 打开统计弹窗
482
- openStatisticsDialog() {
483
- // TODO: 根据当前表格数据查询统计数据
484
- this.statisticsDialogVisible = true
485
- },
486
- // 数据导出
487
- handleExport() {
488
- // TODO: 实现数据导出逻辑
489
- this.$message.success('导出功能开发中...')
490
- },
491
- },
492
- }
493
- </script>
494
-
495
- <style scoped lang="scss">
496
- .event-interpretation {
497
- padding: 20px;
498
- background-color: #f5f7fa;
499
- min-height: calc(100vh - 40px);
500
-
501
- .filter-card {
502
- margin-bottom: 20px;
503
- background-color: #fff;
504
-
505
- .search-form {
506
- padding: 10px 0;
507
- }
508
- }
509
-
510
- .display-card {
511
- background-color: #fff;
512
-
513
- .description-section {
514
- display: flex;
515
- justify-content: space-between;
516
- align-items: center;
517
- padding: 15px 0;
518
- border-bottom: 1px solid #ebeef5;
519
- margin-bottom: 15px;
520
-
521
- .description-left {
522
- flex: 1;
523
-
524
- .fund-summary {
525
- font-size: 14px;
526
- color: #606266;
527
- }
528
- }
529
-
530
- .description-right {
531
- display: flex;
532
- align-items: center;
533
- gap: 10px;
534
-
535
- .text {
536
- font-size: 14px;
537
- color: #606266;
538
- }
539
- }
540
- }
541
-
542
- .result-table {
543
- .expandable-content {
544
- width: 100%;
545
-
546
- /* 折叠状态样式(明确类名) */
547
- .content-collapse {
548
- display: -webkit-box;
549
- -webkit-line-clamp: 3;
550
- line-clamp: 3;
551
- -webkit-box-orient: vertical;
552
- overflow: hidden;
553
- text-overflow: ellipsis;
554
- white-space: normal;
555
- word-wrap: break-word;
556
- }
557
-
558
- /* 展开状态样式 */
559
- .content-expanded {
560
- white-space: normal;
561
- word-wrap: break-word;
562
- overflow: visible;
563
- /* 确保展开后内容完全显示 */
564
- }
565
-
566
- /* 按钮样式优化 */
567
- .el-button {
568
- margin-top: 5px;
569
- color: #409eff;
570
- }
571
- }
572
-
573
- // .expandable-content {
574
- // .content-expanded {
575
- // white-space: normal;
576
- // word-wrap: break-word;
577
- // }
578
-
579
- // div:not(.content-expanded) {
580
- // display: -webkit-box;
581
- // -webkit-line-clamp: 3;
582
- // line-clamp: 3;
583
- // -webkit-box-orient: vertical;
584
- // overflow: hidden;
585
- // text-overflow: ellipsis;
586
- // white-space: normal;
587
- // word-wrap: break-word;
588
- // }
589
- // }
590
- }
591
- }
592
-
593
- // 统计弹窗样式
594
- .statistics-top {
595
- margin-bottom: 30px;
596
-
597
- .statistics-row {
598
- display: flex;
599
- justify-content: space-between;
600
- align-items: center;
601
- margin-bottom: 20px;
602
-
603
- &.statistics-three-columns {
604
- display: flex;
605
- gap: 20px;
606
- margin-top: 20px;
607
-
608
- .statistics-column {
609
- flex: 1;
610
- padding: 15px;
611
- background-color: #f5f7fa;
612
- border-radius: 4px;
613
- text-align: center;
614
-
615
- .column-label {
616
- font-size: 14px;
617
- color: #606266;
618
- margin-bottom: 10px;
619
- }
620
-
621
- .column-value {
622
- font-size: 24px;
623
- font-weight: bold;
624
- color: #409eff;
625
- }
626
- }
627
- }
628
-
629
- .statistics-item-left,
630
- .statistics-item-right {
631
- display: flex;
632
- align-items: center;
633
-
634
- .label {
635
- font-size: 14px;
636
- color: #606266;
637
- margin-right: 5px;
638
- }
639
-
640
- .value {
641
- font-size: 14px;
642
- color: #303133;
643
- font-weight: 500;
644
- }
645
- }
646
- }
647
- }
648
-
649
- .statistics-bottom {
650
- .section-title {
651
- font-size: 16px;
652
- font-weight: bold;
653
- color: #303133;
654
- margin-bottom: 15px;
655
- }
656
-
657
- .distribution-table {
658
- .expand-icon {
659
- cursor: pointer;
660
- display: inline-block;
661
- width: 20px;
662
- text-align: center;
663
- color: #409eff;
664
- margin-right: 5px;
665
- user-select: none;
666
- }
667
-
668
- .index-text {
669
- cursor: pointer;
670
- user-select: none;
671
- color: #409eff;
672
-
673
- &:hover {
674
- text-decoration: underline;
675
- }
676
- }
677
- }
678
- }
679
-
680
- /* 电脑端表单样式 */
681
- .search-form {
682
- display: flex;
683
- align-items: center;
684
- gap: 15px;
685
- /* 统一表单项之间的间距,替代默认margin的混乱 */
686
- flex-wrap: wrap;
687
- /* 极端窄屏(如小尺寸电脑)时自动换行,避免溢出 */
688
- }
689
-
690
- /* 清除Element默认的表单项底边距,避免布局错位 */
691
- .search-form :deep(.el-form-item) {
692
- margin-bottom: 0;
693
- }
694
-
695
- .pagination-container {
696
- margin-top: 20px;
697
- text-align: right;
698
- }
699
-
700
- .statistics-bottom {
701
- .section-title {
702
- font-size: 16px;
703
- font-weight: bold;
704
- color: #303133;
705
- margin-bottom: 15px;
706
- }
707
-
708
- .distribution-table {
709
- .expand-icon {
710
- cursor: pointer;
711
- display: inline-block;
712
- width: 20px;
713
- text-align: center;
714
- color: #409eff;
715
- margin-right: 5px;
716
- user-select: none;
717
- }
718
-
719
- .index-text {
720
- cursor: pointer;
721
- user-select: none;
722
- color: #409eff;
723
-
724
- &:hover {
725
- text-decoration: underline;
726
- }
727
- }
728
- }
729
- }
730
- }
731
- </style>