article.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. import common from '../../utils/util';
  2. import main from '../../utils/main';
  3. import animation from '../../utils/animation';
  4. import commonBehavior from '../../pages/behaviors/commonBehavior';
  5. const Theme = [{
  6. "Name": "DarkColor",
  7. "backgroundColor": "#004433",
  8. "color": "#C1E1C1",
  9. "frontColor": '#ffffff',
  10. }, {
  11. "Name": "LightColor",
  12. "backgroundColor": "#D0ECD3",
  13. "color": "#151815",
  14. "frontColor": '#000000',
  15. }];
  16. const app = getApp();
  17. var timeout1 = []; //用于判断是否是双击
  18. var canSaveSchedule=1;//存进度
  19. Page({
  20. behaviors: [commonBehavior],
  21. data: {
  22. Words: "",
  23. IsShowLightColor: true,
  24. IsShowTranslate: false,
  25. IsShowWordTranslate: false,
  26. IsShowWordDetail: false, //显示单词细节
  27. TranslateHeight: 100, //翻译单词框的高度
  28. lastTapTime: 0, // 记录上一次点击的时间,用于检测双击
  29. Percentage:0,
  30. },
  31. onLoad: function (options) {
  32. let that = this;
  33. let IsShowLightColor = wx.getStorageSync('IsShowLightColor');
  34. if (!IsShowLightColor) {
  35. IsShowLightColor = false;
  36. }
  37. that.setData({
  38. Containnerheight: main.getWindowHeight(),
  39. IsShowLightColor: IsShowLightColor,
  40. Title:options.Title,
  41. Chapter:options.Chapter,
  42. });
  43. wx.setNavigationBarTitle({
  44. title: options.Chapter,
  45. });
  46. that.init(options);
  47. that.setTheme();
  48. setTimeout(function(){
  49. wx.createSelectorQuery().select(".panel1").boundingClientRect(function (rect) {
  50. //console.log("rect.height:"+rect.height);
  51. that.setData({
  52. ArticleHeight: rect.height,
  53. });
  54. }).exec();
  55. },1000);
  56. this.audioCtx = wx.createAudioContext('myAudio');
  57. },
  58. init: function (options) {
  59. let that = this;
  60. let chapter = options.Chapter.replace("Chapter ", "");
  61. main.getData('GetReaderBooksChapterContent?UserID=' + app.globalData.userInfo.UserID + '&Title=' + options.Title + '&Chapter=' + chapter, function (data) {
  62. if (data) {
  63. data = that.updateData(data);
  64. let arr=[];
  65. for(let i=0;i<data.length;i++){
  66. let section={};
  67. section.List=[];
  68. for(let j=0;j<data[i].length;j++){
  69. let sentence={};
  70. sentence.CSS="";
  71. sentence.List=[];
  72. if (data[i][j]){
  73. for(let k=0;k<data[i][j].length;k++){
  74. let word={};
  75. word.CSS="";
  76. word.Word=data[i][j][k];
  77. sentence.List.push(word);
  78. }
  79. }
  80. section.List.push(sentence);
  81. }
  82. arr.push(section);
  83. }
  84. that.setData({
  85. List: arr,
  86. });
  87. setTimeout(function(){
  88. that.enterSchedule();
  89. },1000);
  90. }
  91. });
  92. },
  93. enterSchedule:function(){
  94. let that=this;
  95. let schedule=wx.getStorageSync('Schedule_'+this.data.Title);
  96. if (schedule){
  97. if (!schedule.ScrollTop){
  98. schedule.ScrollTop=0;
  99. }
  100. // let num=Math.ceil(100*(schedule.ScrollTop)/that.data.ArticleHeight);
  101. // if (num>100)
  102. // num=100;
  103. // // 更新scrollTop数据
  104. // that.setData({
  105. // Percentage: num,
  106. // ScrollTop:schedule.ScrollTop,
  107. // });
  108. wx.pageScrollTo({
  109. scrollTop: schedule.ScrollTop,
  110. duration: 300,
  111. });
  112. that.onPageScroll({scrollTop:schedule.ScrollTop});
  113. }
  114. },
  115. updateData: function (content) {
  116. let that = this;
  117. let arr1 = [],
  118. arr2 = [];
  119. for (let j = 0; j < content.length; j++) {
  120. arr2 = [];
  121. for (let i = 0; i < content[j].length; i++) {
  122. // 确保每个句子末尾有空格,避免和下一句紧挨着
  123. let sentence = content[j][i];
  124. if (sentence != "\"") {
  125. // 替换所有单引号为双引号,包括对话中的单引号和句尾的单引号
  126. sentence = sentence.replace(/(^|[,.;:!?\s])'([^']+)'([,.;:!?]|\s|$)/g, '$1"$2"$3');
  127. // 处理常见的带点缩写,将其中的点替换为特殊标记,以防止被分割
  128. // 1. 称谓缩写
  129. sentence = sentence.replace(/\b(Dr|Mr|Mrs|Ms|Prof)\./g, '$1@DOT@');
  130. // 2. 时间缩写
  131. sentence = sentence.replace(/\b([ap])\.m\./gi, '$1@DOT@m@DOT@');
  132. // 3. 学位缩写
  133. sentence = sentence.replace(/\b(B|M|Ph)\.([A-Z])\./gi, '$1@DOT@$2@DOT@');
  134. // 4. 公司名称缩写
  135. sentence = sentence.replace(/\b(Inc|Ltd|Co|Corp)\./g, '$1@DOT@');
  136. // 5. 拉丁缩写
  137. sentence = sentence.replace(/\b(e\.g|i\.e|etc|et al|vs)\./g, '$1@DOT@');
  138. // 6. 军衔缩写
  139. sentence = sentence.replace(/\b(Lt|Col|Gen|Sgt|Capt)\./g, '$1@DOT@');
  140. // 7. 地理缩写
  141. sentence = sentence.replace(/\b(St|Ave|Rd|Blvd)\./g, '$1@DOT@');
  142. // 8. 其他常见缩写
  143. sentence = sentence.replace(/\b(U\.S|U\.K|U\.N)\./g, '$1@DOT@');
  144. // 先处理破折号,在破折号前后添加空格,使其成为独立元素
  145. sentence = sentence.replace(/([^\s])([—\-–—])([^\s])/g, '$1 $2 $3');
  146. // 将句子按空格分割成单词数组
  147. let words = sentence.trim().split(/\s+/);
  148. // 将单词数组添加到ArticleEnglishArr
  149. arr2.push(words);
  150. } else
  151. arr2.push(sentence);
  152. }
  153. arr1.push(arr2);
  154. }
  155. content=arr1;
  156. // 在设置数据前,确保所有@DOT@都被替换回.
  157. that.replaceAllDOTMarkers(content);
  158. return content;
  159. },
  160. // 替换Content对象中所有的@DOT@标记为.
  161. replaceAllDOTMarkers: function (obj) {
  162. if (!obj) return;
  163. // 如果是字符串,直接替换
  164. if (typeof obj === 'string') {
  165. return obj.replace(/@DOT@/g, '.');
  166. }
  167. // 如果是数组,递归处理每个元素
  168. if (Array.isArray(obj)) {
  169. for (let i = 0; i < obj.length; i++) {
  170. if (typeof obj[i] === 'string') {
  171. obj[i] = obj[i].replace(/@DOT@/g, '.');
  172. } else if (typeof obj[i] === 'object' && obj[i] !== null) {
  173. this.replaceAllDOTMarkers(obj[i]);
  174. }
  175. }
  176. return;
  177. }
  178. // 如果是对象,递归处理每个属性
  179. if (typeof obj === 'object') {
  180. for (let key in obj) {
  181. if (obj.hasOwnProperty(key)) {
  182. if (typeof obj[key] === 'string') {
  183. obj[key] = obj[key].replace(/@DOT@/g, '.');
  184. } else if (typeof obj[key] === 'object' && obj[key] !== null) {
  185. this.replaceAllDOTMarkers(obj[key]);
  186. }
  187. }
  188. }
  189. }
  190. },
  191. setTheme: function () {
  192. let that = this;
  193. const css = Theme[that.data.IsShowLightColor ? 1 : 0];
  194. wx.setNavigationBarColor({
  195. frontColor: css.frontColor,
  196. backgroundColor: css.backgroundColor,
  197. });
  198. wx.setBackgroundColor({
  199. backgroundColor: css.backgroundColor,
  200. backgroundColorTop: css.backgroundColor,
  201. backgroundColorBottom: css.backgroundColor,
  202. });
  203. that.setData({
  204. ThemeCSS: css.Name,
  205. });
  206. wx.setStorageSync('IsShowLightColor', that.data.IsShowLightColor);
  207. },
  208. getSentenceTraslate: function (e) {
  209. let that = this;
  210. let index = e.currentTarget.dataset.index;
  211. let index2 = e.currentTarget.dataset.index2;
  212. that.setSelectedObject(e,true);
  213. let engSentence="", chnSentence;
  214. for(let i=0;i<that.data.List[index].List[index2].List.length;i++)
  215. engSentence+=that.data.List[index].List[index2].List[i].Word+" ";
  216. let param = {};
  217. param.Sentence = engSentence;
  218. main.postData('GetSentenceTranslate?UserID=' + app.globalData.userInfo.UserID, param, function (data) {
  219. if (data) {
  220. chnSentence = data;
  221. that.setData({
  222. EnglishSentence: engSentence,
  223. ChineseSentence: chnSentence,
  224. IsShowWordTranslate: true,
  225. TranslateHeight: 240,
  226. });
  227. }
  228. });
  229. },
  230. selectWord: function (e) {
  231. let that = this;
  232. //以下为双击判断
  233. const currentTime = new Date().getTime();
  234. const lastTapTime = this.data.lastTapTime;
  235. const timeDiff = currentTime - lastTapTime;
  236. const param = e;
  237. //以下为单击
  238. const timeout11 = setTimeout(function () {
  239. that.onClickHandler(param);
  240. that.setSelectedObject(param);
  241. }, 300);
  242. timeout1.push(timeout11);
  243. //console.log("timeout1:"+timeout1);
  244. // 如果两次点击的时间间隔小于300毫秒,则认为是双击
  245. if (timeDiff < 300 && timeDiff > 0) {
  246. console.log('双击事件触发');
  247. for (let i = 0; i < timeout1.length; i++)
  248. clearTimeout(timeout1[i]);
  249. // 在这里添加双击事件的处理逻辑
  250. that.getSentenceTraslate(param);
  251. }
  252. // 更新上一次点击的时间
  253. this.setData({
  254. lastTapTime: currentTime
  255. });
  256. },
  257. onClickHandler: function (e) {
  258. let that = this;
  259. let css = e.currentTarget.dataset.css;
  260. let word = e.currentTarget.dataset.word;
  261. let originalWord = e.currentTarget.dataset.originalWord || word;
  262. originalWord = originalWord.replace(/[^\w'-]/g, '');
  263. console.log("点击的单词:", originalWord);
  264. that.playAudio(originalWord);
  265. let b = false;
  266. if (css) {
  267. let list = that.data.Content.FormsOfWords;
  268. for (let i = 0; i < list.length; i++) {
  269. if (list[i].toLowerCase() == originalWord.toLowerCase() && that.data.Content.FormsOfWordsChinese && that.data.Content.FormsOfWordsChinese[i]) {
  270. let wordChinese = that.data.Content.FormsOfWordsChinese[i];
  271. // 直接更新翻译内容,不改变IsShowWordTranslate状态(如果已经是true)
  272. let updateData = {
  273. EnglishSentence: originalWord,
  274. ChineseSentence: wordChinese,
  275. };
  276. //debugger;
  277. // 只有当当前不显示翻译时,才设置IsShowWordTranslate为true
  278. if (!that.data.IsShowWordTranslate) {
  279. updateData.IsShowWordTranslate = true;
  280. }
  281. updateData.TranslateHeight = 100;
  282. that.setData(updateData);
  283. b = true;
  284. break;
  285. }
  286. }
  287. }
  288. if (!b) {
  289. that.getWordChinese(originalWord, function (wordTarget) {
  290. // 准备更新数据
  291. let updateData = {};
  292. updateData.TranslateHeight = 100;
  293. if (wordTarget) {
  294. updateData.EnglishSentence = wordTarget.Word;
  295. updateData.ChineseSentence = wordTarget.Translate;
  296. } else {
  297. updateData.EnglishSentence = originalWord;
  298. updateData.ChineseSentence = "";
  299. }
  300. // 只有当当前不显示翻译时,才设置IsShowWordTranslate为true
  301. if (!that.data.IsShowWordTranslate) {
  302. updateData.IsShowWordTranslate = true;
  303. }
  304. that.setData(updateData);
  305. });
  306. }
  307. that.setData({
  308. IsCollect: false,
  309. });
  310. app.globalData.UserCollect.filter(function (item) {
  311. if (item.Word == originalWord) {
  312. that.setData({
  313. IsCollect: true,
  314. });
  315. }
  316. });
  317. },
  318. onLongPressApi: function (e) {
  319. let that = this;
  320. that.setSelectedObject(e);
  321. let originalWord = e.currentTarget.dataset.originalWord || word;
  322. originalWord = originalWord.replace(/[^\w'-]/g, '');
  323. that.playAudio(originalWord);
  324. that.getWordDetail(originalWord, function (result) {
  325. if (result) {
  326. if (result.ENG.Book) {
  327. for (let i = 0; i < result.ENG.Book.length; i++) {
  328. result.ENG.Book[i] = result.ENG.Book[i].substring(result.ENG.Book[i].indexOf(" "));
  329. result.ENG.Book[i] = result.ENG.Book[i].substring(1, result.ENG.Book[i].indexOf("单元词汇") - 2);
  330. result.ENG.Book[i] = result.ENG.Book[i].replace("英语 ", "英语 人教版PEP ")
  331. }
  332. }
  333. if (result.ENG.ExamplesSentences) {
  334. for (let j = 0; j < 3; j++) {
  335. for (let i = 0; i < result.ENG.ExamplesSentences.length; i++) {
  336. result.ENG.ExamplesSentences[i][0] = result.ENG.ExamplesSentences[i][0].replace("[线]", "");
  337. result.ENG.ExamplesSentences[i][0] = result.ENG.ExamplesSentences[i][0].replace("[/线]", "");
  338. }
  339. }
  340. }
  341. that.setData({
  342. IsShowWordDetail: true,
  343. IsShowWordTranslate: false,
  344. WordJSON: result.ENG,
  345. });
  346. that.setData({
  347. IsCollect: false,
  348. });
  349. app.globalData.UserCollect.filter(function (item) {
  350. if (item.Word == originalWord) {
  351. that.setData({
  352. IsCollect: true,
  353. });
  354. }
  355. });
  356. }
  357. //console.log(result);
  358. });
  359. },
  360. setSelectedObject:function(e,isSentence){
  361. let that=this;
  362. let index=e.currentTarget.dataset.index;
  363. let index2=e.currentTarget.dataset.index2;
  364. let index3=e.currentTarget.dataset.index3;
  365. let list=that.data.List;
  366. for(let i=0;i<list.length;i++){
  367. for(let j=0;j<list[i].List.length;j++){
  368. list[i].List[j].CSS="";
  369. if (i==index && j==index2 && isSentence)
  370. list[i].List[j].CSS="sentence-def-highlight";
  371. for(let k=0;k<list[i].List[j].List.length;k++){
  372. if (i==index && j==index2 && k==index3 && !isSentence)
  373. list[i].List[j].List[k].CSS="highlight";
  374. else
  375. list[i].List[j].List[k].CSS="";
  376. }
  377. }
  378. }
  379. that.setData({
  380. List:list,
  381. });
  382. },
  383. getWordChinese: function (word, callback) {
  384. let that = this;
  385. main.getData('GetWordChinese?UserID=' + app.globalData.userInfo.UserID + '&Word=' + word, function (data) {
  386. if (data) {
  387. callback(data);
  388. } else
  389. callback();
  390. });
  391. },
  392. getWordDetail: function (word, callback) {
  393. let that = this;
  394. main.getData('GetWordDetail?UserID=' + app.globalData.userInfo.UserID + '&Word=' + word, function (data) {
  395. if (data) {
  396. callback(data);
  397. } else
  398. callback();
  399. });
  400. },
  401. saveUserCollect: function (e) {
  402. let that = this;
  403. let word = e.currentTarget.dataset.word;
  404. main.getData('AddOrDeleteYJBDCUserCollect?UserID=' + app.globalData.userInfo.UserID + '&Word=' + word, function (data) {
  405. that.setData({
  406. IsCollect: !that.data.IsCollect,
  407. });
  408. app.globalData.UserCollect = data;
  409. });
  410. },
  411. playAudio: function (word) {
  412. let url = app.globalData.audioUrlBaidu;
  413. if (word.currentTarget)
  414. url = word.currentTarget.dataset.url;
  415. else {
  416. url = url.replace("[token]", app.globalData.BaiduToken);
  417. url = url.replace("[word]", word);
  418. }
  419. this.audioCtx.setSrc(url);
  420. this.audioCtx.play();
  421. },
  422. hideWordTranslate: function () {
  423. console.log("IsShowWordTranslate:false");
  424. // 点击空白处时隐藏单词翻译
  425. this.setData({
  426. IsShowWordTranslate: false
  427. });
  428. },
  429. // 替换Content对象中所有的@DOT@标记为.
  430. replaceAllDOTMarkers: function (obj) {
  431. if (!obj) return;
  432. // 如果是字符串,直接替换
  433. if (typeof obj === 'string') {
  434. return obj.replace(/@DOT@/g, '.');
  435. }
  436. // 如果是数组,递归处理每个元素
  437. if (Array.isArray(obj)) {
  438. for (let i = 0; i < obj.length; i++) {
  439. if (typeof obj[i] === 'string') {
  440. obj[i] = obj[i].replace(/@DOT@/g, '.');
  441. } else if (typeof obj[i] === 'object' && obj[i] !== null) {
  442. this.replaceAllDOTMarkers(obj[i]);
  443. }
  444. }
  445. return;
  446. }
  447. // 如果是对象,递归处理每个属性
  448. if (typeof obj === 'object') {
  449. for (let key in obj) {
  450. if (obj.hasOwnProperty(key)) {
  451. if (typeof obj[key] === 'string') {
  452. obj[key] = obj[key].replace(/@DOT@/g, '.');
  453. } else if (typeof obj[key] === 'object' && obj[key] !== null) {
  454. this.replaceAllDOTMarkers(obj[key]);
  455. }
  456. }
  457. }
  458. }
  459. },
  460. onPageScroll: function(e) {
  461. // 获取当前的scrollTop
  462. const scrollTop = e.scrollTop;
  463. let num=Math.ceil(100*(scrollTop)/this.data.ArticleHeight);
  464. if (num>100)
  465. num=100;
  466. // 更新scrollTop数据
  467. this.setData({
  468. Percentage: num,
  469. ScrollTop:scrollTop,
  470. });
  471. this.saveSchedule();
  472. },
  473. saveSchedule:function(){
  474. if (canSaveSchedule){
  475. let obj={};
  476. obj.Chapter=this.data.Chapter;
  477. obj.ScrollTop=this.data.ScrollTop;
  478. if (!obj.ScrollTop)
  479. obj.ScrollTop=0;
  480. wx.setStorageSync('Schedule_'+this.data.Title, obj);
  481. canSaveSchedule=0;
  482. setTimeout(function(){
  483. canSaveSchedule=1;
  484. },10000);
  485. }
  486. },
  487. onUnload:function(){
  488. this.saveSchedule();
  489. },
  490. catchTouchMove: main.catchTouchMove,
  491. onShareAppMessage: function () {
  492. return {
  493. title: app.globalData.ShareTitle,
  494. path: app.globalData.SharePath + '?goto=article&ID=' + this.data.ID + '&UserID=' + app.globalData.userInfo.UserID,
  495. }
  496. },
  497. })