@focus-teach/ui 1.0.37 → 1.0.39
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/api/index.js +137 -0
- package/lib/img/empty.fcdd9ba5.png +0 -0
- package/lib/ui.common.js +52816 -60188
- package/lib/ui.css +1 -1
- package/lib/ui.umd.js +52816 -60188
- package/lib/ui.umd.min.js +6 -12
- package/package.json +2 -1
- package/utils/common.js +290 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@focus-teach/ui",
|
|
3
3
|
"packageName": "ui",
|
|
4
4
|
"publishName": "@focus-teach/ui",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.39",
|
|
6
6
|
"private": false,
|
|
7
7
|
"main": "lib/ui.umd.min.js",
|
|
8
8
|
"scripts": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"sass": "^1.26.5",
|
|
27
27
|
"sass-loader": "^10.1.1",
|
|
28
28
|
"underscore": "^1.13.1",
|
|
29
|
+
"v-viewer": "^1.7.4",
|
|
29
30
|
"vue": "^2.6.10",
|
|
30
31
|
"vue-infinite-scroll": "^2.0.2",
|
|
31
32
|
"vue-loader": "^15.9.6",
|
package/utils/common.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
const TABLE_PC = 647; // PC所占宽度
|
|
2
|
+
const TABLE_MISP = 959; // 错打所占宽度
|
|
3
|
+
const TABLE_MINIP = 320; // 小程序所占宽度
|
|
4
|
+
const TABLE_DRAWER = 470; // 抽屉所占宽度
|
|
5
|
+
const TABLE_CLASS = 509; // 上课所占宽度
|
|
6
|
+
const TABLE_MISD = 457; // 错打下载所占宽度
|
|
7
|
+
const TABLE_MINI110 = 408; // 小程序110mm所占宽度
|
|
8
|
+
const MAX_HEIGHT = 1024 //一页a4的高度
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
function getFileTypeSuffix(fileName) {
|
|
2
12
|
var index = fileName.lastIndexOf(".");
|
|
3
13
|
if (index > -1) {
|
|
@@ -167,4 +177,284 @@ export function getKlLeafNode(tree){
|
|
|
167
177
|
}
|
|
168
178
|
deep(tree);
|
|
169
179
|
return result;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function ptToPx(pt) {
|
|
183
|
+
var dpi = window.devicePixelRatio * 96;
|
|
184
|
+
return pt * dpi / 72;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function getStringWidthNoImage(text, type, fontSize = '14px',fontFamily='Times New Roman, SimSun, 宋体 ,Segoe UI Symbol') {
|
|
188
|
+
var span = document.createElement("span");
|
|
189
|
+
var result = {};
|
|
190
|
+
result.width = span.offsetWidth;
|
|
191
|
+
result.height = span.offsetHeight;
|
|
192
|
+
span.style.visibility = "hidden";
|
|
193
|
+
span.style.fontSize = fontSize;
|
|
194
|
+
span.style.fontFamily = fontFamily
|
|
195
|
+
span.style.display = "inline-block";
|
|
196
|
+
span.style.whiteSpace = 'break-spaces'
|
|
197
|
+
document.body.appendChild(span);
|
|
198
|
+
if(type == 'text'){
|
|
199
|
+
if (typeof span.textContent != "undefined") {
|
|
200
|
+
span.textContent = text;
|
|
201
|
+
} else {
|
|
202
|
+
span.innerText = text;
|
|
203
|
+
}
|
|
204
|
+
}else{
|
|
205
|
+
span.innerHTML = text
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
result.width = parseFloat(window.getComputedStyle(span).width) - result.width;
|
|
209
|
+
result.height = parseFloat(window.getComputedStyle(span).height) - result.height;
|
|
210
|
+
document.body.removeChild(span);
|
|
211
|
+
return result.width;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getImageWidth(child, maxWidth, maxHeight) {
|
|
215
|
+
let rect = child.getBoundingClientRect()
|
|
216
|
+
let width = rect.width,height = rect.height;
|
|
217
|
+
if(!child.getAttribute('width') || !child.getAttribute('height')){
|
|
218
|
+
child.setAttribute('width',width)
|
|
219
|
+
child.setAttribute('height',height < maxHeight ? height : maxHeight)
|
|
220
|
+
let computedWidth = width > maxWidth ? maxWidth : width
|
|
221
|
+
let computedHeight = (computedWidth * child.naturalHeight / child.naturalWidth)
|
|
222
|
+
if(width >= maxWidth) {
|
|
223
|
+
height = computedWidth
|
|
224
|
+
child.style.width = computedWidth + 'px'//超过高度之后 按原图片等比例缩放的高度设置
|
|
225
|
+
}
|
|
226
|
+
if(height >= maxHeight) {
|
|
227
|
+
height = computedHeight
|
|
228
|
+
child.style.height = computedHeight + 'px'//超过高度之后 按原图片等比例缩放的高度设置
|
|
229
|
+
}
|
|
230
|
+
}else{
|
|
231
|
+
width = rect.width;
|
|
232
|
+
height = rect.height;
|
|
233
|
+
}
|
|
234
|
+
return {width,height}
|
|
235
|
+
}
|
|
236
|
+
function loadImage({child,maxHeight,maxWidth}){//等待图片加载完成
|
|
237
|
+
return new Promise(async (resolve)=>{
|
|
238
|
+
try{
|
|
239
|
+
const promiseArr = [];
|
|
240
|
+
let imgLoadCount = 0;
|
|
241
|
+
if(child.nodeName === 'IMG'){
|
|
242
|
+
promiseArr.push(new Promise(resolve=>{
|
|
243
|
+
let timer = setInterval(function() {
|
|
244
|
+
if(child.complete) {
|
|
245
|
+
clearInterval(timer)
|
|
246
|
+
let { width,height } = getImageWidth(child,maxWidth,maxHeight)
|
|
247
|
+
resolve({width,height})
|
|
248
|
+
}
|
|
249
|
+
if(child.onerror){
|
|
250
|
+
imgLoadCount++
|
|
251
|
+
if(imgLoadCount > 60){
|
|
252
|
+
clearInterval(timer)
|
|
253
|
+
imgLoadCount = 0
|
|
254
|
+
let { width,height } = getImageWidth(child,maxWidth,maxHeight)
|
|
255
|
+
resolve({width,height})
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}, 50)
|
|
259
|
+
}))
|
|
260
|
+
}
|
|
261
|
+
if(!promiseArr.length){
|
|
262
|
+
resolve('other')
|
|
263
|
+
}else{
|
|
264
|
+
try{
|
|
265
|
+
let res = await Promise.all(promiseArr)
|
|
266
|
+
console.log('res is...',res)
|
|
267
|
+
resolve({width:res?.[0]?.width,height:res?.[0]?.height})
|
|
268
|
+
}catch(err){
|
|
269
|
+
setTimeout(()=>{
|
|
270
|
+
resolve('loadError')
|
|
271
|
+
},2000)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}catch(error){
|
|
275
|
+
setTimeout(()=>{
|
|
276
|
+
resolve('loadError')
|
|
277
|
+
},2000)
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// 计算当前选项的列数
|
|
283
|
+
async function getCols(optionArr,TABLE_WIDTH,className){
|
|
284
|
+
let optionCount = optionArr.length, factors = [], cols = 1;
|
|
285
|
+
|
|
286
|
+
// 计算选项公约数
|
|
287
|
+
factors = [...Array(optionCount).keys()].map(item=>item+1).filter(item=> optionCount % item === 0).reverse();
|
|
288
|
+
let widthList = [];
|
|
289
|
+
// let widthList = optionArr.map(async item=>{
|
|
290
|
+
for(let i = 0; i < optionArr.length; i++){
|
|
291
|
+
let item = optionArr[i]
|
|
292
|
+
if(item.includes('img')){
|
|
293
|
+
let div = document.createElement('div')
|
|
294
|
+
div.id = 'preRenderImgContainer'
|
|
295
|
+
div.style.visibility = 'hidden'
|
|
296
|
+
div.innerHTML = item
|
|
297
|
+
document.body.appendChild(div)
|
|
298
|
+
let width = 0
|
|
299
|
+
// Array.from(div.childNodes).forEach((childNode)=>{
|
|
300
|
+
for(let j = 0; j < div.childNodes.length; j++){
|
|
301
|
+
let childNode = div.childNodes[j]
|
|
302
|
+
if(childNode.nodeName == 'IMG'){
|
|
303
|
+
let tempWidth = childNode?.style?.width || childNode.width
|
|
304
|
+
console.log(tempWidth,className,'图片宽度');
|
|
305
|
+
let realWidth = String(tempWidth || '').includes('pt') ? ptToPx(parseFloat(tempWidth)) : parseFloat(tempWidth)
|
|
306
|
+
// 若图片不存在宽度,则随便给一个值,超过编辑器宽度即可,这里给了1000
|
|
307
|
+
if(!realWidth) {
|
|
308
|
+
let { width,height } = await loadImage({child:childNode,maxHeight:MAX_HEIGHT,maxWidth:TABLE_WIDTH})
|
|
309
|
+
realWidth = width
|
|
310
|
+
}
|
|
311
|
+
width += realWidth || MAX_HEIGHT
|
|
312
|
+
}else{
|
|
313
|
+
if(childNode.nodeName == '#text'){
|
|
314
|
+
width += getStringWidthNoImage(childNode.textContent,'text',className == 'options-mistake-print' ? '16px' : '14px',className == 'options-mistake-print' ? 'Avenir, Helvetica, Arial, sans-serif' : undefined)
|
|
315
|
+
console.log(width,'文本节点宽度');
|
|
316
|
+
}else{
|
|
317
|
+
width += getStringWidthNoImage(childNode.outerHTML,'',className == 'options-mistake-print' ? '16px' : '14px',className == 'options-mistake-print' ? 'Avenir, Helvetica, Arial, sans-serif' : undefined)
|
|
318
|
+
console.log(width,'其他标签宽度');
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
div?.remove?.()
|
|
323
|
+
console.log("带图片识别出来的宽",className,width);
|
|
324
|
+
// return width
|
|
325
|
+
widthList.push(width)
|
|
326
|
+
}else{
|
|
327
|
+
let eleWidth = getStringWidthNoImage(item.trim(),'',className == 'options-mistake-print' ? '16px' : '14px',className == 'options-mistake-print' ? 'Avenir, Helvetica, Arial, sans-serif' : undefined)
|
|
328
|
+
widthList.push(eleWidth)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
//当前选项的长度列表
|
|
332
|
+
let maxWidth = Math.max(...widthList); // 当前选项的最大长度
|
|
333
|
+
|
|
334
|
+
let find = factors.find(item=> maxWidth <= TABLE_WIDTH / item)
|
|
335
|
+
find && (cols = find);
|
|
336
|
+
console.log('计算出来的表格列数=====>',cols,maxWidth);
|
|
337
|
+
return cols
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
async function getOptionArr(optionArr,TABLE_WIDTH,className){
|
|
342
|
+
let cols = await getCols(optionArr,TABLE_WIDTH,className);
|
|
343
|
+
let rows = Math.ceil(optionArr.length / cols);
|
|
344
|
+
optionArr = Array.from({ length: rows }, (_, i) => optionArr.slice(i * cols, i * cols + cols));
|
|
345
|
+
return optionArr
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export async function generateTable(optionArr,option) {
|
|
349
|
+
|
|
350
|
+
let table = '<table border="0" class="ckeditor-table cke_show_border option-table" style="border-collapse: collapse; width: 100%;;border:none"><tbody>';
|
|
351
|
+
// 后续有新增类型只需要添加宽度和对应的类名即可
|
|
352
|
+
// !!!!!!!!!!!!!!!!
|
|
353
|
+
// !!!!!!!!!!!!!!!!
|
|
354
|
+
// !!!!!!!!!!!!!!!! 新增类型需要去ckeditor.js源码中在表格转换功能处过滤新增的类型
|
|
355
|
+
// !!!!!!!!!!!!!!!!
|
|
356
|
+
// !!!!!!!!!!!!!!!!
|
|
357
|
+
let tableList = [
|
|
358
|
+
// PC
|
|
359
|
+
{
|
|
360
|
+
className: 'options-origin',
|
|
361
|
+
width: TABLE_PC
|
|
362
|
+
},
|
|
363
|
+
// 错打
|
|
364
|
+
{
|
|
365
|
+
className: 'options-mistake-print',
|
|
366
|
+
width: TABLE_MISP
|
|
367
|
+
},
|
|
368
|
+
// 小程序
|
|
369
|
+
{
|
|
370
|
+
className: 'options-miniprogram',
|
|
371
|
+
width: TABLE_MINIP
|
|
372
|
+
},
|
|
373
|
+
// 抽屉
|
|
374
|
+
{
|
|
375
|
+
className: 'options-drawer',
|
|
376
|
+
width: TABLE_DRAWER
|
|
377
|
+
},
|
|
378
|
+
// 上课
|
|
379
|
+
{
|
|
380
|
+
className: 'options-class',
|
|
381
|
+
width: TABLE_CLASS
|
|
382
|
+
},
|
|
383
|
+
// 错打下载
|
|
384
|
+
{
|
|
385
|
+
className: 'options-mistake-download',
|
|
386
|
+
width: TABLE_MISD
|
|
387
|
+
},
|
|
388
|
+
// 小程序110mm
|
|
389
|
+
{
|
|
390
|
+
className: 'options-mini110',
|
|
391
|
+
width: TABLE_MINI110
|
|
392
|
+
},
|
|
393
|
+
]
|
|
394
|
+
// [[A,B],[C,D]]
|
|
395
|
+
for(let i = 0; i < tableList.length; i++){
|
|
396
|
+
let item = tableList[i]
|
|
397
|
+
let optionsTemp = await getOptionArr(optionArr,item.width,item.className);
|
|
398
|
+
optionsTemp.forEach((optionCols)=>{
|
|
399
|
+
table += `<tr class="options-tr ${item.className}">`
|
|
400
|
+
optionCols.forEach((item)=>{
|
|
401
|
+
table += '<td>'+item+'</td>'
|
|
402
|
+
})
|
|
403
|
+
table += '</tr>'
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
}
|
|
407
|
+
table += '</tbody></table>'
|
|
408
|
+
return table
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// 把选项转换成表格展示
|
|
412
|
+
function optionToTable(stem) {
|
|
413
|
+
let content = [] // 存储题干内容
|
|
414
|
+
let option = '' // 存储选项内容
|
|
415
|
+
let optionPosition = -1 // 选项在题干中的位置
|
|
416
|
+
let div = document.createElement('div');
|
|
417
|
+
div.innerHTML = stem;
|
|
418
|
+
if(div?.childNodes.length){
|
|
419
|
+
div.childNodes.forEach((item,index)=>{
|
|
420
|
+
if(item?.innerHTML.match(/^((\n|\s| )*([A-H]\s*)+[.|、|.])/g) || item?.innerHTML.match(/\n?(\s| )+([A-H])[.|、|.]\s*/g)){
|
|
421
|
+
// 有选项的节点,从中取出选项
|
|
422
|
+
let matchs = item?.innerHTML.match(/^((\n|\s| )*([A-H]\s*)+[.|、|.])/g) || item?.innerHTML.match(/\n?(\s| )+([A-H])[.|、|.]\s*/g);
|
|
423
|
+
let optionIndex = item.innerHTML.indexOf(matchs[0])
|
|
424
|
+
|
|
425
|
+
if(optionIndex > 0){
|
|
426
|
+
// 表示选项前面有其他内容
|
|
427
|
+
content.push(`<p>${item.innerHTML.slice(0,optionIndex)}</p>`)
|
|
428
|
+
option += item?.innerHTML.slice(optionIndex)
|
|
429
|
+
optionPosition < 0 && (optionPosition = index + 1)
|
|
430
|
+
}else{
|
|
431
|
+
option += item?.innerHTML
|
|
432
|
+
// 只记录第一个选项的位置
|
|
433
|
+
optionPosition < 0 && (optionPosition = index)
|
|
434
|
+
}
|
|
435
|
+
}else{
|
|
436
|
+
// content += item?.outerHTML
|
|
437
|
+
content.push(item?.outerHTML)
|
|
438
|
+
}
|
|
439
|
+
})
|
|
440
|
+
}
|
|
441
|
+
console.log(option,'option======');
|
|
442
|
+
if(!option) return stem
|
|
443
|
+
const reg = /([A-H])[.|、|.]\s*(.+?)(?=[A-H][.|、|.]|\s*$)/g;
|
|
444
|
+
let optionArr = option.match(reg);
|
|
445
|
+
if(!optionArr || !optionArr.length) return stem // 没有匹配到选项,直接返回
|
|
446
|
+
// optionArr 肯定是以选项A-H开头的,如果超过一个A开头的选项,说明不符合单选题的规则,直接返回
|
|
447
|
+
// 若匹配到的选项不以A开头,则直接返回
|
|
448
|
+
if(optionArr?.filter(item=>item.startsWith('A'))?.length > 1 || optionArr?.filter(item=>item.startsWith('A'))?.length == 0 ||optionArr?.length > 4) return stem
|
|
449
|
+
optionArr = optionArr.map(item=> item.trim())
|
|
450
|
+
let table = generateTable(optionArr,option);
|
|
451
|
+
|
|
452
|
+
content.splice(optionPosition,0,table)
|
|
453
|
+
return content.join('')
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export function getUpdateTime(timeStr) {
|
|
457
|
+
var oneTime = new Date(timeStr).getTime();
|
|
458
|
+
var date = new Date(oneTime);
|
|
459
|
+
return formatDate(date, "yyyy-MM-dd hh:mm");
|
|
170
460
|
}
|