chengjie пре 6 месеци
родитељ
комит
1ea6128edd
4 измењених фајлова са 799 додато и 3 уклоњено
  1. 459 0
      src/api/pinyin/pinyinController.js
  2. 16 0
      src/api/pinyin/routes.js
  3. 8 3
      src/app.js
  4. 316 0
      src/model/pinyin.js

+ 459 - 0
src/api/pinyin/pinyinController.js

@@ -0,0 +1,459 @@
1
+import moment from 'moment';
2
+import dataUpdateStatus from '../../model/dataUpdateStatus.js';
3
+import pinyin from '../../model/pinyin.js';
4
+import config from '../../config/index.js';
5
+import _ from 'lodash';
6
+import axios from 'axios';
7
+import { Encrypt, Decrypt } from '../../util/crypto/index.js';
8
+import { stringUtils } from '../../util/stringClass.js';
9
+import WXBizDataCrypt from '../../util/WXBizDataCrypt.js';
10
+import { globalCache } from '../../util/GlobalCache.js';
11
+
12
+export async function PinyinLogin(ctx) {
13
+    let param = ctx.request.body;
14
+    if (param.param) {
15
+        const paramStr = Decrypt(param.param, config.urlSecrets.aes_key, config.urlSecrets.aes_iv);
16
+        //console.log("paramStr:"+paramStr);
17
+        param = JSON.parse(paramStr);
18
+    }
19
+    const code = param.Code;
20
+    //console.log("code:"+code);
21
+    const url = `https://api.weixin.qq.com/sns/jscode2session?appid=${config.wx.pinyin_appid}&secret=${config.wx.pinyin_appsecret}&js_code=${code}&grant_type=authorization_code`;
22
+
23
+    let result = await axios.get(url)
24
+        .then(res => {
25
+            const json = res.data;
26
+            //console.log("json:"+json);
27
+            if (json && json.openid) {
28
+                param.OpenID = json.openid;
29
+                param.sessionKey = json.session_key;
30
+                if (json.unionid)
31
+                    param.UnionID = json.unionid;
32
+                return {errcode: 10000};
33
+            }
34
+            else {
35
+                return json;
36
+            }
37
+        })
38
+        .catch(err => {
39
+            return {errcode: 101, errStr: err};
40
+        });
41
+
42
+    if (result.errcode == 10000) {
43
+        delete param.Code;
44
+        if (param.sessionKey && param.iv && param.encryptedData){
45
+            //console.log("param.sessionKey:"+param.sessionKey);
46
+            const pc = new WXBizDataCrypt(config.wx.phonics_appid, param.sessionKey);
47
+            const dataUnionID = pc.decryptData(param.encryptedData , param.iv);
48
+            //console.log(dataUnionID);
49
+            param.UnionID = dataUnionID.unionId;
50
+        }
51
+
52
+        delete param.sessionKey;
53
+        delete param.iv;
54
+        delete param.encryptedData;
55
+
56
+        //todo
57
+        //param.OpenID="o4UHq4gaNlHfdTWxgl3fTgC1mFsI";
58
+
59
+        let userList = await pinyin.GetUsersInfo(param);
60
+        if (userList.length > 0) {
61
+            param.LastLoginTime = new Date();
62
+            const time1 = moment(userList[0].ProductServiceTime).format('YYYY-MM-DD HH:mm:ss');
63
+            const time3 = moment().format('YYYY-MM-DD HH:mm:ss');
64
+            if (time1 < time3)
65
+                param.IsMember = 0;
66
+
67
+            delete param.Introducer;
68
+            delete param.UserSource;
69
+            delete param.SourceID;
70
+            //console.log(param.NickName);
71
+            if (param.NickName == "陌生用户") {
72
+                delete param.NickName;
73
+                delete param.AvatarUrl;
74
+                delete param.Language;
75
+                delete param.Gender;
76
+                delete param.City;
77
+                delete param.Province;
78
+                delete param.Country;
79
+            }
80
+
81
+            await pinyin.UpdateUsers(param);
82
+            userList = await pinyin.GetUsersInfo(param);
83
+        }
84
+        else {
85
+            param.NickName = "陌生用户";
86
+            param.AvatarUrl = "../images/userface_default.png";
87
+            param.CreateTime = new Date();
88
+            param.LastLoginTime = param.CreateTime;
89
+            param.ProductServiceTime = param.CreateTime;
90
+            const inseredID = await pinyin.AddUsers(param);
91
+            userList = await pinyin.GetUsersInfo(param);
92
+        }
93
+
94
+        delete userList[0].OpenID;
95
+        delete userList[0].UnionID;
96
+
97
+        result = {errcode: 10000, result: userList[0]};
98
+    }
99
+
100
+    ctx.body = result;
101
+}
102
+
103
+//新增拼音记录
104
+export async function AddPinyinRecord(ctx) {
105
+    const param = ctx.request.body;
106
+    const inseredID = await pinyin.AddPinyinRecord(param);
107
+
108
+    ctx.body = {errcode: 10000, result: inseredID};
109
+}
110
+
111
+//更新拼音记录
112
+export async function UpdatePinyinRecord(ctx) {
113
+    const param = ctx.request.body;
114
+    await pinyin.UpdatePinyinRecord(param);
115
+    ctx.body = {errcode: 10000};
116
+}
117
+
118
+//得到用户记录
119
+export async function GetPinyinRecordData(ctx) {
120
+    const param = {
121
+        UserID: ctx.query.UserID || 0,
122
+        Version: ctx.query.Version || "1.0.0",
123
+    };
124
+    if (param.UserID === "undefined")
125
+        param.UserID = 0;
126
+
127
+    const result = await pinyin.GetPinyinRecordData(param);
128
+
129
+    if (param.UserID > 0 && result && result.length > 0) {
130
+        const userList = await pinyin.GetUsersInfoByUserID(param);
131
+
132
+        //是否是首日
133
+        const timeCreateTime = moment(userList[0].CreateTime).format('YYYYMMDD');
134
+        const timeToday = moment().format('YYYYMMDD');
135
+        if (timeCreateTime === timeToday)
136
+            result[0].IsFirstDay = true;
137
+        else
138
+            result[0].IsFirstDay = false;
139
+
140
+        const a = moment(userList[0].CreateTime);
141
+        const b = moment();
142
+        result[0].DayNumber = b.diff(a, 'days') + 1;
143
+
144
+        //得到分享新增用户数
145
+        let productServiceTime = moment(userList[0].ProductServiceTime).format('YYYYMMDD');
146
+        if (productServiceTime === "20991231") {
147
+            result[0].NewUserNumber = 999999;
148
+        }
149
+        else {
150
+            const newUserNumber = await pinyin.GetNewUserByUserID(param);
151
+            if (newUserNumber) {
152
+                result[0].NewUserNumber = newUserNumber.length;
153
+                //console.log("userList[0].ActivityTime:"+userList[0].ActivityTime);
154
+
155
+                productServiceTime = moment(userList[0].ProductServiceTime).format('YYYYMMDD');
156
+                const currentTime = moment().format('YYYYMMDD');
157
+
158
+                //如果推荐用户数超过6个,就改为增加3个月
159
+                if (newUserNumber.length >= 6 && !userList[0].ActivityTime && productServiceTime >= currentTime) {
160
+                    const obj = {
161
+                        ActivityTime: moment().format('YYYY-MM-DD HH:mm:ss'),
162
+                        ProductServiceTime: moment(userList[0].ProductServiceTime).add(1, 'months').format('YYYY-MM-DD HH:mm:ss'),
163
+                        OpenID: userList[0].OpenID,
164
+                    }
165
+                    await pinyin.UpdateUsers(obj);
166
+                    result[0].NewUserNumber = 999999;
167
+                }
168
+            }
169
+        }
170
+
171
+        result[0].IsMember = userList[0].IsMember;
172
+        if (productServiceTime < timeToday)
173
+            result[0].IsMember = 0;
174
+
175
+        const result2 = await pinyin.GetPinyinFinishedDataCount(param);
176
+
177
+        if (result2)
178
+            result[0].FinishedCount = result2[0].count;
179
+
180
+        const param2 = {
181
+            ProgramID: 98,
182
+            Version: param.Version,
183
+        };
184
+        const result3 = await dataUpdateStatus.GetProductVersionList(param2);
185
+        if (result3) {
186
+            if ((param.Version === result3[0].Version && result3[0].IsShowPay <= 0)
187
+                || param.Version > result3[0].Version) {
188
+                result[0].IsShow = result3[0].IsShowPay;
189
+            }
190
+            else {
191
+                result[0].IsShow = 1;
192
+            }
193
+
194
+            //针对iphone测试用户,永远是无支付状态
195
+            if (userList[0].Brand === 'iPhone' && userList[0].WXLanguage === 'en-US'
196
+                && userList[0].UserSource === '1001' && userList[0].IsPay === 0) {
197
+                result[0].IsShow = 0;
198
+            }
199
+        }
200
+
201
+        ctx.body = {"errcode": 10000, result: result[0]};
202
+    }
203
+    else
204
+        ctx.body = {"errcode": 10000};
205
+}
206
+
207
+//新增或删除拼音完成结果
208
+export async function UpdatePinyinFinished(ctx) {
209
+    const param = ctx.request.body;
210
+    if (param.Style === "undefined")
211
+        param.Style = "";
212
+    if (param.IsFinished) {
213
+        delete param.IsFinished;
214
+        if (param.UserID) {
215
+            await pinyin.AddPinyinFinished(param);
216
+        }
217
+    }
218
+    else {
219
+        delete param.IsFinished;
220
+        if (param.UserID) {
221
+            await pinyin.DeletePinyinFinished(param);
222
+        }
223
+    }
224
+    ctx.body = {errcode: 10000};
225
+}
226
+
227
+//得到用户完成记录
228
+export async function GetPinyinFinishedData(ctx) {
229
+    const param = {
230
+        UserID: ctx.query.UserID || 0,
231
+        Category: ctx.query.Category || 0,
232
+    };
233
+    if (param.UserID === "undefined")
234
+        param.UserID = 0;
235
+
236
+    const result = await pinyin.GetPinyinFinishedData(param);
237
+    if (result && result.length > 0)
238
+        ctx.body = {"errcode": 10000, result: result};
239
+    else
240
+        ctx.body = {"errcode": 10000};
241
+}
242
+
243
+//帮助用户使用兑换卡
244
+export async function SetPinyinUserExchange(ctx) {
245
+    const param = {
246
+        ExchangeUserID: ctx.query.UserID || 0,
247
+        ID: ctx.query.ProductPayInfoID || 0,
248
+        ExchangeTime: new Date(),
249
+    };
250
+    if (param.ID === "undefined")
251
+        param.ID = 0;
252
+
253
+    const ProductPayInfo = await pinyin.GetPinyinUserExchange(param);
254
+    if (ProductPayInfo && ProductPayInfo.length) {
255
+        if (ProductPayInfo[0].ExchangeUserID === 0) {
256
+            await pinyin.SetPinyinUserExchange(param);
257
+            const param2 = {};
258
+            param2.UserID = param.ExchangeUserID;
259
+            const userList = await pinyin.GetUsersInfoByUserID(param2);
260
+            if (userList && userList.length) {
261
+                const time1 = moment().format('YYYYMMDD');
262
+                const time2 = moment(userList[0].ProductServiceTime).format('YYYYMMDD');
263
+                if (time1 < time2) {
264
+                    param2.ProductServiceTime = moment(userList[0].ProductServiceTime).add(6, 'months').format('YYYY-MM-DD HH:mm:ss');
265
+                }
266
+                else {
267
+                    param2.ProductServiceTime = moment().add(6, 'months').format('YYYY-MM-DD HH:mm:ss');
268
+                }
269
+                param2.IsMember = 1;
270
+
271
+                await pinyin.UpdateUsersByUserID(param2);
272
+            }
273
+            ctx.body = {"errcode": 10000, result: true};
274
+        }
275
+        else
276
+            ctx.body = {"errcode": 10000, result: false};
277
+    }
278
+    else
279
+        ctx.body = {"errcode": 10000, result: false};
280
+}
281
+
282
+//得到拼音单元数据
283
+export async function GetPinyinUnitWords(ctx) {
284
+    const param = {
285
+        BookID: ctx.query.BookID || 44,
286
+        UnitID: ctx.query.UnitID || 431,
287
+        Word: ctx.query.Word || "b",
288
+        TestType: ctx.query.TestType || "read",
289
+    };
290
+
291
+    let result = globalCache.get("GetPinyinUnitWords?TestType=" + param.TestType + "&BookID=" + param.BookID + "&UnitID=" + param.UnitID + "&Word=" + param.Word);
292
+    if (result === 0) {
293
+        result = [];
294
+
295
+        if (param.BookID === 44) {
296
+            let arrExclude = [];
297
+            const arrPinyinBasic = constantClass.getPinyinBasic();
298
+            for (let k = 0; k < arrPinyinBasic.length; k++) {
299
+                for (let i = 0; i < arrPinyinBasic[k].List.length; i++) {
300
+                    if (arrPinyinBasic[k].List[i].Name === param.Word) {
301
+                        arrExclude = arrPinyinBasic[k].List[i].Exclude;
302
+                        break;
303
+                    }
304
+                }
305
+
306
+                if (arrExclude.length > 0)
307
+                    break;
308
+            }
309
+
310
+            const pinyinArr = constantClass.getPinyinArray();
311
+
312
+            const arr = [];
313
+            for (let i = 0; i < pinyinArr.length; i++) {
314
+                let word = param.Word;
315
+                const item = pinyinArr[i];
316
+                if (word === "un") {
317
+                    if (item[0].substr(0, 1) === "j"
318
+                        || item[0].substr(0, 1) === "q"
319
+                        || item[0].substr(0, 1) === "x"
320
+                        || item[0].substr(0, 1) === "y"
321
+                    ) {
322
+                        continue;
323
+                    }
324
+                }
325
+                if (word.indexOf("ü") >= 0) {
326
+                    if (item[0].substr(0, 1) === "j"
327
+                        || item[0].substr(0, 1) === "q"
328
+                        || item[0].substr(0, 1) === "x"
329
+                        || item[0].substr(0, 1) === "y"
330
+                    ) {
331
+                        word = word.replace("ü", "u");
332
+                    }
333
+                    else {
334
+                        word = word.replace("ü", "v");
335
+                    }
336
+                }
337
+
338
+                if (item[0].length > word.length &&
339
+                    ((item[0].indexOf(word) === 0 && item[0].indexOf("5") < 0)
340
+                        || item[0].lastIndexOf(word + "1") === (item[0].length - word.length - 1)
341
+                        || item[0].lastIndexOf(word + "2") === (item[0].length - word.length - 1)
342
+                        || item[0].lastIndexOf(word + "3") === (item[0].length - word.length - 1)
343
+                        || item[0].lastIndexOf(word + "4") === (item[0].length - word.length - 1)
344
+                    )
345
+                ) {
346
+                    let b = true;
347
+                    for (let j = 0; j < arrExclude.length; j++) {
348
+                        if (item[0].indexOf(arrExclude[j]) >= 0) {
349
+                            b = false;
350
+                            break;
351
+                        }
352
+                    }
353
+                    if (b) {
354
+                        if (item[0].indexOf(word) >= 0 && !(item[2].length === 1 && item[2] === "")) {
355
+                            arr.push(item)
356
+                        }
357
+                    }
358
+                }
359
+            }
360
+            //console.log(arr);
361
+            for (let i = 0; i < arr.length; i++) {
362
+                const obj = {};
363
+                obj.ID = i + 1;
364
+                let qustion, answer, tags;
365
+                const ReadString = "https://pinyin-1253256735.file.myqcloud.com/sounds/" + arr[i][0] + ".m4a";
366
+                qustion = arr[i][1];
367
+
368
+                //console.log(JSON.stringify(json.CHN));
369
+
370
+                answer = "[读 src='" + ReadString + "']" + qustion + "[/读]\n\n";
371
+
372
+                answer += arr[i][2].join(",");
373
+
374
+                tags = "拼音怎么念";
375
+
376
+                obj.Word = qustion;
377
+                obj.ReadString = ReadString;
378
+                obj.Content = [];
379
+                obj.Content.push({ContentType: 0, Content: tags});
380
+                obj.Content.push({ContentType: 1, Content: qustion});
381
+                obj.Content.push({ContentType: 2, Content: answer});
382
+                obj.Content.push({ContentType: 3, Content: ""});
383
+                result.push(obj);
384
+            }
385
+        }
386
+        else {
387
+            let arr = "";
388
+            switch (Number(param.UnitID)) {
389
+                case 431:
390
+                    arr = "b,p,m,f,d,t,n,l";
391
+                    break;
392
+                case 432:
393
+                    arr = "g,k,h,j,q,x";
394
+                    break;
395
+                case 433:
396
+                    arr = "zh,ch,sh,r,z,c,s,y,w";
397
+                    break;
398
+                case 434:
399
+                    arr = "a,o,e,i,u,ü";
400
+                    break;
401
+                case 435:
402
+                    arr = "ai,ei,ui,ao,ou,iu,ie,üe,er";
403
+                    break;
404
+                case 436:
405
+                    arr = "an,en,in,un,ün,ang,eng,ing,ong";
406
+                    break;
407
+                case 437:
408
+                    arr = "zhi,chi,shi,ri,zi,ci,si,yi,wu";
409
+                    break;
410
+                case 438:
411
+                    arr = "yu,ye,yue,yin,yun,yuan,ying";
412
+                    break;
413
+            }
414
+            arr = arr.split(",");
415
+            for (let i = 0; i < arr.length; i++) {
416
+                const obj = {};
417
+                obj.ID = i + 1;
418
+                let qustion, answer, tags;
419
+                let sound = arr[i];
420
+                sound = sound.replace("ü", "v");
421
+                const ReadString = "https://pinyin-1253256735.file.myqcloud.com/basic/" + sound + ".m4a";
422
+
423
+                if (param.TestType === "read") {
424
+                    qustion = arr[i];
425
+                    //console.log(JSON.stringify(json.CHN));
426
+                    answer = "[读 src='" + ReadString + "']" + qustion + "[/读]\n\n";
427
+                    tags = "拼音怎么念";
428
+                }
429
+                else {
430
+                    //console.log(result[i].Word);
431
+                    qustion = "[读 src='" + ReadString + "']拼音[/读]\n";
432
+
433
+                    answer = arr[i] + "\n\n";
434
+                    for (let j = 0; j < arr[i].length; j++) {
435
+                        let str = arr[i][j];
436
+                        if (str === "ü")
437
+                            str = "v1"
438
+                        answer += "[图 w='650' h='650']https://miaguo-1253256735.file.myqcloud.com/letter/s" + str + ".gif[/图]\n";
439
+                    }
440
+
441
+                    tags = "拼音怎么写";
442
+                }
443
+
444
+                obj.Word = arr[i];
445
+                obj.ReadString = ReadString;
446
+                obj.Content = [];
447
+                obj.Content.push({ContentType: 0, Content: tags});
448
+                obj.Content.push({ContentType: 1, Content: qustion});
449
+                obj.Content.push({ContentType: 2, Content: answer});
450
+                obj.Content.push({ContentType: 3, Content: ""});
451
+                result.push(obj);
452
+            }
453
+        }
454
+
455
+        globalCache.set("GetPinyinUnitWords?TestType=" + param.TestType + "&BookID=" + param.BookID + "&UnitID=" + param.UnitID + "&Word=" + param.Word, result, config.BufferMemoryTimeHigh);
456
+    }
457
+
458
+    ctx.body = {"errcode": 10000, result: result};
459
+}

