@aggbond/my-file-preview-mobile 1.0.1 → 1.0.3
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/README.md +271 -0
- package/dist/ReadFilePopupMobile.es.js +607 -0
- package/dist/ReadFilePopupMobile.es.min.js +2 -3
- package/dist/ReadFilePopupMobile.umd.js +609 -0
- package/dist/ReadFilePopupMobile.umd.min.js +2 -2
- package/package.json +8 -3
- package/src/ReadFilePopupMobile.js +728 -728
- package/src/ReadFilePopupMobile.ts +783 -783
|
@@ -1,784 +1,784 @@
|
|
|
1
|
-
// ReadFilePopupMobile.ts
|
|
2
|
-
import Popup from "@aggbond/my-popup";
|
|
3
|
-
|
|
4
|
-
interface FileObject {
|
|
5
|
-
name: string;
|
|
6
|
-
file_type: number;
|
|
7
|
-
pdf_url: string;
|
|
8
|
-
content_text: string;
|
|
9
|
-
com_terms?: FileObject[];
|
|
10
|
-
styleStr?: Record<string, string>;
|
|
11
|
-
divType?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface ListObject {
|
|
15
|
-
listId: string;
|
|
16
|
-
fileList: FileObject[];
|
|
17
|
-
fileStyle?: Record<string, string>;
|
|
18
|
-
isCheckButton?: boolean;
|
|
19
|
-
isCoerceReadPopup?: boolean;
|
|
20
|
-
checkCallBack?: (isChecked: boolean) => void;
|
|
21
|
-
listText?: string;
|
|
22
|
-
checkButtonID?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface CoerceReadList {
|
|
26
|
-
titleText?: string;
|
|
27
|
-
fileList: FileObject[];
|
|
28
|
-
fileStyle?: Record<string, string>;
|
|
29
|
-
btnArr?: string[];
|
|
30
|
-
btnStyle?: Record<string, string>[];
|
|
31
|
-
btnBoxStyle?: Record<string, string>;
|
|
32
|
-
showProgressInButton?: boolean | number;
|
|
33
|
-
coerceCallBack?: ((control: ControlObject, buttonIndex: number) => void) | ((control: ControlObject) => void)[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface ConfigOptions {
|
|
37
|
-
basePath?: string;
|
|
38
|
-
modalId?: string;
|
|
39
|
-
contentId?: string;
|
|
40
|
-
closeBtnId?: string;
|
|
41
|
-
fileTypes?: Record<string, string>;
|
|
42
|
-
fileKeyNameConfign?: {
|
|
43
|
-
fileTitle: string;
|
|
44
|
-
fileType: string;
|
|
45
|
-
filePdfUrl: string;
|
|
46
|
-
fileRichContent: string;
|
|
47
|
-
fileArr: string;
|
|
48
|
-
};
|
|
49
|
-
isConfignFileKeyName?: boolean;
|
|
50
|
-
isDrawFileList?: boolean;
|
|
51
|
-
listObj?: ListObject;
|
|
52
|
-
coerceReadList?: CoerceReadList;
|
|
53
|
-
isBindFileClick?: boolean;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
interface ControlObject {
|
|
57
|
-
next: () => void;
|
|
58
|
-
prev: () => void;
|
|
59
|
-
close: () => void;
|
|
60
|
-
getCurrentIndex: () => number;
|
|
61
|
-
getFileList: () => FileObject[];
|
|
62
|
-
isLastFile: () => boolean;
|
|
63
|
-
setButtonTitles: (titles: string[]) => void;
|
|
64
|
-
getVisitedIndices: () => number[];
|
|
65
|
-
goTo: (index: number) => void;
|
|
66
|
-
setCheckboxChecked: (isChecked: boolean) => void;
|
|
67
|
-
isCheckboxChecked: () => boolean;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const myPopup = new Popup();
|
|
71
|
-
|
|
72
|
-
// 文件预览插件
|
|
73
|
-
class FilePreview {
|
|
74
|
-
Configns: Required<ConfigOptions> & {
|
|
75
|
-
listObj: Required<ListObject>;
|
|
76
|
-
coerceReadList: Required<CoerceReadList>;
|
|
77
|
-
fileKeyNameConfign: NonNullable<ConfigOptions['fileKeyNameConfign']>;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
constructor(options: ConfigOptions) {
|
|
81
|
-
// 默认配置
|
|
82
|
-
this.Configns = Object.assign(
|
|
83
|
-
{
|
|
84
|
-
basePath: "/assets/pdfs/", // 文件基础路径
|
|
85
|
-
modalId: "filePreviewModal", // 模态框ID
|
|
86
|
-
contentId: "filePreviewContent", // 内容容器ID
|
|
87
|
-
closeBtnId: "filePreviewCloseBtn", // 关闭按钮ID
|
|
88
|
-
fileTypes: {
|
|
89
|
-
// 支持的文件类型
|
|
90
|
-
pdf: "application/pdf",
|
|
91
|
-
txt: "text/plain",
|
|
92
|
-
html: "text/html",
|
|
93
|
-
"1": "richTextFile", // 富文本
|
|
94
|
-
"2": "choosePdfFile", // pdf
|
|
95
|
-
"3": "quotePdfFile", // 引用文本
|
|
96
|
-
// 可以扩展更多类型
|
|
97
|
-
},
|
|
98
|
-
fileKeyNameConfign: {
|
|
99
|
-
// 配置文件键值key 免于不同格式的数据转换 isConfignFileKeyName 为true,则fielKeyNameConfign为required;
|
|
100
|
-
fileTitle: "name", //标题
|
|
101
|
-
fileType: "doc_type", // 文件类型 1 富文本 2 pdf 3 引用文本,引用文本通常有多份
|
|
102
|
-
filePdfUrl: "pdf_url", // pdf地址 绝对路径
|
|
103
|
-
fileRichContent: "content_text", // 富文本内容
|
|
104
|
-
fileArr: "com_terms", // 可以扩展更多类型
|
|
105
|
-
},
|
|
106
|
-
isConfignFileKeyName: false, // 是否需要转换文件key 默认为false
|
|
107
|
-
isDrawFileList: false, // 是否需要绘制阅读文件列表
|
|
108
|
-
listObj: {
|
|
109
|
-
listId: "", // 列表容器ID require
|
|
110
|
-
fileList: [
|
|
111
|
-
// 文件列表 require
|
|
112
|
-
{
|
|
113
|
-
name: "默认标题", //标题
|
|
114
|
-
file_type: 3, // 文件类型 1 富文本 2 pdf 3 引用文本,引用文本通常有多份
|
|
115
|
-
pdf_url: "", // pdf地址 绝对路径
|
|
116
|
-
content_text: "", // 富文本内容
|
|
117
|
-
com_terms: [
|
|
118
|
-
// 多份文件
|
|
119
|
-
{
|
|
120
|
-
name: "默认标题", //标题
|
|
121
|
-
pdf_url: "clause_pdf: https://showFile.com/address.pdf", // pdf地址
|
|
122
|
-
content_text: "disclaimer<p><strong>默认文件</strong></p>", // 富文本内容
|
|
123
|
-
},
|
|
124
|
-
],
|
|
125
|
-
styleStr: {
|
|
126
|
-
color: "red",
|
|
127
|
-
"font-weight": "bold",
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
],
|
|
131
|
-
fileStyle: {
|
|
132
|
-
color: "red",
|
|
133
|
-
"font-weight": "bold",
|
|
134
|
-
}, // 文件样式span
|
|
135
|
-
isCheckButton: false, // 列表是否需要复选框
|
|
136
|
-
isCoerceReadPopup: true, // 是否强制阅读弹窗
|
|
137
|
-
checkCallBack: (isChecked: boolean) => {
|
|
138
|
-
console.log("复选框状态改变:", isChecked);
|
|
139
|
-
}, // 复选框回调函数
|
|
140
|
-
listText: "更多详情请阅读",
|
|
141
|
-
checkButtonID: "ReadFileCheckBox",
|
|
142
|
-
},
|
|
143
|
-
// 强制阅读弹窗参数
|
|
144
|
-
coerceReadList: {
|
|
145
|
-
titleText: "请阅读并同意以下文件",
|
|
146
|
-
fileList: [
|
|
147
|
-
// 文件列表 require
|
|
148
|
-
{
|
|
149
|
-
name: "默认标题", //标题
|
|
150
|
-
file_type: 3, // 文件类型 1 富文本 2 pdf 3 引用文本,引用文本通常有多份
|
|
151
|
-
pdf_url: "", // pdf地址 绝对路径
|
|
152
|
-
content_text: "", // 富文本内容
|
|
153
|
-
com_terms: [
|
|
154
|
-
// 多份文件
|
|
155
|
-
{
|
|
156
|
-
name: "默认标题", //标题
|
|
157
|
-
pdf_url: "clause_pdf: https://showFile.com/address.pdf", // pdf地址
|
|
158
|
-
content_text: "disclaimer<p><strong>默认文件</strong></p>", // 富文本内容
|
|
159
|
-
},
|
|
160
|
-
],
|
|
161
|
-
styleStr: {
|
|
162
|
-
color: "red",
|
|
163
|
-
"font-weight": "bold",
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
],
|
|
167
|
-
fileStyle: {
|
|
168
|
-
color: "red",
|
|
169
|
-
"font-weight": "bold",
|
|
170
|
-
},
|
|
171
|
-
btnArr: ["确认已阅读并同意", "拒绝"],
|
|
172
|
-
btnStyle: [{ color: "red" }, { color: "gray" }],
|
|
173
|
-
btnBoxStyle: {},
|
|
174
|
-
showProgressInButton: false,
|
|
175
|
-
coerceCallBack: [
|
|
176
|
-
(control: ControlObject, buttonIndex: number) => {
|
|
177
|
-
console.log("btn[0]强制阅读弹窗结果:", control, buttonIndex);
|
|
178
|
-
},
|
|
179
|
-
(control: ControlObject, buttonIndex: number) => {
|
|
180
|
-
console.log("btn[1]强制阅读弹窗结果:", control, buttonIndex);
|
|
181
|
-
},
|
|
182
|
-
],
|
|
183
|
-
},
|
|
184
|
-
isBindFileClick: false, // 是否需要绑定文件点击事件
|
|
185
|
-
},
|
|
186
|
-
options
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
// 初始化模态框
|
|
190
|
-
this.initModal();
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 初始化
|
|
194
|
-
initModal(): void {
|
|
195
|
-
const {
|
|
196
|
-
isDrawFileList,
|
|
197
|
-
listObj,
|
|
198
|
-
isBindFileClick,
|
|
199
|
-
isConfignFileKeyName,
|
|
200
|
-
coerceReadList,
|
|
201
|
-
} = this.Configns;
|
|
202
|
-
|
|
203
|
-
if (
|
|
204
|
-
isConfignFileKeyName &&
|
|
205
|
-
listObj.fileList &&
|
|
206
|
-
listObj.fileList.length > 0
|
|
207
|
-
) {
|
|
208
|
-
this.Configns.listObj.fileList = this.dataChange(listObj.fileList);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (coerceReadList.fileList && coerceReadList.fileList.length > 0) {
|
|
212
|
-
this.Configns.coerceReadList.fileList = this.dataChange(
|
|
213
|
-
coerceReadList.fileList
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
isDrawFileList && this.drawReadFileList(listObj);
|
|
218
|
-
isBindFileClick && this.bindFileClick(listObj.listId, undefined);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// 数据转换
|
|
222
|
-
dataChange(data: any[]): FileObject[] {
|
|
223
|
-
if (!this.Configns.fileKeyNameConfign)
|
|
224
|
-
throw new Error("请传入文件keyNameConfign");
|
|
225
|
-
|
|
226
|
-
const { fileTitle, filePdfUrl, fileRichContent, fileArr, fileType } =
|
|
227
|
-
this.Configns.fileKeyNameConfign;
|
|
228
|
-
|
|
229
|
-
if (!fileTitle || !filePdfUrl || !fileRichContent || !fileArr)
|
|
230
|
-
throw new Error("请传入文件keyNameConfign的参数");
|
|
231
|
-
|
|
232
|
-
data.forEach((item) => {
|
|
233
|
-
item.name = item[fileTitle];
|
|
234
|
-
item.file_type = item[fileType];
|
|
235
|
-
item.pdf_url = item[filePdfUrl];
|
|
236
|
-
item.content_text = item[fileRichContent];
|
|
237
|
-
item.com_terms = item[fileArr];
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
return data as FileObject[];
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
//渲染阅读文件列表
|
|
244
|
-
drawReadFileList(listObj: ListObject): void {
|
|
245
|
-
const {
|
|
246
|
-
listId: ID,
|
|
247
|
-
fileList,
|
|
248
|
-
isCheckButton,
|
|
249
|
-
isCoerceReadPopup,
|
|
250
|
-
checkCallBack,
|
|
251
|
-
listText,
|
|
252
|
-
checkButtonID,
|
|
253
|
-
fileStyle,
|
|
254
|
-
} = listObj;
|
|
255
|
-
|
|
256
|
-
if (!ID) throw new Error("请传入需要添加的dom ID");
|
|
257
|
-
if (fileList.length < 1) throw new Error("请传入需要渲染的文件数据");
|
|
258
|
-
|
|
259
|
-
let html = `${isCheckButton ? `<input type="checkbox" id="${checkButtonID}" />` : ""
|
|
260
|
-
}${listText}`;
|
|
261
|
-
|
|
262
|
-
for (let i = 0, len = fileList.length; i < len; i++) {
|
|
263
|
-
const { name, pdf_url, file_type, styleStr } = fileList[i];
|
|
264
|
-
const type =
|
|
265
|
-
file_type ||
|
|
266
|
-
this.judgeFileType({ type: "", file: fileList[i], index: i });
|
|
267
|
-
|
|
268
|
-
html += `<span class="pdfsee item-contract" data-pdf="${file_type == 2 ? pdf_url : ""
|
|
269
|
-
}" data-title="${name}" data-index="${i}" data-type="${type}" style="${this.objToStr(
|
|
270
|
-
styleStr ? styleStr : fileStyle || {}
|
|
271
|
-
)}">${name}</span>`;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const element = document.querySelector(ID);
|
|
275
|
-
if (!element) throw new Error("未找到元素" + ID);
|
|
276
|
-
element.insertAdjacentHTML("beforeend", html);
|
|
277
|
-
|
|
278
|
-
if (isCheckButton && checkButtonID) {
|
|
279
|
-
const inputBox = document.getElementById(checkButtonID);
|
|
280
|
-
|
|
281
|
-
if (inputBox) {
|
|
282
|
-
inputBox.addEventListener("click", (e) => {
|
|
283
|
-
const target = e.target as HTMLInputElement;
|
|
284
|
-
const isChecked = target.checked;
|
|
285
|
-
|
|
286
|
-
checkCallBack && checkCallBack(isChecked);
|
|
287
|
-
|
|
288
|
-
isChecked && isCoerceReadPopup && this.openCoerceReadPopup();
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// 对象转换为字符串
|
|
295
|
-
objToStr(obj: Record<string, string>): string {
|
|
296
|
-
return Object.entries(obj).reduce(
|
|
297
|
-
(str, [key, value]) => `${str}${key}:${value};`,
|
|
298
|
-
""
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// 判断文件格式
|
|
303
|
-
judgeFileType(
|
|
304
|
-
params: {
|
|
305
|
-
type: string | number;
|
|
306
|
-
file?: FileObject;
|
|
307
|
-
index?: number;
|
|
308
|
-
fromChooseList?: boolean;
|
|
309
|
-
isCoerce?: boolean;
|
|
310
|
-
}
|
|
311
|
-
): number | string | void {
|
|
312
|
-
const { type, file, index, fromChooseList = false, isCoerce = false } = params;
|
|
313
|
-
if (!file) throw new Error("未找到对应文件信息 file is not defined");
|
|
314
|
-
let html;
|
|
315
|
-
switch (type) {
|
|
316
|
-
case "1":
|
|
317
|
-
case 1:
|
|
318
|
-
html = this.richTextFile({ file, fromChooseList, isCoerce });
|
|
319
|
-
break;
|
|
320
|
-
case "2":
|
|
321
|
-
case 2:
|
|
322
|
-
html = this.quotePdfFile({ file, fromChooseList, isCoerce });
|
|
323
|
-
break;
|
|
324
|
-
case "3":
|
|
325
|
-
case 3:
|
|
326
|
-
html = this.choosePdfFile({ file, index, fromChooseList, isCoerce });
|
|
327
|
-
break;
|
|
328
|
-
default:
|
|
329
|
-
const { com_terms, content_text, pdf_url } = file;
|
|
330
|
-
if (com_terms && com_terms.length > 0) {
|
|
331
|
-
return 3;
|
|
332
|
-
} else if (content_text) {
|
|
333
|
-
return 1;
|
|
334
|
-
} else if (pdf_url) {
|
|
335
|
-
return 2;
|
|
336
|
-
}
|
|
337
|
-
break;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
if (isCoerce) return html;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// 富文本文件
|
|
344
|
-
richTextFile(params: {
|
|
345
|
-
file: FileObject;
|
|
346
|
-
fromChooseList?: boolean;
|
|
347
|
-
isCoerce?: boolean;
|
|
348
|
-
}): string | void {
|
|
349
|
-
const { file: filebox, fromChooseList = false, isCoerce = false } = params;
|
|
350
|
-
const { name: title, content_text: text } = filebox;
|
|
351
|
-
const popupInstance = fromChooseList ? new Popup() : myPopup;
|
|
352
|
-
|
|
353
|
-
if (isCoerce) return text;
|
|
354
|
-
|
|
355
|
-
popupInstance.showBottomPopup({
|
|
356
|
-
title: title,
|
|
357
|
-
content: text,
|
|
358
|
-
contentStyle: {},
|
|
359
|
-
titleStyle: {
|
|
360
|
-
fontWeight: "bold",
|
|
361
|
-
},
|
|
362
|
-
// btns: ['确定'],
|
|
363
|
-
callbacks: [function () {
|
|
364
|
-
console.log("richTextFile callbacks");
|
|
365
|
-
}],
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// 多分pdf选择
|
|
370
|
-
choosePdfFile(params: {
|
|
371
|
-
file: FileObject;
|
|
372
|
-
index?: number;
|
|
373
|
-
fromChooseList?: boolean;
|
|
374
|
-
isCoerce?: boolean;
|
|
375
|
-
}): string | void {
|
|
376
|
-
const { file: filebox, index: _index, fromChooseList = false, isCoerce = false } = params;
|
|
377
|
-
console.log("filebox", filebox);
|
|
378
|
-
|
|
379
|
-
const { com_terms: fileArr = [], name: title } = filebox;
|
|
380
|
-
const popupInstance = fromChooseList ? new Popup() : myPopup;
|
|
381
|
-
|
|
382
|
-
let html = "<dl class='ChoosePdfFileList' style='margin:0;padding:0;'>";
|
|
383
|
-
|
|
384
|
-
for (let i = 0; i < fileArr.length; i++) {
|
|
385
|
-
const { pdf_url, name, file_type } = fileArr[i];
|
|
386
|
-
const type =
|
|
387
|
-
file_type ||
|
|
388
|
-
this.judgeFileType({ type: "", file: fileArr[i], index: i });
|
|
389
|
-
|
|
390
|
-
html += `<dd class="cl" data-pdf="${pdf_url}" data-title="${name}" data-index="${i}" style="margin:0">
|
|
391
|
-
<span class="pdfsee item-contract" data-pdf="${pdf_url}" data-title="${name}" data-index="${i}" data-type="${type}">${name}</span>
|
|
392
|
-
</dd>`;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
html += "</dl>";
|
|
396
|
-
|
|
397
|
-
if (isCoerce) return html;
|
|
398
|
-
|
|
399
|
-
popupInstance.showBottomPopup({
|
|
400
|
-
title,
|
|
401
|
-
content: html,
|
|
402
|
-
contentStyle: {},
|
|
403
|
-
titleStyle: {
|
|
404
|
-
fontWeight: "bold",
|
|
405
|
-
},
|
|
406
|
-
// btns: ['确定'],
|
|
407
|
-
callbacks: [function () {
|
|
408
|
-
console.log("choosePDffile callbacks");
|
|
409
|
-
}],
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
this.bindFileClick(".ChoosePdfFileList", fileArr);
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// 引用条款 pdf文件
|
|
416
|
-
quotePdfFile(params: {
|
|
417
|
-
file: FileObject;
|
|
418
|
-
fromChooseList?: boolean;
|
|
419
|
-
isControl?: boolean;
|
|
420
|
-
isCoerce?: boolean;
|
|
421
|
-
}): string | void {
|
|
422
|
-
const { file: filebox, fromChooseList = false, isControl = false, isCoerce = false } = params;
|
|
423
|
-
const { pdf_url: url, name: title, divType = "iframe" } = filebox;
|
|
424
|
-
|
|
425
|
-
// 如果来自选择列表,创建新实例
|
|
426
|
-
const popupInstance = fromChooseList ? new Popup() : myPopup;
|
|
427
|
-
|
|
428
|
-
// 添加参数尝试禁用工具栏
|
|
429
|
-
const modifiedUrl = isControl
|
|
430
|
-
? url
|
|
431
|
-
: `${url}#toolbar=0&navpanes=0&scrollbar=0`;
|
|
432
|
-
|
|
433
|
-
const iframeHtml = `<iframe src="${modifiedUrl}" width="100%" height="800" style="border:none;"></iframe>`;
|
|
434
|
-
const objectHtml = `<object data="${modifiedUrl}" type="application/pdf" width="100%" height="800">
|
|
435
|
-
<p>您的浏览器不支持PDF查看。请<a href="${modifiedUrl}">下载文件</a>。</p></object>`;
|
|
436
|
-
const embedHtml = `<embed src="${modifiedUrl}" type="application/pdf" width="100%" height="800" />`;
|
|
437
|
-
|
|
438
|
-
const html =
|
|
439
|
-
divType === "iframe"
|
|
440
|
-
? iframeHtml
|
|
441
|
-
: divType === "object"
|
|
442
|
-
? objectHtml
|
|
443
|
-
: embedHtml;
|
|
444
|
-
|
|
445
|
-
if (isCoerce) return html;
|
|
446
|
-
|
|
447
|
-
popupInstance.showBottomPopup({
|
|
448
|
-
title: title,
|
|
449
|
-
content: html,
|
|
450
|
-
contentStyle: {
|
|
451
|
-
// maxHeight: '100vh',
|
|
452
|
-
// overflow: 'hidden auto'
|
|
453
|
-
padding: "0",
|
|
454
|
-
},
|
|
455
|
-
contentBoxStyle: {
|
|
456
|
-
maxHeight: "100vh",
|
|
457
|
-
},
|
|
458
|
-
titleStyle: {
|
|
459
|
-
fontWeight: "bold",
|
|
460
|
-
},
|
|
461
|
-
callbacks: [function () {
|
|
462
|
-
console.log("quotePdfFile callback");
|
|
463
|
-
}],
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// 绑定文件点击事件
|
|
470
|
-
bindFileClick(containerSelector: string, fileArr?: FileObject[]): void {
|
|
471
|
-
const container = document.querySelector(containerSelector);
|
|
472
|
-
if (!container) throw new Error("容器未找到:" + containerSelector);
|
|
473
|
-
|
|
474
|
-
container.addEventListener("click", (event) => {
|
|
475
|
-
const target = event.target as HTMLElement;
|
|
476
|
-
if (target.tagName.toLowerCase() === "span") {
|
|
477
|
-
const dataset = target.dataset;
|
|
478
|
-
const type = dataset.type;
|
|
479
|
-
const index = dataset.index ? parseInt(dataset.index) : undefined;
|
|
480
|
-
|
|
481
|
-
if (index !== undefined) {
|
|
482
|
-
const file =
|
|
483
|
-
fileArr?.[index] || this.Configns?.listObj?.fileList?.[index];
|
|
484
|
-
|
|
485
|
-
console.log("read", index, type, file);
|
|
486
|
-
|
|
487
|
-
if (type !== undefined && file) {
|
|
488
|
-
this.judgeFileType({ type, file, index, fromChooseList: !!fileArr });
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// 渲染强制阅读文件内容
|
|
496
|
-
openCoerceReadPopup(): void {
|
|
497
|
-
const {
|
|
498
|
-
fileList,
|
|
499
|
-
btnArr = ["同意并继续"],
|
|
500
|
-
btnStyle,
|
|
501
|
-
btnBoxStyle,
|
|
502
|
-
coerceCallBack,
|
|
503
|
-
titleText,
|
|
504
|
-
showProgressInButton
|
|
505
|
-
} = this.Configns.coerceReadList;
|
|
506
|
-
|
|
507
|
-
if (fileList.length === 0) throw new Error("fileList不能为空");
|
|
508
|
-
|
|
509
|
-
let currentIndex = 0;
|
|
510
|
-
let customButtonTitles: string[] | null = null;
|
|
511
|
-
// 记录已访问的文件索引,用于判断是否可以返回
|
|
512
|
-
let visitedIndices = [0];
|
|
513
|
-
const showNextFile = (_btnTitleArr?: string[]) => {
|
|
514
|
-
if (currentIndex >= fileList.length) return;
|
|
515
|
-
|
|
516
|
-
const file = fileList[currentIndex];
|
|
517
|
-
const isLastFile = currentIndex === fileList.length - 1;
|
|
518
|
-
|
|
519
|
-
// 确保文件类型已设置
|
|
520
|
-
if (!file.file_type) {
|
|
521
|
-
file.file_type = this.judgeFileType({
|
|
522
|
-
type: "",
|
|
523
|
-
file,
|
|
524
|
-
isCoerce: true
|
|
525
|
-
}) as number;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
// 获取文件内容
|
|
529
|
-
const fileContent = this.judgeFileType({
|
|
530
|
-
type: file.file_type,
|
|
531
|
-
file,
|
|
532
|
-
isCoerce: true,
|
|
533
|
-
}) as string;
|
|
534
|
-
|
|
535
|
-
// 创建控制对象供外部回调使用
|
|
536
|
-
const control: ControlObject = {
|
|
537
|
-
next: () => {
|
|
538
|
-
// 下一份文件
|
|
539
|
-
// 重置自定义按钮文字状态
|
|
540
|
-
customButtonTitles = null;
|
|
541
|
-
currentIndex++;
|
|
542
|
-
// 记录访问过的索引
|
|
543
|
-
if (!visitedIndices.includes(currentIndex)) {
|
|
544
|
-
visitedIndices.push(currentIndex);
|
|
545
|
-
}
|
|
546
|
-
showNextFile();
|
|
547
|
-
},
|
|
548
|
-
prev: () => {
|
|
549
|
-
// 上一份文件
|
|
550
|
-
// 重置自定义按钮文字状态
|
|
551
|
-
customButtonTitles = null;
|
|
552
|
-
if (currentIndex > 0) {
|
|
553
|
-
currentIndex--;
|
|
554
|
-
showNextFile();
|
|
555
|
-
}
|
|
556
|
-
},
|
|
557
|
-
close: () => {
|
|
558
|
-
// 关闭弹窗
|
|
559
|
-
myPopup.close();
|
|
560
|
-
},
|
|
561
|
-
getCurrentIndex: () => currentIndex, // 获取当前索引
|
|
562
|
-
getFileList: () => [...fileList], // 返回副本防止外部修改
|
|
563
|
-
isLastFile: () => isLastFile, // 是否为最后一份文件
|
|
564
|
-
setButtonTitles: (titles) => {
|
|
565
|
-
// 允许外部修改按钮文字
|
|
566
|
-
if (Array.isArray(titles)) {
|
|
567
|
-
customButtonTitles = titles;
|
|
568
|
-
}
|
|
569
|
-
},
|
|
570
|
-
// 获取已访问的文件索引列表
|
|
571
|
-
getVisitedIndices: () => [...visitedIndices],
|
|
572
|
-
// 跳转到指定文件索引
|
|
573
|
-
goTo: (index) => {
|
|
574
|
-
if (index >= 0 && index < fileList.length) {
|
|
575
|
-
customButtonTitles = null;
|
|
576
|
-
currentIndex = index;
|
|
577
|
-
if (!visitedIndices.includes(currentIndex)) {
|
|
578
|
-
visitedIndices.push(currentIndex);
|
|
579
|
-
}
|
|
580
|
-
showNextFile();
|
|
581
|
-
}
|
|
582
|
-
},
|
|
583
|
-
// 控制复选框选中状态
|
|
584
|
-
setCheckboxChecked: (isChecked) => {
|
|
585
|
-
const checkboxId = this.Configns.listObj?.checkButtonID;
|
|
586
|
-
if (checkboxId) {
|
|
587
|
-
const checkbox = document.getElementById(checkboxId);
|
|
588
|
-
if (checkbox) {
|
|
589
|
-
(checkbox as HTMLInputElement).checked = isChecked;
|
|
590
|
-
// 触发change事件,确保相关回调被执行
|
|
591
|
-
const event = new Event("change");
|
|
592
|
-
checkbox.dispatchEvent(event);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
},
|
|
596
|
-
// 获取复选框当前状态
|
|
597
|
-
isCheckboxChecked: () => {
|
|
598
|
-
const checkboxId = this.Configns.listObj?.checkButtonID;
|
|
599
|
-
if (checkboxId) {
|
|
600
|
-
const checkbox = document.getElementById(checkboxId);
|
|
601
|
-
return checkbox ? (checkbox as HTMLInputElement).checked : false;
|
|
602
|
-
}
|
|
603
|
-
return false;
|
|
604
|
-
},
|
|
605
|
-
};
|
|
606
|
-
|
|
607
|
-
// 为每个按钮创建回调函数
|
|
608
|
-
const callbacks: (() => void)[] = [];
|
|
609
|
-
if (btnArr && btnArr.length > 0) {
|
|
610
|
-
for (let i = 0; i < btnArr.length; i++) {
|
|
611
|
-
callbacks.push(
|
|
612
|
-
((buttonIndex) => {
|
|
613
|
-
return () => {
|
|
614
|
-
if (typeof coerceCallBack === "function") {
|
|
615
|
-
return coerceCallBack(control, buttonIndex);
|
|
616
|
-
} else if (
|
|
617
|
-
Array.isArray(coerceCallBack) &&
|
|
618
|
-
typeof coerceCallBack[buttonIndex] === "function"
|
|
619
|
-
) {
|
|
620
|
-
return coerceCallBack[buttonIndex](control);
|
|
621
|
-
}
|
|
622
|
-
};
|
|
623
|
-
})(i)
|
|
624
|
-
);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
// 确定最终使用的按钮文字
|
|
629
|
-
let finalButtons = customButtonTitles || btnArr;
|
|
630
|
-
// 如果配置了显示进度且没有自定义按钮标题,则添加进度信息
|
|
631
|
-
if (showProgressInButton !== false && !customButtonTitles && btnArr && btnArr.length > 0) {
|
|
632
|
-
const currentDisplayIndex = currentIndex + 1; // 显示索引从1开始
|
|
633
|
-
const totalLength = fileList.length;
|
|
634
|
-
|
|
635
|
-
finalButtons = [...btnArr]; // 复制原始按钮数组
|
|
636
|
-
|
|
637
|
-
// 根据 showProgressInButton 的值决定在哪个按钮上添加进度信息
|
|
638
|
-
if (typeof showProgressInButton === 'number') {
|
|
639
|
-
// 如果是数字,表示按钮索引
|
|
640
|
-
const buttonIndex = showProgressInButton;
|
|
641
|
-
if (buttonIndex >= 0 && buttonIndex < finalButtons.length) {
|
|
642
|
-
finalButtons[buttonIndex] = `${btnArr[buttonIndex]}(${currentDisplayIndex}/${totalLength})`;
|
|
643
|
-
}
|
|
644
|
-
} else if (showProgressInButton === true) {
|
|
645
|
-
// 如果是 true,表示在第一个按钮上显示
|
|
646
|
-
finalButtons[0] = `${btnArr[0]}(${currentDisplayIndex}/${totalLength})`;
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
console.log("showNextFile", btnArr, finalButtons);
|
|
650
|
-
|
|
651
|
-
const popupConfig = {
|
|
652
|
-
title:
|
|
653
|
-
file.name ||
|
|
654
|
-
`${titleText || "文件"} (${currentIndex + 1}/${fileList.length})`,
|
|
655
|
-
content: fileContent,
|
|
656
|
-
btnBoxStyle: btnBoxStyle || {
|
|
657
|
-
display: "flex",
|
|
658
|
-
justifyContent: "space-around",
|
|
659
|
-
alignItems: "center",
|
|
660
|
-
padding: "0 2.4vw",
|
|
661
|
-
},
|
|
662
|
-
btns: finalButtons,
|
|
663
|
-
btnStyle: btnStyle || [
|
|
664
|
-
{
|
|
665
|
-
display: "inline-block",
|
|
666
|
-
width: "91vw",
|
|
667
|
-
height: "10.667vw",
|
|
668
|
-
color: "#fff",
|
|
669
|
-
backgroundColor: "#29AEEF",
|
|
670
|
-
borderRadius: "8.533vw",
|
|
671
|
-
textAlign: "center",
|
|
672
|
-
lineHeight: "10.667vw",
|
|
673
|
-
cursor: "pointer",
|
|
674
|
-
margin: "5.33vw auto",
|
|
675
|
-
},
|
|
676
|
-
{
|
|
677
|
-
display: "inline-block",
|
|
678
|
-
width: "91vw",
|
|
679
|
-
height: "10.667vw",
|
|
680
|
-
color: "#fff",
|
|
681
|
-
backgroundColor: "#29AEEF",
|
|
682
|
-
borderRadius: "8.533vw",
|
|
683
|
-
textAlign: "center",
|
|
684
|
-
lineHeight: "10.667vw",
|
|
685
|
-
cursor: "pointer",
|
|
686
|
-
margin: "5.33vw auto",
|
|
687
|
-
},
|
|
688
|
-
],
|
|
689
|
-
callbacks,
|
|
690
|
-
};
|
|
691
|
-
|
|
692
|
-
control.setCheckboxChecked(false);
|
|
693
|
-
|
|
694
|
-
myPopup.showBottomPopup(popupConfig);
|
|
695
|
-
|
|
696
|
-
if (file.file_type === 3 && file.com_terms) {
|
|
697
|
-
this.bindFileClick(".ChoosePdfFileList", file.com_terms);
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
|
|
701
|
-
showNextFile();
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// 加载文件内容
|
|
705
|
-
loadFile(filePath: string): void {
|
|
706
|
-
const fileExtension = filePath.split(".").pop()?.toLowerCase();
|
|
707
|
-
if (!fileExtension) {
|
|
708
|
-
console.error("无法识别文件类型:", filePath);
|
|
709
|
-
return;
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
const contentType = this.Configns.fileTypes[fileExtension];
|
|
713
|
-
|
|
714
|
-
if (!contentType) {
|
|
715
|
-
console.error("不支持的文件类型:", fileExtension);
|
|
716
|
-
return;
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
const fileName = filePath.split("/").pop() || "文件";
|
|
720
|
-
|
|
721
|
-
if (contentType === "application/pdf") {
|
|
722
|
-
// 对于PDF文件,直接使用iframe,避免CORS问题
|
|
723
|
-
myPopup.showBottomPopup({
|
|
724
|
-
title: fileName,
|
|
725
|
-
content: `<iframe src="${filePath}" width="100%" height="600px" style="border:none;"></iframe>`,
|
|
726
|
-
contentStyle: {},
|
|
727
|
-
titleStyle: {
|
|
728
|
-
fontWeight: "bold",
|
|
729
|
-
},
|
|
730
|
-
// btns: ['确定'],
|
|
731
|
-
callbacks: [function () {
|
|
732
|
-
console.log("loadFile callback");
|
|
733
|
-
}],
|
|
734
|
-
});
|
|
735
|
-
} else {
|
|
736
|
-
// 对于其他文件类型,仍然使用fetch
|
|
737
|
-
fetch(filePath)
|
|
738
|
-
.then((response) => {
|
|
739
|
-
if (!response.ok) {
|
|
740
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
741
|
-
}
|
|
742
|
-
return response.text();
|
|
743
|
-
})
|
|
744
|
-
.then((data) => {
|
|
745
|
-
// 根据文件类型决定展示方式
|
|
746
|
-
let content: string;
|
|
747
|
-
if (fileExtension === 'html' || fileExtension === 'htm') {
|
|
748
|
-
// 对于HTML文件,直接显示(但需要注意安全问题)
|
|
749
|
-
content = `<div style="max-height: 70vh; overflow-y: auto;">${data}</div>`;
|
|
750
|
-
} else {
|
|
751
|
-
// 对于文本文件,使用<pre>标签保持格式
|
|
752
|
-
content = `<pre style="white-space: pre-wrap; word-wrap: break-word; max-height: 70vh; overflow-y: auto;">${data}</pre>`;
|
|
753
|
-
}
|
|
754
|
-
myPopup.showBottomPopup({
|
|
755
|
-
title: fileName,
|
|
756
|
-
content: content,
|
|
757
|
-
contentStyle: {
|
|
758
|
-
maxHeight: "70vh",
|
|
759
|
-
overflow: "auto",
|
|
760
|
-
},
|
|
761
|
-
titleStyle: {
|
|
762
|
-
fontWeight: "bold",
|
|
763
|
-
},
|
|
764
|
-
callbacks: [function () {
|
|
765
|
-
console.log("文件内容弹窗关闭");
|
|
766
|
-
}],
|
|
767
|
-
});
|
|
768
|
-
})
|
|
769
|
-
.catch((error) => {
|
|
770
|
-
console.error("文件加载失败:", error);
|
|
771
|
-
// 显示错误信息在弹窗中
|
|
772
|
-
myPopup.showBottomPopup({
|
|
773
|
-
title: "文件加载失败",
|
|
774
|
-
content: `<p style="color: red;">无法加载文件: ${filePath}</p><p>错误详情: ${error.message}</p>`,
|
|
775
|
-
callbacks: [function () {
|
|
776
|
-
console.log("错误提示弹窗关闭");
|
|
777
|
-
}],
|
|
778
|
-
});
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
|
|
1
|
+
// ReadFilePopupMobile.ts
|
|
2
|
+
import Popup from "@aggbond/my-popup";
|
|
3
|
+
|
|
4
|
+
interface FileObject {
|
|
5
|
+
name: string;
|
|
6
|
+
file_type: number;
|
|
7
|
+
pdf_url: string;
|
|
8
|
+
content_text: string;
|
|
9
|
+
com_terms?: FileObject[];
|
|
10
|
+
styleStr?: Record<string, string>;
|
|
11
|
+
divType?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ListObject {
|
|
15
|
+
listId: string;
|
|
16
|
+
fileList: FileObject[];
|
|
17
|
+
fileStyle?: Record<string, string>;
|
|
18
|
+
isCheckButton?: boolean;
|
|
19
|
+
isCoerceReadPopup?: boolean;
|
|
20
|
+
checkCallBack?: (isChecked: boolean) => void;
|
|
21
|
+
listText?: string;
|
|
22
|
+
checkButtonID?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
interface CoerceReadList {
|
|
26
|
+
titleText?: string;
|
|
27
|
+
fileList: FileObject[];
|
|
28
|
+
fileStyle?: Record<string, string>;
|
|
29
|
+
btnArr?: string[];
|
|
30
|
+
btnStyle?: Record<string, string>[];
|
|
31
|
+
btnBoxStyle?: Record<string, string>;
|
|
32
|
+
showProgressInButton?: boolean | number;
|
|
33
|
+
coerceCallBack?: ((control: ControlObject, buttonIndex: number) => void) | ((control: ControlObject) => void)[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface ConfigOptions {
|
|
37
|
+
basePath?: string;
|
|
38
|
+
modalId?: string;
|
|
39
|
+
contentId?: string;
|
|
40
|
+
closeBtnId?: string;
|
|
41
|
+
fileTypes?: Record<string, string>;
|
|
42
|
+
fileKeyNameConfign?: {
|
|
43
|
+
fileTitle: string;
|
|
44
|
+
fileType: string;
|
|
45
|
+
filePdfUrl: string;
|
|
46
|
+
fileRichContent: string;
|
|
47
|
+
fileArr: string;
|
|
48
|
+
};
|
|
49
|
+
isConfignFileKeyName?: boolean;
|
|
50
|
+
isDrawFileList?: boolean;
|
|
51
|
+
listObj?: ListObject;
|
|
52
|
+
coerceReadList?: CoerceReadList;
|
|
53
|
+
isBindFileClick?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface ControlObject {
|
|
57
|
+
next: () => void;
|
|
58
|
+
prev: () => void;
|
|
59
|
+
close: () => void;
|
|
60
|
+
getCurrentIndex: () => number;
|
|
61
|
+
getFileList: () => FileObject[];
|
|
62
|
+
isLastFile: () => boolean;
|
|
63
|
+
setButtonTitles: (titles: string[]) => void;
|
|
64
|
+
getVisitedIndices: () => number[];
|
|
65
|
+
goTo: (index: number) => void;
|
|
66
|
+
setCheckboxChecked: (isChecked: boolean) => void;
|
|
67
|
+
isCheckboxChecked: () => boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const myPopup = new Popup();
|
|
71
|
+
|
|
72
|
+
// 文件预览插件
|
|
73
|
+
class FilePreview {
|
|
74
|
+
Configns: Required<ConfigOptions> & {
|
|
75
|
+
listObj: Required<ListObject>;
|
|
76
|
+
coerceReadList: Required<CoerceReadList>;
|
|
77
|
+
fileKeyNameConfign: NonNullable<ConfigOptions['fileKeyNameConfign']>;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
constructor(options: ConfigOptions) {
|
|
81
|
+
// 默认配置
|
|
82
|
+
this.Configns = Object.assign(
|
|
83
|
+
{
|
|
84
|
+
basePath: "/assets/pdfs/", // 文件基础路径
|
|
85
|
+
modalId: "filePreviewModal", // 模态框ID
|
|
86
|
+
contentId: "filePreviewContent", // 内容容器ID
|
|
87
|
+
closeBtnId: "filePreviewCloseBtn", // 关闭按钮ID
|
|
88
|
+
fileTypes: {
|
|
89
|
+
// 支持的文件类型
|
|
90
|
+
pdf: "application/pdf",
|
|
91
|
+
txt: "text/plain",
|
|
92
|
+
html: "text/html",
|
|
93
|
+
"1": "richTextFile", // 富文本
|
|
94
|
+
"2": "choosePdfFile", // pdf
|
|
95
|
+
"3": "quotePdfFile", // 引用文本
|
|
96
|
+
// 可以扩展更多类型
|
|
97
|
+
},
|
|
98
|
+
fileKeyNameConfign: {
|
|
99
|
+
// 配置文件键值key 免于不同格式的数据转换 isConfignFileKeyName 为true,则fielKeyNameConfign为required;
|
|
100
|
+
fileTitle: "name", //标题
|
|
101
|
+
fileType: "doc_type", // 文件类型 1 富文本 2 pdf 3 引用文本,引用文本通常有多份
|
|
102
|
+
filePdfUrl: "pdf_url", // pdf地址 绝对路径
|
|
103
|
+
fileRichContent: "content_text", // 富文本内容
|
|
104
|
+
fileArr: "com_terms", // 可以扩展更多类型
|
|
105
|
+
},
|
|
106
|
+
isConfignFileKeyName: false, // 是否需要转换文件key 默认为false
|
|
107
|
+
isDrawFileList: false, // 是否需要绘制阅读文件列表
|
|
108
|
+
listObj: {
|
|
109
|
+
listId: "", // 列表容器ID require
|
|
110
|
+
fileList: [
|
|
111
|
+
// 文件列表 require
|
|
112
|
+
{
|
|
113
|
+
name: "默认标题", //标题
|
|
114
|
+
file_type: 3, // 文件类型 1 富文本 2 pdf 3 引用文本,引用文本通常有多份
|
|
115
|
+
pdf_url: "", // pdf地址 绝对路径
|
|
116
|
+
content_text: "", // 富文本内容
|
|
117
|
+
com_terms: [
|
|
118
|
+
// 多份文件
|
|
119
|
+
{
|
|
120
|
+
name: "默认标题", //标题
|
|
121
|
+
pdf_url: "clause_pdf: https://showFile.com/address.pdf", // pdf地址
|
|
122
|
+
content_text: "disclaimer<p><strong>默认文件</strong></p>", // 富文本内容
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
styleStr: {
|
|
126
|
+
color: "red",
|
|
127
|
+
"font-weight": "bold",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
fileStyle: {
|
|
132
|
+
color: "red",
|
|
133
|
+
"font-weight": "bold",
|
|
134
|
+
}, // 文件样式span
|
|
135
|
+
isCheckButton: false, // 列表是否需要复选框
|
|
136
|
+
isCoerceReadPopup: true, // 是否强制阅读弹窗
|
|
137
|
+
checkCallBack: (isChecked: boolean) => {
|
|
138
|
+
console.log("复选框状态改变:", isChecked);
|
|
139
|
+
}, // 复选框回调函数
|
|
140
|
+
listText: "更多详情请阅读",
|
|
141
|
+
checkButtonID: "ReadFileCheckBox",
|
|
142
|
+
},
|
|
143
|
+
// 强制阅读弹窗参数
|
|
144
|
+
coerceReadList: {
|
|
145
|
+
titleText: "请阅读并同意以下文件",
|
|
146
|
+
fileList: [
|
|
147
|
+
// 文件列表 require
|
|
148
|
+
{
|
|
149
|
+
name: "默认标题", //标题
|
|
150
|
+
file_type: 3, // 文件类型 1 富文本 2 pdf 3 引用文本,引用文本通常有多份
|
|
151
|
+
pdf_url: "", // pdf地址 绝对路径
|
|
152
|
+
content_text: "", // 富文本内容
|
|
153
|
+
com_terms: [
|
|
154
|
+
// 多份文件
|
|
155
|
+
{
|
|
156
|
+
name: "默认标题", //标题
|
|
157
|
+
pdf_url: "clause_pdf: https://showFile.com/address.pdf", // pdf地址
|
|
158
|
+
content_text: "disclaimer<p><strong>默认文件</strong></p>", // 富文本内容
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
styleStr: {
|
|
162
|
+
color: "red",
|
|
163
|
+
"font-weight": "bold",
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
fileStyle: {
|
|
168
|
+
color: "red",
|
|
169
|
+
"font-weight": "bold",
|
|
170
|
+
},
|
|
171
|
+
btnArr: ["确认已阅读并同意", "拒绝"],
|
|
172
|
+
btnStyle: [{ color: "red" }, { color: "gray" }],
|
|
173
|
+
btnBoxStyle: {},
|
|
174
|
+
showProgressInButton: false,
|
|
175
|
+
coerceCallBack: [
|
|
176
|
+
(control: ControlObject, buttonIndex: number) => {
|
|
177
|
+
console.log("btn[0]强制阅读弹窗结果:", control, buttonIndex);
|
|
178
|
+
},
|
|
179
|
+
(control: ControlObject, buttonIndex: number) => {
|
|
180
|
+
console.log("btn[1]强制阅读弹窗结果:", control, buttonIndex);
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
isBindFileClick: false, // 是否需要绑定文件点击事件
|
|
185
|
+
},
|
|
186
|
+
options
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
// 初始化模态框
|
|
190
|
+
this.initModal();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// 初始化
|
|
194
|
+
initModal(): void {
|
|
195
|
+
const {
|
|
196
|
+
isDrawFileList,
|
|
197
|
+
listObj,
|
|
198
|
+
isBindFileClick,
|
|
199
|
+
isConfignFileKeyName,
|
|
200
|
+
coerceReadList,
|
|
201
|
+
} = this.Configns;
|
|
202
|
+
|
|
203
|
+
if (
|
|
204
|
+
isConfignFileKeyName &&
|
|
205
|
+
listObj.fileList &&
|
|
206
|
+
listObj.fileList.length > 0
|
|
207
|
+
) {
|
|
208
|
+
this.Configns.listObj.fileList = this.dataChange(listObj.fileList);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (coerceReadList.fileList && coerceReadList.fileList.length > 0) {
|
|
212
|
+
this.Configns.coerceReadList.fileList = this.dataChange(
|
|
213
|
+
coerceReadList.fileList
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
isDrawFileList && this.drawReadFileList(listObj);
|
|
218
|
+
isBindFileClick && this.bindFileClick(listObj.listId, undefined);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 数据转换
|
|
222
|
+
dataChange(data: any[]): FileObject[] {
|
|
223
|
+
if (!this.Configns.fileKeyNameConfign)
|
|
224
|
+
throw new Error("请传入文件keyNameConfign");
|
|
225
|
+
|
|
226
|
+
const { fileTitle, filePdfUrl, fileRichContent, fileArr, fileType } =
|
|
227
|
+
this.Configns.fileKeyNameConfign;
|
|
228
|
+
|
|
229
|
+
if (!fileTitle || !filePdfUrl || !fileRichContent || !fileArr)
|
|
230
|
+
throw new Error("请传入文件keyNameConfign的参数");
|
|
231
|
+
|
|
232
|
+
data.forEach((item) => {
|
|
233
|
+
item.name = item[fileTitle];
|
|
234
|
+
item.file_type = item[fileType];
|
|
235
|
+
item.pdf_url = item[filePdfUrl];
|
|
236
|
+
item.content_text = item[fileRichContent];
|
|
237
|
+
item.com_terms = item[fileArr];
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return data as FileObject[];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
//渲染阅读文件列表
|
|
244
|
+
drawReadFileList(listObj: ListObject): void {
|
|
245
|
+
const {
|
|
246
|
+
listId: ID,
|
|
247
|
+
fileList,
|
|
248
|
+
isCheckButton,
|
|
249
|
+
isCoerceReadPopup,
|
|
250
|
+
checkCallBack,
|
|
251
|
+
listText,
|
|
252
|
+
checkButtonID,
|
|
253
|
+
fileStyle,
|
|
254
|
+
} = listObj;
|
|
255
|
+
|
|
256
|
+
if (!ID) throw new Error("请传入需要添加的dom ID");
|
|
257
|
+
if (fileList.length < 1) throw new Error("请传入需要渲染的文件数据");
|
|
258
|
+
|
|
259
|
+
let html = `${isCheckButton ? `<input type="checkbox" id="${checkButtonID}" />` : ""
|
|
260
|
+
}${listText}`;
|
|
261
|
+
|
|
262
|
+
for (let i = 0, len = fileList.length; i < len; i++) {
|
|
263
|
+
const { name, pdf_url, file_type, styleStr } = fileList[i];
|
|
264
|
+
const type =
|
|
265
|
+
file_type ||
|
|
266
|
+
this.judgeFileType({ type: "", file: fileList[i], index: i });
|
|
267
|
+
|
|
268
|
+
html += `<span class="pdfsee item-contract" data-pdf="${file_type == 2 ? pdf_url : ""
|
|
269
|
+
}" data-title="${name}" data-index="${i}" data-type="${type}" style="${this.objToStr(
|
|
270
|
+
styleStr ? styleStr : fileStyle || {}
|
|
271
|
+
)}">${name}</span>`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const element = document.querySelector(ID);
|
|
275
|
+
if (!element) throw new Error("未找到元素" + ID);
|
|
276
|
+
element.insertAdjacentHTML("beforeend", html);
|
|
277
|
+
|
|
278
|
+
if (isCheckButton && checkButtonID) {
|
|
279
|
+
const inputBox = document.getElementById(checkButtonID);
|
|
280
|
+
|
|
281
|
+
if (inputBox) {
|
|
282
|
+
inputBox.addEventListener("click", (e) => {
|
|
283
|
+
const target = e.target as HTMLInputElement;
|
|
284
|
+
const isChecked = target.checked;
|
|
285
|
+
|
|
286
|
+
checkCallBack && checkCallBack(isChecked);
|
|
287
|
+
|
|
288
|
+
isChecked && isCoerceReadPopup && this.openCoerceReadPopup();
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 对象转换为字符串
|
|
295
|
+
objToStr(obj: Record<string, string>): string {
|
|
296
|
+
return Object.entries(obj).reduce(
|
|
297
|
+
(str, [key, value]) => `${str}${key}:${value};`,
|
|
298
|
+
""
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 判断文件格式
|
|
303
|
+
judgeFileType(
|
|
304
|
+
params: {
|
|
305
|
+
type: string | number;
|
|
306
|
+
file?: FileObject;
|
|
307
|
+
index?: number;
|
|
308
|
+
fromChooseList?: boolean;
|
|
309
|
+
isCoerce?: boolean;
|
|
310
|
+
}
|
|
311
|
+
): number | string | void {
|
|
312
|
+
const { type, file, index, fromChooseList = false, isCoerce = false } = params;
|
|
313
|
+
if (!file) throw new Error("未找到对应文件信息 file is not defined");
|
|
314
|
+
let html;
|
|
315
|
+
switch (type) {
|
|
316
|
+
case "1":
|
|
317
|
+
case 1:
|
|
318
|
+
html = this.richTextFile({ file, fromChooseList, isCoerce });
|
|
319
|
+
break;
|
|
320
|
+
case "2":
|
|
321
|
+
case 2:
|
|
322
|
+
html = this.quotePdfFile({ file, fromChooseList, isCoerce });
|
|
323
|
+
break;
|
|
324
|
+
case "3":
|
|
325
|
+
case 3:
|
|
326
|
+
html = this.choosePdfFile({ file, index, fromChooseList, isCoerce });
|
|
327
|
+
break;
|
|
328
|
+
default:
|
|
329
|
+
const { com_terms, content_text, pdf_url } = file;
|
|
330
|
+
if (com_terms && com_terms.length > 0) {
|
|
331
|
+
return 3;
|
|
332
|
+
} else if (content_text) {
|
|
333
|
+
return 1;
|
|
334
|
+
} else if (pdf_url) {
|
|
335
|
+
return 2;
|
|
336
|
+
}
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (isCoerce) return html;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 富文本文件
|
|
344
|
+
richTextFile(params: {
|
|
345
|
+
file: FileObject;
|
|
346
|
+
fromChooseList?: boolean;
|
|
347
|
+
isCoerce?: boolean;
|
|
348
|
+
}): string | void {
|
|
349
|
+
const { file: filebox, fromChooseList = false, isCoerce = false } = params;
|
|
350
|
+
const { name: title, content_text: text } = filebox;
|
|
351
|
+
const popupInstance = fromChooseList ? new Popup() : myPopup;
|
|
352
|
+
|
|
353
|
+
if (isCoerce) return text;
|
|
354
|
+
|
|
355
|
+
popupInstance.showBottomPopup({
|
|
356
|
+
title: title,
|
|
357
|
+
content: text,
|
|
358
|
+
contentStyle: {},
|
|
359
|
+
titleStyle: {
|
|
360
|
+
fontWeight: "bold",
|
|
361
|
+
},
|
|
362
|
+
// btns: ['确定'],
|
|
363
|
+
callbacks: [function () {
|
|
364
|
+
console.log("richTextFile callbacks");
|
|
365
|
+
}],
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// 多分pdf选择
|
|
370
|
+
choosePdfFile(params: {
|
|
371
|
+
file: FileObject;
|
|
372
|
+
index?: number;
|
|
373
|
+
fromChooseList?: boolean;
|
|
374
|
+
isCoerce?: boolean;
|
|
375
|
+
}): string | void {
|
|
376
|
+
const { file: filebox, index: _index, fromChooseList = false, isCoerce = false } = params;
|
|
377
|
+
console.log("filebox", filebox);
|
|
378
|
+
|
|
379
|
+
const { com_terms: fileArr = [], name: title } = filebox;
|
|
380
|
+
const popupInstance = fromChooseList ? new Popup() : myPopup;
|
|
381
|
+
|
|
382
|
+
let html = "<dl class='ChoosePdfFileList' style='margin:0;padding:0;'>";
|
|
383
|
+
|
|
384
|
+
for (let i = 0; i < fileArr.length; i++) {
|
|
385
|
+
const { pdf_url, name, file_type } = fileArr[i];
|
|
386
|
+
const type =
|
|
387
|
+
file_type ||
|
|
388
|
+
this.judgeFileType({ type: "", file: fileArr[i], index: i });
|
|
389
|
+
|
|
390
|
+
html += `<dd class="cl" data-pdf="${pdf_url}" data-title="${name}" data-index="${i}" style="margin:0">
|
|
391
|
+
<span class="pdfsee item-contract" data-pdf="${pdf_url}" data-title="${name}" data-index="${i}" data-type="${type}">${name}</span>
|
|
392
|
+
</dd>`;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
html += "</dl>";
|
|
396
|
+
|
|
397
|
+
if (isCoerce) return html;
|
|
398
|
+
|
|
399
|
+
popupInstance.showBottomPopup({
|
|
400
|
+
title,
|
|
401
|
+
content: html,
|
|
402
|
+
contentStyle: {},
|
|
403
|
+
titleStyle: {
|
|
404
|
+
fontWeight: "bold",
|
|
405
|
+
},
|
|
406
|
+
// btns: ['确定'],
|
|
407
|
+
callbacks: [function () {
|
|
408
|
+
console.log("choosePDffile callbacks");
|
|
409
|
+
}],
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
this.bindFileClick(".ChoosePdfFileList", fileArr);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// 引用条款 pdf文件
|
|
416
|
+
quotePdfFile(params: {
|
|
417
|
+
file: FileObject;
|
|
418
|
+
fromChooseList?: boolean;
|
|
419
|
+
isControl?: boolean;
|
|
420
|
+
isCoerce?: boolean;
|
|
421
|
+
}): string | void {
|
|
422
|
+
const { file: filebox, fromChooseList = false, isControl = false, isCoerce = false } = params;
|
|
423
|
+
const { pdf_url: url, name: title, divType = "iframe" } = filebox;
|
|
424
|
+
|
|
425
|
+
// 如果来自选择列表,创建新实例
|
|
426
|
+
const popupInstance = fromChooseList ? new Popup() : myPopup;
|
|
427
|
+
|
|
428
|
+
// 添加参数尝试禁用工具栏
|
|
429
|
+
const modifiedUrl = isControl
|
|
430
|
+
? url
|
|
431
|
+
: `${url}#toolbar=0&navpanes=0&scrollbar=0`;
|
|
432
|
+
|
|
433
|
+
const iframeHtml = `<iframe src="${modifiedUrl}" width="100%" height="800" style="border:none;"></iframe>`;
|
|
434
|
+
const objectHtml = `<object data="${modifiedUrl}" type="application/pdf" width="100%" height="800">
|
|
435
|
+
<p>您的浏览器不支持PDF查看。请<a href="${modifiedUrl}">下载文件</a>。</p></object>`;
|
|
436
|
+
const embedHtml = `<embed src="${modifiedUrl}" type="application/pdf" width="100%" height="800" />`;
|
|
437
|
+
|
|
438
|
+
const html =
|
|
439
|
+
divType === "iframe"
|
|
440
|
+
? iframeHtml
|
|
441
|
+
: divType === "object"
|
|
442
|
+
? objectHtml
|
|
443
|
+
: embedHtml;
|
|
444
|
+
|
|
445
|
+
if (isCoerce) return html;
|
|
446
|
+
|
|
447
|
+
popupInstance.showBottomPopup({
|
|
448
|
+
title: title,
|
|
449
|
+
content: html,
|
|
450
|
+
contentStyle: {
|
|
451
|
+
// maxHeight: '100vh',
|
|
452
|
+
// overflow: 'hidden auto'
|
|
453
|
+
padding: "0",
|
|
454
|
+
},
|
|
455
|
+
contentBoxStyle: {
|
|
456
|
+
maxHeight: "100vh",
|
|
457
|
+
},
|
|
458
|
+
titleStyle: {
|
|
459
|
+
fontWeight: "bold",
|
|
460
|
+
},
|
|
461
|
+
callbacks: [function () {
|
|
462
|
+
console.log("quotePdfFile callback");
|
|
463
|
+
}],
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// 绑定文件点击事件
|
|
470
|
+
bindFileClick(containerSelector: string, fileArr?: FileObject[]): void {
|
|
471
|
+
const container = document.querySelector(containerSelector);
|
|
472
|
+
if (!container) throw new Error("容器未找到:" + containerSelector);
|
|
473
|
+
|
|
474
|
+
container.addEventListener("click", (event) => {
|
|
475
|
+
const target = event.target as HTMLElement;
|
|
476
|
+
if (target.tagName.toLowerCase() === "span") {
|
|
477
|
+
const dataset = target.dataset;
|
|
478
|
+
const type = dataset.type;
|
|
479
|
+
const index = dataset.index ? parseInt(dataset.index) : undefined;
|
|
480
|
+
|
|
481
|
+
if (index !== undefined) {
|
|
482
|
+
const file =
|
|
483
|
+
fileArr?.[index] || this.Configns?.listObj?.fileList?.[index];
|
|
484
|
+
|
|
485
|
+
console.log("read", index, type, file);
|
|
486
|
+
|
|
487
|
+
if (type !== undefined && file) {
|
|
488
|
+
this.judgeFileType({ type, file, index, fromChooseList: !!fileArr });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// 渲染强制阅读文件内容
|
|
496
|
+
openCoerceReadPopup(): void {
|
|
497
|
+
const {
|
|
498
|
+
fileList,
|
|
499
|
+
btnArr = ["同意并继续"],
|
|
500
|
+
btnStyle,
|
|
501
|
+
btnBoxStyle,
|
|
502
|
+
coerceCallBack,
|
|
503
|
+
titleText,
|
|
504
|
+
showProgressInButton
|
|
505
|
+
} = this.Configns.coerceReadList;
|
|
506
|
+
|
|
507
|
+
if (fileList.length === 0) throw new Error("fileList不能为空");
|
|
508
|
+
|
|
509
|
+
let currentIndex = 0;
|
|
510
|
+
let customButtonTitles: string[] | null = null;
|
|
511
|
+
// 记录已访问的文件索引,用于判断是否可以返回
|
|
512
|
+
let visitedIndices = [0];
|
|
513
|
+
const showNextFile = (_btnTitleArr?: string[]) => {
|
|
514
|
+
if (currentIndex >= fileList.length) return;
|
|
515
|
+
|
|
516
|
+
const file = fileList[currentIndex];
|
|
517
|
+
const isLastFile = currentIndex === fileList.length - 1;
|
|
518
|
+
|
|
519
|
+
// 确保文件类型已设置
|
|
520
|
+
if (!file.file_type) {
|
|
521
|
+
file.file_type = this.judgeFileType({
|
|
522
|
+
type: "",
|
|
523
|
+
file,
|
|
524
|
+
isCoerce: true
|
|
525
|
+
}) as number;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// 获取文件内容
|
|
529
|
+
const fileContent = this.judgeFileType({
|
|
530
|
+
type: file.file_type,
|
|
531
|
+
file,
|
|
532
|
+
isCoerce: true,
|
|
533
|
+
}) as string;
|
|
534
|
+
|
|
535
|
+
// 创建控制对象供外部回调使用
|
|
536
|
+
const control: ControlObject = {
|
|
537
|
+
next: () => {
|
|
538
|
+
// 下一份文件
|
|
539
|
+
// 重置自定义按钮文字状态
|
|
540
|
+
customButtonTitles = null;
|
|
541
|
+
currentIndex++;
|
|
542
|
+
// 记录访问过的索引
|
|
543
|
+
if (!visitedIndices.includes(currentIndex)) {
|
|
544
|
+
visitedIndices.push(currentIndex);
|
|
545
|
+
}
|
|
546
|
+
showNextFile();
|
|
547
|
+
},
|
|
548
|
+
prev: () => {
|
|
549
|
+
// 上一份文件
|
|
550
|
+
// 重置自定义按钮文字状态
|
|
551
|
+
customButtonTitles = null;
|
|
552
|
+
if (currentIndex > 0) {
|
|
553
|
+
currentIndex--;
|
|
554
|
+
showNextFile();
|
|
555
|
+
}
|
|
556
|
+
},
|
|
557
|
+
close: () => {
|
|
558
|
+
// 关闭弹窗
|
|
559
|
+
myPopup.close();
|
|
560
|
+
},
|
|
561
|
+
getCurrentIndex: () => currentIndex, // 获取当前索引
|
|
562
|
+
getFileList: () => [...fileList], // 返回副本防止外部修改
|
|
563
|
+
isLastFile: () => isLastFile, // 是否为最后一份文件
|
|
564
|
+
setButtonTitles: (titles) => {
|
|
565
|
+
// 允许外部修改按钮文字
|
|
566
|
+
if (Array.isArray(titles)) {
|
|
567
|
+
customButtonTitles = titles;
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
// 获取已访问的文件索引列表
|
|
571
|
+
getVisitedIndices: () => [...visitedIndices],
|
|
572
|
+
// 跳转到指定文件索引
|
|
573
|
+
goTo: (index) => {
|
|
574
|
+
if (index >= 0 && index < fileList.length) {
|
|
575
|
+
customButtonTitles = null;
|
|
576
|
+
currentIndex = index;
|
|
577
|
+
if (!visitedIndices.includes(currentIndex)) {
|
|
578
|
+
visitedIndices.push(currentIndex);
|
|
579
|
+
}
|
|
580
|
+
showNextFile();
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
// 控制复选框选中状态
|
|
584
|
+
setCheckboxChecked: (isChecked) => {
|
|
585
|
+
const checkboxId = this.Configns.listObj?.checkButtonID;
|
|
586
|
+
if (checkboxId) {
|
|
587
|
+
const checkbox = document.getElementById(checkboxId);
|
|
588
|
+
if (checkbox) {
|
|
589
|
+
(checkbox as HTMLInputElement).checked = isChecked;
|
|
590
|
+
// 触发change事件,确保相关回调被执行
|
|
591
|
+
const event = new Event("change");
|
|
592
|
+
checkbox.dispatchEvent(event);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
// 获取复选框当前状态
|
|
597
|
+
isCheckboxChecked: () => {
|
|
598
|
+
const checkboxId = this.Configns.listObj?.checkButtonID;
|
|
599
|
+
if (checkboxId) {
|
|
600
|
+
const checkbox = document.getElementById(checkboxId);
|
|
601
|
+
return checkbox ? (checkbox as HTMLInputElement).checked : false;
|
|
602
|
+
}
|
|
603
|
+
return false;
|
|
604
|
+
},
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
// 为每个按钮创建回调函数
|
|
608
|
+
const callbacks: (() => void)[] = [];
|
|
609
|
+
if (btnArr && btnArr.length > 0) {
|
|
610
|
+
for (let i = 0; i < btnArr.length; i++) {
|
|
611
|
+
callbacks.push(
|
|
612
|
+
((buttonIndex) => {
|
|
613
|
+
return () => {
|
|
614
|
+
if (typeof coerceCallBack === "function") {
|
|
615
|
+
return coerceCallBack(control, buttonIndex);
|
|
616
|
+
} else if (
|
|
617
|
+
Array.isArray(coerceCallBack) &&
|
|
618
|
+
typeof coerceCallBack[buttonIndex] === "function"
|
|
619
|
+
) {
|
|
620
|
+
return coerceCallBack[buttonIndex](control);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
})(i)
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// 确定最终使用的按钮文字
|
|
629
|
+
let finalButtons = customButtonTitles || btnArr;
|
|
630
|
+
// 如果配置了显示进度且没有自定义按钮标题,则添加进度信息
|
|
631
|
+
if (showProgressInButton !== false && !customButtonTitles && btnArr && btnArr.length > 0) {
|
|
632
|
+
const currentDisplayIndex = currentIndex + 1; // 显示索引从1开始
|
|
633
|
+
const totalLength = fileList.length;
|
|
634
|
+
|
|
635
|
+
finalButtons = [...btnArr]; // 复制原始按钮数组
|
|
636
|
+
|
|
637
|
+
// 根据 showProgressInButton 的值决定在哪个按钮上添加进度信息
|
|
638
|
+
if (typeof showProgressInButton === 'number') {
|
|
639
|
+
// 如果是数字,表示按钮索引
|
|
640
|
+
const buttonIndex = showProgressInButton;
|
|
641
|
+
if (buttonIndex >= 0 && buttonIndex < finalButtons.length) {
|
|
642
|
+
finalButtons[buttonIndex] = `${btnArr[buttonIndex]}(${currentDisplayIndex}/${totalLength})`;
|
|
643
|
+
}
|
|
644
|
+
} else if (showProgressInButton === true) {
|
|
645
|
+
// 如果是 true,表示在第一个按钮上显示
|
|
646
|
+
finalButtons[0] = `${btnArr[0]}(${currentDisplayIndex}/${totalLength})`;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
console.log("showNextFile", btnArr, finalButtons);
|
|
650
|
+
|
|
651
|
+
const popupConfig = {
|
|
652
|
+
title:
|
|
653
|
+
file.name ||
|
|
654
|
+
`${titleText || "文件"} (${currentIndex + 1}/${fileList.length})`,
|
|
655
|
+
content: fileContent,
|
|
656
|
+
btnBoxStyle: btnBoxStyle || {
|
|
657
|
+
display: "flex",
|
|
658
|
+
justifyContent: "space-around",
|
|
659
|
+
alignItems: "center",
|
|
660
|
+
padding: "0 2.4vw",
|
|
661
|
+
},
|
|
662
|
+
btns: finalButtons,
|
|
663
|
+
btnStyle: btnStyle || [
|
|
664
|
+
{
|
|
665
|
+
display: "inline-block",
|
|
666
|
+
width: "91vw",
|
|
667
|
+
height: "10.667vw",
|
|
668
|
+
color: "#fff",
|
|
669
|
+
backgroundColor: "#29AEEF",
|
|
670
|
+
borderRadius: "8.533vw",
|
|
671
|
+
textAlign: "center",
|
|
672
|
+
lineHeight: "10.667vw",
|
|
673
|
+
cursor: "pointer",
|
|
674
|
+
margin: "5.33vw auto",
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
display: "inline-block",
|
|
678
|
+
width: "91vw",
|
|
679
|
+
height: "10.667vw",
|
|
680
|
+
color: "#fff",
|
|
681
|
+
backgroundColor: "#29AEEF",
|
|
682
|
+
borderRadius: "8.533vw",
|
|
683
|
+
textAlign: "center",
|
|
684
|
+
lineHeight: "10.667vw",
|
|
685
|
+
cursor: "pointer",
|
|
686
|
+
margin: "5.33vw auto",
|
|
687
|
+
},
|
|
688
|
+
],
|
|
689
|
+
callbacks,
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
control.setCheckboxChecked(false);
|
|
693
|
+
|
|
694
|
+
myPopup.showBottomPopup(popupConfig);
|
|
695
|
+
|
|
696
|
+
if (file.file_type === 3 && file.com_terms) {
|
|
697
|
+
this.bindFileClick(".ChoosePdfFileList", file.com_terms);
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
showNextFile();
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// 加载文件内容
|
|
705
|
+
loadFile(filePath: string): void {
|
|
706
|
+
const fileExtension = filePath.split(".").pop()?.toLowerCase();
|
|
707
|
+
if (!fileExtension) {
|
|
708
|
+
console.error("无法识别文件类型:", filePath);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const contentType = this.Configns.fileTypes[fileExtension];
|
|
713
|
+
|
|
714
|
+
if (!contentType) {
|
|
715
|
+
console.error("不支持的文件类型:", fileExtension);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const fileName = filePath.split("/").pop() || "文件";
|
|
720
|
+
|
|
721
|
+
if (contentType === "application/pdf") {
|
|
722
|
+
// 对于PDF文件,直接使用iframe,避免CORS问题
|
|
723
|
+
myPopup.showBottomPopup({
|
|
724
|
+
title: fileName,
|
|
725
|
+
content: `<iframe src="${filePath}" width="100%" height="600px" style="border:none;"></iframe>`,
|
|
726
|
+
contentStyle: {},
|
|
727
|
+
titleStyle: {
|
|
728
|
+
fontWeight: "bold",
|
|
729
|
+
},
|
|
730
|
+
// btns: ['确定'],
|
|
731
|
+
callbacks: [function () {
|
|
732
|
+
console.log("loadFile callback");
|
|
733
|
+
}],
|
|
734
|
+
});
|
|
735
|
+
} else {
|
|
736
|
+
// 对于其他文件类型,仍然使用fetch
|
|
737
|
+
fetch(filePath)
|
|
738
|
+
.then((response) => {
|
|
739
|
+
if (!response.ok) {
|
|
740
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
741
|
+
}
|
|
742
|
+
return response.text();
|
|
743
|
+
})
|
|
744
|
+
.then((data) => {
|
|
745
|
+
// 根据文件类型决定展示方式
|
|
746
|
+
let content: string;
|
|
747
|
+
if (fileExtension === 'html' || fileExtension === 'htm') {
|
|
748
|
+
// 对于HTML文件,直接显示(但需要注意安全问题)
|
|
749
|
+
content = `<div style="max-height: 70vh; overflow-y: auto;">${data}</div>`;
|
|
750
|
+
} else {
|
|
751
|
+
// 对于文本文件,使用<pre>标签保持格式
|
|
752
|
+
content = `<pre style="white-space: pre-wrap; word-wrap: break-word; max-height: 70vh; overflow-y: auto;">${data}</pre>`;
|
|
753
|
+
}
|
|
754
|
+
myPopup.showBottomPopup({
|
|
755
|
+
title: fileName,
|
|
756
|
+
content: content,
|
|
757
|
+
contentStyle: {
|
|
758
|
+
maxHeight: "70vh",
|
|
759
|
+
overflow: "auto",
|
|
760
|
+
},
|
|
761
|
+
titleStyle: {
|
|
762
|
+
fontWeight: "bold",
|
|
763
|
+
},
|
|
764
|
+
callbacks: [function () {
|
|
765
|
+
console.log("文件内容弹窗关闭");
|
|
766
|
+
}],
|
|
767
|
+
});
|
|
768
|
+
})
|
|
769
|
+
.catch((error) => {
|
|
770
|
+
console.error("文件加载失败:", error);
|
|
771
|
+
// 显示错误信息在弹窗中
|
|
772
|
+
myPopup.showBottomPopup({
|
|
773
|
+
title: "文件加载失败",
|
|
774
|
+
content: `<p style="color: red;">无法加载文件: ${filePath}</p><p>错误详情: ${error.message}</p>`,
|
|
775
|
+
callbacks: [function () {
|
|
776
|
+
console.log("错误提示弹窗关闭");
|
|
777
|
+
}],
|
|
778
|
+
});
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
784
|
export default FilePreview;
|