lambo-design-bi 0.0.244 → 0.0.246
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/bi/widget/bulletin/api/bulletin.js +66 -0
- package/bi/widget/bulletin/bulletin-widget.vue +440 -0
- package/bi/widget/charts/index.vue +38 -20
- package/bi/widget/charts/util/charts-data-util.js +621 -0
- package/bi/widget/page/index-page-tm.vue +3 -3
- package/bi/widget/util/widget-map.js +2 -0
- package/package.json +1 -1
- package/pub/charts/factory/charts-factory.vue +99 -3
- package/pub/charts/factory/options.js +1448 -2
- package/pub/doc/preview/components/JsPreviewDocx.vue +8 -3
- package/pub/doc/word/demo//346/214/207/346/240/207/347/251/277/351/200/217/350/256/276/350/256/241 V1.9.html" +2564 -0
- package/pub/doc/word/demo//351/200/232/346/212/245_/345/257/274/345/207/272/347/273/223/346/236/234.docx +0 -0
- package/pub/doc/word/index.vue +642 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import biConfig from "../../config/config"
|
|
2
|
+
import ajax from "@lambo-design/shared/utils/ajax"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 获取简报右侧摘要(data 阶段,单接口)
|
|
6
|
+
* 后端:GET /bs/bulletin/data/summary,服务端读四个 *_api_id 分别取数并归一为 BulletinSummary
|
|
7
|
+
* 前端直接使用返回结构,不再逐段请求。
|
|
8
|
+
*
|
|
9
|
+
* @param {*} bulletinWidgetId 简报控件 id
|
|
10
|
+
* @param {*} params 页面级查询条件
|
|
11
|
+
* @returns { code, data: { title, meta, conclusions[], metrics[], highlights[], risks[], advices[], warnings[] } }
|
|
12
|
+
*/
|
|
13
|
+
export function getBulletinSummary(bulletinWidgetId, params) {
|
|
14
|
+
return ajax.request({
|
|
15
|
+
url: biConfig.dataServerContext + '/bs/bulletin/data/summary',
|
|
16
|
+
method: 'get',
|
|
17
|
+
params: {
|
|
18
|
+
bulletinWidgetId: bulletinWidgetId,
|
|
19
|
+
params: JSON.stringify(params || {})
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 查询简报已发布成品附件(data 阶段)
|
|
26
|
+
* 后端:GET /bs/bulletin/data/publishedDocs,读 plat_bulletin_publish_doc 中 is_publish='1',
|
|
27
|
+
* 按 bulletinWidgetId + params(期间按 period_type 落列 / 组织)过滤。
|
|
28
|
+
*
|
|
29
|
+
* @param {*} bulletinWidgetId 简报控件 id(= plat_bulletin.bulletin_id)
|
|
30
|
+
* @param {*} params 页面级查询条件(如 period / orgCode)
|
|
31
|
+
* @returns { code, data: [{ bulletinId, docId, docName, periodYear, comId, distCtId, publishTime, ... }] }
|
|
32
|
+
*/
|
|
33
|
+
export function getPublishedBulletinDocs(bulletinWidgetId, params) {
|
|
34
|
+
return ajax.request({
|
|
35
|
+
url: biConfig.dataServerContext + '/bs/bulletin/data/publishedDocs',
|
|
36
|
+
method: 'get',
|
|
37
|
+
params: {
|
|
38
|
+
bulletinWidgetId: bulletinWidgetId,
|
|
39
|
+
params: JSON.stringify(params || {})
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 查询简报发布成品列表(data 阶段)
|
|
46
|
+
* 后端:GET /bs/bulletin/doc/list,按 简报×期间×组织 查已发布成品
|
|
47
|
+
* 固定参数外,透传 query 上的额外字段(如命中的原始期间字段名 period_year 等)
|
|
48
|
+
*
|
|
49
|
+
* @param {*} query { bulletinId, periodValue, comId, isPublish, offset, limit, ...额外期间字段 }
|
|
50
|
+
* @returns { code, data: { rows: [{ docId, docName, isPublish, ... }], total } }
|
|
51
|
+
*/
|
|
52
|
+
export function listBulletinPublishDoc(query) {
|
|
53
|
+
const q = query || {}
|
|
54
|
+
return ajax.request({
|
|
55
|
+
url: biConfig.dataServerContext + '/bs/bulletin/doc/list',
|
|
56
|
+
method: 'get',
|
|
57
|
+
params: Object.assign({}, q, {
|
|
58
|
+
offset: q.offset != null ? q.offset : 0,
|
|
59
|
+
limit: q.limit != null ? q.limit : 10,
|
|
60
|
+
bulletinId: q.bulletinId || '',
|
|
61
|
+
periodValue: q.periodValue || '',
|
|
62
|
+
comId: q.comId || '',
|
|
63
|
+
isPublish: q.isPublish || ''
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
}
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
<!-- eslint-disable -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="bulletin-widget">
|
|
4
|
+
<div class="bulletin-header" v-if="hasTitle">
|
|
5
|
+
<div class="bulletin-title">{{ cardTitle }}</div>
|
|
6
|
+
<div class="bulletin-subtitle" v-if="subTitle">{{ subTitle }}</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<div
|
|
10
|
+
class="bulletin-body"
|
|
11
|
+
:class="{ 'is-empty': !previewUrl }"
|
|
12
|
+
:style="containerStyle || {}">
|
|
13
|
+
<div v-if="querying && !previewUrl" class="bulletin-placeholder">
|
|
14
|
+
<p>加载简报中…</p>
|
|
15
|
+
</div>
|
|
16
|
+
<div v-else-if="emptyReason === 'invalid'" class="bulletin-placeholder">
|
|
17
|
+
<p>请先选择查询条件</p>
|
|
18
|
+
<p class="hint">选择简报期间与组织后查看简报</p>
|
|
19
|
+
</div>
|
|
20
|
+
<div v-else-if="!previewUrl" class="bulletin-placeholder">
|
|
21
|
+
<p>尚未发布简报</p>
|
|
22
|
+
<p class="hint">该期间/组织暂无已发布的简报成品</p>
|
|
23
|
+
</div>
|
|
24
|
+
<template v-else>
|
|
25
|
+
<div
|
|
26
|
+
class="bulletin-download-fab"
|
|
27
|
+
title="下载简报"
|
|
28
|
+
@click="doDownload">
|
|
29
|
+
<Icon type="md-download" />
|
|
30
|
+
</div>
|
|
31
|
+
<lambo-doc-word
|
|
32
|
+
:url="previewUrl"
|
|
33
|
+
:key="previewUrl"
|
|
34
|
+
:report="summary" />
|
|
35
|
+
</template>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</template>
|
|
39
|
+
<script>
|
|
40
|
+
import LamboDocWord from '../../../pub/doc/word/index.vue'
|
|
41
|
+
import { parseStyleStr } from '../util/css-util'
|
|
42
|
+
import { getBulletinSummary, listBulletinPublishDoc } from './api/bulletin'
|
|
43
|
+
import { fileGetUrl } from '../api/config'
|
|
44
|
+
|
|
45
|
+
// 统一日志前缀,便于在控制台按关键字过滤简报组件的关键过程
|
|
46
|
+
const LOG = '[BiBulletin]'
|
|
47
|
+
|
|
48
|
+
// 摘要空对象骨架,摘要内容未加载/缺省时兜底,避免 lambo-doc-word 内部空指针
|
|
49
|
+
const EMPTY_SUMMARY = Object.freeze({
|
|
50
|
+
title: '',
|
|
51
|
+
meta: '',
|
|
52
|
+
conclusions: [],
|
|
53
|
+
metrics: [],
|
|
54
|
+
highlights: [],
|
|
55
|
+
risks: [],
|
|
56
|
+
advices: []
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// 期间类型 → params 里期间值的候选 qKey(0年/1半年/2季度/3月)
|
|
60
|
+
const PERIOD_KEY_CANDIDATES = {
|
|
61
|
+
'0': ['period_year', 'periodYear'],
|
|
62
|
+
'1': ['period_half_year', 'periodHalfYear'],
|
|
63
|
+
'2': ['period_quarter', 'periodQuarter'],
|
|
64
|
+
'3': ['period_month', 'periodMonth']
|
|
65
|
+
}
|
|
66
|
+
// 组织编码候选 qKey
|
|
67
|
+
const COM_ID_CANDIDATES = ['comId', 'com_id']
|
|
68
|
+
const DIST_CT_ID_CANDIDATES = ['distCtId', 'dist_ct_id']
|
|
69
|
+
|
|
70
|
+
// 从 params 里按候选 key 取首个非空项,返回命中的 { key, value };均未命中返回 null
|
|
71
|
+
function firstNonBlankEntry(obj, keys) {
|
|
72
|
+
if (!obj || !Array.isArray(keys)) return null
|
|
73
|
+
for (const k of keys) {
|
|
74
|
+
const v = obj[k]
|
|
75
|
+
if (v !== null && v !== undefined && String(v).length > 0) {
|
|
76
|
+
return { key: k, value: Array.isArray(v) ? v.join(',') : String(v) }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default {
|
|
83
|
+
name: "BiBulletin",
|
|
84
|
+
components: { LamboDocWord },
|
|
85
|
+
props: {
|
|
86
|
+
widget: {
|
|
87
|
+
type: Object,
|
|
88
|
+
default: () => ({})
|
|
89
|
+
},
|
|
90
|
+
params: {
|
|
91
|
+
type: Object,
|
|
92
|
+
default: () => ({})
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
data() {
|
|
96
|
+
return {
|
|
97
|
+
containerStyle: {},
|
|
98
|
+
subTitle: null,
|
|
99
|
+
// docx 态
|
|
100
|
+
querying: false,
|
|
101
|
+
previewUrl: '',
|
|
102
|
+
lastDocId: '',
|
|
103
|
+
lastFileName: '',
|
|
104
|
+
// 空态原因:'' 无 / 'invalid' 查询条件不足(校验未过)/ 'empty' 已查询但无成品
|
|
105
|
+
emptyReason: '',
|
|
106
|
+
// 摘要(data 阶段)
|
|
107
|
+
summaryLoading: false,
|
|
108
|
+
summaryData: null
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
computed: {
|
|
112
|
+
bulletinOptions() {
|
|
113
|
+
return Object.assign({}, this.widget.options || {}, this.widget.optsion || {})
|
|
114
|
+
},
|
|
115
|
+
cardTitle() {
|
|
116
|
+
return this.bulletinOptions.title || this.widget.name || '简报'
|
|
117
|
+
},
|
|
118
|
+
hasTitle() {
|
|
119
|
+
return !!(this.cardTitle && this.cardTitle.length > 0)
|
|
120
|
+
},
|
|
121
|
+
// 右侧摘要数据源:data 阶段拉取的 summaryData,缺省用空骨架
|
|
122
|
+
summary() {
|
|
123
|
+
const s = this.summaryData
|
|
124
|
+
if (!s || typeof s !== 'object') return { ...EMPTY_SUMMARY, title: this.cardTitle }
|
|
125
|
+
return Object.assign({}, EMPTY_SUMMARY, { title: this.cardTitle }, s)
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
watch: {
|
|
129
|
+
// params 变化(页面查询条件切换:期间/组织)时,只重跑 data 阶段(docx + 摘要),不重拉 config
|
|
130
|
+
params: {
|
|
131
|
+
deep: true,
|
|
132
|
+
handler(val, oldVal) {
|
|
133
|
+
console.log(LOG, 'params 变化,重跑 data 阶段', { oldVal, val })
|
|
134
|
+
this.loadData(this.params)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
methods: {
|
|
139
|
+
initConfig() {
|
|
140
|
+
if (this.bulletinOptions) {
|
|
141
|
+
if (Object.prototype.hasOwnProperty.call(this.bulletinOptions, "subTitle")) {
|
|
142
|
+
this.subTitle = this.bulletinOptions["subTitle"] || ''
|
|
143
|
+
}
|
|
144
|
+
if (Object.prototype.hasOwnProperty.call(this.bulletinOptions, "style")) {
|
|
145
|
+
this.containerStyle = parseStyleStr(this.bulletinOptions["style"] || {}) || {}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
loadData(params) {
|
|
150
|
+
console.log(LOG, 'loadData 开始 data 阶段', { bulletinId: this.widget && this.widget.id, params })
|
|
151
|
+
// 摘要依赖已发布成品:仅当 loadDoc 命中成品后才拉摘要,未命中则不查摘要
|
|
152
|
+
this.loadDoc(params)
|
|
153
|
+
},
|
|
154
|
+
// 清空右侧摘要
|
|
155
|
+
clearSummary() {
|
|
156
|
+
this.summaryData = null
|
|
157
|
+
},
|
|
158
|
+
// 清空 docx 预览态(未命中/查询失败/校验不通过时展示空态)
|
|
159
|
+
clearPreview(reason) {
|
|
160
|
+
this.lastDocId = ''
|
|
161
|
+
this.lastFileName = ''
|
|
162
|
+
this.previewUrl = ''
|
|
163
|
+
this.emptyReason = reason || ''
|
|
164
|
+
},
|
|
165
|
+
loadDoc(params) {
|
|
166
|
+
if (this.querying) {
|
|
167
|
+
console.log(LOG, 'loadDoc 跳过:正在查询中')
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
const bulletinWidgetId = this.widget && this.widget.id
|
|
171
|
+
if (!bulletinWidgetId) {
|
|
172
|
+
console.warn(LOG, 'loadDoc 中止:简报id为空')
|
|
173
|
+
this.clearSummary()
|
|
174
|
+
this.$Message.error({ content: '简报id为空,无法加载', duration: 2.5 })
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 期间/组织/物流中心:把命中的字段名(key)与值(value)一并作为请求参数
|
|
179
|
+
// - 固定名(periodValue / comId / distCtId):后端 /doc/list 当前实际用于过滤的参数名
|
|
180
|
+
// - entry.key:命中的原始字段名(如 period_year / com_id),作为预留一并传递
|
|
181
|
+
const periodEntry = this.resolvePeriodEntry(params)
|
|
182
|
+
const comEntry = firstNonBlankEntry(params, COM_ID_CANDIDATES)
|
|
183
|
+
const distCtEntry = firstNonBlankEntry(params, DIST_CT_ID_CANDIDATES)
|
|
184
|
+
|
|
185
|
+
// 查询前置校验:periodValue 必须有值,且 comId / distCtId 至少有一个有值,否则不查、展示空态并提示
|
|
186
|
+
if (!periodEntry) {
|
|
187
|
+
console.log(LOG, 'loadDoc 跳过查询:期间值为空,展示空态')
|
|
188
|
+
this.clearPreview('invalid')
|
|
189
|
+
this.clearSummary()
|
|
190
|
+
this.$Message.warning({ content: '请选择简报期间', duration: 2 })
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
if (!comEntry && !distCtEntry) {
|
|
194
|
+
console.log(LOG, 'loadDoc 跳过查询:组织与物流中心均为空,展示空态')
|
|
195
|
+
this.clearPreview('invalid')
|
|
196
|
+
this.clearSummary()
|
|
197
|
+
this.$Message.warning({ content: '请选择简报组织', duration: 2 })
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const query = {
|
|
202
|
+
bulletinId: bulletinWidgetId,
|
|
203
|
+
isPublish: '1',
|
|
204
|
+
offset: 0,
|
|
205
|
+
limit: 1
|
|
206
|
+
}
|
|
207
|
+
query.periodValue = periodEntry.value
|
|
208
|
+
query[periodEntry.key] = periodEntry.value
|
|
209
|
+
if (comEntry) {
|
|
210
|
+
query.comId = comEntry.value
|
|
211
|
+
query[comEntry.key] = comEntry.value
|
|
212
|
+
}
|
|
213
|
+
if (distCtEntry) {
|
|
214
|
+
query.distCtId = distCtEntry.value
|
|
215
|
+
query[distCtEntry.key] = distCtEntry.value
|
|
216
|
+
}
|
|
217
|
+
console.log(LOG, 'loadDoc 查询已发布成品', { bulletinWidgetId, periodEntry, comEntry, distCtEntry })
|
|
218
|
+
this.querying = true
|
|
219
|
+
listBulletinPublishDoc(query)
|
|
220
|
+
.then(res => {
|
|
221
|
+
const body = res && res.data
|
|
222
|
+
const rows = (body && body.data && Array.isArray(body.data.rows)) ? body.data.rows : []
|
|
223
|
+
if (body && body.code === 1 && rows.length > 0 && rows[0].docId) {
|
|
224
|
+
const doc = rows[0]
|
|
225
|
+
console.log(LOG, 'loadDoc 命中已发布成品,直接渲染', { docId: doc.docId, docName: doc.docName })
|
|
226
|
+
this.lastDocId = doc.docId
|
|
227
|
+
this.lastFileName = doc.docName || (this.cardTitle + '.docx')
|
|
228
|
+
this.previewUrl = fileGetUrl + doc.docId
|
|
229
|
+
this.emptyReason = ''
|
|
230
|
+
this.$Message.info({ content: '已展示最近发布的简报', duration: 1.8 })
|
|
231
|
+
// 命中成品后才拉右侧摘要
|
|
232
|
+
this.loadSummary(params)
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
// 未命中已发布成品 → 空态,同时清空摘要(不再查摘要)
|
|
236
|
+
console.log(LOG, 'loadDoc 未命中已发布成品,展示空态', { code: body && body.code, rowCount: rows.length })
|
|
237
|
+
this.clearPreview('empty')
|
|
238
|
+
this.clearSummary()
|
|
239
|
+
})
|
|
240
|
+
.catch(err => {
|
|
241
|
+
console.warn(LOG, 'loadDoc 查询发布成品失败,展示空态:', err)
|
|
242
|
+
this.clearPreview('empty')
|
|
243
|
+
this.clearSummary()
|
|
244
|
+
})
|
|
245
|
+
.finally(() => {
|
|
246
|
+
this.querying = false
|
|
247
|
+
})
|
|
248
|
+
},
|
|
249
|
+
// 依据简报期间类型(periodType)从 params 里解析期间键值对,用于查发布成品
|
|
250
|
+
// 返回命中的 { key, value }(key 为 params 里实际命中的期间字段名);无有效期间时返回 null
|
|
251
|
+
resolvePeriodEntry(params) {
|
|
252
|
+
const periodType = this.bulletinOptions.periodType != null ? String(this.bulletinOptions.periodType) : ''
|
|
253
|
+
// periodType 缺省或非 0/1/2/3 → 无对应候选 key,直接返回 null,避免 firstNonBlankEntry 遍历 undefined 抛错
|
|
254
|
+
if (!periodType) {
|
|
255
|
+
console.warn(LOG, 'resolvePeriodEntry periodType 为空,跳过期间解析')
|
|
256
|
+
return null
|
|
257
|
+
}
|
|
258
|
+
const candidates = PERIOD_KEY_CANDIDATES[periodType]
|
|
259
|
+
if (!Array.isArray(candidates) || candidates.length < 1) {
|
|
260
|
+
console.warn(LOG, 'resolvePeriodEntry periodType 无对应候选 key', { periodType })
|
|
261
|
+
return null
|
|
262
|
+
}
|
|
263
|
+
const entry = firstNonBlankEntry(params, candidates)
|
|
264
|
+
console.log(LOG, 'resolvePeriodEntry', { periodType, candidates, entry })
|
|
265
|
+
return entry
|
|
266
|
+
},
|
|
267
|
+
// data 阶段之二:获取右侧摘要(单接口,后端已聚合四段)
|
|
268
|
+
loadSummary(params) {
|
|
269
|
+
const bulletinWidgetId = this.widget && this.widget.id
|
|
270
|
+
if (!bulletinWidgetId) {
|
|
271
|
+
console.warn(LOG, 'loadSummary 中止:简报id为空')
|
|
272
|
+
this.summaryData = null
|
|
273
|
+
return
|
|
274
|
+
}
|
|
275
|
+
console.log(LOG, 'loadSummary 请求摘要', { bulletinWidgetId, params })
|
|
276
|
+
this.summaryLoading = true
|
|
277
|
+
getBulletinSummary(bulletinWidgetId, params || {})
|
|
278
|
+
.then(res => {
|
|
279
|
+
const body = res && res.data
|
|
280
|
+
if (!body || body.code !== 1) {
|
|
281
|
+
console.warn(LOG, 'loadSummary 失败:', body)
|
|
282
|
+
this.summaryData = null
|
|
283
|
+
return
|
|
284
|
+
}
|
|
285
|
+
this.summaryData = (body.data && typeof body.data === 'object') ? body.data : null
|
|
286
|
+
const s = this.summaryData || {}
|
|
287
|
+
console.log(LOG, 'loadSummary 成功', {
|
|
288
|
+
conclusions: (s.conclusions || []).length,
|
|
289
|
+
metrics: (s.metrics || []).length,
|
|
290
|
+
highlights: (s.highlights || []).length,
|
|
291
|
+
risks: (s.risks || []).length,
|
|
292
|
+
advices: (s.advices || []).length,
|
|
293
|
+
warnings: (s.warnings || []).length
|
|
294
|
+
})
|
|
295
|
+
})
|
|
296
|
+
.catch(err => {
|
|
297
|
+
console.error(LOG, 'loadSummary 异常:', err)
|
|
298
|
+
this.summaryData = null
|
|
299
|
+
})
|
|
300
|
+
.finally(() => {
|
|
301
|
+
this.summaryLoading = false
|
|
302
|
+
})
|
|
303
|
+
},
|
|
304
|
+
// 下载:用当前展示的已发布成品 docId
|
|
305
|
+
doDownload() {
|
|
306
|
+
if (!this.lastDocId) {
|
|
307
|
+
console.log(LOG, 'doDownload 中止:尚无可下载的简报')
|
|
308
|
+
this.$Message.info({ content: '暂无已发布的简报可下载', duration: 1.8 })
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
console.log(LOG, 'doDownload 下载', { docId: this.lastDocId, fileName: this.lastFileName })
|
|
312
|
+
this.triggerDownload(this.lastDocId, this.lastFileName)
|
|
313
|
+
},
|
|
314
|
+
triggerDownload(docId, fileName) {
|
|
315
|
+
const url = fileGetUrl + docId
|
|
316
|
+
// 用隐式 <a download> 触发下载,避免弹新页签打断阅读
|
|
317
|
+
try {
|
|
318
|
+
const a = document.createElement('a')
|
|
319
|
+
a.href = url
|
|
320
|
+
a.download = fileName || ''
|
|
321
|
+
a.style.display = 'none'
|
|
322
|
+
document.body.appendChild(a)
|
|
323
|
+
a.click()
|
|
324
|
+
document.body.removeChild(a)
|
|
325
|
+
} catch (e) {
|
|
326
|
+
console.warn(LOG, 'triggerDownload 降级 window.open', e)
|
|
327
|
+
window.open(url)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
created() {
|
|
332
|
+
console.log(LOG, 'created config 阶段解析', { widget: this.widget, options: this.bulletinOptions })
|
|
333
|
+
// config 阶段:由父页面完成配置装配,此处仅解析结构性配置
|
|
334
|
+
this.initConfig()
|
|
335
|
+
},
|
|
336
|
+
mounted() {
|
|
337
|
+
// params 已有值(父组件同步传入)→ 直接加载;否则等 watcher 触发
|
|
338
|
+
// if (this.params && Object.keys(this.params).length > 0) {
|
|
339
|
+
// console.log(LOG, 'mounted params 已就绪,直接加载', { params: this.params })
|
|
340
|
+
// this.loadData(this.params)
|
|
341
|
+
// } else {
|
|
342
|
+
// console.log(LOG, 'mounted params 为空,等 watcher 触发')
|
|
343
|
+
// }
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
</script>
|
|
347
|
+
|
|
348
|
+
<style scoped>
|
|
349
|
+
.bulletin-widget {
|
|
350
|
+
width: 100%;
|
|
351
|
+
}
|
|
352
|
+
/* 自绘标题栏:无边框,仅与下方内容留间距 */
|
|
353
|
+
.bulletin-header {
|
|
354
|
+
padding: 0 0 12px;
|
|
355
|
+
}
|
|
356
|
+
.bulletin-title {
|
|
357
|
+
font-size: 16px;
|
|
358
|
+
font-weight: 600;
|
|
359
|
+
color: #17233d;
|
|
360
|
+
line-height: 1.4;
|
|
361
|
+
}
|
|
362
|
+
.bulletin-subtitle {
|
|
363
|
+
margin-top: 2px;
|
|
364
|
+
color: #999;
|
|
365
|
+
font-size: 12px;
|
|
366
|
+
line-height: 1.4;
|
|
367
|
+
}
|
|
368
|
+
.bulletin-body {
|
|
369
|
+
width: 100%;
|
|
370
|
+
/* 定位上下文:悬浮下载按钮相对本容器绝对定位 */
|
|
371
|
+
position: relative;
|
|
372
|
+
/* 有文档预览时给 lambo-doc-word 一个明确的高度基线,其内部 word-preview 使用 height:100% */
|
|
373
|
+
height: 720px;
|
|
374
|
+
min-height: 480px;
|
|
375
|
+
}
|
|
376
|
+
/* 悬浮下载按钮:自定义 FAB,悬浮在预览区右上角上层,hover 点亮为主题蓝 */
|
|
377
|
+
.bulletin-download-fab {
|
|
378
|
+
position: absolute;
|
|
379
|
+
top: 16px;
|
|
380
|
+
right: 16px;
|
|
381
|
+
z-index: 10;
|
|
382
|
+
width: 40px;
|
|
383
|
+
height: 40px;
|
|
384
|
+
display: flex;
|
|
385
|
+
align-items: center;
|
|
386
|
+
justify-content: center;
|
|
387
|
+
font-size: 20px;
|
|
388
|
+
color: #2d8cf0;
|
|
389
|
+
cursor: pointer;
|
|
390
|
+
border-radius: 6px;
|
|
391
|
+
background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(240, 247, 255, 0.9));
|
|
392
|
+
backdrop-filter: blur(8px);
|
|
393
|
+
-webkit-backdrop-filter: blur(8px);
|
|
394
|
+
border: 1px solid rgba(45, 140, 240, 0.15);
|
|
395
|
+
box-shadow: 0 4px 14px rgba(31, 45, 61, 0.12);
|
|
396
|
+
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
397
|
+
}
|
|
398
|
+
.bulletin-download-fab:hover {
|
|
399
|
+
color: #fff;
|
|
400
|
+
background: linear-gradient(135deg, #2d8cf0, #57a3f3);
|
|
401
|
+
border-color: transparent;
|
|
402
|
+
transform: translateY(-2px);
|
|
403
|
+
box-shadow: 0 8px 20px rgba(45, 140, 240, 0.4);
|
|
404
|
+
}
|
|
405
|
+
.bulletin-download-fab:active {
|
|
406
|
+
transform: translateY(0);
|
|
407
|
+
box-shadow: 0 3px 10px rgba(45, 140, 240, 0.35);
|
|
408
|
+
}
|
|
409
|
+
/* 空态/加载态:无文档时高度自适应内容,避免撑出大片空白 */
|
|
410
|
+
.bulletin-body.is-empty {
|
|
411
|
+
height: auto;
|
|
412
|
+
min-height: 0;
|
|
413
|
+
}
|
|
414
|
+
.bulletin-placeholder {
|
|
415
|
+
width: 100%;
|
|
416
|
+
height: 100%;
|
|
417
|
+
display: flex;
|
|
418
|
+
flex-direction: column;
|
|
419
|
+
justify-content: center;
|
|
420
|
+
align-items: center;
|
|
421
|
+
gap: 6px;
|
|
422
|
+
color: #94a3b8;
|
|
423
|
+
font-size: 13px;
|
|
424
|
+
background: #f8fafc;
|
|
425
|
+
border: 1px dashed #e2e8f0;
|
|
426
|
+
border-radius: 6px;
|
|
427
|
+
}
|
|
428
|
+
/* 空态容器高度自适应时,用内边距撑出紧凑高度而非塌陷 */
|
|
429
|
+
.bulletin-body.is-empty .bulletin-placeholder {
|
|
430
|
+
height: auto;
|
|
431
|
+
padding: 48px 16px;
|
|
432
|
+
}
|
|
433
|
+
.bulletin-placeholder p {
|
|
434
|
+
margin: 0;
|
|
435
|
+
}
|
|
436
|
+
.bulletin-placeholder .hint {
|
|
437
|
+
font-size: 12px;
|
|
438
|
+
color: #cbd5e1;
|
|
439
|
+
}
|
|
440
|
+
</style>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<LamboChartsFactory v-if="dataX" :height="height" :type="chartsType" :data-x="dataX" :data-y="dataY"
|
|
3
|
-
:data-dim="dataDim" :charts-note="chartsNote">
|
|
3
|
+
:data-dim="dataDim" :data-z="dataZ" :charts-note="chartsNote">
|
|
4
4
|
</LamboChartsFactory>
|
|
5
5
|
</template>
|
|
6
6
|
<script>
|
|
7
7
|
import { getListMapData } from "../api/data"
|
|
8
8
|
import LamboChartsFactory from "../../../pub/charts/factory/charts-factory.vue"
|
|
9
|
-
import { convertChartsData, convertChartsDataType42 } from "./util/charts-data-util"
|
|
9
|
+
import { convertChartsData, convertChartsDataType42, convertChartsDataType46, convertChartsDataType48, convertChartsDataType49, convertChartsDataType50, convertChartsDataType52 } from "./util/charts-data-util"
|
|
10
10
|
import { EventBus, EVENT_TYPES } from '../util/event-bus'
|
|
11
11
|
|
|
12
12
|
export default {
|
|
@@ -29,6 +29,7 @@ export default {
|
|
|
29
29
|
dataX: null,
|
|
30
30
|
dataY: null,
|
|
31
31
|
dataDim: null,
|
|
32
|
+
dataZ: null,
|
|
32
33
|
height: null,
|
|
33
34
|
columns: null,
|
|
34
35
|
xKey: null,
|
|
@@ -69,6 +70,40 @@ export default {
|
|
|
69
70
|
this.linkWidgetId = this.widget.options.linkWidgetId || ''
|
|
70
71
|
this.linkKeys = this.widget.options.linkKeys || null
|
|
71
72
|
},
|
|
73
|
+
handleRows(rows) {
|
|
74
|
+
if (!rows || !this.columns) return
|
|
75
|
+
let resObj = {}
|
|
76
|
+
if (this.chartsType === '42') {
|
|
77
|
+
resObj = convertChartsDataType42(rows, this.columns)
|
|
78
|
+
} else if (this.chartsType === '46' || this.chartsType === '47') {
|
|
79
|
+
// 46: 普通气泡图 47: 象限气泡图
|
|
80
|
+
resObj = convertChartsDataType46(rows, this.columns)
|
|
81
|
+
} else if (this.chartsType === '48') {
|
|
82
|
+
// 48: 差距瀑布图
|
|
83
|
+
resObj = convertChartsDataType48(rows, this.columns)
|
|
84
|
+
} else if (this.chartsType === '49') {
|
|
85
|
+
// 49: 子弹图
|
|
86
|
+
resObj = convertChartsDataType49(rows, this.columns)
|
|
87
|
+
} else if (this.chartsType === '50') {
|
|
88
|
+
// 50: 组内排名图
|
|
89
|
+
resObj = convertChartsDataType50(rows, this.columns)
|
|
90
|
+
} else if (this.chartsType === '52') {
|
|
91
|
+
// 52: 热力分布图
|
|
92
|
+
resObj = convertChartsDataType52(rows, this.columns)
|
|
93
|
+
} else {
|
|
94
|
+
resObj = convertChartsData(rows, this.columns)
|
|
95
|
+
}
|
|
96
|
+
console.log("chartsType:", this.chartsType, "resObj:", resObj)
|
|
97
|
+
if (resObj) {
|
|
98
|
+
this.dataX = resObj.dataX
|
|
99
|
+
this.dataY = resObj.dataY
|
|
100
|
+
this.dataDim = resObj.dataDim
|
|
101
|
+
this.dataZ = resObj.dataZ || null
|
|
102
|
+
} else {
|
|
103
|
+
console.error("charts数据服务[" + this.widget.name + "]数据转换失败:" + resObj)
|
|
104
|
+
this.$Message.warning("charts数据服务[" + this.widget.name + "]数据转换失败")
|
|
105
|
+
}
|
|
106
|
+
},
|
|
72
107
|
doSearch() {
|
|
73
108
|
if (!this.apiId) {
|
|
74
109
|
this.$Message.warning("组件[" + this.widget.name + "]未配置数据接口")
|
|
@@ -79,24 +114,7 @@ export default {
|
|
|
79
114
|
console.error("charts数据服务[" + this.widget.options.apiId + "]请求失败:" + res.data.message)
|
|
80
115
|
} else {
|
|
81
116
|
if (res.data.data.rows.length > 0) {
|
|
82
|
-
|
|
83
|
-
if (rows && this.columns) {
|
|
84
|
-
let resObj = {}
|
|
85
|
-
if (this.chartsType === '42') {
|
|
86
|
-
resObj = convertChartsDataType42(rows, this.columns)
|
|
87
|
-
} else {
|
|
88
|
-
resObj = convertChartsData(rows, this.columns)
|
|
89
|
-
}
|
|
90
|
-
console.log( "chartsType:", this.chartsType, "resObj:", resObj)
|
|
91
|
-
if (resObj) {
|
|
92
|
-
this.dataX = resObj.dataX
|
|
93
|
-
this.dataY = resObj.dataY
|
|
94
|
-
this.dataDim = resObj.dataDim
|
|
95
|
-
} else {
|
|
96
|
-
console.error("charts数据服务[" + this.widget.name + "]数据转换失败:" + resObj)
|
|
97
|
-
this.$Message.warning("charts数据服务[" + this.widget.name + "]数据转换失败")
|
|
98
|
-
}
|
|
99
|
-
}
|
|
117
|
+
this.handleRows(res.data.data.rows)
|
|
100
118
|
} else {
|
|
101
119
|
console.warn("charts数据服务[" + this.widget.options.apiId + "]请求数据为空:" + res.data.message)
|
|
102
120
|
this.dataX = []
|