|
|
@@ -1,4 +1,5 @@
|
|
1
|
1
|
import moment from 'moment';
|
|
|
2
|
+import fs from 'fs';
|
|
2
|
3
|
import commonModel from '../../model/commonModel.js';
|
|
3
|
4
|
import config from '../../config/index.js';
|
|
4
|
5
|
import _ from 'lodash';
|
|
|
@@ -181,7 +182,7 @@ export async function GenerateArticle(ctx) {
|
|
181
|
182
|
let result = globalCache.get(url);
|
|
182
|
183
|
if (result === 0) {
|
|
183
|
184
|
const params = ctx.request.body;
|
|
184
|
|
- const words = JSON.parse(params.Words).join(",");
|
|
|
185
|
+ const words = params.Words;
|
|
185
|
186
|
const articleStyle = params.ArticleStyle;
|
|
186
|
187
|
|
|
187
|
188
|
//文章类型
|
|
|
@@ -199,6 +200,7 @@ export async function GenerateArticle(ctx) {
|
|
199
|
200
|
"动物":"生活在地球上的各种生物,有的会跑,有的会飞,有的会游泳,比如猫、狗、大象、企鹅,它们都有自己的特点和习性。",
|
|
200
|
201
|
"环保":"指环境保护、保护大自然,让地球更干净、更健康。比如节约用水、减少垃圾、种树、不乱扔塑料袋,这样空气会更清新,动物也有更好的家园。每个人都可以从小事做起爱护地球。",
|
|
201
|
202
|
};
|
|
|
203
|
+
|
|
202
|
204
|
//等级难度
|
|
203
|
205
|
const LEVEL=[
|
|
204
|
206
|
{
|
|
|
@@ -221,7 +223,7 @@ export async function GenerateArticle(ctx) {
|
|
221
|
223
|
|
|
222
|
224
|
let content = "将"+words+"这些单词生成一篇英文文章。要求"+
|
|
223
|
225
|
"[难度];"+
|
|
224
|
|
- "单词若是脏话,像'f***'、's***'等,可以忽略;"+
|
|
|
226
|
+ "单词若是脏话,像'fuck'、'shit'等,可以忽略;"+
|
|
225
|
227
|
"文章类型是'"+articleStyle+"([类型])';"+
|
|
226
|
228
|
"文章单词数在200个左右,最多不能超过300个;"+
|
|
227
|
229
|
"文章按每句分成数组,且每句都有中文翻译;"+
|
|
|
@@ -232,6 +234,8 @@ export async function GenerateArticle(ctx) {
|
|
232
|
234
|
|
|
233
|
235
|
content = content.replace("[难度]",LEVEL[Number(params.Level)].Content);
|
|
234
|
236
|
|
|
|
237
|
+ if (articleStyle=="任意")
|
|
|
238
|
+ articleStyle=stringUtils.Random(0,ARTICLE_STYLE.length-1);
|
|
235
|
239
|
content = content.replace("[类型]",ARTICLE_STYLE[articleStyle]);
|
|
236
|
240
|
|
|
237
|
241
|
|
|
|
@@ -390,7 +394,7 @@ export async function GeneratePDF(ctx) {
|
|
390
|
394
|
try {
|
|
391
|
395
|
if (typeof content.Words === 'string') {
|
|
392
|
396
|
// 尝试解析JSON字符串
|
|
393
|
|
- words = JSON.parse(content.Words);
|
|
|
397
|
+ words = content.Words.join(",");
|
|
394
|
398
|
} else if (Array.isArray(content.Words)) {
|
|
395
|
399
|
// 已经是数组
|
|
396
|
400
|
words = content.Words;
|
|
|
@@ -424,7 +428,7 @@ export async function GeneratePDF(ctx) {
|
|
424
|
428
|
.text(articleText, pixelToPt(120), pixelToPt(250), {
|
|
425
|
429
|
width: pixelToPt(1240),
|
|
426
|
430
|
align: 'left',
|
|
427
|
|
- lineGap: pixelToPt(10) // 行间距
|
|
|
431
|
+ lineGap: pixelToPt(50) // 行间距
|
|
428
|
432
|
});
|
|
429
|
433
|
|
|
430
|
434
|
// 记录文章结束位置的y坐标
|
|
|
@@ -503,8 +507,9 @@ export async function GeneratePDF(ctx) {
|
|
503
|
507
|
align: 'left'
|
|
504
|
508
|
});
|
|
505
|
509
|
|
|
506
|
|
- // 问题选项
|
|
507
|
|
- doc.fontSize(pixelToPt(36));
|
|
|
510
|
+ // 问题选项 - 使用常规字体(Regular)
|
|
|
511
|
+ doc.font('Helvetica') // 明确设置为常规字体,不使用粗体
|
|
|
512
|
+ .fontSize(pixelToPt(36));
|
|
508
|
513
|
|
|
509
|
514
|
const options = questions[0].OptionsEnglish || [];
|
|
510
|
515
|
let optionY = doc.y + pixelToPt(20);
|
|
|
@@ -694,7 +699,25 @@ export async function GeneratePDF(ctx) {
|
|
694
|
699
|
width: pixelToPt(380),
|
|
695
|
700
|
align: 'right'
|
|
696
|
701
|
});
|
|
697
|
|
-
|
|
|
702
|
+
|
|
|
703
|
+ // 添加二维码图片
|
|
|
704
|
+ try {
|
|
|
705
|
+ // 计算图片位置:距离右边120像素,距离底部100像素
|
|
|
706
|
+ // 由于PDFKit使用左上角坐标系,需要计算左上角坐标
|
|
|
707
|
+ const qrCodeWidth = pixelToPt(200);
|
|
|
708
|
+ const qrCodeHeight = pixelToPt(200);
|
|
|
709
|
+ const qrCodeX = doc.page.width - pixelToPt(120) - qrCodeWidth; // 右边距离转换为左边距离
|
|
|
710
|
+ const qrCodeY = doc.page.height - pixelToPt(60) - qrCodeHeight; // 底部距离转换为顶部距离
|
|
|
711
|
+
|
|
|
712
|
+ // 添加二维码图片
|
|
|
713
|
+ doc.image('./public/images/acode/YJBDC_QRCode.png', qrCodeX, qrCodeY, {
|
|
|
714
|
+ width: qrCodeWidth,
|
|
|
715
|
+ height: qrCodeHeight
|
|
|
716
|
+ });
|
|
|
717
|
+ console.log("QR Code added successfully");
|
|
|
718
|
+ } catch (imgError) {
|
|
|
719
|
+ console.error("Error adding QR Code image:", imgError);
|
|
|
720
|
+ }
|
|
698
|
721
|
|
|
699
|
722
|
//console.log("PDF generation completed, finalizing document...");
|
|
700
|
723
|
|
|
|
@@ -735,4 +758,74 @@ export async function GeneratePDF(ctx) {
|
|
735
|
758
|
ctx.status = 500;
|
|
736
|
759
|
ctx.body = { error: error.message, stack: error.stack };
|
|
737
|
760
|
}
|
|
|
761
|
+}
|
|
|
762
|
+
|
|
|
763
|
+export async function BuildYJBDCQRCode(ctx) {
|
|
|
764
|
+ try {
|
|
|
765
|
+ // 获取微信访问令牌
|
|
|
766
|
+ const tokenUrl = `https://api.weixin.qq.com/cgi-bin/token?appid=${config.wx.yjbdc_appid}&secret=${config.wx.yjbdc_appsecret}&grant_type=client_credential`;
|
|
|
767
|
+
|
|
|
768
|
+ const tokenResponse = await axios.get(tokenUrl);
|
|
|
769
|
+ const tokenData = tokenResponse.data;
|
|
|
770
|
+
|
|
|
771
|
+ if (!tokenData || !tokenData.access_token) {
|
|
|
772
|
+ ctx.status = 400;
|
|
|
773
|
+ ctx.body = { errcode: 101, errStr: '获取微信访问令牌失败' };
|
|
|
774
|
+ return;
|
|
|
775
|
+ }
|
|
|
776
|
+
|
|
|
777
|
+ const accessToken = tokenData.access_token;
|
|
|
778
|
+
|
|
|
779
|
+ // 生成小程序码
|
|
|
780
|
+ const qrCodeUrl = `https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${accessToken}`;
|
|
|
781
|
+ const path = './public/images/acode/';
|
|
|
782
|
+ const imageUrl = 'YJBDC_QRCode.png';
|
|
|
783
|
+ const fullPath = path + imageUrl;
|
|
|
784
|
+
|
|
|
785
|
+ // 确保目录存在
|
|
|
786
|
+ if (!fs.existsSync(path)) {
|
|
|
787
|
+ fs.mkdirSync(path, { recursive: true });
|
|
|
788
|
+ }
|
|
|
789
|
+
|
|
|
790
|
+ const postData = {
|
|
|
791
|
+ width: 280,
|
|
|
792
|
+ scene: "SourceID=187"
|
|
|
793
|
+ };
|
|
|
794
|
+
|
|
|
795
|
+ // 使用axios获取二维码并保存到文件
|
|
|
796
|
+ const qrCodeResponse = await axios({
|
|
|
797
|
+ method: 'POST',
|
|
|
798
|
+ url: qrCodeUrl,
|
|
|
799
|
+ data: postData,
|
|
|
800
|
+ responseType: 'stream'
|
|
|
801
|
+ });
|
|
|
802
|
+
|
|
|
803
|
+ // 创建写入流
|
|
|
804
|
+ const writer = fs.createWriteStream(fullPath);
|
|
|
805
|
+
|
|
|
806
|
+ // 将响应数据写入文件
|
|
|
807
|
+ qrCodeResponse.data.pipe(writer);
|
|
|
808
|
+
|
|
|
809
|
+ // 返回成功响应
|
|
|
810
|
+ ctx.body = { errcode: 10000, message: "二维码生成请求已发送" };
|
|
|
811
|
+
|
|
|
812
|
+ // 处理文件写入完成事件
|
|
|
813
|
+ writer.on('finish', () => {
|
|
|
814
|
+ console.log("二维码生成成功:", fullPath);
|
|
|
815
|
+ });
|
|
|
816
|
+
|
|
|
817
|
+ // 处理错误
|
|
|
818
|
+ writer.on('error', (err) => {
|
|
|
819
|
+ console.error("二维码文件写入失败:", err);
|
|
|
820
|
+ });
|
|
|
821
|
+
|
|
|
822
|
+ } catch (error) {
|
|
|
823
|
+ console.error("生成二维码失败:", error);
|
|
|
824
|
+ ctx.status = 500;
|
|
|
825
|
+ ctx.body = {
|
|
|
826
|
+ errcode: 500,
|
|
|
827
|
+ errStr: '生成二维码失败',
|
|
|
828
|
+ error: error.message
|
|
|
829
|
+ };
|
|
|
830
|
+ }
|
|
738
|
831
|
}
|