|
@@ -0,0 +1,471 @@
|
|
|
+import pdfMake from "pdfmake/build/pdfmake";
|
|
|
+import pdfFonts from "pdfmake/build/vfs_fonts";
|
|
|
+
|
|
|
+
|
|
|
+import Regular from '@/assets/pdf/font/SourceHanSansCN-Regular.otf'
|
|
|
+import Bold from '@/assets/pdf/font/SourceHanSansCN-Bold.otf'
|
|
|
+import STXINGKA from '@/assets/pdf/font/STXINGKA.TTF'
|
|
|
+
|
|
|
+export const exportPDF = async (_semesterReport) => {
|
|
|
+
|
|
|
+ const semesterReport = JSON.parse(JSON.stringify(_semesterReport))
|
|
|
+
|
|
|
+ const createPdfContent = () => {
|
|
|
+
|
|
|
+ const _data = semesterReport
|
|
|
+
|
|
|
+ const H1 = 30
|
|
|
+
|
|
|
+ const H2 = 20
|
|
|
+
|
|
|
+ const H3 = 14
|
|
|
+
|
|
|
+ const H4 = 12
|
|
|
+
|
|
|
+ const H5 = 10
|
|
|
+
|
|
|
+ const brakePage = {
|
|
|
+ text: " ",
|
|
|
+ margin: [0, 0, 0, 600]
|
|
|
+ }
|
|
|
+
|
|
|
+ const H1Template = (text) => (
|
|
|
+ { text: `${text}`,
|
|
|
+ fontSize: H1,
|
|
|
+ margin: [0, 40, 0, 15],
|
|
|
+ color: "blue",
|
|
|
+ bold: true,
|
|
|
+ font: 'STXINGKA.TTF',
|
|
|
+ alignment: 'center'
|
|
|
+ })
|
|
|
+
|
|
|
+ const H2Template = (text) => (
|
|
|
+ { text: `${text}`,
|
|
|
+ color: '#1a2c5e',
|
|
|
+ fontSize: H2,
|
|
|
+ margin: [0, 15, 0, 15],
|
|
|
+ bold: true
|
|
|
+ })
|
|
|
+
|
|
|
+ const H3Template = (text) => (
|
|
|
+ { text: `${text}`,
|
|
|
+ fontSize: H3,
|
|
|
+ color: '#1a2c5e',
|
|
|
+ margin: [0, 10, 0, 10],
|
|
|
+ bold: true
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ const H3DotTemplate = (text) => (
|
|
|
+ {
|
|
|
+ text: '',
|
|
|
+
|
|
|
+ },
|
|
|
+ {
|
|
|
+ columns: [
|
|
|
+ {
|
|
|
+ image: 'deg',
|
|
|
+ width: 6,
|
|
|
+ margin: [0, 5, 0, 10],
|
|
|
+ },
|
|
|
+ { text: `${text}`,
|
|
|
+ fontSize: H3,
|
|
|
+ // color: '#1a2c5e',
|
|
|
+ margin: [5, 0, 0, 10],
|
|
|
+ bold: true
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+ const H4Template = (text) => (
|
|
|
+ { text: `${text}`,
|
|
|
+ fontSize: H4,
|
|
|
+ color: '#1a2c5e',
|
|
|
+ margin: [0, 15, 0, 15],
|
|
|
+ })
|
|
|
+
|
|
|
+ const H5Template = (text) => (
|
|
|
+ { text: `${text}`,
|
|
|
+ fontSize: H5,
|
|
|
+ margin: [0, 15, 0, 15],
|
|
|
+ lineHeight: 2
|
|
|
+ })
|
|
|
+
|
|
|
+ const H5ColorTemplate = (title, text) => (
|
|
|
+ {
|
|
|
+ columns: [
|
|
|
+ {
|
|
|
+ image: 'deg',
|
|
|
+ width: 6
|
|
|
+ },
|
|
|
+ { text: `${title}`,
|
|
|
+ fontSize: H5,
|
|
|
+ color: '#2a69fd',
|
|
|
+ width: 55,
|
|
|
+ margin: [5, -2, 0, 0],
|
|
|
+ },
|
|
|
+ { text: `${text}`,
|
|
|
+ fontSize: H5,
|
|
|
+ margin: [5, -2, 0, 0],
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+ const qrTemplate = (url) => ({ qr: url, fit: '120', alignment: 'center'})
|
|
|
+
|
|
|
+ const textTemplate = (text) => ({ text: `${text}`, fontSize: H4, margin: [0, 15, 0, 15] })
|
|
|
+
|
|
|
+ const imgTemplate = (url) => ({image: url, width: 160, alignment: 'center', margin: [0, 30, 0, 30] } )
|
|
|
+
|
|
|
+ const caclImgSplit = (arr) => {
|
|
|
+ if (arr.length === 0 ) return [{}]
|
|
|
+
|
|
|
+ let lastValue = null
|
|
|
+
|
|
|
+ if (arr.length % 2 !== 0 && arr.length >= 3 ) {
|
|
|
+ lastValue = arr.splice(arr.length - 1, 1)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (arr.length === 1) return [{...imgTemplate(arr[0])}]
|
|
|
+
|
|
|
+ const _arr = [[]]
|
|
|
+
|
|
|
+ arr.forEach( item => {
|
|
|
+ const lastIndex = _arr.length - 1
|
|
|
+ if (_arr[lastIndex].length < 2) {
|
|
|
+ _arr[lastIndex].push(item)
|
|
|
+ } else {
|
|
|
+ _arr.push([])
|
|
|
+ _arr[_arr.length - 1].push(item)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ const r = _arr.map( imgs => {
|
|
|
+ return {
|
|
|
+ columns: [
|
|
|
+ {
|
|
|
+ text: "",
|
|
|
+ width: 82
|
|
|
+ },
|
|
|
+ imgTemplate(imgs[0]),
|
|
|
+ {
|
|
|
+ text: "",
|
|
|
+ width: 30
|
|
|
+ },
|
|
|
+ imgTemplate(imgs[1])
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ )
|
|
|
+ if (lastValue != null) r.push(imgTemplate(lastValue[0]))
|
|
|
+ return r
|
|
|
+ }
|
|
|
+
|
|
|
+ const calcVideoSplit = (videos) => {
|
|
|
+ return videos.map( video => {
|
|
|
+ return [qrTemplate(video), {...H5Template('视频扫码查看'), alignment: 'center'}]
|
|
|
+ }).flat(2)
|
|
|
+ }
|
|
|
+
|
|
|
+ const cover = {
|
|
|
+ image: 'cover',
|
|
|
+ width: 450,
|
|
|
+ alignment: 'center'
|
|
|
+ }
|
|
|
+
|
|
|
+ const ava = {
|
|
|
+ image: _data.babyHeadImg,
|
|
|
+ width: 200,
|
|
|
+ alignment: 'center',
|
|
|
+ margin: [0, 50,20, 0]
|
|
|
+ }
|
|
|
+
|
|
|
+ const coverInfo = {
|
|
|
+ text: `姓名:${_data.babyName}\n\n班级:${_data.className}\n\n成长阶段:${_data.startDate}-${_data.endDate}`,
|
|
|
+ alignment: 'center',
|
|
|
+ margin: [0, 50, 0, 200],
|
|
|
+ font: 'STXINGKA.TTF',
|
|
|
+ fontSize: 26
|
|
|
+ }
|
|
|
+
|
|
|
+ const userInfo = [
|
|
|
+ {
|
|
|
+ text: `姓名:${_data.babyName}`,
|
|
|
+ alignment: 'center',
|
|
|
+ font: 'STXINGKA.TTF',
|
|
|
+ margin: [0, 0, 0, 0],
|
|
|
+ bold: true,
|
|
|
+ fontSize: 24
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: `年龄:${_data.age}`,
|
|
|
+ margin: [0, 20, 0, 20],
|
|
|
+ alignment: 'center',
|
|
|
+ bold: true,
|
|
|
+ font: 'STXINGKA.TTF',
|
|
|
+ fontSize: 24
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: `我的幼儿园:\n${_data.schoolName}`,
|
|
|
+ margin: [0, 20, 0, 20],
|
|
|
+ alignment: 'center',
|
|
|
+ bold: true,
|
|
|
+ font: 'STXINGKA.TTF',
|
|
|
+ fontSize: 24
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: `我的爱好:\n${_data.hobby}`,
|
|
|
+ margin: [0, 20, 0, 20],
|
|
|
+ alignment: 'center',
|
|
|
+ bold: true,
|
|
|
+ font: 'STXINGKA.TTF',
|
|
|
+ fontSize: 24
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ text: `我的老师:\n${_data.teachers.join('、')}`,
|
|
|
+ // text: `我的老师:\n${_data.teachers.slice(0, 2)}`,
|
|
|
+ margin: [0, 20, 0, 600],
|
|
|
+ alignment: 'center',
|
|
|
+ font: 'STXINGKA.TTF',
|
|
|
+ bold: true,
|
|
|
+ fontSize: 24
|
|
|
+ },
|
|
|
+ ]
|
|
|
+
|
|
|
+ const learnDepthList = [
|
|
|
+ H1Template("综合发展情况"),
|
|
|
+ H2Template("高阶思维评估概括"),
|
|
|
+ textTemplate(_data.learnDepthList.join('、')),
|
|
|
+ H2Template("幼儿分领域评估概括"),
|
|
|
+ ..._data.domainAbilityNameList.map( item => {
|
|
|
+ return [ H3DotTemplate(item.domainName), H5Template('评估了 ' + item.abilityNameList.join('、') + item.abilityNameList.length + ' 个能力' ) ]
|
|
|
+ })
|
|
|
+ ]
|
|
|
+
|
|
|
+ const domainAbilityNameList = [H1Template("分领域能力评估概括")]
|
|
|
+
|
|
|
+ _data.domainAbilityNameList.forEach(item => {
|
|
|
+ domainAbilityNameList.push(H2Template(item.domainName))
|
|
|
+ domainAbilityNameList.push(textTemplate(item.abilityNameList.join('、')))
|
|
|
+ })
|
|
|
+
|
|
|
+ domainAbilityNameList.push(brakePage)
|
|
|
+
|
|
|
+ const questionList = [
|
|
|
+ H1Template("问题探究"),
|
|
|
+ ..._data.questionList.map( item => {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ const r = item.questions.map( (question, index) => {
|
|
|
+
|
|
|
+ const date = {...H5ColorTemplate('记录日期:', question.recordDate), margin: [0, -2, 0, 15],} // + question.recordDate
|
|
|
+
|
|
|
+ const activity = H5ColorTemplate('活动形式:' , question.activityCategories.join('、')) // + question.activityCategories.join('、')
|
|
|
+ // const columns = {
|
|
|
+ // columns: [H4Template('记录日期:' + question.recordDate), H4Template('活动形式:' + question.activityCategories.join('、'))]
|
|
|
+ // }
|
|
|
+ const title1 = H4Template('问题记录:')
|
|
|
+ const quesSection = H5Template(`问题${index + 1}: ${question.question}`)
|
|
|
+ const title2 = H2Template('探究过程')
|
|
|
+
|
|
|
+ const plan = H3DotTemplate('计划')
|
|
|
+
|
|
|
+ const planContent = H5Template(question.plan.content)
|
|
|
+
|
|
|
+ const planImgs = caclImgSplit(question.plan.images)
|
|
|
+
|
|
|
+ const planVideos = calcVideoSplit(question.plan.videos)
|
|
|
+
|
|
|
+ const practice = H3DotTemplate('实施')
|
|
|
+
|
|
|
+ const practiceContent = H5Template(question.practice.content)
|
|
|
+
|
|
|
+ const practiceImgs = caclImgSplit(question.practice.images)
|
|
|
+
|
|
|
+ const practiceVideos = calcVideoSplit(question.practice.videos)
|
|
|
+
|
|
|
+ const summary = H3DotTemplate('总结与反思')
|
|
|
+
|
|
|
+ const summaryContent = H5Template(question.summary.content)
|
|
|
+
|
|
|
+ const summaryImgs = caclImgSplit(question.summary.images)
|
|
|
+
|
|
|
+ const summaryVideos = calcVideoSplit(question.summary.videos)
|
|
|
+
|
|
|
+ const tweaks = H3DotTemplate('调整')
|
|
|
+
|
|
|
+ const tweaksContent = H5Template(question.tweaks.content)
|
|
|
+
|
|
|
+ const tweaksImgs = caclImgSplit(question.tweaks.images)
|
|
|
+
|
|
|
+ const tweaksVideos = calcVideoSplit(question.tweaks.videos)
|
|
|
+
|
|
|
+ // babyResult
|
|
|
+ const baby = H3Template('高阶思维评估')
|
|
|
+
|
|
|
+ const bbContent = []
|
|
|
+
|
|
|
+ question.babyResults.forEach( bb => {
|
|
|
+
|
|
|
+ bbContent.push(H4Template('记录对象:' + bb.babyName))
|
|
|
+
|
|
|
+ bb.list.forEach( b => {
|
|
|
+ bbContent.push(H4Template('·' + b.learnDepth + b.levelCode))
|
|
|
+ bbContent.push(H5Template(b.levelText))
|
|
|
+ })
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ return [
|
|
|
+ date, activity, title1, quesSection, title2, plan, planContent, ...planImgs, ...planVideos,
|
|
|
+ practice, practiceContent, ...practiceImgs, ...practiceVideos, summary, summaryContent, ...summaryImgs, ...summaryVideos, tweaks, tweaksContent, ...tweaksImgs ,
|
|
|
+ ...tweaksVideos, baby, ...bbContent
|
|
|
+ ]
|
|
|
+ })
|
|
|
+
|
|
|
+ return [
|
|
|
+
|
|
|
+
|
|
|
+ H2Template( `${item.topic}`),
|
|
|
+ H5ColorTemplate(`记录教师:`, item.teacherName),
|
|
|
+ H4Template( `${item.background}`),
|
|
|
+ ...r
|
|
|
+ ]
|
|
|
+ })
|
|
|
+ ]
|
|
|
+
|
|
|
+ const domainDataList = [
|
|
|
+ H1Template('行为记录'),
|
|
|
+ ..._data.domainDataList.map( item => {
|
|
|
+ const title = H2Template(item.domainName)
|
|
|
+
|
|
|
+ const recordList = []
|
|
|
+
|
|
|
+ item.recordList.map( record => {
|
|
|
+
|
|
|
+ recordList.push(H4Template('记录日期:' + record.recordDate))
|
|
|
+ recordList.push(H4Template('观察实录:'))
|
|
|
+ recordList.push(caclImgSplit(record.story.images))
|
|
|
+ recordList.push(H4Template(record.abilityName))
|
|
|
+ recordList.push(H4Template('进阶能力描述:'))
|
|
|
+ recordList.push(H4Template(record.growth))
|
|
|
+ recordList.push(H4Template('家园共育策略'))
|
|
|
+ recordList.push(H5ColorTemplate('一日活动', ''))
|
|
|
+ recordList.push(H5Template(record.tactics))
|
|
|
+ recordList.push(H5ColorTemplate('家园共育', ''))
|
|
|
+ recordList.push(H5Template(record.education))
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ return [title, ...recordList]
|
|
|
+ }).flat(2)
|
|
|
+ ]
|
|
|
+
|
|
|
+
|
|
|
+ return [cover, ava, coverInfo, { text: ' ', margin: [0, 0, 0, 120] }, ...userInfo, ...learnDepthList, brakePage, ...questionList.flat(2 ), brakePage, ...domainDataList]
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ const findImgs = () => {
|
|
|
+
|
|
|
+ const question = semesterReport.questionList
|
|
|
+ const domainDataList = semesterReport.domainDataList
|
|
|
+
|
|
|
+ const r = {
|
|
|
+ [semesterReport.babyHeadImg]: semesterReport.babyHeadImg,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ question.forEach(item => {
|
|
|
+ item.questions.forEach(_ => {
|
|
|
+ _.plan.images.forEach( img => r[img ] = img + '?imageMogr2/thumbnail/!72p' )
|
|
|
+ _.practice.images.forEach( img => r[ img] = img + '?imageMogr2/thumbnail/!72p')
|
|
|
+ _.summary.images.forEach( img => r[img ] = img + '?imageMogr2/thumbnail/!72p')
|
|
|
+ _.tweaks.images.forEach( img => r[img] = img + '?imageMogr2/thumbnail/!72p' )
|
|
|
+ }
|
|
|
+ )
|
|
|
+ })
|
|
|
+
|
|
|
+ domainDataList.forEach(item => {
|
|
|
+ item.recordList.forEach( record => {
|
|
|
+ record.story.images.forEach( image => r[image] = image + '?imageMogr2/thumbnail/!72p' )
|
|
|
+ })
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ return r
|
|
|
+ }
|
|
|
+
|
|
|
+ async function generate() {
|
|
|
+
|
|
|
+ const pdfContent = {
|
|
|
+ pageBreakBefore: false,
|
|
|
+ content: null,
|
|
|
+ images: {
|
|
|
+ ...findImgs(),
|
|
|
+ cover: "https://img.luojigou.vip/cover.png",
|
|
|
+ deg: "https://img.luojigou.vip/FvpoQUenV0XVm1U_DxONnfBIq0nR.png",
|
|
|
+ dot: "https://img.luojigou.vip/FjMe6awMO18PnKxhs5mHnmmvUKrt.png",
|
|
|
+
|
|
|
+ },
|
|
|
+ defaultStyle: {
|
|
|
+ font: 'SourceHanSans.ttf'
|
|
|
+ },
|
|
|
+ pageSize: 'A4',
|
|
|
+ pageMargins: [40, 30, 40, 30],
|
|
|
+ footer: function (currentPage, pageCount) {
|
|
|
+ return [
|
|
|
+ { text: currentPage.toString() + ' / ' + pageCount, alignment: 'center' }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ pdfContent.content = createPdfContent()
|
|
|
+ console.log(pdfContent.content );
|
|
|
+ pdfMake.createPdf(pdfContent).download();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ const isDev = import.meta.env.MODE === 'development'
|
|
|
+
|
|
|
+ const prefix = isDev ? location.origin + '/src/static' : `https://luojigou.vip/report/static`
|
|
|
+
|
|
|
+ pdfMake.fonts = isDev? {
|
|
|
+ "SourceHanSans.ttf": {
|
|
|
+ normal: prefix + '/SourceHanSansCN-Regular.otf',
|
|
|
+ bold: prefix + '/SourceHanSansCN-Bold.otf',
|
|
|
+ italics: prefix+ '/SourceHanSansCN-Regular.otf',
|
|
|
+ bolditalics:prefix + '/SourceHanSansCN-Bold.otf'
|
|
|
+ },
|
|
|
+ "STXINGKA.TTF": {
|
|
|
+ normal: prefix + '/STXINGKA.TTF',
|
|
|
+ bold: prefix + '/STXINGKA.TTF',
|
|
|
+ italics: prefix + '/STXINGKA.TTF',
|
|
|
+ bolditalics: prefix + '/STXINGKA.TTF',
|
|
|
+ }
|
|
|
+ } : {
|
|
|
+ "SourceHanSans.ttf": {
|
|
|
+ normal: Regular,
|
|
|
+ bold: Bold,
|
|
|
+ italics: Regular,
|
|
|
+ bolditalics: Bold
|
|
|
+ },
|
|
|
+ "STXINGKA.TTF": {
|
|
|
+ normal: STXINGKA,
|
|
|
+ bold: STXINGKA,
|
|
|
+ italics: STXINGKA,
|
|
|
+ bolditalics: STXINGKA,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ generate()
|
|
|
+}
|