bl-common-vue3 3.8.109 → 3.8.110

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": "bl-common-vue3",
3
- "version": "3.8.109",
3
+ "version": "3.8.110",
4
4
  "main": "index.js",
5
5
  "module": "index.js",
6
6
  "description": "bailing vue3 common components lib",
@@ -41,7 +41,9 @@
41
41
  "file-saver": "^2.0.5",
42
42
  "style-resources-loader": "^1.5.0"
43
43
  },
44
- "dependencies": {},
44
+ "dependencies": {
45
+ "xlsx-js-style": "^1.2.0"
46
+ },
45
47
  "devDependencies": {
46
48
  "@vue/cli-plugin-babel": "~4.5.13",
47
49
  "@vue/cli-plugin-eslint": "~4.5.13",
@@ -1,7 +1,40 @@
1
- import fs from "file-saver";
2
- import * as XLSX from "kj-xlsx";
1
+ import fs from "file-saver";
2
+ import * as LegacyXLSX from "kj-xlsx";
3
+
4
+ const DEFAULT_COLUMN_WIDTH = 16;
5
+ const MAX_COLUMN_WIDTH = 36;
6
+ const HEADER_ROW_HEIGHT = 30;
7
+ const DATA_ROW_HEIGHT = 24;
8
+
9
+ const createBorder = (color) => ({
10
+ top: { style: "thin", color: { rgb: color } },
11
+ bottom: { style: "thin", color: { rgb: color } },
12
+ left: { style: "thin", color: { rgb: color } },
13
+ right: { style: "thin", color: { rgb: color } },
14
+ });
15
+
16
+ const getStyledExportOptions = (options = {}) => {
17
+ // 公共导出默认使用统一基础样式,特殊旧模板仍可通过 enabled: false 关闭。
18
+ const {
19
+ enabled = true,
20
+ detailFields = [],
21
+ fieldAlignments = {},
22
+ columnWidths = {},
23
+ } = options;
24
+
25
+ return {
26
+ enabled,
27
+ detailFields: Array.isArray(detailFields) ? detailFields : [],
28
+ fieldAlignments:
29
+ fieldAlignments && typeof fieldAlignments === "object"
30
+ ? fieldAlignments
31
+ : {},
32
+ columnWidths:
33
+ columnWidths && typeof columnWidths === "object" ? columnWidths : {},
34
+ };
35
+ };
3
36
 
4
- export function getVerticalMergeCells(json, fields, options = {}) {
37
+ export function getVerticalMergeCells(json, fields, options = {}) {
5
38
  const { groupField, mergeFields = [] } = options;
6
39
  if (!groupField || !Array.isArray(mergeFields) || !mergeFields.length) {
7
40
  return [];
@@ -50,13 +83,111 @@ export function getVerticalMergeCells(json, fields, options = {}) {
50
83
  groupStartIndex = rowIndex;
51
84
  }
52
85
 
53
- return merges;
54
- }
55
-
56
- export function xlsx(json, fields, filename = ".xlsx", mergeOptions = {}) {
57
- const merges = getVerticalMergeCells(json, fields, mergeOptions);
58
- //导出xlsx
59
- json.forEach((item) => {
86
+ return merges;
87
+ }
88
+
89
+ const getAutoColumnWidths = (json, fields, columnWidths = {}) => {
90
+ return Object.entries(fields).map(([field, title]) => {
91
+ const configuredWidth = Number(columnWidths[field]);
92
+ if (configuredWidth > 0) {
93
+ return { wch: configuredWidth };
94
+ }
95
+
96
+ const contentWidth = json.reduce((width, item) => {
97
+ const valueLength = String(item?.[field] ?? "").length;
98
+ return Math.max(width, valueLength);
99
+ }, String(title ?? "").length);
100
+
101
+ return {
102
+ wch: Math.min(MAX_COLUMN_WIDTH, Math.max(DEFAULT_COLUMN_WIDTH, contentWidth + 2)),
103
+ };
104
+ });
105
+ };
106
+
107
+ const applyStyledExport = (XLSX, ws, json, fields, options) => {
108
+ const fieldKeys = Object.keys(fields);
109
+ const detailFieldSet = new Set(options.detailFields);
110
+ const headerBorder = createBorder("FFB4C7E7");
111
+ const bodyBorder = createBorder("FFD9E2F3");
112
+
113
+ fieldKeys.forEach((field, columnIndex) => {
114
+ const headerCell = ws[XLSX.utils.encode_cell({ r: 0, c: columnIndex })];
115
+ if (headerCell) {
116
+ const isDetailField = detailFieldSet.has(field);
117
+ headerCell.s = {
118
+ font: {
119
+ name: "Microsoft YaHei",
120
+ sz: 11,
121
+ bold: true,
122
+ color: { rgb: isDetailField ? "FF1F4E78" : "FFFFFFFF" },
123
+ },
124
+ fill: {
125
+ patternType: "solid",
126
+ fgColor: { rgb: isDetailField ? "FFDCE6F1" : "FF4472C4" },
127
+ },
128
+ alignment: {
129
+ horizontal: "center",
130
+ vertical: "center",
131
+ wrapText: true,
132
+ },
133
+ border: headerBorder,
134
+ };
135
+ }
136
+
137
+ json.forEach((item, dataIndex) => {
138
+ const cell = ws[
139
+ XLSX.utils.encode_cell({ r: dataIndex + 1, c: columnIndex })
140
+ ];
141
+ if (!cell) {
142
+ return;
143
+ }
144
+
145
+ const isDetailField = detailFieldSet.has(field);
146
+ cell.s = {
147
+ font: {
148
+ name: "Microsoft YaHei",
149
+ sz: 10,
150
+ color: { rgb: "FF333333" },
151
+ },
152
+ fill: {
153
+ patternType: "solid",
154
+ fgColor: { rgb: isDetailField ? "FFF7FAFD" : "FFFFFFFF" },
155
+ },
156
+ alignment: {
157
+ horizontal: options.fieldAlignments[field] || "left",
158
+ vertical: "center",
159
+ wrapText: true,
160
+ },
161
+ border: bodyBorder,
162
+ };
163
+ });
164
+ });
165
+
166
+ ws["!cols"] = getAutoColumnWidths(json, fields, options.columnWidths);
167
+ ws["!rows"] = [
168
+ { hpt: HEADER_ROW_HEIGHT },
169
+ ...json.map(() => ({ hpt: DATA_ROW_HEIGHT })),
170
+ ];
171
+ };
172
+
173
+ // 暴露工作簿构建方法,便于对合并区域和样式做真实 xlsx 回归检查。
174
+ export async function createWorkbook(
175
+ json,
176
+ fields,
177
+ mergeOptions = {},
178
+ styleOptions = {}
179
+ ) {
180
+ const merges = getVerticalMergeCells(json, fields, mergeOptions);
181
+ const styledExportOptions = getStyledExportOptions(styleOptions);
182
+ const styledXLSXModule = styledExportOptions.enabled
183
+ ? await import("xlsx-js-style")
184
+ : null;
185
+ const XLSX = styledXLSXModule?.default || styledXLSXModule || LegacyXLSX;
186
+ const sourceJson = styledExportOptions.enabled
187
+ ? json.map((item) => ({ ...item }))
188
+ : null;
189
+ //导出xlsx
190
+ json.forEach((item) => {
60
191
  for (let i in item) {
61
192
  // eslint-disable-next-line no-prototype-builtins
62
193
  if (fields.hasOwnProperty(i)) {
@@ -65,14 +196,33 @@ export function xlsx(json, fields, filename = ".xlsx", mergeOptions = {}) {
65
196
  delete item[i]; //删除原先的对象属性
66
197
  }
67
198
  });
68
- let sheetName = filename.replace(/[\\/?*[\]:]/g, "").slice(0, 31) || "Sheet1"; //excel的文件名称
69
- let wb = XLSX.utils.book_new(); //工作簿对象包含一SheetNames数组,以及一个表对象映射表名称到表对象。XLSX.utils.book_new实用函数创建一个新的工作簿对象。
70
- let ws = XLSX.utils.json_to_sheet(json, { header: Object.values(fields) }); //将JS对象数组转换为工作表。
71
- if (merges.length) {
72
- ws["!merges"] = merges;
73
- }
74
- wb.SheetNames.push(sheetName);
75
- wb.Sheets[sheetName] = ws;
199
+ let wb = XLSX.utils.book_new(); //工作簿对象包含一SheetNames数组,以及一个表对象映射表名称到表对象。XLSX.utils.book_new实用函数创建一个新的工作簿对象。
200
+ let ws = XLSX.utils.json_to_sheet(json, { header: Object.values(fields) }); //将JS对象数组转换为工作表。
201
+ if (merges.length) {
202
+ ws["!merges"] = merges;
203
+ }
204
+ if (styledExportOptions.enabled) {
205
+ applyStyledExport(XLSX, ws, sourceJson, fields, styledExportOptions);
206
+ }
207
+ return { XLSX, wb, ws };
208
+ }
209
+
210
+ export async function xlsx(
211
+ json,
212
+ fields,
213
+ filename = ".xlsx",
214
+ mergeOptions = {},
215
+ styleOptions = {}
216
+ ) {
217
+ const { XLSX, wb, ws } = await createWorkbook(
218
+ json,
219
+ fields,
220
+ mergeOptions,
221
+ styleOptions
222
+ );
223
+ const sheetName = filename.replace(/[\\/?*[\]:]/g, "").slice(0, 31) || "Sheet1"; //excel的文件名称
224
+ wb.SheetNames.push(sheetName);
225
+ wb.Sheets[sheetName] = ws;
76
226
  const defaultCellStyle = {
77
227
  font: { name: "Verdana", sz: 13, color: "FF00FF88" },
78
228
  fill: { fgColor: { rgb: "FFFFAA00" } },
@@ -67,10 +67,14 @@ export default defineComponent({
67
67
  type: Object,
68
68
  default: () => ({})
69
69
  },
70
- merge_options: { //导出表格纵向合并配置
71
- type: Object,
72
- default: () => ({})
73
- },
70
+ merge_options: { //导出表格纵向合并配置
71
+ type: Object,
72
+ default: () => ({})
73
+ },
74
+ style_options: { //导出表格样式配置
75
+ type: Object,
76
+ default: () => ({})
77
+ },
74
78
  custom_result: { //导出表格头部
75
79
  type: Object,
76
80
  // eslint-disable-next-line vue/require-valid-default-prop
@@ -125,9 +129,9 @@ export default defineComponent({
125
129
  context.emit("customDataFunc" , state.ExportList)
126
130
  }else {
127
131
  console.log('导出文档')
128
- setTimeout(() => {
129
- let list = utils.deepClone(state.ExportList);
130
- xlsx(list, removeUndefined(props.columnstitle), props.title, props.merge_options);
132
+ setTimeout(async () => {
133
+ let list = utils.deepClone(state.ExportList);
134
+ await xlsx(list, removeUndefined(props.columnstitle), props.title, props.merge_options, props.style_options);
131
135
  context.emit("success", t('ExportComponents.index.921182-2'));
132
136
  closeModal()
133
137
  }, 200);
@@ -142,9 +146,9 @@ export default defineComponent({
142
146
  context.emit("customDataFunc" , state.ExportList)
143
147
  }else {
144
148
  console.log('导出文档')
145
- setTimeout(() => {
146
- let list = utils.deepClone(state.ExportList);
147
- xlsx(list, removeUndefined(props.columnstitle), props.title, props.merge_options);
149
+ setTimeout(async () => {
150
+ let list = utils.deepClone(state.ExportList);
151
+ await xlsx(list, removeUndefined(props.columnstitle), props.title, props.merge_options, props.style_options);
148
152
  context.emit("success", t('ExportComponents.index.921182-2'));
149
153
  closeModal()
150
154
  }, 200);
@@ -162,9 +166,9 @@ export default defineComponent({
162
166
  watch(
163
167
  () => props.custom_result,
164
168
  (val) => {
165
- setTimeout(() => {
166
- let list = utils.deepClone(val);
167
- xlsx(list, removeUndefined(props.columnstitle), props.title, props.merge_options);
169
+ setTimeout(async () => {
170
+ let list = utils.deepClone(val);
171
+ await xlsx(list, removeUndefined(props.columnstitle), props.title, props.merge_options, props.style_options);
168
172
  context.emit("success", t('ExportComponents.index.921182-2'));
169
173
  closeModal()
170
174
  }, 200);