feat:初始化 -融骅
This commit is contained in:
19
front/src/utils/capture.js
Normal file
19
front/src/utils/capture.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 异常捕获
|
||||
*/
|
||||
const ErrorCapture = {
|
||||
|
||||
/**
|
||||
* 处理IMG异常
|
||||
* @param {Event} event
|
||||
*/
|
||||
IMG ({ target }) {
|
||||
target.src = target.className.includes('avatar') ? '/logo.svg' : '/default.svg'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获全局error事件
|
||||
*/
|
||||
document.addEventListener('error', (e) => ErrorCapture[e.target.tagName]?.(e), true)
|
||||
57
front/src/utils/data-report.js
Normal file
57
front/src/utils/data-report.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { reportDataApi } from '@/api/statistic/index'
|
||||
|
||||
export const REPORT_TYPES = {
|
||||
ONLINE_COURSE: '在线课程',
|
||||
LIVE_TEACHING: '教学直播',
|
||||
MOCK_EXAMINATION: '模拟考试',
|
||||
ERROR_CONSOLIDATION: '错题巩固',
|
||||
CLASS_NOTE: '课堂笔记',
|
||||
ONLINE_FAQ: '在线答疑',
|
||||
RESOURCE_VIEW: '资源查看',
|
||||
SYSTEM_USE: '系统使用'
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据上报 mixin
|
||||
*
|
||||
* @param {[keyof REPORT_TYPES]} type 上报类型
|
||||
*
|
||||
* @param {Object} options 方法
|
||||
* @param {boolean} options.isListenerUnload 是否弹出关闭页面提示框
|
||||
* @param {()=>boolean} options.isCancelReport 是否取消上报
|
||||
* @param {()=>{ id?:number, field01?:string, field02?:string, field03?:string, remarks?:string }} options.handleReportData 处理上报数据
|
||||
* field01 备用字段
|
||||
* field02 备用字段
|
||||
* field03 备用字段
|
||||
* remarks 备注说明
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export function dataReportMixin (type, { isListenerUnload, ...methods } = {}) {
|
||||
if (!type) throw Error('上报类型错误')
|
||||
|
||||
return {
|
||||
mounted () {
|
||||
if (this.isCancelReport?.()) return console.warn('上报已中断,上报数据:', type)
|
||||
|
||||
this.reportData()
|
||||
if (isListenerUnload) window.addEventListener('beforeunload', this.reportData)
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
if (isListenerUnload) window.removeEventListener('beforeunload', this.reportData)
|
||||
this.reportData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
...methods,
|
||||
|
||||
async reportData (e) {
|
||||
e && (e.returnValue = '将要退出,是否继续?')
|
||||
|
||||
reportDataApi({ ...this.handleReportData?.(), id: this.__report_data_id__, type })
|
||||
.then(({ data }) => (this.__report_data_id__ = data))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
63
front/src/utils/fetch.js
Normal file
63
front/src/utils/fetch.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { lst } from './index'
|
||||
|
||||
const _instance = window.axios.create({
|
||||
baseURL: import.meta.env.VITE_APP_BASE_URL,
|
||||
timeout: 100000
|
||||
})
|
||||
|
||||
_instance.interceptors.request.use(
|
||||
(config) => {
|
||||
const _token = lst.get('token')
|
||||
_token && (config.headers.Authorization = _token)
|
||||
|
||||
if (config.formData) {
|
||||
config.headers['Content-Type'] = 'multipart/form-data;'
|
||||
config.data = new FormData()
|
||||
for (const k in config.formData) config.data.append(k, config.formData[k])
|
||||
}
|
||||
|
||||
return config
|
||||
},
|
||||
(e) => {
|
||||
throw e
|
||||
}
|
||||
)
|
||||
|
||||
_instance.interceptors.response.use(
|
||||
({ data, status, config }) => {
|
||||
if ([201, 200].includes(status) && (data.code === 0 || config.noCatch)) return data
|
||||
throw new Error(data.msg)
|
||||
},
|
||||
(e) => {
|
||||
throw e
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* @param {Object} option 选项
|
||||
* @param {string} option.url 请求地址
|
||||
* @param {string} option.headers 请求头
|
||||
* @param {{}} option.params URL 参数
|
||||
* @param {{}} option.data body 参数
|
||||
* @param {{}} option.formData FormData 对象参数
|
||||
* @param {'get'|'post'|'patch'|'delete'} option.method
|
||||
*/
|
||||
export default async (option) => {
|
||||
try {
|
||||
return await _instance(option)
|
||||
} catch (err) {
|
||||
let _msg
|
||||
if (err.response) {
|
||||
if (err.response.data.code === 401) {
|
||||
lst.clear()
|
||||
location.href = '/'
|
||||
}
|
||||
_msg = err.response.data.msg
|
||||
}
|
||||
|
||||
if (!option.noNotify) {
|
||||
window.ELEMENT.Message.error(_msg || err.message || '系统繁忙,请稍后再试!')
|
||||
}
|
||||
throw new Error(_msg || err)
|
||||
}
|
||||
}
|
||||
18
front/src/utils/iframe-message.js
Normal file
18
front/src/utils/iframe-message.js
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
const vue = new Vue()
|
||||
window.addEventListener('message', async (e) => {
|
||||
if (e.data.type === 'confim') {
|
||||
// console.log($confirm)
|
||||
await confirm(e)
|
||||
}
|
||||
})
|
||||
async function confirm (e) {
|
||||
vue.$confirm(e.data.title, '操作提示', { type: 'warning' })
|
||||
.then(() => {
|
||||
console.log(e)
|
||||
e.source.postMessage({ status: true, id: e.data.id }, '*')
|
||||
})
|
||||
.catch(() => {
|
||||
e.source.postMessage({ status: false, id: e.data.id }, '*')
|
||||
})
|
||||
}
|
||||
112
front/src/utils/index.js
Normal file
112
front/src/utils/index.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import storage from './storage'
|
||||
|
||||
export function mapToTree (map) {
|
||||
const list = []
|
||||
for (const k in map) {
|
||||
if (map[k].pid === 0) {
|
||||
list.push(map[k])
|
||||
} else {
|
||||
map[map[k].pid].children ??= []
|
||||
map[map[k].pid].children.push(map[k])
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件时 accept 的枚举类
|
||||
*/
|
||||
export const ACCEPT_MAP = {
|
||||
image: { icon: 'i-tupiao', color: '#ff6a4d', name: '图片文件', accept: 'image/*' },
|
||||
audio: { icon: 'i-yinyue', color: '#9660f5', name: '音频文件', accept: 'audio/*' },
|
||||
video: { icon: 'i-shipin', color: '#55d1e0', name: '视频文件', accept: 'video/*' },
|
||||
ppt: { icon: 'i-ppt', color: '#ff9357', name: '演示文稿', accept: 'application/vnd.ms-powerpoint' },
|
||||
pptx: { icon: 'i-pptx', color: '#ff9357', name: '演示文稿', accept: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' },
|
||||
xls: { icon: 'i-xls', color: '#28c17a', name: '表格文件', accept: 'application/vnd.ms-excel' },
|
||||
xlsx: { icon: 'i-xlsx', color: '#28c17a', name: '表格文件', accept: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' },
|
||||
pdf: { icon: 'i-pdf', color: '#ff738e', name: '文本文件', accept: 'application/pdf' },
|
||||
doc: { icon: 'i-doc', color: '#39afff', name: '文本文件', accept: 'application/msword' },
|
||||
docx: { icon: 'i-docx', color: '#39afff', name: '文本文件', accept: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' },
|
||||
folder: { icon: 'i-wenjianjia', color: '#ffd94a', name: '文件夹', accept: '' }
|
||||
}
|
||||
|
||||
export function getAcceptType (accept) {
|
||||
if (!accept) return
|
||||
|
||||
for (const type in ACCEPT_MAP) {
|
||||
if (accept.startsWith(ACCEPT_MAP[type].accept.replace(/\*$/, ''))) return type
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 颜色生成器
|
||||
*
|
||||
* @param {string} value
|
||||
* @returns
|
||||
*/
|
||||
export function colorGenerator (value) {
|
||||
if (!value) return
|
||||
return Number(value.split('').reduce((n, s) => n + s.charCodeAt(), '')).toString(16).replace(/.*(.{6})$/, '#$1')
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件工具类
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {[keyof ACCEPT_MAP]} options.accepts 指定可选的文件类型
|
||||
* @param {boolean} options.multiple 是否允许用户选择多个文件
|
||||
* @returns {Promise}
|
||||
*/
|
||||
export function getDistFile ({ accepts = [], multiple = false } = {}) {
|
||||
if (!getDistFile.el) { // 如果没有 Input Dom对象,则创建
|
||||
getDistFile.el = document.createElement('input')
|
||||
getDistFile.el.type = 'file'
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
getDistFile.el.setAttribute(
|
||||
'accept',
|
||||
(accepts?.length ? accepts : Object.keys(ACCEPT_MAP))
|
||||
.map(k => ACCEPT_MAP[k].accept).join(' , ')
|
||||
)
|
||||
getDistFile.el.setAttribute('multiple', multiple)
|
||||
|
||||
getDistFile.el.onchange = () => {
|
||||
resolve([...getDistFile.el.files])
|
||||
getDistFile.el.value = null
|
||||
}
|
||||
getDistFile.el.click()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载
|
||||
*
|
||||
* @param {string} src 文件地址
|
||||
* @param {string} name 文件下载名
|
||||
* @returns
|
||||
*/
|
||||
export async function download (src, name) {
|
||||
if (!src) return
|
||||
const href = await fetch(src).then(res => {
|
||||
if (res.status === 200) return res.arrayBuffer()
|
||||
throw Error('文件下载出错')
|
||||
})
|
||||
|
||||
if (!download.el) {
|
||||
download.el = document.createElement('a')
|
||||
}
|
||||
|
||||
download.el.download = name || ''
|
||||
download.el.href = URL.createObjectURL(new Blob([href]))
|
||||
download.el.click()
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地存储 localStorage
|
||||
*/
|
||||
export const lst = storage(localStorage)
|
||||
|
||||
/**
|
||||
* 本地存储 sessionStorage
|
||||
*/
|
||||
export const sst = storage(sessionStorage)
|
||||
435
front/src/utils/prototype.js
vendored
Normal file
435
front/src/utils/prototype.js
vendored
Normal file
@@ -0,0 +1,435 @@
|
||||
import jsPDF from 'jspdf'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { font } from './simhei-normal'
|
||||
/* eslint-disable no-extend-native */
|
||||
String.prototype.fetchValue = function (object) {
|
||||
return this.split('.').reduce((o, k) => (o === undefined || o === null ? undefined : o[k]), object || {})
|
||||
}
|
||||
|
||||
String.prototype.resolveObject = function (value) {
|
||||
const [first, ...os] = this.split('.').reverse()
|
||||
return os.reduce((o, k) => ({ [k]: o }), { [first]: value })
|
||||
}
|
||||
|
||||
String.prototype.fileLinkTransfer = function () {
|
||||
if (this) return import.meta.env.VITE_APP_BASE_URL + '/file-bucket/' + this
|
||||
}
|
||||
|
||||
File.prototype.fileLinkTransfer = function () {
|
||||
if (this) return URL.createObjectURL(this)
|
||||
}
|
||||
|
||||
Number.prototype.formatFileSize = function (fractionDigits = 2, type = 'string') {
|
||||
if (isNaN(this)) return this
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||
let size = this
|
||||
let index = 0
|
||||
while (size > 1024 && index < units.length - 1) {
|
||||
size = size / 1024
|
||||
index++
|
||||
}
|
||||
if (type === 'object') return { value: size.toFixed(fractionDigits), unit: units[index] }
|
||||
return size.toFixed(fractionDigits) + units[index]
|
||||
}
|
||||
|
||||
Date.prototype.format = function (fmt) {
|
||||
const o = {
|
||||
'M+': this.getMonth() + 1, // 月份
|
||||
'd+': this.getDate(), // 日
|
||||
'h+': this.getHours(), // 小时
|
||||
'm+': this.getMinutes(), // 分
|
||||
's+': this.getSeconds(), // 秒
|
||||
'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
|
||||
S: this.getMilliseconds() // 毫秒
|
||||
}
|
||||
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
|
||||
for (const k in o) {
|
||||
if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)) }
|
||||
}
|
||||
return fmt
|
||||
}
|
||||
|
||||
Date.prototype.toTypeStr = function (timestamp, fmt) {
|
||||
if (typeof timestamp === 'string') {
|
||||
fmt = timestamp
|
||||
timestamp = undefined
|
||||
}
|
||||
const time = (timestamp || new Date().getTime()) - this.getTime()
|
||||
return time < 60 * 1000
|
||||
? '刚刚'
|
||||
: time < 60 * 60 * 1000
|
||||
? Math.floor(time / (60 * 1000)) + '分钟前'
|
||||
: time < 24 * 60 * 60 * 1000
|
||||
? Math.floor(time / (60 * 60 * 1000)) + '小时前'
|
||||
: time < 48 * 60 * 60 * 1000
|
||||
? '昨天'
|
||||
: this.format(fmt || 'yyyy-MM-dd hh:mm')
|
||||
}
|
||||
|
||||
Array.generate = function (length = 0, fn) {
|
||||
const _list = []
|
||||
if (fn) {
|
||||
let i = 0
|
||||
while (i < length) _list.push(fn(i++))
|
||||
}
|
||||
return _list
|
||||
}
|
||||
|
||||
Array.prototype.toTree = function ({ key = 'id', parentKey = 'pid', childKey = 'children' } = {}) {
|
||||
const list = this // JSON.parse(JSON.stringify(this))
|
||||
const map = {}
|
||||
let index = this.length
|
||||
while (index--) {
|
||||
map[list[index][key]] = list[index]
|
||||
}
|
||||
|
||||
const tree = []
|
||||
const len = list.length
|
||||
while (++index < len) {
|
||||
const item = list[index]
|
||||
const pid = item[parentKey]
|
||||
if (map[pid]) {
|
||||
map[pid][childKey] ??= []
|
||||
map[pid][childKey].push(item)
|
||||
} else {
|
||||
tree.push(item)
|
||||
}
|
||||
}
|
||||
return { map, tree }
|
||||
}
|
||||
|
||||
// window.Vue.prototype.$html2Pdf = async function (id, isPrint) {
|
||||
// const ele = document.getElementById(id)
|
||||
// console.log(ele)
|
||||
// html2canvas(ele, { useCORS: true }).then(canvas => {
|
||||
// // 未生成pdf的html页面高度
|
||||
// // 未生成pdf的html页面高度
|
||||
// let leftHeight = canvas.height
|
||||
|
||||
// const a4Width = 595.28
|
||||
// const a4Height = 841.89 // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
|
||||
// // 一页pdf显示html页面生成的canvas高度;
|
||||
// const a4HeightRef = Math.floor((canvas.width / a4Width) * a4Height)
|
||||
|
||||
// // pdf页面偏移
|
||||
// let position = 0
|
||||
|
||||
// const pageData = canvas.toDataURL('image/jpeg', 1.0)
|
||||
|
||||
// const pdf = new jsPDF('p', 'pt', 'a4') // A4纸,纵向
|
||||
// let index = 1
|
||||
// const canvas1 = document.createElement('canvas')
|
||||
// let height
|
||||
// pdf.setDisplayMode('fullwidth', 'continuous', 'FullScreen')
|
||||
|
||||
// const pdfName = 'title'
|
||||
// function createImpl (canvas) {
|
||||
// console.log(leftHeight, a4HeightRef)
|
||||
// if (leftHeight > 0) {
|
||||
// index++
|
||||
|
||||
// let checkCount = 0
|
||||
// if (leftHeight > a4HeightRef) {
|
||||
// let i = position + a4HeightRef
|
||||
// for (i = position + a4HeightRef; i >= position; i--) {
|
||||
// let isWrite = true
|
||||
// for (let j = 0; j < canvas.width; j++) {
|
||||
// const c = canvas.getContext('2d').getImageData(j, i, 1, 1).data
|
||||
|
||||
// if (c[0] !== 0xff || c[1] !== 0xff || c[2] !== 0xff) {
|
||||
// isWrite = false
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// if (isWrite) {
|
||||
// checkCount++
|
||||
// if (checkCount >= 10) {
|
||||
// break
|
||||
// }
|
||||
// } else {
|
||||
// checkCount = 0
|
||||
// }
|
||||
// }
|
||||
// height = Math.round(i - position) || Math.min(leftHeight, a4HeightRef)
|
||||
// if (height <= 0) {
|
||||
// height = a4HeightRef
|
||||
// }
|
||||
// } else {
|
||||
// height = leftHeight
|
||||
// }
|
||||
|
||||
// canvas1.width = canvas.width
|
||||
// canvas1.height = height
|
||||
|
||||
// console.log(index, 'height:', height, 'pos', position)
|
||||
|
||||
// const ctx = canvas1.getContext('2d')
|
||||
// ctx.drawImage(
|
||||
// canvas,
|
||||
// 0,
|
||||
// position,
|
||||
// canvas.width,
|
||||
// height,
|
||||
// 0,
|
||||
// 0,
|
||||
// canvas.width,
|
||||
// height
|
||||
// )
|
||||
|
||||
// const pageHeight = Math.round((a4Width / canvas.width) * height)
|
||||
// // pdf.setPageSize(null, pageHeight)
|
||||
// if (position !== 0) {
|
||||
// pdf.addPage()
|
||||
// }
|
||||
// pdf.addImage(
|
||||
// canvas1.toDataURL('image/jpeg', 1.0),
|
||||
// 'JPEG',
|
||||
// 20,
|
||||
// 20,
|
||||
// a4Width,
|
||||
// (a4Width / canvas1.width) * height
|
||||
// )
|
||||
// leftHeight -= height
|
||||
// position += height
|
||||
// if (leftHeight > 0) {
|
||||
// setTimeout(createImpl, 500, canvas)
|
||||
// } else {
|
||||
// console.log(pdf)
|
||||
// pdf.autoPrint()
|
||||
// window.open(pdf.output('bloburl'), '_blank')
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // 当内容未超过pdf一页显示的范围,无需分页
|
||||
// if (leftHeight < a4HeightRef) {
|
||||
// pdf.addImage(
|
||||
// pageData,
|
||||
// 'JPEG',
|
||||
// 20,
|
||||
// 20,
|
||||
// a4Width,
|
||||
// (a4Width / canvas.width) * leftHeight
|
||||
// )
|
||||
// console.log(pdf)
|
||||
// pdf.autoPrint()
|
||||
// window.open(pdf.output('bloburl'), '_blank')
|
||||
// } else {
|
||||
// try {
|
||||
// pdf.deletePage(0)
|
||||
// setTimeout(createImpl, 500, canvas)
|
||||
// } catch (err) {
|
||||
// // console.log(err);
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
// window.Vue.prototype.$html2Pdf = async function (id, isPrint) {
|
||||
// const ele = document.getElementById(id)
|
||||
// const pageWidth = 595.28 - 40 // A4纸的宽高 减去左右边距
|
||||
// const pageHeight = 841.89 - 40
|
||||
// // a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
|
||||
|
||||
// html2canvas(ele, {
|
||||
// // allowTaint: true,
|
||||
// // taintTest: false,
|
||||
// useCORS: true,
|
||||
// backgroundColor: '#FFF',
|
||||
// width: ele.offsetWidth - 15, // 因为多出的需要剪裁掉,
|
||||
// height: ele.offsetHeight
|
||||
// // async: true,
|
||||
// // scale: '1', // 放大倍数
|
||||
// // dpi: '192', // 精度
|
||||
// // scrollY: ele.top, // 关键代码
|
||||
// // height: ele.height + 50 // 加高度,避免截取不全
|
||||
// }).then(canvas => {
|
||||
// const contentWidth = canvas.width
|
||||
// const contentHeight = canvas.height
|
||||
// const pageData = canvas.toDataURL('image/jpeg/png', 1)
|
||||
// const PDF = new jsPDF('p', 'mm', 'a4') // , true
|
||||
// let pageCount = 1
|
||||
// // canvas图片的高
|
||||
// const imgHeight = pageWidth / contentWidth * contentHeight // canvas的宽与PDF的宽比列一样的时候,canvas的高缩放后的值
|
||||
|
||||
// let leftHeight = imgHeight
|
||||
// let position = 0
|
||||
// // 如果图片的高小于A4纸的高,不分页
|
||||
// if (leftHeight < pageHeight) {
|
||||
// PDF.addImage(pageData, 'JPEG', 20, 0, pageWidth, imgHeight)
|
||||
// } else {
|
||||
// // 分页
|
||||
// // let index = 0
|
||||
// while (leftHeight > 0) {
|
||||
// pageCount++
|
||||
|
||||
// PDF.addImage(pageData, 'JPEG', 20, position, pageWidth, imgHeight)
|
||||
// leftHeight = leftHeight - pageHeight
|
||||
// position -= pageHeight
|
||||
// if (leftHeight > 0) {
|
||||
// PDF.addPage()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// PDF.addFileToVFS('blobs', font)
|
||||
|
||||
// PDF.addFont('blobs', 'font_blobs', 'normal')
|
||||
// // 通过字体名使用字体
|
||||
// PDF.setFont('font_blobs')
|
||||
|
||||
// for (let i = 1; i < pageCount; i++) {
|
||||
// console.log(i)
|
||||
// PDF.setPage(i)
|
||||
// PDF.setFontSize(8)
|
||||
// PDF.text('当前第 ' + String(i) + '页 共 ' + String(pageCount) + '页', PDF.internal.pageSize.width / 2, pageHeight + 35, {
|
||||
// align: 'center'
|
||||
// })
|
||||
// }
|
||||
// PDF.autoPrint()
|
||||
// window.open(PDF.output('bloburl'), '_blank')
|
||||
// })
|
||||
// }
|
||||
const isSplit = (nodes, index, pageHeight) => {
|
||||
// 计算当前这块dom是否跨越了a4大小,以此分割
|
||||
if (nodes[index].offsetTop + nodes[index].offsetHeight < pageHeight && nodes[index + 1] && nodes[index + 1].offsetTop + nodes[index + 1].offsetHeight > pageHeight) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
const formatPdf = (ele) => {
|
||||
const ST = document.documentElement.scrollTop || document.body.scrollTop
|
||||
const SL = document.documentElement.scrollLeft || document.body.scrollLeft
|
||||
document.documentElement.scrollTop = 0
|
||||
document.documentElement.scrollLeft = 0
|
||||
document.body.scrollTop = 0
|
||||
document.body.scrollLeft = 0
|
||||
// const ST = document.documentElement.scrollTop || document.body.scrollTop
|
||||
// const SL = document.documentElement.scrollLeft || document.body.scrollLeft
|
||||
document.documentElement.scrollTop = 0
|
||||
document.documentElement.scrollLeft = 0
|
||||
document.body.scrollTop = 0
|
||||
document.body.scrollLeft = 0
|
||||
// 获取滚动条的位置并赋值为0,因为是el-dialog弹框,并且内容较多出现了纵向的滚动条,截图出来的效果只能截取到视图窗口显示的部分,超出窗口部分则无法生成。所以先将滚动条置顶
|
||||
const A4_WIDTH = 592.28
|
||||
const A4_HEIGHT = 841.89
|
||||
|
||||
const imageWrapper = ele // 获取DOM
|
||||
const pageHeight = imageWrapper.scrollWidth / A4_WIDTH * A4_HEIGHT + 80
|
||||
// const lableListID = imageWrapper.querySelectorAll('.main-form-area')
|
||||
const lableListID = imageWrapper.querySelectorAll('.answer-item')
|
||||
// 进行分割操作,当dom内容已超出a4的高度,则将该dom前插入一个空dom,把他挤下去,分割
|
||||
for (let i = 0; i < lableListID.length; i++) {
|
||||
// console.log(lableListID[i])
|
||||
const multiple = Math.ceil((lableListID[i].offsetTop + lableListID[i].offsetHeight) / pageHeight)
|
||||
if (isSplit(lableListID, i, multiple * pageHeight)) {
|
||||
// console.log(lableListID[i])
|
||||
const divParent = lableListID[i].parentNode // 获取该div的父节点
|
||||
const newNode = document.createElement('div')
|
||||
newNode.className = 'emptyDiv'
|
||||
newNode.style.background = '#ffffff'
|
||||
const _H = multiple * pageHeight - (lableListID[i].offsetTop + lableListID[i].offsetHeight)
|
||||
// 留白
|
||||
newNode.style.height = _H + 'px'
|
||||
newNode.style.width = '100%'
|
||||
const next = lableListID[i].nextSibling // 获取div的下一个兄弟节点
|
||||
// 判断兄弟节点是否存在
|
||||
if (next) {
|
||||
// 存在则将新节点插入到div的下一个兄弟节点之前,即div之后
|
||||
divParent.insertBefore(newNode, next)
|
||||
} else {
|
||||
// 不存在则直接添加到最后,appendChild默认添加到divParent的最后
|
||||
divParent.appendChild(newNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
window.Vue.prototype.$html2Pdf = async function (id, exportInfo) {
|
||||
const ele = document.getElementById(id)
|
||||
formatPdf(ele)
|
||||
// a4纸的尺寸[595.28,841.89],html页面生成的canvas在pdf中图片的宽高
|
||||
|
||||
html2canvas(ele, {
|
||||
// allowTaint: true,
|
||||
// // taintTest: false,
|
||||
// x: ele.getBoundingClientRect().left + 13, // 绘制的dom元素相对于视口的位置
|
||||
// y: ele.getBoundingClientRect().top,
|
||||
useCORS: true,
|
||||
backgroundColor: '#FFF',
|
||||
width: ele.offsetWidth - 15, // 因为多出的需要剪裁掉,
|
||||
height: ele.offsetHeight,
|
||||
// async: true,
|
||||
scale: 3, // 放大倍数
|
||||
dpi: 350 // 精度
|
||||
// scrollY: ele.top, // 关键代码
|
||||
// height: ele.height + 50 // 加高度,避免截取不全
|
||||
}).then(canvas => {
|
||||
const pdf = new jsPDF('p', 'mm', 'a4') // A4纸,纵向
|
||||
const ctx = canvas.getContext('2d')
|
||||
const a4w = 190; const a4h = 277 // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
|
||||
const imgHeight = Math.floor(a4h * canvas.width / a4w) // 按A4显示比例换算一页图像的像素高度
|
||||
let renderedHeight = 0
|
||||
|
||||
while (renderedHeight < canvas.height) {
|
||||
const page = document.createElement('canvas')
|
||||
page.width = canvas.width
|
||||
page.height = Math.min(imgHeight, canvas.height - renderedHeight)// 可能内容不足一页
|
||||
// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
|
||||
if (renderedHeight === 0) {
|
||||
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, (Math.min(imgHeight, canvas.height - renderedHeight) + 20)), 0, 0)
|
||||
pdf.addImage(page.toDataURL('image/jpeg', 0.2), 'JPEG', 10, 0, a4w, Math.min(a4h, a4w * page.height / page.width)) // 添加图像到页面,保留10mm边距
|
||||
} else {
|
||||
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0)
|
||||
pdf.addImage(page.toDataURL('image/jpeg', 0.2), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)) // 添加图像到页面,保留10mm边距
|
||||
}
|
||||
renderedHeight += imgHeight
|
||||
if (renderedHeight < canvas.height) { pdf.addPage() }// 如果后面还有内容,添加一个空页
|
||||
}
|
||||
const pageCount = pdf.internal.getNumberOfPages()
|
||||
pdf.addFileToVFS('blobs', font)
|
||||
|
||||
pdf.addFont('blobs', 'font_blobs', 'normal')
|
||||
// 通过字体名使用字体
|
||||
pdf.setFont('font_blobs')
|
||||
pdf.setFontSize(8)
|
||||
for (let i = 1; i <= pageCount; i++) {
|
||||
pdf.setPage(i)
|
||||
pdf.text('第 ' + String(i) + ' 页 共 ' + String(pageCount) + ' 页', pdf.internal.pageSize.width / 2, 287 + 5, {
|
||||
align: 'center'
|
||||
})
|
||||
}
|
||||
console.log(exportInfo, 11111111111111)
|
||||
if (exportInfo) {
|
||||
pdf.save(exportInfo.title + '.pdf')
|
||||
} else {
|
||||
pdf.autoPrint()
|
||||
window.open(pdf.output('bloburl'), '_blank')
|
||||
const emptyDivs = ele.querySelectorAll('.emptyDiv')
|
||||
emptyDivs.forEach(item => {
|
||||
item.parentNode.removeChild(item)
|
||||
console.log(item)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.Vue.prototype.$elementFullscreen = async function (ele, callback, todo) {
|
||||
console.log(typeof ele)
|
||||
if (!(ele instanceof HTMLElement)) {
|
||||
ele = ele.$el
|
||||
}
|
||||
const div = document.createElement('div')
|
||||
await ele.requestFullscreen()
|
||||
window.Vue.prototype.$store.isFullscreen = true
|
||||
console.log(todo)
|
||||
todo && todo()
|
||||
|
||||
setTimeout(() => {
|
||||
const fun = () => {
|
||||
ele.removeEventListener('fullscreenchange', fun)
|
||||
window.Vue.prototype.$store.isFullscreen = false
|
||||
callback()
|
||||
}
|
||||
ele.addEventListener('fullscreenchange', fun)
|
||||
}, 100)
|
||||
console.log(ele)
|
||||
}
|
||||
51
front/src/utils/qiankun-init.js
Normal file
51
front/src/utils/qiankun-init.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { registerMicroApps, start } from 'qiankun'
|
||||
import store from '../store'
|
||||
// 子应用配置
|
||||
export const apps = [
|
||||
{
|
||||
name: '子应用1',
|
||||
entry: '//localhost:9099',
|
||||
id: 'app1',
|
||||
container: '#app1',
|
||||
activeRule: '/app1',
|
||||
// 测试传参,并将store传递至子应用进行消息通信!
|
||||
props: { test: 1111, store }
|
||||
},
|
||||
{
|
||||
name: '子应用2',
|
||||
entry: '//localhost:8888',
|
||||
id: 'app2',
|
||||
type: 'qiankun',
|
||||
container: '#app2',
|
||||
activeRule: '/app2',
|
||||
// 测试传参,并将store传递至子应用进行消息通信!
|
||||
props: { test: 1111, store }
|
||||
}
|
||||
]
|
||||
// 乾坤初始化方法
|
||||
export default function qianKunInit () {
|
||||
window.__POWERED_BY_QIANKUN_PARENT__ = true
|
||||
registerMicroApps(apps, {
|
||||
beforeLoad: [
|
||||
(app) => {
|
||||
console.log(app, '111111111111111111')
|
||||
}],
|
||||
destoryed: [
|
||||
(app) => {
|
||||
}
|
||||
]
|
||||
})
|
||||
const mainEle = document.getElementById('qiankun-main')
|
||||
apps.forEach(item => {
|
||||
const child = document.createElement('div')
|
||||
child.id = item.id
|
||||
mainEle.appendChild(child)
|
||||
item.container = child
|
||||
console.log(child)
|
||||
})
|
||||
start({
|
||||
prefetch: false, // 可选,是否开启预加载,默认为 true。 不开启
|
||||
sandbox: true, // 可选,是否开启沙箱,默认为 true。// 从而确保微应用的样式不会对全局造成影响。
|
||||
singular: true // 可选,是否为单实例场景,单实例指的是同一时间只会渲染一个微应用。默认为 true。
|
||||
})
|
||||
}
|
||||
7
front/src/utils/simhei-normal.js
Normal file
7
front/src/utils/simhei-normal.js
Normal file
File diff suppressed because one or more lines are too long
52
front/src/utils/storage.js
Normal file
52
front/src/utils/storage.js
Normal file
@@ -0,0 +1,52 @@
|
||||
export default (storage) => {
|
||||
if (!storage) return
|
||||
|
||||
const skey = (key) => '' + key
|
||||
|
||||
return {
|
||||
/**
|
||||
* 获取
|
||||
* @param {string} key key
|
||||
* @param {any} defaultValue defaultValue
|
||||
*/
|
||||
get (key, defaultValue) {
|
||||
try {
|
||||
return JSON.parse(storage.getItem(skey(key))) || defaultValue
|
||||
} catch (error) {
|
||||
return defaultValue
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存
|
||||
* @param {string} key key
|
||||
* @param {any} val 值
|
||||
*/
|
||||
save (key, val) {
|
||||
if (val === undefined || val === null) return this.remove(key)
|
||||
storage.setItem(skey(key), JSON.stringify(val))
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取 所有key
|
||||
*/
|
||||
keys () {
|
||||
return Object.keys(storage)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param {string} key key
|
||||
*/
|
||||
remove (key) {
|
||||
storage.removeItem(skey(key))
|
||||
},
|
||||
|
||||
/**
|
||||
* 清空
|
||||
*/
|
||||
clear () {
|
||||
storage.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user