+ 16 - 0
src/api/pinyin/routes.js

@@ -0,0 +1,16 @@
1
+import Router from 'koa-router';
2
+import * as pinyin from './pinyinController.js';
3
+
4
+
5
+const router = new Router();
6
+ //拼音
7
+router.post('/api/PinyinLogin',pinyin.PinyinLogin);
8
+router.post('/api/AddPinyinRecord',pinyin.AddPinyinRecord);
9
+router.post('/api/UpdatePinyinRecord',pinyin.UpdatePinyinRecord);
10
+router.get('/api/GetPinyinRecordData',pinyin.GetPinyinRecordData);
11
+router.post('/api/UpdatePinyinFinished',pinyin.UpdatePinyinFinished);
12
+router.get('/api/GetPinyinFinishedData',pinyin.GetPinyinFinishedData);
13
+router.get('/api/SetPinyinUserExchange',pinyin.SetPinyinUserExchange);
14
+router.get('/api/GetPinyinUnitWords',pinyin.GetPinyinUnitWords);
15
+
16
+export default router;

+ 8 - 3
src/app.js

@@ -4,12 +4,15 @@ import serve from 'koa-static';
4 4
 import path from 'path';
5 5
 import { fileURLToPath } from 'url';
6 6
 import config from './config/index.js';
7
-import mpsRouter from './api/mps/routes.js';
8
-import phonicsRouter from './api/phonics/routes.js';
9
-import commonRouter from './api/common/routes.js';
10 7
 import { decryptUrlMiddle } from './util/crypto/index.js';
11 8
 import { stringUtils } from './util/stringClass.js';
12 9
 
10
+
11
+import commonRouter from './api/common/routes.js';
12
+import mpsRouter from './api/mps/routes.js';
13
+import phonicsRouter from './api/phonics/routes.js';
14
+import pinyinRouter from './api/pinyin/routes.js';
15
+
13 16
 const __dirname = path.dirname(fileURLToPath(import.meta.url));
14 17
 
15 18
 const app = new Koa();
@@ -42,6 +45,8 @@ app.use(mpsRouter.routes());
42 45
 app.use(mpsRouter.allowedMethods());
43 46
 app.use(phonicsRouter.routes());
44 47
 app.use(phonicsRouter.allowedMethods());
48
+app.use(pinyinRouter.routes());
49
+app.use(pinyinRouter.allowedMethods());
45 50
 
46 51
 // 启动服务器
47 52
 app.listen(config.port, () => {

+ 316 - 0
src/model/pinyin.js

@@ -0,0 +1,316 @@
1
+import { query } from '../util/db.js';
2
+
3
+/**
4
+ * 拼音模型类
5
+ */
6
+class Pinyin {
7
+    /**
8
+     * 获取用户信息(通过OpenID)
9
+     * @param {Object} obj 查询参数
10
+     * @param {string} obj.OpenID 用户OpenID
11
+     * @returns {Promise<Array>} 用户信息
12
+     */
13
+    static async GetUsersInfo(obj) {
14
+        try {
15
+            const sql = "SELECT * FROM PinyinWXUsers WHERE OpenID=?";
16
+            return await query(sql, [obj.OpenID]);
17
+        } catch (error) {
18
+            console.error('获取用户信息失败:', error);
19
+            throw error;
20
+        }
21
+    }
22
+
23
+    /**
24
+     * 获取用户信息(通过UserID)
25
+     * @param {Object} obj 查询参数
26
+     * @param {number} obj.UserID 用户ID
27
+     * @returns {Promise<Array>} 用户信息
28
+     */
29
+    static async GetUsersInfoByUserID(obj) {
30
+        try {
31
+            const sql = "SELECT * FROM PinyinWXUsers WHERE UserID=?";
32
+            return await query(sql, [obj.UserID]);
33
+        } catch (error) {
34
+            console.error('获取用户信息失败:', error);
35
+            throw error;
36
+        }
37
+    }
38
+
39
+    /**
40
+     * 添加用户
41
+     * @param {Object} obj 用户信息
42
+     * @returns {Promise<Object>} 插入结果
43
+     */
44
+    static async AddUsers(obj) {
45
+        try {
46
+            const sql = "INSERT INTO PinyinWXUsers SET ?";
47
+            return await query(sql, [obj]);
48
+        } catch (error) {
49
+            console.error('添加用户失败:', error);
50
+            throw error;
51
+        }
52
+    }
53
+
54
+    /**
55
+     * 更新用户信息(通过OpenID)
56
+     * @param {Object} obj 更新参数
57
+     * @param {string} obj.OpenID 用户OpenID
58
+     * @returns {Promise<Object>} 更新结果
59
+     */
60
+    static async UpdateUsers(obj) {
61
+        try {
62
+            const sql = "UPDATE PinyinWXUsers SET ? WHERE OpenID=?";
63
+            return await query(sql, [obj, obj.OpenID]);
64
+        } catch (error) {
65
+            console.error('更新用户信息失败:', error);
66
+            throw error;
67
+        }
68
+    }
69
+
70
+    /**
71
+     * 更新用户信息(通过UserID)
72
+     * @param {Object} obj 更新参数
73
+     * @param {number} obj.UserID 用户ID
74
+     * @returns {Promise<Object>} 更新结果
75
+     */
76
+    static async UpdateUsersByUserID(obj) {
77
+        try {
78
+            const sql = "UPDATE PinyinWXUsers SET ? WHERE UserID=?";
79
+            return await query(sql, [obj, obj.UserID]);
80
+        } catch (error) {
81
+            console.error('更新用户信息失败:', error);
82
+            throw error;
83
+        }
84
+    }
85
+
86
+    /**
87
+     * 添加拼音记录
88
+     * @param {Object} obj 记录信息
89
+     * @returns {Promise<Object>} 插入结果
90
+     */
91
+    static async AddPinyinRecord(obj) {
92
+        try {
93
+            const sql = "INSERT INTO PinyinRecords SET ?";
94
+            return await query(sql, [obj]);
95
+        } catch (error) {
96
+            console.error('添加拼音记录失败:', error);
97
+            throw error;
98
+        }
99
+    }
100
+
101
+    /**
102
+     * 更新拼音记录
103
+     * @param {Object} obj 更新参数
104
+     * @param {string} obj.RecordID 记录ID
105
+     * @returns {Promise<Object>} 更新结果
106
+     */
107
+    static async UpdatePinyinRecord(obj) {
108
+        try {
109
+            const sql = "UPDATE PinyinRecords SET ? WHERE RecordID=?";
110
+            return await query(sql, [obj, obj.RecordID]);
111
+        } catch (error) {
112
+            console.error('更新拼音记录失败:', error);
113
+            throw error;
114
+        }
115
+    }
116
+
117
+    /**
118
+     * 获取拼音记录数据
119
+     * @param {Object} obj 查询参数
120
+     * @param {number} obj.UserID 用户ID
121
+     * @returns {Promise<Array>} 记录数据
122
+     */
123
+    static async GetPinyinRecordData(obj) {
124
+        try {
125
+            const sql = `SELECT 
126
+                COUNT(DISTINCT DATE_FORMAT(CreateTime,'%Y-%m-%d')) as DayNumber,
127
+                SUM(PinyinNumber) as PinyinNumber 
128
+                FROM PinyinRecords WHERE UserID=?`;
129
+            return await query(sql, [obj.UserID]);
130
+        } catch (error) {
131
+            console.error('获取拼音记录数据失败:', error);
132
+            throw error;
133
+        }
134
+    }
135
+
136
+    /**
137
+     * 获取新用户信息(通过UserID)
138
+     * @param {Object} obj 查询参数
139
+     * @param {number} obj.UserID 用户ID
140
+     * @returns {Promise<Array>} 用户信息
141
+     */
142
+    static async GetNewUserByUserID(obj) {
143
+        try {
144
+            const sql = "SELECT UserID, NickName, AvatarUrl FROM PinyinWXUsers WHERE Introducer=?";
145
+            return await query(sql, [obj.UserID]);
146
+        } catch (error) {
147
+            console.error('获取新用户信息失败:', error);
148
+            throw error;
149
+        }
150
+    }
151
+
152
+    /**
153
+     * 获取已完成的拼音数量
154
+     * @param {Object} obj 查询参数
155
+     * @param {number} obj.UserID 用户ID
156
+     * @returns {Promise<Array>} 完成数量
157
+     */
158
+    static async GetPinyinFinishedDataCount(obj) {
159
+        try {
160
+            const sql = "SELECT COUNT(*) as count FROM PinyinFinished WHERE UserID=?";
161
+            return await query(sql, [obj.UserID]);
162
+        } catch (error) {
163
+            console.error('获取已完成的拼音数量失败:', error);
164
+            throw error;
165
+        }
166
+    }
167
+
168
+    /**
169
+     * 添加支付信息
170
+     * @param {Object} obj 支付信息
171
+     * @returns {Promise<Object>} 插入结果
172
+     */
173
+    static async AddPayInfo(obj) {
174
+        try {
175
+            obj.ProductID = 98;
176
+            const sql = "INSERT INTO ProductPayInfo SET ?";
177
+            return await query(sql, [obj]);
178
+        } catch (error) {
179
+            console.error('添加支付信息失败:', error);
180
+            throw error;
181
+        }
182
+    }
183
+
184
+    /**
185
+     * 更新支付信息
186
+     * @param {Object} obj 更新参数
187
+     * @param {string} obj.OpenID 用户OpenID
188
+     * @param {string} obj.TradeNo 交易号
189
+     * @returns {Promise<Object>} 更新结果
190
+     */
191
+    static async UpdatePayInfo(obj) {
192
+        try {
193
+            const sql = "UPDATE ProductPayInfo SET ? WHERE OpenID=? AND TradeNo=?";
194
+            return await query(sql, [obj, obj.OpenID, obj.TradeNo]);
195
+        } catch (error) {
196
+            console.error('更新支付信息失败:', error);
197
+            throw error;
198
+        }
199
+    }
200
+
201
+    /**
202
+     * 获取支付信息列表
203
+     * @param {Object} obj 查询参数
204
+     * @param {string} obj.OpenID 用户OpenID
205
+     * @param {string} obj.TradeNo 交易号
206
+     * @returns {Promise<Array>} 支付信息列表
207
+     */
208
+    static async GetPayInfoListByOpenIDAndTradeNo(obj) {
209
+        try {
210
+            const sql = "SELECT * FROM ProductPayInfo WHERE OpenID=? AND TradeNo=?";
211
+            return await query(sql, [obj.OpenID, obj.TradeNo]);
212
+        } catch (error) {
213
+            console.error('获取支付信息列表失败:', error);
214
+            throw error;
215
+        }
216
+    }
217
+
218
+    /**
219
+     * 添加拼音临时数据
220
+     * @param {Object} obj 临时数据
221
+     * @returns {Promise<Object>} 插入结果
222
+     */
223
+    static async AddPinyinTemp(obj) {
224
+        try {
225
+            const sql = "INSERT INTO PinyinTemp SET ?";
226
+            return await query(sql, [obj]);
227
+        } catch (error) {
228
+            console.error('添加拼音临时数据失败:', error);
229
+            throw error;
230
+        }
231
+    }
232
+
233
+    /**
234
+     * 添加已完成的拼音
235
+     * @param {Object} obj 完成记录
236
+     * @returns {Promise<Object>} 插入结果
237
+     */
238
+    static async AddPinyinFinished(obj) {
239
+        try {
240
+            const sql = "INSERT INTO PinyinFinished SET ?";
241
+            return await query(sql, [obj]);
242
+        } catch (error) {
243
+            console.error('添加已完成的拼音失败:', error);
244
+            throw error;
245
+        }
246
+    }
247
+
248
+    /**
249
+     * 删除已完成的拼音
250
+     * @param {Object} obj 删除参数
251
+     * @param {number} obj.UserID 用户ID
252
+     * @param {string} obj.Title 标题
253
+     * @param {string} obj.Style 样式
254
+     * @returns {Promise<Object>} 删除结果
255
+     */
256
+    static async DeletePinyinFinished(obj) {
257
+        try {
258
+            const sql = "DELETE FROM PinyinFinished WHERE UserID=? AND Title=? AND Style=?";
259
+            return await query(sql, [obj.UserID, obj.Title, obj.Style]);
260
+        } catch (error) {
261
+            console.error('删除已完成的拼音失败:', error);
262
+            throw error;
263
+        }
264
+    }
265
+
266
+    /**
267
+     * 获取已完成的拼音数据
268
+     * @param {Object} obj 查询参数
269
+     * @param {number} obj.UserID 用户ID
270
+     * @param {string} obj.Category 分类
271
+     * @returns {Promise<Array>} 完成数据
272
+     */
273
+    static async GetPinyinFinishedData(obj) {
274
+        try {
275
+            const sql = "SELECT * FROM PinyinFinished WHERE UserID=? AND Category=?";
276
+            return await query(sql, [obj.UserID, obj.Category]);
277
+        } catch (error) {
278
+            console.error('获取已完成的拼音数据失败:', error);
279
+            throw error;
280
+        }
281
+    }
282
+
283
+    /**
284
+     * 获取拼音用户兑换信息
285
+     * @param {Object} obj 查询参数
286
+     * @param {number} obj.ID 记录ID
287
+     * @returns {Promise<Array>} 兑换信息
288
+     */
289
+    static async GetPinyinUserExchange(obj) {
290
+        try {
291
+            const sql = "SELECT * FROM ProductPayInfo WHERE ID=?";
292
+            return await query(sql, [obj.ID]);
293
+        } catch (error) {
294
+            console.error('获取拼音用户兑换信息失败:', error);
295
+            throw error;
296
+        }
297
+    }
298
+
299
+    /**
300
+     * 设置拼音用户兑换信息
301
+     * @param {Object} obj 更新参数
302
+     * @param {number} obj.ID 记录ID
303
+     * @returns {Promise<Object>} 更新结果
304
+     */
305
+    static async SetPinyinUserExchange(obj) {
306
+        try {
307
+            const sql = "UPDATE ProductPayInfo SET ? WHERE ID=?";
308
+            return await query(sql, [obj, obj.ID]);
309
+        } catch (error) {
310
+            console.error('设置拼音用户兑换信息失败:', error);
311
+            throw error;
312
+        }
313
+    }
314
+}
315
+
316
+export default Pinyin;